xref: /petsc/src/dm/impls/plex/plexrefine.c (revision c3a233c89d5344b97fcee0623834fc4bdafb4eb7)
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, *fornt;
2288       PetscInt        coneNew[5], orntNew[5];
2289 
2290       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
2291       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
2292       ierr = DMPlexGetConeOrientation(dm, cone[0], &fornt);CHKERRQ(ierr);
2293       for (r = 0; r < 3; ++r) {
2294         coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetTriSubface_Static(ornt[0], r);
2295         orntNew[0] = ornt[0];
2296         coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetTriSubface_Static(ornt[1], r);
2297         orntNew[1] = ornt[1];
2298         coneNew[2] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (cone[2+GetTriEdge_Static(ornt[0], (r+2)%3)] - fMax)*2 + (fornt[GetTriEdge_Static(ornt[0], (r+2)%3)] < 0 ? 0 : 1);
2299         orntNew[2] = 0;
2300         coneNew[3] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (cone[2+GetTriEdge_Static(ornt[0], r)]       - fMax)*2 + (fornt[GetTriEdge_Static(ornt[0], r)]       < 0 ? 1 : 0);
2301         orntNew[3] = 0;
2302         coneNew[4] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (c - cMax)*3 + GetTriSubface_Static(ornt[0], r);
2303         orntNew[4] = 0;
2304         ierr = DMPlexSetCone(rdm, newp+r, coneNew);CHKERRQ(ierr);
2305         ierr = DMPlexSetConeOrientation(rdm, newp+r, orntNew);CHKERRQ(ierr);
2306 #if 1
2307         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);
2308         for (p = 0; p < 2; ++p) {
2309           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);
2310         }
2311         for (p = 2; p < 5; ++p) {
2312           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);
2313         }
2314 #endif
2315       }
2316       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + 3;
2317       orntNew[0] = 0;
2318       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + 3;
2319       orntNew[1] = 0;
2320       coneNew[2] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (c - cMax)*3 + 0;
2321       orntNew[2] = 0;
2322       coneNew[3] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (c - cMax)*3 + 1;
2323       orntNew[3] = 0;
2324       coneNew[4] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (c - cMax)*3 + 2;
2325       orntNew[4] = 0;
2326       ierr = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
2327       ierr = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
2328 #if 1
2329       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);
2330       for (p = 0; p < 2; ++p) {
2331         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);
2332       }
2333       for (p = 2; p < 5; ++p) {
2334         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);
2335       }
2336 #endif
2337     }
2338     /* Split faces have 3 edges and the same cells as the parent */
2339     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
2340     ierr = PetscMalloc((2 + maxSupportSize*2) * sizeof(PetscInt), &supportRef);CHKERRQ(ierr);
2341     for (f = fStart; f < fMax; ++f) {
2342       const PetscInt  newp = fStartNew + (f - fStart)*4;
2343       const PetscInt *cone, *ornt, *support;
2344       PetscInt        coneNew[3], orntNew[3], coneSize, supportSize, s;
2345 
2346       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
2347       ierr = DMPlexGetConeOrientation(dm, f, &ornt);CHKERRQ(ierr);
2348       /* A triangle */
2349       coneNew[0] = eStartNew + (cone[0] - eStart)*2 + (ornt[0] < 0 ? 1 : 0);
2350       orntNew[0] = ornt[0];
2351       coneNew[1] = eStartNew + (eMax    - eStart)*2 + (f - fStart)*3 + 2;
2352       orntNew[1] = -2;
2353       coneNew[2] = eStartNew + (cone[2] - eStart)*2 + (ornt[2] < 0 ? 0 : 1);
2354       orntNew[2] = ornt[2];
2355       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
2356       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
2357 #if 1
2358       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);
2359       for (p = 0; p < 3; ++p) {
2360         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);
2361       }
2362 #endif
2363       /* B triangle */
2364       coneNew[0] = eStartNew + (cone[0] - eStart)*2 + (ornt[0] < 0 ? 0 : 1);
2365       orntNew[0] = ornt[0];
2366       coneNew[1] = eStartNew + (cone[1] - eStart)*2 + (ornt[1] < 0 ? 1 : 0);
2367       orntNew[1] = ornt[1];
2368       coneNew[2] = eStartNew + (eMax    - eStart)*2 + (f - fStart)*3 + 0;
2369       orntNew[2] = -2;
2370       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
2371       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
2372 #if 1
2373       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);
2374       for (p = 0; p < 3; ++p) {
2375         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);
2376       }
2377 #endif
2378       /* C triangle */
2379       coneNew[0] = eStartNew + (eMax    - eStart)*2 + (f - fStart)*3 + 1;
2380       orntNew[0] = -2;
2381       coneNew[1] = eStartNew + (cone[1] - eStart)*2 + (ornt[1] < 0 ? 0 : 1);
2382       orntNew[1] = ornt[1];
2383       coneNew[2] = eStartNew + (cone[2] - eStart)*2 + (ornt[2] < 0 ? 1 : 0);
2384       orntNew[2] = ornt[2];
2385       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
2386       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
2387 #if 1
2388       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);
2389       for (p = 0; p < 3; ++p) {
2390         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);
2391       }
2392 #endif
2393       /* D triangle */
2394       coneNew[0] = eStartNew + (eMax    - eStart)*2 + (f - fStart)*3 + 0;
2395       orntNew[0] = 0;
2396       coneNew[1] = eStartNew + (eMax    - eStart)*2 + (f - fStart)*3 + 1;
2397       orntNew[1] = 0;
2398       coneNew[2] = eStartNew + (eMax    - eStart)*2 + (f - fStart)*3 + 2;
2399       orntNew[2] = 0;
2400       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
2401       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
2402 #if 1
2403       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);
2404       for (p = 0; p < 3; ++p) {
2405         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);
2406       }
2407 #endif
2408       ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
2409       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
2410       for (r = 0; r < 4; ++r) {
2411         for (s = 0; s < supportSize; ++s) {
2412           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
2413           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
2414           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
2415           for (c = 0; c < coneSize; ++c) {
2416             if (cone[c] == f) break;
2417           }
2418           if (support[s] < cMax) {
2419             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]));
2420           } else {
2421             supportRef[s] = cStartNew + (cMax - cStart)*8 + (support[s] - cMax)*4 + (r==3 ? r : GetTriSubfaceInverse_Static(ornt[c], r));
2422           }
2423         }
2424         ierr = DMPlexSetSupport(rdm, newp+r, supportRef);CHKERRQ(ierr);
2425 #if 1
2426         if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
2427         for (p = 0; p < supportSize; ++p) {
2428           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);
2429         }
2430 #endif
2431       }
2432     }
2433     /* Interior cell faces have 3 edges and 2 cells */
2434     for (c = cStart; c < cMax; ++c) {
2435       PetscInt        newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*8;
2436       const PetscInt *cone, *ornt;
2437       PetscInt        coneNew[3], orntNew[3];
2438       PetscInt        supportNew[2];
2439 
2440       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
2441       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
2442       /* Face A: {c, a, d} */
2443       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*3 + (ornt[0] < 0 ? (-(ornt[0]+1)+0)%3 : (ornt[0]+2)%3);
2444       orntNew[0] = ornt[0] < 0 ? -2 : 0;
2445       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*3 + (ornt[1] < 0 ? (-(ornt[1]+1)+0)%3 : (ornt[1]+2)%3);
2446       orntNew[1] = ornt[1] < 0 ? -2 : 0;
2447       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*3 + (ornt[2] < 0 ? (-(ornt[2]+1)+0)%3 : (ornt[2]+2)%3);
2448       orntNew[2] = ornt[2] < 0 ? -2 : 0;
2449       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2450       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
2451 #if 1
2452       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
2453       for (p = 0; p < 3; ++p) {
2454         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);
2455       }
2456 #endif
2457       supportNew[0] = (c - cStart)*8 + 0;
2458       supportNew[1] = (c - cStart)*8 + 0+4;
2459       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
2460 #if 1
2461       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
2462       for (p = 0; p < 2; ++p) {
2463         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);
2464       }
2465 #endif
2466       ++newp;
2467       /* Face B: {a, b, e} */
2468       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*3 + (ornt[0] < 0 ? (-(ornt[0]+1)+2)%3 : (ornt[0]+0)%3);
2469       orntNew[0] = ornt[0] < 0 ? -2 : 0;
2470       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*3 + (ornt[3] < 0 ? (-(ornt[3]+1)+2)%3 : (ornt[3]+0)%3);
2471       orntNew[1] = ornt[3] < 0 ? -2 : 0;
2472       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*3 + (ornt[1] < 0 ? (-(ornt[1]+1)+1)%3 : (ornt[1]+1)%3);
2473       orntNew[2] = ornt[1] < 0 ? -2 : 0;
2474       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2475       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
2476 #if 1
2477       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);
2478       for (p = 0; p < 3; ++p) {
2479         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);
2480       }
2481 #endif
2482       supportNew[0] = (c - cStart)*8 + 1;
2483       supportNew[1] = (c - cStart)*8 + 1+4;
2484       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
2485 #if 1
2486       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
2487       for (p = 0; p < 2; ++p) {
2488         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);
2489       }
2490 #endif
2491       ++newp;
2492       /* Face C: {c, f, b} */
2493       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*3 + (ornt[2] < 0 ? (-(ornt[2]+1)+2)%3 : (ornt[2]+0)%3);
2494       orntNew[0] = ornt[2] < 0 ? -2 : 0;
2495       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*3 + (ornt[3] < 0 ? (-(ornt[3]+1)+0)%3 : (ornt[3]+2)%3);
2496       orntNew[1] = ornt[3] < 0 ? -2 : 0;
2497       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*3 + (ornt[0] < 0 ? (-(ornt[0]+1)+1)%3 : (ornt[0]+1)%3);
2498       orntNew[2] = ornt[0] < 0 ? -2 : 0;
2499       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2500       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
2501 #if 1
2502       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
2503       for (p = 0; p < 3; ++p) {
2504         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);
2505       }
2506 #endif
2507       supportNew[0] = (c - cStart)*8 + 2;
2508       supportNew[1] = (c - cStart)*8 + 2+4;
2509       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
2510 #if 1
2511       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
2512       for (p = 0; p < 2; ++p) {
2513         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);
2514       }
2515 #endif
2516       ++newp;
2517       /* Face D: {d, e, f} */
2518       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*3 + (ornt[1] < 0 ? (-(ornt[1]+1)+2)%3 : (ornt[1]+0)%3);
2519       orntNew[0] = ornt[1] < 0 ? -2 : 0;
2520       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*3 + (ornt[3] < 0 ? (-(ornt[3]+1)+1)%3 : (ornt[3]+1)%3);
2521       orntNew[1] = ornt[3] < 0 ? -2 : 0;
2522       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*3 + (ornt[2] < 0 ? (-(ornt[2]+1)+1)%3 : (ornt[2]+1)%3);
2523       orntNew[2] = ornt[2] < 0 ? -2 : 0;
2524       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2525       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
2526 #if 1
2527       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
2528       for (p = 0; p < 3; ++p) {
2529         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);
2530       }
2531 #endif
2532       supportNew[0] = (c - cStart)*8 + 3;
2533       supportNew[1] = (c - cStart)*8 + 3+4;
2534       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
2535 #if 1
2536       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
2537       for (p = 0; p < 2; ++p) {
2538         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);
2539       }
2540 #endif
2541       ++newp;
2542       /* Face E: {d, f, a} */
2543       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*3 + (ornt[2] < 0 ? (-(ornt[2]+1)+1)%3 : (ornt[2]+1)%3);
2544       orntNew[0] = ornt[2] < 0 ? 0 : -2;
2545       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart);
2546       orntNew[1] = 0;
2547       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*3 + (ornt[1] < 0 ? (-(ornt[1]+1)+0)%3 : (ornt[1]+2)%3);
2548       orntNew[2] = ornt[1] < 0 ? -2 : 0;
2549       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2550       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
2551 #if 1
2552       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
2553       for (p = 0; p < 3; ++p) {
2554         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);
2555       }
2556 #endif
2557       supportNew[0] = (c - cStart)*8 + 0+4;
2558       supportNew[1] = (c - cStart)*8 + 3+4;
2559       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
2560 #if 1
2561       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
2562       for (p = 0; p < 2; ++p) {
2563         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);
2564       }
2565 #endif
2566       ++newp;
2567       /* Face F: {c, a, f} */
2568       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*3 + (ornt[0] < 0 ? (-(ornt[0]+1)+0)%3 : (ornt[0]+2)%3);
2569       orntNew[0] = ornt[0] < 0 ? -2 : 0;
2570       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart);
2571       orntNew[1] = -2;
2572       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*3 + (ornt[2] < 0 ? (-(ornt[2]+1)+2)%3 : (ornt[2]+0)%3);
2573       orntNew[2] = ornt[1] < 0 ? 0 : -2;
2574       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2575       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
2576 #if 1
2577       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
2578       for (p = 0; p < 3; ++p) {
2579         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);
2580       }
2581 #endif
2582       supportNew[0] = (c - cStart)*8 + 0+4;
2583       supportNew[1] = (c - cStart)*8 + 2+4;
2584       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
2585 #if 1
2586       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
2587       for (p = 0; p < 2; ++p) {
2588         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);
2589       }
2590 #endif
2591       ++newp;
2592       /* Face G: {e, a, f} */
2593       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*3 + (ornt[1] < 0 ? (-(ornt[1]+1)+1)%3 : (ornt[1]+1)%3);
2594       orntNew[0] = ornt[1] < 0 ? -2 : 0;
2595       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart);
2596       orntNew[1] = -2;
2597       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*3 + (ornt[3] < 0 ? (-(ornt[3]+1)+1)%3 : (ornt[3]+1)%3);
2598       orntNew[2] = ornt[3] < 0 ? 0 : -2;
2599       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2600       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
2601 #if 1
2602       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
2603       for (p = 0; p < 3; ++p) {
2604         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);
2605       }
2606 #endif
2607       supportNew[0] = (c - cStart)*8 + 1+4;
2608       supportNew[1] = (c - cStart)*8 + 3+4;
2609       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
2610 #if 1
2611       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
2612       for (p = 0; p < 2; ++p) {
2613         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);
2614       }
2615 #endif
2616       ++newp;
2617       /* Face H: {a, b, f} */
2618       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*3 + (ornt[0] < 0 ? (-(ornt[0]+1)+2)%3 : (ornt[0]+0)%3);
2619       orntNew[0] = ornt[0] < 0 ? -2 : 0;
2620       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*3 + (ornt[3] < 0 ? (-(ornt[3]+1)+0)%3 : (ornt[3]+2)%3);
2621       orntNew[1] = ornt[3] < 0 ? 0 : -2;
2622       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart);
2623       orntNew[2] = 0;
2624       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2625       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
2626 #if 1
2627       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
2628       for (p = 0; p < 3; ++p) {
2629         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);
2630       }
2631 #endif
2632       supportNew[0] = (c - cStart)*8 + 1+4;
2633       supportNew[1] = (c - cStart)*8 + 2+4;
2634       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
2635 #if 1
2636       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
2637       for (p = 0; p < 2; ++p) {
2638         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);
2639       }
2640 #endif
2641       ++newp;
2642     }
2643     /* Hybrid split faces have 4 edges and same cells */
2644     for (f = fMax; f < fEnd; ++f) {
2645       const PetscInt *cone, *ornt, *support;
2646       PetscInt        coneNew[4], orntNew[4];
2647       PetscInt        supportNew[2], size, s, c;
2648 
2649       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
2650       ierr = DMPlexGetConeOrientation(dm, f, &ornt);CHKERRQ(ierr);
2651       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
2652       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
2653       for (r = 0; r < 2; ++r) {
2654         const PetscInt newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (f - fMax)*2 + r;
2655 
2656         coneNew[0]   = eStartNew + (cone[0] - eStart)*2 + (ornt[0] < 0 ? 1-r : r);
2657         orntNew[0]   = ornt[0];
2658         coneNew[1]   = eStartNew + (cone[1] - eStart)*2 + (ornt[1] < 0 ? 1-r : r);
2659         orntNew[1]   = ornt[1];
2660         coneNew[2+r] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (cone[2+r] - eMax);
2661         orntNew[2+r] = 0;
2662         coneNew[3-r] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (eEnd      - eMax) + (f - fMax);
2663         orntNew[3-r] = 0;
2664         ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2665         ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
2666 #if 1
2667         if ((newp < fMaxNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid face [%d, %d)", newp, fMaxNew, fEndNew);
2668         for (p = 0; p < 2; ++p) {
2669           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);
2670         }
2671         for (p = 2; p < 4; ++p) {
2672           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);
2673         }
2674 #endif
2675         for (s = 0; s < size; ++s) {
2676           const PetscInt *coneCell, *orntCell, *fornt;
2677 
2678           ierr = DMPlexGetCone(dm, support[s], &coneCell);CHKERRQ(ierr);
2679           ierr = DMPlexGetConeOrientation(dm, support[s], &orntCell);CHKERRQ(ierr);
2680           for (c = 2; c < 5; ++c) if (coneCell[c] == f) break;
2681           if (c >= 5) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Could not find face %d in cone of cell %d", f, support[s]);
2682           ierr = DMPlexGetConeOrientation(dm, coneCell[0], &fornt);CHKERRQ(ierr);
2683           supportNew[s] = cStartNew + (cMax - cStart)*8 + (support[s] - cMax)*4 + (GetTriEdgeInverse_Static(orntCell[0], c-2) + (fornt[c-2] < 0 ? 1-r : r))%3;
2684         }
2685         ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
2686 #if 1
2687         if ((newp < fMaxNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid face [%d, %d)", newp, fMaxNew, fEndNew);
2688         for (p = 0; p < size; ++p) {
2689           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);
2690         }
2691 #endif
2692       }
2693     }
2694     /* Hybrid cell faces have 4 edges and 2 cells */
2695     for (c = cMax; c < cEnd; ++c) {
2696       PetscInt        newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (c - cMax)*3;
2697       const PetscInt *cone, *ornt;
2698       PetscInt        coneNew[4], orntNew[4];
2699       PetscInt        supportNew[2];
2700 
2701       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
2702       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
2703       for (r = 0; r < 3; ++r) {
2704         coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*3 + GetTriSubface_Static(ornt[0], (r+2)%3);
2705         orntNew[0] = 0;
2706         coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*3 + GetTriSubface_Static(ornt[1], (r+2)%3);
2707         orntNew[1] = 0;
2708         coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (eEnd - eMax) + (cone[2+GetTriSubface_Static(ornt[0], (r+2)%3)] - fMax);
2709         orntNew[2] = 0;
2710         coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (eEnd - eMax) + (cone[2+GetTriSubface_Static(ornt[0], r)]       - fMax);
2711         orntNew[3] = 0;
2712         ierr = DMPlexSetCone(rdm, newp+r, coneNew);CHKERRQ(ierr);
2713         ierr = DMPlexSetConeOrientation(rdm, newp+r, orntNew);CHKERRQ(ierr);
2714 #if 1
2715         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);
2716         for (p = 0; p < 2; ++p) {
2717           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);
2718         }
2719         for (p = 2; p < 4; ++p) {
2720           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);
2721         }
2722 #endif
2723         supportNew[0] = cStartNew + (cMax - cStart)*8 + (c - cMax)*4 + GetTriSubface_Static(ornt[0], r);
2724         supportNew[1] = cStartNew + (cMax - cStart)*8 + (c - cMax)*4 + 3;
2725         ierr          = DMPlexSetSupport(rdm, newp+r, supportNew);CHKERRQ(ierr);
2726 #if 1
2727         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);
2728         for (p = 0; p < 2; ++p) {
2729           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);
2730         }
2731 #endif
2732       }
2733     }
2734     /* Interior split edges have 2 vertices and the same faces as the parent */
2735     for (e = eStart; e < eMax; ++e) {
2736       const PetscInt newv = vStartNew + (vEnd - vStart) + (e - eStart);
2737 
2738       for (r = 0; r < 2; ++r) {
2739         const PetscInt  newp = eStartNew + (e - eStart)*2 + r;
2740         const PetscInt *cone, *ornt, *support;
2741         PetscInt        coneNew[2], coneSize, c, supportSize, s;
2742 
2743         ierr             = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
2744         coneNew[0]       = vStartNew + (cone[0] - vStart);
2745         coneNew[1]       = vStartNew + (cone[1] - vStart);
2746         coneNew[(r+1)%2] = newv;
2747         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2748 #if 1
2749         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
2750         for (p = 0; p < 2; ++p) {
2751           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);
2752         }
2753 #endif
2754         ierr = DMPlexGetSupportSize(dm, e, &supportSize);CHKERRQ(ierr);
2755         ierr = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
2756         for (s = 0; s < supportSize; ++s) {
2757           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
2758           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
2759           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
2760           for (c = 0; c < coneSize; ++c) if (cone[c] == e) break;
2761           if (support[s] < fMax) {
2762             supportRef[s] = fStartNew + (support[s] - fStart)*4 + (c + (ornt[c] < 0 ? 1-r : r))%3;
2763           } else {
2764             supportRef[s] = fStartNew + (fMax       - fStart)*4 + (cMax - cStart)*8 + (support[s] - fMax)*2 + (ornt[c] < 0 ? 1-r : r);
2765           }
2766         }
2767         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
2768 #if 1
2769         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
2770         for (p = 0; p < supportSize; ++p) {
2771           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);
2772         }
2773 #endif
2774       }
2775     }
2776     /* Interior face edges have 2 vertices and 2+cells*(1/2) faces */
2777     for (f = fStart; f < fMax; ++f) {
2778       const PetscInt *cone, *ornt, *support;
2779       PetscInt        coneSize, supportSize, s;
2780 
2781       ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
2782       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
2783       for (r = 0; r < 3; ++r) {
2784         const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (f - fStart)*3 + r;
2785         PetscInt        coneNew[2], intFaces = 0, er, eint[4] = {1, 0, 2, 0};
2786         PetscInt        fint[24] = { 1,  7, -1, -1,  0,  5,
2787                                     -1, -1,  1,  6,  0,  4,
2788                                      2,  5,  3,  4, -1, -1,
2789                                     -1, -1,  3,  6,  2,  7};
2790 
2791         ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
2792         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[(r+0)%3] - eStart);
2793         coneNew[1] = vStartNew + (vEnd - vStart) + (cone[(r+1)%3] - eStart);
2794         ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2795 #if 1
2796         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
2797         for (p = 0; p < 2; ++p) {
2798           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);
2799         }
2800 #endif
2801         supportRef[0] = fStartNew + (f - fStart)*4 + (r+1)%3;
2802         supportRef[1] = fStartNew + (f - fStart)*4 + 3;
2803         for (s = 0; s < supportSize; ++s) {
2804           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
2805           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
2806           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
2807           for (c = 0; c < coneSize; ++c) {if (cone[c] == f) break;}
2808           if (support[s] < cMax) {
2809             /* Here we want to determine whether edge newp contains a vertex which is part of the cross-tet edge */
2810             er   = ornt[c] < 0 ? (-(ornt[c]+1) + 2-r)%3 : (ornt[c] + r)%3;
2811             if (er == eint[c]) {
2812               supportRef[2+intFaces++] = fStartNew + (fMax - fStart)*4 + (support[s] - cStart)*8 + (c + 2)%4;
2813             } else {
2814               supportRef[2+intFaces++] = fStartNew + (fMax - fStart)*4 + (support[s] - cStart)*8 + fint[(c*3 + er)*2 + 0];
2815               supportRef[2+intFaces++] = fStartNew + (fMax - fStart)*4 + (support[s] - cStart)*8 + fint[(c*3 + er)*2 + 1];
2816             }
2817           } else {
2818             supportRef[2+intFaces++] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (support[s] - cMax)*3 + (GetTriSubfaceInverse_Static(ornt[c], r) + 1)%3;
2819           }
2820         }
2821         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
2822 #if 1
2823         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
2824         for (p = 0; p < intFaces; ++p) {
2825           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);
2826         }
2827 #endif
2828       }
2829     }
2830     /* Interior cell edges have 2 vertices and 4 faces */
2831     for (c = cStart; c < cMax; ++c) {
2832       const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart);
2833       const PetscInt *cone, *ornt, *fcone;
2834       PetscInt        coneNew[2], supportNew[4], find;
2835 
2836       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
2837       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
2838       ierr = DMPlexGetCone(dm, cone[0], &fcone);CHKERRQ(ierr);
2839       find = GetTriEdge_Static(ornt[0], 0);
2840       coneNew[0] = vStartNew + (vEnd - vStart) + (fcone[find] - eStart);
2841       ierr = DMPlexGetCone(dm, cone[2], &fcone);CHKERRQ(ierr);
2842       find = GetTriEdge_Static(ornt[2], 1);
2843       coneNew[1] = vStartNew + (vEnd - vStart) + (fcone[find] - eStart);
2844       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2845 #if 1
2846       if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
2847       for (p = 0; p < 2; ++p) {
2848         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);
2849       }
2850 #endif
2851       supportNew[0] = fStartNew + (fMax - fStart)*4 + (c - cStart)*8 + 4;
2852       supportNew[1] = fStartNew + (fMax - fStart)*4 + (c - cStart)*8 + 5;
2853       supportNew[2] = fStartNew + (fMax - fStart)*4 + (c - cStart)*8 + 6;
2854       supportNew[3] = fStartNew + (fMax - fStart)*4 + (c - cStart)*8 + 7;
2855       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
2856 #if 1
2857       if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
2858       for (p = 0; p < 4; ++p) {
2859         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);
2860       }
2861 #endif
2862     }
2863     /* Hybrid edges have two vertices and the same faces */
2864     for (e = eMax; e < eEnd; ++e) {
2865       const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (e - eMax);
2866       const PetscInt *cone, *support, *fcone;
2867       PetscInt        coneNew[2], size, fsize, s;
2868 
2869       ierr = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
2870       ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
2871       ierr = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
2872       coneNew[0] = vStartNew + (cone[0] - vStart);
2873       coneNew[1] = vStartNew + (cone[1] - vStart);
2874       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2875 #if 1
2876       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid edge [%d, %d)", newp, eMaxNew, eEndNew);
2877       for (p = 0; p < 2; ++p) {
2878         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);
2879       }
2880 #endif
2881       for (s = 0; s < size; ++s) {
2882         ierr = DMPlexGetConeSize(dm, support[s], &fsize);CHKERRQ(ierr);
2883         ierr = DMPlexGetCone(dm, support[s], &fcone);CHKERRQ(ierr);
2884         for (c = 0; c < fsize; ++c) if (fcone[c] == e) break;
2885         if ((c < 2) || (c > 3)) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Edge %d not found in cone of face %d", e, support[s]);
2886         supportRef[s] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (support[s] - fMax)*2 + c-2;
2887       }
2888       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
2889 #if 1
2890       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid edge [%d, %d)", newp, eMaxNew, eEndNew);
2891       for (p = 0; p < size; ++p) {
2892         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);
2893       }
2894 #endif
2895     }
2896     /* Hybrid face edges have 2 vertices and 2+2*cells faces */
2897     for (f = fMax; f < fEnd; ++f) {
2898       const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (eEnd - eMax) + (f - fMax);
2899       const PetscInt *cone, *support, *ccone, *cornt;
2900       PetscInt        coneNew[2], size, csize, s;
2901 
2902       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
2903       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
2904       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
2905       coneNew[0] = vStartNew + (vEnd - vStart) + (cone[0] - eStart);
2906       coneNew[1] = vStartNew + (vEnd - vStart) + (cone[1] - eStart);
2907       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2908 #if 1
2909       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid edge [%d, %d)", newp, eMaxNew, eEndNew);
2910       for (p = 0; p < 2; ++p) {
2911         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);
2912       }
2913 #endif
2914       supportRef[0] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (f - fMax)*2 + 0;
2915       supportRef[1] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (f - fMax)*2 + 1;
2916       for (s = 0; s < size; ++s) {
2917         ierr = DMPlexGetConeSize(dm, support[s], &csize);CHKERRQ(ierr);
2918         ierr = DMPlexGetCone(dm, support[s], &ccone);CHKERRQ(ierr);
2919         ierr = DMPlexGetConeOrientation(dm, support[s], &cornt);CHKERRQ(ierr);
2920         for (c = 0; c < csize; ++c) if (ccone[c] == f) break;
2921         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]);
2922         supportRef[2+s*2+0] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (support[s] - cMax)*3 + GetTriSubfaceInverse_Static(cornt[0], c-2);
2923         supportRef[2+s*2+1] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (support[s] - cMax)*3 + (GetTriSubfaceInverse_Static(cornt[0], c-2) + 1)%3;
2924       }
2925       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
2926 #if 1
2927       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid edge [%d, %d)", newp, eMaxNew, eEndNew);
2928       for (p = 0; p < 2+size*2; ++p) {
2929         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);
2930       }
2931 #endif
2932     }
2933     /* Interior vertices have identical supports */
2934     for (v = vStart; v < vEnd; ++v) {
2935       const PetscInt  newp = vStartNew + (v - vStart);
2936       const PetscInt *support, *cone;
2937       PetscInt        size, s;
2938 
2939       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
2940       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
2941       for (s = 0; s < size; ++s) {
2942         PetscInt r = 0;
2943 
2944         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
2945         if (cone[1] == v) r = 1;
2946         if (support[s] < eMax) supportRef[s] = eStartNew + (support[s] - eStart)*2 + r;
2947         else                   supportRef[s] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (support[s] - eMax);
2948       }
2949       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
2950 #if 1
2951       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
2952       for (p = 0; p < size; ++p) {
2953         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);
2954       }
2955 #endif
2956     }
2957     /* Interior edge vertices have 2 + interior face*2 + hybrid face + cells*0/1 supports */
2958     for (e = eStart; e < eMax; ++e) {
2959       const PetscInt  newp = vStartNew + (vEnd - vStart) + (e - eStart);
2960       const PetscInt *cone, *support;
2961       PetscInt       *star = NULL, starSize, faceSize = 0, cellSize = 0, coneSize, size, s;
2962 
2963       ierr          = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
2964       ierr          = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
2965       supportRef[0] = eStartNew + (e - eStart)*2 + 0;
2966       supportRef[1] = eStartNew + (e - eStart)*2 + 1;
2967       for (s = 0; s < size; ++s) {
2968         PetscInt r = 0;
2969 
2970         if (support[s] < fMax) {
2971           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
2972           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
2973           for (r = 0; r < coneSize; ++r) {if (cone[r] == e) break;}
2974           supportRef[2+faceSize+0] = eStartNew + (eMax - eStart)*2 + (support[s] - fStart)*3 + (r+0)%3;
2975           supportRef[2+faceSize+1] = eStartNew + (eMax - eStart)*2 + (support[s] - fStart)*3 + (r+2)%3;
2976           faceSize += 2;
2977         } else {
2978           supportRef[2+faceSize+0] = eStartNew + (eMax - eStart)*2 + (fMax       - fStart)*3 + (cMax - cStart) + (eEnd - eMax) + (support[s] - fMax);
2979           ++faceSize;
2980         }
2981       }
2982       ierr = DMPlexGetTransitiveClosure(dm, e, PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
2983       for (s = 0; s < starSize*2; s += 2) {
2984         const PetscInt *cone, *ornt;
2985         PetscInt        e01, e23;
2986 
2987         if ((star[s] >= cStart) && (star[s] < cMax)) {
2988           /* Check edge 0-1 */
2989           ierr = DMPlexGetCone(dm, star[s], &cone);CHKERRQ(ierr);
2990           ierr = DMPlexGetConeOrientation(dm, star[s], &ornt);CHKERRQ(ierr);
2991           ierr = DMPlexGetCone(dm, cone[0], &cone);CHKERRQ(ierr);
2992           e01  = cone[GetTriEdge_Static(ornt[0], 0)];
2993           /* Check edge 2-3 */
2994           ierr = DMPlexGetCone(dm, star[s], &cone);CHKERRQ(ierr);
2995           ierr = DMPlexGetConeOrientation(dm, star[s], &ornt);CHKERRQ(ierr);
2996           ierr = DMPlexGetCone(dm, cone[2], &cone);CHKERRQ(ierr);
2997           e23  = cone[GetTriEdge_Static(ornt[2], 1)];
2998           if ((e01 == e) || (e23 == e)) {supportRef[2+faceSize+cellSize++] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (star[s] - cStart);}
2999         }
3000       }
3001       ierr = DMPlexRestoreTransitiveClosure(dm, e, PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
3002       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
3003 #if 1
3004       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
3005       for (p = 0; p < 2+faceSize+cellSize; ++p) {
3006         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);
3007       }
3008 #endif
3009     }
3010     ierr = PetscFree(supportRef);CHKERRQ(ierr);
3011     ierr = DMPlexRestoreFaces_Internal(dm, 3, cStart, NULL, NULL, &faces);CHKERRQ(ierr);
3012     break;
3013   case 6:
3014     /* Hex 3D */
3015     /*
3016      Bottom (viewed from top)    Top
3017      1---------2---------2       7---------2---------6
3018      |         |         |       |         |         |
3019      |    B    2    C    |       |    H    2    G    |
3020      |         |         |       |         |         |
3021      3----3----0----1----1       3----3----0----1----1
3022      |         |         |       |         |         |
3023      |    A    0    D    |       |    E    0    F    |
3024      |         |         |       |         |         |
3025      0---------0---------3       4---------0---------5
3026      */
3027     /* All cells have 6 faces: Bottom, Top, Front, Back, Right, Left */
3028     for (c = cStart; c < cEnd; ++c) {
3029       const PetscInt  newp = (c - cStart)*8;
3030       const PetscInt *cone, *ornt;
3031       PetscInt        coneNew[6], orntNew[6];
3032 
3033       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
3034       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
3035       /* A hex */
3036       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], 0);
3037       orntNew[0] = ornt[0];
3038       coneNew[1] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  8; /* AE */
3039       orntNew[1] = 0;
3040       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetQuadSubface_Static(ornt[2], 0);
3041       orntNew[2] = ornt[2];
3042       coneNew[3] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  3; /* AB */
3043       orntNew[3] = 0;
3044       coneNew[4] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  0; /* AD */
3045       orntNew[4] = 0;
3046       coneNew[5] = fStartNew + (cone[5] - fStart)*4 + GetQuadSubface_Static(ornt[5], 0);
3047       orntNew[5] = ornt[5];
3048       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
3049       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
3050 #if 1
3051       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);
3052       for (p = 0; p < 6; ++p) {
3053         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);
3054       }
3055 #endif
3056       /* B hex */
3057       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], 1);
3058       orntNew[0] = ornt[0];
3059       coneNew[1] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 + 11; /* BH */
3060       orntNew[1] = 0;
3061       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  3; /* AB */
3062       orntNew[2] = -3;
3063       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetQuadSubface_Static(ornt[3], 1);
3064       orntNew[3] = ornt[3];
3065       coneNew[4] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  2; /* BC */
3066       orntNew[4] = 0;
3067       coneNew[5] = fStartNew + (cone[5] - fStart)*4 + GetQuadSubface_Static(ornt[5], 3);
3068       orntNew[5] = ornt[5];
3069       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
3070       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
3071 #if 1
3072       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);
3073       for (p = 0; p < 6; ++p) {
3074         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);
3075       }
3076 #endif
3077       /* C hex */
3078       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], 2);
3079       orntNew[0] = ornt[0];
3080       coneNew[1] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 + 10; /* CG */
3081       orntNew[1] = 0;
3082       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  1; /* CD */
3083       orntNew[2] = 0;
3084       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetQuadSubface_Static(ornt[3], 0);
3085       orntNew[3] = ornt[3];
3086       coneNew[4] = fStartNew + (cone[4] - fStart)*4 + GetQuadSubface_Static(ornt[4], 1);
3087       orntNew[4] = ornt[4];
3088       coneNew[5] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  2; /* BC */
3089       orntNew[5] = -3;
3090       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
3091       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
3092 #if 1
3093       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);
3094       for (p = 0; p < 6; ++p) {
3095         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);
3096       }
3097 #endif
3098       /* D hex */
3099       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], 3);
3100       orntNew[0] = ornt[0];
3101       coneNew[1] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  9; /* DF */
3102       orntNew[1] = 0;
3103       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetQuadSubface_Static(ornt[2], 1);
3104       orntNew[2] = ornt[2];
3105       coneNew[3] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  1; /* CD */
3106       orntNew[3] = -3;
3107       coneNew[4] = fStartNew + (cone[4] - fStart)*4 + GetQuadSubface_Static(ornt[4], 0);
3108       orntNew[4] = ornt[4];
3109       coneNew[5] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  0; /* AD */
3110       orntNew[5] = -3;
3111       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
3112       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
3113 #if 1
3114       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);
3115       for (p = 0; p < 6; ++p) {
3116         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);
3117       }
3118 #endif
3119       /* E hex */
3120       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  8; /* AE */
3121       orntNew[0] = -3;
3122       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], 0);
3123       orntNew[1] = ornt[1];
3124       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetQuadSubface_Static(ornt[2], 3);
3125       orntNew[2] = ornt[2];
3126       coneNew[3] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  7; /* EH */
3127       orntNew[3] = 0;
3128       coneNew[4] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  4; /* EF */
3129       orntNew[4] = 0;
3130       coneNew[5] = fStartNew + (cone[5] - fStart)*4 + GetQuadSubface_Static(ornt[5], 1);
3131       orntNew[5] = ornt[5];
3132       ierr       = DMPlexSetCone(rdm, newp+4, coneNew);CHKERRQ(ierr);
3133       ierr       = DMPlexSetConeOrientation(rdm, newp+4, orntNew);CHKERRQ(ierr);
3134 #if 1
3135       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);
3136       for (p = 0; p < 6; ++p) {
3137         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);
3138       }
3139 #endif
3140       /* F hex */
3141       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  9; /* DF */
3142       orntNew[0] = -3;
3143       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], 1);
3144       orntNew[1] = ornt[1];
3145       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetQuadSubface_Static(ornt[2], 2);
3146       orntNew[2] = ornt[2];
3147       coneNew[3] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  5; /* FG */
3148       orntNew[3] = 0;
3149       coneNew[4] = fStartNew + (cone[4] - fStart)*4 + GetQuadSubface_Static(ornt[4], 3);
3150       orntNew[4] = ornt[4];
3151       coneNew[5] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  4; /* EF */
3152       orntNew[5] = -3;
3153       ierr       = DMPlexSetCone(rdm, newp+5, coneNew);CHKERRQ(ierr);
3154       ierr       = DMPlexSetConeOrientation(rdm, newp+5, orntNew);CHKERRQ(ierr);
3155 #if 1
3156       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);
3157       for (p = 0; p < 6; ++p) {
3158         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);
3159       }
3160 #endif
3161       /* G hex */
3162       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 + 10; /* CG */
3163       orntNew[0] = -3;
3164       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], 2);
3165       orntNew[1] = ornt[1];
3166       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  5; /* FG */
3167       orntNew[2] = -3;
3168       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetQuadSubface_Static(ornt[3], 3);
3169       orntNew[3] = ornt[3];
3170       coneNew[4] = fStartNew + (cone[4] - fStart)*4 + GetQuadSubface_Static(ornt[4], 2);
3171       orntNew[4] = ornt[4];
3172       coneNew[5] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  6; /* GH */
3173       orntNew[5] = 0;
3174       ierr       = DMPlexSetCone(rdm, newp+6, coneNew);CHKERRQ(ierr);
3175       ierr       = DMPlexSetConeOrientation(rdm, newp+6, orntNew);CHKERRQ(ierr);
3176 #if 1
3177       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);
3178       for (p = 0; p < 6; ++p) {
3179         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);
3180       }
3181 #endif
3182       /* H hex */
3183       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 + 11; /* BH */
3184       orntNew[0] = -3;
3185       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], 3);
3186       orntNew[1] = ornt[1];
3187       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  7; /* EH */
3188       orntNew[2] = -3;
3189       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetQuadSubface_Static(ornt[3], 2);
3190       orntNew[3] = ornt[3];
3191       coneNew[4] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  6; /* GH */
3192       orntNew[4] = -3;
3193       coneNew[5] = fStartNew + (cone[5] - fStart)*4 + GetQuadSubface_Static(ornt[5], 2);
3194       orntNew[5] = ornt[5];
3195       ierr       = DMPlexSetCone(rdm, newp+7, coneNew);CHKERRQ(ierr);
3196       ierr       = DMPlexSetConeOrientation(rdm, newp+7, orntNew);CHKERRQ(ierr);
3197 #if 1
3198       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);
3199       for (p = 0; p < 6; ++p) {
3200         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);
3201       }
3202 #endif
3203     }
3204     /* Split faces have 4 edges and the same cells as the parent */
3205     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
3206     ierr = PetscMalloc((4 + maxSupportSize*2) * sizeof(PetscInt), &supportRef);CHKERRQ(ierr);
3207     for (f = fStart; f < fEnd; ++f) {
3208       for (r = 0; r < 4; ++r) {
3209         /* TODO: This can come from GetFaces_Internal() */
3210         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};
3211         const PetscInt  newp = fStartNew + (f - fStart)*4 + r;
3212         const PetscInt *cone, *ornt, *support;
3213         PetscInt        coneNew[4], orntNew[4], coneSize, c, supportSize, s;
3214 
3215         ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
3216         ierr = DMPlexGetConeOrientation(dm, f, &ornt);CHKERRQ(ierr);
3217         coneNew[0] = eStartNew + (cone[(r+3)%4] - eStart)*2 + (ornt[(r+3)%4] < 0 ? 0 : 1);
3218         orntNew[0] = ornt[(r+3)%4];
3219         coneNew[1] = eStartNew + (cone[r]       - eStart)*2 + (ornt[r] < 0 ? 1 : 0);
3220         orntNew[1] = ornt[r];
3221         coneNew[2] = eStartNew + (eEnd - eStart)*2 + (f - fStart)*4 + r;
3222         orntNew[2] = 0;
3223         coneNew[3] = eStartNew + (eEnd - eStart)*2 + (f - fStart)*4 + (r+3)%4;
3224         orntNew[3] = -2;
3225         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3226         ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3227 #if 1
3228         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
3229         for (p = 0; p < 4; ++p) {
3230           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);
3231         }
3232 #endif
3233         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
3234         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
3235         for (s = 0; s < supportSize; ++s) {
3236           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
3237           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
3238           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
3239           for (c = 0; c < coneSize; ++c) {
3240             if (cone[c] == f) break;
3241           }
3242           supportRef[s] = cStartNew + (support[s] - cStart)*8 + newCells[c*4+GetQuadSubface_Static(ornt[c], r)];
3243         }
3244         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
3245 #if 1
3246         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
3247         for (p = 0; p < supportSize; ++p) {
3248           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);
3249         }
3250 #endif
3251       }
3252     }
3253     /* Interior faces have 4 edges and 2 cells */
3254     for (c = cStart; c < cEnd; ++c) {
3255       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};
3256       const PetscInt *cone, *ornt;
3257       PetscInt        newp, coneNew[4], orntNew[4], supportNew[2];
3258 
3259       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
3260       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
3261       /* A-D face */
3262       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 0;
3263       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*4 + GetQuadEdge_Static(ornt[2], 0);
3264       orntNew[0] = -2;
3265       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*4 + GetQuadEdge_Static(ornt[0], 3);
3266       orntNew[1] = 0;
3267       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 0;
3268       orntNew[2] = 0;
3269       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 2;
3270       orntNew[3] = -2;
3271       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3272       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3273 #if 1
3274       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
3275       for (p = 0; p < 4; ++p) {
3276         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);
3277       }
3278 #endif
3279       /* C-D face */
3280       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 1;
3281       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[4] - fStart)*4 + GetQuadEdge_Static(ornt[4], 0);
3282       orntNew[0] = -2;
3283       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*4 + GetQuadEdge_Static(ornt[0], 2);
3284       orntNew[1] = 0;
3285       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 0;
3286       orntNew[2] = 0;
3287       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 4;
3288       orntNew[3] = -2;
3289       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3290       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3291 #if 1
3292       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
3293       for (p = 0; p < 4; ++p) {
3294         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);
3295       }
3296 #endif
3297       /* B-C face */
3298       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 2;
3299       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*4 + GetQuadEdge_Static(ornt[0], 1);
3300       orntNew[0] = -2;
3301       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*4 + GetQuadEdge_Static(ornt[3], 0);
3302       orntNew[1] = 0;
3303       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 3;
3304       orntNew[2] = 0;
3305       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 0;
3306       orntNew[3] = -2;
3307       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3308       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3309 #if 1
3310       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
3311       for (p = 0; p < 4; ++p) {
3312         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);
3313       }
3314 #endif
3315       /* A-B face */
3316       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 3;
3317       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*4 + GetQuadEdge_Static(ornt[0], 0);
3318       orntNew[0] = -2;
3319       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[5] - fStart)*4 + GetQuadEdge_Static(ornt[5], 3);
3320       orntNew[1] = 0;
3321       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 5;
3322       orntNew[2] = 0;
3323       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 0;
3324       orntNew[3] = -2;
3325       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3326       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3327 #if 1
3328       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
3329       for (p = 0; p < 4; ++p) {
3330         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);
3331       }
3332 #endif
3333       /* E-F face */
3334       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 4;
3335       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*4 + GetQuadEdge_Static(ornt[2], 2);
3336       orntNew[0] = -2;
3337       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*4 + GetQuadEdge_Static(ornt[1], 0);
3338       orntNew[1] = 0;
3339       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 1;
3340       orntNew[2] = 0;
3341       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 2;
3342       orntNew[3] = -2;
3343       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3344       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3345 #if 1
3346       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
3347       for (p = 0; p < 4; ++p) {
3348         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);
3349       }
3350 #endif
3351       /* F-G face */
3352       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 5;
3353       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[4] - fStart)*4 + GetQuadEdge_Static(ornt[4], 2);
3354       orntNew[0] = -2;
3355       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*4 + GetQuadEdge_Static(ornt[1], 1);
3356       orntNew[1] = 0;
3357       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 1;
3358       orntNew[2] = 0;
3359       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 4;
3360       orntNew[3] = -2;
3361       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3362       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3363 #if 1
3364       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
3365       for (p = 0; p < 4; ++p) {
3366         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);
3367       }
3368 #endif
3369       /* G-H face */
3370       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 6;
3371       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*4 + GetQuadEdge_Static(ornt[3], 2);
3372       orntNew[0] = -2;
3373       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*4 + GetQuadEdge_Static(ornt[1], 2);
3374       orntNew[1] = 0;
3375       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 1;
3376       orntNew[2] = 0;
3377       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 3;
3378       orntNew[3] = -2;
3379       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3380       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3381 #if 1
3382       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
3383       for (p = 0; p < 4; ++p) {
3384         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);
3385       }
3386 #endif
3387       /* E-H face */
3388       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 7;
3389       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[5] - fStart)*4 + GetQuadEdge_Static(ornt[5], 1);
3390       orntNew[0] = -2;
3391       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*4 + GetQuadEdge_Static(ornt[1], 3);
3392       orntNew[1] = 0;
3393       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 1;
3394       orntNew[2] = 0;
3395       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 5;
3396       orntNew[3] = -2;
3397       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3398       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3399 #if 1
3400       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
3401       for (p = 0; p < 4; ++p) {
3402         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);
3403       }
3404 #endif
3405       /* A-E face */
3406       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 8;
3407       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[5] - fStart)*4 + GetQuadEdge_Static(ornt[5], 0);
3408       orntNew[0] = -2;
3409       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*4 + GetQuadEdge_Static(ornt[2], 3);
3410       orntNew[1] = 0;
3411       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 2;
3412       orntNew[2] = 0;
3413       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 5;
3414       orntNew[3] = -2;
3415       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3416       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3417 #if 1
3418       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
3419       for (p = 0; p < 4; ++p) {
3420         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);
3421       }
3422 #endif
3423       /* D-F face */
3424       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 9;
3425       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*4 + GetQuadEdge_Static(ornt[2], 1);
3426       orntNew[0] = -2;
3427       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[4] - fStart)*4 + GetQuadEdge_Static(ornt[4], 3);
3428       orntNew[1] = 0;
3429       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 4;
3430       orntNew[2] = 0;
3431       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 2;
3432       orntNew[3] = -2;
3433       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3434       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3435 #if 1
3436       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
3437       for (p = 0; p < 4; ++p) {
3438         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);
3439       }
3440 #endif
3441       /* C-G face */
3442       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 10;
3443       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[4] - fStart)*4 + GetQuadEdge_Static(ornt[4], 1);
3444       orntNew[0] = -2;
3445       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*4 + GetQuadEdge_Static(ornt[3], 3);
3446       orntNew[1] = 0;
3447       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 3;
3448       orntNew[2] = 0;
3449       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 4;
3450       orntNew[3] = -2;
3451       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3452       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3453 #if 1
3454       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
3455       for (p = 0; p < 4; ++p) {
3456         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);
3457       }
3458 #endif
3459       /* B-H face */
3460       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 11;
3461       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*4 + GetQuadEdge_Static(ornt[3], 1);
3462       orntNew[0] = -2;
3463       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[5] - fStart)*4 + GetQuadEdge_Static(ornt[5], 2);
3464       orntNew[1] = 0;
3465       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 5;
3466       orntNew[2] = 0;
3467       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 3;
3468       orntNew[3] = -2;
3469       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3470       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3471 #if 1
3472       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
3473       for (p = 0; p < 4; ++p) {
3474         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);
3475       }
3476 #endif
3477       for (r = 0; r < 12; ++r) {
3478         newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + r;
3479         supportNew[0] = cStartNew + (c - cStart)*8 + newCells[r*2+0];
3480         supportNew[1] = cStartNew + (c - cStart)*8 + newCells[r*2+1];
3481         ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3482 #if 1
3483         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
3484         for (p = 0; p < 2; ++p) {
3485           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);
3486         }
3487 #endif
3488       }
3489     }
3490     /* Split edges have 2 vertices and the same faces as the parent */
3491     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
3492     for (e = eStart; e < eEnd; ++e) {
3493       const PetscInt newv = vStartNew + (vEnd - vStart) + (e - eStart);
3494 
3495       for (r = 0; r < 2; ++r) {
3496         const PetscInt  newp = eStartNew + (e - eStart)*2 + r;
3497         const PetscInt *cone, *ornt, *support;
3498         PetscInt        coneNew[2], coneSize, c, supportSize, s;
3499 
3500         ierr             = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
3501         coneNew[0]       = vStartNew + (cone[0] - vStart);
3502         coneNew[1]       = vStartNew + (cone[1] - vStart);
3503         coneNew[(r+1)%2] = newv;
3504         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3505 #if 1
3506         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
3507         for (p = 0; p < 2; ++p) {
3508           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);
3509         }
3510 #endif
3511         ierr = DMPlexGetSupportSize(dm, e, &supportSize);CHKERRQ(ierr);
3512         ierr = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
3513         for (s = 0; s < supportSize; ++s) {
3514           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
3515           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
3516           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
3517           for (c = 0; c < coneSize; ++c) {
3518             if (cone[c] == e) break;
3519           }
3520           supportRef[s] = fStartNew + (support[s] - fStart)*4 + (ornt[c] < 0 ? (c+1-r)%4 : (c+r)%4);
3521         }
3522         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
3523 #if 1
3524         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
3525         for (p = 0; p < supportSize; ++p) {
3526           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);
3527         }
3528 #endif
3529       }
3530     }
3531     /* Face edges have 2 vertices and 2+cells faces */
3532     for (f = fStart; f < fEnd; ++f) {
3533       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};
3534       const PetscInt  newv = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (f - fStart);
3535       const PetscInt *cone, *coneCell, *orntCell, *support;
3536       PetscInt        coneNew[2], coneSize, c, supportSize, s;
3537 
3538       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
3539       for (r = 0; r < 4; ++r) {
3540         const PetscInt newp = eStartNew + (eEnd - eStart)*2 + (f - fStart)*4 + r;
3541 
3542         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r] - eStart);
3543         coneNew[1] = newv;
3544         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3545 #if 1
3546         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
3547         for (p = 0; p < 2; ++p) {
3548           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);
3549         }
3550 #endif
3551         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
3552         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
3553         supportRef[0] = fStartNew + (f - fStart)*4 + r;
3554         supportRef[1] = fStartNew + (f - fStart)*4 + (r+1)%4;
3555         for (s = 0; s < supportSize; ++s) {
3556           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
3557           ierr = DMPlexGetCone(dm, support[s], &coneCell);CHKERRQ(ierr);
3558           ierr = DMPlexGetConeOrientation(dm, support[s], &orntCell);CHKERRQ(ierr);
3559           for (c = 0; c < coneSize; ++c) if (coneCell[c] == f) break;
3560           supportRef[2+s] = fStartNew + (fEnd - fStart)*4 + (support[s] - cStart)*12 + newFaces[c*4 + GetQuadEdge_Static(orntCell[c], r)];
3561         }
3562         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
3563 #if 1
3564         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
3565         for (p = 0; p < 2+supportSize; ++p) {
3566           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);
3567         }
3568 #endif
3569       }
3570     }
3571     /* Cell edges have 2 vertices and 4 faces */
3572     for (c = cStart; c < cEnd; ++c) {
3573       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};
3574       const PetscInt  newv = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (fEnd - fStart) + (c - cStart);
3575       const PetscInt *cone;
3576       PetscInt        coneNew[2], supportNew[4];
3577 
3578       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
3579       for (r = 0; r < 6; ++r) {
3580         const PetscInt newp = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*4 + (c - cStart)*6 + r;
3581 
3582         coneNew[0] = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (cone[r] - fStart);
3583         coneNew[1] = newv;
3584         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3585 #if 1
3586         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
3587         for (p = 0; p < 2; ++p) {
3588           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);
3589         }
3590 #endif
3591         for (f = 0; f < 4; ++f) supportNew[f] = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + newFaces[r*4+f];
3592         ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3593 #if 1
3594         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
3595         for (p = 0; p < 4; ++p) {
3596           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);
3597         }
3598 #endif
3599       }
3600     }
3601     /* Old vertices have identical supports */
3602     for (v = vStart; v < vEnd; ++v) {
3603       const PetscInt  newp = vStartNew + (v - vStart);
3604       const PetscInt *support, *cone;
3605       PetscInt        size, s;
3606 
3607       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
3608       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
3609       for (s = 0; s < size; ++s) {
3610         PetscInt r = 0;
3611 
3612         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
3613         if (cone[1] == v) r = 1;
3614         supportRef[s] = eStartNew + (support[s] - eStart)*2 + r;
3615       }
3616       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
3617 #if 1
3618       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
3619       for (p = 0; p < size; ++p) {
3620         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);
3621       }
3622 #endif
3623     }
3624     /* Edge vertices have 2 + faces supports */
3625     for (e = eStart; e < eEnd; ++e) {
3626       const PetscInt  newp = vStartNew + (vEnd - vStart) + (e - eStart);
3627       const PetscInt *cone, *support;
3628       PetscInt        size, s;
3629 
3630       ierr          = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
3631       ierr          = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
3632       supportRef[0] = eStartNew + (e - eStart)*2 + 0;
3633       supportRef[1] = eStartNew + (e - eStart)*2 + 1;
3634       for (s = 0; s < size; ++s) {
3635         PetscInt r;
3636 
3637         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
3638         for (r = 0; r < 4; ++r) if (cone[r] == e) break;
3639         supportRef[2+s] = eStartNew + (eEnd - eStart)*2 + (support[s] - fStart)*4 + r;
3640       }
3641       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
3642 #if 1
3643       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
3644       for (p = 0; p < 2+size; ++p) {
3645         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);
3646       }
3647 #endif
3648     }
3649     /* Face vertices have 4 + cells supports */
3650     for (f = fStart; f < fEnd; ++f) {
3651       const PetscInt  newp = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (f - fStart);
3652       const PetscInt *cone, *support;
3653       PetscInt        size, s;
3654 
3655       ierr          = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
3656       ierr          = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
3657       for (r = 0; r < 4; ++r) supportRef[r] = eStartNew + (e - eStart)*2 +  (f - fStart)*4 + r;
3658       for (s = 0; s < size; ++s) {
3659         PetscInt r;
3660 
3661         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
3662         for (r = 0; r < 6; ++r) if (cone[r] == f) break;
3663         supportRef[4+s] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*4 + (support[s] - cStart)*6 + r;
3664       }
3665       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
3666 #if 1
3667       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
3668       for (p = 0; p < 4+size; ++p) {
3669         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);
3670       }
3671 #endif
3672     }
3673     /* Cell vertices have 6 supports */
3674     for (c = cStart; c < cEnd; ++c) {
3675       const PetscInt newp = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (fEnd - fStart) + (c - cStart);
3676       PetscInt       supportNew[6];
3677 
3678       for (r = 0; r < 6; ++r) {
3679         supportNew[r] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*4 + (c - cStart)*6 + r;
3680       }
3681       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3682     }
3683     ierr = PetscFree(supportRef);CHKERRQ(ierr);
3684     break;
3685   default:
3686     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
3687   }
3688   PetscFunctionReturn(0);
3689 }
3690 
3691 #undef __FUNCT__
3692 #define __FUNCT__ "CellRefinerSetCoordinates"
3693 PetscErrorCode CellRefinerSetCoordinates(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
3694 {
3695   PetscSection   coordSection, coordSectionNew;
3696   Vec            coordinates, coordinatesNew;
3697   PetscScalar   *coords, *coordsNew;
3698   const PetscInt numVertices = depthSize ? depthSize[0] : 0;
3699   PetscInt       dim, depth, coordSizeNew, cStart, cEnd, c, vStart, vStartNew, vEnd, v, eStart, eEnd, eMax, e, fStart, fEnd, fMax, f;
3700   PetscErrorCode ierr;
3701 
3702   PetscFunctionBegin;
3703   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
3704   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3705   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
3706   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
3707   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
3708   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
3709   ierr = DMPlexGetHybridBounds(dm, NULL, &fMax, &eMax, NULL);CHKERRQ(ierr);
3710   if (refiner) {ierr = GetDepthStart_Private(depth, depthSize, NULL, NULL, NULL, &vStartNew);CHKERRQ(ierr);}
3711   ierr = GetDepthStart_Private(depth, depthSize, NULL, NULL, NULL, &vStartNew);CHKERRQ(ierr);
3712   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
3713   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)dm), &coordSectionNew);CHKERRQ(ierr);
3714   ierr = PetscSectionSetNumFields(coordSectionNew, 1);CHKERRQ(ierr);
3715   ierr = PetscSectionSetFieldComponents(coordSectionNew, 0, dim);CHKERRQ(ierr);
3716   ierr = PetscSectionSetChart(coordSectionNew, vStartNew, vStartNew+numVertices);CHKERRQ(ierr);
3717   if (fMax < 0) fMax = fEnd;
3718   if (eMax < 0) eMax = eEnd;
3719   /* All vertices have the dim coordinates */
3720   for (v = vStartNew; v < vStartNew+numVertices; ++v) {
3721     ierr = PetscSectionSetDof(coordSectionNew, v, dim);CHKERRQ(ierr);
3722     ierr = PetscSectionSetFieldDof(coordSectionNew, v, 0, dim);CHKERRQ(ierr);
3723   }
3724   ierr = PetscSectionSetUp(coordSectionNew);CHKERRQ(ierr);
3725   ierr = DMPlexSetCoordinateSection(rdm, coordSectionNew);CHKERRQ(ierr);
3726   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
3727   ierr = PetscSectionGetStorageSize(coordSectionNew, &coordSizeNew);CHKERRQ(ierr);
3728   ierr = VecCreate(PetscObjectComm((PetscObject)dm), &coordinatesNew);CHKERRQ(ierr);
3729   ierr = PetscObjectSetName((PetscObject) coordinatesNew, "coordinates");CHKERRQ(ierr);
3730   ierr = VecSetSizes(coordinatesNew, coordSizeNew, PETSC_DETERMINE);CHKERRQ(ierr);
3731   ierr = VecSetFromOptions(coordinatesNew);CHKERRQ(ierr);
3732   ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
3733   ierr = VecGetArray(coordinatesNew, &coordsNew);CHKERRQ(ierr);
3734   switch (refiner) {
3735   case 0: break;
3736   case 6: /* Hex 3D */
3737     /* Face vertices have the average of corner coordinates */
3738     for (f = fStart; f < fEnd; ++f) {
3739       const PetscInt newv = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (f - fStart);
3740       PetscInt      *cone = NULL;
3741       PetscInt       closureSize, coneSize = 0, off[8], offnew, p, d;
3742 
3743       ierr = DMPlexGetTransitiveClosure(dm, f, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
3744       for (p = 0; p < closureSize*2; p += 2) {
3745         const PetscInt point = cone[p];
3746         if ((point >= vStart) && (point < vEnd)) cone[coneSize++] = point;
3747       }
3748       for (v = 0; v < coneSize; ++v) {
3749         ierr = PetscSectionGetOffset(coordSection, cone[v], &off[v]);CHKERRQ(ierr);
3750       }
3751       ierr = PetscSectionGetOffset(coordSectionNew, newv, &offnew);CHKERRQ(ierr);
3752       for (d = 0; d < dim; ++d) {
3753         coordsNew[offnew+d] = 0.0;
3754         for (v = 0; v < coneSize; ++v) coordsNew[offnew+d] += coords[off[v]+d];
3755         coordsNew[offnew+d] /= coneSize;
3756       }
3757       ierr = DMPlexRestoreTransitiveClosure(dm, f, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
3758     }
3759   case 2: /* Hex 2D */
3760     /* Cell vertices have the average of corner coordinates */
3761     for (c = cStart; c < cEnd; ++c) {
3762       const PetscInt newv = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (c - cStart) + (dim > 2 ? (fEnd - fStart) : 0);
3763       PetscInt      *cone = NULL;
3764       PetscInt       closureSize, coneSize = 0, off[8], offnew, p, d;
3765 
3766       ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
3767       for (p = 0; p < closureSize*2; p += 2) {
3768         const PetscInt point = cone[p];
3769         if ((point >= vStart) && (point < vEnd)) cone[coneSize++] = point;
3770       }
3771       for (v = 0; v < coneSize; ++v) {
3772         ierr = PetscSectionGetOffset(coordSection, cone[v], &off[v]);CHKERRQ(ierr);
3773       }
3774       ierr = PetscSectionGetOffset(coordSectionNew, newv, &offnew);CHKERRQ(ierr);
3775       for (d = 0; d < dim; ++d) {
3776         coordsNew[offnew+d] = 0.0;
3777         for (v = 0; v < coneSize; ++v) coordsNew[offnew+d] += coords[off[v]+d];
3778         coordsNew[offnew+d] /= coneSize;
3779       }
3780       ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
3781     }
3782   case 1: /* Simplicial 2D */
3783   case 3: /* Hybrid Simplicial 2D */
3784   case 5: /* Simplicial 3D */
3785   case 7: /* Hybrid Simplicial 3D */
3786     /* Edge vertices have the average of endpoint coordinates */
3787     for (e = eStart; e < eMax; ++e) {
3788       const PetscInt  newv = vStartNew + (vEnd - vStart) + (e - eStart);
3789       const PetscInt *cone;
3790       PetscInt        coneSize, offA, offB, offnew, d;
3791 
3792       ierr = DMPlexGetConeSize(dm, e, &coneSize);CHKERRQ(ierr);
3793       if (coneSize != 2) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Edge %d cone should have two vertices, not %d", e, coneSize);
3794       ierr = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
3795       ierr = PetscSectionGetOffset(coordSection, cone[0], &offA);CHKERRQ(ierr);
3796       ierr = PetscSectionGetOffset(coordSection, cone[1], &offB);CHKERRQ(ierr);
3797       ierr = PetscSectionGetOffset(coordSectionNew, newv, &offnew);CHKERRQ(ierr);
3798       for (d = 0; d < dim; ++d) {
3799         coordsNew[offnew+d] = 0.5*(coords[offA+d] + coords[offB+d]);
3800       }
3801     }
3802     /* Old vertices have the same coordinates */
3803     for (v = vStart; v < vEnd; ++v) {
3804       const PetscInt newv = vStartNew + (v - vStart);
3805       PetscInt       off, offnew, d;
3806 
3807       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
3808       ierr = PetscSectionGetOffset(coordSectionNew, newv, &offnew);CHKERRQ(ierr);
3809       for (d = 0; d < dim; ++d) {
3810         coordsNew[offnew+d] = coords[off+d];
3811       }
3812     }
3813     break;
3814   default:
3815     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
3816   }
3817   ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
3818   ierr = VecRestoreArray(coordinatesNew, &coordsNew);CHKERRQ(ierr);
3819   ierr = DMSetCoordinatesLocal(rdm, coordinatesNew);CHKERRQ(ierr);
3820   ierr = VecDestroy(&coordinatesNew);CHKERRQ(ierr);
3821   ierr = PetscSectionDestroy(&coordSectionNew);CHKERRQ(ierr);
3822   PetscFunctionReturn(0);
3823 }
3824 
3825 #undef __FUNCT__
3826 #define __FUNCT__ "DMPlexCreateProcessSF"
3827 PetscErrorCode DMPlexCreateProcessSF(DM dm, PetscSF sfPoint, IS *processRanks, PetscSF *sfProcess)
3828 {
3829   PetscInt           numRoots, numLeaves, l;
3830   const PetscInt    *localPoints;
3831   const PetscSFNode *remotePoints;
3832   PetscInt          *localPointsNew;
3833   PetscSFNode       *remotePointsNew;
3834   PetscInt          *ranks, *ranksNew;
3835   PetscErrorCode     ierr;
3836 
3837   PetscFunctionBegin;
3838   ierr = PetscSFGetGraph(sfPoint, &numRoots, &numLeaves, &localPoints, &remotePoints);CHKERRQ(ierr);
3839   ierr = PetscMalloc(numLeaves * sizeof(PetscInt), &ranks);CHKERRQ(ierr);
3840   for (l = 0; l < numLeaves; ++l) {
3841     ranks[l] = remotePoints[l].rank;
3842   }
3843   ierr = PetscSortRemoveDupsInt(&numLeaves, ranks);CHKERRQ(ierr);
3844   ierr = PetscMalloc(numLeaves * sizeof(PetscInt),    &ranksNew);CHKERRQ(ierr);
3845   ierr = PetscMalloc(numLeaves * sizeof(PetscInt),    &localPointsNew);CHKERRQ(ierr);
3846   ierr = PetscMalloc(numLeaves * sizeof(PetscSFNode), &remotePointsNew);CHKERRQ(ierr);
3847   for (l = 0; l < numLeaves; ++l) {
3848     ranksNew[l]              = ranks[l];
3849     localPointsNew[l]        = l;
3850     remotePointsNew[l].index = 0;
3851     remotePointsNew[l].rank  = ranksNew[l];
3852   }
3853   ierr = PetscFree(ranks);CHKERRQ(ierr);
3854   ierr = ISCreateGeneral(PetscObjectComm((PetscObject)dm), numLeaves, ranksNew, PETSC_OWN_POINTER, processRanks);CHKERRQ(ierr);
3855   ierr = PetscSFCreate(PetscObjectComm((PetscObject)dm), sfProcess);CHKERRQ(ierr);
3856   ierr = PetscSFSetFromOptions(*sfProcess);CHKERRQ(ierr);
3857   ierr = PetscSFSetGraph(*sfProcess, 1, numLeaves, localPointsNew, PETSC_OWN_POINTER, remotePointsNew, PETSC_OWN_POINTER);CHKERRQ(ierr);
3858   PetscFunctionReturn(0);
3859 }
3860 
3861 #undef __FUNCT__
3862 #define __FUNCT__ "CellRefinerCreateSF"
3863 PetscErrorCode CellRefinerCreateSF(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
3864 {
3865   PetscSF            sf, sfNew, sfProcess;
3866   IS                 processRanks;
3867   MPI_Datatype       depthType;
3868   PetscInt           numRoots, numLeaves, numLeavesNew = 0, l, m;
3869   const PetscInt    *localPoints, *neighbors;
3870   const PetscSFNode *remotePoints;
3871   PetscInt          *localPointsNew;
3872   PetscSFNode       *remotePointsNew;
3873   PetscInt          *depthSizeOld, *rdepthSize, *rdepthSizeOld, *rdepthMaxOld, *rvStart, *rvStartNew, *reStart, *reStartNew, *rfStart, *rfStartNew, *rcStart, *rcStartNew;
3874   PetscInt           depth, numNeighbors, pStartNew, pEndNew, cStart, cStartNew = 0, cEnd, cMax, vStart, vStartNew = 0, vEnd, vMax, fStart, fStartNew = 0, fEnd, fMax, eStart, eStartNew = 0, eEnd, eMax, r, n;
3875   PetscErrorCode     ierr;
3876 
3877   PetscFunctionBegin;
3878   ierr = DMPlexGetChart(rdm, &pStartNew, &pEndNew);CHKERRQ(ierr);
3879   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3880   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
3881   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
3882   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
3883   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
3884   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
3885   if (refiner) {ierr = GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);CHKERRQ(ierr);}
3886   ierr = DMGetPointSF(dm, &sf);CHKERRQ(ierr);
3887   ierr = DMGetPointSF(rdm, &sfNew);CHKERRQ(ierr);
3888   /* Caculate size of new SF */
3889   ierr = PetscSFGetGraph(sf, &numRoots, &numLeaves, &localPoints, &remotePoints);CHKERRQ(ierr);
3890   if (numRoots < 0) PetscFunctionReturn(0);
3891   for (l = 0; l < numLeaves; ++l) {
3892     const PetscInt p = localPoints[l];
3893 
3894     switch (refiner) {
3895     case 1:
3896       /* Simplicial 2D */
3897       if ((p >= vStart) && (p < vEnd)) {
3898         /* Old vertices stay the same */
3899         ++numLeavesNew;
3900       } else if ((p >= fStart) && (p < fEnd)) {
3901         /* Old faces add new faces and vertex */
3902         numLeavesNew += 2 + 1;
3903       } else if ((p >= cStart) && (p < cEnd)) {
3904         /* Old cells add new cells and interior faces */
3905         numLeavesNew += 4 + 3;
3906       }
3907       break;
3908     case 2:
3909       /* Hex 2D */
3910       if ((p >= vStart) && (p < vEnd)) {
3911         /* Old vertices stay the same */
3912         ++numLeavesNew;
3913       } else if ((p >= fStart) && (p < fEnd)) {
3914         /* Old faces add new faces and vertex */
3915         numLeavesNew += 2 + 1;
3916       } else if ((p >= cStart) && (p < cEnd)) {
3917         /* Old cells add new cells, interior faces, and vertex */
3918         numLeavesNew += 4 + 4 + 1;
3919       }
3920       break;
3921     case 5:
3922       /* Simplicial 3D */
3923       if ((p >= vStart) && (p < vEnd)) {
3924         /* Old vertices stay the same */
3925         ++numLeavesNew;
3926       } else if ((p >= eStart) && (p < eEnd)) {
3927         /* Old edges add new edges and vertex */
3928         numLeavesNew += 2 + 1;
3929       } else if ((p >= fStart) && (p < fEnd)) {
3930         /* Old faces add new faces and face edges */
3931         numLeavesNew += 4 + 3;
3932       } else if ((p >= cStart) && (p < cEnd)) {
3933         /* Old cells add new cells and interior faces and edges */
3934         numLeavesNew += 8 + 8 + 1;
3935       }
3936       break;
3937     case 7:
3938       /* Hybrid Simplicial 3D */
3939       if ((p >= vStart) && (p < vEnd)) {
3940         /* Interior vertices stay the same */
3941         ++numLeavesNew;
3942       } else if ((p >= eStart) && (p < eMax)) {
3943         /* Interior edges add new edges and vertex */
3944         numLeavesNew += 2 + 1;
3945       } else if ((p >= eMax) && (p < eEnd)) {
3946         /* Hybrid edges stay the same */
3947         ++numLeavesNew;
3948       } else if ((p >= fStart) && (p < fMax)) {
3949         /* Interior faces add new faces and edges */
3950         numLeavesNew += 4 + 3;
3951       } else if ((p >= fMax) && (p < fEnd)) {
3952         /* Hybrid faces add new faces and edges */
3953         numLeavesNew += 2 + 1;
3954       } else if ((p >= cStart) && (p < cMax)) {
3955         /* Interior cells add new cells, faces, and edges */
3956         numLeavesNew += 8 + 8 + 1;
3957       } else if ((p >= cMax) && (p < cEnd)) {
3958         /* Hybrid cells add new cells and faces */
3959         numLeavesNew += 4 + 3;
3960       }
3961       break;
3962     case 6:
3963       /* Hex 3D */
3964       if ((p >= vStart) && (p < vEnd)) {
3965         /* Old vertices stay the same */
3966         ++numLeavesNew;
3967       } else if ((p >= eStart) && (p < eEnd)) {
3968         /* Old edges add new edges, and vertex */
3969         numLeavesNew += 2 + 1;
3970       } else if ((p >= fStart) && (p < fEnd)) {
3971         /* Old faces add new faces, edges, and vertex */
3972         numLeavesNew += 4 + 4 + 1;
3973       } else if ((p >= cStart) && (p < cEnd)) {
3974         /* Old cells add new cells, faces, edges, and vertex */
3975         numLeavesNew += 8 + 12 + 6 + 1;
3976       }
3977       break;
3978     default:
3979       SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
3980     }
3981   }
3982   /* Communicate depthSizes for each remote rank */
3983   ierr = DMPlexCreateProcessSF(dm, sf, &processRanks, &sfProcess);CHKERRQ(ierr);
3984   ierr = ISGetLocalSize(processRanks, &numNeighbors);CHKERRQ(ierr);
3985   ierr = PetscMalloc5((depth+1)*numNeighbors,PetscInt,&rdepthSize,numNeighbors,PetscInt,&rvStartNew,numNeighbors,PetscInt,&reStartNew,numNeighbors,PetscInt,&rfStartNew,numNeighbors,PetscInt,&rcStartNew);CHKERRQ(ierr);
3986   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);
3987   ierr = MPI_Type_contiguous(depth+1, MPIU_INT, &depthType);CHKERRQ(ierr);
3988   ierr = MPI_Type_commit(&depthType);CHKERRQ(ierr);
3989   ierr = PetscSFBcastBegin(sfProcess, depthType, depthSize, rdepthSize);CHKERRQ(ierr);
3990   ierr = PetscSFBcastEnd(sfProcess, depthType, depthSize, rdepthSize);CHKERRQ(ierr);
3991   for (n = 0; n < numNeighbors; ++n) {
3992     ierr = GetDepthStart_Private(depth, &rdepthSize[n*(depth+1)], &rcStartNew[n], &rfStartNew[n], &reStartNew[n], &rvStartNew[n]);CHKERRQ(ierr);
3993   }
3994   depthSizeOld[depth]   = cMax;
3995   depthSizeOld[0]       = vMax;
3996   depthSizeOld[depth-1] = fMax;
3997   depthSizeOld[1]       = eMax;
3998 
3999   ierr = PetscSFBcastBegin(sfProcess, depthType, depthSizeOld, rdepthMaxOld);CHKERRQ(ierr);
4000   ierr = PetscSFBcastEnd(sfProcess, depthType, depthSizeOld, rdepthMaxOld);CHKERRQ(ierr);
4001 
4002   depthSizeOld[depth]   = cEnd - cStart;
4003   depthSizeOld[0]       = vEnd - vStart;
4004   depthSizeOld[depth-1] = fEnd - fStart;
4005   depthSizeOld[1]       = eEnd - eStart;
4006 
4007   ierr = PetscSFBcastBegin(sfProcess, depthType, depthSizeOld, rdepthSizeOld);CHKERRQ(ierr);
4008   ierr = PetscSFBcastEnd(sfProcess, depthType, depthSizeOld, rdepthSizeOld);CHKERRQ(ierr);
4009   for (n = 0; n < numNeighbors; ++n) {
4010     ierr = GetDepthStart_Private(depth, &rdepthSizeOld[n*(depth+1)], &rcStart[n], &rfStart[n], &reStart[n], &rvStart[n]);CHKERRQ(ierr);
4011   }
4012   ierr = MPI_Type_free(&depthType);CHKERRQ(ierr);
4013   ierr = PetscSFDestroy(&sfProcess);CHKERRQ(ierr);
4014   /* Calculate new point SF */
4015   ierr = PetscMalloc(numLeavesNew * sizeof(PetscInt),    &localPointsNew);CHKERRQ(ierr);
4016   ierr = PetscMalloc(numLeavesNew * sizeof(PetscSFNode), &remotePointsNew);CHKERRQ(ierr);
4017   ierr = ISGetIndices(processRanks, &neighbors);CHKERRQ(ierr);
4018   for (l = 0, m = 0; l < numLeaves; ++l) {
4019     PetscInt    p     = localPoints[l];
4020     PetscInt    rp    = remotePoints[l].index, n;
4021     PetscMPIInt rrank = remotePoints[l].rank;
4022 
4023     ierr = PetscFindInt(rrank, numNeighbors, neighbors, &n);CHKERRQ(ierr);
4024     if (n < 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Could not locate remote rank %d", rrank);
4025     switch (refiner) {
4026     case 1:
4027       /* Simplicial 2D */
4028       if ((p >= vStart) && (p < vEnd)) {
4029         /* Old vertices stay the same */
4030         localPointsNew[m]        = vStartNew     + (p  - vStart);
4031         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
4032         remotePointsNew[m].rank  = rrank;
4033         ++m;
4034       } else if ((p >= fStart) && (p < fEnd)) {
4035         /* Old faces add new faces and vertex */
4036         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - fStart);
4037         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - rfStart[n]);
4038         remotePointsNew[m].rank  = rrank;
4039         ++m;
4040         for (r = 0; r < 2; ++r, ++m) {
4041           localPointsNew[m]        = fStartNew     + (p  - fStart)*2     + r;
4042           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*2 + r;
4043           remotePointsNew[m].rank  = rrank;
4044         }
4045       } else if ((p >= cStart) && (p < cEnd)) {
4046         /* Old cells add new cells and interior faces */
4047         for (r = 0; r < 4; ++r, ++m) {
4048           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
4049           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
4050           remotePointsNew[m].rank  = rrank;
4051         }
4052         for (r = 0; r < 3; ++r, ++m) {
4053           localPointsNew[m]        = fStartNew     + (fEnd - fStart)*2                    + (p  - cStart)*3     + r;
4054           remotePointsNew[m].index = rfStartNew[n] + rdepthSizeOld[n*(depth+1)+depth-1]*2 + (rp - rcStart[n])*3 + r;
4055           remotePointsNew[m].rank  = rrank;
4056         }
4057       }
4058       break;
4059     case 2:
4060       /* Hex 2D */
4061       if ((p >= vStart) && (p < vEnd)) {
4062         /* Old vertices stay the same */
4063         localPointsNew[m]        = vStartNew     + (p  - vStart);
4064         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
4065         remotePointsNew[m].rank  = rrank;
4066         ++m;
4067       } else if ((p >= fStart) && (p < fEnd)) {
4068         /* Old faces add new faces and vertex */
4069         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - fStart);
4070         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - rfStart[n]);
4071         remotePointsNew[m].rank  = rrank;
4072         ++m;
4073         for (r = 0; r < 2; ++r, ++m) {
4074           localPointsNew[m]        = fStartNew     + (p  - fStart)*2     + r;
4075           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*2 + r;
4076           remotePointsNew[m].rank  = rrank;
4077         }
4078       } else if ((p >= cStart) && (p < cEnd)) {
4079         /* Old cells add new cells, interior faces, and vertex */
4080         for (r = 0; r < 4; ++r, ++m) {
4081           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
4082           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
4083           remotePointsNew[m].rank  = rrank;
4084         }
4085         for (r = 0; r < 4; ++r, ++m) {
4086           localPointsNew[m]        = fStartNew     + (fEnd - fStart)*2                    + (p  - cStart)*4     + r;
4087           remotePointsNew[m].index = rfStartNew[n] + rdepthSizeOld[n*(depth+1)+depth-1]*2 + (rp - rcStart[n])*4 + r;
4088           remotePointsNew[m].rank  = rrank;
4089         }
4090         for (r = 0; r < 1; ++r, ++m) {
4091           localPointsNew[m]        = vStartNew     + (fEnd - fStart)                    + (p  - cStart)     + r;
4092           remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+depth-1] + (rp - rcStart[n]) + r;
4093           remotePointsNew[m].rank  = rrank;
4094         }
4095       }
4096       break;
4097     case 3:
4098       /* Hybrid simplicial 2D */
4099       if ((p >= vStart) && (p < vEnd)) {
4100         /* Old vertices stay the same */
4101         localPointsNew[m]        = vStartNew     + (p  - vStart);
4102         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
4103         remotePointsNew[m].rank  = rrank;
4104         ++m;
4105       } else if ((p >= fStart) && (p < fMax)) {
4106         /* Old interior faces add new faces and vertex */
4107         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - fStart);
4108         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - rfStart[n]);
4109         remotePointsNew[m].rank  = rrank;
4110         ++m;
4111         for (r = 0; r < 2; ++r, ++m) {
4112           localPointsNew[m]        = fStartNew     + (p  - fStart)*2     + r;
4113           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*2 + r;
4114           remotePointsNew[m].rank  = rrank;
4115         }
4116       } else if ((p >= fMax) && (p < fEnd)) {
4117         /* Old hybrid faces stay the same */
4118         localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (p  - fMax);
4119         remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*2 + (rp - rdepthMaxOld[n*(depth+1)+depth-1]);
4120         remotePointsNew[m].rank  = rrank;
4121         ++m;
4122       } else if ((p >= cStart) && (p < cMax)) {
4123         /* Old interior cells add new cells and interior faces */
4124         for (r = 0; r < 4; ++r, ++m) {
4125           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
4126           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
4127           remotePointsNew[m].rank  = rrank;
4128         }
4129         for (r = 0; r < 3; ++r, ++m) {
4130           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (p  - cStart)*3     + r;
4131           remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*2 + (rp - rcStart[n])*3 + r;
4132           remotePointsNew[m].rank  = rrank;
4133         }
4134       } else if ((p >= cStart) && (p < cMax)) {
4135         /* Old hybrid cells add new cells and hybrid face */
4136         for (r = 0; r < 2; ++r, ++m) {
4137           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
4138           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
4139           remotePointsNew[m].rank  = rrank;
4140         }
4141         localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (cMax                            - cStart)*3     + (p  - cMax);
4142         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]);
4143         remotePointsNew[m].rank  = rrank;
4144         ++m;
4145       }
4146       break;
4147     case 5:
4148       /* Simplicial 3D */
4149       if ((p >= vStart) && (p < vEnd)) {
4150         /* Old vertices stay the same */
4151         localPointsNew[m]        = vStartNew     + (p  - vStart);
4152         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
4153         remotePointsNew[m].rank  = rrank;
4154         ++m;
4155       } else if ((p >= eStart) && (p < eEnd)) {
4156         /* Old edges add new edges and vertex */
4157         for (r = 0; r < 2; ++r, ++m) {
4158           localPointsNew[m]        = eStartNew     + (p  - eStart)*2     + r;
4159           remotePointsNew[m].index = reStartNew[n] + (rp - reStart[n])*2 + r;
4160           remotePointsNew[m].rank  = rrank;
4161         }
4162         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - eStart);
4163         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - reStart[n]);
4164         remotePointsNew[m].rank  = rrank;
4165         ++m;
4166       } else if ((p >= fStart) && (p < fEnd)) {
4167         /* Old faces add new faces and face edges */
4168         for (r = 0; r < 4; ++r, ++m) {
4169           localPointsNew[m]        = fStartNew     + (p  - fStart)*4     + r;
4170           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*4 + r;
4171           remotePointsNew[m].rank  = rrank;
4172         }
4173         for (r = 0; r < 3; ++r, ++m) {
4174           localPointsNew[m]        = eStartNew     + (eEnd - eStart)*2              + (p  - fStart)*3     + r;
4175           remotePointsNew[m].index = reStartNew[n] + rdepthSizeOld[n*(depth+1)+1]*2 + (rp - rfStart[n])*3 + r;
4176           remotePointsNew[m].rank  = rrank;
4177         }
4178       } else if ((p >= cStart) && (p < cEnd)) {
4179         /* Old cells add new cells and interior faces and edges */
4180         for (r = 0; r < 8; ++r, ++m) {
4181           localPointsNew[m]        = cStartNew     + (p  - cStart)*8     + r;
4182           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*8 + r;
4183           remotePointsNew[m].rank  = rrank;
4184         }
4185         for (r = 0; r < 8; ++r, ++m) {
4186           localPointsNew[m]        = fStartNew     + (fEnd - fStart)*4                    + (p  - cStart)*8     + r;
4187           remotePointsNew[m].index = rfStartNew[n] + rdepthSizeOld[n*(depth+1)+depth-1]*4 + (rp - rcStart[n])*8 + r;
4188           remotePointsNew[m].rank  = rrank;
4189         }
4190         for (r = 0; r < 1; ++r, ++m) {
4191           localPointsNew[m]        = eStartNew     + (eEnd - eStart)*2              + (fEnd - fStart)*3                    + (p  - cStart)*1     + r;
4192           remotePointsNew[m].index = reStartNew[n] + rdepthSizeOld[n*(depth+1)+1]*2 + rdepthSizeOld[n*(depth+1)+depth-1]*3 + (rp - rcStart[n])*1 + r;
4193           remotePointsNew[m].rank  = rrank;
4194         }
4195       }
4196       break;
4197     case 7:
4198       /* Hybrid Simplicial 3D */
4199       if ((p >= vStart) && (p < vEnd)) {
4200         /* Interior vertices stay the same */
4201         localPointsNew[m]        = vStartNew     + (p  - vStart);
4202         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
4203         remotePointsNew[m].rank  = rrank;
4204         ++m;
4205       } else if ((p >= eStart) && (p < eMax)) {
4206         /* Interior edges add new edges and vertex */
4207         for (r = 0; r < 2; ++r, ++m) {
4208           localPointsNew[m]        = eStartNew     + (p  - eStart)*2     + r;
4209           remotePointsNew[m].index = reStartNew[n] + (rp - reStart[n])*2 + r;
4210           remotePointsNew[m].rank  = rrank;
4211         }
4212         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - eStart);
4213         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - reStart[n]);
4214         remotePointsNew[m].rank  = rrank;
4215         ++m;
4216       } else if ((p >= eMax) && (p < eEnd)) {
4217         /* Hybrid edges stay the same */
4218         localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (fMax                              - fStart)*3     + (cMax                            - cStart)     + (p  - eMax);
4219         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]);
4220         remotePointsNew[m].rank  = rrank;
4221         ++m;
4222       } else if ((p >= fStart) && (p < fMax)) {
4223         /* Interior faces add new faces and edges */
4224         for (r = 0; r < 4; ++r, ++m) {
4225           localPointsNew[m]        = fStartNew     + (p  - fStart)*4     + r;
4226           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*4 + r;
4227           remotePointsNew[m].rank  = rrank;
4228         }
4229         for (r = 0; r < 3; ++r, ++m) {
4230           localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (p  - fStart)*3     + r;
4231           remotePointsNew[m].index = reStartNew[n] + (rdepthMaxOld[n*(depth+1)+1] - reStart[n])*2 + (rp - rfStart[n])*3 + r;
4232           remotePointsNew[m].rank  = rrank;
4233         }
4234       } else if ((p >= fMax) && (p < fEnd)) {
4235         /* Hybrid faces add new faces and edges */
4236         for (r = 0; r < 2; ++r, ++m) {
4237           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*4     + (cMax                            - cStart)*8     + (p  - fStart)*2     + r;
4238           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;
4239           remotePointsNew[m].rank  = rrank;
4240         }
4241         localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (fMax                              - fStart)     + (cMax                            - cStart)     + (fEnd                                          - fMax);
4242         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]);
4243         remotePointsNew[m].rank  = rrank;
4244       } else if ((p >= cStart) && (p < cMax)) {
4245         /* Interior cells add new cells, faces, and edges */
4246         for (r = 0; r < 8; ++r, ++m) {
4247           localPointsNew[m]        = cStartNew     + (p  - cStart)*8     + r;
4248           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*8 + r;
4249           remotePointsNew[m].rank  = rrank;
4250         }
4251         for (r = 0; r < 8; ++r, ++m) {
4252           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*4     + (p  - cStart)*8     + r;
4253           remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*4 + (rp - rcStart[n])*8 + r;
4254           remotePointsNew[m].rank  = rrank;
4255         }
4256         localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (fMax                              - fStart)*3     + (p  - cStart)*1     + r;
4257         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;
4258         remotePointsNew[m].rank  = rrank;
4259       } else if ((p >= cMax) && (p < cEnd)) {
4260         /* Hybrid cells add new cells and faces */
4261         for (r = 0; r < 4; ++r, ++m) {
4262           localPointsNew[m]        = cStartNew     + (cMax                            - cStart)*8     + (p  - cMax)*4                            + r;
4263           remotePointsNew[m].index = rcStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth] - rcStart[n])*8 + (rp - rdepthMaxOld[n*(depth+1)+depth])*4 + r;
4264           remotePointsNew[m].rank  = rrank;
4265         }
4266         for (r = 0; r < 3; ++r, ++m) {
4267           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*4     + (cMax                            - cStart)*8     + (fEnd                                          - fMax)*4                              + (p  - cMax)*3                            + r;
4268           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;
4269           remotePointsNew[m].rank  = rrank;
4270         }
4271       }
4272       break;
4273     case 6:
4274       /* Hex 3D */
4275       if ((p >= vStart) && (p < vEnd)) {
4276         /* Old vertices stay the same */
4277         localPointsNew[m]        = vStartNew     + (p  - vStart);
4278         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
4279         remotePointsNew[m].rank  = rrank;
4280         ++m;
4281       } else if ((p >= eStart) && (p < eEnd)) {
4282         /* Old edges add new edges and vertex */
4283         for (r = 0; r < 2; ++r, ++m) {
4284           localPointsNew[m]        = eStartNew     + (p  - eStart)*2     + r;
4285           remotePointsNew[m].index = reStartNew[n] + (rp - reStart[n])*2 + r;
4286           remotePointsNew[m].rank  = rrank;
4287         }
4288         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - eStart);
4289         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - reStart[n]);
4290         remotePointsNew[m].rank  = rrank;
4291         ++m;
4292       } else if ((p >= fStart) && (p < fEnd)) {
4293         /* Old faces add new faces, edges, and vertex */
4294         for (r = 0; r < 4; ++r, ++m) {
4295           localPointsNew[m]        = fStartNew     + (p  - fStart)*4     + r;
4296           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*4 + r;
4297           remotePointsNew[m].rank  = rrank;
4298         }
4299         for (r = 0; r < 4; ++r, ++m) {
4300           localPointsNew[m]        = eStartNew     + (eEnd - eStart)*2              + (p  - fStart)*4     + r;
4301           remotePointsNew[m].index = reStartNew[n] + rdepthSizeOld[n*(depth+1)+1]*2 + (rp - rfStart[n])*4 + r;
4302           remotePointsNew[m].rank  = rrank;
4303         }
4304         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (eEnd - eStart)              + (p  - fStart);
4305         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + rdepthSizeOld[n*(depth+1)+1] + (rp - rfStart[n]);
4306         remotePointsNew[m].rank  = rrank;
4307         ++m;
4308       } else if ((p >= cStart) && (p < cEnd)) {
4309         /* Old cells add new cells, faces, edges, and vertex */
4310         for (r = 0; r < 8; ++r, ++m) {
4311           localPointsNew[m]        = cStartNew     + (p  - cStart)*8     + r;
4312           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*8 + r;
4313           remotePointsNew[m].rank  = rrank;
4314         }
4315         for (r = 0; r < 12; ++r, ++m) {
4316           localPointsNew[m]        = fStartNew     + (fEnd - fStart)*4                    + (p  - cStart)*12     + r;
4317           remotePointsNew[m].index = rfStartNew[n] + rdepthSizeOld[n*(depth+1)+depth-1]*4 + (rp - rcStart[n])*12 + r;
4318           remotePointsNew[m].rank  = rrank;
4319         }
4320         for (r = 0; r < 6; ++r, ++m) {
4321           localPointsNew[m]        = eStartNew     + (eEnd - eStart)*2              + (fEnd - fStart)*4                    + (p  - cStart)*6     + r;
4322           remotePointsNew[m].index = reStartNew[n] + rdepthSizeOld[n*(depth+1)+1]*2 + rdepthSizeOld[n*(depth+1)+depth-1]*4 + (rp - rcStart[n])*6 + r;
4323           remotePointsNew[m].rank  = rrank;
4324         }
4325         for (r = 0; r < 1; ++r, ++m) {
4326           localPointsNew[m]        = vStartNew     + (eEnd - eStart)              + (fEnd - fStart)                    + (p  - cStart)     + r;
4327           remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+1] + rdepthSizeOld[n*(depth+1)+depth-1] + (rp - rcStart[n]) + r;
4328           remotePointsNew[m].rank  = rrank;
4329         }
4330       }
4331       break;
4332     default:
4333       SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
4334     }
4335   }
4336   ierr = ISRestoreIndices(processRanks, &neighbors);CHKERRQ(ierr);
4337   ierr = ISDestroy(&processRanks);CHKERRQ(ierr);
4338   ierr = PetscSFSetGraph(sfNew, pEndNew-pStartNew, numLeavesNew, localPointsNew, PETSC_OWN_POINTER, remotePointsNew, PETSC_OWN_POINTER);CHKERRQ(ierr);
4339   ierr = PetscFree5(rdepthSize,rvStartNew,reStartNew,rfStartNew,rcStartNew);CHKERRQ(ierr);
4340   ierr = PetscFree7(depthSizeOld,rdepthSizeOld,rdepthMaxOld,rvStart,reStart,rfStart,rcStart);CHKERRQ(ierr);
4341   PetscFunctionReturn(0);
4342 }
4343 
4344 #undef __FUNCT__
4345 #define __FUNCT__ "CellRefinerCreateLabels"
4346 PetscErrorCode CellRefinerCreateLabels(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
4347 {
4348   PetscInt       numLabels, l;
4349   PetscInt       depth, newp, cStart, cStartNew = 0, cEnd, cMax, vStart, vStartNew = 0, vEnd, vMax, fStart, fStartNew = 0, fEnd, fMax, eStart, eStartNew = 0, eEnd, eMax, r;
4350   PetscErrorCode ierr;
4351 
4352   PetscFunctionBegin;
4353   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
4354   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
4355   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
4356   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
4357   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
4358   if (refiner) {ierr = GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);CHKERRQ(ierr);}
4359   ierr = DMPlexGetNumLabels(dm, &numLabels);CHKERRQ(ierr);
4360   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
4361   switch (refiner) {
4362   case 0: break;
4363   case 7:
4364   case 8:
4365     if (eMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No edge maximum specified in hybrid mesh");
4366   case 3:
4367   case 4:
4368     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
4369     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
4370   }
4371   for (l = 0; l < numLabels; ++l) {
4372     DMLabel         label, labelNew;
4373     const char     *lname;
4374     PetscBool       isDepth;
4375     IS              valueIS;
4376     const PetscInt *values;
4377     PetscInt        numValues, val;
4378 
4379     ierr = DMPlexGetLabelName(dm, l, &lname);CHKERRQ(ierr);
4380     ierr = PetscStrcmp(lname, "depth", &isDepth);CHKERRQ(ierr);
4381     if (isDepth) continue;
4382     ierr = DMPlexCreateLabel(rdm, lname);CHKERRQ(ierr);
4383     ierr = DMPlexGetLabel(dm, lname, &label);CHKERRQ(ierr);
4384     ierr = DMPlexGetLabel(rdm, lname, &labelNew);CHKERRQ(ierr);
4385     ierr = DMLabelGetValueIS(label, &valueIS);CHKERRQ(ierr);
4386     ierr = ISGetLocalSize(valueIS, &numValues);CHKERRQ(ierr);
4387     ierr = ISGetIndices(valueIS, &values);CHKERRQ(ierr);
4388     for (val = 0; val < numValues; ++val) {
4389       IS              pointIS;
4390       const PetscInt *points;
4391       PetscInt        numPoints, n;
4392 
4393       ierr = DMLabelGetStratumIS(label, values[val], &pointIS);CHKERRQ(ierr);
4394       ierr = ISGetLocalSize(pointIS, &numPoints);CHKERRQ(ierr);
4395       ierr = ISGetIndices(pointIS, &points);CHKERRQ(ierr);
4396       for (n = 0; n < numPoints; ++n) {
4397         const PetscInt p = points[n];
4398         switch (refiner) {
4399         case 1:
4400           /* Simplicial 2D */
4401           if ((p >= vStart) && (p < vEnd)) {
4402             /* Old vertices stay the same */
4403             newp = vStartNew + (p - vStart);
4404             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4405           } else if ((p >= fStart) && (p < fEnd)) {
4406             /* Old faces add new faces and vertex */
4407             newp = vStartNew + (vEnd - vStart) + (p - fStart);
4408             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4409             for (r = 0; r < 2; ++r) {
4410               newp = fStartNew + (p - fStart)*2 + r;
4411               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4412             }
4413           } else if ((p >= cStart) && (p < cEnd)) {
4414             /* Old cells add new cells and interior faces */
4415             for (r = 0; r < 4; ++r) {
4416               newp = cStartNew + (p - cStart)*4 + r;
4417               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4418             }
4419             for (r = 0; r < 3; ++r) {
4420               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*3 + r;
4421               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4422             }
4423           }
4424           break;
4425         case 2:
4426           /* Hex 2D */
4427           if ((p >= vStart) && (p < vEnd)) {
4428             /* Old vertices stay the same */
4429             newp = vStartNew + (p - vStart);
4430             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4431           } else if ((p >= fStart) && (p < fEnd)) {
4432             /* Old faces add new faces and vertex */
4433             newp = vStartNew + (vEnd - vStart) + (p - fStart);
4434             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4435             for (r = 0; r < 2; ++r) {
4436               newp = fStartNew + (p - fStart)*2 + r;
4437               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4438             }
4439           } else if ((p >= cStart) && (p < cEnd)) {
4440             /* Old cells add new cells and interior faces and vertex */
4441             for (r = 0; r < 4; ++r) {
4442               newp = cStartNew + (p - cStart)*4 + r;
4443               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4444             }
4445             for (r = 0; r < 4; ++r) {
4446               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*4 + r;
4447               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4448             }
4449             newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (p - cStart);
4450             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4451           }
4452           break;
4453         case 3:
4454           /* Hybrid simplicial 2D */
4455           if ((p >= vStart) && (p < vEnd)) {
4456             /* Old vertices stay the same */
4457             newp = vStartNew + (p - vStart);
4458             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4459           } else if ((p >= fStart) && (p < fMax)) {
4460             /* Old interior faces add new faces and vertex */
4461             newp = vStartNew + (vEnd - vStart) + (p - fStart);
4462             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4463             for (r = 0; r < 2; ++r) {
4464               newp = fStartNew + (p - fStart)*2 + r;
4465               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4466             }
4467           } else if ((p >= fMax) && (p < fEnd)) {
4468             /* Old hybrid faces stay the same */
4469             newp = fStartNew + (fMax - fStart)*2 + (p - fMax);
4470             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4471           } else if ((p >= cStart) && (p < cMax)) {
4472             /* Old interior cells add new cells and interior faces */
4473             for (r = 0; r < 4; ++r) {
4474               newp = cStartNew + (p - cStart)*4 + r;
4475               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4476             }
4477             for (r = 0; r < 3; ++r) {
4478               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*3 + r;
4479               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4480             }
4481           } else if ((p >= cMax) && (p < cEnd)) {
4482             /* Old hybrid cells add new cells and hybrid face */
4483             for (r = 0; r < 2; ++r) {
4484               newp = cStartNew + (cMax - cStart)*4 + (p - cMax)*2 + r;
4485               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4486             }
4487             newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (p - cMax);
4488             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4489           }
4490           break;
4491         case 5:
4492           /* Simplicial 3D */
4493           if ((p >= vStart) && (p < vEnd)) {
4494             /* Old vertices stay the same */
4495             newp = vStartNew + (p - vStart);
4496             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4497           } else if ((p >= eStart) && (p < eEnd)) {
4498             /* Old edges add new edges and vertex */
4499             for (r = 0; r < 2; ++r) {
4500               newp = eStartNew + (p - eStart)*2 + r;
4501               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4502             }
4503             newp = vStartNew + (vEnd - vStart) + (p - eStart);
4504             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4505           } else if ((p >= fStart) && (p < fEnd)) {
4506             /* Old faces add new faces and edges */
4507             for (r = 0; r < 4; ++r) {
4508               newp = fStartNew + (p - fStart)*4 + r;
4509               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4510             }
4511             for (r = 0; r < 3; ++r) {
4512               newp = eStartNew + (eEnd - eStart)*2 + (p - fStart)*3 + r;
4513               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4514             }
4515           } else if ((p >= cStart) && (p < cEnd)) {
4516             /* Old cells add new cells and interior faces and edges */
4517             for (r = 0; r < 8; ++r) {
4518               newp = cStartNew + (p - cStart)*8 + r;
4519               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4520             }
4521             for (r = 0; r < 8; ++r) {
4522               newp = fStartNew + (fEnd - fStart)*4 + (p - cStart)*8 + r;
4523               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4524             }
4525             for (r = 0; r < 1; ++r) {
4526               newp = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (p - cStart)*1 + r;
4527               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4528             }
4529           }
4530           break;
4531         case 7:
4532           /* Hybrid Simplicial 3D */
4533           if ((p >= vStart) && (p < vEnd)) {
4534             /* Interior vertices stay the same */
4535             newp = vStartNew + (p - vStart);
4536             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4537           } else if ((p >= eStart) && (p < eMax)) {
4538             /* Interior edges add new edges and vertex */
4539             for (r = 0; r < 2; ++r) {
4540               newp = eStartNew + (p - eStart)*2 + r;
4541               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4542             }
4543             newp = vStartNew + (vEnd - vStart) + (p - eStart);
4544             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4545           } else if ((p >= eMax) && (p < eEnd)) {
4546             /* Hybrid edges stay the same */
4547             newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (p - eMax);
4548             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4549           } else if ((p >= fStart) && (p < fMax)) {
4550             /* Interior faces add new faces and edges */
4551             for (r = 0; r < 4; ++r) {
4552               newp = fStartNew + (p - fStart)*4 + r;
4553               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4554             }
4555             for (r = 0; r < 3; ++r) {
4556               newp = eStartNew + (eMax - eStart)*2 + (p - fStart)*3 + r;
4557               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4558             }
4559           } else if ((p >= fMax) && (p < fEnd)) {
4560             /* Hybrid faces add new faces and edges */
4561             for (r = 0; r < 2; ++r) {
4562               newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (p - fMax)*2 + r;
4563               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4564             }
4565             newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (p - fMax);
4566             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4567           } else if ((p >= cStart) && (p < cMax)) {
4568             /* Interior cells add new cells, faces, and edges */
4569             for (r = 0; r < 8; ++r) {
4570               newp = cStartNew + (p - cStart)*8 + r;
4571               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4572             }
4573             for (r = 0; r < 8; ++r) {
4574               newp = fStartNew + (fMax - fStart)*4 + (p - cStart)*8 + r;
4575               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4576             }
4577             newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (p - cStart);
4578             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4579           } else if ((p >= cMax) && (p < cEnd)) {
4580             /* Hybrid cells add new cells and faces */
4581             for (r = 0; r < 4; ++r) {
4582               newp = cStartNew + (cMax - cStart)*8 + (p - cMax)*4 + r;
4583               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4584             }
4585             for (r = 0; r < 3; ++r) {
4586               newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (p - cMax)*3 + r;
4587               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4588             }
4589           }
4590           break;
4591         case 6:
4592           /* Hex 3D */
4593           if ((p >= vStart) && (p < vEnd)) {
4594             /* Old vertices stay the same */
4595             newp = vStartNew + (p - vStart);
4596             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4597           } else if ((p >= eStart) && (p < eEnd)) {
4598             /* Old edges add new edges and vertex */
4599             for (r = 0; r < 2; ++r) {
4600               newp = eStartNew + (p - eStart)*2 + r;
4601               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4602             }
4603             newp = vStartNew + (vEnd - vStart) + (p - eStart);
4604             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4605           } else if ((p >= fStart) && (p < fEnd)) {
4606             /* Old faces add new faces, edges, and vertex */
4607             for (r = 0; r < 4; ++r) {
4608               newp = fStartNew + (p - fStart)*4 + r;
4609               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4610             }
4611             for (r = 0; r < 4; ++r) {
4612               newp = eStartNew + (eEnd - eStart)*2 + (p - fStart)*4 + r;
4613               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4614             }
4615             newp = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (p - fStart);
4616             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4617           } else if ((p >= cStart) && (p < cEnd)) {
4618             /* Old cells add new cells, faces, edges, and vertex */
4619             for (r = 0; r < 8; ++r) {
4620               newp = cStartNew + (p - cStart)*8 + r;
4621               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4622             }
4623             for (r = 0; r < 12; ++r) {
4624               newp = fStartNew + (fEnd - fStart)*4 + (p - cStart)*12 + r;
4625               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4626             }
4627             for (r = 0; r < 6; ++r) {
4628               newp = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*4 + (p - cStart)*6 + r;
4629               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4630             }
4631             newp = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (fEnd - fStart) + (p - cStart);
4632             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4633           }
4634           break;
4635         default:
4636           SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
4637         }
4638       }
4639       ierr = ISRestoreIndices(pointIS, &points);CHKERRQ(ierr);
4640       ierr = ISDestroy(&pointIS);CHKERRQ(ierr);
4641     }
4642     ierr = ISRestoreIndices(valueIS, &values);CHKERRQ(ierr);
4643     ierr = ISDestroy(&valueIS);CHKERRQ(ierr);
4644     if (0) {
4645       ierr = PetscViewerASCIISynchronizedAllow(PETSC_VIEWER_STDOUT_WORLD, PETSC_TRUE);CHKERRQ(ierr);
4646       ierr = DMLabelView(labelNew, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
4647       ierr = PetscViewerFlush(PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
4648     }
4649   }
4650   PetscFunctionReturn(0);
4651 }
4652 
4653 #undef __FUNCT__
4654 #define __FUNCT__ "DMPlexRefineUniform_Internal"
4655 /* This will only work for interpolated meshes */
4656 PetscErrorCode DMPlexRefineUniform_Internal(DM dm, CellRefiner cellRefiner, DM *dmRefined)
4657 {
4658   DM             rdm;
4659   PetscInt      *depthSize;
4660   PetscInt       dim, depth = 0, d, pStart = 0, pEnd = 0;
4661   PetscErrorCode ierr;
4662 
4663   PetscFunctionBegin;
4664   ierr = DMCreate(PetscObjectComm((PetscObject)dm), &rdm);CHKERRQ(ierr);
4665   ierr = DMSetType(rdm, DMPLEX);CHKERRQ(ierr);
4666   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
4667   ierr = DMPlexSetDimension(rdm, dim);CHKERRQ(ierr);
4668   /* Calculate number of new points of each depth */
4669   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
4670   ierr = PetscMalloc((depth+1) * sizeof(PetscInt), &depthSize);CHKERRQ(ierr);
4671   ierr = PetscMemzero(depthSize, (depth+1) * sizeof(PetscInt));CHKERRQ(ierr);
4672   ierr = CellRefinerGetSizes(cellRefiner, dm, depthSize);CHKERRQ(ierr);
4673   /* Step 1: Set chart */
4674   for (d = 0; d <= depth; ++d) pEnd += depthSize[d];
4675   ierr = DMPlexSetChart(rdm, pStart, pEnd);CHKERRQ(ierr);
4676   /* Step 2: Set cone/support sizes */
4677   ierr = CellRefinerSetConeSizes(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
4678   /* Step 3: Setup refined DM */
4679   ierr = DMSetUp(rdm);CHKERRQ(ierr);
4680   /* Step 4: Set cones and supports */
4681   ierr = CellRefinerSetCones(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
4682   /* Step 5: Stratify */
4683   ierr = DMPlexStratify(rdm);CHKERRQ(ierr);
4684   /* Step 6: Set coordinates for vertices */
4685   ierr = CellRefinerSetCoordinates(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
4686   /* Step 7: Create pointSF */
4687   ierr = CellRefinerCreateSF(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
4688   /* Step 8: Create labels */
4689   ierr = CellRefinerCreateLabels(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
4690   ierr = PetscFree(depthSize);CHKERRQ(ierr);
4691 
4692   *dmRefined = rdm;
4693   PetscFunctionReturn(0);
4694 }
4695 
4696 #undef __FUNCT__
4697 #define __FUNCT__ "DMPlexSetRefinementUniform"
4698 PetscErrorCode DMPlexSetRefinementUniform(DM dm, PetscBool refinementUniform)
4699 {
4700   DM_Plex *mesh = (DM_Plex*) dm->data;
4701 
4702   PetscFunctionBegin;
4703   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4704   mesh->refinementUniform = refinementUniform;
4705   PetscFunctionReturn(0);
4706 }
4707 
4708 #undef __FUNCT__
4709 #define __FUNCT__ "DMPlexGetRefinementUniform"
4710 PetscErrorCode DMPlexGetRefinementUniform(DM dm, PetscBool *refinementUniform)
4711 {
4712   DM_Plex *mesh = (DM_Plex*) dm->data;
4713 
4714   PetscFunctionBegin;
4715   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4716   PetscValidPointer(refinementUniform,  2);
4717   *refinementUniform = mesh->refinementUniform;
4718   PetscFunctionReturn(0);
4719 }
4720 
4721 #undef __FUNCT__
4722 #define __FUNCT__ "DMPlexSetRefinementLimit"
4723 PetscErrorCode DMPlexSetRefinementLimit(DM dm, PetscReal refinementLimit)
4724 {
4725   DM_Plex *mesh = (DM_Plex*) dm->data;
4726 
4727   PetscFunctionBegin;
4728   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4729   mesh->refinementLimit = refinementLimit;
4730   PetscFunctionReturn(0);
4731 }
4732 
4733 #undef __FUNCT__
4734 #define __FUNCT__ "DMPlexGetRefinementLimit"
4735 PetscErrorCode DMPlexGetRefinementLimit(DM dm, PetscReal *refinementLimit)
4736 {
4737   DM_Plex *mesh = (DM_Plex*) dm->data;
4738 
4739   PetscFunctionBegin;
4740   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4741   PetscValidPointer(refinementLimit,  2);
4742   /* if (mesh->refinementLimit < 0) = getMaxVolume()/2.0; */
4743   *refinementLimit = mesh->refinementLimit;
4744   PetscFunctionReturn(0);
4745 }
4746 
4747 #undef __FUNCT__
4748 #define __FUNCT__ "DMPlexGetCellRefiner_Internal"
4749 PetscErrorCode DMPlexGetCellRefiner_Internal(DM dm, CellRefiner *cellRefiner)
4750 {
4751   PetscInt       dim, cStart, cEnd, coneSize, cMax;
4752   PetscErrorCode ierr;
4753 
4754   PetscFunctionBegin;
4755   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
4756   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
4757   if (cEnd <= cStart) {*cellRefiner = 0; PetscFunctionReturn(0);}
4758   ierr = DMPlexGetConeSize(dm, cStart, &coneSize);CHKERRQ(ierr);
4759   ierr = DMPlexGetHybridBounds(dm, &cMax, NULL, NULL, NULL);CHKERRQ(ierr);
4760   switch (dim) {
4761   case 2:
4762     switch (coneSize) {
4763     case 3:
4764       if (cMax >= 0) *cellRefiner = 3; /* Hybrid */
4765       else *cellRefiner = 1; /* Triangular */
4766       break;
4767     case 4:
4768       if (cMax >= 0) *cellRefiner = 4; /* Hybrid */
4769       else *cellRefiner = 2; /* Quadrilateral */
4770       break;
4771     default:
4772       SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown coneSize %d in dimension %d for cell refiner", coneSize, dim);
4773     }
4774     break;
4775   case 3:
4776     switch (coneSize) {
4777     case 4:
4778       if (cMax >= 0) *cellRefiner = 7; /* Hybrid */
4779       else *cellRefiner = 5; /* Tetrahedral */
4780       break;
4781     case 6:
4782       if (cMax >= 0) *cellRefiner = 8; /* Hybrid */
4783       else *cellRefiner = 6; /* hexahedral */
4784       break;
4785     default:
4786       SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown coneSize %d in dimension %d for cell refiner", coneSize, dim);
4787     }
4788     break;
4789   default:
4790     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown dimension %d for cell refiner", dim);
4791   }
4792   PetscFunctionReturn(0);
4793 }
4794