xref: /petsc/src/dm/impls/plex/plexrefine.c (revision d3a1cc758acdc862512368188d4348755ef54bc1)
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 + (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;
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         for (c = 0; c < csize; ++c) if (ccone[c] == f) break;
2920         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]);
2921         supportRef[2+s*2+0] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (support[s] - cMax)*3 + (c-2)%3;
2922         supportRef[2+s*2+1] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (support[s] - cMax)*3 + (c-1)%3;
2923       }
2924       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
2925 #if 1
2926       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid edge [%d, %d)", newp, eMaxNew, eEndNew);
2927       for (p = 0; p < 2+size*2; ++p) {
2928         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);
2929       }
2930 #endif
2931     }
2932     /* Interior vertices have identical supports */
2933     for (v = vStart; v < vEnd; ++v) {
2934       const PetscInt  newp = vStartNew + (v - vStart);
2935       const PetscInt *support, *cone;
2936       PetscInt        size, s;
2937 
2938       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
2939       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
2940       for (s = 0; s < size; ++s) {
2941         PetscInt r = 0;
2942 
2943         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
2944         if (cone[1] == v) r = 1;
2945         if (support[s] < eMax) supportRef[s] = eStartNew + (support[s] - eStart)*2 + r;
2946         else                   supportRef[s] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (support[s] - eMax);
2947       }
2948       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
2949 #if 1
2950       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
2951       for (p = 0; p < size; ++p) {
2952         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);
2953       }
2954 #endif
2955     }
2956     /* Interior edge vertices have 2 + interior face*2 + hybrid face + cells*0/1 supports */
2957     for (e = eStart; e < eMax; ++e) {
2958       const PetscInt  newp = vStartNew + (vEnd - vStart) + (e - eStart);
2959       const PetscInt *cone, *support;
2960       PetscInt       *star = NULL, starSize, faceSize = 0, cellSize = 0, coneSize, size, s;
2961 
2962       ierr          = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
2963       ierr          = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
2964       supportRef[0] = eStartNew + (e - eStart)*2 + 0;
2965       supportRef[1] = eStartNew + (e - eStart)*2 + 1;
2966       for (s = 0; s < size; ++s) {
2967         PetscInt r = 0;
2968 
2969         if (support[s] < fMax) {
2970           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
2971           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
2972           for (r = 0; r < coneSize; ++r) {if (cone[r] == e) break;}
2973           supportRef[2+faceSize+0] = eStartNew + (eMax - eStart)*2 + (support[s] - fStart)*3 + (r+0)%3;
2974           supportRef[2+faceSize+1] = eStartNew + (eMax - eStart)*2 + (support[s] - fStart)*3 + (r+2)%3;
2975           faceSize += 2;
2976         } else {
2977           supportRef[2+faceSize+0] = eStartNew + (eMax - eStart)*2 + (fMax       - fStart)*3 + (cMax - cStart) + (eEnd - eMax) + (support[s] - fMax);
2978           ++faceSize;
2979         }
2980       }
2981       ierr = DMPlexGetTransitiveClosure(dm, e, PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
2982       for (s = 0; s < starSize*2; s += 2) {
2983         const PetscInt *cone, *ornt;
2984         PetscInt        e01, e23;
2985 
2986         if ((star[s] >= cStart) && (star[s] < cMax)) {
2987           /* Check edge 0-1 */
2988           ierr = DMPlexGetCone(dm, star[s], &cone);CHKERRQ(ierr);
2989           ierr = DMPlexGetConeOrientation(dm, star[s], &ornt);CHKERRQ(ierr);
2990           ierr = DMPlexGetCone(dm, cone[0], &cone);CHKERRQ(ierr);
2991           e01  = cone[GetTriEdge_Static(ornt[0], 0)];
2992           /* Check edge 2-3 */
2993           ierr = DMPlexGetCone(dm, star[s], &cone);CHKERRQ(ierr);
2994           ierr = DMPlexGetConeOrientation(dm, star[s], &ornt);CHKERRQ(ierr);
2995           ierr = DMPlexGetCone(dm, cone[2], &cone);CHKERRQ(ierr);
2996           e23  = cone[GetTriEdge_Static(ornt[2], 1)];
2997           if ((e01 == e) || (e23 == e)) {supportRef[2+faceSize+cellSize++] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (star[s] - cStart);}
2998         }
2999       }
3000       ierr = DMPlexRestoreTransitiveClosure(dm, e, PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
3001       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
3002 #if 1
3003       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
3004       for (p = 0; p < 2+faceSize+cellSize; ++p) {
3005         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);
3006       }
3007 #endif
3008     }
3009     ierr = PetscFree(supportRef);CHKERRQ(ierr);
3010     ierr = DMPlexRestoreFaces_Internal(dm, 3, cStart, NULL, NULL, &faces);CHKERRQ(ierr);
3011     break;
3012   case 6:
3013     /* Hex 3D */
3014     /*
3015      Bottom (viewed from top)    Top
3016      1---------2---------2       7---------2---------6
3017      |         |         |       |         |         |
3018      |    B    2    C    |       |    H    2    G    |
3019      |         |         |       |         |         |
3020      3----3----0----1----1       3----3----0----1----1
3021      |         |         |       |         |         |
3022      |    A    0    D    |       |    E    0    F    |
3023      |         |         |       |         |         |
3024      0---------0---------3       4---------0---------5
3025      */
3026     /* All cells have 6 faces: Bottom, Top, Front, Back, Right, Left */
3027     for (c = cStart; c < cEnd; ++c) {
3028       const PetscInt  newp = (c - cStart)*8;
3029       const PetscInt *cone, *ornt;
3030       PetscInt        coneNew[6], orntNew[6];
3031 
3032       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
3033       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
3034       /* A hex */
3035       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], 0);
3036       orntNew[0] = ornt[0];
3037       coneNew[1] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  8; /* AE */
3038       orntNew[1] = 0;
3039       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetQuadSubface_Static(ornt[2], 0);
3040       orntNew[2] = ornt[2];
3041       coneNew[3] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  3; /* AB */
3042       orntNew[3] = 0;
3043       coneNew[4] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  0; /* AD */
3044       orntNew[4] = 0;
3045       coneNew[5] = fStartNew + (cone[5] - fStart)*4 + GetQuadSubface_Static(ornt[5], 0);
3046       orntNew[5] = ornt[5];
3047       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
3048       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
3049 #if 1
3050       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);
3051       for (p = 0; p < 6; ++p) {
3052         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);
3053       }
3054 #endif
3055       /* B hex */
3056       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], 1);
3057       orntNew[0] = ornt[0];
3058       coneNew[1] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 + 11; /* BH */
3059       orntNew[1] = 0;
3060       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  3; /* AB */
3061       orntNew[2] = -3;
3062       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetQuadSubface_Static(ornt[3], 1);
3063       orntNew[3] = ornt[3];
3064       coneNew[4] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  2; /* BC */
3065       orntNew[4] = 0;
3066       coneNew[5] = fStartNew + (cone[5] - fStart)*4 + GetQuadSubface_Static(ornt[5], 3);
3067       orntNew[5] = ornt[5];
3068       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
3069       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
3070 #if 1
3071       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);
3072       for (p = 0; p < 6; ++p) {
3073         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);
3074       }
3075 #endif
3076       /* C hex */
3077       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], 2);
3078       orntNew[0] = ornt[0];
3079       coneNew[1] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 + 10; /* CG */
3080       orntNew[1] = 0;
3081       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  1; /* CD */
3082       orntNew[2] = 0;
3083       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetQuadSubface_Static(ornt[3], 0);
3084       orntNew[3] = ornt[3];
3085       coneNew[4] = fStartNew + (cone[4] - fStart)*4 + GetQuadSubface_Static(ornt[4], 1);
3086       orntNew[4] = ornt[4];
3087       coneNew[5] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  2; /* BC */
3088       orntNew[5] = -3;
3089       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
3090       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
3091 #if 1
3092       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);
3093       for (p = 0; p < 6; ++p) {
3094         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);
3095       }
3096 #endif
3097       /* D hex */
3098       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], 3);
3099       orntNew[0] = ornt[0];
3100       coneNew[1] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  9; /* DF */
3101       orntNew[1] = 0;
3102       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetQuadSubface_Static(ornt[2], 1);
3103       orntNew[2] = ornt[2];
3104       coneNew[3] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  1; /* CD */
3105       orntNew[3] = -3;
3106       coneNew[4] = fStartNew + (cone[4] - fStart)*4 + GetQuadSubface_Static(ornt[4], 0);
3107       orntNew[4] = ornt[4];
3108       coneNew[5] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  0; /* AD */
3109       orntNew[5] = -3;
3110       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
3111       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
3112 #if 1
3113       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);
3114       for (p = 0; p < 6; ++p) {
3115         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);
3116       }
3117 #endif
3118       /* E hex */
3119       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  8; /* AE */
3120       orntNew[0] = -3;
3121       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], 0);
3122       orntNew[1] = ornt[1];
3123       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetQuadSubface_Static(ornt[2], 3);
3124       orntNew[2] = ornt[2];
3125       coneNew[3] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  7; /* EH */
3126       orntNew[3] = 0;
3127       coneNew[4] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  4; /* EF */
3128       orntNew[4] = 0;
3129       coneNew[5] = fStartNew + (cone[5] - fStart)*4 + GetQuadSubface_Static(ornt[5], 1);
3130       orntNew[5] = ornt[5];
3131       ierr       = DMPlexSetCone(rdm, newp+4, coneNew);CHKERRQ(ierr);
3132       ierr       = DMPlexSetConeOrientation(rdm, newp+4, orntNew);CHKERRQ(ierr);
3133 #if 1
3134       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);
3135       for (p = 0; p < 6; ++p) {
3136         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);
3137       }
3138 #endif
3139       /* F hex */
3140       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  9; /* DF */
3141       orntNew[0] = -3;
3142       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], 1);
3143       orntNew[1] = ornt[1];
3144       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetQuadSubface_Static(ornt[2], 2);
3145       orntNew[2] = ornt[2];
3146       coneNew[3] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  5; /* FG */
3147       orntNew[3] = 0;
3148       coneNew[4] = fStartNew + (cone[4] - fStart)*4 + GetQuadSubface_Static(ornt[4], 3);
3149       orntNew[4] = ornt[4];
3150       coneNew[5] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  4; /* EF */
3151       orntNew[5] = -3;
3152       ierr       = DMPlexSetCone(rdm, newp+5, coneNew);CHKERRQ(ierr);
3153       ierr       = DMPlexSetConeOrientation(rdm, newp+5, orntNew);CHKERRQ(ierr);
3154 #if 1
3155       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);
3156       for (p = 0; p < 6; ++p) {
3157         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);
3158       }
3159 #endif
3160       /* G hex */
3161       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 + 10; /* CG */
3162       orntNew[0] = -3;
3163       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], 2);
3164       orntNew[1] = ornt[1];
3165       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  5; /* FG */
3166       orntNew[2] = -3;
3167       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetQuadSubface_Static(ornt[3], 3);
3168       orntNew[3] = ornt[3];
3169       coneNew[4] = fStartNew + (cone[4] - fStart)*4 + GetQuadSubface_Static(ornt[4], 2);
3170       orntNew[4] = ornt[4];
3171       coneNew[5] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  6; /* GH */
3172       orntNew[5] = 0;
3173       ierr       = DMPlexSetCone(rdm, newp+6, coneNew);CHKERRQ(ierr);
3174       ierr       = DMPlexSetConeOrientation(rdm, newp+6, orntNew);CHKERRQ(ierr);
3175 #if 1
3176       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);
3177       for (p = 0; p < 6; ++p) {
3178         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);
3179       }
3180 #endif
3181       /* H hex */
3182       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 + 11; /* BH */
3183       orntNew[0] = -3;
3184       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], 3);
3185       orntNew[1] = ornt[1];
3186       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  7; /* EH */
3187       orntNew[2] = -3;
3188       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetQuadSubface_Static(ornt[3], 2);
3189       orntNew[3] = ornt[3];
3190       coneNew[4] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  6; /* GH */
3191       orntNew[4] = -3;
3192       coneNew[5] = fStartNew + (cone[5] - fStart)*4 + GetQuadSubface_Static(ornt[5], 2);
3193       orntNew[5] = ornt[5];
3194       ierr       = DMPlexSetCone(rdm, newp+7, coneNew);CHKERRQ(ierr);
3195       ierr       = DMPlexSetConeOrientation(rdm, newp+7, orntNew);CHKERRQ(ierr);
3196 #if 1
3197       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);
3198       for (p = 0; p < 6; ++p) {
3199         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);
3200       }
3201 #endif
3202     }
3203     /* Split faces have 4 edges and the same cells as the parent */
3204     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
3205     ierr = PetscMalloc((4 + maxSupportSize*2) * sizeof(PetscInt), &supportRef);CHKERRQ(ierr);
3206     for (f = fStart; f < fEnd; ++f) {
3207       for (r = 0; r < 4; ++r) {
3208         /* TODO: This can come from GetFaces_Internal() */
3209         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};
3210         const PetscInt  newp = fStartNew + (f - fStart)*4 + r;
3211         const PetscInt *cone, *ornt, *support;
3212         PetscInt        coneNew[4], orntNew[4], coneSize, c, supportSize, s;
3213 
3214         ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
3215         ierr = DMPlexGetConeOrientation(dm, f, &ornt);CHKERRQ(ierr);
3216         coneNew[0] = eStartNew + (cone[(r+3)%4] - eStart)*2 + (ornt[(r+3)%4] < 0 ? 0 : 1);
3217         orntNew[0] = ornt[(r+3)%4];
3218         coneNew[1] = eStartNew + (cone[r]       - eStart)*2 + (ornt[r] < 0 ? 1 : 0);
3219         orntNew[1] = ornt[r];
3220         coneNew[2] = eStartNew + (eEnd - eStart)*2 + (f - fStart)*4 + r;
3221         orntNew[2] = 0;
3222         coneNew[3] = eStartNew + (eEnd - eStart)*2 + (f - fStart)*4 + (r+3)%4;
3223         orntNew[3] = -2;
3224         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3225         ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3226 #if 1
3227         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
3228         for (p = 0; p < 4; ++p) {
3229           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);
3230         }
3231 #endif
3232         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
3233         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
3234         for (s = 0; s < supportSize; ++s) {
3235           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
3236           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
3237           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
3238           for (c = 0; c < coneSize; ++c) {
3239             if (cone[c] == f) break;
3240           }
3241           supportRef[s] = cStartNew + (support[s] - cStart)*8 + newCells[c*4+GetQuadSubface_Static(ornt[c], r)];
3242         }
3243         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
3244 #if 1
3245         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
3246         for (p = 0; p < supportSize; ++p) {
3247           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);
3248         }
3249 #endif
3250       }
3251     }
3252     /* Interior faces have 4 edges and 2 cells */
3253     for (c = cStart; c < cEnd; ++c) {
3254       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};
3255       const PetscInt *cone, *ornt;
3256       PetscInt        newp, coneNew[4], orntNew[4], supportNew[2];
3257 
3258       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
3259       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
3260       /* A-D face */
3261       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 0;
3262       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*4 + GetQuadEdge_Static(ornt[2], 0);
3263       orntNew[0] = -2;
3264       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*4 + GetQuadEdge_Static(ornt[0], 3);
3265       orntNew[1] = 0;
3266       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 0;
3267       orntNew[2] = 0;
3268       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 2;
3269       orntNew[3] = -2;
3270       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3271       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3272 #if 1
3273       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
3274       for (p = 0; p < 4; ++p) {
3275         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);
3276       }
3277 #endif
3278       /* C-D face */
3279       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 1;
3280       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[4] - fStart)*4 + GetQuadEdge_Static(ornt[4], 0);
3281       orntNew[0] = -2;
3282       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*4 + GetQuadEdge_Static(ornt[0], 2);
3283       orntNew[1] = 0;
3284       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 0;
3285       orntNew[2] = 0;
3286       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 4;
3287       orntNew[3] = -2;
3288       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3289       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3290 #if 1
3291       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
3292       for (p = 0; p < 4; ++p) {
3293         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);
3294       }
3295 #endif
3296       /* B-C face */
3297       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 2;
3298       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*4 + GetQuadEdge_Static(ornt[0], 1);
3299       orntNew[0] = -2;
3300       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*4 + GetQuadEdge_Static(ornt[3], 0);
3301       orntNew[1] = 0;
3302       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 3;
3303       orntNew[2] = 0;
3304       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 0;
3305       orntNew[3] = -2;
3306       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3307       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3308 #if 1
3309       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
3310       for (p = 0; p < 4; ++p) {
3311         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);
3312       }
3313 #endif
3314       /* A-B face */
3315       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 3;
3316       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*4 + GetQuadEdge_Static(ornt[0], 0);
3317       orntNew[0] = -2;
3318       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[5] - fStart)*4 + GetQuadEdge_Static(ornt[5], 3);
3319       orntNew[1] = 0;
3320       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 5;
3321       orntNew[2] = 0;
3322       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 0;
3323       orntNew[3] = -2;
3324       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3325       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3326 #if 1
3327       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
3328       for (p = 0; p < 4; ++p) {
3329         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);
3330       }
3331 #endif
3332       /* E-F face */
3333       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 4;
3334       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*4 + GetQuadEdge_Static(ornt[2], 2);
3335       orntNew[0] = -2;
3336       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*4 + GetQuadEdge_Static(ornt[1], 0);
3337       orntNew[1] = 0;
3338       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 1;
3339       orntNew[2] = 0;
3340       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 2;
3341       orntNew[3] = -2;
3342       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3343       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3344 #if 1
3345       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
3346       for (p = 0; p < 4; ++p) {
3347         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);
3348       }
3349 #endif
3350       /* F-G face */
3351       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 5;
3352       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[4] - fStart)*4 + GetQuadEdge_Static(ornt[4], 2);
3353       orntNew[0] = -2;
3354       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*4 + GetQuadEdge_Static(ornt[1], 1);
3355       orntNew[1] = 0;
3356       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 1;
3357       orntNew[2] = 0;
3358       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 4;
3359       orntNew[3] = -2;
3360       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3361       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3362 #if 1
3363       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
3364       for (p = 0; p < 4; ++p) {
3365         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);
3366       }
3367 #endif
3368       /* G-H face */
3369       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 6;
3370       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*4 + GetQuadEdge_Static(ornt[3], 2);
3371       orntNew[0] = -2;
3372       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*4 + GetQuadEdge_Static(ornt[1], 2);
3373       orntNew[1] = 0;
3374       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 1;
3375       orntNew[2] = 0;
3376       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 3;
3377       orntNew[3] = -2;
3378       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3379       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3380 #if 1
3381       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
3382       for (p = 0; p < 4; ++p) {
3383         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);
3384       }
3385 #endif
3386       /* E-H face */
3387       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 7;
3388       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[5] - fStart)*4 + GetQuadEdge_Static(ornt[5], 1);
3389       orntNew[0] = -2;
3390       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*4 + GetQuadEdge_Static(ornt[1], 3);
3391       orntNew[1] = 0;
3392       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 1;
3393       orntNew[2] = 0;
3394       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 5;
3395       orntNew[3] = -2;
3396       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3397       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3398 #if 1
3399       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
3400       for (p = 0; p < 4; ++p) {
3401         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);
3402       }
3403 #endif
3404       /* A-E face */
3405       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 8;
3406       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[5] - fStart)*4 + GetQuadEdge_Static(ornt[5], 0);
3407       orntNew[0] = -2;
3408       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*4 + GetQuadEdge_Static(ornt[2], 3);
3409       orntNew[1] = 0;
3410       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 2;
3411       orntNew[2] = 0;
3412       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 5;
3413       orntNew[3] = -2;
3414       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3415       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3416 #if 1
3417       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
3418       for (p = 0; p < 4; ++p) {
3419         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);
3420       }
3421 #endif
3422       /* D-F face */
3423       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 9;
3424       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*4 + GetQuadEdge_Static(ornt[2], 1);
3425       orntNew[0] = -2;
3426       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[4] - fStart)*4 + GetQuadEdge_Static(ornt[4], 3);
3427       orntNew[1] = 0;
3428       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 4;
3429       orntNew[2] = 0;
3430       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 2;
3431       orntNew[3] = -2;
3432       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3433       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3434 #if 1
3435       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
3436       for (p = 0; p < 4; ++p) {
3437         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);
3438       }
3439 #endif
3440       /* C-G face */
3441       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 10;
3442       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[4] - fStart)*4 + GetQuadEdge_Static(ornt[4], 1);
3443       orntNew[0] = -2;
3444       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*4 + GetQuadEdge_Static(ornt[3], 3);
3445       orntNew[1] = 0;
3446       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 3;
3447       orntNew[2] = 0;
3448       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 4;
3449       orntNew[3] = -2;
3450       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3451       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3452 #if 1
3453       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
3454       for (p = 0; p < 4; ++p) {
3455         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);
3456       }
3457 #endif
3458       /* B-H face */
3459       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 11;
3460       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*4 + GetQuadEdge_Static(ornt[3], 1);
3461       orntNew[0] = -2;
3462       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[5] - fStart)*4 + GetQuadEdge_Static(ornt[5], 2);
3463       orntNew[1] = 0;
3464       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 5;
3465       orntNew[2] = 0;
3466       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 3;
3467       orntNew[3] = -2;
3468       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3469       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3470 #if 1
3471       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
3472       for (p = 0; p < 4; ++p) {
3473         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);
3474       }
3475 #endif
3476       for (r = 0; r < 12; ++r) {
3477         newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + r;
3478         supportNew[0] = cStartNew + (c - cStart)*8 + newCells[r*2+0];
3479         supportNew[1] = cStartNew + (c - cStart)*8 + newCells[r*2+1];
3480         ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3481 #if 1
3482         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
3483         for (p = 0; p < 2; ++p) {
3484           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);
3485         }
3486 #endif
3487       }
3488     }
3489     /* Split edges have 2 vertices and the same faces as the parent */
3490     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
3491     for (e = eStart; e < eEnd; ++e) {
3492       const PetscInt newv = vStartNew + (vEnd - vStart) + (e - eStart);
3493 
3494       for (r = 0; r < 2; ++r) {
3495         const PetscInt  newp = eStartNew + (e - eStart)*2 + r;
3496         const PetscInt *cone, *ornt, *support;
3497         PetscInt        coneNew[2], coneSize, c, supportSize, s;
3498 
3499         ierr             = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
3500         coneNew[0]       = vStartNew + (cone[0] - vStart);
3501         coneNew[1]       = vStartNew + (cone[1] - vStart);
3502         coneNew[(r+1)%2] = newv;
3503         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3504 #if 1
3505         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
3506         for (p = 0; p < 2; ++p) {
3507           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);
3508         }
3509 #endif
3510         ierr = DMPlexGetSupportSize(dm, e, &supportSize);CHKERRQ(ierr);
3511         ierr = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
3512         for (s = 0; s < supportSize; ++s) {
3513           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
3514           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
3515           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
3516           for (c = 0; c < coneSize; ++c) {
3517             if (cone[c] == e) break;
3518           }
3519           supportRef[s] = fStartNew + (support[s] - fStart)*4 + (ornt[c] < 0 ? (c+1-r)%4 : (c+r)%4);
3520         }
3521         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
3522 #if 1
3523         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
3524         for (p = 0; p < supportSize; ++p) {
3525           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);
3526         }
3527 #endif
3528       }
3529     }
3530     /* Face edges have 2 vertices and 2+cells faces */
3531     for (f = fStart; f < fEnd; ++f) {
3532       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};
3533       const PetscInt  newv = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (f - fStart);
3534       const PetscInt *cone, *coneCell, *orntCell, *support;
3535       PetscInt        coneNew[2], coneSize, c, supportSize, s;
3536 
3537       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
3538       for (r = 0; r < 4; ++r) {
3539         const PetscInt newp = eStartNew + (eEnd - eStart)*2 + (f - fStart)*4 + r;
3540 
3541         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r] - eStart);
3542         coneNew[1] = newv;
3543         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3544 #if 1
3545         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
3546         for (p = 0; p < 2; ++p) {
3547           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);
3548         }
3549 #endif
3550         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
3551         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
3552         supportRef[0] = fStartNew + (f - fStart)*4 + r;
3553         supportRef[1] = fStartNew + (f - fStart)*4 + (r+1)%4;
3554         for (s = 0; s < supportSize; ++s) {
3555           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
3556           ierr = DMPlexGetCone(dm, support[s], &coneCell);CHKERRQ(ierr);
3557           ierr = DMPlexGetConeOrientation(dm, support[s], &orntCell);CHKERRQ(ierr);
3558           for (c = 0; c < coneSize; ++c) if (coneCell[c] == f) break;
3559           supportRef[2+s] = fStartNew + (fEnd - fStart)*4 + (support[s] - cStart)*12 + newFaces[c*4 + GetQuadEdge_Static(orntCell[c], r)];
3560         }
3561         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
3562 #if 1
3563         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
3564         for (p = 0; p < 2+supportSize; ++p) {
3565           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);
3566         }
3567 #endif
3568       }
3569     }
3570     /* Cell edges have 2 vertices and 4 faces */
3571     for (c = cStart; c < cEnd; ++c) {
3572       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};
3573       const PetscInt  newv = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (fEnd - fStart) + (c - cStart);
3574       const PetscInt *cone;
3575       PetscInt        coneNew[2], supportNew[4];
3576 
3577       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
3578       for (r = 0; r < 6; ++r) {
3579         const PetscInt newp = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*4 + (c - cStart)*6 + r;
3580 
3581         coneNew[0] = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (cone[r] - fStart);
3582         coneNew[1] = newv;
3583         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3584 #if 1
3585         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
3586         for (p = 0; p < 2; ++p) {
3587           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);
3588         }
3589 #endif
3590         for (f = 0; f < 4; ++f) supportNew[f] = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + newFaces[r*4+f];
3591         ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3592 #if 1
3593         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
3594         for (p = 0; p < 4; ++p) {
3595           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);
3596         }
3597 #endif
3598       }
3599     }
3600     /* Old vertices have identical supports */
3601     for (v = vStart; v < vEnd; ++v) {
3602       const PetscInt  newp = vStartNew + (v - vStart);
3603       const PetscInt *support, *cone;
3604       PetscInt        size, s;
3605 
3606       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
3607       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
3608       for (s = 0; s < size; ++s) {
3609         PetscInt r = 0;
3610 
3611         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
3612         if (cone[1] == v) r = 1;
3613         supportRef[s] = eStartNew + (support[s] - eStart)*2 + r;
3614       }
3615       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
3616 #if 1
3617       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
3618       for (p = 0; p < size; ++p) {
3619         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);
3620       }
3621 #endif
3622     }
3623     /* Edge vertices have 2 + faces supports */
3624     for (e = eStart; e < eEnd; ++e) {
3625       const PetscInt  newp = vStartNew + (vEnd - vStart) + (e - eStart);
3626       const PetscInt *cone, *support;
3627       PetscInt        size, s;
3628 
3629       ierr          = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
3630       ierr          = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
3631       supportRef[0] = eStartNew + (e - eStart)*2 + 0;
3632       supportRef[1] = eStartNew + (e - eStart)*2 + 1;
3633       for (s = 0; s < size; ++s) {
3634         PetscInt r;
3635 
3636         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
3637         for (r = 0; r < 4; ++r) if (cone[r] == e) break;
3638         supportRef[2+s] = eStartNew + (eEnd - eStart)*2 + (support[s] - fStart)*4 + r;
3639       }
3640       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
3641 #if 1
3642       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
3643       for (p = 0; p < 2+size; ++p) {
3644         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);
3645       }
3646 #endif
3647     }
3648     /* Face vertices have 4 + cells supports */
3649     for (f = fStart; f < fEnd; ++f) {
3650       const PetscInt  newp = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (f - fStart);
3651       const PetscInt *cone, *support;
3652       PetscInt        size, s;
3653 
3654       ierr          = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
3655       ierr          = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
3656       for (r = 0; r < 4; ++r) supportRef[r] = eStartNew + (e - eStart)*2 +  (f - fStart)*4 + r;
3657       for (s = 0; s < size; ++s) {
3658         PetscInt r;
3659 
3660         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
3661         for (r = 0; r < 6; ++r) if (cone[r] == f) break;
3662         supportRef[4+s] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*4 + (support[s] - cStart)*6 + r;
3663       }
3664       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
3665 #if 1
3666       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
3667       for (p = 0; p < 4+size; ++p) {
3668         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);
3669       }
3670 #endif
3671     }
3672     /* Cell vertices have 6 supports */
3673     for (c = cStart; c < cEnd; ++c) {
3674       const PetscInt newp = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (fEnd - fStart) + (c - cStart);
3675       PetscInt       supportNew[6];
3676 
3677       for (r = 0; r < 6; ++r) {
3678         supportNew[r] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*4 + (c - cStart)*6 + r;
3679       }
3680       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3681     }
3682     ierr = PetscFree(supportRef);CHKERRQ(ierr);
3683     break;
3684   default:
3685     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
3686   }
3687   PetscFunctionReturn(0);
3688 }
3689 
3690 #undef __FUNCT__
3691 #define __FUNCT__ "CellRefinerSetCoordinates"
3692 PetscErrorCode CellRefinerSetCoordinates(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
3693 {
3694   PetscSection   coordSection, coordSectionNew;
3695   Vec            coordinates, coordinatesNew;
3696   PetscScalar   *coords, *coordsNew;
3697   const PetscInt numVertices = depthSize ? depthSize[0] : 0;
3698   PetscInt       dim, depth, coordSizeNew, cStart, cEnd, c, vStart, vStartNew, vEnd, v, eStart, eEnd, eMax, e, fStart, fEnd, fMax, f;
3699   PetscErrorCode ierr;
3700 
3701   PetscFunctionBegin;
3702   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
3703   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3704   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
3705   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
3706   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
3707   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
3708   ierr = DMPlexGetHybridBounds(dm, NULL, &fMax, &eMax, NULL);CHKERRQ(ierr);
3709   if (refiner) {ierr = GetDepthStart_Private(depth, depthSize, NULL, NULL, NULL, &vStartNew);CHKERRQ(ierr);}
3710   ierr = GetDepthStart_Private(depth, depthSize, NULL, NULL, NULL, &vStartNew);CHKERRQ(ierr);
3711   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
3712   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)dm), &coordSectionNew);CHKERRQ(ierr);
3713   ierr = PetscSectionSetNumFields(coordSectionNew, 1);CHKERRQ(ierr);
3714   ierr = PetscSectionSetFieldComponents(coordSectionNew, 0, dim);CHKERRQ(ierr);
3715   ierr = PetscSectionSetChart(coordSectionNew, vStartNew, vStartNew+numVertices);CHKERRQ(ierr);
3716   if (fMax < 0) fMax = fEnd;
3717   if (eMax < 0) eMax = eEnd;
3718   /* All vertices have the dim coordinates */
3719   for (v = vStartNew; v < vStartNew+numVertices; ++v) {
3720     ierr = PetscSectionSetDof(coordSectionNew, v, dim);CHKERRQ(ierr);
3721     ierr = PetscSectionSetFieldDof(coordSectionNew, v, 0, dim);CHKERRQ(ierr);
3722   }
3723   ierr = PetscSectionSetUp(coordSectionNew);CHKERRQ(ierr);
3724   ierr = DMPlexSetCoordinateSection(rdm, coordSectionNew);CHKERRQ(ierr);
3725   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
3726   ierr = PetscSectionGetStorageSize(coordSectionNew, &coordSizeNew);CHKERRQ(ierr);
3727   ierr = VecCreate(PetscObjectComm((PetscObject)dm), &coordinatesNew);CHKERRQ(ierr);
3728   ierr = PetscObjectSetName((PetscObject) coordinatesNew, "coordinates");CHKERRQ(ierr);
3729   ierr = VecSetSizes(coordinatesNew, coordSizeNew, PETSC_DETERMINE);CHKERRQ(ierr);
3730   ierr = VecSetFromOptions(coordinatesNew);CHKERRQ(ierr);
3731   ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
3732   ierr = VecGetArray(coordinatesNew, &coordsNew);CHKERRQ(ierr);
3733   switch (refiner) {
3734   case 0: break;
3735   case 6: /* Hex 3D */
3736     /* Face vertices have the average of corner coordinates */
3737     for (f = fStart; f < fEnd; ++f) {
3738       const PetscInt newv = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (f - fStart);
3739       PetscInt      *cone = NULL;
3740       PetscInt       closureSize, coneSize = 0, off[8], offnew, p, d;
3741 
3742       ierr = DMPlexGetTransitiveClosure(dm, f, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
3743       for (p = 0; p < closureSize*2; p += 2) {
3744         const PetscInt point = cone[p];
3745         if ((point >= vStart) && (point < vEnd)) cone[coneSize++] = point;
3746       }
3747       for (v = 0; v < coneSize; ++v) {
3748         ierr = PetscSectionGetOffset(coordSection, cone[v], &off[v]);CHKERRQ(ierr);
3749       }
3750       ierr = PetscSectionGetOffset(coordSectionNew, newv, &offnew);CHKERRQ(ierr);
3751       for (d = 0; d < dim; ++d) {
3752         coordsNew[offnew+d] = 0.0;
3753         for (v = 0; v < coneSize; ++v) coordsNew[offnew+d] += coords[off[v]+d];
3754         coordsNew[offnew+d] /= coneSize;
3755       }
3756       ierr = DMPlexRestoreTransitiveClosure(dm, f, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
3757     }
3758   case 2: /* Hex 2D */
3759     /* Cell vertices have the average of corner coordinates */
3760     for (c = cStart; c < cEnd; ++c) {
3761       const PetscInt newv = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (c - cStart) + (dim > 2 ? (fEnd - fStart) : 0);
3762       PetscInt      *cone = NULL;
3763       PetscInt       closureSize, coneSize = 0, off[8], offnew, p, d;
3764 
3765       ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
3766       for (p = 0; p < closureSize*2; p += 2) {
3767         const PetscInt point = cone[p];
3768         if ((point >= vStart) && (point < vEnd)) cone[coneSize++] = point;
3769       }
3770       for (v = 0; v < coneSize; ++v) {
3771         ierr = PetscSectionGetOffset(coordSection, cone[v], &off[v]);CHKERRQ(ierr);
3772       }
3773       ierr = PetscSectionGetOffset(coordSectionNew, newv, &offnew);CHKERRQ(ierr);
3774       for (d = 0; d < dim; ++d) {
3775         coordsNew[offnew+d] = 0.0;
3776         for (v = 0; v < coneSize; ++v) coordsNew[offnew+d] += coords[off[v]+d];
3777         coordsNew[offnew+d] /= coneSize;
3778       }
3779       ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
3780     }
3781   case 1: /* Simplicial 2D */
3782   case 3: /* Hybrid Simplicial 2D */
3783   case 5: /* Simplicial 3D */
3784   case 7: /* Hybrid Simplicial 3D */
3785     /* Edge vertices have the average of endpoint coordinates */
3786     for (e = eStart; e < eMax; ++e) {
3787       const PetscInt  newv = vStartNew + (vEnd - vStart) + (e - eStart);
3788       const PetscInt *cone;
3789       PetscInt        coneSize, offA, offB, offnew, d;
3790 
3791       ierr = DMPlexGetConeSize(dm, e, &coneSize);CHKERRQ(ierr);
3792       if (coneSize != 2) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Edge %d cone should have two vertices, not %d", e, coneSize);
3793       ierr = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
3794       ierr = PetscSectionGetOffset(coordSection, cone[0], &offA);CHKERRQ(ierr);
3795       ierr = PetscSectionGetOffset(coordSection, cone[1], &offB);CHKERRQ(ierr);
3796       ierr = PetscSectionGetOffset(coordSectionNew, newv, &offnew);CHKERRQ(ierr);
3797       for (d = 0; d < dim; ++d) {
3798         coordsNew[offnew+d] = 0.5*(coords[offA+d] + coords[offB+d]);
3799       }
3800     }
3801     /* Old vertices have the same coordinates */
3802     for (v = vStart; v < vEnd; ++v) {
3803       const PetscInt newv = vStartNew + (v - vStart);
3804       PetscInt       off, offnew, d;
3805 
3806       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
3807       ierr = PetscSectionGetOffset(coordSectionNew, newv, &offnew);CHKERRQ(ierr);
3808       for (d = 0; d < dim; ++d) {
3809         coordsNew[offnew+d] = coords[off+d];
3810       }
3811     }
3812     break;
3813   default:
3814     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
3815   }
3816   ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
3817   ierr = VecRestoreArray(coordinatesNew, &coordsNew);CHKERRQ(ierr);
3818   ierr = DMSetCoordinatesLocal(rdm, coordinatesNew);CHKERRQ(ierr);
3819   ierr = VecDestroy(&coordinatesNew);CHKERRQ(ierr);
3820   ierr = PetscSectionDestroy(&coordSectionNew);CHKERRQ(ierr);
3821   PetscFunctionReturn(0);
3822 }
3823 
3824 #undef __FUNCT__
3825 #define __FUNCT__ "DMPlexCreateProcessSF"
3826 PetscErrorCode DMPlexCreateProcessSF(DM dm, PetscSF sfPoint, IS *processRanks, PetscSF *sfProcess)
3827 {
3828   PetscInt           numRoots, numLeaves, l;
3829   const PetscInt    *localPoints;
3830   const PetscSFNode *remotePoints;
3831   PetscInt          *localPointsNew;
3832   PetscSFNode       *remotePointsNew;
3833   PetscInt          *ranks, *ranksNew;
3834   PetscErrorCode     ierr;
3835 
3836   PetscFunctionBegin;
3837   ierr = PetscSFGetGraph(sfPoint, &numRoots, &numLeaves, &localPoints, &remotePoints);CHKERRQ(ierr);
3838   ierr = PetscMalloc(numLeaves * sizeof(PetscInt), &ranks);CHKERRQ(ierr);
3839   for (l = 0; l < numLeaves; ++l) {
3840     ranks[l] = remotePoints[l].rank;
3841   }
3842   ierr = PetscSortRemoveDupsInt(&numLeaves, ranks);CHKERRQ(ierr);
3843   ierr = PetscMalloc(numLeaves * sizeof(PetscInt),    &ranksNew);CHKERRQ(ierr);
3844   ierr = PetscMalloc(numLeaves * sizeof(PetscInt),    &localPointsNew);CHKERRQ(ierr);
3845   ierr = PetscMalloc(numLeaves * sizeof(PetscSFNode), &remotePointsNew);CHKERRQ(ierr);
3846   for (l = 0; l < numLeaves; ++l) {
3847     ranksNew[l]              = ranks[l];
3848     localPointsNew[l]        = l;
3849     remotePointsNew[l].index = 0;
3850     remotePointsNew[l].rank  = ranksNew[l];
3851   }
3852   ierr = PetscFree(ranks);CHKERRQ(ierr);
3853   ierr = ISCreateGeneral(PetscObjectComm((PetscObject)dm), numLeaves, ranksNew, PETSC_OWN_POINTER, processRanks);CHKERRQ(ierr);
3854   ierr = PetscSFCreate(PetscObjectComm((PetscObject)dm), sfProcess);CHKERRQ(ierr);
3855   ierr = PetscSFSetFromOptions(*sfProcess);CHKERRQ(ierr);
3856   ierr = PetscSFSetGraph(*sfProcess, 1, numLeaves, localPointsNew, PETSC_OWN_POINTER, remotePointsNew, PETSC_OWN_POINTER);CHKERRQ(ierr);
3857   PetscFunctionReturn(0);
3858 }
3859 
3860 #undef __FUNCT__
3861 #define __FUNCT__ "CellRefinerCreateSF"
3862 PetscErrorCode CellRefinerCreateSF(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
3863 {
3864   PetscSF            sf, sfNew, sfProcess;
3865   IS                 processRanks;
3866   MPI_Datatype       depthType;
3867   PetscInt           numRoots, numLeaves, numLeavesNew = 0, l, m;
3868   const PetscInt    *localPoints, *neighbors;
3869   const PetscSFNode *remotePoints;
3870   PetscInt          *localPointsNew;
3871   PetscSFNode       *remotePointsNew;
3872   PetscInt          *depthSizeOld, *rdepthSize, *rdepthSizeOld, *rdepthMaxOld, *rvStart, *rvStartNew, *reStart, *reStartNew, *rfStart, *rfStartNew, *rcStart, *rcStartNew;
3873   PetscInt           depth, numNeighbors, pStartNew, pEndNew, cStart, cStartNew, cEnd, cMax, vStart, vStartNew, vEnd, vMax, fStart, fStartNew, fEnd, fMax, eStart, eStartNew, eEnd, eMax, r, n;
3874   PetscErrorCode     ierr;
3875 
3876   PetscFunctionBegin;
3877   ierr = DMPlexGetChart(rdm, &pStartNew, &pEndNew);CHKERRQ(ierr);
3878   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3879   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
3880   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
3881   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
3882   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
3883   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
3884   if (refiner) {ierr = GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);CHKERRQ(ierr);}
3885   ierr = DMGetPointSF(dm, &sf);CHKERRQ(ierr);
3886   ierr = DMGetPointSF(rdm, &sfNew);CHKERRQ(ierr);
3887   /* Caculate size of new SF */
3888   ierr = PetscSFGetGraph(sf, &numRoots, &numLeaves, &localPoints, &remotePoints);CHKERRQ(ierr);
3889   if (numRoots < 0) PetscFunctionReturn(0);
3890   for (l = 0; l < numLeaves; ++l) {
3891     const PetscInt p = localPoints[l];
3892 
3893     switch (refiner) {
3894     case 1:
3895       /* Simplicial 2D */
3896       if ((p >= vStart) && (p < vEnd)) {
3897         /* Old vertices stay the same */
3898         ++numLeavesNew;
3899       } else if ((p >= fStart) && (p < fEnd)) {
3900         /* Old faces add new faces and vertex */
3901         numLeavesNew += 2 + 1;
3902       } else if ((p >= cStart) && (p < cEnd)) {
3903         /* Old cells add new cells and interior faces */
3904         numLeavesNew += 4 + 3;
3905       }
3906       break;
3907     case 2:
3908       /* Hex 2D */
3909       if ((p >= vStart) && (p < vEnd)) {
3910         /* Old vertices stay the same */
3911         ++numLeavesNew;
3912       } else if ((p >= fStart) && (p < fEnd)) {
3913         /* Old faces add new faces and vertex */
3914         numLeavesNew += 2 + 1;
3915       } else if ((p >= cStart) && (p < cEnd)) {
3916         /* Old cells add new cells, interior faces, and vertex */
3917         numLeavesNew += 4 + 4 + 1;
3918       }
3919       break;
3920     case 5:
3921       /* Simplicial 3D */
3922       if ((p >= vStart) && (p < vEnd)) {
3923         /* Old vertices stay the same */
3924         ++numLeavesNew;
3925       } else if ((p >= eStart) && (p < eEnd)) {
3926         /* Old edges add new edges and vertex */
3927         numLeavesNew += 2 + 1;
3928       } else if ((p >= fStart) && (p < fEnd)) {
3929         /* Old faces add new faces and face edges */
3930         numLeavesNew += 4 + 3;
3931       } else if ((p >= cStart) && (p < cEnd)) {
3932         /* Old cells add new cells and interior faces and edges */
3933         numLeavesNew += 8 + 8 + 1;
3934       }
3935       break;
3936     case 7:
3937       /* Hybrid Simplicial 3D */
3938       if ((p >= vStart) && (p < vEnd)) {
3939         /* Interior vertices stay the same */
3940         ++numLeavesNew;
3941       } else if ((p >= eStart) && (p < eMax)) {
3942         /* Interior edges add new edges and vertex */
3943         numLeavesNew += 2 + 1;
3944       } else if ((p >= eMax) && (p < eEnd)) {
3945         /* Hybrid edges stay the same */
3946         ++numLeavesNew;
3947       } else if ((p >= fStart) && (p < fMax)) {
3948         /* Interior faces add new faces and edges */
3949         numLeavesNew += 4 + 3;
3950       } else if ((p >= fMax) && (p < fEnd)) {
3951         /* Hybrid faces add new faces and edges */
3952         numLeavesNew += 2 + 1;
3953       } else if ((p >= cStart) && (p < cMax)) {
3954         /* Interior cells add new cells, faces, and edges */
3955         numLeavesNew += 8 + 8 + 1;
3956       } else if ((p >= cMax) && (p < cEnd)) {
3957         /* Hybrid cells add new cells and faces */
3958         numLeavesNew += 4 + 3;
3959       }
3960       break;
3961     case 6:
3962       /* Hex 3D */
3963       if ((p >= vStart) && (p < vEnd)) {
3964         /* Old vertices stay the same */
3965         ++numLeavesNew;
3966       } else if ((p >= eStart) && (p < eEnd)) {
3967         /* Old edges add new edges, and vertex */
3968         numLeavesNew += 2 + 1;
3969       } else if ((p >= fStart) && (p < fEnd)) {
3970         /* Old faces add new faces, edges, and vertex */
3971         numLeavesNew += 4 + 4 + 1;
3972       } else if ((p >= cStart) && (p < cEnd)) {
3973         /* Old cells add new cells, faces, edges, and vertex */
3974         numLeavesNew += 8 + 12 + 6 + 1;
3975       }
3976       break;
3977     default:
3978       SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
3979     }
3980   }
3981   /* Communicate depthSizes for each remote rank */
3982   ierr = DMPlexCreateProcessSF(dm, sf, &processRanks, &sfProcess);CHKERRQ(ierr);
3983   ierr = ISGetLocalSize(processRanks, &numNeighbors);CHKERRQ(ierr);
3984   ierr = PetscMalloc5((depth+1)*numNeighbors,PetscInt,&rdepthSize,numNeighbors,PetscInt,&rvStartNew,numNeighbors,PetscInt,&reStartNew,numNeighbors,PetscInt,&rfStartNew,numNeighbors,PetscInt,&rcStartNew);CHKERRQ(ierr);
3985   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);
3986   ierr = MPI_Type_contiguous(depth+1, MPIU_INT, &depthType);CHKERRQ(ierr);
3987   ierr = MPI_Type_commit(&depthType);CHKERRQ(ierr);
3988   ierr = PetscSFBcastBegin(sfProcess, depthType, depthSize, rdepthSize);CHKERRQ(ierr);
3989   ierr = PetscSFBcastEnd(sfProcess, depthType, depthSize, rdepthSize);CHKERRQ(ierr);
3990   for (n = 0; n < numNeighbors; ++n) {
3991     ierr = GetDepthStart_Private(depth, &rdepthSize[n*(depth+1)], &rcStartNew[n], &rfStartNew[n], &reStartNew[n], &rvStartNew[n]);CHKERRQ(ierr);
3992   }
3993   depthSizeOld[depth]   = cMax;
3994   depthSizeOld[0]       = vMax;
3995   depthSizeOld[depth-1] = fMax;
3996   depthSizeOld[1]       = eMax;
3997 
3998   ierr = PetscSFBcastBegin(sfProcess, depthType, depthSizeOld, rdepthMaxOld);CHKERRQ(ierr);
3999   ierr = PetscSFBcastEnd(sfProcess, depthType, depthSizeOld, rdepthMaxOld);CHKERRQ(ierr);
4000 
4001   depthSizeOld[depth]   = cEnd - cStart;
4002   depthSizeOld[0]       = vEnd - vStart;
4003   depthSizeOld[depth-1] = fEnd - fStart;
4004   depthSizeOld[1]       = eEnd - eStart;
4005 
4006   ierr = PetscSFBcastBegin(sfProcess, depthType, depthSizeOld, rdepthSizeOld);CHKERRQ(ierr);
4007   ierr = PetscSFBcastEnd(sfProcess, depthType, depthSizeOld, rdepthSizeOld);CHKERRQ(ierr);
4008   for (n = 0; n < numNeighbors; ++n) {
4009     ierr = GetDepthStart_Private(depth, &rdepthSizeOld[n*(depth+1)], &rcStart[n], &rfStart[n], &reStart[n], &rvStart[n]);CHKERRQ(ierr);
4010   }
4011   ierr = MPI_Type_free(&depthType);CHKERRQ(ierr);
4012   ierr = PetscSFDestroy(&sfProcess);CHKERRQ(ierr);
4013   /* Calculate new point SF */
4014   ierr = PetscMalloc(numLeavesNew * sizeof(PetscInt),    &localPointsNew);CHKERRQ(ierr);
4015   ierr = PetscMalloc(numLeavesNew * sizeof(PetscSFNode), &remotePointsNew);CHKERRQ(ierr);
4016   ierr = ISGetIndices(processRanks, &neighbors);CHKERRQ(ierr);
4017   for (l = 0, m = 0; l < numLeaves; ++l) {
4018     PetscInt    p     = localPoints[l];
4019     PetscInt    rp    = remotePoints[l].index, n;
4020     PetscMPIInt rrank = remotePoints[l].rank;
4021 
4022     ierr = PetscFindInt(rrank, numNeighbors, neighbors, &n);CHKERRQ(ierr);
4023     if (n < 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Could not locate remote rank %d", rrank);
4024     switch (refiner) {
4025     case 1:
4026       /* Simplicial 2D */
4027       if ((p >= vStart) && (p < vEnd)) {
4028         /* Old vertices stay the same */
4029         localPointsNew[m]        = vStartNew     + (p  - vStart);
4030         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
4031         remotePointsNew[m].rank  = rrank;
4032         ++m;
4033       } else if ((p >= fStart) && (p < fEnd)) {
4034         /* Old faces add new faces and vertex */
4035         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - fStart);
4036         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - rfStart[n]);
4037         remotePointsNew[m].rank  = rrank;
4038         ++m;
4039         for (r = 0; r < 2; ++r, ++m) {
4040           localPointsNew[m]        = fStartNew     + (p  - fStart)*2     + r;
4041           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*2 + r;
4042           remotePointsNew[m].rank  = rrank;
4043         }
4044       } else if ((p >= cStart) && (p < cEnd)) {
4045         /* Old cells add new cells and interior faces */
4046         for (r = 0; r < 4; ++r, ++m) {
4047           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
4048           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
4049           remotePointsNew[m].rank  = rrank;
4050         }
4051         for (r = 0; r < 3; ++r, ++m) {
4052           localPointsNew[m]        = fStartNew     + (fEnd - fStart)*2                    + (p  - cStart)*3     + r;
4053           remotePointsNew[m].index = rfStartNew[n] + rdepthSizeOld[n*(depth+1)+depth-1]*2 + (rp - rcStart[n])*3 + r;
4054           remotePointsNew[m].rank  = rrank;
4055         }
4056       }
4057       break;
4058     case 2:
4059       /* Hex 2D */
4060       if ((p >= vStart) && (p < vEnd)) {
4061         /* Old vertices stay the same */
4062         localPointsNew[m]        = vStartNew     + (p  - vStart);
4063         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
4064         remotePointsNew[m].rank  = rrank;
4065         ++m;
4066       } else if ((p >= fStart) && (p < fEnd)) {
4067         /* Old faces add new faces and vertex */
4068         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - fStart);
4069         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - rfStart[n]);
4070         remotePointsNew[m].rank  = rrank;
4071         ++m;
4072         for (r = 0; r < 2; ++r, ++m) {
4073           localPointsNew[m]        = fStartNew     + (p  - fStart)*2     + r;
4074           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*2 + r;
4075           remotePointsNew[m].rank  = rrank;
4076         }
4077       } else if ((p >= cStart) && (p < cEnd)) {
4078         /* Old cells add new cells, interior faces, and vertex */
4079         for (r = 0; r < 4; ++r, ++m) {
4080           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
4081           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
4082           remotePointsNew[m].rank  = rrank;
4083         }
4084         for (r = 0; r < 4; ++r, ++m) {
4085           localPointsNew[m]        = fStartNew     + (fEnd - fStart)*2                    + (p  - cStart)*4     + r;
4086           remotePointsNew[m].index = rfStartNew[n] + rdepthSizeOld[n*(depth+1)+depth-1]*2 + (rp - rcStart[n])*4 + r;
4087           remotePointsNew[m].rank  = rrank;
4088         }
4089         for (r = 0; r < 1; ++r, ++m) {
4090           localPointsNew[m]        = vStartNew     + (fEnd - fStart)                    + (p  - cStart)     + r;
4091           remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+depth-1] + (rp - rcStart[n]) + r;
4092           remotePointsNew[m].rank  = rrank;
4093         }
4094       }
4095       break;
4096     case 3:
4097       /* Hybrid simplicial 2D */
4098       if ((p >= vStart) && (p < vEnd)) {
4099         /* Old vertices stay the same */
4100         localPointsNew[m]        = vStartNew     + (p  - vStart);
4101         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
4102         remotePointsNew[m].rank  = rrank;
4103         ++m;
4104       } else if ((p >= fStart) && (p < fMax)) {
4105         /* Old interior faces add new faces and vertex */
4106         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - fStart);
4107         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - rfStart[n]);
4108         remotePointsNew[m].rank  = rrank;
4109         ++m;
4110         for (r = 0; r < 2; ++r, ++m) {
4111           localPointsNew[m]        = fStartNew     + (p  - fStart)*2     + r;
4112           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*2 + r;
4113           remotePointsNew[m].rank  = rrank;
4114         }
4115       } else if ((p >= fMax) && (p < fEnd)) {
4116         /* Old hybrid faces stay the same */
4117         localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (p  - fMax);
4118         remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*2 + (rp - rdepthMaxOld[n*(depth+1)+depth-1]);
4119         remotePointsNew[m].rank  = rrank;
4120         ++m;
4121       } else if ((p >= cStart) && (p < cMax)) {
4122         /* Old interior cells add new cells and interior faces */
4123         for (r = 0; r < 4; ++r, ++m) {
4124           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
4125           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
4126           remotePointsNew[m].rank  = rrank;
4127         }
4128         for (r = 0; r < 3; ++r, ++m) {
4129           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (p  - cStart)*3     + r;
4130           remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*2 + (rp - rcStart[n])*3 + r;
4131           remotePointsNew[m].rank  = rrank;
4132         }
4133       } else if ((p >= cStart) && (p < cMax)) {
4134         /* Old hybrid cells add new cells and hybrid face */
4135         for (r = 0; r < 2; ++r, ++m) {
4136           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
4137           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
4138           remotePointsNew[m].rank  = rrank;
4139         }
4140         localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (cMax                            - cStart)*3     + (p  - cMax);
4141         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]);
4142         remotePointsNew[m].rank  = rrank;
4143         ++m;
4144       }
4145       break;
4146     case 5:
4147       /* Simplicial 3D */
4148       if ((p >= vStart) && (p < vEnd)) {
4149         /* Old vertices stay the same */
4150         localPointsNew[m]        = vStartNew     + (p  - vStart);
4151         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
4152         remotePointsNew[m].rank  = rrank;
4153         ++m;
4154       } else if ((p >= eStart) && (p < eEnd)) {
4155         /* Old edges add new edges and vertex */
4156         for (r = 0; r < 2; ++r, ++m) {
4157           localPointsNew[m]        = eStartNew     + (p  - eStart)*2     + r;
4158           remotePointsNew[m].index = reStartNew[n] + (rp - reStart[n])*2 + r;
4159           remotePointsNew[m].rank  = rrank;
4160         }
4161         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - eStart);
4162         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - reStart[n]);
4163         remotePointsNew[m].rank  = rrank;
4164         ++m;
4165       } else if ((p >= fStart) && (p < fEnd)) {
4166         /* Old faces add new faces and face edges */
4167         for (r = 0; r < 4; ++r, ++m) {
4168           localPointsNew[m]        = fStartNew     + (p  - fStart)*4     + r;
4169           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*4 + r;
4170           remotePointsNew[m].rank  = rrank;
4171         }
4172         for (r = 0; r < 3; ++r, ++m) {
4173           localPointsNew[m]        = eStartNew     + (eEnd - eStart)*2              + (p  - fStart)*3     + r;
4174           remotePointsNew[m].index = reStartNew[n] + rdepthSizeOld[n*(depth+1)+1]*2 + (rp - rfStart[n])*3 + r;
4175           remotePointsNew[m].rank  = rrank;
4176         }
4177       } else if ((p >= cStart) && (p < cEnd)) {
4178         /* Old cells add new cells and interior faces and edges */
4179         for (r = 0; r < 8; ++r, ++m) {
4180           localPointsNew[m]        = cStartNew     + (p  - cStart)*8     + r;
4181           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*8 + r;
4182           remotePointsNew[m].rank  = rrank;
4183         }
4184         for (r = 0; r < 8; ++r, ++m) {
4185           localPointsNew[m]        = fStartNew     + (fEnd - fStart)*4                    + (p  - cStart)*8     + r;
4186           remotePointsNew[m].index = rfStartNew[n] + rdepthSizeOld[n*(depth+1)+depth-1]*4 + (rp - rcStart[n])*8 + r;
4187           remotePointsNew[m].rank  = rrank;
4188         }
4189         for (r = 0; r < 1; ++r, ++m) {
4190           localPointsNew[m]        = eStartNew     + (eEnd - eStart)*2              + (fEnd - fStart)*3                    + (p  - cStart)*1     + r;
4191           remotePointsNew[m].index = reStartNew[n] + rdepthSizeOld[n*(depth+1)+1]*2 + rdepthSizeOld[n*(depth+1)+depth-1]*3 + (rp - rcStart[n])*1 + r;
4192           remotePointsNew[m].rank  = rrank;
4193         }
4194       }
4195       break;
4196     case 7:
4197       /* Hybrid Simplicial 3D */
4198       if ((p >= vStart) && (p < vEnd)) {
4199         /* Interior vertices stay the same */
4200         localPointsNew[m]        = vStartNew     + (p  - vStart);
4201         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
4202         remotePointsNew[m].rank  = rrank;
4203         ++m;
4204       } else if ((p >= eStart) && (p < eMax)) {
4205         /* Interior edges add new edges and vertex */
4206         for (r = 0; r < 2; ++r, ++m) {
4207           localPointsNew[m]        = eStartNew     + (p  - eStart)*2     + r;
4208           remotePointsNew[m].index = reStartNew[n] + (rp - reStart[n])*2 + r;
4209           remotePointsNew[m].rank  = rrank;
4210         }
4211         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - eStart);
4212         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - reStart[n]);
4213         remotePointsNew[m].rank  = rrank;
4214         ++m;
4215       } else if ((p >= eMax) && (p < eEnd)) {
4216         /* Hybrid edges stay the same */
4217         localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (fMax                              - fStart)*3     + (cMax                            - cStart)     + (p  - eMax);
4218         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]);
4219         remotePointsNew[m].rank  = rrank;
4220         ++m;
4221       } else if ((p >= fStart) && (p < fMax)) {
4222         /* Interior faces add new faces and edges */
4223         for (r = 0; r < 4; ++r, ++m) {
4224           localPointsNew[m]        = fStartNew     + (p  - fStart)*4     + r;
4225           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*4 + r;
4226           remotePointsNew[m].rank  = rrank;
4227         }
4228         for (r = 0; r < 3; ++r, ++m) {
4229           localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (p  - fStart)*3     + r;
4230           remotePointsNew[m].index = reStartNew[n] + (rdepthMaxOld[n*(depth+1)+1] - reStart[n])*2 + (rp - rfStart[n])*3 + r;
4231           remotePointsNew[m].rank  = rrank;
4232         }
4233       } else if ((p >= fMax) && (p < fEnd)) {
4234         /* Hybrid faces add new faces and edges */
4235         for (r = 0; r < 2; ++r, ++m) {
4236           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*4     + (cMax                            - cStart)*8     + (p  - fStart)*2     + r;
4237           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;
4238           remotePointsNew[m].rank  = rrank;
4239         }
4240         localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (fMax                              - fStart)     + (cMax                            - cStart)     + (fEnd                                          - fMax);
4241         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]);
4242         remotePointsNew[m].rank  = rrank;
4243       } else if ((p >= cStart) && (p < cMax)) {
4244         /* Interior cells add new cells, faces, and edges */
4245         for (r = 0; r < 8; ++r, ++m) {
4246           localPointsNew[m]        = cStartNew     + (p  - cStart)*8     + r;
4247           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*8 + r;
4248           remotePointsNew[m].rank  = rrank;
4249         }
4250         for (r = 0; r < 8; ++r, ++m) {
4251           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*4     + (p  - cStart)*8     + r;
4252           remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*4 + (rp - rcStart[n])*8 + r;
4253           remotePointsNew[m].rank  = rrank;
4254         }
4255         localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (fMax                              - fStart)*3     + (p  - cStart)*1     + r;
4256         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;
4257         remotePointsNew[m].rank  = rrank;
4258       } else if ((p >= cMax) && (p < cEnd)) {
4259         /* Hybrid cells add new cells and faces */
4260         for (r = 0; r < 4; ++r, ++m) {
4261           localPointsNew[m]        = cStartNew     + (cMax                            - cStart)*8     + (p  - cMax)*4                            + r;
4262           remotePointsNew[m].index = rcStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth] - rcStart[n])*8 + (rp - rdepthMaxOld[n*(depth+1)+depth])*4 + r;
4263           remotePointsNew[m].rank  = rrank;
4264         }
4265         for (r = 0; r < 3; ++r, ++m) {
4266           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*4     + (cMax                            - cStart)*8     + (fEnd                                          - fMax)*4                              + (p  - cMax)*3                            + r;
4267           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;
4268           remotePointsNew[m].rank  = rrank;
4269         }
4270       }
4271       break;
4272     case 6:
4273       /* Hex 3D */
4274       if ((p >= vStart) && (p < vEnd)) {
4275         /* Old vertices stay the same */
4276         localPointsNew[m]        = vStartNew     + (p  - vStart);
4277         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
4278         remotePointsNew[m].rank  = rrank;
4279         ++m;
4280       } else if ((p >= eStart) && (p < eEnd)) {
4281         /* Old edges add new edges and vertex */
4282         for (r = 0; r < 2; ++r, ++m) {
4283           localPointsNew[m]        = eStartNew     + (p  - eStart)*2     + r;
4284           remotePointsNew[m].index = reStartNew[n] + (rp - reStart[n])*2 + r;
4285           remotePointsNew[m].rank  = rrank;
4286         }
4287         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - eStart);
4288         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - reStart[n]);
4289         remotePointsNew[m].rank  = rrank;
4290         ++m;
4291       } else if ((p >= fStart) && (p < fEnd)) {
4292         /* Old faces add new faces, edges, and vertex */
4293         for (r = 0; r < 4; ++r, ++m) {
4294           localPointsNew[m]        = fStartNew     + (p  - fStart)*4     + r;
4295           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*4 + r;
4296           remotePointsNew[m].rank  = rrank;
4297         }
4298         for (r = 0; r < 4; ++r, ++m) {
4299           localPointsNew[m]        = eStartNew     + (eEnd - eStart)*2              + (p  - fStart)*4     + r;
4300           remotePointsNew[m].index = reStartNew[n] + rdepthSizeOld[n*(depth+1)+1]*2 + (rp - rfStart[n])*4 + r;
4301           remotePointsNew[m].rank  = rrank;
4302         }
4303         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (eEnd - eStart)              + (p  - fStart);
4304         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + rdepthSizeOld[n*(depth+1)+1] + (rp - rfStart[n]);
4305         remotePointsNew[m].rank  = rrank;
4306         ++m;
4307       } else if ((p >= cStart) && (p < cEnd)) {
4308         /* Old cells add new cells, faces, edges, and vertex */
4309         for (r = 0; r < 8; ++r, ++m) {
4310           localPointsNew[m]        = cStartNew     + (p  - cStart)*8     + r;
4311           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*8 + r;
4312           remotePointsNew[m].rank  = rrank;
4313         }
4314         for (r = 0; r < 12; ++r, ++m) {
4315           localPointsNew[m]        = fStartNew     + (fEnd - fStart)*4                    + (p  - cStart)*12     + r;
4316           remotePointsNew[m].index = rfStartNew[n] + rdepthSizeOld[n*(depth+1)+depth-1]*4 + (rp - rcStart[n])*12 + r;
4317           remotePointsNew[m].rank  = rrank;
4318         }
4319         for (r = 0; r < 6; ++r, ++m) {
4320           localPointsNew[m]        = eStartNew     + (eEnd - eStart)*2              + (fEnd - fStart)*4                    + (p  - cStart)*6     + r;
4321           remotePointsNew[m].index = reStartNew[n] + rdepthSizeOld[n*(depth+1)+1]*2 + rdepthSizeOld[n*(depth+1)+depth-1]*4 + (rp - rcStart[n])*6 + r;
4322           remotePointsNew[m].rank  = rrank;
4323         }
4324         for (r = 0; r < 1; ++r, ++m) {
4325           localPointsNew[m]        = vStartNew     + (eEnd - eStart)              + (fEnd - fStart)                    + (p  - cStart)     + r;
4326           remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+1] + rdepthSizeOld[n*(depth+1)+depth-1] + (rp - rcStart[n]) + r;
4327           remotePointsNew[m].rank  = rrank;
4328         }
4329       }
4330       break;
4331     default:
4332       SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
4333     }
4334   }
4335   ierr = ISRestoreIndices(processRanks, &neighbors);CHKERRQ(ierr);
4336   ierr = ISDestroy(&processRanks);CHKERRQ(ierr);
4337   ierr = PetscSFSetGraph(sfNew, pEndNew-pStartNew, numLeavesNew, localPointsNew, PETSC_OWN_POINTER, remotePointsNew, PETSC_OWN_POINTER);CHKERRQ(ierr);
4338   ierr = PetscFree5(rdepthSize,rvStartNew,reStartNew,rfStartNew,rcStartNew);CHKERRQ(ierr);
4339   ierr = PetscFree7(depthSizeOld,rdepthSizeOld,rdepthMaxOld,rvStart,reStart,rfStart,rcStart);CHKERRQ(ierr);
4340   PetscFunctionReturn(0);
4341 }
4342 
4343 #undef __FUNCT__
4344 #define __FUNCT__ "CellRefinerCreateLabels"
4345 PetscErrorCode CellRefinerCreateLabels(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
4346 {
4347   PetscInt       numLabels, l;
4348   PetscInt       depth, newp, cStart, cStartNew, cEnd, cMax, vStart, vStartNew, vEnd, vMax, fStart, fStartNew, fEnd, fMax, eStart, eStartNew, eEnd, eMax, r;
4349   PetscErrorCode ierr;
4350 
4351   PetscFunctionBegin;
4352   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
4353   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
4354   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
4355   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
4356   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
4357   if (refiner) {ierr = GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);CHKERRQ(ierr);}
4358   ierr = DMPlexGetNumLabels(dm, &numLabels);CHKERRQ(ierr);
4359   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
4360   switch (refiner) {
4361   case 0: break;
4362   case 7:
4363   case 8:
4364     if (eMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No edge maximum specified in hybrid mesh");
4365   case 3:
4366   case 4:
4367     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
4368     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
4369   }
4370   for (l = 0; l < numLabels; ++l) {
4371     DMLabel         label, labelNew;
4372     const char     *lname;
4373     PetscBool       isDepth;
4374     IS              valueIS;
4375     const PetscInt *values;
4376     PetscInt        numValues, val;
4377 
4378     ierr = DMPlexGetLabelName(dm, l, &lname);CHKERRQ(ierr);
4379     ierr = PetscStrcmp(lname, "depth", &isDepth);CHKERRQ(ierr);
4380     if (isDepth) continue;
4381     ierr = DMPlexCreateLabel(rdm, lname);CHKERRQ(ierr);
4382     ierr = DMPlexGetLabel(dm, lname, &label);CHKERRQ(ierr);
4383     ierr = DMPlexGetLabel(rdm, lname, &labelNew);CHKERRQ(ierr);
4384     ierr = DMLabelGetValueIS(label, &valueIS);CHKERRQ(ierr);
4385     ierr = ISGetLocalSize(valueIS, &numValues);CHKERRQ(ierr);
4386     ierr = ISGetIndices(valueIS, &values);CHKERRQ(ierr);
4387     for (val = 0; val < numValues; ++val) {
4388       IS              pointIS;
4389       const PetscInt *points;
4390       PetscInt        numPoints, n;
4391 
4392       ierr = DMLabelGetStratumIS(label, values[val], &pointIS);CHKERRQ(ierr);
4393       ierr = ISGetLocalSize(pointIS, &numPoints);CHKERRQ(ierr);
4394       ierr = ISGetIndices(pointIS, &points);CHKERRQ(ierr);
4395       for (n = 0; n < numPoints; ++n) {
4396         const PetscInt p = points[n];
4397         switch (refiner) {
4398         case 1:
4399           /* Simplicial 2D */
4400           if ((p >= vStart) && (p < vEnd)) {
4401             /* Old vertices stay the same */
4402             newp = vStartNew + (p - vStart);
4403             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4404           } else if ((p >= fStart) && (p < fEnd)) {
4405             /* Old faces add new faces and vertex */
4406             newp = vStartNew + (vEnd - vStart) + (p - fStart);
4407             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4408             for (r = 0; r < 2; ++r) {
4409               newp = fStartNew + (p - fStart)*2 + r;
4410               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4411             }
4412           } else if ((p >= cStart) && (p < cEnd)) {
4413             /* Old cells add new cells and interior faces */
4414             for (r = 0; r < 4; ++r) {
4415               newp = cStartNew + (p - cStart)*4 + r;
4416               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4417             }
4418             for (r = 0; r < 3; ++r) {
4419               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*3 + r;
4420               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4421             }
4422           }
4423           break;
4424         case 2:
4425           /* Hex 2D */
4426           if ((p >= vStart) && (p < vEnd)) {
4427             /* Old vertices stay the same */
4428             newp = vStartNew + (p - vStart);
4429             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4430           } else if ((p >= fStart) && (p < fEnd)) {
4431             /* Old faces add new faces and vertex */
4432             newp = vStartNew + (vEnd - vStart) + (p - fStart);
4433             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4434             for (r = 0; r < 2; ++r) {
4435               newp = fStartNew + (p - fStart)*2 + r;
4436               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4437             }
4438           } else if ((p >= cStart) && (p < cEnd)) {
4439             /* Old cells add new cells and interior faces and vertex */
4440             for (r = 0; r < 4; ++r) {
4441               newp = cStartNew + (p - cStart)*4 + r;
4442               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4443             }
4444             for (r = 0; r < 4; ++r) {
4445               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*4 + r;
4446               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4447             }
4448             newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (p - cStart);
4449             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4450           }
4451           break;
4452         case 3:
4453           /* Hybrid simplicial 2D */
4454           if ((p >= vStart) && (p < vEnd)) {
4455             /* Old vertices stay the same */
4456             newp = vStartNew + (p - vStart);
4457             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4458           } else if ((p >= fStart) && (p < fMax)) {
4459             /* Old interior faces add new faces and vertex */
4460             newp = vStartNew + (vEnd - vStart) + (p - fStart);
4461             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4462             for (r = 0; r < 2; ++r) {
4463               newp = fStartNew + (p - fStart)*2 + r;
4464               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4465             }
4466           } else if ((p >= fMax) && (p < fEnd)) {
4467             /* Old hybrid faces stay the same */
4468             newp = fStartNew + (fMax - fStart)*2 + (p - fMax);
4469             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4470           } else if ((p >= cStart) && (p < cMax)) {
4471             /* Old interior cells add new cells and interior faces */
4472             for (r = 0; r < 4; ++r) {
4473               newp = cStartNew + (p - cStart)*4 + r;
4474               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4475             }
4476             for (r = 0; r < 3; ++r) {
4477               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*3 + r;
4478               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4479             }
4480           } else if ((p >= cMax) && (p < cEnd)) {
4481             /* Old hybrid cells add new cells and hybrid face */
4482             for (r = 0; r < 2; ++r) {
4483               newp = cStartNew + (cMax - cStart)*4 + (p - cMax)*2 + r;
4484               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4485             }
4486             newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (p - cMax);
4487             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4488           }
4489           break;
4490         case 5:
4491           /* Simplicial 3D */
4492           if ((p >= vStart) && (p < vEnd)) {
4493             /* Old vertices stay the same */
4494             newp = vStartNew + (p - vStart);
4495             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4496           } else if ((p >= eStart) && (p < eEnd)) {
4497             /* Old edges add new edges and vertex */
4498             for (r = 0; r < 2; ++r) {
4499               newp = eStartNew + (p - eStart)*2 + r;
4500               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4501             }
4502             newp = vStartNew + (vEnd - vStart) + (p - eStart);
4503             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4504           } else if ((p >= fStart) && (p < fEnd)) {
4505             /* Old faces add new faces and edges */
4506             for (r = 0; r < 4; ++r) {
4507               newp = fStartNew + (p - fStart)*4 + r;
4508               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4509             }
4510             for (r = 0; r < 3; ++r) {
4511               newp = eStartNew + (eEnd - eStart)*2 + (p - fStart)*3 + r;
4512               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4513             }
4514           } else if ((p >= cStart) && (p < cEnd)) {
4515             /* Old cells add new cells and interior faces and edges */
4516             for (r = 0; r < 8; ++r) {
4517               newp = cStartNew + (p - cStart)*8 + r;
4518               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4519             }
4520             for (r = 0; r < 8; ++r) {
4521               newp = fStartNew + (fEnd - fStart)*4 + (p - cStart)*8 + r;
4522               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4523             }
4524             for (r = 0; r < 1; ++r) {
4525               newp = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (p - cStart)*1 + r;
4526               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4527             }
4528           }
4529           break;
4530         case 7:
4531           /* Hybrid Simplicial 3D */
4532           if ((p >= vStart) && (p < vEnd)) {
4533             /* Interior vertices stay the same */
4534             newp = vStartNew + (p - vStart);
4535             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4536           } else if ((p >= eStart) && (p < eMax)) {
4537             /* Interior edges add new edges and vertex */
4538             for (r = 0; r < 2; ++r) {
4539               newp = eStartNew + (p - eStart)*2 + r;
4540               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4541             }
4542             newp = vStartNew + (vEnd - vStart) + (p - eStart);
4543             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4544           } else if ((p >= eMax) && (p < eEnd)) {
4545             /* Hybrid edges stay the same */
4546             newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (p - eMax);
4547             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4548           } else if ((p >= fStart) && (p < fMax)) {
4549             /* Interior faces add new faces and edges */
4550             for (r = 0; r < 4; ++r) {
4551               newp = fStartNew + (p - fStart)*4 + r;
4552               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4553             }
4554             for (r = 0; r < 3; ++r) {
4555               newp = eStartNew + (eMax - eStart)*2 + (p - fStart)*3 + r;
4556               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4557             }
4558           } else if ((p >= fMax) && (p < fEnd)) {
4559             /* Hybrid faces add new faces and edges */
4560             for (r = 0; r < 2; ++r) {
4561               newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (p - fMax)*2 + r;
4562               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4563             }
4564             newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (p - fMax);
4565             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4566           } else if ((p >= cStart) && (p < cMax)) {
4567             /* Interior cells add new cells, faces, and edges */
4568             for (r = 0; r < 8; ++r) {
4569               newp = cStartNew + (p - cStart)*8 + r;
4570               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4571             }
4572             for (r = 0; r < 8; ++r) {
4573               newp = fStartNew + (fMax - fStart)*4 + (p - cStart)*8 + r;
4574               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4575             }
4576             newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (p - cStart);
4577             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4578           } else if ((p >= cMax) && (p < cEnd)) {
4579             /* Hybrid cells add new cells and faces */
4580             for (r = 0; r < 4; ++r) {
4581               newp = cStartNew + (cMax - cStart)*8 + (p - cMax)*4 + r;
4582               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4583             }
4584             for (r = 0; r < 3; ++r) {
4585               newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (p - cMax)*3 + r;
4586               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4587             }
4588           }
4589           break;
4590         case 6:
4591           /* Hex 3D */
4592           if ((p >= vStart) && (p < vEnd)) {
4593             /* Old vertices stay the same */
4594             newp = vStartNew + (p - vStart);
4595             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4596           } else if ((p >= eStart) && (p < eEnd)) {
4597             /* Old edges add new edges and vertex */
4598             for (r = 0; r < 2; ++r) {
4599               newp = eStartNew + (p - eStart)*2 + r;
4600               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4601             }
4602             newp = vStartNew + (vEnd - vStart) + (p - eStart);
4603             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4604           } else if ((p >= fStart) && (p < fEnd)) {
4605             /* Old faces add new faces, edges, and vertex */
4606             for (r = 0; r < 4; ++r) {
4607               newp = fStartNew + (p - fStart)*4 + r;
4608               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4609             }
4610             for (r = 0; r < 4; ++r) {
4611               newp = eStartNew + (eEnd - eStart)*2 + (p - fStart)*4 + r;
4612               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4613             }
4614             newp = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (p - fStart);
4615             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4616           } else if ((p >= cStart) && (p < cEnd)) {
4617             /* Old cells add new cells, faces, edges, and vertex */
4618             for (r = 0; r < 8; ++r) {
4619               newp = cStartNew + (p - cStart)*8 + r;
4620               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4621             }
4622             for (r = 0; r < 12; ++r) {
4623               newp = fStartNew + (fEnd - fStart)*4 + (p - cStart)*12 + r;
4624               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4625             }
4626             for (r = 0; r < 6; ++r) {
4627               newp = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*4 + (p - cStart)*6 + r;
4628               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4629             }
4630             newp = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (fEnd - fStart) + (p - cStart);
4631             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4632           }
4633           break;
4634         default:
4635           SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
4636         }
4637       }
4638       ierr = ISRestoreIndices(pointIS, &points);CHKERRQ(ierr);
4639       ierr = ISDestroy(&pointIS);CHKERRQ(ierr);
4640     }
4641     ierr = ISRestoreIndices(valueIS, &values);CHKERRQ(ierr);
4642     ierr = ISDestroy(&valueIS);CHKERRQ(ierr);
4643     if (0) {
4644       ierr = PetscViewerASCIISynchronizedAllow(PETSC_VIEWER_STDOUT_WORLD, PETSC_TRUE);CHKERRQ(ierr);
4645       ierr = DMLabelView(labelNew, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
4646       ierr = PetscViewerFlush(PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
4647     }
4648   }
4649   PetscFunctionReturn(0);
4650 }
4651 
4652 #undef __FUNCT__
4653 #define __FUNCT__ "DMPlexRefineUniform_Internal"
4654 /* This will only work for interpolated meshes */
4655 PetscErrorCode DMPlexRefineUniform_Internal(DM dm, CellRefiner cellRefiner, DM *dmRefined)
4656 {
4657   DM             rdm;
4658   PetscInt      *depthSize;
4659   PetscInt       dim, depth = 0, d, pStart = 0, pEnd = 0;
4660   PetscErrorCode ierr;
4661 
4662   PetscFunctionBegin;
4663   ierr = DMCreate(PetscObjectComm((PetscObject)dm), &rdm);CHKERRQ(ierr);
4664   ierr = DMSetType(rdm, DMPLEX);CHKERRQ(ierr);
4665   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
4666   ierr = DMPlexSetDimension(rdm, dim);CHKERRQ(ierr);
4667   /* Calculate number of new points of each depth */
4668   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
4669   ierr = PetscMalloc((depth+1) * sizeof(PetscInt), &depthSize);CHKERRQ(ierr);
4670   ierr = PetscMemzero(depthSize, (depth+1) * sizeof(PetscInt));CHKERRQ(ierr);
4671   ierr = CellRefinerGetSizes(cellRefiner, dm, depthSize);CHKERRQ(ierr);
4672   /* Step 1: Set chart */
4673   for (d = 0; d <= depth; ++d) pEnd += depthSize[d];
4674   ierr = DMPlexSetChart(rdm, pStart, pEnd);CHKERRQ(ierr);
4675   /* Step 2: Set cone/support sizes */
4676   ierr = CellRefinerSetConeSizes(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
4677   /* Step 3: Setup refined DM */
4678   ierr = DMSetUp(rdm);CHKERRQ(ierr);
4679   /* Step 4: Set cones and supports */
4680   ierr = CellRefinerSetCones(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
4681   /* Step 5: Stratify */
4682   ierr = DMPlexStratify(rdm);CHKERRQ(ierr);
4683   /* Step 6: Set coordinates for vertices */
4684   ierr = CellRefinerSetCoordinates(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
4685   /* Step 7: Create pointSF */
4686   ierr = CellRefinerCreateSF(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
4687   /* Step 8: Create labels */
4688   ierr = CellRefinerCreateLabels(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
4689   ierr = PetscFree(depthSize);CHKERRQ(ierr);
4690 
4691   *dmRefined = rdm;
4692   PetscFunctionReturn(0);
4693 }
4694 
4695 #undef __FUNCT__
4696 #define __FUNCT__ "DMPlexSetRefinementUniform"
4697 PetscErrorCode DMPlexSetRefinementUniform(DM dm, PetscBool refinementUniform)
4698 {
4699   DM_Plex *mesh = (DM_Plex*) dm->data;
4700 
4701   PetscFunctionBegin;
4702   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4703   mesh->refinementUniform = refinementUniform;
4704   PetscFunctionReturn(0);
4705 }
4706 
4707 #undef __FUNCT__
4708 #define __FUNCT__ "DMPlexGetRefinementUniform"
4709 PetscErrorCode DMPlexGetRefinementUniform(DM dm, PetscBool *refinementUniform)
4710 {
4711   DM_Plex *mesh = (DM_Plex*) dm->data;
4712 
4713   PetscFunctionBegin;
4714   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4715   PetscValidPointer(refinementUniform,  2);
4716   *refinementUniform = mesh->refinementUniform;
4717   PetscFunctionReturn(0);
4718 }
4719 
4720 #undef __FUNCT__
4721 #define __FUNCT__ "DMPlexSetRefinementLimit"
4722 PetscErrorCode DMPlexSetRefinementLimit(DM dm, PetscReal refinementLimit)
4723 {
4724   DM_Plex *mesh = (DM_Plex*) dm->data;
4725 
4726   PetscFunctionBegin;
4727   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4728   mesh->refinementLimit = refinementLimit;
4729   PetscFunctionReturn(0);
4730 }
4731 
4732 #undef __FUNCT__
4733 #define __FUNCT__ "DMPlexGetRefinementLimit"
4734 PetscErrorCode DMPlexGetRefinementLimit(DM dm, PetscReal *refinementLimit)
4735 {
4736   DM_Plex *mesh = (DM_Plex*) dm->data;
4737 
4738   PetscFunctionBegin;
4739   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4740   PetscValidPointer(refinementLimit,  2);
4741   /* if (mesh->refinementLimit < 0) = getMaxVolume()/2.0; */
4742   *refinementLimit = mesh->refinementLimit;
4743   PetscFunctionReturn(0);
4744 }
4745 
4746 #undef __FUNCT__
4747 #define __FUNCT__ "DMPlexGetCellRefiner_Internal"
4748 PetscErrorCode DMPlexGetCellRefiner_Internal(DM dm, CellRefiner *cellRefiner)
4749 {
4750   PetscInt       dim, cStart, cEnd, coneSize, cMax;
4751   PetscErrorCode ierr;
4752 
4753   PetscFunctionBegin;
4754   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
4755   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
4756   if (cEnd <= cStart) {*cellRefiner = 0; PetscFunctionReturn(0);}
4757   ierr = DMPlexGetConeSize(dm, cStart, &coneSize);CHKERRQ(ierr);
4758   ierr = DMPlexGetHybridBounds(dm, &cMax, NULL, NULL, NULL);CHKERRQ(ierr);
4759   switch (dim) {
4760   case 2:
4761     switch (coneSize) {
4762     case 3:
4763       if (cMax >= 0) *cellRefiner = 3; /* Hybrid */
4764       else *cellRefiner = 1; /* Triangular */
4765       break;
4766     case 4:
4767       if (cMax >= 0) *cellRefiner = 4; /* Hybrid */
4768       else *cellRefiner = 2; /* Quadrilateral */
4769       break;
4770     default:
4771       SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown coneSize %d in dimension %d for cell refiner", coneSize, dim);
4772     }
4773     break;
4774   case 3:
4775     switch (coneSize) {
4776     case 4:
4777       if (cMax >= 0) *cellRefiner = 7; /* Hybrid */
4778       else *cellRefiner = 5; /* Tetrahedral */
4779       break;
4780     case 6:
4781       if (cMax >= 0) *cellRefiner = 8; /* Hybrid */
4782       else *cellRefiner = 6; /* hexahedral */
4783       break;
4784     default:
4785       SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown coneSize %d in dimension %d for cell refiner", coneSize, dim);
4786     }
4787     break;
4788   default:
4789     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown dimension %d for cell refiner", dim);
4790   }
4791   PetscFunctionReturn(0);
4792 }
4793