xref: /petsc/src/dm/impls/plex/plexrefine.c (revision d856d60f548e55eb3e8fbac696524978547eca9e)
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   default:
95     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
96   }
97   PetscFunctionReturn(0);
98 }
99 
100 /* Return triangle edge for orientation o, if it is r for o == 0 */
101 PETSC_STATIC_INLINE PetscInt GetTriEdge_Static(PetscInt o, PetscInt r) {
102   return (o < 0 ? 2-(o+r) : o+r)%3;
103 }
104 PETSC_STATIC_INLINE PetscInt GetTriEdgeInverse_Static(PetscInt o, PetscInt s) {
105   return (o < 0 ? 2-(o+s) : 3+s-o)%3;
106 }
107 
108 /* Return triangle subface for orientation o, if it is r for o == 0 */
109 PETSC_STATIC_INLINE PetscInt GetTriSubface_Static(PetscInt o, PetscInt r) {
110   return (o < 0 ? 3-(o+r) : o+r)%3;
111 }
112 PETSC_STATIC_INLINE PetscInt GetTriSubfaceInverse_Static(PetscInt o, PetscInt s) {
113   return (o < 0 ? 3-(o+s) : 3+s-o)%3;
114 }
115 
116 /* I HAVE NO IDEA: Return ??? for orientation o, if it is r for o == 0 */
117 PETSC_STATIC_INLINE PetscInt GetTetSomething_Static(PetscInt o, PetscInt r) {
118   return (o < 0 ? 1-(o+r) : o+r)%3;
119 }
120 PETSC_STATIC_INLINE PetscInt GetTetSomethingInverse_Static(PetscInt o, PetscInt s) {
121   return (o < 0 ? 1-(o+s) : 3+s-o)%3;
122 }
123 
124 
125 /* Return quad edge for orientation o, if it is r for o == 0 */
126 PETSC_STATIC_INLINE PetscInt GetQuadEdge_Static(PetscInt o, PetscInt r) {
127   return (o < 0 ? 3-(o+r) : o+r)%4;
128 }
129 PETSC_STATIC_INLINE PetscInt GetQuadEdgeInverse_Static(PetscInt o, PetscInt s) {
130   return (o < 0 ? 3-(o+s) : 4+s-o)%4;
131 }
132 
133 /* Return quad subface for orientation o, if it is r for o == 0 */
134 PETSC_STATIC_INLINE PetscInt GetQuadSubface_Static(PetscInt o, PetscInt r) {
135   return (o < 0 ? 4-(o+r) : o+r)%4;
136 }
137 PETSC_STATIC_INLINE PetscInt GetQuadSubfaceInverse_Static(PetscInt o, PetscInt s) {
138   return (o < 0 ? 4-(o+s) : 4+s-o)%4;
139 }
140 
141 #undef __FUNCT__
142 #define __FUNCT__ "CellRefinerSetConeSizes"
143 static PetscErrorCode CellRefinerSetConeSizes(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
144 {
145   PetscInt       depth, cStart, cStartNew, cEnd, cMax, c, vStart, vStartNew, vEnd, vMax, v, fStart, fStartNew, fEnd, fMax, f, eStart, eStartNew, eEnd, eMax, e, r;
146   PetscErrorCode ierr;
147 
148   PetscFunctionBegin;
149   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
150   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
151   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
152   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
153   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
154   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
155   if (refiner) {ierr = GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);CHKERRQ(ierr);}
156   switch (refiner) {
157   case 0: break;
158   case 1:
159     /* Simplicial 2D */
160     /* All cells have 3 faces */
161     for (c = cStart; c < cEnd; ++c) {
162       for (r = 0; r < 4; ++r) {
163         const PetscInt newp = (c - cStart)*4 + r;
164 
165         ierr = DMPlexSetConeSize(rdm, newp, 3);CHKERRQ(ierr);
166       }
167     }
168     /* Split faces have 2 vertices and the same cells as the parent */
169     for (f = fStart; f < fEnd; ++f) {
170       for (r = 0; r < 2; ++r) {
171         const PetscInt newp = fStartNew + (f - fStart)*2 + r;
172         PetscInt       size;
173 
174         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
175         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
176         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
177       }
178     }
179     /* Interior faces have 2 vertices and 2 cells */
180     for (c = cStart; c < cEnd; ++c) {
181       for (r = 0; r < 3; ++r) {
182         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*3 + r;
183 
184         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
185         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
186       }
187     }
188     /* Old vertices have identical supports */
189     for (v = vStart; v < vEnd; ++v) {
190       const PetscInt newp = vStartNew + (v - vStart);
191       PetscInt       size;
192 
193       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
194       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
195     }
196     /* Face vertices have 2 + cells*2 supports */
197     for (f = fStart; f < fEnd; ++f) {
198       const PetscInt newp = vStartNew + (vEnd - vStart) + (f - fStart);
199       PetscInt       size;
200 
201       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
202       ierr = DMPlexSetSupportSize(rdm, newp, 2 + size*2);CHKERRQ(ierr);
203     }
204     break;
205   case 2:
206     /* Hex 2D */
207     /* All cells have 4 faces */
208     for (c = cStart; c < cEnd; ++c) {
209       for (r = 0; r < 4; ++r) {
210         const PetscInt newp = (c - cStart)*4 + r;
211 
212         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
213       }
214     }
215     /* Split faces have 2 vertices and the same cells as the parent */
216     for (f = fStart; f < fEnd; ++f) {
217       for (r = 0; r < 2; ++r) {
218         const PetscInt newp = fStartNew + (f - fStart)*2 + r;
219         PetscInt       size;
220 
221         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
222         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
223         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
224       }
225     }
226     /* Interior faces have 2 vertices and 2 cells */
227     for (c = cStart; c < cEnd; ++c) {
228       for (r = 0; r < 4; ++r) {
229         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*4 + r;
230 
231         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
232         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
233       }
234     }
235     /* Old vertices have identical supports */
236     for (v = vStart; v < vEnd; ++v) {
237       const PetscInt newp = vStartNew + (v - vStart);
238       PetscInt       size;
239 
240       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
241       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
242     }
243     /* Face vertices have 2 + cells supports */
244     for (f = fStart; f < fEnd; ++f) {
245       const PetscInt newp = vStartNew + (vEnd - vStart) + (f - fStart);
246       PetscInt       size;
247 
248       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
249       ierr = DMPlexSetSupportSize(rdm, newp, 2 + size);CHKERRQ(ierr);
250     }
251     /* Cell vertices have 4 supports */
252     for (c = cStart; c < cEnd; ++c) {
253       const PetscInt newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (c - cStart);
254 
255       ierr = DMPlexSetSupportSize(rdm, newp, 4);CHKERRQ(ierr);
256     }
257     break;
258   case 3:
259     /* Hybrid Simplicial 2D */
260     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
261     cMax = PetscMin(cEnd, cMax);
262     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
263     fMax = PetscMin(fEnd, fMax);
264     ierr = DMPlexSetHybridBounds(rdm, cStartNew + (cMax - cStart)*4, fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3, PETSC_DETERMINE, PETSC_DETERMINE);CHKERRQ(ierr);
265     /* Interior cells have 3 faces */
266     for (c = cStart; c < cMax; ++c) {
267       for (r = 0; r < 4; ++r) {
268         const PetscInt newp = cStartNew + (c - cStart)*4 + r;
269 
270         ierr = DMPlexSetConeSize(rdm, newp, 3);CHKERRQ(ierr);
271       }
272     }
273     /* Hybrid cells have 4 faces */
274     for (c = cMax; c < cEnd; ++c) {
275       for (r = 0; r < 2; ++r) {
276         const PetscInt newp = cStartNew + (cMax - cStart)*4 + (c - cMax)*2 + r;
277 
278         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
279       }
280     }
281     /* Interior split faces have 2 vertices and the same cells as the parent */
282     for (f = fStart; f < fMax; ++f) {
283       for (r = 0; r < 2; ++r) {
284         const PetscInt newp = fStartNew + (f - fStart)*2 + r;
285         PetscInt       size;
286 
287         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
288         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
289         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
290       }
291     }
292     /* Interior cell faces have 2 vertices and 2 cells */
293     for (c = cStart; c < cMax; ++c) {
294       for (r = 0; r < 3; ++r) {
295         const PetscInt newp = fStartNew + (fMax - fStart)*2 + (c - cStart)*3 + r;
296 
297         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
298         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
299       }
300     }
301     /* Hybrid faces have 2 vertices and the same cells */
302     for (f = fMax; f < fEnd; ++f) {
303       const PetscInt newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (f - fMax);
304       PetscInt       size;
305 
306       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
307       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
308       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
309     }
310     /* Hybrid cell faces have 2 vertices and 2 cells */
311     for (c = cMax; c < cEnd; ++c) {
312       const PetscInt newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (fEnd - fMax) + (c - cMax);
313 
314       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
315       ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
316     }
317     /* Old vertices have identical supports */
318     for (v = vStart; v < vEnd; ++v) {
319       const PetscInt newp = vStartNew + (v - vStart);
320       PetscInt       size;
321 
322       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
323       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
324     }
325     /* Face vertices have 2 + (2 interior, 1 hybrid) supports */
326     for (f = fStart; f < fMax; ++f) {
327       const PetscInt newp = vStartNew + (vEnd - vStart) + (f - fStart);
328       const PetscInt *support;
329       PetscInt       size, newSize = 2, s;
330 
331       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
332       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
333       for (s = 0; s < size; ++s) {
334         if (support[s] >= cMax) newSize += 1;
335         else newSize += 2;
336       }
337       ierr = DMPlexSetSupportSize(rdm, newp, newSize);CHKERRQ(ierr);
338     }
339     break;
340   case 5:
341     /* Simplicial 3D */
342     /* All cells have 4 faces */
343     for (c = cStart; c < cEnd; ++c) {
344       for (r = 0; r < 8; ++r) {
345         const PetscInt newp = cStartNew + (c - cStart)*8 + r;
346 
347         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
348       }
349     }
350     /* Split faces have 3 edges and the same cells as the parent */
351     for (f = fStart; f < fEnd; ++f) {
352       for (r = 0; r < 4; ++r) {
353         const PetscInt newp = fStartNew + (f - fStart)*4 + r;
354         PetscInt       size;
355 
356         ierr = DMPlexSetConeSize(rdm, newp, 3);CHKERRQ(ierr);
357         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
358         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
359       }
360     }
361     /* Interior cell faces have 3 edges and 2 cells */
362     for (c = cStart; c < cEnd; ++c) {
363       for (r = 0; r < 8; ++r) {
364         const PetscInt newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*8 + r;
365 
366         ierr = DMPlexSetConeSize(rdm, newp, 3);CHKERRQ(ierr);
367         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
368       }
369     }
370     /* Split edges have 2 vertices and the same faces */
371     for (e = eStart; e < eEnd; ++e) {
372       for (r = 0; r < 2; ++r) {
373         const PetscInt newp = eStartNew + (e - eStart)*2 + r;
374         PetscInt       size;
375 
376         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
377         ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
378         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
379       }
380     }
381     /* Face edges have 2 vertices and 2+cells*(1/2) faces */
382     for (f = fStart; f < fEnd; ++f) {
383       for (r = 0; r < 3; ++r) {
384         const PetscInt  newp = eStartNew + (eEnd - eStart)*2 + (f - fStart)*3 + r;
385         const PetscInt *cone, *ornt, *support, eint[4] = {1, 0, 2, 0};
386         PetscInt        coneSize, c, supportSize, s, er, intFaces = 0;
387 
388         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
389         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
390         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
391         for (s = 0; s < supportSize; ++s) {
392           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
393           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
394           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
395           for (c = 0; c < coneSize; ++c) {if (cone[c] == f) break;}
396           /* Here we want to determine whether edge newp contains a vertex which is part of the cross-tet edge */
397           er = GetTetSomethingInverse_Static(ornt[c], r);
398           if (er == eint[c]) {
399             intFaces += 1;
400           } else {
401             intFaces += 2;
402           }
403         }
404         ierr = DMPlexSetSupportSize(rdm, newp, 2+intFaces);CHKERRQ(ierr);
405       }
406     }
407     /* Interior cell edges have 2 vertices and 4 faces */
408     for (c = cStart; c < cEnd; ++c) {
409       const PetscInt newp = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart);
410 
411       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
412       ierr = DMPlexSetSupportSize(rdm, newp, 4);CHKERRQ(ierr);
413     }
414     /* Old vertices have identical supports */
415     for (v = vStart; v < vEnd; ++v) {
416       const PetscInt newp = vStartNew + (v - vStart);
417       PetscInt       size;
418 
419       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
420       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
421     }
422     /* Edge vertices have 2 + faces*2 + cells*0/1 supports */
423     for (e = eStart; e < eEnd; ++e) {
424       const PetscInt newp = vStartNew + (vEnd - vStart) + (e - eStart);
425       PetscInt       size, *star = NULL, starSize, s, cellSize = 0;
426 
427       ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
428       ierr = DMPlexGetTransitiveClosure(dm, e, PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
429       for (s = 0; s < starSize*2; s += 2) {
430         const PetscInt *cone, *ornt;
431         PetscInt        e01, e23;
432 
433         if ((star[s] >= cStart) && (star[s] < cEnd)) {
434           /* Check edge 0-1 */
435           ierr = DMPlexGetCone(dm, star[s], &cone);CHKERRQ(ierr);
436           ierr = DMPlexGetConeOrientation(dm, star[s], &ornt);CHKERRQ(ierr);
437           ierr = DMPlexGetCone(dm, cone[0], &cone);CHKERRQ(ierr);
438           e01  = cone[GetTriEdge_Static(ornt[0], 0)];
439           /* Check edge 2-3 */
440           ierr = DMPlexGetCone(dm, star[s], &cone);CHKERRQ(ierr);
441           ierr = DMPlexGetConeOrientation(dm, star[s], &ornt);CHKERRQ(ierr);
442           ierr = DMPlexGetCone(dm, cone[2], &cone);CHKERRQ(ierr);
443           e23  = cone[GetTriEdge_Static(ornt[2], 1)];
444           if ((e01 == e) || (e23 == e)) ++cellSize;
445         }
446       }
447       ierr = DMPlexRestoreTransitiveClosure(dm, e, PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
448       ierr = DMPlexSetSupportSize(rdm, newp, 2 + size*2 + cellSize);CHKERRQ(ierr);
449     }
450     break;
451   case 7:
452     /* Hybrid Simplicial 3D */
453     ierr = DMPlexSetHybridBounds(rdm, cStartNew + 8*(cMax-cStart), fStartNew + 4*(fMax - fStart) + 8*(cMax - cStart),
454                                  eStartNew + 2*(eMax - eStart) + 3*(fMax - fStart) + (cMax - cStart), PETSC_DETERMINE);CHKERRQ(ierr);
455     /* Interior cells have 4 faces */
456     for (c = cStart; c < cMax; ++c) {
457       for (r = 0; r < 8; ++r) {
458         const PetscInt newp = cStartNew + (c - cStart)*8 + r;
459 
460         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
461       }
462     }
463     /* Hybrid cells have 5 faces */
464     for (c = cMax; c < cEnd; ++c) {
465       for (r = 0; r < 4; ++r) {
466         const PetscInt newp = cStartNew + (cMax - cStart)*8 + (c - cMax)*4 + r;
467 
468         ierr = DMPlexSetConeSize(rdm, newp, 5);CHKERRQ(ierr);
469       }
470     }
471     /* Interior split faces have 3 edges and the same cells as the parent */
472     for (f = fStart; f < fMax; ++f) {
473       for (r = 0; r < 4; ++r) {
474         const PetscInt newp = fStartNew + (f - fStart)*4 + r;
475         PetscInt       size;
476 
477         ierr = DMPlexSetConeSize(rdm, newp, 3);CHKERRQ(ierr);
478         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
479         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
480       }
481     }
482     /* Interior cell faces have 3 edges and 2 cells */
483     for (c = cStart; c < cMax; ++c) {
484       for (r = 0; r < 8; ++r) {
485         const PetscInt newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*8 + r;
486 
487         ierr = DMPlexSetConeSize(rdm, newp, 3);CHKERRQ(ierr);
488         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
489       }
490     }
491     /* Hybrid split faces have 4 edges and the same cells as the parent */
492     for (f = fMax; f < fEnd; ++f) {
493       for (r = 0; r < 2; ++r) {
494         const PetscInt newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (f - fMax)*2 + r;
495         PetscInt       size;
496 
497         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
498         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
499         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
500       }
501     }
502     /* Hybrid cells faces have 4 edges and 2 cells */
503     for (c = cMax; c < cEnd; ++c) {
504       for (r = 0; r < 3; ++r) {
505         const PetscInt newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (c - cMax)*3 + r;
506 
507         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
508         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
509       }
510     }
511     /* Interior split edges have 2 vertices and the same faces */
512     for (e = eStart; e < eMax; ++e) {
513       for (r = 0; r < 2; ++r) {
514         const PetscInt newp = eStartNew + (e - eStart)*2 + r;
515         PetscInt       size;
516 
517         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
518         ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
519         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
520       }
521     }
522     /* Interior face edges have 2 vertices and 2+cells*(1/2) faces */
523     for (f = fStart; f < fMax; ++f) {
524       for (r = 0; r < 3; ++r) {
525         const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (f - fStart)*3 + r;
526         const PetscInt *cone, *ornt, *support, eint[4] = {1, 0, 2, 0};
527         PetscInt        coneSize, c, supportSize, s, er, intFaces = 0;
528 
529         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
530         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
531         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
532         for (s = 0; s < supportSize; ++s) {
533           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
534           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
535           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
536           for (c = 0; c < coneSize; ++c) {if (cone[c] == f) break;}
537           if (support[s] < cMax) {
538             /* Here we want to determine whether edge newp contains a vertex which is part of the cross-tet edge */
539             er = GetTetSomethingInverse_Static(ornt[c], r);
540             if (er == eint[c]) {
541               intFaces += 1;
542             } else {
543               intFaces += 2;
544             }
545           } else {
546             intFaces += 1;
547           }
548         }
549         ierr = DMPlexSetSupportSize(rdm, newp, 2+intFaces);CHKERRQ(ierr);
550       }
551     }
552     /* Interior cell edges have 2 vertices and 4 faces */
553     for (c = cStart; c < cMax; ++c) {
554       const PetscInt newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart);
555 
556       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
557       ierr = DMPlexSetSupportSize(rdm, newp, 4);CHKERRQ(ierr);
558     }
559     /* Hybrid edges have 2 vertices and the same faces */
560     for (e = eMax; e < eEnd; ++e) {
561       const PetscInt newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (e - eMax);
562       PetscInt       size;
563 
564       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
565       ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
566       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
567     }
568     /* Hybrid face edges have 2 vertices and 2+2*cells faces */
569     for (f = fMax; f < fEnd; ++f) {
570       const PetscInt newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (eEnd - eMax) + (f - fMax);
571       PetscInt       size;
572 
573       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
574       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
575       ierr = DMPlexSetSupportSize(rdm, newp, 2+2*size);CHKERRQ(ierr);
576     }
577     /* Interior vertices have identical supports */
578     for (v = vStart; v < vEnd; ++v) {
579       const PetscInt newp = vStartNew + (v - vStart);
580       PetscInt       size;
581 
582       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
583       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
584     }
585     /* Interior edge vertices have 2 + interior face*2 + hybrid face + cells*0/1 supports */
586     for (e = eStart; e < eMax; ++e) {
587       const PetscInt  newp = vStartNew + (vEnd - vStart) + (e - eStart);
588       const PetscInt *support;
589       PetscInt        size, *star = NULL, starSize, s, faceSize = 0, cellSize = 0;
590 
591       ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
592       ierr = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
593       for (s = 0; s < size; ++s) {
594         if (support[s] < fMax) faceSize += 2;
595         else                   faceSize += 1;
596       }
597       ierr = DMPlexGetTransitiveClosure(dm, e, PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
598       for (s = 0; s < starSize*2; s += 2) {
599         const PetscInt *cone, *ornt;
600         PetscInt        e01, e23;
601 
602         if ((star[s] >= cStart) && (star[s] < cMax)) {
603           /* Check edge 0-1 */
604           ierr = DMPlexGetCone(dm, star[s], &cone);CHKERRQ(ierr);
605           ierr = DMPlexGetConeOrientation(dm, star[s], &ornt);CHKERRQ(ierr);
606           ierr = DMPlexGetCone(dm, cone[0], &cone);CHKERRQ(ierr);
607           e01  = cone[GetTriEdge_Static(ornt[0], 0)];
608           /* Check edge 2-3 */
609           ierr = DMPlexGetCone(dm, star[s], &cone);CHKERRQ(ierr);
610           ierr = DMPlexGetConeOrientation(dm, star[s], &ornt);CHKERRQ(ierr);
611           ierr = DMPlexGetCone(dm, cone[2], &cone);CHKERRQ(ierr);
612           e23  = cone[GetTriEdge_Static(ornt[2], 1)];
613           if ((e01 == e) || (e23 == e)) ++cellSize;
614         }
615       }
616       ierr = DMPlexRestoreTransitiveClosure(dm, e, PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
617       ierr = DMPlexSetSupportSize(rdm, newp, 2 + faceSize + cellSize);CHKERRQ(ierr);
618     }
619     break;
620   case 6:
621     /* Hex 3D */
622     /* All cells have 6 faces */
623     for (c = cStart; c < cEnd; ++c) {
624       for (r = 0; r < 8; ++r) {
625         const PetscInt newp = (c - cStart)*8 + r;
626 
627         ierr = DMPlexSetConeSize(rdm, newp, 6);CHKERRQ(ierr);
628       }
629     }
630     /* Split faces have 4 edges and the same cells as the parent */
631     for (f = fStart; f < fEnd; ++f) {
632       for (r = 0; r < 4; ++r) {
633         const PetscInt newp = fStartNew + (f - fStart)*4 + r;
634         PetscInt       size;
635 
636         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
637         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
638         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
639       }
640     }
641     /* Interior faces have 4 edges and 2 cells */
642     for (c = cStart; c < cEnd; ++c) {
643       for (r = 0; r < 12; ++r) {
644         const PetscInt newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + r;
645 
646         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
647         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
648       }
649     }
650     /* Split edges have 2 vertices and the same faces as the parent */
651     for (e = eStart; e < eEnd; ++e) {
652       for (r = 0; r < 2; ++r) {
653         const PetscInt newp = eStartNew + (e - eStart)*2 + r;
654         PetscInt       size;
655 
656         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
657         ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
658         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
659       }
660     }
661     /* Face edges have 2 vertices and 2+cells faces */
662     for (f = fStart; f < fEnd; ++f) {
663       for (r = 0; r < 4; ++r) {
664         const PetscInt newp = eStartNew + (eEnd - eStart)*2 + (f - fStart)*4 + r;
665         PetscInt       size;
666 
667         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
668         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
669         ierr = DMPlexSetSupportSize(rdm, newp, 2+size);CHKERRQ(ierr);
670       }
671     }
672     /* Cell edges have 2 vertices and 4 faces */
673     for (c = cStart; c < cEnd; ++c) {
674       for (r = 0; r < 6; ++r) {
675         const PetscInt newp = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*4 + (c - cStart)*6 + r;
676 
677         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
678         ierr = DMPlexSetSupportSize(rdm, newp, 4);CHKERRQ(ierr);
679       }
680     }
681     /* Old vertices have identical supports */
682     for (v = vStart; v < vEnd; ++v) {
683       const PetscInt newp = vStartNew + (v - vStart);
684       PetscInt       size;
685 
686       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
687       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
688     }
689     /* Edge vertices have 2 + faces supports */
690     for (e = eStart; e < eEnd; ++e) {
691       const PetscInt newp = vStartNew + (vEnd - vStart) + (e - eStart);
692       PetscInt       size;
693 
694       ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
695       ierr = DMPlexSetSupportSize(rdm, newp, 2 + size);CHKERRQ(ierr);
696     }
697     /* Face vertices have 4 + cells supports */
698     for (f = fStart; f < fEnd; ++f) {
699       const PetscInt newp = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (f - fStart);
700       PetscInt       size;
701 
702       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
703       ierr = DMPlexSetSupportSize(rdm, newp, 4 + size);CHKERRQ(ierr);
704     }
705     /* Cell vertices have 6 supports */
706     for (c = cStart; c < cEnd; ++c) {
707       const PetscInt newp = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (fEnd - fStart) + (c - cStart);
708 
709       ierr = DMPlexSetSupportSize(rdm, newp, 6);CHKERRQ(ierr);
710     }
711     break;
712   default:
713     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
714   }
715   PetscFunctionReturn(0);
716 }
717 
718 #undef __FUNCT__
719 #define __FUNCT__ "CellRefinerSetCones"
720 static PetscErrorCode CellRefinerSetCones(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
721 {
722   const PetscInt *faces, cellInd[4] = {0, 1, 2, 3};
723   PetscInt        cStart,    cEnd,    cMax,    vStart,    vEnd, vMax, fStart,    fEnd,    fMax,    eStart,    eEnd,    eMax;
724   PetscInt        cStartNew, cEndNew, cMaxNew, vStartNew, vEndNew,    fStartNew, fEndNew, fMaxNew, eStartNew, eEndNew, eMaxNew;
725   PetscInt        depth, maxSupportSize, *supportRef, c, f, e, v, r, p;
726   PetscErrorCode  ierr;
727 
728   PetscFunctionBegin;
729   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
730   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
731   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
732   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
733   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
734   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
735   if (refiner) {
736     ierr = GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);CHKERRQ(ierr);
737     ierr = GetDepthEnd_Private(depth, depthSize, &cEndNew, &fEndNew, &eEndNew, &vEndNew);CHKERRQ(ierr);
738   }
739   switch (refiner) {
740   case 0: break;
741   case 1:
742     /* Simplicial 2D */
743     /*
744      2
745      |\
746      | \
747      |  \
748      |   \
749      | C  \
750      |     \
751      |      \
752      2---1---1
753      |\  D  / \
754      | 2   0   \
755      |A \ /  B  \
756      0---0-------1
757      */
758     /* All cells have 3 faces */
759     for (c = cStart; c < cEnd; ++c) {
760       const PetscInt  newp = cStartNew + (c - cStart)*4;
761       const PetscInt *cone, *ornt;
762       PetscInt        coneNew[3], orntNew[3];
763 
764       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
765       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
766       /* A triangle */
767       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
768       orntNew[0] = ornt[0];
769       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 2;
770       orntNew[1] = -2;
771       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
772       orntNew[2] = ornt[2];
773       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
774       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
775 #if 1
776       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);
777       for (p = 0; p < 3; ++p) {
778         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);
779       }
780 #endif
781       /* B triangle */
782       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
783       orntNew[0] = ornt[0];
784       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
785       orntNew[1] = ornt[1];
786       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 0;
787       orntNew[2] = -2;
788       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
789       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
790 #if 1
791       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);
792       for (p = 0; p < 3; ++p) {
793         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);
794       }
795 #endif
796       /* C triangle */
797       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 1;
798       orntNew[0] = -2;
799       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
800       orntNew[1] = ornt[1];
801       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
802       orntNew[2] = ornt[2];
803       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
804       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
805 #if 1
806       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);
807       for (p = 0; p < 3; ++p) {
808         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);
809       }
810 #endif
811       /* D triangle */
812       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 0;
813       orntNew[0] = 0;
814       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 1;
815       orntNew[1] = 0;
816       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 2;
817       orntNew[2] = 0;
818       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
819       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
820 #if 1
821       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);
822       for (p = 0; p < 3; ++p) {
823         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);
824       }
825 #endif
826     }
827     /* Split faces have 2 vertices and the same cells as the parent */
828     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
829     ierr = PetscMalloc1((2 + maxSupportSize*2), &supportRef);CHKERRQ(ierr);
830     for (f = fStart; f < fEnd; ++f) {
831       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);
832 
833       for (r = 0; r < 2; ++r) {
834         const PetscInt  newp = fStartNew + (f - fStart)*2 + r;
835         const PetscInt *cone, *ornt, *support;
836         PetscInt        coneNew[2], coneSize, c, supportSize, s;
837 
838         ierr             = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
839         coneNew[0]       = vStartNew + (cone[0] - vStart);
840         coneNew[1]       = vStartNew + (cone[1] - vStart);
841         coneNew[(r+1)%2] = newv;
842         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
843 #if 1
844         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
845         for (p = 0; p < 2; ++p) {
846           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);
847         }
848 #endif
849         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
850         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
851         for (s = 0; s < supportSize; ++s) {
852           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
853           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
854           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
855           for (c = 0; c < coneSize; ++c) {
856             if (cone[c] == f) break;
857           }
858           supportRef[s] = cStartNew + (support[s] - cStart)*4 + (ornt[c] < 0 ? (c+1-r)%3 : (c+r)%3);
859         }
860         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
861 #if 1
862         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
863         for (p = 0; p < supportSize; ++p) {
864           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);
865         }
866 #endif
867       }
868     }
869     /* Interior faces have 2 vertices and 2 cells */
870     for (c = cStart; c < cEnd; ++c) {
871       const PetscInt *cone;
872 
873       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
874       for (r = 0; r < 3; ++r) {
875         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*3 + r;
876         PetscInt       coneNew[2];
877         PetscInt       supportNew[2];
878 
879         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r]       - fStart);
880         coneNew[1] = vStartNew + (vEnd - vStart) + (cone[(r+1)%3] - fStart);
881         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
882 #if 1
883         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
884         for (p = 0; p < 2; ++p) {
885           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);
886         }
887 #endif
888         supportNew[0] = (c - cStart)*4 + (r+1)%3;
889         supportNew[1] = (c - cStart)*4 + 3;
890         ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
891 #if 1
892         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
893         for (p = 0; p < 2; ++p) {
894           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);
895         }
896 #endif
897       }
898     }
899     /* Old vertices have identical supports */
900     for (v = vStart; v < vEnd; ++v) {
901       const PetscInt  newp = vStartNew + (v - vStart);
902       const PetscInt *support, *cone;
903       PetscInt        size, s;
904 
905       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
906       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
907       for (s = 0; s < size; ++s) {
908         PetscInt r = 0;
909 
910         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
911         if (cone[1] == v) r = 1;
912         supportRef[s] = fStartNew + (support[s] - fStart)*2 + r;
913       }
914       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
915 #if 1
916       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
917       for (p = 0; p < size; ++p) {
918         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);
919       }
920 #endif
921     }
922     /* Face vertices have 2 + cells*2 supports */
923     for (f = fStart; f < fEnd; ++f) {
924       const PetscInt  newp = vStartNew + (vEnd - vStart) + (f - fStart);
925       const PetscInt *cone, *support;
926       PetscInt        size, s;
927 
928       ierr          = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
929       ierr          = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
930       supportRef[0] = fStartNew + (f - fStart)*2 + 0;
931       supportRef[1] = fStartNew + (f - fStart)*2 + 1;
932       for (s = 0; s < size; ++s) {
933         PetscInt r = 0;
934 
935         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
936         if      (cone[1] == f) r = 1;
937         else if (cone[2] == f) r = 2;
938         supportRef[2+s*2+0] = fStartNew + (fEnd - fStart)*2 + (support[s] - cStart)*3 + (r+2)%3;
939         supportRef[2+s*2+1] = fStartNew + (fEnd - fStart)*2 + (support[s] - cStart)*3 + r;
940       }
941       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
942 #if 1
943       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
944       for (p = 0; p < 2+size*2; ++p) {
945         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);
946       }
947 #endif
948     }
949     ierr = PetscFree(supportRef);CHKERRQ(ierr);
950     break;
951   case 2:
952     /* Hex 2D */
953     /*
954      3---------2---------2
955      |         |         |
956      |    D    2    C    |
957      |         |         |
958      3----3----0----1----1
959      |         |         |
960      |    A    0    B    |
961      |         |         |
962      0---------0---------1
963      */
964     /* All cells have 4 faces */
965     for (c = cStart; c < cEnd; ++c) {
966       const PetscInt  newp = (c - cStart)*4;
967       const PetscInt *cone, *ornt;
968       PetscInt        coneNew[4], orntNew[4];
969 
970       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
971       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
972       /* A quad */
973       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
974       orntNew[0] = ornt[0];
975       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 0;
976       orntNew[1] = 0;
977       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 3;
978       orntNew[2] = -2;
979       coneNew[3] = fStartNew + (cone[3] - fStart)*2 + (ornt[3] < 0 ? 0 : 1);
980       orntNew[3] = ornt[3];
981       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
982       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
983 #if 1
984       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);
985       for (p = 0; p < 4; ++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       /* B quad */
990       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
991       orntNew[0] = ornt[0];
992       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
993       orntNew[1] = ornt[1];
994       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 1;
995       orntNew[2] = 0;
996       coneNew[3] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 0;
997       orntNew[3] = -2;
998       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
999       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
1000 #if 1
1001       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);
1002       for (p = 0; p < 4; ++p) {
1003         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);
1004       }
1005 #endif
1006       /* C quad */
1007       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 1;
1008       orntNew[0] = -2;
1009       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
1010       orntNew[1] = ornt[1];
1011       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
1012       orntNew[2] = ornt[2];
1013       coneNew[3] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 2;
1014       orntNew[3] = 0;
1015       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
1016       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
1017 #if 1
1018       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);
1019       for (p = 0; p < 4; ++p) {
1020         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);
1021       }
1022 #endif
1023       /* D quad */
1024       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 3;
1025       orntNew[0] = 0;
1026       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 2;
1027       orntNew[1] = -2;
1028       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
1029       orntNew[2] = ornt[2];
1030       coneNew[3] = fStartNew + (cone[3] - fStart)*2 + (ornt[3] < 0 ? 1 : 0);
1031       orntNew[3] = ornt[3];
1032       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
1033       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
1034 #if 1
1035       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);
1036       for (p = 0; p < 4; ++p) {
1037         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);
1038       }
1039 #endif
1040     }
1041     /* Split faces have 2 vertices and the same cells as the parent */
1042     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
1043     ierr = PetscMalloc1((2 + maxSupportSize*2), &supportRef);CHKERRQ(ierr);
1044     for (f = fStart; f < fEnd; ++f) {
1045       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);
1046 
1047       for (r = 0; r < 2; ++r) {
1048         const PetscInt  newp = fStartNew + (f - fStart)*2 + r;
1049         const PetscInt *cone, *ornt, *support;
1050         PetscInt        coneNew[2], coneSize, c, supportSize, s;
1051 
1052         ierr             = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
1053         coneNew[0]       = vStartNew + (cone[0] - vStart);
1054         coneNew[1]       = vStartNew + (cone[1] - vStart);
1055         coneNew[(r+1)%2] = newv;
1056         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
1057 #if 1
1058         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1059         for (p = 0; p < 2; ++p) {
1060           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);
1061         }
1062 #endif
1063         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
1064         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
1065         for (s = 0; s < supportSize; ++s) {
1066           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
1067           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
1068           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
1069           for (c = 0; c < coneSize; ++c) {
1070             if (cone[c] == f) break;
1071           }
1072           supportRef[s] = cStartNew + (support[s] - cStart)*4 + (ornt[c] < 0 ? (c+1-r)%4 : (c+r)%4);
1073         }
1074         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
1075 #if 1
1076         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1077         for (p = 0; p < supportSize; ++p) {
1078           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);
1079         }
1080 #endif
1081       }
1082     }
1083     /* Interior faces have 2 vertices and 2 cells */
1084     for (c = cStart; c < cEnd; ++c) {
1085       const PetscInt *cone;
1086       PetscInt        coneNew[2], supportNew[2];
1087 
1088       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
1089       for (r = 0; r < 4; ++r) {
1090         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*4 + r;
1091 
1092         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r] - fStart);
1093         coneNew[1] = vStartNew + (vEnd - vStart) + (fEnd    - fStart) + (c - cStart);
1094         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
1095 #if 1
1096         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1097         for (p = 0; p < 2; ++p) {
1098           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);
1099         }
1100 #endif
1101         supportNew[0] = (c - cStart)*4 + r;
1102         supportNew[1] = (c - cStart)*4 + (r+1)%4;
1103         ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
1104 #if 1
1105         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1106         for (p = 0; p < 2; ++p) {
1107           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);
1108         }
1109 #endif
1110       }
1111     }
1112     /* Old vertices have identical supports */
1113     for (v = vStart; v < vEnd; ++v) {
1114       const PetscInt  newp = vStartNew + (v - vStart);
1115       const PetscInt *support, *cone;
1116       PetscInt        size, s;
1117 
1118       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
1119       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
1120       for (s = 0; s < size; ++s) {
1121         PetscInt r = 0;
1122 
1123         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
1124         if (cone[1] == v) r = 1;
1125         supportRef[s] = fStartNew + (support[s] - fStart)*2 + r;
1126       }
1127       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
1128 #if 1
1129       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
1130       for (p = 0; p < size; ++p) {
1131         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);
1132       }
1133 #endif
1134     }
1135     /* Face vertices have 2 + cells supports */
1136     for (f = fStart; f < fEnd; ++f) {
1137       const PetscInt  newp = vStartNew + (vEnd - vStart) + (f - fStart);
1138       const PetscInt *cone, *support;
1139       PetscInt        size, s;
1140 
1141       ierr          = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
1142       ierr          = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
1143       supportRef[0] = fStartNew + (f - fStart)*2 + 0;
1144       supportRef[1] = fStartNew + (f - fStart)*2 + 1;
1145       for (s = 0; s < size; ++s) {
1146         PetscInt r = 0;
1147 
1148         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
1149         if      (cone[1] == f) r = 1;
1150         else if (cone[2] == f) r = 2;
1151         else if (cone[3] == f) r = 3;
1152         supportRef[2+s] = fStartNew + (fEnd - fStart)*2 + (support[s] - cStart)*4 + r;
1153       }
1154       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
1155 #if 1
1156       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
1157       for (p = 0; p < 2+size; ++p) {
1158         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);
1159       }
1160 #endif
1161     }
1162     /* Cell vertices have 4 supports */
1163     for (c = cStart; c < cEnd; ++c) {
1164       const PetscInt newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (c - cStart);
1165       PetscInt       supportNew[4];
1166 
1167       for (r = 0; r < 4; ++r) {
1168         supportNew[r] = fStartNew + (fEnd - fStart)*2 + (c - cStart)*4 + r;
1169       }
1170       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
1171     }
1172     ierr = PetscFree(supportRef);CHKERRQ(ierr);
1173     break;
1174   case 3:
1175     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
1176     cMax = PetscMin(cEnd, cMax);
1177     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
1178     fMax = PetscMin(fEnd, fMax);
1179     /* Interior cells have 3 faces */
1180     for (c = cStart; c < cMax; ++c) {
1181       const PetscInt  newp = cStartNew + (c - cStart)*4;
1182       const PetscInt *cone, *ornt;
1183       PetscInt        coneNew[3], orntNew[3];
1184 
1185       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
1186       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
1187       /* A triangle */
1188       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
1189       orntNew[0] = ornt[0];
1190       coneNew[1] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 2;
1191       orntNew[1] = -2;
1192       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
1193       orntNew[2] = ornt[2];
1194       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
1195       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
1196 #if 1
1197       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);
1198       for (p = 0; p < 3; ++p) {
1199         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);
1200       }
1201 #endif
1202       /* B triangle */
1203       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
1204       orntNew[0] = ornt[0];
1205       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
1206       orntNew[1] = ornt[1];
1207       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 0;
1208       orntNew[2] = -2;
1209       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
1210       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
1211 #if 1
1212       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);
1213       for (p = 0; p < 3; ++p) {
1214         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);
1215       }
1216 #endif
1217       /* C triangle */
1218       coneNew[0] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 1;
1219       orntNew[0] = -2;
1220       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
1221       orntNew[1] = ornt[1];
1222       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
1223       orntNew[2] = ornt[2];
1224       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
1225       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
1226 #if 1
1227       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);
1228       for (p = 0; p < 3; ++p) {
1229         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);
1230       }
1231 #endif
1232       /* D triangle */
1233       coneNew[0] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 0;
1234       orntNew[0] = 0;
1235       coneNew[1] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 1;
1236       orntNew[1] = 0;
1237       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 2;
1238       orntNew[2] = 0;
1239       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
1240       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
1241 #if 1
1242       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);
1243       for (p = 0; p < 3; ++p) {
1244         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
1245       }
1246 #endif
1247     }
1248     /*
1249      2----3----3
1250      |         |
1251      |    B    |
1252      |         |
1253      0----4--- 1
1254      |         |
1255      |    A    |
1256      |         |
1257      0----2----1
1258      */
1259     /* Hybrid cells have 4 faces */
1260     for (c = cMax; c < cEnd; ++c) {
1261       const PetscInt  newp = cStartNew + (cMax - cStart)*4 + (c - cMax)*2;
1262       const PetscInt *cone, *ornt;
1263       PetscInt        coneNew[4], orntNew[4];
1264 
1265       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
1266       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
1267       /* A quad */
1268       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
1269       orntNew[0] = ornt[0];
1270       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
1271       orntNew[1] = ornt[1];
1272       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (cone[2] - fMax);
1273       orntNew[2] = 0;
1274       coneNew[3] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (fEnd    - fMax) + (c - cMax);
1275       orntNew[3] = 0;
1276       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
1277       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
1278 #if 1
1279       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);
1280       for (p = 0; p < 4; ++p) {
1281         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);
1282       }
1283 #endif
1284       /* B quad */
1285       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
1286       orntNew[0] = ornt[0];
1287       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
1288       orntNew[1] = ornt[1];
1289       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (fEnd    - fMax) + (c - cMax);
1290       orntNew[2] = 0;
1291       coneNew[3] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (cone[3] - fMax);
1292       orntNew[3] = 0;
1293       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
1294       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
1295 #if 1
1296       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);
1297       for (p = 0; p < 4; ++p) {
1298         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);
1299       }
1300 #endif
1301     }
1302     /* Interior split faces have 2 vertices and the same cells as the parent */
1303     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
1304     ierr = PetscMalloc1((2 + maxSupportSize*2), &supportRef);CHKERRQ(ierr);
1305     for (f = fStart; f < fMax; ++f) {
1306       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);
1307 
1308       for (r = 0; r < 2; ++r) {
1309         const PetscInt  newp = fStartNew + (f - fStart)*2 + r;
1310         const PetscInt *cone, *ornt, *support;
1311         PetscInt        coneNew[2], coneSize, c, supportSize, s;
1312 
1313         ierr             = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
1314         coneNew[0]       = vStartNew + (cone[0] - vStart);
1315         coneNew[1]       = vStartNew + (cone[1] - vStart);
1316         coneNew[(r+1)%2] = newv;
1317         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
1318 #if 1
1319         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1320         for (p = 0; p < 2; ++p) {
1321           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);
1322         }
1323 #endif
1324         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
1325         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
1326         for (s = 0; s < supportSize; ++s) {
1327           if (support[s] >= cMax) {
1328             supportRef[s] = cStartNew + (cMax - cStart)*4 + (support[s] - cMax)*2 + r;
1329           } else {
1330             ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
1331             ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
1332             ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
1333             for (c = 0; c < coneSize; ++c) {
1334               if (cone[c] == f) break;
1335             }
1336             supportRef[s] = cStartNew + (support[s] - cStart)*4 + (ornt[c] < 0 ? (c+1-r)%3 : (c+r)%3);
1337           }
1338         }
1339         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
1340 #if 1
1341         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1342         for (p = 0; p < supportSize; ++p) {
1343           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);
1344         }
1345 #endif
1346       }
1347     }
1348     /* Interior cell faces have 2 vertices and 2 cells */
1349     for (c = cStart; c < cMax; ++c) {
1350       const PetscInt *cone;
1351 
1352       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
1353       for (r = 0; r < 3; ++r) {
1354         const PetscInt newp = fStartNew + (fMax - fStart)*2 + (c - cStart)*3 + r;
1355         PetscInt       coneNew[2];
1356         PetscInt       supportNew[2];
1357 
1358         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r]       - fStart);
1359         coneNew[1] = vStartNew + (vEnd - vStart) + (cone[(r+1)%3] - fStart);
1360         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
1361 #if 1
1362         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1363         for (p = 0; p < 2; ++p) {
1364           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);
1365         }
1366 #endif
1367         supportNew[0] = (c - cStart)*4 + (r+1)%3;
1368         supportNew[1] = (c - cStart)*4 + 3;
1369         ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
1370 #if 1
1371         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1372         for (p = 0; p < 2; ++p) {
1373           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);
1374         }
1375 #endif
1376       }
1377     }
1378     /* Interior hybrid faces have 2 vertices and the same cells */
1379     for (f = fMax; f < fEnd; ++f) {
1380       const PetscInt  newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (f - fMax);
1381       const PetscInt *cone;
1382       const PetscInt *support;
1383       PetscInt        coneNew[2];
1384       PetscInt        supportNew[2];
1385       PetscInt        size, s, r;
1386 
1387       ierr       = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
1388       coneNew[0] = vStartNew + (cone[0] - vStart);
1389       coneNew[1] = vStartNew + (cone[1] - vStart);
1390       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
1391 #if 1
1392       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1393       for (p = 0; p < 2; ++p) {
1394         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);
1395       }
1396 #endif
1397       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
1398       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
1399       for (s = 0; s < size; ++s) {
1400         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
1401         for (r = 0; r < 2; ++r) {
1402           if (cone[r+2] == f) break;
1403         }
1404         supportNew[s] = (cMax - cStart)*4 + (support[s] - cMax)*2 + r;
1405       }
1406       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
1407 #if 1
1408       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1409       for (p = 0; p < size; ++p) {
1410         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);
1411       }
1412 #endif
1413     }
1414     /* Cell hybrid faces have 2 vertices and 2 cells */
1415     for (c = cMax; c < cEnd; ++c) {
1416       const PetscInt  newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (fEnd - fMax) + (c - cMax);
1417       const PetscInt *cone;
1418       PetscInt        coneNew[2];
1419       PetscInt        supportNew[2];
1420 
1421       ierr       = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
1422       coneNew[0] = vStartNew + (vEnd - vStart) + (cone[0] - fStart);
1423       coneNew[1] = vStartNew + (vEnd - vStart) + (cone[1] - fStart);
1424       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
1425 #if 1
1426       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1427       for (p = 0; p < 2; ++p) {
1428         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);
1429       }
1430 #endif
1431       supportNew[0] = (cMax - cStart)*4 + (c - cMax)*2 + 0;
1432       supportNew[1] = (cMax - cStart)*4 + (c - cMax)*2 + 1;
1433       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
1434 #if 1
1435       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1436       for (p = 0; p < 2; ++p) {
1437         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);
1438       }
1439 #endif
1440     }
1441     /* Old vertices have identical supports */
1442     for (v = vStart; v < vEnd; ++v) {
1443       const PetscInt  newp = vStartNew + (v - vStart);
1444       const PetscInt *support, *cone;
1445       PetscInt        size, s;
1446 
1447       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
1448       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
1449       for (s = 0; s < size; ++s) {
1450         if (support[s] >= fMax) {
1451           supportRef[s] = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (support[s] - fMax);
1452         } else {
1453           PetscInt r = 0;
1454 
1455           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
1456           if (cone[1] == v) r = 1;
1457           supportRef[s] = fStartNew + (support[s] - fStart)*2 + r;
1458         }
1459       }
1460       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
1461 #if 1
1462       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
1463       for (p = 0; p < size; ++p) {
1464         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);
1465       }
1466 #endif
1467     }
1468     /* Face vertices have 2 + (2 interior, 1 hybrid) supports */
1469     for (f = fStart; f < fMax; ++f) {
1470       const PetscInt  newp = vStartNew + (vEnd - vStart) + (f - fStart);
1471       const PetscInt *cone, *support;
1472       PetscInt        size, newSize = 2, s;
1473 
1474       ierr          = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
1475       ierr          = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
1476       supportRef[0] = fStartNew + (f - fStart)*2 + 0;
1477       supportRef[1] = fStartNew + (f - fStart)*2 + 1;
1478       for (s = 0; s < size; ++s) {
1479         PetscInt r = 0;
1480 
1481         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
1482         if (support[s] >= cMax) {
1483           supportRef[newSize+0] = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (fEnd - fMax) + (support[s] - cMax);
1484 
1485           newSize += 1;
1486         } else {
1487           if      (cone[1] == f) r = 1;
1488           else if (cone[2] == f) r = 2;
1489           supportRef[newSize+0] = fStartNew + (fMax - fStart)*2 + (support[s] - cStart)*3 + (r+2)%3;
1490           supportRef[newSize+1] = fStartNew + (fMax - fStart)*2 + (support[s] - cStart)*3 + r;
1491 
1492           newSize += 2;
1493         }
1494       }
1495       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
1496 #if 1
1497       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
1498       for (p = 0; p < newSize; ++p) {
1499         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);
1500       }
1501 #endif
1502     }
1503     ierr = PetscFree(supportRef);CHKERRQ(ierr);
1504     break;
1505   case 5:
1506     /* Simplicial 3D */
1507     /* All cells have 4 faces: Tet face order is prescribed in DMPlexGetFaces_Internal() */
1508     ierr = DMPlexGetRawFaces_Internal(dm, 3, 4, cellInd, NULL, NULL, &faces);CHKERRQ(ierr);
1509     for (c = cStart; c < cEnd; ++c) {
1510       const PetscInt  newp = cStartNew + (c - cStart)*8;
1511       const PetscInt *cone, *ornt;
1512       PetscInt        coneNew[4], orntNew[4];
1513 
1514       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
1515       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
1516       /* A tetrahedron: {0, a, c, d} */
1517       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetTriSubface_Static(ornt[0], 0); /* A */
1518       orntNew[0] = ornt[0];
1519       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetTriSubface_Static(ornt[1], 0); /* A */
1520       orntNew[1] = ornt[1];
1521       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetTriSubface_Static(ornt[2], 0); /* A */
1522       orntNew[2] = ornt[2];
1523       coneNew[3] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 0;
1524       orntNew[3] = 0;
1525       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
1526       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
1527 #if 1
1528       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);
1529       for (p = 0; p < 4; ++p) {
1530         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);
1531       }
1532 #endif
1533       /* B tetrahedron: {a, 1, b, e} */
1534       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetTriSubface_Static(ornt[0], 1); /* B */
1535       orntNew[0] = ornt[0];
1536       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetTriSubface_Static(ornt[1], 2); /* C */
1537       orntNew[1] = ornt[1];
1538       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 1;
1539       orntNew[2] = 0;
1540       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetTriSubface_Static(ornt[3], 1); /* B */
1541       orntNew[3] = ornt[3];
1542       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
1543       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
1544 #if 1
1545       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);
1546       for (p = 0; p < 4; ++p) {
1547         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);
1548       }
1549 #endif
1550       /* C tetrahedron: {c, b, 2, f} */
1551       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetTriSubface_Static(ornt[0], 2); /* C */
1552       orntNew[0] = ornt[0];
1553       coneNew[1] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 2;
1554       orntNew[1] = 0;
1555       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetTriSubface_Static(ornt[2], 1); /* B */
1556       orntNew[2] = ornt[2];
1557       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetTriSubface_Static(ornt[3], 0); /* A */
1558       orntNew[3] = ornt[3];
1559       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
1560       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
1561 #if 1
1562       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);
1563       for (p = 0; p < 4; ++p) {
1564         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);
1565       }
1566 #endif
1567       /* D tetrahedron: {d, e, f, 3} */
1568       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 3;
1569       orntNew[0] = 0;
1570       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetTriSubface_Static(ornt[1], 1); /* B */
1571       orntNew[1] = ornt[1];
1572       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetTriSubface_Static(ornt[2], 2); /* C */
1573       orntNew[2] = ornt[2];
1574       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetTriSubface_Static(ornt[3], 2); /* C */
1575       orntNew[3] = ornt[3];
1576       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
1577       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
1578 #if 1
1579       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);
1580       for (p = 0; p < 4; ++p) {
1581         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);
1582       }
1583 #endif
1584       /* A' tetrahedron: {d, a, c, f} */
1585       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 0;
1586       orntNew[0] = -3;
1587       coneNew[1] = fStartNew + (cone[2] - fStart)*4 + 3;
1588       orntNew[1] = ornt[2] < 0 ? -(GetTetSomething_Static(ornt[2], 0)+1) : GetTetSomething_Static(ornt[2], 0);
1589       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 5;
1590       orntNew[2] = 0;
1591       coneNew[3] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 4;
1592       orntNew[3] = 2;
1593       ierr       = DMPlexSetCone(rdm, newp+4, coneNew);CHKERRQ(ierr);
1594       ierr       = DMPlexSetConeOrientation(rdm, newp+4, orntNew);CHKERRQ(ierr);
1595 #if 1
1596       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);
1597       for (p = 0; p < 4; ++p) {
1598         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);
1599       }
1600 #endif
1601       /* B' tetrahedron: {e, b, a, f} */
1602       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 1;
1603       orntNew[0] = -3;
1604       coneNew[1] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 6;
1605       orntNew[1] = 1;
1606       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 7;
1607       orntNew[2] = 0;
1608       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + 3;
1609       orntNew[3] = ornt[3] < 0 ? -(GetTetSomething_Static(ornt[3], 0)+1) : GetTetSomething_Static(ornt[3], 0);
1610       ierr       = DMPlexSetCone(rdm, newp+5, coneNew);CHKERRQ(ierr);
1611       ierr       = DMPlexSetConeOrientation(rdm, newp+5, orntNew);CHKERRQ(ierr);
1612 #if 1
1613       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);
1614       for (p = 0; p < 4; ++p) {
1615         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);
1616       }
1617 #endif
1618       /* C' tetrahedron: {b, f, c, a} */
1619       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 2;
1620       orntNew[0] = -3;
1621       coneNew[1] = fStartNew + (cone[0] - fStart)*4 + 3;
1622       orntNew[1] = ornt[0] < 0 ? -(GetTetSomething_Static(ornt[0], 2)+1) : GetTetSomething_Static(ornt[0], 2);
1623       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 5;
1624       orntNew[2] = -3;
1625       coneNew[3] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 7;
1626       orntNew[3] = -2;
1627       ierr       = DMPlexSetCone(rdm, newp+6, coneNew);CHKERRQ(ierr);
1628       ierr       = DMPlexSetConeOrientation(rdm, newp+6, orntNew);CHKERRQ(ierr);
1629 #if 1
1630       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);
1631       for (p = 0; p < 4; ++p) {
1632         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);
1633       }
1634 #endif
1635       /* D' tetrahedron: {f, e, d, a} */
1636       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 3;
1637       orntNew[0] = -3;
1638       coneNew[1] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 4;
1639       orntNew[1] = -3;
1640       coneNew[2] = fStartNew + (cone[1] - fStart)*4 + 3;
1641       orntNew[2] = ornt[1] < 0 ? -(GetTetSomething_Static(ornt[1], 0)+1) : GetTetSomething_Static(ornt[1], 0);
1642       coneNew[3] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 6;
1643       orntNew[3] = -3;
1644       ierr       = DMPlexSetCone(rdm, newp+7, coneNew);CHKERRQ(ierr);
1645       ierr       = DMPlexSetConeOrientation(rdm, newp+7, orntNew);CHKERRQ(ierr);
1646 #if 1
1647       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);
1648       for (p = 0; p < 4; ++p) {
1649         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);
1650       }
1651 #endif
1652     }
1653     /* Split faces have 3 edges and the same cells as the parent */
1654     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
1655     ierr = PetscMalloc1((2 + maxSupportSize*2), &supportRef);CHKERRQ(ierr);
1656     for (f = fStart; f < fEnd; ++f) {
1657       const PetscInt  newp = fStartNew + (f - fStart)*4;
1658       const PetscInt *cone, *ornt, *support;
1659       PetscInt        coneNew[3], orntNew[3], coneSize, supportSize, s;
1660 
1661       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
1662       ierr = DMPlexGetConeOrientation(dm, f, &ornt);CHKERRQ(ierr);
1663       /* A triangle */
1664       coneNew[0] = eStartNew + (cone[0] - eStart)*2 + (ornt[0] < 0 ? 1 : 0);
1665       orntNew[0] = ornt[0];
1666       coneNew[1] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 2;
1667       orntNew[1] = -2;
1668       coneNew[2] = eStartNew + (cone[2] - eStart)*2 + (ornt[2] < 0 ? 0 : 1);
1669       orntNew[2] = ornt[2];
1670       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
1671       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
1672 #if 1
1673       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);
1674       for (p = 0; p < 3; ++p) {
1675         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);
1676       }
1677 #endif
1678       /* B triangle */
1679       coneNew[0] = eStartNew + (cone[0] - eStart)*2 + (ornt[0] < 0 ? 0 : 1);
1680       orntNew[0] = ornt[0];
1681       coneNew[1] = eStartNew + (cone[1] - eStart)*2 + (ornt[1] < 0 ? 1 : 0);
1682       orntNew[1] = ornt[1];
1683       coneNew[2] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 0;
1684       orntNew[2] = -2;
1685       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
1686       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
1687 #if 1
1688       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);
1689       for (p = 0; p < 3; ++p) {
1690         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);
1691       }
1692 #endif
1693       /* C triangle */
1694       coneNew[0] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 1;
1695       orntNew[0] = -2;
1696       coneNew[1] = eStartNew + (cone[1] - eStart)*2 + (ornt[1] < 0 ? 0 : 1);
1697       orntNew[1] = ornt[1];
1698       coneNew[2] = eStartNew + (cone[2] - eStart)*2 + (ornt[2] < 0 ? 1 : 0);
1699       orntNew[2] = ornt[2];
1700       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
1701       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
1702 #if 1
1703       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);
1704       for (p = 0; p < 3; ++p) {
1705         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);
1706       }
1707 #endif
1708       /* D triangle */
1709       coneNew[0] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 0;
1710       orntNew[0] = 0;
1711       coneNew[1] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 1;
1712       orntNew[1] = 0;
1713       coneNew[2] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 2;
1714       orntNew[2] = 0;
1715       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
1716       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
1717 #if 1
1718       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);
1719       for (p = 0; p < 3; ++p) {
1720         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);
1721       }
1722 #endif
1723       ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
1724       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
1725       for (r = 0; r < 4; ++r) {
1726         for (s = 0; s < supportSize; ++s) {
1727           PetscInt subf;
1728           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
1729           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
1730           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
1731           for (c = 0; c < coneSize; ++c) {
1732             if (cone[c] == f) break;
1733           }
1734           subf = GetTriSubfaceInverse_Static(ornt[c], r);
1735           supportRef[s] = cStartNew + (support[s] - cStart)*8 + (r==3 ? (c+2)%4 + 4 : faces[c*3+subf]);
1736         }
1737         ierr = DMPlexSetSupport(rdm, newp+r, supportRef);CHKERRQ(ierr);
1738 #if 1
1739         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);
1740         for (p = 0; p < supportSize; ++p) {
1741           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);
1742         }
1743 #endif
1744       }
1745     }
1746     /* Interior faces have 3 edges and 2 cells */
1747     for (c = cStart; c < cEnd; ++c) {
1748       PetscInt        newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*8;
1749       const PetscInt *cone, *ornt;
1750       PetscInt        coneNew[3], orntNew[3];
1751       PetscInt        supportNew[2];
1752 
1753       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
1754       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
1755       /* Face A: {c, a, d} */
1756       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*3 + GetTetSomething_Static(ornt[0], 2);
1757       orntNew[0] = ornt[0] < 0 ? -2 : 0;
1758       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*3 + GetTetSomething_Static(ornt[1], 2);
1759       orntNew[1] = ornt[1] < 0 ? -2 : 0;
1760       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*3 + GetTetSomething_Static(ornt[2], 2);
1761       orntNew[2] = ornt[2] < 0 ? -2 : 0;
1762       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
1763       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
1764 #if 1
1765       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1766       for (p = 0; p < 3; ++p) {
1767         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);
1768       }
1769 #endif
1770       supportNew[0] = (c - cStart)*8 + 0;
1771       supportNew[1] = (c - cStart)*8 + 0+4;
1772       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
1773 #if 1
1774       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1775       for (p = 0; p < 2; ++p) {
1776         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);
1777       }
1778 #endif
1779       ++newp;
1780       /* Face B: {a, b, e} */
1781       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*3 + GetTetSomething_Static(ornt[0], 0);
1782       orntNew[0] = ornt[0] < 0 ? -2 : 0;
1783       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*3 + GetTetSomething_Static(ornt[3], 0);
1784       orntNew[1] = ornt[3] < 0 ? -2 : 0;
1785       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*3 + GetTetSomething_Static(ornt[1], 1);
1786       orntNew[2] = ornt[1] < 0 ? -2 : 0;
1787       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
1788       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
1789 #if 1
1790       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1791       for (p = 0; p < 3; ++p) {
1792         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);
1793       }
1794 #endif
1795       supportNew[0] = (c - cStart)*8 + 1;
1796       supportNew[1] = (c - cStart)*8 + 1+4;
1797       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
1798 #if 1
1799       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1800       for (p = 0; p < 2; ++p) {
1801         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);
1802       }
1803 #endif
1804       ++newp;
1805       /* Face C: {c, f, b} */
1806       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*3 + GetTetSomething_Static(ornt[2], 0);
1807       orntNew[0] = ornt[2] < 0 ? -2 : 0;
1808       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*3 + GetTetSomething_Static(ornt[3], 2);
1809       orntNew[1] = ornt[3] < 0 ? -2 : 0;
1810       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*3 + GetTetSomething_Static(ornt[0], 1);
1811       orntNew[2] = ornt[0] < 0 ? -2 : 0;
1812       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
1813       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
1814 #if 1
1815       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1816       for (p = 0; p < 3; ++p) {
1817         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);
1818       }
1819 #endif
1820       supportNew[0] = (c - cStart)*8 + 2;
1821       supportNew[1] = (c - cStart)*8 + 2+4;
1822       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
1823 #if 1
1824       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1825       for (p = 0; p < 2; ++p) {
1826         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);
1827       }
1828 #endif
1829       ++newp;
1830       /* Face D: {d, e, f} */
1831       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*3 + GetTetSomething_Static(ornt[1], 0);
1832       orntNew[0] = ornt[1] < 0 ? -2 : 0;
1833       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*3 + GetTetSomething_Static(ornt[3], 1);
1834       orntNew[1] = ornt[3] < 0 ? -2 : 0;
1835       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*3 + GetTetSomething_Static(ornt[2], 1);
1836       orntNew[2] = ornt[2] < 0 ? -2 : 0;
1837       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
1838       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
1839 #if 1
1840       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1841       for (p = 0; p < 3; ++p) {
1842         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);
1843       }
1844 #endif
1845       supportNew[0] = (c - cStart)*8 + 3;
1846       supportNew[1] = (c - cStart)*8 + 3+4;
1847       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
1848 #if 1
1849       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1850       for (p = 0; p < 2; ++p) {
1851         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);
1852       }
1853 #endif
1854       ++newp;
1855       /* Face E: {d, f, a} */
1856       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*3 + GetTetSomething_Static(ornt[2], 1);
1857       orntNew[0] = ornt[2] < 0 ? 0 : -2;
1858       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart);
1859       orntNew[1] = -2;
1860       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*3 + GetTetSomething_Static(ornt[1], 2);
1861       orntNew[2] = ornt[1] < 0 ? -2 : 0;
1862       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
1863       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
1864 #if 1
1865       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1866       for (p = 0; p < 3; ++p) {
1867         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);
1868       }
1869 #endif
1870       supportNew[0] = (c - cStart)*8 + 0+4;
1871       supportNew[1] = (c - cStart)*8 + 3+4;
1872       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
1873 #if 1
1874       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1875       for (p = 0; p < 2; ++p) {
1876         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);
1877       }
1878 #endif
1879       ++newp;
1880       /* Face F: {c, a, f} */
1881       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*3 + GetTetSomething_Static(ornt[0], 2);
1882       orntNew[0] = ornt[0] < 0 ? -2 : 0;
1883       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart);
1884       orntNew[1] = 0;
1885       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*3 + GetTetSomething_Static(ornt[2], 0);
1886       orntNew[2] = ornt[2] < 0 ? 0 : -2;
1887       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
1888       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
1889 #if 1
1890       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1891       for (p = 0; p < 3; ++p) {
1892         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);
1893       }
1894 #endif
1895       supportNew[0] = (c - cStart)*8 + 0+4;
1896       supportNew[1] = (c - cStart)*8 + 2+4;
1897       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
1898 #if 1
1899       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1900       for (p = 0; p < 2; ++p) {
1901         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);
1902       }
1903 #endif
1904       ++newp;
1905       /* Face G: {e, a, f} */
1906       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*3 + GetTetSomething_Static(ornt[1], 1);
1907       orntNew[0] = ornt[1] < 0 ? -2 : 0;
1908       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart);
1909       orntNew[1] = 0;
1910       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*3 + GetTetSomething_Static(ornt[3], 1);
1911       orntNew[2] = ornt[3] < 0 ? 0 : -2;
1912       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
1913       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
1914 #if 1
1915       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1916       for (p = 0; p < 3; ++p) {
1917         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);
1918       }
1919 #endif
1920       supportNew[0] = (c - cStart)*8 + 1+4;
1921       supportNew[1] = (c - cStart)*8 + 3+4;
1922       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
1923 #if 1
1924       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1925       for (p = 0; p < 2; ++p) {
1926         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);
1927       }
1928 #endif
1929       ++newp;
1930       /* Face H: {a, b, f} */
1931       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*3 + GetTetSomething_Static(ornt[0], 0);
1932       orntNew[0] = ornt[0] < 0 ? -2 : 0;
1933       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*3 + GetTetSomething_Static(ornt[3], 2);
1934       orntNew[1] = ornt[3] < 0 ? 0 : -2;
1935       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart);
1936       orntNew[2] = -2;
1937       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
1938       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
1939 #if 1
1940       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1941       for (p = 0; p < 3; ++p) {
1942         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);
1943       }
1944 #endif
1945       supportNew[0] = (c - cStart)*8 + 1+4;
1946       supportNew[1] = (c - cStart)*8 + 2+4;
1947       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
1948 #if 1
1949       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1950       for (p = 0; p < 2; ++p) {
1951         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);
1952       }
1953 #endif
1954       ++newp;
1955     }
1956     /* Split Edges have 2 vertices and the same faces as the parent */
1957     for (e = eStart; e < eEnd; ++e) {
1958       const PetscInt newv = vStartNew + (vEnd - vStart) + (e - eStart);
1959 
1960       for (r = 0; r < 2; ++r) {
1961         const PetscInt  newp = eStartNew + (e - eStart)*2 + r;
1962         const PetscInt *cone, *ornt, *support;
1963         PetscInt        coneNew[2], coneSize, c, supportSize, s;
1964 
1965         ierr             = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
1966         coneNew[0]       = vStartNew + (cone[0] - vStart);
1967         coneNew[1]       = vStartNew + (cone[1] - vStart);
1968         coneNew[(r+1)%2] = newv;
1969         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
1970 #if 1
1971         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
1972         for (p = 0; p < 2; ++p) {
1973           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);
1974         }
1975 #endif
1976         ierr = DMPlexGetSupportSize(dm, e, &supportSize);CHKERRQ(ierr);
1977         ierr = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
1978         for (s = 0; s < supportSize; ++s) {
1979           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
1980           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
1981           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
1982           for (c = 0; c < coneSize; ++c) {
1983             if (cone[c] == e) break;
1984           }
1985           supportRef[s] = fStartNew + (support[s] - fStart)*4 + (c + (ornt[c] < 0 ? 1-r : r))%3;
1986         }
1987         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
1988 #if 1
1989         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
1990         for (p = 0; p < supportSize; ++p) {
1991           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);
1992         }
1993 #endif
1994       }
1995     }
1996     /* Face edges have 2 vertices and 2+cells*(1/2) faces */
1997     for (f = fStart; f < fEnd; ++f) {
1998       const PetscInt *cone, *ornt, *support;
1999       PetscInt        coneSize, supportSize, s;
2000 
2001       ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
2002       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
2003       for (r = 0; r < 3; ++r) {
2004         const PetscInt  newp = eStartNew + (eEnd - eStart)*2 + (f - fStart)*3 + r;
2005         PetscInt        coneNew[2], intFaces = 0, er, eint[4] = {1, 0, 2, 0};
2006         PetscInt        fint[24] = { 1,  7, -1, -1,  0,  5,
2007                                     -1, -1,  1,  6,  0,  4,
2008                                      2,  5,  3,  4, -1, -1,
2009                                     -1, -1,  3,  6,  2,  7};
2010 
2011         ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
2012         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[(r+0)%3] - eStart);
2013         coneNew[1] = vStartNew + (vEnd - vStart) + (cone[(r+1)%3] - eStart);
2014         ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2015 #if 1
2016         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
2017         for (p = 0; p < 2; ++p) {
2018           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);
2019         }
2020 #endif
2021         supportRef[0] = fStartNew + (f - fStart)*4 + (r+1)%3;
2022         supportRef[1] = fStartNew + (f - fStart)*4 + 3;
2023         for (s = 0; s < supportSize; ++s) {
2024           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
2025           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
2026           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
2027           for (c = 0; c < coneSize; ++c) {if (cone[c] == f) break;}
2028           /* Here we want to determine whether edge newp contains a vertex which is part of the cross-tet edge */
2029           er = GetTetSomethingInverse_Static(ornt[c], r);
2030           if (er == eint[c]) {
2031             supportRef[2+intFaces++] = fStartNew + (fEnd - fStart)*4 + (support[s] - cStart)*8 + (c + 2)%4;
2032           } else {
2033             supportRef[2+intFaces++] = fStartNew + (fEnd - fStart)*4 + (support[s] - cStart)*8 + fint[(c*3 + er)*2 + 0];
2034             supportRef[2+intFaces++] = fStartNew + (fEnd - fStart)*4 + (support[s] - cStart)*8 + fint[(c*3 + er)*2 + 1];
2035           }
2036         }
2037         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
2038 #if 1
2039         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
2040         for (p = 0; p < intFaces; ++p) {
2041           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);
2042         }
2043 #endif
2044       }
2045     }
2046     /* Interior edges have 2 vertices and 4 faces */
2047     for (c = cStart; c < cEnd; ++c) {
2048       const PetscInt  newp = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart);
2049       const PetscInt *cone, *ornt, *fcone;
2050       PetscInt        coneNew[2], supportNew[4], find;
2051 
2052       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
2053       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
2054       ierr = DMPlexGetCone(dm, cone[0], &fcone);CHKERRQ(ierr);
2055       find = GetTriEdge_Static(ornt[0], 0);
2056       coneNew[0] = vStartNew + (vEnd - vStart) + (fcone[find] - eStart);
2057       ierr = DMPlexGetCone(dm, cone[2], &fcone);CHKERRQ(ierr);
2058       find = GetTriEdge_Static(ornt[2], 1);
2059       coneNew[1] = vStartNew + (vEnd - vStart) + (fcone[find] - eStart);
2060       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2061 #if 1
2062       if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
2063       for (p = 0; p < 2; ++p) {
2064         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);
2065       }
2066 #endif
2067       supportNew[0] = fStartNew + (fEnd - fStart)*4 + (c - cStart)*8 + 4;
2068       supportNew[1] = fStartNew + (fEnd - fStart)*4 + (c - cStart)*8 + 5;
2069       supportNew[2] = fStartNew + (fEnd - fStart)*4 + (c - cStart)*8 + 6;
2070       supportNew[3] = fStartNew + (fEnd - fStart)*4 + (c - cStart)*8 + 7;
2071       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
2072 #if 1
2073       if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
2074       for (p = 0; p < 4; ++p) {
2075         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);
2076       }
2077 #endif
2078     }
2079     /* Old vertices have identical supports */
2080     for (v = vStart; v < vEnd; ++v) {
2081       const PetscInt  newp = vStartNew + (v - vStart);
2082       const PetscInt *support, *cone;
2083       PetscInt        size, s;
2084 
2085       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
2086       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
2087       for (s = 0; s < size; ++s) {
2088         PetscInt r = 0;
2089 
2090         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
2091         if (cone[1] == v) r = 1;
2092         supportRef[s] = eStartNew + (support[s] - eStart)*2 + r;
2093       }
2094       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
2095 #if 1
2096       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
2097       for (p = 0; p < size; ++p) {
2098         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);
2099       }
2100 #endif
2101     }
2102     /* Edge vertices have 2 + face*2 + 0/1 supports */
2103     for (e = eStart; e < eEnd; ++e) {
2104       const PetscInt  newp = vStartNew + (vEnd - vStart) + (e - eStart);
2105       const PetscInt *cone, *support;
2106       PetscInt       *star = NULL, starSize, cellSize = 0, coneSize, size, s;
2107 
2108       ierr          = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
2109       ierr          = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
2110       supportRef[0] = eStartNew + (e - eStart)*2 + 0;
2111       supportRef[1] = eStartNew + (e - eStart)*2 + 1;
2112       for (s = 0; s < size; ++s) {
2113         PetscInt r = 0;
2114 
2115         ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
2116         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
2117         for (r = 0; r < coneSize; ++r) {if (cone[r] == e) break;}
2118         supportRef[2+s*2+0] = eStartNew + (eEnd - eStart)*2 + (support[s] - fStart)*3 + (r+0)%3;
2119         supportRef[2+s*2+1] = eStartNew + (eEnd - eStart)*2 + (support[s] - fStart)*3 + (r+2)%3;
2120       }
2121       ierr = DMPlexGetTransitiveClosure(dm, e, PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
2122       for (s = 0; s < starSize*2; s += 2) {
2123         const PetscInt *cone, *ornt;
2124         PetscInt        e01, e23;
2125 
2126         if ((star[s] >= cStart) && (star[s] < cEnd)) {
2127           /* Check edge 0-1 */
2128           ierr = DMPlexGetCone(dm, star[s], &cone);CHKERRQ(ierr);
2129           ierr = DMPlexGetConeOrientation(dm, star[s], &ornt);CHKERRQ(ierr);
2130           ierr = DMPlexGetCone(dm, cone[0], &cone);CHKERRQ(ierr);
2131           e01  = cone[GetTriEdge_Static(ornt[0], 0)];
2132           /* Check edge 2-3 */
2133           ierr = DMPlexGetCone(dm, star[s], &cone);CHKERRQ(ierr);
2134           ierr = DMPlexGetConeOrientation(dm, star[s], &ornt);CHKERRQ(ierr);
2135           ierr = DMPlexGetCone(dm, cone[2], &cone);CHKERRQ(ierr);
2136           e23  = cone[GetTriEdge_Static(ornt[2], 1)];
2137           if ((e01 == e) || (e23 == e)) {supportRef[2+size*2+cellSize++] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (star[s] - cStart);}
2138         }
2139       }
2140       ierr = DMPlexRestoreTransitiveClosure(dm, e, PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
2141       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
2142 #if 1
2143       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
2144       for (p = 0; p < 2+size*2+cellSize; ++p) {
2145         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);
2146       }
2147 #endif
2148     }
2149     ierr = PetscFree(supportRef);CHKERRQ(ierr);
2150     ierr = DMPlexRestoreFaces_Internal(dm, 3, cStart, NULL, NULL, &faces);CHKERRQ(ierr);
2151     break;
2152   case 7:
2153     /* Hybrid Simplicial 3D */
2154     ierr = DMPlexGetHybridBounds(rdm, &cMaxNew, &fMaxNew, &eMaxNew, NULL);CHKERRQ(ierr);
2155     /* Interior cells have 4 faces: Tet face order is prescribed in DMPlexGetFaces_Internal() */
2156     ierr = DMPlexGetRawFaces_Internal(dm, 3, 4, cellInd, NULL, NULL, &faces);CHKERRQ(ierr);
2157     for (c = cStart; c < cMax; ++c) {
2158       const PetscInt  newp = cStartNew + (c - cStart)*8;
2159       const PetscInt *cone, *ornt;
2160       PetscInt        coneNew[4], orntNew[4];
2161 
2162       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
2163       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
2164       /* A tetrahedron: {0, a, c, d} */
2165       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetTriSubface_Static(ornt[0], 0); /* A */
2166       orntNew[0] = ornt[0];
2167       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetTriSubface_Static(ornt[1], 0); /* A */
2168       orntNew[1] = ornt[1];
2169       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetTriSubface_Static(ornt[2], 0); /* A */
2170       orntNew[2] = ornt[2];
2171       coneNew[3] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 0;
2172       orntNew[3] = 0;
2173       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
2174       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
2175 #if 1
2176       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);
2177       for (p = 0; p < 4; ++p) {
2178         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);
2179       }
2180 #endif
2181       /* B tetrahedron: {a, 1, b, e} */
2182       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetTriSubface_Static(ornt[0], 1); /* B */
2183       orntNew[0] = ornt[0];
2184       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetTriSubface_Static(ornt[1], 2); /* C */
2185       orntNew[1] = ornt[1];
2186       coneNew[2] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 1;
2187       orntNew[2] = 0;
2188       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetTriSubface_Static(ornt[3], 1); /* B */
2189       orntNew[3] = ornt[3];
2190       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
2191       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
2192 #if 1
2193       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);
2194       for (p = 0; p < 4; ++p) {
2195         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);
2196       }
2197 #endif
2198       /* C tetrahedron: {c, b, 2, f} */
2199       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetTriSubface_Static(ornt[0], 2); /* C */
2200       orntNew[0] = ornt[0];
2201       coneNew[1] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 2;
2202       orntNew[1] = 0;
2203       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetTriSubface_Static(ornt[2], 1); /* B */
2204       orntNew[2] = ornt[2];
2205       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetTriSubface_Static(ornt[3], 0); /* A */
2206       orntNew[3] = ornt[3];
2207       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
2208       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
2209 #if 1
2210       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);
2211       for (p = 0; p < 4; ++p) {
2212         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);
2213       }
2214 #endif
2215       /* D tetrahedron: {d, e, f, 3} */
2216       coneNew[0] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 3;
2217       orntNew[0] = 0;
2218       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetTriSubface_Static(ornt[1], 1); /* B */
2219       orntNew[1] = ornt[1];
2220       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetTriSubface_Static(ornt[2], 2); /* C */
2221       orntNew[2] = ornt[2];
2222       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetTriSubface_Static(ornt[3], 2); /* C */
2223       orntNew[3] = ornt[3];
2224       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
2225       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
2226 #if 1
2227       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);
2228       for (p = 0; p < 4; ++p) {
2229         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);
2230       }
2231 #endif
2232       /* A' tetrahedron: {d, a, c, f} */
2233       coneNew[0] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 0;
2234       orntNew[0] = -3;
2235       coneNew[1] = fStartNew + (cone[2] - fStart)*4 + 3;
2236       orntNew[1] = ornt[2] < 0 ? -(GetTetSomething_Static(ornt[2], 0)+1) : GetTetSomething_Static(ornt[2], 0);
2237       coneNew[2] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 5;
2238       orntNew[2] = 0;
2239       coneNew[3] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 4;
2240       orntNew[3] = 2;
2241       ierr       = DMPlexSetCone(rdm, newp+4, coneNew);CHKERRQ(ierr);
2242       ierr       = DMPlexSetConeOrientation(rdm, newp+4, orntNew);CHKERRQ(ierr);
2243 #if 1
2244       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);
2245       for (p = 0; p < 4; ++p) {
2246         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);
2247       }
2248 #endif
2249       /* B' tetrahedron: {e, b, a, f} */
2250       coneNew[0] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 1;
2251       orntNew[0] = -3;
2252       coneNew[1] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 6;
2253       orntNew[1] = 1;
2254       coneNew[2] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 7;
2255       orntNew[2] = 0;
2256       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + 3;
2257       orntNew[3] = ornt[3] < 0 ? -(GetTetSomething_Static(ornt[3], 0)+1) : GetTetSomething_Static(ornt[3], 0);
2258       ierr       = DMPlexSetCone(rdm, newp+5, coneNew);CHKERRQ(ierr);
2259       ierr       = DMPlexSetConeOrientation(rdm, newp+5, orntNew);CHKERRQ(ierr);
2260 #if 1
2261       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);
2262       for (p = 0; p < 4; ++p) {
2263         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);
2264       }
2265 #endif
2266       /* C' tetrahedron: {b, f, c, a} */
2267       coneNew[0] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 2;
2268       orntNew[0] = -3;
2269       coneNew[1] = fStartNew + (cone[0] - fStart)*4 + 3;
2270       orntNew[1] = ornt[0] < 0 ? -(GetTetSomething_Static(ornt[0], 2)+1) : GetTetSomething_Static(ornt[0], 2);
2271       coneNew[2] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 5;
2272       orntNew[2] = -3;
2273       coneNew[3] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 7;
2274       orntNew[3] = -2;
2275       ierr       = DMPlexSetCone(rdm, newp+6, coneNew);CHKERRQ(ierr);
2276       ierr       = DMPlexSetConeOrientation(rdm, newp+6, orntNew);CHKERRQ(ierr);
2277 #if 1
2278       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);
2279       for (p = 0; p < 4; ++p) {
2280         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);
2281       }
2282 #endif
2283       /* D' tetrahedron: {f, e, d, a} */
2284       coneNew[0] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 3;
2285       orntNew[0] = -3;
2286       coneNew[1] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 4;
2287       orntNew[1] = -3;
2288       coneNew[2] = fStartNew + (cone[1] - fStart)*4 + 3;
2289       orntNew[2] = ornt[1] < 0 ? -(GetTetSomething_Static(ornt[1], 0)+1) : GetTetSomething_Static(ornt[1], 0);
2290       coneNew[3] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 6;
2291       orntNew[3] = -3;
2292       ierr       = DMPlexSetCone(rdm, newp+7, coneNew);CHKERRQ(ierr);
2293       ierr       = DMPlexSetConeOrientation(rdm, newp+7, orntNew);CHKERRQ(ierr);
2294 #if 1
2295       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);
2296       for (p = 0; p < 4; ++p) {
2297         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);
2298       }
2299 #endif
2300     }
2301     /* Hybrid cells have 5 faces */
2302     for (c = cMax; c < cEnd; ++c) {
2303       const PetscInt  newp = cStartNew + (cMax - cStart)*8 + (c - cMax)*4;
2304       const PetscInt *cone, *ornt, *fornt;
2305       PetscInt        coneNew[5], orntNew[5];
2306 
2307       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
2308       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
2309       ierr = DMPlexGetConeOrientation(dm, cone[0], &fornt);CHKERRQ(ierr);
2310       for (r = 0; r < 3; ++r) {
2311         coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetTriSubface_Static(ornt[0], r);
2312         orntNew[0] = ornt[0];
2313         coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetTriSubface_Static(ornt[1], r);
2314         orntNew[1] = ornt[1];
2315         coneNew[2] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (cone[2+GetTriEdge_Static(ornt[0], (r+2)%3)] - fMax)*2 + (fornt[GetTriEdge_Static(ornt[0], (r+2)%3)] < 0 ? 0 : 1);
2316         orntNew[2] = 0;
2317         coneNew[3] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (cone[2+GetTriEdge_Static(ornt[0], r)]       - fMax)*2 + (fornt[GetTriEdge_Static(ornt[0], r)]       < 0 ? 1 : 0);
2318         orntNew[3] = 0;
2319         coneNew[4] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (c - cMax)*3 + GetTriSubface_Static(ornt[0], r);
2320         orntNew[4] = 0;
2321         ierr = DMPlexSetCone(rdm, newp+r, coneNew);CHKERRQ(ierr);
2322         ierr = DMPlexSetConeOrientation(rdm, newp+r, orntNew);CHKERRQ(ierr);
2323 #if 1
2324         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);
2325         for (p = 0; p < 2; ++p) {
2326           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);
2327         }
2328         for (p = 2; p < 5; ++p) {
2329           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);
2330         }
2331 #endif
2332       }
2333       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + 3;
2334       orntNew[0] = 0;
2335       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + 3;
2336       orntNew[1] = 0;
2337       coneNew[2] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (c - cMax)*3 + 0;
2338       orntNew[2] = 0;
2339       coneNew[3] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (c - cMax)*3 + 1;
2340       orntNew[3] = 0;
2341       coneNew[4] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (c - cMax)*3 + 2;
2342       orntNew[4] = 0;
2343       ierr = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
2344       ierr = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
2345 #if 1
2346       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);
2347       for (p = 0; p < 2; ++p) {
2348         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);
2349       }
2350       for (p = 2; p < 5; ++p) {
2351         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);
2352       }
2353 #endif
2354     }
2355     /* Split faces have 3 edges and the same cells as the parent */
2356     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
2357     ierr = PetscMalloc1((2 + maxSupportSize*2), &supportRef);CHKERRQ(ierr);
2358     for (f = fStart; f < fMax; ++f) {
2359       const PetscInt  newp = fStartNew + (f - fStart)*4;
2360       const PetscInt *cone, *ornt, *support;
2361       PetscInt        coneNew[3], orntNew[3], coneSize, supportSize, s;
2362 
2363       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
2364       ierr = DMPlexGetConeOrientation(dm, f, &ornt);CHKERRQ(ierr);
2365       /* A triangle */
2366       coneNew[0] = eStartNew + (cone[0] - eStart)*2 + (ornt[0] < 0 ? 1 : 0);
2367       orntNew[0] = ornt[0];
2368       coneNew[1] = eStartNew + (eMax    - eStart)*2 + (f - fStart)*3 + 2;
2369       orntNew[1] = -2;
2370       coneNew[2] = eStartNew + (cone[2] - eStart)*2 + (ornt[2] < 0 ? 0 : 1);
2371       orntNew[2] = ornt[2];
2372       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
2373       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
2374 #if 1
2375       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);
2376       for (p = 0; p < 3; ++p) {
2377         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);
2378       }
2379 #endif
2380       /* B triangle */
2381       coneNew[0] = eStartNew + (cone[0] - eStart)*2 + (ornt[0] < 0 ? 0 : 1);
2382       orntNew[0] = ornt[0];
2383       coneNew[1] = eStartNew + (cone[1] - eStart)*2 + (ornt[1] < 0 ? 1 : 0);
2384       orntNew[1] = ornt[1];
2385       coneNew[2] = eStartNew + (eMax    - eStart)*2 + (f - fStart)*3 + 0;
2386       orntNew[2] = -2;
2387       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
2388       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
2389 #if 1
2390       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);
2391       for (p = 0; p < 3; ++p) {
2392         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);
2393       }
2394 #endif
2395       /* C triangle */
2396       coneNew[0] = eStartNew + (eMax    - eStart)*2 + (f - fStart)*3 + 1;
2397       orntNew[0] = -2;
2398       coneNew[1] = eStartNew + (cone[1] - eStart)*2 + (ornt[1] < 0 ? 0 : 1);
2399       orntNew[1] = ornt[1];
2400       coneNew[2] = eStartNew + (cone[2] - eStart)*2 + (ornt[2] < 0 ? 1 : 0);
2401       orntNew[2] = ornt[2];
2402       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
2403       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
2404 #if 1
2405       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);
2406       for (p = 0; p < 3; ++p) {
2407         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);
2408       }
2409 #endif
2410       /* D triangle */
2411       coneNew[0] = eStartNew + (eMax    - eStart)*2 + (f - fStart)*3 + 0;
2412       orntNew[0] = 0;
2413       coneNew[1] = eStartNew + (eMax    - eStart)*2 + (f - fStart)*3 + 1;
2414       orntNew[1] = 0;
2415       coneNew[2] = eStartNew + (eMax    - eStart)*2 + (f - fStart)*3 + 2;
2416       orntNew[2] = 0;
2417       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
2418       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
2419 #if 1
2420       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);
2421       for (p = 0; p < 3; ++p) {
2422         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);
2423       }
2424 #endif
2425       ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
2426       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
2427       for (r = 0; r < 4; ++r) {
2428         for (s = 0; s < supportSize; ++s) {
2429           PetscInt subf;
2430           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
2431           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
2432           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
2433           for (c = 0; c < coneSize; ++c) {
2434             if (cone[c] == f) break;
2435           }
2436           subf = GetTriSubfaceInverse_Static(ornt[c], r);
2437           if (support[s] < cMax) {
2438             supportRef[s] = cStartNew + (support[s] - cStart)*8 + (r==3 ? (c+2)%4 + 4 : faces[c*3+subf]);
2439           } else {
2440             supportRef[s] = cStartNew + (cMax - cStart)*8 + (support[s] - cMax)*4 + (r==3 ? r : subf);
2441           }
2442         }
2443         ierr = DMPlexSetSupport(rdm, newp+r, supportRef);CHKERRQ(ierr);
2444 #if 1
2445         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);
2446         for (p = 0; p < supportSize; ++p) {
2447           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);
2448         }
2449 #endif
2450       }
2451     }
2452     /* Interior cell faces have 3 edges and 2 cells */
2453     for (c = cStart; c < cMax; ++c) {
2454       PetscInt        newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*8;
2455       const PetscInt *cone, *ornt;
2456       PetscInt        coneNew[3], orntNew[3];
2457       PetscInt        supportNew[2];
2458 
2459       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
2460       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
2461       /* Face A: {c, a, d} */
2462       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*3 + GetTetSomething_Static(ornt[0], 2);
2463       orntNew[0] = ornt[0] < 0 ? -2 : 0;
2464       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*3 + GetTetSomething_Static(ornt[1], 2);
2465       orntNew[1] = ornt[1] < 0 ? -2 : 0;
2466       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*3 + GetTetSomething_Static(ornt[2], 2);
2467       orntNew[2] = ornt[2] < 0 ? -2 : 0;
2468       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2469       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
2470 #if 1
2471       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
2472       for (p = 0; p < 3; ++p) {
2473         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);
2474       }
2475 #endif
2476       supportNew[0] = (c - cStart)*8 + 0;
2477       supportNew[1] = (c - cStart)*8 + 0+4;
2478       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
2479 #if 1
2480       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
2481       for (p = 0; p < 2; ++p) {
2482         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);
2483       }
2484 #endif
2485       ++newp;
2486       /* Face B: {a, b, e} */
2487       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*3 + GetTetSomething_Static(ornt[0], 0);
2488       orntNew[0] = ornt[0] < 0 ? -2 : 0;
2489       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*3 + GetTetSomething_Static(ornt[3], 0);
2490       orntNew[1] = ornt[3] < 0 ? -2 : 0;
2491       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*3 + GetTetSomething_Static(ornt[1], 1);
2492       orntNew[2] = ornt[1] < 0 ? -2 : 0;
2493       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2494       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
2495 #if 1
2496       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);
2497       for (p = 0; p < 3; ++p) {
2498         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);
2499       }
2500 #endif
2501       supportNew[0] = (c - cStart)*8 + 1;
2502       supportNew[1] = (c - cStart)*8 + 1+4;
2503       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
2504 #if 1
2505       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
2506       for (p = 0; p < 2; ++p) {
2507         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);
2508       }
2509 #endif
2510       ++newp;
2511       /* Face C: {c, f, b} */
2512       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*3 + GetTetSomething_Static(ornt[2], 0);
2513       orntNew[0] = ornt[2] < 0 ? -2 : 0;
2514       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*3 + GetTetSomething_Static(ornt[3], 2);
2515       orntNew[1] = ornt[3] < 0 ? -2 : 0;
2516       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*3 + GetTetSomething_Static(ornt[0], 1);
2517       orntNew[2] = ornt[0] < 0 ? -2 : 0;
2518       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2519       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
2520 #if 1
2521       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
2522       for (p = 0; p < 3; ++p) {
2523         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);
2524       }
2525 #endif
2526       supportNew[0] = (c - cStart)*8 + 2;
2527       supportNew[1] = (c - cStart)*8 + 2+4;
2528       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
2529 #if 1
2530       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
2531       for (p = 0; p < 2; ++p) {
2532         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);
2533       }
2534 #endif
2535       ++newp;
2536       /* Face D: {d, e, f} */
2537       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*3 + GetTetSomething_Static(ornt[1], 0);
2538       orntNew[0] = ornt[1] < 0 ? -2 : 0;
2539       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*3 + GetTetSomething_Static(ornt[3], 1);
2540       orntNew[1] = ornt[3] < 0 ? -2 : 0;
2541       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*3 + GetTetSomething_Static(ornt[2], 1);
2542       orntNew[2] = ornt[2] < 0 ? -2 : 0;
2543       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2544       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
2545 #if 1
2546       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
2547       for (p = 0; p < 3; ++p) {
2548         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);
2549       }
2550 #endif
2551       supportNew[0] = (c - cStart)*8 + 3;
2552       supportNew[1] = (c - cStart)*8 + 3+4;
2553       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
2554 #if 1
2555       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
2556       for (p = 0; p < 2; ++p) {
2557         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);
2558       }
2559 #endif
2560       ++newp;
2561       /* Face E: {d, f, a} */
2562       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*3 + GetTetSomething_Static(ornt[2], 1);
2563       orntNew[0] = ornt[2] < 0 ? 0 : -2;
2564       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart);
2565       orntNew[1] = -2;
2566       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*3 + GetTetSomething_Static(ornt[1], 2);
2567       orntNew[2] = ornt[1] < 0 ? -2 : 0;
2568       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2569       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
2570 #if 1
2571       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, 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       supportNew[0] = (c - cStart)*8 + 0+4;
2577       supportNew[1] = (c - cStart)*8 + 3+4;
2578       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
2579 #if 1
2580       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
2581       for (p = 0; p < 2; ++p) {
2582         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);
2583       }
2584 #endif
2585       ++newp;
2586       /* Face F: {c, a, f} */
2587       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*3 + GetTetSomething_Static(ornt[0], 2);
2588       orntNew[0] = ornt[0] < 0 ? -2 : 0;
2589       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart);
2590       orntNew[1] = 0;
2591       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*3 + GetTetSomething_Static(ornt[2], 0);
2592       orntNew[2] = ornt[2] < 0 ? 0 : -2;
2593       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2594       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
2595 #if 1
2596       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
2597       for (p = 0; p < 3; ++p) {
2598         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);
2599       }
2600 #endif
2601       supportNew[0] = (c - cStart)*8 + 0+4;
2602       supportNew[1] = (c - cStart)*8 + 2+4;
2603       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
2604 #if 1
2605       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
2606       for (p = 0; p < 2; ++p) {
2607         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);
2608       }
2609 #endif
2610       ++newp;
2611       /* Face G: {e, a, f} */
2612       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*3 + GetTetSomething_Static(ornt[1], 1);
2613       orntNew[0] = ornt[1] < 0 ? -2 : 0;
2614       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart);
2615       orntNew[1] = 0;
2616       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*3 + GetTetSomething_Static(ornt[3], 1);
2617       orntNew[2] = ornt[3] < 0 ? 0 : -2;
2618       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2619       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
2620 #if 1
2621       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
2622       for (p = 0; p < 3; ++p) {
2623         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);
2624       }
2625 #endif
2626       supportNew[0] = (c - cStart)*8 + 1+4;
2627       supportNew[1] = (c - cStart)*8 + 3+4;
2628       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
2629 #if 1
2630       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
2631       for (p = 0; p < 2; ++p) {
2632         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);
2633       }
2634 #endif
2635       ++newp;
2636       /* Face H: {a, b, f} */
2637       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*3 + GetTetSomething_Static(ornt[0], 0);
2638       orntNew[0] = ornt[0] < 0 ? -2 : 0;
2639       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*3 + GetTetSomething_Static(ornt[3], 2);
2640       orntNew[1] = ornt[3] < 0 ? 0 : -2;
2641       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart);
2642       orntNew[2] = -2;
2643       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2644       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);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 < 3; ++p) {
2648         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);
2649       }
2650 #endif
2651       supportNew[0] = (c - cStart)*8 + 1+4;
2652       supportNew[1] = (c - cStart)*8 + 2+4;
2653       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
2654 #if 1
2655       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
2656       for (p = 0; p < 2; ++p) {
2657         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);
2658       }
2659 #endif
2660       ++newp;
2661     }
2662     /* Hybrid split faces have 4 edges and same cells */
2663     for (f = fMax; f < fEnd; ++f) {
2664       const PetscInt *cone, *ornt, *support;
2665       PetscInt        coneNew[4], orntNew[4];
2666       PetscInt        supportNew[2], size, s, c;
2667 
2668       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
2669       ierr = DMPlexGetConeOrientation(dm, f, &ornt);CHKERRQ(ierr);
2670       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
2671       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
2672       for (r = 0; r < 2; ++r) {
2673         const PetscInt newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (f - fMax)*2 + r;
2674 
2675         coneNew[0]   = eStartNew + (cone[0] - eStart)*2 + (ornt[0] < 0 ? 1-r : r);
2676         orntNew[0]   = ornt[0];
2677         coneNew[1]   = eStartNew + (cone[1] - eStart)*2 + (ornt[1] < 0 ? 1-r : r);
2678         orntNew[1]   = ornt[1];
2679         coneNew[2+r] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (cone[2+r] - eMax);
2680         orntNew[2+r] = 0;
2681         coneNew[3-r] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (eEnd      - eMax) + (f - fMax);
2682         orntNew[3-r] = 0;
2683         ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2684         ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
2685 #if 1
2686         if ((newp < fMaxNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid face [%d, %d)", newp, fMaxNew, fEndNew);
2687         for (p = 0; p < 2; ++p) {
2688           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);
2689         }
2690         for (p = 2; p < 4; ++p) {
2691           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);
2692         }
2693 #endif
2694         for (s = 0; s < size; ++s) {
2695           const PetscInt *coneCell, *orntCell, *fornt;
2696 
2697           ierr = DMPlexGetCone(dm, support[s], &coneCell);CHKERRQ(ierr);
2698           ierr = DMPlexGetConeOrientation(dm, support[s], &orntCell);CHKERRQ(ierr);
2699           for (c = 2; c < 5; ++c) if (coneCell[c] == f) break;
2700           if (c >= 5) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Could not find face %d in cone of cell %d", f, support[s]);
2701           ierr = DMPlexGetConeOrientation(dm, coneCell[0], &fornt);CHKERRQ(ierr);
2702           supportNew[s] = cStartNew + (cMax - cStart)*8 + (support[s] - cMax)*4 + (GetTriEdgeInverse_Static(orntCell[0], c-2) + (fornt[c-2] < 0 ? 1-r : r))%3;
2703         }
2704         ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
2705 #if 1
2706         if ((newp < fMaxNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid face [%d, %d)", newp, fMaxNew, fEndNew);
2707         for (p = 0; p < size; ++p) {
2708           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);
2709         }
2710 #endif
2711       }
2712     }
2713     /* Hybrid cell faces have 4 edges and 2 cells */
2714     for (c = cMax; c < cEnd; ++c) {
2715       PetscInt        newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (c - cMax)*3;
2716       const PetscInt *cone, *ornt;
2717       PetscInt        coneNew[4], orntNew[4];
2718       PetscInt        supportNew[2];
2719 
2720       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
2721       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
2722       for (r = 0; r < 3; ++r) {
2723         coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*3 + GetTriSubface_Static(ornt[0], (r+2)%3);
2724         orntNew[0] = 0;
2725         coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*3 + GetTriSubface_Static(ornt[1], (r+2)%3);
2726         orntNew[1] = 0;
2727         coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (eEnd - eMax) + (cone[2+GetTriSubface_Static(ornt[0], (r+2)%3)] - fMax);
2728         orntNew[2] = 0;
2729         coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (eEnd - eMax) + (cone[2+GetTriSubface_Static(ornt[0], r)]       - fMax);
2730         orntNew[3] = 0;
2731         ierr = DMPlexSetCone(rdm, newp+r, coneNew);CHKERRQ(ierr);
2732         ierr = DMPlexSetConeOrientation(rdm, newp+r, orntNew);CHKERRQ(ierr);
2733 #if 1
2734         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);
2735         for (p = 0; p < 2; ++p) {
2736           if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eMaxNew);
2737         }
2738         for (p = 2; p < 4; ++p) {
2739           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);
2740         }
2741 #endif
2742         supportNew[0] = cStartNew + (cMax - cStart)*8 + (c - cMax)*4 + GetTriSubface_Static(ornt[0], r);
2743         supportNew[1] = cStartNew + (cMax - cStart)*8 + (c - cMax)*4 + 3;
2744         ierr          = DMPlexSetSupport(rdm, newp+r, supportNew);CHKERRQ(ierr);
2745 #if 1
2746         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);
2747         for (p = 0; p < 2; ++p) {
2748           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);
2749         }
2750 #endif
2751       }
2752     }
2753     /* Interior split edges have 2 vertices and the same faces as the parent */
2754     for (e = eStart; e < eMax; ++e) {
2755       const PetscInt newv = vStartNew + (vEnd - vStart) + (e - eStart);
2756 
2757       for (r = 0; r < 2; ++r) {
2758         const PetscInt  newp = eStartNew + (e - eStart)*2 + r;
2759         const PetscInt *cone, *ornt, *support;
2760         PetscInt        coneNew[2], coneSize, c, supportSize, s;
2761 
2762         ierr             = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
2763         coneNew[0]       = vStartNew + (cone[0] - vStart);
2764         coneNew[1]       = vStartNew + (cone[1] - vStart);
2765         coneNew[(r+1)%2] = newv;
2766         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2767 #if 1
2768         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
2769         for (p = 0; p < 2; ++p) {
2770           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);
2771         }
2772 #endif
2773         ierr = DMPlexGetSupportSize(dm, e, &supportSize);CHKERRQ(ierr);
2774         ierr = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
2775         for (s = 0; s < supportSize; ++s) {
2776           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
2777           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
2778           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
2779           for (c = 0; c < coneSize; ++c) if (cone[c] == e) break;
2780           if (support[s] < fMax) {
2781             supportRef[s] = fStartNew + (support[s] - fStart)*4 + (c + (ornt[c] < 0 ? 1-r : r))%3;
2782           } else {
2783             supportRef[s] = fStartNew + (fMax       - fStart)*4 + (cMax - cStart)*8 + (support[s] - fMax)*2 + (ornt[c] < 0 ? 1-r : r);
2784           }
2785         }
2786         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
2787 #if 1
2788         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
2789         for (p = 0; p < supportSize; ++p) {
2790           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);
2791         }
2792 #endif
2793       }
2794     }
2795     /* Interior face edges have 2 vertices and 2+cells*(1/2) faces */
2796     for (f = fStart; f < fMax; ++f) {
2797       const PetscInt *cone, *ornt, *support;
2798       PetscInt        coneSize, supportSize, s;
2799 
2800       ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
2801       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
2802       for (r = 0; r < 3; ++r) {
2803         const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (f - fStart)*3 + r;
2804         PetscInt        coneNew[2], intFaces = 0, er, eint[4] = {1, 0, 2, 0};
2805         PetscInt        fint[24] = { 1,  7, -1, -1,  0,  5,
2806                                     -1, -1,  1,  6,  0,  4,
2807                                      2,  5,  3,  4, -1, -1,
2808                                     -1, -1,  3,  6,  2,  7};
2809 
2810         ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
2811         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[(r+0)%3] - eStart);
2812         coneNew[1] = vStartNew + (vEnd - vStart) + (cone[(r+1)%3] - eStart);
2813         ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2814 #if 1
2815         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
2816         for (p = 0; p < 2; ++p) {
2817           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);
2818         }
2819 #endif
2820         supportRef[0] = fStartNew + (f - fStart)*4 + (r+1)%3;
2821         supportRef[1] = fStartNew + (f - fStart)*4 + 3;
2822         for (s = 0; s < supportSize; ++s) {
2823           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
2824           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
2825           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
2826           for (c = 0; c < coneSize; ++c) {if (cone[c] == f) break;}
2827           if (support[s] < cMax) {
2828             /* Here we want to determine whether edge newp contains a vertex which is part of the cross-tet edge */
2829             er = GetTetSomethingInverse_Static(ornt[c], r);
2830             if (er == eint[c]) {
2831               supportRef[2+intFaces++] = fStartNew + (fMax - fStart)*4 + (support[s] - cStart)*8 + (c + 2)%4;
2832             } else {
2833               supportRef[2+intFaces++] = fStartNew + (fMax - fStart)*4 + (support[s] - cStart)*8 + fint[(c*3 + er)*2 + 0];
2834               supportRef[2+intFaces++] = fStartNew + (fMax - fStart)*4 + (support[s] - cStart)*8 + fint[(c*3 + er)*2 + 1];
2835             }
2836           } else {
2837             supportRef[2+intFaces++] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (support[s] - cMax)*3 + (GetTriSubfaceInverse_Static(ornt[c], r) + 1)%3;
2838           }
2839         }
2840         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
2841 #if 1
2842         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
2843         for (p = 0; p < intFaces; ++p) {
2844           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);
2845         }
2846 #endif
2847       }
2848     }
2849     /* Interior cell edges have 2 vertices and 4 faces */
2850     for (c = cStart; c < cMax; ++c) {
2851       const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart);
2852       const PetscInt *cone, *ornt, *fcone;
2853       PetscInt        coneNew[2], supportNew[4], find;
2854 
2855       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
2856       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
2857       ierr = DMPlexGetCone(dm, cone[0], &fcone);CHKERRQ(ierr);
2858       find = GetTriEdge_Static(ornt[0], 0);
2859       coneNew[0] = vStartNew + (vEnd - vStart) + (fcone[find] - eStart);
2860       ierr = DMPlexGetCone(dm, cone[2], &fcone);CHKERRQ(ierr);
2861       find = GetTriEdge_Static(ornt[2], 1);
2862       coneNew[1] = vStartNew + (vEnd - vStart) + (fcone[find] - eStart);
2863       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2864 #if 1
2865       if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
2866       for (p = 0; p < 2; ++p) {
2867         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);
2868       }
2869 #endif
2870       supportNew[0] = fStartNew + (fMax - fStart)*4 + (c - cStart)*8 + 4;
2871       supportNew[1] = fStartNew + (fMax - fStart)*4 + (c - cStart)*8 + 5;
2872       supportNew[2] = fStartNew + (fMax - fStart)*4 + (c - cStart)*8 + 6;
2873       supportNew[3] = fStartNew + (fMax - fStart)*4 + (c - cStart)*8 + 7;
2874       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
2875 #if 1
2876       if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
2877       for (p = 0; p < 4; ++p) {
2878         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);
2879       }
2880 #endif
2881     }
2882     /* Hybrid edges have two vertices and the same faces */
2883     for (e = eMax; e < eEnd; ++e) {
2884       const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (e - eMax);
2885       const PetscInt *cone, *support, *fcone;
2886       PetscInt        coneNew[2], size, fsize, s;
2887 
2888       ierr = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
2889       ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
2890       ierr = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
2891       coneNew[0] = vStartNew + (cone[0] - vStart);
2892       coneNew[1] = vStartNew + (cone[1] - vStart);
2893       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2894 #if 1
2895       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid edge [%d, %d)", newp, eMaxNew, eEndNew);
2896       for (p = 0; p < 2; ++p) {
2897         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);
2898       }
2899 #endif
2900       for (s = 0; s < size; ++s) {
2901         ierr = DMPlexGetConeSize(dm, support[s], &fsize);CHKERRQ(ierr);
2902         ierr = DMPlexGetCone(dm, support[s], &fcone);CHKERRQ(ierr);
2903         for (c = 0; c < fsize; ++c) if (fcone[c] == e) break;
2904         if ((c < 2) || (c > 3)) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Edge %d not found in cone of face %d", e, support[s]);
2905         supportRef[s] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (support[s] - fMax)*2 + c-2;
2906       }
2907       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
2908 #if 1
2909       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid edge [%d, %d)", newp, eMaxNew, eEndNew);
2910       for (p = 0; p < size; ++p) {
2911         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);
2912       }
2913 #endif
2914     }
2915     /* Hybrid face edges have 2 vertices and 2+2*cells faces */
2916     for (f = fMax; f < fEnd; ++f) {
2917       const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (eEnd - eMax) + (f - fMax);
2918       const PetscInt *cone, *support, *ccone, *cornt;
2919       PetscInt        coneNew[2], size, csize, s;
2920 
2921       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
2922       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
2923       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
2924       coneNew[0] = vStartNew + (vEnd - vStart) + (cone[0] - eStart);
2925       coneNew[1] = vStartNew + (vEnd - vStart) + (cone[1] - eStart);
2926       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2927 #if 1
2928       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid edge [%d, %d)", newp, eMaxNew, eEndNew);
2929       for (p = 0; p < 2; ++p) {
2930         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);
2931       }
2932 #endif
2933       supportRef[0] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (f - fMax)*2 + 0;
2934       supportRef[1] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (f - fMax)*2 + 1;
2935       for (s = 0; s < size; ++s) {
2936         ierr = DMPlexGetConeSize(dm, support[s], &csize);CHKERRQ(ierr);
2937         ierr = DMPlexGetCone(dm, support[s], &ccone);CHKERRQ(ierr);
2938         ierr = DMPlexGetConeOrientation(dm, support[s], &cornt);CHKERRQ(ierr);
2939         for (c = 0; c < csize; ++c) if (ccone[c] == f) break;
2940         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]);
2941         supportRef[2+s*2+0] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (support[s] - cMax)*3 + GetTriSubfaceInverse_Static(cornt[0], c-2);
2942         supportRef[2+s*2+1] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (support[s] - cMax)*3 + (GetTriSubfaceInverse_Static(cornt[0], c-2) + 1)%3;
2943       }
2944       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
2945 #if 1
2946       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid edge [%d, %d)", newp, eMaxNew, eEndNew);
2947       for (p = 0; p < 2+size*2; ++p) {
2948         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);
2949       }
2950 #endif
2951     }
2952     /* Interior vertices have identical supports */
2953     for (v = vStart; v < vEnd; ++v) {
2954       const PetscInt  newp = vStartNew + (v - vStart);
2955       const PetscInt *support, *cone;
2956       PetscInt        size, s;
2957 
2958       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
2959       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
2960       for (s = 0; s < size; ++s) {
2961         PetscInt r = 0;
2962 
2963         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
2964         if (cone[1] == v) r = 1;
2965         if (support[s] < eMax) supportRef[s] = eStartNew + (support[s] - eStart)*2 + r;
2966         else                   supportRef[s] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (support[s] - eMax);
2967       }
2968       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
2969 #if 1
2970       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
2971       for (p = 0; p < size; ++p) {
2972         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);
2973       }
2974 #endif
2975     }
2976     /* Interior edge vertices have 2 + interior face*2 + hybrid face + cells*0/1 supports */
2977     for (e = eStart; e < eMax; ++e) {
2978       const PetscInt  newp = vStartNew + (vEnd - vStart) + (e - eStart);
2979       const PetscInt *cone, *support;
2980       PetscInt       *star = NULL, starSize, faceSize = 0, cellSize = 0, coneSize, size, s;
2981 
2982       ierr          = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
2983       ierr          = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
2984       supportRef[0] = eStartNew + (e - eStart)*2 + 0;
2985       supportRef[1] = eStartNew + (e - eStart)*2 + 1;
2986       for (s = 0; s < size; ++s) {
2987         PetscInt r = 0;
2988 
2989         if (support[s] < fMax) {
2990           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
2991           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
2992           for (r = 0; r < coneSize; ++r) {if (cone[r] == e) break;}
2993           supportRef[2+faceSize+0] = eStartNew + (eMax - eStart)*2 + (support[s] - fStart)*3 + (r+0)%3;
2994           supportRef[2+faceSize+1] = eStartNew + (eMax - eStart)*2 + (support[s] - fStart)*3 + (r+2)%3;
2995           faceSize += 2;
2996         } else {
2997           supportRef[2+faceSize+0] = eStartNew + (eMax - eStart)*2 + (fMax       - fStart)*3 + (cMax - cStart) + (eEnd - eMax) + (support[s] - fMax);
2998           ++faceSize;
2999         }
3000       }
3001       ierr = DMPlexGetTransitiveClosure(dm, e, PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
3002       for (s = 0; s < starSize*2; s += 2) {
3003         const PetscInt *cone, *ornt;
3004         PetscInt        e01, e23;
3005 
3006         if ((star[s] >= cStart) && (star[s] < cMax)) {
3007           /* Check edge 0-1 */
3008           ierr = DMPlexGetCone(dm, star[s], &cone);CHKERRQ(ierr);
3009           ierr = DMPlexGetConeOrientation(dm, star[s], &ornt);CHKERRQ(ierr);
3010           ierr = DMPlexGetCone(dm, cone[0], &cone);CHKERRQ(ierr);
3011           e01  = cone[GetTriEdge_Static(ornt[0], 0)];
3012           /* Check edge 2-3 */
3013           ierr = DMPlexGetCone(dm, star[s], &cone);CHKERRQ(ierr);
3014           ierr = DMPlexGetConeOrientation(dm, star[s], &ornt);CHKERRQ(ierr);
3015           ierr = DMPlexGetCone(dm, cone[2], &cone);CHKERRQ(ierr);
3016           e23  = cone[GetTriEdge_Static(ornt[2], 1)];
3017           if ((e01 == e) || (e23 == e)) {supportRef[2+faceSize+cellSize++] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (star[s] - cStart);}
3018         }
3019       }
3020       ierr = DMPlexRestoreTransitiveClosure(dm, e, PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
3021       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
3022 #if 1
3023       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
3024       for (p = 0; p < 2+faceSize+cellSize; ++p) {
3025         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);
3026       }
3027 #endif
3028     }
3029     ierr = PetscFree(supportRef);CHKERRQ(ierr);
3030     ierr = DMPlexRestoreFaces_Internal(dm, 3, cStart, NULL, NULL, &faces);CHKERRQ(ierr);
3031     break;
3032   case 6:
3033     /* Hex 3D */
3034     /*
3035      Bottom (viewed from top)    Top
3036      1---------2---------2       7---------2---------6
3037      |         |         |       |         |         |
3038      |    B    2    C    |       |    H    2    G    |
3039      |         |         |       |         |         |
3040      3----3----0----1----1       3----3----0----1----1
3041      |         |         |       |         |         |
3042      |    A    0    D    |       |    E    0    F    |
3043      |         |         |       |         |         |
3044      0---------0---------3       4---------0---------5
3045      */
3046     /* All cells have 6 faces: Bottom, Top, Front, Back, Right, Left */
3047     for (c = cStart; c < cEnd; ++c) {
3048       const PetscInt  newp = (c - cStart)*8;
3049       const PetscInt *cone, *ornt;
3050       PetscInt        coneNew[6], orntNew[6];
3051 
3052       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
3053       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
3054       /* A hex */
3055       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], 0);
3056       orntNew[0] = ornt[0];
3057       coneNew[1] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  8; /* AE */
3058       orntNew[1] = 0;
3059       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetQuadSubface_Static(ornt[2], 0);
3060       orntNew[2] = ornt[2];
3061       coneNew[3] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  3; /* AB */
3062       orntNew[3] = 0;
3063       coneNew[4] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  0; /* AD */
3064       orntNew[4] = 0;
3065       coneNew[5] = fStartNew + (cone[5] - fStart)*4 + GetQuadSubface_Static(ornt[5], 0);
3066       orntNew[5] = ornt[5];
3067       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
3068       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
3069 #if 1
3070       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);
3071       for (p = 0; p < 6; ++p) {
3072         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);
3073       }
3074 #endif
3075       /* B hex */
3076       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], 1);
3077       orntNew[0] = ornt[0];
3078       coneNew[1] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 + 11; /* BH */
3079       orntNew[1] = 0;
3080       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  3; /* AB */
3081       orntNew[2] = -1;
3082       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetQuadSubface_Static(ornt[3], 1);
3083       orntNew[3] = ornt[3];
3084       coneNew[4] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  2; /* BC */
3085       orntNew[4] = 0;
3086       coneNew[5] = fStartNew + (cone[5] - fStart)*4 + GetQuadSubface_Static(ornt[5], 3);
3087       orntNew[5] = ornt[5];
3088       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
3089       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
3090 #if 1
3091       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);
3092       for (p = 0; p < 6; ++p) {
3093         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);
3094       }
3095 #endif
3096       /* C hex */
3097       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], 2);
3098       orntNew[0] = ornt[0];
3099       coneNew[1] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 + 10; /* CG */
3100       orntNew[1] = 0;
3101       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  1; /* CD */
3102       orntNew[2] = -1;
3103       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetQuadSubface_Static(ornt[3], 0);
3104       orntNew[3] = ornt[3];
3105       coneNew[4] = fStartNew + (cone[4] - fStart)*4 + GetQuadSubface_Static(ornt[4], 1);
3106       orntNew[4] = ornt[4];
3107       coneNew[5] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  2; /* BC */
3108       orntNew[5] = -4;
3109       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
3110       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
3111 #if 1
3112       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);
3113       for (p = 0; p < 6; ++p) {
3114         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);
3115       }
3116 #endif
3117       /* D hex */
3118       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], 3);
3119       orntNew[0] = ornt[0];
3120       coneNew[1] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  9; /* DF */
3121       orntNew[1] = 0;
3122       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetQuadSubface_Static(ornt[2], 1);
3123       orntNew[2] = ornt[2];
3124       coneNew[3] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  1; /* CD */
3125       orntNew[3] = 0;
3126       coneNew[4] = fStartNew + (cone[4] - fStart)*4 + GetQuadSubface_Static(ornt[4], 0);
3127       orntNew[4] = ornt[4];
3128       coneNew[5] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  0; /* AD */
3129       orntNew[5] = -4;
3130       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
3131       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
3132 #if 1
3133       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);
3134       for (p = 0; p < 6; ++p) {
3135         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);
3136       }
3137 #endif
3138       /* E hex */
3139       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  8; /* AE */
3140       orntNew[0] = -4;
3141       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], 0);
3142       orntNew[1] = ornt[1];
3143       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetQuadSubface_Static(ornt[2], 3);
3144       orntNew[2] = ornt[2];
3145       coneNew[3] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  7; /* EH */
3146       orntNew[3] = 0;
3147       coneNew[4] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  4; /* EF */
3148       orntNew[4] = -1;
3149       coneNew[5] = fStartNew + (cone[5] - fStart)*4 + GetQuadSubface_Static(ornt[5], 1);
3150       orntNew[5] = ornt[5];
3151       ierr       = DMPlexSetCone(rdm, newp+4, coneNew);CHKERRQ(ierr);
3152       ierr       = DMPlexSetConeOrientation(rdm, newp+4, orntNew);CHKERRQ(ierr);
3153 #if 1
3154       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);
3155       for (p = 0; p < 6; ++p) {
3156         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);
3157       }
3158 #endif
3159       /* F hex */
3160       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  9; /* DF */
3161       orntNew[0] = -4;
3162       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], 1);
3163       orntNew[1] = ornt[1];
3164       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetQuadSubface_Static(ornt[2], 2);
3165       orntNew[2] = ornt[2];
3166       coneNew[3] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  5; /* FG */
3167       orntNew[3] = -1;
3168       coneNew[4] = fStartNew + (cone[4] - fStart)*4 + GetQuadSubface_Static(ornt[4], 3);
3169       orntNew[4] = ornt[4];
3170       coneNew[5] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  4; /* EF */
3171       orntNew[5] = 1;
3172       ierr       = DMPlexSetCone(rdm, newp+5, coneNew);CHKERRQ(ierr);
3173       ierr       = DMPlexSetConeOrientation(rdm, newp+5, orntNew);CHKERRQ(ierr);
3174 #if 1
3175       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);
3176       for (p = 0; p < 6; ++p) {
3177         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);
3178       }
3179 #endif
3180       /* G hex */
3181       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 + 10; /* CG */
3182       orntNew[0] = -4;
3183       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], 2);
3184       orntNew[1] = ornt[1];
3185       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  5; /* FG */
3186       orntNew[2] = 0;
3187       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetQuadSubface_Static(ornt[3], 3);
3188       orntNew[3] = ornt[3];
3189       coneNew[4] = fStartNew + (cone[4] - fStart)*4 + GetQuadSubface_Static(ornt[4], 2);
3190       orntNew[4] = ornt[4];
3191       coneNew[5] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  6; /* GH */
3192       orntNew[5] = -3;
3193       ierr       = DMPlexSetCone(rdm, newp+6, coneNew);CHKERRQ(ierr);
3194       ierr       = DMPlexSetConeOrientation(rdm, newp+6, orntNew);CHKERRQ(ierr);
3195 #if 1
3196       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);
3197       for (p = 0; p < 6; ++p) {
3198         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);
3199       }
3200 #endif
3201       /* H hex */
3202       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 + 11; /* BH */
3203       orntNew[0] = -4;
3204       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], 3);
3205       orntNew[1] = ornt[1];
3206       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  7; /* EH */
3207       orntNew[2] = -1;
3208       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetQuadSubface_Static(ornt[3], 2);
3209       orntNew[3] = ornt[3];
3210       coneNew[4] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  6; /* GH */
3211       orntNew[4] = 3;
3212       coneNew[5] = fStartNew + (cone[5] - fStart)*4 + GetQuadSubface_Static(ornt[5], 2);
3213       orntNew[5] = ornt[5];
3214       ierr       = DMPlexSetCone(rdm, newp+7, coneNew);CHKERRQ(ierr);
3215       ierr       = DMPlexSetConeOrientation(rdm, newp+7, orntNew);CHKERRQ(ierr);
3216 #if 1
3217       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);
3218       for (p = 0; p < 6; ++p) {
3219         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);
3220       }
3221 #endif
3222     }
3223     /* Split faces have 4 edges and the same cells as the parent */
3224     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
3225     ierr = PetscMalloc1((4 + maxSupportSize*2), &supportRef);CHKERRQ(ierr);
3226     for (f = fStart; f < fEnd; ++f) {
3227       for (r = 0; r < 4; ++r) {
3228         /* TODO: This can come from GetFaces_Internal() */
3229         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};
3230         const PetscInt  newp = fStartNew + (f - fStart)*4 + r;
3231         const PetscInt *cone, *ornt, *support;
3232         PetscInt        coneNew[4], orntNew[4], coneSize, c, supportSize, s;
3233 
3234         ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
3235         ierr = DMPlexGetConeOrientation(dm, f, &ornt);CHKERRQ(ierr);
3236         coneNew[(r+3)%4] = eStartNew + (cone[(r+3)%4] - eStart)*2 + (ornt[(r+3)%4] < 0 ? 0 : 1);
3237         orntNew[(r+3)%4] = ornt[(r+3)%4];
3238         coneNew[(r+0)%4] = eStartNew + (cone[r]       - eStart)*2 + (ornt[r] < 0 ? 1 : 0);
3239         orntNew[(r+0)%4] = ornt[r];
3240         coneNew[(r+1)%4] = eStartNew + (eEnd - eStart)*2 + (f - fStart)*4 + r;
3241         orntNew[(r+1)%4] = 0;
3242         coneNew[(r+2)%4] = eStartNew + (eEnd - eStart)*2 + (f - fStart)*4 + (r+3)%4;
3243         orntNew[(r+2)%4] = -2;
3244         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3245         ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3246 #if 1
3247         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
3248         for (p = 0; p < 4; ++p) {
3249           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);
3250         }
3251 #endif
3252         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
3253         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
3254         for (s = 0; s < supportSize; ++s) {
3255           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
3256           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
3257           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
3258           for (c = 0; c < coneSize; ++c) {
3259             if (cone[c] == f) break;
3260           }
3261           supportRef[s] = cStartNew + (support[s] - cStart)*8 + newCells[c*4+GetQuadSubfaceInverse_Static(ornt[c], r)];
3262         }
3263         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
3264 #if 1
3265         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
3266         for (p = 0; p < supportSize; ++p) {
3267           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);
3268         }
3269 #endif
3270       }
3271     }
3272     /* Interior faces have 4 edges and 2 cells */
3273     for (c = cStart; c < cEnd; ++c) {
3274       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};
3275       const PetscInt *cone, *ornt;
3276       PetscInt        newp, coneNew[4], orntNew[4], supportNew[2];
3277 
3278       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
3279       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
3280       /* A-D face */
3281       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 0;
3282       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*4 + GetQuadEdge_Static(ornt[0], 3);
3283       orntNew[0] = 0;
3284       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 0;
3285       orntNew[1] = 0;
3286       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 2;
3287       orntNew[2] = -2;
3288       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*4 + GetQuadEdge_Static(ornt[2], 0);
3289       orntNew[3] = -2;
3290       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3291       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3292 #if 1
3293       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
3294       for (p = 0; p < 4; ++p) {
3295         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);
3296       }
3297 #endif
3298       /* C-D face */
3299       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 1;
3300       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*4 + GetQuadEdge_Static(ornt[0], 2);
3301       orntNew[0] = 0;
3302       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 0;
3303       orntNew[1] = 0;
3304       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 4;
3305       orntNew[2] = -2;
3306       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (cone[4] - fStart)*4 + GetQuadEdge_Static(ornt[4], 0);
3307       orntNew[3] = -2;
3308       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3309       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3310 #if 1
3311       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
3312       for (p = 0; p < 4; ++p) {
3313         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);
3314       }
3315 #endif
3316       /* B-C face */
3317       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 2;
3318       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*4 + GetQuadEdge_Static(ornt[0], 1);
3319       orntNew[0] = -2;
3320       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*4 + GetQuadEdge_Static(ornt[3], 0);
3321       orntNew[1] = 0;
3322       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 3;
3323       orntNew[2] = 0;
3324       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 0;
3325       orntNew[3] = -2;
3326       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3327       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3328 #if 1
3329       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
3330       for (p = 0; p < 4; ++p) {
3331         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);
3332       }
3333 #endif
3334       /* A-B face */
3335       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 3;
3336       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*4 + GetQuadEdge_Static(ornt[0], 0);
3337       orntNew[0] = -2;
3338       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[5] - fStart)*4 + GetQuadEdge_Static(ornt[5], 3);
3339       orntNew[1] = 0;
3340       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 5;
3341       orntNew[2] = 0;
3342       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 0;
3343       orntNew[3] = -2;
3344       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3345       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3346 #if 1
3347       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
3348       for (p = 0; p < 4; ++p) {
3349         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);
3350       }
3351 #endif
3352       /* E-F face */
3353       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 4;
3354       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 2;
3355       orntNew[0] = -2;
3356       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*4 + GetQuadEdge_Static(ornt[2], 2);
3357       orntNew[1] = -2;
3358       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*4 + GetQuadEdge_Static(ornt[1], 0);
3359       orntNew[2] = 0;
3360       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 1;
3361       orntNew[3] = 0;
3362       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3363       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3364 #if 1
3365       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
3366       for (p = 0; p < 4; ++p) {
3367         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);
3368       }
3369 #endif
3370       /* F-G face */
3371       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 5;
3372       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 4;
3373       orntNew[0] = -2;
3374       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[4] - fStart)*4 + GetQuadEdge_Static(ornt[4], 2);
3375       orntNew[1] = -2;
3376       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*4 + GetQuadEdge_Static(ornt[1], 1);
3377       orntNew[2] = 0;
3378       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 1;
3379       orntNew[3] = 0;
3380       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3381       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3382 #if 1
3383       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
3384       for (p = 0; p < 4; ++p) {
3385         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);
3386       }
3387 #endif
3388       /* G-H face */
3389       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 6;
3390       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*4 + GetQuadEdge_Static(ornt[3], 2);
3391       orntNew[0] = -2;
3392       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*4 + GetQuadEdge_Static(ornt[1], 2);
3393       orntNew[1] = 0;
3394       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 1;
3395       orntNew[2] = 0;
3396       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 3;
3397       orntNew[3] = -2;
3398       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3399       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3400 #if 1
3401       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
3402       for (p = 0; p < 4; ++p) {
3403         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);
3404       }
3405 #endif
3406       /* E-H face */
3407       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 7;
3408       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 5;
3409       orntNew[0] = -2;
3410       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[5] - fStart)*4 + GetQuadEdge_Static(ornt[5], 1);
3411       orntNew[1] = -2;
3412       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*4 + GetQuadEdge_Static(ornt[1], 3);
3413       orntNew[2] = 0;
3414       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 1;
3415       orntNew[3] = 0;
3416       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3417       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3418 #if 1
3419       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
3420       for (p = 0; p < 4; ++p) {
3421         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);
3422       }
3423 #endif
3424       /* A-E face */
3425       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 8;
3426       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*4 + GetQuadEdge_Static(ornt[2], 3);
3427       orntNew[0] = 0;
3428       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 2;
3429       orntNew[1] = 0;
3430       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 5;
3431       orntNew[2] = -2;
3432       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (cone[5] - fStart)*4 + GetQuadEdge_Static(ornt[5], 0);
3433       orntNew[3] = -2;
3434       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3435       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3436 #if 1
3437       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
3438       for (p = 0; p < 4; ++p) {
3439         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);
3440       }
3441 #endif
3442       /* D-F face */
3443       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 9;
3444       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*4 + GetQuadEdge_Static(ornt[2], 1);
3445       orntNew[0] = -2;
3446       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[4] - fStart)*4 + GetQuadEdge_Static(ornt[4], 3);
3447       orntNew[1] = 0;
3448       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 4;
3449       orntNew[2] = 0;
3450       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 2;
3451       orntNew[3] = -2;
3452       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3453       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3454 #if 1
3455       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
3456       for (p = 0; p < 4; ++p) {
3457         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);
3458       }
3459 #endif
3460       /* C-G face */
3461       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 10;
3462       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 4;
3463       orntNew[0] = -2;
3464       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[4] - fStart)*4 + GetQuadEdge_Static(ornt[4], 1);
3465       orntNew[1] = -2;
3466       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*4 + GetQuadEdge_Static(ornt[3], 3);
3467       orntNew[2] = 0;
3468       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 3;
3469       orntNew[3] = 0;
3470       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3471       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3472 #if 1
3473       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
3474       for (p = 0; p < 4; ++p) {
3475         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);
3476       }
3477 #endif
3478       /* B-H face */
3479       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 11;
3480       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 5;
3481       orntNew[0] = 0;
3482       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 3;
3483       orntNew[1] = -2;
3484       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*4 + GetQuadEdge_Static(ornt[3], 1);
3485       orntNew[2] = -2;
3486       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (cone[5] - fStart)*4 + GetQuadEdge_Static(ornt[5], 2);
3487       orntNew[3] = 0;
3488       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3489       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3490 #if 1
3491       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
3492       for (p = 0; p < 4; ++p) {
3493         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);
3494       }
3495 #endif
3496       for (r = 0; r < 12; ++r) {
3497         newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + r;
3498         supportNew[0] = cStartNew + (c - cStart)*8 + newCells[r*2+0];
3499         supportNew[1] = cStartNew + (c - cStart)*8 + newCells[r*2+1];
3500         ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3501 #if 1
3502         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
3503         for (p = 0; p < 2; ++p) {
3504           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);
3505         }
3506 #endif
3507       }
3508     }
3509     /* Split edges have 2 vertices and the same faces as the parent */
3510     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
3511     for (e = eStart; e < eEnd; ++e) {
3512       const PetscInt newv = vStartNew + (vEnd - vStart) + (e - eStart);
3513 
3514       for (r = 0; r < 2; ++r) {
3515         const PetscInt  newp = eStartNew + (e - eStart)*2 + r;
3516         const PetscInt *cone, *ornt, *support;
3517         PetscInt        coneNew[2], coneSize, c, supportSize, s;
3518 
3519         ierr             = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
3520         coneNew[0]       = vStartNew + (cone[0] - vStart);
3521         coneNew[1]       = vStartNew + (cone[1] - vStart);
3522         coneNew[(r+1)%2] = newv;
3523         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3524 #if 1
3525         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
3526         for (p = 0; p < 2; ++p) {
3527           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);
3528         }
3529 #endif
3530         ierr = DMPlexGetSupportSize(dm, e, &supportSize);CHKERRQ(ierr);
3531         ierr = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
3532         for (s = 0; s < supportSize; ++s) {
3533           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
3534           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
3535           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
3536           for (c = 0; c < coneSize; ++c) {
3537             if (cone[c] == e) break;
3538           }
3539           supportRef[s] = fStartNew + (support[s] - fStart)*4 + (ornt[c] < 0 ? (c+1-r)%4 : (c+r)%4);
3540         }
3541         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
3542 #if 1
3543         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
3544         for (p = 0; p < supportSize; ++p) {
3545           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);
3546         }
3547 #endif
3548       }
3549     }
3550     /* Face edges have 2 vertices and 2+cells faces */
3551     for (f = fStart; f < fEnd; ++f) {
3552       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};
3553       const PetscInt  newv = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (f - fStart);
3554       const PetscInt *cone, *coneCell, *orntCell, *support;
3555       PetscInt        coneNew[2], coneSize, c, supportSize, s;
3556 
3557       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
3558       for (r = 0; r < 4; ++r) {
3559         const PetscInt newp = eStartNew + (eEnd - eStart)*2 + (f - fStart)*4 + r;
3560 
3561         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r] - eStart);
3562         coneNew[1] = newv;
3563         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3564 #if 1
3565         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
3566         for (p = 0; p < 2; ++p) {
3567           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);
3568         }
3569 #endif
3570         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
3571         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
3572         supportRef[0] = fStartNew + (f - fStart)*4 + r;
3573         supportRef[1] = fStartNew + (f - fStart)*4 + (r+1)%4;
3574         for (s = 0; s < supportSize; ++s) {
3575           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
3576           ierr = DMPlexGetCone(dm, support[s], &coneCell);CHKERRQ(ierr);
3577           ierr = DMPlexGetConeOrientation(dm, support[s], &orntCell);CHKERRQ(ierr);
3578           for (c = 0; c < coneSize; ++c) if (coneCell[c] == f) break;
3579           supportRef[2+s] = fStartNew + (fEnd - fStart)*4 + (support[s] - cStart)*12 + newFaces[c*4 + GetQuadEdgeInverse_Static(orntCell[c], r)];
3580         }
3581         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
3582 #if 1
3583         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
3584         for (p = 0; p < 2+supportSize; ++p) {
3585           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);
3586         }
3587 #endif
3588       }
3589     }
3590     /* Cell edges have 2 vertices and 4 faces */
3591     for (c = cStart; c < cEnd; ++c) {
3592       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};
3593       const PetscInt  newv = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (fEnd - fStart) + (c - cStart);
3594       const PetscInt *cone;
3595       PetscInt        coneNew[2], supportNew[4];
3596 
3597       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
3598       for (r = 0; r < 6; ++r) {
3599         const PetscInt newp = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*4 + (c - cStart)*6 + r;
3600 
3601         coneNew[0] = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (cone[r] - fStart);
3602         coneNew[1] = newv;
3603         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3604 #if 1
3605         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
3606         for (p = 0; p < 2; ++p) {
3607           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);
3608         }
3609 #endif
3610         for (f = 0; f < 4; ++f) supportNew[f] = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + newFaces[r*4+f];
3611         ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3612 #if 1
3613         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
3614         for (p = 0; p < 4; ++p) {
3615           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);
3616         }
3617 #endif
3618       }
3619     }
3620     /* Old vertices have identical supports */
3621     for (v = vStart; v < vEnd; ++v) {
3622       const PetscInt  newp = vStartNew + (v - vStart);
3623       const PetscInt *support, *cone;
3624       PetscInt        size, s;
3625 
3626       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
3627       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
3628       for (s = 0; s < size; ++s) {
3629         PetscInt r = 0;
3630 
3631         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
3632         if (cone[1] == v) r = 1;
3633         supportRef[s] = eStartNew + (support[s] - eStart)*2 + r;
3634       }
3635       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
3636 #if 1
3637       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
3638       for (p = 0; p < size; ++p) {
3639         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);
3640       }
3641 #endif
3642     }
3643     /* Edge vertices have 2 + faces supports */
3644     for (e = eStart; e < eEnd; ++e) {
3645       const PetscInt  newp = vStartNew + (vEnd - vStart) + (e - eStart);
3646       const PetscInt *cone, *support;
3647       PetscInt        size, s;
3648 
3649       ierr          = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
3650       ierr          = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
3651       supportRef[0] = eStartNew + (e - eStart)*2 + 0;
3652       supportRef[1] = eStartNew + (e - eStart)*2 + 1;
3653       for (s = 0; s < size; ++s) {
3654         PetscInt r;
3655 
3656         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
3657         for (r = 0; r < 4; ++r) if (cone[r] == e) break;
3658         supportRef[2+s] = eStartNew + (eEnd - eStart)*2 + (support[s] - fStart)*4 + r;
3659       }
3660       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
3661 #if 1
3662       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
3663       for (p = 0; p < 2+size; ++p) {
3664         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);
3665       }
3666 #endif
3667     }
3668     /* Face vertices have 4 + cells supports */
3669     for (f = fStart; f < fEnd; ++f) {
3670       const PetscInt  newp = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (f - fStart);
3671       const PetscInt *cone, *support;
3672       PetscInt        size, s;
3673 
3674       ierr          = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
3675       ierr          = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
3676       for (r = 0; r < 4; ++r) supportRef[r] = eStartNew + (e - eStart)*2 +  (f - fStart)*4 + r;
3677       for (s = 0; s < size; ++s) {
3678         PetscInt r;
3679 
3680         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
3681         for (r = 0; r < 6; ++r) if (cone[r] == f) break;
3682         supportRef[4+s] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*4 + (support[s] - cStart)*6 + r;
3683       }
3684       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
3685 #if 1
3686       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
3687       for (p = 0; p < 4+size; ++p) {
3688         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);
3689       }
3690 #endif
3691     }
3692     /* Cell vertices have 6 supports */
3693     for (c = cStart; c < cEnd; ++c) {
3694       const PetscInt newp = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (fEnd - fStart) + (c - cStart);
3695       PetscInt       supportNew[6];
3696 
3697       for (r = 0; r < 6; ++r) {
3698         supportNew[r] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*4 + (c - cStart)*6 + r;
3699       }
3700       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3701     }
3702     ierr = PetscFree(supportRef);CHKERRQ(ierr);
3703     break;
3704   default:
3705     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
3706   }
3707   PetscFunctionReturn(0);
3708 }
3709 
3710 #undef __FUNCT__
3711 #define __FUNCT__ "CellRefinerSetCoordinates"
3712 static PetscErrorCode CellRefinerSetCoordinates(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
3713 {
3714   PetscSection   coordSection, coordSectionNew;
3715   Vec            coordinates, coordinatesNew;
3716   PetscScalar   *coords, *coordsNew;
3717   const PetscInt numVertices = depthSize ? depthSize[0] : 0;
3718   PetscInt       dim, depth, coordSizeNew, cStart, cEnd, c, vStart, vStartNew, vEnd, v, eStart, eEnd, eMax, e, fStart, fEnd, fMax, f;
3719   PetscErrorCode ierr;
3720 
3721   PetscFunctionBegin;
3722   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
3723   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3724   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
3725   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
3726   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
3727   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
3728   ierr = DMPlexGetHybridBounds(dm, NULL, &fMax, &eMax, NULL);CHKERRQ(ierr);
3729   if (refiner) {ierr = GetDepthStart_Private(depth, depthSize, NULL, NULL, NULL, &vStartNew);CHKERRQ(ierr);}
3730   ierr = GetDepthStart_Private(depth, depthSize, NULL, NULL, NULL, &vStartNew);CHKERRQ(ierr);
3731   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
3732   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)dm), &coordSectionNew);CHKERRQ(ierr);
3733   ierr = PetscSectionSetNumFields(coordSectionNew, 1);CHKERRQ(ierr);
3734   ierr = PetscSectionSetFieldComponents(coordSectionNew, 0, dim);CHKERRQ(ierr);
3735   ierr = PetscSectionSetChart(coordSectionNew, vStartNew, vStartNew+numVertices);CHKERRQ(ierr);
3736   if (fMax < 0) fMax = fEnd;
3737   if (eMax < 0) eMax = eEnd;
3738   /* All vertices have the dim coordinates */
3739   for (v = vStartNew; v < vStartNew+numVertices; ++v) {
3740     ierr = PetscSectionSetDof(coordSectionNew, v, dim);CHKERRQ(ierr);
3741     ierr = PetscSectionSetFieldDof(coordSectionNew, v, 0, dim);CHKERRQ(ierr);
3742   }
3743   ierr = PetscSectionSetUp(coordSectionNew);CHKERRQ(ierr);
3744   ierr = DMPlexSetCoordinateSection(rdm, coordSectionNew);CHKERRQ(ierr);
3745   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
3746   ierr = PetscSectionGetStorageSize(coordSectionNew, &coordSizeNew);CHKERRQ(ierr);
3747   ierr = VecCreate(PetscObjectComm((PetscObject)dm), &coordinatesNew);CHKERRQ(ierr);
3748   ierr = PetscObjectSetName((PetscObject) coordinatesNew, "coordinates");CHKERRQ(ierr);
3749   ierr = VecSetSizes(coordinatesNew, coordSizeNew, PETSC_DETERMINE);CHKERRQ(ierr);
3750   ierr = VecSetFromOptions(coordinatesNew);CHKERRQ(ierr);
3751   ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
3752   ierr = VecGetArray(coordinatesNew, &coordsNew);CHKERRQ(ierr);
3753   switch (refiner) {
3754   case 0: break;
3755   case 6: /* Hex 3D */
3756   case 8: /* Hybrid Hex 3D */
3757     /* Face vertices have the average of corner coordinates */
3758     for (f = fStart; f < fMax; ++f) {
3759       const PetscInt newv = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (f - fStart);
3760       PetscInt      *cone = NULL;
3761       PetscInt       closureSize, coneSize = 0, off[8], offnew, p, d;
3762 
3763       ierr = DMPlexGetTransitiveClosure(dm, f, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
3764       for (p = 0; p < closureSize*2; p += 2) {
3765         const PetscInt point = cone[p];
3766         if ((point >= vStart) && (point < vEnd)) cone[coneSize++] = point;
3767       }
3768       for (v = 0; v < coneSize; ++v) {
3769         ierr = PetscSectionGetOffset(coordSection, cone[v], &off[v]);CHKERRQ(ierr);
3770       }
3771       ierr = PetscSectionGetOffset(coordSectionNew, newv, &offnew);CHKERRQ(ierr);
3772       for (d = 0; d < dim; ++d) {
3773         coordsNew[offnew+d] = 0.0;
3774         for (v = 0; v < coneSize; ++v) coordsNew[offnew+d] += coords[off[v]+d];
3775         coordsNew[offnew+d] /= coneSize;
3776       }
3777       ierr = DMPlexRestoreTransitiveClosure(dm, f, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
3778     }
3779   case 2: /* Hex 2D */
3780     /* Cell vertices have the average of corner coordinates */
3781     for (c = cStart; c < cEnd; ++c) {
3782       const PetscInt newv = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (c - cStart) + (dim > 2 ? (fEnd - fStart) : 0);
3783       PetscInt      *cone = NULL;
3784       PetscInt       closureSize, coneSize = 0, off[8], offnew, p, d;
3785 
3786       ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
3787       for (p = 0; p < closureSize*2; p += 2) {
3788         const PetscInt point = cone[p];
3789         if ((point >= vStart) && (point < vEnd)) cone[coneSize++] = point;
3790       }
3791       for (v = 0; v < coneSize; ++v) {
3792         ierr = PetscSectionGetOffset(coordSection, cone[v], &off[v]);CHKERRQ(ierr);
3793       }
3794       ierr = PetscSectionGetOffset(coordSectionNew, newv, &offnew);CHKERRQ(ierr);
3795       for (d = 0; d < dim; ++d) {
3796         coordsNew[offnew+d] = 0.0;
3797         for (v = 0; v < coneSize; ++v) coordsNew[offnew+d] += coords[off[v]+d];
3798         coordsNew[offnew+d] /= coneSize;
3799       }
3800       ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
3801     }
3802   case 1: /* Simplicial 2D */
3803   case 3: /* Hybrid Simplicial 2D */
3804   case 5: /* Simplicial 3D */
3805   case 7: /* Hybrid Simplicial 3D */
3806     /* Edge vertices have the average of endpoint coordinates */
3807     for (e = eStart; e < eMax; ++e) {
3808       const PetscInt  newv = vStartNew + (vEnd - vStart) + (e - eStart);
3809       const PetscInt *cone;
3810       PetscInt        coneSize, offA, offB, offnew, d;
3811 
3812       ierr = DMPlexGetConeSize(dm, e, &coneSize);CHKERRQ(ierr);
3813       if (coneSize != 2) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Edge %d cone should have two vertices, not %d", e, coneSize);
3814       ierr = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
3815       ierr = PetscSectionGetOffset(coordSection, cone[0], &offA);CHKERRQ(ierr);
3816       ierr = PetscSectionGetOffset(coordSection, cone[1], &offB);CHKERRQ(ierr);
3817       ierr = PetscSectionGetOffset(coordSectionNew, newv, &offnew);CHKERRQ(ierr);
3818       for (d = 0; d < dim; ++d) {
3819         coordsNew[offnew+d] = 0.5*(coords[offA+d] + coords[offB+d]);
3820       }
3821     }
3822     /* Old vertices have the same coordinates */
3823     for (v = vStart; v < vEnd; ++v) {
3824       const PetscInt newv = vStartNew + (v - vStart);
3825       PetscInt       off, offnew, d;
3826 
3827       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
3828       ierr = PetscSectionGetOffset(coordSectionNew, newv, &offnew);CHKERRQ(ierr);
3829       for (d = 0; d < dim; ++d) {
3830         coordsNew[offnew+d] = coords[off+d];
3831       }
3832     }
3833     break;
3834   default:
3835     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
3836   }
3837   ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
3838   ierr = VecRestoreArray(coordinatesNew, &coordsNew);CHKERRQ(ierr);
3839   ierr = DMSetCoordinatesLocal(rdm, coordinatesNew);CHKERRQ(ierr);
3840   ierr = VecDestroy(&coordinatesNew);CHKERRQ(ierr);
3841   ierr = PetscSectionDestroy(&coordSectionNew);CHKERRQ(ierr);
3842   PetscFunctionReturn(0);
3843 }
3844 
3845 #undef __FUNCT__
3846 #define __FUNCT__ "DMPlexCreateProcessSF"
3847 static PetscErrorCode DMPlexCreateProcessSF(DM dm, PetscSF sfPoint, IS *processRanks, PetscSF *sfProcess)
3848 {
3849   PetscInt           numRoots, numLeaves, l;
3850   const PetscInt    *localPoints;
3851   const PetscSFNode *remotePoints;
3852   PetscInt          *localPointsNew;
3853   PetscSFNode       *remotePointsNew;
3854   PetscInt          *ranks, *ranksNew;
3855   PetscErrorCode     ierr;
3856 
3857   PetscFunctionBegin;
3858   ierr = PetscSFGetGraph(sfPoint, &numRoots, &numLeaves, &localPoints, &remotePoints);CHKERRQ(ierr);
3859   ierr = PetscMalloc1(numLeaves, &ranks);CHKERRQ(ierr);
3860   for (l = 0; l < numLeaves; ++l) {
3861     ranks[l] = remotePoints[l].rank;
3862   }
3863   ierr = PetscSortRemoveDupsInt(&numLeaves, ranks);CHKERRQ(ierr);
3864   ierr = PetscMalloc1(numLeaves,    &ranksNew);CHKERRQ(ierr);
3865   ierr = PetscMalloc1(numLeaves,    &localPointsNew);CHKERRQ(ierr);
3866   ierr = PetscMalloc1(numLeaves, &remotePointsNew);CHKERRQ(ierr);
3867   for (l = 0; l < numLeaves; ++l) {
3868     ranksNew[l]              = ranks[l];
3869     localPointsNew[l]        = l;
3870     remotePointsNew[l].index = 0;
3871     remotePointsNew[l].rank  = ranksNew[l];
3872   }
3873   ierr = PetscFree(ranks);CHKERRQ(ierr);
3874   ierr = ISCreateGeneral(PetscObjectComm((PetscObject)dm), numLeaves, ranksNew, PETSC_OWN_POINTER, processRanks);CHKERRQ(ierr);
3875   ierr = PetscSFCreate(PetscObjectComm((PetscObject)dm), sfProcess);CHKERRQ(ierr);
3876   ierr = PetscSFSetFromOptions(*sfProcess);CHKERRQ(ierr);
3877   ierr = PetscSFSetGraph(*sfProcess, 1, numLeaves, localPointsNew, PETSC_OWN_POINTER, remotePointsNew, PETSC_OWN_POINTER);CHKERRQ(ierr);
3878   PetscFunctionReturn(0);
3879 }
3880 
3881 #undef __FUNCT__
3882 #define __FUNCT__ "CellRefinerCreateSF"
3883 static PetscErrorCode CellRefinerCreateSF(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
3884 {
3885   PetscSF            sf, sfNew, sfProcess;
3886   IS                 processRanks;
3887   MPI_Datatype       depthType;
3888   PetscInt           numRoots, numLeaves, numLeavesNew = 0, l, m;
3889   const PetscInt    *localPoints, *neighbors;
3890   const PetscSFNode *remotePoints;
3891   PetscInt          *localPointsNew;
3892   PetscSFNode       *remotePointsNew;
3893   PetscInt          *depthSizeOld, *rdepthSize, *rdepthSizeOld, *rdepthMaxOld, *rvStart, *rvStartNew, *reStart, *reStartNew, *rfStart, *rfStartNew, *rcStart, *rcStartNew;
3894   PetscInt           depth, numNeighbors, pStartNew, pEndNew, cStart, cEnd, cMax, vStart, vEnd, vMax, fStart, fEnd, fMax, eStart, eEnd, eMax, r, n;
3895   PetscInt           cStartNew = 0, vStartNew = 0, fStartNew = 0, eStartNew = 0;
3896   PetscErrorCode     ierr;
3897 
3898   PetscFunctionBegin;
3899   ierr = DMPlexGetChart(rdm, &pStartNew, &pEndNew);CHKERRQ(ierr);
3900   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3901   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
3902   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
3903   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
3904   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
3905   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
3906   if (refiner) {ierr = GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);CHKERRQ(ierr);}
3907   ierr = DMGetPointSF(dm, &sf);CHKERRQ(ierr);
3908   ierr = DMGetPointSF(rdm, &sfNew);CHKERRQ(ierr);
3909   /* Caculate size of new SF */
3910   ierr = PetscSFGetGraph(sf, &numRoots, &numLeaves, &localPoints, &remotePoints);CHKERRQ(ierr);
3911   if (numRoots < 0) PetscFunctionReturn(0);
3912   for (l = 0; l < numLeaves; ++l) {
3913     const PetscInt p = localPoints[l];
3914 
3915     switch (refiner) {
3916     case 1:
3917       /* Simplicial 2D */
3918       if ((p >= vStart) && (p < vEnd)) {
3919         /* Old vertices stay the same */
3920         ++numLeavesNew;
3921       } else if ((p >= fStart) && (p < fEnd)) {
3922         /* Old faces add new faces and vertex */
3923         numLeavesNew += 2 + 1;
3924       } else if ((p >= cStart) && (p < cEnd)) {
3925         /* Old cells add new cells and interior faces */
3926         numLeavesNew += 4 + 3;
3927       }
3928       break;
3929     case 2:
3930       /* Hex 2D */
3931       if ((p >= vStart) && (p < vEnd)) {
3932         /* Old vertices stay the same */
3933         ++numLeavesNew;
3934       } else if ((p >= fStart) && (p < fEnd)) {
3935         /* Old faces add new faces and vertex */
3936         numLeavesNew += 2 + 1;
3937       } else if ((p >= cStart) && (p < cEnd)) {
3938         /* Old cells add new cells, interior faces, and vertex */
3939         numLeavesNew += 4 + 4 + 1;
3940       }
3941       break;
3942     case 5:
3943       /* Simplicial 3D */
3944       if ((p >= vStart) && (p < vEnd)) {
3945         /* Old vertices stay the same */
3946         ++numLeavesNew;
3947       } else if ((p >= eStart) && (p < eEnd)) {
3948         /* Old edges add new edges and vertex */
3949         numLeavesNew += 2 + 1;
3950       } else if ((p >= fStart) && (p < fEnd)) {
3951         /* Old faces add new faces and face edges */
3952         numLeavesNew += 4 + 3;
3953       } else if ((p >= cStart) && (p < cEnd)) {
3954         /* Old cells add new cells and interior faces and edges */
3955         numLeavesNew += 8 + 8 + 1;
3956       }
3957       break;
3958     case 7:
3959       /* Hybrid Simplicial 3D */
3960       if ((p >= vStart) && (p < vEnd)) {
3961         /* Interior vertices stay the same */
3962         ++numLeavesNew;
3963       } else if ((p >= eStart) && (p < eMax)) {
3964         /* Interior edges add new edges and vertex */
3965         numLeavesNew += 2 + 1;
3966       } else if ((p >= eMax) && (p < eEnd)) {
3967         /* Hybrid edges stay the same */
3968         ++numLeavesNew;
3969       } else if ((p >= fStart) && (p < fMax)) {
3970         /* Interior faces add new faces and edges */
3971         numLeavesNew += 4 + 3;
3972       } else if ((p >= fMax) && (p < fEnd)) {
3973         /* Hybrid faces add new faces and edges */
3974         numLeavesNew += 2 + 1;
3975       } else if ((p >= cStart) && (p < cMax)) {
3976         /* Interior cells add new cells, faces, and edges */
3977         numLeavesNew += 8 + 8 + 1;
3978       } else if ((p >= cMax) && (p < cEnd)) {
3979         /* Hybrid cells add new cells and faces */
3980         numLeavesNew += 4 + 3;
3981       }
3982       break;
3983     case 6:
3984       /* Hex 3D */
3985       if ((p >= vStart) && (p < vEnd)) {
3986         /* Old vertices stay the same */
3987         ++numLeavesNew;
3988       } else if ((p >= eStart) && (p < eEnd)) {
3989         /* Old edges add new edges, and vertex */
3990         numLeavesNew += 2 + 1;
3991       } else if ((p >= fStart) && (p < fEnd)) {
3992         /* Old faces add new faces, edges, and vertex */
3993         numLeavesNew += 4 + 4 + 1;
3994       } else if ((p >= cStart) && (p < cEnd)) {
3995         /* Old cells add new cells, faces, edges, and vertex */
3996         numLeavesNew += 8 + 12 + 6 + 1;
3997       }
3998       break;
3999     default:
4000       SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
4001     }
4002   }
4003   /* Communicate depthSizes for each remote rank */
4004   ierr = DMPlexCreateProcessSF(dm, sf, &processRanks, &sfProcess);CHKERRQ(ierr);
4005   ierr = ISGetLocalSize(processRanks, &numNeighbors);CHKERRQ(ierr);
4006   ierr = PetscMalloc5((depth+1)*numNeighbors,&rdepthSize,numNeighbors,&rvStartNew,numNeighbors,&reStartNew,numNeighbors,&rfStartNew,numNeighbors,&rcStartNew);CHKERRQ(ierr);
4007   ierr = PetscMalloc7(depth+1,&depthSizeOld,(depth+1)*numNeighbors,&rdepthSizeOld,(depth+1)*numNeighbors,&rdepthMaxOld,numNeighbors,&rvStart,numNeighbors,&reStart,numNeighbors,&rfStart,numNeighbors,&rcStart);CHKERRQ(ierr);
4008   ierr = MPI_Type_contiguous(depth+1, MPIU_INT, &depthType);CHKERRQ(ierr);
4009   ierr = MPI_Type_commit(&depthType);CHKERRQ(ierr);
4010   ierr = PetscSFBcastBegin(sfProcess, depthType, depthSize, rdepthSize);CHKERRQ(ierr);
4011   ierr = PetscSFBcastEnd(sfProcess, depthType, depthSize, rdepthSize);CHKERRQ(ierr);
4012   for (n = 0; n < numNeighbors; ++n) {
4013     ierr = GetDepthStart_Private(depth, &rdepthSize[n*(depth+1)], &rcStartNew[n], &rfStartNew[n], &reStartNew[n], &rvStartNew[n]);CHKERRQ(ierr);
4014   }
4015   depthSizeOld[depth]   = cMax;
4016   depthSizeOld[0]       = vMax;
4017   depthSizeOld[depth-1] = fMax;
4018   depthSizeOld[1]       = eMax;
4019 
4020   ierr = PetscSFBcastBegin(sfProcess, depthType, depthSizeOld, rdepthMaxOld);CHKERRQ(ierr);
4021   ierr = PetscSFBcastEnd(sfProcess, depthType, depthSizeOld, rdepthMaxOld);CHKERRQ(ierr);
4022 
4023   depthSizeOld[depth]   = cEnd - cStart;
4024   depthSizeOld[0]       = vEnd - vStart;
4025   depthSizeOld[depth-1] = fEnd - fStart;
4026   depthSizeOld[1]       = eEnd - eStart;
4027 
4028   ierr = PetscSFBcastBegin(sfProcess, depthType, depthSizeOld, rdepthSizeOld);CHKERRQ(ierr);
4029   ierr = PetscSFBcastEnd(sfProcess, depthType, depthSizeOld, rdepthSizeOld);CHKERRQ(ierr);
4030   for (n = 0; n < numNeighbors; ++n) {
4031     ierr = GetDepthStart_Private(depth, &rdepthSizeOld[n*(depth+1)], &rcStart[n], &rfStart[n], &reStart[n], &rvStart[n]);CHKERRQ(ierr);
4032   }
4033   ierr = MPI_Type_free(&depthType);CHKERRQ(ierr);
4034   ierr = PetscSFDestroy(&sfProcess);CHKERRQ(ierr);
4035   /* Calculate new point SF */
4036   ierr = PetscMalloc1(numLeavesNew,    &localPointsNew);CHKERRQ(ierr);
4037   ierr = PetscMalloc1(numLeavesNew, &remotePointsNew);CHKERRQ(ierr);
4038   ierr = ISGetIndices(processRanks, &neighbors);CHKERRQ(ierr);
4039   for (l = 0, m = 0; l < numLeaves; ++l) {
4040     PetscInt    p     = localPoints[l];
4041     PetscInt    rp    = remotePoints[l].index, n;
4042     PetscMPIInt rrank = remotePoints[l].rank;
4043 
4044     ierr = PetscFindInt(rrank, numNeighbors, neighbors, &n);CHKERRQ(ierr);
4045     if (n < 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Could not locate remote rank %d", rrank);
4046     switch (refiner) {
4047     case 1:
4048       /* Simplicial 2D */
4049       if ((p >= vStart) && (p < vEnd)) {
4050         /* Old vertices stay the same */
4051         localPointsNew[m]        = vStartNew     + (p  - vStart);
4052         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
4053         remotePointsNew[m].rank  = rrank;
4054         ++m;
4055       } else if ((p >= fStart) && (p < fEnd)) {
4056         /* Old faces add new faces and vertex */
4057         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - fStart);
4058         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - rfStart[n]);
4059         remotePointsNew[m].rank  = rrank;
4060         ++m;
4061         for (r = 0; r < 2; ++r, ++m) {
4062           localPointsNew[m]        = fStartNew     + (p  - fStart)*2     + r;
4063           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*2 + r;
4064           remotePointsNew[m].rank  = rrank;
4065         }
4066       } else if ((p >= cStart) && (p < cEnd)) {
4067         /* Old cells add new cells and interior faces */
4068         for (r = 0; r < 4; ++r, ++m) {
4069           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
4070           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
4071           remotePointsNew[m].rank  = rrank;
4072         }
4073         for (r = 0; r < 3; ++r, ++m) {
4074           localPointsNew[m]        = fStartNew     + (fEnd - fStart)*2                    + (p  - cStart)*3     + r;
4075           remotePointsNew[m].index = rfStartNew[n] + rdepthSizeOld[n*(depth+1)+depth-1]*2 + (rp - rcStart[n])*3 + r;
4076           remotePointsNew[m].rank  = rrank;
4077         }
4078       }
4079       break;
4080     case 2:
4081       /* Hex 2D */
4082       if ((p >= vStart) && (p < vEnd)) {
4083         /* Old vertices stay the same */
4084         localPointsNew[m]        = vStartNew     + (p  - vStart);
4085         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
4086         remotePointsNew[m].rank  = rrank;
4087         ++m;
4088       } else if ((p >= fStart) && (p < fEnd)) {
4089         /* Old faces add new faces and vertex */
4090         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - fStart);
4091         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - rfStart[n]);
4092         remotePointsNew[m].rank  = rrank;
4093         ++m;
4094         for (r = 0; r < 2; ++r, ++m) {
4095           localPointsNew[m]        = fStartNew     + (p  - fStart)*2     + r;
4096           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*2 + r;
4097           remotePointsNew[m].rank  = rrank;
4098         }
4099       } else if ((p >= cStart) && (p < cEnd)) {
4100         /* Old cells add new cells, interior faces, and vertex */
4101         for (r = 0; r < 4; ++r, ++m) {
4102           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
4103           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
4104           remotePointsNew[m].rank  = rrank;
4105         }
4106         for (r = 0; r < 4; ++r, ++m) {
4107           localPointsNew[m]        = fStartNew     + (fEnd - fStart)*2                    + (p  - cStart)*4     + r;
4108           remotePointsNew[m].index = rfStartNew[n] + rdepthSizeOld[n*(depth+1)+depth-1]*2 + (rp - rcStart[n])*4 + r;
4109           remotePointsNew[m].rank  = rrank;
4110         }
4111         for (r = 0; r < 1; ++r, ++m) {
4112           localPointsNew[m]        = vStartNew     + (fEnd - fStart)                    + (p  - cStart)     + r;
4113           remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+depth-1] + (rp - rcStart[n]) + r;
4114           remotePointsNew[m].rank  = rrank;
4115         }
4116       }
4117       break;
4118     case 3:
4119       /* Hybrid simplicial 2D */
4120       if ((p >= vStart) && (p < vEnd)) {
4121         /* Old vertices stay the same */
4122         localPointsNew[m]        = vStartNew     + (p  - vStart);
4123         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
4124         remotePointsNew[m].rank  = rrank;
4125         ++m;
4126       } else if ((p >= fStart) && (p < fMax)) {
4127         /* Old interior faces add new faces and vertex */
4128         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - fStart);
4129         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - rfStart[n]);
4130         remotePointsNew[m].rank  = rrank;
4131         ++m;
4132         for (r = 0; r < 2; ++r, ++m) {
4133           localPointsNew[m]        = fStartNew     + (p  - fStart)*2     + r;
4134           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*2 + r;
4135           remotePointsNew[m].rank  = rrank;
4136         }
4137       } else if ((p >= fMax) && (p < fEnd)) {
4138         /* Old hybrid faces stay the same */
4139         localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (p  - fMax);
4140         remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*2 + (rp - rdepthMaxOld[n*(depth+1)+depth-1]);
4141         remotePointsNew[m].rank  = rrank;
4142         ++m;
4143       } else if ((p >= cStart) && (p < cMax)) {
4144         /* Old interior cells add new cells and interior faces */
4145         for (r = 0; r < 4; ++r, ++m) {
4146           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
4147           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
4148           remotePointsNew[m].rank  = rrank;
4149         }
4150         for (r = 0; r < 3; ++r, ++m) {
4151           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (p  - cStart)*3     + r;
4152           remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*2 + (rp - rcStart[n])*3 + r;
4153           remotePointsNew[m].rank  = rrank;
4154         }
4155       } else if ((p >= cStart) && (p < cMax)) {
4156         /* Old hybrid cells add new cells and hybrid face */
4157         for (r = 0; r < 2; ++r, ++m) {
4158           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
4159           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
4160           remotePointsNew[m].rank  = rrank;
4161         }
4162         localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (cMax                            - cStart)*3     + (p  - cMax);
4163         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]);
4164         remotePointsNew[m].rank  = rrank;
4165         ++m;
4166       }
4167       break;
4168     case 5:
4169       /* Simplicial 3D */
4170       if ((p >= vStart) && (p < vEnd)) {
4171         /* Old vertices stay the same */
4172         localPointsNew[m]        = vStartNew     + (p  - vStart);
4173         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
4174         remotePointsNew[m].rank  = rrank;
4175         ++m;
4176       } else if ((p >= eStart) && (p < eEnd)) {
4177         /* Old edges add new edges and vertex */
4178         for (r = 0; r < 2; ++r, ++m) {
4179           localPointsNew[m]        = eStartNew     + (p  - eStart)*2     + r;
4180           remotePointsNew[m].index = reStartNew[n] + (rp - reStart[n])*2 + r;
4181           remotePointsNew[m].rank  = rrank;
4182         }
4183         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - eStart);
4184         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - reStart[n]);
4185         remotePointsNew[m].rank  = rrank;
4186         ++m;
4187       } else if ((p >= fStart) && (p < fEnd)) {
4188         /* Old faces add new faces and face edges */
4189         for (r = 0; r < 4; ++r, ++m) {
4190           localPointsNew[m]        = fStartNew     + (p  - fStart)*4     + r;
4191           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*4 + r;
4192           remotePointsNew[m].rank  = rrank;
4193         }
4194         for (r = 0; r < 3; ++r, ++m) {
4195           localPointsNew[m]        = eStartNew     + (eEnd - eStart)*2              + (p  - fStart)*3     + r;
4196           remotePointsNew[m].index = reStartNew[n] + rdepthSizeOld[n*(depth+1)+1]*2 + (rp - rfStart[n])*3 + r;
4197           remotePointsNew[m].rank  = rrank;
4198         }
4199       } else if ((p >= cStart) && (p < cEnd)) {
4200         /* Old cells add new cells and interior faces and edges */
4201         for (r = 0; r < 8; ++r, ++m) {
4202           localPointsNew[m]        = cStartNew     + (p  - cStart)*8     + r;
4203           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*8 + r;
4204           remotePointsNew[m].rank  = rrank;
4205         }
4206         for (r = 0; r < 8; ++r, ++m) {
4207           localPointsNew[m]        = fStartNew     + (fEnd - fStart)*4                    + (p  - cStart)*8     + r;
4208           remotePointsNew[m].index = rfStartNew[n] + rdepthSizeOld[n*(depth+1)+depth-1]*4 + (rp - rcStart[n])*8 + r;
4209           remotePointsNew[m].rank  = rrank;
4210         }
4211         for (r = 0; r < 1; ++r, ++m) {
4212           localPointsNew[m]        = eStartNew     + (eEnd - eStart)*2              + (fEnd - fStart)*3                    + (p  - cStart)*1     + r;
4213           remotePointsNew[m].index = reStartNew[n] + rdepthSizeOld[n*(depth+1)+1]*2 + rdepthSizeOld[n*(depth+1)+depth-1]*3 + (rp - rcStart[n])*1 + r;
4214           remotePointsNew[m].rank  = rrank;
4215         }
4216       }
4217       break;
4218     case 7:
4219       /* Hybrid Simplicial 3D */
4220       if ((p >= vStart) && (p < vEnd)) {
4221         /* Interior vertices stay the same */
4222         localPointsNew[m]        = vStartNew     + (p  - vStart);
4223         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
4224         remotePointsNew[m].rank  = rrank;
4225         ++m;
4226       } else if ((p >= eStart) && (p < eMax)) {
4227         /* Interior edges add new edges and vertex */
4228         for (r = 0; r < 2; ++r, ++m) {
4229           localPointsNew[m]        = eStartNew     + (p  - eStart)*2     + r;
4230           remotePointsNew[m].index = reStartNew[n] + (rp - reStart[n])*2 + r;
4231           remotePointsNew[m].rank  = rrank;
4232         }
4233         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - eStart);
4234         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - reStart[n]);
4235         remotePointsNew[m].rank  = rrank;
4236         ++m;
4237       } else if ((p >= eMax) && (p < eEnd)) {
4238         /* Hybrid edges stay the same */
4239         localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (fMax                              - fStart)*3     + (cMax                            - cStart)     + (p  - eMax);
4240         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]);
4241         remotePointsNew[m].rank  = rrank;
4242         ++m;
4243       } else if ((p >= fStart) && (p < fMax)) {
4244         /* Interior faces add new faces and edges */
4245         for (r = 0; r < 4; ++r, ++m) {
4246           localPointsNew[m]        = fStartNew     + (p  - fStart)*4     + r;
4247           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*4 + r;
4248           remotePointsNew[m].rank  = rrank;
4249         }
4250         for (r = 0; r < 3; ++r, ++m) {
4251           localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (p  - fStart)*3     + r;
4252           remotePointsNew[m].index = reStartNew[n] + (rdepthMaxOld[n*(depth+1)+1] - reStart[n])*2 + (rp - rfStart[n])*3 + r;
4253           remotePointsNew[m].rank  = rrank;
4254         }
4255       } else if ((p >= fMax) && (p < fEnd)) {
4256         /* Hybrid faces add new faces and edges */
4257         for (r = 0; r < 2; ++r, ++m) {
4258           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*4     + (cMax                            - cStart)*8     + (p  - fStart)*2     + r;
4259           remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*4 + (rdepthMaxOld[n*(depth+1)+depth] - rcStart[n])*8 + (rp - rfStart[n])*2 + r;
4260           remotePointsNew[m].rank  = rrank;
4261         }
4262         localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (fMax                              - fStart)     + (cMax                            - cStart)     + (fEnd                                          - fMax);
4263         remotePointsNew[m].index = reStartNew[n] + (rdepthMaxOld[n*(depth+1)+1] - reStart[n])*2 + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n]) + (rdepthMaxOld[n*(depth+1)+depth] - rcStart[n]) + (rdepthSizeOld[n*(depth+1)+depth-1]+rfStart[n] - rdepthMaxOld[n*(depth+1)+depth-1]);
4264         remotePointsNew[m].rank  = rrank;
4265         ++m;
4266       } else if ((p >= cStart) && (p < cMax)) {
4267         /* Interior cells add new cells, faces, and edges */
4268         for (r = 0; r < 8; ++r, ++m) {
4269           localPointsNew[m]        = cStartNew     + (p  - cStart)*8     + r;
4270           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*8 + r;
4271           remotePointsNew[m].rank  = rrank;
4272         }
4273         for (r = 0; r < 8; ++r, ++m) {
4274           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*4     + (p  - cStart)*8     + r;
4275           remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*4 + (rp - rcStart[n])*8 + r;
4276           remotePointsNew[m].rank  = rrank;
4277         }
4278         localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (fMax                              - fStart)*3     + (p  - cStart)*1     + r;
4279         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;
4280         remotePointsNew[m].rank  = rrank;
4281         ++m;
4282       } else if ((p >= cMax) && (p < cEnd)) {
4283         /* Hybrid cells add new cells and faces */
4284         for (r = 0; r < 4; ++r, ++m) {
4285           localPointsNew[m]        = cStartNew     + (cMax                            - cStart)*8     + (p  - cMax)*4                            + r;
4286           remotePointsNew[m].index = rcStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth] - rcStart[n])*8 + (rp - rdepthMaxOld[n*(depth+1)+depth])*4 + r;
4287           remotePointsNew[m].rank  = rrank;
4288         }
4289         for (r = 0; r < 3; ++r, ++m) {
4290           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*4     + (cMax                            - cStart)*8     + (fEnd                                          - fMax)*4                              + (p  - cMax)*3                            + r;
4291           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])*4 + (rp - rdepthMaxOld[n*(depth+1)+depth])*3 + r;
4292           remotePointsNew[m].rank  = rrank;
4293         }
4294       }
4295       break;
4296     case 6:
4297       /* Hex 3D */
4298       if ((p >= vStart) && (p < vEnd)) {
4299         /* Old vertices stay the same */
4300         localPointsNew[m]        = vStartNew     + (p  - vStart);
4301         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
4302         remotePointsNew[m].rank  = rrank;
4303         ++m;
4304       } else if ((p >= eStart) && (p < eEnd)) {
4305         /* Old edges add new edges and vertex */
4306         for (r = 0; r < 2; ++r, ++m) {
4307           localPointsNew[m]        = eStartNew     + (p  - eStart)*2     + r;
4308           remotePointsNew[m].index = reStartNew[n] + (rp - reStart[n])*2 + r;
4309           remotePointsNew[m].rank  = rrank;
4310         }
4311         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - eStart);
4312         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - reStart[n]);
4313         remotePointsNew[m].rank  = rrank;
4314         ++m;
4315       } else if ((p >= fStart) && (p < fEnd)) {
4316         /* Old faces add new faces, edges, and vertex */
4317         for (r = 0; r < 4; ++r, ++m) {
4318           localPointsNew[m]        = fStartNew     + (p  - fStart)*4     + r;
4319           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*4 + r;
4320           remotePointsNew[m].rank  = rrank;
4321         }
4322         for (r = 0; r < 4; ++r, ++m) {
4323           localPointsNew[m]        = eStartNew     + (eEnd - eStart)*2              + (p  - fStart)*4     + r;
4324           remotePointsNew[m].index = reStartNew[n] + rdepthSizeOld[n*(depth+1)+1]*2 + (rp - rfStart[n])*4 + r;
4325           remotePointsNew[m].rank  = rrank;
4326         }
4327         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (eEnd - eStart)              + (p  - fStart);
4328         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + rdepthSizeOld[n*(depth+1)+1] + (rp - rfStart[n]);
4329         remotePointsNew[m].rank  = rrank;
4330         ++m;
4331       } else if ((p >= cStart) && (p < cEnd)) {
4332         /* Old cells add new cells, faces, edges, and vertex */
4333         for (r = 0; r < 8; ++r, ++m) {
4334           localPointsNew[m]        = cStartNew     + (p  - cStart)*8     + r;
4335           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*8 + r;
4336           remotePointsNew[m].rank  = rrank;
4337         }
4338         for (r = 0; r < 12; ++r, ++m) {
4339           localPointsNew[m]        = fStartNew     + (fEnd - fStart)*4                    + (p  - cStart)*12     + r;
4340           remotePointsNew[m].index = rfStartNew[n] + rdepthSizeOld[n*(depth+1)+depth-1]*4 + (rp - rcStart[n])*12 + r;
4341           remotePointsNew[m].rank  = rrank;
4342         }
4343         for (r = 0; r < 6; ++r, ++m) {
4344           localPointsNew[m]        = eStartNew     + (eEnd - eStart)*2              + (fEnd - fStart)*4                    + (p  - cStart)*6     + r;
4345           remotePointsNew[m].index = reStartNew[n] + rdepthSizeOld[n*(depth+1)+1]*2 + rdepthSizeOld[n*(depth+1)+depth-1]*4 + (rp - rcStart[n])*6 + r;
4346           remotePointsNew[m].rank  = rrank;
4347         }
4348         for (r = 0; r < 1; ++r, ++m) {
4349           localPointsNew[m]        = vStartNew     + (eEnd - eStart)              + (fEnd - fStart)                    + (p  - cStart)     + r;
4350           remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+1] + rdepthSizeOld[n*(depth+1)+depth-1] + (rp - rcStart[n]) + r;
4351           remotePointsNew[m].rank  = rrank;
4352         }
4353       }
4354       break;
4355     default:
4356       SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
4357     }
4358   }
4359   if (m != numLeavesNew) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Number of leaf point %d should be %d", m, numLeavesNew);
4360   ierr = ISRestoreIndices(processRanks, &neighbors);CHKERRQ(ierr);
4361   ierr = ISDestroy(&processRanks);CHKERRQ(ierr);
4362   ierr = PetscSFSetGraph(sfNew, pEndNew-pStartNew, numLeavesNew, localPointsNew, PETSC_OWN_POINTER, remotePointsNew, PETSC_OWN_POINTER);CHKERRQ(ierr);
4363   ierr = PetscFree5(rdepthSize,rvStartNew,reStartNew,rfStartNew,rcStartNew);CHKERRQ(ierr);
4364   ierr = PetscFree7(depthSizeOld,rdepthSizeOld,rdepthMaxOld,rvStart,reStart,rfStart,rcStart);CHKERRQ(ierr);
4365   PetscFunctionReturn(0);
4366 }
4367 
4368 #undef __FUNCT__
4369 #define __FUNCT__ "CellRefinerCreateLabels"
4370 static PetscErrorCode CellRefinerCreateLabels(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
4371 {
4372   PetscInt       numLabels, l;
4373   PetscInt       depth, newp, cStart, cEnd, cMax, vStart, vEnd, vMax, fStart, fEnd, fMax, eStart, eEnd, eMax, r;
4374   PetscInt       cStartNew = 0, vStartNew = 0, fStartNew = 0, eStartNew = 0;
4375   PetscErrorCode ierr;
4376 
4377   PetscFunctionBegin;
4378   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
4379   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
4380   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
4381   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
4382   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
4383   if (refiner) {ierr = GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);CHKERRQ(ierr);}
4384   ierr = DMPlexGetNumLabels(dm, &numLabels);CHKERRQ(ierr);
4385   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
4386   switch (refiner) {
4387   case 0: break;
4388   case 7:
4389   case 8:
4390     if (eMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No edge maximum specified in hybrid mesh");
4391   case 3:
4392   case 4:
4393     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
4394     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
4395   }
4396   for (l = 0; l < numLabels; ++l) {
4397     DMLabel         label, labelNew;
4398     const char     *lname;
4399     PetscBool       isDepth;
4400     IS              valueIS;
4401     const PetscInt *values;
4402     PetscInt        numValues, val;
4403 
4404     ierr = DMPlexGetLabelName(dm, l, &lname);CHKERRQ(ierr);
4405     ierr = PetscStrcmp(lname, "depth", &isDepth);CHKERRQ(ierr);
4406     if (isDepth) continue;
4407     ierr = DMPlexCreateLabel(rdm, lname);CHKERRQ(ierr);
4408     ierr = DMPlexGetLabel(dm, lname, &label);CHKERRQ(ierr);
4409     ierr = DMPlexGetLabel(rdm, lname, &labelNew);CHKERRQ(ierr);
4410     ierr = DMLabelGetValueIS(label, &valueIS);CHKERRQ(ierr);
4411     ierr = ISGetLocalSize(valueIS, &numValues);CHKERRQ(ierr);
4412     ierr = ISGetIndices(valueIS, &values);CHKERRQ(ierr);
4413     for (val = 0; val < numValues; ++val) {
4414       IS              pointIS;
4415       const PetscInt *points;
4416       PetscInt        numPoints, n;
4417 
4418       ierr = DMLabelGetStratumIS(label, values[val], &pointIS);CHKERRQ(ierr);
4419       ierr = ISGetLocalSize(pointIS, &numPoints);CHKERRQ(ierr);
4420       ierr = ISGetIndices(pointIS, &points);CHKERRQ(ierr);
4421       for (n = 0; n < numPoints; ++n) {
4422         const PetscInt p = points[n];
4423         switch (refiner) {
4424         case 1:
4425           /* Simplicial 2D */
4426           if ((p >= vStart) && (p < vEnd)) {
4427             /* Old vertices stay the same */
4428             newp = vStartNew + (p - vStart);
4429             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4430           } else if ((p >= fStart) && (p < fEnd)) {
4431             /* Old faces add new faces and vertex */
4432             newp = vStartNew + (vEnd - vStart) + (p - fStart);
4433             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4434             for (r = 0; r < 2; ++r) {
4435               newp = fStartNew + (p - fStart)*2 + r;
4436               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4437             }
4438           } else if ((p >= cStart) && (p < cEnd)) {
4439             /* Old cells add new cells and interior faces */
4440             for (r = 0; r < 4; ++r) {
4441               newp = cStartNew + (p - cStart)*4 + r;
4442               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4443             }
4444             for (r = 0; r < 3; ++r) {
4445               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*3 + r;
4446               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4447             }
4448           }
4449           break;
4450         case 2:
4451           /* Hex 2D */
4452           if ((p >= vStart) && (p < vEnd)) {
4453             /* Old vertices stay the same */
4454             newp = vStartNew + (p - vStart);
4455             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4456           } else if ((p >= fStart) && (p < fEnd)) {
4457             /* Old faces add new faces and vertex */
4458             newp = vStartNew + (vEnd - vStart) + (p - fStart);
4459             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4460             for (r = 0; r < 2; ++r) {
4461               newp = fStartNew + (p - fStart)*2 + r;
4462               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4463             }
4464           } else if ((p >= cStart) && (p < cEnd)) {
4465             /* Old cells add new cells and interior faces and vertex */
4466             for (r = 0; r < 4; ++r) {
4467               newp = cStartNew + (p - cStart)*4 + r;
4468               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4469             }
4470             for (r = 0; r < 4; ++r) {
4471               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*4 + r;
4472               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4473             }
4474             newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (p - cStart);
4475             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4476           }
4477           break;
4478         case 3:
4479           /* Hybrid simplicial 2D */
4480           if ((p >= vStart) && (p < vEnd)) {
4481             /* Old vertices stay the same */
4482             newp = vStartNew + (p - vStart);
4483             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4484           } else if ((p >= fStart) && (p < fMax)) {
4485             /* Old interior faces add new faces and vertex */
4486             newp = vStartNew + (vEnd - vStart) + (p - fStart);
4487             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4488             for (r = 0; r < 2; ++r) {
4489               newp = fStartNew + (p - fStart)*2 + r;
4490               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4491             }
4492           } else if ((p >= fMax) && (p < fEnd)) {
4493             /* Old hybrid faces stay the same */
4494             newp = fStartNew + (fMax - fStart)*2 + (p - fMax);
4495             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4496           } else if ((p >= cStart) && (p < cMax)) {
4497             /* Old interior cells add new cells and interior faces */
4498             for (r = 0; r < 4; ++r) {
4499               newp = cStartNew + (p - cStart)*4 + r;
4500               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4501             }
4502             for (r = 0; r < 3; ++r) {
4503               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*3 + r;
4504               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4505             }
4506           } else if ((p >= cMax) && (p < cEnd)) {
4507             /* Old hybrid cells add new cells and hybrid face */
4508             for (r = 0; r < 2; ++r) {
4509               newp = cStartNew + (cMax - cStart)*4 + (p - cMax)*2 + r;
4510               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4511             }
4512             newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (p - cMax);
4513             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4514           }
4515           break;
4516         case 5:
4517           /* Simplicial 3D */
4518           if ((p >= vStart) && (p < vEnd)) {
4519             /* Old vertices stay the same */
4520             newp = vStartNew + (p - vStart);
4521             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4522           } else if ((p >= eStart) && (p < eEnd)) {
4523             /* Old edges add new edges and vertex */
4524             for (r = 0; r < 2; ++r) {
4525               newp = eStartNew + (p - eStart)*2 + r;
4526               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4527             }
4528             newp = vStartNew + (vEnd - vStart) + (p - eStart);
4529             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4530           } else if ((p >= fStart) && (p < fEnd)) {
4531             /* Old faces add new faces and edges */
4532             for (r = 0; r < 4; ++r) {
4533               newp = fStartNew + (p - fStart)*4 + r;
4534               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4535             }
4536             for (r = 0; r < 3; ++r) {
4537               newp = eStartNew + (eEnd - eStart)*2 + (p - fStart)*3 + r;
4538               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4539             }
4540           } else if ((p >= cStart) && (p < cEnd)) {
4541             /* Old cells add new cells and interior faces and edges */
4542             for (r = 0; r < 8; ++r) {
4543               newp = cStartNew + (p - cStart)*8 + r;
4544               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4545             }
4546             for (r = 0; r < 8; ++r) {
4547               newp = fStartNew + (fEnd - fStart)*4 + (p - cStart)*8 + r;
4548               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4549             }
4550             for (r = 0; r < 1; ++r) {
4551               newp = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (p - cStart)*1 + r;
4552               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4553             }
4554           }
4555           break;
4556         case 7:
4557           /* Hybrid Simplicial 3D */
4558           if ((p >= vStart) && (p < vEnd)) {
4559             /* Interior vertices stay the same */
4560             newp = vStartNew + (p - vStart);
4561             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4562           } else if ((p >= eStart) && (p < eMax)) {
4563             /* Interior edges add new edges and vertex */
4564             for (r = 0; r < 2; ++r) {
4565               newp = eStartNew + (p - eStart)*2 + r;
4566               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4567             }
4568             newp = vStartNew + (vEnd - vStart) + (p - eStart);
4569             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4570           } else if ((p >= eMax) && (p < eEnd)) {
4571             /* Hybrid edges stay the same */
4572             newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (p - eMax);
4573             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4574           } else if ((p >= fStart) && (p < fMax)) {
4575             /* Interior faces add new faces and edges */
4576             for (r = 0; r < 4; ++r) {
4577               newp = fStartNew + (p - fStart)*4 + r;
4578               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4579             }
4580             for (r = 0; r < 3; ++r) {
4581               newp = eStartNew + (eMax - eStart)*2 + (p - fStart)*3 + r;
4582               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4583             }
4584           } else if ((p >= fMax) && (p < fEnd)) {
4585             /* Hybrid faces add new faces and edges */
4586             for (r = 0; r < 2; ++r) {
4587               newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (p - fMax)*2 + r;
4588               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4589             }
4590             newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (p - fMax);
4591             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4592           } else if ((p >= cStart) && (p < cMax)) {
4593             /* Interior cells add new cells, faces, and edges */
4594             for (r = 0; r < 8; ++r) {
4595               newp = cStartNew + (p - cStart)*8 + r;
4596               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4597             }
4598             for (r = 0; r < 8; ++r) {
4599               newp = fStartNew + (fMax - fStart)*4 + (p - cStart)*8 + r;
4600               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4601             }
4602             newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (p - cStart);
4603             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4604           } else if ((p >= cMax) && (p < cEnd)) {
4605             /* Hybrid cells add new cells and faces */
4606             for (r = 0; r < 4; ++r) {
4607               newp = cStartNew + (cMax - cStart)*8 + (p - cMax)*4 + r;
4608               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4609             }
4610             for (r = 0; r < 3; ++r) {
4611               newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (p - cMax)*3 + r;
4612               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4613             }
4614           }
4615           break;
4616         case 6:
4617           /* Hex 3D */
4618           if ((p >= vStart) && (p < vEnd)) {
4619             /* Old vertices stay the same */
4620             newp = vStartNew + (p - vStart);
4621             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4622           } else if ((p >= eStart) && (p < eEnd)) {
4623             /* Old edges add new edges and vertex */
4624             for (r = 0; r < 2; ++r) {
4625               newp = eStartNew + (p - eStart)*2 + r;
4626               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4627             }
4628             newp = vStartNew + (vEnd - vStart) + (p - eStart);
4629             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4630           } else if ((p >= fStart) && (p < fEnd)) {
4631             /* Old faces add new faces, edges, and vertex */
4632             for (r = 0; r < 4; ++r) {
4633               newp = fStartNew + (p - fStart)*4 + r;
4634               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4635             }
4636             for (r = 0; r < 4; ++r) {
4637               newp = eStartNew + (eEnd - eStart)*2 + (p - fStart)*4 + r;
4638               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4639             }
4640             newp = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (p - fStart);
4641             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4642           } else if ((p >= cStart) && (p < cEnd)) {
4643             /* Old cells add new cells, faces, edges, and vertex */
4644             for (r = 0; r < 8; ++r) {
4645               newp = cStartNew + (p - cStart)*8 + r;
4646               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4647             }
4648             for (r = 0; r < 12; ++r) {
4649               newp = fStartNew + (fEnd - fStart)*4 + (p - cStart)*12 + r;
4650               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4651             }
4652             for (r = 0; r < 6; ++r) {
4653               newp = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*4 + (p - cStart)*6 + r;
4654               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4655             }
4656             newp = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (fEnd - fStart) + (p - cStart);
4657             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4658           }
4659           break;
4660         default:
4661           SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
4662         }
4663       }
4664       ierr = ISRestoreIndices(pointIS, &points);CHKERRQ(ierr);
4665       ierr = ISDestroy(&pointIS);CHKERRQ(ierr);
4666     }
4667     ierr = ISRestoreIndices(valueIS, &values);CHKERRQ(ierr);
4668     ierr = ISDestroy(&valueIS);CHKERRQ(ierr);
4669     if (0) {
4670       ierr = PetscViewerASCIISynchronizedAllow(PETSC_VIEWER_STDOUT_WORLD, PETSC_TRUE);CHKERRQ(ierr);
4671       ierr = DMLabelView(labelNew, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
4672       ierr = PetscViewerFlush(PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
4673     }
4674   }
4675   PetscFunctionReturn(0);
4676 }
4677 
4678 #undef __FUNCT__
4679 #define __FUNCT__ "DMPlexRefineUniform_Internal"
4680 /* This will only work for interpolated meshes */
4681 PetscErrorCode DMPlexRefineUniform_Internal(DM dm, CellRefiner cellRefiner, DM *dmRefined)
4682 {
4683   DM             rdm;
4684   PetscInt      *depthSize;
4685   PetscInt       dim, depth = 0, d, pStart = 0, pEnd = 0;
4686   PetscErrorCode ierr;
4687 
4688   PetscFunctionBegin;
4689   ierr = DMCreate(PetscObjectComm((PetscObject)dm), &rdm);CHKERRQ(ierr);
4690   ierr = DMSetType(rdm, DMPLEX);CHKERRQ(ierr);
4691   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
4692   ierr = DMPlexSetDimension(rdm, dim);CHKERRQ(ierr);
4693   /* Calculate number of new points of each depth */
4694   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
4695   ierr = PetscMalloc1((depth+1), &depthSize);CHKERRQ(ierr);
4696   ierr = PetscMemzero(depthSize, (depth+1) * sizeof(PetscInt));CHKERRQ(ierr);
4697   ierr = CellRefinerGetSizes(cellRefiner, dm, depthSize);CHKERRQ(ierr);
4698   /* Step 1: Set chart */
4699   for (d = 0; d <= depth; ++d) pEnd += depthSize[d];
4700   ierr = DMPlexSetChart(rdm, pStart, pEnd);CHKERRQ(ierr);
4701   /* Step 2: Set cone/support sizes */
4702   ierr = CellRefinerSetConeSizes(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
4703   /* Step 3: Setup refined DM */
4704   ierr = DMSetUp(rdm);CHKERRQ(ierr);
4705   /* Step 4: Set cones and supports */
4706   ierr = CellRefinerSetCones(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
4707   /* Step 5: Stratify */
4708   ierr = DMPlexStratify(rdm);CHKERRQ(ierr);
4709   /* Step 6: Set coordinates for vertices */
4710   ierr = CellRefinerSetCoordinates(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
4711   /* Step 7: Create pointSF */
4712   ierr = CellRefinerCreateSF(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
4713   /* Step 8: Create labels */
4714   ierr = CellRefinerCreateLabels(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
4715   ierr = PetscFree(depthSize);CHKERRQ(ierr);
4716 
4717   *dmRefined = rdm;
4718   PetscFunctionReturn(0);
4719 }
4720 
4721 #undef __FUNCT__
4722 #define __FUNCT__ "DMPlexSetRefinementUniform"
4723 PetscErrorCode DMPlexSetRefinementUniform(DM dm, PetscBool refinementUniform)
4724 {
4725   DM_Plex *mesh = (DM_Plex*) dm->data;
4726 
4727   PetscFunctionBegin;
4728   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4729   mesh->refinementUniform = refinementUniform;
4730   PetscFunctionReturn(0);
4731 }
4732 
4733 #undef __FUNCT__
4734 #define __FUNCT__ "DMPlexGetRefinementUniform"
4735 PetscErrorCode DMPlexGetRefinementUniform(DM dm, PetscBool *refinementUniform)
4736 {
4737   DM_Plex *mesh = (DM_Plex*) dm->data;
4738 
4739   PetscFunctionBegin;
4740   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4741   PetscValidPointer(refinementUniform,  2);
4742   *refinementUniform = mesh->refinementUniform;
4743   PetscFunctionReturn(0);
4744 }
4745 
4746 #undef __FUNCT__
4747 #define __FUNCT__ "DMPlexSetRefinementLimit"
4748 PetscErrorCode DMPlexSetRefinementLimit(DM dm, PetscReal refinementLimit)
4749 {
4750   DM_Plex *mesh = (DM_Plex*) dm->data;
4751 
4752   PetscFunctionBegin;
4753   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4754   mesh->refinementLimit = refinementLimit;
4755   PetscFunctionReturn(0);
4756 }
4757 
4758 #undef __FUNCT__
4759 #define __FUNCT__ "DMPlexGetRefinementLimit"
4760 PetscErrorCode DMPlexGetRefinementLimit(DM dm, PetscReal *refinementLimit)
4761 {
4762   DM_Plex *mesh = (DM_Plex*) dm->data;
4763 
4764   PetscFunctionBegin;
4765   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4766   PetscValidPointer(refinementLimit,  2);
4767   /* if (mesh->refinementLimit < 0) = getMaxVolume()/2.0; */
4768   *refinementLimit = mesh->refinementLimit;
4769   PetscFunctionReturn(0);
4770 }
4771 
4772 #undef __FUNCT__
4773 #define __FUNCT__ "DMPlexGetCellRefiner_Internal"
4774 PetscErrorCode DMPlexGetCellRefiner_Internal(DM dm, CellRefiner *cellRefiner)
4775 {
4776   PetscInt       dim, cStart, cEnd, coneSize, cMax;
4777   PetscErrorCode ierr;
4778 
4779   PetscFunctionBegin;
4780   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
4781   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
4782   if (cEnd <= cStart) {*cellRefiner = 0; PetscFunctionReturn(0);}
4783   ierr = DMPlexGetConeSize(dm, cStart, &coneSize);CHKERRQ(ierr);
4784   ierr = DMPlexGetHybridBounds(dm, &cMax, NULL, NULL, NULL);CHKERRQ(ierr);
4785   switch (dim) {
4786   case 2:
4787     switch (coneSize) {
4788     case 3:
4789       if (cMax >= 0) *cellRefiner = 3; /* Hybrid */
4790       else *cellRefiner = 1; /* Triangular */
4791       break;
4792     case 4:
4793       if (cMax >= 0) *cellRefiner = 4; /* Hybrid */
4794       else *cellRefiner = 2; /* Quadrilateral */
4795       break;
4796     default:
4797       SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown coneSize %d in dimension %d for cell refiner", coneSize, dim);
4798     }
4799     break;
4800   case 3:
4801     switch (coneSize) {
4802     case 4:
4803       if (cMax >= 0) *cellRefiner = 7; /* Hybrid */
4804       else *cellRefiner = 5; /* Tetrahedral */
4805       break;
4806     case 6:
4807       if (cMax >= 0) *cellRefiner = 8; /* Hybrid */
4808       else *cellRefiner = 6; /* hexahedral */
4809       break;
4810     default:
4811       SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown coneSize %d in dimension %d for cell refiner", coneSize, dim);
4812     }
4813     break;
4814   default:
4815     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown dimension %d for cell refiner", dim);
4816   }
4817   PetscFunctionReturn(0);
4818 }
4819