xref: /petsc/src/dm/impls/plex/plexrefine.c (revision 0f5d826a8a3961d28a20703f4390975100ca0e26)
1 #include <petsc/private/dmpleximpl.h>   /*I      "petscdmplex.h"   I*/
2 #include <petscsf.h>
3 
4 const char * const CellRefiners[] = {"NOOP", "SIMPLEX_1D", "SIMPLEX_2D", "HYBRID_SIMPLEX_2D", "SIMPLEX_TO_HEX_2D", "HYBRID_SIMPLEX_TO_HEX_2D", "HEX_2D", "HYBRID_HEX_2D",
5                                      "SIMPLEX_3D", "HYBRID_SIMPLEX_3D", "SIMPLEX_TO_HEX_3D", "HYBRID_SIMPLEX_TO_HEX_3D", "HEX_3D", "HYBRID_HEX_3D", "CellRefiners", "REFINER_", 0};
6 
7 PETSC_STATIC_INLINE PetscErrorCode GetDepthStart_Private(PetscInt depth, PetscInt depthSize[], PetscInt *cStart, PetscInt *fStart, PetscInt *eStart, PetscInt *vStart)
8 {
9   PetscFunctionBegin;
10   if (cStart) *cStart = 0;
11   if (vStart) *vStart = depth < 0 ? 0 : depthSize[depth];
12   if (fStart) *fStart = depth < 0 ? 0 : depthSize[depth] + depthSize[0];
13   if (eStart) *eStart = depth < 0 ? 0 : depthSize[depth] + depthSize[0] + depthSize[depth-1];
14   PetscFunctionReturn(0);
15 }
16 
17 PETSC_STATIC_INLINE PetscErrorCode GetDepthEnd_Private(PetscInt depth, PetscInt depthSize[], PetscInt *cEnd, PetscInt *fEnd, PetscInt *eEnd, PetscInt *vEnd)
18 {
19   PetscFunctionBegin;
20   if (cEnd) *cEnd = depth < 0 ? 0 : depthSize[depth];
21   if (vEnd) *vEnd = depth < 0 ? 0 : depthSize[depth] + depthSize[0];
22   if (fEnd) *fEnd = depth < 0 ? 0 : depthSize[depth] + depthSize[0] + depthSize[depth-1];
23   if (eEnd) *eEnd = depth < 0 ? 0 : depthSize[depth] + depthSize[0] + depthSize[depth-1] + depthSize[1];
24   PetscFunctionReturn(0);
25 }
26 
27 /*
28   Note that j and invj are non-square:
29          v0 + j x_face = x_cell
30     invj (x_cell - v0) = x_face
31 */
32 PetscErrorCode CellRefinerGetAffineFaceTransforms_Internal(CellRefiner refiner, PetscInt *numFaces, PetscReal *v0[], PetscReal *jac[], PetscReal *invjac[], PetscReal *detj[])
33 {
34   PetscReal     *v = NULL, *j = NULL, *invj = NULL, *dj = NULL;
35   PetscInt       cdim, fdim;
36   PetscErrorCode ierr;
37 
38   PetscFunctionBegin;
39   switch (refiner) {
40   case REFINER_NOOP: break;
41   case REFINER_SIMPLEX_2D:
42     /*
43      2
44      |\
45      | \
46      |  \
47      |   \
48      |    \
49      |     \
50      |      \
51      2       1
52      |        \
53      |         \
54      |          \
55      0---0-------1
56      */
57     cdim = 2;
58     fdim = 1;
59     if (numFaces) *numFaces = 3;
60     if (v0) {
61       ierr = PetscMalloc1(3*cdim,      &v);CHKERRQ(ierr);
62       ierr = PetscMalloc1(3*cdim*fdim, &j);CHKERRQ(ierr);
63       ierr = PetscMalloc1(3*cdim*fdim, &invj);CHKERRQ(ierr);
64       ierr = PetscMalloc1(3,           &dj);CHKERRQ(ierr);
65       /* 0 */
66       v[0+0] =  0.0; v[0+1] = -1.0;
67       j[0+0] =  1.0;
68       j[0+1] =  0.0;
69       invj[0+0] = 1.0; invj[0+1] = 0.0;
70       dj[0]  = 1.0;
71       /* 1 */
72       v[2+0] =  0.0; v[2+1] =  0.0;
73       j[2+0] = -1.0;
74       j[2+1] =  1.0;
75       invj[2+0] = -0.5; invj[2+1] = 0.5;
76       dj[1]  = 1.414213562373095;
77       /* 2 */
78       v[4+0] = -1.0; v[4+1] =  0.0;
79       j[4+0] =  0.0;
80       j[4+1] = -1.0;
81       invj[4+0] = 0.0; invj[4+1] = -1.0;
82       dj[2]  = 1.0;
83     }
84     break;
85   case REFINER_HEX_2D:
86     /*
87      3---------2---------2
88      |                   |
89      |                   |
90      |                   |
91      3                   1
92      |                   |
93      |                   |
94      |                   |
95      0---------0---------1
96      */
97     cdim = 2;
98     fdim = 1;
99     if (numFaces) *numFaces = 4;
100     if (v0) {
101       ierr = PetscMalloc1(4*cdim,      &v);CHKERRQ(ierr);
102       ierr = PetscMalloc1(4*cdim*fdim, &j);CHKERRQ(ierr);
103       ierr = PetscMalloc1(4*cdim*fdim, &invj);CHKERRQ(ierr);
104       ierr = PetscMalloc1(4,           &dj);CHKERRQ(ierr);
105       /* 0 */
106       v[0+0] =  0.0; v[0+1] = -1.0;
107       j[0+0] =  1.0;
108       j[0+1] =  0.0;
109       invj[0+0] =  1.0; invj[0+1] =  0.0;
110       dj[0]  = 1.0;
111       /* 1 */
112       v[2+0] =  1.0; v[2+1] =  0.0;
113       j[2+0] =  0.0;
114       j[2+1] =  1.0;
115       invj[2+0] =  0.0; invj[2+1] =  1.0;
116       dj[1]  = 1.0;
117       /* 2 */
118       v[4+0] =  0.0; v[4+1] = 1.0;
119       j[4+0] = -1.0;
120       j[4+1] =  0.0;
121       invj[4+0] = -1.0; invj[4+1] =  0.0;
122       dj[2]  = 1.0;
123       /* 3 */
124       v[6+0] = -1.0; v[6+1] =  0.0;
125       j[6+0] =  0.0;
126       j[6+1] = -1.0;
127       invj[6+0] =  0.0; invj[6+1] = -1.0;
128       dj[3]  = 1.0;
129     }
130     break;
131   default:
132     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %s", CellRefiners[refiner]);
133   }
134   if (v0)     {*v0     = v;}
135   else        {ierr = PetscFree(v);CHKERRQ(ierr);}
136   if (jac)    {*jac    = j;}
137   else        {ierr = PetscFree(j);CHKERRQ(ierr);}
138   if (invjac) {*invjac = invj;}
139   else        {ierr = PetscFree(invj);CHKERRQ(ierr);}
140   if (invjac) {*invjac = invj;}
141   else        {ierr = PetscFree(invj);CHKERRQ(ierr);}
142   if (detj)   {*detj   = dj;}
143   else        {ierr = PetscFree(dj);CHKERRQ(ierr);}
144   PetscFunctionReturn(0);
145 }
146 
147 /* Gets the affine map from the original cell to each subcell */
148 PetscErrorCode CellRefinerGetAffineTransforms_Internal(CellRefiner refiner, PetscInt *numSubcells, PetscReal *v0[], PetscReal *jac[], PetscReal *invjac[])
149 {
150   PetscReal     *v = NULL, *j = NULL, *invj = NULL, detJ;
151   PetscInt       dim, s;
152   PetscErrorCode ierr;
153 
154   PetscFunctionBegin;
155   switch (refiner) {
156   case REFINER_NOOP: break;
157   case REFINER_SIMPLEX_2D:
158     /*
159      2
160      |\
161      | \
162      |  \
163      |   \
164      | C  \
165      |     \
166      |      \
167      2---1---1
168      |\  D  / \
169      | 2   0   \
170      |A \ /  B  \
171      0---0-------1
172      */
173     dim = 2;
174     if (numSubcells) *numSubcells = 4;
175     if (v0) {
176       ierr = PetscMalloc3(4*dim,&v,4*dim*dim,&j,4*dim*dim,&invj);CHKERRQ(ierr);
177       /* A */
178       v[0+0] = -1.0; v[0+1] = -1.0;
179       j[0+0] =  0.5; j[0+1] =  0.0;
180       j[0+2] =  0.0; j[0+3] =  0.5;
181       /* B */
182       v[2+0] =  0.0; v[2+1] = -1.0;
183       j[4+0] =  0.5; j[4+1] =  0.0;
184       j[4+2] =  0.0; j[4+3] =  0.5;
185       /* C */
186       v[4+0] = -1.0; v[4+1] =  0.0;
187       j[8+0] =  0.5; j[8+1] =  0.0;
188       j[8+2] =  0.0; j[8+3] =  0.5;
189       /* D */
190       v[6+0]  =  0.0; v[6+1]  = -1.0;
191       j[12+0] =  0.0; j[12+1] = -0.5;
192       j[12+2] =  0.5; j[12+3] =  0.5;
193       for (s = 0; s < 4; ++s) {
194         DMPlex_Det2D_Internal(&detJ, &j[s*dim*dim]);
195         DMPlex_Invert2D_Internal(&invj[s*dim*dim], &j[s*dim*dim], detJ);
196       }
197     }
198     break;
199   case REFINER_HEX_2D:
200     /*
201      3---------2---------2
202      |         |         |
203      |    D    2    C    |
204      |         |         |
205      3----3----0----1----1
206      |         |         |
207      |    A    0    B    |
208      |         |         |
209      0---------0---------1
210      */
211     dim = 2;
212     if (numSubcells) *numSubcells = 4;
213     if (v0) {
214       ierr = PetscMalloc3(4*dim,&v,4*dim*dim,&j,4*dim*dim,&invj);CHKERRQ(ierr);
215       /* A */
216       v[0+0] = -1.0; v[0+1] = -1.0;
217       j[0+0] =  0.5; j[0+1] =  0.0;
218       j[0+2] =  0.0; j[0+3] =  0.5;
219       /* B */
220       v[2+0] =  0.0; v[2+1] = -1.0;
221       j[4+0] =  0.5; j[4+1] =  0.0;
222       j[4+2] =  0.0; j[4+3] =  0.5;
223       /* C */
224       v[4+0] =  0.0; v[4+1] =  0.0;
225       j[8+0] =  0.5; j[8+1] =  0.0;
226       j[8+2] =  0.0; j[8+3] =  0.5;
227       /* D */
228       v[6+0]  = -1.0; v[6+1]  =  0.0;
229       j[12+0] =  0.5; j[12+1] =  0.0;
230       j[12+2] =  0.0; j[12+3] =  0.5;
231       for (s = 0; s < 4; ++s) {
232         DMPlex_Det2D_Internal(&detJ, &j[s*dim*dim]);
233         DMPlex_Invert2D_Internal(&invj[s*dim*dim], &j[s*dim*dim], detJ);
234       }
235     }
236     break;
237   case REFINER_HEX_3D:
238     /*
239      Bottom (viewed from top)    Top
240      1---------2---------2       7---------2---------6
241      |         |         |       |         |         |
242      |    B    2    C    |       |    H    2    G    |
243      |         |         |       |         |         |
244      3----3----0----1----1       3----3----0----1----1
245      |         |         |       |         |         |
246      |    A    0    D    |       |    E    0    F    |
247      |         |         |       |         |         |
248      0---------0---------3       4---------0---------5
249      */
250     break;
251     dim = 3;
252     if (numSubcells) *numSubcells = 8;
253     if (v0) {
254       ierr = PetscMalloc3(4*dim,&v,4*dim*dim,&j,4*dim*dim,&invj);CHKERRQ(ierr);
255       /* A */
256       v[0+0] = -1.0; v[0+1] = -1.0; v[0+2] = -1.0;
257       j[0+0] =  0.5; j[0+1] =  0.0; j[0+2] =  0.0;
258       j[0+3] =  0.0; j[0+4] =  0.5; j[0+5] =  0.0;
259       j[0+6] =  0.0; j[0+7] =  0.0; j[0+8] =  0.5;
260       /* B */
261       v[3+0] = -1.0; v[3+1] =  0.0; v[3+2] = -1.0;
262       j[9+0] =  0.5; j[9+1] =  0.0; j[9+2] =  0.0;
263       j[9+3] =  0.0; j[9+4] =  0.5; j[9+5] =  0.0;
264       j[9+6] =  0.0; j[9+7] =  0.0; j[9+8] =  0.5;
265       /* C */
266       v[6+0] =  0.0; v[6+1] =  0.0; v[6+2] = -1.0;
267       j[18+0] = 0.5; j[18+1] = 0.0; j[18+2] = 0.0;
268       j[18+3] = 0.0; j[18+4] = 0.5; j[18+5] = 0.0;
269       j[18+6] = 0.0; j[18+7] = 0.0; j[18+8] = 0.5;
270       /* D */
271       v[9+0] =  0.0; v[9+1] = -1.0; v[9+2] = -1.0;
272       j[27+0] = 0.5; j[27+1] = 0.0; j[27+2] = 0.0;
273       j[27+3] = 0.0; j[27+4] = 0.5; j[27+5] = 0.0;
274       j[27+6] = 0.0; j[27+7] = 0.0; j[27+8] = 0.5;
275       /* E */
276       v[12+0] = -1.0; v[12+1] = -1.0; v[12+2] =  0.0;
277       j[36+0] =  0.5; j[36+1] =  0.0; j[36+2] =  0.0;
278       j[36+3] =  0.0; j[36+4] =  0.5; j[36+5] =  0.0;
279       j[36+6] =  0.0; j[36+7] =  0.0; j[36+8] =  0.5;
280       /* F */
281       v[15+0] =  0.0; v[15+1] = -1.0; v[15+2] =  0.0;
282       j[45+0] =  0.5; j[45+1] =  0.0; j[45+2] =  0.0;
283       j[45+3] =  0.0; j[45+4] =  0.5; j[45+5] =  0.0;
284       j[45+6] =  0.0; j[45+7] =  0.0; j[45+8] =  0.5;
285       /* G */
286       v[18+0] =  0.0; v[18+1] =  0.0; v[18+2] =  0.0;
287       j[54+0] =  0.5; j[54+1] =  0.0; j[54+2] =  0.0;
288       j[54+3] =  0.0; j[54+4] =  0.5; j[54+5] =  0.0;
289       j[54+6] =  0.0; j[54+7] =  0.0; j[54+8] =  0.5;
290       /* H */
291       v[21+0] = -1.0; v[21+1] =  0.0; v[21+2] =  0.0;
292       j[63+0] =  0.5; j[63+1] =  0.0; j[63+2] =  0.0;
293       j[63+3] =  0.0; j[63+4] =  0.5; j[63+5] =  0.0;
294       j[63+6] =  0.0; j[63+7] =  0.0; j[63+8] =  0.5;
295       for (s = 0; s < 8; ++s) {
296         DMPlex_Det3D_Internal(&detJ, &j[s*dim*dim]);
297         DMPlex_Invert3D_Internal(&invj[s*dim*dim], &j[s*dim*dim], detJ);
298       }
299     }
300   default:
301     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %s", CellRefiners[refiner]);
302   }
303   if (v0) {*v0 = v; *jac = j; *invjac = invj;}
304   PetscFunctionReturn(0);
305 }
306 
307 PetscErrorCode CellRefinerRestoreAffineTransforms_Internal(CellRefiner refiner, PetscInt *numSubcells, PetscReal *v0[], PetscReal *jac[], PetscReal *invjac[])
308 {
309   PetscErrorCode ierr;
310 
311   PetscFunctionBegin;
312   ierr = PetscFree3(*v0,*jac,*invjac);CHKERRQ(ierr);
313   PetscFunctionReturn(0);
314 }
315 
316 /* Should this be here or in the DualSpace somehow? */
317 PetscErrorCode CellRefinerInCellTest_Internal(CellRefiner refiner, const PetscReal point[], PetscBool *inside)
318 {
319   PetscReal sum = 0.0;
320   PetscInt  d;
321 
322   PetscFunctionBegin;
323   *inside = PETSC_TRUE;
324   switch (refiner) {
325   case REFINER_NOOP: break;
326   case REFINER_SIMPLEX_2D:
327     for (d = 0; d < 2; ++d) {
328       if (point[d] < -1.0) {*inside = PETSC_FALSE; break;}
329       sum += point[d];
330     }
331     if (sum > 1.0e-10) {*inside = PETSC_FALSE; break;}
332     break;
333   case REFINER_HEX_2D:
334     for (d = 0; d < 2; ++d) if ((point[d] < -1.00000000001) || (point[d] > 1.000000000001)) {*inside = PETSC_FALSE; break;}
335     break;
336   default:
337     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %s", CellRefiners[refiner]);
338   }
339   PetscFunctionReturn(0);
340 }
341 
342 static PetscErrorCode CellRefinerGetSizes(CellRefiner refiner, DM dm, PetscInt depthSize[])
343 {
344   PetscInt       cStart, cEnd, cMax, vStart, vEnd, vMax, fStart, fEnd, fMax, eStart, eEnd, eMax;
345   PetscErrorCode ierr;
346 
347   PetscFunctionBegin;
348   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
349   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
350   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
351   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
352   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
353   switch (refiner) {
354   case REFINER_NOOP:
355     break;
356   case REFINER_SIMPLEX_1D:
357     depthSize[0] = vEnd - vStart + cEnd - cStart;         /* Add a vertex on every cell. */
358     depthSize[1] = 2*(cEnd - cStart);                     /* Split every cell in 2. */
359     break;
360   case REFINER_SIMPLEX_2D:
361     depthSize[0] = vEnd - vStart + fEnd - fStart;         /* Add a vertex on every face */
362     depthSize[1] = 2*(fEnd - fStart) + 3*(cEnd - cStart); /* Every face is split into 2 faces and 3 faces are added for each cell */
363     depthSize[2] = 4*(cEnd - cStart);                     /* Every cell split into 4 cells */
364     break;
365   case REFINER_HYBRID_SIMPLEX_2D:
366     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
367     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
368     depthSize[0] = vEnd - vStart + fMax - fStart;                                         /* Add a vertex on every face, but not hybrid faces */
369     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 */
370     depthSize[2] = 4*(cMax - cStart) + 2*(cEnd - cMax);                                   /* Interior cells split into 4 cells, hybrid cells split into 2 cells */
371     break;
372   case REFINER_SIMPLEX_TO_HEX_2D:
373     depthSize[0] = vEnd - vStart + fEnd - fStart + cEnd - cStart; /* Add a vertex on every face and cell */
374     depthSize[1] = 2*(fEnd - fStart) + 3*(cEnd - cStart);         /* Every face is split into 2 faces and 3 faces are added for each cell */
375     depthSize[2] = 3*(cEnd - cStart);                             /* Every cell split into 3 cells */
376     break;
377   case REFINER_HYBRID_SIMPLEX_TO_HEX_2D:
378     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
379     depthSize[0] = vEnd - vStart + fEnd - fStart + cEnd - cStart;           /* Add a vertex on every face and cell */
380     depthSize[1] = 2*(fEnd - fStart) + 3*(cMax - cStart) + 4*(cEnd - cMax); /* Every face is split into 2 faces and 3 faces are added for each cell. 4 for each hybrid cell */
381     depthSize[2] = 3*(cMax - cStart) + 4*(cEnd - cMax);                     /* Every cell split into 3 cells, hybrid cells split in 4 */
382     break;
383   case REFINER_HEX_2D:
384     depthSize[0] = vEnd - vStart + fEnd - fStart + cEnd - cStart; /* Add a vertex on every face and cell */
385     depthSize[1] = 2*(fEnd - fStart) + 4*(cEnd - cStart);         /* Every face is split into 2 faces and 4 faces are added for each cell */
386     depthSize[2] = 4*(cEnd - cStart);                             /* Every cell split into 4 cells */
387     break;
388   case REFINER_HYBRID_HEX_2D:
389     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
390     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
391     /* Quadrilateral */
392     depthSize[0] = vEnd - vStart + fMax - fStart + cMax - cStart;                 /* Add a vertex on every face and cell */
393     depthSize[1] = 2*(fMax - fStart) + 4*(cMax - cStart);                         /* Every face is split into 2 faces, and 4 faces are added for each cell */
394     depthSize[2] = 4*(cMax - cStart);                                             /* Every cell split into 4 cells */
395     /* Segment Prisms */
396     depthSize[0] += 0;                                                            /* No hybrid vertices */
397     depthSize[1] +=   (fEnd - fMax)  +   (cEnd - cMax);                           /* Every hybrid face remains and 1 faces is added for each hybrid cell */
398     depthSize[2] += 2*(cEnd - cMax);                                              /* Every hybrid cell split into 2 cells */
399     break;
400   case REFINER_SIMPLEX_3D:
401     depthSize[0] =    vEnd - vStart  +    eEnd - eStart;                    /* Add a vertex on every edge */
402     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 */
403     depthSize[2] = 4*(fEnd - fStart) + 8*(cEnd - cStart);                   /* Every face split into 4 faces and 8 faces are added for each cell */
404     depthSize[3] = 8*(cEnd - cStart);                                       /* Every cell split into 8 cells */
405     break;
406   case REFINER_HYBRID_SIMPLEX_3D:
407     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
408     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
409     if (eMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No edge maximum specified in hybrid mesh");
410     /* Tetrahedra */
411     depthSize[0]  =    vEnd - vStart  +    eMax - eStart;                    /* Add a vertex on every interior edge */
412     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 */
413     depthSize[2]  = 4*(fMax - fStart) + 8*(cMax - cStart);                   /* Every interior face split into 4 faces, 8 faces added for each interior cell */
414     depthSize[3]  = 8*(cMax - cStart);                                       /* Every interior cell split into 8 cells */
415     /* Triangular Prisms */
416     depthSize[0] += 0;                                                       /* No hybrid vertices */
417     depthSize[1] +=   (eEnd - eMax)   +   (fEnd - fMax);                     /* Every hybrid edge remains, 1 edge for every hybrid face */
418     depthSize[2] += 2*(fEnd - fMax)   + 3*(cEnd - cMax);                     /* Every hybrid face split into 2 faces and 3 faces are added for each hybrid cell */
419     depthSize[3] += 4*(cEnd - cMax);                                         /* Every hybrid cell split into 4 cells */
420     break;
421   case REFINER_SIMPLEX_TO_HEX_3D:
422     depthSize[0] = vEnd - vStart + fEnd - fStart + eEnd - eStart + cEnd - cStart; /* Add a vertex on every face, edge and cell */
423     depthSize[1] = 2*(eEnd - eStart) + 3*(fEnd - fStart) + 4*(cEnd - cStart);     /* Every edge is split into 2 edges, 3 edges are added for each face, and 4 for each cell */
424     depthSize[2] = 3*(fEnd - fStart) + 6*(cEnd - cStart);                         /* Every face is split into 3 faces and 6 faces are added for each cell */
425     depthSize[3] = 4*(cEnd - cStart);                                             /* Every cell split into 4 cells */
426     break;
427   case REFINER_HYBRID_SIMPLEX_TO_HEX_3D:
428     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
429     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
430     if (eMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No edge maximum specified in hybrid mesh");
431     /* Tetrahedra */
432     depthSize[0]  =    vEnd - vStart  +    eMax - eStart  + fMax - fStart + cMax - cStart; /* Add a vertex on every interior edge, face and cell */
433     depthSize[1]  = 2*(eMax - eStart) + 3*(fMax - fStart) + 4*(cMax - cStart);             /* Every interior edge split into 2 edges, 3 edges added for each interior face, 4 edges for each interior cell */
434     depthSize[2]  = 3*(fMax - fStart) + 6*(cMax - cStart);                                 /* Every interior face split into 3 faces, 6 faces added for each interior cell */
435     depthSize[3]  = 4*(cMax - cStart);                                                     /* Every interior cell split into 8 cells */
436     /* Triangular Prisms */
437     depthSize[0] += 0;                                                 /* No hybrid vertices */
438     depthSize[1] +=   (eEnd - eMax) +   (fEnd - fMax) + (cEnd - cMax); /* Every hybrid edge remains, 1 edge for every hybrid face and cell */
439     depthSize[2] += 2*(fEnd - fMax) + 3*(cEnd - cMax);                 /* Every hybrid face split into 2 faces and 3 faces are added for each hybrid cell */
440     depthSize[3] += 3*(cEnd - cMax);                                   /* Every hybrid cell split into 3 cells */
441     break;
442   case REFINER_HEX_3D:
443     depthSize[0] = vEnd - vStart + eEnd - eStart + fEnd - fStart + cEnd - cStart; /* Add a vertex on every edge, face and cell */
444     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 */
445     depthSize[2] = 4*(fEnd - fStart) + 12*(cEnd - cStart);                        /* Every face is split into 4 faces, and 12 faces are added for each cell */
446     depthSize[3] = 8*(cEnd - cStart);                                             /* Every cell split into 8 cells */
447     break;
448   case REFINER_HYBRID_HEX_3D:
449     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
450     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
451     if (eMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No edge maximum specified in hybrid mesh");
452     /* Hexahedra */
453     depthSize[0] = vEnd - vStart + eMax - eStart + fMax - fStart + cMax - cStart; /* Add a vertex on every edge, face and cell */
454     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 */
455     depthSize[2] = 4*(fMax - fStart) + 12*(cMax - cStart);                        /* Every face is split into 4 faces, and 12 faces are added for each cell */
456     depthSize[3] = 8*(cMax - cStart);                                             /* Every cell split into 8 cells */
457     /* Quadrilateral Prisms */
458     depthSize[0] += 0;                                                            /* No hybrid vertices */
459     depthSize[1] +=   (eEnd - eMax)   +   (fEnd - fMax)   +   (cEnd - cMax);      /* Every hybrid edge remains, 1 edge for every hybrid face and hybrid cell */
460     depthSize[2] += 2*(fEnd - fMax)   + 4*(cEnd - cMax);                          /* Every hybrid face split into 2 faces and 4 faces are added for each hybrid cell */
461     depthSize[3] += 4*(cEnd - cMax);                                              /* Every hybrid cell split into 4 cells */
462     break;
463   default:
464     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %s", CellRefiners[refiner]);
465   }
466   PetscFunctionReturn(0);
467 }
468 
469 /* Return triangle edge for orientation o, if it is r for o == 0 */
470 PETSC_STATIC_INLINE PetscInt GetTriEdge_Static(PetscInt o, PetscInt r) {
471   return (o < 0 ? 2-(o+r) : o+r)%3;
472 }
473 PETSC_STATIC_INLINE PetscInt GetTriEdgeInverse_Static(PetscInt o, PetscInt s) {
474   return (o < 0 ? 2-(o+s) : 3+s-o)%3;
475 }
476 
477 /* Return triangle subface for orientation o, if it is r for o == 0 */
478 PETSC_STATIC_INLINE PetscInt GetTriSubface_Static(PetscInt o, PetscInt r) {
479   return (o < 0 ? 3-(o+r) : o+r)%3;
480 }
481 PETSC_STATIC_INLINE PetscInt GetTriSubfaceInverse_Static(PetscInt o, PetscInt s) {
482   return (o < 0 ? 3-(o+s) : 3+s-o)%3;
483 }
484 
485 /* Return the interior edge number connecting the midpoints of the triangle edges r
486    and r+1 in the transitive closure for triangle orientation o */
487 PETSC_STATIC_INLINE PetscInt GetTriMidEdge_Static(PetscInt o, PetscInt r) {
488   return (o < 0 ? 1-(o+r) : o+r)%3;
489 }
490 PETSC_STATIC_INLINE PetscInt GetTriMidEdgeInverse_Static(PetscInt o, PetscInt s) {
491   return (o < 0 ? 1-(o+s) : 3+s-o)%3;
492 }
493 
494 /* Return the interior edge number connecting the midpoint of the triangle edge r
495    (in the transitive closure) and the vertex in the interior of the face for triangle orientation o */
496 PETSC_STATIC_INLINE PetscInt GetTriInteriorEdge_Static(PetscInt o, PetscInt r) {
497   return (o < 0 ? 2-(o+r) : o+r)%3;
498 }
499 PETSC_STATIC_INLINE PetscInt GetTriInteriorEdgeInverse_Static(PetscInt o, PetscInt s) {
500   return (o < 0 ? 2-(o+s) : 3+s-o)%3;
501 }
502 
503 /* Return quad edge for orientation o, if it is r for o == 0 */
504 PETSC_STATIC_INLINE PetscInt GetQuadEdge_Static(PetscInt o, PetscInt r) {
505   return (o < 0 ? 3-(o+r) : o+r)%4;
506 }
507 PETSC_STATIC_INLINE PetscInt GetQuadEdgeInverse_Static(PetscInt o, PetscInt s) {
508   return (o < 0 ? 3-(o+s) : 4+s-o)%4;
509 }
510 
511 /* Return quad subface for orientation o, if it is r for o == 0 */
512 PETSC_STATIC_INLINE PetscInt GetQuadSubface_Static(PetscInt o, PetscInt r) {
513   return (o < 0 ? 4-(o+r) : o+r)%4;
514 }
515 PETSC_STATIC_INLINE PetscInt GetQuadSubfaceInverse_Static(PetscInt o, PetscInt s) {
516   return (o < 0 ? 4-(o+s) : 4+s-o)%4;
517 }
518 
519 static PetscErrorCode DMLabelSetStratumBounds(DMLabel label, PetscInt value, PetscInt cStart, PetscInt cEnd)
520 {
521   IS             cIS;
522   PetscErrorCode ierr;
523 
524   PetscFunctionBegin;
525   ierr = ISCreateStride(PETSC_COMM_SELF, cEnd - cStart, cStart, 1, &cIS);CHKERRQ(ierr);
526   ierr = DMLabelSetStratumIS(label, value, cIS);CHKERRQ(ierr);
527   ierr = ISDestroy(&cIS);CHKERRQ(ierr);
528   PetscFunctionReturn(0);
529 }
530 
531 static PetscErrorCode CellRefinerSetConeSizes(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
532 {
533   PetscInt       depth, cStart, cStartNew, cEnd, cEndNew, cMax, c, vStart, vStartNew, vEnd, vEndNew, vMax, v, fStart, fStartNew, fEnd, fEndNew, fMax, f, eStart, eStartNew, eEnd, eEndNew, eMax, e, r;
534   DMLabel        depthLabel;
535   PetscErrorCode ierr;
536 
537   PetscFunctionBegin;
538   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
539   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
540   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
541   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
542   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
543   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
544   ierr = GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);CHKERRQ(ierr);
545   ierr = GetDepthEnd_Private(depth, depthSize, &cEndNew, &fEndNew, &eEndNew, &vEndNew);CHKERRQ(ierr);
546   ierr = DMCreateLabel(rdm,"depth");CHKERRQ(ierr);
547   ierr = DMPlexGetDepthLabel(rdm,&depthLabel);CHKERRQ(ierr);
548   ierr = DMLabelSetStratumBounds(depthLabel, 0, vStartNew, vEndNew);CHKERRQ(ierr);
549   if (depth > 2) ierr = DMLabelSetStratumBounds(depthLabel, 1, eStartNew, eEndNew);CHKERRQ(ierr);
550   if (depth > 1) ierr = DMLabelSetStratumBounds(depthLabel, depth - 1, fStartNew, fEndNew);CHKERRQ(ierr);
551   if (depth > 0) ierr = DMLabelSetStratumBounds(depthLabel, depth, cStartNew, cEndNew);CHKERRQ(ierr);
552   {
553     DM_Plex *plex = (DM_Plex *) rdm->data;
554     ierr = PetscObjectStateGet((PetscObject) depthLabel, &plex->depthState);CHKERRQ(ierr);
555   }
556   if (!refiner) PetscFunctionReturn(0);
557   switch (refiner) {
558   case REFINER_SIMPLEX_1D:
559     /* All cells have 2 vertices */
560     for (c = cStart; c < cEnd; ++c) {
561       for (r = 0; r < 2; ++r) {
562         const PetscInt newp = cStartNew + (c - cStart)*2 + r;
563 
564         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
565       }
566     }
567     /* Old vertices have identical supports */
568     for (v = vStart; v < vEnd; ++v) {
569       const PetscInt newp = vStartNew + (v - vStart);
570       PetscInt       size;
571 
572       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
573       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
574     }
575     /* Cell vertices have support 2 */
576     for (c = cStart; c < cEnd; ++c) {
577       const PetscInt newp = vStartNew + (vEnd - vStart) + (c - cStart);
578 
579       ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
580     }
581     break;
582   case REFINER_SIMPLEX_2D:
583     /* All cells have 3 faces */
584     for (c = cStart; c < cEnd; ++c) {
585       for (r = 0; r < 4; ++r) {
586         const PetscInt newp = (c - cStart)*4 + r;
587 
588         ierr = DMPlexSetConeSize(rdm, newp, 3);CHKERRQ(ierr);
589       }
590     }
591     /* Split faces have 2 vertices and the same cells as the parent */
592     for (f = fStart; f < fEnd; ++f) {
593       for (r = 0; r < 2; ++r) {
594         const PetscInt newp = fStartNew + (f - fStart)*2 + r;
595         PetscInt       size;
596 
597         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
598         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
599         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
600       }
601     }
602     /* Interior faces have 2 vertices and 2 cells */
603     for (c = cStart; c < cEnd; ++c) {
604       for (r = 0; r < 3; ++r) {
605         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*3 + r;
606 
607         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
608         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
609       }
610     }
611     /* Old vertices have identical supports */
612     for (v = vStart; v < vEnd; ++v) {
613       const PetscInt newp = vStartNew + (v - vStart);
614       PetscInt       size;
615 
616       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
617       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
618     }
619     /* Face vertices have 2 + cells*2 supports */
620     for (f = fStart; f < fEnd; ++f) {
621       const PetscInt newp = vStartNew + (vEnd - vStart) + (f - fStart);
622       PetscInt       size;
623 
624       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
625       ierr = DMPlexSetSupportSize(rdm, newp, 2 + size*2);CHKERRQ(ierr);
626     }
627     break;
628   case REFINER_SIMPLEX_TO_HEX_2D:
629     /* All cells have 4 faces */
630     for (c = cStart; c < cEnd; ++c) {
631       for (r = 0; r < 3; ++r) {
632         const PetscInt newp = (c - cStart)*3 + r;
633 
634         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
635       }
636     }
637     /* Split faces have 2 vertices and the same cells as the parent */
638     for (f = fStart; f < fEnd; ++f) {
639       for (r = 0; r < 2; ++r) {
640         const PetscInt newp = fStartNew + (f - fStart)*2 + r;
641         PetscInt       size;
642 
643         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
644         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
645         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
646       }
647     }
648     /* Interior faces have 2 vertices and 2 cells */
649     for (c = cStart; c < cEnd; ++c) {
650       for (r = 0; r < 3; ++r) {
651         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*3 + r;
652 
653         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
654         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
655       }
656     }
657     /* Old vertices have identical supports */
658     for (v = vStart; v < vEnd; ++v) {
659       const PetscInt newp = vStartNew + (v - vStart);
660       PetscInt       size;
661 
662       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
663       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
664     }
665     /* Split-face vertices have cells + 2 supports */
666     for (f = fStart; f < fEnd; ++f) {
667       const PetscInt newp = vStartNew + (vEnd - vStart) + (f - fStart);
668       PetscInt       size;
669 
670       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
671       ierr = DMPlexSetSupportSize(rdm, newp, size + 2);CHKERRQ(ierr);
672     }
673     /* Interior vertices have 3 supports */
674     for (c = cStart; c < cEnd; ++c) {
675       const PetscInt newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + c - cStart;
676 
677       ierr = DMPlexSetSupportSize(rdm, newp, 3);CHKERRQ(ierr);
678     }
679     break;
680   case REFINER_HYBRID_SIMPLEX_TO_HEX_2D:
681     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
682     /* the mesh is no longer hybrid */
683     cMax = PetscMin(cEnd, cMax);
684     /* All cells have 4 faces */
685     for (c = cStart; c < cMax; ++c) {
686       for (r = 0; r < 3; ++r) {
687         const PetscInt newp = (c - cStart)*3 + r;
688 
689         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
690       }
691     }
692     for (c = cMax; c < cEnd; ++c) {
693       for (r = 0; r < 4; ++r) {
694         const PetscInt newp = (cMax - cStart)*3 + (c - cMax)*4 + r;
695 
696         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
697       }
698     }
699     /* Split faces have 2 vertices and the same cells as the parent */
700     for (f = fStart; f < fEnd; ++f) {
701       for (r = 0; r < 2; ++r) {
702         const PetscInt newp = fStartNew + (f - fStart)*2 + r;
703         PetscInt       size;
704 
705         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
706         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
707         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
708       }
709     }
710     /* Interior faces have 2 vertices and 2 cells */
711     for (c = cStart; c < cMax; ++c) {
712       for (r = 0; r < 3; ++r) {
713         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*3 + r;
714 
715         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
716         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
717       }
718     }
719     /* Hybrid interior faces have 2 vertices and 2 cells */
720     for (c = cMax; c < cEnd; ++c) {
721       for (r = 0; r < 4; ++r) {
722         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (cMax - cStart)*3 + (c - cMax)*4 + r;
723 
724         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
725         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
726       }
727     }
728     /* Old vertices have identical supports */
729     for (v = vStart; v < vEnd; ++v) {
730       const PetscInt newp = vStartNew + (v - vStart);
731       PetscInt       size;
732 
733       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
734       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
735     }
736     /* Split-face vertices have cells + 2 supports */
737     for (f = fStart; f < fEnd; ++f) {
738       const PetscInt newp = vStartNew + (vEnd - vStart) + (f - fStart);
739       PetscInt       size;
740 
741       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
742       ierr = DMPlexSetSupportSize(rdm, newp, size + 2);CHKERRQ(ierr);
743     }
744     /* Interior vertices have 3 supports */
745     for (c = cStart; c < cMax; ++c) {
746       const PetscInt newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + c - cStart;
747 
748       ierr = DMPlexSetSupportSize(rdm, newp, 3);CHKERRQ(ierr);
749     }
750     /* Hybrid interior vertices have 4 supports */
751     for (c = cMax; c < cEnd; ++c) {
752       const PetscInt newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + c - cStart;
753 
754       ierr = DMPlexSetSupportSize(rdm, newp, 4);CHKERRQ(ierr);
755     }
756     break;
757   case REFINER_HEX_2D:
758     /* All cells have 4 faces */
759     for (c = cStart; c < cEnd; ++c) {
760       for (r = 0; r < 4; ++r) {
761         const PetscInt newp = cStartNew + (c - cStart)*4 + r;
762 
763         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
764       }
765     }
766     /* Split faces have 2 vertices and the same cells as the parent */
767     for (f = fStart; f < fEnd; ++f) {
768       for (r = 0; r < 2; ++r) {
769         const PetscInt newp = fStartNew + (f - fStart)*2 + r;
770         PetscInt       size;
771 
772         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
773         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
774         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
775       }
776     }
777     /* Interior faces have 2 vertices and 2 cells */
778     for (c = cStart; c < cEnd; ++c) {
779       for (r = 0; r < 4; ++r) {
780         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*4 + r;
781 
782         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
783         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
784       }
785     }
786     /* Old vertices have identical supports */
787     for (v = vStart; v < vEnd; ++v) {
788       const PetscInt newp = vStartNew + (v - vStart);
789       PetscInt       size;
790 
791       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
792       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
793     }
794     /* Face vertices have 2 + cells supports */
795     for (f = fStart; f < fEnd; ++f) {
796       const PetscInt newp = vStartNew + (vEnd - vStart) + (f - fStart);
797       PetscInt       size;
798 
799       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
800       ierr = DMPlexSetSupportSize(rdm, newp, 2 + size);CHKERRQ(ierr);
801     }
802     /* Cell vertices have 4 supports */
803     for (c = cStart; c < cEnd; ++c) {
804       const PetscInt newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (c - cStart);
805 
806       ierr = DMPlexSetSupportSize(rdm, newp, 4);CHKERRQ(ierr);
807     }
808     break;
809   case REFINER_HYBRID_SIMPLEX_2D:
810     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
811     cMax = PetscMin(cEnd, cMax);
812     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
813     fMax = PetscMin(fEnd, fMax);
814     ierr = DMPlexSetHybridBounds(rdm, cStartNew + (cMax - cStart)*4, fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3, PETSC_DETERMINE, PETSC_DETERMINE);CHKERRQ(ierr);
815     /* Interior cells have 3 faces */
816     for (c = cStart; c < cMax; ++c) {
817       for (r = 0; r < 4; ++r) {
818         const PetscInt newp = cStartNew + (c - cStart)*4 + r;
819 
820         ierr = DMPlexSetConeSize(rdm, newp, 3);CHKERRQ(ierr);
821       }
822     }
823     /* Hybrid cells have 4 faces */
824     for (c = cMax; c < cEnd; ++c) {
825       for (r = 0; r < 2; ++r) {
826         const PetscInt newp = cStartNew + (cMax - cStart)*4 + (c - cMax)*2 + r;
827 
828         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
829       }
830     }
831     /* Interior split faces have 2 vertices and the same cells as the parent */
832     for (f = fStart; f < fMax; ++f) {
833       for (r = 0; r < 2; ++r) {
834         const PetscInt newp = fStartNew + (f - fStart)*2 + r;
835         PetscInt       size;
836 
837         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
838         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
839         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
840       }
841     }
842     /* Interior cell faces have 2 vertices and 2 cells */
843     for (c = cStart; c < cMax; ++c) {
844       for (r = 0; r < 3; ++r) {
845         const PetscInt newp = fStartNew + (fMax - fStart)*2 + (c - cStart)*3 + r;
846 
847         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
848         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
849       }
850     }
851     /* Hybrid faces have 2 vertices and the same cells */
852     for (f = fMax; f < fEnd; ++f) {
853       const PetscInt newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (f - fMax);
854       PetscInt       size;
855 
856       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
857       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
858       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
859     }
860     /* Hybrid cell faces have 2 vertices and 2 cells */
861     for (c = cMax; c < cEnd; ++c) {
862       const PetscInt newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (fEnd - fMax) + (c - cMax);
863 
864       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
865       ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
866     }
867     /* Old vertices have identical supports */
868     for (v = vStart; v < vEnd; ++v) {
869       const PetscInt newp = vStartNew + (v - vStart);
870       PetscInt       size;
871 
872       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
873       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
874     }
875     /* Face vertices have 2 + (2 interior, 1 hybrid) supports */
876     for (f = fStart; f < fMax; ++f) {
877       const PetscInt newp = vStartNew + (vEnd - vStart) + (f - fStart);
878       const PetscInt *support;
879       PetscInt       size, newSize = 2, s;
880 
881       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
882       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
883       for (s = 0; s < size; ++s) {
884         if (support[s] >= cMax) newSize += 1;
885         else newSize += 2;
886       }
887       ierr = DMPlexSetSupportSize(rdm, newp, newSize);CHKERRQ(ierr);
888     }
889     break;
890   case REFINER_HYBRID_HEX_2D:
891     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
892     cMax = PetscMin(cEnd, cMax);
893     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
894     fMax = PetscMin(fEnd, fMax);
895     ierr = DMPlexSetHybridBounds(rdm, cStartNew + (cMax - cStart)*4, fStartNew + (fMax - fStart)*2 + (cMax - cStart)*4, PETSC_DETERMINE, PETSC_DETERMINE);CHKERRQ(ierr);
896     /* Interior cells have 4 faces */
897     for (c = cStart; c < cMax; ++c) {
898       for (r = 0; r < 4; ++r) {
899         const PetscInt newp = cStartNew + (c - cStart)*4 + r;
900 
901         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
902       }
903     }
904     /* Hybrid cells have 4 faces */
905     for (c = cMax; c < cEnd; ++c) {
906       for (r = 0; r < 2; ++r) {
907         const PetscInt newp = cStartNew + (cMax - cStart)*4 + (c - cMax)*2 + r;
908 
909         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
910       }
911     }
912     /* Interior split faces have 2 vertices and the same cells as the parent */
913     for (f = fStart; f < fMax; ++f) {
914       for (r = 0; r < 2; ++r) {
915         const PetscInt newp = fStartNew + (f - fStart)*2 + r;
916         PetscInt       size;
917 
918         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
919         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
920         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
921       }
922     }
923     /* Interior cell faces have 2 vertices and 2 cells */
924     for (c = cStart; c < cMax; ++c) {
925       for (r = 0; r < 4; ++r) {
926         const PetscInt newp = fStartNew + (fMax - fStart)*2 + (c - cStart)*4 + r;
927 
928         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
929         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
930       }
931     }
932     /* Hybrid faces have 2 vertices and the same cells */
933     for (f = fMax; f < fEnd; ++f) {
934       const PetscInt newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*4 + (f - fMax);
935       PetscInt       size;
936 
937       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
938       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
939       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
940     }
941     /* Hybrid cell faces have 2 vertices and 2 cells */
942     for (c = cMax; c < cEnd; ++c) {
943       const PetscInt newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*4 + (fEnd - fMax) + (c - cMax);
944 
945       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
946       ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
947     }
948     /* Old vertices have identical supports */
949     for (v = vStart; v < vEnd; ++v) {
950       const PetscInt newp = vStartNew + (v - vStart);
951       PetscInt       size;
952 
953       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
954       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
955     }
956     /* Face vertices have 2 + cells supports */
957     for (f = fStart; f < fMax; ++f) {
958       const PetscInt newp = vStartNew + (vEnd - vStart) + (f - fStart);
959       PetscInt       size;
960 
961       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
962       ierr = DMPlexSetSupportSize(rdm, newp, 2 + size);CHKERRQ(ierr);
963     }
964     /* Cell vertices have 4 supports */
965     for (c = cStart; c < cMax; ++c) {
966       const PetscInt newp = vStartNew + (vEnd - vStart) + (fMax - fStart) + (c - cStart);
967 
968       ierr = DMPlexSetSupportSize(rdm, newp, 4);CHKERRQ(ierr);
969     }
970     break;
971   case REFINER_SIMPLEX_3D:
972     /* All cells have 4 faces */
973     for (c = cStart; c < cEnd; ++c) {
974       for (r = 0; r < 8; ++r) {
975         const PetscInt newp = cStartNew + (c - cStart)*8 + r;
976 
977         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
978       }
979     }
980     /* Split faces have 3 edges and the same cells as the parent */
981     for (f = fStart; f < fEnd; ++f) {
982       for (r = 0; r < 4; ++r) {
983         const PetscInt newp = fStartNew + (f - fStart)*4 + r;
984         PetscInt       size;
985 
986         ierr = DMPlexSetConeSize(rdm, newp, 3);CHKERRQ(ierr);
987         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
988         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
989       }
990     }
991     /* Interior cell faces have 3 edges and 2 cells */
992     for (c = cStart; c < cEnd; ++c) {
993       for (r = 0; r < 8; ++r) {
994         const PetscInt newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*8 + r;
995 
996         ierr = DMPlexSetConeSize(rdm, newp, 3);CHKERRQ(ierr);
997         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
998       }
999     }
1000     /* Split edges have 2 vertices and the same faces */
1001     for (e = eStart; e < eEnd; ++e) {
1002       for (r = 0; r < 2; ++r) {
1003         const PetscInt newp = eStartNew + (e - eStart)*2 + r;
1004         PetscInt       size;
1005 
1006         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
1007         ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
1008         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
1009       }
1010     }
1011     /* Face edges have 2 vertices and 2+cells*(1/2) faces */
1012     for (f = fStart; f < fEnd; ++f) {
1013       for (r = 0; r < 3; ++r) {
1014         const PetscInt  newp = eStartNew + (eEnd - eStart)*2 + (f - fStart)*3 + r;
1015         const PetscInt *cone, *ornt, *support, eint[4] = {1, 0, 2, 0};
1016         PetscInt        coneSize, c, supportSize, s, er, intFaces = 0;
1017 
1018         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
1019         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
1020         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
1021         for (s = 0; s < supportSize; ++s) {
1022           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
1023           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
1024           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
1025           for (c = 0; c < coneSize; ++c) {if (cone[c] == f) break;}
1026           /* Here we want to determine whether edge newp contains a vertex which is part of the cross-tet edge */
1027           er = GetTriMidEdgeInverse_Static(ornt[c], r);
1028           if (er == eint[c]) {
1029             intFaces += 1;
1030           } else {
1031             intFaces += 2;
1032           }
1033         }
1034         ierr = DMPlexSetSupportSize(rdm, newp, 2+intFaces);CHKERRQ(ierr);
1035       }
1036     }
1037     /* Interior cell edges have 2 vertices and 4 faces */
1038     for (c = cStart; c < cEnd; ++c) {
1039       const PetscInt newp = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart);
1040 
1041       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
1042       ierr = DMPlexSetSupportSize(rdm, newp, 4);CHKERRQ(ierr);
1043     }
1044     /* Old vertices have identical supports */
1045     for (v = vStart; v < vEnd; ++v) {
1046       const PetscInt newp = vStartNew + (v - vStart);
1047       PetscInt       size;
1048 
1049       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
1050       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
1051     }
1052     /* Edge vertices have 2 + faces*2 + cells*0/1 supports */
1053     for (e = eStart; e < eEnd; ++e) {
1054       const PetscInt newp = vStartNew + (vEnd - vStart) + (e - eStart);
1055       PetscInt       size, *star = NULL, starSize, s, cellSize = 0;
1056 
1057       ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
1058       ierr = DMPlexGetTransitiveClosure(dm, e, PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
1059       for (s = 0; s < starSize*2; s += 2) {
1060         const PetscInt *cone, *ornt;
1061         PetscInt        e01, e23;
1062 
1063         if ((star[s] >= cStart) && (star[s] < cEnd)) {
1064           /* Check edge 0-1 */
1065           ierr = DMPlexGetCone(dm, star[s], &cone);CHKERRQ(ierr);
1066           ierr = DMPlexGetConeOrientation(dm, star[s], &ornt);CHKERRQ(ierr);
1067           ierr = DMPlexGetCone(dm, cone[0], &cone);CHKERRQ(ierr);
1068           e01  = cone[GetTriEdge_Static(ornt[0], 0)];
1069           /* Check edge 2-3 */
1070           ierr = DMPlexGetCone(dm, star[s], &cone);CHKERRQ(ierr);
1071           ierr = DMPlexGetConeOrientation(dm, star[s], &ornt);CHKERRQ(ierr);
1072           ierr = DMPlexGetCone(dm, cone[2], &cone);CHKERRQ(ierr);
1073           e23  = cone[GetTriEdge_Static(ornt[2], 1)];
1074           if ((e01 == e) || (e23 == e)) ++cellSize;
1075         }
1076       }
1077       ierr = DMPlexRestoreTransitiveClosure(dm, e, PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
1078       ierr = DMPlexSetSupportSize(rdm, newp, 2 + size*2 + cellSize);CHKERRQ(ierr);
1079     }
1080     break;
1081   case REFINER_HYBRID_SIMPLEX_3D:
1082     ierr = DMPlexSetHybridBounds(rdm, cStartNew + 8*(cMax-cStart), fStartNew + 4*(fMax - fStart) + 8*(cMax - cStart),
1083                                  eStartNew + 2*(eMax - eStart) + 3*(fMax - fStart) + (cMax - cStart), PETSC_DETERMINE);CHKERRQ(ierr);
1084     /* Interior cells have 4 faces */
1085     for (c = cStart; c < cMax; ++c) {
1086       for (r = 0; r < 8; ++r) {
1087         const PetscInt newp = cStartNew + (c - cStart)*8 + r;
1088 
1089         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
1090       }
1091     }
1092     /* Hybrid cells have 5 faces */
1093     for (c = cMax; c < cEnd; ++c) {
1094       for (r = 0; r < 4; ++r) {
1095         const PetscInt newp = cStartNew + (cMax - cStart)*8 + (c - cMax)*4 + r;
1096 
1097         ierr = DMPlexSetConeSize(rdm, newp, 5);CHKERRQ(ierr);
1098       }
1099     }
1100     /* Interior split faces have 3 edges and the same cells as the parent */
1101     for (f = fStart; f < fMax; ++f) {
1102       for (r = 0; r < 4; ++r) {
1103         const PetscInt newp = fStartNew + (f - fStart)*4 + r;
1104         PetscInt       size;
1105 
1106         ierr = DMPlexSetConeSize(rdm, newp, 3);CHKERRQ(ierr);
1107         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
1108         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
1109       }
1110     }
1111     /* Interior cell faces have 3 edges and 2 cells */
1112     for (c = cStart; c < cMax; ++c) {
1113       for (r = 0; r < 8; ++r) {
1114         const PetscInt newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*8 + r;
1115 
1116         ierr = DMPlexSetConeSize(rdm, newp, 3);CHKERRQ(ierr);
1117         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
1118       }
1119     }
1120     /* Hybrid split faces have 4 edges and the same cells as the parent */
1121     for (f = fMax; f < fEnd; ++f) {
1122       for (r = 0; r < 2; ++r) {
1123         const PetscInt newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (f - fMax)*2 + r;
1124         PetscInt       size;
1125 
1126         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
1127         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
1128         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
1129       }
1130     }
1131     /* Hybrid cells faces have 4 edges and 2 cells */
1132     for (c = cMax; c < cEnd; ++c) {
1133       for (r = 0; r < 3; ++r) {
1134         const PetscInt newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (c - cMax)*3 + r;
1135 
1136         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
1137         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
1138       }
1139     }
1140     /* Interior split edges have 2 vertices and the same faces */
1141     for (e = eStart; e < eMax; ++e) {
1142       for (r = 0; r < 2; ++r) {
1143         const PetscInt newp = eStartNew + (e - eStart)*2 + r;
1144         PetscInt       size;
1145 
1146         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
1147         ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
1148         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
1149       }
1150     }
1151     /* Interior face edges have 2 vertices and 2+cells*(1/2) faces */
1152     for (f = fStart; f < fMax; ++f) {
1153       for (r = 0; r < 3; ++r) {
1154         const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (f - fStart)*3 + r;
1155         const PetscInt *cone, *ornt, *support, eint[4] = {1, 0, 2, 0};
1156         PetscInt        coneSize, c, supportSize, s, er, intFaces = 0;
1157 
1158         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
1159         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
1160         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
1161         for (s = 0; s < supportSize; ++s) {
1162           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
1163           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
1164           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
1165           for (c = 0; c < coneSize; ++c) {if (cone[c] == f) break;}
1166           if (support[s] < cMax) {
1167             /* Here we want to determine whether edge newp contains a vertex which is part of the cross-tet edge */
1168             er = GetTriMidEdgeInverse_Static(ornt[c], r);
1169             if (er == eint[c]) {
1170               intFaces += 1;
1171             } else {
1172               intFaces += 2;
1173             }
1174           } else {
1175             intFaces += 1;
1176           }
1177         }
1178         ierr = DMPlexSetSupportSize(rdm, newp, 2+intFaces);CHKERRQ(ierr);
1179       }
1180     }
1181     /* Interior cell edges have 2 vertices and 4 faces */
1182     for (c = cStart; c < cMax; ++c) {
1183       const PetscInt newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart);
1184 
1185       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
1186       ierr = DMPlexSetSupportSize(rdm, newp, 4);CHKERRQ(ierr);
1187     }
1188     /* Hybrid edges have 2 vertices and the same faces */
1189     for (e = eMax; e < eEnd; ++e) {
1190       const PetscInt newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (e - eMax);
1191       PetscInt       size;
1192 
1193       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
1194       ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
1195       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
1196     }
1197     /* Hybrid face edges have 2 vertices and 2+2*cells faces */
1198     for (f = fMax; f < fEnd; ++f) {
1199       const PetscInt newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (eEnd - eMax) + (f - fMax);
1200       PetscInt       size;
1201 
1202       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
1203       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
1204       ierr = DMPlexSetSupportSize(rdm, newp, 2+2*size);CHKERRQ(ierr);
1205     }
1206     /* Interior vertices have identical supports */
1207     for (v = vStart; v < vEnd; ++v) {
1208       const PetscInt newp = vStartNew + (v - vStart);
1209       PetscInt       size;
1210 
1211       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
1212       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
1213     }
1214     /* Interior edge vertices have 2 + interior face*2 + hybrid face + cells*0/1 supports */
1215     for (e = eStart; e < eMax; ++e) {
1216       const PetscInt  newp = vStartNew + (vEnd - vStart) + (e - eStart);
1217       const PetscInt *support;
1218       PetscInt        size, *star = NULL, starSize, s, faceSize = 0, cellSize = 0;
1219 
1220       ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
1221       ierr = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
1222       for (s = 0; s < size; ++s) {
1223         if (support[s] < fMax) faceSize += 2;
1224         else                   faceSize += 1;
1225       }
1226       ierr = DMPlexGetTransitiveClosure(dm, e, PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
1227       for (s = 0; s < starSize*2; s += 2) {
1228         const PetscInt *cone, *ornt;
1229         PetscInt        e01, e23;
1230 
1231         if ((star[s] >= cStart) && (star[s] < cMax)) {
1232           /* Check edge 0-1 */
1233           ierr = DMPlexGetCone(dm, star[s], &cone);CHKERRQ(ierr);
1234           ierr = DMPlexGetConeOrientation(dm, star[s], &ornt);CHKERRQ(ierr);
1235           ierr = DMPlexGetCone(dm, cone[0], &cone);CHKERRQ(ierr);
1236           e01  = cone[GetTriEdge_Static(ornt[0], 0)];
1237           /* Check edge 2-3 */
1238           ierr = DMPlexGetCone(dm, star[s], &cone);CHKERRQ(ierr);
1239           ierr = DMPlexGetConeOrientation(dm, star[s], &ornt);CHKERRQ(ierr);
1240           ierr = DMPlexGetCone(dm, cone[2], &cone);CHKERRQ(ierr);
1241           e23  = cone[GetTriEdge_Static(ornt[2], 1)];
1242           if ((e01 == e) || (e23 == e)) ++cellSize;
1243         }
1244       }
1245       ierr = DMPlexRestoreTransitiveClosure(dm, e, PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
1246       ierr = DMPlexSetSupportSize(rdm, newp, 2 + faceSize + cellSize);CHKERRQ(ierr);
1247     }
1248     break;
1249   case REFINER_SIMPLEX_TO_HEX_3D:
1250     /* All cells have 6 faces */
1251     for (c = cStart; c < cEnd; ++c) {
1252       for (r = 0; r < 4; ++r) {
1253         const PetscInt newp = cStartNew + (c - cStart)*4 + r;
1254 
1255         ierr = DMPlexSetConeSize(rdm, newp, 6);CHKERRQ(ierr);
1256       }
1257     }
1258     /* Split faces have 4 edges and the same cells as the parent */
1259     for (f = fStart; f < fEnd; ++f) {
1260       for (r = 0; r < 3; ++r) {
1261         const PetscInt newp = fStartNew + (f - fStart)*3 + r;
1262         PetscInt       size;
1263 
1264         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
1265         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
1266         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
1267       }
1268     }
1269     /* Interior cell faces have 4 edges and 2 cells */
1270     for (c = cStart; c < cEnd; ++c) {
1271       for (r = 0; r < 6; ++r) {
1272         const PetscInt newp = fStartNew + (fEnd - fStart)*3 + (c - cStart)*6 + r;
1273 
1274         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
1275         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
1276       }
1277     }
1278     /* Split edges have 2 vertices and the same faces */
1279     for (e = eStart; e < eEnd; ++e) {
1280       for (r = 0; r < 2; ++r) {
1281         const PetscInt newp = eStartNew + (e - eStart)*2 + r;
1282         PetscInt       size;
1283 
1284         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
1285         ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
1286         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
1287       }
1288     }
1289     /* Face edges have 2 vertices and 2 + cell faces supports */
1290     for (f = fStart; f < fEnd; ++f) {
1291       for (r = 0; r < 3; ++r) {
1292         const PetscInt  newp = eStartNew + (eEnd - eStart)*2 + (f - fStart)*3 + r;
1293         PetscInt        size;
1294 
1295         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
1296         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
1297         ierr = DMPlexSetSupportSize(rdm, newp, 2+size);CHKERRQ(ierr);
1298       }
1299     }
1300     /* Interior cell edges have 2 vertices and 3 faces */
1301     for (c = cStart; c < cEnd; ++c) {
1302       for (r = 0; r < 4; ++r) {
1303         const PetscInt newp = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + r;
1304 
1305         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
1306         ierr = DMPlexSetSupportSize(rdm, newp, 3);CHKERRQ(ierr);
1307       }
1308     }
1309     /* Old vertices have identical supports */
1310     for (v = vStart; v < vEnd; ++v) {
1311       const PetscInt newp = vStartNew + (v - vStart);
1312       PetscInt       size;
1313 
1314       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
1315       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
1316     }
1317     /* Edge vertices have 2 + faces supports */
1318     for (e = eStart; e < eEnd; ++e) {
1319       const PetscInt newp = vStartNew + (vEnd - vStart) + (e - eStart);
1320       PetscInt       size;
1321 
1322       ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
1323       ierr = DMPlexSetSupportSize(rdm, newp, 2 + size);CHKERRQ(ierr);
1324     }
1325     /* Face vertices have 3 + cells supports */
1326     for (f = fStart; f < fEnd; ++f) {
1327       const PetscInt newp = vStartNew + (vEnd - vStart) + (eEnd - eStart) + f - fStart;
1328       PetscInt       size;
1329 
1330       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
1331       ierr = DMPlexSetSupportSize(rdm, newp, 3 + size);CHKERRQ(ierr);
1332     }
1333     /* Interior cell vertices have 4 supports */
1334     for (c = cStart; c < cEnd; ++c) {
1335       const PetscInt newp = vStartNew + (vEnd - vStart) + (eEnd - eStart) + fEnd - fStart + c - cStart;
1336 
1337       ierr = DMPlexSetSupportSize(rdm, newp, 4);CHKERRQ(ierr);
1338     }
1339     break;
1340   case REFINER_HYBRID_SIMPLEX_TO_HEX_3D:
1341     /* the mesh is no longer hybrid */
1342     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
1343     cMax = PetscMin(cEnd, cMax);
1344     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
1345     fMax = PetscMin(fEnd, fMax);
1346     if (eMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No edge maximum specified in hybrid mesh");
1347     eMax = PetscMin(eEnd, eMax);
1348     /* All cells have 6 faces */
1349     for (c = cStart; c < cMax; ++c) {
1350       for (r = 0; r < 4; ++r) {
1351         const PetscInt newp = cStartNew + (c - cStart)*4 + r;
1352 
1353         ierr = DMPlexSetConeSize(rdm, newp, 6);CHKERRQ(ierr);
1354       }
1355     }
1356     for (c = cMax; c < cEnd; ++c) {
1357       for (r = 0; r < 3; ++r) {
1358         const PetscInt newp = cStartNew + (cMax - cStart)*4 + (c - cMax)*3 + r;
1359 
1360         ierr = DMPlexSetConeSize(rdm, newp, 6);CHKERRQ(ierr);
1361       }
1362     }
1363     /* Interior split faces have 4 edges and the same cells as the parent */
1364     for (f = fStart; f < fMax; ++f) {
1365       for (r = 0; r < 3; ++r) {
1366         const PetscInt newp = fStartNew + (f - fStart)*3 + r;
1367         PetscInt       size;
1368 
1369         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
1370         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
1371         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
1372       }
1373     }
1374     /* Interior cell faces have 4 edges and 2 cells */
1375     for (c = cStart; c < cMax; ++c) {
1376       for (r = 0; r < 6; ++r) {
1377         const PetscInt newp = fStartNew + (fMax - fStart)*3 + (c - cStart)*6 + r;
1378 
1379         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
1380         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
1381       }
1382     }
1383     /* Hybrid split faces have 4 edges and the same cells as the parent */
1384     for (f = fMax; f < fEnd; ++f) {
1385       for (r = 0; r < 2; ++r) {
1386         const PetscInt newp = fStartNew + (fMax - fStart)*3 + (cMax - cStart)*6 + (f - fMax)*2 + r;
1387         PetscInt       size;
1388 
1389         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
1390         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
1391         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
1392       }
1393     }
1394     /* Hybrid cell faces have 4 edges and 2 cells */
1395     for (c = cMax; c < cEnd; ++c) {
1396       for (r = 0; r < 3; ++r) {
1397         const PetscInt newp = fStartNew + (fMax - fStart)*3 + (cMax - cStart)*6 + (fEnd - fMax)*2 + (c - cMax)*3 + r;
1398 
1399         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
1400         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
1401       }
1402     }
1403     /* Interior split edges have 2 vertices and the same faces */
1404     for (e = eStart; e < eMax; ++e) {
1405       for (r = 0; r < 2; ++r) {
1406         const PetscInt newp = eStartNew + (e - eStart)*2 + r;
1407         PetscInt       size;
1408 
1409         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
1410         ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
1411         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
1412       }
1413     }
1414     /* Interior face edges have 2 vertices and 2 + cell faces supports */
1415     for (f = fStart; f < fMax; ++f) {
1416       for (r = 0; r < 3; ++r) {
1417         const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (f - fStart)*3 + r;
1418         PetscInt        size;
1419 
1420         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
1421         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
1422         ierr = DMPlexSetSupportSize(rdm, newp, 2+size);CHKERRQ(ierr);
1423       }
1424     }
1425     /* Interior cell edges have 2 vertices and 3 faces */
1426     for (c = cStart; c < cMax; ++c) {
1427       for (r = 0; r < 4; ++r) {
1428         const PetscInt newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart)*4 + r;
1429 
1430         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
1431         ierr = DMPlexSetSupportSize(rdm, newp, 3);CHKERRQ(ierr);
1432       }
1433     }
1434     /* Hybrid edges have 2 vertices and the same faces */
1435     for (e = eMax; e < eEnd; ++e) {
1436       const PetscInt newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart)*4 + (e - eMax);
1437       PetscInt       size;
1438 
1439       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
1440       ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
1441       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
1442     }
1443     /* Hybrid face edges have 2 vertices and 2+cells faces */
1444     for (f = fMax; f < fEnd; ++f) {
1445       const PetscInt newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart)*4 + (eEnd - eMax) + (f - fMax);
1446       PetscInt        size;
1447 
1448       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
1449       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
1450       ierr = DMPlexSetSupportSize(rdm, newp, 2+size);CHKERRQ(ierr);
1451     }
1452     /* Hybrid cell edges have 2 vertices and 3 faces */
1453     for (c = cMax; c < cEnd; ++c) {
1454       const PetscInt newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart)*4 + (eEnd - eMax) + (fEnd - fMax) + (c - cMax);
1455 
1456       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
1457       ierr = DMPlexSetSupportSize(rdm, newp, 3);CHKERRQ(ierr);
1458     }
1459     /* Old vertices have identical supports */
1460     for (v = vStart; v < vEnd; ++v) {
1461       const PetscInt newp = vStartNew + (v - vStart);
1462       PetscInt       size;
1463 
1464       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
1465       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
1466     }
1467     /* Interior edge vertices have 2 + faces supports */
1468     for (e = eStart; e < eMax; ++e) {
1469       const PetscInt newp = vStartNew + (vEnd - vStart) + (e - eStart);
1470       PetscInt       size;
1471 
1472       ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
1473       ierr = DMPlexSetSupportSize(rdm, newp, 2 + size);CHKERRQ(ierr);
1474     }
1475     /* Interior face vertices have 3 + cells supports */
1476     for (f = fStart; f < fMax; ++f) {
1477       const PetscInt newp = vStartNew + (vEnd - vStart) + (eMax - eStart) + f - fStart;
1478       PetscInt       size;
1479 
1480       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
1481       ierr = DMPlexSetSupportSize(rdm, newp, 3 + size);CHKERRQ(ierr);
1482     }
1483     /* Interior cell vertices have 4 supports */
1484     for (c = cStart; c < cMax; ++c) {
1485       const PetscInt newp = vStartNew + (vEnd - vStart) + (eMax - eStart) + (fMax - fStart) + c - cStart;
1486 
1487       ierr = DMPlexSetSupportSize(rdm, newp, 4);CHKERRQ(ierr);
1488     }
1489     break;
1490   case REFINER_HEX_3D:
1491     /* All cells have 6 faces */
1492     for (c = cStart; c < cEnd; ++c) {
1493       for (r = 0; r < 8; ++r) {
1494         const PetscInt newp = (c - cStart)*8 + r;
1495 
1496         ierr = DMPlexSetConeSize(rdm, newp, 6);CHKERRQ(ierr);
1497       }
1498     }
1499     /* Split faces have 4 edges and the same cells as the parent */
1500     for (f = fStart; f < fEnd; ++f) {
1501       for (r = 0; r < 4; ++r) {
1502         const PetscInt newp = fStartNew + (f - fStart)*4 + r;
1503         PetscInt       size;
1504 
1505         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
1506         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
1507         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
1508       }
1509     }
1510     /* Interior faces have 4 edges and 2 cells */
1511     for (c = cStart; c < cEnd; ++c) {
1512       for (r = 0; r < 12; ++r) {
1513         const PetscInt newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + r;
1514 
1515         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
1516         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
1517       }
1518     }
1519     /* Split edges have 2 vertices and the same faces as the parent */
1520     for (e = eStart; e < eEnd; ++e) {
1521       for (r = 0; r < 2; ++r) {
1522         const PetscInt newp = eStartNew + (e - eStart)*2 + r;
1523         PetscInt       size;
1524 
1525         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
1526         ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
1527         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
1528       }
1529     }
1530     /* Face edges have 2 vertices and 2+cells faces */
1531     for (f = fStart; f < fEnd; ++f) {
1532       for (r = 0; r < 4; ++r) {
1533         const PetscInt newp = eStartNew + (eEnd - eStart)*2 + (f - fStart)*4 + r;
1534         PetscInt       size;
1535 
1536         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
1537         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
1538         ierr = DMPlexSetSupportSize(rdm, newp, 2+size);CHKERRQ(ierr);
1539       }
1540     }
1541     /* Cell edges have 2 vertices and 4 faces */
1542     for (c = cStart; c < cEnd; ++c) {
1543       for (r = 0; r < 6; ++r) {
1544         const PetscInt newp = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*4 + (c - cStart)*6 + r;
1545 
1546         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
1547         ierr = DMPlexSetSupportSize(rdm, newp, 4);CHKERRQ(ierr);
1548       }
1549     }
1550     /* Old vertices have identical supports */
1551     for (v = vStart; v < vEnd; ++v) {
1552       const PetscInt newp = vStartNew + (v - vStart);
1553       PetscInt       size;
1554 
1555       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
1556       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
1557     }
1558     /* Edge vertices have 2 + faces supports */
1559     for (e = eStart; e < eEnd; ++e) {
1560       const PetscInt newp = vStartNew + (vEnd - vStart) + (e - eStart);
1561       PetscInt       size;
1562 
1563       ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
1564       ierr = DMPlexSetSupportSize(rdm, newp, 2 + size);CHKERRQ(ierr);
1565     }
1566     /* Face vertices have 4 + cells supports */
1567     for (f = fStart; f < fEnd; ++f) {
1568       const PetscInt newp = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (f - fStart);
1569       PetscInt       size;
1570 
1571       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
1572       ierr = DMPlexSetSupportSize(rdm, newp, 4 + size);CHKERRQ(ierr);
1573     }
1574     /* Cell vertices have 6 supports */
1575     for (c = cStart; c < cEnd; ++c) {
1576       const PetscInt newp = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (fEnd - fStart) + (c - cStart);
1577 
1578       ierr = DMPlexSetSupportSize(rdm, newp, 6);CHKERRQ(ierr);
1579     }
1580     break;
1581   case REFINER_HYBRID_HEX_3D:
1582     ierr = DMPlexSetHybridBounds(rdm, cStartNew + 8*(cMax-cStart), fStartNew + 4*(fMax - fStart) + 12*(cMax - cStart),
1583                                  eStartNew + 2*(eMax - eStart) + 4*(fMax - fStart) + 6*(cMax - cStart), PETSC_DETERMINE);CHKERRQ(ierr);
1584     /* Interior cells have 6 faces */
1585     for (c = cStart; c < cMax; ++c) {
1586       for (r = 0; r < 8; ++r) {
1587         const PetscInt newp = cStartNew + (c - cStart)*8 + r;
1588 
1589         ierr = DMPlexSetConeSize(rdm, newp, 6);CHKERRQ(ierr);
1590       }
1591     }
1592     /* Hybrid cells have 6 faces */
1593     for (c = cMax; c < cEnd; ++c) {
1594       for (r = 0; r < 4; ++r) {
1595         const PetscInt newp = cStartNew + (cMax - cStart)*8 + (c - cMax)*4 + r;
1596 
1597         ierr = DMPlexSetConeSize(rdm, newp, 6);CHKERRQ(ierr);
1598       }
1599     }
1600     /* Interior split faces have 4 edges and the same cells as the parent */
1601     for (f = fStart; f < fMax; ++f) {
1602       for (r = 0; r < 4; ++r) {
1603         const PetscInt newp = fStartNew + (f - fStart)*4 + r;
1604         PetscInt       size;
1605 
1606         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
1607         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
1608         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
1609       }
1610     }
1611     /* Interior cell faces have 4 edges and 2 cells */
1612     for (c = cStart; c < cMax; ++c) {
1613       for (r = 0; r < 12; ++r) {
1614         const PetscInt newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + r;
1615 
1616         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
1617         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
1618       }
1619     }
1620     /* Hybrid split faces have 4 edges and the same cells as the parent */
1621     for (f = fMax; f < fEnd; ++f) {
1622       for (r = 0; r < 2; ++r) {
1623         const PetscInt newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (f - fMax)*2 + r;
1624         PetscInt       size;
1625 
1626         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
1627         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
1628         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
1629       }
1630     }
1631     /* Hybrid cells faces have 4 edges and 2 cells */
1632     for (c = cMax; c < cEnd; ++c) {
1633       for (r = 0; r < 4; ++r) {
1634         const PetscInt newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd - fMax)*2 + (c - cMax)*4 + r;
1635 
1636         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
1637         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
1638       }
1639     }
1640     /* Interior split edges have 2 vertices and the same faces as the parent */
1641     for (e = eStart; e < eMax; ++e) {
1642       for (r = 0; r < 2; ++r) {
1643         const PetscInt newp = eStartNew + (e - eStart)*2 + r;
1644         PetscInt       size;
1645 
1646         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
1647         ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
1648         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
1649       }
1650     }
1651     /* Interior face edges have 2 vertices and 2+cells faces */
1652     for (f = fStart; f < fMax; ++f) {
1653       for (r = 0; r < 4; ++r) {
1654         const PetscInt newp = eStartNew + (eMax - eStart)*2 + (f - fStart)*4 + r;
1655         PetscInt       size;
1656 
1657         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
1658         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
1659         ierr = DMPlexSetSupportSize(rdm, newp, 2+size);CHKERRQ(ierr);
1660       }
1661     }
1662     /* Interior cell edges have 2 vertices and 4 faces */
1663     for (c = cStart; c < cMax; ++c) {
1664       for (r = 0; r < 6; ++r) {
1665         const PetscInt newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (c - cStart)*6 + r;
1666 
1667         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
1668         ierr = DMPlexSetSupportSize(rdm, newp, 4);CHKERRQ(ierr);
1669       }
1670     }
1671     /* Hybrid edges have 2 vertices and the same faces */
1672     for (e = eMax; e < eEnd; ++e) {
1673       const PetscInt newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (e - eMax);
1674       PetscInt       size;
1675 
1676       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
1677       ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
1678       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
1679     }
1680     /* Hybrid face edges have 2 vertices and 2+cells faces */
1681     for (f = fMax; f < fEnd; ++f) {
1682       const PetscInt newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (eEnd - eMax) + (f - fMax);
1683       PetscInt       size;
1684 
1685       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
1686       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
1687       ierr = DMPlexSetSupportSize(rdm, newp, 2+size);CHKERRQ(ierr);
1688     }
1689     /* Hybrid cell edges have 2 vertices and 4 faces */
1690     for (c = cMax; c < cEnd; ++c) {
1691       const PetscInt newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (eEnd - eMax) + (fEnd - fMax) + (c - cMax);
1692 
1693       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
1694       ierr = DMPlexSetSupportSize(rdm, newp, 4);CHKERRQ(ierr);
1695     }
1696     /* Interior vertices have identical supports */
1697     for (v = vStart; v < vEnd; ++v) {
1698       const PetscInt newp = vStartNew + (v - vStart);
1699       PetscInt       size;
1700 
1701       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
1702       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
1703     }
1704     /* Interior edge vertices have 2 + faces supports */
1705     for (e = eStart; e < eMax; ++e) {
1706       const PetscInt newp = vStartNew + (vEnd - vStart) + (e - eStart);
1707       PetscInt       size;
1708 
1709       ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
1710       ierr = DMPlexSetSupportSize(rdm, newp, 2 + size);CHKERRQ(ierr);
1711     }
1712     /* Interior face vertices have 4 + cells supports */
1713     for (f = fStart; f < fMax; ++f) {
1714       const PetscInt newp = vStartNew + (vEnd - vStart) + (eMax - eStart) + (f - fStart);
1715       PetscInt       size;
1716 
1717       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
1718       ierr = DMPlexSetSupportSize(rdm, newp, 4 + size);CHKERRQ(ierr);
1719     }
1720     /* Interior cell vertices have 6 supports */
1721     for (c = cStart; c < cMax; ++c) {
1722       const PetscInt newp = vStartNew + (vEnd - vStart) + (eMax - eStart) + (fMax - fStart) + (c - cStart);
1723 
1724       ierr = DMPlexSetSupportSize(rdm, newp, 6);CHKERRQ(ierr);
1725     }
1726     break;
1727   default:
1728     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %s", CellRefiners[refiner]);
1729   }
1730   PetscFunctionReturn(0);
1731 }
1732 
1733 static PetscErrorCode CellRefinerSetCones(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
1734 {
1735   const PetscInt *faces, cellInd[4] = {0, 1, 2, 3};
1736   PetscInt        cStart,    cEnd,    cMax,    vStart,    vEnd, vMax, fStart,    fEnd,    fMax,    eStart,    eEnd,    eMax;
1737   PetscInt        cStartNew, cEndNew, cMaxNew, vStartNew, vEndNew,    fStartNew, fEndNew, fMaxNew, eStartNew, eEndNew, eMaxNew;
1738   PetscInt        depth, maxSupportSize, *supportRef, c, f, e, v, r;
1739 #if defined(PETSC_USE_DEBUG)
1740   PetscInt        p;
1741 #endif
1742   PetscErrorCode  ierr;
1743 
1744   PetscFunctionBegin;
1745   if (!refiner) PetscFunctionReturn(0);
1746   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
1747   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
1748   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
1749   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
1750   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
1751   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
1752   ierr = GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);CHKERRQ(ierr);
1753   ierr = GetDepthEnd_Private(depth, depthSize, &cEndNew, &fEndNew, &eEndNew, &vEndNew);CHKERRQ(ierr);
1754   switch (refiner) {
1755   case REFINER_SIMPLEX_1D:
1756     /* Max support size of refined mesh is 2 */
1757     ierr = PetscMalloc1(2, &supportRef);CHKERRQ(ierr);
1758     /* All cells have 2 vertices */
1759     for (c = cStart; c < cEnd; ++c) {
1760       const PetscInt  newv = vStartNew + (vEnd - vStart) + (c - cStart);
1761 
1762       for (r = 0; r < 2; ++r) {
1763         const PetscInt newp = cStartNew + (c - cStart)*2 + r;
1764         const PetscInt *cone;
1765         PetscInt        coneNew[2];
1766 
1767         ierr             = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
1768         coneNew[0]       = vStartNew + (cone[0] - vStart);
1769         coneNew[1]       = vStartNew + (cone[1] - vStart);
1770         coneNew[(r+1)%2] = newv;
1771         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
1772 #if defined(PETSC_USE_DEBUG)
1773         if ((newp < cStartNew) || (newp >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", newp, cStartNew, cEndNew);
1774         for (p = 0; p < 2; ++p) {
1775           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", coneNew[p], vStartNew, vEndNew);
1776         }
1777 #endif
1778       }
1779     }
1780     /* Old vertices have identical supports */
1781     for (v = vStart; v < vEnd; ++v) {
1782       const PetscInt  newp = vStartNew + (v - vStart);
1783       const PetscInt *support, *cone;
1784       PetscInt        size, s;
1785 
1786       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
1787       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
1788       for (s = 0; s < size; ++s) {
1789         PetscInt r = 0;
1790 
1791         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
1792         if (cone[1] == v) r = 1;
1793         supportRef[s] = cStartNew + (support[s] - cStart)*2 + r;
1794       }
1795       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
1796 #if defined(PETSC_USE_DEBUG)
1797       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", newp, vStartNew, vEndNew);
1798       for (p = 0; p < size; ++p) {
1799         if ((supportRef[p] < cStartNew) || (supportRef[p] >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", supportRef[p], cStartNew, cEndNew);
1800       }
1801 #endif
1802     }
1803     /* Cell vertices have support of 2 cells */
1804     for (c = cStart; c < cEnd; ++c) {
1805       const PetscInt  newp = vStartNew + (vEnd - vStart) + (c - cStart);
1806 
1807       supportRef[0] = cStartNew + (c - cStart)*2 + 0;
1808       supportRef[1] = cStartNew + (c - cStart)*2 + 1;
1809       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
1810 #if defined(PETSC_USE_DEBUG)
1811       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", newp, vStartNew, vEndNew);
1812       for (p = 0; p < 2; ++p) {
1813         if ((supportRef[p] < cStartNew) || (supportRef[p] >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", supportRef[p], cStartNew, cEndNew);
1814       }
1815 #endif
1816     }
1817     ierr = PetscFree(supportRef);CHKERRQ(ierr);
1818     break;
1819   case REFINER_SIMPLEX_2D:
1820     /*
1821      2
1822      |\
1823      | \
1824      |  \
1825      |   \
1826      | C  \
1827      |     \
1828      |      \
1829      2---1---1
1830      |\  D  / \
1831      | 2   0   \
1832      |A \ /  B  \
1833      0---0-------1
1834      */
1835     /* All cells have 3 faces */
1836     for (c = cStart; c < cEnd; ++c) {
1837       const PetscInt  newp = cStartNew + (c - cStart)*4;
1838       const PetscInt *cone, *ornt;
1839       PetscInt        coneNew[3], orntNew[3];
1840 
1841       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
1842       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
1843       /* A triangle */
1844       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
1845       orntNew[0] = ornt[0];
1846       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 2;
1847       orntNew[1] = -2;
1848       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
1849       orntNew[2] = ornt[2];
1850       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
1851       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
1852 #if defined(PETSC_USE_DEBUG)
1853       if ((newp+0 < cStartNew) || (newp+0 >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", newp+0, cStartNew, cEndNew);
1854       for (p = 0; p < 3; ++p) {
1855         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", coneNew[p], fStartNew, fEndNew);
1856       }
1857 #endif
1858       /* B triangle */
1859       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
1860       orntNew[0] = ornt[0];
1861       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
1862       orntNew[1] = ornt[1];
1863       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 0;
1864       orntNew[2] = -2;
1865       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
1866       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
1867 #if defined(PETSC_USE_DEBUG)
1868       if ((newp+1 < cStartNew) || (newp+1 >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", newp+1, cStartNew, cEndNew);
1869       for (p = 0; p < 3; ++p) {
1870         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", coneNew[p], fStartNew, fEndNew);
1871       }
1872 #endif
1873       /* C triangle */
1874       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 1;
1875       orntNew[0] = -2;
1876       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
1877       orntNew[1] = ornt[1];
1878       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
1879       orntNew[2] = ornt[2];
1880       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
1881       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
1882 #if defined(PETSC_USE_DEBUG)
1883       if ((newp+2 < cStartNew) || (newp+2 >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", newp+2, cStartNew, cEndNew);
1884       for (p = 0; p < 3; ++p) {
1885         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", coneNew[p], fStartNew, fEndNew);
1886       }
1887 #endif
1888       /* D triangle */
1889       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 0;
1890       orntNew[0] = 0;
1891       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 1;
1892       orntNew[1] = 0;
1893       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 2;
1894       orntNew[2] = 0;
1895       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
1896       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
1897 #if defined(PETSC_USE_DEBUG)
1898       if ((newp+3 < cStartNew) || (newp+3 >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", newp+3, cStartNew, cEndNew);
1899       for (p = 0; p < 3; ++p) {
1900         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", coneNew[p], fStartNew, fEndNew);
1901       }
1902 #endif
1903     }
1904     /* Split faces have 2 vertices and the same cells as the parent */
1905     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
1906     ierr = PetscMalloc1(2 + maxSupportSize*2, &supportRef);CHKERRQ(ierr);
1907     for (f = fStart; f < fEnd; ++f) {
1908       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);
1909 
1910       for (r = 0; r < 2; ++r) {
1911         const PetscInt  newp = fStartNew + (f - fStart)*2 + r;
1912         const PetscInt *cone, *ornt, *support;
1913         PetscInt        coneNew[2], coneSize, c, supportSize, s;
1914 
1915         ierr             = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
1916         coneNew[0]       = vStartNew + (cone[0] - vStart);
1917         coneNew[1]       = vStartNew + (cone[1] - vStart);
1918         coneNew[(r+1)%2] = newv;
1919         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
1920 #if defined(PETSC_USE_DEBUG)
1921         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
1922         for (p = 0; p < 2; ++p) {
1923           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", coneNew[p], vStartNew, vEndNew);
1924         }
1925 #endif
1926         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
1927         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
1928         for (s = 0; s < supportSize; ++s) {
1929           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
1930           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
1931           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
1932           for (c = 0; c < coneSize; ++c) {
1933             if (cone[c] == f) break;
1934           }
1935           supportRef[s] = cStartNew + (support[s] - cStart)*4 + (ornt[c] < 0 ? (c+1-r)%3 : (c+r)%3);
1936         }
1937         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
1938 #if defined(PETSC_USE_DEBUG)
1939         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
1940         for (p = 0; p < supportSize; ++p) {
1941           if ((supportRef[p] < cStartNew) || (supportRef[p] >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", supportRef[p], cStartNew, cEndNew);
1942         }
1943 #endif
1944       }
1945     }
1946     /* Interior faces have 2 vertices and 2 cells */
1947     for (c = cStart; c < cEnd; ++c) {
1948       const PetscInt *cone;
1949 
1950       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
1951       for (r = 0; r < 3; ++r) {
1952         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*3 + r;
1953         PetscInt       coneNew[2];
1954         PetscInt       supportNew[2];
1955 
1956         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r]       - fStart);
1957         coneNew[1] = vStartNew + (vEnd - vStart) + (cone[(r+1)%3] - fStart);
1958         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
1959 #if defined(PETSC_USE_DEBUG)
1960         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
1961         for (p = 0; p < 2; ++p) {
1962           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", coneNew[p], vStartNew, vEndNew);
1963         }
1964 #endif
1965         supportNew[0] = (c - cStart)*4 + (r+1)%3;
1966         supportNew[1] = (c - cStart)*4 + 3;
1967         ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
1968 #if defined(PETSC_USE_DEBUG)
1969         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
1970         for (p = 0; p < 2; ++p) {
1971           if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", supportNew[p], cStartNew, cEndNew);
1972         }
1973 #endif
1974       }
1975     }
1976     /* Old vertices have identical supports */
1977     for (v = vStart; v < vEnd; ++v) {
1978       const PetscInt  newp = vStartNew + (v - vStart);
1979       const PetscInt *support, *cone;
1980       PetscInt        size, s;
1981 
1982       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
1983       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
1984       for (s = 0; s < size; ++s) {
1985         PetscInt r = 0;
1986 
1987         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
1988         if (cone[1] == v) r = 1;
1989         supportRef[s] = fStartNew + (support[s] - fStart)*2 + r;
1990       }
1991       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
1992 #if defined(PETSC_USE_DEBUG)
1993       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", newp, vStartNew, vEndNew);
1994       for (p = 0; p < size; ++p) {
1995         if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", supportRef[p], fStartNew, fEndNew);
1996       }
1997 #endif
1998     }
1999     /* Face vertices have 2 + cells*2 supports */
2000     for (f = fStart; f < fEnd; ++f) {
2001       const PetscInt  newp = vStartNew + (vEnd - vStart) + (f - fStart);
2002       const PetscInt *cone, *support;
2003       PetscInt        size, s;
2004 
2005       ierr          = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
2006       ierr          = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
2007       supportRef[0] = fStartNew + (f - fStart)*2 + 0;
2008       supportRef[1] = fStartNew + (f - fStart)*2 + 1;
2009       for (s = 0; s < size; ++s) {
2010         PetscInt r = 0;
2011 
2012         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
2013         if      (cone[1] == f) r = 1;
2014         else if (cone[2] == f) r = 2;
2015         supportRef[2+s*2+0] = fStartNew + (fEnd - fStart)*2 + (support[s] - cStart)*3 + (r+2)%3;
2016         supportRef[2+s*2+1] = fStartNew + (fEnd - fStart)*2 + (support[s] - cStart)*3 + r;
2017       }
2018       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
2019 #if defined(PETSC_USE_DEBUG)
2020       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", newp, vStartNew, vEndNew);
2021       for (p = 0; p < 2+size*2; ++p) {
2022         if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", supportRef[p], fStartNew, fEndNew);
2023       }
2024 #endif
2025     }
2026     ierr = PetscFree(supportRef);CHKERRQ(ierr);
2027     break;
2028   case REFINER_SIMPLEX_TO_HEX_2D:
2029     /*
2030      2
2031      |\
2032      | \
2033      |  \
2034      |   \
2035      | C  \
2036      |     \
2037      2      1
2038      |\    / \
2039      | 2  1   \
2040      |  \/     \
2041      |   |      \
2042      |A  |   B   \
2043      |   0        \
2044      |   |         \
2045      0---0----------1
2046      */
2047     /* All cells have 4 faces */
2048     for (c = cStart; c < cEnd; ++c) {
2049       const PetscInt  newp = cStartNew + (c - cStart)*3;
2050       const PetscInt *cone, *ornt;
2051       PetscInt        coneNew[4], orntNew[4];
2052 
2053       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
2054       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
2055       /* A quad */
2056       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
2057       orntNew[0] = ornt[0];
2058       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 0;
2059       orntNew[1] = 0;
2060       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 2;
2061       orntNew[2] = -2;
2062       coneNew[3] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
2063       orntNew[3] = ornt[2];
2064       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
2065       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
2066 #if defined(PETSC_USE_DEBUG)
2067       if ((newp+0 < cStartNew) || (newp+0 >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", newp+0, cStartNew, cEndNew);
2068       for (p = 0; p < 4; ++p) {
2069         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", coneNew[p], fStartNew, fEndNew);
2070       }
2071 #endif
2072       /* B quad */
2073       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
2074       orntNew[0] = ornt[0];
2075       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
2076       orntNew[1] = ornt[1];
2077       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 1;
2078       orntNew[2] = 0;
2079       coneNew[3] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 0;
2080       orntNew[3] = -2;
2081       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
2082       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
2083 #if defined(PETSC_USE_DEBUG)
2084       if ((newp+1 < cStartNew) || (newp+1 >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", newp+1, cStartNew, cEndNew);
2085       for (p = 0; p < 4; ++p) {
2086         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", coneNew[p], fStartNew, fEndNew);
2087       }
2088 #endif
2089       /* C quad */
2090       coneNew[0] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
2091       orntNew[0] = ornt[1];
2092       coneNew[1] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
2093       orntNew[1] = ornt[2];
2094       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 2;
2095       orntNew[2] = 0;
2096       coneNew[3] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 1;
2097       orntNew[3] = -2;
2098       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
2099       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
2100 #if defined(PETSC_USE_DEBUG)
2101       if ((newp+2 < cStartNew) || (newp+2 >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", newp+2, cStartNew, cEndNew);
2102       for (p = 0; p < 4; ++p) {
2103         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", coneNew[p], fStartNew, fEndNew);
2104       }
2105 #endif
2106     }
2107     /* Split faces have 2 vertices and the same cells as the parent */
2108     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
2109     ierr = PetscMalloc1(2 + maxSupportSize*2, &supportRef);CHKERRQ(ierr);
2110     for (f = fStart; f < fEnd; ++f) {
2111       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);
2112 
2113       for (r = 0; r < 2; ++r) {
2114         const PetscInt  newp = fStartNew + (f - fStart)*2 + r;
2115         const PetscInt *cone, *ornt, *support;
2116         PetscInt        coneNew[2], coneSize, c, supportSize, s;
2117 
2118         ierr             = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
2119         coneNew[0]       = vStartNew + (cone[0] - vStart);
2120         coneNew[1]       = vStartNew + (cone[1] - vStart);
2121         coneNew[(r+1)%2] = newv;
2122         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2123 #if defined(PETSC_USE_DEBUG)
2124         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
2125         for (p = 0; p < 2; ++p) {
2126           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", coneNew[p], vStartNew, vEndNew);
2127         }
2128 #endif
2129         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
2130         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
2131         for (s = 0; s < supportSize; ++s) {
2132           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
2133           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
2134           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
2135           for (c = 0; c < coneSize; ++c) {
2136             if (cone[c] == f) break;
2137           }
2138           supportRef[s] = cStartNew + (support[s] - cStart)*3 + (ornt[c] < 0 ? (c+1-r)%3 : (c+r)%3);
2139         }
2140         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
2141 #if defined(PETSC_USE_DEBUG)
2142         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
2143         for (p = 0; p < supportSize; ++p) {
2144           if ((supportRef[p] < cStartNew) || (supportRef[p] >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", supportRef[p], cStartNew, cEndNew);
2145         }
2146 #endif
2147       }
2148     }
2149     /* Interior faces have 2 vertices and 2 cells */
2150     for (c = cStart; c < cEnd; ++c) {
2151       const PetscInt *cone;
2152 
2153       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
2154       for (r = 0; r < 3; ++r) {
2155         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*3 + r;
2156         PetscInt       coneNew[2];
2157         PetscInt       supportNew[2];
2158 
2159         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r] - fStart);
2160         coneNew[1] = vStartNew + (vEnd - vStart) + (fEnd    - fStart) + (c - cStart);
2161         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2162 #if defined(PETSC_USE_DEBUG)
2163         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
2164         for (p = 0; p < 2; ++p) {
2165           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", coneNew[p], vStartNew, vEndNew);
2166         }
2167 #endif
2168         supportNew[0] = (c - cStart)*3 + r%3;
2169         supportNew[1] = (c - cStart)*3 + (r+1)%3;
2170         ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
2171 #if defined(PETSC_USE_DEBUG)
2172         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
2173         for (p = 0; p < 2; ++p) {
2174           if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", supportNew[p], cStartNew, cEndNew);
2175         }
2176 #endif
2177       }
2178     }
2179     /* Old vertices have identical supports */
2180     for (v = vStart; v < vEnd; ++v) {
2181       const PetscInt  newp = vStartNew + (v - vStart);
2182       const PetscInt *support, *cone;
2183       PetscInt        size, s;
2184 
2185       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
2186       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
2187       for (s = 0; s < size; ++s) {
2188         PetscInt r = 0;
2189 
2190         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
2191         if (cone[1] == v) r = 1;
2192         supportRef[s] = fStartNew + (support[s] - fStart)*2 + r;
2193       }
2194       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
2195 #if defined(PETSC_USE_DEBUG)
2196       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", newp, vStartNew, vEndNew);
2197       for (p = 0; p < size; ++p) {
2198         if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", supportRef[p], fStartNew, fEndNew);
2199       }
2200 #endif
2201     }
2202     /* Split-face vertices have cells + 2 supports */
2203     for (f = fStart; f < fEnd; ++f) {
2204       const PetscInt  newp = vStartNew + (vEnd - vStart) + (f - fStart);
2205       const PetscInt *cone, *support;
2206       PetscInt        size, s;
2207 
2208       ierr          = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
2209       ierr          = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
2210       supportRef[0] = fStartNew + (f - fStart)*2 + 0;
2211       supportRef[1] = fStartNew + (f - fStart)*2 + 1;
2212       for (s = 0; s < size; ++s) {
2213         PetscInt r = 0;
2214 
2215         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
2216         if      (cone[1] == f) r = 1;
2217         else if (cone[2] == f) r = 2;
2218         supportRef[2+s+0] = fStartNew + (fEnd - fStart)*2 + (support[s] - cStart)*3 + r;
2219       }
2220       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
2221 #if defined(PETSC_USE_DEBUG)
2222       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", newp, vStartNew, vEndNew);
2223       for (p = 0; p < 2+size; ++p) {
2224         if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", supportRef[p], fStartNew, fEndNew);
2225       }
2226 #endif
2227     }
2228     /* Interior vertices have 3 supports */
2229     for (c = cStart; c < cEnd; ++c) {
2230       const PetscInt newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + c - cStart;
2231 
2232       supportRef[0] = fStartNew + (fEnd - fStart)*2 + (c - cStart)*3 + 0;
2233       supportRef[1] = fStartNew + (fEnd - fStart)*2 + (c - cStart)*3 + 1;
2234       supportRef[2] = fStartNew + (fEnd - fStart)*2 + (c - cStart)*3 + 2;
2235       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
2236     }
2237     ierr = PetscFree(supportRef);CHKERRQ(ierr);
2238     break;
2239   case REFINER_HYBRID_SIMPLEX_TO_HEX_2D:
2240     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
2241     cMax = PetscMin(cEnd, cMax);
2242     for (c = cStart; c < cMax; ++c) {
2243       const PetscInt  newp = cStartNew + (c - cStart)*3;
2244       const PetscInt *cone, *ornt;
2245       PetscInt        coneNew[4], orntNew[4];
2246 
2247       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
2248       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
2249       /* A quad */
2250       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
2251       orntNew[0] = ornt[0];
2252       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 0;
2253       orntNew[1] = 0;
2254       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 2;
2255       orntNew[2] = -2;
2256       coneNew[3] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
2257       orntNew[3] = ornt[2];
2258       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
2259       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
2260 #if defined(PETSC_USE_DEBUG)
2261       if ((newp+0 < cStartNew) || (newp+0 >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", newp+0, cStartNew, cEndNew);
2262       for (p = 0; p < 4; ++p) {
2263         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", coneNew[p], fStartNew, fEndNew);
2264       }
2265 #endif
2266       /* B quad */
2267       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
2268       orntNew[0] = ornt[0];
2269       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
2270       orntNew[1] = ornt[1];
2271       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 1;
2272       orntNew[2] = 0;
2273       coneNew[3] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 0;
2274       orntNew[3] = -2;
2275       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
2276       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
2277 #if defined(PETSC_USE_DEBUG)
2278       if ((newp+1 < cStartNew) || (newp+1 >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", newp+1, cStartNew, cEndNew);
2279       for (p = 0; p < 4; ++p) {
2280         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", coneNew[p], fStartNew, fEndNew);
2281       }
2282 #endif
2283       /* C quad */
2284       coneNew[0] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
2285       orntNew[0] = ornt[1];
2286       coneNew[1] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
2287       orntNew[1] = ornt[2];
2288       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 2;
2289       orntNew[2] = 0;
2290       coneNew[3] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 1;
2291       orntNew[3] = -2;
2292       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
2293       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
2294 #if defined(PETSC_USE_DEBUG)
2295       if ((newp+2 < cStartNew) || (newp+2 >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", newp+2, cStartNew, cEndNew);
2296       for (p = 0; p < 4; ++p) {
2297         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", coneNew[p], fStartNew, fEndNew);
2298       }
2299 #endif
2300     }
2301     /*
2302      2---------1---------3
2303      |         |         |
2304      |    D    1    C    |
2305      |         |         |
2306      2----2----0----3----3
2307      |         |         |
2308      |    A    0    B    |
2309      |         |         |
2310      0---------0---------1
2311      */
2312     /* Parent cells are input as prisms but children are quads, since the mesh is no longer hybrid */
2313     for (c = cMax; c < cEnd; ++c) {
2314       const PetscInt  newp  = cStartNew + (cMax - cStart)*3 + (c - cMax)*4;
2315       const PetscInt  newpt = (cMax - cStart)*3 + (c - cMax)*4;
2316       const PetscInt *cone, *ornt;
2317       PetscInt        coneNew[4], orntNew[4];
2318 
2319       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
2320       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
2321       /* A quad */
2322       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
2323       orntNew[0] = ornt[0];
2324       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + newpt + 0;
2325       orntNew[1] = 0;
2326       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + newpt + 2;
2327       orntNew[2] = -2;
2328       coneNew[3] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
2329       orntNew[3] = ornt[2] < 0 ? 0 : -2;
2330       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
2331       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
2332 #if defined(PETSC_USE_DEBUG)
2333       if ((newp+0 < cStartNew) || (newp+0 >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", newp+0, cStartNew, cEndNew);
2334       for (p = 0; p < 4; ++p) {
2335         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", coneNew[p], fStartNew, fEndNew);
2336       }
2337 #endif
2338       /* B quad */
2339       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
2340       orntNew[0] = ornt[0];
2341       coneNew[1] = fStartNew + (cone[3] - fStart)*2 + (ornt[3] < 0 ? 1 : 0);
2342       orntNew[1] = ornt[3];
2343       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + newpt + 3;
2344       orntNew[2] = 0;
2345       coneNew[3] = fStartNew + (fEnd    - fStart)*2 + newpt + 0;
2346       orntNew[3] = -2;
2347       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
2348       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
2349 #if defined(PETSC_USE_DEBUG)
2350       if ((newp+1 < cStartNew) || (newp+1 >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", newp+1, cStartNew, cEndNew);
2351       for (p = 0; p < 4; ++p) {
2352         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", coneNew[p], fStartNew, fEndNew);
2353       }
2354 #endif
2355       /* C quad */
2356       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + newpt + 3;
2357       orntNew[0] = -2;
2358       coneNew[1] = fStartNew + (cone[3] - fStart)*2 + (ornt[3] < 0 ? 0 : 1);
2359       orntNew[1] = ornt[3];
2360       coneNew[2] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
2361       orntNew[2] = ornt[1] < 0 ? 0 : -2;
2362       coneNew[3] = fStartNew + (fEnd    - fStart)*2 + newpt + 1;
2363       orntNew[3] = 0;
2364       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
2365       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
2366 #if defined(PETSC_USE_DEBUG)
2367       if ((newp+2 < cStartNew) || (newp+2 >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", newp+2, cStartNew, cEndNew);
2368       for (p = 0; p < 4; ++p) {
2369         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", coneNew[p], fStartNew, fEndNew);
2370       }
2371 #endif
2372       /* D quad */
2373       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + newpt + 2;
2374       orntNew[0] = 0;
2375       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + newpt + 1;
2376       orntNew[1] = -2;
2377       coneNew[2] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
2378       orntNew[2] = ornt[1] < 0 ? 0 : -2;
2379       coneNew[3] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
2380       orntNew[3] = ornt[2] < 0 ? 0 : -2;
2381       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
2382       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
2383 #if defined(PETSC_USE_DEBUG)
2384       if ((newp+3 < cStartNew) || (newp+3 >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", newp+3, cStartNew, cEndNew);
2385       for (p = 0; p < 4; ++p) {
2386         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", coneNew[p], fStartNew, fEndNew);
2387       }
2388 #endif
2389     }
2390     /* Split faces have 2 vertices and the same cells as the parent */
2391     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
2392     ierr = PetscMalloc1(2 + maxSupportSize*2, &supportRef);CHKERRQ(ierr);
2393     for (f = fStart; f < fEnd; ++f) {
2394       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);
2395 
2396       for (r = 0; r < 2; ++r) {
2397         const PetscInt  newp = fStartNew + (f - fStart)*2 + r;
2398         const PetscInt *cone, *ornt, *support;
2399         PetscInt        coneNew[2], coneSize, c, supportSize, s;
2400 
2401         ierr             = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
2402         coneNew[0]       = vStartNew + (cone[0] - vStart);
2403         coneNew[1]       = vStartNew + (cone[1] - vStart);
2404         coneNew[(r+1)%2] = newv;
2405         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2406 #if defined(PETSC_USE_DEBUG)
2407         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
2408         for (p = 0; p < 2; ++p) {
2409           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", coneNew[p], vStartNew, vEndNew);
2410         }
2411 #endif
2412         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
2413         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
2414         for (s = 0; s < supportSize; ++s) {
2415           const PetscInt p2q[4][2] = { {0, 1},
2416                                        {3, 2},
2417                                        {0, 3},
2418                                        {1, 2} };
2419 
2420           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
2421           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
2422           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
2423           for (c = 0; c < coneSize; ++c) {
2424             if (cone[c] == f) break;
2425           }
2426           if (coneSize == 3)      supportRef[s] = cStartNew + (support[s] - cStart)*3 + (ornt[c] < 0 ? (c+1-r)%3 : (c+r)%3);
2427           else if (coneSize == 4) supportRef[s] = cStartNew + (cMax - cStart)*3 + (support[s] - cMax)*4 + (ornt[c] < 0 ? p2q[c][(r+1)%2] : p2q[c][r]);
2428           else SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected cone size %D", coneSize);
2429         }
2430         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
2431 #if defined(PETSC_USE_DEBUG)
2432         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
2433         for (p = 0; p < supportSize; ++p) {
2434           if ((supportRef[p] < cStartNew) || (supportRef[p] >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", supportRef[p], cStartNew, cEndNew);
2435         }
2436 #endif
2437       }
2438     }
2439     /* Interior faces have 2 vertices and 2 cells */
2440     for (c = cStart; c < cMax; ++c) {
2441       const PetscInt *cone;
2442 
2443       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
2444       for (r = 0; r < 3; ++r) {
2445         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*3 + r;
2446         PetscInt       coneNew[2];
2447         PetscInt       supportNew[2];
2448 
2449         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r] - fStart);
2450         coneNew[1] = vStartNew + (vEnd - vStart) + (fEnd    - fStart) + (c - cStart);
2451         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2452 #if defined(PETSC_USE_DEBUG)
2453         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
2454         for (p = 0; p < 2; ++p) {
2455           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", coneNew[p], vStartNew, vEndNew);
2456         }
2457 #endif
2458         supportNew[0] = (c - cStart)*3 + r%3;
2459         supportNew[1] = (c - cStart)*3 + (r+1)%3;
2460         ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
2461 #if defined(PETSC_USE_DEBUG)
2462         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
2463         for (p = 0; p < 2; ++p) {
2464           if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", supportNew[p], cStartNew, cEndNew);
2465         }
2466 #endif
2467       }
2468     }
2469     /* Hybrid interior faces have 2 vertices and 2 cells */
2470     for (c = cMax; c < cEnd; ++c) {
2471       const PetscInt *cone;
2472       PetscInt        coneNew[2], supportNew[2];
2473 
2474       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
2475       for (r = 0; r < 4; ++r) {
2476         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (cMax - cStart)*3 + (c - cMax)*4 + r;
2477 
2478         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r] - fStart);
2479         coneNew[1] = vStartNew + (vEnd - vStart) + (fEnd    - fStart) + (cMax - cStart) + (c - cMax);
2480 	ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2481 #if defined(PETSC_USE_DEBUG)
2482         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
2483         for (p = 0; p < 2; ++p) {
2484           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", coneNew[p], vStartNew, vEndNew);
2485         }
2486 #endif
2487         if (r==0) {
2488           supportNew[0] = (cMax - cStart)*3 + (c - cMax)*4 + 0;
2489           supportNew[1] = (cMax - cStart)*3 + (c - cMax)*4 + 1;
2490         } else if (r==1) {
2491           supportNew[0] = (cMax - cStart)*3 + (c - cMax)*4 + 2;
2492           supportNew[1] = (cMax - cStart)*3 + (c - cMax)*4 + 3;
2493         } else if (r==2) {
2494           supportNew[0] = (cMax - cStart)*3 + (c - cMax)*4 + 0;
2495           supportNew[1] = (cMax - cStart)*3 + (c - cMax)*4 + 3;
2496         } else {
2497           supportNew[0] = (cMax - cStart)*3 + (c - cMax)*4 + 1;
2498           supportNew[1] = (cMax - cStart)*3 + (c - cMax)*4 + 2;
2499         }
2500         ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
2501 #if defined(PETSC_USE_DEBUG)
2502         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, 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(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", supportNew[p], cStartNew, cEndNew);
2505         }
2506 #endif
2507       }
2508     }
2509     /* Old vertices have identical supports */
2510     for (v = vStart; v < vEnd; ++v) {
2511       const PetscInt  newp = vStartNew + (v - vStart);
2512       const PetscInt *support, *cone;
2513       PetscInt        size, s;
2514 
2515       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
2516       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
2517       for (s = 0; s < size; ++s) {
2518         PetscInt r = 0;
2519 
2520         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
2521         if (cone[1] == v) r = 1;
2522         supportRef[s] = fStartNew + (support[s] - fStart)*2 + r;
2523       }
2524       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
2525 #if defined(PETSC_USE_DEBUG)
2526       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", newp, vStartNew, vEndNew);
2527       for (p = 0; p < size; ++p) {
2528         if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", supportRef[p], fStartNew, fEndNew);
2529       }
2530 #endif
2531     }
2532     /* Split-face vertices have cells + 2 supports */
2533     for (f = fStart; f < fEnd; ++f) {
2534       const PetscInt  newp = vStartNew + (vEnd - vStart) + (f - fStart);
2535       const PetscInt *cone, *support;
2536       PetscInt        size, s;
2537 
2538       ierr          = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
2539       ierr          = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
2540       supportRef[0] = fStartNew + (f - fStart)*2 + 0;
2541       supportRef[1] = fStartNew + (f - fStart)*2 + 1;
2542       for (s = 0; s < size; ++s) {
2543         PetscInt r = 0, coneSize;
2544 
2545         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
2546         ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
2547         if (coneSize == 3) {
2548           if      (cone[1] == f) r = 1;
2549           else if (cone[2] == f) r = 2;
2550           supportRef[2+s] = fStartNew + (fEnd - fStart)*2 + (support[s] - cStart)*3 + r;
2551         } else if (coneSize == 4) {
2552           if      (cone[1] == f) r = 1;
2553           else if (cone[2] == f) r = 2;
2554           else if (cone[3] == f) r = 3;
2555           supportRef[2+s] = fStartNew + (fEnd - fStart)*2 + (cMax - cStart)*3 + (support[s] - cMax)*4 + r;
2556         } else SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected cone size %D", coneSize);
2557       }
2558       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
2559 #if defined(PETSC_USE_DEBUG)
2560       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", newp, vStartNew, vEndNew);
2561       for (p = 0; p < 2+size; ++p) {
2562         if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", supportRef[p], fStartNew, fEndNew);
2563       }
2564 #endif
2565     }
2566     /* Interior vertices have 3 supports */
2567     for (c = cStart; c < cMax; ++c) {
2568       const PetscInt newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + c - cStart;
2569 
2570       supportRef[0] = fStartNew + (fEnd - fStart)*2 + (c - cStart)*3 + 0;
2571       supportRef[1] = fStartNew + (fEnd - fStart)*2 + (c - cStart)*3 + 1;
2572       supportRef[2] = fStartNew + (fEnd - fStart)*2 + (c - cStart)*3 + 2;
2573       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
2574     }
2575     /* Hybrid interior vertices have 4 supports */
2576     for (c = cMax; c < cEnd; ++c) {
2577       const PetscInt newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + c - cStart;
2578 
2579       supportRef[0] = fStartNew + (fEnd - fStart)*2 + (cMax - cStart)*3 + (c - cMax)*4 + 0;
2580       supportRef[1] = fStartNew + (fEnd - fStart)*2 + (cMax - cStart)*3 + (c - cMax)*4 + 1;
2581       supportRef[2] = fStartNew + (fEnd - fStart)*2 + (cMax - cStart)*3 + (c - cMax)*4 + 2;
2582       supportRef[3] = fStartNew + (fEnd - fStart)*2 + (cMax - cStart)*3 + (c - cMax)*4 + 3;
2583       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
2584     }
2585     ierr = PetscFree(supportRef);CHKERRQ(ierr);
2586     break;
2587   case REFINER_HEX_2D:
2588     /*
2589      3---------2---------2
2590      |         |         |
2591      |    D    2    C    |
2592      |         |         |
2593      3----3----0----1----1
2594      |         |         |
2595      |    A    0    B    |
2596      |         |         |
2597      0---------0---------1
2598      */
2599     /* All cells have 4 faces */
2600     for (c = cStart; c < cEnd; ++c) {
2601       const PetscInt  newp = (c - cStart)*4;
2602       const PetscInt *cone, *ornt;
2603       PetscInt        coneNew[4], orntNew[4];
2604 
2605       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
2606       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
2607       /* A quad */
2608       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
2609       orntNew[0] = ornt[0];
2610       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 0;
2611       orntNew[1] = 0;
2612       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 3;
2613       orntNew[2] = -2;
2614       coneNew[3] = fStartNew + (cone[3] - fStart)*2 + (ornt[3] < 0 ? 0 : 1);
2615       orntNew[3] = ornt[3];
2616       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
2617       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
2618 #if defined(PETSC_USE_DEBUG)
2619       if ((newp+0 < cStartNew) || (newp+0 >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", newp+0, cStartNew, cEndNew);
2620       for (p = 0; p < 4; ++p) {
2621         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", coneNew[p], fStartNew, fEndNew);
2622       }
2623 #endif
2624       /* B quad */
2625       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
2626       orntNew[0] = ornt[0];
2627       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
2628       orntNew[1] = ornt[1];
2629       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 1;
2630       orntNew[2] = -2;
2631       coneNew[3] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 0;
2632       orntNew[3] = -2;
2633       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
2634       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
2635 #if defined(PETSC_USE_DEBUG)
2636       if ((newp+1 < cStartNew) || (newp+1 >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", newp+1, cStartNew, cEndNew);
2637       for (p = 0; p < 4; ++p) {
2638         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", coneNew[p], fStartNew, fEndNew);
2639       }
2640 #endif
2641       /* C quad */
2642       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 1;
2643       orntNew[0] = 0;
2644       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
2645       orntNew[1] = ornt[1];
2646       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
2647       orntNew[2] = ornt[2];
2648       coneNew[3] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 2;
2649       orntNew[3] = -2;
2650       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
2651       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
2652 #if defined(PETSC_USE_DEBUG)
2653       if ((newp+2 < cStartNew) || (newp+2 >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", newp+2, cStartNew, cEndNew);
2654       for (p = 0; p < 4; ++p) {
2655         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", coneNew[p], fStartNew, fEndNew);
2656       }
2657 #endif
2658       /* D quad */
2659       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 3;
2660       orntNew[0] = 0;
2661       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 2;
2662       orntNew[1] = 0;
2663       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
2664       orntNew[2] = ornt[2];
2665       coneNew[3] = fStartNew + (cone[3] - fStart)*2 + (ornt[3] < 0 ? 1 : 0);
2666       orntNew[3] = ornt[3];
2667       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
2668       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
2669 #if defined(PETSC_USE_DEBUG)
2670       if ((newp+3 < cStartNew) || (newp+3 >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", newp+3, cStartNew, cEndNew);
2671       for (p = 0; p < 4; ++p) {
2672         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", coneNew[p], fStartNew, fEndNew);
2673       }
2674 #endif
2675     }
2676     /* Split faces have 2 vertices and the same cells as the parent */
2677     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
2678     ierr = PetscMalloc1(2 + maxSupportSize*2, &supportRef);CHKERRQ(ierr);
2679     for (f = fStart; f < fEnd; ++f) {
2680       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);
2681 
2682       for (r = 0; r < 2; ++r) {
2683         const PetscInt  newp = fStartNew + (f - fStart)*2 + r;
2684         const PetscInt *cone, *ornt, *support;
2685         PetscInt        coneNew[2], coneSize, c, supportSize, s;
2686 
2687         ierr             = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
2688         coneNew[0]       = vStartNew + (cone[0] - vStart);
2689         coneNew[1]       = vStartNew + (cone[1] - vStart);
2690         coneNew[(r+1)%2] = newv;
2691         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2692 #if defined(PETSC_USE_DEBUG)
2693         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
2694         for (p = 0; p < 2; ++p) {
2695           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", coneNew[p], vStartNew, vEndNew);
2696         }
2697 #endif
2698         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
2699         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
2700         for (s = 0; s < supportSize; ++s) {
2701           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
2702           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
2703           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
2704           for (c = 0; c < coneSize; ++c) {
2705             if (cone[c] == f) break;
2706           }
2707           supportRef[s] = cStartNew + (support[s] - cStart)*4 + (ornt[c] < 0 ? (c+1-r)%4 : (c+r)%4);
2708         }
2709         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
2710 #if defined(PETSC_USE_DEBUG)
2711         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
2712         for (p = 0; p < supportSize; ++p) {
2713           if ((supportRef[p] < cStartNew) || (supportRef[p] >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", supportRef[p], cStartNew, cEndNew);
2714         }
2715 #endif
2716       }
2717     }
2718     /* Interior faces have 2 vertices and 2 cells */
2719     for (c = cStart; c < cEnd; ++c) {
2720       const PetscInt *cone;
2721       PetscInt        coneNew[2], supportNew[2];
2722 
2723       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
2724       for (r = 0; r < 4; ++r) {
2725         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*4 + r;
2726 
2727 	if (r==1 || r==2) {
2728           coneNew[0] = vStartNew + (vEnd - vStart) + (fEnd    - fStart) + (c - cStart);
2729           coneNew[1] = vStartNew + (vEnd - vStart) + (cone[r] - fStart);
2730 	} else {
2731           coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r] - fStart);
2732           coneNew[1] = vStartNew + (vEnd - vStart) + (fEnd    - fStart) + (c - cStart);
2733 	}
2734 	ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2735 #if defined(PETSC_USE_DEBUG)
2736         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
2737         for (p = 0; p < 2; ++p) {
2738           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", coneNew[p], vStartNew, vEndNew);
2739         }
2740 #endif
2741         supportNew[0] = (c - cStart)*4 + r;
2742         supportNew[1] = (c - cStart)*4 + (r+1)%4;
2743         ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
2744 #if defined(PETSC_USE_DEBUG)
2745         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
2746         for (p = 0; p < 2; ++p) {
2747           if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", supportNew[p], cStartNew, cEndNew);
2748         }
2749 #endif
2750       }
2751     }
2752     /* Old vertices have identical supports */
2753     for (v = vStart; v < vEnd; ++v) {
2754       const PetscInt  newp = vStartNew + (v - vStart);
2755       const PetscInt *support, *cone;
2756       PetscInt        size, s;
2757 
2758       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
2759       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
2760       for (s = 0; s < size; ++s) {
2761         PetscInt r = 0;
2762 
2763         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
2764         if (cone[1] == v) r = 1;
2765         supportRef[s] = fStartNew + (support[s] - fStart)*2 + r;
2766       }
2767       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
2768 #if defined(PETSC_USE_DEBUG)
2769       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", newp, vStartNew, vEndNew);
2770       for (p = 0; p < size; ++p) {
2771         if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", supportRef[p], fStartNew, fEndNew);
2772       }
2773 #endif
2774     }
2775     /* Face vertices have 2 + cells supports */
2776     for (f = fStart; f < fEnd; ++f) {
2777       const PetscInt  newp = vStartNew + (vEnd - vStart) + (f - fStart);
2778       const PetscInt *cone, *support;
2779       PetscInt        size, s;
2780 
2781       ierr          = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
2782       ierr          = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
2783       supportRef[0] = fStartNew + (f - fStart)*2 + 0;
2784       supportRef[1] = fStartNew + (f - fStart)*2 + 1;
2785       for (s = 0; s < size; ++s) {
2786         PetscInt r = 0;
2787 
2788         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
2789         if      (cone[1] == f) r = 1;
2790         else if (cone[2] == f) r = 2;
2791         else if (cone[3] == f) r = 3;
2792         supportRef[2+s] = fStartNew + (fEnd - fStart)*2 + (support[s] - cStart)*4 + r;
2793       }
2794       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
2795 #if defined(PETSC_USE_DEBUG)
2796       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", newp, vStartNew, vEndNew);
2797       for (p = 0; p < 2+size; ++p) {
2798         if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", supportRef[p], fStartNew, fEndNew);
2799       }
2800 #endif
2801     }
2802     /* Cell vertices have 4 supports */
2803     for (c = cStart; c < cEnd; ++c) {
2804       const PetscInt newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (c - cStart);
2805       PetscInt       supportNew[4];
2806 
2807       for (r = 0; r < 4; ++r) {
2808         supportNew[r] = fStartNew + (fEnd - fStart)*2 + (c - cStart)*4 + r;
2809       }
2810       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
2811     }
2812     ierr = PetscFree(supportRef);CHKERRQ(ierr);
2813     break;
2814   case REFINER_HYBRID_SIMPLEX_2D:
2815     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
2816     cMax = PetscMin(cEnd, cMax);
2817     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
2818     fMax = PetscMin(fEnd, fMax);
2819     ierr = DMPlexGetHybridBounds(rdm, &cMaxNew, &fMaxNew, NULL, NULL);CHKERRQ(ierr);
2820     /* Interior cells have 3 faces */
2821     for (c = cStart; c < cMax; ++c) {
2822       const PetscInt  newp = cStartNew + (c - cStart)*4;
2823       const PetscInt *cone, *ornt;
2824       PetscInt        coneNew[3], orntNew[3];
2825 
2826       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
2827       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
2828       /* A triangle */
2829       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
2830       orntNew[0] = ornt[0];
2831       coneNew[1] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 2;
2832       orntNew[1] = -2;
2833       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
2834       orntNew[2] = ornt[2];
2835       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
2836       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
2837 #if defined(PETSC_USE_DEBUG)
2838       if ((newp+0 < cStartNew) || (newp+0 >= cMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an interior cell [%D, %D)", newp+0, cStartNew, cMaxNew);
2839       for (p = 0; p < 3; ++p) {
2840         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an interior face [%D, %D)", coneNew[p], fStartNew, fMaxNew);
2841       }
2842 #endif
2843       /* B triangle */
2844       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
2845       orntNew[0] = ornt[0];
2846       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
2847       orntNew[1] = ornt[1];
2848       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 0;
2849       orntNew[2] = -2;
2850       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
2851       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
2852 #if defined(PETSC_USE_DEBUG)
2853       if ((newp+1 < cStartNew) || (newp+1 >= cMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an interior cell [%D, %D)", newp+1, cStartNew, cMaxNew);
2854       for (p = 0; p < 3; ++p) {
2855         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an interior face [%D, %D)", coneNew[p], fStartNew, fMaxNew);
2856       }
2857 #endif
2858       /* C triangle */
2859       coneNew[0] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 1;
2860       orntNew[0] = -2;
2861       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
2862       orntNew[1] = ornt[1];
2863       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
2864       orntNew[2] = ornt[2];
2865       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
2866       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
2867 #if defined(PETSC_USE_DEBUG)
2868       if ((newp+2 < cStartNew) || (newp+2 >= cMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an interior cell [%D, %D)", newp+2, cStartNew, cMaxNew);
2869       for (p = 0; p < 3; ++p) {
2870         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an interior face [%D, %D)", coneNew[p], fStartNew, fMaxNew);
2871       }
2872 #endif
2873       /* D triangle */
2874       coneNew[0] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 0;
2875       orntNew[0] = 0;
2876       coneNew[1] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 1;
2877       orntNew[1] = 0;
2878       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 2;
2879       orntNew[2] = 0;
2880       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
2881       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
2882 #if defined(PETSC_USE_DEBUG)
2883       if ((newp+3 < cStartNew) || (newp+3 >= cMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an interior cell [%D, %D)", newp+3, cStartNew, cMaxNew);
2884       for (p = 0; p < 3; ++p) {
2885         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an interior face [%D, %D)", coneNew[p], fStartNew, fMaxNew);
2886       }
2887 #endif
2888     }
2889     /*
2890      2----3----3
2891      |         |
2892      |    B    |
2893      |         |
2894      0----4--- 1
2895      |         |
2896      |    A    |
2897      |         |
2898      0----2----1
2899      */
2900     /* Hybrid cells have 4 faces */
2901     for (c = cMax; c < cEnd; ++c) {
2902       const PetscInt  newp = cStartNew + (cMax - cStart)*4 + (c - cMax)*2;
2903       const PetscInt *cone, *ornt;
2904       PetscInt        coneNew[4], orntNew[4], r;
2905 
2906       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
2907       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
2908       r    = (ornt[0] < 0 ? 1 : 0);
2909       /* A quad */
2910       coneNew[0]   = fStartNew + (cone[0] - fStart)*2 + r;
2911       orntNew[0]   = ornt[0];
2912       coneNew[1]   = fStartNew + (cone[1] - fStart)*2 + r;
2913       orntNew[1]   = ornt[1];
2914       coneNew[2+r] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (cone[2+r] - fMax);
2915       orntNew[2+r] = 0;
2916       coneNew[3-r] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (fEnd    - fMax) + (c - cMax);
2917       orntNew[3-r] = 0;
2918       ierr = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
2919       ierr = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
2920 #if defined(PETSC_USE_DEBUG)
2921       if ((newp+0 < cStartNew) || (newp+0 >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", newp+0, cStartNew, cEndNew);
2922       for (p = 0; p < 4; ++p) {
2923         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", coneNew[p], fStartNew, fEndNew);
2924       }
2925 #endif
2926       /* B quad */
2927       coneNew[0]   = fStartNew + (cone[0] - fStart)*2 + 1-r;
2928       orntNew[0]   = ornt[0];
2929       coneNew[1]   = fStartNew + (cone[1] - fStart)*2 + 1-r;
2930       orntNew[1]   = ornt[1];
2931       coneNew[2+r] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (fEnd    - fMax) + (c - cMax);
2932       orntNew[2+r] = 0;
2933       coneNew[3-r] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (cone[3-r] - fMax);
2934       orntNew[3-r] = 0;
2935       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
2936       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
2937 #if defined(PETSC_USE_DEBUG)
2938       if ((newp+1 < cStartNew) || (newp+1 >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", newp+1, cStartNew, cEndNew);
2939       for (p = 0; p < 4; ++p) {
2940         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", coneNew[p], fStartNew, fEndNew);
2941       }
2942 #endif
2943     }
2944     /* Interior split faces have 2 vertices and the same cells as the parent */
2945     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
2946     ierr = PetscMalloc1(2 + maxSupportSize*2, &supportRef);CHKERRQ(ierr);
2947     for (f = fStart; f < fMax; ++f) {
2948       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);
2949 
2950       for (r = 0; r < 2; ++r) {
2951         const PetscInt  newp = fStartNew + (f - fStart)*2 + r;
2952         const PetscInt *cone, *ornt, *support;
2953         PetscInt        coneNew[2], coneSize, c, supportSize, s;
2954 
2955         ierr             = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
2956         coneNew[0]       = vStartNew + (cone[0] - vStart);
2957         coneNew[1]       = vStartNew + (cone[1] - vStart);
2958         coneNew[(r+1)%2] = newv;
2959         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2960 #if defined(PETSC_USE_DEBUG)
2961         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
2962         for (p = 0; p < 2; ++p) {
2963           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", coneNew[p], vStartNew, vEndNew);
2964         }
2965 #endif
2966         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
2967         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
2968         for (s = 0; s < supportSize; ++s) {
2969           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
2970           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
2971           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
2972           for (c = 0; c < coneSize; ++c) if (cone[c] == f) break;
2973           if (support[s] >= cMax) {
2974             supportRef[s] = cStartNew + (cMax - cStart)*4 + (support[s] - cMax)*2 + (ornt[c] < 0 ? 1-r : r);
2975           } else {
2976             supportRef[s] = cStartNew + (support[s] - cStart)*4 + (ornt[c] < 0 ? (c+1-r)%3 : (c+r)%3);
2977           }
2978         }
2979         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
2980 #if defined(PETSC_USE_DEBUG)
2981         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
2982         for (p = 0; p < supportSize; ++p) {
2983           if ((supportRef[p] < cStartNew) || (supportRef[p] >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", supportRef[p], cStartNew, cEndNew);
2984         }
2985 #endif
2986       }
2987     }
2988     /* Interior cell faces have 2 vertices and 2 cells */
2989     for (c = cStart; c < cMax; ++c) {
2990       const PetscInt *cone;
2991 
2992       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
2993       for (r = 0; r < 3; ++r) {
2994         const PetscInt newp = fStartNew + (fMax - fStart)*2 + (c - cStart)*3 + r;
2995         PetscInt       coneNew[2];
2996         PetscInt       supportNew[2];
2997 
2998         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r]       - fStart);
2999         coneNew[1] = vStartNew + (vEnd - vStart) + (cone[(r+1)%3] - fStart);
3000         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3001 #if defined(PETSC_USE_DEBUG)
3002         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
3003         for (p = 0; p < 2; ++p) {
3004           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", coneNew[p], vStartNew, vEndNew);
3005         }
3006 #endif
3007         supportNew[0] = (c - cStart)*4 + (r+1)%3;
3008         supportNew[1] = (c - cStart)*4 + 3;
3009         ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3010 #if defined(PETSC_USE_DEBUG)
3011         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
3012         for (p = 0; p < 2; ++p) {
3013           if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", supportNew[p], cStartNew, cEndNew);
3014         }
3015 #endif
3016       }
3017     }
3018     /* Interior hybrid faces have 2 vertices and the same cells */
3019     for (f = fMax; f < fEnd; ++f) {
3020       const PetscInt  newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (f - fMax);
3021       const PetscInt *cone, *ornt;
3022       const PetscInt *support;
3023       PetscInt        coneNew[2];
3024       PetscInt        supportNew[2];
3025       PetscInt        size, s, r;
3026 
3027       ierr       = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
3028       coneNew[0] = vStartNew + (cone[0] - vStart);
3029       coneNew[1] = vStartNew + (cone[1] - vStart);
3030       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3031 #if defined(PETSC_USE_DEBUG)
3032       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
3033       for (p = 0; p < 2; ++p) {
3034         if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", coneNew[p], vStartNew, vEndNew);
3035       }
3036 #endif
3037       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
3038       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
3039       for (s = 0; s < size; ++s) {
3040         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
3041         ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
3042         for (r = 0; r < 2; ++r) {
3043           if (cone[r+2] == f) break;
3044         }
3045         supportNew[s] = (cMax - cStart)*4 + (support[s] - cMax)*2 + (ornt[0] < 0 ? 1-r : r);
3046       }
3047       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3048 #if defined(PETSC_USE_DEBUG)
3049       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
3050       for (p = 0; p < size; ++p) {
3051         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", supportNew[p], cStartNew, cEndNew);
3052       }
3053 #endif
3054     }
3055     /* Cell hybrid faces have 2 vertices and 2 cells */
3056     for (c = cMax; c < cEnd; ++c) {
3057       const PetscInt  newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (fEnd - fMax) + (c - cMax);
3058       const PetscInt *cone;
3059       PetscInt        coneNew[2];
3060       PetscInt        supportNew[2];
3061 
3062       ierr       = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
3063       coneNew[0] = vStartNew + (vEnd - vStart) + (cone[0] - fStart);
3064       coneNew[1] = vStartNew + (vEnd - vStart) + (cone[1] - fStart);
3065       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3066 #if defined(PETSC_USE_DEBUG)
3067       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
3068       for (p = 0; p < 2; ++p) {
3069         if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", coneNew[p], vStartNew, vEndNew);
3070       }
3071 #endif
3072       supportNew[0] = (cMax - cStart)*4 + (c - cMax)*2 + 0;
3073       supportNew[1] = (cMax - cStart)*4 + (c - cMax)*2 + 1;
3074       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3075 #if defined(PETSC_USE_DEBUG)
3076       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
3077       for (p = 0; p < 2; ++p) {
3078         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", supportNew[p], cStartNew, cEndNew);
3079       }
3080 #endif
3081     }
3082     /* Old vertices have identical supports */
3083     for (v = vStart; v < vEnd; ++v) {
3084       const PetscInt  newp = vStartNew + (v - vStart);
3085       const PetscInt *support, *cone;
3086       PetscInt        size, s;
3087 
3088       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
3089       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
3090       for (s = 0; s < size; ++s) {
3091         if (support[s] >= fMax) {
3092           supportRef[s] = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (support[s] - fMax);
3093         } else {
3094           PetscInt r = 0;
3095 
3096           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
3097           if (cone[1] == v) r = 1;
3098           supportRef[s] = fStartNew + (support[s] - fStart)*2 + r;
3099         }
3100       }
3101       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
3102 #if defined(PETSC_USE_DEBUG)
3103       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", newp, vStartNew, vEndNew);
3104       for (p = 0; p < size; ++p) {
3105         if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", supportRef[p], fStartNew, fEndNew);
3106       }
3107 #endif
3108     }
3109     /* Face vertices have 2 + (2 interior, 1 hybrid) supports */
3110     for (f = fStart; f < fMax; ++f) {
3111       const PetscInt  newp = vStartNew + (vEnd - vStart) + (f - fStart);
3112       const PetscInt *cone, *support;
3113       PetscInt        size, newSize = 2, s;
3114 
3115       ierr          = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
3116       ierr          = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
3117       supportRef[0] = fStartNew + (f - fStart)*2 + 0;
3118       supportRef[1] = fStartNew + (f - fStart)*2 + 1;
3119       for (s = 0; s < size; ++s) {
3120         PetscInt r = 0;
3121 
3122         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
3123         if (support[s] >= cMax) {
3124           supportRef[newSize+0] = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (fEnd - fMax) + (support[s] - cMax);
3125 
3126           newSize += 1;
3127         } else {
3128           if      (cone[1] == f) r = 1;
3129           else if (cone[2] == f) r = 2;
3130           supportRef[newSize+0] = fStartNew + (fMax - fStart)*2 + (support[s] - cStart)*3 + (r+2)%3;
3131           supportRef[newSize+1] = fStartNew + (fMax - fStart)*2 + (support[s] - cStart)*3 + r;
3132 
3133           newSize += 2;
3134         }
3135       }
3136       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
3137 #if defined(PETSC_USE_DEBUG)
3138       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", newp, vStartNew, vEndNew);
3139       for (p = 0; p < newSize; ++p) {
3140         if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", supportRef[p], fStartNew, fEndNew);
3141       }
3142 #endif
3143     }
3144     ierr = PetscFree(supportRef);CHKERRQ(ierr);
3145     break;
3146   case REFINER_HYBRID_HEX_2D:
3147     /* Hybrid Hex 2D */
3148     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
3149     cMax = PetscMin(cEnd, cMax);
3150     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
3151     fMax = PetscMin(fEnd, fMax);
3152     ierr = DMPlexGetHybridBounds(rdm, &cMaxNew, &fMaxNew, NULL, NULL);CHKERRQ(ierr);
3153     /* Interior cells have 4 faces */
3154     for (c = cStart; c < cMax; ++c) {
3155       const PetscInt  newp = cStartNew + (c - cStart)*4;
3156       const PetscInt *cone, *ornt;
3157       PetscInt        coneNew[4], orntNew[4];
3158 
3159       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
3160       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
3161       /* A quad */
3162       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
3163       orntNew[0] = ornt[0];
3164       coneNew[1] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*4 + 0;
3165       orntNew[1] = 0;
3166       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*4 + 3;
3167       orntNew[2] = -2;
3168       coneNew[3] = fStartNew + (cone[3] - fStart)*2 + (ornt[3] < 0 ? 0 : 1);
3169       orntNew[3] = ornt[3];
3170       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
3171       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
3172 #if defined(PETSC_USE_DEBUG)
3173       if ((newp+0 < cStartNew) || (newp+0 >= cMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an interior cell [%D, %D)", newp+0, cStartNew, cMaxNew);
3174       for (p = 0; p < 4; ++p) {
3175         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an interior face [%D, %D)", coneNew[p], fStartNew, fMaxNew);
3176       }
3177 #endif
3178       /* B quad */
3179       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
3180       orntNew[0] = ornt[0];
3181       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
3182       orntNew[1] = ornt[1];
3183       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*4 + 1;
3184       orntNew[2] = 0;
3185       coneNew[3] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*4 + 0;
3186       orntNew[3] = -2;
3187       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
3188       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
3189 #if defined(PETSC_USE_DEBUG)
3190       if ((newp+1 < cStartNew) || (newp+1 >= cMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an interior cell [%D, %D)", newp+1, cStartNew, cMaxNew);
3191       for (p = 0; p < 4; ++p) {
3192         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an interior face [%D, %D)", coneNew[p], fStartNew, fMaxNew);
3193       }
3194 #endif
3195       /* C quad */
3196       coneNew[0] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*4 + 1;
3197       orntNew[0] = -2;
3198       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
3199       orntNew[1] = ornt[1];
3200       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
3201       orntNew[2] = ornt[2];
3202       coneNew[3] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*4 + 2;
3203       orntNew[3] = 0;
3204       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
3205       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
3206 #if defined(PETSC_USE_DEBUG)
3207       if ((newp+2 < cStartNew) || (newp+2 >= cMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an interior cell [%D, %D)", newp+2, cStartNew, cMaxNew);
3208       for (p = 0; p < 4; ++p) {
3209         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an interior face [%D, %D)", coneNew[p], fStartNew, fMaxNew);
3210       }
3211 #endif
3212       /* D quad */
3213       coneNew[0] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*4 + 3;
3214       orntNew[0] = 0;
3215       coneNew[1] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*4 + 2;
3216       orntNew[1] = -2;
3217       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
3218       orntNew[2] = ornt[2];
3219       coneNew[3] = fStartNew + (cone[3] - fStart)*2 + (ornt[3] < 0 ? 1 : 0);
3220       orntNew[3] = ornt[3];
3221       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
3222       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
3223 #if defined(PETSC_USE_DEBUG)
3224       if ((newp+3 < cStartNew) || (newp+3 >= cMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an interior cell [%D, %D)", newp+3, cStartNew, cMaxNew);
3225       for (p = 0; p < 4; ++p) {
3226         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an interior face [%D, %D)", coneNew[p], fStartNew, fMaxNew);
3227       }
3228 #endif
3229     }
3230     /*
3231      2----3----3
3232      |         |
3233      |    B    |
3234      |         |
3235      0----4--- 1
3236      |         |
3237      |    A    |
3238      |         |
3239      0----2----1
3240      */
3241     /* Hybrid cells have 4 faces */
3242     for (c = cMax; c < cEnd; ++c) {
3243       const PetscInt  newp = cStartNew + (cMax - cStart)*4 + (c - cMax)*2;
3244       const PetscInt *cone, *ornt;
3245       PetscInt        coneNew[4], orntNew[4];
3246 
3247       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
3248       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
3249       /* A quad */
3250       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
3251       orntNew[0] = ornt[0];
3252       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
3253       orntNew[1] = ornt[1];
3254       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*4 + (cone[2] - fMax);
3255       orntNew[2] = 0;
3256       coneNew[3] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*4 + (fEnd    - fMax) + (c - cMax);
3257       orntNew[3] = 0;
3258       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
3259       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
3260 #if defined(PETSC_USE_DEBUG)
3261       if ((newp+0 < cStartNew) || (newp+0 >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", newp+0, cStartNew, cEndNew);
3262       for (p = 0; p < 4; ++p) {
3263         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", coneNew[p], fStartNew, fEndNew);
3264       }
3265 #endif
3266       /* B quad */
3267       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
3268       orntNew[0] = ornt[0];
3269       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
3270       orntNew[1] = ornt[1];
3271       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*4 + (fEnd    - fMax) + (c - cMax);
3272       orntNew[2] = 0;
3273       coneNew[3] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*4 + (cone[3] - fMax);
3274       orntNew[3] = 0;
3275       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
3276       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
3277 #if defined(PETSC_USE_DEBUG)
3278       if ((newp+1 < cStartNew) || (newp+1 >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", newp+1, cStartNew, cEndNew);
3279       for (p = 0; p < 4; ++p) {
3280         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", coneNew[p], fStartNew, fEndNew);
3281       }
3282 #endif
3283     }
3284     /* Interior split faces have 2 vertices and the same cells as the parent */
3285     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
3286     ierr = PetscMalloc1(2 + maxSupportSize*2, &supportRef);CHKERRQ(ierr);
3287     for (f = fStart; f < fMax; ++f) {
3288       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);
3289 
3290       for (r = 0; r < 2; ++r) {
3291         const PetscInt  newp = fStartNew + (f - fStart)*2 + r;
3292         const PetscInt *cone, *ornt, *support;
3293         PetscInt        coneNew[2], coneSize, c, supportSize, s;
3294 
3295         ierr             = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
3296         coneNew[0]       = vStartNew + (cone[0] - vStart);
3297         coneNew[1]       = vStartNew + (cone[1] - vStart);
3298         coneNew[(r+1)%2] = newv;
3299         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3300 #if defined(PETSC_USE_DEBUG)
3301         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
3302         for (p = 0; p < 2; ++p) {
3303           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", coneNew[p], vStartNew, vEndNew);
3304         }
3305 #endif
3306         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
3307         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
3308         for (s = 0; s < supportSize; ++s) {
3309           if (support[s] >= cMax) {
3310             supportRef[s] = cStartNew + (cMax - cStart)*4 + (support[s] - cMax)*2 + r;
3311           } else {
3312             ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
3313             ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
3314             ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
3315             for (c = 0; c < coneSize; ++c) {
3316               if (cone[c] == f) break;
3317             }
3318             supportRef[s] = cStartNew + (support[s] - cStart)*4 + (ornt[c] < 0 ? (c+1-r)%4 : (c+r)%4);
3319           }
3320         }
3321         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
3322 #if defined(PETSC_USE_DEBUG)
3323         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
3324         for (p = 0; p < supportSize; ++p) {
3325           if ((supportRef[p] < cStartNew) || (supportRef[p] >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", supportRef[p], cStartNew, cEndNew);
3326         }
3327 #endif
3328       }
3329     }
3330     /* Interior cell faces have 2 vertices and 2 cells */
3331     for (c = cStart; c < cMax; ++c) {
3332       const PetscInt *cone;
3333 
3334       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
3335       for (r = 0; r < 4; ++r) {
3336         const PetscInt newp = fStartNew + (fMax - fStart)*2 + (c - cStart)*4 + r;
3337         PetscInt       coneNew[2], supportNew[2];
3338 
3339         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r] - fStart);
3340         coneNew[1] = vStartNew + (vEnd - vStart) + (fMax    - fStart) + (c - cStart);
3341         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3342 #if defined(PETSC_USE_DEBUG)
3343         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
3344         for (p = 0; p < 2; ++p) {
3345           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", coneNew[p], vStartNew, vEndNew);
3346         }
3347 #endif
3348         supportNew[0] = (c - cStart)*4 + r;
3349         supportNew[1] = (c - cStart)*4 + (r+1)%4;
3350         ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3351 #if defined(PETSC_USE_DEBUG)
3352         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
3353         for (p = 0; p < 2; ++p) {
3354           if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", supportNew[p], cStartNew, cEndNew);
3355         }
3356 #endif
3357       }
3358     }
3359     /* Hybrid faces have 2 vertices and the same cells */
3360     for (f = fMax; f < fEnd; ++f) {
3361       const PetscInt  newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*4 + (f - fMax);
3362       const PetscInt *cone, *support;
3363       PetscInt        coneNew[2], supportNew[2];
3364       PetscInt        size, s, r;
3365 
3366       ierr       = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
3367       coneNew[0] = vStartNew + (cone[0] - vStart);
3368       coneNew[1] = vStartNew + (cone[1] - vStart);
3369       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3370 #if defined(PETSC_USE_DEBUG)
3371       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
3372       for (p = 0; p < 2; ++p) {
3373         if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", coneNew[p], vStartNew, vEndNew);
3374       }
3375 #endif
3376       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
3377       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
3378       for (s = 0; s < size; ++s) {
3379         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
3380         for (r = 0; r < 2; ++r) {
3381           if (cone[r+2] == f) break;
3382         }
3383         supportNew[s] = (cMax - cStart)*4 + (support[s] - cMax)*2 + r;
3384       }
3385       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3386 #if defined(PETSC_USE_DEBUG)
3387       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
3388       for (p = 0; p < size; ++p) {
3389         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", supportNew[p], cStartNew, cEndNew);
3390       }
3391 #endif
3392     }
3393     /* Cell hybrid faces have 2 vertices and 2 cells */
3394     for (c = cMax; c < cEnd; ++c) {
3395       const PetscInt  newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*4 + (fEnd - fMax) + (c - cMax);
3396       const PetscInt *cone;
3397       PetscInt        coneNew[2], supportNew[2];
3398 
3399       ierr       = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
3400       coneNew[0] = vStartNew + (vEnd - vStart) + (cone[0] - fStart);
3401       coneNew[1] = vStartNew + (vEnd - vStart) + (cone[1] - fStart);
3402       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3403 #if defined(PETSC_USE_DEBUG)
3404       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
3405       for (p = 0; p < 2; ++p) {
3406         if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", coneNew[p], vStartNew, vEndNew);
3407       }
3408 #endif
3409       supportNew[0] = (cMax - cStart)*4 + (c - cMax)*2 + 0;
3410       supportNew[1] = (cMax - cStart)*4 + (c - cMax)*2 + 1;
3411       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3412 #if defined(PETSC_USE_DEBUG)
3413       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
3414       for (p = 0; p < 2; ++p) {
3415         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", supportNew[p], cStartNew, cEndNew);
3416       }
3417 #endif
3418     }
3419     /* Old vertices have identical supports */
3420     for (v = vStart; v < vEnd; ++v) {
3421       const PetscInt  newp = vStartNew + (v - vStart);
3422       const PetscInt *support, *cone;
3423       PetscInt        size, s;
3424 
3425       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
3426       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
3427       for (s = 0; s < size; ++s) {
3428         if (support[s] >= fMax) {
3429           supportRef[s] = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*4 + (support[s] - fMax);
3430         } else {
3431           PetscInt r = 0;
3432 
3433           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
3434           if (cone[1] == v) r = 1;
3435           supportRef[s] = fStartNew + (support[s] - fStart)*2 + r;
3436         }
3437       }
3438       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
3439 #if defined(PETSC_USE_DEBUG)
3440       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", newp, vStartNew, vEndNew);
3441       for (p = 0; p < size; ++p) {
3442         if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", supportRef[p], fStartNew, fEndNew);
3443       }
3444 #endif
3445     }
3446     /* Face vertices have 2 + cells supports */
3447     for (f = fStart; f < fMax; ++f) {
3448       const PetscInt  newp = vStartNew + (vEnd - vStart) + (f - fStart);
3449       const PetscInt *cone, *support;
3450       PetscInt        size, s;
3451 
3452       ierr          = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
3453       ierr          = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
3454       supportRef[0] = fStartNew + (f - fStart)*2 + 0;
3455       supportRef[1] = fStartNew + (f - fStart)*2 + 1;
3456       for (s = 0; s < size; ++s) {
3457         PetscInt r = 0;
3458 
3459         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
3460         if (support[s] >= cMax) {
3461           supportRef[2+s] = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*4 + (fEnd - fMax) + (support[s] - cMax);
3462         } else {
3463           if      (cone[1] == f) r = 1;
3464           else if (cone[2] == f) r = 2;
3465           else if (cone[3] == f) r = 3;
3466           supportRef[2+s] = fStartNew + (fMax - fStart)*2 + (support[s] - cStart)*4 + r;
3467         }
3468       }
3469       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
3470 #if defined(PETSC_USE_DEBUG)
3471       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", newp, vStartNew, vEndNew);
3472       for (p = 0; p < 2+size; ++p) {
3473         if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", supportRef[p], fStartNew, fEndNew);
3474       }
3475 #endif
3476     }
3477     /* Cell vertices have 4 supports */
3478     for (c = cStart; c < cMax; ++c) {
3479       const PetscInt newp = vStartNew + (vEnd - vStart) + (fMax - fStart) + (c - cStart);
3480       PetscInt       supportNew[4];
3481 
3482       for (r = 0; r < 4; ++r) {
3483         supportNew[r] = fStartNew + (fMax - fStart)*2 + (c - cStart)*4 + r;
3484       }
3485       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3486     }
3487     ierr = PetscFree(supportRef);CHKERRQ(ierr);
3488     break;
3489   case REFINER_SIMPLEX_3D:
3490     /* All cells have 4 faces: Tet face order is prescribed in DMPlexGetFaces_Internal() */
3491     ierr = DMPlexGetRawFaces_Internal(dm, 3, 4, cellInd, NULL, NULL, &faces);CHKERRQ(ierr);
3492     for (c = cStart; c < cEnd; ++c) {
3493       const PetscInt  newp = cStartNew + (c - cStart)*8;
3494       const PetscInt *cone, *ornt;
3495       PetscInt        coneNew[4], orntNew[4];
3496 
3497       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
3498       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
3499       /* A tetrahedron: {0, a, c, d} */
3500       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetTriSubface_Static(ornt[0], 0); /* A */
3501       orntNew[0] = ornt[0];
3502       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetTriSubface_Static(ornt[1], 0); /* A */
3503       orntNew[1] = ornt[1];
3504       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetTriSubface_Static(ornt[2], 0); /* A */
3505       orntNew[2] = ornt[2];
3506       coneNew[3] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 0;
3507       orntNew[3] = 0;
3508       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
3509       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
3510 #if defined(PETSC_USE_DEBUG)
3511       if ((newp+0 < cStartNew) || (newp+0 >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", newp+0, cStartNew, cEndNew);
3512       for (p = 0; p < 4; ++p) {
3513         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", coneNew[p], fStartNew, fEndNew);
3514       }
3515 #endif
3516       /* B tetrahedron: {a, 1, b, e} */
3517       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetTriSubface_Static(ornt[0], 1); /* B */
3518       orntNew[0] = ornt[0];
3519       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetTriSubface_Static(ornt[1], 2); /* C */
3520       orntNew[1] = ornt[1];
3521       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 1;
3522       orntNew[2] = 0;
3523       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetTriSubface_Static(ornt[3], 1); /* B */
3524       orntNew[3] = ornt[3];
3525       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
3526       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
3527 #if defined(PETSC_USE_DEBUG)
3528       if ((newp+1 < cStartNew) || (newp+1 >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", newp+1, cStartNew, cEndNew);
3529       for (p = 0; p < 4; ++p) {
3530         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", coneNew[p], fStartNew, fEndNew);
3531       }
3532 #endif
3533       /* C tetrahedron: {c, b, 2, f} */
3534       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetTriSubface_Static(ornt[0], 2); /* C */
3535       orntNew[0] = ornt[0];
3536       coneNew[1] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 2;
3537       orntNew[1] = 0;
3538       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetTriSubface_Static(ornt[2], 1); /* B */
3539       orntNew[2] = ornt[2];
3540       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetTriSubface_Static(ornt[3], 0); /* A */
3541       orntNew[3] = ornt[3];
3542       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
3543       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
3544 #if defined(PETSC_USE_DEBUG)
3545       if ((newp+2 < cStartNew) || (newp+2 >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", newp+2, cStartNew, cEndNew);
3546       for (p = 0; p < 4; ++p) {
3547         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", coneNew[p], fStartNew, fEndNew);
3548       }
3549 #endif
3550       /* D tetrahedron: {d, e, f, 3} */
3551       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 3;
3552       orntNew[0] = 0;
3553       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetTriSubface_Static(ornt[1], 1); /* B */
3554       orntNew[1] = ornt[1];
3555       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetTriSubface_Static(ornt[2], 2); /* C */
3556       orntNew[2] = ornt[2];
3557       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetTriSubface_Static(ornt[3], 2); /* C */
3558       orntNew[3] = ornt[3];
3559       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
3560       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
3561 #if defined(PETSC_USE_DEBUG)
3562       if ((newp+3 < cStartNew) || (newp+3 >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", newp+3, cStartNew, cEndNew);
3563       for (p = 0; p < 4; ++p) {
3564         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", coneNew[p], fStartNew, fEndNew);
3565       }
3566 #endif
3567       /* A' tetrahedron: {c, d, a, f} */
3568       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 0;
3569       orntNew[0] = -3;
3570       coneNew[1] = fStartNew + (cone[2] - fStart)*4 + 3;
3571       orntNew[1] = ornt[2] < 0 ? -(GetTriMidEdge_Static(ornt[2], 0)+1) : GetTriMidEdge_Static(ornt[2], 0);
3572       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 5;
3573       orntNew[2] = 0;
3574       coneNew[3] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 4;
3575       orntNew[3] = 2;
3576       ierr       = DMPlexSetCone(rdm, newp+4, coneNew);CHKERRQ(ierr);
3577       ierr       = DMPlexSetConeOrientation(rdm, newp+4, orntNew);CHKERRQ(ierr);
3578 #if defined(PETSC_USE_DEBUG)
3579       if ((newp+4 < cStartNew) || (newp+4 >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", newp+4, cStartNew, cEndNew);
3580       for (p = 0; p < 4; ++p) {
3581         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", coneNew[p], fStartNew, fEndNew);
3582       }
3583 #endif
3584       /* B' tetrahedron: {e, b, a, f} */
3585       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 1;
3586       orntNew[0] = -2;
3587       coneNew[1] = fStartNew + (cone[3] - fStart)*4 + 3;
3588       orntNew[1] = ornt[3] < 0 ? -(GetTriMidEdge_Static(ornt[3], 1)+1) : GetTriMidEdge_Static(ornt[3], 1);
3589       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 6;
3590       orntNew[2] = 0;
3591       coneNew[3] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 7;
3592       orntNew[3] = 0;
3593       ierr       = DMPlexSetCone(rdm, newp+5, coneNew);CHKERRQ(ierr);
3594       ierr       = DMPlexSetConeOrientation(rdm, newp+5, orntNew);CHKERRQ(ierr);
3595 #if defined(PETSC_USE_DEBUG)
3596       if ((newp+5 < cStartNew) || (newp+5 >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", newp+5, cStartNew, cEndNew);
3597       for (p = 0; p < 4; ++p) {
3598         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", coneNew[p], fStartNew, fEndNew);
3599       }
3600 #endif
3601       /* C' tetrahedron: {f, a, c, b} */
3602       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 5;
3603       orntNew[0] = -2;
3604       coneNew[1] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 7;
3605       orntNew[1] = -2;
3606       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 2;
3607       orntNew[2] = -1;
3608       coneNew[3] = fStartNew + (cone[0] - fStart)*4 + 3;
3609       orntNew[3] = ornt[0] < 0 ? -(GetTriMidEdge_Static(ornt[0], 2)+1) : GetTriMidEdge_Static(ornt[0], 2);
3610       ierr       = DMPlexSetCone(rdm, newp+6, coneNew);CHKERRQ(ierr);
3611       ierr       = DMPlexSetConeOrientation(rdm, newp+6, orntNew);CHKERRQ(ierr);
3612 #if defined(PETSC_USE_DEBUG)
3613       if ((newp+6 < cStartNew) || (newp+6 >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", newp+6, cStartNew, cEndNew);
3614       for (p = 0; p < 4; ++p) {
3615         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", coneNew[p], fStartNew, fEndNew);
3616       }
3617 #endif
3618       /* D' tetrahedron: {f, a, e, d} */
3619       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 6;
3620       orntNew[0] = -2;
3621       coneNew[1] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 4;
3622       orntNew[1] = -1;
3623       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 3;
3624       orntNew[2] = -2;
3625       coneNew[3] = fStartNew + (cone[1] - fStart)*4 + 3;
3626       orntNew[3] = ornt[1] < 0 ? -(GetTriMidEdge_Static(ornt[1], 1)+1) : GetTriMidEdge_Static(ornt[1], 1);
3627       ierr       = DMPlexSetCone(rdm, newp+7, coneNew);CHKERRQ(ierr);
3628       ierr       = DMPlexSetConeOrientation(rdm, newp+7, orntNew);CHKERRQ(ierr);
3629 #if defined(PETSC_USE_DEBUG)
3630       if ((newp+7 < cStartNew) || (newp+7 >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", newp+7, cStartNew, cEndNew);
3631       for (p = 0; p < 4; ++p) {
3632         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", coneNew[p], fStartNew, fEndNew);
3633       }
3634 #endif
3635     }
3636     /* Split faces have 3 edges and the same cells as the parent */
3637     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
3638     ierr = PetscMalloc1(2 + maxSupportSize*3, &supportRef);CHKERRQ(ierr);
3639     for (f = fStart; f < fEnd; ++f) {
3640       const PetscInt  newp = fStartNew + (f - fStart)*4;
3641       const PetscInt *cone, *ornt, *support;
3642       PetscInt        coneNew[3], orntNew[3], coneSize, supportSize, s;
3643 
3644       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
3645       ierr = DMPlexGetConeOrientation(dm, f, &ornt);CHKERRQ(ierr);
3646       /* A triangle */
3647       coneNew[0] = eStartNew + (cone[0] - eStart)*2 + (ornt[0] < 0 ? 1 : 0);
3648       orntNew[0] = ornt[0];
3649       coneNew[1] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 2;
3650       orntNew[1] = -2;
3651       coneNew[2] = eStartNew + (cone[2] - eStart)*2 + (ornt[2] < 0 ? 0 : 1);
3652       orntNew[2] = ornt[2];
3653       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
3654       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
3655 #if defined(PETSC_USE_DEBUG)
3656       if ((newp+0 < fStartNew) || (newp+0 >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp+0, fStartNew, fEndNew);
3657       for (p = 0; p < 3; ++p) {
3658         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", coneNew[p], eStartNew, eEndNew);
3659       }
3660 #endif
3661       /* B triangle */
3662       coneNew[0] = eStartNew + (cone[0] - eStart)*2 + (ornt[0] < 0 ? 0 : 1);
3663       orntNew[0] = ornt[0];
3664       coneNew[1] = eStartNew + (cone[1] - eStart)*2 + (ornt[1] < 0 ? 1 : 0);
3665       orntNew[1] = ornt[1];
3666       coneNew[2] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 0;
3667       orntNew[2] = -2;
3668       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
3669       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
3670 #if defined(PETSC_USE_DEBUG)
3671       if ((newp+1 < fStartNew) || (newp+1 >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp+1, fStartNew, fEndNew);
3672       for (p = 0; p < 3; ++p) {
3673         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", coneNew[p], eStartNew, eEndNew);
3674       }
3675 #endif
3676       /* C triangle */
3677       coneNew[0] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 1;
3678       orntNew[0] = -2;
3679       coneNew[1] = eStartNew + (cone[1] - eStart)*2 + (ornt[1] < 0 ? 0 : 1);
3680       orntNew[1] = ornt[1];
3681       coneNew[2] = eStartNew + (cone[2] - eStart)*2 + (ornt[2] < 0 ? 1 : 0);
3682       orntNew[2] = ornt[2];
3683       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
3684       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
3685 #if defined(PETSC_USE_DEBUG)
3686       if ((newp+2 < fStartNew) || (newp+2 >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp+2, fStartNew, fEndNew);
3687       for (p = 0; p < 3; ++p) {
3688         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", coneNew[p], eStartNew, eEndNew);
3689       }
3690 #endif
3691       /* D triangle */
3692       coneNew[0] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 0;
3693       orntNew[0] = 0;
3694       coneNew[1] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 1;
3695       orntNew[1] = 0;
3696       coneNew[2] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 2;
3697       orntNew[2] = 0;
3698       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
3699       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
3700 #if defined(PETSC_USE_DEBUG)
3701       if ((newp+3 < fStartNew) || (newp+3 >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp+3, fStartNew, fEndNew);
3702       for (p = 0; p < 3; ++p) {
3703         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", coneNew[p], eStartNew, eEndNew);
3704       }
3705 #endif
3706       ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
3707       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
3708       for (r = 0; r < 4; ++r) {
3709         for (s = 0; s < supportSize; ++s) {
3710           PetscInt subf;
3711           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
3712           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
3713           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
3714           for (c = 0; c < coneSize; ++c) {
3715             if (cone[c] == f) break;
3716           }
3717           subf = GetTriSubfaceInverse_Static(ornt[c], r);
3718           supportRef[s] = cStartNew + (support[s] - cStart)*8 + (r==3 ? (c+2)%4 + 4 : faces[c*3+subf]);
3719         }
3720         ierr = DMPlexSetSupport(rdm, newp+r, supportRef);CHKERRQ(ierr);
3721 #if defined(PETSC_USE_DEBUG)
3722         if ((newp+r < fStartNew) || (newp+r >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp+r, fStartNew, fEndNew);
3723         for (p = 0; p < supportSize; ++p) {
3724           if ((supportRef[p] < cStartNew) || (supportRef[p] >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", supportRef[p], cStartNew, cEndNew);
3725         }
3726 #endif
3727       }
3728     }
3729     /* Interior faces have 3 edges and 2 cells */
3730     for (c = cStart; c < cEnd; ++c) {
3731       PetscInt        newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*8;
3732       const PetscInt *cone, *ornt;
3733       PetscInt        coneNew[3], orntNew[3];
3734       PetscInt        supportNew[2];
3735 
3736       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
3737       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
3738       /* Face A: {c, a, d} */
3739       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*3 + GetTriMidEdge_Static(ornt[0], 2);
3740       orntNew[0] = ornt[0] < 0 ? -2 : 0;
3741       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*3 + GetTriMidEdge_Static(ornt[1], 2);
3742       orntNew[1] = ornt[1] < 0 ? -2 : 0;
3743       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*3 + GetTriMidEdge_Static(ornt[2], 2);
3744       orntNew[2] = ornt[2] < 0 ? -2 : 0;
3745       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3746       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3747 #if defined(PETSC_USE_DEBUG)
3748       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
3749       for (p = 0; p < 3; ++p) {
3750         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", coneNew[p], eStartNew, eEndNew);
3751       }
3752 #endif
3753       supportNew[0] = (c - cStart)*8 + 0;
3754       supportNew[1] = (c - cStart)*8 + 0+4;
3755       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3756 #if defined(PETSC_USE_DEBUG)
3757       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
3758       for (p = 0; p < 2; ++p) {
3759         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", supportNew[p], cStartNew, cEndNew);
3760       }
3761 #endif
3762       ++newp;
3763       /* Face B: {a, b, e} */
3764       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*3 + GetTriMidEdge_Static(ornt[0], 0);
3765       orntNew[0] = ornt[0] < 0 ? -2 : 0;
3766       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*3 + GetTriMidEdge_Static(ornt[3], 0);
3767       orntNew[1] = ornt[3] < 0 ? -2 : 0;
3768       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*3 + GetTriMidEdge_Static(ornt[1], 1);
3769       orntNew[2] = ornt[1] < 0 ? -2 : 0;
3770       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3771       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3772 #if defined(PETSC_USE_DEBUG)
3773       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
3774       for (p = 0; p < 3; ++p) {
3775         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", coneNew[p], eStartNew, eEndNew);
3776       }
3777 #endif
3778       supportNew[0] = (c - cStart)*8 + 1;
3779       supportNew[1] = (c - cStart)*8 + 1+4;
3780       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3781 #if defined(PETSC_USE_DEBUG)
3782       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
3783       for (p = 0; p < 2; ++p) {
3784         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", supportNew[p], cStartNew, cEndNew);
3785       }
3786 #endif
3787       ++newp;
3788       /* Face C: {c, f, b} */
3789       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*3 + GetTriMidEdge_Static(ornt[2], 0);
3790       orntNew[0] = ornt[2] < 0 ? -2 : 0;
3791       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*3 + GetTriMidEdge_Static(ornt[3], 2);
3792       orntNew[1] = ornt[3] < 0 ? -2 : 0;
3793       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*3 + GetTriMidEdge_Static(ornt[0], 1);
3794       orntNew[2] = ornt[0] < 0 ? -2 : 0;
3795       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3796       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3797 #if defined(PETSC_USE_DEBUG)
3798       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
3799       for (p = 0; p < 3; ++p) {
3800         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", coneNew[p], eStartNew, eEndNew);
3801       }
3802 #endif
3803       supportNew[0] = (c - cStart)*8 + 2;
3804       supportNew[1] = (c - cStart)*8 + 2+4;
3805       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3806 #if defined(PETSC_USE_DEBUG)
3807       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
3808       for (p = 0; p < 2; ++p) {
3809         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", supportNew[p], cStartNew, cEndNew);
3810       }
3811 #endif
3812       ++newp;
3813       /* Face D: {d, e, f} */
3814       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*3 + GetTriMidEdge_Static(ornt[1], 0);
3815       orntNew[0] = ornt[1] < 0 ? -2 : 0;
3816       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*3 + GetTriMidEdge_Static(ornt[3], 1);
3817       orntNew[1] = ornt[3] < 0 ? -2 : 0;
3818       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*3 + GetTriMidEdge_Static(ornt[2], 1);
3819       orntNew[2] = ornt[2] < 0 ? -2 : 0;
3820       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3821       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3822 #if defined(PETSC_USE_DEBUG)
3823       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
3824       for (p = 0; p < 3; ++p) {
3825         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", coneNew[p], eStartNew, eEndNew);
3826       }
3827 #endif
3828       supportNew[0] = (c - cStart)*8 + 3;
3829       supportNew[1] = (c - cStart)*8 + 3+4;
3830       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3831 #if defined(PETSC_USE_DEBUG)
3832       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
3833       for (p = 0; p < 2; ++p) {
3834         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", supportNew[p], cStartNew, cEndNew);
3835       }
3836 #endif
3837       ++newp;
3838       /* Face E: {d, f, a} */
3839       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*3 + GetTriMidEdge_Static(ornt[2], 1);
3840       orntNew[0] = ornt[2] < 0 ? 0 : -2;
3841       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart);
3842       orntNew[1] = -2;
3843       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*3 + GetTriMidEdge_Static(ornt[1], 2);
3844       orntNew[2] = ornt[1] < 0 ? -2 : 0;
3845       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3846       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3847 #if defined(PETSC_USE_DEBUG)
3848       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
3849       for (p = 0; p < 3; ++p) {
3850         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", coneNew[p], eStartNew, eEndNew);
3851       }
3852 #endif
3853       supportNew[0] = (c - cStart)*8 + 0+4;
3854       supportNew[1] = (c - cStart)*8 + 3+4;
3855       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3856 #if defined(PETSC_USE_DEBUG)
3857       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
3858       for (p = 0; p < 2; ++p) {
3859         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", supportNew[p], cStartNew, cEndNew);
3860       }
3861 #endif
3862       ++newp;
3863       /* Face F: {c, a, f} */
3864       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*3 + GetTriMidEdge_Static(ornt[0], 2);
3865       orntNew[0] = ornt[0] < 0 ? -2 : 0;
3866       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart);
3867       orntNew[1] = 0;
3868       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*3 + GetTriMidEdge_Static(ornt[2], 0);
3869       orntNew[2] = ornt[2] < 0 ? 0 : -2;
3870       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3871       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3872 #if defined(PETSC_USE_DEBUG)
3873       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
3874       for (p = 0; p < 3; ++p) {
3875         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", coneNew[p], eStartNew, eEndNew);
3876       }
3877 #endif
3878       supportNew[0] = (c - cStart)*8 + 0+4;
3879       supportNew[1] = (c - cStart)*8 + 2+4;
3880       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3881 #if defined(PETSC_USE_DEBUG)
3882       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
3883       for (p = 0; p < 2; ++p) {
3884         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", supportNew[p], cStartNew, cEndNew);
3885       }
3886 #endif
3887       ++newp;
3888       /* Face G: {e, a, f} */
3889       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*3 + GetTriMidEdge_Static(ornt[1], 1);
3890       orntNew[0] = ornt[1] < 0 ? -2 : 0;
3891       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart);
3892       orntNew[1] = 0;
3893       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*3 + GetTriMidEdge_Static(ornt[3], 1);
3894       orntNew[2] = ornt[3] < 0 ? 0 : -2;
3895       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3896       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3897 #if defined(PETSC_USE_DEBUG)
3898       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
3899       for (p = 0; p < 3; ++p) {
3900         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", coneNew[p], eStartNew, eEndNew);
3901       }
3902 #endif
3903       supportNew[0] = (c - cStart)*8 + 1+4;
3904       supportNew[1] = (c - cStart)*8 + 3+4;
3905       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3906 #if defined(PETSC_USE_DEBUG)
3907       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
3908       for (p = 0; p < 2; ++p) {
3909         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", supportNew[p], cStartNew, cEndNew);
3910       }
3911 #endif
3912       ++newp;
3913       /* Face H: {a, b, f} */
3914       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*3 + GetTriMidEdge_Static(ornt[0], 0);
3915       orntNew[0] = ornt[0] < 0 ? -2 : 0;
3916       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*3 + GetTriMidEdge_Static(ornt[3], 2);
3917       orntNew[1] = ornt[3] < 0 ? 0 : -2;
3918       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart);
3919       orntNew[2] = -2;
3920       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3921       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3922 #if defined(PETSC_USE_DEBUG)
3923       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
3924       for (p = 0; p < 3; ++p) {
3925         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", coneNew[p], eStartNew, eEndNew);
3926       }
3927 #endif
3928       supportNew[0] = (c - cStart)*8 + 1+4;
3929       supportNew[1] = (c - cStart)*8 + 2+4;
3930       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3931 #if defined(PETSC_USE_DEBUG)
3932       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
3933       for (p = 0; p < 2; ++p) {
3934         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", supportNew[p], cStartNew, cEndNew);
3935       }
3936 #endif
3937       ++newp;
3938     }
3939     /* Split Edges have 2 vertices and the same faces as the parent */
3940     for (e = eStart; e < eEnd; ++e) {
3941       const PetscInt newv = vStartNew + (vEnd - vStart) + (e - eStart);
3942 
3943       for (r = 0; r < 2; ++r) {
3944         const PetscInt  newp = eStartNew + (e - eStart)*2 + r;
3945         const PetscInt *cone, *ornt, *support;
3946         PetscInt        coneNew[2], coneSize, c, supportSize, s;
3947 
3948         ierr             = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
3949         coneNew[0]       = vStartNew + (cone[0] - vStart);
3950         coneNew[1]       = vStartNew + (cone[1] - vStart);
3951         coneNew[(r+1)%2] = newv;
3952         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3953 #if defined(PETSC_USE_DEBUG)
3954         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eEndNew);
3955         for (p = 0; p < 2; ++p) {
3956           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", coneNew[p], vStartNew, vEndNew);
3957         }
3958 #endif
3959         ierr = DMPlexGetSupportSize(dm, e, &supportSize);CHKERRQ(ierr);
3960         ierr = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
3961         for (s = 0; s < supportSize; ++s) {
3962           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
3963           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
3964           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
3965           for (c = 0; c < coneSize; ++c) {
3966             if (cone[c] == e) break;
3967           }
3968           supportRef[s] = fStartNew + (support[s] - fStart)*4 + (c + (ornt[c] < 0 ? 1-r : r))%3;
3969         }
3970         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
3971 #if defined(PETSC_USE_DEBUG)
3972         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eEndNew);
3973         for (p = 0; p < supportSize; ++p) {
3974           if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", supportRef[p], fStartNew, fEndNew);
3975         }
3976 #endif
3977       }
3978     }
3979     /* Face edges have 2 vertices and 2+cells*(1/2) faces */
3980     for (f = fStart; f < fEnd; ++f) {
3981       const PetscInt *cone, *ornt, *support;
3982       PetscInt        coneSize, supportSize, s;
3983 
3984       ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
3985       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
3986       for (r = 0; r < 3; ++r) {
3987         const PetscInt  newp = eStartNew + (eEnd - eStart)*2 + (f - fStart)*3 + r;
3988         PetscInt        coneNew[2], intFaces = 0, er, eint[4] = {1, 0, 2, 0};
3989         PetscInt        fint[24] = { 1,  7, -1, -1,  0,  5,
3990                                     -1, -1,  1,  6,  0,  4,
3991                                      2,  5,  3,  4, -1, -1,
3992                                     -1, -1,  3,  6,  2,  7};
3993 
3994         ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
3995         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[(r+0)%3] - eStart);
3996         coneNew[1] = vStartNew + (vEnd - vStart) + (cone[(r+1)%3] - eStart);
3997         ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3998 #if defined(PETSC_USE_DEBUG)
3999         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eEndNew);
4000         for (p = 0; p < 2; ++p) {
4001           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", coneNew[p], vStartNew, vEndNew);
4002         }
4003 #endif
4004         supportRef[0] = fStartNew + (f - fStart)*4 + (r+1)%3;
4005         supportRef[1] = fStartNew + (f - fStart)*4 + 3;
4006         for (s = 0; s < supportSize; ++s) {
4007           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
4008           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
4009           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
4010           for (c = 0; c < coneSize; ++c) {if (cone[c] == f) break;}
4011           /* Here we want to determine whether edge newp contains a vertex which is part of the cross-tet edge */
4012           er = GetTriMidEdgeInverse_Static(ornt[c], r);
4013           if (er == eint[c]) {
4014             supportRef[2+intFaces++] = fStartNew + (fEnd - fStart)*4 + (support[s] - cStart)*8 + (c + 2)%4;
4015           } else {
4016             supportRef[2+intFaces++] = fStartNew + (fEnd - fStart)*4 + (support[s] - cStart)*8 + fint[(c*3 + er)*2 + 0];
4017             supportRef[2+intFaces++] = fStartNew + (fEnd - fStart)*4 + (support[s] - cStart)*8 + fint[(c*3 + er)*2 + 1];
4018           }
4019         }
4020         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
4021 #if defined(PETSC_USE_DEBUG)
4022         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eEndNew);
4023         for (p = 0; p < intFaces; ++p) {
4024           if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", supportRef[p], fStartNew, fEndNew);
4025         }
4026 #endif
4027       }
4028     }
4029     /* Interior edges have 2 vertices and 4 faces */
4030     for (c = cStart; c < cEnd; ++c) {
4031       const PetscInt  newp = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart);
4032       const PetscInt *cone, *ornt, *fcone;
4033       PetscInt        coneNew[2], supportNew[4], find;
4034 
4035       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
4036       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
4037       ierr = DMPlexGetCone(dm, cone[0], &fcone);CHKERRQ(ierr);
4038       find = GetTriEdge_Static(ornt[0], 0);
4039       coneNew[0] = vStartNew + (vEnd - vStart) + (fcone[find] - eStart);
4040       ierr = DMPlexGetCone(dm, cone[2], &fcone);CHKERRQ(ierr);
4041       find = GetTriEdge_Static(ornt[2], 1);
4042       coneNew[1] = vStartNew + (vEnd - vStart) + (fcone[find] - eStart);
4043       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4044 #if defined(PETSC_USE_DEBUG)
4045       if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eEndNew);
4046       for (p = 0; p < 2; ++p) {
4047         if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", coneNew[p], vStartNew, vEndNew);
4048       }
4049 #endif
4050       supportNew[0] = fStartNew + (fEnd - fStart)*4 + (c - cStart)*8 + 4;
4051       supportNew[1] = fStartNew + (fEnd - fStart)*4 + (c - cStart)*8 + 5;
4052       supportNew[2] = fStartNew + (fEnd - fStart)*4 + (c - cStart)*8 + 6;
4053       supportNew[3] = fStartNew + (fEnd - fStart)*4 + (c - cStart)*8 + 7;
4054       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
4055 #if defined(PETSC_USE_DEBUG)
4056       if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eEndNew);
4057       for (p = 0; p < 4; ++p) {
4058         if ((supportNew[p] < fStartNew) || (supportNew[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", supportNew[p], fStartNew, fEndNew);
4059       }
4060 #endif
4061     }
4062     /* Old vertices have identical supports */
4063     for (v = vStart; v < vEnd; ++v) {
4064       const PetscInt  newp = vStartNew + (v - vStart);
4065       const PetscInt *support, *cone;
4066       PetscInt        size, s;
4067 
4068       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
4069       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
4070       for (s = 0; s < size; ++s) {
4071         PetscInt r = 0;
4072 
4073         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
4074         if (cone[1] == v) r = 1;
4075         supportRef[s] = eStartNew + (support[s] - eStart)*2 + r;
4076       }
4077       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
4078 #if defined(PETSC_USE_DEBUG)
4079       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", newp, vStartNew, vEndNew);
4080       for (p = 0; p < size; ++p) {
4081         if ((supportRef[p] < eStartNew) || (supportRef[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", supportRef[p], eStartNew, eEndNew);
4082       }
4083 #endif
4084     }
4085     /* Edge vertices have 2 + face*2 + 0/1 supports */
4086     for (e = eStart; e < eEnd; ++e) {
4087       const PetscInt  newp = vStartNew + (vEnd - vStart) + (e - eStart);
4088       const PetscInt *cone, *support;
4089       PetscInt       *star = NULL, starSize, cellSize = 0, coneSize, size, s;
4090 
4091       ierr          = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
4092       ierr          = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
4093       supportRef[0] = eStartNew + (e - eStart)*2 + 0;
4094       supportRef[1] = eStartNew + (e - eStart)*2 + 1;
4095       for (s = 0; s < size; ++s) {
4096         PetscInt r = 0;
4097 
4098         ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
4099         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
4100         for (r = 0; r < coneSize; ++r) {if (cone[r] == e) break;}
4101         supportRef[2+s*2+0] = eStartNew + (eEnd - eStart)*2 + (support[s] - fStart)*3 + (r+0)%3;
4102         supportRef[2+s*2+1] = eStartNew + (eEnd - eStart)*2 + (support[s] - fStart)*3 + (r+2)%3;
4103       }
4104       ierr = DMPlexGetTransitiveClosure(dm, e, PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
4105       for (s = 0; s < starSize*2; s += 2) {
4106         const PetscInt *cone, *ornt;
4107         PetscInt        e01, e23;
4108 
4109         if ((star[s] >= cStart) && (star[s] < cEnd)) {
4110           /* Check edge 0-1 */
4111           ierr = DMPlexGetCone(dm, star[s], &cone);CHKERRQ(ierr);
4112           ierr = DMPlexGetConeOrientation(dm, star[s], &ornt);CHKERRQ(ierr);
4113           ierr = DMPlexGetCone(dm, cone[0], &cone);CHKERRQ(ierr);
4114           e01  = cone[GetTriEdge_Static(ornt[0], 0)];
4115           /* Check edge 2-3 */
4116           ierr = DMPlexGetCone(dm, star[s], &cone);CHKERRQ(ierr);
4117           ierr = DMPlexGetConeOrientation(dm, star[s], &ornt);CHKERRQ(ierr);
4118           ierr = DMPlexGetCone(dm, cone[2], &cone);CHKERRQ(ierr);
4119           e23  = cone[GetTriEdge_Static(ornt[2], 1)];
4120           if ((e01 == e) || (e23 == e)) {supportRef[2+size*2+cellSize++] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (star[s] - cStart);}
4121         }
4122       }
4123       ierr = DMPlexRestoreTransitiveClosure(dm, e, PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
4124       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
4125 #if defined(PETSC_USE_DEBUG)
4126       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", newp, vStartNew, vEndNew);
4127       for (p = 0; p < 2+size*2+cellSize; ++p) {
4128         if ((supportRef[p] < eStartNew) || (supportRef[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", supportRef[p], eStartNew, eEndNew);
4129       }
4130 #endif
4131     }
4132     ierr = PetscFree(supportRef);CHKERRQ(ierr);
4133     ierr = DMPlexRestoreFaces_Internal(dm, 3, cStart, NULL, NULL, &faces);CHKERRQ(ierr);
4134     break;
4135   case REFINER_HYBRID_SIMPLEX_3D:
4136     ierr = DMPlexGetHybridBounds(rdm, &cMaxNew, &fMaxNew, &eMaxNew, NULL);CHKERRQ(ierr);
4137     /* Interior cells have 4 faces: Tet face order is prescribed in DMPlexGetFaces_Internal() */
4138     ierr = DMPlexGetRawFaces_Internal(dm, 3, 4, cellInd, NULL, NULL, &faces);CHKERRQ(ierr);
4139     for (c = cStart; c < cMax; ++c) {
4140       const PetscInt  newp = cStartNew + (c - cStart)*8;
4141       const PetscInt *cone, *ornt;
4142       PetscInt        coneNew[4], orntNew[4];
4143 
4144       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
4145       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
4146       /* A tetrahedron: {0, a, c, d} */
4147       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetTriSubface_Static(ornt[0], 0); /* A */
4148       orntNew[0] = ornt[0];
4149       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetTriSubface_Static(ornt[1], 0); /* A */
4150       orntNew[1] = ornt[1];
4151       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetTriSubface_Static(ornt[2], 0); /* A */
4152       orntNew[2] = ornt[2];
4153       coneNew[3] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 0;
4154       orntNew[3] = 0;
4155       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
4156       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
4157 #if defined(PETSC_USE_DEBUG)
4158       if ((newp+0 < cStartNew) || (newp+0 >= cMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", newp+0, cStartNew, cMaxNew);
4159       for (p = 0; p < 4; ++p) {
4160         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", coneNew[p], fStartNew, fMaxNew);
4161       }
4162 #endif
4163       /* B tetrahedron: {a, 1, b, e} */
4164       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetTriSubface_Static(ornt[0], 1); /* B */
4165       orntNew[0] = ornt[0];
4166       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetTriSubface_Static(ornt[1], 2); /* C */
4167       orntNew[1] = ornt[1];
4168       coneNew[2] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 1;
4169       orntNew[2] = 0;
4170       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetTriSubface_Static(ornt[3], 1); /* B */
4171       orntNew[3] = ornt[3];
4172       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
4173       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
4174 #if defined(PETSC_USE_DEBUG)
4175       if ((newp+1 < cStartNew) || (newp+1 >= cMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", newp+1, cStartNew, cMaxNew);
4176       for (p = 0; p < 4; ++p) {
4177         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", coneNew[p], fStartNew, fMaxNew);
4178       }
4179 #endif
4180       /* C tetrahedron: {c, b, 2, f} */
4181       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetTriSubface_Static(ornt[0], 2); /* C */
4182       orntNew[0] = ornt[0];
4183       coneNew[1] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 2;
4184       orntNew[1] = 0;
4185       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetTriSubface_Static(ornt[2], 1); /* B */
4186       orntNew[2] = ornt[2];
4187       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetTriSubface_Static(ornt[3], 0); /* A */
4188       orntNew[3] = ornt[3];
4189       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
4190       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
4191 #if defined(PETSC_USE_DEBUG)
4192       if ((newp+2 < cStartNew) || (newp+2 >= cMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", newp+2, cStartNew, cMaxNew);
4193       for (p = 0; p < 4; ++p) {
4194         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", coneNew[p], fStartNew, fMaxNew);
4195       }
4196 #endif
4197       /* D tetrahedron: {d, e, f, 3} */
4198       coneNew[0] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 3;
4199       orntNew[0] = 0;
4200       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetTriSubface_Static(ornt[1], 1); /* B */
4201       orntNew[1] = ornt[1];
4202       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetTriSubface_Static(ornt[2], 2); /* C */
4203       orntNew[2] = ornt[2];
4204       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetTriSubface_Static(ornt[3], 2); /* C */
4205       orntNew[3] = ornt[3];
4206       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
4207       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
4208 #if defined(PETSC_USE_DEBUG)
4209       if ((newp+3 < cStartNew) || (newp+3 >= cMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", newp+3, cStartNew, cMaxNew);
4210       for (p = 0; p < 4; ++p) {
4211         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", coneNew[p], fStartNew, fMaxNew);
4212       }
4213 #endif
4214       /* A' tetrahedron: {d, a, c, f} */
4215       coneNew[0] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 0;
4216       orntNew[0] = -3;
4217       coneNew[1] = fStartNew + (cone[2] - fStart)*4 + 3;
4218       orntNew[1] = ornt[2] < 0 ? -(GetTriMidEdge_Static(ornt[2], 0)+1) : GetTriMidEdge_Static(ornt[2], 0);
4219       coneNew[2] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 5;
4220       orntNew[2] = 0;
4221       coneNew[3] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 4;
4222       orntNew[3] = 2;
4223       ierr       = DMPlexSetCone(rdm, newp+4, coneNew);CHKERRQ(ierr);
4224       ierr       = DMPlexSetConeOrientation(rdm, newp+4, orntNew);CHKERRQ(ierr);
4225 #if defined(PETSC_USE_DEBUG)
4226       if ((newp+4 < cStartNew) || (newp+4 >= cMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", newp+4, cStartNew, cMaxNew);
4227       for (p = 0; p < 4; ++p) {
4228         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", coneNew[p], fStartNew, fMaxNew);
4229       }
4230 #endif
4231       /* B' tetrahedron: {e, b, a, f} */
4232       coneNew[0] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 1;
4233       orntNew[0] = -3;
4234       coneNew[1] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 6;
4235       orntNew[1] = 1;
4236       coneNew[2] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 7;
4237       orntNew[2] = 0;
4238       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + 3;
4239       orntNew[3] = ornt[3] < 0 ? -(GetTriMidEdge_Static(ornt[3], 0)+1) : GetTriMidEdge_Static(ornt[3], 0);
4240       ierr       = DMPlexSetCone(rdm, newp+5, coneNew);CHKERRQ(ierr);
4241       ierr       = DMPlexSetConeOrientation(rdm, newp+5, orntNew);CHKERRQ(ierr);
4242 #if defined(PETSC_USE_DEBUG)
4243       if ((newp+5 < cStartNew) || (newp+5 >= cMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", newp+5, cStartNew, cMaxNew);
4244       for (p = 0; p < 4; ++p) {
4245         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", coneNew[p], fStartNew, fMaxNew);
4246       }
4247 #endif
4248       /* C' tetrahedron: {b, f, c, a} */
4249       coneNew[0] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 2;
4250       orntNew[0] = -3;
4251       coneNew[1] = fStartNew + (cone[0] - fStart)*4 + 3;
4252       orntNew[1] = ornt[0] < 0 ? -(GetTriMidEdge_Static(ornt[0], 2)+1) : GetTriMidEdge_Static(ornt[0], 2);
4253       coneNew[2] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 5;
4254       orntNew[2] = -3;
4255       coneNew[3] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 7;
4256       orntNew[3] = -2;
4257       ierr       = DMPlexSetCone(rdm, newp+6, coneNew);CHKERRQ(ierr);
4258       ierr       = DMPlexSetConeOrientation(rdm, newp+6, orntNew);CHKERRQ(ierr);
4259 #if defined(PETSC_USE_DEBUG)
4260       if ((newp+6 < cStartNew) || (newp+6 >= cMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", newp+6, cStartNew, cMaxNew);
4261       for (p = 0; p < 4; ++p) {
4262         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", coneNew[p], fStartNew, fMaxNew);
4263       }
4264 #endif
4265       /* D' tetrahedron: {f, e, d, a} */
4266       coneNew[0] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 3;
4267       orntNew[0] = -3;
4268       coneNew[1] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 4;
4269       orntNew[1] = -3;
4270       coneNew[2] = fStartNew + (cone[1] - fStart)*4 + 3;
4271       orntNew[2] = ornt[1] < 0 ? -(GetTriMidEdge_Static(ornt[1], 0)+1) : GetTriMidEdge_Static(ornt[1], 0);
4272       coneNew[3] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 6;
4273       orntNew[3] = -3;
4274       ierr       = DMPlexSetCone(rdm, newp+7, coneNew);CHKERRQ(ierr);
4275       ierr       = DMPlexSetConeOrientation(rdm, newp+7, orntNew);CHKERRQ(ierr);
4276 #if defined(PETSC_USE_DEBUG)
4277       if ((newp+7 < cStartNew) || (newp+7 >= cMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", newp+7, cStartNew, cMaxNew);
4278       for (p = 0; p < 4; ++p) {
4279         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", coneNew[p], fStartNew, fMaxNew);
4280       }
4281 #endif
4282     }
4283     /* Hybrid cells have 5 faces */
4284     for (c = cMax; c < cEnd; ++c) {
4285       const PetscInt  newp = cStartNew + (cMax - cStart)*8 + (c - cMax)*4;
4286       const PetscInt *cone, *ornt, *fornt;
4287       PetscInt        coneNew[5], orntNew[5], o, of, i;
4288 
4289       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
4290       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
4291       ierr = DMPlexGetConeOrientation(dm, cone[0], &fornt);CHKERRQ(ierr);
4292       o = ornt[0] < 0 ? -1 : 1;
4293       for (r = 0; r < 3; ++r) {
4294         coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetTriSubface_Static(ornt[0], r);
4295         orntNew[0] = ornt[0];
4296         coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetTriSubface_Static(ornt[1], r);
4297         orntNew[1] = ornt[1];
4298         of = fornt[GetTriEdge_Static(ornt[0], r)]       < 0 ? -1 : 1;
4299         i  = GetTriEdgeInverse_Static(ornt[0], r)       + 2;
4300         coneNew[i] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (cone[2+GetTriEdge_Static(ornt[0], r)]       - fMax)*2 + (o*of < 0 ? 1 : 0);
4301         orntNew[i] = 0;
4302         i  = GetTriEdgeInverse_Static(ornt[0], (r+1)%3) + 2;
4303         coneNew[i] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (c - cMax)*3 + GetTriSubface_Static(ornt[0], r);
4304         orntNew[i] = 0;
4305         of = fornt[GetTriEdge_Static(ornt[0], (r+2)%3)] < 0 ? -1 : 1;
4306         i  = GetTriEdgeInverse_Static(ornt[0], (r+2)%3) + 2;
4307         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);
4308         orntNew[i] = 0;
4309         ierr = DMPlexSetCone(rdm, newp+r, coneNew);CHKERRQ(ierr);
4310         ierr = DMPlexSetConeOrientation(rdm, newp+r, orntNew);CHKERRQ(ierr);
4311 #if defined(PETSC_USE_DEBUG)
4312         if ((newp+r < cMaxNew) || (newp+r >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a hybrid cell [%D, %D)", newp+r, cMaxNew, cEndNew);
4313         for (p = 0; p < 2; ++p) {
4314           if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", coneNew[p], fStartNew, fMaxNew);
4315         }
4316         for (p = 2; p < 5; ++p) {
4317           if ((coneNew[p] < fMaxNew)   || (coneNew[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a hybrid face [%D, %D)", coneNew[p], fMaxNew, fEndNew);
4318         }
4319 #endif
4320       }
4321       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + 3;
4322       orntNew[0] = 0;
4323       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + 3;
4324       orntNew[1] = 0;
4325       coneNew[2] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (c - cMax)*3 + 1;
4326       orntNew[2] = 0;
4327       coneNew[3] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (c - cMax)*3 + 2;
4328       orntNew[3] = 0;
4329       coneNew[4] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (c - cMax)*3 + 0;
4330       orntNew[4] = 0;
4331       ierr = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
4332       ierr = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
4333 #if defined(PETSC_USE_DEBUG)
4334       if ((newp+3 < cMaxNew) || (newp+3 >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a hybrid cell [%D, %D)", newp+3, cMaxNew, cEndNew);
4335       for (p = 0; p < 2; ++p) {
4336         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", coneNew[p], fStartNew, fMaxNew);
4337       }
4338       for (p = 2; p < 5; ++p) {
4339         if ((coneNew[p] < fMaxNew)   || (coneNew[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a hybrid face [%D, %D)", coneNew[p], fMaxNew, fEndNew);
4340       }
4341 #endif
4342     }
4343     /* Split faces have 3 edges and the same cells as the parent */
4344     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
4345     ierr = PetscMalloc1(2 + maxSupportSize*2, &supportRef);CHKERRQ(ierr);
4346     for (f = fStart; f < fMax; ++f) {
4347       const PetscInt  newp = fStartNew + (f - fStart)*4;
4348       const PetscInt *cone, *ornt, *support;
4349       PetscInt        coneNew[3], orntNew[3], coneSize, supportSize, s;
4350 
4351       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
4352       ierr = DMPlexGetConeOrientation(dm, f, &ornt);CHKERRQ(ierr);
4353       /* A triangle */
4354       coneNew[0] = eStartNew + (cone[0] - eStart)*2 + (ornt[0] < 0 ? 1 : 0);
4355       orntNew[0] = ornt[0];
4356       coneNew[1] = eStartNew + (eMax    - eStart)*2 + (f - fStart)*3 + 2;
4357       orntNew[1] = -2;
4358       coneNew[2] = eStartNew + (cone[2] - eStart)*2 + (ornt[2] < 0 ? 0 : 1);
4359       orntNew[2] = ornt[2];
4360       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
4361       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
4362 #if defined(PETSC_USE_DEBUG)
4363       if ((newp+0 < fStartNew) || (newp+0 >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp+0, fStartNew, fMaxNew);
4364       for (p = 0; p < 3; ++p) {
4365         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", coneNew[p], eStartNew, eMaxNew);
4366       }
4367 #endif
4368       /* B triangle */
4369       coneNew[0] = eStartNew + (cone[0] - eStart)*2 + (ornt[0] < 0 ? 0 : 1);
4370       orntNew[0] = ornt[0];
4371       coneNew[1] = eStartNew + (cone[1] - eStart)*2 + (ornt[1] < 0 ? 1 : 0);
4372       orntNew[1] = ornt[1];
4373       coneNew[2] = eStartNew + (eMax    - eStart)*2 + (f - fStart)*3 + 0;
4374       orntNew[2] = -2;
4375       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
4376       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
4377 #if defined(PETSC_USE_DEBUG)
4378       if ((newp+1 < fStartNew) || (newp+1 >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp+1, fStartNew, fMaxNew);
4379       for (p = 0; p < 3; ++p) {
4380         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", coneNew[p], eStartNew, eMaxNew);
4381       }
4382 #endif
4383       /* C triangle */
4384       coneNew[0] = eStartNew + (eMax    - eStart)*2 + (f - fStart)*3 + 1;
4385       orntNew[0] = -2;
4386       coneNew[1] = eStartNew + (cone[1] - eStart)*2 + (ornt[1] < 0 ? 0 : 1);
4387       orntNew[1] = ornt[1];
4388       coneNew[2] = eStartNew + (cone[2] - eStart)*2 + (ornt[2] < 0 ? 1 : 0);
4389       orntNew[2] = ornt[2];
4390       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
4391       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
4392 #if defined(PETSC_USE_DEBUG)
4393       if ((newp+2 < fStartNew) || (newp+2 >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp+2, fStartNew, fMaxNew);
4394       for (p = 0; p < 3; ++p) {
4395         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", coneNew[p], eStartNew, eMaxNew);
4396       }
4397 #endif
4398       /* D triangle */
4399       coneNew[0] = eStartNew + (eMax    - eStart)*2 + (f - fStart)*3 + 0;
4400       orntNew[0] = 0;
4401       coneNew[1] = eStartNew + (eMax    - eStart)*2 + (f - fStart)*3 + 1;
4402       orntNew[1] = 0;
4403       coneNew[2] = eStartNew + (eMax    - eStart)*2 + (f - fStart)*3 + 2;
4404       orntNew[2] = 0;
4405       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
4406       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
4407 #if defined(PETSC_USE_DEBUG)
4408       if ((newp+3 < fStartNew) || (newp+3 >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp+3, fStartNew, fMaxNew);
4409       for (p = 0; p < 3; ++p) {
4410         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", coneNew[p], eStartNew, eMaxNew);
4411       }
4412 #endif
4413       ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
4414       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
4415       for (r = 0; r < 4; ++r) {
4416         for (s = 0; s < supportSize; ++s) {
4417           PetscInt subf;
4418           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
4419           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
4420           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
4421           for (c = 0; c < coneSize; ++c) {
4422             if (cone[c] == f) break;
4423           }
4424           subf = GetTriSubfaceInverse_Static(ornt[c], r);
4425           if (support[s] < cMax) {
4426             supportRef[s] = cStartNew + (support[s] - cStart)*8 + (r==3 ? (c+2)%4 + 4 : faces[c*3+subf]);
4427           } else {
4428             supportRef[s] = cStartNew + (cMax - cStart)*8 + (support[s] - cMax)*4 + (r==3 ? r : subf);
4429           }
4430         }
4431         ierr = DMPlexSetSupport(rdm, newp+r, supportRef);CHKERRQ(ierr);
4432 #if defined(PETSC_USE_DEBUG)
4433         if ((newp+r < fStartNew) || (newp+r >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp+r, fStartNew, fMaxNew);
4434         for (p = 0; p < supportSize; ++p) {
4435           if ((supportRef[p] < cStartNew) || (supportRef[p] >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an interior or hybrid cell [%D, %D)", supportRef[p], cStartNew, cEndNew);
4436         }
4437 #endif
4438       }
4439     }
4440     /* Interior cell faces have 3 edges and 2 cells */
4441     for (c = cStart; c < cMax; ++c) {
4442       PetscInt        newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*8;
4443       const PetscInt *cone, *ornt;
4444       PetscInt        coneNew[3], orntNew[3];
4445       PetscInt        supportNew[2];
4446 
4447       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
4448       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
4449       /* Face A: {c, a, d} */
4450       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*3 + GetTriMidEdge_Static(ornt[0], 2);
4451       orntNew[0] = ornt[0] < 0 ? -2 : 0;
4452       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*3 + GetTriMidEdge_Static(ornt[1], 2);
4453       orntNew[1] = ornt[1] < 0 ? -2 : 0;
4454       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*3 + GetTriMidEdge_Static(ornt[2], 2);
4455       orntNew[2] = ornt[2] < 0 ? -2 : 0;
4456       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4457       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4458 #if defined(PETSC_USE_DEBUG)
4459       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fMaxNew);
4460       for (p = 0; p < 3; ++p) {
4461         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", coneNew[p], eStartNew, eMaxNew);
4462       }
4463 #endif
4464       supportNew[0] = (c - cStart)*8 + 0;
4465       supportNew[1] = (c - cStart)*8 + 0+4;
4466       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
4467 #if defined(PETSC_USE_DEBUG)
4468       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fMaxNew);
4469       for (p = 0; p < 2; ++p) {
4470         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", supportNew[p], cStartNew, cMaxNew);
4471       }
4472 #endif
4473       ++newp;
4474       /* Face B: {a, b, e} */
4475       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*3 + GetTriMidEdge_Static(ornt[0], 0);
4476       orntNew[0] = ornt[0] < 0 ? -2 : 0;
4477       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*3 + GetTriMidEdge_Static(ornt[3], 0);
4478       orntNew[1] = ornt[3] < 0 ? -2 : 0;
4479       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*3 + GetTriMidEdge_Static(ornt[1], 1);
4480       orntNew[2] = ornt[1] < 0 ? -2 : 0;
4481       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4482       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4483 #if defined(PETSC_USE_DEBUG)
4484       if ((newp+1 < fStartNew) || (newp+1 >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp+1, fStartNew, fMaxNew);
4485       for (p = 0; p < 3; ++p) {
4486         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", coneNew[p], eStartNew, eMaxNew);
4487       }
4488 #endif
4489       supportNew[0] = (c - cStart)*8 + 1;
4490       supportNew[1] = (c - cStart)*8 + 1+4;
4491       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
4492 #if defined(PETSC_USE_DEBUG)
4493       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fMaxNew);
4494       for (p = 0; p < 2; ++p) {
4495         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", supportNew[p], cStartNew, cMaxNew);
4496       }
4497 #endif
4498       ++newp;
4499       /* Face C: {c, f, b} */
4500       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*3 + GetTriMidEdge_Static(ornt[2], 0);
4501       orntNew[0] = ornt[2] < 0 ? -2 : 0;
4502       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*3 + GetTriMidEdge_Static(ornt[3], 2);
4503       orntNew[1] = ornt[3] < 0 ? -2 : 0;
4504       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*3 + GetTriMidEdge_Static(ornt[0], 1);
4505       orntNew[2] = ornt[0] < 0 ? -2 : 0;
4506       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4507       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4508 #if defined(PETSC_USE_DEBUG)
4509       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fMaxNew);
4510       for (p = 0; p < 3; ++p) {
4511         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", coneNew[p], eStartNew, eMaxNew);
4512       }
4513 #endif
4514       supportNew[0] = (c - cStart)*8 + 2;
4515       supportNew[1] = (c - cStart)*8 + 2+4;
4516       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
4517 #if defined(PETSC_USE_DEBUG)
4518       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fMaxNew);
4519       for (p = 0; p < 2; ++p) {
4520         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", supportNew[p], cStartNew, cMaxNew);
4521       }
4522 #endif
4523       ++newp;
4524       /* Face D: {d, e, f} */
4525       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*3 + GetTriMidEdge_Static(ornt[1], 0);
4526       orntNew[0] = ornt[1] < 0 ? -2 : 0;
4527       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*3 + GetTriMidEdge_Static(ornt[3], 1);
4528       orntNew[1] = ornt[3] < 0 ? -2 : 0;
4529       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*3 + GetTriMidEdge_Static(ornt[2], 1);
4530       orntNew[2] = ornt[2] < 0 ? -2 : 0;
4531       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4532       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4533 #if defined(PETSC_USE_DEBUG)
4534       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fMaxNew);
4535       for (p = 0; p < 3; ++p) {
4536         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", coneNew[p], eStartNew, eMaxNew);
4537       }
4538 #endif
4539       supportNew[0] = (c - cStart)*8 + 3;
4540       supportNew[1] = (c - cStart)*8 + 3+4;
4541       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
4542 #if defined(PETSC_USE_DEBUG)
4543       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fMaxNew);
4544       for (p = 0; p < 2; ++p) {
4545         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", supportNew[p], cStartNew, cMaxNew);
4546       }
4547 #endif
4548       ++newp;
4549       /* Face E: {d, f, a} */
4550       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*3 + GetTriMidEdge_Static(ornt[2], 1);
4551       orntNew[0] = ornt[2] < 0 ? 0 : -2;
4552       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart);
4553       orntNew[1] = -2;
4554       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*3 + GetTriMidEdge_Static(ornt[1], 2);
4555       orntNew[2] = ornt[1] < 0 ? -2 : 0;
4556       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4557       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4558 #if defined(PETSC_USE_DEBUG)
4559       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fMaxNew);
4560       for (p = 0; p < 3; ++p) {
4561         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", coneNew[p], eStartNew, eMaxNew);
4562       }
4563 #endif
4564       supportNew[0] = (c - cStart)*8 + 0+4;
4565       supportNew[1] = (c - cStart)*8 + 3+4;
4566       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
4567 #if defined(PETSC_USE_DEBUG)
4568       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fMaxNew);
4569       for (p = 0; p < 2; ++p) {
4570         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", supportNew[p], cStartNew, cMaxNew);
4571       }
4572 #endif
4573       ++newp;
4574       /* Face F: {c, a, f} */
4575       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*3 + GetTriMidEdge_Static(ornt[0], 2);
4576       orntNew[0] = ornt[0] < 0 ? -2 : 0;
4577       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart);
4578       orntNew[1] = 0;
4579       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*3 + GetTriMidEdge_Static(ornt[2], 0);
4580       orntNew[2] = ornt[2] < 0 ? 0 : -2;
4581       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4582       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4583 #if defined(PETSC_USE_DEBUG)
4584       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fMaxNew);
4585       for (p = 0; p < 3; ++p) {
4586         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", coneNew[p], eStartNew, eMaxNew);
4587       }
4588 #endif
4589       supportNew[0] = (c - cStart)*8 + 0+4;
4590       supportNew[1] = (c - cStart)*8 + 2+4;
4591       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
4592 #if defined(PETSC_USE_DEBUG)
4593       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fMaxNew);
4594       for (p = 0; p < 2; ++p) {
4595         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", supportNew[p], cStartNew, cMaxNew);
4596       }
4597 #endif
4598       ++newp;
4599       /* Face G: {e, a, f} */
4600       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*3 + GetTriMidEdge_Static(ornt[1], 1);
4601       orntNew[0] = ornt[1] < 0 ? -2 : 0;
4602       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart);
4603       orntNew[1] = 0;
4604       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*3 + GetTriMidEdge_Static(ornt[3], 1);
4605       orntNew[2] = ornt[3] < 0 ? 0 : -2;
4606       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4607       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4608 #if defined(PETSC_USE_DEBUG)
4609       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fMaxNew);
4610       for (p = 0; p < 3; ++p) {
4611         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", coneNew[p], eStartNew, eMaxNew);
4612       }
4613 #endif
4614       supportNew[0] = (c - cStart)*8 + 1+4;
4615       supportNew[1] = (c - cStart)*8 + 3+4;
4616       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
4617 #if defined(PETSC_USE_DEBUG)
4618       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fMaxNew);
4619       for (p = 0; p < 2; ++p) {
4620         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", supportNew[p], cStartNew, cMaxNew);
4621       }
4622 #endif
4623       ++newp;
4624       /* Face H: {a, b, f} */
4625       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*3 + GetTriMidEdge_Static(ornt[0], 0);
4626       orntNew[0] = ornt[0] < 0 ? -2 : 0;
4627       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*3 + GetTriMidEdge_Static(ornt[3], 2);
4628       orntNew[1] = ornt[3] < 0 ? 0 : -2;
4629       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart);
4630       orntNew[2] = -2;
4631       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4632       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4633 #if defined(PETSC_USE_DEBUG)
4634       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fMaxNew);
4635       for (p = 0; p < 3; ++p) {
4636         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", coneNew[p], eStartNew, eMaxNew);
4637       }
4638 #endif
4639       supportNew[0] = (c - cStart)*8 + 1+4;
4640       supportNew[1] = (c - cStart)*8 + 2+4;
4641       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
4642 #if defined(PETSC_USE_DEBUG)
4643       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fMaxNew);
4644       for (p = 0; p < 2; ++p) {
4645         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", supportNew[p], cStartNew, cMaxNew);
4646       }
4647 #endif
4648       ++newp;
4649     }
4650     /* Hybrid split faces have 4 edges and same cells */
4651     for (f = fMax; f < fEnd; ++f) {
4652       const PetscInt *cone, *ornt, *support;
4653       PetscInt        coneNew[4], orntNew[4];
4654       PetscInt        supportNew[2], size, s, c;
4655 
4656       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
4657       ierr = DMPlexGetConeOrientation(dm, f, &ornt);CHKERRQ(ierr);
4658       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
4659       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
4660       for (r = 0; r < 2; ++r) {
4661         const PetscInt newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (f - fMax)*2 + r;
4662 
4663         coneNew[0]   = eStartNew + (cone[0] - eStart)*2 + (ornt[0] < 0 ? 1-r : r);
4664         orntNew[0]   = ornt[0];
4665         coneNew[1]   = eStartNew + (cone[1] - eStart)*2 + (ornt[1] < 0 ? 1-r : r);
4666         orntNew[1]   = ornt[1];
4667         coneNew[2+r] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (cone[2+r] - eMax);
4668         orntNew[2+r] = 0;
4669         coneNew[3-r] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (eEnd      - eMax) + (f - fMax);
4670         orntNew[3-r] = 0;
4671         ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4672         ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4673 #if defined(PETSC_USE_DEBUG)
4674         if ((newp < fMaxNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a hybrid face [%D, %D)", newp, fMaxNew, fEndNew);
4675         for (p = 0; p < 2; ++p) {
4676           if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", coneNew[p], eStartNew, eMaxNew);
4677         }
4678         for (p = 2; p < 4; ++p) {
4679           if ((coneNew[p] < eMaxNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a hybrid edge [%D, %D)", coneNew[p], eMaxNew, eEndNew);
4680         }
4681 #endif
4682         for (s = 0; s < size; ++s) {
4683           const PetscInt *coneCell, *orntCell, *fornt;
4684           PetscInt        o, of;
4685 
4686           ierr = DMPlexGetCone(dm, support[s], &coneCell);CHKERRQ(ierr);
4687           ierr = DMPlexGetConeOrientation(dm, support[s], &orntCell);CHKERRQ(ierr);
4688           o = orntCell[0] < 0 ? -1 : 1;
4689           for (c = 2; c < 5; ++c) if (coneCell[c] == f) break;
4690           if (c >= 5) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Could not find face %D in cone of cell %D", f, support[s]);
4691           ierr = DMPlexGetConeOrientation(dm, coneCell[0], &fornt);CHKERRQ(ierr);
4692           of = fornt[c-2] < 0 ? -1 : 1;
4693           supportNew[s] = cStartNew + (cMax - cStart)*8 + (support[s] - cMax)*4 + (GetTriEdgeInverse_Static(orntCell[0], c-2) + (o*of < 0 ? 1-r : r))%3;
4694         }
4695         ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
4696 #if defined(PETSC_USE_DEBUG)
4697         if ((newp < fMaxNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a hybrid face [%D, %D)", newp, fMaxNew, fEndNew);
4698         for (p = 0; p < size; ++p) {
4699           if ((supportNew[p] < cMaxNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a hybrid cell [%D, %D)", supportNew[p], cMaxNew, cEndNew);
4700         }
4701 #endif
4702       }
4703     }
4704     /* Hybrid cell faces have 4 edges and 2 cells */
4705     for (c = cMax; c < cEnd; ++c) {
4706       PetscInt        newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (c - cMax)*3;
4707       const PetscInt *cone, *ornt;
4708       PetscInt        coneNew[4], orntNew[4];
4709       PetscInt        supportNew[2];
4710 
4711       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
4712       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
4713       for (r = 0; r < 3; ++r) {
4714         coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*3 + (r+2)%3;
4715         orntNew[0] = 0;
4716         coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*3 + (r+2)%3;
4717         orntNew[1] = 0;
4718         coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (eEnd - eMax) + (cone[2+(r+2)%3] - fMax);
4719         orntNew[2] = 0;
4720         coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (eEnd - eMax) + (cone[2+r]       - fMax);
4721         orntNew[3] = 0;
4722         ierr = DMPlexSetCone(rdm, newp+r, coneNew);CHKERRQ(ierr);
4723         ierr = DMPlexSetConeOrientation(rdm, newp+r, orntNew);CHKERRQ(ierr);
4724 #if defined(PETSC_USE_DEBUG)
4725         if ((newp+r < fMaxNew) || (newp+r >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a hybrid face [%D, %D)", newp+r, fMaxNew, fEndNew);
4726         for (p = 0; p < 2; ++p) {
4727           if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", coneNew[p], eStartNew, eMaxNew);
4728         }
4729         for (p = 2; p < 4; ++p) {
4730           if ((coneNew[p] < eMaxNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a hybrid edge [%D, %D)", coneNew[p], eMaxNew, eEndNew);
4731         }
4732 #endif
4733         supportNew[0] = cStartNew + (cMax - cStart)*8 + (c - cMax)*4 + GetTriSubface_Static(ornt[0], r);
4734         supportNew[1] = cStartNew + (cMax - cStart)*8 + (c - cMax)*4 + 3;
4735         ierr          = DMPlexSetSupport(rdm, newp+r, supportNew);CHKERRQ(ierr);
4736 #if defined(PETSC_USE_DEBUG)
4737         if ((newp+r < fMaxNew) || (newp+r >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a hybrid face [%D, %D)", newp+r, fMaxNew, fEndNew);
4738         for (p = 0; p < 2; ++p) {
4739           if ((supportNew[p] < cMaxNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a hybrid cell [%D, %D)", supportNew[p], cMaxNew, cEndNew);
4740         }
4741 #endif
4742       }
4743     }
4744     /* Interior split edges have 2 vertices and the same faces as the parent */
4745     for (e = eStart; e < eMax; ++e) {
4746       const PetscInt newv = vStartNew + (vEnd - vStart) + (e - eStart);
4747 
4748       for (r = 0; r < 2; ++r) {
4749         const PetscInt  newp = eStartNew + (e - eStart)*2 + r;
4750         const PetscInt *cone, *ornt, *support;
4751         PetscInt        coneNew[2], coneSize, c, supportSize, s;
4752 
4753         ierr             = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
4754         coneNew[0]       = vStartNew + (cone[0] - vStart);
4755         coneNew[1]       = vStartNew + (cone[1] - vStart);
4756         coneNew[(r+1)%2] = newv;
4757         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4758 #if defined(PETSC_USE_DEBUG)
4759         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eMaxNew);
4760         for (p = 0; p < 2; ++p) {
4761           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", coneNew[p], vStartNew, vEndNew);
4762         }
4763 #endif
4764         ierr = DMPlexGetSupportSize(dm, e, &supportSize);CHKERRQ(ierr);
4765         ierr = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
4766         for (s = 0; s < supportSize; ++s) {
4767           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
4768           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
4769           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
4770           for (c = 0; c < coneSize; ++c) if (cone[c] == e) break;
4771           if (support[s] < fMax) {
4772             supportRef[s] = fStartNew + (support[s] - fStart)*4 + (c + (ornt[c] < 0 ? 1-r : r))%3;
4773           } else {
4774             supportRef[s] = fStartNew + (fMax       - fStart)*4 + (cMax - cStart)*8 + (support[s] - fMax)*2 + (ornt[c] < 0 ? 1-r : r);
4775           }
4776         }
4777         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
4778 #if defined(PETSC_USE_DEBUG)
4779         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eMaxNew);
4780         for (p = 0; p < supportSize; ++p) {
4781           if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an interior or hybrid face [%D, %D)", supportRef[p], fStartNew, fEndNew);
4782         }
4783 #endif
4784       }
4785     }
4786     /* Interior face edges have 2 vertices and 2+cells*(1/2) faces */
4787     for (f = fStart; f < fMax; ++f) {
4788       const PetscInt *cone, *ornt, *support;
4789       PetscInt        coneSize, supportSize, s;
4790 
4791       ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
4792       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
4793       for (r = 0; r < 3; ++r) {
4794         const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (f - fStart)*3 + r;
4795         PetscInt        coneNew[2], intFaces = 0, er, eint[4] = {1, 0, 2, 0};
4796         PetscInt        fint[24] = { 1,  7, -1, -1,  0,  5,
4797                                     -1, -1,  1,  6,  0,  4,
4798                                      2,  5,  3,  4, -1, -1,
4799                                     -1, -1,  3,  6,  2,  7};
4800 
4801         ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
4802         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[(r+0)%3] - eStart);
4803         coneNew[1] = vStartNew + (vEnd - vStart) + (cone[(r+1)%3] - eStart);
4804         ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4805 #if defined(PETSC_USE_DEBUG)
4806         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eMaxNew);
4807         for (p = 0; p < 2; ++p) {
4808           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", coneNew[p], vStartNew, vEndNew);
4809         }
4810 #endif
4811         supportRef[0] = fStartNew + (f - fStart)*4 + (r+1)%3;
4812         supportRef[1] = fStartNew + (f - fStart)*4 + 3;
4813         for (s = 0; s < supportSize; ++s) {
4814           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
4815           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
4816           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
4817           for (c = 0; c < coneSize; ++c) {if (cone[c] == f) break;}
4818           if (support[s] < cMax) {
4819             /* Here we want to determine whether edge newp contains a vertex which is part of the cross-tet edge */
4820             er = GetTriMidEdgeInverse_Static(ornt[c], r);
4821             if (er == eint[c]) {
4822               supportRef[2+intFaces++] = fStartNew + (fMax - fStart)*4 + (support[s] - cStart)*8 + (c + 2)%4;
4823             } else {
4824               supportRef[2+intFaces++] = fStartNew + (fMax - fStart)*4 + (support[s] - cStart)*8 + fint[(c*3 + er)*2 + 0];
4825               supportRef[2+intFaces++] = fStartNew + (fMax - fStart)*4 + (support[s] - cStart)*8 + fint[(c*3 + er)*2 + 1];
4826             }
4827           } else {
4828             supportRef[2+intFaces++] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (support[s] - cMax)*3 + (r + 1)%3;
4829           }
4830         }
4831         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
4832 #if defined(PETSC_USE_DEBUG)
4833         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eMaxNew);
4834         for (p = 0; p < intFaces; ++p) {
4835           if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an interior or hybrid face [%D, %D)", supportRef[p], fStartNew, fEndNew);
4836         }
4837 #endif
4838       }
4839     }
4840     /* Interior cell edges have 2 vertices and 4 faces */
4841     for (c = cStart; c < cMax; ++c) {
4842       const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart);
4843       const PetscInt *cone, *ornt, *fcone;
4844       PetscInt        coneNew[2], supportNew[4], find;
4845 
4846       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
4847       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
4848       ierr = DMPlexGetCone(dm, cone[0], &fcone);CHKERRQ(ierr);
4849       find = GetTriEdge_Static(ornt[0], 0);
4850       coneNew[0] = vStartNew + (vEnd - vStart) + (fcone[find] - eStart);
4851       ierr = DMPlexGetCone(dm, cone[2], &fcone);CHKERRQ(ierr);
4852       find = GetTriEdge_Static(ornt[2], 1);
4853       coneNew[1] = vStartNew + (vEnd - vStart) + (fcone[find] - eStart);
4854       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4855 #if defined(PETSC_USE_DEBUG)
4856       if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eMaxNew);
4857       for (p = 0; p < 2; ++p) {
4858         if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", coneNew[p], vStartNew, vEndNew);
4859       }
4860 #endif
4861       supportNew[0] = fStartNew + (fMax - fStart)*4 + (c - cStart)*8 + 4;
4862       supportNew[1] = fStartNew + (fMax - fStart)*4 + (c - cStart)*8 + 5;
4863       supportNew[2] = fStartNew + (fMax - fStart)*4 + (c - cStart)*8 + 6;
4864       supportNew[3] = fStartNew + (fMax - fStart)*4 + (c - cStart)*8 + 7;
4865       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
4866 #if defined(PETSC_USE_DEBUG)
4867       if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eMaxNew);
4868       for (p = 0; p < 4; ++p) {
4869         if ((supportNew[p] < fStartNew) || (supportNew[p] >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", supportNew[p], fStartNew, fMaxNew);
4870       }
4871 #endif
4872     }
4873     /* Hybrid edges have two vertices and the same faces */
4874     for (e = eMax; e < eEnd; ++e) {
4875       const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (e - eMax);
4876       const PetscInt *cone, *support, *fcone;
4877       PetscInt        coneNew[2], size, fsize, s;
4878 
4879       ierr = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
4880       ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
4881       ierr = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
4882       coneNew[0] = vStartNew + (cone[0] - vStart);
4883       coneNew[1] = vStartNew + (cone[1] - vStart);
4884       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4885 #if defined(PETSC_USE_DEBUG)
4886       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a hybrid edge [%D, %D)", newp, eMaxNew, eEndNew);
4887       for (p = 0; p < 2; ++p) {
4888         if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", coneNew[p], vStartNew, vEndNew);
4889       }
4890 #endif
4891       for (s = 0; s < size; ++s) {
4892         ierr = DMPlexGetConeSize(dm, support[s], &fsize);CHKERRQ(ierr);
4893         ierr = DMPlexGetCone(dm, support[s], &fcone);CHKERRQ(ierr);
4894         for (c = 0; c < fsize; ++c) if (fcone[c] == e) break;
4895         if ((c < 2) || (c > 3)) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Edge %D not found in cone of face %D", e, support[s]);
4896         supportRef[s] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (support[s] - fMax)*2 + c-2;
4897       }
4898       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
4899 #if defined(PETSC_USE_DEBUG)
4900       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a hybrid edge [%D, %D)", newp, eMaxNew, eEndNew);
4901       for (p = 0; p < size; ++p) {
4902         if ((supportRef[p] < fMaxNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a hybrid face [%D, %D)", supportRef[p], fMaxNew, fEndNew);
4903       }
4904 #endif
4905     }
4906     /* Hybrid face edges have 2 vertices and 2+2*cells faces */
4907     for (f = fMax; f < fEnd; ++f) {
4908       const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (eEnd - eMax) + (f - fMax);
4909       const PetscInt *cone, *support, *ccone, *cornt;
4910       PetscInt        coneNew[2], size, csize, s;
4911 
4912       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
4913       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
4914       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
4915       coneNew[0] = vStartNew + (vEnd - vStart) + (cone[0] - eStart);
4916       coneNew[1] = vStartNew + (vEnd - vStart) + (cone[1] - eStart);
4917       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4918 #if defined(PETSC_USE_DEBUG)
4919       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a hybrid edge [%D, %D)", newp, eMaxNew, eEndNew);
4920       for (p = 0; p < 2; ++p) {
4921         if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", coneNew[p], vStartNew, vEndNew);
4922       }
4923 #endif
4924       supportRef[0] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (f - fMax)*2 + 0;
4925       supportRef[1] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (f - fMax)*2 + 1;
4926       for (s = 0; s < size; ++s) {
4927         ierr = DMPlexGetConeSize(dm, support[s], &csize);CHKERRQ(ierr);
4928         ierr = DMPlexGetCone(dm, support[s], &ccone);CHKERRQ(ierr);
4929         ierr = DMPlexGetConeOrientation(dm, support[s], &cornt);CHKERRQ(ierr);
4930         for (c = 0; c < csize; ++c) if (ccone[c] == f) break;
4931         if ((c < 2) || (c >= csize)) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Hybrid face %D is not in cone of hybrid cell %D", f, support[s]);
4932         supportRef[2+s*2+0] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (support[s] - cMax)*3 + c-2;
4933         supportRef[2+s*2+1] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (support[s] - cMax)*3 + (c-1)%3;
4934       }
4935       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
4936 #if defined(PETSC_USE_DEBUG)
4937       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a hybrid edge [%D, %D)", newp, eMaxNew, eEndNew);
4938       for (p = 0; p < 2+size*2; ++p) {
4939         if ((supportRef[p] < fMaxNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a hybrid face [%D, %D)", supportRef[p], fMaxNew, fEndNew);
4940       }
4941 #endif
4942     }
4943     /* Interior vertices have identical supports */
4944     for (v = vStart; v < vEnd; ++v) {
4945       const PetscInt  newp = vStartNew + (v - vStart);
4946       const PetscInt *support, *cone;
4947       PetscInt        size, s;
4948 
4949       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
4950       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
4951       for (s = 0; s < size; ++s) {
4952         PetscInt r = 0;
4953 
4954         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
4955         if (cone[1] == v) r = 1;
4956         if (support[s] < eMax) supportRef[s] = eStartNew + (support[s] - eStart)*2 + r;
4957         else                   supportRef[s] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (support[s] - eMax);
4958       }
4959       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
4960 #if defined(PETSC_USE_DEBUG)
4961       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", newp, vStartNew, vEndNew);
4962       for (p = 0; p < size; ++p) {
4963         if ((supportRef[p] < eStartNew) || (supportRef[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an interior or hybrid edge [%D, %D)", supportRef[p], eStartNew, eEndNew);
4964       }
4965 #endif
4966     }
4967     /* Interior edge vertices have 2 + interior face*2 + hybrid face + cells*0/1 supports */
4968     for (e = eStart; e < eMax; ++e) {
4969       const PetscInt  newp = vStartNew + (vEnd - vStart) + (e - eStart);
4970       const PetscInt *cone, *support;
4971       PetscInt       *star = NULL, starSize, faceSize = 0, cellSize = 0, coneSize, size, s;
4972 
4973       ierr          = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
4974       ierr          = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
4975       supportRef[0] = eStartNew + (e - eStart)*2 + 0;
4976       supportRef[1] = eStartNew + (e - eStart)*2 + 1;
4977       for (s = 0; s < size; ++s) {
4978         PetscInt r = 0;
4979 
4980         if (support[s] < fMax) {
4981           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
4982           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
4983           for (r = 0; r < coneSize; ++r) {if (cone[r] == e) break;}
4984           supportRef[2+faceSize+0] = eStartNew + (eMax - eStart)*2 + (support[s] - fStart)*3 + (r+0)%3;
4985           supportRef[2+faceSize+1] = eStartNew + (eMax - eStart)*2 + (support[s] - fStart)*3 + (r+2)%3;
4986           faceSize += 2;
4987         } else {
4988           supportRef[2+faceSize+0] = eStartNew + (eMax - eStart)*2 + (fMax       - fStart)*3 + (cMax - cStart) + (eEnd - eMax) + (support[s] - fMax);
4989           ++faceSize;
4990         }
4991       }
4992       ierr = DMPlexGetTransitiveClosure(dm, e, PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
4993       for (s = 0; s < starSize*2; s += 2) {
4994         const PetscInt *cone, *ornt;
4995         PetscInt        e01, e23;
4996 
4997         if ((star[s] >= cStart) && (star[s] < cMax)) {
4998           /* Check edge 0-1 */
4999           ierr = DMPlexGetCone(dm, star[s], &cone);CHKERRQ(ierr);
5000           ierr = DMPlexGetConeOrientation(dm, star[s], &ornt);CHKERRQ(ierr);
5001           ierr = DMPlexGetCone(dm, cone[0], &cone);CHKERRQ(ierr);
5002           e01  = cone[GetTriEdge_Static(ornt[0], 0)];
5003           /* Check edge 2-3 */
5004           ierr = DMPlexGetCone(dm, star[s], &cone);CHKERRQ(ierr);
5005           ierr = DMPlexGetConeOrientation(dm, star[s], &ornt);CHKERRQ(ierr);
5006           ierr = DMPlexGetCone(dm, cone[2], &cone);CHKERRQ(ierr);
5007           e23  = cone[GetTriEdge_Static(ornt[2], 1)];
5008           if ((e01 == e) || (e23 == e)) {supportRef[2+faceSize+cellSize++] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (star[s] - cStart);}
5009         }
5010       }
5011       ierr = DMPlexRestoreTransitiveClosure(dm, e, PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
5012       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
5013 #if defined(PETSC_USE_DEBUG)
5014       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", newp, vStartNew, vEndNew);
5015       for (p = 0; p < 2+faceSize+cellSize; ++p) {
5016         if ((supportRef[p] < eStartNew) || (supportRef[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an interior or hybrid edge [%D, %D)", supportRef[p], eStartNew, eEndNew);
5017       }
5018 #endif
5019     }
5020     ierr = PetscFree(supportRef);CHKERRQ(ierr);
5021     ierr = DMPlexRestoreFaces_Internal(dm, 3, cStart, NULL, NULL, &faces);CHKERRQ(ierr);
5022     break;
5023   case REFINER_SIMPLEX_TO_HEX_3D:
5024     ierr = DMPlexGetRawFaces_Internal(dm, 3, 4, cellInd, NULL, NULL, &faces);CHKERRQ(ierr);
5025     /* All cells have 6 faces */
5026     for (c = cStart; c < cEnd; ++c) {
5027       const PetscInt  newp = cStartNew + (c - cStart)*4;
5028       const PetscInt *cone, *ornt;
5029       PetscInt        coneNew[6];
5030       PetscInt        orntNew[6];
5031 
5032       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
5033       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
5034       /* A hex */
5035       coneNew[0] = fStartNew + (cone[0] - fStart)*3 + GetTriSubface_Static(ornt[0], 0); /* B */
5036       orntNew[0] = ornt[0] < 0 ? -1 : 1;
5037       coneNew[1] = fStartNew + (fEnd    - fStart)*3 + (c - cStart)*6 + 3;               /* T */
5038       orntNew[1] = -4;
5039       coneNew[2] = fStartNew + (cone[2] - fStart)*3 + GetTriSubface_Static(ornt[2], 0); /* F */
5040       orntNew[2] = ornt[2] < 0 ? -1 : 1;
5041       coneNew[3] = fStartNew + (fEnd    - fStart)*3 + (c - cStart)*6 + 0;               /* K */
5042       orntNew[3] = -1;
5043       coneNew[4] = fStartNew + (fEnd    - fStart)*3 + (c - cStart)*6 + 2;               /* R */
5044       orntNew[4] = 0;
5045       coneNew[5] = fStartNew + (cone[1] - fStart)*3 + GetTriSubface_Static(ornt[1], 0); /* L */
5046       orntNew[5] = ornt[1] < 0 ? -1 : 1;
5047       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
5048       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
5049 #if defined(PETSC_USE_DEBUG)
5050       if ((newp+0 < cStartNew) || (newp+0 >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", newp+0, cStartNew, cEndNew);
5051       for (p = 0; p < 6; ++p) {
5052         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", coneNew[p], fStartNew, fEndNew);
5053       }
5054 #endif
5055       /* B hex */
5056       coneNew[0] = fStartNew + (cone[0] - fStart)*3 + GetTriSubface_Static(ornt[0], 1); /* B */
5057       orntNew[0] = ornt[0] < 0 ? -2 : 0;
5058       coneNew[1] = fStartNew + (fEnd    - fStart)*3 + (c - cStart)*6 + 4;               /* T */
5059       orntNew[1] = 0;
5060       coneNew[2] = fStartNew + (fEnd    - fStart)*3 + (c - cStart)*6 + 0;               /* F */
5061       orntNew[2] = 0;
5062       coneNew[3] = fStartNew + (cone[3] - fStart)*3 + GetTriSubface_Static(ornt[3], 1); /* K */
5063       orntNew[3] = ornt[3] < 0 ? -2 : 0;
5064       coneNew[4] = fStartNew + (fEnd    - fStart)*3 + (c - cStart)*6 + 1;               /* R */
5065       orntNew[4] = 0;
5066       coneNew[5] = fStartNew + (cone[1] - fStart)*3 + GetTriSubface_Static(ornt[1], 2); /* L */
5067       orntNew[5] = ornt[1] < 0 ? -4 : 2;
5068       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
5069       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
5070 #if defined(PETSC_USE_DEBUG)
5071       if ((newp+1 < cStartNew) || (newp+1 >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", newp+1, cStartNew, cEndNew);
5072       for (p = 0; p < 6; ++p) {
5073         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", coneNew[p], fStartNew, fEndNew);
5074       }
5075 #endif
5076       /* C hex */
5077       coneNew[0] = fStartNew + (cone[0] - fStart)*3 + GetTriSubface_Static(ornt[0], 2); /* B */
5078       orntNew[0] = ornt[0] < 0 ? -4 : 2;
5079       coneNew[1] = fStartNew + (fEnd    - fStart)*3 + (c - cStart)*6 + 5;               /* T */
5080       orntNew[1] = -4;
5081       coneNew[2] = fStartNew + (cone[2] - fStart)*3 + GetTriSubface_Static(ornt[2], 1); /* F */
5082       orntNew[2] = ornt[2] < 0 ? -2 : 0;
5083       coneNew[3] = fStartNew + (fEnd    - fStart)*3 + (c - cStart)*6 + 1;               /* K */
5084       orntNew[3] = -1;
5085       coneNew[4] = fStartNew + (cone[3] - fStart)*3 + GetTriSubface_Static(ornt[3], 0); /* R */
5086       orntNew[4] = ornt[3] < 0 ? -1 : 1;
5087       coneNew[5] = fStartNew + (fEnd    - fStart)*3 + (c - cStart)*6 + 2;               /* L */
5088       orntNew[5] = -4;
5089       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
5090       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
5091 #if defined(PETSC_USE_DEBUG)
5092       if ((newp+2 < cStartNew) || (newp+2 >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", newp+2, cStartNew, cEndNew);
5093       for (p = 0; p < 6; ++p) {
5094         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", coneNew[p], fStartNew, fEndNew);
5095       }
5096 #endif
5097       /* D hex */
5098       coneNew[0] = fStartNew + (fEnd    - fStart)*3 + (c - cStart)*6 + 3;               /* B */
5099       orntNew[0] = 0;
5100       coneNew[1] = fStartNew + (cone[3] - fStart)*3 + GetTriSubface_Static(ornt[3], 2); /* T */
5101       orntNew[1] = ornt[3] < 0 ? -1 : 1;
5102       coneNew[2] = fStartNew + (cone[2] - fStart)*3 + GetTriSubface_Static(ornt[2], 2); /* F */
5103       orntNew[2] = ornt[2] < 0 ? -4 : 2;
5104       coneNew[3] = fStartNew + (fEnd    - fStart)*3 + (c - cStart)*6 + 4;               /* K */
5105       orntNew[3] = -1;
5106       coneNew[4] = fStartNew + (fEnd    - fStart)*3 + (c - cStart)*6 + 5;               /* R */
5107       orntNew[4] = 0;
5108       coneNew[5] = fStartNew + (cone[1] - fStart)*3 + GetTriSubface_Static(ornt[1], 1); /* L */
5109       orntNew[5] = ornt[1] < 0 ? -2 : 0;
5110       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
5111       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
5112 #if defined(PETSC_USE_DEBUG)
5113       if ((newp+3 < cStartNew) || (newp+3 >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", newp+3, cStartNew, cEndNew);
5114       for (p = 0; p < 6; ++p) {
5115         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", coneNew[p], fStartNew, fEndNew);
5116       }
5117 #endif
5118     }
5119     /* Split faces have 4 edges and the same cells as the parent */
5120     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
5121     ierr = PetscMalloc1(2 + maxSupportSize*2, &supportRef);CHKERRQ(ierr);
5122     for (f = fStart; f < fEnd; ++f) {
5123       const PetscInt  newp = fStartNew + (f - fStart)*3;
5124       const PetscInt *cone, *ornt, *support;
5125       PetscInt        coneNew[4], orntNew[4], coneSize, supportSize, s;
5126 
5127       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
5128       ierr = DMPlexGetConeOrientation(dm, f, &ornt);CHKERRQ(ierr);
5129       /* A quad */
5130       coneNew[0] = eStartNew + (cone[2] - eStart)*2 + (ornt[2] < 0 ? 0 : 1);
5131       orntNew[0] = ornt[2];
5132       coneNew[1] = eStartNew + (cone[0] - eStart)*2 + (ornt[0] < 0 ? 1 : 0);
5133       orntNew[1] = ornt[0];
5134       coneNew[2] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 0;
5135       orntNew[2] = 0;
5136       coneNew[3] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 2;
5137       orntNew[3] = -2;
5138       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
5139       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
5140 #if defined(PETSC_USE_DEBUG)
5141       if ((newp+0 < fStartNew) || (newp+0 >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp+0, fStartNew, fEndNew);
5142       for (p = 0; p < 4; ++p) {
5143         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", coneNew[p], eStartNew, eEndNew);
5144       }
5145 #endif
5146       /* B quad */
5147       coneNew[0] = eStartNew + (cone[0] - eStart)*2 + (ornt[0] < 0 ? 0 : 1);
5148       orntNew[0] = ornt[0];
5149       coneNew[1] = eStartNew + (cone[1] - eStart)*2 + (ornt[1] < 0 ? 1 : 0);
5150       orntNew[1] = ornt[1];
5151       coneNew[2] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 1;
5152       orntNew[2] = 0;
5153       coneNew[3] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 0;
5154       orntNew[3] = -2;
5155       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
5156       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
5157 #if defined(PETSC_USE_DEBUG)
5158       if ((newp+1 < fStartNew) || (newp+1 >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp+1, fStartNew, fEndNew);
5159       for (p = 0; p < 4; ++p) {
5160         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", coneNew[p], eStartNew, eEndNew);
5161       }
5162 #endif
5163       /* C quad */
5164       coneNew[0] = eStartNew + (cone[1] - eStart)*2 + (ornt[1] < 0 ? 0 : 1);
5165       orntNew[0] = ornt[1];
5166       coneNew[1] = eStartNew + (cone[2] - eStart)*2 + (ornt[2] < 0 ? 1 : 0);
5167       orntNew[1] = ornt[2];
5168       coneNew[2] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 2;
5169       orntNew[2] = 0;
5170       coneNew[3] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 1;
5171       orntNew[3] = -2;
5172       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
5173       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
5174 #if defined(PETSC_USE_DEBUG)
5175       if ((newp+2 < fStartNew) || (newp+2 >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp+2, fStartNew, fEndNew);
5176       for (p = 0; p < 4; ++p) {
5177         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", coneNew[p], eStartNew, eEndNew);
5178       }
5179 #endif
5180       ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
5181       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
5182       for (r = 0; r < 3; ++r) {
5183         for (s = 0; s < supportSize; ++s) {
5184           PetscInt subf;
5185           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
5186           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
5187           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
5188           for (c = 0; c < coneSize; ++c) {
5189             if (cone[c] == f) break;
5190           }
5191           subf = GetTriSubfaceInverse_Static(ornt[c], r);
5192           supportRef[s] = cStartNew + (support[s] - cStart)*4 + faces[c*3+subf];
5193         }
5194         ierr = DMPlexSetSupport(rdm, newp+r, supportRef);CHKERRQ(ierr);
5195 #if defined(PETSC_USE_DEBUG)
5196         if ((newp+r < fStartNew) || (newp+r >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp+r, fStartNew, fEndNew);
5197         for (p = 0; p < supportSize; ++p) {
5198           if ((supportRef[p] < cStartNew) || (supportRef[p] >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", supportRef[p], cStartNew, cEndNew);
5199         }
5200 #endif
5201       }
5202     }
5203     /* Interior faces have 4 edges and 2 cells */
5204     for (c = cStart; c < cEnd; ++c) {
5205       PetscInt        newp = fStartNew + (fEnd - fStart)*3 + (c - cStart)*6;
5206       const PetscInt *cone, *ornt;
5207       PetscInt        coneNew[4], orntNew[4];
5208       PetscInt        supportNew[2];
5209 
5210       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
5211       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
5212       /* Face {a, g, m, h} */
5213       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*3 + GetTriInteriorEdge_Static(ornt[0],0);
5214       orntNew[0] = 0;
5215       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + 0;
5216       orntNew[1] = 0;
5217       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + 1;
5218       orntNew[2] = -2;
5219       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*3 + GetTriInteriorEdge_Static(ornt[1],2);
5220       orntNew[3] = -2;
5221       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5222       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
5223 #if defined(PETSC_USE_DEBUG)
5224       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
5225       for (p = 0; p < 4; ++p) {
5226         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", coneNew[p], eStartNew, eEndNew);
5227       }
5228 #endif
5229       supportNew[0] = (c - cStart)*4 + 0;
5230       supportNew[1] = (c - cStart)*4 + 1;
5231       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
5232 #if defined(PETSC_USE_DEBUG)
5233       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
5234       for (p = 0; p < 2; ++p) {
5235         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", supportNew[p], cStartNew, cEndNew);
5236       }
5237 #endif
5238       ++newp;
5239       /* Face {g, b, l , m} */
5240       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*3 + GetTriInteriorEdge_Static(ornt[0],1);
5241       orntNew[0] = -2;
5242       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*3 + GetTriInteriorEdge_Static(ornt[3],0);
5243       orntNew[1] = 0;
5244       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + 3;
5245       orntNew[2] = 0;
5246       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + 0;
5247       orntNew[3] = -2;
5248       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5249       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
5250 #if defined(PETSC_USE_DEBUG)
5251       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
5252       for (p = 0; p < 4; ++p) {
5253         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", coneNew[p], eStartNew, eEndNew);
5254       }
5255 #endif
5256       supportNew[0] = (c - cStart)*4 + 1;
5257       supportNew[1] = (c - cStart)*4 + 2;
5258       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
5259 #if defined(PETSC_USE_DEBUG)
5260       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
5261       for (p = 0; p < 2; ++p) {
5262         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", supportNew[p], cStartNew, cEndNew);
5263       }
5264 #endif
5265       ++newp;
5266       /* Face {c, g, m, i} */
5267       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*3 + GetTriInteriorEdge_Static(ornt[0],2);
5268       orntNew[0] = 0;
5269       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + 0;
5270       orntNew[1] = 0;
5271       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + 2;
5272       orntNew[2] = -2;
5273       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*3 + GetTriInteriorEdge_Static(ornt[2],0);
5274       orntNew[3] = -2;
5275       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5276       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
5277 #if defined(PETSC_USE_DEBUG)
5278       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
5279       for (p = 0; p < 4; ++p) {
5280         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", coneNew[p], eStartNew, eEndNew);
5281       }
5282 #endif
5283       supportNew[0] = (c - cStart)*4 + 0;
5284       supportNew[1] = (c - cStart)*4 + 2;
5285       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
5286 #if defined(PETSC_USE_DEBUG)
5287       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
5288       for (p = 0; p < 2; ++p) {
5289         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", supportNew[p], cStartNew, cEndNew);
5290       }
5291 #endif
5292       ++newp;
5293       /* Face {d, h, m, i} */
5294       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*3 + GetTriInteriorEdge_Static(ornt[1],0);
5295       orntNew[0] = 0;
5296       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + 1;
5297       orntNew[1] = 0;
5298       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + 2;
5299       orntNew[2] = -2;
5300       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*3 + GetTriInteriorEdge_Static(ornt[2],2);
5301       orntNew[3] = -2;
5302       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5303       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
5304 #if defined(PETSC_USE_DEBUG)
5305       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
5306       for (p = 0; p < 4; ++p) {
5307         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", coneNew[p], eStartNew, eEndNew);
5308       }
5309 #endif
5310       supportNew[0] = (c - cStart)*4 + 0;
5311       supportNew[1] = (c - cStart)*4 + 3;
5312       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
5313 #if defined(PETSC_USE_DEBUG)
5314       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
5315       for (p = 0; p < 2; ++p) {
5316         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", supportNew[p], cStartNew, cEndNew);
5317       }
5318 #endif
5319       ++newp;
5320       /* Face {h, m, l, e} */
5321       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + 1;
5322       orntNew[0] = 0;
5323       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + 3;
5324       orntNew[1] = -2;
5325       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*3 + GetTriInteriorEdge_Static(ornt[3],1);
5326       orntNew[2] = -2;
5327       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*3 + GetTriInteriorEdge_Static(ornt[1],1);
5328       orntNew[3] = 0;
5329       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5330       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
5331 #if defined(PETSC_USE_DEBUG)
5332       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
5333       for (p = 0; p < 4; ++p) {
5334         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", coneNew[p], eStartNew, eEndNew);
5335       }
5336 #endif
5337       supportNew[0] = (c - cStart)*4 + 1;
5338       supportNew[1] = (c - cStart)*4 + 3;
5339       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
5340 #if defined(PETSC_USE_DEBUG)
5341       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
5342       for (p = 0; p < 2; ++p) {
5343         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", supportNew[p], cStartNew, cEndNew);
5344       }
5345 #endif
5346       ++newp;
5347       /* Face {i, m, l, f} */
5348       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + 2;
5349       orntNew[0] = 0;
5350       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + 3;
5351       orntNew[1] = -2;
5352       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*3 + GetTriInteriorEdge_Static(ornt[3],2);
5353       orntNew[2] = -2;
5354       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*3 + GetTriInteriorEdge_Static(ornt[2],1);
5355       orntNew[3] = 0;
5356       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5357       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
5358 #if defined(PETSC_USE_DEBUG)
5359       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
5360       for (p = 0; p < 4; ++p) {
5361         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", coneNew[p], eStartNew, eEndNew);
5362       }
5363 #endif
5364       supportNew[0] = (c - cStart)*4 + 2;
5365       supportNew[1] = (c - cStart)*4 + 3;
5366       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
5367 #if defined(PETSC_USE_DEBUG)
5368       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
5369       for (p = 0; p < 2; ++p) {
5370         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", supportNew[p], cStartNew, cEndNew);
5371       }
5372 #endif
5373       ++newp;
5374     }
5375     /* Split Edges have 2 vertices and the same faces as the parent */
5376     for (e = eStart; e < eEnd; ++e) {
5377       const PetscInt newv = vStartNew + (vEnd - vStart) + (e - eStart);
5378 
5379       for (r = 0; r < 2; ++r) {
5380         const PetscInt  newp = eStartNew + (e - eStart)*2 + r;
5381         const PetscInt *cone, *ornt, *support;
5382         PetscInt        coneNew[2], coneSize, c, supportSize, s;
5383 
5384         ierr             = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
5385         coneNew[0]       = vStartNew + (cone[0] - vStart);
5386         coneNew[1]       = vStartNew + (cone[1] - vStart);
5387         coneNew[(r+1)%2] = newv;
5388         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5389 #if defined(PETSC_USE_DEBUG)
5390         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eEndNew);
5391         for (p = 0; p < 2; ++p) {
5392           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", coneNew[p], vStartNew, vEndNew);
5393         }
5394 #endif
5395         ierr = DMPlexGetSupportSize(dm, e, &supportSize);CHKERRQ(ierr);
5396         ierr = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
5397         for (s = 0; s < supportSize; ++s) {
5398           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
5399           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
5400           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
5401           for (c = 0; c < coneSize; ++c) {
5402             if (cone[c] == e) break;
5403           }
5404           supportRef[s] = fStartNew + (support[s] - fStart)*3 + (c + (ornt[c] < 0 ? 1-r : r))%3;
5405         }
5406         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
5407 #if defined(PETSC_USE_DEBUG)
5408         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eEndNew);
5409         for (p = 0; p < supportSize; ++p) {
5410           if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", supportRef[p], fStartNew, fEndNew);
5411         }
5412 #endif
5413       }
5414     }
5415     /* Face edges have 2 vertices and 2 + cell faces supports */
5416     for (f = fStart; f < fEnd; ++f) {
5417       const PetscInt *cone, *ornt, *support;
5418       PetscInt        coneSize, supportSize, s;
5419 
5420       ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
5421       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
5422       for (r = 0; r < 3; ++r) {
5423         const PetscInt  newp = eStartNew + (eEnd - eStart)*2 + (f - fStart)*3 + r;
5424         PetscInt        coneNew[2];
5425         PetscInt        fint[4][3] = { {0, 1, 2},
5426                                        {3, 4, 0},
5427                                        {2, 5, 3},
5428                                        {1, 4, 5} };
5429 
5430         ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
5431         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r] - eStart);
5432         coneNew[1] = vStartNew + (vEnd - vStart) + (eEnd - eStart) + f - fStart;
5433         ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5434 #if defined(PETSC_USE_DEBUG)
5435         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eEndNew);
5436         for (p = 0; p < 2; ++p) {
5437           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", coneNew[p], vStartNew, vEndNew);
5438         }
5439 #endif
5440         supportRef[0] = fStartNew + (f - fStart)*3 + (r+0)%3;
5441         supportRef[1] = fStartNew + (f - fStart)*3 + (r+1)%3;
5442         for (s = 0; s < supportSize; ++s) {
5443           PetscInt er;
5444           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
5445           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
5446           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
5447           for (c = 0; c < coneSize; ++c) {if (cone[c] == f) break;}
5448           er = GetTriInteriorEdgeInverse_Static(ornt[c], r);
5449           supportRef[2+s] = fStartNew + (fEnd - fStart)*3 + (support[s] - cStart)*6 + fint[c][er];
5450         }
5451         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
5452 #if defined(PETSC_USE_DEBUG)
5453         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eEndNew);
5454         for (p = 0; p < supportSize + 2; ++p) {
5455           if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", supportRef[p], fStartNew, fEndNew);
5456         }
5457 #endif
5458       }
5459     }
5460     /* Interior cell edges have 2 vertices and 3 faces */
5461     for (c = cStart; c < cEnd; ++c) {
5462       const PetscInt *cone;
5463       PetscInt       fint[4][3] = { {0,1,2},
5464                                     {0,3,4},
5465                                     {2,3,5},
5466                                     {1,4,5} } ;
5467 
5468       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
5469       for (r = 0; r < 4; r++) {
5470         PetscInt       coneNew[2], supportNew[3];
5471         const PetscInt newp = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + r;
5472 
5473         coneNew[0] = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (cone[r] - fStart);
5474         coneNew[1] = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (fEnd -fStart) + c - cStart;
5475         ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5476 #if defined(PETSC_USE_DEBUG)
5477         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eEndNew);
5478         for (p = 0; p < 2; ++p) {
5479           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", coneNew[p], vStartNew, vEndNew);
5480         }
5481 #endif
5482         supportNew[0] = fStartNew + (fEnd - fStart)*3 + (c - cStart)*6 + fint[r][0];
5483         supportNew[1] = fStartNew + (fEnd - fStart)*3 + (c - cStart)*6 + fint[r][1];
5484         supportNew[2] = fStartNew + (fEnd - fStart)*3 + (c - cStart)*6 + fint[r][2];
5485         ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
5486 #if defined(PETSC_USE_DEBUG)
5487         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eEndNew);
5488         for (p = 0; p < 3; ++p) {
5489           if ((supportNew[p] < fStartNew) || (supportNew[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", supportNew[p], fStartNew, fEndNew);
5490         }
5491 #endif
5492       }
5493     }
5494     /* Old vertices have identical supports */
5495     for (v = vStart; v < vEnd; ++v) {
5496       const PetscInt  newp = vStartNew + (v - vStart);
5497       const PetscInt *support, *cone;
5498       PetscInt        size, s;
5499 
5500       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
5501       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
5502       for (s = 0; s < size; ++s) {
5503         PetscInt r = 0;
5504 
5505         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
5506         if (cone[1] == v) r = 1;
5507         supportRef[s] = eStartNew + (support[s] - eStart)*2 + r;
5508       }
5509       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
5510 #if defined(PETSC_USE_DEBUG)
5511       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", newp, vStartNew, vEndNew);
5512       for (p = 0; p < size; ++p) {
5513         if ((supportRef[p] < eStartNew) || (supportRef[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", supportRef[p], eStartNew, eEndNew);
5514       }
5515 #endif
5516     }
5517     /* Edge vertices have 2 + faces supports */
5518     for (e = eStart; e < eEnd; ++e) {
5519       const PetscInt  newp = vStartNew + (vEnd - vStart) + (e - eStart);
5520       const PetscInt *cone, *support;
5521       PetscInt        size, s;
5522 
5523       ierr          = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
5524       ierr          = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
5525       supportRef[0] = eStartNew + (e - eStart)*2 + 0;
5526       supportRef[1] = eStartNew + (e - eStart)*2 + 1;
5527       for (s = 0; s < size; ++s) {
5528         PetscInt r = 0, coneSize;
5529 
5530         ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
5531         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
5532         for (r = 0; r < coneSize; ++r) {if (cone[r] == e) break;}
5533         supportRef[2+s] = eStartNew + (eEnd - eStart)*2 + (support[s] - fStart)*3 + r;
5534       }
5535       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
5536 #if defined(PETSC_USE_DEBUG)
5537       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", newp, vStartNew, vEndNew);
5538       for (p = 0; p < 2+size; ++p) {
5539         if ((supportRef[p] < eStartNew) || (supportRef[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", supportRef[p], eStartNew, eEndNew);
5540       }
5541 #endif
5542     }
5543     /* Face vertices have 3 + cells supports */
5544     for (f = fStart; f < fEnd; ++f) {
5545       const PetscInt  newp = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (f - fStart);
5546       const PetscInt *cone, *support;
5547       PetscInt        size, s;
5548 
5549       ierr          = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
5550       ierr          = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
5551       supportRef[0] = eStartNew + (eEnd - eStart)*2 + (f - fStart)*3 + 0;
5552       supportRef[1] = eStartNew + (eEnd - eStart)*2 + (f - fStart)*3 + 1;
5553       supportRef[2] = eStartNew + (eEnd - eStart)*2 + (f - fStart)*3 + 2;
5554       for (s = 0; s < size; ++s) {
5555         PetscInt r = 0, coneSize;
5556 
5557         ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
5558         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
5559         for (r = 0; r < coneSize; ++r) {if (cone[r] == f) break;}
5560         supportRef[3+s] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (support[s] - cStart)*4 + r;
5561       }
5562       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
5563 #if defined(PETSC_USE_DEBUG)
5564       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", newp, vStartNew, vEndNew);
5565       for (p = 0; p < 3+size; ++p) {
5566         if ((supportRef[p] < eStartNew) || (supportRef[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", supportRef[p], eStartNew, eEndNew);
5567       }
5568 #endif
5569     }
5570     /* Interior cell vertices have 4 supports */
5571     for (c = cStart; c < cEnd; ++c) {
5572       const PetscInt  newp = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (fEnd - fStart) + c - cStart;
5573       supportRef[0] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + 0;
5574       supportRef[1] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + 1;
5575       supportRef[2] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + 2;
5576       supportRef[3] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + 3;
5577       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
5578 #if defined(PETSC_USE_DEBUG)
5579       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", newp, vStartNew, vEndNew);
5580       for (p = 0; p < 4; ++p) {
5581         if ((supportRef[p] < eStartNew) || (supportRef[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", supportRef[p], eStartNew, eEndNew);
5582       }
5583 #endif
5584     }
5585     ierr = PetscFree(supportRef);CHKERRQ(ierr);
5586     ierr = DMPlexRestoreFaces_Internal(dm, 3, cStart, NULL, NULL, &faces);CHKERRQ(ierr);
5587     break;
5588   case REFINER_HYBRID_SIMPLEX_TO_HEX_3D:
5589     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
5590     cMax = PetscMin(cEnd, cMax);
5591     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
5592     fMax = PetscMin(fEnd, fMax);
5593     if (eMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
5594     eMax = PetscMin(eEnd, eMax);
5595     ierr = DMPlexGetRawFaces_Internal(dm, 3, 4, cellInd, NULL, NULL, &faces);CHKERRQ(ierr);
5596     /* All cells have 6 faces */
5597     for (c = cStart; c < cMax; ++c) {
5598       const PetscInt  newp = cStartNew + (c - cStart)*4;
5599       const PetscInt *cone, *ornt;
5600       PetscInt        coneNew[6];
5601       PetscInt        orntNew[6];
5602 
5603       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
5604 #if defined(PETSC_USE_DEBUG)
5605       for (p = 0; p < 4; ++p) {
5606         if (cone[p] >= fMax) SETERRQ4(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected hybrid face %D (fMax %D) in cone position %D for cell %D", cone[p], p, fMax, c);
5607       }
5608 #endif
5609       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
5610       /* A hex */
5611       coneNew[0] = fStartNew + (cone[0] - fStart)*3 + GetTriSubface_Static(ornt[0], 0); /* B */
5612       orntNew[0] = ornt[0] < 0 ? -1 : 1;
5613       coneNew[1] = fStartNew + (fMax    - fStart)*3 + (c - cStart)*6 + 3;               /* T */
5614       orntNew[1] = -4;
5615       coneNew[2] = fStartNew + (cone[2] - fStart)*3 + GetTriSubface_Static(ornt[2], 0); /* F */
5616       orntNew[2] = ornt[2] < 0 ? -1 : 1;
5617       coneNew[3] = fStartNew + (fMax    - fStart)*3 + (c - cStart)*6 + 0;               /* K */
5618       orntNew[3] = -1;
5619       coneNew[4] = fStartNew + (fMax    - fStart)*3 + (c - cStart)*6 + 2;               /* R */
5620       orntNew[4] = 0;
5621       coneNew[5] = fStartNew + (cone[1] - fStart)*3 + GetTriSubface_Static(ornt[1], 0); /* L */
5622       orntNew[5] = ornt[1] < 0 ? -1 : 1;
5623       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
5624       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
5625 #if defined(PETSC_USE_DEBUG)
5626       if ((newp+0 < cStartNew) || (newp+0 >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", newp+0, cStartNew, cEndNew);
5627       for (p = 0; p < 6; ++p) {
5628         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", coneNew[p], fStartNew, fEndNew);
5629       }
5630 #endif
5631       /* B hex */
5632       coneNew[0] = fStartNew + (cone[0] - fStart)*3 + GetTriSubface_Static(ornt[0], 1); /* B */
5633       orntNew[0] = ornt[0] < 0 ? -2 : 0;
5634       coneNew[1] = fStartNew + (fMax    - fStart)*3 + (c - cStart)*6 + 4;               /* T */
5635       orntNew[1] = 0;
5636       coneNew[2] = fStartNew + (fMax    - fStart)*3 + (c - cStart)*6 + 0;               /* F */
5637       orntNew[2] = 0;
5638       coneNew[3] = fStartNew + (cone[3] - fStart)*3 + GetTriSubface_Static(ornt[3], 1); /* K */
5639       orntNew[3] = ornt[3] < 0 ? -2 : 0;
5640       coneNew[4] = fStartNew + (fMax    - fStart)*3 + (c - cStart)*6 + 1;               /* R */
5641       orntNew[4] = 0;
5642       coneNew[5] = fStartNew + (cone[1] - fStart)*3 + GetTriSubface_Static(ornt[1], 2); /* L */
5643       orntNew[5] = ornt[1] < 0 ? -4 : 2;
5644       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
5645       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
5646 #if defined(PETSC_USE_DEBUG)
5647       if ((newp+1 < cStartNew) || (newp+1 >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", newp+1, cStartNew, cEndNew);
5648       for (p = 0; p < 6; ++p) {
5649         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", coneNew[p], fStartNew, fEndNew);
5650       }
5651 #endif
5652       /* C hex */
5653       coneNew[0] = fStartNew + (cone[0] - fStart)*3 + GetTriSubface_Static(ornt[0], 2); /* B */
5654       orntNew[0] = ornt[0] < 0 ? -4 : 2;
5655       coneNew[1] = fStartNew + (fMax    - fStart)*3 + (c - cStart)*6 + 5;               /* T */
5656       orntNew[1] = -4;
5657       coneNew[2] = fStartNew + (cone[2] - fStart)*3 + GetTriSubface_Static(ornt[2], 1); /* F */
5658       orntNew[2] = ornt[2] < 0 ? -2 : 0;
5659       coneNew[3] = fStartNew + (fMax    - fStart)*3 + (c - cStart)*6 + 1;               /* K */
5660       orntNew[3] = -1;
5661       coneNew[4] = fStartNew + (cone[3] - fStart)*3 + GetTriSubface_Static(ornt[3], 0); /* R */
5662       orntNew[4] = ornt[3] < 0 ? -1 : 1;
5663       coneNew[5] = fStartNew + (fMax    - fStart)*3 + (c - cStart)*6 + 2;               /* L */
5664       orntNew[5] = -4;
5665       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
5666       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
5667 #if defined(PETSC_USE_DEBUG)
5668       if ((newp+2 < cStartNew) || (newp+2 >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", newp+2, cStartNew, cEndNew);
5669       for (p = 0; p < 6; ++p) {
5670         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", coneNew[p], fStartNew, fEndNew);
5671       }
5672 #endif
5673       /* D hex */
5674       coneNew[0] = fStartNew + (fMax    - fStart)*3 + (c - cStart)*6 + 3;               /* B */
5675       orntNew[0] = 0;
5676       coneNew[1] = fStartNew + (cone[3] - fStart)*3 + GetTriSubface_Static(ornt[3], 2); /* T */
5677       orntNew[1] = ornt[3] < 0 ? -1 : 1;
5678       coneNew[2] = fStartNew + (cone[2] - fStart)*3 + GetTriSubface_Static(ornt[2], 2); /* F */
5679       orntNew[2] = ornt[2] < 0 ? -4 : 2;
5680       coneNew[3] = fStartNew + (fMax    - fStart)*3 + (c - cStart)*6 + 4;               /* K */
5681       orntNew[3] = -1;
5682       coneNew[4] = fStartNew + (fMax    - fStart)*3 + (c - cStart)*6 + 5;               /* R */
5683       orntNew[4] = 0;
5684       coneNew[5] = fStartNew + (cone[1] - fStart)*3 + GetTriSubface_Static(ornt[1], 1); /* L */
5685       orntNew[5] = ornt[1] < 0 ? -2 : 0;
5686       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
5687       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
5688 #if defined(PETSC_USE_DEBUG)
5689       if ((newp+3 < cStartNew) || (newp+3 >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", newp+3, cStartNew, cEndNew);
5690       for (p = 0; p < 6; ++p) {
5691         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", coneNew[p], fStartNew, fEndNew);
5692       }
5693 #endif
5694     }
5695     for (c = cMax; c < cEnd; ++c) {
5696       const PetscInt  newp = cStartNew + (cMax - cStart)*4 + (c - cMax)*3;
5697       const PetscInt *cone, *ornt, *fornt;
5698       PetscInt        coneNew[6], orntNew[6];
5699       PetscInt        o, of, cf;
5700 
5701       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
5702 #if defined(PETSC_USE_DEBUG)
5703       if (cone[0] >= fMax) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected hybrid face %D (fMax %D) in cone position 0 for cell %D", cone[0], fMax, c);
5704       if (cone[1] >= fMax) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected hybrid face %D (fMax %D) in cone position 1 for cell %D", cone[1], fMax, c);
5705       if (cone[2] <  fMax) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected face %D (fMax %D) in cone position 2 for cell %D", cone[2], fMax, c);
5706       if (cone[3] <  fMax) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected face %D (fMax %D) in cone position 3 for cell %D", cone[3], fMax, c);
5707       if (cone[4] <  fMax) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected face %D (fMax %D) in cone position 4 for cell %D", cone[4], fMax, c);
5708 #endif
5709       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
5710       ierr = DMPlexGetConeOrientation(dm, cone[0], &fornt);CHKERRQ(ierr);
5711       o    = ornt[0] < 0 ? -1 : 1;
5712       /* A hex */
5713       coneNew[0] = fStartNew + (cone[0] - fStart)*3 + GetTriSubface_Static(ornt[0], 0);                            /* B */
5714       orntNew[0] = ornt[0] < 0 ? -1 :  1;
5715       coneNew[1] = fStartNew + (cone[1] - fStart)*3 + GetTriSubface_Static(ornt[1], 0);                            /* T */
5716       orntNew[1] = ornt[1] < 0 ?  1 : -1;
5717       cf         = GetTriEdge_Static(ornt[0], 2);
5718       of         = fornt[cf] < 0 ? -1 : 1;
5719       coneNew[2] = fStartNew + (fMax - fStart)*3 + (cMax - cStart)*6 + (cone[2+cf] - fMax)*2 + (o*of < 0 ? 0 : 1); /* F */
5720       orntNew[2] = o*of < 0 ? 0 : -1;
5721       coneNew[3] = fStartNew + (fMax - fStart)*3 + (cMax - cStart)*6 + (fEnd - fMax)*2 + (c - cMax)*3 + 0;         /* K */
5722       orntNew[3] = -1;
5723       coneNew[4] = fStartNew + (fMax - fStart)*3 + (cMax - cStart)*6 + (fEnd - fMax)*2 + (c - cMax)*3 + 2;         /* R */
5724       orntNew[4] = 0;
5725       cf         = GetTriEdge_Static(ornt[0], 0);
5726       of         = fornt[cf] < 0 ? -1 : 1;
5727       coneNew[5] = fStartNew + (fMax - fStart)*3 + (cMax - cStart)*6 + (cone[2+cf] - fMax)*2 + (o*of < 0 ? 1 : 0); /* L */
5728       orntNew[5] = o*of < 0 ? 1 : -4;
5729       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
5730       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
5731 #if defined(PETSC_USE_DEBUG)
5732       if ((newp+0 < cStartNew) || (newp+0 >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", newp+0, cStartNew, cEndNew);
5733       for (p = 0; p < 6; ++p) {
5734         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", coneNew[p], fStartNew, fEndNew);
5735       }
5736 #endif
5737       /* B hex */
5738       coneNew[0] = fStartNew + (cone[0] - fStart)*3 + GetTriSubface_Static(ornt[0], 1);                            /* B */
5739       orntNew[0] = ornt[0] < 0 ? -2 :  0;
5740       coneNew[1] = fStartNew + (cone[1] - fStart)*3 + GetTriSubface_Static(ornt[1], 1);                            /* T */
5741       orntNew[1] = ornt[1] < 0 ?  2 : -4;
5742       coneNew[2] = fStartNew + (fMax - fStart)*3 + (cMax - cStart)*6 + (fEnd - fMax)*2 + (c - cMax)*3 + 0;         /* F */
5743       orntNew[2] = 0;
5744       cf         = GetTriEdge_Static(ornt[0], 1);
5745       of         = fornt[cf] < 0 ? -1 : 1;
5746       coneNew[3] = fStartNew + (fMax - fStart)*3 + (cMax - cStart)*6 + (cone[2+cf] - fMax)*2 + (o*of < 0 ? 1 : 0); /* K */
5747       orntNew[3] = o*of < 0 ? 0 : -1;
5748       coneNew[4] = fStartNew + (fMax - fStart)*3 + (cMax - cStart)*6 + (fEnd - fMax)*2 + (c - cMax)*3 + 1;         /* R */
5749       orntNew[4] = -1;
5750       cf         = GetTriEdge_Static(ornt[0], 0);
5751       of         = fornt[cf] < 0 ? -1 : 1;
5752       coneNew[5] = fStartNew + (fMax - fStart)*3 + (cMax - cStart)*6 + (cone[2+cf] - fMax)*2 + (o*of < 0 ? 0 : 1); /* L */
5753       orntNew[5] = o*of < 0 ? 1 : -4;
5754       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
5755       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
5756 #if defined(PETSC_USE_DEBUG)
5757       if ((newp+1 < cStartNew) || (newp+1 >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", newp+1, cStartNew, cEndNew);
5758       for (p = 0; p < 6; ++p) {
5759         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", coneNew[p], fStartNew, fEndNew);
5760       }
5761 #endif
5762       /* C hex */
5763       coneNew[0] = fStartNew + (cone[0] - fStart)*3 + GetTriSubface_Static(ornt[0], 2);                            /* B */
5764       orntNew[0] = ornt[0] < 0 ? -4 : 2;
5765       coneNew[1] = fStartNew + (cone[1] - fStart)*3 + GetTriSubface_Static(ornt[1], 2);                            /* T */
5766       orntNew[1] = ornt[1] < 0 ? 0 : -2;
5767       cf         = GetTriEdge_Static(ornt[0], 2);
5768       of         = fornt[cf] < 0 ? -1 : 1;
5769       coneNew[2] = fStartNew + (fMax - fStart)*3 + (cMax - cStart)*6 + (cone[2+cf] - fMax)*2 + (o*of < 0 ? 1 : 0); /* F */
5770       orntNew[2] = o*of < 0 ? 0 : -1;
5771       coneNew[3] = fStartNew + (fMax - fStart)*3 + (cMax - cStart)*6 + (fEnd - fMax)*2 + (c - cMax)*3 + 1;         /* K */
5772       orntNew[3] = 0;
5773       cf         = GetTriEdge_Static(ornt[0], 1);
5774       of         = fornt[cf] < 0 ? -1 : 1;
5775       coneNew[4] = fStartNew + (fMax - fStart)*3 + (cMax - cStart)*6 + (cone[2+cf] - fMax)*2 + (o*of < 0 ? 0 : 1); /* R */
5776       orntNew[4] = o*of < 0 ? 0 : -1;
5777       coneNew[5] = fStartNew + (fMax - fStart)*3 + (cMax - cStart)*6 + (fEnd - fMax)*2 + (c - cMax)*3 + 2;         /* L */
5778       orntNew[5] = -4;
5779       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
5780       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
5781 #if defined(PETSC_USE_DEBUG)
5782       if ((newp+2 < cStartNew) || (newp+2 >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", newp+2, cStartNew, cEndNew);
5783       for (p = 0; p < 6; ++p) {
5784         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", coneNew[p], fStartNew, fEndNew);
5785       }
5786 #endif
5787     }
5788 
5789     /* Split faces have 4 edges and the same cells as the parent */
5790     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
5791     ierr = PetscMalloc1(2 + maxSupportSize*2, &supportRef);CHKERRQ(ierr);
5792     for (f = fStart; f < fMax; ++f) {
5793       const PetscInt  newp = fStartNew + (f - fStart)*3;
5794       const PetscInt *cone, *ornt, *support;
5795       PetscInt        coneNew[4], orntNew[4], coneSize, supportSize, s;
5796 
5797       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
5798 #if defined(PETSC_USE_DEBUG)
5799       for (p = 0; p < 3; ++p) {
5800         if (cone[p] >= eMax) SETERRQ4(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected hybrid edge %D (eMax %D) in cone position %D for face %D", cone[p], p, eMax, f);
5801       }
5802 #endif
5803       ierr = DMPlexGetConeOrientation(dm, f, &ornt);CHKERRQ(ierr);
5804       /* A quad */
5805       coneNew[0] = eStartNew + (cone[2] - eStart)*2 + (ornt[2] < 0 ? 0 : 1);
5806       orntNew[0] = ornt[2];
5807       coneNew[1] = eStartNew + (cone[0] - eStart)*2 + (ornt[0] < 0 ? 1 : 0);
5808       orntNew[1] = ornt[0];
5809       coneNew[2] = eStartNew + (eMax    - eStart)*2 + (f - fStart)*3 + 0;
5810       orntNew[2] = 0;
5811       coneNew[3] = eStartNew + (eMax    - eStart)*2 + (f - fStart)*3 + 2;
5812       orntNew[3] = -2;
5813       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
5814       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
5815 #if defined(PETSC_USE_DEBUG)
5816       if ((newp+0 < fStartNew) || (newp+0 >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp+0, fStartNew, fEndNew);
5817       for (p = 0; p < 4; ++p) {
5818         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", coneNew[p], eStartNew, eEndNew);
5819       }
5820 #endif
5821       /* B quad */
5822       coneNew[0] = eStartNew + (cone[0] - eStart)*2 + (ornt[0] < 0 ? 0 : 1);
5823       orntNew[0] = ornt[0];
5824       coneNew[1] = eStartNew + (cone[1] - eStart)*2 + (ornt[1] < 0 ? 1 : 0);
5825       orntNew[1] = ornt[1];
5826       coneNew[2] = eStartNew + (eMax    - eStart)*2 + (f - fStart)*3 + 1;
5827       orntNew[2] = 0;
5828       coneNew[3] = eStartNew + (eMax    - eStart)*2 + (f - fStart)*3 + 0;
5829       orntNew[3] = -2;
5830       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
5831       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
5832 #if defined(PETSC_USE_DEBUG)
5833       if ((newp+1 < fStartNew) || (newp+1 >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp+1, fStartNew, fEndNew);
5834       for (p = 0; p < 4; ++p) {
5835         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", coneNew[p], eStartNew, eEndNew);
5836       }
5837 #endif
5838       /* C quad */
5839       coneNew[0] = eStartNew + (cone[1] - eStart)*2 + (ornt[1] < 0 ? 0 : 1);
5840       orntNew[0] = ornt[1];
5841       coneNew[1] = eStartNew + (cone[2] - eStart)*2 + (ornt[2] < 0 ? 1 : 0);
5842       orntNew[1] = ornt[2];
5843       coneNew[2] = eStartNew + (eMax    - eStart)*2 + (f - fStart)*3 + 2;
5844       orntNew[2] = 0;
5845       coneNew[3] = eStartNew + (eMax    - eStart)*2 + (f - fStart)*3 + 1;
5846       orntNew[3] = -2;
5847       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
5848       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
5849 #if defined(PETSC_USE_DEBUG)
5850       if ((newp+2 < fStartNew) || (newp+2 >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp+2, fStartNew, fEndNew);
5851       for (p = 0; p < 4; ++p) {
5852         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", coneNew[p], eStartNew, eEndNew);
5853       }
5854 #endif
5855       ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
5856       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
5857       for (r = 0; r < 3; ++r) {
5858         for (s = 0; s < supportSize; ++s) {
5859           PetscInt subf;
5860 
5861           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
5862           if (coneSize != 5 && support[s] >= cMax) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected conesize %D for cell %D (cMax %D)", coneSize, support[s], cMax);
5863           if (coneSize != 4 && support[s] <  cMax) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected conesize %D for cell %D (cMax %D)", coneSize, support[s], cMax);
5864           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
5865           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
5866           for (c = 0; c < coneSize; ++c) {
5867             if (cone[c] == f) break;
5868           }
5869           subf = GetTriSubfaceInverse_Static(ornt[c], r);
5870           if (coneSize == 4) {
5871             supportRef[s] = cStartNew + (support[s] - cStart)*4 + faces[c*3+subf];
5872           } else if (coneSize == 5) {
5873             if (c != 0 && c != 1) SETERRQ4(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected position %D in cone %D of cell %D (cMax %D) for face %D", c, support[s], cMax, f);
5874             supportRef[s] = cStartNew + (cMax - cStart)*4 + (support[s] - cMax)*3 + subf;
5875           } else SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected conesize %D for cell %D (cMax %D)", coneSize, support[s], cMax);
5876         }
5877         ierr = DMPlexSetSupport(rdm, newp+r, supportRef);CHKERRQ(ierr);
5878 #if defined(PETSC_USE_DEBUG)
5879         if ((newp+r < fStartNew) || (newp+r >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp+r, fStartNew, fEndNew);
5880         for (p = 0; p < supportSize; ++p) {
5881           if ((supportRef[p] < cStartNew) || (supportRef[p] >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", supportRef[p], cStartNew, cEndNew);
5882         }
5883 #endif
5884       }
5885     }
5886     /* Interior faces have 4 edges and 2 cells */
5887     for (c = cStart; c < cMax; ++c) {
5888       PetscInt        newp = fStartNew + (fMax - fStart)*3 + (c - cStart)*6;
5889       const PetscInt *cone, *ornt;
5890       PetscInt        coneNew[4], orntNew[4];
5891       PetscInt        supportNew[2];
5892 
5893       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
5894 #if defined(PETSC_USE_DEBUG)
5895       for (p = 0; p < 4; ++p) {
5896         if (cone[p] >= fMax) SETERRQ4(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected hybrid face %D (fMax %D) in cone position %D for face %D", cone[p], p, fMax, f);
5897       }
5898 #endif
5899       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
5900       /* Face {a, g, m, h} */
5901       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*3 + GetTriInteriorEdge_Static(ornt[0],0);
5902       orntNew[0] = 0;
5903       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart)*4 + 0;
5904       orntNew[1] = 0;
5905       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart)*4 + 1;
5906       orntNew[2] = -2;
5907       coneNew[3] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*3 + GetTriInteriorEdge_Static(ornt[1],2);
5908       orntNew[3] = -2;
5909       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5910       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
5911 #if defined(PETSC_USE_DEBUG)
5912       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
5913       for (p = 0; p < 4; ++p) {
5914         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", coneNew[p], eStartNew, eEndNew);
5915       }
5916 #endif
5917       supportNew[0] = cStartNew + (c - cStart)*4 + 0;
5918       supportNew[1] = cStartNew + (c - cStart)*4 + 1;
5919       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
5920 #if defined(PETSC_USE_DEBUG)
5921       for (p = 0; p < 2; ++p) {
5922         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", supportNew[p], cStartNew, cEndNew);
5923       }
5924 #endif
5925       ++newp;
5926       /* Face {g, b, l , m} */
5927       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*3 + GetTriInteriorEdge_Static(ornt[0],1);
5928       orntNew[0] = -2;
5929       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*3 + GetTriInteriorEdge_Static(ornt[3],0);
5930       orntNew[1] = 0;
5931       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart)*4 + 3;
5932       orntNew[2] = 0;
5933       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart)*4 + 0;
5934       orntNew[3] = -2;
5935       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5936       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
5937 #if defined(PETSC_USE_DEBUG)
5938       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
5939       for (p = 0; p < 4; ++p) {
5940         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", coneNew[p], eStartNew, eEndNew);
5941       }
5942 #endif
5943       supportNew[0] = cStartNew + (c - cStart)*4 + 1;
5944       supportNew[1] = cStartNew + (c - cStart)*4 + 2;
5945       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
5946 #if defined(PETSC_USE_DEBUG)
5947       for (p = 0; p < 2; ++p) {
5948         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", supportNew[p], cStartNew, cEndNew);
5949       }
5950 #endif
5951       ++newp;
5952       /* Face {c, g, m, i} */
5953       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*3 + GetTriInteriorEdge_Static(ornt[0],2);
5954       orntNew[0] = 0;
5955       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart)*4 + 0;
5956       orntNew[1] = 0;
5957       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart)*4 + 2;
5958       orntNew[2] = -2;
5959       coneNew[3] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*3 + GetTriInteriorEdge_Static(ornt[2],0);
5960       orntNew[3] = -2;
5961       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5962       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
5963 #if defined(PETSC_USE_DEBUG)
5964       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
5965       for (p = 0; p < 4; ++p) {
5966         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", coneNew[p], eStartNew, eEndNew);
5967       }
5968 #endif
5969       supportNew[0] = cStartNew + (c - cStart)*4 + 0;
5970       supportNew[1] = cStartNew + (c - cStart)*4 + 2;
5971       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
5972 #if defined(PETSC_USE_DEBUG)
5973       for (p = 0; p < 2; ++p) {
5974         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", supportNew[p], cStartNew, cEndNew);
5975       }
5976 #endif
5977       ++newp;
5978       /* Face {d, h, m, i} */
5979       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*3 + GetTriInteriorEdge_Static(ornt[1],0);
5980       orntNew[0] = 0;
5981       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart)*4 + 1;
5982       orntNew[1] = 0;
5983       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart)*4 + 2;
5984       orntNew[2] = -2;
5985       coneNew[3] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*3 + GetTriInteriorEdge_Static(ornt[2],2);
5986       orntNew[3] = -2;
5987       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5988       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
5989 #if defined(PETSC_USE_DEBUG)
5990       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
5991       for (p = 0; p < 4; ++p) {
5992         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", coneNew[p], eStartNew, eEndNew);
5993       }
5994 #endif
5995       supportNew[0] = cStartNew + (c - cStart)*4 + 0;
5996       supportNew[1] = cStartNew + (c - cStart)*4 + 3;
5997       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
5998 #if defined(PETSC_USE_DEBUG)
5999       for (p = 0; p < 2; ++p) {
6000         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", supportNew[p], cStartNew, cEndNew);
6001       }
6002 #endif
6003       ++newp;
6004       /* Face {h, m, l, e} */
6005       coneNew[0] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart)*4 + 1;
6006       orntNew[0] = 0;
6007       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart)*4 + 3;
6008       orntNew[1] = -2;
6009       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*3 + GetTriInteriorEdge_Static(ornt[3],1);
6010       orntNew[2] = -2;
6011       coneNew[3] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*3 + GetTriInteriorEdge_Static(ornt[1],1);
6012       orntNew[3] = 0;
6013       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6014       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
6015 #if defined(PETSC_USE_DEBUG)
6016       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
6017       for (p = 0; p < 4; ++p) {
6018         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", coneNew[p], eStartNew, eEndNew);
6019       }
6020 #endif
6021       supportNew[0] = cStartNew + (c - cStart)*4 + 1;
6022       supportNew[1] = cStartNew + (c - cStart)*4 + 3;
6023       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
6024 #if defined(PETSC_USE_DEBUG)
6025       for (p = 0; p < 2; ++p) {
6026         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", supportNew[p], cStartNew, cEndNew);
6027       }
6028 #endif
6029       ++newp;
6030       /* Face {i, m, l, f} */
6031       coneNew[0] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart)*4 + 2;
6032       orntNew[0] = 0;
6033       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart)*4 + 3;
6034       orntNew[1] = -2;
6035       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*3 + GetTriInteriorEdge_Static(ornt[3],2);
6036       orntNew[2] = -2;
6037       coneNew[3] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*3 + GetTriInteriorEdge_Static(ornt[2],1);
6038       orntNew[3] = 0;
6039       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6040       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
6041 #if defined(PETSC_USE_DEBUG)
6042       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
6043       for (p = 0; p < 4; ++p) {
6044         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", coneNew[p], eStartNew, eEndNew);
6045       }
6046 #endif
6047       supportNew[0] = cStartNew + (c - cStart)*4 + 2;
6048       supportNew[1] = cStartNew + (c - cStart)*4 + 3;
6049       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
6050 #if defined(PETSC_USE_DEBUG)
6051       for (p = 0; p < 2; ++p) {
6052         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", supportNew[p], cStartNew, cEndNew);
6053       }
6054 #endif
6055       ++newp;
6056     }
6057     /* Hybrid split faces have 4 edges and same cells */
6058     for (f = fMax; f < fEnd; ++f) {
6059       const PetscInt *cone, *ornt, *support;
6060       PetscInt        coneNew[4], orntNew[4];
6061       PetscInt        size, s;
6062       const PetscInt  newp = fStartNew + (fMax - fStart)*3 + (cMax - cStart)*6 + (f - fMax)*2;
6063 
6064       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
6065 #if defined(PETSC_USE_DEBUG)
6066       if (cone[0] >= eMax) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected hybrid edge %D (eMax %D) in cone position 0 for face %D", cone[0], eMax, f);
6067       if (cone[1] >= eMax) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected hybrid edge %D (eMax %D) in cone position 1 for face %D", cone[1], eMax, f);
6068       if (cone[2] <  eMax) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected edge %D (eMax %D) in cone position 2 for face %D", cone[2], eMax, f);
6069       if (cone[3] <  eMax) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected edge %D (eMax %D) in cone position 3 for face %D", cone[3], eMax, f);
6070 #endif
6071       ierr = DMPlexGetConeOrientation(dm, f, &ornt);CHKERRQ(ierr);
6072       /* A face */
6073       coneNew[0] = eStartNew + (cone[0] - eStart)*2 + (ornt[0] < 0 ? 1 : 0);
6074       orntNew[0] = ornt[0];
6075       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart)*4 + (eEnd - eMax) + (f - fMax);
6076       orntNew[1] = 0;
6077       coneNew[2] = eStartNew + (cone[1] - eStart)*2 + (ornt[1] < 0 ? 1 : 0);
6078       orntNew[2] = ornt[1] < 0 ? 0 : -2;
6079       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart)*4 + (cone[2] - eMax);
6080       orntNew[3] = ornt[2] < 0 ? 0 : -2;
6081       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6082       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
6083 #if defined(PETSC_USE_DEBUG)
6084       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
6085       for (p = 0; p < 4; ++p) {
6086         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", coneNew[p], eStartNew, eEndNew);
6087       }
6088 #endif
6089 
6090       /* B face */
6091       coneNew[0] = eStartNew + (cone[0] - eStart)*2 + (ornt[0] < 0 ? 0 : 1);
6092       orntNew[0] = ornt[0];
6093       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart)*4 + (cone[3] - eMax);
6094       orntNew[1] = ornt[3];
6095       coneNew[2] = eStartNew + (cone[1] - eStart)*2 + (ornt[1] < 0 ? 0 : 1);
6096       orntNew[2] = ornt[1] < 0 ? 0 : -2;
6097       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart)*4 + (eEnd - eMax) + (f - fMax);
6098       orntNew[3] = -2;
6099       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
6100       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
6101 #if defined(PETSC_USE_DEBUG)
6102       if ((newp+1 < fStartNew) || (newp+1 >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp+1, fStartNew, fEndNew);
6103       for (p = 0; p < 4; ++p) {
6104         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", coneNew[p], eStartNew, eEndNew);
6105       }
6106 #endif
6107 
6108       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
6109       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
6110       for (r = 0; r < 2; ++r) {
6111         for (s = 0; s < size; ++s) {
6112           const PetscInt *coneCell, *orntCell, *fornt;
6113           PetscInt        coneSize, o, of, c;
6114 
6115           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
6116           if (coneSize != 5 || support[s] < cMax) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected conesize %D for cell %D (cMax %D)", coneSize, support[s], cMax);
6117           ierr = DMPlexGetCone(dm, support[s], &coneCell);CHKERRQ(ierr);
6118           ierr = DMPlexGetConeOrientation(dm, support[s], &orntCell);CHKERRQ(ierr);
6119           o = orntCell[0] < 0 ? -1 : 1;
6120           for (c = 0; c < coneSize; ++c) if (coneCell[c] == f) break;
6121           if (c == 0 || c == 1) SETERRQ4(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected position in cone %D of cell %D (cMax %D) for face %D", c, support[s], cMax, f);
6122           if (c == coneSize) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Could not find face %D in cone of cell %D", f, support[s]);
6123           ierr = DMPlexGetConeOrientation(dm, coneCell[0], &fornt);CHKERRQ(ierr);
6124           of = fornt[c-2] < 0 ? -1 : 1;
6125           supportRef[s] = cStartNew + (cMax - cStart)*4 + (support[s] - cMax)*3 + (GetTriEdgeInverse_Static(orntCell[0], c-2) + (o*of < 0 ? 1-r : r))%3;
6126         }
6127         ierr = DMPlexSetSupport(rdm, newp + r, supportRef);CHKERRQ(ierr);
6128 #if defined(PETSC_USE_DEBUG)
6129         for (p = 0; p < size; ++p) {
6130           if ((supportRef[p] < cStartNew) || (supportRef[p] >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", supportRef[p], cStartNew, cEndNew);
6131         }
6132 #endif
6133       }
6134     }
6135     /* Interior hybrid faces have 4 edges and 2 cells */
6136     for (c = cMax; c < cEnd; ++c) {
6137       PetscInt        newp = fStartNew + (fMax - fStart)*3 + (cMax - cStart)*6 + (fEnd - fMax)*2 + (c - cMax)*3;
6138       const PetscInt *cone, *ornt;
6139       PetscInt        coneNew[4], orntNew[4];
6140       PetscInt        supportNew[2];
6141 
6142       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
6143 #if defined(PETSC_USE_DEBUG)
6144       if (cone[0] >= fMax) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected hybrid face %D (fMax %D) in cone position 0 for cell %D", cone[0], fMax, c);
6145       if (cone[1] >= fMax) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected hybrid face %D (fMax %D) in cone position 1 for cell %D", cone[1], fMax, c);
6146       if (cone[2] <  fMax) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected face %D (fMax %D) in cone position 2 for cell %D", cone[2], fMax, c);
6147       if (cone[3] <  fMax) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected face %D (fMax %D) in cone position 3 for cell %D", cone[3], fMax, c);
6148       if (cone[4] <  fMax) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected face %D (fMax %D) in cone position 3 for cell %D", cone[3], fMax, c);
6149 #endif
6150       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
6151       /* Face {a, g, h, d} */
6152       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*3 + GetTriInteriorEdge_Static(ornt[0],0);
6153       orntNew[0] = 0;
6154       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart)*4 + (eEnd - eMax) + (fEnd - fMax) + c - cMax;
6155       orntNew[1] = 0;
6156       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*3 + GetTriInteriorEdge_Static(ornt[1],0);
6157       orntNew[2] = -2;
6158       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart)*4 + (eEnd - eMax) + (cone[2] - fMax);
6159       orntNew[3] = -2;
6160       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6161       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
6162 #if defined(PETSC_USE_DEBUG)
6163       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
6164       for (p = 0; p < 4; ++p) {
6165         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", coneNew[p], eStartNew, eEndNew);
6166       }
6167 #endif
6168       supportNew[0] = cStartNew + (cMax - cStart)*4 + (c - cMax)*3 + 0;
6169       supportNew[1] = cStartNew + (cMax - cStart)*4 + (c - cMax)*3 + 1;
6170       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
6171 #if defined(PETSC_USE_DEBUG)
6172       for (p = 0; p < 2; ++p) {
6173         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", supportNew[p], cStartNew, cEndNew);
6174       }
6175 #endif
6176       ++newp;
6177       /* Face {b, g, h, l} */
6178       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*3 + GetTriInteriorEdge_Static(ornt[0],1);
6179       orntNew[0] = 0;
6180       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart)*4 + (eEnd - eMax) + (fEnd - fMax) + c - cMax;
6181       orntNew[1] = 0;
6182       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*3 + GetTriInteriorEdge_Static(ornt[1],1);
6183       orntNew[2] = -2;
6184       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart)*4 + (eEnd - eMax) + (cone[3] - fMax);
6185       orntNew[3] = -2;
6186       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6187       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
6188 #if defined(PETSC_USE_DEBUG)
6189       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
6190       for (p = 0; p < 4; ++p) {
6191         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", coneNew[p], eStartNew, eEndNew);
6192       }
6193 #endif
6194       supportNew[0] = cStartNew + (cMax - cStart)*4 + (c - cMax)*3 + 1;
6195       supportNew[1] = cStartNew + (cMax - cStart)*4 + (c - cMax)*3 + 2;
6196       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
6197 #if defined(PETSC_USE_DEBUG)
6198       for (p = 0; p < 2; ++p) {
6199         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", supportNew[p], cStartNew, cEndNew);
6200       }
6201 #endif
6202       ++newp;
6203       /* Face {c, g, h, f} */
6204       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*3 + GetTriInteriorEdge_Static(ornt[0],2);
6205       orntNew[0] = 0;
6206       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart)*4 + (eEnd - eMax) + (fEnd - fMax) + c - cMax;
6207       orntNew[1] = 0;
6208       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*3 + GetTriInteriorEdge_Static(ornt[1],2);
6209       orntNew[2] = -2;
6210       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart)*4 + (eEnd - eMax) + (cone[4] - fMax);
6211       orntNew[3] = -2;
6212       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6213       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
6214 #if defined(PETSC_USE_DEBUG)
6215       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
6216       for (p = 0; p < 4; ++p) {
6217         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", coneNew[p], eStartNew, eEndNew);
6218       }
6219 #endif
6220       supportNew[0] = cStartNew + (cMax - cStart)*4 + (c - cMax)*3 + 2;
6221       supportNew[1] = cStartNew + (cMax - cStart)*4 + (c - cMax)*3 + 0;
6222       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
6223 #if defined(PETSC_USE_DEBUG)
6224       for (p = 0; p < 2; ++p) {
6225         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", supportNew[p], cStartNew, cEndNew);
6226       }
6227 #endif
6228     }
6229     /* Face edges have 2 vertices and 2 + cell faces supports */
6230     for (f = fStart; f < fMax; ++f) {
6231       const PetscInt *cone, *ornt, *support;
6232       PetscInt        coneSize, supportSize, s;
6233 
6234       ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
6235       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
6236       for (r = 0; r < 3; ++r) {
6237         const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (f - fStart)*3 + r;
6238         PetscInt        coneNew[2];
6239         PetscInt        fint[4][3] = { {0, 1, 2},
6240                                        {3, 4, 0},
6241                                        {2, 5, 3},
6242                                        {1, 4, 5} };
6243 
6244         ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
6245         if (cone[r] >= eMax) SETERRQ4(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected cone point %D in position %D for face %D (eMax %D)", cone[r], r, f, eMax);
6246         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r] - eStart);
6247         coneNew[1] = vStartNew + (vEnd - vStart) + (eMax - eStart) + f - fStart;
6248         ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6249 #if defined(PETSC_USE_DEBUG)
6250         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eEndNew);
6251         for (p = 0; p < 2; ++p) {
6252           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", coneNew[p], vStartNew, vEndNew);
6253         }
6254 #endif
6255         supportRef[0] = fStartNew + (f - fStart)*3 + (r+0)%3;
6256         supportRef[1] = fStartNew + (f - fStart)*3 + (r+1)%3;
6257         for (s = 0; s < supportSize; ++s) {
6258           PetscInt er;
6259 
6260           supportRef[2+s] = -1;
6261           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
6262           if (coneSize != 5 && support[s] >= cMax) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected conesize %D for cell %D (cMax %D)", coneSize, support[s], cMax);
6263           if (coneSize != 4 && support[s] <  cMax) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected conesize %D for cell %D (cMax %D)", coneSize, support[s], cMax);
6264           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6265           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
6266           for (c = 0; c < coneSize; ++c) {if (cone[c] == f) break;}
6267           er = GetTriInteriorEdgeInverse_Static(ornt[c], r);
6268           if (coneSize == 4) {
6269             supportRef[2+s] = fStartNew + (fMax - fStart)*3 + (support[s] - cStart)*6 + fint[c][er];
6270           } else if (coneSize == 5) {
6271             if (c != 0 && c != 1) SETERRQ4(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected position %D in cone %D of cell %D (cMax %D) for face %D", c, support[s], cMax, f);
6272             supportRef[2+s] = fStartNew + (fMax - fStart)*3 + (cMax - cStart)*6 + (fEnd - fMax)*2 + (support[s] - cMax)*3 + er;
6273           }
6274         }
6275         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6276 #if defined(PETSC_USE_DEBUG)
6277         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eEndNew);
6278         for (p = 0; p < supportSize + 2; ++p) {
6279           if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", supportRef[p], fStartNew, fEndNew);
6280         }
6281 #endif
6282       }
6283     }
6284     /* Interior cell edges have 2 vertices and 3 faces */
6285     for (c = cStart; c < cMax; ++c) {
6286       const PetscInt *cone;
6287       PetscInt       fint[4][3] = { {0,1,2},
6288                                     {0,3,4},
6289                                     {2,3,5},
6290                                     {1,4,5} } ;
6291 
6292       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
6293       for (r = 0; r < 4; r++) {
6294         PetscInt       coneNew[2], supportNew[3];
6295         const PetscInt newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart)*4 + r;
6296 
6297         if (cone[r] >= fMax) SETERRQ4(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected hybrid face %D (fMax %D) in cone position %D for cell %D", cone[r], r, fMax, c);
6298         coneNew[0] = vStartNew + (vEnd - vStart) + (eMax - eStart) + (cone[r] - fStart);
6299         coneNew[1] = vStartNew + (vEnd - vStart) + (eMax - eStart) + (fMax     -fStart) + c - cStart;
6300         ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6301 #if defined(PETSC_USE_DEBUG)
6302         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eEndNew);
6303         for (p = 0; p < 2; ++p) {
6304           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", coneNew[p], vStartNew, vEndNew);
6305         }
6306 #endif
6307         supportNew[0] = fStartNew + (fMax - fStart)*3 + (c - cStart)*6 + fint[r][0];
6308         supportNew[1] = fStartNew + (fMax - fStart)*3 + (c - cStart)*6 + fint[r][1];
6309         supportNew[2] = fStartNew + (fMax - fStart)*3 + (c - cStart)*6 + fint[r][2];
6310         ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
6311 #if defined(PETSC_USE_DEBUG)
6312         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eEndNew);
6313         for (p = 0; p < 3; ++p) {
6314           if ((supportNew[p] < fStartNew) || (supportNew[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", supportNew[p], fStartNew, fEndNew);
6315         }
6316 #endif
6317       }
6318     }
6319     /* Hybrid edges have two vertices and the same faces */
6320     for (e = eMax; e < eEnd; ++e) {
6321       const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart)*4 + (e - eMax);
6322       const PetscInt *cone, *support, *fcone;
6323       PetscInt        coneNew[2], size, fsize, s;
6324 
6325       ierr = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
6326       ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
6327       ierr = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
6328       coneNew[0] = vStartNew + (cone[0] - vStart);
6329       coneNew[1] = vStartNew + (cone[1] - vStart);
6330       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6331 #if defined(PETSC_USE_DEBUG)
6332       if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is a edge [%D, %D)", newp, eStartNew, eEndNew);
6333       for (p = 0; p < 2; ++p) {
6334         if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", coneNew[p], vStartNew, vEndNew);
6335       }
6336 #endif
6337       for (s = 0; s < size; ++s) {
6338         ierr = DMPlexGetConeSize(dm, support[s], &fsize);CHKERRQ(ierr);
6339         ierr = DMPlexGetCone(dm, support[s], &fcone);CHKERRQ(ierr);
6340         for (c = 0; c < fsize; ++c) if (fcone[c] == e) break;
6341         if ((c < 2) || (c > 3)) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Edge %D not found in cone of face %D", e, support[s]);
6342         supportRef[s] = fStartNew + (fMax - fStart)*3 + (cMax - cStart)*6 + (support[s] - fMax)*2 + c-2;
6343       }
6344       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6345 #if defined(PETSC_USE_DEBUG)
6346       for (p = 0; p < size; ++p) {
6347         if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", supportRef[p], fStartNew, fEndNew);
6348       }
6349 #endif
6350     }
6351     /* Hybrid face edges have 2 vertices and 2 + cell faces supports */
6352     for (f = fMax; f < fEnd; ++f) {
6353       const PetscInt *cone, *ornt, *support;
6354       PetscInt        coneSize, supportSize;
6355       const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart)*4 + (eEnd - eMax) + f - fMax;
6356       PetscInt        coneNew[2], s;
6357 
6358       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
6359 #if defined(PETSC_USE_DEBUG)
6360       if (cone[0] >= eMax) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected cone point %D in position 0 for face %D (eMax %D)", cone[0], f, eMax);
6361       if (cone[1] >= eMax) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected cone point %D in position 1 for face %D (eMax %D)", cone[1], f, eMax);
6362 #endif
6363       coneNew[0] = vStartNew + (vEnd - vStart) + (cone[0] - eStart);
6364       coneNew[1] = vStartNew + (vEnd - vStart) + (cone[1] - eStart);
6365       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6366 #if defined(PETSC_USE_DEBUG)
6367       if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eEndNew);
6368       for (p = 0; p < 2; ++p) {
6369         if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", coneNew[p], vStartNew, vEndNew);
6370       }
6371 #endif
6372       supportRef[0] = fStartNew + (fMax - fStart)*3 + (cMax - cStart)*6 + (f- fMax)*2 + 0;
6373       supportRef[1] = fStartNew + (fMax - fStart)*3 + (cMax - cStart)*6 + (f- fMax)*2 + 1;
6374       ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
6375       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
6376       for (s = 0; s < supportSize; ++s) {
6377         ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
6378         if (coneSize != 5 || support[s] < cMax) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected conesize %D for cell %D (cMax %D)", coneSize, support[s], cMax);
6379         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6380         ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
6381         for (c = 0; c < coneSize; ++c) {if (cone[c] == f) break;}
6382         if (c == 0 || c == 1) SETERRQ4(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected position in cone %D of cell %D (cMax %D) for face %D", c, support[s], cMax, f);
6383         supportRef[2+s] = fStartNew + (fMax - fStart)*3 + (cMax - cStart)*6 + (fEnd - fMax)*2 + (support[s] - cMax)*3 + c - 2;
6384       }
6385       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6386 #if defined(PETSC_USE_DEBUG)
6387       if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eEndNew);
6388       for (p = 0; p < supportSize + 2; ++p) {
6389         if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", supportRef[p], fStartNew, fEndNew);
6390       }
6391 #endif
6392     }
6393     /* Hybrid cell edges have 2 vertices and 3 faces */
6394     for (c = cMax; c < cEnd; ++c) {
6395       PetscInt       coneNew[2], supportNew[3];
6396       const PetscInt newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart)*4 + (eEnd - eMax) + (fEnd - fMax) + c - cMax;
6397       const PetscInt *cone;
6398 
6399       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
6400 #if defined(PETSC_USE_DEBUG)
6401       if (cone[0] >= fMax) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected hybrid face %D (fMax %D) in cone position 0 for cell %D", cone[0], fMax, c);
6402       if (cone[1] >= fMax) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected hybrid face %D (fMax %D) in cone position 1 for cell %D", cone[1], fMax, c);
6403 #endif
6404       coneNew[0] = vStartNew + (vEnd - vStart) + (eMax - eStart) + (cone[0] - fStart);
6405       coneNew[1] = vStartNew + (vEnd - vStart) + (eMax - eStart) + (cone[1] - fStart);
6406       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6407 #if defined(PETSC_USE_DEBUG)
6408       if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eEndNew);
6409       for (p = 0; p < 2; ++p) {
6410         if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", coneNew[p], vStartNew, vEndNew);
6411       }
6412 #endif
6413       supportNew[0] = fStartNew + (fMax - fStart)*3 + (cMax - cStart)*6 + (fEnd - fMax)*2 + (c - cMax)*3 + 0;
6414       supportNew[1] = fStartNew + (fMax - fStart)*3 + (cMax - cStart)*6 + (fEnd - fMax)*2 + (c - cMax)*3 + 1;
6415       supportNew[2] = fStartNew + (fMax - fStart)*3 + (cMax - cStart)*6 + (fEnd - fMax)*2 + (c - cMax)*3 + 2;
6416       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
6417 #if defined(PETSC_USE_DEBUG)
6418       if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eEndNew);
6419       for (p = 0; p < 3; ++p) {
6420         if ((supportNew[p] < fStartNew) || (supportNew[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", supportNew[p], fStartNew, fEndNew);
6421       }
6422 #endif
6423     }
6424     /* Old vertices have identical supports */
6425     for (v = vStart; v < vEnd; ++v) {
6426       const PetscInt  newp = vStartNew + (v - vStart);
6427       const PetscInt *support, *cone;
6428       PetscInt        size, s;
6429 
6430       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
6431       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
6432       for (s = 0; s < size; ++s) {
6433         const PetscInt e = support[s];
6434 
6435         supportRef[s] = -1;
6436         if (eStart <= e) {
6437           if (e < eMax) {
6438             ierr = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
6439             supportRef[s] = eStartNew + (e - eStart)*2 + (cone[1] == v ? 1 : 0);
6440           } else if (e < eEnd) {
6441             supportRef[s] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart)*4 + e - eMax;
6442           } else SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", e, eStart, eEnd);
6443         } else SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", e, eStart, eEnd);
6444       }
6445       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6446 #if defined(PETSC_USE_DEBUG)
6447       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", newp, vStartNew, vEndNew);
6448       for (p = 0; p < size; ++p) {
6449         if ((supportRef[p] < eStartNew) || (supportRef[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", supportRef[p], eStartNew, eEndNew);
6450       }
6451 #endif
6452     }
6453     /* Interior edge vertices have 2 + faces supports */
6454     for (e = eStart; e < eMax; ++e) {
6455       const PetscInt  newp = vStartNew + (vEnd - vStart) + (e - eStart);
6456       const PetscInt *cone, *support;
6457       PetscInt        size, s;
6458 
6459       ierr          = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
6460       ierr          = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
6461       supportRef[0] = eStartNew + (e - eStart)*2 + 0;
6462       supportRef[1] = eStartNew + (e - eStart)*2 + 1;
6463       for (s = 0; s < size; ++s) {
6464         PetscInt r, coneSize;
6465 
6466         supportRef[2+s] = -1;
6467         ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
6468         if (coneSize != 4 && support[s] >= fMax) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected conesize %D for face %D (fMax %D)", coneSize, support[s], fMax);
6469         if (coneSize != 3 && support[s] <  fMax) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected conesize %D for face %D (fMax %D)", coneSize, support[s], fMax);
6470         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6471         for (r = 0; r < coneSize; ++r) {if (cone[r] == e) break;}
6472         if (coneSize == 3) supportRef[2+s] = eStartNew + (eMax - eStart)*2 + (support[s] - fStart)*3 + r;
6473         else if (coneSize == 4) {
6474           if (r != 0 && r != 1) SETERRQ4(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected position in cone %D of face %D (fMax %D) for edge %D", r, support[s], fMax, e);
6475           supportRef[2+s] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart)*4 + (eEnd - eMax) + support[s] - fMax;
6476         } else SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected conesize %D for face %D (fMax %D)", coneSize, support[s], fMax);
6477       }
6478       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6479 #if defined(PETSC_USE_DEBUG)
6480       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", newp, vStartNew, vEndNew);
6481       for (p = 0; p < 2+size; ++p) {
6482         if ((supportRef[p] < eStartNew) || (supportRef[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", supportRef[p], eStartNew, eEndNew);
6483       }
6484 #endif
6485     }
6486     /* Split Edges have 2 vertices and the same faces as the parent */
6487     for (e = eStart; e < eMax; ++e) {
6488       const PetscInt newv = vStartNew + (vEnd - vStart) + (e - eStart);
6489 
6490       for (r = 0; r < 2; ++r) {
6491         const PetscInt  newp = eStartNew + (e - eStart)*2 + r;
6492         const PetscInt *cone, *ornt, *support;
6493         PetscInt        coneNew[2], coneSize, c, supportSize, s;
6494 
6495         ierr             = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
6496         coneNew[0]       = vStartNew + (cone[0] - vStart);
6497         coneNew[1]       = vStartNew + (cone[1] - vStart);
6498         coneNew[(r+1)%2] = newv;
6499         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6500 #if defined(PETSC_USE_DEBUG)
6501         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eEndNew);
6502         for (p = 0; p < 2; ++p) {
6503           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", coneNew[p], vStartNew, vEndNew);
6504         }
6505 #endif
6506         ierr = DMPlexGetSupportSize(dm, e, &supportSize);CHKERRQ(ierr);
6507         ierr = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
6508         for (s = 0; s < supportSize; ++s) {
6509           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
6510           if (coneSize != 4 && support[s] >= fMax) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected conesize %D for face %D (fMax %D)", coneSize, support[s], fMax);
6511           if (coneSize != 3 && support[s] <  fMax) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected conesize %D for face %D (fMax %D)", coneSize, support[s], fMax);
6512           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6513           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
6514           for (c = 0; c < coneSize; ++c) {
6515             if (cone[c] == e) break;
6516           }
6517           if (coneSize == 3) supportRef[s] = fStartNew + (support[s] - fStart)*3 + (c + (ornt[c] < 0 ? 1-r : r))%3;
6518           else if (coneSize == 4) {
6519             if (c != 0 && c != 1) SETERRQ4(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected position in cone %D of face %D (fMax %D) for edge %D", c, support[s], fMax, e);
6520             supportRef[s] = fStartNew + (fMax - fStart)*3 + (cMax - cStart)*6 + (support[s] - fMax)*2 + (ornt[c] < 0 ? 1-r : r);
6521           } else SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected conesize %D for face %D (fMax %D)", coneSize, support[s], fMax);
6522         }
6523         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6524 #if defined(PETSC_USE_DEBUG)
6525         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eEndNew);
6526         for (p = 0; p < supportSize; ++p) {
6527           if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", supportRef[p], fStartNew, fEndNew);
6528         }
6529 #endif
6530       }
6531     }
6532     /* Face vertices have 3 + cells supports */
6533     for (f = fStart; f < fMax; ++f) {
6534       const PetscInt  newp = vStartNew + (vEnd - vStart) + (eMax - eStart) + (f - fStart);
6535       const PetscInt *cone, *support;
6536       PetscInt        size, s;
6537 
6538       ierr          = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
6539       ierr          = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
6540       supportRef[0] = eStartNew + (eMax - eStart)*2 + (f - fStart)*3 + 0;
6541       supportRef[1] = eStartNew + (eMax - eStart)*2 + (f - fStart)*3 + 1;
6542       supportRef[2] = eStartNew + (eMax - eStart)*2 + (f - fStart)*3 + 2;
6543       for (s = 0; s < size; ++s) {
6544         PetscInt r, coneSize;
6545 
6546         supportRef[3+s] = -1;
6547         ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
6548         if (coneSize != 5 && support[s] >= cMax) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected conesize %D for cell %D (cMax %D)", coneSize, support[s], cMax);
6549         if (coneSize != 4 && support[s] <  cMax) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected conesize %D for cell %D (cMax %D)", coneSize, support[s], cMax);
6550         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6551         for (r = 0; r < coneSize; ++r) {if (cone[r] == f) break;}
6552         if (coneSize == 4) supportRef[3+s] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (support[s] - cStart)*4 + r;
6553         else if (coneSize == 5) {
6554           if (r != 0 && r != 1) SETERRQ4(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected position in cone %D of cell %D (cMax %D) for face %D", r, support[s], cMax, f);
6555           supportRef[3+s] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart)*4 + (eEnd - eMax) + (fEnd - fMax) + support[s] - cMax;
6556         }
6557       }
6558       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6559 #if defined(PETSC_USE_DEBUG)
6560       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", newp, vStartNew, vEndNew);
6561       for (p = 0; p < 3+size; ++p) {
6562         if ((supportRef[p] < eStartNew) || (supportRef[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", supportRef[p], eStartNew, eEndNew);
6563       }
6564 #endif
6565     }
6566     /* Interior cell vertices have 4 supports */
6567     for (c = cStart; c < cMax; ++c) {
6568       const PetscInt  newp = vStartNew + (vEnd - vStart) + (eMax - eStart) + (fMax - fStart) + c - cStart;
6569 
6570       supportRef[0] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart)*4 + 0;
6571       supportRef[1] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart)*4 + 1;
6572       supportRef[2] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart)*4 + 2;
6573       supportRef[3] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart)*4 + 3;
6574       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6575 #if defined(PETSC_USE_DEBUG)
6576       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", newp, vStartNew, vEndNew);
6577       for (p = 0; p < 4; ++p) {
6578         if ((supportRef[p] < eStartNew) || (supportRef[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", supportRef[p], eStartNew, eEndNew);
6579       }
6580 #endif
6581     }
6582     ierr = PetscFree(supportRef);CHKERRQ(ierr);
6583     ierr = DMPlexRestoreFaces_Internal(dm, 3, cStart, NULL, NULL, &faces);CHKERRQ(ierr);
6584     break;
6585   case REFINER_HEX_3D:
6586     /*
6587      Bottom (viewed from top)    Top
6588      1---------2---------2       7---------2---------6
6589      |         |         |       |         |         |
6590      |    B    2    C    |       |    H    2    G    |
6591      |         |         |       |         |         |
6592      3----3----0----1----1       3----3----0----1----1
6593      |         |         |       |         |         |
6594      |    A    0    D    |       |    E    0    F    |
6595      |         |         |       |         |         |
6596      0---------0---------3       4---------0---------5
6597      */
6598     /* All cells have 6 faces: Bottom, Top, Front, Back, Right, Left */
6599     for (c = cStart; c < cEnd; ++c) {
6600       const PetscInt  newp = (c - cStart)*8;
6601       const PetscInt *cone, *ornt;
6602       PetscInt        coneNew[6], orntNew[6];
6603 
6604       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
6605       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
6606       /* A hex */
6607       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], 0);
6608       orntNew[0] = ornt[0];
6609       coneNew[1] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  8; /* AE */
6610       orntNew[1] = 0;
6611       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetQuadSubface_Static(ornt[2], 0);
6612       orntNew[2] = ornt[2];
6613       coneNew[3] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  3; /* AB */
6614       orntNew[3] = 0;
6615       coneNew[4] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  0; /* AD */
6616       orntNew[4] = 0;
6617       coneNew[5] = fStartNew + (cone[5] - fStart)*4 + GetQuadSubface_Static(ornt[5], 0);
6618       orntNew[5] = ornt[5];
6619       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
6620       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
6621 #if defined(PETSC_USE_DEBUG)
6622       if ((newp+0 < cStartNew) || (newp+0 >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", newp+0, cStartNew, cEndNew);
6623       for (p = 0; p < 6; ++p) {
6624         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", coneNew[p], fStartNew, fEndNew);
6625       }
6626 #endif
6627       /* B hex */
6628       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], 1);
6629       orntNew[0] = ornt[0];
6630       coneNew[1] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 + 11; /* BH */
6631       orntNew[1] = 0;
6632       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  3; /* AB */
6633       orntNew[2] = -1;
6634       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetQuadSubface_Static(ornt[3], 1);
6635       orntNew[3] = ornt[3];
6636       coneNew[4] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  2; /* BC */
6637       orntNew[4] = 0;
6638       coneNew[5] = fStartNew + (cone[5] - fStart)*4 + GetQuadSubface_Static(ornt[5], 3);
6639       orntNew[5] = ornt[5];
6640       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
6641       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
6642 #if defined(PETSC_USE_DEBUG)
6643       if ((newp+1 < cStartNew) || (newp+1 >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", newp+1, cStartNew, cEndNew);
6644       for (p = 0; p < 6; ++p) {
6645         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", coneNew[p], fStartNew, fEndNew);
6646       }
6647 #endif
6648       /* C hex */
6649       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], 2);
6650       orntNew[0] = ornt[0];
6651       coneNew[1] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 + 10; /* CG */
6652       orntNew[1] = 0;
6653       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  1; /* CD */
6654       orntNew[2] = -1;
6655       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetQuadSubface_Static(ornt[3], 0);
6656       orntNew[3] = ornt[3];
6657       coneNew[4] = fStartNew + (cone[4] - fStart)*4 + GetQuadSubface_Static(ornt[4], 1);
6658       orntNew[4] = ornt[4];
6659       coneNew[5] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  2; /* BC */
6660       orntNew[5] = -4;
6661       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
6662       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
6663 #if defined(PETSC_USE_DEBUG)
6664       if ((newp+2 < cStartNew) || (newp+2 >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", newp+2, cStartNew, cEndNew);
6665       for (p = 0; p < 6; ++p) {
6666         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", coneNew[p], fStartNew, fEndNew);
6667       }
6668 #endif
6669       /* D hex */
6670       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], 3);
6671       orntNew[0] = ornt[0];
6672       coneNew[1] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  9; /* DF */
6673       orntNew[1] = 0;
6674       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetQuadSubface_Static(ornt[2], 1);
6675       orntNew[2] = ornt[2];
6676       coneNew[3] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  1; /* CD */
6677       orntNew[3] = 0;
6678       coneNew[4] = fStartNew + (cone[4] - fStart)*4 + GetQuadSubface_Static(ornt[4], 0);
6679       orntNew[4] = ornt[4];
6680       coneNew[5] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  0; /* AD */
6681       orntNew[5] = -4;
6682       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
6683       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
6684 #if defined(PETSC_USE_DEBUG)
6685       if ((newp+3 < cStartNew) || (newp+3 >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", newp+3, cStartNew, cEndNew);
6686       for (p = 0; p < 6; ++p) {
6687         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", coneNew[p], fStartNew, fEndNew);
6688       }
6689 #endif
6690       /* E hex */
6691       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  8; /* AE */
6692       orntNew[0] = -4;
6693       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], 0);
6694       orntNew[1] = ornt[1];
6695       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetQuadSubface_Static(ornt[2], 3);
6696       orntNew[2] = ornt[2];
6697       coneNew[3] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  7; /* EH */
6698       orntNew[3] = 0;
6699       coneNew[4] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  4; /* EF */
6700       orntNew[4] = -1;
6701       coneNew[5] = fStartNew + (cone[5] - fStart)*4 + GetQuadSubface_Static(ornt[5], 1);
6702       orntNew[5] = ornt[5];
6703       ierr       = DMPlexSetCone(rdm, newp+4, coneNew);CHKERRQ(ierr);
6704       ierr       = DMPlexSetConeOrientation(rdm, newp+4, orntNew);CHKERRQ(ierr);
6705 #if defined(PETSC_USE_DEBUG)
6706       if ((newp+4 < cStartNew) || (newp+4 >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", newp+4, cStartNew, cEndNew);
6707       for (p = 0; p < 6; ++p) {
6708         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", coneNew[p], fStartNew, fEndNew);
6709       }
6710 #endif
6711       /* F hex */
6712       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  9; /* DF */
6713       orntNew[0] = -4;
6714       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], 1);
6715       orntNew[1] = ornt[1];
6716       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetQuadSubface_Static(ornt[2], 2);
6717       orntNew[2] = ornt[2];
6718       coneNew[3] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  5; /* FG */
6719       orntNew[3] = -1;
6720       coneNew[4] = fStartNew + (cone[4] - fStart)*4 + GetQuadSubface_Static(ornt[4], 3);
6721       orntNew[4] = ornt[4];
6722       coneNew[5] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  4; /* EF */
6723       orntNew[5] = 1;
6724       ierr       = DMPlexSetCone(rdm, newp+5, coneNew);CHKERRQ(ierr);
6725       ierr       = DMPlexSetConeOrientation(rdm, newp+5, orntNew);CHKERRQ(ierr);
6726 #if defined(PETSC_USE_DEBUG)
6727       if ((newp+5 < cStartNew) || (newp+5 >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", newp+5, cStartNew, cEndNew);
6728       for (p = 0; p < 6; ++p) {
6729         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", coneNew[p], fStartNew, fEndNew);
6730       }
6731 #endif
6732       /* G hex */
6733       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 + 10; /* CG */
6734       orntNew[0] = -4;
6735       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], 2);
6736       orntNew[1] = ornt[1];
6737       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  5; /* FG */
6738       orntNew[2] = 0;
6739       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetQuadSubface_Static(ornt[3], 3);
6740       orntNew[3] = ornt[3];
6741       coneNew[4] = fStartNew + (cone[4] - fStart)*4 + GetQuadSubface_Static(ornt[4], 2);
6742       orntNew[4] = ornt[4];
6743       coneNew[5] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  6; /* GH */
6744       orntNew[5] = -3;
6745       ierr       = DMPlexSetCone(rdm, newp+6, coneNew);CHKERRQ(ierr);
6746       ierr       = DMPlexSetConeOrientation(rdm, newp+6, orntNew);CHKERRQ(ierr);
6747 #if defined(PETSC_USE_DEBUG)
6748       if ((newp+6 < cStartNew) || (newp+6 >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", newp+6, cStartNew, cEndNew);
6749       for (p = 0; p < 6; ++p) {
6750         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", coneNew[p], fStartNew, fEndNew);
6751       }
6752 #endif
6753       /* H hex */
6754       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 + 11; /* BH */
6755       orntNew[0] = -4;
6756       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], 3);
6757       orntNew[1] = ornt[1];
6758       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  7; /* EH */
6759       orntNew[2] = -1;
6760       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetQuadSubface_Static(ornt[3], 2);
6761       orntNew[3] = ornt[3];
6762       coneNew[4] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  6; /* GH */
6763       orntNew[4] = 3;
6764       coneNew[5] = fStartNew + (cone[5] - fStart)*4 + GetQuadSubface_Static(ornt[5], 2);
6765       orntNew[5] = ornt[5];
6766       ierr       = DMPlexSetCone(rdm, newp+7, coneNew);CHKERRQ(ierr);
6767       ierr       = DMPlexSetConeOrientation(rdm, newp+7, orntNew);CHKERRQ(ierr);
6768 #if defined(PETSC_USE_DEBUG)
6769       if ((newp+7 < cStartNew) || (newp+7 >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", newp+7, cStartNew, cEndNew);
6770       for (p = 0; p < 6; ++p) {
6771         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", coneNew[p], fStartNew, fEndNew);
6772       }
6773 #endif
6774     }
6775     /* Split faces have 4 edges and the same cells as the parent */
6776     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
6777     ierr = PetscMalloc1(4 + maxSupportSize*2, &supportRef);CHKERRQ(ierr);
6778     for (f = fStart; f < fEnd; ++f) {
6779       for (r = 0; r < 4; ++r) {
6780         /* TODO: This can come from GetFaces_Internal() */
6781         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};
6782         const PetscInt  newp = fStartNew + (f - fStart)*4 + r;
6783         const PetscInt *cone, *ornt, *support;
6784         PetscInt        coneNew[4], orntNew[4], coneSize, c, supportSize, s;
6785 
6786         ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
6787         ierr = DMPlexGetConeOrientation(dm, f, &ornt);CHKERRQ(ierr);
6788         coneNew[(r+3)%4] = eStartNew + (cone[(r+3)%4] - eStart)*2 + (ornt[(r+3)%4] < 0 ? 0 : 1);
6789         orntNew[(r+3)%4] = ornt[(r+3)%4];
6790         coneNew[(r+0)%4] = eStartNew + (cone[r]       - eStart)*2 + (ornt[r] < 0 ? 1 : 0);
6791         orntNew[(r+0)%4] = ornt[r];
6792         coneNew[(r+1)%4] = eStartNew + (eEnd - eStart)*2 + (f - fStart)*4 + r;
6793         orntNew[(r+1)%4] = 0;
6794         coneNew[(r+2)%4] = eStartNew + (eEnd - eStart)*2 + (f - fStart)*4 + (r+3)%4;
6795         orntNew[(r+2)%4] = -2;
6796         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6797         ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
6798 #if defined(PETSC_USE_DEBUG)
6799         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
6800         for (p = 0; p < 4; ++p) {
6801           if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", coneNew[p], eStartNew, eEndNew);
6802         }
6803 #endif
6804         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
6805         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
6806         for (s = 0; s < supportSize; ++s) {
6807           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
6808           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6809           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
6810           for (c = 0; c < coneSize; ++c) {
6811             if (cone[c] == f) break;
6812           }
6813           supportRef[s] = cStartNew + (support[s] - cStart)*8 + newCells[c*4+GetQuadSubfaceInverse_Static(ornt[c], r)];
6814         }
6815         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6816 #if defined(PETSC_USE_DEBUG)
6817         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
6818         for (p = 0; p < supportSize; ++p) {
6819           if ((supportRef[p] < cStartNew) || (supportRef[p] >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", supportRef[p], cStartNew, cEndNew);
6820         }
6821 #endif
6822       }
6823     }
6824     /* Interior faces have 4 edges and 2 cells */
6825     for (c = cStart; c < cEnd; ++c) {
6826       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};
6827       const PetscInt *cone, *ornt;
6828       PetscInt        newp, coneNew[4], orntNew[4], supportNew[2];
6829 
6830       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
6831       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
6832       /* A-D face */
6833       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 0;
6834       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*4 + GetQuadEdge_Static(ornt[0], 3);
6835       orntNew[0] = 0;
6836       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 0;
6837       orntNew[1] = 0;
6838       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 2;
6839       orntNew[2] = -2;
6840       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*4 + GetQuadEdge_Static(ornt[2], 0);
6841       orntNew[3] = -2;
6842       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6843       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
6844 #if defined(PETSC_USE_DEBUG)
6845       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
6846       for (p = 0; p < 4; ++p) {
6847         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", coneNew[p], eStartNew, eEndNew);
6848       }
6849 #endif
6850       /* C-D face */
6851       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 1;
6852       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*4 + GetQuadEdge_Static(ornt[0], 2);
6853       orntNew[0] = 0;
6854       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 0;
6855       orntNew[1] = 0;
6856       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 4;
6857       orntNew[2] = -2;
6858       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (cone[4] - fStart)*4 + GetQuadEdge_Static(ornt[4], 0);
6859       orntNew[3] = -2;
6860       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6861       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
6862 #if defined(PETSC_USE_DEBUG)
6863       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
6864       for (p = 0; p < 4; ++p) {
6865         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", coneNew[p], eStartNew, eEndNew);
6866       }
6867 #endif
6868       /* B-C face */
6869       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 2;
6870       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*4 + GetQuadEdge_Static(ornt[0], 1);
6871       orntNew[0] = -2;
6872       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*4 + GetQuadEdge_Static(ornt[3], 0);
6873       orntNew[1] = 0;
6874       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 3;
6875       orntNew[2] = 0;
6876       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 0;
6877       orntNew[3] = -2;
6878       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6879       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
6880 #if defined(PETSC_USE_DEBUG)
6881       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
6882       for (p = 0; p < 4; ++p) {
6883         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", coneNew[p], eStartNew, eEndNew);
6884       }
6885 #endif
6886       /* A-B face */
6887       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 3;
6888       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*4 + GetQuadEdge_Static(ornt[0], 0);
6889       orntNew[0] = -2;
6890       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[5] - fStart)*4 + GetQuadEdge_Static(ornt[5], 3);
6891       orntNew[1] = 0;
6892       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 5;
6893       orntNew[2] = 0;
6894       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 0;
6895       orntNew[3] = -2;
6896       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6897       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
6898 #if defined(PETSC_USE_DEBUG)
6899       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
6900       for (p = 0; p < 4; ++p) {
6901         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", coneNew[p], eStartNew, eEndNew);
6902       }
6903 #endif
6904       /* E-F face */
6905       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 4;
6906       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 2;
6907       orntNew[0] = -2;
6908       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*4 + GetQuadEdge_Static(ornt[2], 2);
6909       orntNew[1] = -2;
6910       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*4 + GetQuadEdge_Static(ornt[1], 0);
6911       orntNew[2] = 0;
6912       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 1;
6913       orntNew[3] = 0;
6914       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6915       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
6916 #if defined(PETSC_USE_DEBUG)
6917       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
6918       for (p = 0; p < 4; ++p) {
6919         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", coneNew[p], eStartNew, eEndNew);
6920       }
6921 #endif
6922       /* F-G face */
6923       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 5;
6924       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 4;
6925       orntNew[0] = -2;
6926       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[4] - fStart)*4 + GetQuadEdge_Static(ornt[4], 2);
6927       orntNew[1] = -2;
6928       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*4 + GetQuadEdge_Static(ornt[1], 1);
6929       orntNew[2] = 0;
6930       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 1;
6931       orntNew[3] = 0;
6932       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6933       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
6934 #if defined(PETSC_USE_DEBUG)
6935       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
6936       for (p = 0; p < 4; ++p) {
6937         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", coneNew[p], eStartNew, eEndNew);
6938       }
6939 #endif
6940       /* G-H face */
6941       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 6;
6942       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*4 + GetQuadEdge_Static(ornt[3], 2);
6943       orntNew[0] = -2;
6944       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*4 + GetQuadEdge_Static(ornt[1], 2);
6945       orntNew[1] = 0;
6946       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 1;
6947       orntNew[2] = 0;
6948       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 3;
6949       orntNew[3] = -2;
6950       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6951       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
6952 #if defined(PETSC_USE_DEBUG)
6953       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
6954       for (p = 0; p < 4; ++p) {
6955         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", coneNew[p], eStartNew, eEndNew);
6956       }
6957 #endif
6958       /* E-H face */
6959       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 7;
6960       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 5;
6961       orntNew[0] = -2;
6962       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[5] - fStart)*4 + GetQuadEdge_Static(ornt[5], 1);
6963       orntNew[1] = -2;
6964       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*4 + GetQuadEdge_Static(ornt[1], 3);
6965       orntNew[2] = 0;
6966       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 1;
6967       orntNew[3] = 0;
6968       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6969       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
6970 #if defined(PETSC_USE_DEBUG)
6971       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
6972       for (p = 0; p < 4; ++p) {
6973         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", coneNew[p], eStartNew, eEndNew);
6974       }
6975 #endif
6976       /* A-E face */
6977       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 8;
6978       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*4 + GetQuadEdge_Static(ornt[2], 3);
6979       orntNew[0] = 0;
6980       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 2;
6981       orntNew[1] = 0;
6982       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 5;
6983       orntNew[2] = -2;
6984       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (cone[5] - fStart)*4 + GetQuadEdge_Static(ornt[5], 0);
6985       orntNew[3] = -2;
6986       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6987       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
6988 #if defined(PETSC_USE_DEBUG)
6989       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
6990       for (p = 0; p < 4; ++p) {
6991         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", coneNew[p], eStartNew, eEndNew);
6992       }
6993 #endif
6994       /* D-F face */
6995       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 9;
6996       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*4 + GetQuadEdge_Static(ornt[2], 1);
6997       orntNew[0] = -2;
6998       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[4] - fStart)*4 + GetQuadEdge_Static(ornt[4], 3);
6999       orntNew[1] = 0;
7000       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 4;
7001       orntNew[2] = 0;
7002       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 2;
7003       orntNew[3] = -2;
7004       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
7005       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
7006 #if defined(PETSC_USE_DEBUG)
7007       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
7008       for (p = 0; p < 4; ++p) {
7009         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", coneNew[p], eStartNew, eEndNew);
7010       }
7011 #endif
7012       /* C-G face */
7013       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 10;
7014       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 4;
7015       orntNew[0] = -2;
7016       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[4] - fStart)*4 + GetQuadEdge_Static(ornt[4], 1);
7017       orntNew[1] = -2;
7018       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*4 + GetQuadEdge_Static(ornt[3], 3);
7019       orntNew[2] = 0;
7020       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 3;
7021       orntNew[3] = 0;
7022       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
7023       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
7024 #if defined(PETSC_USE_DEBUG)
7025       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
7026       for (p = 0; p < 4; ++p) {
7027         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", coneNew[p], eStartNew, eEndNew);
7028       }
7029 #endif
7030       /* B-H face */
7031       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 11;
7032       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 5;
7033       orntNew[0] = 0;
7034       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 3;
7035       orntNew[1] = -2;
7036       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*4 + GetQuadEdge_Static(ornt[3], 1);
7037       orntNew[2] = -2;
7038       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (cone[5] - fStart)*4 + GetQuadEdge_Static(ornt[5], 2);
7039       orntNew[3] = 0;
7040       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
7041       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
7042 #if defined(PETSC_USE_DEBUG)
7043       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
7044       for (p = 0; p < 4; ++p) {
7045         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", coneNew[p], eStartNew, eEndNew);
7046       }
7047 #endif
7048       for (r = 0; r < 12; ++r) {
7049         newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + r;
7050         supportNew[0] = cStartNew + (c - cStart)*8 + newCells[r*2+0];
7051         supportNew[1] = cStartNew + (c - cStart)*8 + newCells[r*2+1];
7052         ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
7053 #if defined(PETSC_USE_DEBUG)
7054         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
7055         for (p = 0; p < 2; ++p) {
7056           if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", supportNew[p], cStartNew, cEndNew);
7057         }
7058 #endif
7059       }
7060     }
7061     /* Split edges have 2 vertices and the same faces as the parent */
7062     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
7063     for (e = eStart; e < eEnd; ++e) {
7064       const PetscInt newv = vStartNew + (vEnd - vStart) + (e - eStart);
7065 
7066       for (r = 0; r < 2; ++r) {
7067         const PetscInt  newp = eStartNew + (e - eStart)*2 + r;
7068         const PetscInt *cone, *ornt, *support;
7069         PetscInt        coneNew[2], coneSize, c, supportSize, s;
7070 
7071         ierr             = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
7072         coneNew[0]       = vStartNew + (cone[0] - vStart);
7073         coneNew[1]       = vStartNew + (cone[1] - vStart);
7074         coneNew[(r+1)%2] = newv;
7075         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
7076 #if defined(PETSC_USE_DEBUG)
7077         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eEndNew);
7078         for (p = 0; p < 2; ++p) {
7079           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", coneNew[p], vStartNew, vEndNew);
7080         }
7081 #endif
7082         ierr = DMPlexGetSupportSize(dm, e, &supportSize);CHKERRQ(ierr);
7083         ierr = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
7084         for (s = 0; s < supportSize; ++s) {
7085           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
7086           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
7087           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
7088           for (c = 0; c < coneSize; ++c) {
7089             if (cone[c] == e) break;
7090           }
7091           supportRef[s] = fStartNew + (support[s] - fStart)*4 + (ornt[c] < 0 ? (c+1-r)%4 : (c+r)%4);
7092         }
7093         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
7094 #if defined(PETSC_USE_DEBUG)
7095         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eEndNew);
7096         for (p = 0; p < supportSize; ++p) {
7097           if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", supportRef[p], fStartNew, fEndNew);
7098         }
7099 #endif
7100       }
7101     }
7102     /* Face edges have 2 vertices and 2+cells faces */
7103     for (f = fStart; f < fEnd; ++f) {
7104       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};
7105       const PetscInt  newv = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (f - fStart);
7106       const PetscInt *cone, *coneCell, *orntCell, *support;
7107       PetscInt        coneNew[2], coneSize, c, supportSize, s;
7108 
7109       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
7110       for (r = 0; r < 4; ++r) {
7111         const PetscInt newp = eStartNew + (eEnd - eStart)*2 + (f - fStart)*4 + r;
7112 
7113         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r] - eStart);
7114         coneNew[1] = newv;
7115         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
7116 #if defined(PETSC_USE_DEBUG)
7117         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eEndNew);
7118         for (p = 0; p < 2; ++p) {
7119           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", coneNew[p], vStartNew, vEndNew);
7120         }
7121 #endif
7122         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
7123         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
7124         supportRef[0] = fStartNew + (f - fStart)*4 + r;
7125         supportRef[1] = fStartNew + (f - fStart)*4 + (r+1)%4;
7126         for (s = 0; s < supportSize; ++s) {
7127           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
7128           ierr = DMPlexGetCone(dm, support[s], &coneCell);CHKERRQ(ierr);
7129           ierr = DMPlexGetConeOrientation(dm, support[s], &orntCell);CHKERRQ(ierr);
7130           for (c = 0; c < coneSize; ++c) if (coneCell[c] == f) break;
7131           supportRef[2+s] = fStartNew + (fEnd - fStart)*4 + (support[s] - cStart)*12 + newFaces[c*4 + GetQuadEdgeInverse_Static(orntCell[c], r)];
7132         }
7133         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
7134 #if defined(PETSC_USE_DEBUG)
7135         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eEndNew);
7136         for (p = 0; p < 2+supportSize; ++p) {
7137           if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", supportRef[p], fStartNew, fEndNew);
7138         }
7139 #endif
7140       }
7141     }
7142     /* Cell edges have 2 vertices and 4 faces */
7143     for (c = cStart; c < cEnd; ++c) {
7144       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};
7145       const PetscInt  newv = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (fEnd - fStart) + (c - cStart);
7146       const PetscInt *cone;
7147       PetscInt        coneNew[2], supportNew[4];
7148 
7149       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
7150       for (r = 0; r < 6; ++r) {
7151         const PetscInt newp = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*4 + (c - cStart)*6 + r;
7152 
7153         coneNew[0] = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (cone[r] - fStart);
7154         coneNew[1] = newv;
7155         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
7156 #if defined(PETSC_USE_DEBUG)
7157         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eEndNew);
7158         for (p = 0; p < 2; ++p) {
7159           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", coneNew[p], vStartNew, vEndNew);
7160         }
7161 #endif
7162         for (f = 0; f < 4; ++f) supportNew[f] = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + newFaces[r*4+f];
7163         ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
7164 #if defined(PETSC_USE_DEBUG)
7165         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eEndNew);
7166         for (p = 0; p < 4; ++p) {
7167           if ((supportNew[p] < fStartNew) || (supportNew[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", supportNew[p], fStartNew, fEndNew);
7168         }
7169 #endif
7170       }
7171     }
7172     /* Old vertices have identical supports */
7173     for (v = vStart; v < vEnd; ++v) {
7174       const PetscInt  newp = vStartNew + (v - vStart);
7175       const PetscInt *support, *cone;
7176       PetscInt        size, s;
7177 
7178       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
7179       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
7180       for (s = 0; s < size; ++s) {
7181         PetscInt r = 0;
7182 
7183         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
7184         if (cone[1] == v) r = 1;
7185         supportRef[s] = eStartNew + (support[s] - eStart)*2 + r;
7186       }
7187       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
7188 #if defined(PETSC_USE_DEBUG)
7189       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", newp, vStartNew, vEndNew);
7190       for (p = 0; p < size; ++p) {
7191         if ((supportRef[p] < eStartNew) || (supportRef[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", supportRef[p], eStartNew, eEndNew);
7192       }
7193 #endif
7194     }
7195     /* Edge vertices have 2 + faces supports */
7196     for (e = eStart; e < eEnd; ++e) {
7197       const PetscInt  newp = vStartNew + (vEnd - vStart) + (e - eStart);
7198       const PetscInt *cone, *support;
7199       PetscInt        size, s;
7200 
7201       ierr          = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
7202       ierr          = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
7203       supportRef[0] = eStartNew + (e - eStart)*2 + 0;
7204       supportRef[1] = eStartNew + (e - eStart)*2 + 1;
7205       for (s = 0; s < size; ++s) {
7206         PetscInt r;
7207 
7208         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
7209         for (r = 0; r < 4; ++r) if (cone[r] == e) break;
7210         supportRef[2+s] = eStartNew + (eEnd - eStart)*2 + (support[s] - fStart)*4 + r;
7211       }
7212       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
7213 #if defined(PETSC_USE_DEBUG)
7214       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", newp, vStartNew, vEndNew);
7215       for (p = 0; p < 2+size; ++p) {
7216         if ((supportRef[p] < eStartNew) || (supportRef[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", supportRef[p], eStartNew, eEndNew);
7217       }
7218 #endif
7219     }
7220     /* Face vertices have 4 + cells supports */
7221     for (f = fStart; f < fEnd; ++f) {
7222       const PetscInt  newp = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (f - fStart);
7223       const PetscInt *cone, *support;
7224       PetscInt        size, s;
7225 
7226       ierr          = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
7227       ierr          = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
7228       for (r = 0; r < 4; ++r) supportRef[r] = eStartNew + (eEnd - eStart)*2 +  (f - fStart)*4 + r;
7229       for (s = 0; s < size; ++s) {
7230         PetscInt r;
7231 
7232         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
7233         for (r = 0; r < 6; ++r) if (cone[r] == f) break;
7234         supportRef[4+s] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*4 + (support[s] - cStart)*6 + r;
7235       }
7236       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
7237 #if defined(PETSC_USE_DEBUG)
7238       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", newp, vStartNew, vEndNew);
7239       for (p = 0; p < 4+size; ++p) {
7240         if ((supportRef[p] < eStartNew) || (supportRef[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", supportRef[p], eStartNew, eEndNew);
7241       }
7242 #endif
7243     }
7244     /* Cell vertices have 6 supports */
7245     for (c = cStart; c < cEnd; ++c) {
7246       const PetscInt newp = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (fEnd - fStart) + (c - cStart);
7247       PetscInt       supportNew[6];
7248 
7249       for (r = 0; r < 6; ++r) {
7250         supportNew[r] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*4 + (c - cStart)*6 + r;
7251       }
7252       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
7253     }
7254     ierr = PetscFree(supportRef);CHKERRQ(ierr);
7255     break;
7256   case REFINER_HYBRID_HEX_3D:
7257     ierr = DMPlexGetHybridBounds(rdm, &cMaxNew, &fMaxNew, &eMaxNew, NULL);CHKERRQ(ierr);
7258     /*
7259      Bottom (viewed from top)    Top
7260      1---------2---------2       7---------2---------6
7261      |         |         |       |         |         |
7262      |    B    2    C    |       |    H    2    G    |
7263      |         |         |       |         |         |
7264      3----3----0----1----1       3----3----0----1----1
7265      |         |         |       |         |         |
7266      |    A    0    D    |       |    E    0    F    |
7267      |         |         |       |         |         |
7268      0---------0---------3       4---------0---------5
7269      */
7270     /* Interior cells have 6 faces: Bottom, Top, Front, Back, Right, Left */
7271     for (c = cStart; c < cMax; ++c) {
7272       const PetscInt  newp = (c - cStart)*8;
7273       const PetscInt *cone, *ornt;
7274       PetscInt        coneNew[6], orntNew[6];
7275 
7276       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
7277       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
7278       /* A hex */
7279       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], 0);
7280       orntNew[0] = ornt[0];
7281       coneNew[1] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  8; /* AE */
7282       orntNew[1] = 0;
7283       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetQuadSubface_Static(ornt[2], 0);
7284       orntNew[2] = ornt[2];
7285       coneNew[3] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  3; /* AB */
7286       orntNew[3] = 0;
7287       coneNew[4] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  0; /* AD */
7288       orntNew[4] = 0;
7289       coneNew[5] = fStartNew + (cone[5] - fStart)*4 + GetQuadSubface_Static(ornt[5], 0);
7290       orntNew[5] = ornt[5];
7291       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
7292       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
7293 #if defined(PETSC_USE_DEBUG)
7294       if ((newp+0 < cStartNew) || (newp+0 >= cMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", newp+0, cStartNew, cMaxNew);
7295       for (p = 0; p < 6; ++p) {
7296         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", coneNew[p], fStartNew, fMaxNew);
7297       }
7298 #endif
7299       /* B hex */
7300       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], 1);
7301       orntNew[0] = ornt[0];
7302       coneNew[1] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 + 11; /* BH */
7303       orntNew[1] = 0;
7304       coneNew[2] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  3; /* AB */
7305       orntNew[2] = -1;
7306       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetQuadSubface_Static(ornt[3], 1);
7307       orntNew[3] = ornt[3];
7308       coneNew[4] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  2; /* BC */
7309       orntNew[4] = 0;
7310       coneNew[5] = fStartNew + (cone[5] - fStart)*4 + GetQuadSubface_Static(ornt[5], 3);
7311       orntNew[5] = ornt[5];
7312       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
7313       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
7314 #if defined(PETSC_USE_DEBUG)
7315       if ((newp+1 < cStartNew) || (newp+1 >= cMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", newp+1, cStartNew, cMaxNew);
7316       for (p = 0; p < 6; ++p) {
7317         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", coneNew[p], fStartNew, fMaxNew);
7318       }
7319 #endif
7320       /* C hex */
7321       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], 2);
7322       orntNew[0] = ornt[0];
7323       coneNew[1] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 + 10; /* CG */
7324       orntNew[1] = 0;
7325       coneNew[2] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  1; /* CD */
7326       orntNew[2] = -1;
7327       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetQuadSubface_Static(ornt[3], 0);
7328       orntNew[3] = ornt[3];
7329       coneNew[4] = fStartNew + (cone[4] - fStart)*4 + GetQuadSubface_Static(ornt[4], 1);
7330       orntNew[4] = ornt[4];
7331       coneNew[5] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  2; /* BC */
7332       orntNew[5] = -4;
7333       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
7334       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
7335 #if defined(PETSC_USE_DEBUG)
7336       if ((newp+2 < cStartNew) || (newp+2 >= cMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", newp+2, cStartNew, cMaxNew);
7337       for (p = 0; p < 6; ++p) {
7338         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", coneNew[p], fStartNew, fMaxNew);
7339       }
7340 #endif
7341       /* D hex */
7342       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], 3);
7343       orntNew[0] = ornt[0];
7344       coneNew[1] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  9; /* DF */
7345       orntNew[1] = 0;
7346       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetQuadSubface_Static(ornt[2], 1);
7347       orntNew[2] = ornt[2];
7348       coneNew[3] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  1; /* CD */
7349       orntNew[3] = 0;
7350       coneNew[4] = fStartNew + (cone[4] - fStart)*4 + GetQuadSubface_Static(ornt[4], 0);
7351       orntNew[4] = ornt[4];
7352       coneNew[5] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  0; /* AD */
7353       orntNew[5] = -4;
7354       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
7355       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
7356 #if defined(PETSC_USE_DEBUG)
7357       if ((newp+3 < cStartNew) || (newp+3 >= cMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", newp+3, cStartNew, cMaxNew);
7358       for (p = 0; p < 6; ++p) {
7359         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", coneNew[p], fStartNew, fMaxNew);
7360       }
7361 #endif
7362       /* E hex */
7363       coneNew[0] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  8; /* AE */
7364       orntNew[0] = -4;
7365       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], 0);
7366       orntNew[1] = ornt[1];
7367       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetQuadSubface_Static(ornt[2], 3);
7368       orntNew[2] = ornt[2];
7369       coneNew[3] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  7; /* EH */
7370       orntNew[3] = 0;
7371       coneNew[4] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  4; /* EF */
7372       orntNew[4] = -1;
7373       coneNew[5] = fStartNew + (cone[5] - fStart)*4 + GetQuadSubface_Static(ornt[5], 1);
7374       orntNew[5] = ornt[5];
7375       ierr       = DMPlexSetCone(rdm, newp+4, coneNew);CHKERRQ(ierr);
7376       ierr       = DMPlexSetConeOrientation(rdm, newp+4, orntNew);CHKERRQ(ierr);
7377 #if defined(PETSC_USE_DEBUG)
7378       if ((newp+4 < cStartNew) || (newp+4 >= cMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", newp+4, cStartNew, cMaxNew);
7379       for (p = 0; p < 6; ++p) {
7380         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", coneNew[p], fStartNew, fMaxNew);
7381       }
7382 #endif
7383       /* F hex */
7384       coneNew[0] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  9; /* DF */
7385       orntNew[0] = -4;
7386       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], 1);
7387       orntNew[1] = ornt[1];
7388       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetQuadSubface_Static(ornt[2], 2);
7389       orntNew[2] = ornt[2];
7390       coneNew[3] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  5; /* FG */
7391       orntNew[3] = -1;
7392       coneNew[4] = fStartNew + (cone[4] - fStart)*4 + GetQuadSubface_Static(ornt[4], 3);
7393       orntNew[4] = ornt[4];
7394       coneNew[5] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  4; /* EF */
7395       orntNew[5] = 1;
7396       ierr       = DMPlexSetCone(rdm, newp+5, coneNew);CHKERRQ(ierr);
7397       ierr       = DMPlexSetConeOrientation(rdm, newp+5, orntNew);CHKERRQ(ierr);
7398 #if defined(PETSC_USE_DEBUG)
7399       if ((newp+5 < cStartNew) || (newp+5 >= cMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", newp+5, cStartNew, cMaxNew);
7400       for (p = 0; p < 6; ++p) {
7401         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", coneNew[p], fStartNew, fMaxNew);
7402       }
7403 #endif
7404       /* G hex */
7405       coneNew[0] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 + 10; /* CG */
7406       orntNew[0] = -4;
7407       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], 2);
7408       orntNew[1] = ornt[1];
7409       coneNew[2] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  5; /* FG */
7410       orntNew[2] = 0;
7411       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetQuadSubface_Static(ornt[3], 3);
7412       orntNew[3] = ornt[3];
7413       coneNew[4] = fStartNew + (cone[4] - fStart)*4 + GetQuadSubface_Static(ornt[4], 2);
7414       orntNew[4] = ornt[4];
7415       coneNew[5] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  6; /* GH */
7416       orntNew[5] = -3;
7417       ierr       = DMPlexSetCone(rdm, newp+6, coneNew);CHKERRQ(ierr);
7418       ierr       = DMPlexSetConeOrientation(rdm, newp+6, orntNew);CHKERRQ(ierr);
7419 #if defined(PETSC_USE_DEBUG)
7420       if ((newp+6 < cStartNew) || (newp+6 >= cMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", newp+6, cStartNew, cMaxNew);
7421       for (p = 0; p < 6; ++p) {
7422         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", coneNew[p], fStartNew, fMaxNew);
7423       }
7424 #endif
7425       /* H hex */
7426       coneNew[0] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 + 11; /* BH */
7427       orntNew[0] = -4;
7428       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], 3);
7429       orntNew[1] = ornt[1];
7430       coneNew[2] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  7; /* EH */
7431       orntNew[2] = -1;
7432       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetQuadSubface_Static(ornt[3], 2);
7433       orntNew[3] = ornt[3];
7434       coneNew[4] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  6; /* GH */
7435       orntNew[4] = 3;
7436       coneNew[5] = fStartNew + (cone[5] - fStart)*4 + GetQuadSubface_Static(ornt[5], 2);
7437       orntNew[5] = ornt[5];
7438       ierr       = DMPlexSetCone(rdm, newp+7, coneNew);CHKERRQ(ierr);
7439       ierr       = DMPlexSetConeOrientation(rdm, newp+7, orntNew);CHKERRQ(ierr);
7440 #if defined(PETSC_USE_DEBUG)
7441       if ((newp+7 < cStartNew) || (newp+7 >= cMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", newp+7, cStartNew, cMaxNew);
7442       for (p = 0; p < 6; ++p) {
7443         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", coneNew[p], fStartNew, fMaxNew);
7444       }
7445 #endif
7446     }
7447     /* Hybrid cells have 6 faces: Front, Back, Sides */
7448     /*
7449      3---------2---------2
7450      |         |         |
7451      |    D    2    C    |
7452      |         |         |
7453      3----3----0----1----1
7454      |         |         |
7455      |    A    0    B    |
7456      |         |         |
7457      0---------0---------1
7458      */
7459     for (c = cMax; c < cEnd; ++c) {
7460       const PetscInt  newp = (cMax - cStart)*8 + (c - cMax)*4;
7461       const PetscInt *cone, *ornt, *fornt;
7462       PetscInt        coneNew[6], orntNew[6], o, of, i;
7463 
7464       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
7465       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
7466       ierr = DMPlexGetConeOrientation(dm, cone[0], &fornt);CHKERRQ(ierr);
7467       o = ornt[0] < 0 ? -1 : 1;
7468       for (r = 0; r < 4; ++r) {
7469         PetscInt subfA = GetQuadSubface_Static(ornt[0], r);
7470         PetscInt edgeA = GetQuadEdge_Static(ornt[0], r);
7471         PetscInt edgeB = GetQuadEdge_Static(ornt[0], (r+3)%4);
7472         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]);
7473         coneNew[0]         = fStartNew + (cone[0] - fStart)*4 + subfA;
7474         orntNew[0]         = ornt[0];
7475         coneNew[1]         = fStartNew + (cone[1] - fStart)*4 + subfA;
7476         orntNew[1]         = ornt[0];
7477         of = fornt[edgeA] < 0 ? -1 : 1;
7478         i  = GetQuadEdgeInverse_Static(ornt[0], r) + 2;
7479         coneNew[i] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (cone[2+edgeA] - fMax)*2 + (o*of < 0 ? 1 : 0);
7480         orntNew[i] = ornt[edgeA];
7481         i  = GetQuadEdgeInverse_Static(ornt[0], (r+1)%4) + 2;
7482         coneNew[i] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd          - fMax)*2 + (c - cMax)*4 + edgeA;
7483         orntNew[i] = 0;
7484         i  = GetQuadEdgeInverse_Static(ornt[0], (r+2)%4) + 2;
7485         coneNew[i] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd          - fMax)*2 + (c - cMax)*4 + edgeB;
7486         orntNew[i] = -2;
7487         of = fornt[edgeB] < 0 ? -1 : 1;
7488         i  = GetQuadEdgeInverse_Static(ornt[0], (r+3)%4) + 2;
7489         coneNew[i] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (cone[2+edgeB] - fMax)*2 + (o*of < 0 ? 0 : 1);
7490         orntNew[i] = ornt[edgeB];
7491         ierr       = DMPlexSetCone(rdm, newp+r, coneNew);CHKERRQ(ierr);
7492         ierr       = DMPlexSetConeOrientation(rdm, newp+r, orntNew);CHKERRQ(ierr);
7493 #if defined(PETSC_USE_DEBUG)
7494         if ((newp+r < cMaxNew) || (newp+r >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a hybrid cell [%D, %D)", newp+r, cMaxNew, cEndNew);
7495         for (p = 0; p < 2; ++p) {
7496           if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", coneNew[p], fStartNew, fMaxNew);
7497         }
7498         for (p = 2; p < 6; ++p) {
7499           if ((coneNew[p] < fMaxNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a hybrid face [%D, %D)", coneNew[p], fMaxNew, fEndNew);
7500         }
7501 #endif
7502       }
7503     }
7504     /* Interior split faces have 4 edges and the same cells as the parent */
7505     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
7506     ierr = PetscMalloc1(4 + maxSupportSize*2, &supportRef);CHKERRQ(ierr);
7507     for (f = fStart; f < fMax; ++f) {
7508       for (r = 0; r < 4; ++r) {
7509         /* TODO: This can come from GetFaces_Internal() */
7510         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};
7511         const PetscInt  newp = fStartNew + (f - fStart)*4 + r;
7512         const PetscInt *cone, *ornt, *support;
7513         PetscInt        coneNew[4], orntNew[4], coneSize, c, supportSize, s;
7514 
7515         ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
7516         ierr = DMPlexGetConeOrientation(dm, f, &ornt);CHKERRQ(ierr);
7517         coneNew[(r+3)%4] = eStartNew + (cone[(r+3)%4] - eStart)*2 + (ornt[(r+3)%4] < 0 ? 0 : 1);
7518         orntNew[(r+3)%4] = ornt[(r+3)%4];
7519         coneNew[(r+0)%4] = eStartNew + (cone[r]       - eStart)*2 + (ornt[r] < 0 ? 1 : 0);
7520         orntNew[(r+0)%4] = ornt[r];
7521         coneNew[(r+1)%4] = eStartNew + (eMax - eStart)*2 + (f - fStart)*4 + r;
7522         orntNew[(r+1)%4] = 0;
7523         coneNew[(r+2)%4] = eStartNew + (eMax - eStart)*2 + (f - fStart)*4 + (r+3)%4;
7524         orntNew[(r+2)%4] = -2;
7525         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
7526         ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
7527 #if defined(PETSC_USE_DEBUG)
7528         if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fMaxNew);
7529         for (p = 0; p < 4; ++p) {
7530           if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", coneNew[p], eStartNew, eMaxNew);
7531         }
7532 #endif
7533         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
7534         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
7535         for (s = 0; s < supportSize; ++s) {
7536           PetscInt subf;
7537           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
7538           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
7539           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
7540           for (c = 0; c < coneSize; ++c) {
7541             if (cone[c] == f) break;
7542           }
7543           subf = GetQuadSubfaceInverse_Static(ornt[c], r);
7544           if (support[s] < cMax) {
7545             supportRef[s] = cStartNew + (support[s] - cStart)*8 + newCells[c*4+subf];
7546           } else {
7547             supportRef[s] = cStartNew + (cMax       - cStart)*8 + (support[s] - cMax)*4 + subf;
7548           }
7549         }
7550         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
7551 #if defined(PETSC_USE_DEBUG)
7552         if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fMaxNew);
7553         for (p = 0; p < supportSize; ++p) {
7554           if ((supportRef[p] < cStartNew) || (supportRef[p] >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", supportRef[p], cStartNew, cEndNew);
7555         }
7556 #endif
7557       }
7558     }
7559     /* Interior cell faces have 4 edges and 2 cells */
7560     for (c = cStart; c < cMax; ++c) {
7561       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};
7562       const PetscInt *cone, *ornt;
7563       PetscInt        newp, coneNew[4], orntNew[4], supportNew[2];
7564 
7565       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
7566       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
7567       /* A-D face */
7568       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 0;
7569       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*4 + GetQuadEdge_Static(ornt[0], 3);
7570       orntNew[0] = 0;
7571       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 0;
7572       orntNew[1] = 0;
7573       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 2;
7574       orntNew[2] = -2;
7575       coneNew[3] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*4 + GetQuadEdge_Static(ornt[2], 0);
7576       orntNew[3] = -2;
7577       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
7578       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
7579 #if defined(PETSC_USE_DEBUG)
7580       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fMaxNew);
7581       for (p = 0; p < 4; ++p) {
7582         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", coneNew[p], eStartNew, eMaxNew);
7583       }
7584 #endif
7585       /* C-D face */
7586       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 1;
7587       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*4 + GetQuadEdge_Static(ornt[0], 2);
7588       orntNew[0] = 0;
7589       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 0;
7590       orntNew[1] = 0;
7591       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 4;
7592       orntNew[2] = -2;
7593       coneNew[3] = eStartNew + (eMax - eStart)*2 + (cone[4] - fStart)*4 + GetQuadEdge_Static(ornt[4], 0);
7594       orntNew[3] = -2;
7595       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
7596       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
7597 #if defined(PETSC_USE_DEBUG)
7598       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fMaxNew);
7599       for (p = 0; p < 4; ++p) {
7600         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", coneNew[p], eStartNew, eMaxNew);
7601       }
7602 #endif
7603       /* B-C face */
7604       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 2;
7605       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*4 + GetQuadEdge_Static(ornt[0], 1);
7606       orntNew[0] = -2;
7607       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*4 + GetQuadEdge_Static(ornt[3], 0);
7608       orntNew[1] = 0;
7609       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 3;
7610       orntNew[2] = 0;
7611       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 0;
7612       orntNew[3] = -2;
7613       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
7614       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
7615 #if defined(PETSC_USE_DEBUG)
7616       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fMaxNew);
7617       for (p = 0; p < 4; ++p) {
7618         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", coneNew[p], eStartNew, eMaxNew);
7619       }
7620 #endif
7621       /* A-B face */
7622       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 3;
7623       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*4 + GetQuadEdge_Static(ornt[0], 0);
7624       orntNew[0] = -2;
7625       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[5] - fStart)*4 + GetQuadEdge_Static(ornt[5], 3);
7626       orntNew[1] = 0;
7627       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 5;
7628       orntNew[2] = 0;
7629       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 0;
7630       orntNew[3] = -2;
7631       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
7632       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
7633 #if defined(PETSC_USE_DEBUG)
7634       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fMaxNew);
7635       for (p = 0; p < 4; ++p) {
7636         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", coneNew[p], eStartNew, eMaxNew);
7637       }
7638 #endif
7639       /* E-F face */
7640       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 4;
7641       coneNew[0] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 2;
7642       orntNew[0] = -2;
7643       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*4 + GetQuadEdge_Static(ornt[2], 2);
7644       orntNew[1] = -2;
7645       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*4 + GetQuadEdge_Static(ornt[1], 0);
7646       orntNew[2] = 0;
7647       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 1;
7648       orntNew[3] = 0;
7649       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
7650       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
7651 #if defined(PETSC_USE_DEBUG)
7652       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fMaxNew);
7653       for (p = 0; p < 4; ++p) {
7654         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", coneNew[p], eStartNew, eMaxNew);
7655       }
7656 #endif
7657       /* F-G face */
7658       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 5;
7659       coneNew[0] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 4;
7660       orntNew[0] = -2;
7661       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[4] - fStart)*4 + GetQuadEdge_Static(ornt[4], 2);
7662       orntNew[1] = -2;
7663       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*4 + GetQuadEdge_Static(ornt[1], 1);
7664       orntNew[2] = 0;
7665       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 1;
7666       orntNew[3] = 0;
7667       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
7668       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
7669 #if defined(PETSC_USE_DEBUG)
7670       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fMaxNew);
7671       for (p = 0; p < 4; ++p) {
7672         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", coneNew[p], eStartNew, eMaxNew);
7673       }
7674 #endif
7675       /* G-H face */
7676       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 6;
7677       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*4 + GetQuadEdge_Static(ornt[3], 2);
7678       orntNew[0] = -2;
7679       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*4 + GetQuadEdge_Static(ornt[1], 2);
7680       orntNew[1] = 0;
7681       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 1;
7682       orntNew[2] = 0;
7683       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 3;
7684       orntNew[3] = -2;
7685       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
7686       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
7687 #if defined(PETSC_USE_DEBUG)
7688       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fMaxNew);
7689       for (p = 0; p < 4; ++p) {
7690         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", coneNew[p], eStartNew, eMaxNew);
7691       }
7692 #endif
7693       /* E-H face */
7694       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 7;
7695       coneNew[0] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 5;
7696       orntNew[0] = -2;
7697       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[5] - fStart)*4 + GetQuadEdge_Static(ornt[5], 1);
7698       orntNew[1] = -2;
7699       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*4 + GetQuadEdge_Static(ornt[1], 3);
7700       orntNew[2] = 0;
7701       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 1;
7702       orntNew[3] = 0;
7703       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
7704       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
7705 #if defined(PETSC_USE_DEBUG)
7706       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fMaxNew);
7707       for (p = 0; p < 4; ++p) {
7708         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", coneNew[p], eStartNew, eMaxNew);
7709       }
7710 #endif
7711       /* A-E face */
7712       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 8;
7713       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*4 + GetQuadEdge_Static(ornt[2], 3);
7714       orntNew[0] = 0;
7715       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 2;
7716       orntNew[1] = 0;
7717       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 5;
7718       orntNew[2] = -2;
7719       coneNew[3] = eStartNew + (eMax - eStart)*2 + (cone[5] - fStart)*4 + GetQuadEdge_Static(ornt[5], 0);
7720       orntNew[3] = -2;
7721       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
7722       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
7723 #if defined(PETSC_USE_DEBUG)
7724       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fMaxNew);
7725       for (p = 0; p < 4; ++p) {
7726         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", coneNew[p], eStartNew, eMaxNew);
7727       }
7728 #endif
7729       /* D-F face */
7730       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 9;
7731       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*4 + GetQuadEdge_Static(ornt[2], 1);
7732       orntNew[0] = -2;
7733       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[4] - fStart)*4 + GetQuadEdge_Static(ornt[4], 3);
7734       orntNew[1] = 0;
7735       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 4;
7736       orntNew[2] = 0;
7737       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 2;
7738       orntNew[3] = -2;
7739       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
7740       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
7741 #if defined(PETSC_USE_DEBUG)
7742       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fMaxNew);
7743       for (p = 0; p < 4; ++p) {
7744         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", coneNew[p], eStartNew, eMaxNew);
7745       }
7746 #endif
7747       /* C-G face */
7748       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 10;
7749       coneNew[0] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 4;
7750       orntNew[0] = -2;
7751       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[4] - fStart)*4 + GetQuadEdge_Static(ornt[4], 1);
7752       orntNew[1] = -2;
7753       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*4 + GetQuadEdge_Static(ornt[3], 3);
7754       orntNew[2] = 0;
7755       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 3;
7756       orntNew[3] = 0;
7757       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
7758       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
7759 #if defined(PETSC_USE_DEBUG)
7760       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fMaxNew);
7761       for (p = 0; p < 4; ++p) {
7762         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", coneNew[p], eStartNew, eMaxNew);
7763       }
7764 #endif
7765       /* B-H face */
7766       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 11;
7767       coneNew[0] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 5;
7768       orntNew[0] = 0;
7769       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 3;
7770       orntNew[1] = -2;
7771       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*4 + GetQuadEdge_Static(ornt[3], 1);
7772       orntNew[2] = -2;
7773       coneNew[3] = eStartNew + (eMax - eStart)*2 + (cone[5] - fStart)*4 + GetQuadEdge_Static(ornt[5], 2);
7774       orntNew[3] = 0;
7775       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
7776       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
7777 #if defined(PETSC_USE_DEBUG)
7778       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fMaxNew);
7779       for (p = 0; p < 4; ++p) {
7780         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", coneNew[p], eStartNew, eMaxNew);
7781       }
7782 #endif
7783       for (r = 0; r < 12; ++r) {
7784         newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + r;
7785         supportNew[0] = cStartNew + (c - cStart)*8 + newCells[r*2+0];
7786         supportNew[1] = cStartNew + (c - cStart)*8 + newCells[r*2+1];
7787         ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
7788 #if defined(PETSC_USE_DEBUG)
7789         if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fMaxNew);
7790         for (p = 0; p < 2; ++p) {
7791           if ((supportNew[p] < cStartNew) || (supportNew[p] >= cMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", supportNew[p], cStartNew, cMaxNew);
7792         }
7793 #endif
7794       }
7795     }
7796     /* Hybrid split faces have 4 edges and same cells */
7797     for (f = fMax; f < fEnd; ++f) {
7798       const PetscInt *cone, *ornt, *support;
7799       PetscInt        coneNew[4], orntNew[4];
7800       PetscInt        supportNew[2], size, s, c;
7801 
7802       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
7803       ierr = DMPlexGetConeOrientation(dm, f, &ornt);CHKERRQ(ierr);
7804       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
7805       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
7806       for (r = 0; r < 2; ++r) {
7807         const PetscInt newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (f - fMax)*2 + r;
7808 
7809         coneNew[0]   = eStartNew + (cone[0] - eStart)*2 + (ornt[0] < 0 ? 1-r : r);
7810         orntNew[0]   = ornt[0];
7811         coneNew[1]   = eStartNew + (cone[1] - eStart)*2 + (ornt[1] < 0 ? 1-r : r);
7812         orntNew[1]   = ornt[1];
7813         coneNew[2+r] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (cone[2+r] - eMax);
7814         orntNew[2+r] = 0;
7815         coneNew[3-r] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (eEnd      - eMax) + (f - fMax);
7816         orntNew[3-r] = 0;
7817         ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
7818         ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
7819 #if defined(PETSC_USE_DEBUG)
7820         if ((newp < fMaxNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a hybrid face [%D, %D)", newp, fMaxNew, fEndNew);
7821         for (p = 0; p < 2; ++p) {
7822           if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", coneNew[p], eStartNew, eMaxNew);
7823         }
7824         for (p = 2; p < 4; ++p) {
7825           if ((coneNew[p] < eMaxNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a hybrid edge [%D, %D)", coneNew[p], eMaxNew, eEndNew);
7826         }
7827 #endif
7828         for (s = 0; s < size; ++s) {
7829           const PetscInt *coneCell, *orntCell, *fornt;
7830           PetscInt        o, of;
7831 
7832           ierr = DMPlexGetCone(dm, support[s], &coneCell);CHKERRQ(ierr);
7833           ierr = DMPlexGetConeOrientation(dm, support[s], &orntCell);CHKERRQ(ierr);
7834           o = orntCell[0] < 0 ? -1 : 1;
7835           for (c = 2; c < 6; ++c) if (coneCell[c] == f) break;
7836           if (c >= 6) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Could not find face %D in cone of cell %D", f, support[s]);
7837           ierr = DMPlexGetConeOrientation(dm, coneCell[0], &fornt);CHKERRQ(ierr);
7838           of = fornt[c-2] < 0 ? -1 : 1;
7839           supportNew[s] = cStartNew + (cMax - cStart)*8 + (support[s] - cMax)*4 + (GetQuadEdgeInverse_Static(orntCell[0], c-2) + (o*of < 0 ? 1-r : r))%4;
7840         }
7841         ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
7842 #if defined(PETSC_USE_DEBUG)
7843         if ((newp < fMaxNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a hybrid face [%D, %D)", newp, fMaxNew, fEndNew);
7844         for (p = 0; p < size; ++p) {
7845           if ((supportNew[p] < cMaxNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a hybrid cell [%D, %D)", supportNew[p], cMaxNew, cEndNew);
7846         }
7847 #endif
7848       }
7849     }
7850     /* Hybrid cell faces have 4 edges and 2 cells */
7851     for (c = cMax; c < cEnd; ++c) {
7852       PetscInt        newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd - fMax)*2 + (c - cMax)*4;
7853       const PetscInt *cone, *ornt;
7854       PetscInt        coneNew[4], orntNew[4];
7855       PetscInt        supportNew[2];
7856 
7857       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
7858       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
7859       for (r = 0; r < 4; ++r) {
7860 #if 0
7861         coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], r);
7862         orntNew[0] = 0;
7863         coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], r);
7864         orntNew[1] = 0;
7865         coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (eEnd - eMax) + (cone[2+GetQuadEdge_Static(ornt[0], r)] - fMax);
7866         orntNew[2] = 0;
7867         coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (eEnd - eMax) + (fEnd                                   - fMax) + (c - cMax);
7868         orntNew[3] = 0;
7869 #else
7870         coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*4 + r;
7871         orntNew[0] = 0;
7872         coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*4 + r;
7873         orntNew[1] = 0;
7874         coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (eEnd - eMax) + (cone[2+r] - fMax);
7875         orntNew[2] = 0;
7876         coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (eEnd - eMax) + (fEnd      - fMax) + (c - cMax);
7877         orntNew[3] = 0;
7878 #endif
7879         ierr = DMPlexSetCone(rdm, newp+r, coneNew);CHKERRQ(ierr);
7880         ierr = DMPlexSetConeOrientation(rdm, newp+r, orntNew);CHKERRQ(ierr);
7881 #if defined(PETSC_USE_DEBUG)
7882         if ((newp+r < fMaxNew) || (newp+r >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a hybrid face [%D, %D)", newp+r, fMaxNew, fEndNew);
7883         for (p = 0; p < 2; ++p) {
7884           if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", coneNew[p], eStartNew, eMaxNew);
7885         }
7886         for (p = 2; p < 4; ++p) {
7887           if ((coneNew[p] < eMaxNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a hybrid edge [%D, %D)", coneNew[p], eMaxNew, eEndNew);
7888         }
7889 #endif
7890         supportNew[0] = cStartNew + (cMax - cStart)*8 + (c - cMax)*4 + GetQuadSubface_Static(ornt[0], r);
7891         supportNew[1] = cStartNew + (cMax - cStart)*8 + (c - cMax)*4 + GetQuadSubface_Static(ornt[0], (r+1)%4);
7892         ierr          = DMPlexSetSupport(rdm, newp+r, supportNew);CHKERRQ(ierr);
7893 #if defined(PETSC_USE_DEBUG)
7894         if ((newp+r < fMaxNew) || (newp+r >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a hybrid face [%D, %D)", newp+r, fMaxNew, fEndNew);
7895         for (p = 0; p < 2; ++p) {
7896           if ((supportNew[p] < cMaxNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a hybrid cell [%D, %D)", supportNew[p], cMaxNew, cEndNew);
7897         }
7898 #endif
7899       }
7900     }
7901     /* Interior split edges have 2 vertices and the same faces as the parent */
7902     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
7903     for (e = eStart; e < eMax; ++e) {
7904       const PetscInt newv = vStartNew + (vEnd - vStart) + (e - eStart);
7905 
7906       for (r = 0; r < 2; ++r) {
7907         const PetscInt  newp = eStartNew + (e - eStart)*2 + r;
7908         const PetscInt *cone, *ornt, *support;
7909         PetscInt        coneNew[2], coneSize, c, supportSize, s;
7910 
7911         ierr             = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
7912         coneNew[0]       = vStartNew + (cone[0] - vStart);
7913         coneNew[1]       = vStartNew + (cone[1] - vStart);
7914         coneNew[(r+1)%2] = newv;
7915         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
7916 #if defined(PETSC_USE_DEBUG)
7917         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eMaxNew);
7918         for (p = 0; p < 2; ++p) {
7919           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", coneNew[p], vStartNew, vEndNew);
7920         }
7921 #endif
7922         ierr = DMPlexGetSupportSize(dm, e, &supportSize);CHKERRQ(ierr);
7923         ierr = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
7924         for (s = 0; s < supportSize; ++s) {
7925           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
7926           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
7927           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
7928           for (c = 0; c < coneSize; ++c) {
7929             if (cone[c] == e) break;
7930           }
7931           if (support[s] < fMax) {
7932             supportRef[s] = fStartNew + (support[s] - fStart)*4 + (c + (ornt[c] < 0 ? 1-r : r))%4;
7933           } else {
7934             supportRef[s] = fStartNew + (fMax       - fStart)*4 + (cMax - cStart)*12 + (support[s] - fMax)*2 + (ornt[c] < 0 ? 1-r : r);
7935           }
7936         }
7937         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
7938 #if defined(PETSC_USE_DEBUG)
7939         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eMaxNew);
7940         for (p = 0; p < supportSize; ++p) {
7941           if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", supportRef[p], fStartNew, fEndNew);
7942         }
7943 #endif
7944       }
7945     }
7946     /* Interior face edges have 2 vertices and 2+cells faces */
7947     for (f = fStart; f < fMax; ++f) {
7948       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};
7949       const PetscInt  newv = vStartNew + (vEnd - vStart) + (eMax - eStart) + (f - fStart);
7950       const PetscInt *cone, *coneCell, *orntCell, *support;
7951       PetscInt        coneNew[2], coneSize, c, supportSize, s;
7952 
7953       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
7954       for (r = 0; r < 4; ++r) {
7955         const PetscInt newp = eStartNew + (eMax - eStart)*2 + (f - fStart)*4 + r;
7956 
7957         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r] - eStart);
7958         coneNew[1] = newv;
7959         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
7960 #if defined(PETSC_USE_DEBUG)
7961         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eMaxNew);
7962         for (p = 0; p < 2; ++p) {
7963           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", coneNew[p], vStartNew, vEndNew);
7964         }
7965 #endif
7966         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
7967         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
7968         supportRef[0] = fStartNew + (f - fStart)*4 + r;
7969         supportRef[1] = fStartNew + (f - fStart)*4 + (r+1)%4;
7970         for (s = 0; s < supportSize; ++s) {
7971           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
7972           ierr = DMPlexGetCone(dm, support[s], &coneCell);CHKERRQ(ierr);
7973           ierr = DMPlexGetConeOrientation(dm, support[s], &orntCell);CHKERRQ(ierr);
7974           for (c = 0; c < coneSize; ++c) if (coneCell[c] == f) break;
7975           if (support[s] < cMax) {
7976             supportRef[2+s] = fStartNew + (fMax - fStart)*4 + (support[s] - cStart)*12 + newFaces[c*4 + GetQuadEdgeInverse_Static(orntCell[c], r)];
7977           } else {
7978             supportRef[2+s] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd - fMax)*2 + (support[s] - cMax)*4 + r;
7979           }
7980         }
7981         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
7982 #if defined(PETSC_USE_DEBUG)
7983         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eMaxNew);
7984         for (p = 0; p < 2+supportSize; ++p) {
7985           if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", supportRef[p], fStartNew, fEndNew);
7986         }
7987 #endif
7988       }
7989     }
7990     /* Interior cell edges have 2 vertices and 4 faces */
7991     for (c = cStart; c < cMax; ++c) {
7992       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};
7993       const PetscInt  newv = vStartNew + (vEnd - vStart) + (eMax - eStart) + (fMax - fStart) + (c - cStart);
7994       const PetscInt *cone;
7995       PetscInt        coneNew[2], supportNew[4];
7996 
7997       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
7998       for (r = 0; r < 6; ++r) {
7999         const PetscInt newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (c - cStart)*6 + r;
8000 
8001         coneNew[0] = vStartNew + (vEnd - vStart) + (eMax - eStart) + (cone[r] - fStart);
8002         coneNew[1] = newv;
8003         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
8004 #if defined(PETSC_USE_DEBUG)
8005         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eMaxNew);
8006         for (p = 0; p < 2; ++p) {
8007           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", coneNew[p], vStartNew, vEndNew);
8008         }
8009 #endif
8010         for (f = 0; f < 4; ++f) supportNew[f] = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + newFaces[r*4+f];
8011         ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
8012 #if defined(PETSC_USE_DEBUG)
8013         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eMaxNew);
8014         for (p = 0; p < 4; ++p) {
8015           if ((supportNew[p] < fStartNew) || (supportNew[p] >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", supportNew[p], fStartNew, fMaxNew);
8016         }
8017 #endif
8018       }
8019     }
8020     /* Hybrid edges have two vertices and the same faces */
8021     for (e = eMax; e < eEnd; ++e) {
8022       const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (e - eMax);
8023       const PetscInt *cone, *support, *fcone;
8024       PetscInt        coneNew[2], size, fsize, s;
8025 
8026       ierr = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
8027       ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
8028       ierr = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
8029       coneNew[0] = vStartNew + (cone[0] - vStart);
8030       coneNew[1] = vStartNew + (cone[1] - vStart);
8031       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
8032 #if defined(PETSC_USE_DEBUG)
8033       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a hybrid edge [%D, %D)", newp, eMaxNew, eEndNew);
8034       for (p = 0; p < 2; ++p) {
8035         if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", coneNew[p], vStartNew, vEndNew);
8036       }
8037 #endif
8038       for (s = 0; s < size; ++s) {
8039         ierr = DMPlexGetConeSize(dm, support[s], &fsize);CHKERRQ(ierr);
8040         ierr = DMPlexGetCone(dm, support[s], &fcone);CHKERRQ(ierr);
8041         for (c = 0; c < fsize; ++c) if (fcone[c] == e) break;
8042         if ((c < 2) || (c > 3)) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Edge %D not found in cone of face %D", e, support[s]);
8043         supportRef[s] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (support[s] - fMax)*2 + c-2;
8044       }
8045       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
8046 #if defined(PETSC_USE_DEBUG)
8047       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a hybrid edge [%D, %D)", newp, eMaxNew, eEndNew);
8048       for (p = 0; p < size; ++p) {
8049         if ((supportRef[p] < fMaxNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a hybrid face [%D, %D)", supportRef[p], fMaxNew, fEndNew);
8050       }
8051 #endif
8052     }
8053     /* Hybrid face edges have 2 vertices and 2+cells faces */
8054     for (f = fMax; f < fEnd; ++f) {
8055       const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (eEnd - eMax) + (f - fMax);
8056       const PetscInt *cone, *support, *ccone, *cornt;
8057       PetscInt        coneNew[2], size, csize, s;
8058 
8059       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
8060       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
8061       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
8062       coneNew[0] = vStartNew + (vEnd - vStart) + (cone[0] - eStart);
8063       coneNew[1] = vStartNew + (vEnd - vStart) + (cone[1] - eStart);
8064       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
8065 #if defined(PETSC_USE_DEBUG)
8066       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a hybrid edge [%D, %D)", newp, eMaxNew, eEndNew);
8067       for (p = 0; p < 2; ++p) {
8068         if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", coneNew[p], vStartNew, vEndNew);
8069       }
8070 #endif
8071       supportRef[0] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (f - fMax)*2 + 0;
8072       supportRef[1] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (f - fMax)*2 + 1;
8073       for (s = 0; s < size; ++s) {
8074         ierr = DMPlexGetConeSize(dm, support[s], &csize);CHKERRQ(ierr);
8075         ierr = DMPlexGetCone(dm, support[s], &ccone);CHKERRQ(ierr);
8076         ierr = DMPlexGetConeOrientation(dm, support[s], &cornt);CHKERRQ(ierr);
8077         for (c = 0; c < csize; ++c) if (ccone[c] == f) break;
8078         if ((c < 2) || (c >= csize)) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Hybrid face %D is not in cone of hybrid cell %D", f, support[s]);
8079         supportRef[2+s] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd - fMax)*2 + (support[s] - cMax)*4 + c-2;
8080       }
8081       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
8082 #if defined(PETSC_USE_DEBUG)
8083       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a hybrid edge [%D, %D)", newp, eMaxNew, eEndNew);
8084       for (p = 0; p < 2+size; ++p) {
8085         if ((supportRef[p] < fMaxNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a hybrid face [%D, %D)", supportRef[p], fMaxNew, fEndNew);
8086       }
8087 #endif
8088     }
8089     /* Hybrid cell edges have 2 vertices and 4 faces */
8090     for (c = cMax; c < cEnd; ++c) {
8091       const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (eEnd - eMax) + (fEnd - fMax) + (c - cMax);
8092       const PetscInt *cone, *support;
8093       PetscInt        coneNew[2], size;
8094 
8095       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
8096       ierr = DMPlexGetSupportSize(dm, c, &size);CHKERRQ(ierr);
8097       ierr = DMPlexGetSupport(dm, c, &support);CHKERRQ(ierr);
8098       coneNew[0] = vStartNew + (vEnd - vStart) + (eMax - eStart) + (cone[0] - fStart);
8099       coneNew[1] = vStartNew + (vEnd - vStart) + (eMax - eStart) + (cone[1] - fStart);
8100       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
8101 #if defined(PETSC_USE_DEBUG)
8102       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a hybrid edge [%D, %D)", newp, eMaxNew, eEndNew);
8103       for (p = 0; p < 2; ++p) {
8104         if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", coneNew[p], vStartNew, vEndNew);
8105       }
8106 #endif
8107       supportRef[0] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd - fMax)*2 + (c - cMax)*4 + 0;
8108       supportRef[1] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd - fMax)*2 + (c - cMax)*4 + 1;
8109       supportRef[2] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd - fMax)*2 + (c - cMax)*4 + 2;
8110       supportRef[3] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd - fMax)*2 + (c - cMax)*4 + 3;
8111       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
8112 #if defined(PETSC_USE_DEBUG)
8113       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a hybrid edge [%D, %D)", newp, eMaxNew, eEndNew);
8114       for (p = 0; p < 4; ++p) {
8115         if ((supportRef[p] < fMaxNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a hybrid face [%D, %D)", supportRef[p], fMaxNew, fEndNew);
8116       }
8117 #endif
8118     }
8119     /* Interior vertices have identical supports */
8120     for (v = vStart; v < vEnd; ++v) {
8121       const PetscInt  newp = vStartNew + (v - vStart);
8122       const PetscInt *support, *cone;
8123       PetscInt        size, s;
8124 
8125       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
8126       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
8127       for (s = 0; s < size; ++s) {
8128         PetscInt r = 0;
8129 
8130         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
8131         if (cone[1] == v) r = 1;
8132         if (support[s] < eMax) supportRef[s] = eStartNew + (support[s] - eStart)*2 + r;
8133         else                   supportRef[s] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (support[s] - eMax);
8134       }
8135       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
8136 #if defined(PETSC_USE_DEBUG)
8137       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", newp, vStartNew, vEndNew);
8138       for (p = 0; p < size; ++p) {
8139         if ((supportRef[p] < eStartNew) || (supportRef[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", supportRef[p], eStartNew, eEndNew);
8140       }
8141 #endif
8142     }
8143     /* Interior edge vertices have 2 + faces supports */
8144     for (e = eStart; e < eMax; ++e) {
8145       const PetscInt  newp = vStartNew + (vEnd - vStart) + (e - eStart);
8146       const PetscInt *cone, *support;
8147       PetscInt        size, s;
8148 
8149       ierr          = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
8150       ierr          = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
8151       supportRef[0] = eStartNew + (e - eStart)*2 + 0;
8152       supportRef[1] = eStartNew + (e - eStart)*2 + 1;
8153       for (s = 0; s < size; ++s) {
8154         PetscInt r;
8155 
8156         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
8157         for (r = 0; r < 4; ++r) if (cone[r] == e) break;
8158         if (support[s] < fMax) {
8159           supportRef[2+s] = eStartNew + (eMax - eStart)*2 + (support[s] - fStart)*4 + r;
8160         } else {
8161           supportRef[2+s] = eStartNew + (eMax - eStart)*2 + (fMax       - fStart)*4 + (cMax - cStart)*6 + (eEnd - eMax) + (support[s] - fMax);
8162         }
8163       }
8164       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
8165 #if defined(PETSC_USE_DEBUG)
8166       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", newp, vStartNew, vEndNew);
8167       for (p = 0; p < 2+size; ++p) {
8168         if ((supportRef[p] < eStartNew) || (supportRef[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", supportRef[p], eStartNew, eEndNew);
8169       }
8170 #endif
8171     }
8172     /* Interior face vertices have 4 + cells supports */
8173     for (f = fStart; f < fMax; ++f) {
8174       const PetscInt  newp = vStartNew + (vEnd - vStart) + (eMax - eStart) + (f - fStart);
8175       const PetscInt *cone, *support;
8176       PetscInt        size, s;
8177 
8178       ierr          = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
8179       ierr          = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
8180       for (r = 0; r < 4; ++r) supportRef[r] = eStartNew + (eMax - eStart)*2 +  (f - fStart)*4 + r;
8181       for (s = 0; s < size; ++s) {
8182         PetscInt r;
8183 
8184         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
8185         for (r = 0; r < 6; ++r) if (cone[r] == f) break;
8186         if (support[s] < cMax) {
8187           supportRef[4+s] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (support[s] - cStart)*6 + r;
8188         } else {
8189           supportRef[4+s] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax       - cStart)*6 + (eEnd - eMax) + (fEnd - fMax) + (support[s] - cMax);
8190         }
8191       }
8192       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
8193 #if defined(PETSC_USE_DEBUG)
8194       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", newp, vStartNew, vEndNew);
8195       for (p = 0; p < 4+size; ++p) {
8196         if ((supportRef[p] < eStartNew) || (supportRef[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", supportRef[p], eStartNew, eEndNew);
8197       }
8198 #endif
8199     }
8200     /* Cell vertices have 6 supports */
8201     for (c = cStart; c < cMax; ++c) {
8202       const PetscInt newp = vStartNew + (vEnd - vStart) + (eMax - eStart) + (fMax - fStart) + (c - cStart);
8203       PetscInt       supportNew[6];
8204 
8205       for (r = 0; r < 6; ++r) {
8206         supportNew[r] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (c - cStart)*6 + r;
8207       }
8208       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
8209     }
8210     ierr = PetscFree(supportRef);CHKERRQ(ierr);
8211     break;
8212   default:
8213     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %s", CellRefiners[refiner]);
8214   }
8215   PetscFunctionReturn(0);
8216 }
8217 
8218 static PetscErrorCode CellRefinerSetCoordinates(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
8219 {
8220   PetscSection          coordSection, coordSectionNew;
8221   Vec                   coordinates, coordinatesNew;
8222   PetscScalar          *coords, *coordsNew;
8223   const PetscInt        numVertices = depthSize ? depthSize[0] : 0;
8224   PetscInt              dim, spaceDim, depth, bs, coordSizeNew, cStart, cEnd, cMax;
8225   PetscInt              c, vStart, vStartNew, vEnd, v, eStart, eEnd, eMax, e, fStart, fEnd, fMax, f;
8226   PetscInt              cStartNew, cEndNew, vEndNew, *parentId = NULL;
8227   VecType               vtype;
8228   PetscBool             isperiodic, localize = PETSC_FALSE, needcoords = PETSC_FALSE;
8229   const PetscReal      *maxCell, *L;
8230   const DMBoundaryType *bd;
8231   PetscErrorCode        ierr;
8232 
8233   PetscFunctionBegin;
8234   ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr);
8235   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
8236   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
8237   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
8238   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
8239   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
8240   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, NULL);CHKERRQ(ierr);
8241   if (cMax < 0) cMax = cEnd;
8242   if (fMax < 0) fMax = fEnd;
8243   if (eMax < 0) eMax = eEnd;
8244   ierr = GetDepthStart_Private(depth, depthSize, &cStartNew, NULL, NULL, &vStartNew);CHKERRQ(ierr);
8245   ierr = GetDepthEnd_Private(depth, depthSize, &cEndNew, NULL, NULL, &vEndNew);CHKERRQ(ierr);
8246   ierr = DMGetPeriodicity(dm, &isperiodic, &maxCell, &L, &bd);CHKERRQ(ierr);
8247   /* Determine if we need to localize coordinates when generating them */
8248   if (isperiodic && !maxCell) {
8249     ierr = DMGetCoordinatesLocalized(dm, &localize);CHKERRQ(ierr);
8250     if (!localize) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_USER,"Cannot refine if coordinates have not been localized");
8251   }
8252   if (isperiodic) {
8253     ierr = PetscOptionsBegin(PetscObjectComm((PetscObject)dm),((PetscObject)dm)->prefix,"DMPlex coords refinement options","DM");CHKERRQ(ierr);
8254     ierr = PetscOptionsBool("-dm_plex_refine_localize","Automatically localize from parent cells",NULL,localize,&localize,NULL);CHKERRQ(ierr);
8255     ierr = PetscOptionsEnd();CHKERRQ(ierr);
8256     if (localize) {
8257       ierr = DMLocalizeCoordinates(dm);CHKERRQ(ierr);
8258     }
8259   }
8260   ierr = DMSetPeriodicity(rdm, isperiodic,  maxCell,  L,  bd);CHKERRQ(ierr);
8261 
8262   ierr = DMGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
8263   ierr = PetscSectionGetFieldComponents(coordSection, 0, &spaceDim);CHKERRQ(ierr);
8264   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)dm), &coordSectionNew);CHKERRQ(ierr);
8265   ierr = PetscSectionSetNumFields(coordSectionNew, 1);CHKERRQ(ierr);
8266   ierr = PetscSectionSetFieldComponents(coordSectionNew, 0, spaceDim);CHKERRQ(ierr);
8267 
8268   if (localize) {
8269     PetscInt p, r, newp, *pi;
8270 
8271     /* New coordinates will be already localized on the cell */
8272     ierr = PetscSectionSetChart(coordSectionNew, 0, vStartNew+numVertices);CHKERRQ(ierr);
8273 
8274     /* We need the parentId to properly localize coordinates */
8275     ierr = PetscMalloc1(cEndNew-cStartNew,&pi);CHKERRQ(ierr);
8276     switch (refiner) {
8277     case REFINER_NOOP:
8278       break;
8279     case REFINER_SIMPLEX_1D:
8280       for (p = cStart; p < cEnd; ++p) {
8281         for (r = 0; r < 2; ++r) {
8282           newp     = (p - cStart)*2 + r;
8283           pi[newp] = p;
8284         }
8285       }
8286       break;
8287     case REFINER_SIMPLEX_2D:
8288       for (p = cStart; p < cEnd; ++p) {
8289         for (r = 0; r < 4; ++r) {
8290           newp     = (p - cStart)*4 + r;
8291           pi[newp] = p;
8292         }
8293       }
8294       break;
8295     case REFINER_HEX_2D:
8296       for (p = cStart; p < cEnd; ++p) {
8297         for (r = 0; r < 4; ++r) {
8298           newp     = (p - cStart)*4 + r;
8299           pi[newp] = p;
8300         }
8301       }
8302       break;
8303     case REFINER_SIMPLEX_TO_HEX_2D:
8304       for (p = cStart; p < cEnd; ++p) {
8305         for (r = 0; r < 3; ++r) {
8306           newp     = (p - cStart)*3 + r;
8307           pi[newp] = p;
8308         }
8309       }
8310       break;
8311     case REFINER_HYBRID_SIMPLEX_TO_HEX_2D:
8312       for (p = cStart; p < cMax; ++p) {
8313         for (r = 0; r < 3; ++r) {
8314           newp     = (p - cStart)*3 + r;
8315           pi[newp] = p;
8316         }
8317       }
8318       for (p = cMax; p < cEnd; ++p) {
8319         for (r = 0; r < 4; ++r) {
8320           newp     = (cMax - cStart)*3 + (p - cMax)*4 + r;
8321           pi[newp] = p;
8322         }
8323       }
8324       /* The refiner needs midpoint vertices on hybrid edges and hybrid cells */
8325       cMax = cEnd;
8326       eMax = eEnd;
8327       break;
8328     case REFINER_HYBRID_SIMPLEX_2D:
8329       for (p = cStart; p < cMax; ++p) {
8330         for (r = 0; r < 4; ++r) {
8331           newp     = (p - cStart)*4 + r;
8332           pi[newp] = p;
8333         }
8334       }
8335       for (p = cMax; p < cEnd; ++p) {
8336         for (r = 0; r < 2; ++r) {
8337           newp     = (cMax - cStart)*4 + (p - cMax)*2 + r;
8338           pi[newp] = p;
8339         }
8340       }
8341       break;
8342     case REFINER_HYBRID_HEX_2D:
8343       for (p = cStart; p < cMax; ++p) {
8344         for (r = 0; r < 4; ++r) {
8345           newp     = (p - cStart)*4 + r;
8346           pi[newp] = p;
8347         }
8348       }
8349       for (p = cMax; p < cEnd; ++p) {
8350         for (r = 0; r < 2; ++r) {
8351           newp     = (cMax - cStart)*4 + (p - cMax)*2 + r;
8352           pi[newp] = p;
8353         }
8354       }
8355       break;
8356     case REFINER_SIMPLEX_3D:
8357       for (p = cStart; p < cEnd; ++p) {
8358         for (r = 0; r < 8; ++r) {
8359           newp     = (p - cStart)*8 + r;
8360           pi[newp] = p;
8361         }
8362       }
8363       break;
8364     case REFINER_HYBRID_SIMPLEX_3D:
8365       for (p = cStart; p < cMax; ++p) {
8366         for (r = 0; r < 8; ++r) {
8367           newp     = (p - cStart)*8 + r;
8368           pi[newp] = p;
8369         }
8370       }
8371       for (p = cMax; p < cEnd; ++p) {
8372         for (r = 0; r < 4; ++r) {
8373           newp     = (cMax - cStart)*8 + (p - cMax)*4 + r;
8374           pi[newp] = p;
8375         }
8376       }
8377       break;
8378     case REFINER_SIMPLEX_TO_HEX_3D:
8379       for (p = cStart; p < cEnd; ++p) {
8380         for (r = 0; r < 4; ++r) {
8381           newp     = (p - cStart)*4 + r;
8382           pi[newp] = p;
8383         }
8384       }
8385       break;
8386     case REFINER_HYBRID_SIMPLEX_TO_HEX_3D:
8387       for (p = cStart; p < cMax; ++p) {
8388         for (r = 0; r < 4; ++r) {
8389           newp     = (p - cStart)*4 + r;
8390           pi[newp] = p;
8391         }
8392       }
8393       for (p = cMax; p < cEnd; ++p) {
8394         for (r = 0; r < 3; ++r) {
8395           newp     = (cMax - cStart)*4 + (p - cMax)*3 + r;
8396           pi[newp] = p;
8397         }
8398       }
8399       break;
8400     case REFINER_HEX_3D:
8401       for (p = cStart; p < cEnd; ++p) {
8402         for (r = 0; r < 8; ++r) {
8403           newp = (p - cStart)*8 + r;
8404           pi[newp] = p;
8405         }
8406       }
8407       break;
8408     case REFINER_HYBRID_HEX_3D:
8409       for (p = cStart; p < cMax; ++p) {
8410         for (r = 0; r < 8; ++r) {
8411           newp = (p - cStart)*8 + r;
8412           pi[newp] = p;
8413         }
8414       }
8415       for (p = cMax; p < cEnd; ++p) {
8416         for (r = 0; r < 4; ++r) {
8417           newp = (cMax - cStart)*8 + (p - cMax)*4 + r;
8418           pi[newp] = p;
8419         }
8420       }
8421       break;
8422     default:
8423       SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %s", CellRefiners[refiner]);
8424     }
8425     parentId = pi;
8426   } else {
8427     /* The refiner needs midpoint vertices on hybrid edges and hybrid cells */
8428     if (REFINER_HYBRID_SIMPLEX_TO_HEX_2D == refiner) { cMax = cEnd; eMax = eEnd; }
8429     ierr = PetscSectionSetChart(coordSectionNew, vStartNew, vStartNew+numVertices);CHKERRQ(ierr);
8430   }
8431 
8432   /* All vertices have the spaceDim coordinates */
8433   if (localize) {
8434     PetscInt c;
8435 
8436     for (c = cStartNew; c < cEndNew; ++c) {
8437       PetscInt *cone = NULL;
8438       PetscInt  closureSize, coneSize = 0, p, pdof;
8439 
8440       ierr = PetscSectionGetDof(coordSection, parentId[c], &pdof); CHKERRQ(ierr);
8441       if (pdof) { /* localize on all cells that are refinement of a localized parent cell */
8442         ierr = DMPlexGetTransitiveClosure(rdm, c, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
8443         for (p = 0; p < closureSize*2; p += 2) {
8444           const PetscInt point = cone[p];
8445           if ((point >= vStartNew) && (point < vEndNew)) coneSize++;
8446         }
8447         ierr = DMPlexRestoreTransitiveClosure(rdm, c, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
8448         ierr = PetscSectionSetDof(coordSectionNew, c, coneSize*spaceDim);CHKERRQ(ierr);
8449         ierr = PetscSectionSetFieldDof(coordSectionNew, c, 0, coneSize*spaceDim);CHKERRQ(ierr);
8450       }
8451     }
8452   }
8453   for (v = vStartNew; v < vStartNew+numVertices; ++v) {
8454     ierr = PetscSectionSetDof(coordSectionNew, v, spaceDim);CHKERRQ(ierr);
8455     ierr = PetscSectionSetFieldDof(coordSectionNew, v, 0, spaceDim);CHKERRQ(ierr);
8456   }
8457   ierr = PetscSectionSetUp(coordSectionNew);CHKERRQ(ierr);
8458   ierr = DMSetCoordinateSection(rdm, PETSC_DETERMINE, coordSectionNew);CHKERRQ(ierr);
8459   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
8460   ierr = PetscSectionGetStorageSize(coordSectionNew, &coordSizeNew);CHKERRQ(ierr);
8461   ierr = VecCreate(PETSC_COMM_SELF, &coordinatesNew);CHKERRQ(ierr);
8462   ierr = PetscObjectSetName((PetscObject) coordinatesNew, "coordinates");CHKERRQ(ierr);
8463   ierr = VecSetSizes(coordinatesNew, coordSizeNew, PETSC_DETERMINE);CHKERRQ(ierr);
8464   ierr = VecGetBlockSize(coordinates, &bs);CHKERRQ(ierr);
8465   ierr = VecSetBlockSize(coordinatesNew, bs);CHKERRQ(ierr);
8466   ierr = VecGetType(coordinates, &vtype);CHKERRQ(ierr);
8467   ierr = VecSetType(coordinatesNew, vtype);CHKERRQ(ierr);
8468   ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
8469   ierr = VecGetArray(coordinatesNew, &coordsNew);CHKERRQ(ierr);
8470 
8471   switch (refiner) {
8472   case REFINER_NOOP: break;
8473   case REFINER_HYBRID_SIMPLEX_TO_HEX_3D:
8474   case REFINER_SIMPLEX_TO_HEX_3D:
8475   case REFINER_HEX_3D:
8476   case REFINER_HYBRID_HEX_3D:
8477     /* Face vertices have the average of corner coordinates */
8478     for (f = fStart; f < fMax; ++f) {
8479       const PetscInt newv = vStartNew + (vEnd - vStart) + (eMax - eStart) + (f - fStart);
8480       PetscInt      *cone = NULL;
8481       PetscInt       closureSize, coneSize = 0, off[8], offnew, p, d;
8482 
8483       ierr = DMPlexGetTransitiveClosure(dm, f, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
8484       for (p = 0; p < closureSize*2; p += 2) {
8485         const PetscInt point = cone[p];
8486         if ((point >= vStart) && (point < vEnd)) cone[coneSize++] = point;
8487       }
8488       if (localize) {
8489         const PetscInt *support = NULL;
8490         PetscInt       *rStar = NULL;
8491         PetscInt        supportSize, rStarSize, coff, s, ccoff[8];
8492         PetscBool       cellfound = PETSC_FALSE;
8493 
8494         ierr = DMPlexGetTransitiveClosure(rdm, newv, PETSC_FALSE, &rStarSize, &rStar);CHKERRQ(ierr);
8495         ierr = DMPlexGetSupportSize(dm,f,&supportSize);CHKERRQ(ierr);
8496         ierr = DMPlexGetSupport(dm,f,&support);CHKERRQ(ierr);
8497         /* Compute average of coordinates for each cell sharing the face */
8498         for (s = 0; s < supportSize; ++s) {
8499           PetscScalar     coordsNewAux[3] = { 0.0, 0.0, 0.0 };
8500           PetscInt       *cellCone = NULL;
8501           PetscInt        cellClosureSize, cellConeSize = 0, cdof;
8502           const PetscInt  cell = support[s];
8503           PetscBool       copyoff = PETSC_FALSE;
8504 
8505           ierr = DMPlexGetTransitiveClosure(dm, cell, PETSC_TRUE, &cellClosureSize, &cellCone);CHKERRQ(ierr);
8506           for (p = 0; p < cellClosureSize*2; p += 2) {
8507             const PetscInt point = cellCone[p];
8508             if ((point >= vStart) && (point < vEnd)) cellCone[cellConeSize++] = point;
8509           }
8510           ierr = PetscSectionGetDof(coordSection, cell, &cdof);CHKERRQ(ierr);
8511           if (!cdof) { /* the parent cell does not have localized coordinates */
8512             cellfound = PETSC_TRUE;
8513             for (v = 0; v < coneSize; ++v) {
8514               ierr = PetscSectionGetOffset(coordSection, cone[v], &off[v]);CHKERRQ(ierr);
8515               for (d = 0; d < spaceDim; ++d) coordsNewAux[d] += coords[off[v]+d];
8516             }
8517             for (d = 0; d < spaceDim; ++d) coordsNewAux[d] /= coneSize;
8518           } else {
8519             ierr = PetscSectionGetOffset(coordSection, cell, &coff);CHKERRQ(ierr);
8520             for (p = 0; p < coneSize; ++p) {
8521               const PetscInt tv = cone[p];
8522               PetscInt       cv, voff;
8523               PetscBool      locv = PETSC_TRUE;
8524 
8525               for (cv = 0; cv < cellConeSize; ++cv) {
8526                 if (cellCone[cv] == tv) {
8527                   ccoff[p] = spaceDim*cv + coff;
8528                   break;
8529                 }
8530               }
8531               if (cv == cellConeSize) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Unable to map vertex %D",tv);
8532 
8533               ierr = PetscSectionGetOffset(coordSection, cone[p], &voff);CHKERRQ(ierr);
8534               for (d = 0; d < spaceDim; ++d) {
8535                 coordsNewAux[d] += coords[ccoff[p]+d];
8536                 if (!cellfound && coords[voff+d] != coords[ccoff[p]+d]) locv = PETSC_FALSE;
8537               }
8538               if (locv && !cellfound) {
8539                 cellfound = PETSC_TRUE;
8540                 copyoff   = PETSC_TRUE;
8541               }
8542             }
8543             for (d = 0; d < spaceDim; ++d) coordsNewAux[d] /= coneSize;
8544 
8545             /* Found a valid face for the "vertex" part of the Section (physical space)
8546                i.e., a face that has at least one corner in the physical space */
8547             if (copyoff) for (p = 0; p < coneSize; ++p) off[p] = ccoff[p];
8548           }
8549 
8550           /* Localize new coordinates on each refined cell */
8551           for (v = 0; v < rStarSize*2; v += 2) {
8552             if ((rStar[v] >= cStartNew) && (rStar[v] < cEndNew) && parentId[rStar[v]-cStartNew] == cell) {
8553               PetscInt       *rcone = NULL, rclosureSize, lid, rcdof, rcoff;
8554               const PetscInt  rcell = rStar[v];
8555 
8556               ierr = PetscSectionGetDof(coordSectionNew, rcell, &rcdof);CHKERRQ(ierr);
8557               if (!rcdof) continue;
8558               ierr = PetscSectionGetOffset(coordSectionNew, rcell, &rcoff);CHKERRQ(ierr);
8559               ierr = DMPlexGetTransitiveClosure(rdm, rcell, PETSC_TRUE, &rclosureSize, &rcone);CHKERRQ(ierr);
8560               for (p = 0, lid = 0; p < rclosureSize*2; p += 2) {
8561                 if (rcone[p] == newv) {
8562                   for (d = 0; d < spaceDim; d++) coordsNew[rcoff + lid*spaceDim + d] = coordsNewAux[d];
8563                   break;
8564                 }
8565                 if (rcone[p] >= vStartNew && rcone[p] < vEndNew) lid++;
8566               }
8567               ierr = DMPlexRestoreTransitiveClosure(rdm, rcell, PETSC_TRUE, &rclosureSize, &rcone);CHKERRQ(ierr);
8568               if (p == closureSize*2) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Unable to map new vertex %D",newv);
8569             }
8570           }
8571           ierr = DMPlexRestoreTransitiveClosure(dm, cell, PETSC_TRUE, &cellClosureSize, &cellCone);CHKERRQ(ierr);
8572         }
8573         ierr = DMPlexRestoreTransitiveClosure(rdm, newv, PETSC_FALSE, &rStarSize, &rStar);CHKERRQ(ierr);
8574         if (!cellfound) {
8575           /* Could not find a valid face for the vertex part, we will get this vertex later (final reduction) */
8576           needcoords = PETSC_TRUE;
8577           coneSize   = 0;
8578         }
8579       } else {
8580         for (v = 0; v < coneSize; ++v) {
8581           ierr = PetscSectionGetOffset(coordSection, cone[v], &off[v]);CHKERRQ(ierr);
8582         }
8583       }
8584       ierr = PetscSectionGetOffset(coordSectionNew, newv, &offnew);CHKERRQ(ierr);
8585       if (coneSize) {
8586         for (d = 0; d < spaceDim; ++d) coordsNew[offnew+d] = 0.0;
8587         for (v = 0; v < coneSize; ++v) {ierr = DMLocalizeAddCoordinate_Internal(dm, spaceDim, &coords[off[0]], &coords[off[v]], &coordsNew[offnew]);CHKERRQ(ierr);}
8588         for (d = 0; d < spaceDim; ++d) coordsNew[offnew+d] /= coneSize;
8589       } else {
8590         for (d = 0; d < spaceDim; ++d) coordsNew[offnew+d] = PETSC_MIN_REAL;
8591       }
8592       ierr = DMPlexRestoreTransitiveClosure(dm, f, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
8593     }
8594   case REFINER_HYBRID_SIMPLEX_TO_HEX_2D:
8595   case REFINER_SIMPLEX_TO_HEX_2D:
8596   case REFINER_HEX_2D:
8597   case REFINER_HYBRID_HEX_2D:
8598   case REFINER_SIMPLEX_1D:
8599     /* Cell vertices have the average of corner coordinates */
8600     for (c = cStart; c < cMax; ++c) {
8601       const PetscInt newv = vStartNew + (vEnd - vStart) + (dim > 1 ? (eMax - eStart) : 0) + (c - cStart) + (dim > 2 ? (fMax - fStart) : 0);
8602       PetscInt      *cone = NULL;
8603       PetscInt       closureSize, coneSize = 0, off[8], offnew, p, d, cdof = 0;
8604 
8605       ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
8606       for (p = 0; p < closureSize*2; p += 2) {
8607         const PetscInt point = cone[p];
8608         if ((point >= vStart) && (point < vEnd)) cone[coneSize++] = point;
8609       }
8610       if (localize) {
8611         ierr = PetscSectionGetDof(coordSection, c, &cdof);CHKERRQ(ierr);
8612       }
8613       if (cdof) {
8614         PetscInt coff;
8615 
8616         ierr = PetscSectionGetOffset(coordSection, c, &coff);CHKERRQ(ierr);
8617         for (v = 0; v < coneSize; ++v) off[v] = spaceDim*v + coff;
8618       } else {
8619         for (v = 0; v < coneSize; ++v) {
8620           ierr = PetscSectionGetOffset(coordSection, cone[v], &off[v]);CHKERRQ(ierr);
8621         }
8622       }
8623       ierr = PetscSectionGetOffset(coordSectionNew, newv, &offnew);CHKERRQ(ierr);
8624       for (d = 0; d < spaceDim; ++d) coordsNew[offnew+d] = 0.0;
8625       for (v = 0; v < coneSize; ++v) {ierr = DMLocalizeAddCoordinate_Internal(dm, spaceDim, &coords[off[0]], &coords[off[v]], &coordsNew[offnew]);CHKERRQ(ierr);}
8626       for (d = 0; d < spaceDim; ++d) coordsNew[offnew+d] /= coneSize;
8627       ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
8628 
8629       /* Localize new coordinates on each refined cell */
8630       if (cdof) {
8631         PetscInt *rStar = NULL, rStarSize;
8632 
8633         ierr = DMPlexGetTransitiveClosure(rdm, newv, PETSC_FALSE, &rStarSize, &rStar);CHKERRQ(ierr);
8634         for (v = 0; v < rStarSize*2; v += 2) {
8635           if ((rStar[v] >= cStartNew) && (rStar[v] < cEndNew)) {
8636             PetscInt *cone = NULL, closureSize, lid, coff, rc, rcdof;
8637 
8638             rc   = rStar[v];
8639             ierr = PetscSectionGetDof(coordSectionNew, rc, &rcdof);CHKERRQ(ierr);
8640             if (!rcdof) continue;
8641             ierr = PetscSectionGetOffset(coordSectionNew, rc, &coff);CHKERRQ(ierr);
8642             ierr = DMPlexGetTransitiveClosure(rdm, rc, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
8643             for (p = 0, lid = 0; p < closureSize*2; p += 2) {
8644               if (cone[p] == newv) {
8645                 for (d = 0; d < spaceDim; d++) coordsNew[coff + lid*spaceDim + d] = coordsNew[offnew + d];
8646                 break;
8647               }
8648               if (cone[p] >= vStartNew && cone[p] < vEndNew) lid++;
8649             }
8650             if (p == closureSize*2) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Unable to map new vertex %D",newv);
8651             ierr = DMPlexRestoreTransitiveClosure(rdm, rc, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
8652           }
8653         }
8654         ierr = DMPlexRestoreTransitiveClosure(rdm, newv, PETSC_FALSE, &rStarSize, &rStar);CHKERRQ(ierr);
8655       }
8656     }
8657   case REFINER_SIMPLEX_2D:
8658   case REFINER_HYBRID_SIMPLEX_2D:
8659   case REFINER_SIMPLEX_3D:
8660   case REFINER_HYBRID_SIMPLEX_3D:
8661     /* Edge vertices have the average of endpoint coordinates */
8662     for (e = eStart; e < eMax; ++e) {
8663       const PetscInt  newv = vStartNew + (vEnd - vStart) + (e - eStart);
8664       const PetscInt *cone;
8665       PetscInt        coneSize, offA, offB, offnew, d;
8666 
8667       ierr = DMPlexGetConeSize(dm, e, &coneSize);CHKERRQ(ierr);
8668       if (coneSize != 2) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Edge %D cone should have two vertices, not %D", e, coneSize);
8669       ierr = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
8670       if (localize) {
8671         PetscInt   coff, toffA = -1, toffB = -1, voffA, voffB;
8672         PetscInt  *eStar = NULL, eStarSize;
8673         PetscInt  *rStar = NULL, rStarSize;
8674         PetscBool  cellfound = PETSC_FALSE;
8675 
8676         offA = offB = -1;
8677         ierr = PetscSectionGetOffset(coordSection, cone[0], &voffA);CHKERRQ(ierr);
8678         ierr = PetscSectionGetOffset(coordSection, cone[1], &voffB);CHKERRQ(ierr);
8679         ierr = DMPlexGetTransitiveClosure(dm, e, PETSC_FALSE, &eStarSize, &eStar);CHKERRQ(ierr);
8680         ierr = DMPlexGetTransitiveClosure(rdm, newv, PETSC_FALSE, &rStarSize, &rStar);CHKERRQ(ierr);
8681         for (v = 0; v < eStarSize*2; v += 2) {
8682           if ((eStar[v] >= cStart) && (eStar[v] < cEnd)) {
8683             PetscScalar     coordsNewAux[3];
8684             PetscInt       *cellCone = NULL;
8685             PetscInt        cellClosureSize, s, cv, cdof;
8686             PetscBool       locvA = PETSC_TRUE, locvB = PETSC_TRUE;
8687             const PetscInt  cell = eStar[v];
8688 
8689             ierr = PetscSectionGetDof(coordSection, cell, &cdof);CHKERRQ(ierr);
8690             if (!cdof) {
8691               /* Found a valid edge for the "vertex" part of the Section */
8692               offA = voffA;
8693               offB = voffB;
8694               cellfound = PETSC_TRUE;
8695             } else {
8696               ierr = PetscSectionGetOffset(coordSection, cell, &coff);CHKERRQ(ierr);
8697               ierr = DMPlexGetTransitiveClosure(dm, cell, PETSC_TRUE, &cellClosureSize, &cellCone);CHKERRQ(ierr);
8698               for (s = 0, cv = 0; s < cellClosureSize*2; s += 2) {
8699                 const PetscInt point = cellCone[s];
8700                 if ((point >= vStart) && (point < vEnd)) {
8701                   if (point == cone[0]) toffA = spaceDim*cv + coff;
8702                   else if (point == cone[1]) toffB = spaceDim*cv + coff;
8703                   cv++;
8704                 }
8705               }
8706               ierr = DMPlexRestoreTransitiveClosure(dm, cell, PETSC_TRUE, &cellClosureSize, &cellCone);CHKERRQ(ierr);
8707               for (d = 0; d < spaceDim; ++d) {
8708                 coordsNewAux[d] = 0.5*(coords[toffA+d] + coords[toffB+d]);
8709                 if (coords[toffA+d] != coords[voffA+d]) locvA = PETSC_FALSE;
8710                 if (coords[toffB+d] != coords[voffB+d]) locvB = PETSC_FALSE;
8711               }
8712               /* Found a valid edge for the "vertex" part of the Section */
8713               if (!cellfound && (locvA || locvB)) {
8714                 cellfound = PETSC_TRUE;
8715                 offA = toffA;
8716                 offB = toffB;
8717               }
8718             }
8719 
8720             /* Localize new coordinates on each refined cell */
8721             for (s = 0; s < rStarSize*2; s += 2) {
8722               if ((rStar[s] >= cStartNew) && (rStar[s] < cEndNew) && parentId[rStar[s]-cStartNew] == cell) {
8723                 PetscInt       *rcone = NULL, rclosureSize, lid, p, rcdof;
8724                 const PetscInt  rcell = rStar[s];
8725 
8726                 ierr = PetscSectionGetDof(coordSectionNew, rcell, &rcdof);CHKERRQ(ierr);
8727                 if (!rcdof) continue;
8728                 ierr = PetscSectionGetOffset(coordSectionNew, rcell, &coff);CHKERRQ(ierr);
8729                 ierr = DMPlexGetTransitiveClosure(rdm, rcell, PETSC_TRUE, &rclosureSize, &rcone);CHKERRQ(ierr);
8730                 for (p = 0, lid = 0; p < rclosureSize*2; p += 2) {
8731                   if (rcone[p] == newv) {
8732                     for (d = 0; d < spaceDim; d++) coordsNew[coff + lid*spaceDim + d] = coordsNewAux[d];
8733                     break;
8734                   }
8735                   if (rcone[p] >= vStartNew && rcone[p] < vEndNew) lid++;
8736                 }
8737                 ierr = DMPlexRestoreTransitiveClosure(rdm, rcell, PETSC_TRUE, &rclosureSize, &rcone);CHKERRQ(ierr);
8738                 if (p == rclosureSize*2) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Unable to map new vertex %D",newv);
8739               }
8740             }
8741           }
8742         }
8743         ierr = DMPlexRestoreTransitiveClosure(dm, e, PETSC_FALSE, &eStarSize, &eStar);CHKERRQ(ierr);
8744         ierr = DMPlexRestoreTransitiveClosure(rdm, newv, PETSC_FALSE, &rStarSize, &rStar);CHKERRQ(ierr);
8745         if (!cellfound) {
8746           /* Could not find a valid edge for the vertex part, we will get this vertex later (final reduction) */
8747           needcoords = PETSC_TRUE;
8748         }
8749       } else {
8750         ierr = PetscSectionGetOffset(coordSection, cone[0], &offA);CHKERRQ(ierr);
8751         ierr = PetscSectionGetOffset(coordSection, cone[1], &offB);CHKERRQ(ierr);
8752       }
8753       ierr = PetscSectionGetOffset(coordSectionNew, newv, &offnew);CHKERRQ(ierr);
8754       if (offA != -1 && offB != -1) {
8755         ierr = DMLocalizeCoordinate_Internal(dm, spaceDim, &coords[offA], &coords[offB], &coordsNew[offnew]);CHKERRQ(ierr);
8756         for (d = 0; d < spaceDim; ++d) {
8757           coordsNew[offnew+d] = 0.5*(coords[offA+d] + coordsNew[offnew+d]);
8758         }
8759       } else {
8760         for (d = 0; d < spaceDim; ++d) coordsNew[offnew+d] = PETSC_MIN_REAL;
8761       }
8762     }
8763     /* Old vertices have the same coordinates */
8764     for (v = vStart; v < vEnd; ++v) {
8765       const PetscInt newv = vStartNew + (v - vStart);
8766       PetscInt       off, offnew, d;
8767 
8768       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
8769       ierr = PetscSectionGetOffset(coordSectionNew, newv, &offnew);CHKERRQ(ierr);
8770       for (d = 0; d < spaceDim; ++d) {
8771         coordsNew[offnew+d] = coords[off+d];
8772       }
8773 
8774       /* Localize new coordinates on each refined cell */
8775       if (localize) {
8776         PetscInt  p;
8777         PetscInt *rStar = NULL, rStarSize;
8778 
8779         ierr = DMPlexGetTransitiveClosure(rdm, newv, PETSC_FALSE, &rStarSize, &rStar);CHKERRQ(ierr);
8780         for (p = 0; p < rStarSize*2; p += 2) {
8781           if ((rStar[p] >= cStartNew) && (rStar[p] < cEndNew)) {
8782             PetscScalar  ocoords[3];
8783             PetscInt    *cone = NULL, closureSize, lid, coff, s, oc, cdof;
8784 
8785             c    = rStar[p];
8786             oc   = parentId[c-cStartNew];
8787             ierr = PetscSectionGetDof(coordSectionNew, c, &cdof);CHKERRQ(ierr);
8788             if (!cdof) continue;
8789             ierr = PetscSectionGetDof(coordSection, oc, &cdof);CHKERRQ(ierr);
8790             if (!cdof) continue;
8791             ierr = PetscSectionGetOffset(coordSection, oc, &coff);CHKERRQ(ierr);
8792             ierr = DMPlexGetTransitiveClosure(dm, oc, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
8793             for (s = 0, lid = 0; s < closureSize*2; s += 2) {
8794               if (cone[s] == v) {
8795                 for (d = 0; d < spaceDim; d++) ocoords[d] = coords[coff + lid*spaceDim + d];
8796                 break;
8797               }
8798               if (cone[s] >= vStart && cone[s] < vEnd) lid++;
8799             }
8800             if (s == closureSize*2) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Unable to map old vertex %D",v);
8801             ierr = DMPlexRestoreTransitiveClosure(dm, oc, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
8802 
8803             ierr = PetscSectionGetOffset(coordSectionNew, c, &coff);CHKERRQ(ierr);
8804             ierr = DMPlexGetTransitiveClosure(rdm, c, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
8805             for (s = 0, lid = 0; s < closureSize*2; s += 2) {
8806               if (cone[s] == newv) {
8807                 for (d = 0; d < spaceDim; d++) coordsNew[coff + lid*spaceDim + d] = ocoords[d];
8808                 break;
8809               }
8810               if (cone[s] >= vStartNew && cone[s] < vEndNew) lid++;
8811             }
8812             if (s == closureSize*2) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Unable to map new vertex %D",newv);
8813             ierr = DMPlexRestoreTransitiveClosure(rdm, c, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
8814           }
8815         }
8816         ierr = DMPlexRestoreTransitiveClosure(rdm, newv, PETSC_FALSE, &rStarSize, &rStar);CHKERRQ(ierr);
8817       }
8818     }
8819     break;
8820   default:
8821     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %s", CellRefiners[refiner]);
8822   }
8823   ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
8824   ierr = VecRestoreArray(coordinatesNew, &coordsNew);CHKERRQ(ierr);
8825   ierr = DMSetCoordinatesLocal(rdm, coordinatesNew);CHKERRQ(ierr);
8826 
8827   /* Final reduction (if needed) if we are localizing */
8828   if (localize) {
8829     PetscBool gred;
8830 
8831     ierr = MPIU_Allreduce(&needcoords, &gred, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject)rdm));CHKERRQ(ierr);
8832     if (gred) {
8833       DM                 cdm;
8834       Vec                aux;
8835       PetscSF            sf;
8836       const PetscScalar *lArray;
8837       PetscScalar       *gArray;
8838 #if defined(PETSC_USE_COMPLEX)
8839       PetscInt          i, ln, gn;
8840       PetscReal         *lrArray;
8841       PetscReal         *grArray;
8842 #endif
8843 
8844       ierr = DMGetCoordinateDM(rdm, &cdm);CHKERRQ(ierr);
8845       ierr = DMCreateGlobalVector(cdm, &aux);CHKERRQ(ierr);
8846       ierr = DMGetDefaultSF(cdm, &sf);CHKERRQ(ierr);
8847       ierr = VecGetArrayRead(coordinatesNew, &lArray);CHKERRQ(ierr);
8848       ierr = VecSet(aux, PETSC_MIN_REAL);CHKERRQ(ierr);
8849       ierr = VecGetArray(aux, &gArray);CHKERRQ(ierr);
8850 #if defined(PETSC_USE_COMPLEX)
8851       ierr = VecGetLocalSize(aux, &gn);CHKERRQ(ierr);
8852       ierr = VecGetLocalSize(coordinatesNew, &ln);CHKERRQ(ierr);
8853       ierr = PetscMalloc2(ln,&lrArray,gn,&grArray);CHKERRQ(ierr);
8854       for (i=0;i<ln;i++) lrArray[i] = PetscRealPart(lArray[i]);
8855       for (i=0;i<gn;i++) grArray[i] = PetscRealPart(gArray[i]);
8856       ierr = PetscSFReduceBegin(sf, MPIU_REAL, lrArray, grArray, MPIU_MAX);CHKERRQ(ierr);
8857       ierr = PetscSFReduceEnd(sf, MPIU_REAL, lrArray, grArray, MPIU_MAX);CHKERRQ(ierr);
8858       for (i=0;i<gn;i++) gArray[i] = grArray[i];
8859       ierr = PetscFree2(lrArray,grArray);CHKERRQ(ierr);
8860 #else
8861       ierr = PetscSFReduceBegin(sf, MPIU_SCALAR, lArray, gArray, MPIU_MAX);CHKERRQ(ierr);
8862       ierr = PetscSFReduceEnd(sf, MPIU_SCALAR, lArray, gArray, MPIU_MAX);CHKERRQ(ierr);
8863 #endif
8864       ierr = VecRestoreArrayRead(coordinatesNew, &lArray);CHKERRQ(ierr);
8865       ierr = VecRestoreArray(aux, &gArray);CHKERRQ(ierr);
8866       ierr = DMGlobalToLocalBegin(cdm, aux, INSERT_VALUES, coordinatesNew);CHKERRQ(ierr);
8867       ierr = DMGlobalToLocalEnd(cdm, aux, INSERT_VALUES, coordinatesNew);CHKERRQ(ierr);
8868       ierr = VecDestroy(&aux);CHKERRQ(ierr);
8869     }
8870   }
8871   ierr = VecDestroy(&coordinatesNew);CHKERRQ(ierr);
8872   ierr = PetscSectionDestroy(&coordSectionNew);CHKERRQ(ierr);
8873   ierr = PetscFree(parentId);CHKERRQ(ierr);
8874   PetscFunctionReturn(0);
8875 }
8876 
8877 /*@
8878   DMPlexCreateProcessSF - Create an SF which just has process connectivity
8879 
8880   Collective on DM
8881 
8882   Input Parameters:
8883 + dm      - The DM
8884 - sfPoint - The PetscSF which encodes point connectivity
8885 
8886   Output Parameters:
8887 + processRanks - A list of process neighbors, or NULL
8888 - sfProcess    - An SF encoding the process connectivity, or NULL
8889 
8890   Level: developer
8891 
8892 .seealso: PetscSFCreate(), DMPlexCreateTwoSidedProcessSF()
8893 @*/
8894 PetscErrorCode DMPlexCreateProcessSF(DM dm, PetscSF sfPoint, IS *processRanks, PetscSF *sfProcess)
8895 {
8896   PetscInt           numRoots, numLeaves, l;
8897   const PetscInt    *localPoints;
8898   const PetscSFNode *remotePoints;
8899   PetscInt          *localPointsNew;
8900   PetscSFNode       *remotePointsNew;
8901   PetscInt          *ranks, *ranksNew;
8902   PetscMPIInt        size;
8903   PetscErrorCode     ierr;
8904 
8905   PetscFunctionBegin;
8906   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8907   PetscValidHeaderSpecific(sfPoint, PETSCSF_CLASSID, 2);
8908   if (processRanks) {PetscValidPointer(processRanks, 3);}
8909   if (sfProcess)    {PetscValidPointer(sfProcess, 4);}
8910   ierr = MPI_Comm_size(PetscObjectComm((PetscObject) dm), &size);CHKERRQ(ierr);
8911   ierr = PetscSFGetGraph(sfPoint, &numRoots, &numLeaves, &localPoints, &remotePoints);CHKERRQ(ierr);
8912   ierr = PetscMalloc1(numLeaves, &ranks);CHKERRQ(ierr);
8913   for (l = 0; l < numLeaves; ++l) {
8914     ranks[l] = remotePoints[l].rank;
8915   }
8916   ierr = PetscSortRemoveDupsInt(&numLeaves, ranks);CHKERRQ(ierr);
8917   ierr = PetscMalloc1(numLeaves, &ranksNew);CHKERRQ(ierr);
8918   ierr = PetscMalloc1(numLeaves, &localPointsNew);CHKERRQ(ierr);
8919   ierr = PetscMalloc1(numLeaves, &remotePointsNew);CHKERRQ(ierr);
8920   for (l = 0; l < numLeaves; ++l) {
8921     ranksNew[l]              = ranks[l];
8922     localPointsNew[l]        = l;
8923     remotePointsNew[l].index = 0;
8924     remotePointsNew[l].rank  = ranksNew[l];
8925   }
8926   ierr = PetscFree(ranks);CHKERRQ(ierr);
8927   if (processRanks) {ierr = ISCreateGeneral(PetscObjectComm((PetscObject)dm), numLeaves, ranksNew, PETSC_OWN_POINTER, processRanks);CHKERRQ(ierr);}
8928   else              {ierr = PetscFree(ranksNew);CHKERRQ(ierr);}
8929   if (sfProcess) {
8930     ierr = PetscSFCreate(PetscObjectComm((PetscObject)dm), sfProcess);CHKERRQ(ierr);
8931     ierr = PetscObjectSetName((PetscObject) *sfProcess, "Process SF");CHKERRQ(ierr);
8932     ierr = PetscSFSetFromOptions(*sfProcess);CHKERRQ(ierr);
8933     ierr = PetscSFSetGraph(*sfProcess, size, numLeaves, localPointsNew, PETSC_OWN_POINTER, remotePointsNew, PETSC_OWN_POINTER);CHKERRQ(ierr);
8934   }
8935   PetscFunctionReturn(0);
8936 }
8937 
8938 static PetscErrorCode CellRefinerCreateSF(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
8939 {
8940   PetscSF            sf, sfNew, sfProcess;
8941   IS                 processRanks;
8942   MPI_Datatype       depthType;
8943   PetscInt           numRoots, numLeaves, numLeavesNew = 0, l, m;
8944   const PetscInt    *localPoints, *neighbors;
8945   const PetscSFNode *remotePoints;
8946   PetscInt          *localPointsNew;
8947   PetscSFNode       *remotePointsNew;
8948   PetscInt          *depthSizeOld, *rdepthSize, *rdepthSizeOld, *rdepthMaxOld, *rvStart, *rvStartNew, *reStart, *reStartNew, *rfStart, *rfStartNew, *rcStart, *rcStartNew;
8949   PetscInt           ldepth, depth, numNeighbors, pStartNew, pEndNew, cStart, cEnd, cMax, vStart, vEnd, vMax, fStart, fEnd, fMax, eStart, eEnd, eMax, r, n;
8950   PetscInt           cStartNew = 0, vStartNew = 0, fStartNew = 0, eStartNew = 0;
8951   PetscErrorCode     ierr;
8952 
8953   PetscFunctionBegin;
8954   ierr = DMPlexGetChart(rdm, &pStartNew, &pEndNew);CHKERRQ(ierr);
8955   ierr = DMPlexGetDepth(dm, &ldepth);CHKERRQ(ierr);
8956   ierr = MPIU_Allreduce(&ldepth, &depth, 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject) dm));CHKERRQ(ierr);
8957   if ((ldepth >= 0) && (depth != ldepth)) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Inconsistent Plex depth %D != %D", ldepth, depth);
8958   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
8959   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
8960   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
8961   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
8962   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
8963   cMax = cMax < 0 ? cEnd : cMax;
8964   fMax = fMax < 0 ? fEnd : fMax;
8965   eMax = eMax < 0 ? eEnd : eMax;
8966   if (refiner) {ierr = GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);CHKERRQ(ierr);}
8967   ierr = DMGetPointSF(dm, &sf);CHKERRQ(ierr);
8968   ierr = DMGetPointSF(rdm, &sfNew);CHKERRQ(ierr);
8969   /* Calculate size of new SF */
8970   ierr = PetscSFGetGraph(sf, &numRoots, &numLeaves, &localPoints, &remotePoints);CHKERRQ(ierr);
8971   if (numRoots < 0) PetscFunctionReturn(0);
8972   for (l = 0; l < numLeaves; ++l) {
8973     const PetscInt p = localPoints[l];
8974 
8975     switch (refiner) {
8976     case REFINER_SIMPLEX_1D:
8977       if ((p >= vStart) && (p < vEnd)) {
8978         /* Interior vertices stay the same */
8979         ++numLeavesNew;
8980       } else if ((p >= cStart && p < cMax)) {
8981         /* Interior cells add new cells and interior vertices */
8982         numLeavesNew += 2 + 1;
8983       }
8984       break;
8985     case REFINER_SIMPLEX_2D:
8986     case REFINER_HYBRID_SIMPLEX_2D:
8987       if ((p >= vStart) && (p < vEnd)) {
8988         /* Interior vertices stay the same */
8989         ++numLeavesNew;
8990       } else if ((p >= fStart) && (p < fMax)) {
8991         /* Interior faces add new faces and vertex */
8992         numLeavesNew += 2 + 1;
8993       } else if ((p >= fMax) && (p < fEnd)) {
8994         /* Hybrid faces stay the same */
8995         ++numLeavesNew;
8996       } else if ((p >= cStart) && (p < cMax)) {
8997         /* Interior cells add new cells and interior faces */
8998         numLeavesNew += 4 + 3;
8999       } else if ((p >= cMax) && (p < cEnd)) {
9000         /* Hybrid cells add new cells and hybrid face */
9001         numLeavesNew += 2 + 1;
9002       }
9003       break;
9004     case REFINER_HYBRID_SIMPLEX_TO_HEX_2D:
9005     case REFINER_SIMPLEX_TO_HEX_2D:
9006       if ((p >= vStart) && (p < vEnd)) {
9007         /* Interior vertices stay the same */
9008         ++numLeavesNew;
9009       } else if ((p >= fStart) && (p < fEnd)) {
9010         /* Interior faces add new faces and vertex */
9011         numLeavesNew += 2 + 1;
9012       } else if ((p >= cStart) && (p < cMax)) {
9013         /* Interior cells add new cells, interior faces, and vertex */
9014         numLeavesNew += 3 + 3 + 1;
9015       } else if ((p >= cMax) && (p < cEnd)) {
9016         /* Hybrid cells add new cells, interior faces, and vertex */
9017         numLeavesNew += 4 + 4 + 1;
9018       }
9019       break;
9020     case REFINER_HEX_2D:
9021     case REFINER_HYBRID_HEX_2D:
9022       if ((p >= vStart) && (p < vEnd)) {
9023         /* Interior vertices stay the same */
9024         ++numLeavesNew;
9025       } else if ((p >= fStart) && (p < fMax)) {
9026         /* Interior faces add new faces and vertex */
9027         numLeavesNew += 2 + 1;
9028       } else if ((p >= fMax) && (p < fEnd)) {
9029         /* Hybrid faces stay the same */
9030         ++numLeavesNew;
9031       } else if ((p >= cStart) && (p < cMax)) {
9032         /* Interior cells add new cells, interior faces, and vertex */
9033         numLeavesNew += 4 + 4 + 1;
9034       } else if ((p >= cMax) && (p < cEnd)) {
9035         /* Hybrid cells add new cells and hybrid face */
9036         numLeavesNew += 2 + 1;
9037       }
9038       break;
9039     case REFINER_SIMPLEX_3D:
9040     case REFINER_HYBRID_SIMPLEX_3D:
9041       if ((p >= vStart) && (p < vEnd)) {
9042         /* Interior vertices stay the same */
9043         ++numLeavesNew;
9044       } else if ((p >= eStart) && (p < eMax)) {
9045         /* Interior edges add new edges and vertex */
9046         numLeavesNew += 2 + 1;
9047       } else if ((p >= eMax) && (p < eEnd)) {
9048         /* Hybrid edges stay the same */
9049         ++numLeavesNew;
9050       } else if ((p >= fStart) && (p < fMax)) {
9051         /* Interior faces add new faces and edges */
9052         numLeavesNew += 4 + 3;
9053       } else if ((p >= fMax) && (p < fEnd)) {
9054         /* Hybrid faces add new faces and edges */
9055         numLeavesNew += 2 + 1;
9056       } else if ((p >= cStart) && (p < cMax)) {
9057         /* Interior cells add new cells, faces, and edges */
9058         numLeavesNew += 8 + 8 + 1;
9059       } else if ((p >= cMax) && (p < cEnd)) {
9060         /* Hybrid cells add new cells and faces */
9061         numLeavesNew += 4 + 3;
9062       }
9063       break;
9064     case REFINER_HYBRID_SIMPLEX_TO_HEX_3D:
9065     case REFINER_SIMPLEX_TO_HEX_3D:
9066       if ((p >= vStart) && (p < vEnd)) {
9067         /* Interior vertices stay the same */
9068         ++numLeavesNew;
9069       } else if ((p >= eStart) && (p < eMax)) {
9070         /* Interior edges add new edges and vertex */
9071         numLeavesNew += 2 + 1;
9072       } else if ((p >= eMax) && (p < eEnd)) {
9073         /* Hybrid edges stay the same */
9074         ++numLeavesNew;
9075       } else if ((p >= fStart) && (p < fMax)) {
9076         /* Interior faces add new faces, edges and a vertex */
9077         numLeavesNew += 3 + 3 + 1;
9078       } else if ((p >= fMax) && (p < fEnd)) {
9079         /* Hybrid faces add new faces and an edge */
9080         numLeavesNew += 2 + 1;
9081       } else if ((p >= cStart) && (p < cMax)) {
9082         /* Interior cells add new cells, faces, edges and a vertex */
9083         numLeavesNew += 4 + 6 + 4 + 1;
9084       } else if ((p >= cMax) && (p < cEnd)) {
9085         /* Hybrid cells add new cells, faces and an edge */
9086         numLeavesNew += 3 + 3 + 1;
9087       }
9088       break;
9089     case REFINER_HEX_3D:
9090     case REFINER_HYBRID_HEX_3D:
9091       if ((p >= vStart) && (p < vEnd)) {
9092         /* Old vertices stay the same */
9093         ++numLeavesNew;
9094       } else if ((p >= eStart) && (p < eMax)) {
9095         /* Interior edges add new edges, and vertex */
9096         numLeavesNew += 2 + 1;
9097       } else if ((p >= eMax) && (p < eEnd)) {
9098         /* Hybrid edges stay the same */
9099         ++numLeavesNew;
9100       } else if ((p >= fStart) && (p < fMax)) {
9101         /* Interior faces add new faces, edges, and vertex */
9102         numLeavesNew += 4 + 4 + 1;
9103       } else if ((p >= fMax) && (p < fEnd)) {
9104         /* Hybrid faces add new faces and edges */
9105         numLeavesNew += 2 + 1;
9106       } else if ((p >= cStart) && (p < cMax)) {
9107         /* Interior cells add new cells, faces, edges, and vertex */
9108         numLeavesNew += 8 + 12 + 6 + 1;
9109       } else if ((p >= cStart) && (p < cEnd)) {
9110         /* Hybrid cells add new cells, faces, and edges */
9111         numLeavesNew += 4 + 4 + 1;
9112       }
9113       break;
9114     default:
9115       SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %s", CellRefiners[refiner]);
9116     }
9117   }
9118   /* Communicate depthSizes for each remote rank */
9119   ierr = DMPlexCreateProcessSF(dm, sf, &processRanks, &sfProcess);CHKERRQ(ierr);
9120   ierr = ISGetLocalSize(processRanks, &numNeighbors);CHKERRQ(ierr);
9121   ierr = PetscMalloc5((depth+1)*numNeighbors,&rdepthSize,numNeighbors,&rvStartNew,numNeighbors,&reStartNew,numNeighbors,&rfStartNew,numNeighbors,&rcStartNew);CHKERRQ(ierr);
9122   ierr = PetscMalloc7(depth+1,&depthSizeOld,(depth+1)*numNeighbors,&rdepthSizeOld,(depth+1)*numNeighbors,&rdepthMaxOld,numNeighbors,&rvStart,numNeighbors,&reStart,numNeighbors,&rfStart,numNeighbors,&rcStart);CHKERRQ(ierr);
9123   ierr = MPI_Type_contiguous(depth+1, MPIU_INT, &depthType);CHKERRQ(ierr);
9124   ierr = MPI_Type_commit(&depthType);CHKERRQ(ierr);
9125   ierr = PetscSFBcastBegin(sfProcess, depthType, depthSize, rdepthSize);CHKERRQ(ierr);
9126   ierr = PetscSFBcastEnd(sfProcess, depthType, depthSize, rdepthSize);CHKERRQ(ierr);
9127   for (n = 0; n < numNeighbors; ++n) {
9128     ierr = GetDepthStart_Private(depth, &rdepthSize[n*(depth+1)], &rcStartNew[n], &rfStartNew[n], &reStartNew[n], &rvStartNew[n]);CHKERRQ(ierr);
9129   }
9130   depthSizeOld[depth]   = cMax;
9131   depthSizeOld[0]       = vMax;
9132   depthSizeOld[depth-1] = fMax;
9133   depthSizeOld[1]       = eMax;
9134 
9135   ierr = PetscSFBcastBegin(sfProcess, depthType, depthSizeOld, rdepthMaxOld);CHKERRQ(ierr);
9136   ierr = PetscSFBcastEnd(sfProcess, depthType, depthSizeOld, rdepthMaxOld);CHKERRQ(ierr);
9137 
9138   depthSizeOld[depth]   = cEnd - cStart;
9139   depthSizeOld[0]       = vEnd - vStart;
9140   depthSizeOld[depth-1] = fEnd - fStart;
9141   depthSizeOld[1]       = eEnd - eStart;
9142 
9143   ierr = PetscSFBcastBegin(sfProcess, depthType, depthSizeOld, rdepthSizeOld);CHKERRQ(ierr);
9144   ierr = PetscSFBcastEnd(sfProcess, depthType, depthSizeOld, rdepthSizeOld);CHKERRQ(ierr);
9145   for (n = 0; n < numNeighbors; ++n) {
9146     ierr = GetDepthStart_Private(depth, &rdepthSizeOld[n*(depth+1)], &rcStart[n], &rfStart[n], &reStart[n], &rvStart[n]);CHKERRQ(ierr);
9147     rdepthMaxOld[n*(depth+1)+depth]   = rdepthMaxOld[n*(depth+1)+depth]   < 0 ? rdepthSizeOld[n*(depth+1)+depth]  +rcStart[n]: rdepthMaxOld[n*(depth+1)+depth];
9148     rdepthMaxOld[n*(depth+1)+depth-1] = rdepthMaxOld[n*(depth+1)+depth-1] < 0 ? rdepthSizeOld[n*(depth+1)+depth-1]+rfStart[n]: rdepthMaxOld[n*(depth+1)+depth-1];
9149     rdepthMaxOld[n*(depth+1)+1]       = rdepthMaxOld[n*(depth+1)+1]       < 0 ? rdepthSizeOld[n*(depth+1)+1]      +reStart[n]: rdepthMaxOld[n*(depth+1)+1];
9150   }
9151   ierr = MPI_Type_free(&depthType);CHKERRQ(ierr);
9152   ierr = PetscSFDestroy(&sfProcess);CHKERRQ(ierr);
9153   /* Calculate new point SF */
9154   ierr = PetscMalloc1(numLeavesNew, &localPointsNew);CHKERRQ(ierr);
9155   ierr = PetscMalloc1(numLeavesNew, &remotePointsNew);CHKERRQ(ierr);
9156   ierr = ISGetIndices(processRanks, &neighbors);CHKERRQ(ierr);
9157   for (l = 0, m = 0; l < numLeaves; ++l) {
9158     PetscInt    p     = localPoints[l];
9159     PetscInt    rp    = remotePoints[l].index, n;
9160     PetscMPIInt rrank = remotePoints[l].rank;
9161 
9162     ierr = PetscFindInt(rrank, numNeighbors, neighbors, &n);CHKERRQ(ierr);
9163     if (n < 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Could not locate remote rank %D", rrank);
9164     switch (refiner) {
9165     case REFINER_SIMPLEX_1D:
9166       if ((p >= vStart) && (p < vEnd)) {
9167         /* Old vertices stay the same */
9168         localPointsNew[m]        = vStartNew     + (p  - vStart);
9169         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
9170         remotePointsNew[m].rank  = rrank;
9171         ++m;
9172       } else if ((p >= cStart) && (p < cMax)) {
9173         /* Old interior cells add new cells and vertex */
9174         for (r = 0; r < 2; ++r, ++m) {
9175           localPointsNew[m]        = cStartNew     + (p  - cStart)*2     + r;
9176           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*2 + r;
9177           remotePointsNew[m].rank  = rrank;
9178         }
9179         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - cStart);
9180         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - rcStart[n]);
9181         remotePointsNew[m].rank  = rrank;
9182         ++m;
9183       }
9184       break;
9185     case REFINER_SIMPLEX_2D:
9186     case REFINER_HYBRID_SIMPLEX_2D:
9187       if ((p >= vStart) && (p < vEnd)) {
9188         /* Old vertices stay the same */
9189         localPointsNew[m]        = vStartNew     + (p  - vStart);
9190         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
9191         remotePointsNew[m].rank  = rrank;
9192         ++m;
9193       } else if ((p >= fStart) && (p < fMax)) {
9194         /* Old interior faces add new faces and vertex */
9195         for (r = 0; r < 2; ++r, ++m) {
9196           localPointsNew[m]        = fStartNew     + (p  - fStart)*2     + r;
9197           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*2 + r;
9198           remotePointsNew[m].rank  = rrank;
9199         }
9200         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - fStart);
9201         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - rfStart[n]);
9202         remotePointsNew[m].rank  = rrank;
9203         ++m;
9204       } else if ((p >= fMax) && (p < fEnd)) {
9205         /* Old hybrid faces stay the same */
9206         localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (p  - fMax);
9207         remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*2 + (rp - rdepthMaxOld[n*(depth+1)+depth-1]);
9208         remotePointsNew[m].rank  = rrank;
9209         ++m;
9210       } else if ((p >= cStart) && (p < cMax)) {
9211         /* Old interior cells add new cells and interior faces */
9212         for (r = 0; r < 4; ++r, ++m) {
9213           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
9214           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
9215           remotePointsNew[m].rank  = rrank;
9216         }
9217         for (r = 0; r < 3; ++r, ++m) {
9218           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (p  - cStart)*3     + r;
9219           remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*2 + (rp - rcStart[n])*3 + r;
9220           remotePointsNew[m].rank  = rrank;
9221         }
9222       } else if ((p >= cMax) && (p < cEnd)) {
9223         /* Old hybrid cells add new cells and hybrid face */
9224         for (r = 0; r < 2; ++r, ++m) {
9225           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
9226           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
9227           remotePointsNew[m].rank  = rrank;
9228         }
9229         localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (cMax                            - cStart)*3     + (p  - cMax);
9230         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]);
9231         remotePointsNew[m].rank  = rrank;
9232         ++m;
9233       }
9234       break;
9235     case REFINER_HYBRID_SIMPLEX_TO_HEX_2D:
9236     case REFINER_SIMPLEX_TO_HEX_2D:
9237       if ((p >= vStart) && (p < vEnd)) {
9238         /* Old vertices stay the same */
9239         localPointsNew[m]        = vStartNew     + (p  - vStart);
9240         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
9241         remotePointsNew[m].rank  = rrank;
9242         ++m;
9243       } else if ((p >= fStart) && (p < fEnd)) {
9244         /* Old interior faces add new faces and vertex */
9245         for (r = 0; r < 2; ++r, ++m) {
9246           localPointsNew[m]        = fStartNew     + (p  - fStart)*2     + r;
9247           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*2 + r;
9248           remotePointsNew[m].rank  = rrank;
9249         }
9250         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - fStart);
9251         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - rfStart[n]);
9252         remotePointsNew[m].rank  = rrank;
9253         ++m;
9254       } else if ((p >= cStart) && (p < cMax)) {
9255         /* Old interior cells add new cells, interior faces, and a vertex */
9256         for (r = 0; r < 3; ++r, ++m) {
9257           localPointsNew[m]        = cStartNew     + (p  - cStart)*3     + r;
9258           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*3 + r;
9259           remotePointsNew[m].rank  = rrank;
9260         }
9261         for (r = 0; r < 3; ++r, ++m) {
9262           localPointsNew[m]        = fStartNew     + (fEnd - fStart)*2                    + (p  - cStart)*3     + r;
9263           remotePointsNew[m].index = rfStartNew[n] + rdepthSizeOld[n*(depth+1)+depth-1]*2 + (rp - rcStart[n])*3 + r;
9264           remotePointsNew[m].rank  = rrank;
9265         }
9266         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (fEnd - fStart)                    + (p  - cStart);
9267         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + rdepthSizeOld[n*(depth+1)+depth-1] + (rp - rcStart[n]);
9268         remotePointsNew[m].rank  = rrank;
9269         ++m;
9270       } else if ((p >= cMax) && (p < cEnd)) {
9271         /* Old interior hybrid cells add new cells, interior faces, and a vertex */
9272         for (r = 0; r < 4; ++r, ++m) {
9273           localPointsNew[m]        = cStartNew     + (cMax  - cStart)*3                               + (p  - cMax)*4 + r;
9274           remotePointsNew[m].index = rcStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth] - rcStart[n])*3 + (rp - rdepthMaxOld[n*(depth+1)+depth])*4 + r;
9275           remotePointsNew[m].rank  = rrank;
9276         }
9277         for (r = 0; r < 4; ++r, ++m) {
9278           localPointsNew[m]        = fStartNew     + (fEnd - fStart)*2                    + (cMax  - cStart)*3                               + (p - cMax)*4 + r;
9279           remotePointsNew[m].index = rfStartNew[n] + rdepthSizeOld[n*(depth+1)+depth-1]*2 + (rdepthMaxOld[n*(depth+1)+depth] - rcStart[n])*3 + (rp - rdepthMaxOld[n*(depth+1)+depth])*4 + r;
9280           remotePointsNew[m].rank  = rrank;
9281         }
9282         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (fEnd - fStart)                    + (p  - cStart);
9283         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + rdepthSizeOld[n*(depth+1)+depth-1] + (rp - rcStart[n]);
9284         remotePointsNew[m].rank  = rrank;
9285         ++m;
9286       }
9287       break;
9288     case REFINER_HEX_2D:
9289     case REFINER_HYBRID_HEX_2D:
9290       if ((p >= vStart) && (p < vEnd)) {
9291         /* Old vertices stay the same */
9292         localPointsNew[m]        = vStartNew     + (p  - vStart);
9293         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
9294         remotePointsNew[m].rank  = rrank;
9295         ++m;
9296       } else if ((p >= fStart) && (p < fMax)) {
9297         /* Old interior faces add new faces and vertex */
9298         for (r = 0; r < 2; ++r, ++m) {
9299           localPointsNew[m]        = fStartNew     + (p  - fStart)*2     + r;
9300           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*2 + r;
9301           remotePointsNew[m].rank  = rrank;
9302         }
9303         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - fStart);
9304         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - rfStart[n]);
9305         remotePointsNew[m].rank  = rrank;
9306         ++m;
9307       } else if ((p >= fMax) && (p < fEnd)) {
9308         /* Old hybrid faces stay the same */
9309         localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (p  - fMax);
9310         remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*2 + (rp - rdepthMaxOld[n*(depth+1)+depth-1]);
9311         remotePointsNew[m].rank  = rrank;
9312         ++m;
9313       } else if ((p >= cStart) && (p < cMax)) {
9314         /* Old interior cells add new cells, interior faces, and vertex */
9315         for (r = 0; r < 4; ++r, ++m) {
9316           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
9317           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
9318           remotePointsNew[m].rank  = rrank;
9319         }
9320         for (r = 0; r < 4; ++r, ++m) {
9321           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (p  - cStart)*4     + r;
9322           remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*2 + (rp - rcStart[n])*4 + r;
9323           remotePointsNew[m].rank  = rrank;
9324         }
9325         localPointsNew[m]        = vStartNew     + (vEnd - vStart)               + (fMax                              - fStart)     + (p  - cStart);
9326         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0]  + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n]) + (rp - rcStart[n]);
9327         remotePointsNew[m].rank  = rrank;
9328         ++m;
9329       } else if ((p >= cStart) && (p < cMax)) {
9330         /* Old hybrid cells add new cells and hybrid face */
9331         for (r = 0; r < 2; ++r, ++m) {
9332           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r; /* TODO: is this a bug? */
9333           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r; /* TODO: is this a bug? */
9334           remotePointsNew[m].rank  = rrank;
9335         }
9336         localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (cMax                            - cStart)*4     + (p  - cMax);
9337         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]);
9338         remotePointsNew[m].rank  = rrank;
9339         ++m;
9340       }
9341       break;
9342     case REFINER_SIMPLEX_3D:
9343     case REFINER_HYBRID_SIMPLEX_3D:
9344       if ((p >= vStart) && (p < vEnd)) {
9345         /* Interior vertices stay the same */
9346         localPointsNew[m]        = vStartNew     + (p  - vStart);
9347         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
9348         remotePointsNew[m].rank  = rrank;
9349         ++m;
9350       } else if ((p >= eStart) && (p < eMax)) {
9351         /* Interior edges add new edges and vertex */
9352         for (r = 0; r < 2; ++r, ++m) {
9353           localPointsNew[m]        = eStartNew     + (p  - eStart)*2     + r;
9354           remotePointsNew[m].index = reStartNew[n] + (rp - reStart[n])*2 + r;
9355           remotePointsNew[m].rank  = rrank;
9356         }
9357         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - eStart);
9358         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - reStart[n]);
9359         remotePointsNew[m].rank  = rrank;
9360         ++m;
9361       } else if ((p >= eMax) && (p < eEnd)) {
9362         /* Hybrid edges stay the same */
9363         localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (fMax                              - fStart)*3     + (cMax                            - cStart)     + (p  - eMax);
9364         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)+1]);
9365         remotePointsNew[m].rank  = rrank;
9366         ++m;
9367       } else if ((p >= fStart) && (p < fMax)) {
9368         /* Interior faces add new faces and edges */
9369         for (r = 0; r < 4; ++r, ++m) {
9370           localPointsNew[m]        = fStartNew     + (p  - fStart)*4     + r;
9371           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*4 + r;
9372           remotePointsNew[m].rank  = rrank;
9373         }
9374         for (r = 0; r < 3; ++r, ++m) {
9375           localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (p  - fStart)*3     + r;
9376           remotePointsNew[m].index = reStartNew[n] + (rdepthMaxOld[n*(depth+1)+1] - reStart[n])*2 + (rp - rfStart[n])*3 + r;
9377           remotePointsNew[m].rank  = rrank;
9378         }
9379       } else if ((p >= fMax) && (p < fEnd)) {
9380         /* Hybrid faces add new faces and edges */
9381         for (r = 0; r < 2; ++r, ++m) {
9382           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*4     + (cMax                            - cStart)*8     + (p  - fMax)*2                              + r;
9383           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;
9384           remotePointsNew[m].rank  = rrank;
9385         }
9386         localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (fMax                              - fStart)*3     + (cMax                            - cStart)     + (eEnd                                    - eMax)                        + (p  - fMax);
9387         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]) + (rdepthSizeOld[n*(depth+1)+1]+reStart[n] - rdepthMaxOld[n*(depth+1)+1]) + (rp - rdepthMaxOld[n*(depth+1)+depth-1]);
9388         remotePointsNew[m].rank  = rrank;
9389         ++m;
9390       } else if ((p >= cStart) && (p < cMax)) {
9391         /* Interior cells add new cells, faces, and edges */
9392         for (r = 0; r < 8; ++r, ++m) {
9393           localPointsNew[m]        = cStartNew     + (p  - cStart)*8     + r;
9394           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*8 + r;
9395           remotePointsNew[m].rank  = rrank;
9396         }
9397         for (r = 0; r < 8; ++r, ++m) {
9398           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*4     + (p  - cStart)*8     + r;
9399           remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*4 + (rp - rcStart[n])*8 + r;
9400           remotePointsNew[m].rank  = rrank;
9401         }
9402         localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (fMax                              - fStart)*3     + (p  - cStart)*1     + 0;
9403         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 + 0;
9404         remotePointsNew[m].rank  = rrank;
9405         ++m;
9406       } else if ((p >= cMax) && (p < cEnd)) {
9407         /* Hybrid cells add new cells and faces */
9408         for (r = 0; r < 4; ++r, ++m) {
9409           localPointsNew[m]        = cStartNew     + (cMax                            - cStart)*8     + (p  - cMax)*4                            + r;
9410           remotePointsNew[m].index = rcStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth] - rcStart[n])*8 + (rp - rdepthMaxOld[n*(depth+1)+depth])*4 + r;
9411           remotePointsNew[m].rank  = rrank;
9412         }
9413         for (r = 0; r < 3; ++r, ++m) {
9414           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*4     + (cMax                            - cStart)*8     + (fEnd                                          - fMax)*2                              + (p  - cMax)*3                            + r;
9415           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;
9416           remotePointsNew[m].rank  = rrank;
9417         }
9418       }
9419       break;
9420     case REFINER_HYBRID_SIMPLEX_TO_HEX_3D:
9421     case REFINER_SIMPLEX_TO_HEX_3D:
9422       if ((p >= vStart) && (p < vEnd)) {
9423         /* Interior vertices stay the same */
9424         localPointsNew[m]        = vStartNew     + (p  - vStart);
9425         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
9426         remotePointsNew[m].rank  = rrank;
9427         ++m;
9428       } else if ((p >= eStart) && (p < eMax)) {
9429         /* Interior edges add new edges and vertex */
9430         for (r = 0; r < 2; ++r, ++m) {
9431           localPointsNew[m]        = eStartNew     + (p  - eStart)*2     + r;
9432           remotePointsNew[m].index = reStartNew[n] + (rp - reStart[n])*2 + r;
9433           remotePointsNew[m].rank  = rrank;
9434         }
9435         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - eStart);
9436         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - reStart[n]);
9437         remotePointsNew[m].rank  = rrank;
9438         ++m;
9439       } else if ((p >= eMax) && (p < eEnd)) {
9440         /* Hybrid edges stay the same */
9441         localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (fMax                              - fStart)*3     + (cMax                            - cStart)*4     + (p  - eMax);
9442         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])*4 + (rp - rdepthMaxOld[n*(depth+1)+1]);
9443         remotePointsNew[m].rank  = rrank;
9444         ++m;
9445       } else if ((p >= fStart) && (p < fMax)) {
9446         /* Interior faces add new faces, edges and a vertex */
9447         for (r = 0; r < 3; ++r, ++m) {
9448           localPointsNew[m]        = fStartNew     + (p  - fStart)*3     + r;
9449           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*3 + r;
9450           remotePointsNew[m].rank  = rrank;
9451         }
9452         for (r = 0; r < 3; ++r, ++m) {
9453           localPointsNew[m]        = eStartNew     + (eMax - eStart)*2                            + (p  - fStart)*3     + r;
9454           remotePointsNew[m].index = reStartNew[n] + (rdepthMaxOld[n*(depth+1)+1] - reStart[n])*2 + (rp - rfStart[n])*3 + r;
9455           remotePointsNew[m].rank  = rrank;
9456         }
9457         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (eMax - eStart)                            + (p - fStart);
9458         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rdepthMaxOld[n*(depth+1)+1] - reStart[n]) + (rp - rfStart[n]);
9459         remotePointsNew[m].rank  = rrank;
9460         ++m;
9461       } else if ((p >= fMax) && (p < fEnd)) {
9462         /* Interior hybrid faces add new faces and an edge */
9463         for (r = 0; r < 2; ++r, ++m) {
9464           localPointsNew[m]        = fStartNew     + (fMax - fStart)*3                                 + (cMax - cStart)*6                                + (p  - fMax)*2 + r;
9465           remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1]- rfStart[n])*3 + (rdepthMaxOld[n*(depth+1)+depth] - rcStart[n])*6 + (rp - rdepthMaxOld[n*(depth+1)+depth-1])*2 + r;
9466           remotePointsNew[m].rank  = rrank;
9467         }
9468         localPointsNew[m]        = eStartNew     + (eMax - eStart)*2                            + (fMax - fStart)*3                                 + (cMax - cStart)*4                                + (eEnd - eMax)                                                           + (p  - fMax);
9469         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])*4 + (rdepthSizeOld[n*(depth+1)+1]+reStart[n] - rdepthMaxOld[n*(depth+1)+1]) + (rp - rdepthMaxOld[n*(depth+1)+depth-1]);
9470         remotePointsNew[m].rank  = rrank;
9471         ++m;
9472       } else if ((p >= cStart) && (p < cMax)) {
9473         /* Interior cells add new cells, faces, edges, and a vertex */
9474         for (r = 0; r < 4; ++r, ++m) {
9475           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
9476           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
9477           remotePointsNew[m].rank  = rrank;
9478         }
9479         for (r = 0; r < 6; ++r, ++m) {
9480           localPointsNew[m]        = fStartNew     + (fMax - fStart)*3                                 + (p  - cStart)*6     + r;
9481           remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1]- rfStart[n])*3 + (rp - rcStart[n])*6 + r;
9482           remotePointsNew[m].rank  = rrank;
9483         }
9484         for (r = 0; r < 4; ++r, ++m) {
9485           localPointsNew[m]        = eStartNew     + (eMax - eStart)*2                           + (fMax - fStart)*3                                 + (p  - cStart)*4 + r;
9486           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])*4 + r;
9487           remotePointsNew[m].rank  = rrank;
9488         }
9489         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (eMax - eStart)                           + (fMax - fStart)                                 + (p  - cStart);
9490         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rdepthMaxOld[n*(depth+1)+1]- reStart[n]) + (rdepthMaxOld[n*(depth+1)+depth-1]- rfStart[n]) + (rp - rcStart[n]);
9491         remotePointsNew[m].rank  = rrank;
9492         ++m;
9493       } else if ((p >= cMax) && (p < cEnd)) {
9494         /* Interior hybrid cells add new cells, faces and an edge */
9495         for (r = 0; r < 3; ++r, ++m) {
9496           localPointsNew[m]        = cStartNew     + (cMax                            - cStart)*4     + (p  - cMax)*3                            + r;
9497           remotePointsNew[m].index = rcStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth] - rcStart[n])*4 + (rp - rdepthMaxOld[n*(depth+1)+depth])*3 + r;
9498           remotePointsNew[m].rank  = rrank;
9499         }
9500         for (r = 0; r < 3; ++r, ++m) {
9501           localPointsNew[m]        = fStartNew     + (fMax - fStart)*3                                 + (cMax - cStart)*6                                + (fEnd  - fMax)*2                                                                      + (p  - cMax)*3 + r;
9502           remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1]- rfStart[n])*3 + (rdepthMaxOld[n*(depth+1)+depth] - rcStart[n])*6 + (rdepthSizeOld[n*(depth+1)+depth-1]+rfStart[n] - rdepthMaxOld[n*(depth+1)+depth-1])*2 + (rp - rdepthMaxOld[n*(depth+1)+depth])*3 + r;
9503           remotePointsNew[m].rank  = rrank;
9504         }
9505         localPointsNew[m]        = eStartNew     + (eMax - eStart)*2                           + (fMax - fStart)*3                                 + (cMax - cStart)*4                                + (eEnd  - eMax)                                                          + (fEnd  - fMax)                                                                      + (p  - cMax);
9506         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])*4 + (rdepthSizeOld[n*(depth+1)+1]+reStart[n] - rdepthMaxOld[n*(depth+1)+1]) + (rdepthSizeOld[n*(depth+1)+depth-1]+rfStart[n] - rdepthMaxOld[n*(depth+1)+depth-1]) + (rp - rdepthMaxOld[n*(depth+1)+depth]);
9507         remotePointsNew[m].rank  = rrank;
9508         ++m;
9509       }
9510       break;
9511     case REFINER_HEX_3D:
9512     case REFINER_HYBRID_HEX_3D:
9513       if ((p >= vStart) && (p < vEnd)) {
9514         /* Interior vertices stay the same */
9515         localPointsNew[m]        = vStartNew     + (p  - vStart);
9516         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
9517         remotePointsNew[m].rank  = rrank;
9518         ++m;
9519       } else if ((p >= eStart) && (p < eMax)) {
9520         /* Interior edges add new edges and vertex */
9521         for (r = 0; r < 2; ++r, ++m) {
9522           localPointsNew[m]        = eStartNew     + (p  - eStart)*2     + r;
9523           remotePointsNew[m].index = reStartNew[n] + (rp - reStart[n])*2 + r;
9524           remotePointsNew[m].rank  = rrank;
9525         }
9526         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - eStart);
9527         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - reStart[n]);
9528         remotePointsNew[m].rank  = rrank;
9529         ++m;
9530       } else if ((p >= eMax) && (p < eEnd)) {
9531         /* Hybrid edges stay the same */
9532         localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (fMax                              - fStart)*4     + (cMax                            - cStart)*6     + (p  - eMax);
9533         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 + (rp - rdepthMaxOld[n*(depth+1)+1]);
9534         remotePointsNew[m].rank  = rrank;
9535         ++m;
9536       } else if ((p >= fStart) && (p < fMax)) {
9537         /* Interior faces add new faces, edges, and vertex */
9538         for (r = 0; r < 4; ++r, ++m) {
9539           localPointsNew[m]        = fStartNew     + (p  - fStart)*4     + r;
9540           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*4 + r;
9541           remotePointsNew[m].rank  = rrank;
9542         }
9543         for (r = 0; r < 4; ++r, ++m) {
9544           localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (p  - fStart)*4     + r;
9545           remotePointsNew[m].index = reStartNew[n] + (rdepthMaxOld[n*(depth+1)+1] - reStart[n])*2 + (rp - rfStart[n])*4 + r;
9546           remotePointsNew[m].rank  = rrank;
9547         }
9548         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (eMax                        - eStart)     + (p  - fStart);
9549         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rdepthMaxOld[n*(depth+1)+1] - reStart[n]) + (rp - rfStart[n]);
9550         remotePointsNew[m].rank  = rrank;
9551         ++m;
9552       } else if ((p >= fMax) && (p < fEnd)) {
9553         /* Hybrid faces add new faces and edges */
9554         for (r = 0; r < 2; ++r, ++m) {
9555           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*4     + (cMax                            - cStart)*12     + (p  - fMax)*2                              + r;
9556           remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*4 + (rdepthMaxOld[n*(depth+1)+depth] - rcStart[n])*12 + (rp - rdepthMaxOld[n*(depth+1)+depth-1])*2 + r;
9557           remotePointsNew[m].rank  = rrank;
9558         }
9559         localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (fMax                              - fStart)*4     + (cMax                            - cStart)*6     + (eEnd                                    - eMax)                        + (p  - fMax);
9560         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)+1]+reStart[n] - rdepthMaxOld[n*(depth+1)+1]) + (rp - rdepthMaxOld[n*(depth+1)+depth-1]);
9561         remotePointsNew[m].rank  = rrank;
9562         ++m;
9563       } else if ((p >= cStart) && (p < cMax)) {
9564         /* Interior cells add new cells, faces, edges, and vertex */
9565         for (r = 0; r < 8; ++r, ++m) {
9566           localPointsNew[m]        = cStartNew     + (p  - cStart)*8     + r;
9567           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*8 + r;
9568           remotePointsNew[m].rank  = rrank;
9569         }
9570         for (r = 0; r < 12; ++r, ++m) {
9571           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*4     + (p  - cStart)*12     + r;
9572           remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*4 + (rp - rcStart[n])*12 + r;
9573           remotePointsNew[m].rank  = rrank;
9574         }
9575         for (r = 0; r < 6; ++r, ++m) {
9576           localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (fMax                              - fStart)*4     + (p  - cStart)*6     + r;
9577           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;
9578           remotePointsNew[m].rank  = rrank;
9579         }
9580         for (r = 0; r < 1; ++r, ++m) {
9581           localPointsNew[m]        = vStartNew     + (eMax                        - eStart)     + (fMax                              - fStart)     + (p  - cStart)     + r;
9582           remotePointsNew[m].index = rvStartNew[n] + (rdepthMaxOld[n*(depth+1)+1] - reStart[n]) + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n]) + (rp - rcStart[n]) + r;
9583           remotePointsNew[m].rank  = rrank;
9584         }
9585       } else if ((p >= cMax) && (p < cEnd)) {
9586         /* Hybrid cells add new cells, faces, and edges */
9587         for (r = 0; r < 4; ++r, ++m) {
9588           localPointsNew[m]        = cStartNew     + (cMax                            - cStart)*8     + (p  - cMax)*4                            + r;
9589           remotePointsNew[m].index = rcStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth] - rcStart[n])*8 + (rp - rdepthMaxOld[n*(depth+1)+depth])*4 + r;
9590           remotePointsNew[m].rank  = rrank;
9591         }
9592         for (r = 0; r < 4; ++r, ++m) {
9593           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*4     + (cMax                            - cStart)*12     + (fEnd                                          - fMax)*2                              + (p  - cMax)*4                            + r;
9594           remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*4 + (rdepthMaxOld[n*(depth+1)+depth] - rcStart[n])*12 + (rdepthSizeOld[n*(depth+1)+depth-1]+rfStart[n] - rdepthMaxOld[n*(depth+1)+depth-1])*2 + (rp - rdepthMaxOld[n*(depth+1)+depth])*4 + r;
9595           remotePointsNew[m].rank  = rrank;
9596         }
9597         localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (fMax                              - fStart)*4     + (cMax                            - cStart)*6     + (eEnd                                    - eMax)                        + (fEnd                                          - fMax)                              + (p  - cMax);
9598         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)+1]+reStart[n] - rdepthMaxOld[n*(depth+1)+1]) + (rdepthSizeOld[n*(depth+1)+depth-1]+rfStart[n] - rdepthMaxOld[n*(depth+1)+depth-1]) + (rp - rdepthMaxOld[n*(depth+1)+depth]);
9599         remotePointsNew[m].rank  = rrank;
9600         ++m;
9601       }
9602       break;
9603     default:
9604       SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %s", CellRefiners[refiner]);
9605     }
9606   }
9607   if (m != numLeavesNew) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Number of leaf point %D should be %D", m, numLeavesNew);
9608   ierr = ISRestoreIndices(processRanks, &neighbors);CHKERRQ(ierr);
9609   ierr = ISDestroy(&processRanks);CHKERRQ(ierr);
9610   {
9611     PetscSFNode *rp, *rtmp;
9612     PetscInt    *lp, *idx, *ltmp, i;
9613 
9614     /* SF needs sorted leaves to correct calculate Gather */
9615     ierr = PetscMalloc1(numLeavesNew,&idx);CHKERRQ(ierr);
9616     ierr = PetscMalloc1(numLeavesNew, &lp);CHKERRQ(ierr);
9617     ierr = PetscMalloc1(numLeavesNew, &rp);CHKERRQ(ierr);
9618     for (i = 0; i < numLeavesNew; ++i) {
9619       if ((localPointsNew[i] < pStartNew) || (localPointsNew[i] >= pEndNew)) SETERRQ4(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Local SF point %D (%D) not in [%D, %D)", localPointsNew[i], i, pStartNew, pEndNew);
9620       idx[i] = i;
9621     }
9622     ierr = PetscSortIntWithPermutation(numLeavesNew, localPointsNew, idx);CHKERRQ(ierr);
9623     for (i = 0; i < numLeavesNew; ++i) {
9624       lp[i] = localPointsNew[idx[i]];
9625       rp[i] = remotePointsNew[idx[i]];
9626     }
9627     ltmp            = localPointsNew;
9628     localPointsNew  = lp;
9629     rtmp            = remotePointsNew;
9630     remotePointsNew = rp;
9631     ierr = PetscFree(idx);CHKERRQ(ierr);
9632     ierr = PetscFree(ltmp);CHKERRQ(ierr);
9633     ierr = PetscFree(rtmp);CHKERRQ(ierr);
9634   }
9635   ierr = PetscSFSetGraph(sfNew, pEndNew-pStartNew, numLeavesNew, localPointsNew, PETSC_OWN_POINTER, remotePointsNew, PETSC_OWN_POINTER);CHKERRQ(ierr);
9636   ierr = PetscFree5(rdepthSize,rvStartNew,reStartNew,rfStartNew,rcStartNew);CHKERRQ(ierr);
9637   ierr = PetscFree7(depthSizeOld,rdepthSizeOld,rdepthMaxOld,rvStart,reStart,rfStart,rcStart);CHKERRQ(ierr);
9638   PetscFunctionReturn(0);
9639 }
9640 
9641 static PetscErrorCode CellRefinerCreateLabels(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
9642 {
9643   PetscInt       numLabels, l;
9644   PetscInt       depth, newp, cStart, cEnd, cMax, vStart, vEnd, vMax, fStart, fEnd, fMax, eStart, eEnd, eMax, r;
9645   PetscInt       cStartNew = 0, vStartNew = 0, fStartNew = 0, eStartNew = 0;
9646   PetscErrorCode ierr;
9647 
9648   PetscFunctionBegin;
9649   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
9650   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
9651   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
9652   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
9653   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
9654   if (refiner) {ierr = GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);CHKERRQ(ierr);}
9655   ierr = DMGetNumLabels(dm, &numLabels);CHKERRQ(ierr);
9656   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
9657   switch (refiner) {
9658   case REFINER_NOOP:
9659   case REFINER_SIMPLEX_1D:
9660   case REFINER_SIMPLEX_2D:
9661   case REFINER_SIMPLEX_TO_HEX_2D:
9662   case REFINER_HEX_2D:
9663   case REFINER_SIMPLEX_3D:
9664   case REFINER_HEX_3D:
9665   case REFINER_SIMPLEX_TO_HEX_3D:
9666     break;
9667   case REFINER_HYBRID_SIMPLEX_TO_HEX_3D:
9668   case REFINER_HYBRID_SIMPLEX_3D:
9669   case REFINER_HYBRID_HEX_3D:
9670     if (eMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No edge maximum specified in hybrid mesh");
9671   case REFINER_HYBRID_SIMPLEX_2D:
9672   case REFINER_HYBRID_HEX_2D:
9673     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
9674   case REFINER_HYBRID_SIMPLEX_TO_HEX_2D:
9675     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
9676     break;
9677   default:
9678     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %s", CellRefiners[refiner]);
9679   }
9680   cMax = cMax < 0 ? cEnd : cMax;
9681   fMax = fMax < 0 ? fEnd : fMax;
9682   eMax = eMax < 0 ? eEnd : eMax;
9683   for (l = 0; l < numLabels; ++l) {
9684     DMLabel         label, labelNew;
9685     const char     *lname;
9686     PetscBool       isDepth;
9687     IS              valueIS;
9688     const PetscInt *values;
9689     PetscInt        defVal;
9690     PetscInt        numValues, val;
9691 
9692     ierr = DMGetLabelName(dm, l, &lname);CHKERRQ(ierr);
9693     ierr = PetscStrcmp(lname, "depth", &isDepth);CHKERRQ(ierr);
9694     if (isDepth) continue;
9695     ierr = DMCreateLabel(rdm, lname);CHKERRQ(ierr);
9696     ierr = DMGetLabel(dm, lname, &label);CHKERRQ(ierr);
9697     ierr = DMGetLabel(rdm, lname, &labelNew);CHKERRQ(ierr);
9698     ierr = DMLabelGetDefaultValue(label,&defVal);CHKERRQ(ierr);
9699     ierr = DMLabelSetDefaultValue(labelNew,defVal);CHKERRQ(ierr);
9700     ierr = DMLabelGetValueIS(label, &valueIS);CHKERRQ(ierr);
9701     ierr = ISGetLocalSize(valueIS, &numValues);CHKERRQ(ierr);
9702     ierr = ISGetIndices(valueIS, &values);CHKERRQ(ierr);
9703     for (val = 0; val < numValues; ++val) {
9704       IS              pointIS;
9705       const PetscInt *points;
9706       PetscInt        numPoints, n;
9707 
9708       ierr = DMLabelGetStratumIS(label, values[val], &pointIS);CHKERRQ(ierr);
9709       ierr = ISGetLocalSize(pointIS, &numPoints);CHKERRQ(ierr);
9710       ierr = ISGetIndices(pointIS, &points);CHKERRQ(ierr);
9711       /* Ensure refined label is created with same number of strata as
9712        * original (even if no entries here). */
9713       ierr = DMLabelAddStratum(labelNew, values[val]);CHKERRQ(ierr);
9714       for (n = 0; n < numPoints; ++n) {
9715         const PetscInt p = points[n];
9716         switch (refiner) {
9717         case REFINER_SIMPLEX_1D:
9718           if ((p >= vStart) && (p < vEnd)) {
9719             /* Old vertices stay the same */
9720             newp = vStartNew + (p - vStart);
9721             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9722           } else if ((p >= cStart) && (p < cEnd)) {
9723             /* Old cells add new cells and vertex */
9724             newp = vStartNew + (vEnd - vStart) + (p - cStart);
9725             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9726             for (r = 0; r < 2; ++r) {
9727               newp = cStartNew + (p - cStart)*2 + r;
9728               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9729             }
9730           }
9731           break;
9732         case REFINER_SIMPLEX_2D:
9733           if ((p >= vStart) && (p < vEnd)) {
9734             /* Old vertices stay the same */
9735             newp = vStartNew + (p - vStart);
9736             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9737           } else if ((p >= fStart) && (p < fEnd)) {
9738             /* Old faces add new faces and vertex */
9739             newp = vStartNew + (vEnd - vStart) + (p - fStart);
9740             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9741             for (r = 0; r < 2; ++r) {
9742               newp = fStartNew + (p - fStart)*2 + r;
9743               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9744             }
9745           } else if ((p >= cStart) && (p < cEnd)) {
9746             /* Old cells add new cells and interior faces */
9747             for (r = 0; r < 4; ++r) {
9748               newp = cStartNew + (p - cStart)*4 + r;
9749               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9750             }
9751             for (r = 0; r < 3; ++r) {
9752               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*3 + r;
9753               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9754             }
9755           }
9756           break;
9757         case REFINER_HYBRID_SIMPLEX_TO_HEX_2D:
9758         case REFINER_SIMPLEX_TO_HEX_2D:
9759           if ((p >= vStart) && (p < vEnd)) {
9760             /* Old vertices stay the same */
9761             newp = vStartNew + (p - vStart);
9762             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9763           } else if ((p >= fStart) && (p < fEnd)) {
9764             /* Old faces add new faces and vertex */
9765             newp = vStartNew + (vEnd - vStart) + (p - fStart);
9766             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9767             for (r = 0; r < 2; ++r) {
9768               newp = fStartNew + (p - fStart)*2 + r;
9769               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9770             }
9771           } else if ((p >= cStart) && (p < cMax)) {
9772             /* Old cells add new cells, interior faces, and a vertex */
9773             for (r = 0; r < 3; ++r) {
9774               newp = cStartNew + (p - cStart)*3 + r;
9775               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9776             }
9777             for (r = 0; r < 3; ++r) {
9778               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*3 + r;
9779               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9780             }
9781             newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + p;
9782             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9783           } else if ((p >= cMax) && (p < cEnd)) {
9784             /* Old hybrid cells add new cells, interior faces, and a vertex */
9785             for (r = 0; r < 4; ++r) {
9786               newp = cStartNew + (cMax - cStart)*3 + (p - cMax)*4 + r;
9787               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9788             }
9789             for (r = 0; r < 4; ++r) {
9790               newp = fStartNew + (fEnd - fStart)*2 + (cMax - cStart)*3 + (p - cMax)*4 + r;
9791               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9792             }
9793             newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + p;
9794             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9795           }
9796           break;
9797         case REFINER_HEX_2D:
9798           if ((p >= vStart) && (p < vEnd)) {
9799             /* Old vertices stay the same */
9800             newp = vStartNew + (p - vStart);
9801             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9802           } else if ((p >= fStart) && (p < fEnd)) {
9803             /* Old faces add new faces and vertex */
9804             newp = vStartNew + (vEnd - vStart) + (p - fStart);
9805             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9806             for (r = 0; r < 2; ++r) {
9807               newp = fStartNew + (p - fStart)*2 + r;
9808               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9809             }
9810           } else if ((p >= cStart) && (p < cEnd)) {
9811             /* Old cells add new cells and interior faces and vertex */
9812             for (r = 0; r < 4; ++r) {
9813               newp = cStartNew + (p - cStart)*4 + r;
9814               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9815             }
9816             for (r = 0; r < 4; ++r) {
9817               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*4 + r;
9818               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9819             }
9820             newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (p - cStart);
9821             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9822           }
9823           break;
9824         case REFINER_HYBRID_SIMPLEX_2D:
9825           if ((p >= vStart) && (p < vEnd)) {
9826             /* Old vertices stay the same */
9827             newp = vStartNew + (p - vStart);
9828             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9829           } else if ((p >= fStart) && (p < fMax)) {
9830             /* Old interior faces add new faces and vertex */
9831             newp = vStartNew + (vEnd - vStart) + (p - fStart);
9832             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9833             for (r = 0; r < 2; ++r) {
9834               newp = fStartNew + (p - fStart)*2 + r;
9835               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9836             }
9837           } else if ((p >= fMax) && (p < fEnd)) {
9838             /* Old hybrid faces stay the same */
9839             newp = fStartNew + (fMax - fStart)*2 + (p - fMax);
9840             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9841           } else if ((p >= cStart) && (p < cMax)) {
9842             /* Old interior cells add new cells and interior faces */
9843             for (r = 0; r < 4; ++r) {
9844               newp = cStartNew + (p - cStart)*4 + r;
9845               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9846             }
9847             for (r = 0; r < 3; ++r) {
9848               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*3 + r;
9849               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9850             }
9851           } else if ((p >= cMax) && (p < cEnd)) {
9852             /* Old hybrid cells add new cells and hybrid face */
9853             for (r = 0; r < 2; ++r) {
9854               newp = cStartNew + (cMax - cStart)*4 + (p - cMax)*2 + r;
9855               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9856             }
9857             newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (p - cMax);
9858             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9859           }
9860           break;
9861         case REFINER_HYBRID_HEX_2D:
9862           if ((p >= vStart) && (p < vEnd)) {
9863             /* Old vertices stay the same */
9864             newp = vStartNew + (p - vStart);
9865             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9866           } else if ((p >= fStart) && (p < fMax)) {
9867             /* Old interior faces add new faces and vertex */
9868             newp = vStartNew + (vEnd - vStart) + (p - fStart);
9869             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9870             for (r = 0; r < 2; ++r) {
9871               newp = fStartNew + (p - fStart)*2 + r;
9872               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9873             }
9874           } else if ((p >= fMax) && (p < fEnd)) {
9875             /* Old hybrid faces stay the same */
9876             newp = fStartNew + (fMax - fStart)*2 + (p - fMax);
9877             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9878           } else if ((p >= cStart) && (p < cMax)) {
9879             /* Old interior cells add new cells, interior faces, and vertex */
9880             for (r = 0; r < 4; ++r) {
9881               newp = cStartNew + (p - cStart)*4 + r;
9882               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9883             }
9884             for (r = 0; r < 4; ++r) {
9885               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*4 + r;
9886               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9887             }
9888             newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (p - cStart);
9889             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9890           } else if ((p >= cMax) && (p < cEnd)) {
9891             /* Old hybrid cells add new cells and hybrid face */
9892             for (r = 0; r < 2; ++r) {
9893               newp = cStartNew + (cMax - cStart)*4 + (p - cMax)*2 + r;
9894               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9895             }
9896             newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*4 + (p - cMax);
9897             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9898           }
9899           break;
9900         case REFINER_SIMPLEX_3D:
9901           if ((p >= vStart) && (p < vEnd)) {
9902             /* Old vertices stay the same */
9903             newp = vStartNew + (p - vStart);
9904             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9905           } else if ((p >= eStart) && (p < eEnd)) {
9906             /* Old edges add new edges and vertex */
9907             for (r = 0; r < 2; ++r) {
9908               newp = eStartNew + (p - eStart)*2 + r;
9909               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9910             }
9911             newp = vStartNew + (vEnd - vStart) + (p - eStart);
9912             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9913           } else if ((p >= fStart) && (p < fEnd)) {
9914             /* Old faces add new faces and edges */
9915             for (r = 0; r < 4; ++r) {
9916               newp = fStartNew + (p - fStart)*4 + r;
9917               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9918             }
9919             for (r = 0; r < 3; ++r) {
9920               newp = eStartNew + (eEnd - eStart)*2 + (p - fStart)*3 + r;
9921               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9922             }
9923           } else if ((p >= cStart) && (p < cEnd)) {
9924             /* Old cells add new cells and interior faces and edges */
9925             for (r = 0; r < 8; ++r) {
9926               newp = cStartNew + (p - cStart)*8 + r;
9927               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9928             }
9929             for (r = 0; r < 8; ++r) {
9930               newp = fStartNew + (fEnd - fStart)*4 + (p - cStart)*8 + r;
9931               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9932             }
9933             for (r = 0; r < 1; ++r) {
9934               newp = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (p - cStart)*1 + r;
9935               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9936             }
9937           }
9938           break;
9939         case REFINER_HYBRID_SIMPLEX_TO_HEX_3D:
9940         case REFINER_SIMPLEX_TO_HEX_3D:
9941           if ((p >= vStart) && (p < vEnd)) {
9942             /* Old vertices stay the same */
9943             newp = vStartNew + (p - vStart);
9944             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9945           } else if ((p >= eStart) && (p < eMax)) {
9946             /* Interior edges add new edges and vertex */
9947             for (r = 0; r < 2; ++r) {
9948               newp = eStartNew + (p - eStart)*2 + r;
9949               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9950             }
9951             newp = vStartNew + (vEnd - vStart) + (p - eStart);
9952             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9953           } else if ((p >= eMax) && (p < eEnd)) {
9954             /* Hybrid edges stay the same */
9955             newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart)*4 + p - eMax;
9956             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9957           } else if ((p >= fStart) && (p < fMax)) {
9958             /* Old faces add new faces, edges and a vertex */
9959             for (r = 0; r < 3; ++r) {
9960               newp = fStartNew + (p - fStart)*3 + r;
9961               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9962             }
9963             for (r = 0; r < 3; ++r) {
9964               newp = eStartNew + (eMax - eStart)*2 + (p - fStart)*3 + r;
9965               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9966             }
9967           } else if ((p >= fMax) && (p < fEnd)) {
9968             /* Old hybrid faces add new faces and an edge */
9969             for (r = 0; r < 2; ++r) {
9970               newp = fStartNew + (fMax - fStart)*3 + (cMax - cStart)*6 + (p - fMax)*2 + r;
9971               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9972             }
9973             newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart)*4 + (eEnd - eMax) + (p - fMax);
9974             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9975           } else if ((p >= cStart) && (p < cMax)) {
9976             /* Old cells add new cells and interior faces and edges and a vertex */
9977             for (r = 0; r < 4; ++r) {
9978               newp = cStartNew + (p - cStart)*4 + r;
9979               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9980             }
9981             for (r = 0; r < 6; ++r) {
9982               newp = fStartNew + (fMax - fStart)*3 + (p - cStart)*6 + r;
9983               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9984             }
9985             for (r = 0; r < 4; ++r) {
9986               newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (p - cStart)*4 + r;
9987               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9988             }
9989             newp = vStartNew + (vEnd - vStart) + (eMax - eStart) + (fMax - fStart) + p - cStart;
9990             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9991           } else if ((p >= cMax) && (p < cEnd)) {
9992             /* Old hybrid cells add new cells and interior faces and an edge */
9993             for (r = 0; r < 3; ++r) {
9994               newp = cStartNew + (cMax - cStart)*4 + (p - cMax)*3 + r;
9995               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9996             }
9997             for (r = 0; r < 3; ++r) {
9998               newp = fStartNew + (fMax - fStart)*3 + (cMax - cStart)*6 + (fEnd - fMax)*2 + (p - cMax)*3 + r;
9999               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
10000             }
10001             newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart)*4 + (eEnd - eMax) + (fEnd - fMax) + p - cMax;
10002             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
10003           }
10004           break;
10005         case REFINER_HYBRID_SIMPLEX_3D:
10006           if ((p >= vStart) && (p < vEnd)) {
10007             /* Interior vertices stay the same */
10008             newp = vStartNew + (p - vStart);
10009             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
10010           } else if ((p >= eStart) && (p < eMax)) {
10011             /* Interior edges add new edges and vertex */
10012             for (r = 0; r < 2; ++r) {
10013               newp = eStartNew + (p - eStart)*2 + r;
10014               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
10015             }
10016             newp = vStartNew + (vEnd - vStart) + (p - eStart);
10017             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
10018           } else if ((p >= eMax) && (p < eEnd)) {
10019             /* Hybrid edges stay the same */
10020             newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (p - eMax);
10021             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
10022           } else if ((p >= fStart) && (p < fMax)) {
10023             /* Interior faces add new faces and edges */
10024             for (r = 0; r < 4; ++r) {
10025               newp = fStartNew + (p - fStart)*4 + r;
10026               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
10027             }
10028             for (r = 0; r < 3; ++r) {
10029               newp = eStartNew + (eMax - eStart)*2 + (p - fStart)*3 + r;
10030               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
10031             }
10032           } else if ((p >= fMax) && (p < fEnd)) {
10033             /* Hybrid faces add new faces and edges */
10034             for (r = 0; r < 2; ++r) {
10035               newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (p - fMax)*2 + r;
10036               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
10037             }
10038             newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (p - fMax);
10039             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
10040           } else if ((p >= cStart) && (p < cMax)) {
10041             /* Interior cells add new cells, faces, and edges */
10042             for (r = 0; r < 8; ++r) {
10043               newp = cStartNew + (p - cStart)*8 + r;
10044               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
10045             }
10046             for (r = 0; r < 8; ++r) {
10047               newp = fStartNew + (fMax - fStart)*4 + (p - cStart)*8 + r;
10048               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
10049             }
10050             newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (p - cStart);
10051             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
10052           } else if ((p >= cMax) && (p < cEnd)) {
10053             /* Hybrid cells add new cells and faces */
10054             for (r = 0; r < 4; ++r) {
10055               newp = cStartNew + (cMax - cStart)*8 + (p - cMax)*4 + r;
10056               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
10057             }
10058             for (r = 0; r < 3; ++r) {
10059               newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (p - cMax)*3 + r;
10060               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
10061             }
10062           }
10063           break;
10064         case REFINER_HEX_3D:
10065           if ((p >= vStart) && (p < vEnd)) {
10066             /* Old vertices stay the same */
10067             newp = vStartNew + (p - vStart);
10068             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
10069           } else if ((p >= eStart) && (p < eEnd)) {
10070             /* Old edges add new edges and vertex */
10071             for (r = 0; r < 2; ++r) {
10072               newp = eStartNew + (p - eStart)*2 + r;
10073               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
10074             }
10075             newp = vStartNew + (vEnd - vStart) + (p - eStart);
10076             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
10077           } else if ((p >= fStart) && (p < fEnd)) {
10078             /* Old faces add new faces, edges, and vertex */
10079             for (r = 0; r < 4; ++r) {
10080               newp = fStartNew + (p - fStart)*4 + r;
10081               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
10082             }
10083             for (r = 0; r < 4; ++r) {
10084               newp = eStartNew + (eEnd - eStart)*2 + (p - fStart)*4 + r;
10085               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
10086             }
10087             newp = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (p - fStart);
10088             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
10089           } else if ((p >= cStart) && (p < cEnd)) {
10090             /* Old cells add new cells, faces, edges, and vertex */
10091             for (r = 0; r < 8; ++r) {
10092               newp = cStartNew + (p - cStart)*8 + r;
10093               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
10094             }
10095             for (r = 0; r < 12; ++r) {
10096               newp = fStartNew + (fEnd - fStart)*4 + (p - cStart)*12 + r;
10097               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
10098             }
10099             for (r = 0; r < 6; ++r) {
10100               newp = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*4 + (p - cStart)*6 + r;
10101               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
10102             }
10103             newp = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (fEnd - fStart) + (p - cStart);
10104             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
10105           }
10106           break;
10107         case REFINER_HYBRID_HEX_3D:
10108           if ((p >= vStart) && (p < vEnd)) {
10109             /* Interior vertices stay the same */
10110             newp = vStartNew + (p - vStart);
10111             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
10112           } else if ((p >= eStart) && (p < eMax)) {
10113             /* Interior edges add new edges and vertex */
10114             for (r = 0; r < 2; ++r) {
10115               newp = eStartNew + (p - eStart)*2 + r;
10116               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
10117             }
10118             newp = vStartNew + (vEnd - vStart) + (p - eStart);
10119             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
10120           } else if ((p >= eMax) && (p < eEnd)) {
10121             /* Hybrid edges stay the same */
10122             newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (p - eMax);
10123             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
10124           } else if ((p >= fStart) && (p < fMax)) {
10125             /* Interior faces add new faces, edges, and vertex */
10126             for (r = 0; r < 4; ++r) {
10127               newp = fStartNew + (p - fStart)*4 + r;
10128               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
10129             }
10130             for (r = 0; r < 4; ++r) {
10131               newp = eStartNew + (eMax - eStart)*2 + (p - fStart)*4 + r;
10132               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
10133             }
10134             newp = vStartNew + (vEnd - vStart) + (eMax - eStart) + (p - fStart);
10135             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
10136           } else if ((p >= fMax) && (p < fEnd)) {
10137             /* Hybrid faces add new faces and edges */
10138             for (r = 0; r < 2; ++r) {
10139               newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (p - fMax)*2 + r;
10140               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
10141             }
10142             newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (p - fMax);
10143             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
10144           } else if ((p >= cStart) && (p < cMax)) {
10145             /* Interior cells add new cells, faces, edges, and vertex */
10146             for (r = 0; r < 8; ++r) {
10147               newp = cStartNew + (p - cStart)*8 + r;
10148               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
10149             }
10150             for (r = 0; r < 12; ++r) {
10151               newp = fStartNew + (fMax - fStart)*4 + (p - cStart)*12 + r;
10152               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
10153             }
10154             for (r = 0; r < 6; ++r) {
10155               newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (p - cStart)*6 + r;
10156               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
10157             }
10158             newp = vStartNew + (vEnd - vStart) + (eMax - eStart) + (fMax - fStart) + (p - cStart);
10159             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
10160           } else if ((p >= cMax) && (p < cEnd)) {
10161             /* Hybrid cells add new cells, faces, and edges */
10162             for (r = 0; r < 4; ++r) {
10163               newp = cStartNew + (cMax - cStart)*8 + (p - cMax)*4 + r;
10164               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
10165             }
10166             for (r = 0; r < 4; ++r) {
10167               newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd - fMax)*2 + (p - cMax)*4 + r;
10168               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
10169             }
10170             newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (fEnd - fMax) + (p - cMax);
10171             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
10172           }
10173           break;
10174         default:
10175           SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %s", CellRefiners[refiner]);
10176         }
10177       }
10178       ierr = ISRestoreIndices(pointIS, &points);CHKERRQ(ierr);
10179       ierr = ISDestroy(&pointIS);CHKERRQ(ierr);
10180     }
10181     ierr = ISRestoreIndices(valueIS, &values);CHKERRQ(ierr);
10182     ierr = ISDestroy(&valueIS);CHKERRQ(ierr);
10183   }
10184   PetscFunctionReturn(0);
10185 }
10186 
10187 /* This will only work for interpolated meshes */
10188 PetscErrorCode DMPlexRefineUniform_Internal(DM dm, CellRefiner cellRefiner, DM *dmRefined)
10189 {
10190   DM             rdm;
10191   PetscInt      *depthSize;
10192   PetscInt       dim, embedDim, depth = 0, d, pStart = 0, pEnd = 0;
10193   PetscErrorCode ierr;
10194 
10195   PetscFunctionBegin;
10196   ierr = DMCreate(PetscObjectComm((PetscObject)dm), &rdm);CHKERRQ(ierr);
10197   ierr = DMSetType(rdm, DMPLEX);CHKERRQ(ierr);
10198   ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr);
10199   ierr = DMSetDimension(rdm, dim);CHKERRQ(ierr);
10200   ierr = DMGetCoordinateDim(dm, &embedDim);CHKERRQ(ierr);
10201   ierr = DMSetCoordinateDim(rdm, embedDim);CHKERRQ(ierr);
10202   /* Calculate number of new points of each depth */
10203   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
10204   if (depth >= 0 && dim != depth) SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "Mesh must be interpolated for regular refinement");
10205   ierr = PetscMalloc1(depth+1, &depthSize);CHKERRQ(ierr);
10206   ierr = PetscMemzero(depthSize, (depth+1) * sizeof(PetscInt));CHKERRQ(ierr);
10207   ierr = CellRefinerGetSizes(cellRefiner, dm, depthSize);CHKERRQ(ierr);
10208   /* Step 1: Set chart */
10209   for (d = 0; d <= depth; ++d) pEnd += depthSize[d];
10210   ierr = DMPlexSetChart(rdm, pStart, pEnd);CHKERRQ(ierr);
10211   /* Step 2: Set cone/support sizes (automatically stratifies) */
10212   ierr = CellRefinerSetConeSizes(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
10213   /* Step 3: Setup refined DM */
10214   ierr = DMSetUp(rdm);CHKERRQ(ierr);
10215   /* Step 4: Set cones and supports (automatically symmetrizes) */
10216   ierr = CellRefinerSetCones(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
10217   /* Step 5: Create pointSF */
10218   ierr = CellRefinerCreateSF(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
10219   /* Step 6: Create labels */
10220   ierr = CellRefinerCreateLabels(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
10221   /* Step 7: Set coordinates */
10222   ierr = CellRefinerSetCoordinates(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
10223   ierr = PetscFree(depthSize);CHKERRQ(ierr);
10224 
10225   *dmRefined = rdm;
10226   PetscFunctionReturn(0);
10227 }
10228 
10229 /*@
10230   DMPlexCreateCoarsePointIS - Creates an IS covering the coarse DM chart with the fine points as data
10231 
10232   Input Parameter:
10233 . dm - The coarse DM
10234 
10235   Output Parameter:
10236 . fpointIS - The IS of all the fine points which exist in the original coarse mesh
10237 
10238   Level: developer
10239 
10240 .seealso: DMRefine(), DMPlexSetRefinementUniform(), DMPlexCreateSubpointIS()
10241 @*/
10242 PetscErrorCode DMPlexCreateCoarsePointIS(DM dm, IS *fpointIS)
10243 {
10244   CellRefiner    cellRefiner;
10245   PetscInt      *depthSize, *fpoints;
10246   PetscInt       cStartNew = 0, vStartNew = 0, fStartNew = 0, eStartNew = 0;
10247   PetscInt       depth, pStart, pEnd, p, vStart, vEnd, v;
10248   PetscErrorCode ierr;
10249 
10250   PetscFunctionBegin;
10251   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
10252   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
10253   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
10254   ierr = DMPlexGetCellRefiner_Internal(dm, &cellRefiner);CHKERRQ(ierr);
10255   ierr = PetscMalloc1(depth+1, &depthSize);CHKERRQ(ierr);
10256   ierr = CellRefinerGetSizes(cellRefiner, dm, depthSize);CHKERRQ(ierr);
10257   if (cellRefiner) {ierr = GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);CHKERRQ(ierr);}
10258   ierr = PetscMalloc1(pEnd-pStart,&fpoints);CHKERRQ(ierr);
10259   for (p = 0; p < pEnd-pStart; ++p) fpoints[p] = -1;
10260   switch (cellRefiner) {
10261   case REFINER_SIMPLEX_1D:
10262   case REFINER_SIMPLEX_2D:
10263   case REFINER_HYBRID_SIMPLEX_2D:
10264   case REFINER_HEX_2D:
10265   case REFINER_HYBRID_HEX_2D:
10266   case REFINER_SIMPLEX_3D:
10267   case REFINER_HYBRID_SIMPLEX_3D:
10268   case REFINER_HEX_3D:
10269   case REFINER_HYBRID_HEX_3D:
10270     for (v = vStart; v < vEnd; ++v) fpoints[v-pStart] = vStartNew + (v - vStart);
10271     break;
10272   default:
10273     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %s", CellRefiners[cellRefiner]);
10274   }
10275   ierr = ISCreateGeneral(PETSC_COMM_SELF, pEnd-pStart, fpoints, PETSC_OWN_POINTER, fpointIS);CHKERRQ(ierr);
10276   ierr = PetscFree(depthSize);CHKERRQ(ierr);
10277   PetscFunctionReturn(0);
10278 }
10279 
10280 /*@
10281   DMPlexSetRefinementUniform - Set the flag for uniform refinement
10282 
10283   Input Parameters:
10284 + dm - The DM
10285 - refinementUniform - The flag for uniform refinement
10286 
10287   Level: developer
10288 
10289 .seealso: DMRefine(), DMPlexGetRefinementUniform(), DMPlexGetRefinementLimit(), DMPlexSetRefinementLimit()
10290 @*/
10291 PetscErrorCode DMPlexSetRefinementUniform(DM dm, PetscBool refinementUniform)
10292 {
10293   DM_Plex *mesh = (DM_Plex*) dm->data;
10294 
10295   PetscFunctionBegin;
10296   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
10297   mesh->refinementUniform = refinementUniform;
10298   PetscFunctionReturn(0);
10299 }
10300 
10301 /*@
10302   DMPlexGetRefinementUniform - Retrieve the flag for uniform refinement
10303 
10304   Input Parameter:
10305 . dm - The DM
10306 
10307   Output Parameter:
10308 . refinementUniform - The flag for uniform refinement
10309 
10310   Level: developer
10311 
10312 .seealso: DMRefine(), DMPlexSetRefinementUniform(), DMPlexGetRefinementLimit(), DMPlexSetRefinementLimit()
10313 @*/
10314 PetscErrorCode DMPlexGetRefinementUniform(DM dm, PetscBool *refinementUniform)
10315 {
10316   DM_Plex *mesh = (DM_Plex*) dm->data;
10317 
10318   PetscFunctionBegin;
10319   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
10320   PetscValidPointer(refinementUniform,  2);
10321   *refinementUniform = mesh->refinementUniform;
10322   PetscFunctionReturn(0);
10323 }
10324 
10325 /*@
10326   DMPlexSetRefinementLimit - Set the maximum cell volume for refinement
10327 
10328   Input Parameters:
10329 + dm - The DM
10330 - refinementLimit - The maximum cell volume in the refined mesh
10331 
10332   Level: developer
10333 
10334 .seealso: DMRefine(), DMPlexGetRefinementLimit(), DMPlexGetRefinementUniform(), DMPlexSetRefinementUniform()
10335 @*/
10336 PetscErrorCode DMPlexSetRefinementLimit(DM dm, PetscReal refinementLimit)
10337 {
10338   DM_Plex *mesh = (DM_Plex*) dm->data;
10339 
10340   PetscFunctionBegin;
10341   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
10342   mesh->refinementLimit = refinementLimit;
10343   PetscFunctionReturn(0);
10344 }
10345 
10346 /*@
10347   DMPlexGetRefinementLimit - Retrieve the maximum cell volume for refinement
10348 
10349   Input Parameter:
10350 . dm - The DM
10351 
10352   Output Parameter:
10353 . refinementLimit - The maximum cell volume in the refined mesh
10354 
10355   Level: developer
10356 
10357 .seealso: DMRefine(), DMPlexSetRefinementLimit(), DMPlexGetRefinementUniform(), DMPlexSetRefinementUniform()
10358 @*/
10359 PetscErrorCode DMPlexGetRefinementLimit(DM dm, PetscReal *refinementLimit)
10360 {
10361   DM_Plex *mesh = (DM_Plex*) dm->data;
10362 
10363   PetscFunctionBegin;
10364   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
10365   PetscValidPointer(refinementLimit,  2);
10366   /* if (mesh->refinementLimit < 0) = getMaxVolume()/2.0; */
10367   *refinementLimit = mesh->refinementLimit;
10368   PetscFunctionReturn(0);
10369 }
10370 
10371 /*@
10372   DMPlexSetRefinementFunction - Set the function giving the maximum cell volume for refinement
10373 
10374   Input Parameters:
10375 + dm - The DM
10376 - refinementFunc - Function giving the maximum cell volume in the refined mesh
10377 
10378   Note: The calling sequence is refinementFunc(coords, limit)
10379 $ coords - Coordinates of the current point, usually a cell centroid
10380 $ limit  - The maximum cell volume for a cell containing this point
10381 
10382   Level: developer
10383 
10384 .seealso: DMRefine(), DMPlexGetRefinementFunction(), DMPlexGetRefinementUniform(), DMPlexSetRefinementUniform(), DMPlexGetRefinementLimit(), DMPlexSetRefinementLimit()
10385 @*/
10386 PetscErrorCode DMPlexSetRefinementFunction(DM dm, PetscErrorCode (*refinementFunc)(const PetscReal [], PetscReal *))
10387 {
10388   DM_Plex *mesh = (DM_Plex*) dm->data;
10389 
10390   PetscFunctionBegin;
10391   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
10392   mesh->refinementFunc = refinementFunc;
10393   PetscFunctionReturn(0);
10394 }
10395 
10396 /*@
10397   DMPlexGetRefinementFunction - Get the function giving the maximum cell volume for refinement
10398 
10399   Input Parameter:
10400 . dm - The DM
10401 
10402   Output Parameter:
10403 . refinementFunc - Function giving the maximum cell volume in the refined mesh
10404 
10405   Note: The calling sequence is refinementFunc(coords, limit)
10406 $ coords - Coordinates of the current point, usually a cell centroid
10407 $ limit  - The maximum cell volume for a cell containing this point
10408 
10409   Level: developer
10410 
10411 .seealso: DMRefine(), DMPlexSetRefinementFunction(), DMPlexGetRefinementUniform(), DMPlexSetRefinementUniform(), DMPlexGetRefinementLimit(), DMPlexSetRefinementLimit()
10412 @*/
10413 PetscErrorCode DMPlexGetRefinementFunction(DM dm, PetscErrorCode (**refinementFunc)(const PetscReal [], PetscReal *))
10414 {
10415   DM_Plex *mesh = (DM_Plex*) dm->data;
10416 
10417   PetscFunctionBegin;
10418   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
10419   PetscValidPointer(refinementFunc,  2);
10420   *refinementFunc = mesh->refinementFunc;
10421   PetscFunctionReturn(0);
10422 }
10423 
10424 PetscErrorCode DMPlexGetCellRefiner_Internal(DM dm, CellRefiner *cellRefiner)
10425 {
10426   PetscInt       dim, cStart, cEnd, coneSize, cMax, fMax;
10427   PetscErrorCode ierr;
10428 
10429   PetscFunctionBegin;
10430   ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr);
10431   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
10432   if (cEnd <= cStart) {*cellRefiner = REFINER_NOOP; PetscFunctionReturn(0);}
10433   ierr = DMPlexGetConeSize(dm, cStart, &coneSize);CHKERRQ(ierr);
10434   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, NULL, NULL);CHKERRQ(ierr);
10435   switch (dim) {
10436   case 1:
10437     switch (coneSize) {
10438     case 2:
10439       *cellRefiner = REFINER_SIMPLEX_1D;
10440       break;
10441     default:
10442       SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown coneSize %D in dimension %D for cell refiner", coneSize, dim);
10443     }
10444     break;
10445   case 2:
10446     switch (coneSize) {
10447     case 3:
10448       if (cMax >= 0) *cellRefiner = REFINER_HYBRID_SIMPLEX_2D;
10449       else *cellRefiner = REFINER_SIMPLEX_2D;
10450       break;
10451     case 4:
10452       if (cMax >= 0 && fMax >= 0) *cellRefiner = REFINER_HYBRID_HEX_2D;
10453       else *cellRefiner = REFINER_HEX_2D;
10454       break;
10455     default:
10456       SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown coneSize %D in dimension %D for cell refiner", coneSize, dim);
10457     }
10458     break;
10459   case 3:
10460     switch (coneSize) {
10461     case 4:
10462       if (cMax >= 0) *cellRefiner = REFINER_HYBRID_SIMPLEX_3D;
10463       else *cellRefiner = REFINER_SIMPLEX_3D;
10464       break;
10465     case 5:
10466       if (cMax == 0) *cellRefiner = REFINER_HYBRID_SIMPLEX_3D;
10467       else SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown coneSize %D in dimension %D for cell refiner", coneSize, dim);
10468       break;
10469     case 6:
10470       if (cMax >= 0) *cellRefiner = REFINER_HYBRID_HEX_3D;
10471       else *cellRefiner = REFINER_HEX_3D;
10472       break;
10473     default:
10474       SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown coneSize %D in dimension %D for cell refiner", coneSize, dim);
10475     }
10476     break;
10477   default:
10478     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown dimension %D for cell refiner", dim);
10479   }
10480   PetscFunctionReturn(0);
10481 }
10482 
10483 PetscErrorCode DMRefine_Plex(DM dm, MPI_Comm comm, DM *dmRefined)
10484 {
10485   PetscBool      isUniform;
10486   PetscErrorCode ierr;
10487 
10488   PetscFunctionBegin;
10489   ierr = DMPlexGetRefinementUniform(dm, &isUniform);CHKERRQ(ierr);
10490   if (isUniform) {
10491     CellRefiner cellRefiner;
10492     PetscBool   localized;
10493 
10494     ierr = DMGetCoordinatesLocalized(dm, &localized);CHKERRQ(ierr);
10495     ierr = DMPlexGetCellRefiner_Internal(dm, &cellRefiner);CHKERRQ(ierr);
10496     ierr = DMPlexRefineUniform_Internal(dm, cellRefiner, dmRefined);CHKERRQ(ierr);
10497     ierr = DMPlexSetRegularRefinement(*dmRefined, PETSC_TRUE);CHKERRQ(ierr);
10498     ierr = DMCopyBoundary(dm, *dmRefined);CHKERRQ(ierr);
10499     if (localized) {ierr = DMLocalizeCoordinates(*dmRefined);CHKERRQ(ierr);}
10500   } else {
10501     ierr = DMPlexRefine_Internal(dm, NULL, dmRefined);CHKERRQ(ierr);
10502   }
10503   PetscFunctionReturn(0);
10504 }
10505 
10506 PetscErrorCode DMRefineHierarchy_Plex(DM dm, PetscInt nlevels, DM dmRefined[])
10507 {
10508   DM             cdm = dm;
10509   PetscInt       r;
10510   PetscBool      isUniform, localized;
10511   PetscErrorCode ierr;
10512 
10513   PetscFunctionBegin;
10514   ierr = DMPlexGetRefinementUniform(dm, &isUniform);CHKERRQ(ierr);
10515   ierr = DMGetCoordinatesLocalized(dm, &localized);CHKERRQ(ierr);
10516   if (isUniform) {
10517     for (r = 0; r < nlevels; ++r) {
10518       CellRefiner cellRefiner;
10519 
10520       ierr = DMPlexGetCellRefiner_Internal(cdm, &cellRefiner);CHKERRQ(ierr);
10521       ierr = DMPlexRefineUniform_Internal(cdm, cellRefiner, &dmRefined[r]);CHKERRQ(ierr);
10522       ierr = DMSetCoarsenLevel(dmRefined[r], cdm->leveldown);CHKERRQ(ierr);
10523       ierr = DMSetRefineLevel(dmRefined[r], cdm->levelup+1);CHKERRQ(ierr);
10524       ierr = DMCopyBoundary(cdm, dmRefined[r]);CHKERRQ(ierr);
10525       if (localized) {ierr = DMLocalizeCoordinates(dmRefined[r]);CHKERRQ(ierr);}
10526       ierr = DMSetCoarseDM(dmRefined[r], cdm);CHKERRQ(ierr);
10527       ierr = DMPlexSetRegularRefinement(dmRefined[r], PETSC_TRUE);CHKERRQ(ierr);
10528       cdm  = dmRefined[r];
10529     }
10530   } else {
10531     for (r = 0; r < nlevels; ++r) {
10532       ierr = DMRefine(cdm, PetscObjectComm((PetscObject) dm), &dmRefined[r]);CHKERRQ(ierr);
10533       ierr = DMCopyBoundary(cdm, dmRefined[r]);CHKERRQ(ierr);
10534       if (localized) {ierr = DMLocalizeCoordinates(dmRefined[r]);CHKERRQ(ierr);}
10535       ierr = DMSetCoarseDM(dmRefined[r], cdm);CHKERRQ(ierr);
10536       cdm  = dmRefined[r];
10537     }
10538   }
10539   PetscFunctionReturn(0);
10540 }
10541