xref: /petsc/src/dm/impls/plex/plexrefine.c (revision b598a9d59955a586d38f5d29f8b91f1c9b565fe0)
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], o, of;
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       o = ornt[0] < 0 ? -1 : 1;
2474       for (r = 0; r < 3; ++r) {
2475         coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetTriSubface_Static(ornt[0], r);
2476         orntNew[0] = ornt[0];
2477         coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetTriSubface_Static(ornt[1], r);
2478         orntNew[1] = ornt[1];
2479         of = fornt[GetTriEdge_Static(ornt[0], (r+2)%3)] < 0 ? -1 : 1;
2480         coneNew[2] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (cone[2+GetTriEdge_Static(ornt[0], (r+2)%3)] - fMax)*2 + (o*of < 0 ? 0 : 1);
2481         orntNew[2] = 0;
2482         of = fornt[GetTriEdge_Static(ornt[0], r)]       < 0 ? -1 : 1;
2483         coneNew[3] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (cone[2+GetTriEdge_Static(ornt[0], r)]       - fMax)*2 + (o*of < 0 ? 1 : 0);
2484         orntNew[3] = 0;
2485         coneNew[4] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (c - cMax)*3 + GetTriSubface_Static(ornt[0], r);
2486         orntNew[4] = 0;
2487         ierr = DMPlexSetCone(rdm, newp+r, coneNew);CHKERRQ(ierr);
2488         ierr = DMPlexSetConeOrientation(rdm, newp+r, orntNew);CHKERRQ(ierr);
2489 #if 1
2490         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);
2491         for (p = 0; p < 2; ++p) {
2492           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);
2493         }
2494         for (p = 2; p < 5; ++p) {
2495           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);
2496         }
2497 #endif
2498       }
2499       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + 3;
2500       orntNew[0] = 0;
2501       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + 3;
2502       orntNew[1] = 0;
2503       coneNew[2] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (c - cMax)*3 + 0;
2504       orntNew[2] = 0;
2505       coneNew[3] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (c - cMax)*3 + 1;
2506       orntNew[3] = 0;
2507       coneNew[4] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (c - cMax)*3 + 2;
2508       orntNew[4] = 0;
2509       ierr = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
2510       ierr = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
2511 #if 1
2512       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);
2513       for (p = 0; p < 2; ++p) {
2514         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);
2515       }
2516       for (p = 2; p < 5; ++p) {
2517         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);
2518       }
2519 #endif
2520     }
2521     /* Split faces have 3 edges and the same cells as the parent */
2522     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
2523     ierr = PetscMalloc1((2 + maxSupportSize*2), &supportRef);CHKERRQ(ierr);
2524     for (f = fStart; f < fMax; ++f) {
2525       const PetscInt  newp = fStartNew + (f - fStart)*4;
2526       const PetscInt *cone, *ornt, *support;
2527       PetscInt        coneNew[3], orntNew[3], coneSize, supportSize, s;
2528 
2529       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
2530       ierr = DMPlexGetConeOrientation(dm, f, &ornt);CHKERRQ(ierr);
2531       /* A triangle */
2532       coneNew[0] = eStartNew + (cone[0] - eStart)*2 + (ornt[0] < 0 ? 1 : 0);
2533       orntNew[0] = ornt[0];
2534       coneNew[1] = eStartNew + (eMax    - eStart)*2 + (f - fStart)*3 + 2;
2535       orntNew[1] = -2;
2536       coneNew[2] = eStartNew + (cone[2] - eStart)*2 + (ornt[2] < 0 ? 0 : 1);
2537       orntNew[2] = ornt[2];
2538       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
2539       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
2540 #if 1
2541       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);
2542       for (p = 0; p < 3; ++p) {
2543         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);
2544       }
2545 #endif
2546       /* B triangle */
2547       coneNew[0] = eStartNew + (cone[0] - eStart)*2 + (ornt[0] < 0 ? 0 : 1);
2548       orntNew[0] = ornt[0];
2549       coneNew[1] = eStartNew + (cone[1] - eStart)*2 + (ornt[1] < 0 ? 1 : 0);
2550       orntNew[1] = ornt[1];
2551       coneNew[2] = eStartNew + (eMax    - eStart)*2 + (f - fStart)*3 + 0;
2552       orntNew[2] = -2;
2553       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
2554       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
2555 #if 1
2556       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);
2557       for (p = 0; p < 3; ++p) {
2558         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);
2559       }
2560 #endif
2561       /* C triangle */
2562       coneNew[0] = eStartNew + (eMax    - eStart)*2 + (f - fStart)*3 + 1;
2563       orntNew[0] = -2;
2564       coneNew[1] = eStartNew + (cone[1] - eStart)*2 + (ornt[1] < 0 ? 0 : 1);
2565       orntNew[1] = ornt[1];
2566       coneNew[2] = eStartNew + (cone[2] - eStart)*2 + (ornt[2] < 0 ? 1 : 0);
2567       orntNew[2] = ornt[2];
2568       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
2569       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
2570 #if 1
2571       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);
2572       for (p = 0; p < 3; ++p) {
2573         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);
2574       }
2575 #endif
2576       /* D triangle */
2577       coneNew[0] = eStartNew + (eMax    - eStart)*2 + (f - fStart)*3 + 0;
2578       orntNew[0] = 0;
2579       coneNew[1] = eStartNew + (eMax    - eStart)*2 + (f - fStart)*3 + 1;
2580       orntNew[1] = 0;
2581       coneNew[2] = eStartNew + (eMax    - eStart)*2 + (f - fStart)*3 + 2;
2582       orntNew[2] = 0;
2583       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
2584       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
2585 #if 1
2586       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);
2587       for (p = 0; p < 3; ++p) {
2588         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);
2589       }
2590 #endif
2591       ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
2592       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
2593       for (r = 0; r < 4; ++r) {
2594         for (s = 0; s < supportSize; ++s) {
2595           PetscInt subf;
2596           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
2597           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
2598           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
2599           for (c = 0; c < coneSize; ++c) {
2600             if (cone[c] == f) break;
2601           }
2602           subf = GetTriSubfaceInverse_Static(ornt[c], r);
2603           if (support[s] < cMax) {
2604             supportRef[s] = cStartNew + (support[s] - cStart)*8 + (r==3 ? (c+2)%4 + 4 : faces[c*3+subf]);
2605           } else {
2606             supportRef[s] = cStartNew + (cMax - cStart)*8 + (support[s] - cMax)*4 + (r==3 ? r : subf);
2607           }
2608         }
2609         ierr = DMPlexSetSupport(rdm, newp+r, supportRef);CHKERRQ(ierr);
2610 #if 1
2611         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);
2612         for (p = 0; p < supportSize; ++p) {
2613           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);
2614         }
2615 #endif
2616       }
2617     }
2618     /* Interior cell faces have 3 edges and 2 cells */
2619     for (c = cStart; c < cMax; ++c) {
2620       PetscInt        newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*8;
2621       const PetscInt *cone, *ornt;
2622       PetscInt        coneNew[3], orntNew[3];
2623       PetscInt        supportNew[2];
2624 
2625       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
2626       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
2627       /* Face A: {c, a, d} */
2628       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*3 + GetTetSomething_Static(ornt[0], 2);
2629       orntNew[0] = ornt[0] < 0 ? -2 : 0;
2630       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*3 + GetTetSomething_Static(ornt[1], 2);
2631       orntNew[1] = ornt[1] < 0 ? -2 : 0;
2632       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*3 + GetTetSomething_Static(ornt[2], 2);
2633       orntNew[2] = ornt[2] < 0 ? -2 : 0;
2634       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2635       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
2636 #if 1
2637       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
2638       for (p = 0; p < 3; ++p) {
2639         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);
2640       }
2641 #endif
2642       supportNew[0] = (c - cStart)*8 + 0;
2643       supportNew[1] = (c - cStart)*8 + 0+4;
2644       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
2645 #if 1
2646       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
2647       for (p = 0; p < 2; ++p) {
2648         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);
2649       }
2650 #endif
2651       ++newp;
2652       /* Face B: {a, b, e} */
2653       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*3 + GetTetSomething_Static(ornt[0], 0);
2654       orntNew[0] = ornt[0] < 0 ? -2 : 0;
2655       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*3 + GetTetSomething_Static(ornt[3], 0);
2656       orntNew[1] = ornt[3] < 0 ? -2 : 0;
2657       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*3 + GetTetSomething_Static(ornt[1], 1);
2658       orntNew[2] = ornt[1] < 0 ? -2 : 0;
2659       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2660       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
2661 #if 1
2662       if ((newp+1 < fStartNew) || (newp+1 >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp+1, fStartNew, fMaxNew);
2663       for (p = 0; p < 3; ++p) {
2664         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);
2665       }
2666 #endif
2667       supportNew[0] = (c - cStart)*8 + 1;
2668       supportNew[1] = (c - cStart)*8 + 1+4;
2669       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
2670 #if 1
2671       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
2672       for (p = 0; p < 2; ++p) {
2673         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);
2674       }
2675 #endif
2676       ++newp;
2677       /* Face C: {c, f, b} */
2678       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*3 + GetTetSomething_Static(ornt[2], 0);
2679       orntNew[0] = ornt[2] < 0 ? -2 : 0;
2680       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*3 + GetTetSomething_Static(ornt[3], 2);
2681       orntNew[1] = ornt[3] < 0 ? -2 : 0;
2682       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*3 + GetTetSomething_Static(ornt[0], 1);
2683       orntNew[2] = ornt[0] < 0 ? -2 : 0;
2684       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2685       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
2686 #if 1
2687       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
2688       for (p = 0; p < 3; ++p) {
2689         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);
2690       }
2691 #endif
2692       supportNew[0] = (c - cStart)*8 + 2;
2693       supportNew[1] = (c - cStart)*8 + 2+4;
2694       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
2695 #if 1
2696       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
2697       for (p = 0; p < 2; ++p) {
2698         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);
2699       }
2700 #endif
2701       ++newp;
2702       /* Face D: {d, e, f} */
2703       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*3 + GetTetSomething_Static(ornt[1], 0);
2704       orntNew[0] = ornt[1] < 0 ? -2 : 0;
2705       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*3 + GetTetSomething_Static(ornt[3], 1);
2706       orntNew[1] = ornt[3] < 0 ? -2 : 0;
2707       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*3 + GetTetSomething_Static(ornt[2], 1);
2708       orntNew[2] = ornt[2] < 0 ? -2 : 0;
2709       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2710       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
2711 #if 1
2712       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
2713       for (p = 0; p < 3; ++p) {
2714         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);
2715       }
2716 #endif
2717       supportNew[0] = (c - cStart)*8 + 3;
2718       supportNew[1] = (c - cStart)*8 + 3+4;
2719       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
2720 #if 1
2721       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
2722       for (p = 0; p < 2; ++p) {
2723         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);
2724       }
2725 #endif
2726       ++newp;
2727       /* Face E: {d, f, a} */
2728       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*3 + GetTetSomething_Static(ornt[2], 1);
2729       orntNew[0] = ornt[2] < 0 ? 0 : -2;
2730       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart);
2731       orntNew[1] = -2;
2732       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*3 + GetTetSomething_Static(ornt[1], 2);
2733       orntNew[2] = ornt[1] < 0 ? -2 : 0;
2734       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2735       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
2736 #if 1
2737       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
2738       for (p = 0; p < 3; ++p) {
2739         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);
2740       }
2741 #endif
2742       supportNew[0] = (c - cStart)*8 + 0+4;
2743       supportNew[1] = (c - cStart)*8 + 3+4;
2744       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
2745 #if 1
2746       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
2747       for (p = 0; p < 2; ++p) {
2748         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);
2749       }
2750 #endif
2751       ++newp;
2752       /* Face F: {c, a, f} */
2753       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*3 + GetTetSomething_Static(ornt[0], 2);
2754       orntNew[0] = ornt[0] < 0 ? -2 : 0;
2755       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart);
2756       orntNew[1] = 0;
2757       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*3 + GetTetSomething_Static(ornt[2], 0);
2758       orntNew[2] = ornt[2] < 0 ? 0 : -2;
2759       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2760       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
2761 #if 1
2762       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
2763       for (p = 0; p < 3; ++p) {
2764         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);
2765       }
2766 #endif
2767       supportNew[0] = (c - cStart)*8 + 0+4;
2768       supportNew[1] = (c - cStart)*8 + 2+4;
2769       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
2770 #if 1
2771       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
2772       for (p = 0; p < 2; ++p) {
2773         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);
2774       }
2775 #endif
2776       ++newp;
2777       /* Face G: {e, a, f} */
2778       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*3 + GetTetSomething_Static(ornt[1], 1);
2779       orntNew[0] = ornt[1] < 0 ? -2 : 0;
2780       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart);
2781       orntNew[1] = 0;
2782       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*3 + GetTetSomething_Static(ornt[3], 1);
2783       orntNew[2] = ornt[3] < 0 ? 0 : -2;
2784       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2785       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
2786 #if 1
2787       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
2788       for (p = 0; p < 3; ++p) {
2789         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);
2790       }
2791 #endif
2792       supportNew[0] = (c - cStart)*8 + 1+4;
2793       supportNew[1] = (c - cStart)*8 + 3+4;
2794       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
2795 #if 1
2796       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
2797       for (p = 0; p < 2; ++p) {
2798         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);
2799       }
2800 #endif
2801       ++newp;
2802       /* Face H: {a, b, f} */
2803       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*3 + GetTetSomething_Static(ornt[0], 0);
2804       orntNew[0] = ornt[0] < 0 ? -2 : 0;
2805       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*3 + GetTetSomething_Static(ornt[3], 2);
2806       orntNew[1] = ornt[3] < 0 ? 0 : -2;
2807       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart);
2808       orntNew[2] = -2;
2809       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2810       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
2811 #if 1
2812       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
2813       for (p = 0; p < 3; ++p) {
2814         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);
2815       }
2816 #endif
2817       supportNew[0] = (c - cStart)*8 + 1+4;
2818       supportNew[1] = (c - cStart)*8 + 2+4;
2819       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
2820 #if 1
2821       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
2822       for (p = 0; p < 2; ++p) {
2823         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);
2824       }
2825 #endif
2826       ++newp;
2827     }
2828     /* Hybrid split faces have 4 edges and same cells */
2829     for (f = fMax; f < fEnd; ++f) {
2830       const PetscInt *cone, *ornt, *support;
2831       PetscInt        coneNew[4], orntNew[4];
2832       PetscInt        supportNew[2], size, s, c;
2833 
2834       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
2835       ierr = DMPlexGetConeOrientation(dm, f, &ornt);CHKERRQ(ierr);
2836       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
2837       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
2838       for (r = 0; r < 2; ++r) {
2839         const PetscInt newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (f - fMax)*2 + r;
2840 
2841         coneNew[0]   = eStartNew + (cone[0] - eStart)*2 + (ornt[0] < 0 ? 1-r : r);
2842         orntNew[0]   = ornt[0];
2843         coneNew[1]   = eStartNew + (cone[1] - eStart)*2 + (ornt[1] < 0 ? 1-r : r);
2844         orntNew[1]   = ornt[1];
2845         coneNew[2+r] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (cone[2+r] - eMax);
2846         orntNew[2+r] = 0;
2847         coneNew[3-r] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (eEnd      - eMax) + (f - fMax);
2848         orntNew[3-r] = 0;
2849         ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2850         ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
2851 #if 1
2852         if ((newp < fMaxNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid face [%d, %d)", newp, fMaxNew, fEndNew);
2853         for (p = 0; p < 2; ++p) {
2854           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);
2855         }
2856         for (p = 2; p < 4; ++p) {
2857           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);
2858         }
2859 #endif
2860         for (s = 0; s < size; ++s) {
2861           const PetscInt *coneCell, *orntCell, *fornt;
2862           PetscInt        o, of;
2863 
2864           ierr = DMPlexGetCone(dm, support[s], &coneCell);CHKERRQ(ierr);
2865           ierr = DMPlexGetConeOrientation(dm, support[s], &orntCell);CHKERRQ(ierr);
2866           o = orntCell[0] < 0 ? -1 : 1;
2867           for (c = 2; c < 5; ++c) if (coneCell[c] == f) break;
2868           if (c >= 5) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Could not find face %d in cone of cell %d", f, support[s]);
2869           ierr = DMPlexGetConeOrientation(dm, coneCell[0], &fornt);CHKERRQ(ierr);
2870           of = fornt[c-2] < 0 ? -1 : 1;
2871           supportNew[s] = cStartNew + (cMax - cStart)*8 + (support[s] - cMax)*4 + (GetTriEdgeInverse_Static(orntCell[0], c-2) + (o*of < 0 ? 1-r : r))%3;
2872         }
2873         ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
2874 #if 1
2875         if ((newp < fMaxNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid face [%d, %d)", newp, fMaxNew, fEndNew);
2876         for (p = 0; p < size; ++p) {
2877           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);
2878         }
2879 #endif
2880       }
2881     }
2882     /* Hybrid cell faces have 4 edges and 2 cells */
2883     for (c = cMax; c < cEnd; ++c) {
2884       PetscInt        newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (c - cMax)*3;
2885       const PetscInt *cone, *ornt;
2886       PetscInt        coneNew[4], orntNew[4];
2887       PetscInt        supportNew[2];
2888 
2889       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
2890       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
2891       for (r = 0; r < 3; ++r) {
2892         coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*3 + (r+2)%3;
2893         orntNew[0] = 0;
2894         coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*3 + (r+2)%3;
2895         orntNew[1] = 0;
2896         coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (eEnd - eMax) + (cone[2+(r+2)%3] - fMax);
2897         orntNew[2] = 0;
2898         coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (eEnd - eMax) + (cone[2+r]       - fMax);
2899         orntNew[3] = 0;
2900         ierr = DMPlexSetCone(rdm, newp+r, coneNew);CHKERRQ(ierr);
2901         ierr = DMPlexSetConeOrientation(rdm, newp+r, orntNew);CHKERRQ(ierr);
2902 #if 1
2903         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);
2904         for (p = 0; p < 2; ++p) {
2905           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);
2906         }
2907         for (p = 2; p < 4; ++p) {
2908           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);
2909         }
2910 #endif
2911         supportNew[0] = cStartNew + (cMax - cStart)*8 + (c - cMax)*4 + GetTriSubface_Static(ornt[0], r);
2912         supportNew[1] = cStartNew + (cMax - cStart)*8 + (c - cMax)*4 + 3;
2913         ierr          = DMPlexSetSupport(rdm, newp+r, supportNew);CHKERRQ(ierr);
2914 #if 1
2915         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);
2916         for (p = 0; p < 2; ++p) {
2917           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);
2918         }
2919 #endif
2920       }
2921     }
2922     /* Interior split edges have 2 vertices and the same faces as the parent */
2923     for (e = eStart; e < eMax; ++e) {
2924       const PetscInt newv = vStartNew + (vEnd - vStart) + (e - eStart);
2925 
2926       for (r = 0; r < 2; ++r) {
2927         const PetscInt  newp = eStartNew + (e - eStart)*2 + r;
2928         const PetscInt *cone, *ornt, *support;
2929         PetscInt        coneNew[2], coneSize, c, supportSize, s;
2930 
2931         ierr             = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
2932         coneNew[0]       = vStartNew + (cone[0] - vStart);
2933         coneNew[1]       = vStartNew + (cone[1] - vStart);
2934         coneNew[(r+1)%2] = newv;
2935         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2936 #if 1
2937         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
2938         for (p = 0; p < 2; ++p) {
2939           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);
2940         }
2941 #endif
2942         ierr = DMPlexGetSupportSize(dm, e, &supportSize);CHKERRQ(ierr);
2943         ierr = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
2944         for (s = 0; s < supportSize; ++s) {
2945           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
2946           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
2947           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
2948           for (c = 0; c < coneSize; ++c) if (cone[c] == e) break;
2949           if (support[s] < fMax) {
2950             supportRef[s] = fStartNew + (support[s] - fStart)*4 + (c + (ornt[c] < 0 ? 1-r : r))%3;
2951           } else {
2952             supportRef[s] = fStartNew + (fMax       - fStart)*4 + (cMax - cStart)*8 + (support[s] - fMax)*2 + (ornt[c] < 0 ? 1-r : r);
2953           }
2954         }
2955         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
2956 #if 1
2957         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
2958         for (p = 0; p < supportSize; ++p) {
2959           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);
2960         }
2961 #endif
2962       }
2963     }
2964     /* Interior face edges have 2 vertices and 2+cells*(1/2) faces */
2965     for (f = fStart; f < fMax; ++f) {
2966       const PetscInt *cone, *ornt, *support;
2967       PetscInt        coneSize, supportSize, s;
2968 
2969       ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
2970       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
2971       for (r = 0; r < 3; ++r) {
2972         const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (f - fStart)*3 + r;
2973         PetscInt        coneNew[2], intFaces = 0, er, eint[4] = {1, 0, 2, 0};
2974         PetscInt        fint[24] = { 1,  7, -1, -1,  0,  5,
2975                                     -1, -1,  1,  6,  0,  4,
2976                                      2,  5,  3,  4, -1, -1,
2977                                     -1, -1,  3,  6,  2,  7};
2978 
2979         ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
2980         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[(r+0)%3] - eStart);
2981         coneNew[1] = vStartNew + (vEnd - vStart) + (cone[(r+1)%3] - eStart);
2982         ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2983 #if 1
2984         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
2985         for (p = 0; p < 2; ++p) {
2986           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);
2987         }
2988 #endif
2989         supportRef[0] = fStartNew + (f - fStart)*4 + (r+1)%3;
2990         supportRef[1] = fStartNew + (f - fStart)*4 + 3;
2991         for (s = 0; s < supportSize; ++s) {
2992           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
2993           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
2994           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
2995           for (c = 0; c < coneSize; ++c) {if (cone[c] == f) break;}
2996           if (support[s] < cMax) {
2997             /* Here we want to determine whether edge newp contains a vertex which is part of the cross-tet edge */
2998             er = GetTetSomethingInverse_Static(ornt[c], r);
2999             if (er == eint[c]) {
3000               supportRef[2+intFaces++] = fStartNew + (fMax - fStart)*4 + (support[s] - cStart)*8 + (c + 2)%4;
3001             } else {
3002               supportRef[2+intFaces++] = fStartNew + (fMax - fStart)*4 + (support[s] - cStart)*8 + fint[(c*3 + er)*2 + 0];
3003               supportRef[2+intFaces++] = fStartNew + (fMax - fStart)*4 + (support[s] - cStart)*8 + fint[(c*3 + er)*2 + 1];
3004             }
3005           } else {
3006             supportRef[2+intFaces++] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (support[s] - cMax)*3 + (r + 1)%3;
3007           }
3008         }
3009         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
3010 #if 1
3011         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
3012         for (p = 0; p < intFaces; ++p) {
3013           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);
3014         }
3015 #endif
3016       }
3017     }
3018     /* Interior cell edges have 2 vertices and 4 faces */
3019     for (c = cStart; c < cMax; ++c) {
3020       const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart);
3021       const PetscInt *cone, *ornt, *fcone;
3022       PetscInt        coneNew[2], supportNew[4], find;
3023 
3024       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
3025       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
3026       ierr = DMPlexGetCone(dm, cone[0], &fcone);CHKERRQ(ierr);
3027       find = GetTriEdge_Static(ornt[0], 0);
3028       coneNew[0] = vStartNew + (vEnd - vStart) + (fcone[find] - eStart);
3029       ierr = DMPlexGetCone(dm, cone[2], &fcone);CHKERRQ(ierr);
3030       find = GetTriEdge_Static(ornt[2], 1);
3031       coneNew[1] = vStartNew + (vEnd - vStart) + (fcone[find] - eStart);
3032       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3033 #if 1
3034       if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
3035       for (p = 0; p < 2; ++p) {
3036         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);
3037       }
3038 #endif
3039       supportNew[0] = fStartNew + (fMax - fStart)*4 + (c - cStart)*8 + 4;
3040       supportNew[1] = fStartNew + (fMax - fStart)*4 + (c - cStart)*8 + 5;
3041       supportNew[2] = fStartNew + (fMax - fStart)*4 + (c - cStart)*8 + 6;
3042       supportNew[3] = fStartNew + (fMax - fStart)*4 + (c - cStart)*8 + 7;
3043       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3044 #if 1
3045       if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
3046       for (p = 0; p < 4; ++p) {
3047         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);
3048       }
3049 #endif
3050     }
3051     /* Hybrid edges have two vertices and the same faces */
3052     for (e = eMax; e < eEnd; ++e) {
3053       const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (e - eMax);
3054       const PetscInt *cone, *support, *fcone;
3055       PetscInt        coneNew[2], size, fsize, s;
3056 
3057       ierr = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
3058       ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
3059       ierr = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
3060       coneNew[0] = vStartNew + (cone[0] - vStart);
3061       coneNew[1] = vStartNew + (cone[1] - vStart);
3062       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3063 #if 1
3064       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid edge [%d, %d)", newp, eMaxNew, eEndNew);
3065       for (p = 0; p < 2; ++p) {
3066         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);
3067       }
3068 #endif
3069       for (s = 0; s < size; ++s) {
3070         ierr = DMPlexGetConeSize(dm, support[s], &fsize);CHKERRQ(ierr);
3071         ierr = DMPlexGetCone(dm, support[s], &fcone);CHKERRQ(ierr);
3072         for (c = 0; c < fsize; ++c) if (fcone[c] == e) break;
3073         if ((c < 2) || (c > 3)) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Edge %d not found in cone of face %d", e, support[s]);
3074         supportRef[s] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (support[s] - fMax)*2 + c-2;
3075       }
3076       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
3077 #if 1
3078       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid edge [%d, %d)", newp, eMaxNew, eEndNew);
3079       for (p = 0; p < size; ++p) {
3080         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);
3081       }
3082 #endif
3083     }
3084     /* Hybrid face edges have 2 vertices and 2+2*cells faces */
3085     for (f = fMax; f < fEnd; ++f) {
3086       const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (eEnd - eMax) + (f - fMax);
3087       const PetscInt *cone, *support, *ccone, *cornt;
3088       PetscInt        coneNew[2], size, csize, s;
3089 
3090       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
3091       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
3092       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
3093       coneNew[0] = vStartNew + (vEnd - vStart) + (cone[0] - eStart);
3094       coneNew[1] = vStartNew + (vEnd - vStart) + (cone[1] - eStart);
3095       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3096 #if 1
3097       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid edge [%d, %d)", newp, eMaxNew, eEndNew);
3098       for (p = 0; p < 2; ++p) {
3099         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);
3100       }
3101 #endif
3102       supportRef[0] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (f - fMax)*2 + 0;
3103       supportRef[1] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (f - fMax)*2 + 1;
3104       for (s = 0; s < size; ++s) {
3105         ierr = DMPlexGetConeSize(dm, support[s], &csize);CHKERRQ(ierr);
3106         ierr = DMPlexGetCone(dm, support[s], &ccone);CHKERRQ(ierr);
3107         ierr = DMPlexGetConeOrientation(dm, support[s], &cornt);CHKERRQ(ierr);
3108         for (c = 0; c < csize; ++c) if (ccone[c] == f) break;
3109         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]);
3110         supportRef[2+s*2+0] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (support[s] - cMax)*3 + c-2;
3111         supportRef[2+s*2+1] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (support[s] - cMax)*3 + (c-1)%3;
3112       }
3113       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
3114 #if 1
3115       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid edge [%d, %d)", newp, eMaxNew, eEndNew);
3116       for (p = 0; p < 2+size*2; ++p) {
3117         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);
3118       }
3119 #endif
3120     }
3121     /* Interior vertices have identical supports */
3122     for (v = vStart; v < vEnd; ++v) {
3123       const PetscInt  newp = vStartNew + (v - vStart);
3124       const PetscInt *support, *cone;
3125       PetscInt        size, s;
3126 
3127       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
3128       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
3129       for (s = 0; s < size; ++s) {
3130         PetscInt r = 0;
3131 
3132         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
3133         if (cone[1] == v) r = 1;
3134         if (support[s] < eMax) supportRef[s] = eStartNew + (support[s] - eStart)*2 + r;
3135         else                   supportRef[s] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (support[s] - eMax);
3136       }
3137       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
3138 #if 1
3139       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
3140       for (p = 0; p < size; ++p) {
3141         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);
3142       }
3143 #endif
3144     }
3145     /* Interior edge vertices have 2 + interior face*2 + hybrid face + cells*0/1 supports */
3146     for (e = eStart; e < eMax; ++e) {
3147       const PetscInt  newp = vStartNew + (vEnd - vStart) + (e - eStart);
3148       const PetscInt *cone, *support;
3149       PetscInt       *star = NULL, starSize, faceSize = 0, cellSize = 0, coneSize, size, s;
3150 
3151       ierr          = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
3152       ierr          = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
3153       supportRef[0] = eStartNew + (e - eStart)*2 + 0;
3154       supportRef[1] = eStartNew + (e - eStart)*2 + 1;
3155       for (s = 0; s < size; ++s) {
3156         PetscInt r = 0;
3157 
3158         if (support[s] < fMax) {
3159           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
3160           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
3161           for (r = 0; r < coneSize; ++r) {if (cone[r] == e) break;}
3162           supportRef[2+faceSize+0] = eStartNew + (eMax - eStart)*2 + (support[s] - fStart)*3 + (r+0)%3;
3163           supportRef[2+faceSize+1] = eStartNew + (eMax - eStart)*2 + (support[s] - fStart)*3 + (r+2)%3;
3164           faceSize += 2;
3165         } else {
3166           supportRef[2+faceSize+0] = eStartNew + (eMax - eStart)*2 + (fMax       - fStart)*3 + (cMax - cStart) + (eEnd - eMax) + (support[s] - fMax);
3167           ++faceSize;
3168         }
3169       }
3170       ierr = DMPlexGetTransitiveClosure(dm, e, PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
3171       for (s = 0; s < starSize*2; s += 2) {
3172         const PetscInt *cone, *ornt;
3173         PetscInt        e01, e23;
3174 
3175         if ((star[s] >= cStart) && (star[s] < cMax)) {
3176           /* Check edge 0-1 */
3177           ierr = DMPlexGetCone(dm, star[s], &cone);CHKERRQ(ierr);
3178           ierr = DMPlexGetConeOrientation(dm, star[s], &ornt);CHKERRQ(ierr);
3179           ierr = DMPlexGetCone(dm, cone[0], &cone);CHKERRQ(ierr);
3180           e01  = cone[GetTriEdge_Static(ornt[0], 0)];
3181           /* Check edge 2-3 */
3182           ierr = DMPlexGetCone(dm, star[s], &cone);CHKERRQ(ierr);
3183           ierr = DMPlexGetConeOrientation(dm, star[s], &ornt);CHKERRQ(ierr);
3184           ierr = DMPlexGetCone(dm, cone[2], &cone);CHKERRQ(ierr);
3185           e23  = cone[GetTriEdge_Static(ornt[2], 1)];
3186           if ((e01 == e) || (e23 == e)) {supportRef[2+faceSize+cellSize++] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (star[s] - cStart);}
3187         }
3188       }
3189       ierr = DMPlexRestoreTransitiveClosure(dm, e, PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
3190       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
3191 #if 1
3192       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
3193       for (p = 0; p < 2+faceSize+cellSize; ++p) {
3194         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);
3195       }
3196 #endif
3197     }
3198     ierr = PetscFree(supportRef);CHKERRQ(ierr);
3199     ierr = DMPlexRestoreFaces_Internal(dm, 3, cStart, NULL, NULL, &faces);CHKERRQ(ierr);
3200     break;
3201   case 6:
3202     /* Hex 3D */
3203     /*
3204      Bottom (viewed from top)    Top
3205      1---------2---------2       7---------2---------6
3206      |         |         |       |         |         |
3207      |    B    2    C    |       |    H    2    G    |
3208      |         |         |       |         |         |
3209      3----3----0----1----1       3----3----0----1----1
3210      |         |         |       |         |         |
3211      |    A    0    D    |       |    E    0    F    |
3212      |         |         |       |         |         |
3213      0---------0---------3       4---------0---------5
3214      */
3215     /* All cells have 6 faces: Bottom, Top, Front, Back, Right, Left */
3216     for (c = cStart; c < cEnd; ++c) {
3217       const PetscInt  newp = (c - cStart)*8;
3218       const PetscInt *cone, *ornt;
3219       PetscInt        coneNew[6], orntNew[6];
3220 
3221       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
3222       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
3223       /* A hex */
3224       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], 0);
3225       orntNew[0] = ornt[0];
3226       coneNew[1] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  8; /* AE */
3227       orntNew[1] = 0;
3228       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetQuadSubface_Static(ornt[2], 0);
3229       orntNew[2] = ornt[2];
3230       coneNew[3] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  3; /* AB */
3231       orntNew[3] = 0;
3232       coneNew[4] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  0; /* AD */
3233       orntNew[4] = 0;
3234       coneNew[5] = fStartNew + (cone[5] - fStart)*4 + GetQuadSubface_Static(ornt[5], 0);
3235       orntNew[5] = ornt[5];
3236       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
3237       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
3238 #if 1
3239       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);
3240       for (p = 0; p < 6; ++p) {
3241         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);
3242       }
3243 #endif
3244       /* B hex */
3245       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], 1);
3246       orntNew[0] = ornt[0];
3247       coneNew[1] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 + 11; /* BH */
3248       orntNew[1] = 0;
3249       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  3; /* AB */
3250       orntNew[2] = -1;
3251       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetQuadSubface_Static(ornt[3], 1);
3252       orntNew[3] = ornt[3];
3253       coneNew[4] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  2; /* BC */
3254       orntNew[4] = 0;
3255       coneNew[5] = fStartNew + (cone[5] - fStart)*4 + GetQuadSubface_Static(ornt[5], 3);
3256       orntNew[5] = ornt[5];
3257       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
3258       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
3259 #if 1
3260       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);
3261       for (p = 0; p < 6; ++p) {
3262         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);
3263       }
3264 #endif
3265       /* C hex */
3266       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], 2);
3267       orntNew[0] = ornt[0];
3268       coneNew[1] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 + 10; /* CG */
3269       orntNew[1] = 0;
3270       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  1; /* CD */
3271       orntNew[2] = -1;
3272       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetQuadSubface_Static(ornt[3], 0);
3273       orntNew[3] = ornt[3];
3274       coneNew[4] = fStartNew + (cone[4] - fStart)*4 + GetQuadSubface_Static(ornt[4], 1);
3275       orntNew[4] = ornt[4];
3276       coneNew[5] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  2; /* BC */
3277       orntNew[5] = -4;
3278       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
3279       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
3280 #if 1
3281       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);
3282       for (p = 0; p < 6; ++p) {
3283         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);
3284       }
3285 #endif
3286       /* D hex */
3287       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], 3);
3288       orntNew[0] = ornt[0];
3289       coneNew[1] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  9; /* DF */
3290       orntNew[1] = 0;
3291       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetQuadSubface_Static(ornt[2], 1);
3292       orntNew[2] = ornt[2];
3293       coneNew[3] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  1; /* CD */
3294       orntNew[3] = 0;
3295       coneNew[4] = fStartNew + (cone[4] - fStart)*4 + GetQuadSubface_Static(ornt[4], 0);
3296       orntNew[4] = ornt[4];
3297       coneNew[5] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  0; /* AD */
3298       orntNew[5] = -4;
3299       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
3300       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
3301 #if 1
3302       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);
3303       for (p = 0; p < 6; ++p) {
3304         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);
3305       }
3306 #endif
3307       /* E hex */
3308       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  8; /* AE */
3309       orntNew[0] = -4;
3310       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], 0);
3311       orntNew[1] = ornt[1];
3312       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetQuadSubface_Static(ornt[2], 3);
3313       orntNew[2] = ornt[2];
3314       coneNew[3] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  7; /* EH */
3315       orntNew[3] = 0;
3316       coneNew[4] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  4; /* EF */
3317       orntNew[4] = -1;
3318       coneNew[5] = fStartNew + (cone[5] - fStart)*4 + GetQuadSubface_Static(ornt[5], 1);
3319       orntNew[5] = ornt[5];
3320       ierr       = DMPlexSetCone(rdm, newp+4, coneNew);CHKERRQ(ierr);
3321       ierr       = DMPlexSetConeOrientation(rdm, newp+4, orntNew);CHKERRQ(ierr);
3322 #if 1
3323       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);
3324       for (p = 0; p < 6; ++p) {
3325         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);
3326       }
3327 #endif
3328       /* F hex */
3329       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  9; /* DF */
3330       orntNew[0] = -4;
3331       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], 1);
3332       orntNew[1] = ornt[1];
3333       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetQuadSubface_Static(ornt[2], 2);
3334       orntNew[2] = ornt[2];
3335       coneNew[3] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  5; /* FG */
3336       orntNew[3] = -1;
3337       coneNew[4] = fStartNew + (cone[4] - fStart)*4 + GetQuadSubface_Static(ornt[4], 3);
3338       orntNew[4] = ornt[4];
3339       coneNew[5] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  4; /* EF */
3340       orntNew[5] = 1;
3341       ierr       = DMPlexSetCone(rdm, newp+5, coneNew);CHKERRQ(ierr);
3342       ierr       = DMPlexSetConeOrientation(rdm, newp+5, orntNew);CHKERRQ(ierr);
3343 #if 1
3344       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);
3345       for (p = 0; p < 6; ++p) {
3346         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);
3347       }
3348 #endif
3349       /* G hex */
3350       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 + 10; /* CG */
3351       orntNew[0] = -4;
3352       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], 2);
3353       orntNew[1] = ornt[1];
3354       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  5; /* FG */
3355       orntNew[2] = 0;
3356       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetQuadSubface_Static(ornt[3], 3);
3357       orntNew[3] = ornt[3];
3358       coneNew[4] = fStartNew + (cone[4] - fStart)*4 + GetQuadSubface_Static(ornt[4], 2);
3359       orntNew[4] = ornt[4];
3360       coneNew[5] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  6; /* GH */
3361       orntNew[5] = -3;
3362       ierr       = DMPlexSetCone(rdm, newp+6, coneNew);CHKERRQ(ierr);
3363       ierr       = DMPlexSetConeOrientation(rdm, newp+6, orntNew);CHKERRQ(ierr);
3364 #if 1
3365       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);
3366       for (p = 0; p < 6; ++p) {
3367         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);
3368       }
3369 #endif
3370       /* H hex */
3371       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 + 11; /* BH */
3372       orntNew[0] = -4;
3373       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], 3);
3374       orntNew[1] = ornt[1];
3375       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  7; /* EH */
3376       orntNew[2] = -1;
3377       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetQuadSubface_Static(ornt[3], 2);
3378       orntNew[3] = ornt[3];
3379       coneNew[4] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  6; /* GH */
3380       orntNew[4] = 3;
3381       coneNew[5] = fStartNew + (cone[5] - fStart)*4 + GetQuadSubface_Static(ornt[5], 2);
3382       orntNew[5] = ornt[5];
3383       ierr       = DMPlexSetCone(rdm, newp+7, coneNew);CHKERRQ(ierr);
3384       ierr       = DMPlexSetConeOrientation(rdm, newp+7, orntNew);CHKERRQ(ierr);
3385 #if 1
3386       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);
3387       for (p = 0; p < 6; ++p) {
3388         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);
3389       }
3390 #endif
3391     }
3392     /* Split faces have 4 edges and the same cells as the parent */
3393     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
3394     ierr = PetscMalloc1((4 + maxSupportSize*2), &supportRef);CHKERRQ(ierr);
3395     for (f = fStart; f < fEnd; ++f) {
3396       for (r = 0; r < 4; ++r) {
3397         /* TODO: This can come from GetFaces_Internal() */
3398         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};
3399         const PetscInt  newp = fStartNew + (f - fStart)*4 + r;
3400         const PetscInt *cone, *ornt, *support;
3401         PetscInt        coneNew[4], orntNew[4], coneSize, c, supportSize, s;
3402 
3403         ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
3404         ierr = DMPlexGetConeOrientation(dm, f, &ornt);CHKERRQ(ierr);
3405         coneNew[(r+3)%4] = eStartNew + (cone[(r+3)%4] - eStart)*2 + (ornt[(r+3)%4] < 0 ? 0 : 1);
3406         orntNew[(r+3)%4] = ornt[(r+3)%4];
3407         coneNew[(r+0)%4] = eStartNew + (cone[r]       - eStart)*2 + (ornt[r] < 0 ? 1 : 0);
3408         orntNew[(r+0)%4] = ornt[r];
3409         coneNew[(r+1)%4] = eStartNew + (eEnd - eStart)*2 + (f - fStart)*4 + r;
3410         orntNew[(r+1)%4] = 0;
3411         coneNew[(r+2)%4] = eStartNew + (eEnd - eStart)*2 + (f - fStart)*4 + (r+3)%4;
3412         orntNew[(r+2)%4] = -2;
3413         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3414         ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3415 #if 1
3416         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
3417         for (p = 0; p < 4; ++p) {
3418           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);
3419         }
3420 #endif
3421         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
3422         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
3423         for (s = 0; s < supportSize; ++s) {
3424           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
3425           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
3426           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
3427           for (c = 0; c < coneSize; ++c) {
3428             if (cone[c] == f) break;
3429           }
3430           supportRef[s] = cStartNew + (support[s] - cStart)*8 + newCells[c*4+GetQuadSubfaceInverse_Static(ornt[c], r)];
3431         }
3432         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
3433 #if 1
3434         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
3435         for (p = 0; p < supportSize; ++p) {
3436           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);
3437         }
3438 #endif
3439       }
3440     }
3441     /* Interior faces have 4 edges and 2 cells */
3442     for (c = cStart; c < cEnd; ++c) {
3443       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};
3444       const PetscInt *cone, *ornt;
3445       PetscInt        newp, coneNew[4], orntNew[4], supportNew[2];
3446 
3447       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
3448       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
3449       /* A-D face */
3450       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 0;
3451       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*4 + GetQuadEdge_Static(ornt[0], 3);
3452       orntNew[0] = 0;
3453       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 0;
3454       orntNew[1] = 0;
3455       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 2;
3456       orntNew[2] = -2;
3457       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*4 + GetQuadEdge_Static(ornt[2], 0);
3458       orntNew[3] = -2;
3459       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3460       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3461 #if 1
3462       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
3463       for (p = 0; p < 4; ++p) {
3464         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);
3465       }
3466 #endif
3467       /* C-D face */
3468       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 1;
3469       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*4 + GetQuadEdge_Static(ornt[0], 2);
3470       orntNew[0] = 0;
3471       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 0;
3472       orntNew[1] = 0;
3473       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 4;
3474       orntNew[2] = -2;
3475       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (cone[4] - fStart)*4 + GetQuadEdge_Static(ornt[4], 0);
3476       orntNew[3] = -2;
3477       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3478       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3479 #if 1
3480       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
3481       for (p = 0; p < 4; ++p) {
3482         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);
3483       }
3484 #endif
3485       /* B-C face */
3486       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 2;
3487       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*4 + GetQuadEdge_Static(ornt[0], 1);
3488       orntNew[0] = -2;
3489       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*4 + GetQuadEdge_Static(ornt[3], 0);
3490       orntNew[1] = 0;
3491       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 3;
3492       orntNew[2] = 0;
3493       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 0;
3494       orntNew[3] = -2;
3495       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3496       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3497 #if 1
3498       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
3499       for (p = 0; p < 4; ++p) {
3500         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);
3501       }
3502 #endif
3503       /* A-B face */
3504       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 3;
3505       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*4 + GetQuadEdge_Static(ornt[0], 0);
3506       orntNew[0] = -2;
3507       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[5] - fStart)*4 + GetQuadEdge_Static(ornt[5], 3);
3508       orntNew[1] = 0;
3509       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 5;
3510       orntNew[2] = 0;
3511       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 0;
3512       orntNew[3] = -2;
3513       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3514       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3515 #if 1
3516       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
3517       for (p = 0; p < 4; ++p) {
3518         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);
3519       }
3520 #endif
3521       /* E-F face */
3522       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 4;
3523       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 2;
3524       orntNew[0] = -2;
3525       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*4 + GetQuadEdge_Static(ornt[2], 2);
3526       orntNew[1] = -2;
3527       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*4 + GetQuadEdge_Static(ornt[1], 0);
3528       orntNew[2] = 0;
3529       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 1;
3530       orntNew[3] = 0;
3531       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3532       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3533 #if 1
3534       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
3535       for (p = 0; p < 4; ++p) {
3536         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);
3537       }
3538 #endif
3539       /* F-G face */
3540       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 5;
3541       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 4;
3542       orntNew[0] = -2;
3543       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[4] - fStart)*4 + GetQuadEdge_Static(ornt[4], 2);
3544       orntNew[1] = -2;
3545       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*4 + GetQuadEdge_Static(ornt[1], 1);
3546       orntNew[2] = 0;
3547       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 1;
3548       orntNew[3] = 0;
3549       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3550       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3551 #if 1
3552       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
3553       for (p = 0; p < 4; ++p) {
3554         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);
3555       }
3556 #endif
3557       /* G-H face */
3558       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 6;
3559       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*4 + GetQuadEdge_Static(ornt[3], 2);
3560       orntNew[0] = -2;
3561       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*4 + GetQuadEdge_Static(ornt[1], 2);
3562       orntNew[1] = 0;
3563       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 1;
3564       orntNew[2] = 0;
3565       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 3;
3566       orntNew[3] = -2;
3567       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3568       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3569 #if 1
3570       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
3571       for (p = 0; p < 4; ++p) {
3572         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);
3573       }
3574 #endif
3575       /* E-H face */
3576       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 7;
3577       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 5;
3578       orntNew[0] = -2;
3579       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[5] - fStart)*4 + GetQuadEdge_Static(ornt[5], 1);
3580       orntNew[1] = -2;
3581       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*4 + GetQuadEdge_Static(ornt[1], 3);
3582       orntNew[2] = 0;
3583       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 1;
3584       orntNew[3] = 0;
3585       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3586       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3587 #if 1
3588       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
3589       for (p = 0; p < 4; ++p) {
3590         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);
3591       }
3592 #endif
3593       /* A-E face */
3594       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 8;
3595       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*4 + GetQuadEdge_Static(ornt[2], 3);
3596       orntNew[0] = 0;
3597       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 2;
3598       orntNew[1] = 0;
3599       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 5;
3600       orntNew[2] = -2;
3601       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (cone[5] - fStart)*4 + GetQuadEdge_Static(ornt[5], 0);
3602       orntNew[3] = -2;
3603       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3604       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3605 #if 1
3606       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
3607       for (p = 0; p < 4; ++p) {
3608         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);
3609       }
3610 #endif
3611       /* D-F face */
3612       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 9;
3613       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*4 + GetQuadEdge_Static(ornt[2], 1);
3614       orntNew[0] = -2;
3615       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[4] - fStart)*4 + GetQuadEdge_Static(ornt[4], 3);
3616       orntNew[1] = 0;
3617       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 4;
3618       orntNew[2] = 0;
3619       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 2;
3620       orntNew[3] = -2;
3621       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3622       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3623 #if 1
3624       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
3625       for (p = 0; p < 4; ++p) {
3626         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);
3627       }
3628 #endif
3629       /* C-G face */
3630       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 10;
3631       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 4;
3632       orntNew[0] = -2;
3633       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[4] - fStart)*4 + GetQuadEdge_Static(ornt[4], 1);
3634       orntNew[1] = -2;
3635       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*4 + GetQuadEdge_Static(ornt[3], 3);
3636       orntNew[2] = 0;
3637       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 3;
3638       orntNew[3] = 0;
3639       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3640       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3641 #if 1
3642       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
3643       for (p = 0; p < 4; ++p) {
3644         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);
3645       }
3646 #endif
3647       /* B-H face */
3648       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 11;
3649       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 5;
3650       orntNew[0] = 0;
3651       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 3;
3652       orntNew[1] = -2;
3653       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*4 + GetQuadEdge_Static(ornt[3], 1);
3654       orntNew[2] = -2;
3655       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (cone[5] - fStart)*4 + GetQuadEdge_Static(ornt[5], 2);
3656       orntNew[3] = 0;
3657       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3658       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3659 #if 1
3660       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
3661       for (p = 0; p < 4; ++p) {
3662         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);
3663       }
3664 #endif
3665       for (r = 0; r < 12; ++r) {
3666         newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + r;
3667         supportNew[0] = cStartNew + (c - cStart)*8 + newCells[r*2+0];
3668         supportNew[1] = cStartNew + (c - cStart)*8 + newCells[r*2+1];
3669         ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3670 #if 1
3671         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
3672         for (p = 0; p < 2; ++p) {
3673           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);
3674         }
3675 #endif
3676       }
3677     }
3678     /* Split edges have 2 vertices and the same faces as the parent */
3679     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
3680     for (e = eStart; e < eEnd; ++e) {
3681       const PetscInt newv = vStartNew + (vEnd - vStart) + (e - eStart);
3682 
3683       for (r = 0; r < 2; ++r) {
3684         const PetscInt  newp = eStartNew + (e - eStart)*2 + r;
3685         const PetscInt *cone, *ornt, *support;
3686         PetscInt        coneNew[2], coneSize, c, supportSize, s;
3687 
3688         ierr             = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
3689         coneNew[0]       = vStartNew + (cone[0] - vStart);
3690         coneNew[1]       = vStartNew + (cone[1] - vStart);
3691         coneNew[(r+1)%2] = newv;
3692         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3693 #if 1
3694         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
3695         for (p = 0; p < 2; ++p) {
3696           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);
3697         }
3698 #endif
3699         ierr = DMPlexGetSupportSize(dm, e, &supportSize);CHKERRQ(ierr);
3700         ierr = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
3701         for (s = 0; s < supportSize; ++s) {
3702           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
3703           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
3704           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
3705           for (c = 0; c < coneSize; ++c) {
3706             if (cone[c] == e) break;
3707           }
3708           supportRef[s] = fStartNew + (support[s] - fStart)*4 + (ornt[c] < 0 ? (c+1-r)%4 : (c+r)%4);
3709         }
3710         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
3711 #if 1
3712         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
3713         for (p = 0; p < supportSize; ++p) {
3714           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);
3715         }
3716 #endif
3717       }
3718     }
3719     /* Face edges have 2 vertices and 2+cells faces */
3720     for (f = fStart; f < fEnd; ++f) {
3721       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};
3722       const PetscInt  newv = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (f - fStart);
3723       const PetscInt *cone, *coneCell, *orntCell, *support;
3724       PetscInt        coneNew[2], coneSize, c, supportSize, s;
3725 
3726       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
3727       for (r = 0; r < 4; ++r) {
3728         const PetscInt newp = eStartNew + (eEnd - eStart)*2 + (f - fStart)*4 + r;
3729 
3730         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r] - eStart);
3731         coneNew[1] = newv;
3732         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3733 #if 1
3734         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
3735         for (p = 0; p < 2; ++p) {
3736           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);
3737         }
3738 #endif
3739         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
3740         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
3741         supportRef[0] = fStartNew + (f - fStart)*4 + r;
3742         supportRef[1] = fStartNew + (f - fStart)*4 + (r+1)%4;
3743         for (s = 0; s < supportSize; ++s) {
3744           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
3745           ierr = DMPlexGetCone(dm, support[s], &coneCell);CHKERRQ(ierr);
3746           ierr = DMPlexGetConeOrientation(dm, support[s], &orntCell);CHKERRQ(ierr);
3747           for (c = 0; c < coneSize; ++c) if (coneCell[c] == f) break;
3748           supportRef[2+s] = fStartNew + (fEnd - fStart)*4 + (support[s] - cStart)*12 + newFaces[c*4 + GetQuadEdgeInverse_Static(orntCell[c], r)];
3749         }
3750         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
3751 #if 1
3752         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
3753         for (p = 0; p < 2+supportSize; ++p) {
3754           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);
3755         }
3756 #endif
3757       }
3758     }
3759     /* Cell edges have 2 vertices and 4 faces */
3760     for (c = cStart; c < cEnd; ++c) {
3761       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};
3762       const PetscInt  newv = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (fEnd - fStart) + (c - cStart);
3763       const PetscInt *cone;
3764       PetscInt        coneNew[2], supportNew[4];
3765 
3766       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
3767       for (r = 0; r < 6; ++r) {
3768         const PetscInt newp = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*4 + (c - cStart)*6 + r;
3769 
3770         coneNew[0] = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (cone[r] - fStart);
3771         coneNew[1] = newv;
3772         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3773 #if 1
3774         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
3775         for (p = 0; p < 2; ++p) {
3776           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);
3777         }
3778 #endif
3779         for (f = 0; f < 4; ++f) supportNew[f] = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + newFaces[r*4+f];
3780         ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3781 #if 1
3782         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
3783         for (p = 0; p < 4; ++p) {
3784           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);
3785         }
3786 #endif
3787       }
3788     }
3789     /* Old vertices have identical supports */
3790     for (v = vStart; v < vEnd; ++v) {
3791       const PetscInt  newp = vStartNew + (v - vStart);
3792       const PetscInt *support, *cone;
3793       PetscInt        size, s;
3794 
3795       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
3796       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
3797       for (s = 0; s < size; ++s) {
3798         PetscInt r = 0;
3799 
3800         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
3801         if (cone[1] == v) r = 1;
3802         supportRef[s] = eStartNew + (support[s] - eStart)*2 + r;
3803       }
3804       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
3805 #if 1
3806       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
3807       for (p = 0; p < size; ++p) {
3808         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);
3809       }
3810 #endif
3811     }
3812     /* Edge vertices have 2 + faces supports */
3813     for (e = eStart; e < eEnd; ++e) {
3814       const PetscInt  newp = vStartNew + (vEnd - vStart) + (e - eStart);
3815       const PetscInt *cone, *support;
3816       PetscInt        size, s;
3817 
3818       ierr          = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
3819       ierr          = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
3820       supportRef[0] = eStartNew + (e - eStart)*2 + 0;
3821       supportRef[1] = eStartNew + (e - eStart)*2 + 1;
3822       for (s = 0; s < size; ++s) {
3823         PetscInt r;
3824 
3825         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
3826         for (r = 0; r < 4; ++r) if (cone[r] == e) break;
3827         supportRef[2+s] = eStartNew + (eEnd - eStart)*2 + (support[s] - fStart)*4 + r;
3828       }
3829       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
3830 #if 1
3831       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
3832       for (p = 0; p < 2+size; ++p) {
3833         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);
3834       }
3835 #endif
3836     }
3837     /* Face vertices have 4 + cells supports */
3838     for (f = fStart; f < fEnd; ++f) {
3839       const PetscInt  newp = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (f - fStart);
3840       const PetscInt *cone, *support;
3841       PetscInt        size, s;
3842 
3843       ierr          = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
3844       ierr          = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
3845       for (r = 0; r < 4; ++r) supportRef[r] = eStartNew + (eEnd - eStart)*2 +  (f - fStart)*4 + r;
3846       for (s = 0; s < size; ++s) {
3847         PetscInt r;
3848 
3849         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
3850         for (r = 0; r < 6; ++r) if (cone[r] == f) break;
3851         supportRef[4+s] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*4 + (support[s] - cStart)*6 + r;
3852       }
3853       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
3854 #if 1
3855       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
3856       for (p = 0; p < 4+size; ++p) {
3857         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);
3858       }
3859 #endif
3860     }
3861     /* Cell vertices have 6 supports */
3862     for (c = cStart; c < cEnd; ++c) {
3863       const PetscInt newp = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (fEnd - fStart) + (c - cStart);
3864       PetscInt       supportNew[6];
3865 
3866       for (r = 0; r < 6; ++r) {
3867         supportNew[r] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*4 + (c - cStart)*6 + r;
3868       }
3869       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3870     }
3871     ierr = PetscFree(supportRef);CHKERRQ(ierr);
3872     break;
3873   case 8:
3874     /* Hybrid Hex 3D */
3875     ierr = DMPlexGetHybridBounds(rdm, &cMaxNew, &fMaxNew, &eMaxNew, NULL);CHKERRQ(ierr);
3876     /*
3877      Bottom (viewed from top)    Top
3878      1---------2---------2       7---------2---------6
3879      |         |         |       |         |         |
3880      |    B    2    C    |       |    H    2    G    |
3881      |         |         |       |         |         |
3882      3----3----0----1----1       3----3----0----1----1
3883      |         |         |       |         |         |
3884      |    A    0    D    |       |    E    0    F    |
3885      |         |         |       |         |         |
3886      0---------0---------3       4---------0---------5
3887      */
3888     /* Interior cells have 6 faces: Bottom, Top, Front, Back, Right, Left */
3889     for (c = cStart; c < cMax; ++c) {
3890       const PetscInt  newp = (c - cStart)*8;
3891       const PetscInt *cone, *ornt;
3892       PetscInt        coneNew[6], orntNew[6];
3893 
3894       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
3895       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
3896       /* A hex */
3897       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], 0);
3898       orntNew[0] = ornt[0];
3899       coneNew[1] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  8; /* AE */
3900       orntNew[1] = 0;
3901       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetQuadSubface_Static(ornt[2], 0);
3902       orntNew[2] = ornt[2];
3903       coneNew[3] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  3; /* AB */
3904       orntNew[3] = 0;
3905       coneNew[4] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  0; /* AD */
3906       orntNew[4] = 0;
3907       coneNew[5] = fStartNew + (cone[5] - fStart)*4 + GetQuadSubface_Static(ornt[5], 0);
3908       orntNew[5] = ornt[5];
3909       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
3910       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
3911 #if 1
3912       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);
3913       for (p = 0; p < 6; ++p) {
3914         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);
3915       }
3916 #endif
3917       /* B hex */
3918       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], 1);
3919       orntNew[0] = ornt[0];
3920       coneNew[1] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 + 11; /* BH */
3921       orntNew[1] = 0;
3922       coneNew[2] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  3; /* AB */
3923       orntNew[2] = -1;
3924       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetQuadSubface_Static(ornt[3], 1);
3925       orntNew[3] = ornt[3];
3926       coneNew[4] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  2; /* BC */
3927       orntNew[4] = 0;
3928       coneNew[5] = fStartNew + (cone[5] - fStart)*4 + GetQuadSubface_Static(ornt[5], 3);
3929       orntNew[5] = ornt[5];
3930       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
3931       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
3932 #if 1
3933       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);
3934       for (p = 0; p < 6; ++p) {
3935         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);
3936       }
3937 #endif
3938       /* C hex */
3939       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], 2);
3940       orntNew[0] = ornt[0];
3941       coneNew[1] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 + 10; /* CG */
3942       orntNew[1] = 0;
3943       coneNew[2] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  1; /* CD */
3944       orntNew[2] = -1;
3945       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetQuadSubface_Static(ornt[3], 0);
3946       orntNew[3] = ornt[3];
3947       coneNew[4] = fStartNew + (cone[4] - fStart)*4 + GetQuadSubface_Static(ornt[4], 1);
3948       orntNew[4] = ornt[4];
3949       coneNew[5] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  2; /* BC */
3950       orntNew[5] = -4;
3951       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
3952       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
3953 #if 1
3954       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);
3955       for (p = 0; p < 6; ++p) {
3956         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);
3957       }
3958 #endif
3959       /* D hex */
3960       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], 3);
3961       orntNew[0] = ornt[0];
3962       coneNew[1] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  9; /* DF */
3963       orntNew[1] = 0;
3964       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetQuadSubface_Static(ornt[2], 1);
3965       orntNew[2] = ornt[2];
3966       coneNew[3] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  1; /* CD */
3967       orntNew[3] = 0;
3968       coneNew[4] = fStartNew + (cone[4] - fStart)*4 + GetQuadSubface_Static(ornt[4], 0);
3969       orntNew[4] = ornt[4];
3970       coneNew[5] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  0; /* AD */
3971       orntNew[5] = -4;
3972       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
3973       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
3974 #if 1
3975       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);
3976       for (p = 0; p < 6; ++p) {
3977         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);
3978       }
3979 #endif
3980       /* E hex */
3981       coneNew[0] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  8; /* AE */
3982       orntNew[0] = -4;
3983       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], 0);
3984       orntNew[1] = ornt[1];
3985       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetQuadSubface_Static(ornt[2], 3);
3986       orntNew[2] = ornt[2];
3987       coneNew[3] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  7; /* EH */
3988       orntNew[3] = 0;
3989       coneNew[4] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  4; /* EF */
3990       orntNew[4] = -1;
3991       coneNew[5] = fStartNew + (cone[5] - fStart)*4 + GetQuadSubface_Static(ornt[5], 1);
3992       orntNew[5] = ornt[5];
3993       ierr       = DMPlexSetCone(rdm, newp+4, coneNew);CHKERRQ(ierr);
3994       ierr       = DMPlexSetConeOrientation(rdm, newp+4, orntNew);CHKERRQ(ierr);
3995 #if 1
3996       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);
3997       for (p = 0; p < 6; ++p) {
3998         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);
3999       }
4000 #endif
4001       /* F hex */
4002       coneNew[0] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  9; /* DF */
4003       orntNew[0] = -4;
4004       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], 1);
4005       orntNew[1] = ornt[1];
4006       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetQuadSubface_Static(ornt[2], 2);
4007       orntNew[2] = ornt[2];
4008       coneNew[3] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  5; /* FG */
4009       orntNew[3] = -1;
4010       coneNew[4] = fStartNew + (cone[4] - fStart)*4 + GetQuadSubface_Static(ornt[4], 3);
4011       orntNew[4] = ornt[4];
4012       coneNew[5] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  4; /* EF */
4013       orntNew[5] = 1;
4014       ierr       = DMPlexSetCone(rdm, newp+5, coneNew);CHKERRQ(ierr);
4015       ierr       = DMPlexSetConeOrientation(rdm, newp+5, orntNew);CHKERRQ(ierr);
4016 #if 1
4017       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);
4018       for (p = 0; p < 6; ++p) {
4019         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);
4020       }
4021 #endif
4022       /* G hex */
4023       coneNew[0] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 + 10; /* CG */
4024       orntNew[0] = -4;
4025       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], 2);
4026       orntNew[1] = ornt[1];
4027       coneNew[2] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  5; /* FG */
4028       orntNew[2] = 0;
4029       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetQuadSubface_Static(ornt[3], 3);
4030       orntNew[3] = ornt[3];
4031       coneNew[4] = fStartNew + (cone[4] - fStart)*4 + GetQuadSubface_Static(ornt[4], 2);
4032       orntNew[4] = ornt[4];
4033       coneNew[5] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  6; /* GH */
4034       orntNew[5] = -3;
4035       ierr       = DMPlexSetCone(rdm, newp+6, coneNew);CHKERRQ(ierr);
4036       ierr       = DMPlexSetConeOrientation(rdm, newp+6, orntNew);CHKERRQ(ierr);
4037 #if 1
4038       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);
4039       for (p = 0; p < 6; ++p) {
4040         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);
4041       }
4042 #endif
4043       /* H hex */
4044       coneNew[0] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 + 11; /* BH */
4045       orntNew[0] = -4;
4046       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], 3);
4047       orntNew[1] = ornt[1];
4048       coneNew[2] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  7; /* EH */
4049       orntNew[2] = -1;
4050       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetQuadSubface_Static(ornt[3], 2);
4051       orntNew[3] = ornt[3];
4052       coneNew[4] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  6; /* GH */
4053       orntNew[4] = 3;
4054       coneNew[5] = fStartNew + (cone[5] - fStart)*4 + GetQuadSubface_Static(ornt[5], 2);
4055       orntNew[5] = ornt[5];
4056       ierr       = DMPlexSetCone(rdm, newp+7, coneNew);CHKERRQ(ierr);
4057       ierr       = DMPlexSetConeOrientation(rdm, newp+7, orntNew);CHKERRQ(ierr);
4058 #if 1
4059       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);
4060       for (p = 0; p < 6; ++p) {
4061         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);
4062       }
4063 #endif
4064     }
4065     /* Hybrid cells have 6 faces: Front, Back, Sides */
4066     /*
4067      3---------2---------2
4068      |         |         |
4069      |    D    2    C    |
4070      |         |         |
4071      3----3----0----1----1
4072      |         |         |
4073      |    A    0    B    |
4074      |         |         |
4075      0---------0---------1
4076      */
4077     for (c = cMax; c < cEnd; ++c) {
4078       const PetscInt  newp = (cMax - cStart)*8 + (c - cMax)*4;
4079       const PetscInt *cone, *ornt, *fornt;
4080       PetscInt        coneNew[6], orntNew[6];
4081 
4082       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
4083       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
4084       ierr = DMPlexGetConeOrientation(dm, cone[0], &fornt);CHKERRQ(ierr);
4085       for (r = 0; r < 4; ++r) {
4086         PetscInt subfA = GetQuadSubface_Static(ornt[0], r);
4087         PetscInt edgeA = GetQuadEdge_Static(ornt[0], r);
4088         PetscInt edgeB = (edgeA+3)%4;
4089         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]);
4090         coneNew[0]         = fStartNew + (cone[0] - fStart)*4 + subfA;
4091         orntNew[0]         = ornt[0];
4092         coneNew[1]         = fStartNew + (cone[1] - fStart)*4 + subfA;
4093         orntNew[1]         = ornt[0];
4094         coneNew[(r+0)%4+2] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (cone[edgeA+2] - fMax)*2 + (fornt[edgeA] < 0 ? 1 : 0);
4095         orntNew[(r+0)%4+2] = ornt[edgeA];
4096         coneNew[(r+1)%4+2] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd          - fMax)*2 + (c - cMax)*4 + edgeA;
4097         orntNew[(r+1)%4+2] = 0;
4098         coneNew[(r+2)%4+2] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd          - fMax)*2 + (c - cMax)*4 + edgeB;
4099         orntNew[(r+2)%4+2] = -2;
4100         coneNew[(r+3)%4+2] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (cone[edgeB+2] - fMax)*2 + (fornt[edgeB] < 0 ? 0 : 1);
4101         orntNew[(r+3)%4+2] = ornt[edgeB];
4102         ierr       = DMPlexSetCone(rdm, newp+r, coneNew);CHKERRQ(ierr);
4103         ierr       = DMPlexSetConeOrientation(rdm, newp+r, orntNew);CHKERRQ(ierr);
4104 #if 1
4105         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);
4106         for (p = 0; p < 2; ++p) {
4107           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);
4108         }
4109         for (p = 2; p < 6; ++p) {
4110           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);
4111         }
4112 #endif
4113       }
4114     }
4115     /* Interior split faces have 4 edges and the same cells as the parent */
4116     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
4117     ierr = PetscMalloc1((4 + maxSupportSize*2), &supportRef);CHKERRQ(ierr);
4118     for (f = fStart; f < fMax; ++f) {
4119       for (r = 0; r < 4; ++r) {
4120         /* TODO: This can come from GetFaces_Internal() */
4121         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};
4122         const PetscInt  newp = fStartNew + (f - fStart)*4 + r;
4123         const PetscInt *cone, *ornt, *support;
4124         PetscInt        coneNew[4], orntNew[4], coneSize, c, supportSize, s;
4125 
4126         ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
4127         ierr = DMPlexGetConeOrientation(dm, f, &ornt);CHKERRQ(ierr);
4128         coneNew[(r+3)%4] = eStartNew + (cone[(r+3)%4] - eStart)*2 + (ornt[(r+3)%4] < 0 ? 0 : 1);
4129         orntNew[(r+3)%4] = ornt[(r+3)%4];
4130         coneNew[(r+0)%4] = eStartNew + (cone[r]       - eStart)*2 + (ornt[r] < 0 ? 1 : 0);
4131         orntNew[(r+0)%4] = ornt[r];
4132         coneNew[(r+1)%4] = eStartNew + (eMax - eStart)*2 + (f - fStart)*4 + r;
4133         orntNew[(r+1)%4] = 0;
4134         coneNew[(r+2)%4] = eStartNew + (eMax - eStart)*2 + (f - fStart)*4 + (r+3)%4;
4135         orntNew[(r+2)%4] = -2;
4136         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4137         ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4138 #if 1
4139         if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
4140         for (p = 0; p < 4; ++p) {
4141           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);
4142         }
4143 #endif
4144         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
4145         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
4146         for (s = 0; s < supportSize; ++s) {
4147           PetscInt subf;
4148           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
4149           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
4150           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
4151           for (c = 0; c < coneSize; ++c) {
4152             if (cone[c] == f) break;
4153           }
4154           subf = GetQuadSubfaceInverse_Static(ornt[c], r);
4155           if (support[s] < cMax) {
4156             supportRef[s] = cStartNew + (support[s] - cStart)*8 + newCells[c*4+subf];
4157           } else {
4158             supportRef[s] = cStartNew + (cMax       - cStart)*8 + (support[s] - cMax)*4 + subf;
4159           }
4160         }
4161         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
4162 #if 1
4163         if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
4164         for (p = 0; p < supportSize; ++p) {
4165           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);
4166         }
4167 #endif
4168       }
4169     }
4170     /* Interior faces have 4 edges and 2 cells */
4171     for (c = cStart; c < cMax; ++c) {
4172       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};
4173       const PetscInt *cone, *ornt;
4174       PetscInt        newp, coneNew[4], orntNew[4], supportNew[2];
4175 
4176       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
4177       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
4178       /* A-D face */
4179       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 0;
4180       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*4 + GetQuadEdge_Static(ornt[0], 3);
4181       orntNew[0] = 0;
4182       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 0;
4183       orntNew[1] = 0;
4184       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 2;
4185       orntNew[2] = -2;
4186       coneNew[3] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*4 + GetQuadEdge_Static(ornt[2], 0);
4187       orntNew[3] = -2;
4188       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4189       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4190 #if 1
4191       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
4192       for (p = 0; p < 4; ++p) {
4193         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);
4194       }
4195 #endif
4196       /* C-D face */
4197       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 1;
4198       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*4 + GetQuadEdge_Static(ornt[0], 2);
4199       orntNew[0] = 0;
4200       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 0;
4201       orntNew[1] = 0;
4202       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 4;
4203       orntNew[2] = -2;
4204       coneNew[3] = eStartNew + (eMax - eStart)*2 + (cone[4] - fStart)*4 + GetQuadEdge_Static(ornt[4], 0);
4205       orntNew[3] = -2;
4206       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4207       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4208 #if 1
4209       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
4210       for (p = 0; p < 4; ++p) {
4211         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);
4212       }
4213 #endif
4214       /* B-C face */
4215       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 2;
4216       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*4 + GetQuadEdge_Static(ornt[0], 1);
4217       orntNew[0] = -2;
4218       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*4 + GetQuadEdge_Static(ornt[3], 0);
4219       orntNew[1] = 0;
4220       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 3;
4221       orntNew[2] = 0;
4222       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 0;
4223       orntNew[3] = -2;
4224       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4225       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4226 #if 1
4227       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
4228       for (p = 0; p < 4; ++p) {
4229         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);
4230       }
4231 #endif
4232       /* A-B face */
4233       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 3;
4234       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*4 + GetQuadEdge_Static(ornt[0], 0);
4235       orntNew[0] = -2;
4236       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[5] - fStart)*4 + GetQuadEdge_Static(ornt[5], 3);
4237       orntNew[1] = 0;
4238       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 5;
4239       orntNew[2] = 0;
4240       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 0;
4241       orntNew[3] = -2;
4242       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4243       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4244 #if 1
4245       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
4246       for (p = 0; p < 4; ++p) {
4247         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);
4248       }
4249 #endif
4250       /* E-F face */
4251       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 4;
4252       coneNew[0] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 2;
4253       orntNew[0] = -2;
4254       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*4 + GetQuadEdge_Static(ornt[2], 2);
4255       orntNew[1] = -2;
4256       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*4 + GetQuadEdge_Static(ornt[1], 0);
4257       orntNew[2] = 0;
4258       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 1;
4259       orntNew[3] = 0;
4260       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4261       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4262 #if 1
4263       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
4264       for (p = 0; p < 4; ++p) {
4265         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);
4266       }
4267 #endif
4268       /* F-G face */
4269       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 5;
4270       coneNew[0] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 4;
4271       orntNew[0] = -2;
4272       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[4] - fStart)*4 + GetQuadEdge_Static(ornt[4], 2);
4273       orntNew[1] = -2;
4274       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*4 + GetQuadEdge_Static(ornt[1], 1);
4275       orntNew[2] = 0;
4276       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 1;
4277       orntNew[3] = 0;
4278       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4279       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4280 #if 1
4281       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
4282       for (p = 0; p < 4; ++p) {
4283         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);
4284       }
4285 #endif
4286       /* G-H face */
4287       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 6;
4288       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*4 + GetQuadEdge_Static(ornt[3], 2);
4289       orntNew[0] = -2;
4290       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*4 + GetQuadEdge_Static(ornt[1], 2);
4291       orntNew[1] = 0;
4292       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 1;
4293       orntNew[2] = 0;
4294       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 3;
4295       orntNew[3] = -2;
4296       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4297       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4298 #if 1
4299       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
4300       for (p = 0; p < 4; ++p) {
4301         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);
4302       }
4303 #endif
4304       /* E-H face */
4305       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 7;
4306       coneNew[0] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 5;
4307       orntNew[0] = -2;
4308       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[5] - fStart)*4 + GetQuadEdge_Static(ornt[5], 1);
4309       orntNew[1] = -2;
4310       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*4 + GetQuadEdge_Static(ornt[1], 3);
4311       orntNew[2] = 0;
4312       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 1;
4313       orntNew[3] = 0;
4314       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4315       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4316 #if 1
4317       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
4318       for (p = 0; p < 4; ++p) {
4319         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);
4320       }
4321 #endif
4322       /* A-E face */
4323       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 8;
4324       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*4 + GetQuadEdge_Static(ornt[2], 3);
4325       orntNew[0] = 0;
4326       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 2;
4327       orntNew[1] = 0;
4328       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 5;
4329       orntNew[2] = -2;
4330       coneNew[3] = eStartNew + (eMax - eStart)*2 + (cone[5] - fStart)*4 + GetQuadEdge_Static(ornt[5], 0);
4331       orntNew[3] = -2;
4332       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4333       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4334 #if 1
4335       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
4336       for (p = 0; p < 4; ++p) {
4337         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);
4338       }
4339 #endif
4340       /* D-F face */
4341       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 9;
4342       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*4 + GetQuadEdge_Static(ornt[2], 1);
4343       orntNew[0] = -2;
4344       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[4] - fStart)*4 + GetQuadEdge_Static(ornt[4], 3);
4345       orntNew[1] = 0;
4346       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 4;
4347       orntNew[2] = 0;
4348       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 2;
4349       orntNew[3] = -2;
4350       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4351       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4352 #if 1
4353       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
4354       for (p = 0; p < 4; ++p) {
4355         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);
4356       }
4357 #endif
4358       /* C-G face */
4359       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 10;
4360       coneNew[0] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 4;
4361       orntNew[0] = -2;
4362       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[4] - fStart)*4 + GetQuadEdge_Static(ornt[4], 1);
4363       orntNew[1] = -2;
4364       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*4 + GetQuadEdge_Static(ornt[3], 3);
4365       orntNew[2] = 0;
4366       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 3;
4367       orntNew[3] = 0;
4368       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4369       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4370 #if 1
4371       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
4372       for (p = 0; p < 4; ++p) {
4373         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);
4374       }
4375 #endif
4376       /* B-H face */
4377       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 11;
4378       coneNew[0] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 5;
4379       orntNew[0] = 0;
4380       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 3;
4381       orntNew[1] = -2;
4382       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*4 + GetQuadEdge_Static(ornt[3], 1);
4383       orntNew[2] = -2;
4384       coneNew[3] = eStartNew + (eMax - eStart)*2 + (cone[5] - fStart)*4 + GetQuadEdge_Static(ornt[5], 2);
4385       orntNew[3] = 0;
4386       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4387       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4388 #if 1
4389       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
4390       for (p = 0; p < 4; ++p) {
4391         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);
4392       }
4393 #endif
4394       for (r = 0; r < 12; ++r) {
4395         newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + r;
4396         supportNew[0] = cStartNew + (c - cStart)*8 + newCells[r*2+0];
4397         supportNew[1] = cStartNew + (c - cStart)*8 + newCells[r*2+1];
4398         ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
4399 #if 1
4400         if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
4401         for (p = 0; p < 2; ++p) {
4402           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);
4403         }
4404 #endif
4405       }
4406     }
4407     /* Hybrid split faces have 4 edges and same cells */
4408     for (f = fMax; f < fEnd; ++f) {
4409       const PetscInt *cone, *ornt, *support;
4410       PetscInt        coneNew[4], orntNew[4];
4411       PetscInt        supportNew[2], size, s, c;
4412 
4413       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
4414       ierr = DMPlexGetConeOrientation(dm, f, &ornt);CHKERRQ(ierr);
4415       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
4416       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
4417       for (r = 0; r < 2; ++r) {
4418         const PetscInt newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (f - fMax)*2 + r;
4419 
4420         coneNew[0]   = eStartNew + (cone[0] - eStart)*2 + (ornt[0] < 0 ? 1-r : r);
4421         orntNew[0]   = ornt[0];
4422         coneNew[1]   = eStartNew + (cone[1] - eStart)*2 + (ornt[1] < 0 ? 1-r : r);
4423         orntNew[1]   = ornt[1];
4424         coneNew[2+r] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (cone[2+r] - eMax);
4425         orntNew[2+r] = 0;
4426         coneNew[3-r] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (eEnd      - eMax) + (f - fMax);
4427         orntNew[3-r] = 0;
4428         ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4429         ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4430 #if 1
4431         if ((newp < fMaxNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid face [%d, %d)", newp, fMaxNew, fEndNew);
4432         for (p = 0; p < 2; ++p) {
4433           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);
4434         }
4435         for (p = 2; p < 4; ++p) {
4436           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);
4437         }
4438 #endif
4439         for (s = 0; s < size; ++s) {
4440           const PetscInt *coneCell, *orntCell, *fornt;
4441 
4442           ierr = DMPlexGetCone(dm, support[s], &coneCell);CHKERRQ(ierr);
4443           ierr = DMPlexGetConeOrientation(dm, support[s], &orntCell);CHKERRQ(ierr);
4444           for (c = 2; c < 6; ++c) if (coneCell[c] == f) break;
4445           if (c >= 6) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Could not find face %d in cone of cell %d", f, support[s]);
4446           ierr = DMPlexGetConeOrientation(dm, coneCell[0], &fornt);CHKERRQ(ierr);
4447           supportNew[s] = cStartNew + (cMax - cStart)*8 + (support[s] - cMax)*4 + (GetQuadEdgeInverse_Static(orntCell[0], c-2) + (fornt[c-2] < 0 ? 1-r : r))%4;
4448         }
4449         ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
4450 #if 1
4451         if ((newp < fMaxNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid face [%d, %d)", newp, fMaxNew, fEndNew);
4452         for (p = 0; p < size; ++p) {
4453           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);
4454         }
4455 #endif
4456       }
4457     }
4458     /* Hybrid cell faces have 4 edges and 2 cells */
4459     for (c = cMax; c < cEnd; ++c) {
4460       PetscInt        newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd - fMax)*2 + (c - cMax)*4;
4461       const PetscInt *cone, *ornt;
4462       PetscInt        coneNew[4], orntNew[4];
4463       PetscInt        supportNew[2];
4464 
4465       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
4466       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
4467       for (r = 0; r < 4; ++r) {
4468         coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], r);
4469         orntNew[0] = 0;
4470         coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], r);
4471         orntNew[1] = 0;
4472         coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (eEnd - eMax) + (cone[2+GetQuadEdge_Static(ornt[0], r)] - fMax);
4473         orntNew[2] = 0;
4474         coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (eEnd - eMax) + (fEnd                                   - fMax) + (c - cMax);
4475         orntNew[3] = 0;
4476         ierr = DMPlexSetCone(rdm, newp+r, coneNew);CHKERRQ(ierr);
4477         ierr = DMPlexSetConeOrientation(rdm, newp+r, orntNew);CHKERRQ(ierr);
4478 #if 1
4479         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);
4480         for (p = 0; p < 2; ++p) {
4481           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);
4482         }
4483         for (p = 2; p < 4; ++p) {
4484           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);
4485         }
4486 #endif
4487         supportNew[0] = cStartNew + (cMax - cStart)*8 + (c - cMax)*4 + GetQuadSubface_Static(ornt[0], r);
4488         supportNew[1] = cStartNew + (cMax - cStart)*8 + (c - cMax)*4 + GetQuadSubface_Static(ornt[0], (r+1)%4);
4489         ierr          = DMPlexSetSupport(rdm, newp+r, supportNew);CHKERRQ(ierr);
4490 #if 1
4491         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);
4492         for (p = 0; p < 2; ++p) {
4493           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);
4494         }
4495 #endif
4496       }
4497     }
4498     /* Interior split edges have 2 vertices and the same faces as the parent */
4499     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
4500     for (e = eStart; e < eMax; ++e) {
4501       const PetscInt newv = vStartNew + (vEnd - vStart) + (e - eStart);
4502 
4503       for (r = 0; r < 2; ++r) {
4504         const PetscInt  newp = eStartNew + (e - eStart)*2 + r;
4505         const PetscInt *cone, *ornt, *support;
4506         PetscInt        coneNew[2], coneSize, c, supportSize, s;
4507 
4508         ierr             = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
4509         coneNew[0]       = vStartNew + (cone[0] - vStart);
4510         coneNew[1]       = vStartNew + (cone[1] - vStart);
4511         coneNew[(r+1)%2] = newv;
4512         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4513 #if 1
4514         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
4515         for (p = 0; p < 2; ++p) {
4516           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);
4517         }
4518 #endif
4519         ierr = DMPlexGetSupportSize(dm, e, &supportSize);CHKERRQ(ierr);
4520         ierr = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
4521         for (s = 0; s < supportSize; ++s) {
4522           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
4523           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
4524           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
4525           for (c = 0; c < coneSize; ++c) {
4526             if (cone[c] == e) break;
4527           }
4528           if (support[s] < fMax) {
4529             supportRef[s] = fStartNew + (support[s] - fStart)*4 + (c + (ornt[c] < 0 ? 1-r : r))%4;
4530           } else {
4531             supportRef[s] = fStartNew + (fMax       - fStart)*4 + (cMax - cStart)*12 + (support[s] - fMax)*2 + (ornt[c] < 0 ? 1-r : r);
4532           }
4533         }
4534         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
4535 #if 1
4536         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
4537         for (p = 0; p < supportSize; ++p) {
4538           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);
4539         }
4540 #endif
4541       }
4542     }
4543     /* Interior face edges have 2 vertices and 2+cells faces */
4544     for (f = fStart; f < fMax; ++f) {
4545       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};
4546       const PetscInt  newv = vStartNew + (vEnd - vStart) + (eMax - eStart) + (f - fStart);
4547       const PetscInt *cone, *coneCell, *orntCell, *support;
4548       PetscInt        coneNew[2], coneSize, c, supportSize, s;
4549 
4550       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
4551       for (r = 0; r < 4; ++r) {
4552         const PetscInt newp = eStartNew + (eMax - eStart)*2 + (f - fStart)*4 + r;
4553 
4554         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r] - eStart);
4555         coneNew[1] = newv;
4556         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4557 #if 1
4558         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
4559         for (p = 0; p < 2; ++p) {
4560           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);
4561         }
4562 #endif
4563         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
4564         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
4565         supportRef[0] = fStartNew + (f - fStart)*4 + r;
4566         supportRef[1] = fStartNew + (f - fStart)*4 + (r+1)%4;
4567         for (s = 0; s < supportSize; ++s) {
4568           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
4569           ierr = DMPlexGetCone(dm, support[s], &coneCell);CHKERRQ(ierr);
4570           ierr = DMPlexGetConeOrientation(dm, support[s], &orntCell);CHKERRQ(ierr);
4571           for (c = 0; c < coneSize; ++c) if (coneCell[c] == f) break;
4572           if (support[s] < cMax) {
4573             supportRef[2+s] = fStartNew + (fMax - fStart)*4 + (support[s] - cStart)*12 + newFaces[c*4 + GetQuadEdgeInverse_Static(orntCell[c], r)];
4574           } else {
4575             supportRef[2+s] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd - fMax)*2 + (support[s] - cMax)*4 + GetQuadEdgeInverse_Static(orntCell[c], r);
4576           }
4577         }
4578         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
4579 #if 1
4580         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
4581         for (p = 0; p < 2+supportSize; ++p) {
4582           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);
4583         }
4584 #endif
4585       }
4586     }
4587     /* Interior cell edges have 2 vertices and 4 faces */
4588     for (c = cStart; c < cMax; ++c) {
4589       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};
4590       const PetscInt  newv = vStartNew + (vEnd - vStart) + (eMax - eStart) + (fMax - fStart) + (c - cStart);
4591       const PetscInt *cone;
4592       PetscInt        coneNew[2], supportNew[4];
4593 
4594       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
4595       for (r = 0; r < 6; ++r) {
4596         const PetscInt newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (c - cStart)*6 + r;
4597 
4598         coneNew[0] = vStartNew + (vEnd - vStart) + (eMax - eStart) + (cone[r] - fStart);
4599         coneNew[1] = newv;
4600         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4601 #if 1
4602         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
4603         for (p = 0; p < 2; ++p) {
4604           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);
4605         }
4606 #endif
4607         for (f = 0; f < 4; ++f) supportNew[f] = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + newFaces[r*4+f];
4608         ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
4609 #if 1
4610         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
4611         for (p = 0; p < 4; ++p) {
4612           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);
4613         }
4614 #endif
4615       }
4616     }
4617     /* Hybrid edges have two vertices and the same faces */
4618     for (e = eMax; e < eEnd; ++e) {
4619       const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (e - eMax);
4620       const PetscInt *cone, *support, *fcone;
4621       PetscInt        coneNew[2], size, fsize, s;
4622 
4623       ierr = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
4624       ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
4625       ierr = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
4626       coneNew[0] = vStartNew + (cone[0] - vStart);
4627       coneNew[1] = vStartNew + (cone[1] - vStart);
4628       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4629 #if 1
4630       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid edge [%d, %d)", newp, eMaxNew, eEndNew);
4631       for (p = 0; p < 2; ++p) {
4632         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);
4633       }
4634 #endif
4635       for (s = 0; s < size; ++s) {
4636         ierr = DMPlexGetConeSize(dm, support[s], &fsize);CHKERRQ(ierr);
4637         ierr = DMPlexGetCone(dm, support[s], &fcone);CHKERRQ(ierr);
4638         for (c = 0; c < fsize; ++c) if (fcone[c] == e) break;
4639         if ((c < 2) || (c > 3)) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Edge %d not found in cone of face %d", e, support[s]);
4640         supportRef[s] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (support[s] - fMax)*2 + c-2;
4641       }
4642       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
4643 #if 1
4644       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid edge [%d, %d)", newp, eMaxNew, eEndNew);
4645       for (p = 0; p < size; ++p) {
4646         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);
4647       }
4648 #endif
4649     }
4650     /* Hybrid face edges have 2 vertices and 2+cells faces */
4651     for (f = fMax; f < fEnd; ++f) {
4652       const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (eEnd - eMax) + (f - fMax);
4653       const PetscInt *cone, *support, *ccone, *cornt;
4654       PetscInt        coneNew[2], size, csize, s;
4655 
4656       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
4657       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
4658       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
4659       coneNew[0] = vStartNew + (vEnd - vStart) + (cone[0] - eStart);
4660       coneNew[1] = vStartNew + (vEnd - vStart) + (cone[1] - eStart);
4661       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4662 #if 1
4663       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid edge [%d, %d)", newp, eMaxNew, eEndNew);
4664       for (p = 0; p < 2; ++p) {
4665         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);
4666       }
4667 #endif
4668       supportRef[0] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (f - fMax)*2 + 0;
4669       supportRef[1] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (f - fMax)*2 + 1;
4670       for (s = 0; s < size; ++s) {
4671         ierr = DMPlexGetConeSize(dm, support[s], &csize);CHKERRQ(ierr);
4672         ierr = DMPlexGetCone(dm, support[s], &ccone);CHKERRQ(ierr);
4673         ierr = DMPlexGetConeOrientation(dm, support[s], &cornt);CHKERRQ(ierr);
4674         for (c = 0; c < csize; ++c) if (ccone[c] == f) break;
4675         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]);
4676         supportRef[2+s] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd - fMax)*2 + (support[s] - cMax)*4 + GetQuadSubfaceInverse_Static(cornt[0], c-2);
4677       }
4678       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
4679 #if 1
4680       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid edge [%d, %d)", newp, eMaxNew, eEndNew);
4681       for (p = 0; p < 2+size; ++p) {
4682         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);
4683       }
4684 #endif
4685     }
4686     /* Hybrid cell edges have 2 vertices and 4 faces */
4687     for (c = cMax; c < cEnd; ++c) {
4688       const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (eEnd - eMax) + (fEnd - fMax) + (c - cMax);
4689       const PetscInt *cone, *support;
4690       PetscInt        coneNew[2], size;
4691 
4692       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
4693       ierr = DMPlexGetSupportSize(dm, c, &size);CHKERRQ(ierr);
4694       ierr = DMPlexGetSupport(dm, c, &support);CHKERRQ(ierr);
4695       coneNew[0] = vStartNew + (vEnd - vStart) + (eMax - eStart) + (cone[0] - fStart);
4696       coneNew[1] = vStartNew + (vEnd - vStart) + (eMax - eStart) + (cone[1] - fStart);
4697       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4698 #if 1
4699       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid edge [%d, %d)", newp, eMaxNew, eEndNew);
4700       for (p = 0; p < 2; ++p) {
4701         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);
4702       }
4703 #endif
4704       supportRef[0] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd - fMax)*2 + (c - cMax)*4 + 0;
4705       supportRef[1] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd - fMax)*2 + (c - cMax)*4 + 1;
4706       supportRef[2] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd - fMax)*2 + (c - cMax)*4 + 2;
4707       supportRef[3] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd - fMax)*2 + (c - cMax)*4 + 3;
4708       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
4709 #if 1
4710       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid edge [%d, %d)", newp, eMaxNew, eEndNew);
4711       for (p = 0; p < 4; ++p) {
4712         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);
4713       }
4714 #endif
4715     }
4716     /* Interior vertices have identical supports */
4717     for (v = vStart; v < vEnd; ++v) {
4718       const PetscInt  newp = vStartNew + (v - vStart);
4719       const PetscInt *support, *cone;
4720       PetscInt        size, s;
4721 
4722       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
4723       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
4724       for (s = 0; s < size; ++s) {
4725         PetscInt r = 0;
4726 
4727         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
4728         if (cone[1] == v) r = 1;
4729         if (support[s] < eMax) supportRef[s] = eStartNew + (support[s] - eStart)*2 + r;
4730         else                   supportRef[s] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (support[s] - eMax);
4731       }
4732       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
4733 #if 1
4734       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
4735       for (p = 0; p < size; ++p) {
4736         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);
4737       }
4738 #endif
4739     }
4740     /* Interior edge vertices have 2 + faces supports */
4741     for (e = eStart; e < eMax; ++e) {
4742       const PetscInt  newp = vStartNew + (vEnd - vStart) + (e - eStart);
4743       const PetscInt *cone, *support;
4744       PetscInt        size, s;
4745 
4746       ierr          = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
4747       ierr          = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
4748       supportRef[0] = eStartNew + (e - eStart)*2 + 0;
4749       supportRef[1] = eStartNew + (e - eStart)*2 + 1;
4750       for (s = 0; s < size; ++s) {
4751         PetscInt r;
4752 
4753         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
4754         for (r = 0; r < 4; ++r) if (cone[r] == e) break;
4755         if (support[s] < fMax) {
4756           supportRef[2+s] = eStartNew + (eMax - eStart)*2 + (support[s] - fStart)*4 + r;
4757         } else {
4758           supportRef[2+s] = eStartNew + (eMax - eStart)*2 + (fMax       - fStart)*4 + (cMax - cStart)*6 + (eEnd - eMax) + (support[s] - fMax);
4759         }
4760       }
4761       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
4762 #if 1
4763       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
4764       for (p = 0; p < 2+size; ++p) {
4765         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);
4766       }
4767 #endif
4768     }
4769     /* Interior face vertices have 4 + cells supports */
4770     for (f = fStart; f < fMax; ++f) {
4771       const PetscInt  newp = vStartNew + (vEnd - vStart) + (eMax - eStart) + (f - fStart);
4772       const PetscInt *cone, *support;
4773       PetscInt        size, s;
4774 
4775       ierr          = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
4776       ierr          = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
4777       for (r = 0; r < 4; ++r) supportRef[r] = eStartNew + (eMax - eStart)*2 +  (f - fStart)*4 + r;
4778       for (s = 0; s < size; ++s) {
4779         PetscInt r;
4780 
4781         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
4782         for (r = 0; r < 6; ++r) if (cone[r] == f) break;
4783         if (support[s] < cMax) {
4784           supportRef[4+s] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (support[s] - cStart)*6 + r;
4785         } else {
4786           supportRef[4+s] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax       - cStart)*6 + (eEnd - eMax) + (fEnd - fMax) + (support[s] - cMax);
4787         }
4788       }
4789       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
4790 #if 1
4791       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
4792       for (p = 0; p < 4+size; ++p) {
4793         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);
4794       }
4795 #endif
4796     }
4797     /* Cell vertices have 6 supports */
4798     for (c = cStart; c < cMax; ++c) {
4799       const PetscInt newp = vStartNew + (vEnd - vStart) + (eMax - eStart) + (fMax - fStart) + (c - cStart);
4800       PetscInt       supportNew[6];
4801 
4802       for (r = 0; r < 6; ++r) {
4803         supportNew[r] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (c - cStart)*6 + r;
4804       }
4805       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
4806     }
4807     ierr = PetscFree(supportRef);CHKERRQ(ierr);
4808     break;
4809   default:
4810     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
4811   }
4812   PetscFunctionReturn(0);
4813 }
4814 
4815 #undef __FUNCT__
4816 #define __FUNCT__ "CellRefinerSetCoordinates"
4817 static PetscErrorCode CellRefinerSetCoordinates(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
4818 {
4819   PetscSection   coordSection, coordSectionNew;
4820   Vec            coordinates, coordinatesNew;
4821   PetscScalar   *coords, *coordsNew;
4822   const PetscInt numVertices = depthSize ? depthSize[0] : 0;
4823   PetscInt       dim, depth, coordSizeNew, cStart, cEnd, cMax, c, vStart, vStartNew, vEnd, v, eStart, eEnd, eMax, e, fStart, fEnd, fMax, f;
4824   PetscErrorCode ierr;
4825 
4826   PetscFunctionBegin;
4827   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
4828   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
4829   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
4830   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
4831   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
4832   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
4833   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, NULL);CHKERRQ(ierr);
4834   if (refiner) {ierr = GetDepthStart_Private(depth, depthSize, NULL, NULL, NULL, &vStartNew);CHKERRQ(ierr);}
4835   ierr = GetDepthStart_Private(depth, depthSize, NULL, NULL, NULL, &vStartNew);CHKERRQ(ierr);
4836   ierr = DMGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
4837   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)dm), &coordSectionNew);CHKERRQ(ierr);
4838   ierr = PetscSectionSetNumFields(coordSectionNew, 1);CHKERRQ(ierr);
4839   ierr = PetscSectionSetFieldComponents(coordSectionNew, 0, dim);CHKERRQ(ierr);
4840   ierr = PetscSectionSetChart(coordSectionNew, vStartNew, vStartNew+numVertices);CHKERRQ(ierr);
4841   if (cMax < 0) cMax = cEnd;
4842   if (fMax < 0) fMax = fEnd;
4843   if (eMax < 0) eMax = eEnd;
4844   /* All vertices have the dim coordinates */
4845   for (v = vStartNew; v < vStartNew+numVertices; ++v) {
4846     ierr = PetscSectionSetDof(coordSectionNew, v, dim);CHKERRQ(ierr);
4847     ierr = PetscSectionSetFieldDof(coordSectionNew, v, 0, dim);CHKERRQ(ierr);
4848   }
4849   ierr = PetscSectionSetUp(coordSectionNew);CHKERRQ(ierr);
4850   ierr = DMSetCoordinateSection(rdm, coordSectionNew);CHKERRQ(ierr);
4851   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
4852   ierr = PetscSectionGetStorageSize(coordSectionNew, &coordSizeNew);CHKERRQ(ierr);
4853   ierr = VecCreate(PetscObjectComm((PetscObject)dm), &coordinatesNew);CHKERRQ(ierr);
4854   ierr = PetscObjectSetName((PetscObject) coordinatesNew, "coordinates");CHKERRQ(ierr);
4855   ierr = VecSetSizes(coordinatesNew, coordSizeNew, PETSC_DETERMINE);CHKERRQ(ierr);
4856   ierr = VecSetFromOptions(coordinatesNew);CHKERRQ(ierr);
4857   ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
4858   ierr = VecGetArray(coordinatesNew, &coordsNew);CHKERRQ(ierr);
4859   switch (refiner) {
4860   case 0: break;
4861   case 6: /* Hex 3D */
4862   case 8: /* Hybrid Hex 3D */
4863     /* Face vertices have the average of corner coordinates */
4864     for (f = fStart; f < fMax; ++f) {
4865       const PetscInt newv = vStartNew + (vEnd - vStart) + (eMax - eStart) + (f - fStart);
4866       PetscInt      *cone = NULL;
4867       PetscInt       closureSize, coneSize = 0, off[8], offnew, p, d;
4868 
4869       ierr = DMPlexGetTransitiveClosure(dm, f, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
4870       for (p = 0; p < closureSize*2; p += 2) {
4871         const PetscInt point = cone[p];
4872         if ((point >= vStart) && (point < vEnd)) cone[coneSize++] = point;
4873       }
4874       for (v = 0; v < coneSize; ++v) {
4875         ierr = PetscSectionGetOffset(coordSection, cone[v], &off[v]);CHKERRQ(ierr);
4876       }
4877       ierr = PetscSectionGetOffset(coordSectionNew, newv, &offnew);CHKERRQ(ierr);
4878       for (d = 0; d < dim; ++d) {
4879         coordsNew[offnew+d] = 0.0;
4880         for (v = 0; v < coneSize; ++v) coordsNew[offnew+d] += coords[off[v]+d];
4881         coordsNew[offnew+d] /= coneSize;
4882       }
4883       ierr = DMPlexRestoreTransitiveClosure(dm, f, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
4884     }
4885   case 2: /* Hex 2D */
4886     /* Cell vertices have the average of corner coordinates */
4887     for (c = cStart; c < cMax; ++c) {
4888       const PetscInt newv = vStartNew + (vEnd - vStart) + (eMax - eStart) + (c - cStart) + (dim > 2 ? (fMax - fStart) : 0);
4889       PetscInt      *cone = NULL;
4890       PetscInt       closureSize, coneSize = 0, off[8], offnew, p, d;
4891 
4892       ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
4893       for (p = 0; p < closureSize*2; p += 2) {
4894         const PetscInt point = cone[p];
4895         if ((point >= vStart) && (point < vEnd)) cone[coneSize++] = point;
4896       }
4897       for (v = 0; v < coneSize; ++v) {
4898         ierr = PetscSectionGetOffset(coordSection, cone[v], &off[v]);CHKERRQ(ierr);
4899       }
4900       ierr = PetscSectionGetOffset(coordSectionNew, newv, &offnew);CHKERRQ(ierr);
4901       for (d = 0; d < dim; ++d) {
4902         coordsNew[offnew+d] = 0.0;
4903         for (v = 0; v < coneSize; ++v) coordsNew[offnew+d] += coords[off[v]+d];
4904         coordsNew[offnew+d] /= coneSize;
4905       }
4906       ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
4907     }
4908   case 1: /* Simplicial 2D */
4909   case 3: /* Hybrid Simplicial 2D */
4910   case 5: /* Simplicial 3D */
4911   case 7: /* Hybrid Simplicial 3D */
4912     /* Edge vertices have the average of endpoint coordinates */
4913     for (e = eStart; e < eMax; ++e) {
4914       const PetscInt  newv = vStartNew + (vEnd - vStart) + (e - eStart);
4915       const PetscInt *cone;
4916       PetscInt        coneSize, offA, offB, offnew, d;
4917 
4918       ierr = DMPlexGetConeSize(dm, e, &coneSize);CHKERRQ(ierr);
4919       if (coneSize != 2) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Edge %d cone should have two vertices, not %d", e, coneSize);
4920       ierr = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
4921       ierr = PetscSectionGetOffset(coordSection, cone[0], &offA);CHKERRQ(ierr);
4922       ierr = PetscSectionGetOffset(coordSection, cone[1], &offB);CHKERRQ(ierr);
4923       ierr = PetscSectionGetOffset(coordSectionNew, newv, &offnew);CHKERRQ(ierr);
4924       for (d = 0; d < dim; ++d) {
4925         coordsNew[offnew+d] = 0.5*(coords[offA+d] + coords[offB+d]);
4926       }
4927     }
4928     /* Old vertices have the same coordinates */
4929     for (v = vStart; v < vEnd; ++v) {
4930       const PetscInt newv = vStartNew + (v - vStart);
4931       PetscInt       off, offnew, d;
4932 
4933       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
4934       ierr = PetscSectionGetOffset(coordSectionNew, newv, &offnew);CHKERRQ(ierr);
4935       for (d = 0; d < dim; ++d) {
4936         coordsNew[offnew+d] = coords[off+d];
4937       }
4938     }
4939     break;
4940   default:
4941     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
4942   }
4943   ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
4944   ierr = VecRestoreArray(coordinatesNew, &coordsNew);CHKERRQ(ierr);
4945   ierr = DMSetCoordinatesLocal(rdm, coordinatesNew);CHKERRQ(ierr);
4946   ierr = VecDestroy(&coordinatesNew);CHKERRQ(ierr);
4947   ierr = PetscSectionDestroy(&coordSectionNew);CHKERRQ(ierr);
4948   PetscFunctionReturn(0);
4949 }
4950 
4951 #undef __FUNCT__
4952 #define __FUNCT__ "DMPlexCreateProcessSF"
4953 static PetscErrorCode DMPlexCreateProcessSF(DM dm, PetscSF sfPoint, IS *processRanks, PetscSF *sfProcess)
4954 {
4955   PetscInt           numRoots, numLeaves, l;
4956   const PetscInt    *localPoints;
4957   const PetscSFNode *remotePoints;
4958   PetscInt          *localPointsNew;
4959   PetscSFNode       *remotePointsNew;
4960   PetscInt          *ranks, *ranksNew;
4961   PetscErrorCode     ierr;
4962 
4963   PetscFunctionBegin;
4964   ierr = PetscSFGetGraph(sfPoint, &numRoots, &numLeaves, &localPoints, &remotePoints);CHKERRQ(ierr);
4965   ierr = PetscMalloc1(numLeaves, &ranks);CHKERRQ(ierr);
4966   for (l = 0; l < numLeaves; ++l) {
4967     ranks[l] = remotePoints[l].rank;
4968   }
4969   ierr = PetscSortRemoveDupsInt(&numLeaves, ranks);CHKERRQ(ierr);
4970   ierr = PetscMalloc1(numLeaves,    &ranksNew);CHKERRQ(ierr);
4971   ierr = PetscMalloc1(numLeaves,    &localPointsNew);CHKERRQ(ierr);
4972   ierr = PetscMalloc1(numLeaves, &remotePointsNew);CHKERRQ(ierr);
4973   for (l = 0; l < numLeaves; ++l) {
4974     ranksNew[l]              = ranks[l];
4975     localPointsNew[l]        = l;
4976     remotePointsNew[l].index = 0;
4977     remotePointsNew[l].rank  = ranksNew[l];
4978   }
4979   ierr = PetscFree(ranks);CHKERRQ(ierr);
4980   ierr = ISCreateGeneral(PetscObjectComm((PetscObject)dm), numLeaves, ranksNew, PETSC_OWN_POINTER, processRanks);CHKERRQ(ierr);
4981   ierr = PetscSFCreate(PetscObjectComm((PetscObject)dm), sfProcess);CHKERRQ(ierr);
4982   ierr = PetscSFSetFromOptions(*sfProcess);CHKERRQ(ierr);
4983   ierr = PetscSFSetGraph(*sfProcess, 1, numLeaves, localPointsNew, PETSC_OWN_POINTER, remotePointsNew, PETSC_OWN_POINTER);CHKERRQ(ierr);
4984   PetscFunctionReturn(0);
4985 }
4986 
4987 #undef __FUNCT__
4988 #define __FUNCT__ "CellRefinerCreateSF"
4989 static PetscErrorCode CellRefinerCreateSF(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
4990 {
4991   PetscSF            sf, sfNew, sfProcess;
4992   IS                 processRanks;
4993   MPI_Datatype       depthType;
4994   PetscInt           numRoots, numLeaves, numLeavesNew = 0, l, m;
4995   const PetscInt    *localPoints, *neighbors;
4996   const PetscSFNode *remotePoints;
4997   PetscInt          *localPointsNew;
4998   PetscSFNode       *remotePointsNew;
4999   PetscInt          *depthSizeOld, *rdepthSize, *rdepthSizeOld, *rdepthMaxOld, *rvStart, *rvStartNew, *reStart, *reStartNew, *rfStart, *rfStartNew, *rcStart, *rcStartNew;
5000   PetscInt           depth, numNeighbors, pStartNew, pEndNew, cStart, cEnd, cMax, vStart, vEnd, vMax, fStart, fEnd, fMax, eStart, eEnd, eMax, r, n;
5001   PetscInt           cStartNew = 0, vStartNew = 0, fStartNew = 0, eStartNew = 0;
5002   PetscErrorCode     ierr;
5003 
5004   PetscFunctionBegin;
5005   ierr = DMPlexGetChart(rdm, &pStartNew, &pEndNew);CHKERRQ(ierr);
5006   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
5007   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
5008   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
5009   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
5010   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
5011   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
5012   if (refiner) {ierr = GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);CHKERRQ(ierr);}
5013   ierr = DMGetPointSF(dm, &sf);CHKERRQ(ierr);
5014   ierr = DMGetPointSF(rdm, &sfNew);CHKERRQ(ierr);
5015   /* Caculate size of new SF */
5016   ierr = PetscSFGetGraph(sf, &numRoots, &numLeaves, &localPoints, &remotePoints);CHKERRQ(ierr);
5017   if (numRoots < 0) PetscFunctionReturn(0);
5018   for (l = 0; l < numLeaves; ++l) {
5019     const PetscInt p = localPoints[l];
5020 
5021     switch (refiner) {
5022     case 1:
5023       /* Simplicial 2D */
5024       if ((p >= vStart) && (p < vEnd)) {
5025         /* Old vertices stay the same */
5026         ++numLeavesNew;
5027       } else if ((p >= fStart) && (p < fEnd)) {
5028         /* Old faces add new faces and vertex */
5029         numLeavesNew += 2 + 1;
5030       } else if ((p >= cStart) && (p < cEnd)) {
5031         /* Old cells add new cells and interior faces */
5032         numLeavesNew += 4 + 3;
5033       }
5034       break;
5035     case 2:
5036       /* Hex 2D */
5037       if ((p >= vStart) && (p < vEnd)) {
5038         /* Old vertices stay the same */
5039         ++numLeavesNew;
5040       } else if ((p >= fStart) && (p < fEnd)) {
5041         /* Old faces add new faces and vertex */
5042         numLeavesNew += 2 + 1;
5043       } else if ((p >= cStart) && (p < cEnd)) {
5044         /* Old cells add new cells, interior faces, and vertex */
5045         numLeavesNew += 4 + 4 + 1;
5046       }
5047       break;
5048     case 5:
5049       /* Simplicial 3D */
5050       if ((p >= vStart) && (p < vEnd)) {
5051         /* Old vertices stay the same */
5052         ++numLeavesNew;
5053       } else if ((p >= eStart) && (p < eEnd)) {
5054         /* Old edges add new edges and vertex */
5055         numLeavesNew += 2 + 1;
5056       } else if ((p >= fStart) && (p < fEnd)) {
5057         /* Old faces add new faces and face edges */
5058         numLeavesNew += 4 + 3;
5059       } else if ((p >= cStart) && (p < cEnd)) {
5060         /* Old cells add new cells and interior faces and edges */
5061         numLeavesNew += 8 + 8 + 1;
5062       }
5063       break;
5064     case 7:
5065       /* Hybrid Simplicial 3D */
5066       if ((p >= vStart) && (p < vEnd)) {
5067         /* Interior vertices stay the same */
5068         ++numLeavesNew;
5069       } else if ((p >= eStart) && (p < eMax)) {
5070         /* Interior edges add new edges and vertex */
5071         numLeavesNew += 2 + 1;
5072       } else if ((p >= eMax) && (p < eEnd)) {
5073         /* Hybrid edges stay the same */
5074         ++numLeavesNew;
5075       } else if ((p >= fStart) && (p < fMax)) {
5076         /* Interior faces add new faces and edges */
5077         numLeavesNew += 4 + 3;
5078       } else if ((p >= fMax) && (p < fEnd)) {
5079         /* Hybrid faces add new faces and edges */
5080         numLeavesNew += 2 + 1;
5081       } else if ((p >= cStart) && (p < cMax)) {
5082         /* Interior cells add new cells, faces, and edges */
5083         numLeavesNew += 8 + 8 + 1;
5084       } else if ((p >= cMax) && (p < cEnd)) {
5085         /* Hybrid cells add new cells and faces */
5086         numLeavesNew += 4 + 3;
5087       }
5088       break;
5089     case 6:
5090       /* Hex 3D */
5091       if ((p >= vStart) && (p < vEnd)) {
5092         /* Old vertices stay the same */
5093         ++numLeavesNew;
5094       } else if ((p >= eStart) && (p < eEnd)) {
5095         /* Old edges add new edges, and vertex */
5096         numLeavesNew += 2 + 1;
5097       } else if ((p >= fStart) && (p < fEnd)) {
5098         /* Old faces add new faces, edges, and vertex */
5099         numLeavesNew += 4 + 4 + 1;
5100       } else if ((p >= cStart) && (p < cEnd)) {
5101         /* Old cells add new cells, faces, edges, and vertex */
5102         numLeavesNew += 8 + 12 + 6 + 1;
5103       }
5104       break;
5105     case 8:
5106       /* Hybrid Hex 3D */
5107       if ((p >= vStart) && (p < vEnd)) {
5108         /* Old vertices stay the same */
5109         ++numLeavesNew;
5110       } else if ((p >= eStart) && (p < eMax)) {
5111         /* Interior edges add new edges, and vertex */
5112         numLeavesNew += 2 + 1;
5113       } else if ((p >= eMax) && (p < eEnd)) {
5114         /* Hybrid edges stay the same */
5115         ++numLeavesNew;
5116       } else if ((p >= fStart) && (p < fMax)) {
5117         /* Interior faces add new faces, edges, and vertex */
5118         numLeavesNew += 4 + 4 + 1;
5119       } else if ((p >= fMax) && (p < fEnd)) {
5120         /* Hybrid faces add new faces and edges */
5121         numLeavesNew += 2 + 1;
5122       } else if ((p >= cStart) && (p < cMax)) {
5123         /* Interior cells add new cells, faces, edges, and vertex */
5124         numLeavesNew += 8 + 12 + 6 + 1;
5125       } else if ((p >= cStart) && (p < cEnd)) {
5126         /* Hybrid cells add new cells, faces, and edges */
5127         numLeavesNew += 4 + 4 + 1;
5128       }
5129       break;
5130     default:
5131       SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
5132     }
5133   }
5134   /* Communicate depthSizes for each remote rank */
5135   ierr = DMPlexCreateProcessSF(dm, sf, &processRanks, &sfProcess);CHKERRQ(ierr);
5136   ierr = ISGetLocalSize(processRanks, &numNeighbors);CHKERRQ(ierr);
5137   ierr = PetscMalloc5((depth+1)*numNeighbors,&rdepthSize,numNeighbors,&rvStartNew,numNeighbors,&reStartNew,numNeighbors,&rfStartNew,numNeighbors,&rcStartNew);CHKERRQ(ierr);
5138   ierr = PetscMalloc7(depth+1,&depthSizeOld,(depth+1)*numNeighbors,&rdepthSizeOld,(depth+1)*numNeighbors,&rdepthMaxOld,numNeighbors,&rvStart,numNeighbors,&reStart,numNeighbors,&rfStart,numNeighbors,&rcStart);CHKERRQ(ierr);
5139   ierr = MPI_Type_contiguous(depth+1, MPIU_INT, &depthType);CHKERRQ(ierr);
5140   ierr = MPI_Type_commit(&depthType);CHKERRQ(ierr);
5141   ierr = PetscSFBcastBegin(sfProcess, depthType, depthSize, rdepthSize);CHKERRQ(ierr);
5142   ierr = PetscSFBcastEnd(sfProcess, depthType, depthSize, rdepthSize);CHKERRQ(ierr);
5143   for (n = 0; n < numNeighbors; ++n) {
5144     ierr = GetDepthStart_Private(depth, &rdepthSize[n*(depth+1)], &rcStartNew[n], &rfStartNew[n], &reStartNew[n], &rvStartNew[n]);CHKERRQ(ierr);
5145   }
5146   depthSizeOld[depth]   = cMax;
5147   depthSizeOld[0]       = vMax;
5148   depthSizeOld[depth-1] = fMax;
5149   depthSizeOld[1]       = eMax;
5150 
5151   ierr = PetscSFBcastBegin(sfProcess, depthType, depthSizeOld, rdepthMaxOld);CHKERRQ(ierr);
5152   ierr = PetscSFBcastEnd(sfProcess, depthType, depthSizeOld, rdepthMaxOld);CHKERRQ(ierr);
5153 
5154   depthSizeOld[depth]   = cEnd - cStart;
5155   depthSizeOld[0]       = vEnd - vStart;
5156   depthSizeOld[depth-1] = fEnd - fStart;
5157   depthSizeOld[1]       = eEnd - eStart;
5158 
5159   ierr = PetscSFBcastBegin(sfProcess, depthType, depthSizeOld, rdepthSizeOld);CHKERRQ(ierr);
5160   ierr = PetscSFBcastEnd(sfProcess, depthType, depthSizeOld, rdepthSizeOld);CHKERRQ(ierr);
5161   for (n = 0; n < numNeighbors; ++n) {
5162     ierr = GetDepthStart_Private(depth, &rdepthSizeOld[n*(depth+1)], &rcStart[n], &rfStart[n], &reStart[n], &rvStart[n]);CHKERRQ(ierr);
5163   }
5164   ierr = MPI_Type_free(&depthType);CHKERRQ(ierr);
5165   ierr = PetscSFDestroy(&sfProcess);CHKERRQ(ierr);
5166   /* Calculate new point SF */
5167   ierr = PetscMalloc1(numLeavesNew,    &localPointsNew);CHKERRQ(ierr);
5168   ierr = PetscMalloc1(numLeavesNew, &remotePointsNew);CHKERRQ(ierr);
5169   ierr = ISGetIndices(processRanks, &neighbors);CHKERRQ(ierr);
5170   for (l = 0, m = 0; l < numLeaves; ++l) {
5171     PetscInt    p     = localPoints[l];
5172     PetscInt    rp    = remotePoints[l].index, n;
5173     PetscMPIInt rrank = remotePoints[l].rank;
5174 
5175     ierr = PetscFindInt(rrank, numNeighbors, neighbors, &n);CHKERRQ(ierr);
5176     if (n < 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Could not locate remote rank %d", rrank);
5177     switch (refiner) {
5178     case 1:
5179       /* Simplicial 2D */
5180       if ((p >= vStart) && (p < vEnd)) {
5181         /* Old vertices stay the same */
5182         localPointsNew[m]        = vStartNew     + (p  - vStart);
5183         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
5184         remotePointsNew[m].rank  = rrank;
5185         ++m;
5186       } else if ((p >= fStart) && (p < fEnd)) {
5187         /* Old faces add new faces and vertex */
5188         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - fStart);
5189         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - rfStart[n]);
5190         remotePointsNew[m].rank  = rrank;
5191         ++m;
5192         for (r = 0; r < 2; ++r, ++m) {
5193           localPointsNew[m]        = fStartNew     + (p  - fStart)*2     + r;
5194           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*2 + r;
5195           remotePointsNew[m].rank  = rrank;
5196         }
5197       } else if ((p >= cStart) && (p < cEnd)) {
5198         /* Old cells add new cells and interior faces */
5199         for (r = 0; r < 4; ++r, ++m) {
5200           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
5201           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
5202           remotePointsNew[m].rank  = rrank;
5203         }
5204         for (r = 0; r < 3; ++r, ++m) {
5205           localPointsNew[m]        = fStartNew     + (fEnd - fStart)*2                    + (p  - cStart)*3     + r;
5206           remotePointsNew[m].index = rfStartNew[n] + rdepthSizeOld[n*(depth+1)+depth-1]*2 + (rp - rcStart[n])*3 + r;
5207           remotePointsNew[m].rank  = rrank;
5208         }
5209       }
5210       break;
5211     case 2:
5212       /* Hex 2D */
5213       if ((p >= vStart) && (p < vEnd)) {
5214         /* Old vertices stay the same */
5215         localPointsNew[m]        = vStartNew     + (p  - vStart);
5216         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
5217         remotePointsNew[m].rank  = rrank;
5218         ++m;
5219       } else if ((p >= fStart) && (p < fEnd)) {
5220         /* Old faces add new faces and vertex */
5221         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - fStart);
5222         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - rfStart[n]);
5223         remotePointsNew[m].rank  = rrank;
5224         ++m;
5225         for (r = 0; r < 2; ++r, ++m) {
5226           localPointsNew[m]        = fStartNew     + (p  - fStart)*2     + r;
5227           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*2 + r;
5228           remotePointsNew[m].rank  = rrank;
5229         }
5230       } else if ((p >= cStart) && (p < cEnd)) {
5231         /* Old cells add new cells, interior faces, and vertex */
5232         for (r = 0; r < 4; ++r, ++m) {
5233           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
5234           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
5235           remotePointsNew[m].rank  = rrank;
5236         }
5237         for (r = 0; r < 4; ++r, ++m) {
5238           localPointsNew[m]        = fStartNew     + (fEnd - fStart)*2                    + (p  - cStart)*4     + r;
5239           remotePointsNew[m].index = rfStartNew[n] + rdepthSizeOld[n*(depth+1)+depth-1]*2 + (rp - rcStart[n])*4 + r;
5240           remotePointsNew[m].rank  = rrank;
5241         }
5242         for (r = 0; r < 1; ++r, ++m) {
5243           localPointsNew[m]        = vStartNew     + (fEnd - fStart)                    + (p  - cStart)     + r;
5244           remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+depth-1] + (rp - rcStart[n]) + r;
5245           remotePointsNew[m].rank  = rrank;
5246         }
5247       }
5248       break;
5249     case 3:
5250       /* Hybrid simplicial 2D */
5251       if ((p >= vStart) && (p < vEnd)) {
5252         /* Old vertices stay the same */
5253         localPointsNew[m]        = vStartNew     + (p  - vStart);
5254         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
5255         remotePointsNew[m].rank  = rrank;
5256         ++m;
5257       } else if ((p >= fStart) && (p < fMax)) {
5258         /* Old interior faces add new faces and vertex */
5259         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - fStart);
5260         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - rfStart[n]);
5261         remotePointsNew[m].rank  = rrank;
5262         ++m;
5263         for (r = 0; r < 2; ++r, ++m) {
5264           localPointsNew[m]        = fStartNew     + (p  - fStart)*2     + r;
5265           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*2 + r;
5266           remotePointsNew[m].rank  = rrank;
5267         }
5268       } else if ((p >= fMax) && (p < fEnd)) {
5269         /* Old hybrid faces stay the same */
5270         localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (p  - fMax);
5271         remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*2 + (rp - rdepthMaxOld[n*(depth+1)+depth-1]);
5272         remotePointsNew[m].rank  = rrank;
5273         ++m;
5274       } else if ((p >= cStart) && (p < cMax)) {
5275         /* Old interior cells add new cells and interior faces */
5276         for (r = 0; r < 4; ++r, ++m) {
5277           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
5278           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
5279           remotePointsNew[m].rank  = rrank;
5280         }
5281         for (r = 0; r < 3; ++r, ++m) {
5282           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (p  - cStart)*3     + r;
5283           remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*2 + (rp - rcStart[n])*3 + r;
5284           remotePointsNew[m].rank  = rrank;
5285         }
5286       } else if ((p >= cStart) && (p < cMax)) {
5287         /* Old hybrid cells add new cells and hybrid face */
5288         for (r = 0; r < 2; ++r, ++m) {
5289           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
5290           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
5291           remotePointsNew[m].rank  = rrank;
5292         }
5293         localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (cMax                            - cStart)*3     + (p  - cMax);
5294         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]);
5295         remotePointsNew[m].rank  = rrank;
5296         ++m;
5297       }
5298       break;
5299     case 5:
5300       /* Simplicial 3D */
5301       if ((p >= vStart) && (p < vEnd)) {
5302         /* Old vertices stay the same */
5303         localPointsNew[m]        = vStartNew     + (p  - vStart);
5304         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
5305         remotePointsNew[m].rank  = rrank;
5306         ++m;
5307       } else if ((p >= eStart) && (p < eEnd)) {
5308         /* Old edges add new edges and vertex */
5309         for (r = 0; r < 2; ++r, ++m) {
5310           localPointsNew[m]        = eStartNew     + (p  - eStart)*2     + r;
5311           remotePointsNew[m].index = reStartNew[n] + (rp - reStart[n])*2 + r;
5312           remotePointsNew[m].rank  = rrank;
5313         }
5314         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - eStart);
5315         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - reStart[n]);
5316         remotePointsNew[m].rank  = rrank;
5317         ++m;
5318       } else if ((p >= fStart) && (p < fEnd)) {
5319         /* Old faces add new faces and face edges */
5320         for (r = 0; r < 4; ++r, ++m) {
5321           localPointsNew[m]        = fStartNew     + (p  - fStart)*4     + r;
5322           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*4 + r;
5323           remotePointsNew[m].rank  = rrank;
5324         }
5325         for (r = 0; r < 3; ++r, ++m) {
5326           localPointsNew[m]        = eStartNew     + (eEnd - eStart)*2              + (p  - fStart)*3     + r;
5327           remotePointsNew[m].index = reStartNew[n] + rdepthSizeOld[n*(depth+1)+1]*2 + (rp - rfStart[n])*3 + r;
5328           remotePointsNew[m].rank  = rrank;
5329         }
5330       } else if ((p >= cStart) && (p < cEnd)) {
5331         /* Old cells add new cells and interior faces and edges */
5332         for (r = 0; r < 8; ++r, ++m) {
5333           localPointsNew[m]        = cStartNew     + (p  - cStart)*8     + r;
5334           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*8 + r;
5335           remotePointsNew[m].rank  = rrank;
5336         }
5337         for (r = 0; r < 8; ++r, ++m) {
5338           localPointsNew[m]        = fStartNew     + (fEnd - fStart)*4                    + (p  - cStart)*8     + r;
5339           remotePointsNew[m].index = rfStartNew[n] + rdepthSizeOld[n*(depth+1)+depth-1]*4 + (rp - rcStart[n])*8 + r;
5340           remotePointsNew[m].rank  = rrank;
5341         }
5342         for (r = 0; r < 1; ++r, ++m) {
5343           localPointsNew[m]        = eStartNew     + (eEnd - eStart)*2              + (fEnd - fStart)*3                    + (p  - cStart)*1     + r;
5344           remotePointsNew[m].index = reStartNew[n] + rdepthSizeOld[n*(depth+1)+1]*2 + rdepthSizeOld[n*(depth+1)+depth-1]*3 + (rp - rcStart[n])*1 + r;
5345           remotePointsNew[m].rank  = rrank;
5346         }
5347       }
5348       break;
5349     case 7:
5350       /* Hybrid Simplicial 3D */
5351       if ((p >= vStart) && (p < vEnd)) {
5352         /* Interior vertices stay the same */
5353         localPointsNew[m]        = vStartNew     + (p  - vStart);
5354         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
5355         remotePointsNew[m].rank  = rrank;
5356         ++m;
5357       } else if ((p >= eStart) && (p < eMax)) {
5358         /* Interior edges add new edges and vertex */
5359         for (r = 0; r < 2; ++r, ++m) {
5360           localPointsNew[m]        = eStartNew     + (p  - eStart)*2     + r;
5361           remotePointsNew[m].index = reStartNew[n] + (rp - reStart[n])*2 + r;
5362           remotePointsNew[m].rank  = rrank;
5363         }
5364         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - eStart);
5365         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - reStart[n]);
5366         remotePointsNew[m].rank  = rrank;
5367         ++m;
5368       } else if ((p >= eMax) && (p < eEnd)) {
5369         /* Hybrid edges stay the same */
5370         localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (fMax                              - fStart)*3     + (cMax                            - cStart)     + (p  - eMax);
5371         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]);
5372         remotePointsNew[m].rank  = rrank;
5373         ++m;
5374       } else if ((p >= fStart) && (p < fMax)) {
5375         /* Interior faces add new faces and edges */
5376         for (r = 0; r < 4; ++r, ++m) {
5377           localPointsNew[m]        = fStartNew     + (p  - fStart)*4     + r;
5378           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*4 + r;
5379           remotePointsNew[m].rank  = rrank;
5380         }
5381         for (r = 0; r < 3; ++r, ++m) {
5382           localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (p  - fStart)*3     + r;
5383           remotePointsNew[m].index = reStartNew[n] + (rdepthMaxOld[n*(depth+1)+1] - reStart[n])*2 + (rp - rfStart[n])*3 + r;
5384           remotePointsNew[m].rank  = rrank;
5385         }
5386       } else if ((p >= fMax) && (p < fEnd)) {
5387         /* Hybrid faces add new faces and edges */
5388         for (r = 0; r < 2; ++r, ++m) {
5389           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*4     + (cMax                            - cStart)*8     + (p  - fMax)*2                              + r;
5390           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;
5391           remotePointsNew[m].rank  = rrank;
5392         }
5393         localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (fMax                              - fStart)*3     + (cMax                            - cStart)     + (p  - fMax);
5394         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]);
5395         remotePointsNew[m].rank  = rrank;
5396         ++m;
5397       } else if ((p >= cStart) && (p < cMax)) {
5398         /* Interior cells add new cells, faces, and edges */
5399         for (r = 0; r < 8; ++r, ++m) {
5400           localPointsNew[m]        = cStartNew     + (p  - cStart)*8     + r;
5401           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*8 + r;
5402           remotePointsNew[m].rank  = rrank;
5403         }
5404         for (r = 0; r < 8; ++r, ++m) {
5405           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*4     + (p  - cStart)*8     + r;
5406           remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*4 + (rp - rcStart[n])*8 + r;
5407           remotePointsNew[m].rank  = rrank;
5408         }
5409         localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (fMax                              - fStart)*3     + (p  - cStart)*1     + r;
5410         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;
5411         remotePointsNew[m].rank  = rrank;
5412         ++m;
5413       } else if ((p >= cMax) && (p < cEnd)) {
5414         /* Hybrid cells add new cells and faces */
5415         for (r = 0; r < 4; ++r, ++m) {
5416           localPointsNew[m]        = cStartNew     + (cMax                            - cStart)*8     + (p  - cMax)*4                            + r;
5417           remotePointsNew[m].index = rcStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth] - rcStart[n])*8 + (rp - rdepthMaxOld[n*(depth+1)+depth])*4 + r;
5418           remotePointsNew[m].rank  = rrank;
5419         }
5420         for (r = 0; r < 3; ++r, ++m) {
5421           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*4     + (cMax                            - cStart)*8     + (fEnd                                          - fMax)*2                              + (p  - cMax)*3                            + r;
5422           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;
5423           remotePointsNew[m].rank  = rrank;
5424         }
5425       }
5426       break;
5427     case 6:
5428       /* Hex 3D */
5429       if ((p >= vStart) && (p < vEnd)) {
5430         /* Old vertices stay the same */
5431         localPointsNew[m]        = vStartNew     + (p  - vStart);
5432         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
5433         remotePointsNew[m].rank  = rrank;
5434         ++m;
5435       } else if ((p >= eStart) && (p < eEnd)) {
5436         /* Old edges add new edges and vertex */
5437         for (r = 0; r < 2; ++r, ++m) {
5438           localPointsNew[m]        = eStartNew     + (p  - eStart)*2     + r;
5439           remotePointsNew[m].index = reStartNew[n] + (rp - reStart[n])*2 + r;
5440           remotePointsNew[m].rank  = rrank;
5441         }
5442         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - eStart);
5443         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - reStart[n]);
5444         remotePointsNew[m].rank  = rrank;
5445         ++m;
5446       } else if ((p >= fStart) && (p < fEnd)) {
5447         /* Old faces add new faces, edges, and vertex */
5448         for (r = 0; r < 4; ++r, ++m) {
5449           localPointsNew[m]        = fStartNew     + (p  - fStart)*4     + r;
5450           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*4 + r;
5451           remotePointsNew[m].rank  = rrank;
5452         }
5453         for (r = 0; r < 4; ++r, ++m) {
5454           localPointsNew[m]        = eStartNew     + (eEnd - eStart)*2              + (p  - fStart)*4     + r;
5455           remotePointsNew[m].index = reStartNew[n] + rdepthSizeOld[n*(depth+1)+1]*2 + (rp - rfStart[n])*4 + r;
5456           remotePointsNew[m].rank  = rrank;
5457         }
5458         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (eEnd - eStart)              + (p  - fStart);
5459         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + rdepthSizeOld[n*(depth+1)+1] + (rp - rfStart[n]);
5460         remotePointsNew[m].rank  = rrank;
5461         ++m;
5462       } else if ((p >= cStart) && (p < cEnd)) {
5463         /* Old cells add new cells, faces, edges, and vertex */
5464         for (r = 0; r < 8; ++r, ++m) {
5465           localPointsNew[m]        = cStartNew     + (p  - cStart)*8     + r;
5466           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*8 + r;
5467           remotePointsNew[m].rank  = rrank;
5468         }
5469         for (r = 0; r < 12; ++r, ++m) {
5470           localPointsNew[m]        = fStartNew     + (fEnd - fStart)*4                    + (p  - cStart)*12     + r;
5471           remotePointsNew[m].index = rfStartNew[n] + rdepthSizeOld[n*(depth+1)+depth-1]*4 + (rp - rcStart[n])*12 + r;
5472           remotePointsNew[m].rank  = rrank;
5473         }
5474         for (r = 0; r < 6; ++r, ++m) {
5475           localPointsNew[m]        = eStartNew     + (eEnd - eStart)*2              + (fEnd - fStart)*4                    + (p  - cStart)*6     + r;
5476           remotePointsNew[m].index = reStartNew[n] + rdepthSizeOld[n*(depth+1)+1]*2 + rdepthSizeOld[n*(depth+1)+depth-1]*4 + (rp - rcStart[n])*6 + r;
5477           remotePointsNew[m].rank  = rrank;
5478         }
5479         for (r = 0; r < 1; ++r, ++m) {
5480           localPointsNew[m]        = vStartNew     + (eEnd - eStart)              + (fEnd - fStart)                    + (p  - cStart)     + r;
5481           remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+1] + rdepthSizeOld[n*(depth+1)+depth-1] + (rp - rcStart[n]) + r;
5482           remotePointsNew[m].rank  = rrank;
5483         }
5484       }
5485       break;
5486     case 8:
5487       /* Hybrid Hex 3D */
5488       if ((p >= vStart) && (p < vEnd)) {
5489         /* Interior vertices stay the same */
5490         localPointsNew[m]        = vStartNew     + (p  - vStart);
5491         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
5492         remotePointsNew[m].rank  = rrank;
5493         ++m;
5494       } else if ((p >= eStart) && (p < eMax)) {
5495         /* Interior edges add new edges and vertex */
5496         for (r = 0; r < 2; ++r, ++m) {
5497           localPointsNew[m]        = eStartNew     + (p  - eStart)*2     + r;
5498           remotePointsNew[m].index = reStartNew[n] + (rp - reStart[n])*2 + r;
5499           remotePointsNew[m].rank  = rrank;
5500         }
5501         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - eStart);
5502         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - reStart[n]);
5503         remotePointsNew[m].rank  = rrank;
5504         ++m;
5505       } else if ((p >= eMax) && (p < eEnd)) {
5506         /* Hybrid edges stay the same */
5507         localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (fMax                              - fStart)*4     + (cMax                            - cStart)*6     + (p  - eMax);
5508         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]);
5509         remotePointsNew[m].rank  = rrank;
5510         ++m;
5511       } else if ((p >= fStart) && (p < fMax)) {
5512         /* Interior faces add new faces, edges, and vertex */
5513         for (r = 0; r < 4; ++r, ++m) {
5514           localPointsNew[m]        = fStartNew     + (p  - fStart)*4     + r;
5515           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*4 + r;
5516           remotePointsNew[m].rank  = rrank;
5517         }
5518         for (r = 0; r < 4; ++r, ++m) {
5519           localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (p  - fStart)*4     + r;
5520           remotePointsNew[m].index = reStartNew[n] + (rdepthMaxOld[n*(depth+1)+1] - reStart[n])*2 + (rp - rfStart[n])*4 + r;
5521           remotePointsNew[m].rank  = rrank;
5522         }
5523         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (eMax                        - eStart)     + (p  - fStart);
5524         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rdepthMaxOld[n*(depth+1)+1] - reStart[n]) + (rp - rfStart[n]);
5525         remotePointsNew[m].rank  = rrank;
5526         ++m;
5527       } else if ((p >= fMax) && (p < fEnd)) {
5528         /* Hybrid faces add new faces and edges */
5529         for (r = 0; r < 2; ++r, ++m) {
5530           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*4     + (cMax                            - cStart)*8     + (p  - fMax)*2                              + r;
5531           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;
5532           remotePointsNew[m].rank  = rrank;
5533         }
5534         localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (fMax                              - fStart)*4     + (cMax                            - cStart)*6     + (fEnd                                          - fMax);
5535         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]);
5536         remotePointsNew[m].rank  = rrank;
5537         ++m;
5538       } else if ((p >= cStart) && (p < cMax)) {
5539         /* Interior cells add new cells, faces, edges, and vertex */
5540         for (r = 0; r < 8; ++r, ++m) {
5541           localPointsNew[m]        = cStartNew     + (p  - cStart)*8     + r;
5542           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*8 + r;
5543           remotePointsNew[m].rank  = rrank;
5544         }
5545         for (r = 0; r < 12; ++r, ++m) {
5546           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*4     + (p  - cStart)*12     + r;
5547           remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*4 + (rp - rcStart[n])*12 + r;
5548           remotePointsNew[m].rank  = rrank;
5549         }
5550         for (r = 0; r < 6; ++r, ++m) {
5551           localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (fMax                              - fStart)*4     + (p  - cStart)*6     + r;
5552           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;
5553           remotePointsNew[m].rank  = rrank;
5554         }
5555         for (r = 0; r < 1; ++r, ++m) {
5556           localPointsNew[m]        = vStartNew     + (eMax                        - eStart)     + (fMax                              - fStart)     + (p  - cStart)     + r;
5557           remotePointsNew[m].index = rvStartNew[n] + (rdepthMaxOld[n*(depth+1)+1] - reStart[n]) + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n]) + (rp - rcStart[n]) + r;
5558           remotePointsNew[m].rank  = rrank;
5559         }
5560       } else if ((p >= cMax) && (p < cEnd)) {
5561         /* Hybrid cells add new cells, faces, and edges */
5562         for (r = 0; r < 4; ++r, ++m) {
5563           localPointsNew[m]        = cStartNew     + (cMax                            - cStart)*8     + (p  - cMax)*4                            + r;
5564           remotePointsNew[m].index = rcStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth] - rcStart[n])*8 + (rp - rdepthMaxOld[n*(depth+1)+depth])*4 + r;
5565           remotePointsNew[m].rank  = rrank;
5566         }
5567         for (r = 0; r < 4; ++r, ++m) {
5568           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*4     + (cMax                            - cStart)*8     + (fEnd                                          - fMax)*2                              + (p  - cMax)*4                            + r;
5569           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;
5570           remotePointsNew[m].rank  = rrank;
5571         }
5572         localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (fMax                              - fStart)*4     + (cMax                            - cStart)*6     + (fEnd                                          - fMax)                              + (p  - cMax);
5573         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]);
5574         remotePointsNew[m].rank  = rrank;
5575         ++m;
5576       }
5577       break;
5578     default:
5579       SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
5580     }
5581   }
5582   if (m != numLeavesNew) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Number of leaf point %d should be %d", m, numLeavesNew);
5583   ierr = ISRestoreIndices(processRanks, &neighbors);CHKERRQ(ierr);
5584   ierr = ISDestroy(&processRanks);CHKERRQ(ierr);
5585   ierr = PetscSFSetGraph(sfNew, pEndNew-pStartNew, numLeavesNew, localPointsNew, PETSC_OWN_POINTER, remotePointsNew, PETSC_OWN_POINTER);CHKERRQ(ierr);
5586   ierr = PetscFree5(rdepthSize,rvStartNew,reStartNew,rfStartNew,rcStartNew);CHKERRQ(ierr);
5587   ierr = PetscFree7(depthSizeOld,rdepthSizeOld,rdepthMaxOld,rvStart,reStart,rfStart,rcStart);CHKERRQ(ierr);
5588   PetscFunctionReturn(0);
5589 }
5590 
5591 #undef __FUNCT__
5592 #define __FUNCT__ "CellRefinerCreateLabels"
5593 static PetscErrorCode CellRefinerCreateLabels(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
5594 {
5595   PetscInt       numLabels, l;
5596   PetscInt       depth, newp, cStart, cEnd, cMax, vStart, vEnd, vMax, fStart, fEnd, fMax, eStart, eEnd, eMax, r;
5597   PetscInt       cStartNew = 0, vStartNew = 0, fStartNew = 0, eStartNew = 0;
5598   PetscErrorCode ierr;
5599 
5600   PetscFunctionBegin;
5601   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
5602   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
5603   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
5604   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
5605   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
5606   if (refiner) {ierr = GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);CHKERRQ(ierr);}
5607   ierr = DMPlexGetNumLabels(dm, &numLabels);CHKERRQ(ierr);
5608   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
5609   switch (refiner) {
5610   case 0: break;
5611   case 7:
5612   case 8:
5613     if (eMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No edge maximum specified in hybrid mesh");
5614   case 3:
5615   case 4:
5616     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
5617     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
5618   }
5619   for (l = 0; l < numLabels; ++l) {
5620     DMLabel         label, labelNew;
5621     const char     *lname;
5622     PetscBool       isDepth;
5623     IS              valueIS;
5624     const PetscInt *values;
5625     PetscInt        numValues, val;
5626 
5627     ierr = DMPlexGetLabelName(dm, l, &lname);CHKERRQ(ierr);
5628     ierr = PetscStrcmp(lname, "depth", &isDepth);CHKERRQ(ierr);
5629     if (isDepth) continue;
5630     ierr = DMPlexCreateLabel(rdm, lname);CHKERRQ(ierr);
5631     ierr = DMPlexGetLabel(dm, lname, &label);CHKERRQ(ierr);
5632     ierr = DMPlexGetLabel(rdm, lname, &labelNew);CHKERRQ(ierr);
5633     ierr = DMLabelGetValueIS(label, &valueIS);CHKERRQ(ierr);
5634     ierr = ISGetLocalSize(valueIS, &numValues);CHKERRQ(ierr);
5635     ierr = ISGetIndices(valueIS, &values);CHKERRQ(ierr);
5636     for (val = 0; val < numValues; ++val) {
5637       IS              pointIS;
5638       const PetscInt *points;
5639       PetscInt        numPoints, n;
5640 
5641       ierr = DMLabelGetStratumIS(label, values[val], &pointIS);CHKERRQ(ierr);
5642       ierr = ISGetLocalSize(pointIS, &numPoints);CHKERRQ(ierr);
5643       ierr = ISGetIndices(pointIS, &points);CHKERRQ(ierr);
5644       for (n = 0; n < numPoints; ++n) {
5645         const PetscInt p = points[n];
5646         switch (refiner) {
5647         case 1:
5648           /* Simplicial 2D */
5649           if ((p >= vStart) && (p < vEnd)) {
5650             /* Old vertices stay the same */
5651             newp = vStartNew + (p - vStart);
5652             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5653           } else if ((p >= fStart) && (p < fEnd)) {
5654             /* Old faces add new faces and vertex */
5655             newp = vStartNew + (vEnd - vStart) + (p - fStart);
5656             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5657             for (r = 0; r < 2; ++r) {
5658               newp = fStartNew + (p - fStart)*2 + r;
5659               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5660             }
5661           } else if ((p >= cStart) && (p < cEnd)) {
5662             /* Old cells add new cells and interior faces */
5663             for (r = 0; r < 4; ++r) {
5664               newp = cStartNew + (p - cStart)*4 + r;
5665               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5666             }
5667             for (r = 0; r < 3; ++r) {
5668               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*3 + r;
5669               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5670             }
5671           }
5672           break;
5673         case 2:
5674           /* Hex 2D */
5675           if ((p >= vStart) && (p < vEnd)) {
5676             /* Old vertices stay the same */
5677             newp = vStartNew + (p - vStart);
5678             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5679           } else if ((p >= fStart) && (p < fEnd)) {
5680             /* Old faces add new faces and vertex */
5681             newp = vStartNew + (vEnd - vStart) + (p - fStart);
5682             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5683             for (r = 0; r < 2; ++r) {
5684               newp = fStartNew + (p - fStart)*2 + r;
5685               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5686             }
5687           } else if ((p >= cStart) && (p < cEnd)) {
5688             /* Old cells add new cells and interior faces and vertex */
5689             for (r = 0; r < 4; ++r) {
5690               newp = cStartNew + (p - cStart)*4 + r;
5691               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5692             }
5693             for (r = 0; r < 4; ++r) {
5694               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*4 + r;
5695               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5696             }
5697             newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (p - cStart);
5698             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5699           }
5700           break;
5701         case 3:
5702           /* Hybrid simplicial 2D */
5703           if ((p >= vStart) && (p < vEnd)) {
5704             /* Old vertices stay the same */
5705             newp = vStartNew + (p - vStart);
5706             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5707           } else if ((p >= fStart) && (p < fMax)) {
5708             /* Old interior faces add new faces and vertex */
5709             newp = vStartNew + (vEnd - vStart) + (p - fStart);
5710             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5711             for (r = 0; r < 2; ++r) {
5712               newp = fStartNew + (p - fStart)*2 + r;
5713               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5714             }
5715           } else if ((p >= fMax) && (p < fEnd)) {
5716             /* Old hybrid faces stay the same */
5717             newp = fStartNew + (fMax - fStart)*2 + (p - fMax);
5718             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5719           } else if ((p >= cStart) && (p < cMax)) {
5720             /* Old interior cells add new cells and interior faces */
5721             for (r = 0; r < 4; ++r) {
5722               newp = cStartNew + (p - cStart)*4 + r;
5723               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5724             }
5725             for (r = 0; r < 3; ++r) {
5726               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*3 + r;
5727               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5728             }
5729           } else if ((p >= cMax) && (p < cEnd)) {
5730             /* Old hybrid cells add new cells and hybrid face */
5731             for (r = 0; r < 2; ++r) {
5732               newp = cStartNew + (cMax - cStart)*4 + (p - cMax)*2 + r;
5733               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5734             }
5735             newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (p - cMax);
5736             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5737           }
5738           break;
5739         case 5:
5740           /* Simplicial 3D */
5741           if ((p >= vStart) && (p < vEnd)) {
5742             /* Old vertices stay the same */
5743             newp = vStartNew + (p - vStart);
5744             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5745           } else if ((p >= eStart) && (p < eEnd)) {
5746             /* Old edges add new edges and vertex */
5747             for (r = 0; r < 2; ++r) {
5748               newp = eStartNew + (p - eStart)*2 + r;
5749               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5750             }
5751             newp = vStartNew + (vEnd - vStart) + (p - eStart);
5752             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5753           } else if ((p >= fStart) && (p < fEnd)) {
5754             /* Old faces add new faces and edges */
5755             for (r = 0; r < 4; ++r) {
5756               newp = fStartNew + (p - fStart)*4 + r;
5757               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5758             }
5759             for (r = 0; r < 3; ++r) {
5760               newp = eStartNew + (eEnd - eStart)*2 + (p - fStart)*3 + r;
5761               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5762             }
5763           } else if ((p >= cStart) && (p < cEnd)) {
5764             /* Old cells add new cells and interior faces and edges */
5765             for (r = 0; r < 8; ++r) {
5766               newp = cStartNew + (p - cStart)*8 + r;
5767               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5768             }
5769             for (r = 0; r < 8; ++r) {
5770               newp = fStartNew + (fEnd - fStart)*4 + (p - cStart)*8 + r;
5771               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5772             }
5773             for (r = 0; r < 1; ++r) {
5774               newp = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (p - cStart)*1 + r;
5775               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5776             }
5777           }
5778           break;
5779         case 7:
5780           /* Hybrid Simplicial 3D */
5781           if ((p >= vStart) && (p < vEnd)) {
5782             /* Interior vertices stay the same */
5783             newp = vStartNew + (p - vStart);
5784             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5785           } else if ((p >= eStart) && (p < eMax)) {
5786             /* Interior edges add new edges and vertex */
5787             for (r = 0; r < 2; ++r) {
5788               newp = eStartNew + (p - eStart)*2 + r;
5789               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5790             }
5791             newp = vStartNew + (vEnd - vStart) + (p - eStart);
5792             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5793           } else if ((p >= eMax) && (p < eEnd)) {
5794             /* Hybrid edges stay the same */
5795             newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (p - eMax);
5796             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5797           } else if ((p >= fStart) && (p < fMax)) {
5798             /* Interior faces add new faces and edges */
5799             for (r = 0; r < 4; ++r) {
5800               newp = fStartNew + (p - fStart)*4 + r;
5801               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5802             }
5803             for (r = 0; r < 3; ++r) {
5804               newp = eStartNew + (eMax - eStart)*2 + (p - fStart)*3 + r;
5805               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5806             }
5807           } else if ((p >= fMax) && (p < fEnd)) {
5808             /* Hybrid faces add new faces and edges */
5809             for (r = 0; r < 2; ++r) {
5810               newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (p - fMax)*2 + r;
5811               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5812             }
5813             newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (p - fMax);
5814             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5815           } else if ((p >= cStart) && (p < cMax)) {
5816             /* Interior cells add new cells, faces, and edges */
5817             for (r = 0; r < 8; ++r) {
5818               newp = cStartNew + (p - cStart)*8 + r;
5819               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5820             }
5821             for (r = 0; r < 8; ++r) {
5822               newp = fStartNew + (fMax - fStart)*4 + (p - cStart)*8 + r;
5823               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5824             }
5825             newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (p - cStart);
5826             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5827           } else if ((p >= cMax) && (p < cEnd)) {
5828             /* Hybrid cells add new cells and faces */
5829             for (r = 0; r < 4; ++r) {
5830               newp = cStartNew + (cMax - cStart)*8 + (p - cMax)*4 + r;
5831               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5832             }
5833             for (r = 0; r < 3; ++r) {
5834               newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (p - cMax)*3 + r;
5835               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5836             }
5837           }
5838           break;
5839         case 6:
5840           /* Hex 3D */
5841           if ((p >= vStart) && (p < vEnd)) {
5842             /* Old vertices stay the same */
5843             newp = vStartNew + (p - vStart);
5844             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5845           } else if ((p >= eStart) && (p < eEnd)) {
5846             /* Old edges add new edges and vertex */
5847             for (r = 0; r < 2; ++r) {
5848               newp = eStartNew + (p - eStart)*2 + r;
5849               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5850             }
5851             newp = vStartNew + (vEnd - vStart) + (p - eStart);
5852             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5853           } else if ((p >= fStart) && (p < fEnd)) {
5854             /* Old faces add new faces, edges, and vertex */
5855             for (r = 0; r < 4; ++r) {
5856               newp = fStartNew + (p - fStart)*4 + r;
5857               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5858             }
5859             for (r = 0; r < 4; ++r) {
5860               newp = eStartNew + (eEnd - eStart)*2 + (p - fStart)*4 + r;
5861               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5862             }
5863             newp = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (p - fStart);
5864             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5865           } else if ((p >= cStart) && (p < cEnd)) {
5866             /* Old cells add new cells, faces, edges, and vertex */
5867             for (r = 0; r < 8; ++r) {
5868               newp = cStartNew + (p - cStart)*8 + r;
5869               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5870             }
5871             for (r = 0; r < 12; ++r) {
5872               newp = fStartNew + (fEnd - fStart)*4 + (p - cStart)*12 + r;
5873               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5874             }
5875             for (r = 0; r < 6; ++r) {
5876               newp = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*4 + (p - cStart)*6 + r;
5877               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5878             }
5879             newp = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (fEnd - fStart) + (p - cStart);
5880             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5881           }
5882           break;
5883         case 8:
5884           /* Hybrid Hex 3D */
5885           if ((p >= vStart) && (p < vEnd)) {
5886             /* Interior vertices stay the same */
5887             newp = vStartNew + (p - vStart);
5888             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5889           } else if ((p >= eStart) && (p < eMax)) {
5890             /* Interior edges add new edges and vertex */
5891             for (r = 0; r < 2; ++r) {
5892               newp = eStartNew + (p - eStart)*2 + r;
5893               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5894             }
5895             newp = vStartNew + (vEnd - vStart) + (p - eStart);
5896             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5897           } else if ((p >= eMax) && (p < eEnd)) {
5898             /* Hybrid edges stay the same */
5899             newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (p - eMax);
5900             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5901           } else if ((p >= fStart) && (p < fMax)) {
5902             /* Interior faces add new faces, edges, and vertex */
5903             for (r = 0; r < 4; ++r) {
5904               newp = fStartNew + (p - fStart)*4 + r;
5905               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5906             }
5907             for (r = 0; r < 4; ++r) {
5908               newp = eStartNew + (eMax - eStart)*2 + (p - fStart)*4 + r;
5909               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5910             }
5911             newp = vStartNew + (vEnd - vStart) + (eMax - eStart) + (p - fStart);
5912             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5913           } else if ((p >= fMax) && (p < fEnd)) {
5914             /* Hybrid faces add new faces and edges */
5915             for (r = 0; r < 2; ++r) {
5916               newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (p - fMax)*2 + r;
5917               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5918             }
5919             newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (p - fMax);
5920             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5921           } else if ((p >= cStart) && (p < cMax)) {
5922             /* Interior cells add new cells, faces, edges, and vertex */
5923             for (r = 0; r < 8; ++r) {
5924               newp = cStartNew + (p - cStart)*8 + r;
5925               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5926             }
5927             for (r = 0; r < 12; ++r) {
5928               newp = fStartNew + (fMax - fStart)*4 + (p - cStart)*12 + r;
5929               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5930             }
5931             for (r = 0; r < 6; ++r) {
5932               newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (p - cStart)*6 + r;
5933               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5934             }
5935             newp = vStartNew + (vEnd - vStart) + (eMax - eStart) + (fMax - fStart) + (p - cStart);
5936             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5937           } else if ((p >= cMax) && (p < cEnd)) {
5938             /* Hybrid cells add new cells, faces, and edges */
5939             for (r = 0; r < 4; ++r) {
5940               newp = cStartNew + (cMax - cStart)*8 + (p - cMax)*4 + r;
5941               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5942             }
5943             for (r = 0; r < 4; ++r) {
5944               newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd - fMax)*2 + (p - cMax)*4 + r;
5945               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5946             }
5947             newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (fEnd - fMax) + (p - cMax);
5948             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5949           }
5950           break;
5951         default:
5952           SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
5953         }
5954       }
5955       ierr = ISRestoreIndices(pointIS, &points);CHKERRQ(ierr);
5956       ierr = ISDestroy(&pointIS);CHKERRQ(ierr);
5957     }
5958     ierr = ISRestoreIndices(valueIS, &values);CHKERRQ(ierr);
5959     ierr = ISDestroy(&valueIS);CHKERRQ(ierr);
5960     if (0) {
5961       ierr = PetscViewerASCIISynchronizedAllow(PETSC_VIEWER_STDOUT_WORLD, PETSC_TRUE);CHKERRQ(ierr);
5962       ierr = DMLabelView(labelNew, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
5963       ierr = PetscViewerFlush(PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
5964     }
5965   }
5966   PetscFunctionReturn(0);
5967 }
5968 
5969 #undef __FUNCT__
5970 #define __FUNCT__ "DMPlexRefineUniform_Internal"
5971 /* This will only work for interpolated meshes */
5972 PetscErrorCode DMPlexRefineUniform_Internal(DM dm, CellRefiner cellRefiner, DM *dmRefined)
5973 {
5974   DM             rdm;
5975   PetscInt      *depthSize;
5976   PetscInt       dim, depth = 0, d, pStart = 0, pEnd = 0;
5977   PetscErrorCode ierr;
5978 
5979   PetscFunctionBegin;
5980   ierr = DMCreate(PetscObjectComm((PetscObject)dm), &rdm);CHKERRQ(ierr);
5981   ierr = DMSetType(rdm, DMPLEX);CHKERRQ(ierr);
5982   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
5983   ierr = DMPlexSetDimension(rdm, dim);CHKERRQ(ierr);
5984   /* Calculate number of new points of each depth */
5985   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
5986   ierr = PetscMalloc1((depth+1), &depthSize);CHKERRQ(ierr);
5987   ierr = PetscMemzero(depthSize, (depth+1) * sizeof(PetscInt));CHKERRQ(ierr);
5988   ierr = CellRefinerGetSizes(cellRefiner, dm, depthSize);CHKERRQ(ierr);
5989   /* Step 1: Set chart */
5990   for (d = 0; d <= depth; ++d) pEnd += depthSize[d];
5991   ierr = DMPlexSetChart(rdm, pStart, pEnd);CHKERRQ(ierr);
5992   /* Step 2: Set cone/support sizes */
5993   ierr = CellRefinerSetConeSizes(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
5994   /* Step 3: Setup refined DM */
5995   ierr = DMSetUp(rdm);CHKERRQ(ierr);
5996   /* Step 4: Set cones and supports */
5997   ierr = CellRefinerSetCones(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
5998   /* Step 5: Stratify */
5999   ierr = DMPlexStratify(rdm);CHKERRQ(ierr);
6000   /* Step 6: Set coordinates for vertices */
6001   ierr = CellRefinerSetCoordinates(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
6002   /* Step 7: Create pointSF */
6003   ierr = CellRefinerCreateSF(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
6004   /* Step 8: Create labels */
6005   ierr = CellRefinerCreateLabels(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
6006   ierr = PetscFree(depthSize);CHKERRQ(ierr);
6007 
6008   *dmRefined = rdm;
6009   PetscFunctionReturn(0);
6010 }
6011 
6012 #undef __FUNCT__
6013 #define __FUNCT__ "DMPlexSetRefinementUniform"
6014 PetscErrorCode DMPlexSetRefinementUniform(DM dm, PetscBool refinementUniform)
6015 {
6016   DM_Plex *mesh = (DM_Plex*) dm->data;
6017 
6018   PetscFunctionBegin;
6019   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6020   mesh->refinementUniform = refinementUniform;
6021   PetscFunctionReturn(0);
6022 }
6023 
6024 #undef __FUNCT__
6025 #define __FUNCT__ "DMPlexGetRefinementUniform"
6026 PetscErrorCode DMPlexGetRefinementUniform(DM dm, PetscBool *refinementUniform)
6027 {
6028   DM_Plex *mesh = (DM_Plex*) dm->data;
6029 
6030   PetscFunctionBegin;
6031   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6032   PetscValidPointer(refinementUniform,  2);
6033   *refinementUniform = mesh->refinementUniform;
6034   PetscFunctionReturn(0);
6035 }
6036 
6037 #undef __FUNCT__
6038 #define __FUNCT__ "DMPlexSetRefinementLimit"
6039 PetscErrorCode DMPlexSetRefinementLimit(DM dm, PetscReal refinementLimit)
6040 {
6041   DM_Plex *mesh = (DM_Plex*) dm->data;
6042 
6043   PetscFunctionBegin;
6044   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6045   mesh->refinementLimit = refinementLimit;
6046   PetscFunctionReturn(0);
6047 }
6048 
6049 #undef __FUNCT__
6050 #define __FUNCT__ "DMPlexGetRefinementLimit"
6051 PetscErrorCode DMPlexGetRefinementLimit(DM dm, PetscReal *refinementLimit)
6052 {
6053   DM_Plex *mesh = (DM_Plex*) dm->data;
6054 
6055   PetscFunctionBegin;
6056   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6057   PetscValidPointer(refinementLimit,  2);
6058   /* if (mesh->refinementLimit < 0) = getMaxVolume()/2.0; */
6059   *refinementLimit = mesh->refinementLimit;
6060   PetscFunctionReturn(0);
6061 }
6062 
6063 #undef __FUNCT__
6064 #define __FUNCT__ "DMPlexGetCellRefiner_Internal"
6065 PetscErrorCode DMPlexGetCellRefiner_Internal(DM dm, CellRefiner *cellRefiner)
6066 {
6067   PetscInt       dim, cStart, cEnd, coneSize, cMax;
6068   PetscErrorCode ierr;
6069 
6070   PetscFunctionBegin;
6071   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
6072   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
6073   if (cEnd <= cStart) {*cellRefiner = 0; PetscFunctionReturn(0);}
6074   ierr = DMPlexGetConeSize(dm, cStart, &coneSize);CHKERRQ(ierr);
6075   ierr = DMPlexGetHybridBounds(dm, &cMax, NULL, NULL, NULL);CHKERRQ(ierr);
6076   switch (dim) {
6077   case 2:
6078     switch (coneSize) {
6079     case 3:
6080       if (cMax >= 0) *cellRefiner = 3; /* Hybrid */
6081       else *cellRefiner = 1; /* Triangular */
6082       break;
6083     case 4:
6084       if (cMax >= 0) *cellRefiner = 4; /* Hybrid */
6085       else *cellRefiner = 2; /* Quadrilateral */
6086       break;
6087     default:
6088       SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown coneSize %d in dimension %d for cell refiner", coneSize, dim);
6089     }
6090     break;
6091   case 3:
6092     switch (coneSize) {
6093     case 4:
6094       if (cMax >= 0) *cellRefiner = 7; /* Hybrid */
6095       else *cellRefiner = 5; /* Tetrahedral */
6096       break;
6097     case 6:
6098       if (cMax >= 0) *cellRefiner = 8; /* Hybrid */
6099       else *cellRefiner = 6; /* hexahedral */
6100       break;
6101     default:
6102       SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown coneSize %d in dimension %d for cell refiner", coneSize, dim);
6103     }
6104     break;
6105   default:
6106     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown dimension %d for cell refiner", dim);
6107   }
6108   PetscFunctionReturn(0);
6109 }
6110