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