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