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