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