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