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