xref: /petsc/src/dm/impls/plex/plexrefine.c (revision 89d949e22d93de971d3ed7d7fdc00f23508da20b)
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 static PetscErrorCode CellRefinerGetSizes(CellRefiner refiner, DM dm, PetscInt depthSize[])
31 {
32   PetscInt       cStart, cEnd, cMax, vStart, vEnd, vMax, fStart, fEnd, fMax, eStart, eEnd, eMax;
33   PetscErrorCode ierr;
34 
35   PetscFunctionBegin;
36   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
37   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
38   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
39   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
40   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
41   switch (refiner) {
42   case 0:
43     break;
44   case 1:
45     /* Simplicial 2D */
46     depthSize[0] = vEnd - vStart + fEnd - fStart;         /* Add a vertex on every face */
47     depthSize[1] = 2*(fEnd - fStart) + 3*(cEnd - cStart); /* Every face is split into 2 faces and 3 faces are added for each cell */
48     depthSize[2] = 4*(cEnd - cStart);                     /* Every cell split into 4 cells */
49     break;
50   case 3:
51     /* Hybrid Simplicial 2D */
52     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
53     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
54     depthSize[0] = vEnd - vStart + fMax - fStart;                                         /* Add a vertex on every face, but not hybrid faces */
55     depthSize[1] = 2*(fMax - fStart) + 3*(cMax - cStart) + (fEnd - fMax) + (cEnd - cMax); /* Every interior face is split into 2 faces, 3 faces are added for each interior cell, and one in each hybrid cell */
56     depthSize[2] = 4*(cMax - cStart) + 2*(cEnd - cMax);                                   /* Interior cells split into 4 cells, Hybrid cells split into 2 cells */
57     break;
58   case 2:
59     /* Hex 2D */
60     depthSize[0] = vEnd - vStart + fEnd - fStart + cEnd - cStart; /* Add a vertex on every face and cell */
61     depthSize[1] = 2*(fEnd - fStart) + 4*(cEnd - cStart);         /* Every face is split into 2 faces and 4 faces are added for each cell */
62     depthSize[2] = 4*(cEnd - cStart);                             /* Every cell split into 4 cells */
63     break;
64   case 4:
65     /* Hybrid Hex 2D */
66     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
67     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
68     /* Quadrilateral */
69     depthSize[0] = vEnd - vStart + fMax - fStart + cMax - cStart;                 /* Add a vertex on every face and cell */
70     depthSize[1] = 2*(fMax - fStart) + 4*(cMax - cStart);                         /* Every face is split into 2 faces, and 4 faces are added for each cell */
71     depthSize[2] = 4*(cMax - cStart);                                             /* Every cell split into 4 cells */
72     /* Segment Prisms */
73     depthSize[0] += 0;                                                            /* No hybrid vertices */
74     depthSize[1] +=   (fEnd - fMax)  +   (cEnd - cMax);                           /* Every hybrid face remains and 1 faces is added for each hybrid cell */
75     depthSize[2] += 2*(cEnd - cMax);                                              /* Every hybrid cell split into 2 cells */
76     break;
77   case 5:
78     /* Simplicial 3D */
79     depthSize[0] =    vEnd - vStart  +    eEnd - eStart;                    /* Add a vertex on every edge */
80     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 */
81     depthSize[2] = 4*(fEnd - fStart) + 8*(cEnd - cStart);                   /* Every face split into 4 faces and 8 faces are added for each cell */
82     depthSize[3] = 8*(cEnd - cStart);                                       /* Every cell split into 8 cells */
83     break;
84   case 7:
85     /* Hybrid Simplicial 3D */
86     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
87     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
88     if (eMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No edge maximum specified in hybrid mesh");
89     /* Tetrahedra */
90     depthSize[0]  =    vEnd - vStart  +    eMax - eStart;                    /* Add a vertex on every interior edge */
91     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 */
92     depthSize[2]  = 4*(fMax - fStart) + 8*(cMax - cStart);                   /* Every interior face split into 4 faces, 8 faces added for each interior cell */
93     depthSize[3]  = 8*(cMax - cStart);                                       /* Every interior cell split into 8 cells */
94     /* Triangular Prisms */
95     depthSize[0] += 0;                                                       /* No hybrid vertices */
96     depthSize[1] +=   (eEnd - eMax)   +   (fEnd - fMax);                     /* Every hybrid edge remains, 1 edge for every hybrid face */
97     depthSize[2] += 2*(fEnd - fMax)   + 3*(cEnd - cMax);                     /* Every hybrid face split into 2 faces and 3 faces are added for each hybrid cell */
98     depthSize[3] += 4*(cEnd - cMax);                                         /* Every hybrid cell split into 4 cells */
99     break;
100   case 6:
101     /* Hex 3D */
102     depthSize[0] = vEnd - vStart + eEnd - eStart + fEnd - fStart + cEnd - cStart; /* Add a vertex on every edge, face and cell */
103     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 */
104     depthSize[2] = 4*(fEnd - fStart) + 12*(cEnd - cStart);                        /* Every face is split into 4 faces, and 12 faces are added for each cell */
105     depthSize[3] = 8*(cEnd - cStart);                                             /* Every cell split into 8 cells */
106     break;
107   case 8:
108     /* Hybrid Hex 3D */
109     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
110     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
111     if (eMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No edge maximum specified in hybrid mesh");
112     /* Hexahedra */
113     depthSize[0] = vEnd - vStart + eMax - eStart + fMax - fStart + cMax - cStart; /* Add a vertex on every edge, face and cell */
114     depthSize[1] = 2*(eMax - eStart) +  4*(fMax - fStart) + 6*(cMax - cStart);    /* Every edge is split into 2 edge, 4 edges are added for each face, and 6 edges for each cell */
115     depthSize[2] = 4*(fMax - fStart) + 12*(cMax - cStart);                        /* Every face is split into 4 faces, and 12 faces are added for each cell */
116     depthSize[3] = 8*(cMax - cStart);                                             /* Every cell split into 8 cells */
117     /* Quadrilateral Prisms */
118     depthSize[0] += 0;                                                            /* No hybrid vertices */
119     depthSize[1] +=   (eEnd - eMax)   +   (fEnd - fMax)   +   (cEnd - cMax);      /* Every hybrid edge remains, 1 edge for every hybrid face and hybrid cell */
120     depthSize[2] += 2*(fEnd - fMax)   + 4*(cEnd - cMax);                          /* Every hybrid face split into 2 faces and 4 faces are added for each hybrid cell */
121     depthSize[3] += 4*(cEnd - cMax);                                              /* Every hybrid cell split into 4 cells */
122     break;
123   default:
124     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
125   }
126   PetscFunctionReturn(0);
127 }
128 
129 /* Return triangle edge for orientation o, if it is r for o == 0 */
130 PETSC_STATIC_INLINE PetscInt GetTriEdge_Static(PetscInt o, PetscInt r) {
131   return (o < 0 ? 2-(o+r) : o+r)%3;
132 }
133 PETSC_STATIC_INLINE PetscInt GetTriEdgeInverse_Static(PetscInt o, PetscInt s) {
134   return (o < 0 ? 2-(o+s) : 3+s-o)%3;
135 }
136 
137 /* Return triangle subface for orientation o, if it is r for o == 0 */
138 PETSC_STATIC_INLINE PetscInt GetTriSubface_Static(PetscInt o, PetscInt r) {
139   return (o < 0 ? 3-(o+r) : o+r)%3;
140 }
141 PETSC_STATIC_INLINE PetscInt GetTriSubfaceInverse_Static(PetscInt o, PetscInt s) {
142   return (o < 0 ? 3-(o+s) : 3+s-o)%3;
143 }
144 
145 /* I HAVE NO IDEA: Return ??? for orientation o, if it is r for o == 0 */
146 PETSC_STATIC_INLINE PetscInt GetTetSomething_Static(PetscInt o, PetscInt r) {
147   return (o < 0 ? 1-(o+r) : o+r)%3;
148 }
149 PETSC_STATIC_INLINE PetscInt GetTetSomethingInverse_Static(PetscInt o, PetscInt s) {
150   return (o < 0 ? 1-(o+s) : 3+s-o)%3;
151 }
152 
153 
154 /* Return quad edge for orientation o, if it is r for o == 0 */
155 PETSC_STATIC_INLINE PetscInt GetQuadEdge_Static(PetscInt o, PetscInt r) {
156   return (o < 0 ? 3-(o+r) : o+r)%4;
157 }
158 PETSC_STATIC_INLINE PetscInt GetQuadEdgeInverse_Static(PetscInt o, PetscInt s) {
159   return (o < 0 ? 3-(o+s) : 4+s-o)%4;
160 }
161 
162 /* Return quad subface for orientation o, if it is r for o == 0 */
163 PETSC_STATIC_INLINE PetscInt GetQuadSubface_Static(PetscInt o, PetscInt r) {
164   return (o < 0 ? 4-(o+r) : o+r)%4;
165 }
166 PETSC_STATIC_INLINE PetscInt GetQuadSubfaceInverse_Static(PetscInt o, PetscInt s) {
167   return (o < 0 ? 4-(o+s) : 4+s-o)%4;
168 }
169 
170 #undef __FUNCT__
171 #define __FUNCT__ "CellRefinerSetConeSizes"
172 static PetscErrorCode CellRefinerSetConeSizes(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
173 {
174   PetscInt       depth, cStart, cStartNew, cEnd, cMax, c, vStart, vStartNew, vEnd, vMax, v, fStart, fStartNew, fEnd, fMax, f, eStart, eStartNew, eEnd, eMax, e, r;
175   PetscErrorCode ierr;
176 
177   PetscFunctionBegin;
178   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
179   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
180   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
181   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
182   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
183   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
184   if (refiner) {ierr = GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);CHKERRQ(ierr);}
185   switch (refiner) {
186   case 0: break;
187   case 1:
188     /* Simplicial 2D */
189     /* All cells have 3 faces */
190     for (c = cStart; c < cEnd; ++c) {
191       for (r = 0; r < 4; ++r) {
192         const PetscInt newp = (c - cStart)*4 + r;
193 
194         ierr = DMPlexSetConeSize(rdm, newp, 3);CHKERRQ(ierr);
195       }
196     }
197     /* Split faces have 2 vertices and the same cells as the parent */
198     for (f = fStart; f < fEnd; ++f) {
199       for (r = 0; r < 2; ++r) {
200         const PetscInt newp = fStartNew + (f - fStart)*2 + r;
201         PetscInt       size;
202 
203         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
204         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
205         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
206       }
207     }
208     /* Interior faces have 2 vertices and 2 cells */
209     for (c = cStart; c < cEnd; ++c) {
210       for (r = 0; r < 3; ++r) {
211         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*3 + r;
212 
213         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
214         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
215       }
216     }
217     /* Old vertices have identical supports */
218     for (v = vStart; v < vEnd; ++v) {
219       const PetscInt newp = vStartNew + (v - vStart);
220       PetscInt       size;
221 
222       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
223       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
224     }
225     /* Face vertices have 2 + cells*2 supports */
226     for (f = fStart; f < fEnd; ++f) {
227       const PetscInt newp = vStartNew + (vEnd - vStart) + (f - fStart);
228       PetscInt       size;
229 
230       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
231       ierr = DMPlexSetSupportSize(rdm, newp, 2 + size*2);CHKERRQ(ierr);
232     }
233     break;
234   case 2:
235     /* Hex 2D */
236     /* All cells have 4 faces */
237     for (c = cStart; c < cEnd; ++c) {
238       for (r = 0; r < 4; ++r) {
239         const PetscInt newp = cStartNew + (c - cStart)*4 + r;
240 
241         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
242       }
243     }
244     /* Split faces have 2 vertices and the same cells as the parent */
245     for (f = fStart; f < fEnd; ++f) {
246       for (r = 0; r < 2; ++r) {
247         const PetscInt newp = fStartNew + (f - fStart)*2 + r;
248         PetscInt       size;
249 
250         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
251         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
252         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
253       }
254     }
255     /* Interior faces have 2 vertices and 2 cells */
256     for (c = cStart; c < cEnd; ++c) {
257       for (r = 0; r < 4; ++r) {
258         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*4 + r;
259 
260         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
261         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
262       }
263     }
264     /* Old vertices have identical supports */
265     for (v = vStart; v < vEnd; ++v) {
266       const PetscInt newp = vStartNew + (v - vStart);
267       PetscInt       size;
268 
269       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
270       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
271     }
272     /* Face vertices have 2 + cells supports */
273     for (f = fStart; f < fEnd; ++f) {
274       const PetscInt newp = vStartNew + (vEnd - vStart) + (f - fStart);
275       PetscInt       size;
276 
277       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
278       ierr = DMPlexSetSupportSize(rdm, newp, 2 + size);CHKERRQ(ierr);
279     }
280     /* Cell vertices have 4 supports */
281     for (c = cStart; c < cEnd; ++c) {
282       const PetscInt newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (c - cStart);
283 
284       ierr = DMPlexSetSupportSize(rdm, newp, 4);CHKERRQ(ierr);
285     }
286     break;
287   case 3:
288     /* Hybrid Simplicial 2D */
289     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
290     cMax = PetscMin(cEnd, cMax);
291     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
292     fMax = PetscMin(fEnd, fMax);
293     ierr = DMPlexSetHybridBounds(rdm, cStartNew + (cMax - cStart)*4, fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3, PETSC_DETERMINE, PETSC_DETERMINE);CHKERRQ(ierr);
294     /* Interior cells have 3 faces */
295     for (c = cStart; c < cMax; ++c) {
296       for (r = 0; r < 4; ++r) {
297         const PetscInt newp = cStartNew + (c - cStart)*4 + r;
298 
299         ierr = DMPlexSetConeSize(rdm, newp, 3);CHKERRQ(ierr);
300       }
301     }
302     /* Hybrid cells have 4 faces */
303     for (c = cMax; c < cEnd; ++c) {
304       for (r = 0; r < 2; ++r) {
305         const PetscInt newp = cStartNew + (cMax - cStart)*4 + (c - cMax)*2 + r;
306 
307         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
308       }
309     }
310     /* Interior split faces have 2 vertices and the same cells as the parent */
311     for (f = fStart; f < fMax; ++f) {
312       for (r = 0; r < 2; ++r) {
313         const PetscInt newp = fStartNew + (f - fStart)*2 + r;
314         PetscInt       size;
315 
316         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
317         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
318         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
319       }
320     }
321     /* Interior cell faces have 2 vertices and 2 cells */
322     for (c = cStart; c < cMax; ++c) {
323       for (r = 0; r < 3; ++r) {
324         const PetscInt newp = fStartNew + (fMax - fStart)*2 + (c - cStart)*3 + r;
325 
326         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
327         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
328       }
329     }
330     /* Hybrid faces have 2 vertices and the same cells */
331     for (f = fMax; f < fEnd; ++f) {
332       const PetscInt newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (f - fMax);
333       PetscInt       size;
334 
335       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
336       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
337       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
338     }
339     /* Hybrid cell faces have 2 vertices and 2 cells */
340     for (c = cMax; c < cEnd; ++c) {
341       const PetscInt newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (fEnd - fMax) + (c - cMax);
342 
343       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
344       ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
345     }
346     /* Old vertices have identical supports */
347     for (v = vStart; v < vEnd; ++v) {
348       const PetscInt newp = vStartNew + (v - vStart);
349       PetscInt       size;
350 
351       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
352       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
353     }
354     /* Face vertices have 2 + (2 interior, 1 hybrid) supports */
355     for (f = fStart; f < fMax; ++f) {
356       const PetscInt newp = vStartNew + (vEnd - vStart) + (f - fStart);
357       const PetscInt *support;
358       PetscInt       size, newSize = 2, s;
359 
360       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
361       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
362       for (s = 0; s < size; ++s) {
363         if (support[s] >= cMax) newSize += 1;
364         else newSize += 2;
365       }
366       ierr = DMPlexSetSupportSize(rdm, newp, newSize);CHKERRQ(ierr);
367     }
368     break;
369   case 4:
370     /* Hybrid Hex 2D */
371     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
372     cMax = PetscMin(cEnd, cMax);
373     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
374     fMax = PetscMin(fEnd, fMax);
375     ierr = DMPlexSetHybridBounds(rdm, cStartNew + (cMax - cStart)*4, fStartNew + (fMax - fStart)*2 + (cMax - cStart)*4, PETSC_DETERMINE, PETSC_DETERMINE);CHKERRQ(ierr);
376     /* Interior cells have 4 faces */
377     for (c = cStart; c < cMax; ++c) {
378       for (r = 0; r < 4; ++r) {
379         const PetscInt newp = cStartNew + (c - cStart)*4 + r;
380 
381         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
382       }
383     }
384     /* Hybrid cells have 4 faces */
385     for (c = cMax; c < cEnd; ++c) {
386       for (r = 0; r < 2; ++r) {
387         const PetscInt newp = cStartNew + (cMax - cStart)*4 + (c - cMax)*2 + r;
388 
389         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
390       }
391     }
392     /* Interior split faces have 2 vertices and the same cells as the parent */
393     for (f = fStart; f < fMax; ++f) {
394       for (r = 0; r < 2; ++r) {
395         const PetscInt newp = fStartNew + (f - fStart)*2 + r;
396         PetscInt       size;
397 
398         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
399         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
400         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
401       }
402     }
403     /* Interior cell faces have 2 vertices and 2 cells */
404     for (c = cStart; c < cMax; ++c) {
405       for (r = 0; r < 4; ++r) {
406         const PetscInt newp = fStartNew + (fMax - fStart)*2 + (c - cStart)*4 + r;
407 
408         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
409         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
410       }
411     }
412     /* Hybrid faces have 2 vertices and the same cells */
413     for (f = fMax; f < fEnd; ++f) {
414       const PetscInt newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*4 + (f - fMax);
415       PetscInt       size;
416 
417       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
418       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
419       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
420     }
421     /* Hybrid cell faces have 2 vertices and 2 cells */
422     for (c = cMax; c < cEnd; ++c) {
423       const PetscInt newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*4 + (fEnd - fMax) + (c - cMax);
424 
425       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
426       ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
427     }
428     /* Old vertices have identical supports */
429     for (v = vStart; v < vEnd; ++v) {
430       const PetscInt newp = vStartNew + (v - vStart);
431       PetscInt       size;
432 
433       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
434       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
435     }
436     /* Face vertices have 2 + cells supports */
437     for (f = fStart; f < fMax; ++f) {
438       const PetscInt newp = vStartNew + (vEnd - vStart) + (f - fStart);
439       PetscInt       size;
440 
441       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
442       ierr = DMPlexSetSupportSize(rdm, newp, 2 + size);CHKERRQ(ierr);
443     }
444     /* Cell vertices have 4 supports */
445     for (c = cStart; c < cMax; ++c) {
446       const PetscInt newp = vStartNew + (vEnd - vStart) + (fMax - fStart) + (c - cStart);
447 
448       ierr = DMPlexSetSupportSize(rdm, newp, 4);CHKERRQ(ierr);
449     }
450     break;
451   case 5:
452     /* Simplicial 3D */
453     /* All cells have 4 faces */
454     for (c = cStart; c < cEnd; ++c) {
455       for (r = 0; r < 8; ++r) {
456         const PetscInt newp = cStartNew + (c - cStart)*8 + r;
457 
458         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
459       }
460     }
461     /* Split faces have 3 edges and the same cells as the parent */
462     for (f = fStart; f < fEnd; ++f) {
463       for (r = 0; r < 4; ++r) {
464         const PetscInt newp = fStartNew + (f - fStart)*4 + r;
465         PetscInt       size;
466 
467         ierr = DMPlexSetConeSize(rdm, newp, 3);CHKERRQ(ierr);
468         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
469         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
470       }
471     }
472     /* Interior cell faces have 3 edges and 2 cells */
473     for (c = cStart; c < cEnd; ++c) {
474       for (r = 0; r < 8; ++r) {
475         const PetscInt newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*8 + r;
476 
477         ierr = DMPlexSetConeSize(rdm, newp, 3);CHKERRQ(ierr);
478         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
479       }
480     }
481     /* Split edges have 2 vertices and the same faces */
482     for (e = eStart; e < eEnd; ++e) {
483       for (r = 0; r < 2; ++r) {
484         const PetscInt newp = eStartNew + (e - eStart)*2 + r;
485         PetscInt       size;
486 
487         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
488         ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
489         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
490       }
491     }
492     /* Face edges have 2 vertices and 2+cells*(1/2) faces */
493     for (f = fStart; f < fEnd; ++f) {
494       for (r = 0; r < 3; ++r) {
495         const PetscInt  newp = eStartNew + (eEnd - eStart)*2 + (f - fStart)*3 + r;
496         const PetscInt *cone, *ornt, *support, eint[4] = {1, 0, 2, 0};
497         PetscInt        coneSize, c, supportSize, s, er, intFaces = 0;
498 
499         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
500         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
501         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
502         for (s = 0; s < supportSize; ++s) {
503           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
504           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
505           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
506           for (c = 0; c < coneSize; ++c) {if (cone[c] == f) break;}
507           /* Here we want to determine whether edge newp contains a vertex which is part of the cross-tet edge */
508           er = GetTetSomethingInverse_Static(ornt[c], r);
509           if (er == eint[c]) {
510             intFaces += 1;
511           } else {
512             intFaces += 2;
513           }
514         }
515         ierr = DMPlexSetSupportSize(rdm, newp, 2+intFaces);CHKERRQ(ierr);
516       }
517     }
518     /* Interior cell edges have 2 vertices and 4 faces */
519     for (c = cStart; c < cEnd; ++c) {
520       const PetscInt newp = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart);
521 
522       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
523       ierr = DMPlexSetSupportSize(rdm, newp, 4);CHKERRQ(ierr);
524     }
525     /* Old vertices have identical supports */
526     for (v = vStart; v < vEnd; ++v) {
527       const PetscInt newp = vStartNew + (v - vStart);
528       PetscInt       size;
529 
530       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
531       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
532     }
533     /* Edge vertices have 2 + faces*2 + cells*0/1 supports */
534     for (e = eStart; e < eEnd; ++e) {
535       const PetscInt newp = vStartNew + (vEnd - vStart) + (e - eStart);
536       PetscInt       size, *star = NULL, starSize, s, cellSize = 0;
537 
538       ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
539       ierr = DMPlexGetTransitiveClosure(dm, e, PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
540       for (s = 0; s < starSize*2; s += 2) {
541         const PetscInt *cone, *ornt;
542         PetscInt        e01, e23;
543 
544         if ((star[s] >= cStart) && (star[s] < cEnd)) {
545           /* Check edge 0-1 */
546           ierr = DMPlexGetCone(dm, star[s], &cone);CHKERRQ(ierr);
547           ierr = DMPlexGetConeOrientation(dm, star[s], &ornt);CHKERRQ(ierr);
548           ierr = DMPlexGetCone(dm, cone[0], &cone);CHKERRQ(ierr);
549           e01  = cone[GetTriEdge_Static(ornt[0], 0)];
550           /* Check edge 2-3 */
551           ierr = DMPlexGetCone(dm, star[s], &cone);CHKERRQ(ierr);
552           ierr = DMPlexGetConeOrientation(dm, star[s], &ornt);CHKERRQ(ierr);
553           ierr = DMPlexGetCone(dm, cone[2], &cone);CHKERRQ(ierr);
554           e23  = cone[GetTriEdge_Static(ornt[2], 1)];
555           if ((e01 == e) || (e23 == e)) ++cellSize;
556         }
557       }
558       ierr = DMPlexRestoreTransitiveClosure(dm, e, PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
559       ierr = DMPlexSetSupportSize(rdm, newp, 2 + size*2 + cellSize);CHKERRQ(ierr);
560     }
561     break;
562   case 7:
563     /* Hybrid Simplicial 3D */
564     ierr = DMPlexSetHybridBounds(rdm, cStartNew + 8*(cMax-cStart), fStartNew + 4*(fMax - fStart) + 8*(cMax - cStart),
565                                  eStartNew + 2*(eMax - eStart) + 3*(fMax - fStart) + (cMax - cStart), PETSC_DETERMINE);CHKERRQ(ierr);
566     /* Interior cells have 4 faces */
567     for (c = cStart; c < cMax; ++c) {
568       for (r = 0; r < 8; ++r) {
569         const PetscInt newp = cStartNew + (c - cStart)*8 + r;
570 
571         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
572       }
573     }
574     /* Hybrid cells have 5 faces */
575     for (c = cMax; c < cEnd; ++c) {
576       for (r = 0; r < 4; ++r) {
577         const PetscInt newp = cStartNew + (cMax - cStart)*8 + (c - cMax)*4 + r;
578 
579         ierr = DMPlexSetConeSize(rdm, newp, 5);CHKERRQ(ierr);
580       }
581     }
582     /* Interior split faces have 3 edges and the same cells as the parent */
583     for (f = fStart; f < fMax; ++f) {
584       for (r = 0; r < 4; ++r) {
585         const PetscInt newp = fStartNew + (f - fStart)*4 + r;
586         PetscInt       size;
587 
588         ierr = DMPlexSetConeSize(rdm, newp, 3);CHKERRQ(ierr);
589         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
590         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
591       }
592     }
593     /* Interior cell faces have 3 edges and 2 cells */
594     for (c = cStart; c < cMax; ++c) {
595       for (r = 0; r < 8; ++r) {
596         const PetscInt newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*8 + r;
597 
598         ierr = DMPlexSetConeSize(rdm, newp, 3);CHKERRQ(ierr);
599         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
600       }
601     }
602     /* Hybrid split faces have 4 edges and the same cells as the parent */
603     for (f = fMax; f < fEnd; ++f) {
604       for (r = 0; r < 2; ++r) {
605         const PetscInt newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (f - fMax)*2 + r;
606         PetscInt       size;
607 
608         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
609         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
610         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
611       }
612     }
613     /* Hybrid cells faces have 4 edges and 2 cells */
614     for (c = cMax; c < cEnd; ++c) {
615       for (r = 0; r < 3; ++r) {
616         const PetscInt newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (c - cMax)*3 + r;
617 
618         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
619         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
620       }
621     }
622     /* Interior split edges have 2 vertices and the same faces */
623     for (e = eStart; e < eMax; ++e) {
624       for (r = 0; r < 2; ++r) {
625         const PetscInt newp = eStartNew + (e - eStart)*2 + r;
626         PetscInt       size;
627 
628         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
629         ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
630         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
631       }
632     }
633     /* Interior face edges have 2 vertices and 2+cells*(1/2) faces */
634     for (f = fStart; f < fMax; ++f) {
635       for (r = 0; r < 3; ++r) {
636         const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (f - fStart)*3 + r;
637         const PetscInt *cone, *ornt, *support, eint[4] = {1, 0, 2, 0};
638         PetscInt        coneSize, c, supportSize, s, er, intFaces = 0;
639 
640         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
641         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
642         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
643         for (s = 0; s < supportSize; ++s) {
644           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
645           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
646           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
647           for (c = 0; c < coneSize; ++c) {if (cone[c] == f) break;}
648           if (support[s] < cMax) {
649             /* Here we want to determine whether edge newp contains a vertex which is part of the cross-tet edge */
650             er = GetTetSomethingInverse_Static(ornt[c], r);
651             if (er == eint[c]) {
652               intFaces += 1;
653             } else {
654               intFaces += 2;
655             }
656           } else {
657             intFaces += 1;
658           }
659         }
660         ierr = DMPlexSetSupportSize(rdm, newp, 2+intFaces);CHKERRQ(ierr);
661       }
662     }
663     /* Interior cell edges have 2 vertices and 4 faces */
664     for (c = cStart; c < cMax; ++c) {
665       const PetscInt newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart);
666 
667       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
668       ierr = DMPlexSetSupportSize(rdm, newp, 4);CHKERRQ(ierr);
669     }
670     /* Hybrid edges have 2 vertices and the same faces */
671     for (e = eMax; e < eEnd; ++e) {
672       const PetscInt newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (e - eMax);
673       PetscInt       size;
674 
675       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
676       ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
677       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
678     }
679     /* Hybrid face edges have 2 vertices and 2+2*cells faces */
680     for (f = fMax; f < fEnd; ++f) {
681       const PetscInt newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (eEnd - eMax) + (f - fMax);
682       PetscInt       size;
683 
684       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
685       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
686       ierr = DMPlexSetSupportSize(rdm, newp, 2+2*size);CHKERRQ(ierr);
687     }
688     /* Interior vertices have identical supports */
689     for (v = vStart; v < vEnd; ++v) {
690       const PetscInt newp = vStartNew + (v - vStart);
691       PetscInt       size;
692 
693       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
694       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
695     }
696     /* Interior edge vertices have 2 + interior face*2 + hybrid face + cells*0/1 supports */
697     for (e = eStart; e < eMax; ++e) {
698       const PetscInt  newp = vStartNew + (vEnd - vStart) + (e - eStart);
699       const PetscInt *support;
700       PetscInt        size, *star = NULL, starSize, s, faceSize = 0, cellSize = 0;
701 
702       ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
703       ierr = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
704       for (s = 0; s < size; ++s) {
705         if (support[s] < fMax) faceSize += 2;
706         else                   faceSize += 1;
707       }
708       ierr = DMPlexGetTransitiveClosure(dm, e, PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
709       for (s = 0; s < starSize*2; s += 2) {
710         const PetscInt *cone, *ornt;
711         PetscInt        e01, e23;
712 
713         if ((star[s] >= cStart) && (star[s] < cMax)) {
714           /* Check edge 0-1 */
715           ierr = DMPlexGetCone(dm, star[s], &cone);CHKERRQ(ierr);
716           ierr = DMPlexGetConeOrientation(dm, star[s], &ornt);CHKERRQ(ierr);
717           ierr = DMPlexGetCone(dm, cone[0], &cone);CHKERRQ(ierr);
718           e01  = cone[GetTriEdge_Static(ornt[0], 0)];
719           /* Check edge 2-3 */
720           ierr = DMPlexGetCone(dm, star[s], &cone);CHKERRQ(ierr);
721           ierr = DMPlexGetConeOrientation(dm, star[s], &ornt);CHKERRQ(ierr);
722           ierr = DMPlexGetCone(dm, cone[2], &cone);CHKERRQ(ierr);
723           e23  = cone[GetTriEdge_Static(ornt[2], 1)];
724           if ((e01 == e) || (e23 == e)) ++cellSize;
725         }
726       }
727       ierr = DMPlexRestoreTransitiveClosure(dm, e, PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
728       ierr = DMPlexSetSupportSize(rdm, newp, 2 + faceSize + cellSize);CHKERRQ(ierr);
729     }
730     break;
731   case 6:
732     /* Hex 3D */
733     /* All cells have 6 faces */
734     for (c = cStart; c < cEnd; ++c) {
735       for (r = 0; r < 8; ++r) {
736         const PetscInt newp = (c - cStart)*8 + r;
737 
738         ierr = DMPlexSetConeSize(rdm, newp, 6);CHKERRQ(ierr);
739       }
740     }
741     /* Split faces have 4 edges and the same cells as the parent */
742     for (f = fStart; f < fEnd; ++f) {
743       for (r = 0; r < 4; ++r) {
744         const PetscInt newp = fStartNew + (f - fStart)*4 + r;
745         PetscInt       size;
746 
747         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
748         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
749         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
750       }
751     }
752     /* Interior faces have 4 edges and 2 cells */
753     for (c = cStart; c < cEnd; ++c) {
754       for (r = 0; r < 12; ++r) {
755         const PetscInt newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + r;
756 
757         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
758         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
759       }
760     }
761     /* Split edges have 2 vertices and the same faces as the parent */
762     for (e = eStart; e < eEnd; ++e) {
763       for (r = 0; r < 2; ++r) {
764         const PetscInt newp = eStartNew + (e - eStart)*2 + r;
765         PetscInt       size;
766 
767         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
768         ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
769         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
770       }
771     }
772     /* Face edges have 2 vertices and 2+cells faces */
773     for (f = fStart; f < fEnd; ++f) {
774       for (r = 0; r < 4; ++r) {
775         const PetscInt newp = eStartNew + (eEnd - eStart)*2 + (f - fStart)*4 + r;
776         PetscInt       size;
777 
778         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
779         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
780         ierr = DMPlexSetSupportSize(rdm, newp, 2+size);CHKERRQ(ierr);
781       }
782     }
783     /* Cell edges have 2 vertices and 4 faces */
784     for (c = cStart; c < cEnd; ++c) {
785       for (r = 0; r < 6; ++r) {
786         const PetscInt newp = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*4 + (c - cStart)*6 + r;
787 
788         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
789         ierr = DMPlexSetSupportSize(rdm, newp, 4);CHKERRQ(ierr);
790       }
791     }
792     /* Old vertices have identical supports */
793     for (v = vStart; v < vEnd; ++v) {
794       const PetscInt newp = vStartNew + (v - vStart);
795       PetscInt       size;
796 
797       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
798       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
799     }
800     /* Edge vertices have 2 + faces supports */
801     for (e = eStart; e < eEnd; ++e) {
802       const PetscInt newp = vStartNew + (vEnd - vStart) + (e - eStart);
803       PetscInt       size;
804 
805       ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
806       ierr = DMPlexSetSupportSize(rdm, newp, 2 + size);CHKERRQ(ierr);
807     }
808     /* Face vertices have 4 + cells supports */
809     for (f = fStart; f < fEnd; ++f) {
810       const PetscInt newp = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (f - fStart);
811       PetscInt       size;
812 
813       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
814       ierr = DMPlexSetSupportSize(rdm, newp, 4 + size);CHKERRQ(ierr);
815     }
816     /* Cell vertices have 6 supports */
817     for (c = cStart; c < cEnd; ++c) {
818       const PetscInt newp = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (fEnd - fStart) + (c - cStart);
819 
820       ierr = DMPlexSetSupportSize(rdm, newp, 6);CHKERRQ(ierr);
821     }
822     break;
823   case 8:
824     /* Hybrid Hex 3D */
825     ierr = DMPlexSetHybridBounds(rdm, cStartNew + 8*(cMax-cStart), fStartNew + 4*(fMax - fStart) + 12*(cMax - cStart),
826                                  eStartNew + 2*(eMax - eStart) + 4*(fMax - fStart) + 6*(cMax - cStart), PETSC_DETERMINE);CHKERRQ(ierr);
827     /* Interior cells have 6 faces */
828     for (c = cStart; c < cMax; ++c) {
829       for (r = 0; r < 8; ++r) {
830         const PetscInt newp = cStartNew + (c - cStart)*8 + r;
831 
832         ierr = DMPlexSetConeSize(rdm, newp, 6);CHKERRQ(ierr);
833       }
834     }
835     /* Hybrid cells have 6 faces */
836     for (c = cMax; c < cEnd; ++c) {
837       for (r = 0; r < 4; ++r) {
838         const PetscInt newp = cStartNew + (cMax - cStart)*8 + (c - cMax)*4 + r;
839 
840         ierr = DMPlexSetConeSize(rdm, newp, 6);CHKERRQ(ierr);
841       }
842     }
843     /* Interior split faces have 4 edges and the same cells as the parent */
844     for (f = fStart; f < fMax; ++f) {
845       for (r = 0; r < 4; ++r) {
846         const PetscInt newp = fStartNew + (f - fStart)*4 + r;
847         PetscInt       size;
848 
849         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
850         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
851         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
852       }
853     }
854     /* Interior cell faces have 4 edges and 2 cells */
855     for (c = cStart; c < cMax; ++c) {
856       for (r = 0; r < 12; ++r) {
857         const PetscInt newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + r;
858 
859         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
860         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
861       }
862     }
863     /* Hybrid split faces have 4 edges and the same cells as the parent */
864     for (f = fMax; f < fEnd; ++f) {
865       for (r = 0; r < 2; ++r) {
866         const PetscInt newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (f - fMax)*2 + r;
867         PetscInt       size;
868 
869         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
870         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
871         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
872       }
873     }
874     /* Hybrid cells faces have 4 edges and 2 cells */
875     for (c = cMax; c < cEnd; ++c) {
876       for (r = 0; r < 4; ++r) {
877         const PetscInt newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd - fMax)*2 + (c - cMax)*4 + r;
878 
879         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
880         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
881       }
882     }
883     /* Interior split edges have 2 vertices and the same faces as the parent */
884     for (e = eStart; e < eMax; ++e) {
885       for (r = 0; r < 2; ++r) {
886         const PetscInt newp = eStartNew + (e - eStart)*2 + r;
887         PetscInt       size;
888 
889         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
890         ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
891         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
892       }
893     }
894     /* Interior face edges have 2 vertices and 2+cells faces */
895     for (f = fStart; f < fMax; ++f) {
896       for (r = 0; r < 4; ++r) {
897         const PetscInt newp = eStartNew + (eMax - eStart)*2 + (f - fStart)*4 + r;
898         PetscInt       size;
899 
900         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
901         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
902         ierr = DMPlexSetSupportSize(rdm, newp, 2+size);CHKERRQ(ierr);
903       }
904     }
905     /* Interior cell edges have 2 vertices and 4 faces */
906     for (c = cStart; c < cMax; ++c) {
907       for (r = 0; r < 6; ++r) {
908         const PetscInt newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (c - cStart)*6 + r;
909 
910         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
911         ierr = DMPlexSetSupportSize(rdm, newp, 4);CHKERRQ(ierr);
912       }
913     }
914     /* Hybrid edges have 2 vertices and the same faces */
915     for (e = eMax; e < eEnd; ++e) {
916       const PetscInt newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (e - eMax);
917       PetscInt       size;
918 
919       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
920       ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
921       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
922     }
923     /* Hybrid face edges have 2 vertices and 2+cells faces */
924     for (f = fMax; f < fEnd; ++f) {
925       const PetscInt newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (eEnd - eMax) + (f - fMax);
926       PetscInt       size;
927 
928       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
929       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
930       ierr = DMPlexSetSupportSize(rdm, newp, 2+size);CHKERRQ(ierr);
931     }
932     /* Hybrid cell edges have 2 vertices and 4 faces */
933     for (c = cMax; c < cEnd; ++c) {
934       const PetscInt newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (eEnd - eMax) + (fEnd - fMax) + (c - cMax);
935 
936       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
937       ierr = DMPlexSetSupportSize(rdm, newp, 4);CHKERRQ(ierr);
938     }
939     /* Interior vertices have identical supports */
940     for (v = vStart; v < vEnd; ++v) {
941       const PetscInt newp = vStartNew + (v - vStart);
942       PetscInt       size;
943 
944       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
945       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
946     }
947     /* Interior edge vertices have 2 + faces supports */
948     for (e = eStart; e < eMax; ++e) {
949       const PetscInt newp = vStartNew + (vEnd - vStart) + (e - eStart);
950       PetscInt       size;
951 
952       ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
953       ierr = DMPlexSetSupportSize(rdm, newp, 2 + size);CHKERRQ(ierr);
954     }
955     /* Interior face vertices have 4 + cells supports */
956     for (f = fStart; f < fMax; ++f) {
957       const PetscInt newp = vStartNew + (vEnd - vStart) + (eMax - eStart) + (f - fStart);
958       PetscInt       size;
959 
960       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
961       ierr = DMPlexSetSupportSize(rdm, newp, 4 + size);CHKERRQ(ierr);
962     }
963     /* Interior cell vertices have 6 supports */
964     for (c = cStart; c < cMax; ++c) {
965       const PetscInt newp = vStartNew + (vEnd - vStart) + (eMax - eStart) + (fMax - fStart) + (c - cStart);
966 
967       ierr = DMPlexSetSupportSize(rdm, newp, 6);CHKERRQ(ierr);
968     }
969     break;
970   default:
971     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
972   }
973   PetscFunctionReturn(0);
974 }
975 
976 #undef __FUNCT__
977 #define __FUNCT__ "CellRefinerSetCones"
978 static PetscErrorCode CellRefinerSetCones(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
979 {
980   const PetscInt *faces, cellInd[4] = {0, 1, 2, 3};
981   PetscInt        cStart,    cEnd,    cMax,    vStart,    vEnd, vMax, fStart,    fEnd,    fMax,    eStart,    eEnd,    eMax;
982   PetscInt        cStartNew, cEndNew, cMaxNew, vStartNew, vEndNew,    fStartNew, fEndNew, fMaxNew, eStartNew, eEndNew, eMaxNew;
983   PetscInt        depth, maxSupportSize, *supportRef, c, f, e, v, r, p;
984   PetscErrorCode  ierr;
985 
986   PetscFunctionBegin;
987   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
988   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
989   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
990   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
991   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
992   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
993   if (refiner) {
994     ierr = GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);CHKERRQ(ierr);
995     ierr = GetDepthEnd_Private(depth, depthSize, &cEndNew, &fEndNew, &eEndNew, &vEndNew);CHKERRQ(ierr);
996   }
997   switch (refiner) {
998   case 0: break;
999   case 1:
1000     /* Simplicial 2D */
1001     /*
1002      2
1003      |\
1004      | \
1005      |  \
1006      |   \
1007      | C  \
1008      |     \
1009      |      \
1010      2---1---1
1011      |\  D  / \
1012      | 2   0   \
1013      |A \ /  B  \
1014      0---0-------1
1015      */
1016     /* All cells have 3 faces */
1017     for (c = cStart; c < cEnd; ++c) {
1018       const PetscInt  newp = cStartNew + (c - cStart)*4;
1019       const PetscInt *cone, *ornt;
1020       PetscInt        coneNew[3], orntNew[3];
1021 
1022       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
1023       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
1024       /* A triangle */
1025       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
1026       orntNew[0] = ornt[0];
1027       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 2;
1028       orntNew[1] = -2;
1029       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
1030       orntNew[2] = ornt[2];
1031       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
1032       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
1033 #if 1
1034       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);
1035       for (p = 0; p < 3; ++p) {
1036         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);
1037       }
1038 #endif
1039       /* B triangle */
1040       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
1041       orntNew[0] = ornt[0];
1042       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
1043       orntNew[1] = ornt[1];
1044       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 0;
1045       orntNew[2] = -2;
1046       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
1047       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
1048 #if 1
1049       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);
1050       for (p = 0; p < 3; ++p) {
1051         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);
1052       }
1053 #endif
1054       /* C triangle */
1055       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 1;
1056       orntNew[0] = -2;
1057       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
1058       orntNew[1] = ornt[1];
1059       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
1060       orntNew[2] = ornt[2];
1061       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
1062       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
1063 #if 1
1064       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);
1065       for (p = 0; p < 3; ++p) {
1066         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);
1067       }
1068 #endif
1069       /* D triangle */
1070       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 0;
1071       orntNew[0] = 0;
1072       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 1;
1073       orntNew[1] = 0;
1074       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 2;
1075       orntNew[2] = 0;
1076       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
1077       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
1078 #if 1
1079       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);
1080       for (p = 0; p < 3; ++p) {
1081         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);
1082       }
1083 #endif
1084     }
1085     /* Split faces have 2 vertices and the same cells as the parent */
1086     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
1087     ierr = PetscMalloc1((2 + maxSupportSize*2), &supportRef);CHKERRQ(ierr);
1088     for (f = fStart; f < fEnd; ++f) {
1089       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);
1090 
1091       for (r = 0; r < 2; ++r) {
1092         const PetscInt  newp = fStartNew + (f - fStart)*2 + r;
1093         const PetscInt *cone, *ornt, *support;
1094         PetscInt        coneNew[2], coneSize, c, supportSize, s;
1095 
1096         ierr             = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
1097         coneNew[0]       = vStartNew + (cone[0] - vStart);
1098         coneNew[1]       = vStartNew + (cone[1] - vStart);
1099         coneNew[(r+1)%2] = newv;
1100         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
1101 #if 1
1102         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1103         for (p = 0; p < 2; ++p) {
1104           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);
1105         }
1106 #endif
1107         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
1108         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
1109         for (s = 0; s < supportSize; ++s) {
1110           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
1111           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
1112           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
1113           for (c = 0; c < coneSize; ++c) {
1114             if (cone[c] == f) break;
1115           }
1116           supportRef[s] = cStartNew + (support[s] - cStart)*4 + (ornt[c] < 0 ? (c+1-r)%3 : (c+r)%3);
1117         }
1118         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
1119 #if 1
1120         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1121         for (p = 0; p < supportSize; ++p) {
1122           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);
1123         }
1124 #endif
1125       }
1126     }
1127     /* Interior faces have 2 vertices and 2 cells */
1128     for (c = cStart; c < cEnd; ++c) {
1129       const PetscInt *cone;
1130 
1131       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
1132       for (r = 0; r < 3; ++r) {
1133         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*3 + r;
1134         PetscInt       coneNew[2];
1135         PetscInt       supportNew[2];
1136 
1137         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r]       - fStart);
1138         coneNew[1] = vStartNew + (vEnd - vStart) + (cone[(r+1)%3] - fStart);
1139         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
1140 #if 1
1141         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1142         for (p = 0; p < 2; ++p) {
1143           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);
1144         }
1145 #endif
1146         supportNew[0] = (c - cStart)*4 + (r+1)%3;
1147         supportNew[1] = (c - cStart)*4 + 3;
1148         ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
1149 #if 1
1150         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1151         for (p = 0; p < 2; ++p) {
1152           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);
1153         }
1154 #endif
1155       }
1156     }
1157     /* Old vertices have identical supports */
1158     for (v = vStart; v < vEnd; ++v) {
1159       const PetscInt  newp = vStartNew + (v - vStart);
1160       const PetscInt *support, *cone;
1161       PetscInt        size, s;
1162 
1163       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
1164       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
1165       for (s = 0; s < size; ++s) {
1166         PetscInt r = 0;
1167 
1168         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
1169         if (cone[1] == v) r = 1;
1170         supportRef[s] = fStartNew + (support[s] - fStart)*2 + r;
1171       }
1172       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
1173 #if 1
1174       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
1175       for (p = 0; p < size; ++p) {
1176         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);
1177       }
1178 #endif
1179     }
1180     /* Face vertices have 2 + cells*2 supports */
1181     for (f = fStart; f < fEnd; ++f) {
1182       const PetscInt  newp = vStartNew + (vEnd - vStart) + (f - fStart);
1183       const PetscInt *cone, *support;
1184       PetscInt        size, s;
1185 
1186       ierr          = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
1187       ierr          = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
1188       supportRef[0] = fStartNew + (f - fStart)*2 + 0;
1189       supportRef[1] = fStartNew + (f - fStart)*2 + 1;
1190       for (s = 0; s < size; ++s) {
1191         PetscInt r = 0;
1192 
1193         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
1194         if      (cone[1] == f) r = 1;
1195         else if (cone[2] == f) r = 2;
1196         supportRef[2+s*2+0] = fStartNew + (fEnd - fStart)*2 + (support[s] - cStart)*3 + (r+2)%3;
1197         supportRef[2+s*2+1] = fStartNew + (fEnd - fStart)*2 + (support[s] - cStart)*3 + r;
1198       }
1199       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
1200 #if 1
1201       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
1202       for (p = 0; p < 2+size*2; ++p) {
1203         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);
1204       }
1205 #endif
1206     }
1207     ierr = PetscFree(supportRef);CHKERRQ(ierr);
1208     break;
1209   case 2:
1210     /* Hex 2D */
1211     /*
1212      3---------2---------2
1213      |         |         |
1214      |    D    2    C    |
1215      |         |         |
1216      3----3----0----1----1
1217      |         |         |
1218      |    A    0    B    |
1219      |         |         |
1220      0---------0---------1
1221      */
1222     /* All cells have 4 faces */
1223     for (c = cStart; c < cEnd; ++c) {
1224       const PetscInt  newp = (c - cStart)*4;
1225       const PetscInt *cone, *ornt;
1226       PetscInt        coneNew[4], orntNew[4];
1227 
1228       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
1229       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
1230       /* A quad */
1231       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
1232       orntNew[0] = ornt[0];
1233       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 0;
1234       orntNew[1] = 0;
1235       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 3;
1236       orntNew[2] = -2;
1237       coneNew[3] = fStartNew + (cone[3] - fStart)*2 + (ornt[3] < 0 ? 0 : 1);
1238       orntNew[3] = ornt[3];
1239       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
1240       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
1241 #if 1
1242       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);
1243       for (p = 0; p < 4; ++p) {
1244         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);
1245       }
1246 #endif
1247       /* B quad */
1248       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
1249       orntNew[0] = ornt[0];
1250       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
1251       orntNew[1] = ornt[1];
1252       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 1;
1253       orntNew[2] = 0;
1254       coneNew[3] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 0;
1255       orntNew[3] = -2;
1256       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
1257       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
1258 #if 1
1259       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);
1260       for (p = 0; p < 4; ++p) {
1261         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);
1262       }
1263 #endif
1264       /* C quad */
1265       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 1;
1266       orntNew[0] = -2;
1267       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
1268       orntNew[1] = ornt[1];
1269       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
1270       orntNew[2] = ornt[2];
1271       coneNew[3] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 2;
1272       orntNew[3] = 0;
1273       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
1274       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
1275 #if 1
1276       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);
1277       for (p = 0; p < 4; ++p) {
1278         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);
1279       }
1280 #endif
1281       /* D quad */
1282       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 3;
1283       orntNew[0] = 0;
1284       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 2;
1285       orntNew[1] = -2;
1286       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
1287       orntNew[2] = ornt[2];
1288       coneNew[3] = fStartNew + (cone[3] - fStart)*2 + (ornt[3] < 0 ? 1 : 0);
1289       orntNew[3] = ornt[3];
1290       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
1291       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
1292 #if 1
1293       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);
1294       for (p = 0; p < 4; ++p) {
1295         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);
1296       }
1297 #endif
1298     }
1299     /* Split faces have 2 vertices and the same cells as the parent */
1300     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
1301     ierr = PetscMalloc1((2 + maxSupportSize*2), &supportRef);CHKERRQ(ierr);
1302     for (f = fStart; f < fEnd; ++f) {
1303       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);
1304 
1305       for (r = 0; r < 2; ++r) {
1306         const PetscInt  newp = fStartNew + (f - fStart)*2 + r;
1307         const PetscInt *cone, *ornt, *support;
1308         PetscInt        coneNew[2], coneSize, c, supportSize, s;
1309 
1310         ierr             = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
1311         coneNew[0]       = vStartNew + (cone[0] - vStart);
1312         coneNew[1]       = vStartNew + (cone[1] - vStart);
1313         coneNew[(r+1)%2] = newv;
1314         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
1315 #if 1
1316         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1317         for (p = 0; p < 2; ++p) {
1318           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);
1319         }
1320 #endif
1321         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
1322         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
1323         for (s = 0; s < supportSize; ++s) {
1324           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
1325           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
1326           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
1327           for (c = 0; c < coneSize; ++c) {
1328             if (cone[c] == f) break;
1329           }
1330           supportRef[s] = cStartNew + (support[s] - cStart)*4 + (ornt[c] < 0 ? (c+1-r)%4 : (c+r)%4);
1331         }
1332         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
1333 #if 1
1334         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1335         for (p = 0; p < supportSize; ++p) {
1336           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);
1337         }
1338 #endif
1339       }
1340     }
1341     /* Interior faces have 2 vertices and 2 cells */
1342     for (c = cStart; c < cEnd; ++c) {
1343       const PetscInt *cone;
1344       PetscInt        coneNew[2], supportNew[2];
1345 
1346       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
1347       for (r = 0; r < 4; ++r) {
1348         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*4 + r;
1349 
1350         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r] - fStart);
1351         coneNew[1] = vStartNew + (vEnd - vStart) + (fEnd    - fStart) + (c - cStart);
1352         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
1353 #if 1
1354         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1355         for (p = 0; p < 2; ++p) {
1356           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);
1357         }
1358 #endif
1359         supportNew[0] = (c - cStart)*4 + r;
1360         supportNew[1] = (c - cStart)*4 + (r+1)%4;
1361         ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
1362 #if 1
1363         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1364         for (p = 0; p < 2; ++p) {
1365           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);
1366         }
1367 #endif
1368       }
1369     }
1370     /* Old vertices have identical supports */
1371     for (v = vStart; v < vEnd; ++v) {
1372       const PetscInt  newp = vStartNew + (v - vStart);
1373       const PetscInt *support, *cone;
1374       PetscInt        size, s;
1375 
1376       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
1377       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
1378       for (s = 0; s < size; ++s) {
1379         PetscInt r = 0;
1380 
1381         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
1382         if (cone[1] == v) r = 1;
1383         supportRef[s] = fStartNew + (support[s] - fStart)*2 + r;
1384       }
1385       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
1386 #if 1
1387       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
1388       for (p = 0; p < size; ++p) {
1389         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);
1390       }
1391 #endif
1392     }
1393     /* Face vertices have 2 + cells supports */
1394     for (f = fStart; f < fEnd; ++f) {
1395       const PetscInt  newp = vStartNew + (vEnd - vStart) + (f - fStart);
1396       const PetscInt *cone, *support;
1397       PetscInt        size, s;
1398 
1399       ierr          = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
1400       ierr          = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
1401       supportRef[0] = fStartNew + (f - fStart)*2 + 0;
1402       supportRef[1] = fStartNew + (f - fStart)*2 + 1;
1403       for (s = 0; s < size; ++s) {
1404         PetscInt r = 0;
1405 
1406         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
1407         if      (cone[1] == f) r = 1;
1408         else if (cone[2] == f) r = 2;
1409         else if (cone[3] == f) r = 3;
1410         supportRef[2+s] = fStartNew + (fEnd - fStart)*2 + (support[s] - cStart)*4 + r;
1411       }
1412       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
1413 #if 1
1414       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
1415       for (p = 0; p < 2+size; ++p) {
1416         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);
1417       }
1418 #endif
1419     }
1420     /* Cell vertices have 4 supports */
1421     for (c = cStart; c < cEnd; ++c) {
1422       const PetscInt newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (c - cStart);
1423       PetscInt       supportNew[4];
1424 
1425       for (r = 0; r < 4; ++r) {
1426         supportNew[r] = fStartNew + (fEnd - fStart)*2 + (c - cStart)*4 + r;
1427       }
1428       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
1429     }
1430     ierr = PetscFree(supportRef);CHKERRQ(ierr);
1431     break;
1432   case 3:
1433     /* Hybrid Simplicial 2D */
1434     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
1435     cMax = PetscMin(cEnd, cMax);
1436     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
1437     fMax = PetscMin(fEnd, fMax);
1438     ierr = DMPlexGetHybridBounds(rdm, &cMaxNew, &fMaxNew, NULL, NULL);CHKERRQ(ierr);
1439     /* Interior cells have 3 faces */
1440     for (c = cStart; c < cMax; ++c) {
1441       const PetscInt  newp = cStartNew + (c - cStart)*4;
1442       const PetscInt *cone, *ornt;
1443       PetscInt        coneNew[3], orntNew[3];
1444 
1445       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
1446       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
1447       /* A triangle */
1448       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
1449       orntNew[0] = ornt[0];
1450       coneNew[1] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 2;
1451       orntNew[1] = -2;
1452       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
1453       orntNew[2] = ornt[2];
1454       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
1455       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
1456 #if 1
1457       if ((newp+0 < cStartNew) || (newp+0 >= cMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an interior cell [%d, %d)", newp+0, cStartNew, cMaxNew);
1458       for (p = 0; p < 3; ++p) {
1459         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an interior face [%d, %d)", coneNew[p], fStartNew, fMaxNew);
1460       }
1461 #endif
1462       /* B triangle */
1463       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
1464       orntNew[0] = ornt[0];
1465       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
1466       orntNew[1] = ornt[1];
1467       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 0;
1468       orntNew[2] = -2;
1469       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
1470       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
1471 #if 1
1472       if ((newp+1 < cStartNew) || (newp+1 >= cMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an interior cell [%d, %d)", newp+1, cStartNew, cMaxNew);
1473       for (p = 0; p < 3; ++p) {
1474         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an interior face [%d, %d)", coneNew[p], fStartNew, fMaxNew);
1475       }
1476 #endif
1477       /* C triangle */
1478       coneNew[0] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 1;
1479       orntNew[0] = -2;
1480       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
1481       orntNew[1] = ornt[1];
1482       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
1483       orntNew[2] = ornt[2];
1484       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
1485       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
1486 #if 1
1487       if ((newp+2 < cStartNew) || (newp+2 >= cMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an interior cell [%d, %d)", newp+2, cStartNew, cMaxNew);
1488       for (p = 0; p < 3; ++p) {
1489         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an interior face [%d, %d)", coneNew[p], fStartNew, fMaxNew);
1490       }
1491 #endif
1492       /* D triangle */
1493       coneNew[0] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 0;
1494       orntNew[0] = 0;
1495       coneNew[1] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 1;
1496       orntNew[1] = 0;
1497       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 2;
1498       orntNew[2] = 0;
1499       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
1500       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
1501 #if 1
1502       if ((newp+3 < cStartNew) || (newp+3 >= cMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an interior cell [%d, %d)", newp+3, cStartNew, cMaxNew);
1503       for (p = 0; p < 3; ++p) {
1504         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an interior face [%d, %d)", coneNew[p], fStartNew, fMaxNew);
1505       }
1506 #endif
1507     }
1508     /*
1509      2----3----3
1510      |         |
1511      |    B    |
1512      |         |
1513      0----4--- 1
1514      |         |
1515      |    A    |
1516      |         |
1517      0----2----1
1518      */
1519     /* Hybrid cells have 4 faces */
1520     for (c = cMax; c < cEnd; ++c) {
1521       const PetscInt  newp = cStartNew + (cMax - cStart)*4 + (c - cMax)*2;
1522       const PetscInt *cone, *ornt;
1523       PetscInt        coneNew[4], orntNew[4], r;
1524 
1525       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
1526       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
1527       r    = (ornt[0] < 0 ? 1 : 0);
1528       /* A quad */
1529       coneNew[0]   = fStartNew + (cone[0] - fStart)*2 + r;
1530       orntNew[0]   = ornt[0];
1531       coneNew[1]   = fStartNew + (cone[1] - fStart)*2 + r;
1532       orntNew[1]   = ornt[1];
1533       coneNew[2+r] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (cone[2+r] - fMax);
1534       orntNew[2+r] = 0;
1535       coneNew[3-r] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (fEnd    - fMax) + (c - cMax);
1536       orntNew[3-r] = 0;
1537       ierr = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
1538       ierr = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
1539 #if 1
1540       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);
1541       for (p = 0; p < 4; ++p) {
1542         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);
1543       }
1544 #endif
1545       /* B quad */
1546       coneNew[0]   = fStartNew + (cone[0] - fStart)*2 + 1-r;
1547       orntNew[0]   = ornt[0];
1548       coneNew[1]   = fStartNew + (cone[1] - fStart)*2 + 1-r;
1549       orntNew[1]   = ornt[1];
1550       coneNew[2+r] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (fEnd    - fMax) + (c - cMax);
1551       orntNew[2+r] = 0;
1552       coneNew[3-r] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (cone[3-r] - fMax);
1553       orntNew[3-r] = 0;
1554       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
1555       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
1556 #if 1
1557       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);
1558       for (p = 0; p < 4; ++p) {
1559         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);
1560       }
1561 #endif
1562     }
1563     /* Interior split faces have 2 vertices and the same cells as the parent */
1564     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
1565     ierr = PetscMalloc1((2 + maxSupportSize*2), &supportRef);CHKERRQ(ierr);
1566     for (f = fStart; f < fMax; ++f) {
1567       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);
1568 
1569       for (r = 0; r < 2; ++r) {
1570         const PetscInt  newp = fStartNew + (f - fStart)*2 + r;
1571         const PetscInt *cone, *ornt, *support;
1572         PetscInt        coneNew[2], coneSize, c, supportSize, s;
1573 
1574         ierr             = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
1575         coneNew[0]       = vStartNew + (cone[0] - vStart);
1576         coneNew[1]       = vStartNew + (cone[1] - vStart);
1577         coneNew[(r+1)%2] = newv;
1578         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
1579 #if 1
1580         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1581         for (p = 0; p < 2; ++p) {
1582           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);
1583         }
1584 #endif
1585         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
1586         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
1587         for (s = 0; s < supportSize; ++s) {
1588           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
1589           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
1590           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
1591           for (c = 0; c < coneSize; ++c) if (cone[c] == f) break;
1592           if (support[s] >= cMax) {
1593             supportRef[s] = cStartNew + (cMax - cStart)*4 + (support[s] - cMax)*2 + (ornt[c] < 0 ? 1-r : r);
1594           } else {
1595             supportRef[s] = cStartNew + (support[s] - cStart)*4 + (ornt[c] < 0 ? (c+1-r)%3 : (c+r)%3);
1596           }
1597         }
1598         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
1599 #if 1
1600         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1601         for (p = 0; p < supportSize; ++p) {
1602           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);
1603         }
1604 #endif
1605       }
1606     }
1607     /* Interior cell faces have 2 vertices and 2 cells */
1608     for (c = cStart; c < cMax; ++c) {
1609       const PetscInt *cone;
1610 
1611       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
1612       for (r = 0; r < 3; ++r) {
1613         const PetscInt newp = fStartNew + (fMax - fStart)*2 + (c - cStart)*3 + r;
1614         PetscInt       coneNew[2];
1615         PetscInt       supportNew[2];
1616 
1617         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r]       - fStart);
1618         coneNew[1] = vStartNew + (vEnd - vStart) + (cone[(r+1)%3] - fStart);
1619         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
1620 #if 1
1621         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1622         for (p = 0; p < 2; ++p) {
1623           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);
1624         }
1625 #endif
1626         supportNew[0] = (c - cStart)*4 + (r+1)%3;
1627         supportNew[1] = (c - cStart)*4 + 3;
1628         ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
1629 #if 1
1630         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1631         for (p = 0; p < 2; ++p) {
1632           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);
1633         }
1634 #endif
1635       }
1636     }
1637     /* Interior hybrid faces have 2 vertices and the same cells */
1638     for (f = fMax; f < fEnd; ++f) {
1639       const PetscInt  newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (f - fMax);
1640       const PetscInt *cone, *ornt;
1641       const PetscInt *support;
1642       PetscInt        coneNew[2];
1643       PetscInt        supportNew[2];
1644       PetscInt        size, s, r;
1645 
1646       ierr       = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
1647       coneNew[0] = vStartNew + (cone[0] - vStart);
1648       coneNew[1] = vStartNew + (cone[1] - vStart);
1649       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
1650 #if 1
1651       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1652       for (p = 0; p < 2; ++p) {
1653         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);
1654       }
1655 #endif
1656       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
1657       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
1658       for (s = 0; s < size; ++s) {
1659         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
1660         ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
1661         for (r = 0; r < 2; ++r) {
1662           if (cone[r+2] == f) break;
1663         }
1664         supportNew[s] = (cMax - cStart)*4 + (support[s] - cMax)*2 + (ornt[0] < 0 ? 1-r : r);
1665       }
1666       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
1667 #if 1
1668       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1669       for (p = 0; p < size; ++p) {
1670         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);
1671       }
1672 #endif
1673     }
1674     /* Cell hybrid faces have 2 vertices and 2 cells */
1675     for (c = cMax; c < cEnd; ++c) {
1676       const PetscInt  newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (fEnd - fMax) + (c - cMax);
1677       const PetscInt *cone;
1678       PetscInt        coneNew[2];
1679       PetscInt        supportNew[2];
1680 
1681       ierr       = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
1682       coneNew[0] = vStartNew + (vEnd - vStart) + (cone[0] - fStart);
1683       coneNew[1] = vStartNew + (vEnd - vStart) + (cone[1] - fStart);
1684       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
1685 #if 1
1686       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1687       for (p = 0; p < 2; ++p) {
1688         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);
1689       }
1690 #endif
1691       supportNew[0] = (cMax - cStart)*4 + (c - cMax)*2 + 0;
1692       supportNew[1] = (cMax - cStart)*4 + (c - cMax)*2 + 1;
1693       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
1694 #if 1
1695       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1696       for (p = 0; p < 2; ++p) {
1697         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);
1698       }
1699 #endif
1700     }
1701     /* Old vertices have identical supports */
1702     for (v = vStart; v < vEnd; ++v) {
1703       const PetscInt  newp = vStartNew + (v - vStart);
1704       const PetscInt *support, *cone;
1705       PetscInt        size, s;
1706 
1707       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
1708       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
1709       for (s = 0; s < size; ++s) {
1710         if (support[s] >= fMax) {
1711           supportRef[s] = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (support[s] - fMax);
1712         } else {
1713           PetscInt r = 0;
1714 
1715           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
1716           if (cone[1] == v) r = 1;
1717           supportRef[s] = fStartNew + (support[s] - fStart)*2 + r;
1718         }
1719       }
1720       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
1721 #if 1
1722       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
1723       for (p = 0; p < size; ++p) {
1724         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);
1725       }
1726 #endif
1727     }
1728     /* Face vertices have 2 + (2 interior, 1 hybrid) supports */
1729     for (f = fStart; f < fMax; ++f) {
1730       const PetscInt  newp = vStartNew + (vEnd - vStart) + (f - fStart);
1731       const PetscInt *cone, *support;
1732       PetscInt        size, newSize = 2, s;
1733 
1734       ierr          = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
1735       ierr          = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
1736       supportRef[0] = fStartNew + (f - fStart)*2 + 0;
1737       supportRef[1] = fStartNew + (f - fStart)*2 + 1;
1738       for (s = 0; s < size; ++s) {
1739         PetscInt r = 0;
1740 
1741         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
1742         if (support[s] >= cMax) {
1743           supportRef[newSize+0] = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (fEnd - fMax) + (support[s] - cMax);
1744 
1745           newSize += 1;
1746         } else {
1747           if      (cone[1] == f) r = 1;
1748           else if (cone[2] == f) r = 2;
1749           supportRef[newSize+0] = fStartNew + (fMax - fStart)*2 + (support[s] - cStart)*3 + (r+2)%3;
1750           supportRef[newSize+1] = fStartNew + (fMax - fStart)*2 + (support[s] - cStart)*3 + r;
1751 
1752           newSize += 2;
1753         }
1754       }
1755       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
1756 #if 1
1757       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
1758       for (p = 0; p < newSize; ++p) {
1759         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);
1760       }
1761 #endif
1762     }
1763     ierr = PetscFree(supportRef);CHKERRQ(ierr);
1764     break;
1765   case 4:
1766     /* Hybrid Hex 2D */
1767     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
1768     cMax = PetscMin(cEnd, cMax);
1769     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
1770     fMax = PetscMin(fEnd, fMax);
1771     ierr = DMPlexGetHybridBounds(rdm, &cMaxNew, &fMaxNew, NULL, NULL);CHKERRQ(ierr);
1772     /* Interior cells have 4 faces */
1773     for (c = cStart; c < cMax; ++c) {
1774       const PetscInt  newp = cStartNew + (c - cStart)*4;
1775       const PetscInt *cone, *ornt;
1776       PetscInt        coneNew[4], orntNew[4];
1777 
1778       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
1779       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
1780       /* A quad */
1781       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
1782       orntNew[0] = ornt[0];
1783       coneNew[1] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*4 + 0;
1784       orntNew[1] = 0;
1785       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*4 + 3;
1786       orntNew[2] = -2;
1787       coneNew[3] = fStartNew + (cone[3] - fStart)*2 + (ornt[3] < 0 ? 0 : 1);
1788       orntNew[3] = ornt[3];
1789       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
1790       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
1791 #if 1
1792       if ((newp+0 < cStartNew) || (newp+0 >= cMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an interior cell [%d, %d)", newp+0, cStartNew, cMaxNew);
1793       for (p = 0; p < 4; ++p) {
1794         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an interior face [%d, %d)", coneNew[p], fStartNew, fMaxNew);
1795       }
1796 #endif
1797       /* B quad */
1798       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
1799       orntNew[0] = ornt[0];
1800       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
1801       orntNew[1] = ornt[1];
1802       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*4 + 1;
1803       orntNew[2] = 0;
1804       coneNew[3] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*4 + 0;
1805       orntNew[3] = -2;
1806       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
1807       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
1808 #if 1
1809       if ((newp+1 < cStartNew) || (newp+1 >= cMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an interior cell [%d, %d)", newp+1, cStartNew, cMaxNew);
1810       for (p = 0; p < 4; ++p) {
1811         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an interior face [%d, %d)", coneNew[p], fStartNew, fMaxNew);
1812       }
1813 #endif
1814       /* C quad */
1815       coneNew[0] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*4 + 1;
1816       orntNew[0] = -2;
1817       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
1818       orntNew[1] = ornt[1];
1819       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
1820       orntNew[2] = ornt[2];
1821       coneNew[3] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*4 + 2;
1822       orntNew[3] = 0;
1823       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
1824       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
1825 #if 1
1826       if ((newp+2 < cStartNew) || (newp+2 >= cMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an interior cell [%d, %d)", newp+2, cStartNew, cMaxNew);
1827       for (p = 0; p < 4; ++p) {
1828         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an interior face [%d, %d)", coneNew[p], fStartNew, fMaxNew);
1829       }
1830 #endif
1831       /* D quad */
1832       coneNew[0] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*4 + 3;
1833       orntNew[0] = 0;
1834       coneNew[1] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*4 + 2;
1835       orntNew[1] = -2;
1836       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
1837       orntNew[2] = ornt[2];
1838       coneNew[3] = fStartNew + (cone[3] - fStart)*2 + (ornt[3] < 0 ? 1 : 0);
1839       orntNew[3] = ornt[3];
1840       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
1841       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
1842 #if 1
1843       if ((newp+3 < cStartNew) || (newp+3 >= cMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an interior cell [%d, %d)", newp+3, cStartNew, cMaxNew);
1844       for (p = 0; p < 4; ++p) {
1845         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an interior face [%d, %d)", coneNew[p], fStartNew, fMaxNew);
1846       }
1847 #endif
1848     }
1849     /*
1850      2----3----3
1851      |         |
1852      |    B    |
1853      |         |
1854      0----4--- 1
1855      |         |
1856      |    A    |
1857      |         |
1858      0----2----1
1859      */
1860     /* Hybrid cells have 4 faces */
1861     for (c = cMax; c < cEnd; ++c) {
1862       const PetscInt  newp = cStartNew + (cMax - cStart)*4 + (c - cMax)*2;
1863       const PetscInt *cone, *ornt;
1864       PetscInt        coneNew[4], orntNew[4];
1865 
1866       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
1867       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
1868       /* A quad */
1869       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
1870       orntNew[0] = ornt[0];
1871       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
1872       orntNew[1] = ornt[1];
1873       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*4 + (cone[2] - fMax);
1874       orntNew[2] = 0;
1875       coneNew[3] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*4 + (fEnd    - fMax) + (c - cMax);
1876       orntNew[3] = 0;
1877       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
1878       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
1879 #if 1
1880       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);
1881       for (p = 0; p < 4; ++p) {
1882         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);
1883       }
1884 #endif
1885       /* B quad */
1886       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
1887       orntNew[0] = ornt[0];
1888       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
1889       orntNew[1] = ornt[1];
1890       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*4 + (fEnd    - fMax) + (c - cMax);
1891       orntNew[2] = 0;
1892       coneNew[3] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*4 + (cone[3] - fMax);
1893       orntNew[3] = 0;
1894       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
1895       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
1896 #if 1
1897       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);
1898       for (p = 0; p < 4; ++p) {
1899         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);
1900       }
1901 #endif
1902     }
1903     /* Interior split faces have 2 vertices and the same cells as the parent */
1904     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
1905     ierr = PetscMalloc1((2 + maxSupportSize*2), &supportRef);CHKERRQ(ierr);
1906     for (f = fStart; f < fMax; ++f) {
1907       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);
1908 
1909       for (r = 0; r < 2; ++r) {
1910         const PetscInt  newp = fStartNew + (f - fStart)*2 + r;
1911         const PetscInt *cone, *ornt, *support;
1912         PetscInt        coneNew[2], coneSize, c, supportSize, s;
1913 
1914         ierr             = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
1915         coneNew[0]       = vStartNew + (cone[0] - vStart);
1916         coneNew[1]       = vStartNew + (cone[1] - vStart);
1917         coneNew[(r+1)%2] = newv;
1918         ierr             = DMPlexSetCone(rdm, newp, coneNew);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 ((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);
1923         }
1924 #endif
1925         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
1926         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
1927         for (s = 0; s < supportSize; ++s) {
1928           if (support[s] >= cMax) {
1929             supportRef[s] = cStartNew + (cMax - cStart)*4 + (support[s] - cMax)*2 + r;
1930           } else {
1931             ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
1932             ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
1933             ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
1934             for (c = 0; c < coneSize; ++c) {
1935               if (cone[c] == f) break;
1936             }
1937             supportRef[s] = cStartNew + (support[s] - cStart)*4 + (ornt[c] < 0 ? (c+1-r)%4 : (c+r)%4);
1938           }
1939         }
1940         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
1941 #if 1
1942         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1943         for (p = 0; p < supportSize; ++p) {
1944           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);
1945         }
1946 #endif
1947       }
1948     }
1949     /* Interior cell faces have 2 vertices and 2 cells */
1950     for (c = cStart; c < cMax; ++c) {
1951       const PetscInt *cone;
1952 
1953       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
1954       for (r = 0; r < 4; ++r) {
1955         const PetscInt newp = fStartNew + (fMax - fStart)*2 + (c - cStart)*4 + r;
1956         PetscInt       coneNew[2], supportNew[2];
1957 
1958         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r] - fStart);
1959         coneNew[1] = vStartNew + (vEnd - vStart) + (fMax    - fStart) + (c - cStart);
1960         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
1961 #if 1
1962         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1963         for (p = 0; p < 2; ++p) {
1964           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
1965         }
1966 #endif
1967         supportNew[0] = (c - cStart)*4 + r;
1968         supportNew[1] = (c - cStart)*4 + (r+1)%4;
1969         ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
1970 #if 1
1971         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1972         for (p = 0; p < 2; ++p) {
1973           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);
1974         }
1975 #endif
1976       }
1977     }
1978     /* Hybrid faces have 2 vertices and the same cells */
1979     for (f = fMax; f < fEnd; ++f) {
1980       const PetscInt  newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*4 + (f - fMax);
1981       const PetscInt *cone, *support;
1982       PetscInt        coneNew[2], supportNew[2];
1983       PetscInt        size, s, r;
1984 
1985       ierr       = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
1986       coneNew[0] = vStartNew + (cone[0] - vStart);
1987       coneNew[1] = vStartNew + (cone[1] - vStart);
1988       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
1989 #if 1
1990       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1991       for (p = 0; p < 2; ++p) {
1992         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);
1993       }
1994 #endif
1995       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
1996       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
1997       for (s = 0; s < size; ++s) {
1998         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
1999         for (r = 0; r < 2; ++r) {
2000           if (cone[r+2] == f) break;
2001         }
2002         supportNew[s] = (cMax - cStart)*4 + (support[s] - cMax)*2 + r;
2003       }
2004       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
2005 #if 1
2006       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2007       for (p = 0; p < size; ++p) {
2008         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);
2009       }
2010 #endif
2011     }
2012     /* Cell hybrid faces have 2 vertices and 2 cells */
2013     for (c = cMax; c < cEnd; ++c) {
2014       const PetscInt  newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*4 + (fEnd - fMax) + (c - cMax);
2015       const PetscInt *cone;
2016       PetscInt        coneNew[2], supportNew[2];
2017 
2018       ierr       = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
2019       coneNew[0] = vStartNew + (vEnd - vStart) + (cone[0] - fStart);
2020       coneNew[1] = vStartNew + (vEnd - vStart) + (cone[1] - fStart);
2021       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2022 #if 1
2023       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2024       for (p = 0; p < 2; ++p) {
2025         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);
2026       }
2027 #endif
2028       supportNew[0] = (cMax - cStart)*4 + (c - cMax)*2 + 0;
2029       supportNew[1] = (cMax - cStart)*4 + (c - cMax)*2 + 1;
2030       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
2031 #if 1
2032       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2033       for (p = 0; p < 2; ++p) {
2034         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);
2035       }
2036 #endif
2037     }
2038     /* Old vertices have identical supports */
2039     for (v = vStart; v < vEnd; ++v) {
2040       const PetscInt  newp = vStartNew + (v - vStart);
2041       const PetscInt *support, *cone;
2042       PetscInt        size, s;
2043 
2044       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
2045       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
2046       for (s = 0; s < size; ++s) {
2047         if (support[s] >= fMax) {
2048           supportRef[s] = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*4 + (support[s] - fMax);
2049         } else {
2050           PetscInt r = 0;
2051 
2052           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
2053           if (cone[1] == v) r = 1;
2054           supportRef[s] = fStartNew + (support[s] - fStart)*2 + r;
2055         }
2056       }
2057       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
2058 #if 1
2059       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
2060       for (p = 0; p < size; ++p) {
2061         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);
2062       }
2063 #endif
2064     }
2065     /* Face vertices have 2 + cells supports */
2066     for (f = fStart; f < fMax; ++f) {
2067       const PetscInt  newp = vStartNew + (vEnd - vStart) + (f - fStart);
2068       const PetscInt *cone, *support;
2069       PetscInt        size, s;
2070 
2071       ierr          = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
2072       ierr          = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
2073       supportRef[0] = fStartNew + (f - fStart)*2 + 0;
2074       supportRef[1] = fStartNew + (f - fStart)*2 + 1;
2075       for (s = 0; s < size; ++s) {
2076         PetscInt r = 0;
2077 
2078         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
2079         if (support[s] >= cMax) {
2080           supportRef[2+s] = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*4 + (fEnd - fMax) + (support[s] - cMax);
2081         } else {
2082           if      (cone[1] == f) r = 1;
2083           else if (cone[2] == f) r = 2;
2084           else if (cone[3] == f) r = 3;
2085           supportRef[2+s] = fStartNew + (fMax - fStart)*2 + (support[s] - cStart)*4 + r;
2086         }
2087       }
2088       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
2089 #if 1
2090       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
2091       for (p = 0; p < 2+size; ++p) {
2092         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);
2093       }
2094 #endif
2095     }
2096     /* Cell vertices have 4 supports */
2097     for (c = cStart; c < cMax; ++c) {
2098       const PetscInt newp = vStartNew + (vEnd - vStart) + (fMax - fStart) + (c - cStart);
2099       PetscInt       supportNew[4];
2100 
2101       for (r = 0; r < 4; ++r) {
2102         supportNew[r] = fStartNew + (fMax - fStart)*2 + (c - cStart)*4 + r;
2103       }
2104       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
2105     }
2106     ierr = PetscFree(supportRef);CHKERRQ(ierr);
2107     break;
2108   case 5:
2109     /* Simplicial 3D */
2110     /* All cells have 4 faces: Tet face order is prescribed in DMPlexGetFaces_Internal() */
2111     ierr = DMPlexGetRawFaces_Internal(dm, 3, 4, cellInd, NULL, NULL, &faces);CHKERRQ(ierr);
2112     for (c = cStart; c < cEnd; ++c) {
2113       const PetscInt  newp = cStartNew + (c - cStart)*8;
2114       const PetscInt *cone, *ornt;
2115       PetscInt        coneNew[4], orntNew[4];
2116 
2117       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
2118       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
2119       /* A tetrahedron: {0, a, c, d} */
2120       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetTriSubface_Static(ornt[0], 0); /* A */
2121       orntNew[0] = ornt[0];
2122       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetTriSubface_Static(ornt[1], 0); /* A */
2123       orntNew[1] = ornt[1];
2124       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetTriSubface_Static(ornt[2], 0); /* A */
2125       orntNew[2] = ornt[2];
2126       coneNew[3] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 0;
2127       orntNew[3] = 0;
2128       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
2129       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
2130 #if 1
2131       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);
2132       for (p = 0; p < 4; ++p) {
2133         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);
2134       }
2135 #endif
2136       /* B tetrahedron: {a, 1, b, e} */
2137       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetTriSubface_Static(ornt[0], 1); /* B */
2138       orntNew[0] = ornt[0];
2139       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetTriSubface_Static(ornt[1], 2); /* C */
2140       orntNew[1] = ornt[1];
2141       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 1;
2142       orntNew[2] = 0;
2143       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetTriSubface_Static(ornt[3], 1); /* B */
2144       orntNew[3] = ornt[3];
2145       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
2146       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
2147 #if 1
2148       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);
2149       for (p = 0; p < 4; ++p) {
2150         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);
2151       }
2152 #endif
2153       /* C tetrahedron: {c, b, 2, f} */
2154       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetTriSubface_Static(ornt[0], 2); /* C */
2155       orntNew[0] = ornt[0];
2156       coneNew[1] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 2;
2157       orntNew[1] = 0;
2158       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetTriSubface_Static(ornt[2], 1); /* B */
2159       orntNew[2] = ornt[2];
2160       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetTriSubface_Static(ornt[3], 0); /* A */
2161       orntNew[3] = ornt[3];
2162       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
2163       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
2164 #if 1
2165       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);
2166       for (p = 0; p < 4; ++p) {
2167         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);
2168       }
2169 #endif
2170       /* D tetrahedron: {d, e, f, 3} */
2171       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 3;
2172       orntNew[0] = 0;
2173       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetTriSubface_Static(ornt[1], 1); /* B */
2174       orntNew[1] = ornt[1];
2175       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetTriSubface_Static(ornt[2], 2); /* C */
2176       orntNew[2] = ornt[2];
2177       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetTriSubface_Static(ornt[3], 2); /* C */
2178       orntNew[3] = ornt[3];
2179       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
2180       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
2181 #if 1
2182       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);
2183       for (p = 0; p < 4; ++p) {
2184         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);
2185       }
2186 #endif
2187       /* A' tetrahedron: {d, a, c, f} */
2188       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 0;
2189       orntNew[0] = -3;
2190       coneNew[1] = fStartNew + (cone[2] - fStart)*4 + 3;
2191       orntNew[1] = ornt[2] < 0 ? -(GetTetSomething_Static(ornt[2], 0)+1) : GetTetSomething_Static(ornt[2], 0);
2192       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 5;
2193       orntNew[2] = 0;
2194       coneNew[3] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 4;
2195       orntNew[3] = 2;
2196       ierr       = DMPlexSetCone(rdm, newp+4, coneNew);CHKERRQ(ierr);
2197       ierr       = DMPlexSetConeOrientation(rdm, newp+4, orntNew);CHKERRQ(ierr);
2198 #if 1
2199       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);
2200       for (p = 0; p < 4; ++p) {
2201         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);
2202       }
2203 #endif
2204       /* B' tetrahedron: {e, b, a, f} */
2205       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 1;
2206       orntNew[0] = -3;
2207       coneNew[1] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 6;
2208       orntNew[1] = 1;
2209       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 7;
2210       orntNew[2] = 0;
2211       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + 3;
2212       orntNew[3] = ornt[3] < 0 ? -(GetTetSomething_Static(ornt[3], 0)+1) : GetTetSomething_Static(ornt[3], 0);
2213       ierr       = DMPlexSetCone(rdm, newp+5, coneNew);CHKERRQ(ierr);
2214       ierr       = DMPlexSetConeOrientation(rdm, newp+5, orntNew);CHKERRQ(ierr);
2215 #if 1
2216       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);
2217       for (p = 0; p < 4; ++p) {
2218         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);
2219       }
2220 #endif
2221       /* C' tetrahedron: {b, f, c, a} */
2222       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 2;
2223       orntNew[0] = -3;
2224       coneNew[1] = fStartNew + (cone[0] - fStart)*4 + 3;
2225       orntNew[1] = ornt[0] < 0 ? -(GetTetSomething_Static(ornt[0], 2)+1) : GetTetSomething_Static(ornt[0], 2);
2226       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 5;
2227       orntNew[2] = -3;
2228       coneNew[3] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 7;
2229       orntNew[3] = -2;
2230       ierr       = DMPlexSetCone(rdm, newp+6, coneNew);CHKERRQ(ierr);
2231       ierr       = DMPlexSetConeOrientation(rdm, newp+6, orntNew);CHKERRQ(ierr);
2232 #if 1
2233       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);
2234       for (p = 0; p < 4; ++p) {
2235         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);
2236       }
2237 #endif
2238       /* D' tetrahedron: {f, e, d, a} */
2239       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 3;
2240       orntNew[0] = -3;
2241       coneNew[1] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 4;
2242       orntNew[1] = -3;
2243       coneNew[2] = fStartNew + (cone[1] - fStart)*4 + 3;
2244       orntNew[2] = ornt[1] < 0 ? -(GetTetSomething_Static(ornt[1], 0)+1) : GetTetSomething_Static(ornt[1], 0);
2245       coneNew[3] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 6;
2246       orntNew[3] = -3;
2247       ierr       = DMPlexSetCone(rdm, newp+7, coneNew);CHKERRQ(ierr);
2248       ierr       = DMPlexSetConeOrientation(rdm, newp+7, orntNew);CHKERRQ(ierr);
2249 #if 1
2250       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);
2251       for (p = 0; p < 4; ++p) {
2252         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);
2253       }
2254 #endif
2255     }
2256     /* Split faces have 3 edges and the same cells as the parent */
2257     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
2258     ierr = PetscMalloc1((2 + maxSupportSize*2), &supportRef);CHKERRQ(ierr);
2259     for (f = fStart; f < fEnd; ++f) {
2260       const PetscInt  newp = fStartNew + (f - fStart)*4;
2261       const PetscInt *cone, *ornt, *support;
2262       PetscInt        coneNew[3], orntNew[3], coneSize, supportSize, s;
2263 
2264       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
2265       ierr = DMPlexGetConeOrientation(dm, f, &ornt);CHKERRQ(ierr);
2266       /* A triangle */
2267       coneNew[0] = eStartNew + (cone[0] - eStart)*2 + (ornt[0] < 0 ? 1 : 0);
2268       orntNew[0] = ornt[0];
2269       coneNew[1] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 2;
2270       orntNew[1] = -2;
2271       coneNew[2] = eStartNew + (cone[2] - eStart)*2 + (ornt[2] < 0 ? 0 : 1);
2272       orntNew[2] = ornt[2];
2273       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
2274       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
2275 #if 1
2276       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);
2277       for (p = 0; p < 3; ++p) {
2278         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);
2279       }
2280 #endif
2281       /* B triangle */
2282       coneNew[0] = eStartNew + (cone[0] - eStart)*2 + (ornt[0] < 0 ? 0 : 1);
2283       orntNew[0] = ornt[0];
2284       coneNew[1] = eStartNew + (cone[1] - eStart)*2 + (ornt[1] < 0 ? 1 : 0);
2285       orntNew[1] = ornt[1];
2286       coneNew[2] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 0;
2287       orntNew[2] = -2;
2288       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
2289       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
2290 #if 1
2291       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);
2292       for (p = 0; p < 3; ++p) {
2293         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);
2294       }
2295 #endif
2296       /* C triangle */
2297       coneNew[0] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 1;
2298       orntNew[0] = -2;
2299       coneNew[1] = eStartNew + (cone[1] - eStart)*2 + (ornt[1] < 0 ? 0 : 1);
2300       orntNew[1] = ornt[1];
2301       coneNew[2] = eStartNew + (cone[2] - eStart)*2 + (ornt[2] < 0 ? 1 : 0);
2302       orntNew[2] = ornt[2];
2303       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
2304       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
2305 #if 1
2306       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);
2307       for (p = 0; p < 3; ++p) {
2308         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);
2309       }
2310 #endif
2311       /* D triangle */
2312       coneNew[0] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 0;
2313       orntNew[0] = 0;
2314       coneNew[1] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 1;
2315       orntNew[1] = 0;
2316       coneNew[2] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 2;
2317       orntNew[2] = 0;
2318       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
2319       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
2320 #if 1
2321       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);
2322       for (p = 0; p < 3; ++p) {
2323         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);
2324       }
2325 #endif
2326       ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
2327       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
2328       for (r = 0; r < 4; ++r) {
2329         for (s = 0; s < supportSize; ++s) {
2330           PetscInt subf;
2331           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
2332           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
2333           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
2334           for (c = 0; c < coneSize; ++c) {
2335             if (cone[c] == f) break;
2336           }
2337           subf = GetTriSubfaceInverse_Static(ornt[c], r);
2338           supportRef[s] = cStartNew + (support[s] - cStart)*8 + (r==3 ? (c+2)%4 + 4 : faces[c*3+subf]);
2339         }
2340         ierr = DMPlexSetSupport(rdm, newp+r, supportRef);CHKERRQ(ierr);
2341 #if 1
2342         if ((newp+r < fStartNew) || (newp+r >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp+r, fStartNew, fEndNew);
2343         for (p = 0; p < supportSize; ++p) {
2344           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);
2345         }
2346 #endif
2347       }
2348     }
2349     /* Interior faces have 3 edges and 2 cells */
2350     for (c = cStart; c < cEnd; ++c) {
2351       PetscInt        newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*8;
2352       const PetscInt *cone, *ornt;
2353       PetscInt        coneNew[3], orntNew[3];
2354       PetscInt        supportNew[2];
2355 
2356       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
2357       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
2358       /* Face A: {c, a, d} */
2359       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*3 + GetTetSomething_Static(ornt[0], 2);
2360       orntNew[0] = ornt[0] < 0 ? -2 : 0;
2361       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*3 + GetTetSomething_Static(ornt[1], 2);
2362       orntNew[1] = ornt[1] < 0 ? -2 : 0;
2363       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*3 + GetTetSomething_Static(ornt[2], 2);
2364       orntNew[2] = ornt[2] < 0 ? -2 : 0;
2365       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2366       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
2367 #if 1
2368       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2369       for (p = 0; p < 3; ++p) {
2370         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);
2371       }
2372 #endif
2373       supportNew[0] = (c - cStart)*8 + 0;
2374       supportNew[1] = (c - cStart)*8 + 0+4;
2375       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
2376 #if 1
2377       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2378       for (p = 0; p < 2; ++p) {
2379         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);
2380       }
2381 #endif
2382       ++newp;
2383       /* Face B: {a, b, e} */
2384       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*3 + GetTetSomething_Static(ornt[0], 0);
2385       orntNew[0] = ornt[0] < 0 ? -2 : 0;
2386       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*3 + GetTetSomething_Static(ornt[3], 0);
2387       orntNew[1] = ornt[3] < 0 ? -2 : 0;
2388       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*3 + GetTetSomething_Static(ornt[1], 1);
2389       orntNew[2] = ornt[1] < 0 ? -2 : 0;
2390       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2391       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
2392 #if 1
2393       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2394       for (p = 0; p < 3; ++p) {
2395         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);
2396       }
2397 #endif
2398       supportNew[0] = (c - cStart)*8 + 1;
2399       supportNew[1] = (c - cStart)*8 + 1+4;
2400       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
2401 #if 1
2402       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2403       for (p = 0; p < 2; ++p) {
2404         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);
2405       }
2406 #endif
2407       ++newp;
2408       /* Face C: {c, f, b} */
2409       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*3 + GetTetSomething_Static(ornt[2], 0);
2410       orntNew[0] = ornt[2] < 0 ? -2 : 0;
2411       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*3 + GetTetSomething_Static(ornt[3], 2);
2412       orntNew[1] = ornt[3] < 0 ? -2 : 0;
2413       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*3 + GetTetSomething_Static(ornt[0], 1);
2414       orntNew[2] = ornt[0] < 0 ? -2 : 0;
2415       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2416       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
2417 #if 1
2418       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2419       for (p = 0; p < 3; ++p) {
2420         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);
2421       }
2422 #endif
2423       supportNew[0] = (c - cStart)*8 + 2;
2424       supportNew[1] = (c - cStart)*8 + 2+4;
2425       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
2426 #if 1
2427       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2428       for (p = 0; p < 2; ++p) {
2429         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);
2430       }
2431 #endif
2432       ++newp;
2433       /* Face D: {d, e, f} */
2434       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*3 + GetTetSomething_Static(ornt[1], 0);
2435       orntNew[0] = ornt[1] < 0 ? -2 : 0;
2436       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*3 + GetTetSomething_Static(ornt[3], 1);
2437       orntNew[1] = ornt[3] < 0 ? -2 : 0;
2438       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*3 + GetTetSomething_Static(ornt[2], 1);
2439       orntNew[2] = ornt[2] < 0 ? -2 : 0;
2440       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2441       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
2442 #if 1
2443       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2444       for (p = 0; p < 3; ++p) {
2445         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);
2446       }
2447 #endif
2448       supportNew[0] = (c - cStart)*8 + 3;
2449       supportNew[1] = (c - cStart)*8 + 3+4;
2450       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
2451 #if 1
2452       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2453       for (p = 0; p < 2; ++p) {
2454         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);
2455       }
2456 #endif
2457       ++newp;
2458       /* Face E: {d, f, a} */
2459       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*3 + GetTetSomething_Static(ornt[2], 1);
2460       orntNew[0] = ornt[2] < 0 ? 0 : -2;
2461       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart);
2462       orntNew[1] = -2;
2463       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*3 + GetTetSomething_Static(ornt[1], 2);
2464       orntNew[2] = ornt[1] < 0 ? -2 : 0;
2465       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2466       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
2467 #if 1
2468       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2469       for (p = 0; p < 3; ++p) {
2470         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);
2471       }
2472 #endif
2473       supportNew[0] = (c - cStart)*8 + 0+4;
2474       supportNew[1] = (c - cStart)*8 + 3+4;
2475       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
2476 #if 1
2477       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2478       for (p = 0; p < 2; ++p) {
2479         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);
2480       }
2481 #endif
2482       ++newp;
2483       /* Face F: {c, a, f} */
2484       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*3 + GetTetSomething_Static(ornt[0], 2);
2485       orntNew[0] = ornt[0] < 0 ? -2 : 0;
2486       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart);
2487       orntNew[1] = 0;
2488       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*3 + GetTetSomething_Static(ornt[2], 0);
2489       orntNew[2] = ornt[2] < 0 ? 0 : -2;
2490       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2491       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
2492 #if 1
2493       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2494       for (p = 0; p < 3; ++p) {
2495         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);
2496       }
2497 #endif
2498       supportNew[0] = (c - cStart)*8 + 0+4;
2499       supportNew[1] = (c - cStart)*8 + 2+4;
2500       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
2501 #if 1
2502       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2503       for (p = 0; p < 2; ++p) {
2504         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);
2505       }
2506 #endif
2507       ++newp;
2508       /* Face G: {e, a, f} */
2509       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*3 + GetTetSomething_Static(ornt[1], 1);
2510       orntNew[0] = ornt[1] < 0 ? -2 : 0;
2511       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart);
2512       orntNew[1] = 0;
2513       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*3 + GetTetSomething_Static(ornt[3], 1);
2514       orntNew[2] = ornt[3] < 0 ? 0 : -2;
2515       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2516       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
2517 #if 1
2518       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2519       for (p = 0; p < 3; ++p) {
2520         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);
2521       }
2522 #endif
2523       supportNew[0] = (c - cStart)*8 + 1+4;
2524       supportNew[1] = (c - cStart)*8 + 3+4;
2525       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
2526 #if 1
2527       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2528       for (p = 0; p < 2; ++p) {
2529         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);
2530       }
2531 #endif
2532       ++newp;
2533       /* Face H: {a, b, f} */
2534       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*3 + GetTetSomething_Static(ornt[0], 0);
2535       orntNew[0] = ornt[0] < 0 ? -2 : 0;
2536       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*3 + GetTetSomething_Static(ornt[3], 2);
2537       orntNew[1] = ornt[3] < 0 ? 0 : -2;
2538       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart);
2539       orntNew[2] = -2;
2540       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2541       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
2542 #if 1
2543       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2544       for (p = 0; p < 3; ++p) {
2545         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);
2546       }
2547 #endif
2548       supportNew[0] = (c - cStart)*8 + 1+4;
2549       supportNew[1] = (c - cStart)*8 + 2+4;
2550       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
2551 #if 1
2552       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2553       for (p = 0; p < 2; ++p) {
2554         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);
2555       }
2556 #endif
2557       ++newp;
2558     }
2559     /* Split Edges have 2 vertices and the same faces as the parent */
2560     for (e = eStart; e < eEnd; ++e) {
2561       const PetscInt newv = vStartNew + (vEnd - vStart) + (e - eStart);
2562 
2563       for (r = 0; r < 2; ++r) {
2564         const PetscInt  newp = eStartNew + (e - eStart)*2 + r;
2565         const PetscInt *cone, *ornt, *support;
2566         PetscInt        coneNew[2], coneSize, c, supportSize, s;
2567 
2568         ierr             = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
2569         coneNew[0]       = vStartNew + (cone[0] - vStart);
2570         coneNew[1]       = vStartNew + (cone[1] - vStart);
2571         coneNew[(r+1)%2] = newv;
2572         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2573 #if 1
2574         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
2575         for (p = 0; p < 2; ++p) {
2576           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);
2577         }
2578 #endif
2579         ierr = DMPlexGetSupportSize(dm, e, &supportSize);CHKERRQ(ierr);
2580         ierr = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
2581         for (s = 0; s < supportSize; ++s) {
2582           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
2583           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
2584           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
2585           for (c = 0; c < coneSize; ++c) {
2586             if (cone[c] == e) break;
2587           }
2588           supportRef[s] = fStartNew + (support[s] - fStart)*4 + (c + (ornt[c] < 0 ? 1-r : r))%3;
2589         }
2590         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
2591 #if 1
2592         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
2593         for (p = 0; p < supportSize; ++p) {
2594           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);
2595         }
2596 #endif
2597       }
2598     }
2599     /* Face edges have 2 vertices and 2+cells*(1/2) faces */
2600     for (f = fStart; f < fEnd; ++f) {
2601       const PetscInt *cone, *ornt, *support;
2602       PetscInt        coneSize, supportSize, s;
2603 
2604       ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
2605       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
2606       for (r = 0; r < 3; ++r) {
2607         const PetscInt  newp = eStartNew + (eEnd - eStart)*2 + (f - fStart)*3 + r;
2608         PetscInt        coneNew[2], intFaces = 0, er, eint[4] = {1, 0, 2, 0};
2609         PetscInt        fint[24] = { 1,  7, -1, -1,  0,  5,
2610                                     -1, -1,  1,  6,  0,  4,
2611                                      2,  5,  3,  4, -1, -1,
2612                                     -1, -1,  3,  6,  2,  7};
2613 
2614         ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
2615         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[(r+0)%3] - eStart);
2616         coneNew[1] = vStartNew + (vEnd - vStart) + (cone[(r+1)%3] - eStart);
2617         ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2618 #if 1
2619         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
2620         for (p = 0; p < 2; ++p) {
2621           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);
2622         }
2623 #endif
2624         supportRef[0] = fStartNew + (f - fStart)*4 + (r+1)%3;
2625         supportRef[1] = fStartNew + (f - fStart)*4 + 3;
2626         for (s = 0; s < supportSize; ++s) {
2627           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
2628           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
2629           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
2630           for (c = 0; c < coneSize; ++c) {if (cone[c] == f) break;}
2631           /* Here we want to determine whether edge newp contains a vertex which is part of the cross-tet edge */
2632           er = GetTetSomethingInverse_Static(ornt[c], r);
2633           if (er == eint[c]) {
2634             supportRef[2+intFaces++] = fStartNew + (fEnd - fStart)*4 + (support[s] - cStart)*8 + (c + 2)%4;
2635           } else {
2636             supportRef[2+intFaces++] = fStartNew + (fEnd - fStart)*4 + (support[s] - cStart)*8 + fint[(c*3 + er)*2 + 0];
2637             supportRef[2+intFaces++] = fStartNew + (fEnd - fStart)*4 + (support[s] - cStart)*8 + fint[(c*3 + er)*2 + 1];
2638           }
2639         }
2640         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
2641 #if 1
2642         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
2643         for (p = 0; p < intFaces; ++p) {
2644           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);
2645         }
2646 #endif
2647       }
2648     }
2649     /* Interior edges have 2 vertices and 4 faces */
2650     for (c = cStart; c < cEnd; ++c) {
2651       const PetscInt  newp = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart);
2652       const PetscInt *cone, *ornt, *fcone;
2653       PetscInt        coneNew[2], supportNew[4], find;
2654 
2655       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
2656       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
2657       ierr = DMPlexGetCone(dm, cone[0], &fcone);CHKERRQ(ierr);
2658       find = GetTriEdge_Static(ornt[0], 0);
2659       coneNew[0] = vStartNew + (vEnd - vStart) + (fcone[find] - eStart);
2660       ierr = DMPlexGetCone(dm, cone[2], &fcone);CHKERRQ(ierr);
2661       find = GetTriEdge_Static(ornt[2], 1);
2662       coneNew[1] = vStartNew + (vEnd - vStart) + (fcone[find] - eStart);
2663       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2664 #if 1
2665       if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
2666       for (p = 0; p < 2; ++p) {
2667         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);
2668       }
2669 #endif
2670       supportNew[0] = fStartNew + (fEnd - fStart)*4 + (c - cStart)*8 + 4;
2671       supportNew[1] = fStartNew + (fEnd - fStart)*4 + (c - cStart)*8 + 5;
2672       supportNew[2] = fStartNew + (fEnd - fStart)*4 + (c - cStart)*8 + 6;
2673       supportNew[3] = fStartNew + (fEnd - fStart)*4 + (c - cStart)*8 + 7;
2674       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
2675 #if 1
2676       if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
2677       for (p = 0; p < 4; ++p) {
2678         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);
2679       }
2680 #endif
2681     }
2682     /* Old vertices have identical supports */
2683     for (v = vStart; v < vEnd; ++v) {
2684       const PetscInt  newp = vStartNew + (v - vStart);
2685       const PetscInt *support, *cone;
2686       PetscInt        size, s;
2687 
2688       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
2689       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
2690       for (s = 0; s < size; ++s) {
2691         PetscInt r = 0;
2692 
2693         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
2694         if (cone[1] == v) r = 1;
2695         supportRef[s] = eStartNew + (support[s] - eStart)*2 + r;
2696       }
2697       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
2698 #if 1
2699       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
2700       for (p = 0; p < size; ++p) {
2701         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);
2702       }
2703 #endif
2704     }
2705     /* Edge vertices have 2 + face*2 + 0/1 supports */
2706     for (e = eStart; e < eEnd; ++e) {
2707       const PetscInt  newp = vStartNew + (vEnd - vStart) + (e - eStart);
2708       const PetscInt *cone, *support;
2709       PetscInt       *star = NULL, starSize, cellSize = 0, coneSize, size, s;
2710 
2711       ierr          = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
2712       ierr          = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
2713       supportRef[0] = eStartNew + (e - eStart)*2 + 0;
2714       supportRef[1] = eStartNew + (e - eStart)*2 + 1;
2715       for (s = 0; s < size; ++s) {
2716         PetscInt r = 0;
2717 
2718         ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
2719         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
2720         for (r = 0; r < coneSize; ++r) {if (cone[r] == e) break;}
2721         supportRef[2+s*2+0] = eStartNew + (eEnd - eStart)*2 + (support[s] - fStart)*3 + (r+0)%3;
2722         supportRef[2+s*2+1] = eStartNew + (eEnd - eStart)*2 + (support[s] - fStart)*3 + (r+2)%3;
2723       }
2724       ierr = DMPlexGetTransitiveClosure(dm, e, PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
2725       for (s = 0; s < starSize*2; s += 2) {
2726         const PetscInt *cone, *ornt;
2727         PetscInt        e01, e23;
2728 
2729         if ((star[s] >= cStart) && (star[s] < cEnd)) {
2730           /* Check edge 0-1 */
2731           ierr = DMPlexGetCone(dm, star[s], &cone);CHKERRQ(ierr);
2732           ierr = DMPlexGetConeOrientation(dm, star[s], &ornt);CHKERRQ(ierr);
2733           ierr = DMPlexGetCone(dm, cone[0], &cone);CHKERRQ(ierr);
2734           e01  = cone[GetTriEdge_Static(ornt[0], 0)];
2735           /* Check edge 2-3 */
2736           ierr = DMPlexGetCone(dm, star[s], &cone);CHKERRQ(ierr);
2737           ierr = DMPlexGetConeOrientation(dm, star[s], &ornt);CHKERRQ(ierr);
2738           ierr = DMPlexGetCone(dm, cone[2], &cone);CHKERRQ(ierr);
2739           e23  = cone[GetTriEdge_Static(ornt[2], 1)];
2740           if ((e01 == e) || (e23 == e)) {supportRef[2+size*2+cellSize++] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (star[s] - cStart);}
2741         }
2742       }
2743       ierr = DMPlexRestoreTransitiveClosure(dm, e, PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
2744       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
2745 #if 1
2746       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
2747       for (p = 0; p < 2+size*2+cellSize; ++p) {
2748         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);
2749       }
2750 #endif
2751     }
2752     ierr = PetscFree(supportRef);CHKERRQ(ierr);
2753     ierr = DMPlexRestoreFaces_Internal(dm, 3, cStart, NULL, NULL, &faces);CHKERRQ(ierr);
2754     break;
2755   case 7:
2756     /* Hybrid Simplicial 3D */
2757     ierr = DMPlexGetHybridBounds(rdm, &cMaxNew, &fMaxNew, &eMaxNew, NULL);CHKERRQ(ierr);
2758     /* Interior cells have 4 faces: Tet face order is prescribed in DMPlexGetFaces_Internal() */
2759     ierr = DMPlexGetRawFaces_Internal(dm, 3, 4, cellInd, NULL, NULL, &faces);CHKERRQ(ierr);
2760     for (c = cStart; c < cMax; ++c) {
2761       const PetscInt  newp = cStartNew + (c - cStart)*8;
2762       const PetscInt *cone, *ornt;
2763       PetscInt        coneNew[4], orntNew[4];
2764 
2765       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
2766       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
2767       /* A tetrahedron: {0, a, c, d} */
2768       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetTriSubface_Static(ornt[0], 0); /* A */
2769       orntNew[0] = ornt[0];
2770       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetTriSubface_Static(ornt[1], 0); /* A */
2771       orntNew[1] = ornt[1];
2772       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetTriSubface_Static(ornt[2], 0); /* A */
2773       orntNew[2] = ornt[2];
2774       coneNew[3] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 0;
2775       orntNew[3] = 0;
2776       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
2777       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
2778 #if 1
2779       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);
2780       for (p = 0; p < 4; ++p) {
2781         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);
2782       }
2783 #endif
2784       /* B tetrahedron: {a, 1, b, e} */
2785       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetTriSubface_Static(ornt[0], 1); /* B */
2786       orntNew[0] = ornt[0];
2787       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetTriSubface_Static(ornt[1], 2); /* C */
2788       orntNew[1] = ornt[1];
2789       coneNew[2] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 1;
2790       orntNew[2] = 0;
2791       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetTriSubface_Static(ornt[3], 1); /* B */
2792       orntNew[3] = ornt[3];
2793       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
2794       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
2795 #if 1
2796       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);
2797       for (p = 0; p < 4; ++p) {
2798         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);
2799       }
2800 #endif
2801       /* C tetrahedron: {c, b, 2, f} */
2802       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetTriSubface_Static(ornt[0], 2); /* C */
2803       orntNew[0] = ornt[0];
2804       coneNew[1] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 2;
2805       orntNew[1] = 0;
2806       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetTriSubface_Static(ornt[2], 1); /* B */
2807       orntNew[2] = ornt[2];
2808       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetTriSubface_Static(ornt[3], 0); /* A */
2809       orntNew[3] = ornt[3];
2810       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
2811       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
2812 #if 1
2813       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);
2814       for (p = 0; p < 4; ++p) {
2815         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);
2816       }
2817 #endif
2818       /* D tetrahedron: {d, e, f, 3} */
2819       coneNew[0] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 3;
2820       orntNew[0] = 0;
2821       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetTriSubface_Static(ornt[1], 1); /* B */
2822       orntNew[1] = ornt[1];
2823       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetTriSubface_Static(ornt[2], 2); /* C */
2824       orntNew[2] = ornt[2];
2825       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetTriSubface_Static(ornt[3], 2); /* C */
2826       orntNew[3] = ornt[3];
2827       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
2828       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
2829 #if 1
2830       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);
2831       for (p = 0; p < 4; ++p) {
2832         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);
2833       }
2834 #endif
2835       /* A' tetrahedron: {d, a, c, f} */
2836       coneNew[0] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 0;
2837       orntNew[0] = -3;
2838       coneNew[1] = fStartNew + (cone[2] - fStart)*4 + 3;
2839       orntNew[1] = ornt[2] < 0 ? -(GetTetSomething_Static(ornt[2], 0)+1) : GetTetSomething_Static(ornt[2], 0);
2840       coneNew[2] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 5;
2841       orntNew[2] = 0;
2842       coneNew[3] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 4;
2843       orntNew[3] = 2;
2844       ierr       = DMPlexSetCone(rdm, newp+4, coneNew);CHKERRQ(ierr);
2845       ierr       = DMPlexSetConeOrientation(rdm, newp+4, orntNew);CHKERRQ(ierr);
2846 #if 1
2847       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);
2848       for (p = 0; p < 4; ++p) {
2849         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);
2850       }
2851 #endif
2852       /* B' tetrahedron: {e, b, a, f} */
2853       coneNew[0] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 1;
2854       orntNew[0] = -3;
2855       coneNew[1] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 6;
2856       orntNew[1] = 1;
2857       coneNew[2] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 7;
2858       orntNew[2] = 0;
2859       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + 3;
2860       orntNew[3] = ornt[3] < 0 ? -(GetTetSomething_Static(ornt[3], 0)+1) : GetTetSomething_Static(ornt[3], 0);
2861       ierr       = DMPlexSetCone(rdm, newp+5, coneNew);CHKERRQ(ierr);
2862       ierr       = DMPlexSetConeOrientation(rdm, newp+5, orntNew);CHKERRQ(ierr);
2863 #if 1
2864       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);
2865       for (p = 0; p < 4; ++p) {
2866         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);
2867       }
2868 #endif
2869       /* C' tetrahedron: {b, f, c, a} */
2870       coneNew[0] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 2;
2871       orntNew[0] = -3;
2872       coneNew[1] = fStartNew + (cone[0] - fStart)*4 + 3;
2873       orntNew[1] = ornt[0] < 0 ? -(GetTetSomething_Static(ornt[0], 2)+1) : GetTetSomething_Static(ornt[0], 2);
2874       coneNew[2] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 5;
2875       orntNew[2] = -3;
2876       coneNew[3] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 7;
2877       orntNew[3] = -2;
2878       ierr       = DMPlexSetCone(rdm, newp+6, coneNew);CHKERRQ(ierr);
2879       ierr       = DMPlexSetConeOrientation(rdm, newp+6, orntNew);CHKERRQ(ierr);
2880 #if 1
2881       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);
2882       for (p = 0; p < 4; ++p) {
2883         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);
2884       }
2885 #endif
2886       /* D' tetrahedron: {f, e, d, a} */
2887       coneNew[0] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 3;
2888       orntNew[0] = -3;
2889       coneNew[1] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 4;
2890       orntNew[1] = -3;
2891       coneNew[2] = fStartNew + (cone[1] - fStart)*4 + 3;
2892       orntNew[2] = ornt[1] < 0 ? -(GetTetSomething_Static(ornt[1], 0)+1) : GetTetSomething_Static(ornt[1], 0);
2893       coneNew[3] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 6;
2894       orntNew[3] = -3;
2895       ierr       = DMPlexSetCone(rdm, newp+7, coneNew);CHKERRQ(ierr);
2896       ierr       = DMPlexSetConeOrientation(rdm, newp+7, orntNew);CHKERRQ(ierr);
2897 #if 1
2898       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);
2899       for (p = 0; p < 4; ++p) {
2900         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);
2901       }
2902 #endif
2903     }
2904     /* Hybrid cells have 5 faces */
2905     for (c = cMax; c < cEnd; ++c) {
2906       const PetscInt  newp = cStartNew + (cMax - cStart)*8 + (c - cMax)*4;
2907       const PetscInt *cone, *ornt, *fornt;
2908       PetscInt        coneNew[5], orntNew[5], o, of, i;
2909 
2910       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
2911       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
2912       ierr = DMPlexGetConeOrientation(dm, cone[0], &fornt);CHKERRQ(ierr);
2913       o = ornt[0] < 0 ? -1 : 1;
2914       for (r = 0; r < 3; ++r) {
2915         coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetTriSubface_Static(ornt[0], r);
2916         orntNew[0] = ornt[0];
2917         coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetTriSubface_Static(ornt[1], r);
2918         orntNew[1] = ornt[1];
2919         of = fornt[GetTriEdge_Static(ornt[0], r)]       < 0 ? -1 : 1;
2920         i  = GetTriEdgeInverse_Static(ornt[0], r)       + 2;
2921         coneNew[i] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (cone[2+GetTriEdge_Static(ornt[0], r)]       - fMax)*2 + (o*of < 0 ? 1 : 0);
2922         orntNew[i] = 0;
2923         i  = GetTriEdgeInverse_Static(ornt[0], (r+1)%3) + 2;
2924         coneNew[i] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (c - cMax)*3 + GetTriSubface_Static(ornt[0], r);
2925         orntNew[i] = 0;
2926         of = fornt[GetTriEdge_Static(ornt[0], (r+2)%3)] < 0 ? -1 : 1;
2927         i  = GetTriEdgeInverse_Static(ornt[0], (r+2)%3) + 2;
2928         coneNew[i] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (cone[2+GetTriEdge_Static(ornt[0], (r+2)%3)] - fMax)*2 + (o*of < 0 ? 0 : 1);
2929         orntNew[i] = 0;
2930         ierr = DMPlexSetCone(rdm, newp+r, coneNew);CHKERRQ(ierr);
2931         ierr = DMPlexSetConeOrientation(rdm, newp+r, orntNew);CHKERRQ(ierr);
2932 #if 1
2933         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);
2934         for (p = 0; p < 2; ++p) {
2935           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);
2936         }
2937         for (p = 2; p < 5; ++p) {
2938           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);
2939         }
2940 #endif
2941       }
2942       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + 3;
2943       orntNew[0] = 0;
2944       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + 3;
2945       orntNew[1] = 0;
2946       coneNew[2] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (c - cMax)*3 + 1;
2947       orntNew[2] = 0;
2948       coneNew[3] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (c - cMax)*3 + 2;
2949       orntNew[3] = 0;
2950       coneNew[4] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (c - cMax)*3 + 0;
2951       orntNew[4] = 0;
2952       ierr = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
2953       ierr = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
2954 #if 1
2955       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);
2956       for (p = 0; p < 2; ++p) {
2957         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);
2958       }
2959       for (p = 2; p < 5; ++p) {
2960         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);
2961       }
2962 #endif
2963     }
2964     /* Split faces have 3 edges and the same cells as the parent */
2965     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
2966     ierr = PetscMalloc1((2 + maxSupportSize*2), &supportRef);CHKERRQ(ierr);
2967     for (f = fStart; f < fMax; ++f) {
2968       const PetscInt  newp = fStartNew + (f - fStart)*4;
2969       const PetscInt *cone, *ornt, *support;
2970       PetscInt        coneNew[3], orntNew[3], coneSize, supportSize, s;
2971 
2972       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
2973       ierr = DMPlexGetConeOrientation(dm, f, &ornt);CHKERRQ(ierr);
2974       /* A triangle */
2975       coneNew[0] = eStartNew + (cone[0] - eStart)*2 + (ornt[0] < 0 ? 1 : 0);
2976       orntNew[0] = ornt[0];
2977       coneNew[1] = eStartNew + (eMax    - eStart)*2 + (f - fStart)*3 + 2;
2978       orntNew[1] = -2;
2979       coneNew[2] = eStartNew + (cone[2] - eStart)*2 + (ornt[2] < 0 ? 0 : 1);
2980       orntNew[2] = ornt[2];
2981       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
2982       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
2983 #if 1
2984       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);
2985       for (p = 0; p < 3; ++p) {
2986         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);
2987       }
2988 #endif
2989       /* B triangle */
2990       coneNew[0] = eStartNew + (cone[0] - eStart)*2 + (ornt[0] < 0 ? 0 : 1);
2991       orntNew[0] = ornt[0];
2992       coneNew[1] = eStartNew + (cone[1] - eStart)*2 + (ornt[1] < 0 ? 1 : 0);
2993       orntNew[1] = ornt[1];
2994       coneNew[2] = eStartNew + (eMax    - eStart)*2 + (f - fStart)*3 + 0;
2995       orntNew[2] = -2;
2996       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
2997       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
2998 #if 1
2999       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);
3000       for (p = 0; p < 3; ++p) {
3001         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);
3002       }
3003 #endif
3004       /* C triangle */
3005       coneNew[0] = eStartNew + (eMax    - eStart)*2 + (f - fStart)*3 + 1;
3006       orntNew[0] = -2;
3007       coneNew[1] = eStartNew + (cone[1] - eStart)*2 + (ornt[1] < 0 ? 0 : 1);
3008       orntNew[1] = ornt[1];
3009       coneNew[2] = eStartNew + (cone[2] - eStart)*2 + (ornt[2] < 0 ? 1 : 0);
3010       orntNew[2] = ornt[2];
3011       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
3012       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
3013 #if 1
3014       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);
3015       for (p = 0; p < 3; ++p) {
3016         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);
3017       }
3018 #endif
3019       /* D triangle */
3020       coneNew[0] = eStartNew + (eMax    - eStart)*2 + (f - fStart)*3 + 0;
3021       orntNew[0] = 0;
3022       coneNew[1] = eStartNew + (eMax    - eStart)*2 + (f - fStart)*3 + 1;
3023       orntNew[1] = 0;
3024       coneNew[2] = eStartNew + (eMax    - eStart)*2 + (f - fStart)*3 + 2;
3025       orntNew[2] = 0;
3026       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
3027       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
3028 #if 1
3029       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);
3030       for (p = 0; p < 3; ++p) {
3031         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);
3032       }
3033 #endif
3034       ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
3035       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
3036       for (r = 0; r < 4; ++r) {
3037         for (s = 0; s < supportSize; ++s) {
3038           PetscInt subf;
3039           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
3040           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
3041           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
3042           for (c = 0; c < coneSize; ++c) {
3043             if (cone[c] == f) break;
3044           }
3045           subf = GetTriSubfaceInverse_Static(ornt[c], r);
3046           if (support[s] < cMax) {
3047             supportRef[s] = cStartNew + (support[s] - cStart)*8 + (r==3 ? (c+2)%4 + 4 : faces[c*3+subf]);
3048           } else {
3049             supportRef[s] = cStartNew + (cMax - cStart)*8 + (support[s] - cMax)*4 + (r==3 ? r : subf);
3050           }
3051         }
3052         ierr = DMPlexSetSupport(rdm, newp+r, supportRef);CHKERRQ(ierr);
3053 #if 1
3054         if ((newp+r < fStartNew) || (newp+r >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp+r, fStartNew, fMaxNew);
3055         for (p = 0; p < supportSize; ++p) {
3056           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);
3057         }
3058 #endif
3059       }
3060     }
3061     /* Interior cell faces have 3 edges and 2 cells */
3062     for (c = cStart; c < cMax; ++c) {
3063       PetscInt        newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*8;
3064       const PetscInt *cone, *ornt;
3065       PetscInt        coneNew[3], orntNew[3];
3066       PetscInt        supportNew[2];
3067 
3068       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
3069       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
3070       /* Face A: {c, a, d} */
3071       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*3 + GetTetSomething_Static(ornt[0], 2);
3072       orntNew[0] = ornt[0] < 0 ? -2 : 0;
3073       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*3 + GetTetSomething_Static(ornt[1], 2);
3074       orntNew[1] = ornt[1] < 0 ? -2 : 0;
3075       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*3 + GetTetSomething_Static(ornt[2], 2);
3076       orntNew[2] = ornt[2] < 0 ? -2 : 0;
3077       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3078       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3079 #if 1
3080       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
3081       for (p = 0; p < 3; ++p) {
3082         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);
3083       }
3084 #endif
3085       supportNew[0] = (c - cStart)*8 + 0;
3086       supportNew[1] = (c - cStart)*8 + 0+4;
3087       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3088 #if 1
3089       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
3090       for (p = 0; p < 2; ++p) {
3091         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);
3092       }
3093 #endif
3094       ++newp;
3095       /* Face B: {a, b, e} */
3096       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*3 + GetTetSomething_Static(ornt[0], 0);
3097       orntNew[0] = ornt[0] < 0 ? -2 : 0;
3098       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*3 + GetTetSomething_Static(ornt[3], 0);
3099       orntNew[1] = ornt[3] < 0 ? -2 : 0;
3100       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*3 + GetTetSomething_Static(ornt[1], 1);
3101       orntNew[2] = ornt[1] < 0 ? -2 : 0;
3102       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3103       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3104 #if 1
3105       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);
3106       for (p = 0; p < 3; ++p) {
3107         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);
3108       }
3109 #endif
3110       supportNew[0] = (c - cStart)*8 + 1;
3111       supportNew[1] = (c - cStart)*8 + 1+4;
3112       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3113 #if 1
3114       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
3115       for (p = 0; p < 2; ++p) {
3116         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);
3117       }
3118 #endif
3119       ++newp;
3120       /* Face C: {c, f, b} */
3121       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*3 + GetTetSomething_Static(ornt[2], 0);
3122       orntNew[0] = ornt[2] < 0 ? -2 : 0;
3123       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*3 + GetTetSomething_Static(ornt[3], 2);
3124       orntNew[1] = ornt[3] < 0 ? -2 : 0;
3125       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*3 + GetTetSomething_Static(ornt[0], 1);
3126       orntNew[2] = ornt[0] < 0 ? -2 : 0;
3127       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3128       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3129 #if 1
3130       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
3131       for (p = 0; p < 3; ++p) {
3132         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);
3133       }
3134 #endif
3135       supportNew[0] = (c - cStart)*8 + 2;
3136       supportNew[1] = (c - cStart)*8 + 2+4;
3137       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3138 #if 1
3139       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
3140       for (p = 0; p < 2; ++p) {
3141         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);
3142       }
3143 #endif
3144       ++newp;
3145       /* Face D: {d, e, f} */
3146       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*3 + GetTetSomething_Static(ornt[1], 0);
3147       orntNew[0] = ornt[1] < 0 ? -2 : 0;
3148       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*3 + GetTetSomething_Static(ornt[3], 1);
3149       orntNew[1] = ornt[3] < 0 ? -2 : 0;
3150       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*3 + GetTetSomething_Static(ornt[2], 1);
3151       orntNew[2] = ornt[2] < 0 ? -2 : 0;
3152       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3153       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3154 #if 1
3155       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
3156       for (p = 0; p < 3; ++p) {
3157         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);
3158       }
3159 #endif
3160       supportNew[0] = (c - cStart)*8 + 3;
3161       supportNew[1] = (c - cStart)*8 + 3+4;
3162       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3163 #if 1
3164       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
3165       for (p = 0; p < 2; ++p) {
3166         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);
3167       }
3168 #endif
3169       ++newp;
3170       /* Face E: {d, f, a} */
3171       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*3 + GetTetSomething_Static(ornt[2], 1);
3172       orntNew[0] = ornt[2] < 0 ? 0 : -2;
3173       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart);
3174       orntNew[1] = -2;
3175       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*3 + GetTetSomething_Static(ornt[1], 2);
3176       orntNew[2] = ornt[1] < 0 ? -2 : 0;
3177       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3178       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3179 #if 1
3180       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
3181       for (p = 0; p < 3; ++p) {
3182         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);
3183       }
3184 #endif
3185       supportNew[0] = (c - cStart)*8 + 0+4;
3186       supportNew[1] = (c - cStart)*8 + 3+4;
3187       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3188 #if 1
3189       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
3190       for (p = 0; p < 2; ++p) {
3191         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);
3192       }
3193 #endif
3194       ++newp;
3195       /* Face F: {c, a, f} */
3196       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*3 + GetTetSomething_Static(ornt[0], 2);
3197       orntNew[0] = ornt[0] < 0 ? -2 : 0;
3198       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart);
3199       orntNew[1] = 0;
3200       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*3 + GetTetSomething_Static(ornt[2], 0);
3201       orntNew[2] = ornt[2] < 0 ? 0 : -2;
3202       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3203       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3204 #if 1
3205       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
3206       for (p = 0; p < 3; ++p) {
3207         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);
3208       }
3209 #endif
3210       supportNew[0] = (c - cStart)*8 + 0+4;
3211       supportNew[1] = (c - cStart)*8 + 2+4;
3212       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3213 #if 1
3214       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
3215       for (p = 0; p < 2; ++p) {
3216         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);
3217       }
3218 #endif
3219       ++newp;
3220       /* Face G: {e, a, f} */
3221       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*3 + GetTetSomething_Static(ornt[1], 1);
3222       orntNew[0] = ornt[1] < 0 ? -2 : 0;
3223       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart);
3224       orntNew[1] = 0;
3225       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*3 + GetTetSomething_Static(ornt[3], 1);
3226       orntNew[2] = ornt[3] < 0 ? 0 : -2;
3227       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3228       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3229 #if 1
3230       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
3231       for (p = 0; p < 3; ++p) {
3232         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);
3233       }
3234 #endif
3235       supportNew[0] = (c - cStart)*8 + 1+4;
3236       supportNew[1] = (c - cStart)*8 + 3+4;
3237       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3238 #if 1
3239       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
3240       for (p = 0; p < 2; ++p) {
3241         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);
3242       }
3243 #endif
3244       ++newp;
3245       /* Face H: {a, b, f} */
3246       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*3 + GetTetSomething_Static(ornt[0], 0);
3247       orntNew[0] = ornt[0] < 0 ? -2 : 0;
3248       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*3 + GetTetSomething_Static(ornt[3], 2);
3249       orntNew[1] = ornt[3] < 0 ? 0 : -2;
3250       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart);
3251       orntNew[2] = -2;
3252       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3253       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3254 #if 1
3255       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
3256       for (p = 0; p < 3; ++p) {
3257         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);
3258       }
3259 #endif
3260       supportNew[0] = (c - cStart)*8 + 1+4;
3261       supportNew[1] = (c - cStart)*8 + 2+4;
3262       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3263 #if 1
3264       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
3265       for (p = 0; p < 2; ++p) {
3266         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);
3267       }
3268 #endif
3269       ++newp;
3270     }
3271     /* Hybrid split faces have 4 edges and same cells */
3272     for (f = fMax; f < fEnd; ++f) {
3273       const PetscInt *cone, *ornt, *support;
3274       PetscInt        coneNew[4], orntNew[4];
3275       PetscInt        supportNew[2], size, s, c;
3276 
3277       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
3278       ierr = DMPlexGetConeOrientation(dm, f, &ornt);CHKERRQ(ierr);
3279       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
3280       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
3281       for (r = 0; r < 2; ++r) {
3282         const PetscInt newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (f - fMax)*2 + r;
3283 
3284         coneNew[0]   = eStartNew + (cone[0] - eStart)*2 + (ornt[0] < 0 ? 1-r : r);
3285         orntNew[0]   = ornt[0];
3286         coneNew[1]   = eStartNew + (cone[1] - eStart)*2 + (ornt[1] < 0 ? 1-r : r);
3287         orntNew[1]   = ornt[1];
3288         coneNew[2+r] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (cone[2+r] - eMax);
3289         orntNew[2+r] = 0;
3290         coneNew[3-r] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (eEnd      - eMax) + (f - fMax);
3291         orntNew[3-r] = 0;
3292         ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3293         ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3294 #if 1
3295         if ((newp < fMaxNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid face [%d, %d)", newp, fMaxNew, fEndNew);
3296         for (p = 0; p < 2; ++p) {
3297           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);
3298         }
3299         for (p = 2; p < 4; ++p) {
3300           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);
3301         }
3302 #endif
3303         for (s = 0; s < size; ++s) {
3304           const PetscInt *coneCell, *orntCell, *fornt;
3305           PetscInt        o, of;
3306 
3307           ierr = DMPlexGetCone(dm, support[s], &coneCell);CHKERRQ(ierr);
3308           ierr = DMPlexGetConeOrientation(dm, support[s], &orntCell);CHKERRQ(ierr);
3309           o = orntCell[0] < 0 ? -1 : 1;
3310           for (c = 2; c < 5; ++c) if (coneCell[c] == f) break;
3311           if (c >= 5) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Could not find face %d in cone of cell %d", f, support[s]);
3312           ierr = DMPlexGetConeOrientation(dm, coneCell[0], &fornt);CHKERRQ(ierr);
3313           of = fornt[c-2] < 0 ? -1 : 1;
3314           supportNew[s] = cStartNew + (cMax - cStart)*8 + (support[s] - cMax)*4 + (GetTriEdgeInverse_Static(orntCell[0], c-2) + (o*of < 0 ? 1-r : r))%3;
3315         }
3316         ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3317 #if 1
3318         if ((newp < fMaxNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid face [%d, %d)", newp, fMaxNew, fEndNew);
3319         for (p = 0; p < size; ++p) {
3320           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);
3321         }
3322 #endif
3323       }
3324     }
3325     /* Hybrid cell faces have 4 edges and 2 cells */
3326     for (c = cMax; c < cEnd; ++c) {
3327       PetscInt        newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (c - cMax)*3;
3328       const PetscInt *cone, *ornt;
3329       PetscInt        coneNew[4], orntNew[4];
3330       PetscInt        supportNew[2];
3331 
3332       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
3333       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
3334       for (r = 0; r < 3; ++r) {
3335         coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*3 + (r+2)%3;
3336         orntNew[0] = 0;
3337         coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*3 + (r+2)%3;
3338         orntNew[1] = 0;
3339         coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (eEnd - eMax) + (cone[2+(r+2)%3] - fMax);
3340         orntNew[2] = 0;
3341         coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (eEnd - eMax) + (cone[2+r]       - fMax);
3342         orntNew[3] = 0;
3343         ierr = DMPlexSetCone(rdm, newp+r, coneNew);CHKERRQ(ierr);
3344         ierr = DMPlexSetConeOrientation(rdm, newp+r, orntNew);CHKERRQ(ierr);
3345 #if 1
3346         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);
3347         for (p = 0; p < 2; ++p) {
3348           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);
3349         }
3350         for (p = 2; p < 4; ++p) {
3351           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);
3352         }
3353 #endif
3354         supportNew[0] = cStartNew + (cMax - cStart)*8 + (c - cMax)*4 + GetTriSubface_Static(ornt[0], r);
3355         supportNew[1] = cStartNew + (cMax - cStart)*8 + (c - cMax)*4 + 3;
3356         ierr          = DMPlexSetSupport(rdm, newp+r, supportNew);CHKERRQ(ierr);
3357 #if 1
3358         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);
3359         for (p = 0; p < 2; ++p) {
3360           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);
3361         }
3362 #endif
3363       }
3364     }
3365     /* Interior split edges have 2 vertices and the same faces as the parent */
3366     for (e = eStart; e < eMax; ++e) {
3367       const PetscInt newv = vStartNew + (vEnd - vStart) + (e - eStart);
3368 
3369       for (r = 0; r < 2; ++r) {
3370         const PetscInt  newp = eStartNew + (e - eStart)*2 + r;
3371         const PetscInt *cone, *ornt, *support;
3372         PetscInt        coneNew[2], coneSize, c, supportSize, s;
3373 
3374         ierr             = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
3375         coneNew[0]       = vStartNew + (cone[0] - vStart);
3376         coneNew[1]       = vStartNew + (cone[1] - vStart);
3377         coneNew[(r+1)%2] = newv;
3378         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3379 #if 1
3380         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
3381         for (p = 0; p < 2; ++p) {
3382           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);
3383         }
3384 #endif
3385         ierr = DMPlexGetSupportSize(dm, e, &supportSize);CHKERRQ(ierr);
3386         ierr = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
3387         for (s = 0; s < supportSize; ++s) {
3388           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
3389           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
3390           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
3391           for (c = 0; c < coneSize; ++c) if (cone[c] == e) break;
3392           if (support[s] < fMax) {
3393             supportRef[s] = fStartNew + (support[s] - fStart)*4 + (c + (ornt[c] < 0 ? 1-r : r))%3;
3394           } else {
3395             supportRef[s] = fStartNew + (fMax       - fStart)*4 + (cMax - cStart)*8 + (support[s] - fMax)*2 + (ornt[c] < 0 ? 1-r : r);
3396           }
3397         }
3398         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
3399 #if 1
3400         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
3401         for (p = 0; p < supportSize; ++p) {
3402           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);
3403         }
3404 #endif
3405       }
3406     }
3407     /* Interior face edges have 2 vertices and 2+cells*(1/2) faces */
3408     for (f = fStart; f < fMax; ++f) {
3409       const PetscInt *cone, *ornt, *support;
3410       PetscInt        coneSize, supportSize, s;
3411 
3412       ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
3413       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
3414       for (r = 0; r < 3; ++r) {
3415         const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (f - fStart)*3 + r;
3416         PetscInt        coneNew[2], intFaces = 0, er, eint[4] = {1, 0, 2, 0};
3417         PetscInt        fint[24] = { 1,  7, -1, -1,  0,  5,
3418                                     -1, -1,  1,  6,  0,  4,
3419                                      2,  5,  3,  4, -1, -1,
3420                                     -1, -1,  3,  6,  2,  7};
3421 
3422         ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
3423         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[(r+0)%3] - eStart);
3424         coneNew[1] = vStartNew + (vEnd - vStart) + (cone[(r+1)%3] - eStart);
3425         ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3426 #if 1
3427         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
3428         for (p = 0; p < 2; ++p) {
3429           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);
3430         }
3431 #endif
3432         supportRef[0] = fStartNew + (f - fStart)*4 + (r+1)%3;
3433         supportRef[1] = fStartNew + (f - fStart)*4 + 3;
3434         for (s = 0; s < supportSize; ++s) {
3435           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
3436           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
3437           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
3438           for (c = 0; c < coneSize; ++c) {if (cone[c] == f) break;}
3439           if (support[s] < cMax) {
3440             /* Here we want to determine whether edge newp contains a vertex which is part of the cross-tet edge */
3441             er = GetTetSomethingInverse_Static(ornt[c], r);
3442             if (er == eint[c]) {
3443               supportRef[2+intFaces++] = fStartNew + (fMax - fStart)*4 + (support[s] - cStart)*8 + (c + 2)%4;
3444             } else {
3445               supportRef[2+intFaces++] = fStartNew + (fMax - fStart)*4 + (support[s] - cStart)*8 + fint[(c*3 + er)*2 + 0];
3446               supportRef[2+intFaces++] = fStartNew + (fMax - fStart)*4 + (support[s] - cStart)*8 + fint[(c*3 + er)*2 + 1];
3447             }
3448           } else {
3449             supportRef[2+intFaces++] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (support[s] - cMax)*3 + (r + 1)%3;
3450           }
3451         }
3452         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
3453 #if 1
3454         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
3455         for (p = 0; p < intFaces; ++p) {
3456           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);
3457         }
3458 #endif
3459       }
3460     }
3461     /* Interior cell edges have 2 vertices and 4 faces */
3462     for (c = cStart; c < cMax; ++c) {
3463       const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart);
3464       const PetscInt *cone, *ornt, *fcone;
3465       PetscInt        coneNew[2], supportNew[4], find;
3466 
3467       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
3468       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
3469       ierr = DMPlexGetCone(dm, cone[0], &fcone);CHKERRQ(ierr);
3470       find = GetTriEdge_Static(ornt[0], 0);
3471       coneNew[0] = vStartNew + (vEnd - vStart) + (fcone[find] - eStart);
3472       ierr = DMPlexGetCone(dm, cone[2], &fcone);CHKERRQ(ierr);
3473       find = GetTriEdge_Static(ornt[2], 1);
3474       coneNew[1] = vStartNew + (vEnd - vStart) + (fcone[find] - eStart);
3475       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3476 #if 1
3477       if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
3478       for (p = 0; p < 2; ++p) {
3479         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);
3480       }
3481 #endif
3482       supportNew[0] = fStartNew + (fMax - fStart)*4 + (c - cStart)*8 + 4;
3483       supportNew[1] = fStartNew + (fMax - fStart)*4 + (c - cStart)*8 + 5;
3484       supportNew[2] = fStartNew + (fMax - fStart)*4 + (c - cStart)*8 + 6;
3485       supportNew[3] = fStartNew + (fMax - fStart)*4 + (c - cStart)*8 + 7;
3486       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3487 #if 1
3488       if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
3489       for (p = 0; p < 4; ++p) {
3490         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);
3491       }
3492 #endif
3493     }
3494     /* Hybrid edges have two vertices and the same faces */
3495     for (e = eMax; e < eEnd; ++e) {
3496       const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (e - eMax);
3497       const PetscInt *cone, *support, *fcone;
3498       PetscInt        coneNew[2], size, fsize, s;
3499 
3500       ierr = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
3501       ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
3502       ierr = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
3503       coneNew[0] = vStartNew + (cone[0] - vStart);
3504       coneNew[1] = vStartNew + (cone[1] - vStart);
3505       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3506 #if 1
3507       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid edge [%d, %d)", newp, eMaxNew, eEndNew);
3508       for (p = 0; p < 2; ++p) {
3509         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);
3510       }
3511 #endif
3512       for (s = 0; s < size; ++s) {
3513         ierr = DMPlexGetConeSize(dm, support[s], &fsize);CHKERRQ(ierr);
3514         ierr = DMPlexGetCone(dm, support[s], &fcone);CHKERRQ(ierr);
3515         for (c = 0; c < fsize; ++c) if (fcone[c] == e) break;
3516         if ((c < 2) || (c > 3)) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Edge %d not found in cone of face %d", e, support[s]);
3517         supportRef[s] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (support[s] - fMax)*2 + c-2;
3518       }
3519       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
3520 #if 1
3521       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid edge [%d, %d)", newp, eMaxNew, eEndNew);
3522       for (p = 0; p < size; ++p) {
3523         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);
3524       }
3525 #endif
3526     }
3527     /* Hybrid face edges have 2 vertices and 2+2*cells faces */
3528     for (f = fMax; f < fEnd; ++f) {
3529       const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (eEnd - eMax) + (f - fMax);
3530       const PetscInt *cone, *support, *ccone, *cornt;
3531       PetscInt        coneNew[2], size, csize, s;
3532 
3533       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
3534       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
3535       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
3536       coneNew[0] = vStartNew + (vEnd - vStart) + (cone[0] - eStart);
3537       coneNew[1] = vStartNew + (vEnd - vStart) + (cone[1] - eStart);
3538       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3539 #if 1
3540       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid edge [%d, %d)", newp, eMaxNew, eEndNew);
3541       for (p = 0; p < 2; ++p) {
3542         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);
3543       }
3544 #endif
3545       supportRef[0] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (f - fMax)*2 + 0;
3546       supportRef[1] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (f - fMax)*2 + 1;
3547       for (s = 0; s < size; ++s) {
3548         ierr = DMPlexGetConeSize(dm, support[s], &csize);CHKERRQ(ierr);
3549         ierr = DMPlexGetCone(dm, support[s], &ccone);CHKERRQ(ierr);
3550         ierr = DMPlexGetConeOrientation(dm, support[s], &cornt);CHKERRQ(ierr);
3551         for (c = 0; c < csize; ++c) if (ccone[c] == f) break;
3552         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]);
3553         supportRef[2+s*2+0] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (support[s] - cMax)*3 + c-2;
3554         supportRef[2+s*2+1] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (support[s] - cMax)*3 + (c-1)%3;
3555       }
3556       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
3557 #if 1
3558       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid edge [%d, %d)", newp, eMaxNew, eEndNew);
3559       for (p = 0; p < 2+size*2; ++p) {
3560         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);
3561       }
3562 #endif
3563     }
3564     /* Interior vertices have identical supports */
3565     for (v = vStart; v < vEnd; ++v) {
3566       const PetscInt  newp = vStartNew + (v - vStart);
3567       const PetscInt *support, *cone;
3568       PetscInt        size, s;
3569 
3570       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
3571       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
3572       for (s = 0; s < size; ++s) {
3573         PetscInt r = 0;
3574 
3575         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
3576         if (cone[1] == v) r = 1;
3577         if (support[s] < eMax) supportRef[s] = eStartNew + (support[s] - eStart)*2 + r;
3578         else                   supportRef[s] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (support[s] - eMax);
3579       }
3580       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
3581 #if 1
3582       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
3583       for (p = 0; p < size; ++p) {
3584         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);
3585       }
3586 #endif
3587     }
3588     /* Interior edge vertices have 2 + interior face*2 + hybrid face + cells*0/1 supports */
3589     for (e = eStart; e < eMax; ++e) {
3590       const PetscInt  newp = vStartNew + (vEnd - vStart) + (e - eStart);
3591       const PetscInt *cone, *support;
3592       PetscInt       *star = NULL, starSize, faceSize = 0, cellSize = 0, coneSize, size, s;
3593 
3594       ierr          = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
3595       ierr          = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
3596       supportRef[0] = eStartNew + (e - eStart)*2 + 0;
3597       supportRef[1] = eStartNew + (e - eStart)*2 + 1;
3598       for (s = 0; s < size; ++s) {
3599         PetscInt r = 0;
3600 
3601         if (support[s] < fMax) {
3602           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
3603           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
3604           for (r = 0; r < coneSize; ++r) {if (cone[r] == e) break;}
3605           supportRef[2+faceSize+0] = eStartNew + (eMax - eStart)*2 + (support[s] - fStart)*3 + (r+0)%3;
3606           supportRef[2+faceSize+1] = eStartNew + (eMax - eStart)*2 + (support[s] - fStart)*3 + (r+2)%3;
3607           faceSize += 2;
3608         } else {
3609           supportRef[2+faceSize+0] = eStartNew + (eMax - eStart)*2 + (fMax       - fStart)*3 + (cMax - cStart) + (eEnd - eMax) + (support[s] - fMax);
3610           ++faceSize;
3611         }
3612       }
3613       ierr = DMPlexGetTransitiveClosure(dm, e, PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
3614       for (s = 0; s < starSize*2; s += 2) {
3615         const PetscInt *cone, *ornt;
3616         PetscInt        e01, e23;
3617 
3618         if ((star[s] >= cStart) && (star[s] < cMax)) {
3619           /* Check edge 0-1 */
3620           ierr = DMPlexGetCone(dm, star[s], &cone);CHKERRQ(ierr);
3621           ierr = DMPlexGetConeOrientation(dm, star[s], &ornt);CHKERRQ(ierr);
3622           ierr = DMPlexGetCone(dm, cone[0], &cone);CHKERRQ(ierr);
3623           e01  = cone[GetTriEdge_Static(ornt[0], 0)];
3624           /* Check edge 2-3 */
3625           ierr = DMPlexGetCone(dm, star[s], &cone);CHKERRQ(ierr);
3626           ierr = DMPlexGetConeOrientation(dm, star[s], &ornt);CHKERRQ(ierr);
3627           ierr = DMPlexGetCone(dm, cone[2], &cone);CHKERRQ(ierr);
3628           e23  = cone[GetTriEdge_Static(ornt[2], 1)];
3629           if ((e01 == e) || (e23 == e)) {supportRef[2+faceSize+cellSize++] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (star[s] - cStart);}
3630         }
3631       }
3632       ierr = DMPlexRestoreTransitiveClosure(dm, e, PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
3633       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
3634 #if 1
3635       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
3636       for (p = 0; p < 2+faceSize+cellSize; ++p) {
3637         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);
3638       }
3639 #endif
3640     }
3641     ierr = PetscFree(supportRef);CHKERRQ(ierr);
3642     ierr = DMPlexRestoreFaces_Internal(dm, 3, cStart, NULL, NULL, &faces);CHKERRQ(ierr);
3643     break;
3644   case 6:
3645     /* Hex 3D */
3646     /*
3647      Bottom (viewed from top)    Top
3648      1---------2---------2       7---------2---------6
3649      |         |         |       |         |         |
3650      |    B    2    C    |       |    H    2    G    |
3651      |         |         |       |         |         |
3652      3----3----0----1----1       3----3----0----1----1
3653      |         |         |       |         |         |
3654      |    A    0    D    |       |    E    0    F    |
3655      |         |         |       |         |         |
3656      0---------0---------3       4---------0---------5
3657      */
3658     /* All cells have 6 faces: Bottom, Top, Front, Back, Right, Left */
3659     for (c = cStart; c < cEnd; ++c) {
3660       const PetscInt  newp = (c - cStart)*8;
3661       const PetscInt *cone, *ornt;
3662       PetscInt        coneNew[6], orntNew[6];
3663 
3664       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
3665       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
3666       /* A hex */
3667       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], 0);
3668       orntNew[0] = ornt[0];
3669       coneNew[1] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  8; /* AE */
3670       orntNew[1] = 0;
3671       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetQuadSubface_Static(ornt[2], 0);
3672       orntNew[2] = ornt[2];
3673       coneNew[3] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  3; /* AB */
3674       orntNew[3] = 0;
3675       coneNew[4] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  0; /* AD */
3676       orntNew[4] = 0;
3677       coneNew[5] = fStartNew + (cone[5] - fStart)*4 + GetQuadSubface_Static(ornt[5], 0);
3678       orntNew[5] = ornt[5];
3679       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
3680       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
3681 #if 1
3682       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);
3683       for (p = 0; p < 6; ++p) {
3684         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);
3685       }
3686 #endif
3687       /* B hex */
3688       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], 1);
3689       orntNew[0] = ornt[0];
3690       coneNew[1] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 + 11; /* BH */
3691       orntNew[1] = 0;
3692       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  3; /* AB */
3693       orntNew[2] = -1;
3694       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetQuadSubface_Static(ornt[3], 1);
3695       orntNew[3] = ornt[3];
3696       coneNew[4] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  2; /* BC */
3697       orntNew[4] = 0;
3698       coneNew[5] = fStartNew + (cone[5] - fStart)*4 + GetQuadSubface_Static(ornt[5], 3);
3699       orntNew[5] = ornt[5];
3700       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
3701       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
3702 #if 1
3703       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);
3704       for (p = 0; p < 6; ++p) {
3705         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);
3706       }
3707 #endif
3708       /* C hex */
3709       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], 2);
3710       orntNew[0] = ornt[0];
3711       coneNew[1] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 + 10; /* CG */
3712       orntNew[1] = 0;
3713       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  1; /* CD */
3714       orntNew[2] = -1;
3715       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetQuadSubface_Static(ornt[3], 0);
3716       orntNew[3] = ornt[3];
3717       coneNew[4] = fStartNew + (cone[4] - fStart)*4 + GetQuadSubface_Static(ornt[4], 1);
3718       orntNew[4] = ornt[4];
3719       coneNew[5] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  2; /* BC */
3720       orntNew[5] = -4;
3721       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
3722       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
3723 #if 1
3724       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);
3725       for (p = 0; p < 6; ++p) {
3726         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);
3727       }
3728 #endif
3729       /* D hex */
3730       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], 3);
3731       orntNew[0] = ornt[0];
3732       coneNew[1] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  9; /* DF */
3733       orntNew[1] = 0;
3734       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetQuadSubface_Static(ornt[2], 1);
3735       orntNew[2] = ornt[2];
3736       coneNew[3] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  1; /* CD */
3737       orntNew[3] = 0;
3738       coneNew[4] = fStartNew + (cone[4] - fStart)*4 + GetQuadSubface_Static(ornt[4], 0);
3739       orntNew[4] = ornt[4];
3740       coneNew[5] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  0; /* AD */
3741       orntNew[5] = -4;
3742       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
3743       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
3744 #if 1
3745       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);
3746       for (p = 0; p < 6; ++p) {
3747         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);
3748       }
3749 #endif
3750       /* E hex */
3751       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  8; /* AE */
3752       orntNew[0] = -4;
3753       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], 0);
3754       orntNew[1] = ornt[1];
3755       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetQuadSubface_Static(ornt[2], 3);
3756       orntNew[2] = ornt[2];
3757       coneNew[3] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  7; /* EH */
3758       orntNew[3] = 0;
3759       coneNew[4] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  4; /* EF */
3760       orntNew[4] = -1;
3761       coneNew[5] = fStartNew + (cone[5] - fStart)*4 + GetQuadSubface_Static(ornt[5], 1);
3762       orntNew[5] = ornt[5];
3763       ierr       = DMPlexSetCone(rdm, newp+4, coneNew);CHKERRQ(ierr);
3764       ierr       = DMPlexSetConeOrientation(rdm, newp+4, orntNew);CHKERRQ(ierr);
3765 #if 1
3766       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);
3767       for (p = 0; p < 6; ++p) {
3768         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);
3769       }
3770 #endif
3771       /* F hex */
3772       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  9; /* DF */
3773       orntNew[0] = -4;
3774       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], 1);
3775       orntNew[1] = ornt[1];
3776       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetQuadSubface_Static(ornt[2], 2);
3777       orntNew[2] = ornt[2];
3778       coneNew[3] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  5; /* FG */
3779       orntNew[3] = -1;
3780       coneNew[4] = fStartNew + (cone[4] - fStart)*4 + GetQuadSubface_Static(ornt[4], 3);
3781       orntNew[4] = ornt[4];
3782       coneNew[5] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  4; /* EF */
3783       orntNew[5] = 1;
3784       ierr       = DMPlexSetCone(rdm, newp+5, coneNew);CHKERRQ(ierr);
3785       ierr       = DMPlexSetConeOrientation(rdm, newp+5, orntNew);CHKERRQ(ierr);
3786 #if 1
3787       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);
3788       for (p = 0; p < 6; ++p) {
3789         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);
3790       }
3791 #endif
3792       /* G hex */
3793       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 + 10; /* CG */
3794       orntNew[0] = -4;
3795       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], 2);
3796       orntNew[1] = ornt[1];
3797       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  5; /* FG */
3798       orntNew[2] = 0;
3799       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetQuadSubface_Static(ornt[3], 3);
3800       orntNew[3] = ornt[3];
3801       coneNew[4] = fStartNew + (cone[4] - fStart)*4 + GetQuadSubface_Static(ornt[4], 2);
3802       orntNew[4] = ornt[4];
3803       coneNew[5] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  6; /* GH */
3804       orntNew[5] = -3;
3805       ierr       = DMPlexSetCone(rdm, newp+6, coneNew);CHKERRQ(ierr);
3806       ierr       = DMPlexSetConeOrientation(rdm, newp+6, orntNew);CHKERRQ(ierr);
3807 #if 1
3808       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);
3809       for (p = 0; p < 6; ++p) {
3810         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);
3811       }
3812 #endif
3813       /* H hex */
3814       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 + 11; /* BH */
3815       orntNew[0] = -4;
3816       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], 3);
3817       orntNew[1] = ornt[1];
3818       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  7; /* EH */
3819       orntNew[2] = -1;
3820       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetQuadSubface_Static(ornt[3], 2);
3821       orntNew[3] = ornt[3];
3822       coneNew[4] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  6; /* GH */
3823       orntNew[4] = 3;
3824       coneNew[5] = fStartNew + (cone[5] - fStart)*4 + GetQuadSubface_Static(ornt[5], 2);
3825       orntNew[5] = ornt[5];
3826       ierr       = DMPlexSetCone(rdm, newp+7, coneNew);CHKERRQ(ierr);
3827       ierr       = DMPlexSetConeOrientation(rdm, newp+7, orntNew);CHKERRQ(ierr);
3828 #if 1
3829       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);
3830       for (p = 0; p < 6; ++p) {
3831         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);
3832       }
3833 #endif
3834     }
3835     /* Split faces have 4 edges and the same cells as the parent */
3836     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
3837     ierr = PetscMalloc1((4 + maxSupportSize*2), &supportRef);CHKERRQ(ierr);
3838     for (f = fStart; f < fEnd; ++f) {
3839       for (r = 0; r < 4; ++r) {
3840         /* TODO: This can come from GetFaces_Internal() */
3841         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};
3842         const PetscInt  newp = fStartNew + (f - fStart)*4 + r;
3843         const PetscInt *cone, *ornt, *support;
3844         PetscInt        coneNew[4], orntNew[4], coneSize, c, supportSize, s;
3845 
3846         ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
3847         ierr = DMPlexGetConeOrientation(dm, f, &ornt);CHKERRQ(ierr);
3848         coneNew[(r+3)%4] = eStartNew + (cone[(r+3)%4] - eStart)*2 + (ornt[(r+3)%4] < 0 ? 0 : 1);
3849         orntNew[(r+3)%4] = ornt[(r+3)%4];
3850         coneNew[(r+0)%4] = eStartNew + (cone[r]       - eStart)*2 + (ornt[r] < 0 ? 1 : 0);
3851         orntNew[(r+0)%4] = ornt[r];
3852         coneNew[(r+1)%4] = eStartNew + (eEnd - eStart)*2 + (f - fStart)*4 + r;
3853         orntNew[(r+1)%4] = 0;
3854         coneNew[(r+2)%4] = eStartNew + (eEnd - eStart)*2 + (f - fStart)*4 + (r+3)%4;
3855         orntNew[(r+2)%4] = -2;
3856         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3857         ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3858 #if 1
3859         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
3860         for (p = 0; p < 4; ++p) {
3861           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);
3862         }
3863 #endif
3864         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
3865         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
3866         for (s = 0; s < supportSize; ++s) {
3867           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
3868           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
3869           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
3870           for (c = 0; c < coneSize; ++c) {
3871             if (cone[c] == f) break;
3872           }
3873           supportRef[s] = cStartNew + (support[s] - cStart)*8 + newCells[c*4+GetQuadSubfaceInverse_Static(ornt[c], r)];
3874         }
3875         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
3876 #if 1
3877         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
3878         for (p = 0; p < supportSize; ++p) {
3879           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);
3880         }
3881 #endif
3882       }
3883     }
3884     /* Interior faces have 4 edges and 2 cells */
3885     for (c = cStart; c < cEnd; ++c) {
3886       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};
3887       const PetscInt *cone, *ornt;
3888       PetscInt        newp, coneNew[4], orntNew[4], supportNew[2];
3889 
3890       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
3891       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
3892       /* A-D face */
3893       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 0;
3894       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*4 + GetQuadEdge_Static(ornt[0], 3);
3895       orntNew[0] = 0;
3896       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 0;
3897       orntNew[1] = 0;
3898       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 2;
3899       orntNew[2] = -2;
3900       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*4 + GetQuadEdge_Static(ornt[2], 0);
3901       orntNew[3] = -2;
3902       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3903       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3904 #if 1
3905       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
3906       for (p = 0; p < 4; ++p) {
3907         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);
3908       }
3909 #endif
3910       /* C-D face */
3911       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 1;
3912       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*4 + GetQuadEdge_Static(ornt[0], 2);
3913       orntNew[0] = 0;
3914       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 0;
3915       orntNew[1] = 0;
3916       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 4;
3917       orntNew[2] = -2;
3918       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (cone[4] - fStart)*4 + GetQuadEdge_Static(ornt[4], 0);
3919       orntNew[3] = -2;
3920       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3921       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3922 #if 1
3923       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
3924       for (p = 0; p < 4; ++p) {
3925         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);
3926       }
3927 #endif
3928       /* B-C face */
3929       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 2;
3930       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*4 + GetQuadEdge_Static(ornt[0], 1);
3931       orntNew[0] = -2;
3932       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*4 + GetQuadEdge_Static(ornt[3], 0);
3933       orntNew[1] = 0;
3934       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 3;
3935       orntNew[2] = 0;
3936       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 0;
3937       orntNew[3] = -2;
3938       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3939       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3940 #if 1
3941       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
3942       for (p = 0; p < 4; ++p) {
3943         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);
3944       }
3945 #endif
3946       /* A-B face */
3947       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 3;
3948       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*4 + GetQuadEdge_Static(ornt[0], 0);
3949       orntNew[0] = -2;
3950       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[5] - fStart)*4 + GetQuadEdge_Static(ornt[5], 3);
3951       orntNew[1] = 0;
3952       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 5;
3953       orntNew[2] = 0;
3954       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 0;
3955       orntNew[3] = -2;
3956       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3957       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3958 #if 1
3959       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
3960       for (p = 0; p < 4; ++p) {
3961         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);
3962       }
3963 #endif
3964       /* E-F face */
3965       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 4;
3966       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 2;
3967       orntNew[0] = -2;
3968       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*4 + GetQuadEdge_Static(ornt[2], 2);
3969       orntNew[1] = -2;
3970       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*4 + GetQuadEdge_Static(ornt[1], 0);
3971       orntNew[2] = 0;
3972       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 1;
3973       orntNew[3] = 0;
3974       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3975       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3976 #if 1
3977       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
3978       for (p = 0; p < 4; ++p) {
3979         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);
3980       }
3981 #endif
3982       /* F-G face */
3983       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 5;
3984       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 4;
3985       orntNew[0] = -2;
3986       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[4] - fStart)*4 + GetQuadEdge_Static(ornt[4], 2);
3987       orntNew[1] = -2;
3988       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*4 + GetQuadEdge_Static(ornt[1], 1);
3989       orntNew[2] = 0;
3990       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 1;
3991       orntNew[3] = 0;
3992       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3993       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3994 #if 1
3995       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
3996       for (p = 0; p < 4; ++p) {
3997         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);
3998       }
3999 #endif
4000       /* G-H face */
4001       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 6;
4002       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*4 + GetQuadEdge_Static(ornt[3], 2);
4003       orntNew[0] = -2;
4004       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*4 + GetQuadEdge_Static(ornt[1], 2);
4005       orntNew[1] = 0;
4006       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 1;
4007       orntNew[2] = 0;
4008       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 3;
4009       orntNew[3] = -2;
4010       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4011       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4012 #if 1
4013       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4014       for (p = 0; p < 4; ++p) {
4015         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);
4016       }
4017 #endif
4018       /* E-H face */
4019       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 7;
4020       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 5;
4021       orntNew[0] = -2;
4022       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[5] - fStart)*4 + GetQuadEdge_Static(ornt[5], 1);
4023       orntNew[1] = -2;
4024       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*4 + GetQuadEdge_Static(ornt[1], 3);
4025       orntNew[2] = 0;
4026       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 1;
4027       orntNew[3] = 0;
4028       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4029       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4030 #if 1
4031       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4032       for (p = 0; p < 4; ++p) {
4033         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);
4034       }
4035 #endif
4036       /* A-E face */
4037       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 8;
4038       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*4 + GetQuadEdge_Static(ornt[2], 3);
4039       orntNew[0] = 0;
4040       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 2;
4041       orntNew[1] = 0;
4042       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 5;
4043       orntNew[2] = -2;
4044       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (cone[5] - fStart)*4 + GetQuadEdge_Static(ornt[5], 0);
4045       orntNew[3] = -2;
4046       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4047       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4048 #if 1
4049       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4050       for (p = 0; p < 4; ++p) {
4051         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);
4052       }
4053 #endif
4054       /* D-F face */
4055       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 9;
4056       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*4 + GetQuadEdge_Static(ornt[2], 1);
4057       orntNew[0] = -2;
4058       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[4] - fStart)*4 + GetQuadEdge_Static(ornt[4], 3);
4059       orntNew[1] = 0;
4060       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 4;
4061       orntNew[2] = 0;
4062       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 2;
4063       orntNew[3] = -2;
4064       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4065       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4066 #if 1
4067       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4068       for (p = 0; p < 4; ++p) {
4069         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);
4070       }
4071 #endif
4072       /* C-G face */
4073       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 10;
4074       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 4;
4075       orntNew[0] = -2;
4076       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[4] - fStart)*4 + GetQuadEdge_Static(ornt[4], 1);
4077       orntNew[1] = -2;
4078       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*4 + GetQuadEdge_Static(ornt[3], 3);
4079       orntNew[2] = 0;
4080       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 3;
4081       orntNew[3] = 0;
4082       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4083       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4084 #if 1
4085       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4086       for (p = 0; p < 4; ++p) {
4087         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);
4088       }
4089 #endif
4090       /* B-H face */
4091       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 11;
4092       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 5;
4093       orntNew[0] = 0;
4094       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 3;
4095       orntNew[1] = -2;
4096       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*4 + GetQuadEdge_Static(ornt[3], 1);
4097       orntNew[2] = -2;
4098       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (cone[5] - fStart)*4 + GetQuadEdge_Static(ornt[5], 2);
4099       orntNew[3] = 0;
4100       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4101       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4102 #if 1
4103       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4104       for (p = 0; p < 4; ++p) {
4105         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);
4106       }
4107 #endif
4108       for (r = 0; r < 12; ++r) {
4109         newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + r;
4110         supportNew[0] = cStartNew + (c - cStart)*8 + newCells[r*2+0];
4111         supportNew[1] = cStartNew + (c - cStart)*8 + newCells[r*2+1];
4112         ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
4113 #if 1
4114         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4115         for (p = 0; p < 2; ++p) {
4116           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);
4117         }
4118 #endif
4119       }
4120     }
4121     /* Split edges have 2 vertices and the same faces as the parent */
4122     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
4123     for (e = eStart; e < eEnd; ++e) {
4124       const PetscInt newv = vStartNew + (vEnd - vStart) + (e - eStart);
4125 
4126       for (r = 0; r < 2; ++r) {
4127         const PetscInt  newp = eStartNew + (e - eStart)*2 + r;
4128         const PetscInt *cone, *ornt, *support;
4129         PetscInt        coneNew[2], coneSize, c, supportSize, s;
4130 
4131         ierr             = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
4132         coneNew[0]       = vStartNew + (cone[0] - vStart);
4133         coneNew[1]       = vStartNew + (cone[1] - vStart);
4134         coneNew[(r+1)%2] = newv;
4135         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4136 #if 1
4137         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
4138         for (p = 0; p < 2; ++p) {
4139           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);
4140         }
4141 #endif
4142         ierr = DMPlexGetSupportSize(dm, e, &supportSize);CHKERRQ(ierr);
4143         ierr = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
4144         for (s = 0; s < supportSize; ++s) {
4145           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
4146           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
4147           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
4148           for (c = 0; c < coneSize; ++c) {
4149             if (cone[c] == e) break;
4150           }
4151           supportRef[s] = fStartNew + (support[s] - fStart)*4 + (ornt[c] < 0 ? (c+1-r)%4 : (c+r)%4);
4152         }
4153         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
4154 #if 1
4155         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
4156         for (p = 0; p < supportSize; ++p) {
4157           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);
4158         }
4159 #endif
4160       }
4161     }
4162     /* Face edges have 2 vertices and 2+cells faces */
4163     for (f = fStart; f < fEnd; ++f) {
4164       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};
4165       const PetscInt  newv = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (f - fStart);
4166       const PetscInt *cone, *coneCell, *orntCell, *support;
4167       PetscInt        coneNew[2], coneSize, c, supportSize, s;
4168 
4169       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
4170       for (r = 0; r < 4; ++r) {
4171         const PetscInt newp = eStartNew + (eEnd - eStart)*2 + (f - fStart)*4 + r;
4172 
4173         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r] - eStart);
4174         coneNew[1] = newv;
4175         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4176 #if 1
4177         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
4178         for (p = 0; p < 2; ++p) {
4179           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);
4180         }
4181 #endif
4182         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
4183         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
4184         supportRef[0] = fStartNew + (f - fStart)*4 + r;
4185         supportRef[1] = fStartNew + (f - fStart)*4 + (r+1)%4;
4186         for (s = 0; s < supportSize; ++s) {
4187           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
4188           ierr = DMPlexGetCone(dm, support[s], &coneCell);CHKERRQ(ierr);
4189           ierr = DMPlexGetConeOrientation(dm, support[s], &orntCell);CHKERRQ(ierr);
4190           for (c = 0; c < coneSize; ++c) if (coneCell[c] == f) break;
4191           supportRef[2+s] = fStartNew + (fEnd - fStart)*4 + (support[s] - cStart)*12 + newFaces[c*4 + GetQuadEdgeInverse_Static(orntCell[c], r)];
4192         }
4193         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
4194 #if 1
4195         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
4196         for (p = 0; p < 2+supportSize; ++p) {
4197           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);
4198         }
4199 #endif
4200       }
4201     }
4202     /* Cell edges have 2 vertices and 4 faces */
4203     for (c = cStart; c < cEnd; ++c) {
4204       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};
4205       const PetscInt  newv = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (fEnd - fStart) + (c - cStart);
4206       const PetscInt *cone;
4207       PetscInt        coneNew[2], supportNew[4];
4208 
4209       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
4210       for (r = 0; r < 6; ++r) {
4211         const PetscInt newp = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*4 + (c - cStart)*6 + r;
4212 
4213         coneNew[0] = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (cone[r] - fStart);
4214         coneNew[1] = newv;
4215         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4216 #if 1
4217         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
4218         for (p = 0; p < 2; ++p) {
4219           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);
4220         }
4221 #endif
4222         for (f = 0; f < 4; ++f) supportNew[f] = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + newFaces[r*4+f];
4223         ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
4224 #if 1
4225         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
4226         for (p = 0; p < 4; ++p) {
4227           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);
4228         }
4229 #endif
4230       }
4231     }
4232     /* Old vertices have identical supports */
4233     for (v = vStart; v < vEnd; ++v) {
4234       const PetscInt  newp = vStartNew + (v - vStart);
4235       const PetscInt *support, *cone;
4236       PetscInt        size, s;
4237 
4238       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
4239       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
4240       for (s = 0; s < size; ++s) {
4241         PetscInt r = 0;
4242 
4243         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
4244         if (cone[1] == v) r = 1;
4245         supportRef[s] = eStartNew + (support[s] - eStart)*2 + r;
4246       }
4247       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
4248 #if 1
4249       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
4250       for (p = 0; p < size; ++p) {
4251         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);
4252       }
4253 #endif
4254     }
4255     /* Edge vertices have 2 + faces supports */
4256     for (e = eStart; e < eEnd; ++e) {
4257       const PetscInt  newp = vStartNew + (vEnd - vStart) + (e - eStart);
4258       const PetscInt *cone, *support;
4259       PetscInt        size, s;
4260 
4261       ierr          = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
4262       ierr          = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
4263       supportRef[0] = eStartNew + (e - eStart)*2 + 0;
4264       supportRef[1] = eStartNew + (e - eStart)*2 + 1;
4265       for (s = 0; s < size; ++s) {
4266         PetscInt r;
4267 
4268         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
4269         for (r = 0; r < 4; ++r) if (cone[r] == e) break;
4270         supportRef[2+s] = eStartNew + (eEnd - eStart)*2 + (support[s] - fStart)*4 + r;
4271       }
4272       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
4273 #if 1
4274       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
4275       for (p = 0; p < 2+size; ++p) {
4276         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);
4277       }
4278 #endif
4279     }
4280     /* Face vertices have 4 + cells supports */
4281     for (f = fStart; f < fEnd; ++f) {
4282       const PetscInt  newp = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (f - fStart);
4283       const PetscInt *cone, *support;
4284       PetscInt        size, s;
4285 
4286       ierr          = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
4287       ierr          = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
4288       for (r = 0; r < 4; ++r) supportRef[r] = eStartNew + (eEnd - eStart)*2 +  (f - fStart)*4 + r;
4289       for (s = 0; s < size; ++s) {
4290         PetscInt r;
4291 
4292         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
4293         for (r = 0; r < 6; ++r) if (cone[r] == f) break;
4294         supportRef[4+s] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*4 + (support[s] - cStart)*6 + r;
4295       }
4296       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
4297 #if 1
4298       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
4299       for (p = 0; p < 4+size; ++p) {
4300         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);
4301       }
4302 #endif
4303     }
4304     /* Cell vertices have 6 supports */
4305     for (c = cStart; c < cEnd; ++c) {
4306       const PetscInt newp = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (fEnd - fStart) + (c - cStart);
4307       PetscInt       supportNew[6];
4308 
4309       for (r = 0; r < 6; ++r) {
4310         supportNew[r] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*4 + (c - cStart)*6 + r;
4311       }
4312       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
4313     }
4314     ierr = PetscFree(supportRef);CHKERRQ(ierr);
4315     break;
4316   case 8:
4317     /* Hybrid Hex 3D */
4318     ierr = DMPlexGetHybridBounds(rdm, &cMaxNew, &fMaxNew, &eMaxNew, NULL);CHKERRQ(ierr);
4319     /*
4320      Bottom (viewed from top)    Top
4321      1---------2---------2       7---------2---------6
4322      |         |         |       |         |         |
4323      |    B    2    C    |       |    H    2    G    |
4324      |         |         |       |         |         |
4325      3----3----0----1----1       3----3----0----1----1
4326      |         |         |       |         |         |
4327      |    A    0    D    |       |    E    0    F    |
4328      |         |         |       |         |         |
4329      0---------0---------3       4---------0---------5
4330      */
4331     /* Interior cells have 6 faces: Bottom, Top, Front, Back, Right, Left */
4332     for (c = cStart; c < cMax; ++c) {
4333       const PetscInt  newp = (c - cStart)*8;
4334       const PetscInt *cone, *ornt;
4335       PetscInt        coneNew[6], orntNew[6];
4336 
4337       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
4338       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
4339       /* A hex */
4340       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], 0);
4341       orntNew[0] = ornt[0];
4342       coneNew[1] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  8; /* AE */
4343       orntNew[1] = 0;
4344       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetQuadSubface_Static(ornt[2], 0);
4345       orntNew[2] = ornt[2];
4346       coneNew[3] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  3; /* AB */
4347       orntNew[3] = 0;
4348       coneNew[4] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  0; /* AD */
4349       orntNew[4] = 0;
4350       coneNew[5] = fStartNew + (cone[5] - fStart)*4 + GetQuadSubface_Static(ornt[5], 0);
4351       orntNew[5] = ornt[5];
4352       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
4353       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
4354 #if 1
4355       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);
4356       for (p = 0; p < 6; ++p) {
4357         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);
4358       }
4359 #endif
4360       /* B hex */
4361       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], 1);
4362       orntNew[0] = ornt[0];
4363       coneNew[1] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 + 11; /* BH */
4364       orntNew[1] = 0;
4365       coneNew[2] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  3; /* AB */
4366       orntNew[2] = -1;
4367       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetQuadSubface_Static(ornt[3], 1);
4368       orntNew[3] = ornt[3];
4369       coneNew[4] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  2; /* BC */
4370       orntNew[4] = 0;
4371       coneNew[5] = fStartNew + (cone[5] - fStart)*4 + GetQuadSubface_Static(ornt[5], 3);
4372       orntNew[5] = ornt[5];
4373       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
4374       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
4375 #if 1
4376       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);
4377       for (p = 0; p < 6; ++p) {
4378         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);
4379       }
4380 #endif
4381       /* C hex */
4382       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], 2);
4383       orntNew[0] = ornt[0];
4384       coneNew[1] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 + 10; /* CG */
4385       orntNew[1] = 0;
4386       coneNew[2] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  1; /* CD */
4387       orntNew[2] = -1;
4388       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetQuadSubface_Static(ornt[3], 0);
4389       orntNew[3] = ornt[3];
4390       coneNew[4] = fStartNew + (cone[4] - fStart)*4 + GetQuadSubface_Static(ornt[4], 1);
4391       orntNew[4] = ornt[4];
4392       coneNew[5] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  2; /* BC */
4393       orntNew[5] = -4;
4394       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
4395       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
4396 #if 1
4397       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);
4398       for (p = 0; p < 6; ++p) {
4399         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);
4400       }
4401 #endif
4402       /* D hex */
4403       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], 3);
4404       orntNew[0] = ornt[0];
4405       coneNew[1] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  9; /* DF */
4406       orntNew[1] = 0;
4407       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetQuadSubface_Static(ornt[2], 1);
4408       orntNew[2] = ornt[2];
4409       coneNew[3] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  1; /* CD */
4410       orntNew[3] = 0;
4411       coneNew[4] = fStartNew + (cone[4] - fStart)*4 + GetQuadSubface_Static(ornt[4], 0);
4412       orntNew[4] = ornt[4];
4413       coneNew[5] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  0; /* AD */
4414       orntNew[5] = -4;
4415       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
4416       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
4417 #if 1
4418       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);
4419       for (p = 0; p < 6; ++p) {
4420         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);
4421       }
4422 #endif
4423       /* E hex */
4424       coneNew[0] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  8; /* AE */
4425       orntNew[0] = -4;
4426       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], 0);
4427       orntNew[1] = ornt[1];
4428       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetQuadSubface_Static(ornt[2], 3);
4429       orntNew[2] = ornt[2];
4430       coneNew[3] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  7; /* EH */
4431       orntNew[3] = 0;
4432       coneNew[4] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  4; /* EF */
4433       orntNew[4] = -1;
4434       coneNew[5] = fStartNew + (cone[5] - fStart)*4 + GetQuadSubface_Static(ornt[5], 1);
4435       orntNew[5] = ornt[5];
4436       ierr       = DMPlexSetCone(rdm, newp+4, coneNew);CHKERRQ(ierr);
4437       ierr       = DMPlexSetConeOrientation(rdm, newp+4, orntNew);CHKERRQ(ierr);
4438 #if 1
4439       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);
4440       for (p = 0; p < 6; ++p) {
4441         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);
4442       }
4443 #endif
4444       /* F hex */
4445       coneNew[0] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  9; /* DF */
4446       orntNew[0] = -4;
4447       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], 1);
4448       orntNew[1] = ornt[1];
4449       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetQuadSubface_Static(ornt[2], 2);
4450       orntNew[2] = ornt[2];
4451       coneNew[3] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  5; /* FG */
4452       orntNew[3] = -1;
4453       coneNew[4] = fStartNew + (cone[4] - fStart)*4 + GetQuadSubface_Static(ornt[4], 3);
4454       orntNew[4] = ornt[4];
4455       coneNew[5] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  4; /* EF */
4456       orntNew[5] = 1;
4457       ierr       = DMPlexSetCone(rdm, newp+5, coneNew);CHKERRQ(ierr);
4458       ierr       = DMPlexSetConeOrientation(rdm, newp+5, orntNew);CHKERRQ(ierr);
4459 #if 1
4460       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);
4461       for (p = 0; p < 6; ++p) {
4462         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);
4463       }
4464 #endif
4465       /* G hex */
4466       coneNew[0] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 + 10; /* CG */
4467       orntNew[0] = -4;
4468       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], 2);
4469       orntNew[1] = ornt[1];
4470       coneNew[2] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  5; /* FG */
4471       orntNew[2] = 0;
4472       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetQuadSubface_Static(ornt[3], 3);
4473       orntNew[3] = ornt[3];
4474       coneNew[4] = fStartNew + (cone[4] - fStart)*4 + GetQuadSubface_Static(ornt[4], 2);
4475       orntNew[4] = ornt[4];
4476       coneNew[5] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  6; /* GH */
4477       orntNew[5] = -3;
4478       ierr       = DMPlexSetCone(rdm, newp+6, coneNew);CHKERRQ(ierr);
4479       ierr       = DMPlexSetConeOrientation(rdm, newp+6, orntNew);CHKERRQ(ierr);
4480 #if 1
4481       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);
4482       for (p = 0; p < 6; ++p) {
4483         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);
4484       }
4485 #endif
4486       /* H hex */
4487       coneNew[0] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 + 11; /* BH */
4488       orntNew[0] = -4;
4489       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], 3);
4490       orntNew[1] = ornt[1];
4491       coneNew[2] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  7; /* EH */
4492       orntNew[2] = -1;
4493       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetQuadSubface_Static(ornt[3], 2);
4494       orntNew[3] = ornt[3];
4495       coneNew[4] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  6; /* GH */
4496       orntNew[4] = 3;
4497       coneNew[5] = fStartNew + (cone[5] - fStart)*4 + GetQuadSubface_Static(ornt[5], 2);
4498       orntNew[5] = ornt[5];
4499       ierr       = DMPlexSetCone(rdm, newp+7, coneNew);CHKERRQ(ierr);
4500       ierr       = DMPlexSetConeOrientation(rdm, newp+7, orntNew);CHKERRQ(ierr);
4501 #if 1
4502       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);
4503       for (p = 0; p < 6; ++p) {
4504         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);
4505       }
4506 #endif
4507     }
4508     /* Hybrid cells have 6 faces: Front, Back, Sides */
4509     /*
4510      3---------2---------2
4511      |         |         |
4512      |    D    2    C    |
4513      |         |         |
4514      3----3----0----1----1
4515      |         |         |
4516      |    A    0    B    |
4517      |         |         |
4518      0---------0---------1
4519      */
4520     for (c = cMax; c < cEnd; ++c) {
4521       const PetscInt  newp = (cMax - cStart)*8 + (c - cMax)*4;
4522       const PetscInt *cone, *ornt, *fornt;
4523       PetscInt        coneNew[6], orntNew[6];
4524 
4525       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
4526       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
4527       ierr = DMPlexGetConeOrientation(dm, cone[0], &fornt);CHKERRQ(ierr);
4528       for (r = 0; r < 4; ++r) {
4529         PetscInt subfA = GetQuadSubface_Static(ornt[0], r);
4530         PetscInt edgeA = GetQuadEdge_Static(ornt[0], r);
4531         PetscInt edgeB = (edgeA+3)%4;
4532         if (ornt[0] != ornt[1]) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Inconsistent ordering for matching ends of hybrid cell %d: %d != %d", c, ornt[0], ornt[1]);
4533         coneNew[0]         = fStartNew + (cone[0] - fStart)*4 + subfA;
4534         orntNew[0]         = ornt[0];
4535         coneNew[1]         = fStartNew + (cone[1] - fStart)*4 + subfA;
4536         orntNew[1]         = ornt[0];
4537         coneNew[(r+0)%4+2] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (cone[edgeA+2] - fMax)*2 + (fornt[edgeA] < 0 ? 1 : 0);
4538         orntNew[(r+0)%4+2] = ornt[edgeA];
4539         coneNew[(r+1)%4+2] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd          - fMax)*2 + (c - cMax)*4 + edgeA;
4540         orntNew[(r+1)%4+2] = 0;
4541         coneNew[(r+2)%4+2] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd          - fMax)*2 + (c - cMax)*4 + edgeB;
4542         orntNew[(r+2)%4+2] = -2;
4543         coneNew[(r+3)%4+2] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (cone[edgeB+2] - fMax)*2 + (fornt[edgeB] < 0 ? 0 : 1);
4544         orntNew[(r+3)%4+2] = ornt[edgeB];
4545         ierr       = DMPlexSetCone(rdm, newp+r, coneNew);CHKERRQ(ierr);
4546         ierr       = DMPlexSetConeOrientation(rdm, newp+r, orntNew);CHKERRQ(ierr);
4547 #if 1
4548         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);
4549         for (p = 0; p < 2; ++p) {
4550           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);
4551         }
4552         for (p = 2; p < 6; ++p) {
4553           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);
4554         }
4555 #endif
4556       }
4557     }
4558     /* Interior split faces have 4 edges and the same cells as the parent */
4559     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
4560     ierr = PetscMalloc1((4 + maxSupportSize*2), &supportRef);CHKERRQ(ierr);
4561     for (f = fStart; f < fMax; ++f) {
4562       for (r = 0; r < 4; ++r) {
4563         /* TODO: This can come from GetFaces_Internal() */
4564         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};
4565         const PetscInt  newp = fStartNew + (f - fStart)*4 + r;
4566         const PetscInt *cone, *ornt, *support;
4567         PetscInt        coneNew[4], orntNew[4], coneSize, c, supportSize, s;
4568 
4569         ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
4570         ierr = DMPlexGetConeOrientation(dm, f, &ornt);CHKERRQ(ierr);
4571         coneNew[(r+3)%4] = eStartNew + (cone[(r+3)%4] - eStart)*2 + (ornt[(r+3)%4] < 0 ? 0 : 1);
4572         orntNew[(r+3)%4] = ornt[(r+3)%4];
4573         coneNew[(r+0)%4] = eStartNew + (cone[r]       - eStart)*2 + (ornt[r] < 0 ? 1 : 0);
4574         orntNew[(r+0)%4] = ornt[r];
4575         coneNew[(r+1)%4] = eStartNew + (eMax - eStart)*2 + (f - fStart)*4 + r;
4576         orntNew[(r+1)%4] = 0;
4577         coneNew[(r+2)%4] = eStartNew + (eMax - eStart)*2 + (f - fStart)*4 + (r+3)%4;
4578         orntNew[(r+2)%4] = -2;
4579         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4580         ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4581 #if 1
4582         if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
4583         for (p = 0; p < 4; ++p) {
4584           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);
4585         }
4586 #endif
4587         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
4588         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
4589         for (s = 0; s < supportSize; ++s) {
4590           PetscInt subf;
4591           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
4592           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
4593           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
4594           for (c = 0; c < coneSize; ++c) {
4595             if (cone[c] == f) break;
4596           }
4597           subf = GetQuadSubfaceInverse_Static(ornt[c], r);
4598           if (support[s] < cMax) {
4599             supportRef[s] = cStartNew + (support[s] - cStart)*8 + newCells[c*4+subf];
4600           } else {
4601             supportRef[s] = cStartNew + (cMax       - cStart)*8 + (support[s] - cMax)*4 + subf;
4602           }
4603         }
4604         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
4605 #if 1
4606         if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
4607         for (p = 0; p < supportSize; ++p) {
4608           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);
4609         }
4610 #endif
4611       }
4612     }
4613     /* Interior faces have 4 edges and 2 cells */
4614     for (c = cStart; c < cMax; ++c) {
4615       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};
4616       const PetscInt *cone, *ornt;
4617       PetscInt        newp, coneNew[4], orntNew[4], supportNew[2];
4618 
4619       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
4620       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
4621       /* A-D face */
4622       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 0;
4623       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*4 + GetQuadEdge_Static(ornt[0], 3);
4624       orntNew[0] = 0;
4625       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 0;
4626       orntNew[1] = 0;
4627       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 2;
4628       orntNew[2] = -2;
4629       coneNew[3] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*4 + GetQuadEdge_Static(ornt[2], 0);
4630       orntNew[3] = -2;
4631       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4632       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4633 #if 1
4634       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
4635       for (p = 0; p < 4; ++p) {
4636         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);
4637       }
4638 #endif
4639       /* C-D face */
4640       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 1;
4641       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*4 + GetQuadEdge_Static(ornt[0], 2);
4642       orntNew[0] = 0;
4643       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 0;
4644       orntNew[1] = 0;
4645       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 4;
4646       orntNew[2] = -2;
4647       coneNew[3] = eStartNew + (eMax - eStart)*2 + (cone[4] - fStart)*4 + GetQuadEdge_Static(ornt[4], 0);
4648       orntNew[3] = -2;
4649       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4650       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4651 #if 1
4652       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
4653       for (p = 0; p < 4; ++p) {
4654         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);
4655       }
4656 #endif
4657       /* B-C face */
4658       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 2;
4659       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*4 + GetQuadEdge_Static(ornt[0], 1);
4660       orntNew[0] = -2;
4661       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*4 + GetQuadEdge_Static(ornt[3], 0);
4662       orntNew[1] = 0;
4663       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 3;
4664       orntNew[2] = 0;
4665       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 0;
4666       orntNew[3] = -2;
4667       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4668       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4669 #if 1
4670       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
4671       for (p = 0; p < 4; ++p) {
4672         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);
4673       }
4674 #endif
4675       /* A-B face */
4676       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 3;
4677       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*4 + GetQuadEdge_Static(ornt[0], 0);
4678       orntNew[0] = -2;
4679       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[5] - fStart)*4 + GetQuadEdge_Static(ornt[5], 3);
4680       orntNew[1] = 0;
4681       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 5;
4682       orntNew[2] = 0;
4683       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 0;
4684       orntNew[3] = -2;
4685       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4686       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4687 #if 1
4688       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
4689       for (p = 0; p < 4; ++p) {
4690         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);
4691       }
4692 #endif
4693       /* E-F face */
4694       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 4;
4695       coneNew[0] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 2;
4696       orntNew[0] = -2;
4697       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*4 + GetQuadEdge_Static(ornt[2], 2);
4698       orntNew[1] = -2;
4699       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*4 + GetQuadEdge_Static(ornt[1], 0);
4700       orntNew[2] = 0;
4701       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 1;
4702       orntNew[3] = 0;
4703       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4704       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4705 #if 1
4706       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
4707       for (p = 0; p < 4; ++p) {
4708         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);
4709       }
4710 #endif
4711       /* F-G face */
4712       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 5;
4713       coneNew[0] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 4;
4714       orntNew[0] = -2;
4715       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[4] - fStart)*4 + GetQuadEdge_Static(ornt[4], 2);
4716       orntNew[1] = -2;
4717       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*4 + GetQuadEdge_Static(ornt[1], 1);
4718       orntNew[2] = 0;
4719       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 1;
4720       orntNew[3] = 0;
4721       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4722       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4723 #if 1
4724       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
4725       for (p = 0; p < 4; ++p) {
4726         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);
4727       }
4728 #endif
4729       /* G-H face */
4730       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 6;
4731       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*4 + GetQuadEdge_Static(ornt[3], 2);
4732       orntNew[0] = -2;
4733       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*4 + GetQuadEdge_Static(ornt[1], 2);
4734       orntNew[1] = 0;
4735       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 1;
4736       orntNew[2] = 0;
4737       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 3;
4738       orntNew[3] = -2;
4739       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4740       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4741 #if 1
4742       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
4743       for (p = 0; p < 4; ++p) {
4744         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);
4745       }
4746 #endif
4747       /* E-H face */
4748       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 7;
4749       coneNew[0] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 5;
4750       orntNew[0] = -2;
4751       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[5] - fStart)*4 + GetQuadEdge_Static(ornt[5], 1);
4752       orntNew[1] = -2;
4753       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*4 + GetQuadEdge_Static(ornt[1], 3);
4754       orntNew[2] = 0;
4755       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 1;
4756       orntNew[3] = 0;
4757       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4758       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4759 #if 1
4760       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
4761       for (p = 0; p < 4; ++p) {
4762         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);
4763       }
4764 #endif
4765       /* A-E face */
4766       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 8;
4767       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*4 + GetQuadEdge_Static(ornt[2], 3);
4768       orntNew[0] = 0;
4769       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 2;
4770       orntNew[1] = 0;
4771       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 5;
4772       orntNew[2] = -2;
4773       coneNew[3] = eStartNew + (eMax - eStart)*2 + (cone[5] - fStart)*4 + GetQuadEdge_Static(ornt[5], 0);
4774       orntNew[3] = -2;
4775       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4776       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4777 #if 1
4778       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
4779       for (p = 0; p < 4; ++p) {
4780         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);
4781       }
4782 #endif
4783       /* D-F face */
4784       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 9;
4785       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*4 + GetQuadEdge_Static(ornt[2], 1);
4786       orntNew[0] = -2;
4787       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[4] - fStart)*4 + GetQuadEdge_Static(ornt[4], 3);
4788       orntNew[1] = 0;
4789       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 4;
4790       orntNew[2] = 0;
4791       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 2;
4792       orntNew[3] = -2;
4793       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4794       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4795 #if 1
4796       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
4797       for (p = 0; p < 4; ++p) {
4798         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);
4799       }
4800 #endif
4801       /* C-G face */
4802       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 10;
4803       coneNew[0] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 4;
4804       orntNew[0] = -2;
4805       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[4] - fStart)*4 + GetQuadEdge_Static(ornt[4], 1);
4806       orntNew[1] = -2;
4807       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*4 + GetQuadEdge_Static(ornt[3], 3);
4808       orntNew[2] = 0;
4809       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 3;
4810       orntNew[3] = 0;
4811       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4812       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4813 #if 1
4814       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
4815       for (p = 0; p < 4; ++p) {
4816         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);
4817       }
4818 #endif
4819       /* B-H face */
4820       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 11;
4821       coneNew[0] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 5;
4822       orntNew[0] = 0;
4823       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 3;
4824       orntNew[1] = -2;
4825       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*4 + GetQuadEdge_Static(ornt[3], 1);
4826       orntNew[2] = -2;
4827       coneNew[3] = eStartNew + (eMax - eStart)*2 + (cone[5] - fStart)*4 + GetQuadEdge_Static(ornt[5], 2);
4828       orntNew[3] = 0;
4829       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4830       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4831 #if 1
4832       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
4833       for (p = 0; p < 4; ++p) {
4834         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);
4835       }
4836 #endif
4837       for (r = 0; r < 12; ++r) {
4838         newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + r;
4839         supportNew[0] = cStartNew + (c - cStart)*8 + newCells[r*2+0];
4840         supportNew[1] = cStartNew + (c - cStart)*8 + newCells[r*2+1];
4841         ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
4842 #if 1
4843         if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
4844         for (p = 0; p < 2; ++p) {
4845           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);
4846         }
4847 #endif
4848       }
4849     }
4850     /* Hybrid split faces have 4 edges and same cells */
4851     for (f = fMax; f < fEnd; ++f) {
4852       const PetscInt *cone, *ornt, *support;
4853       PetscInt        coneNew[4], orntNew[4];
4854       PetscInt        supportNew[2], size, s, c;
4855 
4856       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
4857       ierr = DMPlexGetConeOrientation(dm, f, &ornt);CHKERRQ(ierr);
4858       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
4859       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
4860       for (r = 0; r < 2; ++r) {
4861         const PetscInt newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (f - fMax)*2 + r;
4862 
4863         coneNew[0]   = eStartNew + (cone[0] - eStart)*2 + (ornt[0] < 0 ? 1-r : r);
4864         orntNew[0]   = ornt[0];
4865         coneNew[1]   = eStartNew + (cone[1] - eStart)*2 + (ornt[1] < 0 ? 1-r : r);
4866         orntNew[1]   = ornt[1];
4867         coneNew[2+r] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (cone[2+r] - eMax);
4868         orntNew[2+r] = 0;
4869         coneNew[3-r] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (eEnd      - eMax) + (f - fMax);
4870         orntNew[3-r] = 0;
4871         ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4872         ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4873 #if 1
4874         if ((newp < fMaxNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid face [%d, %d)", newp, fMaxNew, fEndNew);
4875         for (p = 0; p < 2; ++p) {
4876           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);
4877         }
4878         for (p = 2; p < 4; ++p) {
4879           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);
4880         }
4881 #endif
4882         for (s = 0; s < size; ++s) {
4883           const PetscInt *coneCell, *orntCell, *fornt;
4884 
4885           ierr = DMPlexGetCone(dm, support[s], &coneCell);CHKERRQ(ierr);
4886           ierr = DMPlexGetConeOrientation(dm, support[s], &orntCell);CHKERRQ(ierr);
4887           for (c = 2; c < 6; ++c) if (coneCell[c] == f) break;
4888           if (c >= 6) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Could not find face %d in cone of cell %d", f, support[s]);
4889           ierr = DMPlexGetConeOrientation(dm, coneCell[0], &fornt);CHKERRQ(ierr);
4890           supportNew[s] = cStartNew + (cMax - cStart)*8 + (support[s] - cMax)*4 + (GetQuadEdgeInverse_Static(orntCell[0], c-2) + (fornt[c-2] < 0 ? 1-r : r))%4;
4891         }
4892         ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
4893 #if 1
4894         if ((newp < fMaxNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid face [%d, %d)", newp, fMaxNew, fEndNew);
4895         for (p = 0; p < size; ++p) {
4896           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);
4897         }
4898 #endif
4899       }
4900     }
4901     /* Hybrid cell faces have 4 edges and 2 cells */
4902     for (c = cMax; c < cEnd; ++c) {
4903       PetscInt        newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd - fMax)*2 + (c - cMax)*4;
4904       const PetscInt *cone, *ornt;
4905       PetscInt        coneNew[4], orntNew[4];
4906       PetscInt        supportNew[2];
4907 
4908       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
4909       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
4910       for (r = 0; r < 4; ++r) {
4911         coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], r);
4912         orntNew[0] = 0;
4913         coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], r);
4914         orntNew[1] = 0;
4915         coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (eEnd - eMax) + (cone[2+GetQuadEdge_Static(ornt[0], r)] - fMax);
4916         orntNew[2] = 0;
4917         coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (eEnd - eMax) + (fEnd                                   - fMax) + (c - cMax);
4918         orntNew[3] = 0;
4919         ierr = DMPlexSetCone(rdm, newp+r, coneNew);CHKERRQ(ierr);
4920         ierr = DMPlexSetConeOrientation(rdm, newp+r, orntNew);CHKERRQ(ierr);
4921 #if 1
4922         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);
4923         for (p = 0; p < 2; ++p) {
4924           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);
4925         }
4926         for (p = 2; p < 4; ++p) {
4927           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);
4928         }
4929 #endif
4930         supportNew[0] = cStartNew + (cMax - cStart)*8 + (c - cMax)*4 + GetQuadSubface_Static(ornt[0], r);
4931         supportNew[1] = cStartNew + (cMax - cStart)*8 + (c - cMax)*4 + GetQuadSubface_Static(ornt[0], (r+1)%4);
4932         ierr          = DMPlexSetSupport(rdm, newp+r, supportNew);CHKERRQ(ierr);
4933 #if 1
4934         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);
4935         for (p = 0; p < 2; ++p) {
4936           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);
4937         }
4938 #endif
4939       }
4940     }
4941     /* Interior split edges have 2 vertices and the same faces as the parent */
4942     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
4943     for (e = eStart; e < eMax; ++e) {
4944       const PetscInt newv = vStartNew + (vEnd - vStart) + (e - eStart);
4945 
4946       for (r = 0; r < 2; ++r) {
4947         const PetscInt  newp = eStartNew + (e - eStart)*2 + r;
4948         const PetscInt *cone, *ornt, *support;
4949         PetscInt        coneNew[2], coneSize, c, supportSize, s;
4950 
4951         ierr             = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
4952         coneNew[0]       = vStartNew + (cone[0] - vStart);
4953         coneNew[1]       = vStartNew + (cone[1] - vStart);
4954         coneNew[(r+1)%2] = newv;
4955         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4956 #if 1
4957         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
4958         for (p = 0; p < 2; ++p) {
4959           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);
4960         }
4961 #endif
4962         ierr = DMPlexGetSupportSize(dm, e, &supportSize);CHKERRQ(ierr);
4963         ierr = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
4964         for (s = 0; s < supportSize; ++s) {
4965           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
4966           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
4967           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
4968           for (c = 0; c < coneSize; ++c) {
4969             if (cone[c] == e) break;
4970           }
4971           if (support[s] < fMax) {
4972             supportRef[s] = fStartNew + (support[s] - fStart)*4 + (c + (ornt[c] < 0 ? 1-r : r))%4;
4973           } else {
4974             supportRef[s] = fStartNew + (fMax       - fStart)*4 + (cMax - cStart)*12 + (support[s] - fMax)*2 + (ornt[c] < 0 ? 1-r : r);
4975           }
4976         }
4977         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
4978 #if 1
4979         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
4980         for (p = 0; p < supportSize; ++p) {
4981           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);
4982         }
4983 #endif
4984       }
4985     }
4986     /* Interior face edges have 2 vertices and 2+cells faces */
4987     for (f = fStart; f < fMax; ++f) {
4988       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};
4989       const PetscInt  newv = vStartNew + (vEnd - vStart) + (eMax - eStart) + (f - fStart);
4990       const PetscInt *cone, *coneCell, *orntCell, *support;
4991       PetscInt        coneNew[2], coneSize, c, supportSize, s;
4992 
4993       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
4994       for (r = 0; r < 4; ++r) {
4995         const PetscInt newp = eStartNew + (eMax - eStart)*2 + (f - fStart)*4 + r;
4996 
4997         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r] - eStart);
4998         coneNew[1] = newv;
4999         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5000 #if 1
5001         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
5002         for (p = 0; p < 2; ++p) {
5003           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);
5004         }
5005 #endif
5006         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
5007         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
5008         supportRef[0] = fStartNew + (f - fStart)*4 + r;
5009         supportRef[1] = fStartNew + (f - fStart)*4 + (r+1)%4;
5010         for (s = 0; s < supportSize; ++s) {
5011           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
5012           ierr = DMPlexGetCone(dm, support[s], &coneCell);CHKERRQ(ierr);
5013           ierr = DMPlexGetConeOrientation(dm, support[s], &orntCell);CHKERRQ(ierr);
5014           for (c = 0; c < coneSize; ++c) if (coneCell[c] == f) break;
5015           if (support[s] < cMax) {
5016             supportRef[2+s] = fStartNew + (fMax - fStart)*4 + (support[s] - cStart)*12 + newFaces[c*4 + GetQuadEdgeInverse_Static(orntCell[c], r)];
5017           } else {
5018             supportRef[2+s] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd - fMax)*2 + (support[s] - cMax)*4 + GetQuadEdgeInverse_Static(orntCell[c], r);
5019           }
5020         }
5021         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
5022 #if 1
5023         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
5024         for (p = 0; p < 2+supportSize; ++p) {
5025           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);
5026         }
5027 #endif
5028       }
5029     }
5030     /* Interior cell edges have 2 vertices and 4 faces */
5031     for (c = cStart; c < cMax; ++c) {
5032       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};
5033       const PetscInt  newv = vStartNew + (vEnd - vStart) + (eMax - eStart) + (fMax - fStart) + (c - cStart);
5034       const PetscInt *cone;
5035       PetscInt        coneNew[2], supportNew[4];
5036 
5037       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
5038       for (r = 0; r < 6; ++r) {
5039         const PetscInt newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (c - cStart)*6 + r;
5040 
5041         coneNew[0] = vStartNew + (vEnd - vStart) + (eMax - eStart) + (cone[r] - fStart);
5042         coneNew[1] = newv;
5043         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5044 #if 1
5045         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
5046         for (p = 0; p < 2; ++p) {
5047           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);
5048         }
5049 #endif
5050         for (f = 0; f < 4; ++f) supportNew[f] = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + newFaces[r*4+f];
5051         ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
5052 #if 1
5053         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
5054         for (p = 0; p < 4; ++p) {
5055           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);
5056         }
5057 #endif
5058       }
5059     }
5060     /* Hybrid edges have two vertices and the same faces */
5061     for (e = eMax; e < eEnd; ++e) {
5062       const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (e - eMax);
5063       const PetscInt *cone, *support, *fcone;
5064       PetscInt        coneNew[2], size, fsize, s;
5065 
5066       ierr = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
5067       ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
5068       ierr = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
5069       coneNew[0] = vStartNew + (cone[0] - vStart);
5070       coneNew[1] = vStartNew + (cone[1] - vStart);
5071       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5072 #if 1
5073       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid edge [%d, %d)", newp, eMaxNew, eEndNew);
5074       for (p = 0; p < 2; ++p) {
5075         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);
5076       }
5077 #endif
5078       for (s = 0; s < size; ++s) {
5079         ierr = DMPlexGetConeSize(dm, support[s], &fsize);CHKERRQ(ierr);
5080         ierr = DMPlexGetCone(dm, support[s], &fcone);CHKERRQ(ierr);
5081         for (c = 0; c < fsize; ++c) if (fcone[c] == e) break;
5082         if ((c < 2) || (c > 3)) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Edge %d not found in cone of face %d", e, support[s]);
5083         supportRef[s] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (support[s] - fMax)*2 + c-2;
5084       }
5085       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
5086 #if 1
5087       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid edge [%d, %d)", newp, eMaxNew, eEndNew);
5088       for (p = 0; p < size; ++p) {
5089         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);
5090       }
5091 #endif
5092     }
5093     /* Hybrid face edges have 2 vertices and 2+cells faces */
5094     for (f = fMax; f < fEnd; ++f) {
5095       const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (eEnd - eMax) + (f - fMax);
5096       const PetscInt *cone, *support, *ccone, *cornt;
5097       PetscInt        coneNew[2], size, csize, s;
5098 
5099       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
5100       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
5101       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
5102       coneNew[0] = vStartNew + (vEnd - vStart) + (cone[0] - eStart);
5103       coneNew[1] = vStartNew + (vEnd - vStart) + (cone[1] - eStart);
5104       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5105 #if 1
5106       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid edge [%d, %d)", newp, eMaxNew, eEndNew);
5107       for (p = 0; p < 2; ++p) {
5108         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);
5109       }
5110 #endif
5111       supportRef[0] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (f - fMax)*2 + 0;
5112       supportRef[1] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (f - fMax)*2 + 1;
5113       for (s = 0; s < size; ++s) {
5114         ierr = DMPlexGetConeSize(dm, support[s], &csize);CHKERRQ(ierr);
5115         ierr = DMPlexGetCone(dm, support[s], &ccone);CHKERRQ(ierr);
5116         ierr = DMPlexGetConeOrientation(dm, support[s], &cornt);CHKERRQ(ierr);
5117         for (c = 0; c < csize; ++c) if (ccone[c] == f) break;
5118         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]);
5119         supportRef[2+s] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd - fMax)*2 + (support[s] - cMax)*4 + GetQuadSubfaceInverse_Static(cornt[0], c-2);
5120       }
5121       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
5122 #if 1
5123       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid edge [%d, %d)", newp, eMaxNew, eEndNew);
5124       for (p = 0; p < 2+size; ++p) {
5125         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);
5126       }
5127 #endif
5128     }
5129     /* Hybrid cell edges have 2 vertices and 4 faces */
5130     for (c = cMax; c < cEnd; ++c) {
5131       const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (eEnd - eMax) + (fEnd - fMax) + (c - cMax);
5132       const PetscInt *cone, *support;
5133       PetscInt        coneNew[2], size;
5134 
5135       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
5136       ierr = DMPlexGetSupportSize(dm, c, &size);CHKERRQ(ierr);
5137       ierr = DMPlexGetSupport(dm, c, &support);CHKERRQ(ierr);
5138       coneNew[0] = vStartNew + (vEnd - vStart) + (eMax - eStart) + (cone[0] - fStart);
5139       coneNew[1] = vStartNew + (vEnd - vStart) + (eMax - eStart) + (cone[1] - fStart);
5140       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5141 #if 1
5142       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid edge [%d, %d)", newp, eMaxNew, eEndNew);
5143       for (p = 0; p < 2; ++p) {
5144         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);
5145       }
5146 #endif
5147       supportRef[0] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd - fMax)*2 + (c - cMax)*4 + 0;
5148       supportRef[1] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd - fMax)*2 + (c - cMax)*4 + 1;
5149       supportRef[2] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd - fMax)*2 + (c - cMax)*4 + 2;
5150       supportRef[3] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd - fMax)*2 + (c - cMax)*4 + 3;
5151       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
5152 #if 1
5153       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid edge [%d, %d)", newp, eMaxNew, eEndNew);
5154       for (p = 0; p < 4; ++p) {
5155         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);
5156       }
5157 #endif
5158     }
5159     /* Interior vertices have identical supports */
5160     for (v = vStart; v < vEnd; ++v) {
5161       const PetscInt  newp = vStartNew + (v - vStart);
5162       const PetscInt *support, *cone;
5163       PetscInt        size, s;
5164 
5165       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
5166       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
5167       for (s = 0; s < size; ++s) {
5168         PetscInt r = 0;
5169 
5170         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
5171         if (cone[1] == v) r = 1;
5172         if (support[s] < eMax) supportRef[s] = eStartNew + (support[s] - eStart)*2 + r;
5173         else                   supportRef[s] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (support[s] - eMax);
5174       }
5175       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
5176 #if 1
5177       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
5178       for (p = 0; p < size; ++p) {
5179         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);
5180       }
5181 #endif
5182     }
5183     /* Interior edge vertices have 2 + faces supports */
5184     for (e = eStart; e < eMax; ++e) {
5185       const PetscInt  newp = vStartNew + (vEnd - vStart) + (e - eStart);
5186       const PetscInt *cone, *support;
5187       PetscInt        size, s;
5188 
5189       ierr          = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
5190       ierr          = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
5191       supportRef[0] = eStartNew + (e - eStart)*2 + 0;
5192       supportRef[1] = eStartNew + (e - eStart)*2 + 1;
5193       for (s = 0; s < size; ++s) {
5194         PetscInt r;
5195 
5196         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
5197         for (r = 0; r < 4; ++r) if (cone[r] == e) break;
5198         if (support[s] < fMax) {
5199           supportRef[2+s] = eStartNew + (eMax - eStart)*2 + (support[s] - fStart)*4 + r;
5200         } else {
5201           supportRef[2+s] = eStartNew + (eMax - eStart)*2 + (fMax       - fStart)*4 + (cMax - cStart)*6 + (eEnd - eMax) + (support[s] - fMax);
5202         }
5203       }
5204       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
5205 #if 1
5206       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
5207       for (p = 0; p < 2+size; ++p) {
5208         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);
5209       }
5210 #endif
5211     }
5212     /* Interior face vertices have 4 + cells supports */
5213     for (f = fStart; f < fMax; ++f) {
5214       const PetscInt  newp = vStartNew + (vEnd - vStart) + (eMax - eStart) + (f - fStart);
5215       const PetscInt *cone, *support;
5216       PetscInt        size, s;
5217 
5218       ierr          = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
5219       ierr          = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
5220       for (r = 0; r < 4; ++r) supportRef[r] = eStartNew + (eMax - eStart)*2 +  (f - fStart)*4 + r;
5221       for (s = 0; s < size; ++s) {
5222         PetscInt r;
5223 
5224         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
5225         for (r = 0; r < 6; ++r) if (cone[r] == f) break;
5226         if (support[s] < cMax) {
5227           supportRef[4+s] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (support[s] - cStart)*6 + r;
5228         } else {
5229           supportRef[4+s] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax       - cStart)*6 + (eEnd - eMax) + (fEnd - fMax) + (support[s] - cMax);
5230         }
5231       }
5232       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
5233 #if 1
5234       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
5235       for (p = 0; p < 4+size; ++p) {
5236         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);
5237       }
5238 #endif
5239     }
5240     /* Cell vertices have 6 supports */
5241     for (c = cStart; c < cMax; ++c) {
5242       const PetscInt newp = vStartNew + (vEnd - vStart) + (eMax - eStart) + (fMax - fStart) + (c - cStart);
5243       PetscInt       supportNew[6];
5244 
5245       for (r = 0; r < 6; ++r) {
5246         supportNew[r] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (c - cStart)*6 + r;
5247       }
5248       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
5249     }
5250     ierr = PetscFree(supportRef);CHKERRQ(ierr);
5251     break;
5252   default:
5253     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
5254   }
5255   PetscFunctionReturn(0);
5256 }
5257 
5258 #undef __FUNCT__
5259 #define __FUNCT__ "CellRefinerSetCoordinates"
5260 static PetscErrorCode CellRefinerSetCoordinates(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
5261 {
5262   PetscSection   coordSection, coordSectionNew;
5263   Vec            coordinates, coordinatesNew;
5264   PetscScalar   *coords, *coordsNew;
5265   const PetscInt numVertices = depthSize ? depthSize[0] : 0;
5266   PetscInt       dim, depth, coordSizeNew, cStart, cEnd, cMax, c, vStart, vStartNew, vEnd, v, eStart, eEnd, eMax, e, fStart, fEnd, fMax, f;
5267   PetscErrorCode ierr;
5268 
5269   PetscFunctionBegin;
5270   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
5271   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
5272   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
5273   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
5274   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
5275   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
5276   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, NULL);CHKERRQ(ierr);
5277   if (refiner) {ierr = GetDepthStart_Private(depth, depthSize, NULL, NULL, NULL, &vStartNew);CHKERRQ(ierr);}
5278   ierr = GetDepthStart_Private(depth, depthSize, NULL, NULL, NULL, &vStartNew);CHKERRQ(ierr);
5279   ierr = DMGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
5280   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)dm), &coordSectionNew);CHKERRQ(ierr);
5281   ierr = PetscSectionSetNumFields(coordSectionNew, 1);CHKERRQ(ierr);
5282   ierr = PetscSectionSetFieldComponents(coordSectionNew, 0, dim);CHKERRQ(ierr);
5283   ierr = PetscSectionSetChart(coordSectionNew, vStartNew, vStartNew+numVertices);CHKERRQ(ierr);
5284   if (cMax < 0) cMax = cEnd;
5285   if (fMax < 0) fMax = fEnd;
5286   if (eMax < 0) eMax = eEnd;
5287   /* All vertices have the dim coordinates */
5288   for (v = vStartNew; v < vStartNew+numVertices; ++v) {
5289     ierr = PetscSectionSetDof(coordSectionNew, v, dim);CHKERRQ(ierr);
5290     ierr = PetscSectionSetFieldDof(coordSectionNew, v, 0, dim);CHKERRQ(ierr);
5291   }
5292   ierr = PetscSectionSetUp(coordSectionNew);CHKERRQ(ierr);
5293   ierr = DMSetCoordinateSection(rdm, coordSectionNew);CHKERRQ(ierr);
5294   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
5295   ierr = PetscSectionGetStorageSize(coordSectionNew, &coordSizeNew);CHKERRQ(ierr);
5296   ierr = VecCreate(PetscObjectComm((PetscObject)dm), &coordinatesNew);CHKERRQ(ierr);
5297   ierr = PetscObjectSetName((PetscObject) coordinatesNew, "coordinates");CHKERRQ(ierr);
5298   ierr = VecSetSizes(coordinatesNew, coordSizeNew, PETSC_DETERMINE);CHKERRQ(ierr);
5299   ierr = VecSetFromOptions(coordinatesNew);CHKERRQ(ierr);
5300   ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
5301   ierr = VecGetArray(coordinatesNew, &coordsNew);CHKERRQ(ierr);
5302   switch (refiner) {
5303   case 0: break;
5304   case 6: /* Hex 3D */
5305   case 8: /* Hybrid Hex 3D */
5306     /* Face vertices have the average of corner coordinates */
5307     for (f = fStart; f < fMax; ++f) {
5308       const PetscInt newv = vStartNew + (vEnd - vStart) + (eMax - eStart) + (f - fStart);
5309       PetscInt      *cone = NULL;
5310       PetscInt       closureSize, coneSize = 0, off[8], offnew, p, d;
5311 
5312       ierr = DMPlexGetTransitiveClosure(dm, f, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
5313       for (p = 0; p < closureSize*2; p += 2) {
5314         const PetscInt point = cone[p];
5315         if ((point >= vStart) && (point < vEnd)) cone[coneSize++] = point;
5316       }
5317       for (v = 0; v < coneSize; ++v) {
5318         ierr = PetscSectionGetOffset(coordSection, cone[v], &off[v]);CHKERRQ(ierr);
5319       }
5320       ierr = PetscSectionGetOffset(coordSectionNew, newv, &offnew);CHKERRQ(ierr);
5321       for (d = 0; d < dim; ++d) {
5322         coordsNew[offnew+d] = 0.0;
5323         for (v = 0; v < coneSize; ++v) coordsNew[offnew+d] += coords[off[v]+d];
5324         coordsNew[offnew+d] /= coneSize;
5325       }
5326       ierr = DMPlexRestoreTransitiveClosure(dm, f, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
5327     }
5328   case 2: /* Hex 2D */
5329   case 4: /* Hybrid Hex 2D */
5330     /* Cell vertices have the average of corner coordinates */
5331     for (c = cStart; c < cMax; ++c) {
5332       const PetscInt newv = vStartNew + (vEnd - vStart) + (eMax - eStart) + (c - cStart) + (dim > 2 ? (fMax - fStart) : 0);
5333       PetscInt      *cone = NULL;
5334       PetscInt       closureSize, coneSize = 0, off[8], offnew, p, d;
5335 
5336       ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
5337       for (p = 0; p < closureSize*2; p += 2) {
5338         const PetscInt point = cone[p];
5339         if ((point >= vStart) && (point < vEnd)) cone[coneSize++] = point;
5340       }
5341       for (v = 0; v < coneSize; ++v) {
5342         ierr = PetscSectionGetOffset(coordSection, cone[v], &off[v]);CHKERRQ(ierr);
5343       }
5344       ierr = PetscSectionGetOffset(coordSectionNew, newv, &offnew);CHKERRQ(ierr);
5345       for (d = 0; d < dim; ++d) {
5346         coordsNew[offnew+d] = 0.0;
5347         for (v = 0; v < coneSize; ++v) coordsNew[offnew+d] += coords[off[v]+d];
5348         coordsNew[offnew+d] /= coneSize;
5349       }
5350       ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
5351     }
5352   case 1: /* Simplicial 2D */
5353   case 3: /* Hybrid Simplicial 2D */
5354   case 5: /* Simplicial 3D */
5355   case 7: /* Hybrid Simplicial 3D */
5356     /* Edge vertices have the average of endpoint coordinates */
5357     for (e = eStart; e < eMax; ++e) {
5358       const PetscInt  newv = vStartNew + (vEnd - vStart) + (e - eStart);
5359       const PetscInt *cone;
5360       PetscInt        coneSize, offA, offB, offnew, d;
5361 
5362       ierr = DMPlexGetConeSize(dm, e, &coneSize);CHKERRQ(ierr);
5363       if (coneSize != 2) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Edge %d cone should have two vertices, not %d", e, coneSize);
5364       ierr = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
5365       ierr = PetscSectionGetOffset(coordSection, cone[0], &offA);CHKERRQ(ierr);
5366       ierr = PetscSectionGetOffset(coordSection, cone[1], &offB);CHKERRQ(ierr);
5367       ierr = PetscSectionGetOffset(coordSectionNew, newv, &offnew);CHKERRQ(ierr);
5368       for (d = 0; d < dim; ++d) {
5369         coordsNew[offnew+d] = 0.5*(coords[offA+d] + coords[offB+d]);
5370       }
5371     }
5372     /* Old vertices have the same coordinates */
5373     for (v = vStart; v < vEnd; ++v) {
5374       const PetscInt newv = vStartNew + (v - vStart);
5375       PetscInt       off, offnew, d;
5376 
5377       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
5378       ierr = PetscSectionGetOffset(coordSectionNew, newv, &offnew);CHKERRQ(ierr);
5379       for (d = 0; d < dim; ++d) {
5380         coordsNew[offnew+d] = coords[off+d];
5381       }
5382     }
5383     break;
5384   default:
5385     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
5386   }
5387   ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
5388   ierr = VecRestoreArray(coordinatesNew, &coordsNew);CHKERRQ(ierr);
5389   ierr = DMSetCoordinatesLocal(rdm, coordinatesNew);CHKERRQ(ierr);
5390   ierr = VecDestroy(&coordinatesNew);CHKERRQ(ierr);
5391   ierr = PetscSectionDestroy(&coordSectionNew);CHKERRQ(ierr);
5392   PetscFunctionReturn(0);
5393 }
5394 
5395 #undef __FUNCT__
5396 #define __FUNCT__ "DMPlexCreateProcessSF"
5397 static PetscErrorCode DMPlexCreateProcessSF(DM dm, PetscSF sfPoint, IS *processRanks, PetscSF *sfProcess)
5398 {
5399   PetscInt           numRoots, numLeaves, l;
5400   const PetscInt    *localPoints;
5401   const PetscSFNode *remotePoints;
5402   PetscInt          *localPointsNew;
5403   PetscSFNode       *remotePointsNew;
5404   PetscInt          *ranks, *ranksNew;
5405   PetscErrorCode     ierr;
5406 
5407   PetscFunctionBegin;
5408   ierr = PetscSFGetGraph(sfPoint, &numRoots, &numLeaves, &localPoints, &remotePoints);CHKERRQ(ierr);
5409   ierr = PetscMalloc1(numLeaves, &ranks);CHKERRQ(ierr);
5410   for (l = 0; l < numLeaves; ++l) {
5411     ranks[l] = remotePoints[l].rank;
5412   }
5413   ierr = PetscSortRemoveDupsInt(&numLeaves, ranks);CHKERRQ(ierr);
5414   ierr = PetscMalloc1(numLeaves,    &ranksNew);CHKERRQ(ierr);
5415   ierr = PetscMalloc1(numLeaves,    &localPointsNew);CHKERRQ(ierr);
5416   ierr = PetscMalloc1(numLeaves, &remotePointsNew);CHKERRQ(ierr);
5417   for (l = 0; l < numLeaves; ++l) {
5418     ranksNew[l]              = ranks[l];
5419     localPointsNew[l]        = l;
5420     remotePointsNew[l].index = 0;
5421     remotePointsNew[l].rank  = ranksNew[l];
5422   }
5423   ierr = PetscFree(ranks);CHKERRQ(ierr);
5424   ierr = ISCreateGeneral(PetscObjectComm((PetscObject)dm), numLeaves, ranksNew, PETSC_OWN_POINTER, processRanks);CHKERRQ(ierr);
5425   ierr = PetscSFCreate(PetscObjectComm((PetscObject)dm), sfProcess);CHKERRQ(ierr);
5426   ierr = PetscSFSetFromOptions(*sfProcess);CHKERRQ(ierr);
5427   ierr = PetscSFSetGraph(*sfProcess, 1, numLeaves, localPointsNew, PETSC_OWN_POINTER, remotePointsNew, PETSC_OWN_POINTER);CHKERRQ(ierr);
5428   PetscFunctionReturn(0);
5429 }
5430 
5431 #undef __FUNCT__
5432 #define __FUNCT__ "CellRefinerCreateSF"
5433 static PetscErrorCode CellRefinerCreateSF(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
5434 {
5435   PetscSF            sf, sfNew, sfProcess;
5436   IS                 processRanks;
5437   MPI_Datatype       depthType;
5438   PetscInt           numRoots, numLeaves, numLeavesNew = 0, l, m;
5439   const PetscInt    *localPoints, *neighbors;
5440   const PetscSFNode *remotePoints;
5441   PetscInt          *localPointsNew;
5442   PetscSFNode       *remotePointsNew;
5443   PetscInt          *depthSizeOld, *rdepthSize, *rdepthSizeOld, *rdepthMaxOld, *rvStart, *rvStartNew, *reStart, *reStartNew, *rfStart, *rfStartNew, *rcStart, *rcStartNew;
5444   PetscInt           depth, numNeighbors, pStartNew, pEndNew, cStart, cEnd, cMax, vStart, vEnd, vMax, fStart, fEnd, fMax, eStart, eEnd, eMax, r, n;
5445   PetscInt           cStartNew = 0, vStartNew = 0, fStartNew = 0, eStartNew = 0;
5446   PetscErrorCode     ierr;
5447 
5448   PetscFunctionBegin;
5449   ierr = DMPlexGetChart(rdm, &pStartNew, &pEndNew);CHKERRQ(ierr);
5450   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
5451   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
5452   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
5453   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
5454   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
5455   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
5456   if (refiner) {ierr = GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);CHKERRQ(ierr);}
5457   ierr = DMGetPointSF(dm, &sf);CHKERRQ(ierr);
5458   ierr = DMGetPointSF(rdm, &sfNew);CHKERRQ(ierr);
5459   /* Caculate size of new SF */
5460   ierr = PetscSFGetGraph(sf, &numRoots, &numLeaves, &localPoints, &remotePoints);CHKERRQ(ierr);
5461   if (numRoots < 0) PetscFunctionReturn(0);
5462   for (l = 0; l < numLeaves; ++l) {
5463     const PetscInt p = localPoints[l];
5464 
5465     switch (refiner) {
5466     case 1:
5467       /* Simplicial 2D */
5468       if ((p >= vStart) && (p < vEnd)) {
5469         /* Old vertices stay the same */
5470         ++numLeavesNew;
5471       } else if ((p >= fStart) && (p < fEnd)) {
5472         /* Old faces add new faces and vertex */
5473         numLeavesNew += 2 + 1;
5474       } else if ((p >= cStart) && (p < cEnd)) {
5475         /* Old cells add new cells and interior faces */
5476         numLeavesNew += 4 + 3;
5477       }
5478       break;
5479     case 3:
5480       /* Hybrid Simplicial 2D */
5481       if ((p >= vStart) && (p < vEnd)) {
5482         /* Interior vertices stay the same */
5483         ++numLeavesNew;
5484       } else if ((p >= fStart) && (p < fMax)) {
5485         /* Interior faces add new faces and vertex */
5486         numLeavesNew += 2 + 1;
5487       } else if ((p >= fMax) && (p < fEnd)) {
5488         /* Hybrid faces stay the same */
5489         ++numLeavesNew;
5490       } else if ((p >= cStart) && (p < cMax)) {
5491         /* Interior cells add new cells and interior faces */
5492         numLeavesNew += 4 + 3;
5493       } else if ((p >= cMax) && (p < cEnd)) {
5494         /* Hybrid cells add new cells and hybrid face */
5495         numLeavesNew += 2 + 1;
5496       }
5497       break;
5498     case 2:
5499       /* Hex 2D */
5500       if ((p >= vStart) && (p < vEnd)) {
5501         /* Old vertices stay the same */
5502         ++numLeavesNew;
5503       } else if ((p >= fStart) && (p < fEnd)) {
5504         /* Old faces add new faces and vertex */
5505         numLeavesNew += 2 + 1;
5506       } else if ((p >= cStart) && (p < cEnd)) {
5507         /* Old cells add new cells, interior faces, and vertex */
5508         numLeavesNew += 4 + 4 + 1;
5509       }
5510       break;
5511     case 4:
5512       /* Hybrid Hex 2D */
5513       if ((p >= vStart) && (p < vEnd)) {
5514         /* Interior vertices stay the same */
5515         ++numLeavesNew;
5516       } else if ((p >= fStart) && (p < fMax)) {
5517         /* Interior faces add new faces and vertex */
5518         numLeavesNew += 2 + 1;
5519       } else if ((p >= fMax) && (p < fEnd)) {
5520         /* Hybrid faces stay the same */
5521         ++numLeavesNew;
5522       } else if ((p >= cStart) && (p < cMax)) {
5523         /* Interior cells add new cells, interior faces, and vertex */
5524         numLeavesNew += 4 + 4 + 1;
5525       } else if ((p >= cMax) && (p < cEnd)) {
5526         /* Hybrid cells add new cells and hybrid face */
5527         numLeavesNew += 2 + 1;
5528       }
5529       break;
5530     case 5:
5531       /* Simplicial 3D */
5532       if ((p >= vStart) && (p < vEnd)) {
5533         /* Old vertices stay the same */
5534         ++numLeavesNew;
5535       } else if ((p >= eStart) && (p < eEnd)) {
5536         /* Old edges add new edges and vertex */
5537         numLeavesNew += 2 + 1;
5538       } else if ((p >= fStart) && (p < fEnd)) {
5539         /* Old faces add new faces and face edges */
5540         numLeavesNew += 4 + 3;
5541       } else if ((p >= cStart) && (p < cEnd)) {
5542         /* Old cells add new cells and interior faces and edges */
5543         numLeavesNew += 8 + 8 + 1;
5544       }
5545       break;
5546     case 7:
5547       /* Hybrid Simplicial 3D */
5548       if ((p >= vStart) && (p < vEnd)) {
5549         /* Interior vertices stay the same */
5550         ++numLeavesNew;
5551       } else if ((p >= eStart) && (p < eMax)) {
5552         /* Interior edges add new edges and vertex */
5553         numLeavesNew += 2 + 1;
5554       } else if ((p >= eMax) && (p < eEnd)) {
5555         /* Hybrid edges stay the same */
5556         ++numLeavesNew;
5557       } else if ((p >= fStart) && (p < fMax)) {
5558         /* Interior faces add new faces and edges */
5559         numLeavesNew += 4 + 3;
5560       } else if ((p >= fMax) && (p < fEnd)) {
5561         /* Hybrid faces add new faces and edges */
5562         numLeavesNew += 2 + 1;
5563       } else if ((p >= cStart) && (p < cMax)) {
5564         /* Interior cells add new cells, faces, and edges */
5565         numLeavesNew += 8 + 8 + 1;
5566       } else if ((p >= cMax) && (p < cEnd)) {
5567         /* Hybrid cells add new cells and faces */
5568         numLeavesNew += 4 + 3;
5569       }
5570       break;
5571     case 6:
5572       /* Hex 3D */
5573       if ((p >= vStart) && (p < vEnd)) {
5574         /* Old vertices stay the same */
5575         ++numLeavesNew;
5576       } else if ((p >= eStart) && (p < eEnd)) {
5577         /* Old edges add new edges, and vertex */
5578         numLeavesNew += 2 + 1;
5579       } else if ((p >= fStart) && (p < fEnd)) {
5580         /* Old faces add new faces, edges, and vertex */
5581         numLeavesNew += 4 + 4 + 1;
5582       } else if ((p >= cStart) && (p < cEnd)) {
5583         /* Old cells add new cells, faces, edges, and vertex */
5584         numLeavesNew += 8 + 12 + 6 + 1;
5585       }
5586       break;
5587     case 8:
5588       /* Hybrid Hex 3D */
5589       if ((p >= vStart) && (p < vEnd)) {
5590         /* Old vertices stay the same */
5591         ++numLeavesNew;
5592       } else if ((p >= eStart) && (p < eMax)) {
5593         /* Interior edges add new edges, and vertex */
5594         numLeavesNew += 2 + 1;
5595       } else if ((p >= eMax) && (p < eEnd)) {
5596         /* Hybrid edges stay the same */
5597         ++numLeavesNew;
5598       } else if ((p >= fStart) && (p < fMax)) {
5599         /* Interior faces add new faces, edges, and vertex */
5600         numLeavesNew += 4 + 4 + 1;
5601       } else if ((p >= fMax) && (p < fEnd)) {
5602         /* Hybrid faces add new faces and edges */
5603         numLeavesNew += 2 + 1;
5604       } else if ((p >= cStart) && (p < cMax)) {
5605         /* Interior cells add new cells, faces, edges, and vertex */
5606         numLeavesNew += 8 + 12 + 6 + 1;
5607       } else if ((p >= cStart) && (p < cEnd)) {
5608         /* Hybrid cells add new cells, faces, and edges */
5609         numLeavesNew += 4 + 4 + 1;
5610       }
5611       break;
5612     default:
5613       SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
5614     }
5615   }
5616   /* Communicate depthSizes for each remote rank */
5617   ierr = DMPlexCreateProcessSF(dm, sf, &processRanks, &sfProcess);CHKERRQ(ierr);
5618   ierr = ISGetLocalSize(processRanks, &numNeighbors);CHKERRQ(ierr);
5619   ierr = PetscMalloc5((depth+1)*numNeighbors,&rdepthSize,numNeighbors,&rvStartNew,numNeighbors,&reStartNew,numNeighbors,&rfStartNew,numNeighbors,&rcStartNew);CHKERRQ(ierr);
5620   ierr = PetscMalloc7(depth+1,&depthSizeOld,(depth+1)*numNeighbors,&rdepthSizeOld,(depth+1)*numNeighbors,&rdepthMaxOld,numNeighbors,&rvStart,numNeighbors,&reStart,numNeighbors,&rfStart,numNeighbors,&rcStart);CHKERRQ(ierr);
5621   ierr = MPI_Type_contiguous(depth+1, MPIU_INT, &depthType);CHKERRQ(ierr);
5622   ierr = MPI_Type_commit(&depthType);CHKERRQ(ierr);
5623   ierr = PetscSFBcastBegin(sfProcess, depthType, depthSize, rdepthSize);CHKERRQ(ierr);
5624   ierr = PetscSFBcastEnd(sfProcess, depthType, depthSize, rdepthSize);CHKERRQ(ierr);
5625   for (n = 0; n < numNeighbors; ++n) {
5626     ierr = GetDepthStart_Private(depth, &rdepthSize[n*(depth+1)], &rcStartNew[n], &rfStartNew[n], &reStartNew[n], &rvStartNew[n]);CHKERRQ(ierr);
5627   }
5628   depthSizeOld[depth]   = cMax;
5629   depthSizeOld[0]       = vMax;
5630   depthSizeOld[depth-1] = fMax;
5631   depthSizeOld[1]       = eMax;
5632 
5633   ierr = PetscSFBcastBegin(sfProcess, depthType, depthSizeOld, rdepthMaxOld);CHKERRQ(ierr);
5634   ierr = PetscSFBcastEnd(sfProcess, depthType, depthSizeOld, rdepthMaxOld);CHKERRQ(ierr);
5635 
5636   depthSizeOld[depth]   = cEnd - cStart;
5637   depthSizeOld[0]       = vEnd - vStart;
5638   depthSizeOld[depth-1] = fEnd - fStart;
5639   depthSizeOld[1]       = eEnd - eStart;
5640 
5641   ierr = PetscSFBcastBegin(sfProcess, depthType, depthSizeOld, rdepthSizeOld);CHKERRQ(ierr);
5642   ierr = PetscSFBcastEnd(sfProcess, depthType, depthSizeOld, rdepthSizeOld);CHKERRQ(ierr);
5643   for (n = 0; n < numNeighbors; ++n) {
5644     ierr = GetDepthStart_Private(depth, &rdepthSizeOld[n*(depth+1)], &rcStart[n], &rfStart[n], &reStart[n], &rvStart[n]);CHKERRQ(ierr);
5645   }
5646   ierr = MPI_Type_free(&depthType);CHKERRQ(ierr);
5647   ierr = PetscSFDestroy(&sfProcess);CHKERRQ(ierr);
5648   /* Calculate new point SF */
5649   ierr = PetscMalloc1(numLeavesNew,    &localPointsNew);CHKERRQ(ierr);
5650   ierr = PetscMalloc1(numLeavesNew, &remotePointsNew);CHKERRQ(ierr);
5651   ierr = ISGetIndices(processRanks, &neighbors);CHKERRQ(ierr);
5652   for (l = 0, m = 0; l < numLeaves; ++l) {
5653     PetscInt    p     = localPoints[l];
5654     PetscInt    rp    = remotePoints[l].index, n;
5655     PetscMPIInt rrank = remotePoints[l].rank;
5656 
5657     ierr = PetscFindInt(rrank, numNeighbors, neighbors, &n);CHKERRQ(ierr);
5658     if (n < 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Could not locate remote rank %d", rrank);
5659     switch (refiner) {
5660     case 1:
5661       /* Simplicial 2D */
5662       if ((p >= vStart) && (p < vEnd)) {
5663         /* Old vertices stay the same */
5664         localPointsNew[m]        = vStartNew     + (p  - vStart);
5665         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
5666         remotePointsNew[m].rank  = rrank;
5667         ++m;
5668       } else if ((p >= fStart) && (p < fEnd)) {
5669         /* Old faces add new faces and vertex */
5670         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - fStart);
5671         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - rfStart[n]);
5672         remotePointsNew[m].rank  = rrank;
5673         ++m;
5674         for (r = 0; r < 2; ++r, ++m) {
5675           localPointsNew[m]        = fStartNew     + (p  - fStart)*2     + r;
5676           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*2 + r;
5677           remotePointsNew[m].rank  = rrank;
5678         }
5679       } else if ((p >= cStart) && (p < cEnd)) {
5680         /* Old cells add new cells and interior faces */
5681         for (r = 0; r < 4; ++r, ++m) {
5682           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
5683           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
5684           remotePointsNew[m].rank  = rrank;
5685         }
5686         for (r = 0; r < 3; ++r, ++m) {
5687           localPointsNew[m]        = fStartNew     + (fEnd - fStart)*2                    + (p  - cStart)*3     + r;
5688           remotePointsNew[m].index = rfStartNew[n] + rdepthSizeOld[n*(depth+1)+depth-1]*2 + (rp - rcStart[n])*3 + r;
5689           remotePointsNew[m].rank  = rrank;
5690         }
5691       }
5692       break;
5693     case 2:
5694       /* Hex 2D */
5695       if ((p >= vStart) && (p < vEnd)) {
5696         /* Old vertices stay the same */
5697         localPointsNew[m]        = vStartNew     + (p  - vStart);
5698         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
5699         remotePointsNew[m].rank  = rrank;
5700         ++m;
5701       } else if ((p >= fStart) && (p < fEnd)) {
5702         /* Old faces add new faces and vertex */
5703         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - fStart);
5704         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - rfStart[n]);
5705         remotePointsNew[m].rank  = rrank;
5706         ++m;
5707         for (r = 0; r < 2; ++r, ++m) {
5708           localPointsNew[m]        = fStartNew     + (p  - fStart)*2     + r;
5709           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*2 + r;
5710           remotePointsNew[m].rank  = rrank;
5711         }
5712       } else if ((p >= cStart) && (p < cEnd)) {
5713         /* Old cells add new cells, interior faces, and vertex */
5714         for (r = 0; r < 4; ++r, ++m) {
5715           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
5716           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
5717           remotePointsNew[m].rank  = rrank;
5718         }
5719         for (r = 0; r < 4; ++r, ++m) {
5720           localPointsNew[m]        = fStartNew     + (fEnd - fStart)*2                    + (p  - cStart)*4     + r;
5721           remotePointsNew[m].index = rfStartNew[n] + rdepthSizeOld[n*(depth+1)+depth-1]*2 + (rp - rcStart[n])*4 + r;
5722           remotePointsNew[m].rank  = rrank;
5723         }
5724         for (r = 0; r < 1; ++r, ++m) {
5725           localPointsNew[m]        = vStartNew     + (vEnd - vStart)               + (fEnd - fStart)                    + (p  - cStart)     + r;
5726           remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0]  + rdepthSizeOld[n*(depth+1)+depth-1] + (rp - rcStart[n]) + r;
5727           remotePointsNew[m].rank  = rrank;
5728         }
5729       }
5730       break;
5731     case 3:
5732       /* Hybrid simplicial 2D */
5733       if ((p >= vStart) && (p < vEnd)) {
5734         /* Old vertices stay the same */
5735         localPointsNew[m]        = vStartNew     + (p  - vStart);
5736         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
5737         remotePointsNew[m].rank  = rrank;
5738         ++m;
5739       } else if ((p >= fStart) && (p < fMax)) {
5740         /* Old interior faces add new faces and vertex */
5741         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - fStart);
5742         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - rfStart[n]);
5743         remotePointsNew[m].rank  = rrank;
5744         ++m;
5745         for (r = 0; r < 2; ++r, ++m) {
5746           localPointsNew[m]        = fStartNew     + (p  - fStart)*2     + r;
5747           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*2 + r;
5748           remotePointsNew[m].rank  = rrank;
5749         }
5750       } else if ((p >= fMax) && (p < fEnd)) {
5751         /* Old hybrid faces stay the same */
5752         localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (p  - fMax);
5753         remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*2 + (rp - rdepthMaxOld[n*(depth+1)+depth-1]);
5754         remotePointsNew[m].rank  = rrank;
5755         ++m;
5756       } else if ((p >= cStart) && (p < cMax)) {
5757         /* Old interior cells add new cells and interior faces */
5758         for (r = 0; r < 4; ++r, ++m) {
5759           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
5760           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
5761           remotePointsNew[m].rank  = rrank;
5762         }
5763         for (r = 0; r < 3; ++r, ++m) {
5764           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (p  - cStart)*3     + r;
5765           remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*2 + (rp - rcStart[n])*3 + r;
5766           remotePointsNew[m].rank  = rrank;
5767         }
5768       } else if ((p >= cStart) && (p < cMax)) {
5769         /* Old hybrid cells add new cells and hybrid face */
5770         for (r = 0; r < 2; ++r, ++m) {
5771           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
5772           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
5773           remotePointsNew[m].rank  = rrank;
5774         }
5775         localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (cMax                            - cStart)*3     + (p  - cMax);
5776         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]);
5777         remotePointsNew[m].rank  = rrank;
5778         ++m;
5779       }
5780       break;
5781     case 4:
5782       /* Hybrid Hex 2D */
5783       if ((p >= vStart) && (p < vEnd)) {
5784         /* Old vertices stay the same */
5785         localPointsNew[m]        = vStartNew     + (p  - vStart);
5786         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
5787         remotePointsNew[m].rank  = rrank;
5788         ++m;
5789       } else if ((p >= fStart) && (p < fMax)) {
5790         /* Old interior faces add new faces and vertex */
5791         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - fStart);
5792         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - rfStart[n]);
5793         remotePointsNew[m].rank  = rrank;
5794         ++m;
5795         for (r = 0; r < 2; ++r, ++m) {
5796           localPointsNew[m]        = fStartNew     + (p  - fStart)*2     + r;
5797           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*2 + r;
5798           remotePointsNew[m].rank  = rrank;
5799         }
5800       } else if ((p >= fMax) && (p < fEnd)) {
5801         /* Old hybrid faces stay the same */
5802         localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (p  - fMax);
5803         remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*2 + (rp - rdepthMaxOld[n*(depth+1)+depth-1]);
5804         remotePointsNew[m].rank  = rrank;
5805         ++m;
5806       } else if ((p >= cStart) && (p < cMax)) {
5807         /* Old interior cells add new cells, interior faces, and vertex */
5808         localPointsNew[m]        = vStartNew     + (vEnd - vStart)               + (fEnd - fStart)                    + (p  - cStart);
5809         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0]  + rdepthSizeOld[n*(depth+1)+depth-1] + (rp - rcStart[n]);
5810         remotePointsNew[m].rank  = rrank;
5811         ++m;
5812         for (r = 0; r < 4; ++r, ++m) {
5813           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
5814           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
5815           remotePointsNew[m].rank  = rrank;
5816         }
5817         for (r = 0; r < 4; ++r, ++m) {
5818           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (p  - cStart)*4     + r;
5819           remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*2 + (rp - rcStart[n])*4 + r;
5820           remotePointsNew[m].rank  = rrank;
5821         }
5822       } else if ((p >= cStart) && (p < cMax)) {
5823         /* Old hybrid cells add new cells and hybrid face */
5824         for (r = 0; r < 2; ++r, ++m) {
5825           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
5826           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
5827           remotePointsNew[m].rank  = rrank;
5828         }
5829         localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (cMax                            - cStart)*4     + (p  - cMax);
5830         remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*2 + (rdepthMaxOld[n*(depth+1)+depth] - rcStart[n])*4 + (rp - rdepthMaxOld[n*(depth+1)+depth]);
5831         remotePointsNew[m].rank  = rrank;
5832         ++m;
5833       }
5834       break;
5835     case 5:
5836       /* Simplicial 3D */
5837       if ((p >= vStart) && (p < vEnd)) {
5838         /* Old vertices stay the same */
5839         localPointsNew[m]        = vStartNew     + (p  - vStart);
5840         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
5841         remotePointsNew[m].rank  = rrank;
5842         ++m;
5843       } else if ((p >= eStart) && (p < eEnd)) {
5844         /* Old edges add new edges and vertex */
5845         for (r = 0; r < 2; ++r, ++m) {
5846           localPointsNew[m]        = eStartNew     + (p  - eStart)*2     + r;
5847           remotePointsNew[m].index = reStartNew[n] + (rp - reStart[n])*2 + r;
5848           remotePointsNew[m].rank  = rrank;
5849         }
5850         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - eStart);
5851         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - reStart[n]);
5852         remotePointsNew[m].rank  = rrank;
5853         ++m;
5854       } else if ((p >= fStart) && (p < fEnd)) {
5855         /* Old faces add new faces and face edges */
5856         for (r = 0; r < 4; ++r, ++m) {
5857           localPointsNew[m]        = fStartNew     + (p  - fStart)*4     + r;
5858           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*4 + r;
5859           remotePointsNew[m].rank  = rrank;
5860         }
5861         for (r = 0; r < 3; ++r, ++m) {
5862           localPointsNew[m]        = eStartNew     + (eEnd - eStart)*2              + (p  - fStart)*3     + r;
5863           remotePointsNew[m].index = reStartNew[n] + rdepthSizeOld[n*(depth+1)+1]*2 + (rp - rfStart[n])*3 + r;
5864           remotePointsNew[m].rank  = rrank;
5865         }
5866       } else if ((p >= cStart) && (p < cEnd)) {
5867         /* Old cells add new cells and interior faces and edges */
5868         for (r = 0; r < 8; ++r, ++m) {
5869           localPointsNew[m]        = cStartNew     + (p  - cStart)*8     + r;
5870           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*8 + r;
5871           remotePointsNew[m].rank  = rrank;
5872         }
5873         for (r = 0; r < 8; ++r, ++m) {
5874           localPointsNew[m]        = fStartNew     + (fEnd - fStart)*4                    + (p  - cStart)*8     + r;
5875           remotePointsNew[m].index = rfStartNew[n] + rdepthSizeOld[n*(depth+1)+depth-1]*4 + (rp - rcStart[n])*8 + r;
5876           remotePointsNew[m].rank  = rrank;
5877         }
5878         for (r = 0; r < 1; ++r, ++m) {
5879           localPointsNew[m]        = eStartNew     + (eEnd - eStart)*2              + (fEnd - fStart)*3                    + (p  - cStart)*1     + r;
5880           remotePointsNew[m].index = reStartNew[n] + rdepthSizeOld[n*(depth+1)+1]*2 + rdepthSizeOld[n*(depth+1)+depth-1]*3 + (rp - rcStart[n])*1 + r;
5881           remotePointsNew[m].rank  = rrank;
5882         }
5883       }
5884       break;
5885     case 7:
5886       /* Hybrid Simplicial 3D */
5887       if ((p >= vStart) && (p < vEnd)) {
5888         /* Interior vertices stay the same */
5889         localPointsNew[m]        = vStartNew     + (p  - vStart);
5890         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
5891         remotePointsNew[m].rank  = rrank;
5892         ++m;
5893       } else if ((p >= eStart) && (p < eMax)) {
5894         /* Interior edges add new edges and vertex */
5895         for (r = 0; r < 2; ++r, ++m) {
5896           localPointsNew[m]        = eStartNew     + (p  - eStart)*2     + r;
5897           remotePointsNew[m].index = reStartNew[n] + (rp - reStart[n])*2 + r;
5898           remotePointsNew[m].rank  = rrank;
5899         }
5900         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - eStart);
5901         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - reStart[n]);
5902         remotePointsNew[m].rank  = rrank;
5903         ++m;
5904       } else if ((p >= eMax) && (p < eEnd)) {
5905         /* Hybrid edges stay the same */
5906         localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (fMax                              - fStart)*3     + (cMax                            - cStart)     + (p  - eMax);
5907         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]);
5908         remotePointsNew[m].rank  = rrank;
5909         ++m;
5910       } else if ((p >= fStart) && (p < fMax)) {
5911         /* Interior faces add new faces and edges */
5912         for (r = 0; r < 4; ++r, ++m) {
5913           localPointsNew[m]        = fStartNew     + (p  - fStart)*4     + r;
5914           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*4 + r;
5915           remotePointsNew[m].rank  = rrank;
5916         }
5917         for (r = 0; r < 3; ++r, ++m) {
5918           localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (p  - fStart)*3     + r;
5919           remotePointsNew[m].index = reStartNew[n] + (rdepthMaxOld[n*(depth+1)+1] - reStart[n])*2 + (rp - rfStart[n])*3 + r;
5920           remotePointsNew[m].rank  = rrank;
5921         }
5922       } else if ((p >= fMax) && (p < fEnd)) {
5923         /* Hybrid faces add new faces and edges */
5924         for (r = 0; r < 2; ++r, ++m) {
5925           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*4     + (cMax                            - cStart)*8     + (p  - fMax)*2                              + r;
5926           remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*4 + (rdepthMaxOld[n*(depth+1)+depth] - rcStart[n])*8 + (rp - rdepthMaxOld[n*(depth+1)+depth-1])*2 + r;
5927           remotePointsNew[m].rank  = rrank;
5928         }
5929         localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (fMax                              - fStart)*3     + (cMax                            - cStart)     + (p  - fMax);
5930         remotePointsNew[m].index = reStartNew[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)+depth-1]);
5931         remotePointsNew[m].rank  = rrank;
5932         ++m;
5933       } else if ((p >= cStart) && (p < cMax)) {
5934         /* Interior cells add new cells, faces, and edges */
5935         for (r = 0; r < 8; ++r, ++m) {
5936           localPointsNew[m]        = cStartNew     + (p  - cStart)*8     + r;
5937           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*8 + r;
5938           remotePointsNew[m].rank  = rrank;
5939         }
5940         for (r = 0; r < 8; ++r, ++m) {
5941           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*4     + (p  - cStart)*8     + r;
5942           remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*4 + (rp - rcStart[n])*8 + r;
5943           remotePointsNew[m].rank  = rrank;
5944         }
5945         localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (fMax                              - fStart)*3     + (p  - cStart)*1     + r;
5946         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;
5947         remotePointsNew[m].rank  = rrank;
5948         ++m;
5949       } else if ((p >= cMax) && (p < cEnd)) {
5950         /* Hybrid cells add new cells and faces */
5951         for (r = 0; r < 4; ++r, ++m) {
5952           localPointsNew[m]        = cStartNew     + (cMax                            - cStart)*8     + (p  - cMax)*4                            + r;
5953           remotePointsNew[m].index = rcStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth] - rcStart[n])*8 + (rp - rdepthMaxOld[n*(depth+1)+depth])*4 + r;
5954           remotePointsNew[m].rank  = rrank;
5955         }
5956         for (r = 0; r < 3; ++r, ++m) {
5957           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*4     + (cMax                            - cStart)*8     + (fEnd                                          - fMax)*2                              + (p  - cMax)*3                            + r;
5958           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])*2 + (rp - rdepthMaxOld[n*(depth+1)+depth])*3 + r;
5959           remotePointsNew[m].rank  = rrank;
5960         }
5961       }
5962       break;
5963     case 6:
5964       /* Hex 3D */
5965       if ((p >= vStart) && (p < vEnd)) {
5966         /* Old vertices stay the same */
5967         localPointsNew[m]        = vStartNew     + (p  - vStart);
5968         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
5969         remotePointsNew[m].rank  = rrank;
5970         ++m;
5971       } else if ((p >= eStart) && (p < eEnd)) {
5972         /* Old edges add new edges and vertex */
5973         for (r = 0; r < 2; ++r, ++m) {
5974           localPointsNew[m]        = eStartNew     + (p  - eStart)*2     + r;
5975           remotePointsNew[m].index = reStartNew[n] + (rp - reStart[n])*2 + r;
5976           remotePointsNew[m].rank  = rrank;
5977         }
5978         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - eStart);
5979         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - reStart[n]);
5980         remotePointsNew[m].rank  = rrank;
5981         ++m;
5982       } else if ((p >= fStart) && (p < fEnd)) {
5983         /* Old faces add new faces, edges, and vertex */
5984         for (r = 0; r < 4; ++r, ++m) {
5985           localPointsNew[m]        = fStartNew     + (p  - fStart)*4     + r;
5986           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*4 + r;
5987           remotePointsNew[m].rank  = rrank;
5988         }
5989         for (r = 0; r < 4; ++r, ++m) {
5990           localPointsNew[m]        = eStartNew     + (eEnd - eStart)*2              + (p  - fStart)*4     + r;
5991           remotePointsNew[m].index = reStartNew[n] + rdepthSizeOld[n*(depth+1)+1]*2 + (rp - rfStart[n])*4 + r;
5992           remotePointsNew[m].rank  = rrank;
5993         }
5994         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (eEnd - eStart)              + (p  - fStart);
5995         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + rdepthSizeOld[n*(depth+1)+1] + (rp - rfStart[n]);
5996         remotePointsNew[m].rank  = rrank;
5997         ++m;
5998       } else if ((p >= cStart) && (p < cEnd)) {
5999         /* Old cells add new cells, faces, edges, and vertex */
6000         for (r = 0; r < 8; ++r, ++m) {
6001           localPointsNew[m]        = cStartNew     + (p  - cStart)*8     + r;
6002           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*8 + r;
6003           remotePointsNew[m].rank  = rrank;
6004         }
6005         for (r = 0; r < 12; ++r, ++m) {
6006           localPointsNew[m]        = fStartNew     + (fEnd - fStart)*4                    + (p  - cStart)*12     + r;
6007           remotePointsNew[m].index = rfStartNew[n] + rdepthSizeOld[n*(depth+1)+depth-1]*4 + (rp - rcStart[n])*12 + r;
6008           remotePointsNew[m].rank  = rrank;
6009         }
6010         for (r = 0; r < 6; ++r, ++m) {
6011           localPointsNew[m]        = eStartNew     + (eEnd - eStart)*2              + (fEnd - fStart)*4                    + (p  - cStart)*6     + r;
6012           remotePointsNew[m].index = reStartNew[n] + rdepthSizeOld[n*(depth+1)+1]*2 + rdepthSizeOld[n*(depth+1)+depth-1]*4 + (rp - rcStart[n])*6 + r;
6013           remotePointsNew[m].rank  = rrank;
6014         }
6015         for (r = 0; r < 1; ++r, ++m) {
6016           localPointsNew[m]        = vStartNew     + (eEnd - eStart)              + (fEnd - fStart)                    + (p  - cStart)     + r;
6017           remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+1] + rdepthSizeOld[n*(depth+1)+depth-1] + (rp - rcStart[n]) + r;
6018           remotePointsNew[m].rank  = rrank;
6019         }
6020       }
6021       break;
6022     case 8:
6023       /* Hybrid Hex 3D */
6024       if ((p >= vStart) && (p < vEnd)) {
6025         /* Interior vertices stay the same */
6026         localPointsNew[m]        = vStartNew     + (p  - vStart);
6027         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
6028         remotePointsNew[m].rank  = rrank;
6029         ++m;
6030       } else if ((p >= eStart) && (p < eMax)) {
6031         /* Interior edges add new edges and vertex */
6032         for (r = 0; r < 2; ++r, ++m) {
6033           localPointsNew[m]        = eStartNew     + (p  - eStart)*2     + r;
6034           remotePointsNew[m].index = reStartNew[n] + (rp - reStart[n])*2 + r;
6035           remotePointsNew[m].rank  = rrank;
6036         }
6037         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - eStart);
6038         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - reStart[n]);
6039         remotePointsNew[m].rank  = rrank;
6040         ++m;
6041       } else if ((p >= eMax) && (p < eEnd)) {
6042         /* Hybrid edges stay the same */
6043         localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (fMax                              - fStart)*4     + (cMax                            - cStart)*6     + (p  - eMax);
6044         remotePointsNew[m].index = rvStartNew[n] + (rdepthMaxOld[n*(depth+1)+1] - reStart[n])*2 + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*4 + (rdepthMaxOld[n*(depth+1)+depth] - rcStart[n])*6 + (rp - rdepthMaxOld[n*(depth+1)+1]);
6045         remotePointsNew[m].rank  = rrank;
6046         ++m;
6047       } else if ((p >= fStart) && (p < fMax)) {
6048         /* Interior faces add new faces, edges, and vertex */
6049         for (r = 0; r < 4; ++r, ++m) {
6050           localPointsNew[m]        = fStartNew     + (p  - fStart)*4     + r;
6051           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*4 + r;
6052           remotePointsNew[m].rank  = rrank;
6053         }
6054         for (r = 0; r < 4; ++r, ++m) {
6055           localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (p  - fStart)*4     + r;
6056           remotePointsNew[m].index = reStartNew[n] + (rdepthMaxOld[n*(depth+1)+1] - reStart[n])*2 + (rp - rfStart[n])*4 + r;
6057           remotePointsNew[m].rank  = rrank;
6058         }
6059         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (eMax                        - eStart)     + (p  - fStart);
6060         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rdepthMaxOld[n*(depth+1)+1] - reStart[n]) + (rp - rfStart[n]);
6061         remotePointsNew[m].rank  = rrank;
6062         ++m;
6063       } else if ((p >= fMax) && (p < fEnd)) {
6064         /* Hybrid faces add new faces and edges */
6065         for (r = 0; r < 2; ++r, ++m) {
6066           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*4     + (cMax                            - cStart)*8     + (p  - fMax)*2                              + r;
6067           remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*4 + (rdepthMaxOld[n*(depth+1)+depth] - rcStart[n])*8 + (rp - rdepthMaxOld[n*(depth+1)+depth-1])*2 + r;
6068           remotePointsNew[m].rank  = rrank;
6069         }
6070         localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (fMax                              - fStart)*4     + (cMax                            - cStart)*6     + (fEnd                                          - fMax);
6071         remotePointsNew[m].index = reStartNew[n] + (rdepthMaxOld[n*(depth+1)+1] - reStart[n])*2 + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*4 + (rdepthMaxOld[n*(depth+1)+depth] - rcStart[n])*6 + (rdepthSizeOld[n*(depth+1)+depth-1]+rfStart[n] - rdepthMaxOld[n*(depth+1)+depth-1]);
6072         remotePointsNew[m].rank  = rrank;
6073         ++m;
6074       } else if ((p >= cStart) && (p < cMax)) {
6075         /* Interior cells add new cells, faces, edges, and vertex */
6076         for (r = 0; r < 8; ++r, ++m) {
6077           localPointsNew[m]        = cStartNew     + (p  - cStart)*8     + r;
6078           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*8 + r;
6079           remotePointsNew[m].rank  = rrank;
6080         }
6081         for (r = 0; r < 12; ++r, ++m) {
6082           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*4     + (p  - cStart)*12     + r;
6083           remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*4 + (rp - rcStart[n])*12 + r;
6084           remotePointsNew[m].rank  = rrank;
6085         }
6086         for (r = 0; r < 6; ++r, ++m) {
6087           localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (fMax                              - fStart)*4     + (p  - cStart)*6     + r;
6088           remotePointsNew[m].index = reStartNew[n] + (rdepthMaxOld[n*(depth+1)+1] - reStart[n])*2 + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*4 + (rp - rcStart[n])*6 + r;
6089           remotePointsNew[m].rank  = rrank;
6090         }
6091         for (r = 0; r < 1; ++r, ++m) {
6092           localPointsNew[m]        = vStartNew     + (eMax                        - eStart)     + (fMax                              - fStart)     + (p  - cStart)     + r;
6093           remotePointsNew[m].index = rvStartNew[n] + (rdepthMaxOld[n*(depth+1)+1] - reStart[n]) + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n]) + (rp - rcStart[n]) + r;
6094           remotePointsNew[m].rank  = rrank;
6095         }
6096       } else if ((p >= cMax) && (p < cEnd)) {
6097         /* Hybrid cells add new cells, faces, and edges */
6098         for (r = 0; r < 4; ++r, ++m) {
6099           localPointsNew[m]        = cStartNew     + (cMax                            - cStart)*8     + (p  - cMax)*4                            + r;
6100           remotePointsNew[m].index = rcStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth] - rcStart[n])*8 + (rp - rdepthMaxOld[n*(depth+1)+depth])*4 + r;
6101           remotePointsNew[m].rank  = rrank;
6102         }
6103         for (r = 0; r < 4; ++r, ++m) {
6104           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*4     + (cMax                            - cStart)*8     + (fEnd                                          - fMax)*2                              + (p  - cMax)*4                            + r;
6105           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])*2 + (rp - rdepthMaxOld[n*(depth+1)+depth])*4 + r;
6106           remotePointsNew[m].rank  = rrank;
6107         }
6108         localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (fMax                              - fStart)*4     + (cMax                            - cStart)*6     + (fEnd                                          - fMax)                              + (p  - cMax);
6109         remotePointsNew[m].index = reStartNew[n] + (rdepthMaxOld[n*(depth+1)+1] - reStart[n])*2 + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*4 + (rdepthMaxOld[n*(depth+1)+depth] - rcStart[n])*6 + (rdepthSizeOld[n*(depth+1)+depth-1]+rfStart[n] - rdepthMaxOld[n*(depth+1)+depth-1]) + (rp - rdepthMaxOld[n*(depth+1)+depth]);
6110         remotePointsNew[m].rank  = rrank;
6111         ++m;
6112       }
6113       break;
6114     default:
6115       SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
6116     }
6117   }
6118   if (m != numLeavesNew) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Number of leaf point %d should be %d", m, numLeavesNew);
6119   ierr = ISRestoreIndices(processRanks, &neighbors);CHKERRQ(ierr);
6120   ierr = ISDestroy(&processRanks);CHKERRQ(ierr);
6121   ierr = PetscSFSetGraph(sfNew, pEndNew-pStartNew, numLeavesNew, localPointsNew, PETSC_OWN_POINTER, remotePointsNew, PETSC_OWN_POINTER);CHKERRQ(ierr);
6122   ierr = PetscFree5(rdepthSize,rvStartNew,reStartNew,rfStartNew,rcStartNew);CHKERRQ(ierr);
6123   ierr = PetscFree7(depthSizeOld,rdepthSizeOld,rdepthMaxOld,rvStart,reStart,rfStart,rcStart);CHKERRQ(ierr);
6124   PetscFunctionReturn(0);
6125 }
6126 
6127 #undef __FUNCT__
6128 #define __FUNCT__ "CellRefinerCreateLabels"
6129 static PetscErrorCode CellRefinerCreateLabels(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
6130 {
6131   PetscInt       numLabels, l;
6132   PetscInt       depth, newp, cStart, cEnd, cMax, vStart, vEnd, vMax, fStart, fEnd, fMax, eStart, eEnd, eMax, r;
6133   PetscInt       cStartNew = 0, vStartNew = 0, fStartNew = 0, eStartNew = 0;
6134   PetscErrorCode ierr;
6135 
6136   PetscFunctionBegin;
6137   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
6138   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
6139   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
6140   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
6141   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
6142   if (refiner) {ierr = GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);CHKERRQ(ierr);}
6143   ierr = DMPlexGetNumLabels(dm, &numLabels);CHKERRQ(ierr);
6144   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
6145   switch (refiner) {
6146   case 0: break;
6147   case 7:
6148   case 8:
6149     if (eMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No edge maximum specified in hybrid mesh");
6150   case 3:
6151   case 4:
6152     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
6153     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
6154   }
6155   for (l = 0; l < numLabels; ++l) {
6156     DMLabel         label, labelNew;
6157     const char     *lname;
6158     PetscBool       isDepth;
6159     IS              valueIS;
6160     const PetscInt *values;
6161     PetscInt        numValues, val;
6162 
6163     ierr = DMPlexGetLabelName(dm, l, &lname);CHKERRQ(ierr);
6164     ierr = PetscStrcmp(lname, "depth", &isDepth);CHKERRQ(ierr);
6165     if (isDepth) continue;
6166     ierr = DMPlexCreateLabel(rdm, lname);CHKERRQ(ierr);
6167     ierr = DMPlexGetLabel(dm, lname, &label);CHKERRQ(ierr);
6168     ierr = DMPlexGetLabel(rdm, lname, &labelNew);CHKERRQ(ierr);
6169     ierr = DMLabelGetValueIS(label, &valueIS);CHKERRQ(ierr);
6170     ierr = ISGetLocalSize(valueIS, &numValues);CHKERRQ(ierr);
6171     ierr = ISGetIndices(valueIS, &values);CHKERRQ(ierr);
6172     for (val = 0; val < numValues; ++val) {
6173       IS              pointIS;
6174       const PetscInt *points;
6175       PetscInt        numPoints, n;
6176 
6177       ierr = DMLabelGetStratumIS(label, values[val], &pointIS);CHKERRQ(ierr);
6178       ierr = ISGetLocalSize(pointIS, &numPoints);CHKERRQ(ierr);
6179       ierr = ISGetIndices(pointIS, &points);CHKERRQ(ierr);
6180       for (n = 0; n < numPoints; ++n) {
6181         const PetscInt p = points[n];
6182         switch (refiner) {
6183         case 1:
6184           /* Simplicial 2D */
6185           if ((p >= vStart) && (p < vEnd)) {
6186             /* Old vertices stay the same */
6187             newp = vStartNew + (p - vStart);
6188             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6189           } else if ((p >= fStart) && (p < fEnd)) {
6190             /* Old faces add new faces and vertex */
6191             newp = vStartNew + (vEnd - vStart) + (p - fStart);
6192             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6193             for (r = 0; r < 2; ++r) {
6194               newp = fStartNew + (p - fStart)*2 + r;
6195               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6196             }
6197           } else if ((p >= cStart) && (p < cEnd)) {
6198             /* Old cells add new cells and interior faces */
6199             for (r = 0; r < 4; ++r) {
6200               newp = cStartNew + (p - cStart)*4 + r;
6201               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6202             }
6203             for (r = 0; r < 3; ++r) {
6204               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*3 + r;
6205               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6206             }
6207           }
6208           break;
6209         case 2:
6210           /* Hex 2D */
6211           if ((p >= vStart) && (p < vEnd)) {
6212             /* Old vertices stay the same */
6213             newp = vStartNew + (p - vStart);
6214             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6215           } else if ((p >= fStart) && (p < fEnd)) {
6216             /* Old faces add new faces and vertex */
6217             newp = vStartNew + (vEnd - vStart) + (p - fStart);
6218             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6219             for (r = 0; r < 2; ++r) {
6220               newp = fStartNew + (p - fStart)*2 + r;
6221               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6222             }
6223           } else if ((p >= cStart) && (p < cEnd)) {
6224             /* Old cells add new cells and interior faces and vertex */
6225             for (r = 0; r < 4; ++r) {
6226               newp = cStartNew + (p - cStart)*4 + r;
6227               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6228             }
6229             for (r = 0; r < 4; ++r) {
6230               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*4 + r;
6231               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6232             }
6233             newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (p - cStart);
6234             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6235           }
6236           break;
6237         case 3:
6238           /* Hybrid simplicial 2D */
6239           if ((p >= vStart) && (p < vEnd)) {
6240             /* Old vertices stay the same */
6241             newp = vStartNew + (p - vStart);
6242             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6243           } else if ((p >= fStart) && (p < fMax)) {
6244             /* Old interior faces add new faces and vertex */
6245             newp = vStartNew + (vEnd - vStart) + (p - fStart);
6246             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6247             for (r = 0; r < 2; ++r) {
6248               newp = fStartNew + (p - fStart)*2 + r;
6249               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6250             }
6251           } else if ((p >= fMax) && (p < fEnd)) {
6252             /* Old hybrid faces stay the same */
6253             newp = fStartNew + (fMax - fStart)*2 + (p - fMax);
6254             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6255           } else if ((p >= cStart) && (p < cMax)) {
6256             /* Old interior cells add new cells and interior faces */
6257             for (r = 0; r < 4; ++r) {
6258               newp = cStartNew + (p - cStart)*4 + r;
6259               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6260             }
6261             for (r = 0; r < 3; ++r) {
6262               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*3 + r;
6263               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6264             }
6265           } else if ((p >= cMax) && (p < cEnd)) {
6266             /* Old hybrid cells add new cells and hybrid face */
6267             for (r = 0; r < 2; ++r) {
6268               newp = cStartNew + (cMax - cStart)*4 + (p - cMax)*2 + r;
6269               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6270             }
6271             newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (p - cMax);
6272             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6273           }
6274           break;
6275         case 4:
6276           /* Hybrid Hex 2D */
6277           if ((p >= vStart) && (p < vEnd)) {
6278             /* Old vertices stay the same */
6279             newp = vStartNew + (p - vStart);
6280             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6281           } else if ((p >= fStart) && (p < fMax)) {
6282             /* Old interior faces add new faces and vertex */
6283             newp = vStartNew + (vEnd - vStart) + (p - fStart);
6284             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6285             for (r = 0; r < 2; ++r) {
6286               newp = fStartNew + (p - fStart)*2 + r;
6287               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6288             }
6289           } else if ((p >= fMax) && (p < fEnd)) {
6290             /* Old hybrid faces stay the same */
6291             newp = fStartNew + (fMax - fStart)*2 + (p - fMax);
6292             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6293           } else if ((p >= cStart) && (p < cMax)) {
6294             /* Old interior cells add new cells, interior faces, and vertex */
6295             for (r = 0; r < 4; ++r) {
6296               newp = cStartNew + (p - cStart)*4 + r;
6297               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6298             }
6299             for (r = 0; r < 4; ++r) {
6300               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*4 + r;
6301               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6302             }
6303             newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (p - cStart);
6304             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6305           } else if ((p >= cMax) && (p < cEnd)) {
6306             /* Old hybrid cells add new cells and hybrid face */
6307             for (r = 0; r < 2; ++r) {
6308               newp = cStartNew + (cMax - cStart)*4 + (p - cMax)*2 + r;
6309               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6310             }
6311             newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*4 + (p - cMax);
6312             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6313           }
6314           break;
6315         case 5:
6316           /* Simplicial 3D */
6317           if ((p >= vStart) && (p < vEnd)) {
6318             /* Old vertices stay the same */
6319             newp = vStartNew + (p - vStart);
6320             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6321           } else if ((p >= eStart) && (p < eEnd)) {
6322             /* Old edges add new edges and vertex */
6323             for (r = 0; r < 2; ++r) {
6324               newp = eStartNew + (p - eStart)*2 + r;
6325               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6326             }
6327             newp = vStartNew + (vEnd - vStart) + (p - eStart);
6328             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6329           } else if ((p >= fStart) && (p < fEnd)) {
6330             /* Old faces add new faces and edges */
6331             for (r = 0; r < 4; ++r) {
6332               newp = fStartNew + (p - fStart)*4 + r;
6333               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6334             }
6335             for (r = 0; r < 3; ++r) {
6336               newp = eStartNew + (eEnd - eStart)*2 + (p - fStart)*3 + r;
6337               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6338             }
6339           } else if ((p >= cStart) && (p < cEnd)) {
6340             /* Old cells add new cells and interior faces and edges */
6341             for (r = 0; r < 8; ++r) {
6342               newp = cStartNew + (p - cStart)*8 + r;
6343               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6344             }
6345             for (r = 0; r < 8; ++r) {
6346               newp = fStartNew + (fEnd - fStart)*4 + (p - cStart)*8 + r;
6347               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6348             }
6349             for (r = 0; r < 1; ++r) {
6350               newp = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (p - cStart)*1 + r;
6351               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6352             }
6353           }
6354           break;
6355         case 7:
6356           /* Hybrid Simplicial 3D */
6357           if ((p >= vStart) && (p < vEnd)) {
6358             /* Interior vertices stay the same */
6359             newp = vStartNew + (p - vStart);
6360             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6361           } else if ((p >= eStart) && (p < eMax)) {
6362             /* Interior edges add new edges and vertex */
6363             for (r = 0; r < 2; ++r) {
6364               newp = eStartNew + (p - eStart)*2 + r;
6365               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6366             }
6367             newp = vStartNew + (vEnd - vStart) + (p - eStart);
6368             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6369           } else if ((p >= eMax) && (p < eEnd)) {
6370             /* Hybrid edges stay the same */
6371             newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (p - eMax);
6372             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6373           } else if ((p >= fStart) && (p < fMax)) {
6374             /* Interior faces add new faces and edges */
6375             for (r = 0; r < 4; ++r) {
6376               newp = fStartNew + (p - fStart)*4 + r;
6377               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6378             }
6379             for (r = 0; r < 3; ++r) {
6380               newp = eStartNew + (eMax - eStart)*2 + (p - fStart)*3 + r;
6381               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6382             }
6383           } else if ((p >= fMax) && (p < fEnd)) {
6384             /* Hybrid faces add new faces and edges */
6385             for (r = 0; r < 2; ++r) {
6386               newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (p - fMax)*2 + r;
6387               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6388             }
6389             newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (p - fMax);
6390             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6391           } else if ((p >= cStart) && (p < cMax)) {
6392             /* Interior cells add new cells, faces, and edges */
6393             for (r = 0; r < 8; ++r) {
6394               newp = cStartNew + (p - cStart)*8 + r;
6395               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6396             }
6397             for (r = 0; r < 8; ++r) {
6398               newp = fStartNew + (fMax - fStart)*4 + (p - cStart)*8 + r;
6399               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6400             }
6401             newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (p - cStart);
6402             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6403           } else if ((p >= cMax) && (p < cEnd)) {
6404             /* Hybrid cells add new cells and faces */
6405             for (r = 0; r < 4; ++r) {
6406               newp = cStartNew + (cMax - cStart)*8 + (p - cMax)*4 + r;
6407               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6408             }
6409             for (r = 0; r < 3; ++r) {
6410               newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (p - cMax)*3 + r;
6411               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6412             }
6413           }
6414           break;
6415         case 6:
6416           /* Hex 3D */
6417           if ((p >= vStart) && (p < vEnd)) {
6418             /* Old vertices stay the same */
6419             newp = vStartNew + (p - vStart);
6420             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6421           } else if ((p >= eStart) && (p < eEnd)) {
6422             /* Old edges add new edges and vertex */
6423             for (r = 0; r < 2; ++r) {
6424               newp = eStartNew + (p - eStart)*2 + r;
6425               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6426             }
6427             newp = vStartNew + (vEnd - vStart) + (p - eStart);
6428             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6429           } else if ((p >= fStart) && (p < fEnd)) {
6430             /* Old faces add new faces, edges, and vertex */
6431             for (r = 0; r < 4; ++r) {
6432               newp = fStartNew + (p - fStart)*4 + r;
6433               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6434             }
6435             for (r = 0; r < 4; ++r) {
6436               newp = eStartNew + (eEnd - eStart)*2 + (p - fStart)*4 + r;
6437               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6438             }
6439             newp = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (p - fStart);
6440             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6441           } else if ((p >= cStart) && (p < cEnd)) {
6442             /* Old cells add new cells, faces, edges, and vertex */
6443             for (r = 0; r < 8; ++r) {
6444               newp = cStartNew + (p - cStart)*8 + r;
6445               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6446             }
6447             for (r = 0; r < 12; ++r) {
6448               newp = fStartNew + (fEnd - fStart)*4 + (p - cStart)*12 + r;
6449               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6450             }
6451             for (r = 0; r < 6; ++r) {
6452               newp = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*4 + (p - cStart)*6 + r;
6453               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6454             }
6455             newp = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (fEnd - fStart) + (p - cStart);
6456             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6457           }
6458           break;
6459         case 8:
6460           /* Hybrid Hex 3D */
6461           if ((p >= vStart) && (p < vEnd)) {
6462             /* Interior vertices stay the same */
6463             newp = vStartNew + (p - vStart);
6464             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6465           } else if ((p >= eStart) && (p < eMax)) {
6466             /* Interior edges add new edges and vertex */
6467             for (r = 0; r < 2; ++r) {
6468               newp = eStartNew + (p - eStart)*2 + r;
6469               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6470             }
6471             newp = vStartNew + (vEnd - vStart) + (p - eStart);
6472             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6473           } else if ((p >= eMax) && (p < eEnd)) {
6474             /* Hybrid edges stay the same */
6475             newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (p - eMax);
6476             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6477           } else if ((p >= fStart) && (p < fMax)) {
6478             /* Interior faces add new faces, edges, and vertex */
6479             for (r = 0; r < 4; ++r) {
6480               newp = fStartNew + (p - fStart)*4 + r;
6481               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6482             }
6483             for (r = 0; r < 4; ++r) {
6484               newp = eStartNew + (eMax - eStart)*2 + (p - fStart)*4 + r;
6485               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6486             }
6487             newp = vStartNew + (vEnd - vStart) + (eMax - eStart) + (p - fStart);
6488             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6489           } else if ((p >= fMax) && (p < fEnd)) {
6490             /* Hybrid faces add new faces and edges */
6491             for (r = 0; r < 2; ++r) {
6492               newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (p - fMax)*2 + r;
6493               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6494             }
6495             newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (p - fMax);
6496             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6497           } else if ((p >= cStart) && (p < cMax)) {
6498             /* Interior cells add new cells, faces, edges, and vertex */
6499             for (r = 0; r < 8; ++r) {
6500               newp = cStartNew + (p - cStart)*8 + r;
6501               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6502             }
6503             for (r = 0; r < 12; ++r) {
6504               newp = fStartNew + (fMax - fStart)*4 + (p - cStart)*12 + r;
6505               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6506             }
6507             for (r = 0; r < 6; ++r) {
6508               newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (p - cStart)*6 + r;
6509               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6510             }
6511             newp = vStartNew + (vEnd - vStart) + (eMax - eStart) + (fMax - fStart) + (p - cStart);
6512             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6513           } else if ((p >= cMax) && (p < cEnd)) {
6514             /* Hybrid cells add new cells, faces, and edges */
6515             for (r = 0; r < 4; ++r) {
6516               newp = cStartNew + (cMax - cStart)*8 + (p - cMax)*4 + r;
6517               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6518             }
6519             for (r = 0; r < 4; ++r) {
6520               newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd - fMax)*2 + (p - cMax)*4 + r;
6521               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6522             }
6523             newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (fEnd - fMax) + (p - cMax);
6524             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6525           }
6526           break;
6527         default:
6528           SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
6529         }
6530       }
6531       ierr = ISRestoreIndices(pointIS, &points);CHKERRQ(ierr);
6532       ierr = ISDestroy(&pointIS);CHKERRQ(ierr);
6533     }
6534     ierr = ISRestoreIndices(valueIS, &values);CHKERRQ(ierr);
6535     ierr = ISDestroy(&valueIS);CHKERRQ(ierr);
6536     if (0) {
6537       ierr = PetscViewerASCIISynchronizedAllow(PETSC_VIEWER_STDOUT_WORLD, PETSC_TRUE);CHKERRQ(ierr);
6538       ierr = DMLabelView(labelNew, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
6539       ierr = PetscViewerFlush(PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
6540     }
6541   }
6542   PetscFunctionReturn(0);
6543 }
6544 
6545 #undef __FUNCT__
6546 #define __FUNCT__ "DMPlexRefineUniform_Internal"
6547 /* This will only work for interpolated meshes */
6548 PetscErrorCode DMPlexRefineUniform_Internal(DM dm, CellRefiner cellRefiner, DM *dmRefined)
6549 {
6550   DM             rdm;
6551   PetscInt      *depthSize;
6552   PetscInt       dim, depth = 0, d, pStart = 0, pEnd = 0;
6553   PetscErrorCode ierr;
6554 
6555   PetscFunctionBegin;
6556   ierr = DMCreate(PetscObjectComm((PetscObject)dm), &rdm);CHKERRQ(ierr);
6557   ierr = DMSetType(rdm, DMPLEX);CHKERRQ(ierr);
6558   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
6559   ierr = DMPlexSetDimension(rdm, dim);CHKERRQ(ierr);
6560   /* Calculate number of new points of each depth */
6561   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
6562   ierr = PetscMalloc1((depth+1), &depthSize);CHKERRQ(ierr);
6563   ierr = PetscMemzero(depthSize, (depth+1) * sizeof(PetscInt));CHKERRQ(ierr);
6564   ierr = CellRefinerGetSizes(cellRefiner, dm, depthSize);CHKERRQ(ierr);
6565   /* Step 1: Set chart */
6566   for (d = 0; d <= depth; ++d) pEnd += depthSize[d];
6567   ierr = DMPlexSetChart(rdm, pStart, pEnd);CHKERRQ(ierr);
6568   /* Step 2: Set cone/support sizes */
6569   ierr = CellRefinerSetConeSizes(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
6570   /* Step 3: Setup refined DM */
6571   ierr = DMSetUp(rdm);CHKERRQ(ierr);
6572   /* Step 4: Set cones and supports */
6573   ierr = CellRefinerSetCones(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
6574   /* Step 5: Stratify */
6575   ierr = DMPlexStratify(rdm);CHKERRQ(ierr);
6576   /* Step 6: Set coordinates for vertices */
6577   ierr = CellRefinerSetCoordinates(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
6578   /* Step 7: Create pointSF */
6579   ierr = CellRefinerCreateSF(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
6580   /* Step 8: Create labels */
6581   ierr = CellRefinerCreateLabels(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
6582   ierr = PetscFree(depthSize);CHKERRQ(ierr);
6583 
6584   *dmRefined = rdm;
6585   PetscFunctionReturn(0);
6586 }
6587 
6588 #undef __FUNCT__
6589 #define __FUNCT__ "DMPlexSetRefinementUniform"
6590 PetscErrorCode DMPlexSetRefinementUniform(DM dm, PetscBool refinementUniform)
6591 {
6592   DM_Plex *mesh = (DM_Plex*) dm->data;
6593 
6594   PetscFunctionBegin;
6595   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6596   mesh->refinementUniform = refinementUniform;
6597   PetscFunctionReturn(0);
6598 }
6599 
6600 #undef __FUNCT__
6601 #define __FUNCT__ "DMPlexGetRefinementUniform"
6602 PetscErrorCode DMPlexGetRefinementUniform(DM dm, PetscBool *refinementUniform)
6603 {
6604   DM_Plex *mesh = (DM_Plex*) dm->data;
6605 
6606   PetscFunctionBegin;
6607   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6608   PetscValidPointer(refinementUniform,  2);
6609   *refinementUniform = mesh->refinementUniform;
6610   PetscFunctionReturn(0);
6611 }
6612 
6613 #undef __FUNCT__
6614 #define __FUNCT__ "DMPlexSetRefinementLimit"
6615 PetscErrorCode DMPlexSetRefinementLimit(DM dm, PetscReal refinementLimit)
6616 {
6617   DM_Plex *mesh = (DM_Plex*) dm->data;
6618 
6619   PetscFunctionBegin;
6620   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6621   mesh->refinementLimit = refinementLimit;
6622   PetscFunctionReturn(0);
6623 }
6624 
6625 #undef __FUNCT__
6626 #define __FUNCT__ "DMPlexGetRefinementLimit"
6627 PetscErrorCode DMPlexGetRefinementLimit(DM dm, PetscReal *refinementLimit)
6628 {
6629   DM_Plex *mesh = (DM_Plex*) dm->data;
6630 
6631   PetscFunctionBegin;
6632   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6633   PetscValidPointer(refinementLimit,  2);
6634   /* if (mesh->refinementLimit < 0) = getMaxVolume()/2.0; */
6635   *refinementLimit = mesh->refinementLimit;
6636   PetscFunctionReturn(0);
6637 }
6638 
6639 #undef __FUNCT__
6640 #define __FUNCT__ "DMPlexGetCellRefiner_Internal"
6641 PetscErrorCode DMPlexGetCellRefiner_Internal(DM dm, CellRefiner *cellRefiner)
6642 {
6643   PetscInt       dim, cStart, cEnd, coneSize, cMax;
6644   PetscErrorCode ierr;
6645 
6646   PetscFunctionBegin;
6647   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
6648   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
6649   if (cEnd <= cStart) {*cellRefiner = 0; PetscFunctionReturn(0);}
6650   ierr = DMPlexGetConeSize(dm, cStart, &coneSize);CHKERRQ(ierr);
6651   ierr = DMPlexGetHybridBounds(dm, &cMax, NULL, NULL, NULL);CHKERRQ(ierr);
6652   switch (dim) {
6653   case 2:
6654     switch (coneSize) {
6655     case 3:
6656       if (cMax >= 0) *cellRefiner = 3; /* Hybrid */
6657       else *cellRefiner = 1; /* Triangular */
6658       break;
6659     case 4:
6660       if (cMax >= 0) *cellRefiner = 4; /* Hybrid */
6661       else *cellRefiner = 2; /* Quadrilateral */
6662       break;
6663     default:
6664       SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown coneSize %d in dimension %d for cell refiner", coneSize, dim);
6665     }
6666     break;
6667   case 3:
6668     switch (coneSize) {
6669     case 4:
6670       if (cMax >= 0) *cellRefiner = 7; /* Hybrid */
6671       else *cellRefiner = 5; /* Tetrahedral */
6672       break;
6673     case 6:
6674       if (cMax >= 0) *cellRefiner = 8; /* Hybrid */
6675       else *cellRefiner = 6; /* hexahedral */
6676       break;
6677     default:
6678       SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown coneSize %d in dimension %d for cell refiner", coneSize, dim);
6679     }
6680     break;
6681   default:
6682     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown dimension %d for cell refiner", dim);
6683   }
6684   PetscFunctionReturn(0);
6685 }
6686