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