xref: /petsc/src/dm/impls/plex/plexrefine.c (revision fe998a80077c9ee0917a39496df43fc256e1b478)
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: {d, a, c, 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       /* B' tetrahedron: {e, b, a, f} */
2413       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 1;
2414       orntNew[0] = -3;
2415       coneNew[1] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 6;
2416       orntNew[1] = 1;
2417       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 7;
2418       orntNew[2] = 0;
2419       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + 3;
2420       orntNew[3] = ornt[3] < 0 ? -(GetTetSomething_Static(ornt[3], 0)+1) : GetTetSomething_Static(ornt[3], 0);
2421       ierr       = DMPlexSetCone(rdm, newp+5, coneNew);CHKERRQ(ierr);
2422       ierr       = DMPlexSetConeOrientation(rdm, newp+5, orntNew);CHKERRQ(ierr);
2423 #if 1
2424       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);
2425       for (p = 0; p < 4; ++p) {
2426         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);
2427       }
2428 #endif
2429       /* C' tetrahedron: {b, f, c, a} */
2430       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 2;
2431       orntNew[0] = -3;
2432       coneNew[1] = fStartNew + (cone[0] - fStart)*4 + 3;
2433       orntNew[1] = ornt[0] < 0 ? -(GetTetSomething_Static(ornt[0], 2)+1) : GetTetSomething_Static(ornt[0], 2);
2434       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 5;
2435       orntNew[2] = -3;
2436       coneNew[3] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 7;
2437       orntNew[3] = -2;
2438       ierr       = DMPlexSetCone(rdm, newp+6, coneNew);CHKERRQ(ierr);
2439       ierr       = DMPlexSetConeOrientation(rdm, newp+6, orntNew);CHKERRQ(ierr);
2440 #if 1
2441       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);
2442       for (p = 0; p < 4; ++p) {
2443         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);
2444       }
2445 #endif
2446       /* D' tetrahedron: {f, e, d, a} */
2447       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 3;
2448       orntNew[0] = -3;
2449       coneNew[1] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 4;
2450       orntNew[1] = -3;
2451       coneNew[2] = fStartNew + (cone[1] - fStart)*4 + 3;
2452       orntNew[2] = ornt[1] < 0 ? -(GetTetSomething_Static(ornt[1], 0)+1) : GetTetSomething_Static(ornt[1], 0);
2453       coneNew[3] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 6;
2454       orntNew[3] = -3;
2455       ierr       = DMPlexSetCone(rdm, newp+7, coneNew);CHKERRQ(ierr);
2456       ierr       = DMPlexSetConeOrientation(rdm, newp+7, orntNew);CHKERRQ(ierr);
2457 #if 1
2458       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);
2459       for (p = 0; p < 4; ++p) {
2460         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);
2461       }
2462 #endif
2463     }
2464     /* Split faces have 3 edges and the same cells as the parent */
2465     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
2466     ierr = PetscMalloc1(2 + maxSupportSize*2, &supportRef);CHKERRQ(ierr);
2467     for (f = fStart; f < fEnd; ++f) {
2468       const PetscInt  newp = fStartNew + (f - fStart)*4;
2469       const PetscInt *cone, *ornt, *support;
2470       PetscInt        coneNew[3], orntNew[3], coneSize, supportSize, s;
2471 
2472       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
2473       ierr = DMPlexGetConeOrientation(dm, f, &ornt);CHKERRQ(ierr);
2474       /* A triangle */
2475       coneNew[0] = eStartNew + (cone[0] - eStart)*2 + (ornt[0] < 0 ? 1 : 0);
2476       orntNew[0] = ornt[0];
2477       coneNew[1] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 2;
2478       orntNew[1] = -2;
2479       coneNew[2] = eStartNew + (cone[2] - eStart)*2 + (ornt[2] < 0 ? 0 : 1);
2480       orntNew[2] = ornt[2];
2481       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
2482       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
2483 #if 1
2484       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);
2485       for (p = 0; p < 3; ++p) {
2486         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eEndNew);
2487       }
2488 #endif
2489       /* B triangle */
2490       coneNew[0] = eStartNew + (cone[0] - eStart)*2 + (ornt[0] < 0 ? 0 : 1);
2491       orntNew[0] = ornt[0];
2492       coneNew[1] = eStartNew + (cone[1] - eStart)*2 + (ornt[1] < 0 ? 1 : 0);
2493       orntNew[1] = ornt[1];
2494       coneNew[2] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 0;
2495       orntNew[2] = -2;
2496       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
2497       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
2498 #if 1
2499       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);
2500       for (p = 0; p < 3; ++p) {
2501         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);
2502       }
2503 #endif
2504       /* C triangle */
2505       coneNew[0] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 1;
2506       orntNew[0] = -2;
2507       coneNew[1] = eStartNew + (cone[1] - eStart)*2 + (ornt[1] < 0 ? 0 : 1);
2508       orntNew[1] = ornt[1];
2509       coneNew[2] = eStartNew + (cone[2] - eStart)*2 + (ornt[2] < 0 ? 1 : 0);
2510       orntNew[2] = ornt[2];
2511       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
2512       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
2513 #if 1
2514       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);
2515       for (p = 0; p < 3; ++p) {
2516         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);
2517       }
2518 #endif
2519       /* D triangle */
2520       coneNew[0] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 0;
2521       orntNew[0] = 0;
2522       coneNew[1] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 1;
2523       orntNew[1] = 0;
2524       coneNew[2] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 2;
2525       orntNew[2] = 0;
2526       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
2527       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
2528 #if 1
2529       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);
2530       for (p = 0; p < 3; ++p) {
2531         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eEndNew);
2532       }
2533 #endif
2534       ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
2535       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
2536       for (r = 0; r < 4; ++r) {
2537         for (s = 0; s < supportSize; ++s) {
2538           PetscInt subf;
2539           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
2540           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
2541           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
2542           for (c = 0; c < coneSize; ++c) {
2543             if (cone[c] == f) break;
2544           }
2545           subf = GetTriSubfaceInverse_Static(ornt[c], r);
2546           supportRef[s] = cStartNew + (support[s] - cStart)*8 + (r==3 ? (c+2)%4 + 4 : faces[c*3+subf]);
2547         }
2548         ierr = DMPlexSetSupport(rdm, newp+r, supportRef);CHKERRQ(ierr);
2549 #if 1
2550         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);
2551         for (p = 0; p < supportSize; ++p) {
2552           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);
2553         }
2554 #endif
2555       }
2556     }
2557     /* Interior faces have 3 edges and 2 cells */
2558     for (c = cStart; c < cEnd; ++c) {
2559       PetscInt        newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*8;
2560       const PetscInt *cone, *ornt;
2561       PetscInt        coneNew[3], orntNew[3];
2562       PetscInt        supportNew[2];
2563 
2564       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
2565       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
2566       /* Face A: {c, a, d} */
2567       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*3 + GetTetSomething_Static(ornt[0], 2);
2568       orntNew[0] = ornt[0] < 0 ? -2 : 0;
2569       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*3 + GetTetSomething_Static(ornt[1], 2);
2570       orntNew[1] = ornt[1] < 0 ? -2 : 0;
2571       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*3 + GetTetSomething_Static(ornt[2], 2);
2572       orntNew[2] = ornt[2] < 0 ? -2 : 0;
2573       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2574       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
2575 #if 1
2576       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2577       for (p = 0; p < 3; ++p) {
2578         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eEndNew);
2579       }
2580 #endif
2581       supportNew[0] = (c - cStart)*8 + 0;
2582       supportNew[1] = (c - cStart)*8 + 0+4;
2583       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
2584 #if 1
2585       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2586       for (p = 0; p < 2; ++p) {
2587         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cEndNew);
2588       }
2589 #endif
2590       ++newp;
2591       /* Face B: {a, b, e} */
2592       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*3 + GetTetSomething_Static(ornt[0], 0);
2593       orntNew[0] = ornt[0] < 0 ? -2 : 0;
2594       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*3 + GetTetSomething_Static(ornt[3], 0);
2595       orntNew[1] = ornt[3] < 0 ? -2 : 0;
2596       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*3 + GetTetSomething_Static(ornt[1], 1);
2597       orntNew[2] = ornt[1] < 0 ? -2 : 0;
2598       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2599       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
2600 #if 1
2601       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2602       for (p = 0; p < 3; ++p) {
2603         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eEndNew);
2604       }
2605 #endif
2606       supportNew[0] = (c - cStart)*8 + 1;
2607       supportNew[1] = (c - cStart)*8 + 1+4;
2608       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
2609 #if 1
2610       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2611       for (p = 0; p < 2; ++p) {
2612         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cEndNew);
2613       }
2614 #endif
2615       ++newp;
2616       /* Face C: {c, f, b} */
2617       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*3 + GetTetSomething_Static(ornt[2], 0);
2618       orntNew[0] = ornt[2] < 0 ? -2 : 0;
2619       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*3 + GetTetSomething_Static(ornt[3], 2);
2620       orntNew[1] = ornt[3] < 0 ? -2 : 0;
2621       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*3 + GetTetSomething_Static(ornt[0], 1);
2622       orntNew[2] = ornt[0] < 0 ? -2 : 0;
2623       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2624       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
2625 #if 1
2626       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2627       for (p = 0; p < 3; ++p) {
2628         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eEndNew);
2629       }
2630 #endif
2631       supportNew[0] = (c - cStart)*8 + 2;
2632       supportNew[1] = (c - cStart)*8 + 2+4;
2633       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
2634 #if 1
2635       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2636       for (p = 0; p < 2; ++p) {
2637         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cEndNew);
2638       }
2639 #endif
2640       ++newp;
2641       /* Face D: {d, e, f} */
2642       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*3 + GetTetSomething_Static(ornt[1], 0);
2643       orntNew[0] = ornt[1] < 0 ? -2 : 0;
2644       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*3 + GetTetSomething_Static(ornt[3], 1);
2645       orntNew[1] = ornt[3] < 0 ? -2 : 0;
2646       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*3 + GetTetSomething_Static(ornt[2], 1);
2647       orntNew[2] = ornt[2] < 0 ? -2 : 0;
2648       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2649       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
2650 #if 1
2651       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2652       for (p = 0; p < 3; ++p) {
2653         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eEndNew);
2654       }
2655 #endif
2656       supportNew[0] = (c - cStart)*8 + 3;
2657       supportNew[1] = (c - cStart)*8 + 3+4;
2658       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
2659 #if 1
2660       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2661       for (p = 0; p < 2; ++p) {
2662         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cEndNew);
2663       }
2664 #endif
2665       ++newp;
2666       /* Face E: {d, f, a} */
2667       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*3 + GetTetSomething_Static(ornt[2], 1);
2668       orntNew[0] = ornt[2] < 0 ? 0 : -2;
2669       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart);
2670       orntNew[1] = -2;
2671       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*3 + GetTetSomething_Static(ornt[1], 2);
2672       orntNew[2] = ornt[1] < 0 ? -2 : 0;
2673       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2674       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
2675 #if 1
2676       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2677       for (p = 0; p < 3; ++p) {
2678         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);
2679       }
2680 #endif
2681       supportNew[0] = (c - cStart)*8 + 0+4;
2682       supportNew[1] = (c - cStart)*8 + 3+4;
2683       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
2684 #if 1
2685       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2686       for (p = 0; p < 2; ++p) {
2687         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);
2688       }
2689 #endif
2690       ++newp;
2691       /* Face F: {c, a, f} */
2692       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*3 + GetTetSomething_Static(ornt[0], 2);
2693       orntNew[0] = ornt[0] < 0 ? -2 : 0;
2694       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart);
2695       orntNew[1] = 0;
2696       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*3 + GetTetSomething_Static(ornt[2], 0);
2697       orntNew[2] = ornt[2] < 0 ? 0 : -2;
2698       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2699       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
2700 #if 1
2701       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2702       for (p = 0; p < 3; ++p) {
2703         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);
2704       }
2705 #endif
2706       supportNew[0] = (c - cStart)*8 + 0+4;
2707       supportNew[1] = (c - cStart)*8 + 2+4;
2708       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
2709 #if 1
2710       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2711       for (p = 0; p < 2; ++p) {
2712         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);
2713       }
2714 #endif
2715       ++newp;
2716       /* Face G: {e, a, f} */
2717       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*3 + GetTetSomething_Static(ornt[1], 1);
2718       orntNew[0] = ornt[1] < 0 ? -2 : 0;
2719       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart);
2720       orntNew[1] = 0;
2721       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*3 + GetTetSomething_Static(ornt[3], 1);
2722       orntNew[2] = ornt[3] < 0 ? 0 : -2;
2723       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2724       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
2725 #if 1
2726       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2727       for (p = 0; p < 3; ++p) {
2728         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);
2729       }
2730 #endif
2731       supportNew[0] = (c - cStart)*8 + 1+4;
2732       supportNew[1] = (c - cStart)*8 + 3+4;
2733       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
2734 #if 1
2735       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2736       for (p = 0; p < 2; ++p) {
2737         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);
2738       }
2739 #endif
2740       ++newp;
2741       /* Face H: {a, b, f} */
2742       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*3 + GetTetSomething_Static(ornt[0], 0);
2743       orntNew[0] = ornt[0] < 0 ? -2 : 0;
2744       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*3 + GetTetSomething_Static(ornt[3], 2);
2745       orntNew[1] = ornt[3] < 0 ? 0 : -2;
2746       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart);
2747       orntNew[2] = -2;
2748       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2749       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
2750 #if 1
2751       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2752       for (p = 0; p < 3; ++p) {
2753         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);
2754       }
2755 #endif
2756       supportNew[0] = (c - cStart)*8 + 1+4;
2757       supportNew[1] = (c - cStart)*8 + 2+4;
2758       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
2759 #if 1
2760       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2761       for (p = 0; p < 2; ++p) {
2762         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);
2763       }
2764 #endif
2765       ++newp;
2766     }
2767     /* Split Edges have 2 vertices and the same faces as the parent */
2768     for (e = eStart; e < eEnd; ++e) {
2769       const PetscInt newv = vStartNew + (vEnd - vStart) + (e - eStart);
2770 
2771       for (r = 0; r < 2; ++r) {
2772         const PetscInt  newp = eStartNew + (e - eStart)*2 + r;
2773         const PetscInt *cone, *ornt, *support;
2774         PetscInt        coneNew[2], coneSize, c, supportSize, s;
2775 
2776         ierr             = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
2777         coneNew[0]       = vStartNew + (cone[0] - vStart);
2778         coneNew[1]       = vStartNew + (cone[1] - vStart);
2779         coneNew[(r+1)%2] = newv;
2780         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2781 #if 1
2782         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
2783         for (p = 0; p < 2; ++p) {
2784           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);
2785         }
2786 #endif
2787         ierr = DMPlexGetSupportSize(dm, e, &supportSize);CHKERRQ(ierr);
2788         ierr = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
2789         for (s = 0; s < supportSize; ++s) {
2790           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
2791           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
2792           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
2793           for (c = 0; c < coneSize; ++c) {
2794             if (cone[c] == e) break;
2795           }
2796           supportRef[s] = fStartNew + (support[s] - fStart)*4 + (c + (ornt[c] < 0 ? 1-r : r))%3;
2797         }
2798         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
2799 #if 1
2800         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
2801         for (p = 0; p < supportSize; ++p) {
2802           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);
2803         }
2804 #endif
2805       }
2806     }
2807     /* Face edges have 2 vertices and 2+cells*(1/2) faces */
2808     for (f = fStart; f < fEnd; ++f) {
2809       const PetscInt *cone, *ornt, *support;
2810       PetscInt        coneSize, supportSize, s;
2811 
2812       ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
2813       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
2814       for (r = 0; r < 3; ++r) {
2815         const PetscInt  newp = eStartNew + (eEnd - eStart)*2 + (f - fStart)*3 + r;
2816         PetscInt        coneNew[2], intFaces = 0, er, eint[4] = {1, 0, 2, 0};
2817         PetscInt        fint[24] = { 1,  7, -1, -1,  0,  5,
2818                                     -1, -1,  1,  6,  0,  4,
2819                                      2,  5,  3,  4, -1, -1,
2820                                     -1, -1,  3,  6,  2,  7};
2821 
2822         ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
2823         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[(r+0)%3] - eStart);
2824         coneNew[1] = vStartNew + (vEnd - vStart) + (cone[(r+1)%3] - eStart);
2825         ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2826 #if 1
2827         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
2828         for (p = 0; p < 2; ++p) {
2829           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);
2830         }
2831 #endif
2832         supportRef[0] = fStartNew + (f - fStart)*4 + (r+1)%3;
2833         supportRef[1] = fStartNew + (f - fStart)*4 + 3;
2834         for (s = 0; s < supportSize; ++s) {
2835           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
2836           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
2837           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
2838           for (c = 0; c < coneSize; ++c) {if (cone[c] == f) break;}
2839           /* Here we want to determine whether edge newp contains a vertex which is part of the cross-tet edge */
2840           er = GetTetSomethingInverse_Static(ornt[c], r);
2841           if (er == eint[c]) {
2842             supportRef[2+intFaces++] = fStartNew + (fEnd - fStart)*4 + (support[s] - cStart)*8 + (c + 2)%4;
2843           } else {
2844             supportRef[2+intFaces++] = fStartNew + (fEnd - fStart)*4 + (support[s] - cStart)*8 + fint[(c*3 + er)*2 + 0];
2845             supportRef[2+intFaces++] = fStartNew + (fEnd - fStart)*4 + (support[s] - cStart)*8 + fint[(c*3 + er)*2 + 1];
2846           }
2847         }
2848         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
2849 #if 1
2850         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
2851         for (p = 0; p < intFaces; ++p) {
2852           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);
2853         }
2854 #endif
2855       }
2856     }
2857     /* Interior edges have 2 vertices and 4 faces */
2858     for (c = cStart; c < cEnd; ++c) {
2859       const PetscInt  newp = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart);
2860       const PetscInt *cone, *ornt, *fcone;
2861       PetscInt        coneNew[2], supportNew[4], find;
2862 
2863       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
2864       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
2865       ierr = DMPlexGetCone(dm, cone[0], &fcone);CHKERRQ(ierr);
2866       find = GetTriEdge_Static(ornt[0], 0);
2867       coneNew[0] = vStartNew + (vEnd - vStart) + (fcone[find] - eStart);
2868       ierr = DMPlexGetCone(dm, cone[2], &fcone);CHKERRQ(ierr);
2869       find = GetTriEdge_Static(ornt[2], 1);
2870       coneNew[1] = vStartNew + (vEnd - vStart) + (fcone[find] - eStart);
2871       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2872 #if 1
2873       if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
2874       for (p = 0; p < 2; ++p) {
2875         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);
2876       }
2877 #endif
2878       supportNew[0] = fStartNew + (fEnd - fStart)*4 + (c - cStart)*8 + 4;
2879       supportNew[1] = fStartNew + (fEnd - fStart)*4 + (c - cStart)*8 + 5;
2880       supportNew[2] = fStartNew + (fEnd - fStart)*4 + (c - cStart)*8 + 6;
2881       supportNew[3] = fStartNew + (fEnd - fStart)*4 + (c - cStart)*8 + 7;
2882       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
2883 #if 1
2884       if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
2885       for (p = 0; p < 4; ++p) {
2886         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);
2887       }
2888 #endif
2889     }
2890     /* Old vertices have identical supports */
2891     for (v = vStart; v < vEnd; ++v) {
2892       const PetscInt  newp = vStartNew + (v - vStart);
2893       const PetscInt *support, *cone;
2894       PetscInt        size, s;
2895 
2896       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
2897       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
2898       for (s = 0; s < size; ++s) {
2899         PetscInt r = 0;
2900 
2901         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
2902         if (cone[1] == v) r = 1;
2903         supportRef[s] = eStartNew + (support[s] - eStart)*2 + r;
2904       }
2905       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
2906 #if 1
2907       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
2908       for (p = 0; p < size; ++p) {
2909         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);
2910       }
2911 #endif
2912     }
2913     /* Edge vertices have 2 + face*2 + 0/1 supports */
2914     for (e = eStart; e < eEnd; ++e) {
2915       const PetscInt  newp = vStartNew + (vEnd - vStart) + (e - eStart);
2916       const PetscInt *cone, *support;
2917       PetscInt       *star = NULL, starSize, cellSize = 0, coneSize, size, s;
2918 
2919       ierr          = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
2920       ierr          = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
2921       supportRef[0] = eStartNew + (e - eStart)*2 + 0;
2922       supportRef[1] = eStartNew + (e - eStart)*2 + 1;
2923       for (s = 0; s < size; ++s) {
2924         PetscInt r = 0;
2925 
2926         ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
2927         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
2928         for (r = 0; r < coneSize; ++r) {if (cone[r] == e) break;}
2929         supportRef[2+s*2+0] = eStartNew + (eEnd - eStart)*2 + (support[s] - fStart)*3 + (r+0)%3;
2930         supportRef[2+s*2+1] = eStartNew + (eEnd - eStart)*2 + (support[s] - fStart)*3 + (r+2)%3;
2931       }
2932       ierr = DMPlexGetTransitiveClosure(dm, e, PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
2933       for (s = 0; s < starSize*2; s += 2) {
2934         const PetscInt *cone, *ornt;
2935         PetscInt        e01, e23;
2936 
2937         if ((star[s] >= cStart) && (star[s] < cEnd)) {
2938           /* Check edge 0-1 */
2939           ierr = DMPlexGetCone(dm, star[s], &cone);CHKERRQ(ierr);
2940           ierr = DMPlexGetConeOrientation(dm, star[s], &ornt);CHKERRQ(ierr);
2941           ierr = DMPlexGetCone(dm, cone[0], &cone);CHKERRQ(ierr);
2942           e01  = cone[GetTriEdge_Static(ornt[0], 0)];
2943           /* Check edge 2-3 */
2944           ierr = DMPlexGetCone(dm, star[s], &cone);CHKERRQ(ierr);
2945           ierr = DMPlexGetConeOrientation(dm, star[s], &ornt);CHKERRQ(ierr);
2946           ierr = DMPlexGetCone(dm, cone[2], &cone);CHKERRQ(ierr);
2947           e23  = cone[GetTriEdge_Static(ornt[2], 1)];
2948           if ((e01 == e) || (e23 == e)) {supportRef[2+size*2+cellSize++] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (star[s] - cStart);}
2949         }
2950       }
2951       ierr = DMPlexRestoreTransitiveClosure(dm, e, PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
2952       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
2953 #if 1
2954       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
2955       for (p = 0; p < 2+size*2+cellSize; ++p) {
2956         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);
2957       }
2958 #endif
2959     }
2960     ierr = PetscFree(supportRef);CHKERRQ(ierr);
2961     ierr = DMPlexRestoreFaces_Internal(dm, 3, cStart, NULL, NULL, &faces);CHKERRQ(ierr);
2962     break;
2963   case REFINER_HYBRID_SIMPLEX_3D:
2964     ierr = DMPlexGetHybridBounds(rdm, &cMaxNew, &fMaxNew, &eMaxNew, NULL);CHKERRQ(ierr);
2965     /* Interior cells have 4 faces: Tet face order is prescribed in DMPlexGetFaces_Internal() */
2966     ierr = DMPlexGetRawFaces_Internal(dm, 3, 4, cellInd, NULL, NULL, &faces);CHKERRQ(ierr);
2967     for (c = cStart; c < cMax; ++c) {
2968       const PetscInt  newp = cStartNew + (c - cStart)*8;
2969       const PetscInt *cone, *ornt;
2970       PetscInt        coneNew[4], orntNew[4];
2971 
2972       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
2973       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
2974       /* A tetrahedron: {0, a, c, d} */
2975       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetTriSubface_Static(ornt[0], 0); /* A */
2976       orntNew[0] = ornt[0];
2977       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetTriSubface_Static(ornt[1], 0); /* A */
2978       orntNew[1] = ornt[1];
2979       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetTriSubface_Static(ornt[2], 0); /* A */
2980       orntNew[2] = ornt[2];
2981       coneNew[3] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 0;
2982       orntNew[3] = 0;
2983       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
2984       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
2985 #if 1
2986       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);
2987       for (p = 0; p < 4; ++p) {
2988         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);
2989       }
2990 #endif
2991       /* B tetrahedron: {a, 1, b, e} */
2992       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetTriSubface_Static(ornt[0], 1); /* B */
2993       orntNew[0] = ornt[0];
2994       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetTriSubface_Static(ornt[1], 2); /* C */
2995       orntNew[1] = ornt[1];
2996       coneNew[2] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 1;
2997       orntNew[2] = 0;
2998       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetTriSubface_Static(ornt[3], 1); /* B */
2999       orntNew[3] = ornt[3];
3000       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
3001       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
3002 #if 1
3003       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);
3004       for (p = 0; p < 4; ++p) {
3005         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);
3006       }
3007 #endif
3008       /* C tetrahedron: {c, b, 2, f} */
3009       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetTriSubface_Static(ornt[0], 2); /* C */
3010       orntNew[0] = ornt[0];
3011       coneNew[1] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 2;
3012       orntNew[1] = 0;
3013       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetTriSubface_Static(ornt[2], 1); /* B */
3014       orntNew[2] = ornt[2];
3015       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetTriSubface_Static(ornt[3], 0); /* A */
3016       orntNew[3] = ornt[3];
3017       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
3018       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
3019 #if 1
3020       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);
3021       for (p = 0; p < 4; ++p) {
3022         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);
3023       }
3024 #endif
3025       /* D tetrahedron: {d, e, f, 3} */
3026       coneNew[0] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 3;
3027       orntNew[0] = 0;
3028       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetTriSubface_Static(ornt[1], 1); /* B */
3029       orntNew[1] = ornt[1];
3030       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetTriSubface_Static(ornt[2], 2); /* C */
3031       orntNew[2] = ornt[2];
3032       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetTriSubface_Static(ornt[3], 2); /* C */
3033       orntNew[3] = ornt[3];
3034       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
3035       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
3036 #if 1
3037       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);
3038       for (p = 0; p < 4; ++p) {
3039         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);
3040       }
3041 #endif
3042       /* A' tetrahedron: {d, a, c, f} */
3043       coneNew[0] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 0;
3044       orntNew[0] = -3;
3045       coneNew[1] = fStartNew + (cone[2] - fStart)*4 + 3;
3046       orntNew[1] = ornt[2] < 0 ? -(GetTetSomething_Static(ornt[2], 0)+1) : GetTetSomething_Static(ornt[2], 0);
3047       coneNew[2] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 5;
3048       orntNew[2] = 0;
3049       coneNew[3] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 4;
3050       orntNew[3] = 2;
3051       ierr       = DMPlexSetCone(rdm, newp+4, coneNew);CHKERRQ(ierr);
3052       ierr       = DMPlexSetConeOrientation(rdm, newp+4, orntNew);CHKERRQ(ierr);
3053 #if 1
3054       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);
3055       for (p = 0; p < 4; ++p) {
3056         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);
3057       }
3058 #endif
3059       /* B' tetrahedron: {e, b, a, f} */
3060       coneNew[0] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 1;
3061       orntNew[0] = -3;
3062       coneNew[1] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 6;
3063       orntNew[1] = 1;
3064       coneNew[2] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 7;
3065       orntNew[2] = 0;
3066       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + 3;
3067       orntNew[3] = ornt[3] < 0 ? -(GetTetSomething_Static(ornt[3], 0)+1) : GetTetSomething_Static(ornt[3], 0);
3068       ierr       = DMPlexSetCone(rdm, newp+5, coneNew);CHKERRQ(ierr);
3069       ierr       = DMPlexSetConeOrientation(rdm, newp+5, orntNew);CHKERRQ(ierr);
3070 #if 1
3071       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);
3072       for (p = 0; p < 4; ++p) {
3073         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);
3074       }
3075 #endif
3076       /* C' tetrahedron: {b, f, c, a} */
3077       coneNew[0] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 2;
3078       orntNew[0] = -3;
3079       coneNew[1] = fStartNew + (cone[0] - fStart)*4 + 3;
3080       orntNew[1] = ornt[0] < 0 ? -(GetTetSomething_Static(ornt[0], 2)+1) : GetTetSomething_Static(ornt[0], 2);
3081       coneNew[2] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 5;
3082       orntNew[2] = -3;
3083       coneNew[3] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 7;
3084       orntNew[3] = -2;
3085       ierr       = DMPlexSetCone(rdm, newp+6, coneNew);CHKERRQ(ierr);
3086       ierr       = DMPlexSetConeOrientation(rdm, newp+6, orntNew);CHKERRQ(ierr);
3087 #if 1
3088       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);
3089       for (p = 0; p < 4; ++p) {
3090         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);
3091       }
3092 #endif
3093       /* D' tetrahedron: {f, e, d, a} */
3094       coneNew[0] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 3;
3095       orntNew[0] = -3;
3096       coneNew[1] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 4;
3097       orntNew[1] = -3;
3098       coneNew[2] = fStartNew + (cone[1] - fStart)*4 + 3;
3099       orntNew[2] = ornt[1] < 0 ? -(GetTetSomething_Static(ornt[1], 0)+1) : GetTetSomething_Static(ornt[1], 0);
3100       coneNew[3] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 6;
3101       orntNew[3] = -3;
3102       ierr       = DMPlexSetCone(rdm, newp+7, coneNew);CHKERRQ(ierr);
3103       ierr       = DMPlexSetConeOrientation(rdm, newp+7, orntNew);CHKERRQ(ierr);
3104 #if 1
3105       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);
3106       for (p = 0; p < 4; ++p) {
3107         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);
3108       }
3109 #endif
3110     }
3111     /* Hybrid cells have 5 faces */
3112     for (c = cMax; c < cEnd; ++c) {
3113       const PetscInt  newp = cStartNew + (cMax - cStart)*8 + (c - cMax)*4;
3114       const PetscInt *cone, *ornt, *fornt;
3115       PetscInt        coneNew[5], orntNew[5], o, of, i;
3116 
3117       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
3118       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
3119       ierr = DMPlexGetConeOrientation(dm, cone[0], &fornt);CHKERRQ(ierr);
3120       o = ornt[0] < 0 ? -1 : 1;
3121       for (r = 0; r < 3; ++r) {
3122         coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetTriSubface_Static(ornt[0], r);
3123         orntNew[0] = ornt[0];
3124         coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetTriSubface_Static(ornt[1], r);
3125         orntNew[1] = ornt[1];
3126         of = fornt[GetTriEdge_Static(ornt[0], r)]       < 0 ? -1 : 1;
3127         i  = GetTriEdgeInverse_Static(ornt[0], r)       + 2;
3128         coneNew[i] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (cone[2+GetTriEdge_Static(ornt[0], r)]       - fMax)*2 + (o*of < 0 ? 1 : 0);
3129         orntNew[i] = 0;
3130         i  = GetTriEdgeInverse_Static(ornt[0], (r+1)%3) + 2;
3131         coneNew[i] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (c - cMax)*3 + GetTriSubface_Static(ornt[0], r);
3132         orntNew[i] = 0;
3133         of = fornt[GetTriEdge_Static(ornt[0], (r+2)%3)] < 0 ? -1 : 1;
3134         i  = GetTriEdgeInverse_Static(ornt[0], (r+2)%3) + 2;
3135         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);
3136         orntNew[i] = 0;
3137         ierr = DMPlexSetCone(rdm, newp+r, coneNew);CHKERRQ(ierr);
3138         ierr = DMPlexSetConeOrientation(rdm, newp+r, orntNew);CHKERRQ(ierr);
3139 #if 1
3140         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);
3141         for (p = 0; p < 2; ++p) {
3142           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);
3143         }
3144         for (p = 2; p < 5; ++p) {
3145           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);
3146         }
3147 #endif
3148       }
3149       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + 3;
3150       orntNew[0] = 0;
3151       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + 3;
3152       orntNew[1] = 0;
3153       coneNew[2] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (c - cMax)*3 + 1;
3154       orntNew[2] = 0;
3155       coneNew[3] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (c - cMax)*3 + 2;
3156       orntNew[3] = 0;
3157       coneNew[4] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (c - cMax)*3 + 0;
3158       orntNew[4] = 0;
3159       ierr = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
3160       ierr = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
3161 #if 1
3162       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);
3163       for (p = 0; p < 2; ++p) {
3164         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);
3165       }
3166       for (p = 2; p < 5; ++p) {
3167         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);
3168       }
3169 #endif
3170     }
3171     /* Split faces have 3 edges and the same cells as the parent */
3172     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
3173     ierr = PetscMalloc1(2 + maxSupportSize*2, &supportRef);CHKERRQ(ierr);
3174     for (f = fStart; f < fMax; ++f) {
3175       const PetscInt  newp = fStartNew + (f - fStart)*4;
3176       const PetscInt *cone, *ornt, *support;
3177       PetscInt        coneNew[3], orntNew[3], coneSize, supportSize, s;
3178 
3179       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
3180       ierr = DMPlexGetConeOrientation(dm, f, &ornt);CHKERRQ(ierr);
3181       /* A triangle */
3182       coneNew[0] = eStartNew + (cone[0] - eStart)*2 + (ornt[0] < 0 ? 1 : 0);
3183       orntNew[0] = ornt[0];
3184       coneNew[1] = eStartNew + (eMax    - eStart)*2 + (f - fStart)*3 + 2;
3185       orntNew[1] = -2;
3186       coneNew[2] = eStartNew + (cone[2] - eStart)*2 + (ornt[2] < 0 ? 0 : 1);
3187       orntNew[2] = ornt[2];
3188       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
3189       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
3190 #if 1
3191       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);
3192       for (p = 0; p < 3; ++p) {
3193         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);
3194       }
3195 #endif
3196       /* B triangle */
3197       coneNew[0] = eStartNew + (cone[0] - eStart)*2 + (ornt[0] < 0 ? 0 : 1);
3198       orntNew[0] = ornt[0];
3199       coneNew[1] = eStartNew + (cone[1] - eStart)*2 + (ornt[1] < 0 ? 1 : 0);
3200       orntNew[1] = ornt[1];
3201       coneNew[2] = eStartNew + (eMax    - eStart)*2 + (f - fStart)*3 + 0;
3202       orntNew[2] = -2;
3203       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
3204       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
3205 #if 1
3206       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);
3207       for (p = 0; p < 3; ++p) {
3208         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);
3209       }
3210 #endif
3211       /* C triangle */
3212       coneNew[0] = eStartNew + (eMax    - eStart)*2 + (f - fStart)*3 + 1;
3213       orntNew[0] = -2;
3214       coneNew[1] = eStartNew + (cone[1] - eStart)*2 + (ornt[1] < 0 ? 0 : 1);
3215       orntNew[1] = ornt[1];
3216       coneNew[2] = eStartNew + (cone[2] - eStart)*2 + (ornt[2] < 0 ? 1 : 0);
3217       orntNew[2] = ornt[2];
3218       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
3219       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
3220 #if 1
3221       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);
3222       for (p = 0; p < 3; ++p) {
3223         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);
3224       }
3225 #endif
3226       /* D triangle */
3227       coneNew[0] = eStartNew + (eMax    - eStart)*2 + (f - fStart)*3 + 0;
3228       orntNew[0] = 0;
3229       coneNew[1] = eStartNew + (eMax    - eStart)*2 + (f - fStart)*3 + 1;
3230       orntNew[1] = 0;
3231       coneNew[2] = eStartNew + (eMax    - eStart)*2 + (f - fStart)*3 + 2;
3232       orntNew[2] = 0;
3233       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
3234       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
3235 #if 1
3236       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);
3237       for (p = 0; p < 3; ++p) {
3238         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);
3239       }
3240 #endif
3241       ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
3242       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
3243       for (r = 0; r < 4; ++r) {
3244         for (s = 0; s < supportSize; ++s) {
3245           PetscInt subf;
3246           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
3247           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
3248           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
3249           for (c = 0; c < coneSize; ++c) {
3250             if (cone[c] == f) break;
3251           }
3252           subf = GetTriSubfaceInverse_Static(ornt[c], r);
3253           if (support[s] < cMax) {
3254             supportRef[s] = cStartNew + (support[s] - cStart)*8 + (r==3 ? (c+2)%4 + 4 : faces[c*3+subf]);
3255           } else {
3256             supportRef[s] = cStartNew + (cMax - cStart)*8 + (support[s] - cMax)*4 + (r==3 ? r : subf);
3257           }
3258         }
3259         ierr = DMPlexSetSupport(rdm, newp+r, supportRef);CHKERRQ(ierr);
3260 #if 1
3261         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);
3262         for (p = 0; p < supportSize; ++p) {
3263           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);
3264         }
3265 #endif
3266       }
3267     }
3268     /* Interior cell faces have 3 edges and 2 cells */
3269     for (c = cStart; c < cMax; ++c) {
3270       PetscInt        newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*8;
3271       const PetscInt *cone, *ornt;
3272       PetscInt        coneNew[3], orntNew[3];
3273       PetscInt        supportNew[2];
3274 
3275       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
3276       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
3277       /* Face A: {c, a, d} */
3278       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*3 + GetTetSomething_Static(ornt[0], 2);
3279       orntNew[0] = ornt[0] < 0 ? -2 : 0;
3280       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*3 + GetTetSomething_Static(ornt[1], 2);
3281       orntNew[1] = ornt[1] < 0 ? -2 : 0;
3282       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*3 + GetTetSomething_Static(ornt[2], 2);
3283       orntNew[2] = ornt[2] < 0 ? -2 : 0;
3284       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3285       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3286 #if 1
3287       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
3288       for (p = 0; p < 3; ++p) {
3289         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);
3290       }
3291 #endif
3292       supportNew[0] = (c - cStart)*8 + 0;
3293       supportNew[1] = (c - cStart)*8 + 0+4;
3294       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3295 #if 1
3296       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
3297       for (p = 0; p < 2; ++p) {
3298         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);
3299       }
3300 #endif
3301       ++newp;
3302       /* Face B: {a, b, e} */
3303       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*3 + GetTetSomething_Static(ornt[0], 0);
3304       orntNew[0] = ornt[0] < 0 ? -2 : 0;
3305       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*3 + GetTetSomething_Static(ornt[3], 0);
3306       orntNew[1] = ornt[3] < 0 ? -2 : 0;
3307       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*3 + GetTetSomething_Static(ornt[1], 1);
3308       orntNew[2] = ornt[1] < 0 ? -2 : 0;
3309       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3310       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3311 #if 1
3312       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);
3313       for (p = 0; p < 3; ++p) {
3314         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);
3315       }
3316 #endif
3317       supportNew[0] = (c - cStart)*8 + 1;
3318       supportNew[1] = (c - cStart)*8 + 1+4;
3319       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3320 #if 1
3321       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
3322       for (p = 0; p < 2; ++p) {
3323         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);
3324       }
3325 #endif
3326       ++newp;
3327       /* Face C: {c, f, b} */
3328       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*3 + GetTetSomething_Static(ornt[2], 0);
3329       orntNew[0] = ornt[2] < 0 ? -2 : 0;
3330       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*3 + GetTetSomething_Static(ornt[3], 2);
3331       orntNew[1] = ornt[3] < 0 ? -2 : 0;
3332       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*3 + GetTetSomething_Static(ornt[0], 1);
3333       orntNew[2] = ornt[0] < 0 ? -2 : 0;
3334       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3335       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3336 #if 1
3337       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
3338       for (p = 0; p < 3; ++p) {
3339         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);
3340       }
3341 #endif
3342       supportNew[0] = (c - cStart)*8 + 2;
3343       supportNew[1] = (c - cStart)*8 + 2+4;
3344       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3345 #if 1
3346       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
3347       for (p = 0; p < 2; ++p) {
3348         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);
3349       }
3350 #endif
3351       ++newp;
3352       /* Face D: {d, e, f} */
3353       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*3 + GetTetSomething_Static(ornt[1], 0);
3354       orntNew[0] = ornt[1] < 0 ? -2 : 0;
3355       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*3 + GetTetSomething_Static(ornt[3], 1);
3356       orntNew[1] = ornt[3] < 0 ? -2 : 0;
3357       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*3 + GetTetSomething_Static(ornt[2], 1);
3358       orntNew[2] = ornt[2] < 0 ? -2 : 0;
3359       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3360       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3361 #if 1
3362       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
3363       for (p = 0; p < 3; ++p) {
3364         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);
3365       }
3366 #endif
3367       supportNew[0] = (c - cStart)*8 + 3;
3368       supportNew[1] = (c - cStart)*8 + 3+4;
3369       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3370 #if 1
3371       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
3372       for (p = 0; p < 2; ++p) {
3373         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);
3374       }
3375 #endif
3376       ++newp;
3377       /* Face E: {d, f, a} */
3378       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*3 + GetTetSomething_Static(ornt[2], 1);
3379       orntNew[0] = ornt[2] < 0 ? 0 : -2;
3380       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart);
3381       orntNew[1] = -2;
3382       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*3 + GetTetSomething_Static(ornt[1], 2);
3383       orntNew[2] = ornt[1] < 0 ? -2 : 0;
3384       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3385       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3386 #if 1
3387       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
3388       for (p = 0; p < 3; ++p) {
3389         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);
3390       }
3391 #endif
3392       supportNew[0] = (c - cStart)*8 + 0+4;
3393       supportNew[1] = (c - cStart)*8 + 3+4;
3394       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3395 #if 1
3396       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
3397       for (p = 0; p < 2; ++p) {
3398         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);
3399       }
3400 #endif
3401       ++newp;
3402       /* Face F: {c, a, f} */
3403       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*3 + GetTetSomething_Static(ornt[0], 2);
3404       orntNew[0] = ornt[0] < 0 ? -2 : 0;
3405       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart);
3406       orntNew[1] = 0;
3407       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*3 + GetTetSomething_Static(ornt[2], 0);
3408       orntNew[2] = ornt[2] < 0 ? 0 : -2;
3409       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3410       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3411 #if 1
3412       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
3413       for (p = 0; p < 3; ++p) {
3414         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);
3415       }
3416 #endif
3417       supportNew[0] = (c - cStart)*8 + 0+4;
3418       supportNew[1] = (c - cStart)*8 + 2+4;
3419       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3420 #if 1
3421       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
3422       for (p = 0; p < 2; ++p) {
3423         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);
3424       }
3425 #endif
3426       ++newp;
3427       /* Face G: {e, a, f} */
3428       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*3 + GetTetSomething_Static(ornt[1], 1);
3429       orntNew[0] = ornt[1] < 0 ? -2 : 0;
3430       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart);
3431       orntNew[1] = 0;
3432       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*3 + GetTetSomething_Static(ornt[3], 1);
3433       orntNew[2] = ornt[3] < 0 ? 0 : -2;
3434       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3435       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3436 #if 1
3437       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
3438       for (p = 0; p < 3; ++p) {
3439         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);
3440       }
3441 #endif
3442       supportNew[0] = (c - cStart)*8 + 1+4;
3443       supportNew[1] = (c - cStart)*8 + 3+4;
3444       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3445 #if 1
3446       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
3447       for (p = 0; p < 2; ++p) {
3448         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);
3449       }
3450 #endif
3451       ++newp;
3452       /* Face H: {a, b, f} */
3453       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*3 + GetTetSomething_Static(ornt[0], 0);
3454       orntNew[0] = ornt[0] < 0 ? -2 : 0;
3455       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*3 + GetTetSomething_Static(ornt[3], 2);
3456       orntNew[1] = ornt[3] < 0 ? 0 : -2;
3457       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart);
3458       orntNew[2] = -2;
3459       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3460       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3461 #if 1
3462       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
3463       for (p = 0; p < 3; ++p) {
3464         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);
3465       }
3466 #endif
3467       supportNew[0] = (c - cStart)*8 + 1+4;
3468       supportNew[1] = (c - cStart)*8 + 2+4;
3469       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3470 #if 1
3471       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
3472       for (p = 0; p < 2; ++p) {
3473         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);
3474       }
3475 #endif
3476       ++newp;
3477     }
3478     /* Hybrid split faces have 4 edges and same cells */
3479     for (f = fMax; f < fEnd; ++f) {
3480       const PetscInt *cone, *ornt, *support;
3481       PetscInt        coneNew[4], orntNew[4];
3482       PetscInt        supportNew[2], size, s, c;
3483 
3484       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
3485       ierr = DMPlexGetConeOrientation(dm, f, &ornt);CHKERRQ(ierr);
3486       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
3487       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
3488       for (r = 0; r < 2; ++r) {
3489         const PetscInt newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (f - fMax)*2 + r;
3490 
3491         coneNew[0]   = eStartNew + (cone[0] - eStart)*2 + (ornt[0] < 0 ? 1-r : r);
3492         orntNew[0]   = ornt[0];
3493         coneNew[1]   = eStartNew + (cone[1] - eStart)*2 + (ornt[1] < 0 ? 1-r : r);
3494         orntNew[1]   = ornt[1];
3495         coneNew[2+r] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (cone[2+r] - eMax);
3496         orntNew[2+r] = 0;
3497         coneNew[3-r] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (eEnd      - eMax) + (f - fMax);
3498         orntNew[3-r] = 0;
3499         ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3500         ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3501 #if 1
3502         if ((newp < fMaxNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid face [%d, %d)", newp, fMaxNew, fEndNew);
3503         for (p = 0; p < 2; ++p) {
3504           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);
3505         }
3506         for (p = 2; p < 4; ++p) {
3507           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);
3508         }
3509 #endif
3510         for (s = 0; s < size; ++s) {
3511           const PetscInt *coneCell, *orntCell, *fornt;
3512           PetscInt        o, of;
3513 
3514           ierr = DMPlexGetCone(dm, support[s], &coneCell);CHKERRQ(ierr);
3515           ierr = DMPlexGetConeOrientation(dm, support[s], &orntCell);CHKERRQ(ierr);
3516           o = orntCell[0] < 0 ? -1 : 1;
3517           for (c = 2; c < 5; ++c) if (coneCell[c] == f) break;
3518           if (c >= 5) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Could not find face %d in cone of cell %d", f, support[s]);
3519           ierr = DMPlexGetConeOrientation(dm, coneCell[0], &fornt);CHKERRQ(ierr);
3520           of = fornt[c-2] < 0 ? -1 : 1;
3521           supportNew[s] = cStartNew + (cMax - cStart)*8 + (support[s] - cMax)*4 + (GetTriEdgeInverse_Static(orntCell[0], c-2) + (o*of < 0 ? 1-r : r))%3;
3522         }
3523         ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3524 #if 1
3525         if ((newp < fMaxNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid face [%d, %d)", newp, fMaxNew, fEndNew);
3526         for (p = 0; p < size; ++p) {
3527           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);
3528         }
3529 #endif
3530       }
3531     }
3532     /* Hybrid cell faces have 4 edges and 2 cells */
3533     for (c = cMax; c < cEnd; ++c) {
3534       PetscInt        newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (c - cMax)*3;
3535       const PetscInt *cone, *ornt;
3536       PetscInt        coneNew[4], orntNew[4];
3537       PetscInt        supportNew[2];
3538 
3539       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
3540       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
3541       for (r = 0; r < 3; ++r) {
3542         coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*3 + (r+2)%3;
3543         orntNew[0] = 0;
3544         coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*3 + (r+2)%3;
3545         orntNew[1] = 0;
3546         coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (eEnd - eMax) + (cone[2+(r+2)%3] - fMax);
3547         orntNew[2] = 0;
3548         coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (eEnd - eMax) + (cone[2+r]       - fMax);
3549         orntNew[3] = 0;
3550         ierr = DMPlexSetCone(rdm, newp+r, coneNew);CHKERRQ(ierr);
3551         ierr = DMPlexSetConeOrientation(rdm, newp+r, orntNew);CHKERRQ(ierr);
3552 #if 1
3553         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);
3554         for (p = 0; p < 2; ++p) {
3555           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);
3556         }
3557         for (p = 2; p < 4; ++p) {
3558           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);
3559         }
3560 #endif
3561         supportNew[0] = cStartNew + (cMax - cStart)*8 + (c - cMax)*4 + GetTriSubface_Static(ornt[0], r);
3562         supportNew[1] = cStartNew + (cMax - cStart)*8 + (c - cMax)*4 + 3;
3563         ierr          = DMPlexSetSupport(rdm, newp+r, supportNew);CHKERRQ(ierr);
3564 #if 1
3565         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);
3566         for (p = 0; p < 2; ++p) {
3567           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);
3568         }
3569 #endif
3570       }
3571     }
3572     /* Interior split edges have 2 vertices and the same faces as the parent */
3573     for (e = eStart; e < eMax; ++e) {
3574       const PetscInt newv = vStartNew + (vEnd - vStart) + (e - eStart);
3575 
3576       for (r = 0; r < 2; ++r) {
3577         const PetscInt  newp = eStartNew + (e - eStart)*2 + r;
3578         const PetscInt *cone, *ornt, *support;
3579         PetscInt        coneNew[2], coneSize, c, supportSize, s;
3580 
3581         ierr             = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
3582         coneNew[0]       = vStartNew + (cone[0] - vStart);
3583         coneNew[1]       = vStartNew + (cone[1] - vStart);
3584         coneNew[(r+1)%2] = newv;
3585         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3586 #if 1
3587         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
3588         for (p = 0; p < 2; ++p) {
3589           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);
3590         }
3591 #endif
3592         ierr = DMPlexGetSupportSize(dm, e, &supportSize);CHKERRQ(ierr);
3593         ierr = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
3594         for (s = 0; s < supportSize; ++s) {
3595           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
3596           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
3597           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
3598           for (c = 0; c < coneSize; ++c) if (cone[c] == e) break;
3599           if (support[s] < fMax) {
3600             supportRef[s] = fStartNew + (support[s] - fStart)*4 + (c + (ornt[c] < 0 ? 1-r : r))%3;
3601           } else {
3602             supportRef[s] = fStartNew + (fMax       - fStart)*4 + (cMax - cStart)*8 + (support[s] - fMax)*2 + (ornt[c] < 0 ? 1-r : r);
3603           }
3604         }
3605         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
3606 #if 1
3607         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
3608         for (p = 0; p < supportSize; ++p) {
3609           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);
3610         }
3611 #endif
3612       }
3613     }
3614     /* Interior face edges have 2 vertices and 2+cells*(1/2) faces */
3615     for (f = fStart; f < fMax; ++f) {
3616       const PetscInt *cone, *ornt, *support;
3617       PetscInt        coneSize, supportSize, s;
3618 
3619       ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
3620       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
3621       for (r = 0; r < 3; ++r) {
3622         const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (f - fStart)*3 + r;
3623         PetscInt        coneNew[2], intFaces = 0, er, eint[4] = {1, 0, 2, 0};
3624         PetscInt        fint[24] = { 1,  7, -1, -1,  0,  5,
3625                                     -1, -1,  1,  6,  0,  4,
3626                                      2,  5,  3,  4, -1, -1,
3627                                     -1, -1,  3,  6,  2,  7};
3628 
3629         ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
3630         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[(r+0)%3] - eStart);
3631         coneNew[1] = vStartNew + (vEnd - vStart) + (cone[(r+1)%3] - eStart);
3632         ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3633 #if 1
3634         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
3635         for (p = 0; p < 2; ++p) {
3636           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);
3637         }
3638 #endif
3639         supportRef[0] = fStartNew + (f - fStart)*4 + (r+1)%3;
3640         supportRef[1] = fStartNew + (f - fStart)*4 + 3;
3641         for (s = 0; s < supportSize; ++s) {
3642           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
3643           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
3644           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
3645           for (c = 0; c < coneSize; ++c) {if (cone[c] == f) break;}
3646           if (support[s] < cMax) {
3647             /* Here we want to determine whether edge newp contains a vertex which is part of the cross-tet edge */
3648             er = GetTetSomethingInverse_Static(ornt[c], r);
3649             if (er == eint[c]) {
3650               supportRef[2+intFaces++] = fStartNew + (fMax - fStart)*4 + (support[s] - cStart)*8 + (c + 2)%4;
3651             } else {
3652               supportRef[2+intFaces++] = fStartNew + (fMax - fStart)*4 + (support[s] - cStart)*8 + fint[(c*3 + er)*2 + 0];
3653               supportRef[2+intFaces++] = fStartNew + (fMax - fStart)*4 + (support[s] - cStart)*8 + fint[(c*3 + er)*2 + 1];
3654             }
3655           } else {
3656             supportRef[2+intFaces++] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (support[s] - cMax)*3 + (r + 1)%3;
3657           }
3658         }
3659         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
3660 #if 1
3661         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
3662         for (p = 0; p < intFaces; ++p) {
3663           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);
3664         }
3665 #endif
3666       }
3667     }
3668     /* Interior cell edges have 2 vertices and 4 faces */
3669     for (c = cStart; c < cMax; ++c) {
3670       const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart);
3671       const PetscInt *cone, *ornt, *fcone;
3672       PetscInt        coneNew[2], supportNew[4], find;
3673 
3674       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
3675       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
3676       ierr = DMPlexGetCone(dm, cone[0], &fcone);CHKERRQ(ierr);
3677       find = GetTriEdge_Static(ornt[0], 0);
3678       coneNew[0] = vStartNew + (vEnd - vStart) + (fcone[find] - eStart);
3679       ierr = DMPlexGetCone(dm, cone[2], &fcone);CHKERRQ(ierr);
3680       find = GetTriEdge_Static(ornt[2], 1);
3681       coneNew[1] = vStartNew + (vEnd - vStart) + (fcone[find] - eStart);
3682       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3683 #if 1
3684       if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
3685       for (p = 0; p < 2; ++p) {
3686         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);
3687       }
3688 #endif
3689       supportNew[0] = fStartNew + (fMax - fStart)*4 + (c - cStart)*8 + 4;
3690       supportNew[1] = fStartNew + (fMax - fStart)*4 + (c - cStart)*8 + 5;
3691       supportNew[2] = fStartNew + (fMax - fStart)*4 + (c - cStart)*8 + 6;
3692       supportNew[3] = fStartNew + (fMax - fStart)*4 + (c - cStart)*8 + 7;
3693       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3694 #if 1
3695       if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
3696       for (p = 0; p < 4; ++p) {
3697         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);
3698       }
3699 #endif
3700     }
3701     /* Hybrid edges have two vertices and the same faces */
3702     for (e = eMax; e < eEnd; ++e) {
3703       const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (e - eMax);
3704       const PetscInt *cone, *support, *fcone;
3705       PetscInt        coneNew[2], size, fsize, s;
3706 
3707       ierr = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
3708       ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
3709       ierr = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
3710       coneNew[0] = vStartNew + (cone[0] - vStart);
3711       coneNew[1] = vStartNew + (cone[1] - vStart);
3712       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3713 #if 1
3714       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid edge [%d, %d)", newp, eMaxNew, eEndNew);
3715       for (p = 0; p < 2; ++p) {
3716         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);
3717       }
3718 #endif
3719       for (s = 0; s < size; ++s) {
3720         ierr = DMPlexGetConeSize(dm, support[s], &fsize);CHKERRQ(ierr);
3721         ierr = DMPlexGetCone(dm, support[s], &fcone);CHKERRQ(ierr);
3722         for (c = 0; c < fsize; ++c) if (fcone[c] == e) break;
3723         if ((c < 2) || (c > 3)) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Edge %d not found in cone of face %d", e, support[s]);
3724         supportRef[s] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (support[s] - fMax)*2 + c-2;
3725       }
3726       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
3727 #if 1
3728       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid edge [%d, %d)", newp, eMaxNew, eEndNew);
3729       for (p = 0; p < size; ++p) {
3730         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);
3731       }
3732 #endif
3733     }
3734     /* Hybrid face edges have 2 vertices and 2+2*cells faces */
3735     for (f = fMax; f < fEnd; ++f) {
3736       const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (eEnd - eMax) + (f - fMax);
3737       const PetscInt *cone, *support, *ccone, *cornt;
3738       PetscInt        coneNew[2], size, csize, s;
3739 
3740       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
3741       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
3742       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
3743       coneNew[0] = vStartNew + (vEnd - vStart) + (cone[0] - eStart);
3744       coneNew[1] = vStartNew + (vEnd - vStart) + (cone[1] - eStart);
3745       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3746 #if 1
3747       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid edge [%d, %d)", newp, eMaxNew, eEndNew);
3748       for (p = 0; p < 2; ++p) {
3749         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);
3750       }
3751 #endif
3752       supportRef[0] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (f - fMax)*2 + 0;
3753       supportRef[1] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (f - fMax)*2 + 1;
3754       for (s = 0; s < size; ++s) {
3755         ierr = DMPlexGetConeSize(dm, support[s], &csize);CHKERRQ(ierr);
3756         ierr = DMPlexGetCone(dm, support[s], &ccone);CHKERRQ(ierr);
3757         ierr = DMPlexGetConeOrientation(dm, support[s], &cornt);CHKERRQ(ierr);
3758         for (c = 0; c < csize; ++c) if (ccone[c] == f) break;
3759         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]);
3760         supportRef[2+s*2+0] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (support[s] - cMax)*3 + c-2;
3761         supportRef[2+s*2+1] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (support[s] - cMax)*3 + (c-1)%3;
3762       }
3763       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
3764 #if 1
3765       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid edge [%d, %d)", newp, eMaxNew, eEndNew);
3766       for (p = 0; p < 2+size*2; ++p) {
3767         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);
3768       }
3769 #endif
3770     }
3771     /* Interior vertices have identical supports */
3772     for (v = vStart; v < vEnd; ++v) {
3773       const PetscInt  newp = vStartNew + (v - vStart);
3774       const PetscInt *support, *cone;
3775       PetscInt        size, s;
3776 
3777       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
3778       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
3779       for (s = 0; s < size; ++s) {
3780         PetscInt r = 0;
3781 
3782         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
3783         if (cone[1] == v) r = 1;
3784         if (support[s] < eMax) supportRef[s] = eStartNew + (support[s] - eStart)*2 + r;
3785         else                   supportRef[s] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (support[s] - eMax);
3786       }
3787       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
3788 #if 1
3789       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
3790       for (p = 0; p < size; ++p) {
3791         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);
3792       }
3793 #endif
3794     }
3795     /* Interior edge vertices have 2 + interior face*2 + hybrid face + cells*0/1 supports */
3796     for (e = eStart; e < eMax; ++e) {
3797       const PetscInt  newp = vStartNew + (vEnd - vStart) + (e - eStart);
3798       const PetscInt *cone, *support;
3799       PetscInt       *star = NULL, starSize, faceSize = 0, cellSize = 0, coneSize, size, s;
3800 
3801       ierr          = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
3802       ierr          = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
3803       supportRef[0] = eStartNew + (e - eStart)*2 + 0;
3804       supportRef[1] = eStartNew + (e - eStart)*2 + 1;
3805       for (s = 0; s < size; ++s) {
3806         PetscInt r = 0;
3807 
3808         if (support[s] < fMax) {
3809           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
3810           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
3811           for (r = 0; r < coneSize; ++r) {if (cone[r] == e) break;}
3812           supportRef[2+faceSize+0] = eStartNew + (eMax - eStart)*2 + (support[s] - fStart)*3 + (r+0)%3;
3813           supportRef[2+faceSize+1] = eStartNew + (eMax - eStart)*2 + (support[s] - fStart)*3 + (r+2)%3;
3814           faceSize += 2;
3815         } else {
3816           supportRef[2+faceSize+0] = eStartNew + (eMax - eStart)*2 + (fMax       - fStart)*3 + (cMax - cStart) + (eEnd - eMax) + (support[s] - fMax);
3817           ++faceSize;
3818         }
3819       }
3820       ierr = DMPlexGetTransitiveClosure(dm, e, PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
3821       for (s = 0; s < starSize*2; s += 2) {
3822         const PetscInt *cone, *ornt;
3823         PetscInt        e01, e23;
3824 
3825         if ((star[s] >= cStart) && (star[s] < cMax)) {
3826           /* Check edge 0-1 */
3827           ierr = DMPlexGetCone(dm, star[s], &cone);CHKERRQ(ierr);
3828           ierr = DMPlexGetConeOrientation(dm, star[s], &ornt);CHKERRQ(ierr);
3829           ierr = DMPlexGetCone(dm, cone[0], &cone);CHKERRQ(ierr);
3830           e01  = cone[GetTriEdge_Static(ornt[0], 0)];
3831           /* Check edge 2-3 */
3832           ierr = DMPlexGetCone(dm, star[s], &cone);CHKERRQ(ierr);
3833           ierr = DMPlexGetConeOrientation(dm, star[s], &ornt);CHKERRQ(ierr);
3834           ierr = DMPlexGetCone(dm, cone[2], &cone);CHKERRQ(ierr);
3835           e23  = cone[GetTriEdge_Static(ornt[2], 1)];
3836           if ((e01 == e) || (e23 == e)) {supportRef[2+faceSize+cellSize++] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (star[s] - cStart);}
3837         }
3838       }
3839       ierr = DMPlexRestoreTransitiveClosure(dm, e, PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
3840       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
3841 #if 1
3842       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
3843       for (p = 0; p < 2+faceSize+cellSize; ++p) {
3844         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);
3845       }
3846 #endif
3847     }
3848     ierr = PetscFree(supportRef);CHKERRQ(ierr);
3849     ierr = DMPlexRestoreFaces_Internal(dm, 3, cStart, NULL, NULL, &faces);CHKERRQ(ierr);
3850     break;
3851   case REFINER_HEX_3D:
3852     /*
3853      Bottom (viewed from top)    Top
3854      1---------2---------2       7---------2---------6
3855      |         |         |       |         |         |
3856      |    B    2    C    |       |    H    2    G    |
3857      |         |         |       |         |         |
3858      3----3----0----1----1       3----3----0----1----1
3859      |         |         |       |         |         |
3860      |    A    0    D    |       |    E    0    F    |
3861      |         |         |       |         |         |
3862      0---------0---------3       4---------0---------5
3863      */
3864     /* All cells have 6 faces: Bottom, Top, Front, Back, Right, Left */
3865     for (c = cStart; c < cEnd; ++c) {
3866       const PetscInt  newp = (c - cStart)*8;
3867       const PetscInt *cone, *ornt;
3868       PetscInt        coneNew[6], orntNew[6];
3869 
3870       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
3871       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
3872       /* A hex */
3873       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], 0);
3874       orntNew[0] = ornt[0];
3875       coneNew[1] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  8; /* AE */
3876       orntNew[1] = 0;
3877       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetQuadSubface_Static(ornt[2], 0);
3878       orntNew[2] = ornt[2];
3879       coneNew[3] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  3; /* AB */
3880       orntNew[3] = 0;
3881       coneNew[4] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  0; /* AD */
3882       orntNew[4] = 0;
3883       coneNew[5] = fStartNew + (cone[5] - fStart)*4 + GetQuadSubface_Static(ornt[5], 0);
3884       orntNew[5] = ornt[5];
3885       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
3886       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
3887 #if 1
3888       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);
3889       for (p = 0; p < 6; ++p) {
3890         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);
3891       }
3892 #endif
3893       /* B hex */
3894       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], 1);
3895       orntNew[0] = ornt[0];
3896       coneNew[1] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 + 11; /* BH */
3897       orntNew[1] = 0;
3898       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  3; /* AB */
3899       orntNew[2] = -1;
3900       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetQuadSubface_Static(ornt[3], 1);
3901       orntNew[3] = ornt[3];
3902       coneNew[4] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  2; /* BC */
3903       orntNew[4] = 0;
3904       coneNew[5] = fStartNew + (cone[5] - fStart)*4 + GetQuadSubface_Static(ornt[5], 3);
3905       orntNew[5] = ornt[5];
3906       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
3907       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
3908 #if 1
3909       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);
3910       for (p = 0; p < 6; ++p) {
3911         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);
3912       }
3913 #endif
3914       /* C hex */
3915       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], 2);
3916       orntNew[0] = ornt[0];
3917       coneNew[1] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 + 10; /* CG */
3918       orntNew[1] = 0;
3919       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  1; /* CD */
3920       orntNew[2] = -1;
3921       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetQuadSubface_Static(ornt[3], 0);
3922       orntNew[3] = ornt[3];
3923       coneNew[4] = fStartNew + (cone[4] - fStart)*4 + GetQuadSubface_Static(ornt[4], 1);
3924       orntNew[4] = ornt[4];
3925       coneNew[5] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  2; /* BC */
3926       orntNew[5] = -4;
3927       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
3928       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
3929 #if 1
3930       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);
3931       for (p = 0; p < 6; ++p) {
3932         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);
3933       }
3934 #endif
3935       /* D hex */
3936       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], 3);
3937       orntNew[0] = ornt[0];
3938       coneNew[1] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  9; /* DF */
3939       orntNew[1] = 0;
3940       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetQuadSubface_Static(ornt[2], 1);
3941       orntNew[2] = ornt[2];
3942       coneNew[3] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  1; /* CD */
3943       orntNew[3] = 0;
3944       coneNew[4] = fStartNew + (cone[4] - fStart)*4 + GetQuadSubface_Static(ornt[4], 0);
3945       orntNew[4] = ornt[4];
3946       coneNew[5] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  0; /* AD */
3947       orntNew[5] = -4;
3948       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
3949       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
3950 #if 1
3951       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);
3952       for (p = 0; p < 6; ++p) {
3953         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);
3954       }
3955 #endif
3956       /* E hex */
3957       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  8; /* AE */
3958       orntNew[0] = -4;
3959       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], 0);
3960       orntNew[1] = ornt[1];
3961       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetQuadSubface_Static(ornt[2], 3);
3962       orntNew[2] = ornt[2];
3963       coneNew[3] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  7; /* EH */
3964       orntNew[3] = 0;
3965       coneNew[4] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  4; /* EF */
3966       orntNew[4] = -1;
3967       coneNew[5] = fStartNew + (cone[5] - fStart)*4 + GetQuadSubface_Static(ornt[5], 1);
3968       orntNew[5] = ornt[5];
3969       ierr       = DMPlexSetCone(rdm, newp+4, coneNew);CHKERRQ(ierr);
3970       ierr       = DMPlexSetConeOrientation(rdm, newp+4, orntNew);CHKERRQ(ierr);
3971 #if 1
3972       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);
3973       for (p = 0; p < 6; ++p) {
3974         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);
3975       }
3976 #endif
3977       /* F hex */
3978       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  9; /* DF */
3979       orntNew[0] = -4;
3980       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], 1);
3981       orntNew[1] = ornt[1];
3982       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetQuadSubface_Static(ornt[2], 2);
3983       orntNew[2] = ornt[2];
3984       coneNew[3] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  5; /* FG */
3985       orntNew[3] = -1;
3986       coneNew[4] = fStartNew + (cone[4] - fStart)*4 + GetQuadSubface_Static(ornt[4], 3);
3987       orntNew[4] = ornt[4];
3988       coneNew[5] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  4; /* EF */
3989       orntNew[5] = 1;
3990       ierr       = DMPlexSetCone(rdm, newp+5, coneNew);CHKERRQ(ierr);
3991       ierr       = DMPlexSetConeOrientation(rdm, newp+5, orntNew);CHKERRQ(ierr);
3992 #if 1
3993       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);
3994       for (p = 0; p < 6; ++p) {
3995         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);
3996       }
3997 #endif
3998       /* G hex */
3999       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 + 10; /* CG */
4000       orntNew[0] = -4;
4001       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], 2);
4002       orntNew[1] = ornt[1];
4003       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  5; /* FG */
4004       orntNew[2] = 0;
4005       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetQuadSubface_Static(ornt[3], 3);
4006       orntNew[3] = ornt[3];
4007       coneNew[4] = fStartNew + (cone[4] - fStart)*4 + GetQuadSubface_Static(ornt[4], 2);
4008       orntNew[4] = ornt[4];
4009       coneNew[5] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  6; /* GH */
4010       orntNew[5] = -3;
4011       ierr       = DMPlexSetCone(rdm, newp+6, coneNew);CHKERRQ(ierr);
4012       ierr       = DMPlexSetConeOrientation(rdm, newp+6, orntNew);CHKERRQ(ierr);
4013 #if 1
4014       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);
4015       for (p = 0; p < 6; ++p) {
4016         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);
4017       }
4018 #endif
4019       /* H hex */
4020       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 + 11; /* BH */
4021       orntNew[0] = -4;
4022       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], 3);
4023       orntNew[1] = ornt[1];
4024       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  7; /* EH */
4025       orntNew[2] = -1;
4026       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetQuadSubface_Static(ornt[3], 2);
4027       orntNew[3] = ornt[3];
4028       coneNew[4] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  6; /* GH */
4029       orntNew[4] = 3;
4030       coneNew[5] = fStartNew + (cone[5] - fStart)*4 + GetQuadSubface_Static(ornt[5], 2);
4031       orntNew[5] = ornt[5];
4032       ierr       = DMPlexSetCone(rdm, newp+7, coneNew);CHKERRQ(ierr);
4033       ierr       = DMPlexSetConeOrientation(rdm, newp+7, orntNew);CHKERRQ(ierr);
4034 #if 1
4035       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);
4036       for (p = 0; p < 6; ++p) {
4037         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);
4038       }
4039 #endif
4040     }
4041     /* Split faces have 4 edges and the same cells as the parent */
4042     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
4043     ierr = PetscMalloc1(4 + maxSupportSize*2, &supportRef);CHKERRQ(ierr);
4044     for (f = fStart; f < fEnd; ++f) {
4045       for (r = 0; r < 4; ++r) {
4046         /* TODO: This can come from GetFaces_Internal() */
4047         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};
4048         const PetscInt  newp = fStartNew + (f - fStart)*4 + r;
4049         const PetscInt *cone, *ornt, *support;
4050         PetscInt        coneNew[4], orntNew[4], coneSize, c, supportSize, s;
4051 
4052         ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
4053         ierr = DMPlexGetConeOrientation(dm, f, &ornt);CHKERRQ(ierr);
4054         coneNew[(r+3)%4] = eStartNew + (cone[(r+3)%4] - eStart)*2 + (ornt[(r+3)%4] < 0 ? 0 : 1);
4055         orntNew[(r+3)%4] = ornt[(r+3)%4];
4056         coneNew[(r+0)%4] = eStartNew + (cone[r]       - eStart)*2 + (ornt[r] < 0 ? 1 : 0);
4057         orntNew[(r+0)%4] = ornt[r];
4058         coneNew[(r+1)%4] = eStartNew + (eEnd - eStart)*2 + (f - fStart)*4 + r;
4059         orntNew[(r+1)%4] = 0;
4060         coneNew[(r+2)%4] = eStartNew + (eEnd - eStart)*2 + (f - fStart)*4 + (r+3)%4;
4061         orntNew[(r+2)%4] = -2;
4062         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4063         ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4064 #if 1
4065         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4066         for (p = 0; p < 4; ++p) {
4067           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);
4068         }
4069 #endif
4070         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
4071         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
4072         for (s = 0; s < supportSize; ++s) {
4073           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
4074           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
4075           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
4076           for (c = 0; c < coneSize; ++c) {
4077             if (cone[c] == f) break;
4078           }
4079           supportRef[s] = cStartNew + (support[s] - cStart)*8 + newCells[c*4+GetQuadSubfaceInverse_Static(ornt[c], r)];
4080         }
4081         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
4082 #if 1
4083         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4084         for (p = 0; p < supportSize; ++p) {
4085           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);
4086         }
4087 #endif
4088       }
4089     }
4090     /* Interior faces have 4 edges and 2 cells */
4091     for (c = cStart; c < cEnd; ++c) {
4092       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};
4093       const PetscInt *cone, *ornt;
4094       PetscInt        newp, coneNew[4], orntNew[4], supportNew[2];
4095 
4096       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
4097       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
4098       /* A-D face */
4099       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 0;
4100       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*4 + GetQuadEdge_Static(ornt[0], 3);
4101       orntNew[0] = 0;
4102       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 0;
4103       orntNew[1] = 0;
4104       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 2;
4105       orntNew[2] = -2;
4106       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*4 + GetQuadEdge_Static(ornt[2], 0);
4107       orntNew[3] = -2;
4108       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4109       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4110 #if 1
4111       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4112       for (p = 0; p < 4; ++p) {
4113         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);
4114       }
4115 #endif
4116       /* C-D face */
4117       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 1;
4118       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*4 + GetQuadEdge_Static(ornt[0], 2);
4119       orntNew[0] = 0;
4120       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 0;
4121       orntNew[1] = 0;
4122       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 4;
4123       orntNew[2] = -2;
4124       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (cone[4] - fStart)*4 + GetQuadEdge_Static(ornt[4], 0);
4125       orntNew[3] = -2;
4126       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4127       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4128 #if 1
4129       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4130       for (p = 0; p < 4; ++p) {
4131         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);
4132       }
4133 #endif
4134       /* B-C face */
4135       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 2;
4136       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*4 + GetQuadEdge_Static(ornt[0], 1);
4137       orntNew[0] = -2;
4138       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*4 + GetQuadEdge_Static(ornt[3], 0);
4139       orntNew[1] = 0;
4140       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 3;
4141       orntNew[2] = 0;
4142       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 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       /* A-B face */
4153       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 3;
4154       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*4 + GetQuadEdge_Static(ornt[0], 0);
4155       orntNew[0] = -2;
4156       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[5] - fStart)*4 + GetQuadEdge_Static(ornt[5], 3);
4157       orntNew[1] = 0;
4158       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 5;
4159       orntNew[2] = 0;
4160       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 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       /* E-F face */
4171       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 4;
4172       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 2;
4173       orntNew[0] = -2;
4174       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*4 + GetQuadEdge_Static(ornt[2], 2);
4175       orntNew[1] = -2;
4176       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*4 + GetQuadEdge_Static(ornt[1], 0);
4177       orntNew[2] = 0;
4178       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 1;
4179       orntNew[3] = 0;
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       /* F-G face */
4189       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 5;
4190       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 4;
4191       orntNew[0] = -2;
4192       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[4] - fStart)*4 + GetQuadEdge_Static(ornt[4], 2);
4193       orntNew[1] = -2;
4194       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*4 + GetQuadEdge_Static(ornt[1], 1);
4195       orntNew[2] = 0;
4196       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 1;
4197       orntNew[3] = 0;
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       /* G-H face */
4207       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 6;
4208       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*4 + GetQuadEdge_Static(ornt[3], 2);
4209       orntNew[0] = -2;
4210       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*4 + GetQuadEdge_Static(ornt[1], 2);
4211       orntNew[1] = 0;
4212       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 1;
4213       orntNew[2] = 0;
4214       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 3;
4215       orntNew[3] = -2;
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       /* E-H face */
4225       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 7;
4226       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 5;
4227       orntNew[0] = -2;
4228       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[5] - fStart)*4 + GetQuadEdge_Static(ornt[5], 1);
4229       orntNew[1] = -2;
4230       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*4 + GetQuadEdge_Static(ornt[1], 3);
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       /* A-E face */
4243       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 8;
4244       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*4 + GetQuadEdge_Static(ornt[2], 3);
4245       orntNew[0] = 0;
4246       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 2;
4247       orntNew[1] = 0;
4248       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 5;
4249       orntNew[2] = -2;
4250       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (cone[5] - fStart)*4 + GetQuadEdge_Static(ornt[5], 0);
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       /* D-F face */
4261       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 9;
4262       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*4 + GetQuadEdge_Static(ornt[2], 1);
4263       orntNew[0] = -2;
4264       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[4] - fStart)*4 + GetQuadEdge_Static(ornt[4], 3);
4265       orntNew[1] = 0;
4266       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 4;
4267       orntNew[2] = 0;
4268       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 2;
4269       orntNew[3] = -2;
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       /* C-G face */
4279       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 10;
4280       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 4;
4281       orntNew[0] = -2;
4282       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[4] - fStart)*4 + GetQuadEdge_Static(ornt[4], 1);
4283       orntNew[1] = -2;
4284       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*4 + GetQuadEdge_Static(ornt[3], 3);
4285       orntNew[2] = 0;
4286       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 3;
4287       orntNew[3] = 0;
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       /* B-H face */
4297       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 11;
4298       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 5;
4299       orntNew[0] = 0;
4300       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 3;
4301       orntNew[1] = -2;
4302       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*4 + GetQuadEdge_Static(ornt[3], 1);
4303       orntNew[2] = -2;
4304       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (cone[5] - fStart)*4 + GetQuadEdge_Static(ornt[5], 2);
4305       orntNew[3] = 0;
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       for (r = 0; r < 12; ++r) {
4315         newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + r;
4316         supportNew[0] = cStartNew + (c - cStart)*8 + newCells[r*2+0];
4317         supportNew[1] = cStartNew + (c - cStart)*8 + newCells[r*2+1];
4318         ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
4319 #if 1
4320         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4321         for (p = 0; p < 2; ++p) {
4322           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);
4323         }
4324 #endif
4325       }
4326     }
4327     /* Split edges have 2 vertices and the same faces as the parent */
4328     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
4329     for (e = eStart; e < eEnd; ++e) {
4330       const PetscInt newv = vStartNew + (vEnd - vStart) + (e - eStart);
4331 
4332       for (r = 0; r < 2; ++r) {
4333         const PetscInt  newp = eStartNew + (e - eStart)*2 + r;
4334         const PetscInt *cone, *ornt, *support;
4335         PetscInt        coneNew[2], coneSize, c, supportSize, s;
4336 
4337         ierr             = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
4338         coneNew[0]       = vStartNew + (cone[0] - vStart);
4339         coneNew[1]       = vStartNew + (cone[1] - vStart);
4340         coneNew[(r+1)%2] = newv;
4341         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4342 #if 1
4343         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
4344         for (p = 0; p < 2; ++p) {
4345           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);
4346         }
4347 #endif
4348         ierr = DMPlexGetSupportSize(dm, e, &supportSize);CHKERRQ(ierr);
4349         ierr = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
4350         for (s = 0; s < supportSize; ++s) {
4351           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
4352           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
4353           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
4354           for (c = 0; c < coneSize; ++c) {
4355             if (cone[c] == e) break;
4356           }
4357           supportRef[s] = fStartNew + (support[s] - fStart)*4 + (ornt[c] < 0 ? (c+1-r)%4 : (c+r)%4);
4358         }
4359         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
4360 #if 1
4361         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
4362         for (p = 0; p < supportSize; ++p) {
4363           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);
4364         }
4365 #endif
4366       }
4367     }
4368     /* Face edges have 2 vertices and 2+cells faces */
4369     for (f = fStart; f < fEnd; ++f) {
4370       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};
4371       const PetscInt  newv = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (f - fStart);
4372       const PetscInt *cone, *coneCell, *orntCell, *support;
4373       PetscInt        coneNew[2], coneSize, c, supportSize, s;
4374 
4375       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
4376       for (r = 0; r < 4; ++r) {
4377         const PetscInt newp = eStartNew + (eEnd - eStart)*2 + (f - fStart)*4 + r;
4378 
4379         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r] - eStart);
4380         coneNew[1] = newv;
4381         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4382 #if 1
4383         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
4384         for (p = 0; p < 2; ++p) {
4385           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);
4386         }
4387 #endif
4388         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
4389         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
4390         supportRef[0] = fStartNew + (f - fStart)*4 + r;
4391         supportRef[1] = fStartNew + (f - fStart)*4 + (r+1)%4;
4392         for (s = 0; s < supportSize; ++s) {
4393           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
4394           ierr = DMPlexGetCone(dm, support[s], &coneCell);CHKERRQ(ierr);
4395           ierr = DMPlexGetConeOrientation(dm, support[s], &orntCell);CHKERRQ(ierr);
4396           for (c = 0; c < coneSize; ++c) if (coneCell[c] == f) break;
4397           supportRef[2+s] = fStartNew + (fEnd - fStart)*4 + (support[s] - cStart)*12 + newFaces[c*4 + GetQuadEdgeInverse_Static(orntCell[c], r)];
4398         }
4399         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
4400 #if 1
4401         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
4402         for (p = 0; p < 2+supportSize; ++p) {
4403           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);
4404         }
4405 #endif
4406       }
4407     }
4408     /* Cell edges have 2 vertices and 4 faces */
4409     for (c = cStart; c < cEnd; ++c) {
4410       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};
4411       const PetscInt  newv = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (fEnd - fStart) + (c - cStart);
4412       const PetscInt *cone;
4413       PetscInt        coneNew[2], supportNew[4];
4414 
4415       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
4416       for (r = 0; r < 6; ++r) {
4417         const PetscInt newp = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*4 + (c - cStart)*6 + r;
4418 
4419         coneNew[0] = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (cone[r] - fStart);
4420         coneNew[1] = newv;
4421         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4422 #if 1
4423         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
4424         for (p = 0; p < 2; ++p) {
4425           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);
4426         }
4427 #endif
4428         for (f = 0; f < 4; ++f) supportNew[f] = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + newFaces[r*4+f];
4429         ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
4430 #if 1
4431         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
4432         for (p = 0; p < 4; ++p) {
4433           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);
4434         }
4435 #endif
4436       }
4437     }
4438     /* Old vertices have identical supports */
4439     for (v = vStart; v < vEnd; ++v) {
4440       const PetscInt  newp = vStartNew + (v - vStart);
4441       const PetscInt *support, *cone;
4442       PetscInt        size, s;
4443 
4444       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
4445       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
4446       for (s = 0; s < size; ++s) {
4447         PetscInt r = 0;
4448 
4449         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
4450         if (cone[1] == v) r = 1;
4451         supportRef[s] = eStartNew + (support[s] - eStart)*2 + r;
4452       }
4453       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
4454 #if 1
4455       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
4456       for (p = 0; p < size; ++p) {
4457         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);
4458       }
4459 #endif
4460     }
4461     /* Edge vertices have 2 + faces supports */
4462     for (e = eStart; e < eEnd; ++e) {
4463       const PetscInt  newp = vStartNew + (vEnd - vStart) + (e - eStart);
4464       const PetscInt *cone, *support;
4465       PetscInt        size, s;
4466 
4467       ierr          = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
4468       ierr          = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
4469       supportRef[0] = eStartNew + (e - eStart)*2 + 0;
4470       supportRef[1] = eStartNew + (e - eStart)*2 + 1;
4471       for (s = 0; s < size; ++s) {
4472         PetscInt r;
4473 
4474         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
4475         for (r = 0; r < 4; ++r) if (cone[r] == e) break;
4476         supportRef[2+s] = eStartNew + (eEnd - eStart)*2 + (support[s] - fStart)*4 + r;
4477       }
4478       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
4479 #if 1
4480       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
4481       for (p = 0; p < 2+size; ++p) {
4482         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);
4483       }
4484 #endif
4485     }
4486     /* Face vertices have 4 + cells supports */
4487     for (f = fStart; f < fEnd; ++f) {
4488       const PetscInt  newp = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (f - fStart);
4489       const PetscInt *cone, *support;
4490       PetscInt        size, s;
4491 
4492       ierr          = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
4493       ierr          = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
4494       for (r = 0; r < 4; ++r) supportRef[r] = eStartNew + (eEnd - eStart)*2 +  (f - fStart)*4 + r;
4495       for (s = 0; s < size; ++s) {
4496         PetscInt r;
4497 
4498         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
4499         for (r = 0; r < 6; ++r) if (cone[r] == f) break;
4500         supportRef[4+s] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*4 + (support[s] - cStart)*6 + r;
4501       }
4502       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
4503 #if 1
4504       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
4505       for (p = 0; p < 4+size; ++p) {
4506         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);
4507       }
4508 #endif
4509     }
4510     /* Cell vertices have 6 supports */
4511     for (c = cStart; c < cEnd; ++c) {
4512       const PetscInt newp = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (fEnd - fStart) + (c - cStart);
4513       PetscInt       supportNew[6];
4514 
4515       for (r = 0; r < 6; ++r) {
4516         supportNew[r] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*4 + (c - cStart)*6 + r;
4517       }
4518       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
4519     }
4520     ierr = PetscFree(supportRef);CHKERRQ(ierr);
4521     break;
4522   case REFINER_HYBRID_HEX_3D:
4523     ierr = DMPlexGetHybridBounds(rdm, &cMaxNew, &fMaxNew, &eMaxNew, NULL);CHKERRQ(ierr);
4524     /*
4525      Bottom (viewed from top)    Top
4526      1---------2---------2       7---------2---------6
4527      |         |         |       |         |         |
4528      |    B    2    C    |       |    H    2    G    |
4529      |         |         |       |         |         |
4530      3----3----0----1----1       3----3----0----1----1
4531      |         |         |       |         |         |
4532      |    A    0    D    |       |    E    0    F    |
4533      |         |         |       |         |         |
4534      0---------0---------3       4---------0---------5
4535      */
4536     /* Interior cells have 6 faces: Bottom, Top, Front, Back, Right, Left */
4537     for (c = cStart; c < cMax; ++c) {
4538       const PetscInt  newp = (c - cStart)*8;
4539       const PetscInt *cone, *ornt;
4540       PetscInt        coneNew[6], orntNew[6];
4541 
4542       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
4543       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
4544       /* A hex */
4545       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], 0);
4546       orntNew[0] = ornt[0];
4547       coneNew[1] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  8; /* AE */
4548       orntNew[1] = 0;
4549       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetQuadSubface_Static(ornt[2], 0);
4550       orntNew[2] = ornt[2];
4551       coneNew[3] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  3; /* AB */
4552       orntNew[3] = 0;
4553       coneNew[4] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  0; /* AD */
4554       orntNew[4] = 0;
4555       coneNew[5] = fStartNew + (cone[5] - fStart)*4 + GetQuadSubface_Static(ornt[5], 0);
4556       orntNew[5] = ornt[5];
4557       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
4558       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
4559 #if 1
4560       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);
4561       for (p = 0; p < 6; ++p) {
4562         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);
4563       }
4564 #endif
4565       /* B hex */
4566       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], 1);
4567       orntNew[0] = ornt[0];
4568       coneNew[1] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 + 11; /* BH */
4569       orntNew[1] = 0;
4570       coneNew[2] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  3; /* AB */
4571       orntNew[2] = -1;
4572       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetQuadSubface_Static(ornt[3], 1);
4573       orntNew[3] = ornt[3];
4574       coneNew[4] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  2; /* BC */
4575       orntNew[4] = 0;
4576       coneNew[5] = fStartNew + (cone[5] - fStart)*4 + GetQuadSubface_Static(ornt[5], 3);
4577       orntNew[5] = ornt[5];
4578       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
4579       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
4580 #if 1
4581       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);
4582       for (p = 0; p < 6; ++p) {
4583         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);
4584       }
4585 #endif
4586       /* C hex */
4587       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], 2);
4588       orntNew[0] = ornt[0];
4589       coneNew[1] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 + 10; /* CG */
4590       orntNew[1] = 0;
4591       coneNew[2] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  1; /* CD */
4592       orntNew[2] = -1;
4593       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetQuadSubface_Static(ornt[3], 0);
4594       orntNew[3] = ornt[3];
4595       coneNew[4] = fStartNew + (cone[4] - fStart)*4 + GetQuadSubface_Static(ornt[4], 1);
4596       orntNew[4] = ornt[4];
4597       coneNew[5] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  2; /* BC */
4598       orntNew[5] = -4;
4599       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
4600       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
4601 #if 1
4602       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);
4603       for (p = 0; p < 6; ++p) {
4604         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);
4605       }
4606 #endif
4607       /* D hex */
4608       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], 3);
4609       orntNew[0] = ornt[0];
4610       coneNew[1] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  9; /* DF */
4611       orntNew[1] = 0;
4612       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetQuadSubface_Static(ornt[2], 1);
4613       orntNew[2] = ornt[2];
4614       coneNew[3] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  1; /* CD */
4615       orntNew[3] = 0;
4616       coneNew[4] = fStartNew + (cone[4] - fStart)*4 + GetQuadSubface_Static(ornt[4], 0);
4617       orntNew[4] = ornt[4];
4618       coneNew[5] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  0; /* AD */
4619       orntNew[5] = -4;
4620       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
4621       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
4622 #if 1
4623       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);
4624       for (p = 0; p < 6; ++p) {
4625         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);
4626       }
4627 #endif
4628       /* E hex */
4629       coneNew[0] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  8; /* AE */
4630       orntNew[0] = -4;
4631       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], 0);
4632       orntNew[1] = ornt[1];
4633       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetQuadSubface_Static(ornt[2], 3);
4634       orntNew[2] = ornt[2];
4635       coneNew[3] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  7; /* EH */
4636       orntNew[3] = 0;
4637       coneNew[4] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  4; /* EF */
4638       orntNew[4] = -1;
4639       coneNew[5] = fStartNew + (cone[5] - fStart)*4 + GetQuadSubface_Static(ornt[5], 1);
4640       orntNew[5] = ornt[5];
4641       ierr       = DMPlexSetCone(rdm, newp+4, coneNew);CHKERRQ(ierr);
4642       ierr       = DMPlexSetConeOrientation(rdm, newp+4, orntNew);CHKERRQ(ierr);
4643 #if 1
4644       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);
4645       for (p = 0; p < 6; ++p) {
4646         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);
4647       }
4648 #endif
4649       /* F hex */
4650       coneNew[0] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  9; /* DF */
4651       orntNew[0] = -4;
4652       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], 1);
4653       orntNew[1] = ornt[1];
4654       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetQuadSubface_Static(ornt[2], 2);
4655       orntNew[2] = ornt[2];
4656       coneNew[3] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  5; /* FG */
4657       orntNew[3] = -1;
4658       coneNew[4] = fStartNew + (cone[4] - fStart)*4 + GetQuadSubface_Static(ornt[4], 3);
4659       orntNew[4] = ornt[4];
4660       coneNew[5] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  4; /* EF */
4661       orntNew[5] = 1;
4662       ierr       = DMPlexSetCone(rdm, newp+5, coneNew);CHKERRQ(ierr);
4663       ierr       = DMPlexSetConeOrientation(rdm, newp+5, orntNew);CHKERRQ(ierr);
4664 #if 1
4665       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);
4666       for (p = 0; p < 6; ++p) {
4667         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);
4668       }
4669 #endif
4670       /* G hex */
4671       coneNew[0] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 + 10; /* CG */
4672       orntNew[0] = -4;
4673       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], 2);
4674       orntNew[1] = ornt[1];
4675       coneNew[2] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  5; /* FG */
4676       orntNew[2] = 0;
4677       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetQuadSubface_Static(ornt[3], 3);
4678       orntNew[3] = ornt[3];
4679       coneNew[4] = fStartNew + (cone[4] - fStart)*4 + GetQuadSubface_Static(ornt[4], 2);
4680       orntNew[4] = ornt[4];
4681       coneNew[5] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  6; /* GH */
4682       orntNew[5] = -3;
4683       ierr       = DMPlexSetCone(rdm, newp+6, coneNew);CHKERRQ(ierr);
4684       ierr       = DMPlexSetConeOrientation(rdm, newp+6, orntNew);CHKERRQ(ierr);
4685 #if 1
4686       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);
4687       for (p = 0; p < 6; ++p) {
4688         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);
4689       }
4690 #endif
4691       /* H hex */
4692       coneNew[0] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 + 11; /* BH */
4693       orntNew[0] = -4;
4694       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], 3);
4695       orntNew[1] = ornt[1];
4696       coneNew[2] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  7; /* EH */
4697       orntNew[2] = -1;
4698       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetQuadSubface_Static(ornt[3], 2);
4699       orntNew[3] = ornt[3];
4700       coneNew[4] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  6; /* GH */
4701       orntNew[4] = 3;
4702       coneNew[5] = fStartNew + (cone[5] - fStart)*4 + GetQuadSubface_Static(ornt[5], 2);
4703       orntNew[5] = ornt[5];
4704       ierr       = DMPlexSetCone(rdm, newp+7, coneNew);CHKERRQ(ierr);
4705       ierr       = DMPlexSetConeOrientation(rdm, newp+7, orntNew);CHKERRQ(ierr);
4706 #if 1
4707       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);
4708       for (p = 0; p < 6; ++p) {
4709         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);
4710       }
4711 #endif
4712     }
4713     /* Hybrid cells have 6 faces: Front, Back, Sides */
4714     /*
4715      3---------2---------2
4716      |         |         |
4717      |    D    2    C    |
4718      |         |         |
4719      3----3----0----1----1
4720      |         |         |
4721      |    A    0    B    |
4722      |         |         |
4723      0---------0---------1
4724      */
4725     for (c = cMax; c < cEnd; ++c) {
4726       const PetscInt  newp = (cMax - cStart)*8 + (c - cMax)*4;
4727       const PetscInt *cone, *ornt, *fornt;
4728       PetscInt        coneNew[6], orntNew[6], o, of, i;
4729 
4730       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
4731       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
4732       ierr = DMPlexGetConeOrientation(dm, cone[0], &fornt);CHKERRQ(ierr);
4733       o = ornt[0] < 0 ? -1 : 1;
4734       for (r = 0; r < 4; ++r) {
4735         PetscInt subfA = GetQuadSubface_Static(ornt[0], r);
4736         PetscInt edgeA = GetQuadEdge_Static(ornt[0], r);
4737         PetscInt edgeB = GetQuadEdge_Static(ornt[0], (r+3)%4);
4738         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]);
4739         coneNew[0]         = fStartNew + (cone[0] - fStart)*4 + subfA;
4740         orntNew[0]         = ornt[0];
4741         coneNew[1]         = fStartNew + (cone[1] - fStart)*4 + subfA;
4742         orntNew[1]         = ornt[0];
4743         of = fornt[edgeA] < 0 ? -1 : 1;
4744         i  = GetQuadEdgeInverse_Static(ornt[0], r) + 2;
4745         coneNew[i] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (cone[2+edgeA] - fMax)*2 + (o*of < 0 ? 1 : 0);
4746         orntNew[i] = ornt[edgeA];
4747         i  = GetQuadEdgeInverse_Static(ornt[0], (r+1)%4) + 2;
4748         coneNew[i] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd          - fMax)*2 + (c - cMax)*4 + edgeA;
4749         orntNew[i] = 0;
4750         i  = GetQuadEdgeInverse_Static(ornt[0], (r+2)%4) + 2;
4751         coneNew[i] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd          - fMax)*2 + (c - cMax)*4 + edgeB;
4752         orntNew[i] = -2;
4753         of = fornt[edgeB] < 0 ? -1 : 1;
4754         i  = GetQuadEdgeInverse_Static(ornt[0], (r+3)%4) + 2;
4755         coneNew[i] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (cone[2+edgeB] - fMax)*2 + (o*of < 0 ? 0 : 1);
4756         orntNew[i] = ornt[edgeB];
4757         ierr       = DMPlexSetCone(rdm, newp+r, coneNew);CHKERRQ(ierr);
4758         ierr       = DMPlexSetConeOrientation(rdm, newp+r, orntNew);CHKERRQ(ierr);
4759 #if 1
4760         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);
4761         for (p = 0; p < 2; ++p) {
4762           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);
4763         }
4764         for (p = 2; p < 6; ++p) {
4765           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);
4766         }
4767 #endif
4768       }
4769     }
4770     /* Interior split faces have 4 edges and the same cells as the parent */
4771     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
4772     ierr = PetscMalloc1(4 + maxSupportSize*2, &supportRef);CHKERRQ(ierr);
4773     for (f = fStart; f < fMax; ++f) {
4774       for (r = 0; r < 4; ++r) {
4775         /* TODO: This can come from GetFaces_Internal() */
4776         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};
4777         const PetscInt  newp = fStartNew + (f - fStart)*4 + r;
4778         const PetscInt *cone, *ornt, *support;
4779         PetscInt        coneNew[4], orntNew[4], coneSize, c, supportSize, s;
4780 
4781         ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
4782         ierr = DMPlexGetConeOrientation(dm, f, &ornt);CHKERRQ(ierr);
4783         coneNew[(r+3)%4] = eStartNew + (cone[(r+3)%4] - eStart)*2 + (ornt[(r+3)%4] < 0 ? 0 : 1);
4784         orntNew[(r+3)%4] = ornt[(r+3)%4];
4785         coneNew[(r+0)%4] = eStartNew + (cone[r]       - eStart)*2 + (ornt[r] < 0 ? 1 : 0);
4786         orntNew[(r+0)%4] = ornt[r];
4787         coneNew[(r+1)%4] = eStartNew + (eMax - eStart)*2 + (f - fStart)*4 + r;
4788         orntNew[(r+1)%4] = 0;
4789         coneNew[(r+2)%4] = eStartNew + (eMax - eStart)*2 + (f - fStart)*4 + (r+3)%4;
4790         orntNew[(r+2)%4] = -2;
4791         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4792         ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4793 #if 1
4794         if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
4795         for (p = 0; p < 4; ++p) {
4796           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);
4797         }
4798 #endif
4799         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
4800         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
4801         for (s = 0; s < supportSize; ++s) {
4802           PetscInt subf;
4803           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
4804           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
4805           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
4806           for (c = 0; c < coneSize; ++c) {
4807             if (cone[c] == f) break;
4808           }
4809           subf = GetQuadSubfaceInverse_Static(ornt[c], r);
4810           if (support[s] < cMax) {
4811             supportRef[s] = cStartNew + (support[s] - cStart)*8 + newCells[c*4+subf];
4812           } else {
4813             supportRef[s] = cStartNew + (cMax       - cStart)*8 + (support[s] - cMax)*4 + subf;
4814           }
4815         }
4816         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
4817 #if 1
4818         if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
4819         for (p = 0; p < supportSize; ++p) {
4820           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);
4821         }
4822 #endif
4823       }
4824     }
4825     /* Interior cell faces have 4 edges and 2 cells */
4826     for (c = cStart; c < cMax; ++c) {
4827       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};
4828       const PetscInt *cone, *ornt;
4829       PetscInt        newp, coneNew[4], orntNew[4], supportNew[2];
4830 
4831       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
4832       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
4833       /* A-D face */
4834       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 0;
4835       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*4 + GetQuadEdge_Static(ornt[0], 3);
4836       orntNew[0] = 0;
4837       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 0;
4838       orntNew[1] = 0;
4839       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 2;
4840       orntNew[2] = -2;
4841       coneNew[3] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*4 + GetQuadEdge_Static(ornt[2], 0);
4842       orntNew[3] = -2;
4843       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4844       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4845 #if 1
4846       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
4847       for (p = 0; p < 4; ++p) {
4848         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);
4849       }
4850 #endif
4851       /* C-D face */
4852       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 1;
4853       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*4 + GetQuadEdge_Static(ornt[0], 2);
4854       orntNew[0] = 0;
4855       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 0;
4856       orntNew[1] = 0;
4857       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 4;
4858       orntNew[2] = -2;
4859       coneNew[3] = eStartNew + (eMax - eStart)*2 + (cone[4] - fStart)*4 + GetQuadEdge_Static(ornt[4], 0);
4860       orntNew[3] = -2;
4861       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4862       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4863 #if 1
4864       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
4865       for (p = 0; p < 4; ++p) {
4866         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);
4867       }
4868 #endif
4869       /* B-C face */
4870       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 2;
4871       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*4 + GetQuadEdge_Static(ornt[0], 1);
4872       orntNew[0] = -2;
4873       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*4 + GetQuadEdge_Static(ornt[3], 0);
4874       orntNew[1] = 0;
4875       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 3;
4876       orntNew[2] = 0;
4877       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 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       /* A-B face */
4888       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 3;
4889       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*4 + GetQuadEdge_Static(ornt[0], 0);
4890       orntNew[0] = -2;
4891       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[5] - fStart)*4 + GetQuadEdge_Static(ornt[5], 3);
4892       orntNew[1] = 0;
4893       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 5;
4894       orntNew[2] = 0;
4895       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 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       /* E-F face */
4906       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 4;
4907       coneNew[0] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 2;
4908       orntNew[0] = -2;
4909       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*4 + GetQuadEdge_Static(ornt[2], 2);
4910       orntNew[1] = -2;
4911       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*4 + GetQuadEdge_Static(ornt[1], 0);
4912       orntNew[2] = 0;
4913       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 1;
4914       orntNew[3] = 0;
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       /* F-G face */
4924       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 5;
4925       coneNew[0] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 4;
4926       orntNew[0] = -2;
4927       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[4] - fStart)*4 + GetQuadEdge_Static(ornt[4], 2);
4928       orntNew[1] = -2;
4929       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*4 + GetQuadEdge_Static(ornt[1], 1);
4930       orntNew[2] = 0;
4931       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 1;
4932       orntNew[3] = 0;
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       /* G-H face */
4942       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 6;
4943       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*4 + GetQuadEdge_Static(ornt[3], 2);
4944       orntNew[0] = -2;
4945       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*4 + GetQuadEdge_Static(ornt[1], 2);
4946       orntNew[1] = 0;
4947       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 1;
4948       orntNew[2] = 0;
4949       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 3;
4950       orntNew[3] = -2;
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       /* E-H face */
4960       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 7;
4961       coneNew[0] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 5;
4962       orntNew[0] = -2;
4963       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[5] - fStart)*4 + GetQuadEdge_Static(ornt[5], 1);
4964       orntNew[1] = -2;
4965       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*4 + GetQuadEdge_Static(ornt[1], 3);
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       /* A-E face */
4978       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 8;
4979       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*4 + GetQuadEdge_Static(ornt[2], 3);
4980       orntNew[0] = 0;
4981       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 2;
4982       orntNew[1] = 0;
4983       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 5;
4984       orntNew[2] = -2;
4985       coneNew[3] = eStartNew + (eMax - eStart)*2 + (cone[5] - fStart)*4 + GetQuadEdge_Static(ornt[5], 0);
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       /* D-F face */
4996       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 9;
4997       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*4 + GetQuadEdge_Static(ornt[2], 1);
4998       orntNew[0] = -2;
4999       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[4] - fStart)*4 + GetQuadEdge_Static(ornt[4], 3);
5000       orntNew[1] = 0;
5001       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 4;
5002       orntNew[2] = 0;
5003       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 2;
5004       orntNew[3] = -2;
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       /* C-G face */
5014       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 10;
5015       coneNew[0] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 4;
5016       orntNew[0] = -2;
5017       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[4] - fStart)*4 + GetQuadEdge_Static(ornt[4], 1);
5018       orntNew[1] = -2;
5019       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*4 + GetQuadEdge_Static(ornt[3], 3);
5020       orntNew[2] = 0;
5021       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 3;
5022       orntNew[3] = 0;
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       /* B-H face */
5032       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 11;
5033       coneNew[0] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 5;
5034       orntNew[0] = 0;
5035       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 3;
5036       orntNew[1] = -2;
5037       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*4 + GetQuadEdge_Static(ornt[3], 1);
5038       orntNew[2] = -2;
5039       coneNew[3] = eStartNew + (eMax - eStart)*2 + (cone[5] - fStart)*4 + GetQuadEdge_Static(ornt[5], 2);
5040       orntNew[3] = 0;
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       for (r = 0; r < 12; ++r) {
5050         newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + r;
5051         supportNew[0] = cStartNew + (c - cStart)*8 + newCells[r*2+0];
5052         supportNew[1] = cStartNew + (c - cStart)*8 + newCells[r*2+1];
5053         ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
5054 #if 1
5055         if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
5056         for (p = 0; p < 2; ++p) {
5057           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);
5058         }
5059 #endif
5060       }
5061     }
5062     /* Hybrid split faces have 4 edges and same cells */
5063     for (f = fMax; f < fEnd; ++f) {
5064       const PetscInt *cone, *ornt, *support;
5065       PetscInt        coneNew[4], orntNew[4];
5066       PetscInt        supportNew[2], size, s, c;
5067 
5068       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
5069       ierr = DMPlexGetConeOrientation(dm, f, &ornt);CHKERRQ(ierr);
5070       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
5071       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
5072       for (r = 0; r < 2; ++r) {
5073         const PetscInt newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (f - fMax)*2 + r;
5074 
5075         coneNew[0]   = eStartNew + (cone[0] - eStart)*2 + (ornt[0] < 0 ? 1-r : r);
5076         orntNew[0]   = ornt[0];
5077         coneNew[1]   = eStartNew + (cone[1] - eStart)*2 + (ornt[1] < 0 ? 1-r : r);
5078         orntNew[1]   = ornt[1];
5079         coneNew[2+r] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (cone[2+r] - eMax);
5080         orntNew[2+r] = 0;
5081         coneNew[3-r] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (eEnd      - eMax) + (f - fMax);
5082         orntNew[3-r] = 0;
5083         ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5084         ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
5085 #if 1
5086         if ((newp < fMaxNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid face [%d, %d)", newp, fMaxNew, fEndNew);
5087         for (p = 0; p < 2; ++p) {
5088           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);
5089         }
5090         for (p = 2; p < 4; ++p) {
5091           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);
5092         }
5093 #endif
5094         for (s = 0; s < size; ++s) {
5095           const PetscInt *coneCell, *orntCell, *fornt;
5096           PetscInt        o, of;
5097 
5098           ierr = DMPlexGetCone(dm, support[s], &coneCell);CHKERRQ(ierr);
5099           ierr = DMPlexGetConeOrientation(dm, support[s], &orntCell);CHKERRQ(ierr);
5100           o = orntCell[0] < 0 ? -1 : 1;
5101           for (c = 2; c < 6; ++c) if (coneCell[c] == f) break;
5102           if (c >= 6) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Could not find face %d in cone of cell %d", f, support[s]);
5103           ierr = DMPlexGetConeOrientation(dm, coneCell[0], &fornt);CHKERRQ(ierr);
5104           of = fornt[c-2] < 0 ? -1 : 1;
5105           supportNew[s] = cStartNew + (cMax - cStart)*8 + (support[s] - cMax)*4 + (GetQuadEdgeInverse_Static(orntCell[0], c-2) + (o*of < 0 ? 1-r : r))%4;
5106         }
5107         ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
5108 #if 1
5109         if ((newp < fMaxNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid face [%d, %d)", newp, fMaxNew, fEndNew);
5110         for (p = 0; p < size; ++p) {
5111           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);
5112         }
5113 #endif
5114       }
5115     }
5116     /* Hybrid cell faces have 4 edges and 2 cells */
5117     for (c = cMax; c < cEnd; ++c) {
5118       PetscInt        newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd - fMax)*2 + (c - cMax)*4;
5119       const PetscInt *cone, *ornt;
5120       PetscInt        coneNew[4], orntNew[4];
5121       PetscInt        supportNew[2];
5122 
5123       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
5124       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
5125       for (r = 0; r < 4; ++r) {
5126 #if 0
5127         coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], r);
5128         orntNew[0] = 0;
5129         coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], r);
5130         orntNew[1] = 0;
5131         coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (eEnd - eMax) + (cone[2+GetQuadEdge_Static(ornt[0], r)] - fMax);
5132         orntNew[2] = 0;
5133         coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (eEnd - eMax) + (fEnd                                   - fMax) + (c - cMax);
5134         orntNew[3] = 0;
5135 #else
5136         coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*4 + r;
5137         orntNew[0] = 0;
5138         coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*4 + r;
5139         orntNew[1] = 0;
5140         coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (eEnd - eMax) + (cone[2+r] - fMax);
5141         orntNew[2] = 0;
5142         coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (eEnd - eMax) + (fEnd      - fMax) + (c - cMax);
5143         orntNew[3] = 0;
5144 #endif
5145         ierr = DMPlexSetCone(rdm, newp+r, coneNew);CHKERRQ(ierr);
5146         ierr = DMPlexSetConeOrientation(rdm, newp+r, orntNew);CHKERRQ(ierr);
5147 #if 1
5148         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);
5149         for (p = 0; p < 2; ++p) {
5150           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);
5151         }
5152         for (p = 2; p < 4; ++p) {
5153           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);
5154         }
5155 #endif
5156         supportNew[0] = cStartNew + (cMax - cStart)*8 + (c - cMax)*4 + GetQuadSubface_Static(ornt[0], r);
5157         supportNew[1] = cStartNew + (cMax - cStart)*8 + (c - cMax)*4 + GetQuadSubface_Static(ornt[0], (r+1)%4);
5158         ierr          = DMPlexSetSupport(rdm, newp+r, supportNew);CHKERRQ(ierr);
5159 #if 1
5160         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);
5161         for (p = 0; p < 2; ++p) {
5162           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);
5163         }
5164 #endif
5165       }
5166     }
5167     /* Interior split edges have 2 vertices and the same faces as the parent */
5168     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
5169     for (e = eStart; e < eMax; ++e) {
5170       const PetscInt newv = vStartNew + (vEnd - vStart) + (e - eStart);
5171 
5172       for (r = 0; r < 2; ++r) {
5173         const PetscInt  newp = eStartNew + (e - eStart)*2 + r;
5174         const PetscInt *cone, *ornt, *support;
5175         PetscInt        coneNew[2], coneSize, c, supportSize, s;
5176 
5177         ierr             = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
5178         coneNew[0]       = vStartNew + (cone[0] - vStart);
5179         coneNew[1]       = vStartNew + (cone[1] - vStart);
5180         coneNew[(r+1)%2] = newv;
5181         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5182 #if 1
5183         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
5184         for (p = 0; p < 2; ++p) {
5185           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);
5186         }
5187 #endif
5188         ierr = DMPlexGetSupportSize(dm, e, &supportSize);CHKERRQ(ierr);
5189         ierr = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
5190         for (s = 0; s < supportSize; ++s) {
5191           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
5192           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
5193           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
5194           for (c = 0; c < coneSize; ++c) {
5195             if (cone[c] == e) break;
5196           }
5197           if (support[s] < fMax) {
5198             supportRef[s] = fStartNew + (support[s] - fStart)*4 + (c + (ornt[c] < 0 ? 1-r : r))%4;
5199           } else {
5200             supportRef[s] = fStartNew + (fMax       - fStart)*4 + (cMax - cStart)*12 + (support[s] - fMax)*2 + (ornt[c] < 0 ? 1-r : r);
5201           }
5202         }
5203         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
5204 #if 1
5205         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
5206         for (p = 0; p < supportSize; ++p) {
5207           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);
5208         }
5209 #endif
5210       }
5211     }
5212     /* Interior face edges have 2 vertices and 2+cells faces */
5213     for (f = fStart; f < fMax; ++f) {
5214       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};
5215       const PetscInt  newv = vStartNew + (vEnd - vStart) + (eMax - eStart) + (f - fStart);
5216       const PetscInt *cone, *coneCell, *orntCell, *support;
5217       PetscInt        coneNew[2], coneSize, c, supportSize, s;
5218 
5219       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
5220       for (r = 0; r < 4; ++r) {
5221         const PetscInt newp = eStartNew + (eMax - eStart)*2 + (f - fStart)*4 + r;
5222 
5223         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r] - eStart);
5224         coneNew[1] = newv;
5225         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5226 #if 1
5227         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
5228         for (p = 0; p < 2; ++p) {
5229           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);
5230         }
5231 #endif
5232         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
5233         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
5234         supportRef[0] = fStartNew + (f - fStart)*4 + r;
5235         supportRef[1] = fStartNew + (f - fStart)*4 + (r+1)%4;
5236         for (s = 0; s < supportSize; ++s) {
5237           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
5238           ierr = DMPlexGetCone(dm, support[s], &coneCell);CHKERRQ(ierr);
5239           ierr = DMPlexGetConeOrientation(dm, support[s], &orntCell);CHKERRQ(ierr);
5240           for (c = 0; c < coneSize; ++c) if (coneCell[c] == f) break;
5241           if (support[s] < cMax) {
5242             supportRef[2+s] = fStartNew + (fMax - fStart)*4 + (support[s] - cStart)*12 + newFaces[c*4 + GetQuadEdgeInverse_Static(orntCell[c], r)];
5243           } else {
5244             supportRef[2+s] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd - fMax)*2 + (support[s] - cMax)*4 + r;
5245           }
5246         }
5247         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
5248 #if 1
5249         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
5250         for (p = 0; p < 2+supportSize; ++p) {
5251           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);
5252         }
5253 #endif
5254       }
5255     }
5256     /* Interior cell edges have 2 vertices and 4 faces */
5257     for (c = cStart; c < cMax; ++c) {
5258       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};
5259       const PetscInt  newv = vStartNew + (vEnd - vStart) + (eMax - eStart) + (fMax - fStart) + (c - cStart);
5260       const PetscInt *cone;
5261       PetscInt        coneNew[2], supportNew[4];
5262 
5263       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
5264       for (r = 0; r < 6; ++r) {
5265         const PetscInt newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (c - cStart)*6 + r;
5266 
5267         coneNew[0] = vStartNew + (vEnd - vStart) + (eMax - eStart) + (cone[r] - fStart);
5268         coneNew[1] = newv;
5269         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5270 #if 1
5271         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
5272         for (p = 0; p < 2; ++p) {
5273           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
5274         }
5275 #endif
5276         for (f = 0; f < 4; ++f) supportNew[f] = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + newFaces[r*4+f];
5277         ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
5278 #if 1
5279         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
5280         for (p = 0; p < 4; ++p) {
5281           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);
5282         }
5283 #endif
5284       }
5285     }
5286     /* Hybrid edges have two vertices and the same faces */
5287     for (e = eMax; e < eEnd; ++e) {
5288       const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (e - eMax);
5289       const PetscInt *cone, *support, *fcone;
5290       PetscInt        coneNew[2], size, fsize, s;
5291 
5292       ierr = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
5293       ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
5294       ierr = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
5295       coneNew[0] = vStartNew + (cone[0] - vStart);
5296       coneNew[1] = vStartNew + (cone[1] - vStart);
5297       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5298 #if 1
5299       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid edge [%d, %d)", newp, eMaxNew, eEndNew);
5300       for (p = 0; p < 2; ++p) {
5301         if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
5302       }
5303 #endif
5304       for (s = 0; s < size; ++s) {
5305         ierr = DMPlexGetConeSize(dm, support[s], &fsize);CHKERRQ(ierr);
5306         ierr = DMPlexGetCone(dm, support[s], &fcone);CHKERRQ(ierr);
5307         for (c = 0; c < fsize; ++c) if (fcone[c] == e) break;
5308         if ((c < 2) || (c > 3)) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Edge %d not found in cone of face %d", e, support[s]);
5309         supportRef[s] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (support[s] - fMax)*2 + c-2;
5310       }
5311       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
5312 #if 1
5313       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid edge [%d, %d)", newp, eMaxNew, eEndNew);
5314       for (p = 0; p < size; ++p) {
5315         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);
5316       }
5317 #endif
5318     }
5319     /* Hybrid face edges have 2 vertices and 2+cells faces */
5320     for (f = fMax; f < fEnd; ++f) {
5321       const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (eEnd - eMax) + (f - fMax);
5322       const PetscInt *cone, *support, *ccone, *cornt;
5323       PetscInt        coneNew[2], size, csize, s;
5324 
5325       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
5326       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
5327       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
5328       coneNew[0] = vStartNew + (vEnd - vStart) + (cone[0] - eStart);
5329       coneNew[1] = vStartNew + (vEnd - vStart) + (cone[1] - eStart);
5330       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5331 #if 1
5332       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid edge [%d, %d)", newp, eMaxNew, eEndNew);
5333       for (p = 0; p < 2; ++p) {
5334         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);
5335       }
5336 #endif
5337       supportRef[0] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (f - fMax)*2 + 0;
5338       supportRef[1] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (f - fMax)*2 + 1;
5339       for (s = 0; s < size; ++s) {
5340         ierr = DMPlexGetConeSize(dm, support[s], &csize);CHKERRQ(ierr);
5341         ierr = DMPlexGetCone(dm, support[s], &ccone);CHKERRQ(ierr);
5342         ierr = DMPlexGetConeOrientation(dm, support[s], &cornt);CHKERRQ(ierr);
5343         for (c = 0; c < csize; ++c) if (ccone[c] == f) break;
5344         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]);
5345         supportRef[2+s] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd - fMax)*2 + (support[s] - cMax)*4 + 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 < 2+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 cell edges have 2 vertices and 4 faces */
5356     for (c = cMax; c < cEnd; ++c) {
5357       const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (eEnd - eMax) + (fEnd - fMax) + (c - cMax);
5358       const PetscInt *cone, *support;
5359       PetscInt        coneNew[2], size;
5360 
5361       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
5362       ierr = DMPlexGetSupportSize(dm, c, &size);CHKERRQ(ierr);
5363       ierr = DMPlexGetSupport(dm, c, &support);CHKERRQ(ierr);
5364       coneNew[0] = vStartNew + (vEnd - vStart) + (eMax - eStart) + (cone[0] - fStart);
5365       coneNew[1] = vStartNew + (vEnd - vStart) + (eMax - eStart) + (cone[1] - fStart);
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 + (fEnd - fMax)*2 + (c - cMax)*4 + 0;
5374       supportRef[1] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd - fMax)*2 + (c - cMax)*4 + 1;
5375       supportRef[2] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd - fMax)*2 + (c - cMax)*4 + 2;
5376       supportRef[3] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd - fMax)*2 + (c - cMax)*4 + 3;
5377       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
5378 #if 1
5379       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid edge [%d, %d)", newp, eMaxNew, eEndNew);
5380       for (p = 0; p < 4; ++p) {
5381         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);
5382       }
5383 #endif
5384     }
5385     /* Interior vertices have identical supports */
5386     for (v = vStart; v < vEnd; ++v) {
5387       const PetscInt  newp = vStartNew + (v - vStart);
5388       const PetscInt *support, *cone;
5389       PetscInt        size, s;
5390 
5391       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
5392       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
5393       for (s = 0; s < size; ++s) {
5394         PetscInt r = 0;
5395 
5396         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
5397         if (cone[1] == v) r = 1;
5398         if (support[s] < eMax) supportRef[s] = eStartNew + (support[s] - eStart)*2 + r;
5399         else                   supportRef[s] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (support[s] - eMax);
5400       }
5401       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
5402 #if 1
5403       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
5404       for (p = 0; p < size; ++p) {
5405         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);
5406       }
5407 #endif
5408     }
5409     /* Interior edge vertices have 2 + faces supports */
5410     for (e = eStart; e < eMax; ++e) {
5411       const PetscInt  newp = vStartNew + (vEnd - vStart) + (e - eStart);
5412       const PetscInt *cone, *support;
5413       PetscInt        size, s;
5414 
5415       ierr          = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
5416       ierr          = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
5417       supportRef[0] = eStartNew + (e - eStart)*2 + 0;
5418       supportRef[1] = eStartNew + (e - eStart)*2 + 1;
5419       for (s = 0; s < size; ++s) {
5420         PetscInt r;
5421 
5422         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
5423         for (r = 0; r < 4; ++r) if (cone[r] == e) break;
5424         if (support[s] < fMax) {
5425           supportRef[2+s] = eStartNew + (eMax - eStart)*2 + (support[s] - fStart)*4 + r;
5426         } else {
5427           supportRef[2+s] = eStartNew + (eMax - eStart)*2 + (fMax       - fStart)*4 + (cMax - cStart)*6 + (eEnd - eMax) + (support[s] - fMax);
5428         }
5429       }
5430       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
5431 #if 1
5432       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
5433       for (p = 0; p < 2+size; ++p) {
5434         if ((supportRef[p] < eStartNew) || (supportRef[p] >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", supportRef[p], eStartNew, eEndNew);
5435       }
5436 #endif
5437     }
5438     /* Interior face vertices have 4 + cells supports */
5439     for (f = fStart; f < fMax; ++f) {
5440       const PetscInt  newp = vStartNew + (vEnd - vStart) + (eMax - eStart) + (f - fStart);
5441       const PetscInt *cone, *support;
5442       PetscInt        size, s;
5443 
5444       ierr          = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
5445       ierr          = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
5446       for (r = 0; r < 4; ++r) supportRef[r] = eStartNew + (eMax - eStart)*2 +  (f - fStart)*4 + r;
5447       for (s = 0; s < size; ++s) {
5448         PetscInt r;
5449 
5450         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
5451         for (r = 0; r < 6; ++r) if (cone[r] == f) break;
5452         if (support[s] < cMax) {
5453           supportRef[4+s] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (support[s] - cStart)*6 + r;
5454         } else {
5455           supportRef[4+s] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax       - cStart)*6 + (eEnd - eMax) + (fEnd - fMax) + (support[s] - cMax);
5456         }
5457       }
5458       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
5459 #if 1
5460       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
5461       for (p = 0; p < 4+size; ++p) {
5462         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);
5463       }
5464 #endif
5465     }
5466     /* Cell vertices have 6 supports */
5467     for (c = cStart; c < cMax; ++c) {
5468       const PetscInt newp = vStartNew + (vEnd - vStart) + (eMax - eStart) + (fMax - fStart) + (c - cStart);
5469       PetscInt       supportNew[6];
5470 
5471       for (r = 0; r < 6; ++r) {
5472         supportNew[r] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (c - cStart)*6 + r;
5473       }
5474       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
5475     }
5476     ierr = PetscFree(supportRef);CHKERRQ(ierr);
5477     break;
5478   default:
5479     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
5480   }
5481   PetscFunctionReturn(0);
5482 }
5483 
5484 #undef __FUNCT__
5485 #define __FUNCT__ "CellRefinerSetCoordinates"
5486 static PetscErrorCode CellRefinerSetCoordinates(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
5487 {
5488   PetscSection   coordSection, coordSectionNew;
5489   Vec            coordinates, coordinatesNew;
5490   PetscScalar   *coords, *coordsNew;
5491   const PetscInt numVertices = depthSize ? depthSize[0] : 0;
5492   PetscInt       dim, spaceDim, depth, bs, coordSizeNew, cStart, cEnd, cMax, c, vStart, vStartNew, vEnd, v, eStart, eEnd, eMax, e, fStart, fEnd, fMax, f;
5493   PetscErrorCode ierr;
5494 
5495   PetscFunctionBegin;
5496   ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr);
5497   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
5498   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
5499   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
5500   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
5501   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
5502   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, NULL);CHKERRQ(ierr);
5503   if (refiner) {ierr = GetDepthStart_Private(depth, depthSize, NULL, NULL, NULL, &vStartNew);CHKERRQ(ierr);}
5504   ierr = GetDepthStart_Private(depth, depthSize, NULL, NULL, NULL, &vStartNew);CHKERRQ(ierr);
5505   ierr = DMGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
5506   ierr = PetscSectionGetFieldComponents(coordSection, 0, &spaceDim);CHKERRQ(ierr);
5507   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)dm), &coordSectionNew);CHKERRQ(ierr);
5508   ierr = PetscSectionSetNumFields(coordSectionNew, 1);CHKERRQ(ierr);
5509   ierr = PetscSectionSetFieldComponents(coordSectionNew, 0, spaceDim);CHKERRQ(ierr);
5510   ierr = PetscSectionSetChart(coordSectionNew, vStartNew, vStartNew+numVertices);CHKERRQ(ierr);
5511   if (cMax < 0) cMax = cEnd;
5512   if (fMax < 0) fMax = fEnd;
5513   if (eMax < 0) eMax = eEnd;
5514   /* All vertices have the spaceDim coordinates */
5515   for (v = vStartNew; v < vStartNew+numVertices; ++v) {
5516     ierr = PetscSectionSetDof(coordSectionNew, v, spaceDim);CHKERRQ(ierr);
5517     ierr = PetscSectionSetFieldDof(coordSectionNew, v, 0, spaceDim);CHKERRQ(ierr);
5518   }
5519   ierr = PetscSectionSetUp(coordSectionNew);CHKERRQ(ierr);
5520   ierr = DMSetCoordinateSection(rdm, PETSC_DETERMINE, coordSectionNew);CHKERRQ(ierr);
5521   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
5522   ierr = PetscSectionGetStorageSize(coordSectionNew, &coordSizeNew);CHKERRQ(ierr);
5523   ierr = VecCreate(PetscObjectComm((PetscObject)dm), &coordinatesNew);CHKERRQ(ierr);
5524   ierr = PetscObjectSetName((PetscObject) coordinatesNew, "coordinates");CHKERRQ(ierr);
5525   ierr = VecSetSizes(coordinatesNew, coordSizeNew, PETSC_DETERMINE);CHKERRQ(ierr);
5526   ierr = VecGetBlockSize(coordinates, &bs);CHKERRQ(ierr);
5527   ierr = VecSetBlockSize(coordinatesNew, bs);CHKERRQ(ierr);
5528   ierr = VecSetFromOptions(coordinatesNew);CHKERRQ(ierr);
5529   ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
5530   ierr = VecGetArray(coordinatesNew, &coordsNew);CHKERRQ(ierr);
5531   switch (refiner) {
5532   case REFINER_NOOP: break;
5533   case REFINER_HEX_3D:
5534   case REFINER_HYBRID_HEX_3D:
5535     /* Face vertices have the average of corner coordinates */
5536     for (f = fStart; f < fMax; ++f) {
5537       const PetscInt newv = vStartNew + (vEnd - vStart) + (eMax - eStart) + (f - fStart);
5538       PetscInt      *cone = NULL;
5539       PetscInt       closureSize, coneSize = 0, off[8], offnew, p, d;
5540 
5541       ierr = DMPlexGetTransitiveClosure(dm, f, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
5542       for (p = 0; p < closureSize*2; p += 2) {
5543         const PetscInt point = cone[p];
5544         if ((point >= vStart) && (point < vEnd)) cone[coneSize++] = point;
5545       }
5546       for (v = 0; v < coneSize; ++v) {
5547         ierr = PetscSectionGetOffset(coordSection, cone[v], &off[v]);CHKERRQ(ierr);
5548       }
5549       ierr = PetscSectionGetOffset(coordSectionNew, newv, &offnew);CHKERRQ(ierr);
5550       for (d = 0; d < spaceDim; ++d) coordsNew[offnew+d] = 0.0;
5551       for (v = 0; v < coneSize; ++v) {ierr = DMPlexLocalizeAddCoordinate_Internal(dm, spaceDim, &coords[off[0]], &coords[off[v]], &coordsNew[offnew]);CHKERRQ(ierr);}
5552       for (d = 0; d < spaceDim; ++d) coordsNew[offnew+d] /= coneSize;
5553       ierr = DMPlexRestoreTransitiveClosure(dm, f, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
5554     }
5555   case REFINER_HEX_2D:
5556   case REFINER_HYBRID_HEX_2D:
5557   case REFINER_SIMPLEX_1D:
5558     /* Cell vertices have the average of corner coordinates */
5559     for (c = cStart; c < cMax; ++c) {
5560       const PetscInt newv = vStartNew + (vEnd - vStart) + (eMax - eStart) + (c - cStart) + (dim > 2 ? (fMax - fStart) : 0);
5561       PetscInt      *cone = NULL;
5562       PetscInt       closureSize, coneSize = 0, off[8], offnew, p, d;
5563 
5564       ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
5565       for (p = 0; p < closureSize*2; p += 2) {
5566         const PetscInt point = cone[p];
5567         if ((point >= vStart) && (point < vEnd)) cone[coneSize++] = point;
5568       }
5569       for (v = 0; v < coneSize; ++v) {
5570         ierr = PetscSectionGetOffset(coordSection, cone[v], &off[v]);CHKERRQ(ierr);
5571       }
5572       ierr = PetscSectionGetOffset(coordSectionNew, newv, &offnew);CHKERRQ(ierr);
5573       for (d = 0; d < spaceDim; ++d) coordsNew[offnew+d] = 0.0;
5574       for (v = 0; v < coneSize; ++v) {ierr = DMPlexLocalizeAddCoordinate_Internal(dm, spaceDim, &coords[off[0]], &coords[off[v]], &coordsNew[offnew]);CHKERRQ(ierr);}
5575       for (d = 0; d < spaceDim; ++d) coordsNew[offnew+d] /= coneSize;
5576       ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
5577     }
5578   case REFINER_SIMPLEX_2D:
5579   case REFINER_HYBRID_SIMPLEX_2D:
5580   case REFINER_SIMPLEX_3D:
5581   case REFINER_HYBRID_SIMPLEX_3D:
5582     /* Edge vertices have the average of endpoint coordinates */
5583     for (e = eStart; e < eMax; ++e) {
5584       const PetscInt  newv = vStartNew + (vEnd - vStart) + (e - eStart);
5585       const PetscInt *cone;
5586       PetscInt        coneSize, offA, offB, offnew, d;
5587 
5588       ierr = DMPlexGetConeSize(dm, e, &coneSize);CHKERRQ(ierr);
5589       if (coneSize != 2) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Edge %d cone should have two vertices, not %d", e, coneSize);
5590       ierr = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
5591       ierr = PetscSectionGetOffset(coordSection, cone[0], &offA);CHKERRQ(ierr);
5592       ierr = PetscSectionGetOffset(coordSection, cone[1], &offB);CHKERRQ(ierr);
5593       ierr = PetscSectionGetOffset(coordSectionNew, newv, &offnew);CHKERRQ(ierr);
5594       ierr = DMPlexLocalizeCoordinate_Internal(dm, spaceDim, &coords[offA], &coords[offB], &coordsNew[offnew]);CHKERRQ(ierr);
5595       for (d = 0; d < spaceDim; ++d) {
5596         coordsNew[offnew+d] = 0.5*(coords[offA+d] + coordsNew[offnew+d]);
5597       }
5598     }
5599     /* Old vertices have the same coordinates */
5600     for (v = vStart; v < vEnd; ++v) {
5601       const PetscInt newv = vStartNew + (v - vStart);
5602       PetscInt       off, offnew, d;
5603 
5604       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
5605       ierr = PetscSectionGetOffset(coordSectionNew, newv, &offnew);CHKERRQ(ierr);
5606       for (d = 0; d < spaceDim; ++d) {
5607         coordsNew[offnew+d] = coords[off+d];
5608       }
5609     }
5610     break;
5611   default:
5612     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
5613   }
5614   ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
5615   ierr = VecRestoreArray(coordinatesNew, &coordsNew);CHKERRQ(ierr);
5616   ierr = DMSetCoordinatesLocal(rdm, coordinatesNew);CHKERRQ(ierr);
5617   ierr = VecDestroy(&coordinatesNew);CHKERRQ(ierr);
5618   ierr = PetscSectionDestroy(&coordSectionNew);CHKERRQ(ierr);
5619   if (dm->maxCell) {
5620     const PetscReal *maxCell, *L;
5621     ierr = DMGetPeriodicity(dm,  &maxCell, &L);CHKERRQ(ierr);
5622     ierr = DMSetPeriodicity(rdm,  maxCell,  L);CHKERRQ(ierr);
5623   }
5624   PetscFunctionReturn(0);
5625 }
5626 
5627 #undef __FUNCT__
5628 #define __FUNCT__ "DMPlexCreateProcessSF"
5629 /*@
5630   DMPlexCreateProcessSF - Create an SF which just has process connectivity
5631 
5632   Collective on DM
5633 
5634   Input Parameters:
5635 + dm      - The DM
5636 - sfPoint - The PetscSF which encodes point connectivity
5637 
5638   Output Parameters:
5639 + processRanks - A list of process neighbors, or NULL
5640 - sfProcess    - An SF encoding the process connectivity, or NULL
5641 
5642   Level: developer
5643 
5644 .seealso: PetscSFCreate(), DMPlexCreateTwoSidedProcessSF()
5645 @*/
5646 PetscErrorCode DMPlexCreateProcessSF(DM dm, PetscSF sfPoint, IS *processRanks, PetscSF *sfProcess)
5647 {
5648   PetscInt           numRoots, numLeaves, l;
5649   const PetscInt    *localPoints;
5650   const PetscSFNode *remotePoints;
5651   PetscInt          *localPointsNew;
5652   PetscSFNode       *remotePointsNew;
5653   PetscInt          *ranks, *ranksNew;
5654   PetscMPIInt        numProcs;
5655   PetscErrorCode     ierr;
5656 
5657   PetscFunctionBegin;
5658   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5659   PetscValidHeaderSpecific(sfPoint, PETSCSF_CLASSID, 2);
5660   if (processRanks) {PetscValidPointer(processRanks, 3);}
5661   if (sfProcess)    {PetscValidPointer(sfProcess, 4);}
5662   ierr = MPI_Comm_size(PetscObjectComm((PetscObject) dm), &numProcs);CHKERRQ(ierr);
5663   ierr = PetscSFGetGraph(sfPoint, &numRoots, &numLeaves, &localPoints, &remotePoints);CHKERRQ(ierr);
5664   ierr = PetscMalloc1(numLeaves, &ranks);CHKERRQ(ierr);
5665   for (l = 0; l < numLeaves; ++l) {
5666     ranks[l] = remotePoints[l].rank;
5667   }
5668   ierr = PetscSortRemoveDupsInt(&numLeaves, ranks);CHKERRQ(ierr);
5669   ierr = PetscMalloc1(numLeaves, &ranksNew);CHKERRQ(ierr);
5670   ierr = PetscMalloc1(numLeaves, &localPointsNew);CHKERRQ(ierr);
5671   ierr = PetscMalloc1(numLeaves, &remotePointsNew);CHKERRQ(ierr);
5672   for (l = 0; l < numLeaves; ++l) {
5673     ranksNew[l]              = ranks[l];
5674     localPointsNew[l]        = l;
5675     remotePointsNew[l].index = 0;
5676     remotePointsNew[l].rank  = ranksNew[l];
5677   }
5678   ierr = PetscFree(ranks);CHKERRQ(ierr);
5679   if (processRanks) {ierr = ISCreateGeneral(PetscObjectComm((PetscObject)dm), numLeaves, ranksNew, PETSC_OWN_POINTER, processRanks);CHKERRQ(ierr);}
5680   else              {ierr = PetscFree(ranksNew);CHKERRQ(ierr);}
5681   if (sfProcess) {
5682     ierr = PetscSFCreate(PetscObjectComm((PetscObject)dm), sfProcess);CHKERRQ(ierr);
5683     ierr = PetscObjectSetName((PetscObject) *sfProcess, "Process SF");CHKERRQ(ierr);
5684     ierr = PetscSFSetFromOptions(*sfProcess);CHKERRQ(ierr);
5685     ierr = PetscSFSetGraph(*sfProcess, numProcs, numLeaves, localPointsNew, PETSC_OWN_POINTER, remotePointsNew, PETSC_OWN_POINTER);CHKERRQ(ierr);
5686   }
5687   PetscFunctionReturn(0);
5688 }
5689 
5690 #undef __FUNCT__
5691 #define __FUNCT__ "CellRefinerCreateSF"
5692 static PetscErrorCode CellRefinerCreateSF(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
5693 {
5694   PetscSF            sf, sfNew, sfProcess;
5695   IS                 processRanks;
5696   MPI_Datatype       depthType;
5697   PetscInt           numRoots, numLeaves, numLeavesNew = 0, l, m;
5698   const PetscInt    *localPoints, *neighbors;
5699   const PetscSFNode *remotePoints;
5700   PetscInt          *localPointsNew;
5701   PetscSFNode       *remotePointsNew;
5702   PetscInt          *depthSizeOld, *rdepthSize, *rdepthSizeOld, *rdepthMaxOld, *rvStart, *rvStartNew, *reStart, *reStartNew, *rfStart, *rfStartNew, *rcStart, *rcStartNew;
5703   PetscInt           depth, numNeighbors, pStartNew, pEndNew, cStart, cEnd, cMax, vStart, vEnd, vMax, fStart, fEnd, fMax, eStart, eEnd, eMax, r, n;
5704   PetscInt           cStartNew = 0, vStartNew = 0, fStartNew = 0, eStartNew = 0;
5705   PetscErrorCode     ierr;
5706 
5707   PetscFunctionBegin;
5708   ierr = DMPlexGetChart(rdm, &pStartNew, &pEndNew);CHKERRQ(ierr);
5709   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
5710   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
5711   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
5712   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
5713   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
5714   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
5715   cMax = cMax < 0 ? cEnd : cMax;
5716   fMax = fMax < 0 ? fEnd : fMax;
5717   eMax = eMax < 0 ? eEnd : eMax;
5718   if (refiner) {ierr = GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);CHKERRQ(ierr);}
5719   ierr = DMGetPointSF(dm, &sf);CHKERRQ(ierr);
5720   ierr = DMGetPointSF(rdm, &sfNew);CHKERRQ(ierr);
5721   /* Calculate size of new SF */
5722   ierr = PetscSFGetGraph(sf, &numRoots, &numLeaves, &localPoints, &remotePoints);CHKERRQ(ierr);
5723   if (numRoots < 0) PetscFunctionReturn(0);
5724   for (l = 0; l < numLeaves; ++l) {
5725     const PetscInt p = localPoints[l];
5726 
5727     switch (refiner) {
5728     case REFINER_SIMPLEX_1D:
5729       if ((p >= vStart) && (p < vEnd)) {
5730         /* Interior vertices stay the same */
5731         ++numLeavesNew;
5732       } else if ((p >= cStart && p < cMax)) {
5733         /* Interior cells add new cells and interior vertices */
5734         numLeavesNew += 2 + 1;
5735       }
5736       break;
5737     case REFINER_SIMPLEX_2D:
5738     case REFINER_HYBRID_SIMPLEX_2D:
5739       if ((p >= vStart) && (p < vEnd)) {
5740         /* Interior vertices stay the same */
5741         ++numLeavesNew;
5742       } else if ((p >= fStart) && (p < fMax)) {
5743         /* Interior faces add new faces and vertex */
5744         numLeavesNew += 2 + 1;
5745       } else if ((p >= fMax) && (p < fEnd)) {
5746         /* Hybrid faces stay the same */
5747         ++numLeavesNew;
5748       } else if ((p >= cStart) && (p < cMax)) {
5749         /* Interior cells add new cells and interior faces */
5750         numLeavesNew += 4 + 3;
5751       } else if ((p >= cMax) && (p < cEnd)) {
5752         /* Hybrid cells add new cells and hybrid face */
5753         numLeavesNew += 2 + 1;
5754       }
5755       break;
5756     case REFINER_HEX_2D:
5757     case REFINER_HYBRID_HEX_2D:
5758       if ((p >= vStart) && (p < vEnd)) {
5759         /* Interior vertices stay the same */
5760         ++numLeavesNew;
5761       } else if ((p >= fStart) && (p < fMax)) {
5762         /* Interior faces add new faces and vertex */
5763         numLeavesNew += 2 + 1;
5764       } else if ((p >= fMax) && (p < fEnd)) {
5765         /* Hybrid faces stay the same */
5766         ++numLeavesNew;
5767       } else if ((p >= cStart) && (p < cMax)) {
5768         /* Interior cells add new cells, interior faces, and vertex */
5769         numLeavesNew += 4 + 4 + 1;
5770       } else if ((p >= cMax) && (p < cEnd)) {
5771         /* Hybrid cells add new cells and hybrid face */
5772         numLeavesNew += 2 + 1;
5773       }
5774       break;
5775     case REFINER_SIMPLEX_3D:
5776     case REFINER_HYBRID_SIMPLEX_3D:
5777       if ((p >= vStart) && (p < vEnd)) {
5778         /* Interior vertices stay the same */
5779         ++numLeavesNew;
5780       } else if ((p >= eStart) && (p < eMax)) {
5781         /* Interior edges add new edges and vertex */
5782         numLeavesNew += 2 + 1;
5783       } else if ((p >= eMax) && (p < eEnd)) {
5784         /* Hybrid edges stay the same */
5785         ++numLeavesNew;
5786       } else if ((p >= fStart) && (p < fMax)) {
5787         /* Interior faces add new faces and edges */
5788         numLeavesNew += 4 + 3;
5789       } else if ((p >= fMax) && (p < fEnd)) {
5790         /* Hybrid faces add new faces and edges */
5791         numLeavesNew += 2 + 1;
5792       } else if ((p >= cStart) && (p < cMax)) {
5793         /* Interior cells add new cells, faces, and edges */
5794         numLeavesNew += 8 + 8 + 1;
5795       } else if ((p >= cMax) && (p < cEnd)) {
5796         /* Hybrid cells add new cells and faces */
5797         numLeavesNew += 4 + 3;
5798       }
5799       break;
5800     case REFINER_HEX_3D:
5801     case REFINER_HYBRID_HEX_3D:
5802       if ((p >= vStart) && (p < vEnd)) {
5803         /* Old vertices stay the same */
5804         ++numLeavesNew;
5805       } else if ((p >= eStart) && (p < eMax)) {
5806         /* Interior edges add new edges, and vertex */
5807         numLeavesNew += 2 + 1;
5808       } else if ((p >= eMax) && (p < eEnd)) {
5809         /* Hybrid edges stay the same */
5810         ++numLeavesNew;
5811       } else if ((p >= fStart) && (p < fMax)) {
5812         /* Interior faces add new faces, edges, and vertex */
5813         numLeavesNew += 4 + 4 + 1;
5814       } else if ((p >= fMax) && (p < fEnd)) {
5815         /* Hybrid faces add new faces and edges */
5816         numLeavesNew += 2 + 1;
5817       } else if ((p >= cStart) && (p < cMax)) {
5818         /* Interior cells add new cells, faces, edges, and vertex */
5819         numLeavesNew += 8 + 12 + 6 + 1;
5820       } else if ((p >= cStart) && (p < cEnd)) {
5821         /* Hybrid cells add new cells, faces, and edges */
5822         numLeavesNew += 4 + 4 + 1;
5823       }
5824       break;
5825     default:
5826       SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
5827     }
5828   }
5829   /* Communicate depthSizes for each remote rank */
5830   ierr = DMPlexCreateProcessSF(dm, sf, &processRanks, &sfProcess);CHKERRQ(ierr);
5831   ierr = ISGetLocalSize(processRanks, &numNeighbors);CHKERRQ(ierr);
5832   ierr = PetscMalloc5((depth+1)*numNeighbors,&rdepthSize,numNeighbors,&rvStartNew,numNeighbors,&reStartNew,numNeighbors,&rfStartNew,numNeighbors,&rcStartNew);CHKERRQ(ierr);
5833   ierr = PetscMalloc7(depth+1,&depthSizeOld,(depth+1)*numNeighbors,&rdepthSizeOld,(depth+1)*numNeighbors,&rdepthMaxOld,numNeighbors,&rvStart,numNeighbors,&reStart,numNeighbors,&rfStart,numNeighbors,&rcStart);CHKERRQ(ierr);
5834   ierr = MPI_Type_contiguous(depth+1, MPIU_INT, &depthType);CHKERRQ(ierr);
5835   ierr = MPI_Type_commit(&depthType);CHKERRQ(ierr);
5836   ierr = PetscSFBcastBegin(sfProcess, depthType, depthSize, rdepthSize);CHKERRQ(ierr);
5837   ierr = PetscSFBcastEnd(sfProcess, depthType, depthSize, rdepthSize);CHKERRQ(ierr);
5838   for (n = 0; n < numNeighbors; ++n) {
5839     ierr = GetDepthStart_Private(depth, &rdepthSize[n*(depth+1)], &rcStartNew[n], &rfStartNew[n], &reStartNew[n], &rvStartNew[n]);CHKERRQ(ierr);
5840   }
5841   depthSizeOld[depth]   = cMax;
5842   depthSizeOld[0]       = vMax;
5843   depthSizeOld[depth-1] = fMax;
5844   depthSizeOld[1]       = eMax;
5845 
5846   ierr = PetscSFBcastBegin(sfProcess, depthType, depthSizeOld, rdepthMaxOld);CHKERRQ(ierr);
5847   ierr = PetscSFBcastEnd(sfProcess, depthType, depthSizeOld, rdepthMaxOld);CHKERRQ(ierr);
5848 
5849   depthSizeOld[depth]   = cEnd - cStart;
5850   depthSizeOld[0]       = vEnd - vStart;
5851   depthSizeOld[depth-1] = fEnd - fStart;
5852   depthSizeOld[1]       = eEnd - eStart;
5853 
5854   ierr = PetscSFBcastBegin(sfProcess, depthType, depthSizeOld, rdepthSizeOld);CHKERRQ(ierr);
5855   ierr = PetscSFBcastEnd(sfProcess, depthType, depthSizeOld, rdepthSizeOld);CHKERRQ(ierr);
5856   for (n = 0; n < numNeighbors; ++n) {
5857     ierr = GetDepthStart_Private(depth, &rdepthSizeOld[n*(depth+1)], &rcStart[n], &rfStart[n], &reStart[n], &rvStart[n]);CHKERRQ(ierr);
5858     rdepthMaxOld[n*(depth+1)+depth]   = rdepthMaxOld[n*(depth+1)+depth]   < 0 ? rdepthSizeOld[n*(depth+1)+depth]  +rcStart[n]: rdepthMaxOld[n*(depth+1)+depth];
5859     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];
5860     rdepthMaxOld[n*(depth+1)+1]       = rdepthMaxOld[n*(depth+1)+1]       < 0 ? rdepthSizeOld[n*(depth+1)+1]      +reStart[n]: rdepthMaxOld[n*(depth+1)+1];
5861   }
5862   ierr = MPI_Type_free(&depthType);CHKERRQ(ierr);
5863   ierr = PetscSFDestroy(&sfProcess);CHKERRQ(ierr);
5864   /* Calculate new point SF */
5865   ierr = PetscMalloc1(numLeavesNew, &localPointsNew);CHKERRQ(ierr);
5866   ierr = PetscMalloc1(numLeavesNew, &remotePointsNew);CHKERRQ(ierr);
5867   ierr = ISGetIndices(processRanks, &neighbors);CHKERRQ(ierr);
5868   for (l = 0, m = 0; l < numLeaves; ++l) {
5869     PetscInt    p     = localPoints[l];
5870     PetscInt    rp    = remotePoints[l].index, n;
5871     PetscMPIInt rrank = remotePoints[l].rank;
5872 
5873     ierr = PetscFindInt(rrank, numNeighbors, neighbors, &n);CHKERRQ(ierr);
5874     if (n < 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Could not locate remote rank %d", rrank);
5875     switch (refiner) {
5876     case REFINER_SIMPLEX_1D:
5877       if ((p >= vStart) && (p < vEnd)) {
5878         /* Old vertices stay the same */
5879         localPointsNew[m]        = vStartNew     + (p  - vStart);
5880         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
5881         remotePointsNew[m].rank  = rrank;
5882         ++m;
5883       } else if ((p >= cStart) && (p < cMax)) {
5884         /* Old interior cells add new cells and vertex */
5885         for (r = 0; r < 2; ++r, ++m) {
5886           localPointsNew[m]        = cStartNew     + (p  - cStart)*2     + r;
5887           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*2 + r;
5888           remotePointsNew[m].rank  = rrank;
5889         }
5890         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - cStart);
5891         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - rcStart[n]);
5892         remotePointsNew[m].rank  = rrank;
5893         ++m;
5894       }
5895       break;
5896     case REFINER_SIMPLEX_2D:
5897     case REFINER_HYBRID_SIMPLEX_2D:
5898       if ((p >= vStart) && (p < vEnd)) {
5899         /* Old vertices stay the same */
5900         localPointsNew[m]        = vStartNew     + (p  - vStart);
5901         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
5902         remotePointsNew[m].rank  = rrank;
5903         ++m;
5904       } else if ((p >= fStart) && (p < fMax)) {
5905         /* Old interior faces add new faces and vertex */
5906         for (r = 0; r < 2; ++r, ++m) {
5907           localPointsNew[m]        = fStartNew     + (p  - fStart)*2     + r;
5908           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*2 + r;
5909           remotePointsNew[m].rank  = rrank;
5910         }
5911         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - fStart);
5912         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - rfStart[n]);
5913         remotePointsNew[m].rank  = rrank;
5914         ++m;
5915       } else if ((p >= fMax) && (p < fEnd)) {
5916         /* Old hybrid faces stay the same */
5917         localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (p  - fMax);
5918         remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*2 + (rp - rdepthMaxOld[n*(depth+1)+depth-1]);
5919         remotePointsNew[m].rank  = rrank;
5920         ++m;
5921       } else if ((p >= cStart) && (p < cMax)) {
5922         /* Old interior cells add new cells and interior faces */
5923         for (r = 0; r < 4; ++r, ++m) {
5924           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
5925           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
5926           remotePointsNew[m].rank  = rrank;
5927         }
5928         for (r = 0; r < 3; ++r, ++m) {
5929           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (p  - cStart)*3     + r;
5930           remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*2 + (rp - rcStart[n])*3 + r;
5931           remotePointsNew[m].rank  = rrank;
5932         }
5933       } else if ((p >= cMax) && (p < cEnd)) {
5934         /* Old hybrid cells add new cells and hybrid face */
5935         for (r = 0; r < 2; ++r, ++m) {
5936           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
5937           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
5938           remotePointsNew[m].rank  = rrank;
5939         }
5940         localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (cMax                            - cStart)*3     + (p  - cMax);
5941         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]);
5942         remotePointsNew[m].rank  = rrank;
5943         ++m;
5944       }
5945       break;
5946     case REFINER_HEX_2D:
5947     case REFINER_HYBRID_HEX_2D:
5948       if ((p >= vStart) && (p < vEnd)) {
5949         /* Old vertices stay the same */
5950         localPointsNew[m]        = vStartNew     + (p  - vStart);
5951         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
5952         remotePointsNew[m].rank  = rrank;
5953         ++m;
5954       } else if ((p >= fStart) && (p < fMax)) {
5955         /* Old interior faces add new faces and vertex */
5956         for (r = 0; r < 2; ++r, ++m) {
5957           localPointsNew[m]        = fStartNew     + (p  - fStart)*2     + r;
5958           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*2 + r;
5959           remotePointsNew[m].rank  = rrank;
5960         }
5961         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - fStart);
5962         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - rfStart[n]);
5963         remotePointsNew[m].rank  = rrank;
5964         ++m;
5965       } else if ((p >= fMax) && (p < fEnd)) {
5966         /* Old hybrid faces stay the same */
5967         localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (p  - fMax);
5968         remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*2 + (rp - rdepthMaxOld[n*(depth+1)+depth-1]);
5969         remotePointsNew[m].rank  = rrank;
5970         ++m;
5971       } else if ((p >= cStart) && (p < cMax)) {
5972         /* Old interior cells add new cells, interior faces, and vertex */
5973         for (r = 0; r < 4; ++r, ++m) {
5974           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
5975           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
5976           remotePointsNew[m].rank  = rrank;
5977         }
5978         for (r = 0; r < 4; ++r, ++m) {
5979           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (p  - cStart)*4     + r;
5980           remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*2 + (rp - rcStart[n])*4 + r;
5981           remotePointsNew[m].rank  = rrank;
5982         }
5983         localPointsNew[m]        = vStartNew     + (vEnd - vStart)               + (fMax                              - fStart)     + (p  - cStart);
5984         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0]  + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n]) + (rp - rcStart[n]);
5985         remotePointsNew[m].rank  = rrank;
5986         ++m;
5987       } else if ((p >= cStart) && (p < cMax)) {
5988         /* Old hybrid cells add new cells and hybrid face */
5989         for (r = 0; r < 2; ++r, ++m) {
5990           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
5991           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
5992           remotePointsNew[m].rank  = rrank;
5993         }
5994         localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (cMax                            - cStart)*4     + (p  - cMax);
5995         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]);
5996         remotePointsNew[m].rank  = rrank;
5997         ++m;
5998       }
5999       break;
6000     case REFINER_SIMPLEX_3D:
6001     case REFINER_HYBRID_SIMPLEX_3D:
6002       if ((p >= vStart) && (p < vEnd)) {
6003         /* Interior vertices stay the same */
6004         localPointsNew[m]        = vStartNew     + (p  - vStart);
6005         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
6006         remotePointsNew[m].rank  = rrank;
6007         ++m;
6008       } else if ((p >= eStart) && (p < eMax)) {
6009         /* Interior edges add new edges and vertex */
6010         for (r = 0; r < 2; ++r, ++m) {
6011           localPointsNew[m]        = eStartNew     + (p  - eStart)*2     + r;
6012           remotePointsNew[m].index = reStartNew[n] + (rp - reStart[n])*2 + r;
6013           remotePointsNew[m].rank  = rrank;
6014         }
6015         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - eStart);
6016         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - reStart[n]);
6017         remotePointsNew[m].rank  = rrank;
6018         ++m;
6019       } else if ((p >= eMax) && (p < eEnd)) {
6020         /* Hybrid edges stay the same */
6021         localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (fMax                              - fStart)*3     + (cMax                            - cStart)     + (p  - eMax);
6022         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]);
6023         remotePointsNew[m].rank  = rrank;
6024         ++m;
6025       } else if ((p >= fStart) && (p < fMax)) {
6026         /* Interior faces add new faces and edges */
6027         for (r = 0; r < 4; ++r, ++m) {
6028           localPointsNew[m]        = fStartNew     + (p  - fStart)*4     + r;
6029           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*4 + r;
6030           remotePointsNew[m].rank  = rrank;
6031         }
6032         for (r = 0; r < 3; ++r, ++m) {
6033           localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (p  - fStart)*3     + r;
6034           remotePointsNew[m].index = reStartNew[n] + (rdepthMaxOld[n*(depth+1)+1] - reStart[n])*2 + (rp - rfStart[n])*3 + r;
6035           remotePointsNew[m].rank  = rrank;
6036         }
6037       } else if ((p >= fMax) && (p < fEnd)) {
6038         /* Hybrid faces add new faces and edges */
6039         for (r = 0; r < 2; ++r, ++m) {
6040           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*4     + (cMax                            - cStart)*8     + (p  - fMax)*2                              + r;
6041           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;
6042           remotePointsNew[m].rank  = rrank;
6043         }
6044         localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (fMax                              - fStart)*3     + (cMax                            - cStart)     + (eEnd                                    - eMax)                        + (p  - fMax);
6045         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]);
6046         remotePointsNew[m].rank  = rrank;
6047         ++m;
6048       } else if ((p >= cStart) && (p < cMax)) {
6049         /* Interior cells add new cells, faces, and edges */
6050         for (r = 0; r < 8; ++r, ++m) {
6051           localPointsNew[m]        = cStartNew     + (p  - cStart)*8     + r;
6052           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*8 + r;
6053           remotePointsNew[m].rank  = rrank;
6054         }
6055         for (r = 0; r < 8; ++r, ++m) {
6056           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*4     + (p  - cStart)*8     + r;
6057           remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*4 + (rp - rcStart[n])*8 + r;
6058           remotePointsNew[m].rank  = rrank;
6059         }
6060         localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (fMax                              - fStart)*3     + (p  - cStart)*1     + 0;
6061         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;
6062         remotePointsNew[m].rank  = rrank;
6063         ++m;
6064       } else if ((p >= cMax) && (p < cEnd)) {
6065         /* Hybrid cells add new cells and faces */
6066         for (r = 0; r < 4; ++r, ++m) {
6067           localPointsNew[m]        = cStartNew     + (cMax                            - cStart)*8     + (p  - cMax)*4                            + r;
6068           remotePointsNew[m].index = rcStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth] - rcStart[n])*8 + (rp - rdepthMaxOld[n*(depth+1)+depth])*4 + r;
6069           remotePointsNew[m].rank  = rrank;
6070         }
6071         for (r = 0; r < 3; ++r, ++m) {
6072           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*4     + (cMax                            - cStart)*8     + (fEnd                                          - fMax)*2                              + (p  - cMax)*3                            + r;
6073           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;
6074           remotePointsNew[m].rank  = rrank;
6075         }
6076       }
6077       break;
6078     case REFINER_HEX_3D:
6079     case REFINER_HYBRID_HEX_3D:
6080       if ((p >= vStart) && (p < vEnd)) {
6081         /* Interior vertices stay the same */
6082         localPointsNew[m]        = vStartNew     + (p  - vStart);
6083         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
6084         remotePointsNew[m].rank  = rrank;
6085         ++m;
6086       } else if ((p >= eStart) && (p < eMax)) {
6087         /* Interior edges add new edges and vertex */
6088         for (r = 0; r < 2; ++r, ++m) {
6089           localPointsNew[m]        = eStartNew     + (p  - eStart)*2     + r;
6090           remotePointsNew[m].index = reStartNew[n] + (rp - reStart[n])*2 + r;
6091           remotePointsNew[m].rank  = rrank;
6092         }
6093         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - eStart);
6094         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - reStart[n]);
6095         remotePointsNew[m].rank  = rrank;
6096         ++m;
6097       } else if ((p >= eMax) && (p < eEnd)) {
6098         /* Hybrid edges stay the same */
6099         localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (fMax                              - fStart)*4     + (cMax                            - cStart)*6     + (p  - eMax);
6100         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]);
6101         remotePointsNew[m].rank  = rrank;
6102         ++m;
6103       } else if ((p >= fStart) && (p < fMax)) {
6104         /* Interior faces add new faces, edges, and vertex */
6105         for (r = 0; r < 4; ++r, ++m) {
6106           localPointsNew[m]        = fStartNew     + (p  - fStart)*4     + r;
6107           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*4 + r;
6108           remotePointsNew[m].rank  = rrank;
6109         }
6110         for (r = 0; r < 4; ++r, ++m) {
6111           localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (p  - fStart)*4     + r;
6112           remotePointsNew[m].index = reStartNew[n] + (rdepthMaxOld[n*(depth+1)+1] - reStart[n])*2 + (rp - rfStart[n])*4 + r;
6113           remotePointsNew[m].rank  = rrank;
6114         }
6115         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (eMax                        - eStart)     + (p  - fStart);
6116         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rdepthMaxOld[n*(depth+1)+1] - reStart[n]) + (rp - rfStart[n]);
6117         remotePointsNew[m].rank  = rrank;
6118         ++m;
6119       } else if ((p >= fMax) && (p < fEnd)) {
6120         /* Hybrid faces add new faces and edges */
6121         for (r = 0; r < 2; ++r, ++m) {
6122           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*4     + (cMax                            - cStart)*12     + (p  - fMax)*2                              + r;
6123           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;
6124           remotePointsNew[m].rank  = rrank;
6125         }
6126         localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (fMax                              - fStart)*4     + (cMax                            - cStart)*6     + (eEnd                                    - eMax)                        + (p  - fMax);
6127         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]);
6128         remotePointsNew[m].rank  = rrank;
6129         ++m;
6130       } else if ((p >= cStart) && (p < cMax)) {
6131         /* Interior cells add new cells, faces, edges, and vertex */
6132         for (r = 0; r < 8; ++r, ++m) {
6133           localPointsNew[m]        = cStartNew     + (p  - cStart)*8     + r;
6134           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*8 + r;
6135           remotePointsNew[m].rank  = rrank;
6136         }
6137         for (r = 0; r < 12; ++r, ++m) {
6138           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*4     + (p  - cStart)*12     + r;
6139           remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*4 + (rp - rcStart[n])*12 + r;
6140           remotePointsNew[m].rank  = rrank;
6141         }
6142         for (r = 0; r < 6; ++r, ++m) {
6143           localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (fMax                              - fStart)*4     + (p  - cStart)*6     + r;
6144           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;
6145           remotePointsNew[m].rank  = rrank;
6146         }
6147         for (r = 0; r < 1; ++r, ++m) {
6148           localPointsNew[m]        = vStartNew     + (eMax                        - eStart)     + (fMax                              - fStart)     + (p  - cStart)     + r;
6149           remotePointsNew[m].index = rvStartNew[n] + (rdepthMaxOld[n*(depth+1)+1] - reStart[n]) + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n]) + (rp - rcStart[n]) + r;
6150           remotePointsNew[m].rank  = rrank;
6151         }
6152       } else if ((p >= cMax) && (p < cEnd)) {
6153         /* Hybrid cells add new cells, faces, and edges */
6154         for (r = 0; r < 4; ++r, ++m) {
6155           localPointsNew[m]        = cStartNew     + (cMax                            - cStart)*8     + (p  - cMax)*4                            + r;
6156           remotePointsNew[m].index = rcStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth] - rcStart[n])*8 + (rp - rdepthMaxOld[n*(depth+1)+depth])*4 + r;
6157           remotePointsNew[m].rank  = rrank;
6158         }
6159         for (r = 0; r < 4; ++r, ++m) {
6160           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*4     + (cMax                            - cStart)*12     + (fEnd                                          - fMax)*2                              + (p  - cMax)*4                            + r;
6161           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;
6162           remotePointsNew[m].rank  = rrank;
6163         }
6164         localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (fMax                              - fStart)*4     + (cMax                            - cStart)*6     + (eEnd                                    - eMax)                        + (fEnd                                          - fMax)                              + (p  - cMax);
6165         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]);
6166         remotePointsNew[m].rank  = rrank;
6167         ++m;
6168       }
6169       break;
6170     default:
6171       SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
6172     }
6173   }
6174   if (m != numLeavesNew) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Number of leaf point %d should be %d", m, numLeavesNew);
6175   ierr = ISRestoreIndices(processRanks, &neighbors);CHKERRQ(ierr);
6176   ierr = ISDestroy(&processRanks);CHKERRQ(ierr);
6177   {
6178     PetscSFNode *rp, *rtmp;
6179     PetscInt    *lp, *idx, *ltmp, i;
6180 
6181     /* SF needs sorted leaves to correct calculate Gather */
6182     ierr = PetscMalloc1(numLeavesNew,&idx);CHKERRQ(ierr);
6183     ierr = PetscMalloc1(numLeavesNew, &lp);CHKERRQ(ierr);
6184     ierr = PetscMalloc1(numLeavesNew, &rp);CHKERRQ(ierr);
6185     for (i = 0; i < numLeavesNew; ++i) {
6186       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);
6187       idx[i] = i;
6188     }
6189     ierr = PetscSortIntWithPermutation(numLeavesNew, localPointsNew, idx);CHKERRQ(ierr);
6190     for (i = 0; i < numLeavesNew; ++i) {
6191       lp[i] = localPointsNew[idx[i]];
6192       rp[i] = remotePointsNew[idx[i]];
6193     }
6194     ltmp            = localPointsNew;
6195     localPointsNew  = lp;
6196     rtmp            = remotePointsNew;
6197     remotePointsNew = rp;
6198     ierr = PetscFree(idx);CHKERRQ(ierr);
6199     ierr = PetscFree(ltmp);CHKERRQ(ierr);
6200     ierr = PetscFree(rtmp);CHKERRQ(ierr);
6201   }
6202   ierr = PetscSFSetGraph(sfNew, pEndNew-pStartNew, numLeavesNew, localPointsNew, PETSC_OWN_POINTER, remotePointsNew, PETSC_OWN_POINTER);CHKERRQ(ierr);
6203   ierr = PetscFree5(rdepthSize,rvStartNew,reStartNew,rfStartNew,rcStartNew);CHKERRQ(ierr);
6204   ierr = PetscFree7(depthSizeOld,rdepthSizeOld,rdepthMaxOld,rvStart,reStart,rfStart,rcStart);CHKERRQ(ierr);
6205   PetscFunctionReturn(0);
6206 }
6207 
6208 #undef __FUNCT__
6209 #define __FUNCT__ "CellRefinerCreateLabels"
6210 static PetscErrorCode CellRefinerCreateLabels(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
6211 {
6212   PetscInt       numLabels, l;
6213   PetscInt       depth, newp, cStart, cEnd, cMax, vStart, vEnd, vMax, fStart, fEnd, fMax, eStart, eEnd, eMax, r;
6214   PetscInt       cStartNew = 0, vStartNew = 0, fStartNew = 0, eStartNew = 0;
6215   PetscErrorCode ierr;
6216 
6217   PetscFunctionBegin;
6218   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
6219   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
6220   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
6221   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
6222   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
6223   if (refiner) {ierr = GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);CHKERRQ(ierr);}
6224   ierr = DMPlexGetNumLabels(dm, &numLabels);CHKERRQ(ierr);
6225   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
6226   switch (refiner) {
6227   case REFINER_NOOP:
6228   case REFINER_SIMPLEX_1D:
6229   case REFINER_SIMPLEX_2D:
6230   case REFINER_HEX_2D:
6231   case REFINER_SIMPLEX_3D:
6232   case REFINER_HEX_3D:
6233     break;
6234   case REFINER_HYBRID_SIMPLEX_3D:
6235   case REFINER_HYBRID_HEX_3D:
6236     if (eMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No edge maximum specified in hybrid mesh");
6237   case REFINER_HYBRID_SIMPLEX_2D:
6238   case REFINER_HYBRID_HEX_2D:
6239     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
6240     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
6241     break;
6242   default:
6243     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
6244   }
6245   for (l = 0; l < numLabels; ++l) {
6246     DMLabel         label, labelNew;
6247     const char     *lname;
6248     PetscBool       isDepth;
6249     IS              valueIS;
6250     const PetscInt *values;
6251     PetscInt        numValues, val;
6252 
6253     ierr = DMPlexGetLabelName(dm, l, &lname);CHKERRQ(ierr);
6254     ierr = PetscStrcmp(lname, "depth", &isDepth);CHKERRQ(ierr);
6255     if (isDepth) continue;
6256     ierr = DMPlexCreateLabel(rdm, lname);CHKERRQ(ierr);
6257     ierr = DMPlexGetLabel(dm, lname, &label);CHKERRQ(ierr);
6258     ierr = DMPlexGetLabel(rdm, lname, &labelNew);CHKERRQ(ierr);
6259     ierr = DMLabelGetValueIS(label, &valueIS);CHKERRQ(ierr);
6260     ierr = ISGetLocalSize(valueIS, &numValues);CHKERRQ(ierr);
6261     ierr = ISGetIndices(valueIS, &values);CHKERRQ(ierr);
6262     for (val = 0; val < numValues; ++val) {
6263       IS              pointIS;
6264       const PetscInt *points;
6265       PetscInt        numPoints, n;
6266 
6267       ierr = DMLabelGetStratumIS(label, values[val], &pointIS);CHKERRQ(ierr);
6268       ierr = ISGetLocalSize(pointIS, &numPoints);CHKERRQ(ierr);
6269       ierr = ISGetIndices(pointIS, &points);CHKERRQ(ierr);
6270       /* Ensure refined label is created with same number of strata as
6271        * original (even if no entries here). */
6272       if (!numPoints) {
6273         ierr = DMLabelSetValue(labelNew, 0, values[val]);CHKERRQ(ierr);
6274         ierr = DMLabelClearValue(labelNew, 0, values[val]);CHKERRQ(ierr);
6275       }
6276       for (n = 0; n < numPoints; ++n) {
6277         const PetscInt p = points[n];
6278         switch (refiner) {
6279         case REFINER_SIMPLEX_1D:
6280           if ((p >= vStart) && (p < vEnd)) {
6281             /* Old vertices stay the same */
6282             newp = vStartNew + (p - vStart);
6283             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6284           } else if ((p >= cStart) && (p < cEnd)) {
6285             /* Old cells add new cells and vertex */
6286             newp = vStartNew + (vEnd - vStart) + (p - cStart);
6287             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6288             for (r = 0; r < 2; ++r) {
6289               newp = cStartNew + (p - cStart)*2 + r;
6290               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6291             }
6292           }
6293           break;
6294         case REFINER_SIMPLEX_2D:
6295           if ((p >= vStart) && (p < vEnd)) {
6296             /* Old vertices stay the same */
6297             newp = vStartNew + (p - vStart);
6298             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6299           } else if ((p >= fStart) && (p < fEnd)) {
6300             /* Old faces add new faces and vertex */
6301             newp = vStartNew + (vEnd - vStart) + (p - fStart);
6302             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6303             for (r = 0; r < 2; ++r) {
6304               newp = fStartNew + (p - fStart)*2 + r;
6305               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6306             }
6307           } else if ((p >= cStart) && (p < cEnd)) {
6308             /* Old cells add new cells and interior faces */
6309             for (r = 0; r < 4; ++r) {
6310               newp = cStartNew + (p - cStart)*4 + r;
6311               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6312             }
6313             for (r = 0; r < 3; ++r) {
6314               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*3 + r;
6315               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6316             }
6317           }
6318           break;
6319         case REFINER_HEX_2D:
6320           if ((p >= vStart) && (p < vEnd)) {
6321             /* Old vertices stay the same */
6322             newp = vStartNew + (p - vStart);
6323             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6324           } else if ((p >= fStart) && (p < fEnd)) {
6325             /* Old faces add new faces and vertex */
6326             newp = vStartNew + (vEnd - vStart) + (p - fStart);
6327             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6328             for (r = 0; r < 2; ++r) {
6329               newp = fStartNew + (p - fStart)*2 + r;
6330               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6331             }
6332           } else if ((p >= cStart) && (p < cEnd)) {
6333             /* Old cells add new cells and interior faces and vertex */
6334             for (r = 0; r < 4; ++r) {
6335               newp = cStartNew + (p - cStart)*4 + r;
6336               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6337             }
6338             for (r = 0; r < 4; ++r) {
6339               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*4 + r;
6340               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6341             }
6342             newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (p - cStart);
6343             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6344           }
6345           break;
6346         case REFINER_HYBRID_SIMPLEX_2D:
6347           if ((p >= vStart) && (p < vEnd)) {
6348             /* Old vertices stay the same */
6349             newp = vStartNew + (p - vStart);
6350             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6351           } else if ((p >= fStart) && (p < fMax)) {
6352             /* Old interior faces add new faces and vertex */
6353             newp = vStartNew + (vEnd - vStart) + (p - fStart);
6354             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6355             for (r = 0; r < 2; ++r) {
6356               newp = fStartNew + (p - fStart)*2 + r;
6357               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6358             }
6359           } else if ((p >= fMax) && (p < fEnd)) {
6360             /* Old hybrid faces stay the same */
6361             newp = fStartNew + (fMax - fStart)*2 + (p - fMax);
6362             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6363           } else if ((p >= cStart) && (p < cMax)) {
6364             /* Old interior cells add new cells and interior faces */
6365             for (r = 0; r < 4; ++r) {
6366               newp = cStartNew + (p - cStart)*4 + r;
6367               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6368             }
6369             for (r = 0; r < 3; ++r) {
6370               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*3 + r;
6371               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6372             }
6373           } else if ((p >= cMax) && (p < cEnd)) {
6374             /* Old hybrid cells add new cells and hybrid face */
6375             for (r = 0; r < 2; ++r) {
6376               newp = cStartNew + (cMax - cStart)*4 + (p - cMax)*2 + r;
6377               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6378             }
6379             newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (p - cMax);
6380             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6381           }
6382           break;
6383         case REFINER_HYBRID_HEX_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, interior faces, and vertex */
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 < 4; ++r) {
6407               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*4 + r;
6408               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6409             }
6410             newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (p - cStart);
6411             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6412           } else if ((p >= cMax) && (p < cEnd)) {
6413             /* Old hybrid cells add new cells and hybrid face */
6414             for (r = 0; r < 2; ++r) {
6415               newp = cStartNew + (cMax - cStart)*4 + (p - cMax)*2 + r;
6416               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6417             }
6418             newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*4 + (p - cMax);
6419             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6420           }
6421           break;
6422         case REFINER_SIMPLEX_3D:
6423           if ((p >= vStart) && (p < vEnd)) {
6424             /* Old vertices stay the same */
6425             newp = vStartNew + (p - vStart);
6426             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6427           } else if ((p >= eStart) && (p < eEnd)) {
6428             /* Old edges add new edges and vertex */
6429             for (r = 0; r < 2; ++r) {
6430               newp = eStartNew + (p - eStart)*2 + r;
6431               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6432             }
6433             newp = vStartNew + (vEnd - vStart) + (p - eStart);
6434             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6435           } else if ((p >= fStart) && (p < fEnd)) {
6436             /* Old faces add new faces and edges */
6437             for (r = 0; r < 4; ++r) {
6438               newp = fStartNew + (p - fStart)*4 + r;
6439               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6440             }
6441             for (r = 0; r < 3; ++r) {
6442               newp = eStartNew + (eEnd - eStart)*2 + (p - fStart)*3 + r;
6443               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6444             }
6445           } else if ((p >= cStart) && (p < cEnd)) {
6446             /* Old cells add new cells and interior faces and edges */
6447             for (r = 0; r < 8; ++r) {
6448               newp = cStartNew + (p - cStart)*8 + r;
6449               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6450             }
6451             for (r = 0; r < 8; ++r) {
6452               newp = fStartNew + (fEnd - fStart)*4 + (p - cStart)*8 + r;
6453               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6454             }
6455             for (r = 0; r < 1; ++r) {
6456               newp = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (p - cStart)*1 + r;
6457               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6458             }
6459           }
6460           break;
6461         case REFINER_HYBRID_SIMPLEX_3D:
6462           if ((p >= vStart) && (p < vEnd)) {
6463             /* Interior vertices stay the same */
6464             newp = vStartNew + (p - vStart);
6465             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6466           } else if ((p >= eStart) && (p < eMax)) {
6467             /* Interior edges add new edges and vertex */
6468             for (r = 0; r < 2; ++r) {
6469               newp = eStartNew + (p - eStart)*2 + r;
6470               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6471             }
6472             newp = vStartNew + (vEnd - vStart) + (p - eStart);
6473             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6474           } else if ((p >= eMax) && (p < eEnd)) {
6475             /* Hybrid edges stay the same */
6476             newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (p - eMax);
6477             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6478           } else if ((p >= fStart) && (p < fMax)) {
6479             /* Interior faces add new faces and edges */
6480             for (r = 0; r < 4; ++r) {
6481               newp = fStartNew + (p - fStart)*4 + r;
6482               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6483             }
6484             for (r = 0; r < 3; ++r) {
6485               newp = eStartNew + (eMax - eStart)*2 + (p - fStart)*3 + r;
6486               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6487             }
6488           } else if ((p >= fMax) && (p < fEnd)) {
6489             /* Hybrid faces add new faces and edges */
6490             for (r = 0; r < 2; ++r) {
6491               newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (p - fMax)*2 + r;
6492               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6493             }
6494             newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (p - fMax);
6495             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6496           } else if ((p >= cStart) && (p < cMax)) {
6497             /* Interior cells add new cells, faces, and edges */
6498             for (r = 0; r < 8; ++r) {
6499               newp = cStartNew + (p - cStart)*8 + r;
6500               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6501             }
6502             for (r = 0; r < 8; ++r) {
6503               newp = fStartNew + (fMax - fStart)*4 + (p - cStart)*8 + r;
6504               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6505             }
6506             newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (p - cStart);
6507             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6508           } else if ((p >= cMax) && (p < cEnd)) {
6509             /* Hybrid cells add new cells and faces */
6510             for (r = 0; r < 4; ++r) {
6511               newp = cStartNew + (cMax - cStart)*8 + (p - cMax)*4 + r;
6512               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6513             }
6514             for (r = 0; r < 3; ++r) {
6515               newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (p - cMax)*3 + r;
6516               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6517             }
6518           }
6519           break;
6520         case REFINER_HEX_3D:
6521           if ((p >= vStart) && (p < vEnd)) {
6522             /* Old vertices stay the same */
6523             newp = vStartNew + (p - vStart);
6524             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6525           } else if ((p >= eStart) && (p < eEnd)) {
6526             /* Old edges add new edges and vertex */
6527             for (r = 0; r < 2; ++r) {
6528               newp = eStartNew + (p - eStart)*2 + r;
6529               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6530             }
6531             newp = vStartNew + (vEnd - vStart) + (p - eStart);
6532             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6533           } else if ((p >= fStart) && (p < fEnd)) {
6534             /* Old faces add new faces, edges, and vertex */
6535             for (r = 0; r < 4; ++r) {
6536               newp = fStartNew + (p - fStart)*4 + r;
6537               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6538             }
6539             for (r = 0; r < 4; ++r) {
6540               newp = eStartNew + (eEnd - eStart)*2 + (p - fStart)*4 + r;
6541               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6542             }
6543             newp = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (p - fStart);
6544             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6545           } else if ((p >= cStart) && (p < cEnd)) {
6546             /* Old cells add new cells, faces, edges, and vertex */
6547             for (r = 0; r < 8; ++r) {
6548               newp = cStartNew + (p - cStart)*8 + r;
6549               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6550             }
6551             for (r = 0; r < 12; ++r) {
6552               newp = fStartNew + (fEnd - fStart)*4 + (p - cStart)*12 + r;
6553               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6554             }
6555             for (r = 0; r < 6; ++r) {
6556               newp = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*4 + (p - cStart)*6 + r;
6557               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6558             }
6559             newp = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (fEnd - fStart) + (p - cStart);
6560             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6561           }
6562           break;
6563         case REFINER_HYBRID_HEX_3D:
6564           if ((p >= vStart) && (p < vEnd)) {
6565             /* Interior vertices stay the same */
6566             newp = vStartNew + (p - vStart);
6567             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6568           } else if ((p >= eStart) && (p < eMax)) {
6569             /* Interior edges add new edges and vertex */
6570             for (r = 0; r < 2; ++r) {
6571               newp = eStartNew + (p - eStart)*2 + r;
6572               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6573             }
6574             newp = vStartNew + (vEnd - vStart) + (p - eStart);
6575             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6576           } else if ((p >= eMax) && (p < eEnd)) {
6577             /* Hybrid edges stay the same */
6578             newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (p - eMax);
6579             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6580           } else if ((p >= fStart) && (p < fMax)) {
6581             /* Interior faces add new faces, edges, and vertex */
6582             for (r = 0; r < 4; ++r) {
6583               newp = fStartNew + (p - fStart)*4 + r;
6584               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6585             }
6586             for (r = 0; r < 4; ++r) {
6587               newp = eStartNew + (eMax - eStart)*2 + (p - fStart)*4 + r;
6588               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6589             }
6590             newp = vStartNew + (vEnd - vStart) + (eMax - eStart) + (p - fStart);
6591             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6592           } else if ((p >= fMax) && (p < fEnd)) {
6593             /* Hybrid faces add new faces and edges */
6594             for (r = 0; r < 2; ++r) {
6595               newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (p - fMax)*2 + r;
6596               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6597             }
6598             newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (p - fMax);
6599             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6600           } else if ((p >= cStart) && (p < cMax)) {
6601             /* Interior cells add new cells, faces, edges, and vertex */
6602             for (r = 0; r < 8; ++r) {
6603               newp = cStartNew + (p - cStart)*8 + r;
6604               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6605             }
6606             for (r = 0; r < 12; ++r) {
6607               newp = fStartNew + (fMax - fStart)*4 + (p - cStart)*12 + r;
6608               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6609             }
6610             for (r = 0; r < 6; ++r) {
6611               newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (p - cStart)*6 + r;
6612               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6613             }
6614             newp = vStartNew + (vEnd - vStart) + (eMax - eStart) + (fMax - fStart) + (p - cStart);
6615             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6616           } else if ((p >= cMax) && (p < cEnd)) {
6617             /* Hybrid cells add new cells, faces, and edges */
6618             for (r = 0; r < 4; ++r) {
6619               newp = cStartNew + (cMax - cStart)*8 + (p - cMax)*4 + r;
6620               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6621             }
6622             for (r = 0; r < 4; ++r) {
6623               newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd - fMax)*2 + (p - cMax)*4 + r;
6624               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6625             }
6626             newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (fEnd - fMax) + (p - cMax);
6627             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6628           }
6629           break;
6630         default:
6631           SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
6632         }
6633       }
6634       ierr = ISRestoreIndices(pointIS, &points);CHKERRQ(ierr);
6635       ierr = ISDestroy(&pointIS);CHKERRQ(ierr);
6636     }
6637     ierr = ISRestoreIndices(valueIS, &values);CHKERRQ(ierr);
6638     ierr = ISDestroy(&valueIS);CHKERRQ(ierr);
6639     if (0) {
6640       ierr = PetscViewerASCIISynchronizedAllow(PETSC_VIEWER_STDOUT_WORLD, PETSC_TRUE);CHKERRQ(ierr);
6641       ierr = DMLabelView(labelNew, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
6642       ierr = PetscViewerFlush(PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
6643     }
6644   }
6645   PetscFunctionReturn(0);
6646 }
6647 
6648 #undef __FUNCT__
6649 #define __FUNCT__ "DMPlexRefineUniform_Internal"
6650 /* This will only work for interpolated meshes */
6651 PetscErrorCode DMPlexRefineUniform_Internal(DM dm, CellRefiner cellRefiner, DM *dmRefined)
6652 {
6653   DM             rdm;
6654   PetscInt      *depthSize;
6655   PetscInt       dim, depth = 0, d, pStart = 0, pEnd = 0;
6656   PetscErrorCode ierr;
6657 
6658   PetscFunctionBegin;
6659   ierr = DMCreate(PetscObjectComm((PetscObject)dm), &rdm);CHKERRQ(ierr);
6660   ierr = DMSetType(rdm, DMPLEX);CHKERRQ(ierr);
6661   ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr);
6662   ierr = DMSetDimension(rdm, dim);CHKERRQ(ierr);
6663   /* Calculate number of new points of each depth */
6664   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
6665   if (dim != depth) SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "Mesh must be interpolated for regular refinement");
6666   ierr = PetscMalloc1(depth+1, &depthSize);CHKERRQ(ierr);
6667   ierr = PetscMemzero(depthSize, (depth+1) * sizeof(PetscInt));CHKERRQ(ierr);
6668   ierr = CellRefinerGetSizes(cellRefiner, dm, depthSize);CHKERRQ(ierr);
6669   /* Step 1: Set chart */
6670   for (d = 0; d <= depth; ++d) pEnd += depthSize[d];
6671   ierr = DMPlexSetChart(rdm, pStart, pEnd);CHKERRQ(ierr);
6672   /* Step 2: Set cone/support sizes */
6673   ierr = CellRefinerSetConeSizes(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
6674   /* Step 3: Setup refined DM */
6675   ierr = DMSetUp(rdm);CHKERRQ(ierr);
6676   /* Step 4: Set cones and supports */
6677   ierr = CellRefinerSetCones(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
6678   /* Step 5: Stratify */
6679   ierr = DMPlexStratify(rdm);CHKERRQ(ierr);
6680   /* Step 6: Create pointSF */
6681   ierr = CellRefinerCreateSF(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
6682   /* Step 7: Set coordinates for vertices */
6683   ierr = CellRefinerSetCoordinates(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
6684   /* Step 8: Create labels */
6685   ierr = CellRefinerCreateLabels(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
6686   ierr = PetscFree(depthSize);CHKERRQ(ierr);
6687 
6688   *dmRefined = rdm;
6689   PetscFunctionReturn(0);
6690 }
6691 
6692 #undef __FUNCT__
6693 #define __FUNCT__ "DMPlexCreateCoarsePointIS"
6694 /*@
6695   DMPlexCreateCoarsePointIS - Creates an IS covering the coarse DM chart with the fine points as data
6696 
6697   Input Parameter:
6698 . dm - The coarse DM
6699 
6700   Output Parameter:
6701 . fpointIS - The IS of all the fine points which exist in the original coarse mesh
6702 
6703   Level: developer
6704 
6705 .seealso: DMRefine(), DMPlexSetRefinementUniform(), DMPlexCreateSubpointIS()
6706 @*/
6707 PetscErrorCode DMPlexCreateCoarsePointIS(DM dm, IS *fpointIS)
6708 {
6709   CellRefiner    cellRefiner;
6710   PetscInt      *depthSize, *fpoints;
6711   PetscInt       cStartNew = 0, vStartNew = 0, fStartNew = 0, eStartNew = 0;
6712   PetscInt       depth, pStart, pEnd, p, vStart, vEnd, v;
6713   PetscErrorCode ierr;
6714 
6715   PetscFunctionBegin;
6716   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
6717   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
6718   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
6719   ierr = DMPlexGetCellRefiner_Internal(dm, &cellRefiner);CHKERRQ(ierr);
6720   ierr = PetscMalloc1(depth+1, &depthSize);CHKERRQ(ierr);
6721   ierr = CellRefinerGetSizes(cellRefiner, dm, depthSize);CHKERRQ(ierr);
6722   if (cellRefiner) {ierr = GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);CHKERRQ(ierr);}
6723   ierr = PetscMalloc1(pEnd-pStart,&fpoints);CHKERRQ(ierr);
6724   for (p = 0; p < pEnd-pStart; ++p) fpoints[p] = -1;
6725   switch (cellRefiner) {
6726   case REFINER_SIMPLEX_1D:
6727   case REFINER_SIMPLEX_2D:
6728   case REFINER_HYBRID_SIMPLEX_2D:
6729   case REFINER_HEX_2D:
6730   case REFINER_HYBRID_HEX_2D:
6731   case REFINER_SIMPLEX_3D:
6732   case REFINER_HYBRID_SIMPLEX_3D:
6733   case REFINER_HEX_3D:
6734   case REFINER_HYBRID_HEX_3D:
6735     for (v = vStart; v < vEnd; ++v) fpoints[v-pStart] = vStartNew + (v - vStart);
6736     break;
6737   default:
6738     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", cellRefiner);
6739   }
6740   ierr = ISCreateGeneral(PETSC_COMM_SELF, pEnd-pStart, fpoints, PETSC_OWN_POINTER, fpointIS);CHKERRQ(ierr);
6741   ierr = PetscFree(depthSize);CHKERRQ(ierr);
6742   PetscFunctionReturn(0);
6743 }
6744 
6745 #undef __FUNCT__
6746 #define __FUNCT__ "DMPlexSetRefinementUniform"
6747 /*@
6748   DMPlexSetRefinementUniform - Set the flag for uniform refinement
6749 
6750   Input Parameters:
6751 + dm - The DM
6752 - refinementUniform - The flag for uniform refinement
6753 
6754   Level: developer
6755 
6756 .seealso: DMRefine(), DMPlexGetRefinementUniform(), DMPlexGetRefinementLimit(), DMPlexSetRefinementLimit()
6757 @*/
6758 PetscErrorCode DMPlexSetRefinementUniform(DM dm, PetscBool refinementUniform)
6759 {
6760   DM_Plex *mesh = (DM_Plex*) dm->data;
6761 
6762   PetscFunctionBegin;
6763   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6764   mesh->refinementUniform = refinementUniform;
6765   PetscFunctionReturn(0);
6766 }
6767 
6768 #undef __FUNCT__
6769 #define __FUNCT__ "DMPlexGetRefinementUniform"
6770 /*@
6771   DMPlexGetRefinementUniform - Retrieve the flag for uniform refinement
6772 
6773   Input Parameter:
6774 . dm - The DM
6775 
6776   Output Parameter:
6777 . refinementUniform - The flag for uniform refinement
6778 
6779   Level: developer
6780 
6781 .seealso: DMRefine(), DMPlexSetRefinementUniform(), DMPlexGetRefinementLimit(), DMPlexSetRefinementLimit()
6782 @*/
6783 PetscErrorCode DMPlexGetRefinementUniform(DM dm, PetscBool *refinementUniform)
6784 {
6785   DM_Plex *mesh = (DM_Plex*) dm->data;
6786 
6787   PetscFunctionBegin;
6788   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6789   PetscValidPointer(refinementUniform,  2);
6790   *refinementUniform = mesh->refinementUniform;
6791   PetscFunctionReturn(0);
6792 }
6793 
6794 #undef __FUNCT__
6795 #define __FUNCT__ "DMPlexSetRefinementLimit"
6796 /*@
6797   DMPlexSetRefinementLimit - Set the maximum cell volume for refinement
6798 
6799   Input Parameters:
6800 + dm - The DM
6801 - refinementLimit - The maximum cell volume in the refined mesh
6802 
6803   Level: developer
6804 
6805 .seealso: DMRefine(), DMPlexGetRefinementLimit(), DMPlexGetRefinementUniform(), DMPlexSetRefinementUniform()
6806 @*/
6807 PetscErrorCode DMPlexSetRefinementLimit(DM dm, PetscReal refinementLimit)
6808 {
6809   DM_Plex *mesh = (DM_Plex*) dm->data;
6810 
6811   PetscFunctionBegin;
6812   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6813   mesh->refinementLimit = refinementLimit;
6814   PetscFunctionReturn(0);
6815 }
6816 
6817 #undef __FUNCT__
6818 #define __FUNCT__ "DMPlexGetRefinementLimit"
6819 /*@
6820   DMPlexGetRefinementLimit - Retrieve the maximum cell volume for refinement
6821 
6822   Input Parameter:
6823 . dm - The DM
6824 
6825   Output Parameter:
6826 . refinementLimit - The maximum cell volume in the refined mesh
6827 
6828   Level: developer
6829 
6830 .seealso: DMRefine(), DMPlexSetRefinementLimit(), DMPlexGetRefinementUniform(), DMPlexSetRefinementUniform()
6831 @*/
6832 PetscErrorCode DMPlexGetRefinementLimit(DM dm, PetscReal *refinementLimit)
6833 {
6834   DM_Plex *mesh = (DM_Plex*) dm->data;
6835 
6836   PetscFunctionBegin;
6837   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6838   PetscValidPointer(refinementLimit,  2);
6839   /* if (mesh->refinementLimit < 0) = getMaxVolume()/2.0; */
6840   *refinementLimit = mesh->refinementLimit;
6841   PetscFunctionReturn(0);
6842 }
6843 
6844 #undef __FUNCT__
6845 #define __FUNCT__ "DMPlexGetCellRefiner_Internal"
6846 PetscErrorCode DMPlexGetCellRefiner_Internal(DM dm, CellRefiner *cellRefiner)
6847 {
6848   PetscInt       dim, cStart, cEnd, coneSize, cMax;
6849   PetscErrorCode ierr;
6850 
6851   PetscFunctionBegin;
6852   ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr);
6853   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
6854   if (cEnd <= cStart) {*cellRefiner = REFINER_NOOP; PetscFunctionReturn(0);}
6855   ierr = DMPlexGetConeSize(dm, cStart, &coneSize);CHKERRQ(ierr);
6856   ierr = DMPlexGetHybridBounds(dm, &cMax, NULL, NULL, NULL);CHKERRQ(ierr);
6857   switch (dim) {
6858   case 1:
6859     switch (coneSize) {
6860     case 2:
6861       *cellRefiner = REFINER_SIMPLEX_1D;
6862       break;
6863     default:
6864       SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown coneSize %d in dimension %d for cell refiner", coneSize, dim);
6865     }
6866     break;
6867   case 2:
6868     switch (coneSize) {
6869     case 3:
6870       if (cMax >= 0) *cellRefiner = REFINER_HYBRID_SIMPLEX_2D;
6871       else *cellRefiner = REFINER_SIMPLEX_2D;
6872       break;
6873     case 4:
6874       if (cMax >= 0) *cellRefiner = REFINER_HYBRID_HEX_2D;
6875       else *cellRefiner = REFINER_HEX_2D;
6876       break;
6877     default:
6878       SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown coneSize %d in dimension %d for cell refiner", coneSize, dim);
6879     }
6880     break;
6881   case 3:
6882     switch (coneSize) {
6883     case 4:
6884       if (cMax >= 0) *cellRefiner = REFINER_HYBRID_SIMPLEX_3D;
6885       else *cellRefiner = REFINER_SIMPLEX_3D;
6886       break;
6887     case 6:
6888       if (cMax >= 0) *cellRefiner = REFINER_HYBRID_HEX_3D;
6889       else *cellRefiner = REFINER_HEX_3D;
6890       break;
6891     default:
6892       SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown coneSize %d in dimension %d for cell refiner", coneSize, dim);
6893     }
6894     break;
6895   default:
6896     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown dimension %d for cell refiner", dim);
6897   }
6898   PetscFunctionReturn(0);
6899 }
6900