xref: /petsc/src/dm/impls/plex/plexrefine.c (revision 8e5aa403b7b03f534f06e51c3ce666d21d397ddd)
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     dim = 3;
251     if (numSubcells) *numSubcells = 8;
252     if (v0) {
253       ierr = PetscMalloc3(8*dim,&v,8*dim*dim,&j,8*dim*dim,&invj);CHKERRQ(ierr);
254       /* A */
255       v[0+0] = -1.0; v[0+1] = -1.0; v[0+2] = -1.0;
256       j[0+0] =  0.5; j[0+1] =  0.0; j[0+2] =  0.0;
257       j[0+3] =  0.0; j[0+4] =  0.5; j[0+5] =  0.0;
258       j[0+6] =  0.0; j[0+7] =  0.0; j[0+8] =  0.5;
259       /* B */
260       v[3+0] = -1.0; v[3+1] =  0.0; v[3+2] = -1.0;
261       j[9+0] =  0.5; j[9+1] =  0.0; j[9+2] =  0.0;
262       j[9+3] =  0.0; j[9+4] =  0.5; j[9+5] =  0.0;
263       j[9+6] =  0.0; j[9+7] =  0.0; j[9+8] =  0.5;
264       /* C */
265       v[6+0] =  0.0; v[6+1] =  0.0; v[6+2] = -1.0;
266       j[18+0] = 0.5; j[18+1] = 0.0; j[18+2] = 0.0;
267       j[18+3] = 0.0; j[18+4] = 0.5; j[18+5] = 0.0;
268       j[18+6] = 0.0; j[18+7] = 0.0; j[18+8] = 0.5;
269       /* D */
270       v[9+0] =  0.0; v[9+1] = -1.0; v[9+2] = -1.0;
271       j[27+0] = 0.5; j[27+1] = 0.0; j[27+2] = 0.0;
272       j[27+3] = 0.0; j[27+4] = 0.5; j[27+5] = 0.0;
273       j[27+6] = 0.0; j[27+7] = 0.0; j[27+8] = 0.5;
274       /* E */
275       v[12+0] = -1.0; v[12+1] = -1.0; v[12+2] =  0.0;
276       j[36+0] =  0.5; j[36+1] =  0.0; j[36+2] =  0.0;
277       j[36+3] =  0.0; j[36+4] =  0.5; j[36+5] =  0.0;
278       j[36+6] =  0.0; j[36+7] =  0.0; j[36+8] =  0.5;
279       /* F */
280       v[15+0] =  0.0; v[15+1] = -1.0; v[15+2] =  0.0;
281       j[45+0] =  0.5; j[45+1] =  0.0; j[45+2] =  0.0;
282       j[45+3] =  0.0; j[45+4] =  0.5; j[45+5] =  0.0;
283       j[45+6] =  0.0; j[45+7] =  0.0; j[45+8] =  0.5;
284       /* G */
285       v[18+0] =  0.0; v[18+1] =  0.0; v[18+2] =  0.0;
286       j[54+0] =  0.5; j[54+1] =  0.0; j[54+2] =  0.0;
287       j[54+3] =  0.0; j[54+4] =  0.5; j[54+5] =  0.0;
288       j[54+6] =  0.0; j[54+7] =  0.0; j[54+8] =  0.5;
289       /* H */
290       v[21+0] = -1.0; v[21+1] =  0.0; v[21+2] =  0.0;
291       j[63+0] =  0.5; j[63+1] =  0.0; j[63+2] =  0.0;
292       j[63+3] =  0.0; j[63+4] =  0.5; j[63+5] =  0.0;
293       j[63+6] =  0.0; j[63+7] =  0.0; j[63+8] =  0.5;
294       for (s = 0; s < 8; ++s) {
295         DMPlex_Det3D_Internal(&detJ, &j[s*dim*dim]);
296         DMPlex_Invert3D_Internal(&invj[s*dim*dim], &j[s*dim*dim], detJ);
297       }
298     }
299     break;
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   case REFINER_HEX_3D:
337     for (d = 0; d < 3; d++) if (PetscAbsReal(point[d]) > 1 + PETSC_SMALL) {*inside = PETSC_FALSE; break;}
338     break;
339   default:
340     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %s", CellRefiners[refiner]);
341   }
342   PetscFunctionReturn(0);
343 }
344 
345 static PetscErrorCode CellRefinerGetSizes(CellRefiner refiner, DM dm, PetscInt depthSize[])
346 {
347   PetscInt       cStart, cEnd, cMax, vStart, vEnd, vMax, fStart, fEnd, fMax, eStart, eEnd, eMax;
348   PetscErrorCode ierr;
349 
350   PetscFunctionBegin;
351   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
352   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
353   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
354   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
355   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
356   switch (refiner) {
357   case REFINER_NOOP:
358     break;
359   case REFINER_SIMPLEX_1D:
360     depthSize[0] = vEnd - vStart + cEnd - cStart;         /* Add a vertex on every cell. */
361     depthSize[1] = 2*(cEnd - cStart);                     /* Split every cell in 2. */
362     break;
363   case REFINER_SIMPLEX_2D:
364     depthSize[0] = vEnd - vStart + fEnd - fStart;         /* Add a vertex on every face */
365     depthSize[1] = 2*(fEnd - fStart) + 3*(cEnd - cStart); /* Every face is split into 2 faces and 3 faces are added for each cell */
366     depthSize[2] = 4*(cEnd - cStart);                     /* Every cell split into 4 cells */
367     break;
368   case REFINER_HYBRID_SIMPLEX_2D:
369     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
370     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
371     depthSize[0] = vEnd - vStart + fMax - fStart;                                         /* Add a vertex on every face, but not hybrid faces */
372     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 */
373     depthSize[2] = 4*(cMax - cStart) + 2*(cEnd - cMax);                                   /* Interior cells split into 4 cells, hybrid cells split into 2 cells */
374     break;
375   case REFINER_SIMPLEX_TO_HEX_2D:
376     depthSize[0] = vEnd - vStart + fEnd - fStart + cEnd - cStart; /* Add a vertex on every face and cell */
377     depthSize[1] = 2*(fEnd - fStart) + 3*(cEnd - cStart);         /* Every face is split into 2 faces and 3 faces are added for each cell */
378     depthSize[2] = 3*(cEnd - cStart);                             /* Every cell split into 3 cells */
379     break;
380   case REFINER_HYBRID_SIMPLEX_TO_HEX_2D:
381     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
382     depthSize[0] = vEnd - vStart + fEnd - fStart + cEnd - cStart;           /* Add a vertex on every face and cell */
383     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 */
384     depthSize[2] = 3*(cMax - cStart) + 4*(cEnd - cMax);                     /* Every cell split into 3 cells, hybrid cells split in 4 */
385     break;
386   case REFINER_HEX_2D:
387     depthSize[0] = vEnd - vStart + fEnd - fStart + cEnd - cStart; /* Add a vertex on every face and cell */
388     depthSize[1] = 2*(fEnd - fStart) + 4*(cEnd - cStart);         /* Every face is split into 2 faces and 4 faces are added for each cell */
389     depthSize[2] = 4*(cEnd - cStart);                             /* Every cell split into 4 cells */
390     break;
391   case REFINER_HYBRID_HEX_2D:
392     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
393     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
394     /* Quadrilateral */
395     depthSize[0] = vEnd - vStart + fMax - fStart + cMax - cStart;                 /* Add a vertex on every face and cell */
396     depthSize[1] = 2*(fMax - fStart) + 4*(cMax - cStart);                         /* Every face is split into 2 faces, and 4 faces are added for each cell */
397     depthSize[2] = 4*(cMax - cStart);                                             /* Every cell split into 4 cells */
398     /* Segment Prisms */
399     depthSize[0] += 0;                                                            /* No hybrid vertices */
400     depthSize[1] +=   (fEnd - fMax)  +   (cEnd - cMax);                           /* Every hybrid face remains and 1 faces is added for each hybrid cell */
401     depthSize[2] += 2*(cEnd - cMax);                                              /* Every hybrid cell split into 2 cells */
402     break;
403   case REFINER_SIMPLEX_3D:
404     depthSize[0] =    vEnd - vStart  +    eEnd - eStart;                    /* Add a vertex on every edge */
405     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 */
406     depthSize[2] = 4*(fEnd - fStart) + 8*(cEnd - cStart);                   /* Every face split into 4 faces and 8 faces are added for each cell */
407     depthSize[3] = 8*(cEnd - cStart);                                       /* Every cell split into 8 cells */
408     break;
409   case REFINER_HYBRID_SIMPLEX_3D:
410     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
411     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
412     if (eMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No edge maximum specified in hybrid mesh");
413     /* Tetrahedra */
414     depthSize[0]  =    vEnd - vStart  +    eMax - eStart;                    /* Add a vertex on every interior edge */
415     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 */
416     depthSize[2]  = 4*(fMax - fStart) + 8*(cMax - cStart);                   /* Every interior face split into 4 faces, 8 faces added for each interior cell */
417     depthSize[3]  = 8*(cMax - cStart);                                       /* Every interior cell split into 8 cells */
418     /* Triangular Prisms */
419     depthSize[0] += 0;                                                       /* No hybrid vertices */
420     depthSize[1] +=   (eEnd - eMax)   +   (fEnd - fMax);                     /* Every hybrid edge remains, 1 edge for every hybrid face */
421     depthSize[2] += 2*(fEnd - fMax)   + 3*(cEnd - cMax);                     /* Every hybrid face split into 2 faces and 3 faces are added for each hybrid cell */
422     depthSize[3] += 4*(cEnd - cMax);                                         /* Every hybrid cell split into 4 cells */
423     break;
424   case REFINER_SIMPLEX_TO_HEX_3D:
425     depthSize[0] = vEnd - vStart + fEnd - fStart + eEnd - eStart + cEnd - cStart; /* Add a vertex on every face, edge and cell */
426     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 */
427     depthSize[2] = 3*(fEnd - fStart) + 6*(cEnd - cStart);                         /* Every face is split into 3 faces and 6 faces are added for each cell */
428     depthSize[3] = 4*(cEnd - cStart);                                             /* Every cell split into 4 cells */
429     break;
430   case REFINER_HYBRID_SIMPLEX_TO_HEX_3D:
431     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
432     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
433     if (eMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No edge maximum specified in hybrid mesh");
434     /* Tetrahedra */
435     depthSize[0]  =    vEnd - vStart  +    eMax - eStart  + fMax - fStart + cMax - cStart; /* Add a vertex on every interior edge, face and cell */
436     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 */
437     depthSize[2]  = 3*(fMax - fStart) + 6*(cMax - cStart);                                 /* Every interior face split into 3 faces, 6 faces added for each interior cell */
438     depthSize[3]  = 4*(cMax - cStart);                                                     /* Every interior cell split into 8 cells */
439     /* Triangular Prisms */
440     depthSize[0] += 0;                                                 /* No hybrid vertices */
441     depthSize[1] +=   (eEnd - eMax) +   (fEnd - fMax) + (cEnd - cMax); /* Every hybrid edge remains, 1 edge for every hybrid face and cell */
442     depthSize[2] += 2*(fEnd - fMax) + 3*(cEnd - cMax);                 /* Every hybrid face split into 2 faces and 3 faces are added for each hybrid cell */
443     depthSize[3] += 3*(cEnd - cMax);                                   /* Every hybrid cell split into 3 cells */
444     break;
445   case REFINER_HEX_3D:
446     depthSize[0] = vEnd - vStart + eEnd - eStart + fEnd - fStart + cEnd - cStart; /* Add a vertex on every edge, face and cell */
447     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 */
448     depthSize[2] = 4*(fEnd - fStart) + 12*(cEnd - cStart);                        /* Every face is split into 4 faces, and 12 faces are added for each cell */
449     depthSize[3] = 8*(cEnd - cStart);                                             /* Every cell split into 8 cells */
450     break;
451   case REFINER_HYBRID_HEX_3D:
452     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
453     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
454     if (eMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No edge maximum specified in hybrid mesh");
455     /* Hexahedra */
456     depthSize[0] = vEnd - vStart + eMax - eStart + fMax - fStart + cMax - cStart; /* Add a vertex on every edge, face and cell */
457     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 */
458     depthSize[2] = 4*(fMax - fStart) + 12*(cMax - cStart);                        /* Every face is split into 4 faces, and 12 faces are added for each cell */
459     depthSize[3] = 8*(cMax - cStart);                                             /* Every cell split into 8 cells */
460     /* Quadrilateral Prisms */
461     depthSize[0] += 0;                                                            /* No hybrid vertices */
462     depthSize[1] +=   (eEnd - eMax)   +   (fEnd - fMax)   +   (cEnd - cMax);      /* Every hybrid edge remains, 1 edge for every hybrid face and hybrid cell */
463     depthSize[2] += 2*(fEnd - fMax)   + 4*(cEnd - cMax);                          /* Every hybrid face split into 2 faces and 4 faces are added for each hybrid cell */
464     depthSize[3] += 4*(cEnd - cMax);                                              /* Every hybrid cell split into 4 cells */
465     break;
466   default:
467     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %s", CellRefiners[refiner]);
468   }
469   PetscFunctionReturn(0);
470 }
471 
472 /* Return triangle edge for orientation o, if it is r for o == 0 */
473 PETSC_STATIC_INLINE PetscInt GetTriEdge_Static(PetscInt o, PetscInt r) {
474   return (o < 0 ? 2-(o+r) : o+r)%3;
475 }
476 PETSC_STATIC_INLINE PetscInt GetTriEdgeInverse_Static(PetscInt o, PetscInt s) {
477   return (o < 0 ? 2-(o+s) : 3+s-o)%3;
478 }
479 
480 /* Return triangle subface for orientation o, if it is r for o == 0 */
481 PETSC_STATIC_INLINE PetscInt GetTriSubface_Static(PetscInt o, PetscInt r) {
482   return (o < 0 ? 3-(o+r) : o+r)%3;
483 }
484 PETSC_STATIC_INLINE PetscInt GetTriSubfaceInverse_Static(PetscInt o, PetscInt s) {
485   return (o < 0 ? 3-(o+s) : 3+s-o)%3;
486 }
487 
488 /* Return the interior edge number connecting the midpoints of the triangle edges r
489    and r+1 in the transitive closure for triangle orientation o */
490 PETSC_STATIC_INLINE PetscInt GetTriMidEdge_Static(PetscInt o, PetscInt r) {
491   return (o < 0 ? 1-(o+r) : o+r)%3;
492 }
493 PETSC_STATIC_INLINE PetscInt GetTriMidEdgeInverse_Static(PetscInt o, PetscInt s) {
494   return (o < 0 ? 1-(o+s) : 3+s-o)%3;
495 }
496 
497 /* Return the interior edge number connecting the midpoint of the triangle edge r
498    (in the transitive closure) and the vertex in the interior of the face for triangle orientation o */
499 PETSC_STATIC_INLINE PetscInt GetTriInteriorEdge_Static(PetscInt o, PetscInt r) {
500   return (o < 0 ? 2-(o+r) : o+r)%3;
501 }
502 PETSC_STATIC_INLINE PetscInt GetTriInteriorEdgeInverse_Static(PetscInt o, PetscInt s) {
503   return (o < 0 ? 2-(o+s) : 3+s-o)%3;
504 }
505 
506 /* Return quad edge for orientation o, if it is r for o == 0 */
507 PETSC_STATIC_INLINE PetscInt GetQuadEdge_Static(PetscInt o, PetscInt r) {
508   return (o < 0 ? 3-(o+r) : o+r)%4;
509 }
510 PETSC_STATIC_INLINE PetscInt GetQuadEdgeInverse_Static(PetscInt o, PetscInt s) {
511   return (o < 0 ? 3-(o+s) : 4+s-o)%4;
512 }
513 
514 /* Return quad subface for orientation o, if it is r for o == 0 */
515 PETSC_STATIC_INLINE PetscInt GetQuadSubface_Static(PetscInt o, PetscInt r) {
516   return (o < 0 ? 4-(o+r) : o+r)%4;
517 }
518 PETSC_STATIC_INLINE PetscInt GetQuadSubfaceInverse_Static(PetscInt o, PetscInt s) {
519   return (o < 0 ? 4-(o+s) : 4+s-o)%4;
520 }
521 
522 static PetscErrorCode DMLabelSetStratumBounds(DMLabel label, PetscInt value, PetscInt cStart, PetscInt cEnd)
523 {
524   IS             cIS;
525   PetscErrorCode ierr;
526 
527   PetscFunctionBegin;
528   ierr = ISCreateStride(PETSC_COMM_SELF, cEnd - cStart, cStart, 1, &cIS);CHKERRQ(ierr);
529   ierr = DMLabelSetStratumIS(label, value, cIS);CHKERRQ(ierr);
530   ierr = ISDestroy(&cIS);CHKERRQ(ierr);
531   PetscFunctionReturn(0);
532 }
533 
534 static PetscErrorCode CellRefinerSetConeSizes(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
535 {
536   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;
537   DMLabel        depthLabel;
538   PetscErrorCode ierr;
539 
540   PetscFunctionBegin;
541   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
542   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
543   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
544   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
545   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
546   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
547   ierr = GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);CHKERRQ(ierr);
548   ierr = GetDepthEnd_Private(depth, depthSize, &cEndNew, &fEndNew, &eEndNew, &vEndNew);CHKERRQ(ierr);
549   ierr = DMCreateLabel(rdm,"depth");CHKERRQ(ierr);
550   ierr = DMPlexGetDepthLabel(rdm,&depthLabel);CHKERRQ(ierr);
551   ierr = DMLabelSetStratumBounds(depthLabel, 0, vStartNew, vEndNew);CHKERRQ(ierr);
552   if (depth > 2) ierr = DMLabelSetStratumBounds(depthLabel, 1, eStartNew, eEndNew);CHKERRQ(ierr);
553   if (depth > 1) ierr = DMLabelSetStratumBounds(depthLabel, depth - 1, fStartNew, fEndNew);CHKERRQ(ierr);
554   if (depth > 0) ierr = DMLabelSetStratumBounds(depthLabel, depth, cStartNew, cEndNew);CHKERRQ(ierr);
555   {
556     DM_Plex *plex = (DM_Plex *) rdm->data;
557     ierr = PetscObjectStateGet((PetscObject) depthLabel, &plex->depthState);CHKERRQ(ierr);
558   }
559   if (!refiner) PetscFunctionReturn(0);
560   switch (refiner) {
561   case REFINER_SIMPLEX_1D:
562     /* All cells have 2 vertices */
563     for (c = cStart; c < cEnd; ++c) {
564       for (r = 0; r < 2; ++r) {
565         const PetscInt newp = cStartNew + (c - cStart)*2 + r;
566 
567         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
568       }
569     }
570     /* Old vertices have identical supports */
571     for (v = vStart; v < vEnd; ++v) {
572       const PetscInt newp = vStartNew + (v - vStart);
573       PetscInt       size;
574 
575       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
576       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
577     }
578     /* Cell vertices have support 2 */
579     for (c = cStart; c < cEnd; ++c) {
580       const PetscInt newp = vStartNew + (vEnd - vStart) + (c - cStart);
581 
582       ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
583     }
584     break;
585   case REFINER_SIMPLEX_2D:
586     /* All cells have 3 faces */
587     for (c = cStart; c < cEnd; ++c) {
588       for (r = 0; r < 4; ++r) {
589         const PetscInt newp = (c - cStart)*4 + r;
590 
591         ierr = DMPlexSetConeSize(rdm, newp, 3);CHKERRQ(ierr);
592       }
593     }
594     /* Split faces have 2 vertices and the same cells as the parent */
595     for (f = fStart; f < fEnd; ++f) {
596       for (r = 0; r < 2; ++r) {
597         const PetscInt newp = fStartNew + (f - fStart)*2 + r;
598         PetscInt       size;
599 
600         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
601         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
602         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
603       }
604     }
605     /* Interior faces have 2 vertices and 2 cells */
606     for (c = cStart; c < cEnd; ++c) {
607       for (r = 0; r < 3; ++r) {
608         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*3 + r;
609 
610         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
611         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
612       }
613     }
614     /* Old vertices have identical supports */
615     for (v = vStart; v < vEnd; ++v) {
616       const PetscInt newp = vStartNew + (v - vStart);
617       PetscInt       size;
618 
619       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
620       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
621     }
622     /* Face vertices have 2 + cells*2 supports */
623     for (f = fStart; f < fEnd; ++f) {
624       const PetscInt newp = vStartNew + (vEnd - vStart) + (f - fStart);
625       PetscInt       size;
626 
627       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
628       ierr = DMPlexSetSupportSize(rdm, newp, 2 + size*2);CHKERRQ(ierr);
629     }
630     break;
631   case REFINER_SIMPLEX_TO_HEX_2D:
632     /* All cells have 4 faces */
633     for (c = cStart; c < cEnd; ++c) {
634       for (r = 0; r < 3; ++r) {
635         const PetscInt newp = (c - cStart)*3 + r;
636 
637         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
638       }
639     }
640     /* Split faces have 2 vertices and the same cells as the parent */
641     for (f = fStart; f < fEnd; ++f) {
642       for (r = 0; r < 2; ++r) {
643         const PetscInt newp = fStartNew + (f - fStart)*2 + r;
644         PetscInt       size;
645 
646         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
647         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
648         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
649       }
650     }
651     /* Interior faces have 2 vertices and 2 cells */
652     for (c = cStart; c < cEnd; ++c) {
653       for (r = 0; r < 3; ++r) {
654         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*3 + r;
655 
656         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
657         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
658       }
659     }
660     /* Old vertices have identical supports */
661     for (v = vStart; v < vEnd; ++v) {
662       const PetscInt newp = vStartNew + (v - vStart);
663       PetscInt       size;
664 
665       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
666       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
667     }
668     /* Split-face vertices have cells + 2 supports */
669     for (f = fStart; f < fEnd; ++f) {
670       const PetscInt newp = vStartNew + (vEnd - vStart) + (f - fStart);
671       PetscInt       size;
672 
673       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
674       ierr = DMPlexSetSupportSize(rdm, newp, size + 2);CHKERRQ(ierr);
675     }
676     /* Interior vertices have 3 supports */
677     for (c = cStart; c < cEnd; ++c) {
678       const PetscInt newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + c - cStart;
679 
680       ierr = DMPlexSetSupportSize(rdm, newp, 3);CHKERRQ(ierr);
681     }
682     break;
683   case REFINER_HYBRID_SIMPLEX_TO_HEX_2D:
684     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
685     /* the mesh is no longer hybrid */
686     cMax = PetscMin(cEnd, cMax);
687     /* All cells have 4 faces */
688     for (c = cStart; c < cMax; ++c) {
689       for (r = 0; r < 3; ++r) {
690         const PetscInt newp = (c - cStart)*3 + r;
691 
692         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
693       }
694     }
695     for (c = cMax; c < cEnd; ++c) {
696       for (r = 0; r < 4; ++r) {
697         const PetscInt newp = (cMax - cStart)*3 + (c - cMax)*4 + r;
698 
699         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
700       }
701     }
702     /* Split faces have 2 vertices and the same cells as the parent */
703     for (f = fStart; f < fEnd; ++f) {
704       for (r = 0; r < 2; ++r) {
705         const PetscInt newp = fStartNew + (f - fStart)*2 + r;
706         PetscInt       size;
707 
708         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
709         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
710         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
711       }
712     }
713     /* Interior faces have 2 vertices and 2 cells */
714     for (c = cStart; c < cMax; ++c) {
715       for (r = 0; r < 3; ++r) {
716         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*3 + r;
717 
718         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
719         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
720       }
721     }
722     /* Hybrid interior faces have 2 vertices and 2 cells */
723     for (c = cMax; c < cEnd; ++c) {
724       for (r = 0; r < 4; ++r) {
725         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (cMax - cStart)*3 + (c - cMax)*4 + r;
726 
727         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
728         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
729       }
730     }
731     /* Old vertices have identical supports */
732     for (v = vStart; v < vEnd; ++v) {
733       const PetscInt newp = vStartNew + (v - vStart);
734       PetscInt       size;
735 
736       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
737       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
738     }
739     /* Split-face vertices have cells + 2 supports */
740     for (f = fStart; f < fEnd; ++f) {
741       const PetscInt newp = vStartNew + (vEnd - vStart) + (f - fStart);
742       PetscInt       size;
743 
744       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
745       ierr = DMPlexSetSupportSize(rdm, newp, size + 2);CHKERRQ(ierr);
746     }
747     /* Interior vertices have 3 supports */
748     for (c = cStart; c < cMax; ++c) {
749       const PetscInt newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + c - cStart;
750 
751       ierr = DMPlexSetSupportSize(rdm, newp, 3);CHKERRQ(ierr);
752     }
753     /* Hybrid interior vertices have 4 supports */
754     for (c = cMax; c < cEnd; ++c) {
755       const PetscInt newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + c - cStart;
756 
757       ierr = DMPlexSetSupportSize(rdm, newp, 4);CHKERRQ(ierr);
758     }
759     break;
760   case REFINER_HEX_2D:
761     /* All cells have 4 faces */
762     for (c = cStart; c < cEnd; ++c) {
763       for (r = 0; r < 4; ++r) {
764         const PetscInt newp = cStartNew + (c - cStart)*4 + r;
765 
766         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
767       }
768     }
769     /* Split faces have 2 vertices and the same cells as the parent */
770     for (f = fStart; f < fEnd; ++f) {
771       for (r = 0; r < 2; ++r) {
772         const PetscInt newp = fStartNew + (f - fStart)*2 + r;
773         PetscInt       size;
774 
775         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
776         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
777         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
778       }
779     }
780     /* Interior faces have 2 vertices and 2 cells */
781     for (c = cStart; c < cEnd; ++c) {
782       for (r = 0; r < 4; ++r) {
783         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*4 + r;
784 
785         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
786         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
787       }
788     }
789     /* Old vertices have identical supports */
790     for (v = vStart; v < vEnd; ++v) {
791       const PetscInt newp = vStartNew + (v - vStart);
792       PetscInt       size;
793 
794       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
795       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
796     }
797     /* Face vertices have 2 + cells supports */
798     for (f = fStart; f < fEnd; ++f) {
799       const PetscInt newp = vStartNew + (vEnd - vStart) + (f - fStart);
800       PetscInt       size;
801 
802       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
803       ierr = DMPlexSetSupportSize(rdm, newp, 2 + size);CHKERRQ(ierr);
804     }
805     /* Cell vertices have 4 supports */
806     for (c = cStart; c < cEnd; ++c) {
807       const PetscInt newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (c - cStart);
808 
809       ierr = DMPlexSetSupportSize(rdm, newp, 4);CHKERRQ(ierr);
810     }
811     break;
812   case REFINER_HYBRID_SIMPLEX_2D:
813     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
814     cMax = PetscMin(cEnd, cMax);
815     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
816     fMax = PetscMin(fEnd, fMax);
817     ierr = DMPlexSetHybridBounds(rdm, cStartNew + (cMax - cStart)*4, fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3, PETSC_DETERMINE, PETSC_DETERMINE);CHKERRQ(ierr);
818     /* Interior cells have 3 faces */
819     for (c = cStart; c < cMax; ++c) {
820       for (r = 0; r < 4; ++r) {
821         const PetscInt newp = cStartNew + (c - cStart)*4 + r;
822 
823         ierr = DMPlexSetConeSize(rdm, newp, 3);CHKERRQ(ierr);
824       }
825     }
826     /* Hybrid cells have 4 faces */
827     for (c = cMax; c < cEnd; ++c) {
828       for (r = 0; r < 2; ++r) {
829         const PetscInt newp = cStartNew + (cMax - cStart)*4 + (c - cMax)*2 + r;
830 
831         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
832       }
833     }
834     /* Interior split faces have 2 vertices and the same cells as the parent */
835     for (f = fStart; f < fMax; ++f) {
836       for (r = 0; r < 2; ++r) {
837         const PetscInt newp = fStartNew + (f - fStart)*2 + r;
838         PetscInt       size;
839 
840         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
841         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
842         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
843       }
844     }
845     /* Interior cell faces have 2 vertices and 2 cells */
846     for (c = cStart; c < cMax; ++c) {
847       for (r = 0; r < 3; ++r) {
848         const PetscInt newp = fStartNew + (fMax - fStart)*2 + (c - cStart)*3 + r;
849 
850         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
851         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
852       }
853     }
854     /* Hybrid faces have 2 vertices and the same cells */
855     for (f = fMax; f < fEnd; ++f) {
856       const PetscInt newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (f - fMax);
857       PetscInt       size;
858 
859       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
860       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
861       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
862     }
863     /* Hybrid cell faces have 2 vertices and 2 cells */
864     for (c = cMax; c < cEnd; ++c) {
865       const PetscInt newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (fEnd - fMax) + (c - cMax);
866 
867       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
868       ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
869     }
870     /* Old vertices have identical supports */
871     for (v = vStart; v < vEnd; ++v) {
872       const PetscInt newp = vStartNew + (v - vStart);
873       PetscInt       size;
874 
875       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
876       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
877     }
878     /* Face vertices have 2 + (2 interior, 1 hybrid) supports */
879     for (f = fStart; f < fMax; ++f) {
880       const PetscInt newp = vStartNew + (vEnd - vStart) + (f - fStart);
881       const PetscInt *support;
882       PetscInt       size, newSize = 2, s;
883 
884       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
885       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
886       for (s = 0; s < size; ++s) {
887         if (support[s] >= cMax) newSize += 1;
888         else newSize += 2;
889       }
890       ierr = DMPlexSetSupportSize(rdm, newp, newSize);CHKERRQ(ierr);
891     }
892     break;
893   case REFINER_HYBRID_HEX_2D:
894     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
895     cMax = PetscMin(cEnd, cMax);
896     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
897     fMax = PetscMin(fEnd, fMax);
898     ierr = DMPlexSetHybridBounds(rdm, cStartNew + (cMax - cStart)*4, fStartNew + (fMax - fStart)*2 + (cMax - cStart)*4, PETSC_DETERMINE, PETSC_DETERMINE);CHKERRQ(ierr);
899     /* Interior cells have 4 faces */
900     for (c = cStart; c < cMax; ++c) {
901       for (r = 0; r < 4; ++r) {
902         const PetscInt newp = cStartNew + (c - cStart)*4 + r;
903 
904         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
905       }
906     }
907     /* Hybrid cells have 4 faces */
908     for (c = cMax; c < cEnd; ++c) {
909       for (r = 0; r < 2; ++r) {
910         const PetscInt newp = cStartNew + (cMax - cStart)*4 + (c - cMax)*2 + r;
911 
912         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
913       }
914     }
915     /* Interior split faces have 2 vertices and the same cells as the parent */
916     for (f = fStart; f < fMax; ++f) {
917       for (r = 0; r < 2; ++r) {
918         const PetscInt newp = fStartNew + (f - fStart)*2 + r;
919         PetscInt       size;
920 
921         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
922         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
923         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
924       }
925     }
926     /* Interior cell faces have 2 vertices and 2 cells */
927     for (c = cStart; c < cMax; ++c) {
928       for (r = 0; r < 4; ++r) {
929         const PetscInt newp = fStartNew + (fMax - fStart)*2 + (c - cStart)*4 + r;
930 
931         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
932         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
933       }
934     }
935     /* Hybrid faces have 2 vertices and the same cells */
936     for (f = fMax; f < fEnd; ++f) {
937       const PetscInt newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*4 + (f - fMax);
938       PetscInt       size;
939 
940       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
941       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
942       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
943     }
944     /* Hybrid cell faces have 2 vertices and 2 cells */
945     for (c = cMax; c < cEnd; ++c) {
946       const PetscInt newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*4 + (fEnd - fMax) + (c - cMax);
947 
948       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
949       ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
950     }
951     /* Old vertices have identical supports */
952     for (v = vStart; v < vEnd; ++v) {
953       const PetscInt newp = vStartNew + (v - vStart);
954       PetscInt       size;
955 
956       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
957       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
958     }
959     /* Face vertices have 2 + cells supports */
960     for (f = fStart; f < fMax; ++f) {
961       const PetscInt newp = vStartNew + (vEnd - vStart) + (f - fStart);
962       PetscInt       size;
963 
964       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
965       ierr = DMPlexSetSupportSize(rdm, newp, 2 + size);CHKERRQ(ierr);
966     }
967     /* Cell vertices have 4 supports */
968     for (c = cStart; c < cMax; ++c) {
969       const PetscInt newp = vStartNew + (vEnd - vStart) + (fMax - fStart) + (c - cStart);
970 
971       ierr = DMPlexSetSupportSize(rdm, newp, 4);CHKERRQ(ierr);
972     }
973     break;
974   case REFINER_SIMPLEX_3D:
975     /* All cells have 4 faces */
976     for (c = cStart; c < cEnd; ++c) {
977       for (r = 0; r < 8; ++r) {
978         const PetscInt newp = cStartNew + (c - cStart)*8 + r;
979 
980         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
981       }
982     }
983     /* Split faces have 3 edges and the same cells as the parent */
984     for (f = fStart; f < fEnd; ++f) {
985       for (r = 0; r < 4; ++r) {
986         const PetscInt newp = fStartNew + (f - fStart)*4 + r;
987         PetscInt       size;
988 
989         ierr = DMPlexSetConeSize(rdm, newp, 3);CHKERRQ(ierr);
990         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
991         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
992       }
993     }
994     /* Interior cell faces have 3 edges and 2 cells */
995     for (c = cStart; c < cEnd; ++c) {
996       for (r = 0; r < 8; ++r) {
997         const PetscInt newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*8 + r;
998 
999         ierr = DMPlexSetConeSize(rdm, newp, 3);CHKERRQ(ierr);
1000         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
1001       }
1002     }
1003     /* Split edges have 2 vertices and the same faces */
1004     for (e = eStart; e < eEnd; ++e) {
1005       for (r = 0; r < 2; ++r) {
1006         const PetscInt newp = eStartNew + (e - eStart)*2 + r;
1007         PetscInt       size;
1008 
1009         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
1010         ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
1011         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
1012       }
1013     }
1014     /* Face edges have 2 vertices and 2+cells*(1/2) faces */
1015     for (f = fStart; f < fEnd; ++f) {
1016       for (r = 0; r < 3; ++r) {
1017         const PetscInt  newp = eStartNew + (eEnd - eStart)*2 + (f - fStart)*3 + r;
1018         const PetscInt *cone, *ornt, *support, eint[4] = {1, 0, 2, 0};
1019         PetscInt        coneSize, c, supportSize, s, er, intFaces = 0;
1020 
1021         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
1022         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
1023         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
1024         for (s = 0; s < supportSize; ++s) {
1025           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
1026           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
1027           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
1028           for (c = 0; c < coneSize; ++c) {if (cone[c] == f) break;}
1029           /* Here we want to determine whether edge newp contains a vertex which is part of the cross-tet edge */
1030           er = GetTriMidEdgeInverse_Static(ornt[c], r);
1031           if (er == eint[c]) {
1032             intFaces += 1;
1033           } else {
1034             intFaces += 2;
1035           }
1036         }
1037         ierr = DMPlexSetSupportSize(rdm, newp, 2+intFaces);CHKERRQ(ierr);
1038       }
1039     }
1040     /* Interior cell edges have 2 vertices and 4 faces */
1041     for (c = cStart; c < cEnd; ++c) {
1042       const PetscInt newp = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart);
1043 
1044       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
1045       ierr = DMPlexSetSupportSize(rdm, newp, 4);CHKERRQ(ierr);
1046     }
1047     /* Old vertices have identical supports */
1048     for (v = vStart; v < vEnd; ++v) {
1049       const PetscInt newp = vStartNew + (v - vStart);
1050       PetscInt       size;
1051 
1052       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
1053       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
1054     }
1055     /* Edge vertices have 2 + faces*2 + cells*0/1 supports */
1056     for (e = eStart; e < eEnd; ++e) {
1057       const PetscInt newp = vStartNew + (vEnd - vStart) + (e - eStart);
1058       PetscInt       size, *star = NULL, starSize, s, cellSize = 0;
1059 
1060       ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
1061       ierr = DMPlexGetTransitiveClosure(dm, e, PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
1062       for (s = 0; s < starSize*2; s += 2) {
1063         const PetscInt *cone, *ornt;
1064         PetscInt        e01, e23;
1065 
1066         if ((star[s] >= cStart) && (star[s] < cEnd)) {
1067           /* Check edge 0-1 */
1068           ierr = DMPlexGetCone(dm, star[s], &cone);CHKERRQ(ierr);
1069           ierr = DMPlexGetConeOrientation(dm, star[s], &ornt);CHKERRQ(ierr);
1070           ierr = DMPlexGetCone(dm, cone[0], &cone);CHKERRQ(ierr);
1071           e01  = cone[GetTriEdge_Static(ornt[0], 0)];
1072           /* Check edge 2-3 */
1073           ierr = DMPlexGetCone(dm, star[s], &cone);CHKERRQ(ierr);
1074           ierr = DMPlexGetConeOrientation(dm, star[s], &ornt);CHKERRQ(ierr);
1075           ierr = DMPlexGetCone(dm, cone[2], &cone);CHKERRQ(ierr);
1076           e23  = cone[GetTriEdge_Static(ornt[2], 1)];
1077           if ((e01 == e) || (e23 == e)) ++cellSize;
1078         }
1079       }
1080       ierr = DMPlexRestoreTransitiveClosure(dm, e, PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
1081       ierr = DMPlexSetSupportSize(rdm, newp, 2 + size*2 + cellSize);CHKERRQ(ierr);
1082     }
1083     break;
1084   case REFINER_HYBRID_SIMPLEX_3D:
1085     ierr = DMPlexSetHybridBounds(rdm, cStartNew + 8*(cMax-cStart), fStartNew + 4*(fMax - fStart) + 8*(cMax - cStart),
1086                                  eStartNew + 2*(eMax - eStart) + 3*(fMax - fStart) + (cMax - cStart), PETSC_DETERMINE);CHKERRQ(ierr);
1087     /* Interior cells have 4 faces */
1088     for (c = cStart; c < cMax; ++c) {
1089       for (r = 0; r < 8; ++r) {
1090         const PetscInt newp = cStartNew + (c - cStart)*8 + r;
1091 
1092         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
1093       }
1094     }
1095     /* Hybrid cells have 5 faces */
1096     for (c = cMax; c < cEnd; ++c) {
1097       for (r = 0; r < 4; ++r) {
1098         const PetscInt newp = cStartNew + (cMax - cStart)*8 + (c - cMax)*4 + r;
1099 
1100         ierr = DMPlexSetConeSize(rdm, newp, 5);CHKERRQ(ierr);
1101       }
1102     }
1103     /* Interior split faces have 3 edges and the same cells as the parent */
1104     for (f = fStart; f < fMax; ++f) {
1105       for (r = 0; r < 4; ++r) {
1106         const PetscInt newp = fStartNew + (f - fStart)*4 + r;
1107         PetscInt       size;
1108 
1109         ierr = DMPlexSetConeSize(rdm, newp, 3);CHKERRQ(ierr);
1110         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
1111         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
1112       }
1113     }
1114     /* Interior cell faces have 3 edges and 2 cells */
1115     for (c = cStart; c < cMax; ++c) {
1116       for (r = 0; r < 8; ++r) {
1117         const PetscInt newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*8 + r;
1118 
1119         ierr = DMPlexSetConeSize(rdm, newp, 3);CHKERRQ(ierr);
1120         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
1121       }
1122     }
1123     /* Hybrid split faces have 4 edges and the same cells as the parent */
1124     for (f = fMax; f < fEnd; ++f) {
1125       for (r = 0; r < 2; ++r) {
1126         const PetscInt newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (f - fMax)*2 + r;
1127         PetscInt       size;
1128 
1129         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
1130         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
1131         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
1132       }
1133     }
1134     /* Hybrid cells faces have 4 edges and 2 cells */
1135     for (c = cMax; c < cEnd; ++c) {
1136       for (r = 0; r < 3; ++r) {
1137         const PetscInt newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (c - cMax)*3 + r;
1138 
1139         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
1140         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
1141       }
1142     }
1143     /* Interior split edges have 2 vertices and the same faces */
1144     for (e = eStart; e < eMax; ++e) {
1145       for (r = 0; r < 2; ++r) {
1146         const PetscInt newp = eStartNew + (e - eStart)*2 + r;
1147         PetscInt       size;
1148 
1149         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
1150         ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
1151         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
1152       }
1153     }
1154     /* Interior face edges have 2 vertices and 2+cells*(1/2) faces */
1155     for (f = fStart; f < fMax; ++f) {
1156       for (r = 0; r < 3; ++r) {
1157         const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (f - fStart)*3 + r;
1158         const PetscInt *cone, *ornt, *support, eint[4] = {1, 0, 2, 0};
1159         PetscInt        coneSize, c, supportSize, s, er, intFaces = 0;
1160 
1161         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
1162         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
1163         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
1164         for (s = 0; s < supportSize; ++s) {
1165           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
1166           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
1167           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
1168           for (c = 0; c < coneSize; ++c) {if (cone[c] == f) break;}
1169           if (support[s] < cMax) {
1170             /* Here we want to determine whether edge newp contains a vertex which is part of the cross-tet edge */
1171             er = GetTriMidEdgeInverse_Static(ornt[c], r);
1172             if (er == eint[c]) {
1173               intFaces += 1;
1174             } else {
1175               intFaces += 2;
1176             }
1177           } else {
1178             intFaces += 1;
1179           }
1180         }
1181         ierr = DMPlexSetSupportSize(rdm, newp, 2+intFaces);CHKERRQ(ierr);
1182       }
1183     }
1184     /* Interior cell edges have 2 vertices and 4 faces */
1185     for (c = cStart; c < cMax; ++c) {
1186       const PetscInt newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart);
1187 
1188       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
1189       ierr = DMPlexSetSupportSize(rdm, newp, 4);CHKERRQ(ierr);
1190     }
1191     /* Hybrid edges have 2 vertices and the same faces */
1192     for (e = eMax; e < eEnd; ++e) {
1193       const PetscInt newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (e - eMax);
1194       PetscInt       size;
1195 
1196       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
1197       ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
1198       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
1199     }
1200     /* Hybrid face edges have 2 vertices and 2+2*cells faces */
1201     for (f = fMax; f < fEnd; ++f) {
1202       const PetscInt newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (eEnd - eMax) + (f - fMax);
1203       PetscInt       size;
1204 
1205       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
1206       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
1207       ierr = DMPlexSetSupportSize(rdm, newp, 2+2*size);CHKERRQ(ierr);
1208     }
1209     /* Interior vertices have identical supports */
1210     for (v = vStart; v < vEnd; ++v) {
1211       const PetscInt newp = vStartNew + (v - vStart);
1212       PetscInt       size;
1213 
1214       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
1215       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
1216     }
1217     /* Interior edge vertices have 2 + interior face*2 + hybrid face + cells*0/1 supports */
1218     for (e = eStart; e < eMax; ++e) {
1219       const PetscInt  newp = vStartNew + (vEnd - vStart) + (e - eStart);
1220       const PetscInt *support;
1221       PetscInt        size, *star = NULL, starSize, s, faceSize = 0, cellSize = 0;
1222 
1223       ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
1224       ierr = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
1225       for (s = 0; s < size; ++s) {
1226         if (support[s] < fMax) faceSize += 2;
1227         else                   faceSize += 1;
1228       }
1229       ierr = DMPlexGetTransitiveClosure(dm, e, PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
1230       for (s = 0; s < starSize*2; s += 2) {
1231         const PetscInt *cone, *ornt;
1232         PetscInt        e01, e23;
1233 
1234         if ((star[s] >= cStart) && (star[s] < cMax)) {
1235           /* Check edge 0-1 */
1236           ierr = DMPlexGetCone(dm, star[s], &cone);CHKERRQ(ierr);
1237           ierr = DMPlexGetConeOrientation(dm, star[s], &ornt);CHKERRQ(ierr);
1238           ierr = DMPlexGetCone(dm, cone[0], &cone);CHKERRQ(ierr);
1239           e01  = cone[GetTriEdge_Static(ornt[0], 0)];
1240           /* Check edge 2-3 */
1241           ierr = DMPlexGetCone(dm, star[s], &cone);CHKERRQ(ierr);
1242           ierr = DMPlexGetConeOrientation(dm, star[s], &ornt);CHKERRQ(ierr);
1243           ierr = DMPlexGetCone(dm, cone[2], &cone);CHKERRQ(ierr);
1244           e23  = cone[GetTriEdge_Static(ornt[2], 1)];
1245           if ((e01 == e) || (e23 == e)) ++cellSize;
1246         }
1247       }
1248       ierr = DMPlexRestoreTransitiveClosure(dm, e, PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
1249       ierr = DMPlexSetSupportSize(rdm, newp, 2 + faceSize + cellSize);CHKERRQ(ierr);
1250     }
1251     break;
1252   case REFINER_SIMPLEX_TO_HEX_3D:
1253     /* All cells have 6 faces */
1254     for (c = cStart; c < cEnd; ++c) {
1255       for (r = 0; r < 4; ++r) {
1256         const PetscInt newp = cStartNew + (c - cStart)*4 + r;
1257 
1258         ierr = DMPlexSetConeSize(rdm, newp, 6);CHKERRQ(ierr);
1259       }
1260     }
1261     /* Split faces have 4 edges and the same cells as the parent */
1262     for (f = fStart; f < fEnd; ++f) {
1263       for (r = 0; r < 3; ++r) {
1264         const PetscInt newp = fStartNew + (f - fStart)*3 + r;
1265         PetscInt       size;
1266 
1267         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
1268         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
1269         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
1270       }
1271     }
1272     /* Interior cell faces have 4 edges and 2 cells */
1273     for (c = cStart; c < cEnd; ++c) {
1274       for (r = 0; r < 6; ++r) {
1275         const PetscInt newp = fStartNew + (fEnd - fStart)*3 + (c - cStart)*6 + r;
1276 
1277         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
1278         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
1279       }
1280     }
1281     /* Split edges have 2 vertices and the same faces */
1282     for (e = eStart; e < eEnd; ++e) {
1283       for (r = 0; r < 2; ++r) {
1284         const PetscInt newp = eStartNew + (e - eStart)*2 + r;
1285         PetscInt       size;
1286 
1287         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
1288         ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
1289         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
1290       }
1291     }
1292     /* Face edges have 2 vertices and 2 + cell faces supports */
1293     for (f = fStart; f < fEnd; ++f) {
1294       for (r = 0; r < 3; ++r) {
1295         const PetscInt  newp = eStartNew + (eEnd - eStart)*2 + (f - fStart)*3 + r;
1296         PetscInt        size;
1297 
1298         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
1299         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
1300         ierr = DMPlexSetSupportSize(rdm, newp, 2+size);CHKERRQ(ierr);
1301       }
1302     }
1303     /* Interior cell edges have 2 vertices and 3 faces */
1304     for (c = cStart; c < cEnd; ++c) {
1305       for (r = 0; r < 4; ++r) {
1306         const PetscInt newp = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + r;
1307 
1308         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
1309         ierr = DMPlexSetSupportSize(rdm, newp, 3);CHKERRQ(ierr);
1310       }
1311     }
1312     /* Old vertices have identical supports */
1313     for (v = vStart; v < vEnd; ++v) {
1314       const PetscInt newp = vStartNew + (v - vStart);
1315       PetscInt       size;
1316 
1317       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
1318       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
1319     }
1320     /* Edge vertices have 2 + faces supports */
1321     for (e = eStart; e < eEnd; ++e) {
1322       const PetscInt newp = vStartNew + (vEnd - vStart) + (e - eStart);
1323       PetscInt       size;
1324 
1325       ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
1326       ierr = DMPlexSetSupportSize(rdm, newp, 2 + size);CHKERRQ(ierr);
1327     }
1328     /* Face vertices have 3 + cells supports */
1329     for (f = fStart; f < fEnd; ++f) {
1330       const PetscInt newp = vStartNew + (vEnd - vStart) + (eEnd - eStart) + f - fStart;
1331       PetscInt       size;
1332 
1333       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
1334       ierr = DMPlexSetSupportSize(rdm, newp, 3 + size);CHKERRQ(ierr);
1335     }
1336     /* Interior cell vertices have 4 supports */
1337     for (c = cStart; c < cEnd; ++c) {
1338       const PetscInt newp = vStartNew + (vEnd - vStart) + (eEnd - eStart) + fEnd - fStart + c - cStart;
1339 
1340       ierr = DMPlexSetSupportSize(rdm, newp, 4);CHKERRQ(ierr);
1341     }
1342     break;
1343   case REFINER_HYBRID_SIMPLEX_TO_HEX_3D:
1344     /* the mesh is no longer hybrid */
1345     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
1346     cMax = PetscMin(cEnd, cMax);
1347     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
1348     fMax = PetscMin(fEnd, fMax);
1349     if (eMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No edge maximum specified in hybrid mesh");
1350     eMax = PetscMin(eEnd, eMax);
1351     /* All cells have 6 faces */
1352     for (c = cStart; c < cMax; ++c) {
1353       for (r = 0; r < 4; ++r) {
1354         const PetscInt newp = cStartNew + (c - cStart)*4 + r;
1355 
1356         ierr = DMPlexSetConeSize(rdm, newp, 6);CHKERRQ(ierr);
1357       }
1358     }
1359     for (c = cMax; c < cEnd; ++c) {
1360       for (r = 0; r < 3; ++r) {
1361         const PetscInt newp = cStartNew + (cMax - cStart)*4 + (c - cMax)*3 + r;
1362 
1363         ierr = DMPlexSetConeSize(rdm, newp, 6);CHKERRQ(ierr);
1364       }
1365     }
1366     /* Interior split faces have 4 edges and the same cells as the parent */
1367     for (f = fStart; f < fMax; ++f) {
1368       for (r = 0; r < 3; ++r) {
1369         const PetscInt newp = fStartNew + (f - fStart)*3 + r;
1370         PetscInt       size;
1371 
1372         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
1373         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
1374         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
1375       }
1376     }
1377     /* Interior cell faces have 4 edges and 2 cells */
1378     for (c = cStart; c < cMax; ++c) {
1379       for (r = 0; r < 6; ++r) {
1380         const PetscInt newp = fStartNew + (fMax - fStart)*3 + (c - cStart)*6 + r;
1381 
1382         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
1383         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
1384       }
1385     }
1386     /* Hybrid split faces have 4 edges and the same cells as the parent */
1387     for (f = fMax; f < fEnd; ++f) {
1388       for (r = 0; r < 2; ++r) {
1389         const PetscInt newp = fStartNew + (fMax - fStart)*3 + (cMax - cStart)*6 + (f - fMax)*2 + r;
1390         PetscInt       size;
1391 
1392         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
1393         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
1394         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
1395       }
1396     }
1397     /* Hybrid cell faces have 4 edges and 2 cells */
1398     for (c = cMax; c < cEnd; ++c) {
1399       for (r = 0; r < 3; ++r) {
1400         const PetscInt newp = fStartNew + (fMax - fStart)*3 + (cMax - cStart)*6 + (fEnd - fMax)*2 + (c - cMax)*3 + r;
1401 
1402         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
1403         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
1404       }
1405     }
1406     /* Interior split edges have 2 vertices and the same faces */
1407     for (e = eStart; e < eMax; ++e) {
1408       for (r = 0; r < 2; ++r) {
1409         const PetscInt newp = eStartNew + (e - eStart)*2 + r;
1410         PetscInt       size;
1411 
1412         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
1413         ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
1414         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
1415       }
1416     }
1417     /* Interior face edges have 2 vertices and 2 + cell faces supports */
1418     for (f = fStart; f < fMax; ++f) {
1419       for (r = 0; r < 3; ++r) {
1420         const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (f - fStart)*3 + r;
1421         PetscInt        size;
1422 
1423         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
1424         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
1425         ierr = DMPlexSetSupportSize(rdm, newp, 2+size);CHKERRQ(ierr);
1426       }
1427     }
1428     /* Interior cell edges have 2 vertices and 3 faces */
1429     for (c = cStart; c < cMax; ++c) {
1430       for (r = 0; r < 4; ++r) {
1431         const PetscInt newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart)*4 + r;
1432 
1433         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
1434         ierr = DMPlexSetSupportSize(rdm, newp, 3);CHKERRQ(ierr);
1435       }
1436     }
1437     /* Hybrid edges have 2 vertices and the same faces */
1438     for (e = eMax; e < eEnd; ++e) {
1439       const PetscInt newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart)*4 + (e - eMax);
1440       PetscInt       size;
1441 
1442       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
1443       ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
1444       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
1445     }
1446     /* Hybrid face edges have 2 vertices and 2+cells faces */
1447     for (f = fMax; f < fEnd; ++f) {
1448       const PetscInt newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart)*4 + (eEnd - eMax) + (f - fMax);
1449       PetscInt        size;
1450 
1451       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
1452       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
1453       ierr = DMPlexSetSupportSize(rdm, newp, 2+size);CHKERRQ(ierr);
1454     }
1455     /* Hybrid cell edges have 2 vertices and 3 faces */
1456     for (c = cMax; c < cEnd; ++c) {
1457       const PetscInt newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart)*4 + (eEnd - eMax) + (fEnd - fMax) + (c - cMax);
1458 
1459       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
1460       ierr = DMPlexSetSupportSize(rdm, newp, 3);CHKERRQ(ierr);
1461     }
1462     /* Old vertices have identical supports */
1463     for (v = vStart; v < vEnd; ++v) {
1464       const PetscInt newp = vStartNew + (v - vStart);
1465       PetscInt       size;
1466 
1467       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
1468       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
1469     }
1470     /* Interior edge vertices have 2 + faces supports */
1471     for (e = eStart; e < eMax; ++e) {
1472       const PetscInt newp = vStartNew + (vEnd - vStart) + (e - eStart);
1473       PetscInt       size;
1474 
1475       ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
1476       ierr = DMPlexSetSupportSize(rdm, newp, 2 + size);CHKERRQ(ierr);
1477     }
1478     /* Interior face vertices have 3 + cells supports */
1479     for (f = fStart; f < fMax; ++f) {
1480       const PetscInt newp = vStartNew + (vEnd - vStart) + (eMax - eStart) + f - fStart;
1481       PetscInt       size;
1482 
1483       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
1484       ierr = DMPlexSetSupportSize(rdm, newp, 3 + size);CHKERRQ(ierr);
1485     }
1486     /* Interior cell vertices have 4 supports */
1487     for (c = cStart; c < cMax; ++c) {
1488       const PetscInt newp = vStartNew + (vEnd - vStart) + (eMax - eStart) + (fMax - fStart) + c - cStart;
1489 
1490       ierr = DMPlexSetSupportSize(rdm, newp, 4);CHKERRQ(ierr);
1491     }
1492     break;
1493   case REFINER_HEX_3D:
1494     /* All cells have 6 faces */
1495     for (c = cStart; c < cEnd; ++c) {
1496       for (r = 0; r < 8; ++r) {
1497         const PetscInt newp = (c - cStart)*8 + r;
1498 
1499         ierr = DMPlexSetConeSize(rdm, newp, 6);CHKERRQ(ierr);
1500       }
1501     }
1502     /* Split faces have 4 edges and the same cells as the parent */
1503     for (f = fStart; f < fEnd; ++f) {
1504       for (r = 0; r < 4; ++r) {
1505         const PetscInt newp = fStartNew + (f - fStart)*4 + r;
1506         PetscInt       size;
1507 
1508         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
1509         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
1510         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
1511       }
1512     }
1513     /* Interior faces have 4 edges and 2 cells */
1514     for (c = cStart; c < cEnd; ++c) {
1515       for (r = 0; r < 12; ++r) {
1516         const PetscInt newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + r;
1517 
1518         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
1519         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
1520       }
1521     }
1522     /* Split edges have 2 vertices and the same faces as the parent */
1523     for (e = eStart; e < eEnd; ++e) {
1524       for (r = 0; r < 2; ++r) {
1525         const PetscInt newp = eStartNew + (e - eStart)*2 + r;
1526         PetscInt       size;
1527 
1528         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
1529         ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
1530         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
1531       }
1532     }
1533     /* Face edges have 2 vertices and 2+cells faces */
1534     for (f = fStart; f < fEnd; ++f) {
1535       for (r = 0; r < 4; ++r) {
1536         const PetscInt newp = eStartNew + (eEnd - eStart)*2 + (f - fStart)*4 + r;
1537         PetscInt       size;
1538 
1539         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
1540         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
1541         ierr = DMPlexSetSupportSize(rdm, newp, 2+size);CHKERRQ(ierr);
1542       }
1543     }
1544     /* Cell edges have 2 vertices and 4 faces */
1545     for (c = cStart; c < cEnd; ++c) {
1546       for (r = 0; r < 6; ++r) {
1547         const PetscInt newp = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*4 + (c - cStart)*6 + r;
1548 
1549         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
1550         ierr = DMPlexSetSupportSize(rdm, newp, 4);CHKERRQ(ierr);
1551       }
1552     }
1553     /* Old vertices have identical supports */
1554     for (v = vStart; v < vEnd; ++v) {
1555       const PetscInt newp = vStartNew + (v - vStart);
1556       PetscInt       size;
1557 
1558       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
1559       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
1560     }
1561     /* Edge vertices have 2 + faces supports */
1562     for (e = eStart; e < eEnd; ++e) {
1563       const PetscInt newp = vStartNew + (vEnd - vStart) + (e - eStart);
1564       PetscInt       size;
1565 
1566       ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
1567       ierr = DMPlexSetSupportSize(rdm, newp, 2 + size);CHKERRQ(ierr);
1568     }
1569     /* Face vertices have 4 + cells supports */
1570     for (f = fStart; f < fEnd; ++f) {
1571       const PetscInt newp = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (f - fStart);
1572       PetscInt       size;
1573 
1574       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
1575       ierr = DMPlexSetSupportSize(rdm, newp, 4 + size);CHKERRQ(ierr);
1576     }
1577     /* Cell vertices have 6 supports */
1578     for (c = cStart; c < cEnd; ++c) {
1579       const PetscInt newp = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (fEnd - fStart) + (c - cStart);
1580 
1581       ierr = DMPlexSetSupportSize(rdm, newp, 6);CHKERRQ(ierr);
1582     }
1583     break;
1584   case REFINER_HYBRID_HEX_3D:
1585     ierr = DMPlexSetHybridBounds(rdm, cStartNew + 8*(cMax-cStart), fStartNew + 4*(fMax - fStart) + 12*(cMax - cStart),
1586                                  eStartNew + 2*(eMax - eStart) + 4*(fMax - fStart) + 6*(cMax - cStart), PETSC_DETERMINE);CHKERRQ(ierr);
1587     /* Interior cells have 6 faces */
1588     for (c = cStart; c < cMax; ++c) {
1589       for (r = 0; r < 8; ++r) {
1590         const PetscInt newp = cStartNew + (c - cStart)*8 + r;
1591 
1592         ierr = DMPlexSetConeSize(rdm, newp, 6);CHKERRQ(ierr);
1593       }
1594     }
1595     /* Hybrid cells have 6 faces */
1596     for (c = cMax; c < cEnd; ++c) {
1597       for (r = 0; r < 4; ++r) {
1598         const PetscInt newp = cStartNew + (cMax - cStart)*8 + (c - cMax)*4 + r;
1599 
1600         ierr = DMPlexSetConeSize(rdm, newp, 6);CHKERRQ(ierr);
1601       }
1602     }
1603     /* Interior split faces have 4 edges and the same cells as the parent */
1604     for (f = fStart; f < fMax; ++f) {
1605       for (r = 0; r < 4; ++r) {
1606         const PetscInt newp = fStartNew + (f - fStart)*4 + r;
1607         PetscInt       size;
1608 
1609         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
1610         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
1611         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
1612       }
1613     }
1614     /* Interior cell faces have 4 edges and 2 cells */
1615     for (c = cStart; c < cMax; ++c) {
1616       for (r = 0; r < 12; ++r) {
1617         const PetscInt newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + r;
1618 
1619         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
1620         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
1621       }
1622     }
1623     /* Hybrid split faces have 4 edges and the same cells as the parent */
1624     for (f = fMax; f < fEnd; ++f) {
1625       for (r = 0; r < 2; ++r) {
1626         const PetscInt newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (f - fMax)*2 + r;
1627         PetscInt       size;
1628 
1629         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
1630         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
1631         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
1632       }
1633     }
1634     /* Hybrid cells faces have 4 edges and 2 cells */
1635     for (c = cMax; c < cEnd; ++c) {
1636       for (r = 0; r < 4; ++r) {
1637         const PetscInt newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd - fMax)*2 + (c - cMax)*4 + r;
1638 
1639         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
1640         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
1641       }
1642     }
1643     /* Interior split edges have 2 vertices and the same faces as the parent */
1644     for (e = eStart; e < eMax; ++e) {
1645       for (r = 0; r < 2; ++r) {
1646         const PetscInt newp = eStartNew + (e - eStart)*2 + r;
1647         PetscInt       size;
1648 
1649         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
1650         ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
1651         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
1652       }
1653     }
1654     /* Interior face edges have 2 vertices and 2+cells faces */
1655     for (f = fStart; f < fMax; ++f) {
1656       for (r = 0; r < 4; ++r) {
1657         const PetscInt newp = eStartNew + (eMax - eStart)*2 + (f - fStart)*4 + r;
1658         PetscInt       size;
1659 
1660         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
1661         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
1662         ierr = DMPlexSetSupportSize(rdm, newp, 2+size);CHKERRQ(ierr);
1663       }
1664     }
1665     /* Interior cell edges have 2 vertices and 4 faces */
1666     for (c = cStart; c < cMax; ++c) {
1667       for (r = 0; r < 6; ++r) {
1668         const PetscInt newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (c - cStart)*6 + r;
1669 
1670         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
1671         ierr = DMPlexSetSupportSize(rdm, newp, 4);CHKERRQ(ierr);
1672       }
1673     }
1674     /* Hybrid edges have 2 vertices and the same faces */
1675     for (e = eMax; e < eEnd; ++e) {
1676       const PetscInt newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (e - eMax);
1677       PetscInt       size;
1678 
1679       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
1680       ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
1681       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
1682     }
1683     /* Hybrid face edges have 2 vertices and 2+cells faces */
1684     for (f = fMax; f < fEnd; ++f) {
1685       const PetscInt newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (eEnd - eMax) + (f - fMax);
1686       PetscInt       size;
1687 
1688       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
1689       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
1690       ierr = DMPlexSetSupportSize(rdm, newp, 2+size);CHKERRQ(ierr);
1691     }
1692     /* Hybrid cell edges have 2 vertices and 4 faces */
1693     for (c = cMax; c < cEnd; ++c) {
1694       const PetscInt newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (eEnd - eMax) + (fEnd - fMax) + (c - cMax);
1695 
1696       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
1697       ierr = DMPlexSetSupportSize(rdm, newp, 4);CHKERRQ(ierr);
1698     }
1699     /* Interior vertices have identical supports */
1700     for (v = vStart; v < vEnd; ++v) {
1701       const PetscInt newp = vStartNew + (v - vStart);
1702       PetscInt       size;
1703 
1704       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
1705       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
1706     }
1707     /* Interior edge vertices have 2 + faces supports */
1708     for (e = eStart; e < eMax; ++e) {
1709       const PetscInt newp = vStartNew + (vEnd - vStart) + (e - eStart);
1710       PetscInt       size;
1711 
1712       ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
1713       ierr = DMPlexSetSupportSize(rdm, newp, 2 + size);CHKERRQ(ierr);
1714     }
1715     /* Interior face vertices have 4 + cells supports */
1716     for (f = fStart; f < fMax; ++f) {
1717       const PetscInt newp = vStartNew + (vEnd - vStart) + (eMax - eStart) + (f - fStart);
1718       PetscInt       size;
1719 
1720       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
1721       ierr = DMPlexSetSupportSize(rdm, newp, 4 + size);CHKERRQ(ierr);
1722     }
1723     /* Interior cell vertices have 6 supports */
1724     for (c = cStart; c < cMax; ++c) {
1725       const PetscInt newp = vStartNew + (vEnd - vStart) + (eMax - eStart) + (fMax - fStart) + (c - cStart);
1726 
1727       ierr = DMPlexSetSupportSize(rdm, newp, 6);CHKERRQ(ierr);
1728     }
1729     break;
1730   default:
1731     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %s", CellRefiners[refiner]);
1732   }
1733   PetscFunctionReturn(0);
1734 }
1735 
1736 static PetscErrorCode CellRefinerSetCones(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
1737 {
1738   const PetscInt *faces, cellInd[4] = {0, 1, 2, 3};
1739   PetscInt        cStart,    cEnd,    cMax,    vStart,    vEnd, vMax, fStart,    fEnd,    fMax,    eStart,    eEnd,    eMax;
1740   PetscInt        cStartNew, cEndNew, cMaxNew, vStartNew, vEndNew,    fStartNew, fEndNew, fMaxNew, eStartNew, eEndNew, eMaxNew;
1741   PetscInt        depth, maxSupportSize, *supportRef, c, f, e, v, r;
1742 #if defined(PETSC_USE_DEBUG)
1743   PetscInt        p;
1744 #endif
1745   PetscErrorCode  ierr;
1746 
1747   PetscFunctionBegin;
1748   if (!refiner) PetscFunctionReturn(0);
1749   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
1750   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
1751   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
1752   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
1753   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
1754   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
1755   ierr = GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);CHKERRQ(ierr);
1756   ierr = GetDepthEnd_Private(depth, depthSize, &cEndNew, &fEndNew, &eEndNew, &vEndNew);CHKERRQ(ierr);
1757   switch (refiner) {
1758   case REFINER_SIMPLEX_1D:
1759     /* Max support size of refined mesh is 2 */
1760     ierr = PetscMalloc1(2, &supportRef);CHKERRQ(ierr);
1761     /* All cells have 2 vertices */
1762     for (c = cStart; c < cEnd; ++c) {
1763       const PetscInt  newv = vStartNew + (vEnd - vStart) + (c - cStart);
1764 
1765       for (r = 0; r < 2; ++r) {
1766         const PetscInt newp = cStartNew + (c - cStart)*2 + r;
1767         const PetscInt *cone;
1768         PetscInt        coneNew[2];
1769 
1770         ierr             = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
1771         coneNew[0]       = vStartNew + (cone[0] - vStart);
1772         coneNew[1]       = vStartNew + (cone[1] - vStart);
1773         coneNew[(r+1)%2] = newv;
1774         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
1775 #if defined(PETSC_USE_DEBUG)
1776         if ((newp < cStartNew) || (newp >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", newp, cStartNew, cEndNew);
1777         for (p = 0; p < 2; ++p) {
1778           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);
1779         }
1780 #endif
1781       }
1782     }
1783     /* Old vertices have identical supports */
1784     for (v = vStart; v < vEnd; ++v) {
1785       const PetscInt  newp = vStartNew + (v - vStart);
1786       const PetscInt *support, *cone;
1787       PetscInt        size, s;
1788 
1789       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
1790       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
1791       for (s = 0; s < size; ++s) {
1792         PetscInt r = 0;
1793 
1794         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
1795         if (cone[1] == v) r = 1;
1796         supportRef[s] = cStartNew + (support[s] - cStart)*2 + r;
1797       }
1798       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
1799 #if defined(PETSC_USE_DEBUG)
1800       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", newp, vStartNew, vEndNew);
1801       for (p = 0; p < size; ++p) {
1802         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);
1803       }
1804 #endif
1805     }
1806     /* Cell vertices have support of 2 cells */
1807     for (c = cStart; c < cEnd; ++c) {
1808       const PetscInt  newp = vStartNew + (vEnd - vStart) + (c - cStart);
1809 
1810       supportRef[0] = cStartNew + (c - cStart)*2 + 0;
1811       supportRef[1] = cStartNew + (c - cStart)*2 + 1;
1812       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
1813 #if defined(PETSC_USE_DEBUG)
1814       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", newp, vStartNew, vEndNew);
1815       for (p = 0; p < 2; ++p) {
1816         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);
1817       }
1818 #endif
1819     }
1820     ierr = PetscFree(supportRef);CHKERRQ(ierr);
1821     break;
1822   case REFINER_SIMPLEX_2D:
1823     /*
1824      2
1825      |\
1826      | \
1827      |  \
1828      |   \
1829      | C  \
1830      |     \
1831      |      \
1832      2---1---1
1833      |\  D  / \
1834      | 2   0   \
1835      |A \ /  B  \
1836      0---0-------1
1837      */
1838     /* All cells have 3 faces */
1839     for (c = cStart; c < cEnd; ++c) {
1840       const PetscInt  newp = cStartNew + (c - cStart)*4;
1841       const PetscInt *cone, *ornt;
1842       PetscInt        coneNew[3], orntNew[3];
1843 
1844       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
1845       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
1846       /* A triangle */
1847       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
1848       orntNew[0] = ornt[0];
1849       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 2;
1850       orntNew[1] = -2;
1851       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
1852       orntNew[2] = ornt[2];
1853       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
1854       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
1855 #if defined(PETSC_USE_DEBUG)
1856       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);
1857       for (p = 0; p < 3; ++p) {
1858         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);
1859       }
1860 #endif
1861       /* B triangle */
1862       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
1863       orntNew[0] = ornt[0];
1864       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
1865       orntNew[1] = ornt[1];
1866       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 0;
1867       orntNew[2] = -2;
1868       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
1869       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
1870 #if defined(PETSC_USE_DEBUG)
1871       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);
1872       for (p = 0; p < 3; ++p) {
1873         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);
1874       }
1875 #endif
1876       /* C triangle */
1877       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 1;
1878       orntNew[0] = -2;
1879       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
1880       orntNew[1] = ornt[1];
1881       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
1882       orntNew[2] = ornt[2];
1883       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
1884       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
1885 #if defined(PETSC_USE_DEBUG)
1886       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);
1887       for (p = 0; p < 3; ++p) {
1888         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);
1889       }
1890 #endif
1891       /* D triangle */
1892       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 0;
1893       orntNew[0] = 0;
1894       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 1;
1895       orntNew[1] = 0;
1896       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 2;
1897       orntNew[2] = 0;
1898       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
1899       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
1900 #if defined(PETSC_USE_DEBUG)
1901       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);
1902       for (p = 0; p < 3; ++p) {
1903         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);
1904       }
1905 #endif
1906     }
1907     /* Split faces have 2 vertices and the same cells as the parent */
1908     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
1909     ierr = PetscMalloc1(2 + maxSupportSize*2, &supportRef);CHKERRQ(ierr);
1910     for (f = fStart; f < fEnd; ++f) {
1911       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);
1912 
1913       for (r = 0; r < 2; ++r) {
1914         const PetscInt  newp = fStartNew + (f - fStart)*2 + r;
1915         const PetscInt *cone, *ornt, *support;
1916         PetscInt        coneNew[2], coneSize, c, supportSize, s;
1917 
1918         ierr             = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
1919         coneNew[0]       = vStartNew + (cone[0] - vStart);
1920         coneNew[1]       = vStartNew + (cone[1] - vStart);
1921         coneNew[(r+1)%2] = newv;
1922         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
1923 #if defined(PETSC_USE_DEBUG)
1924         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
1925         for (p = 0; p < 2; ++p) {
1926           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);
1927         }
1928 #endif
1929         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
1930         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
1931         for (s = 0; s < supportSize; ++s) {
1932           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
1933           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
1934           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
1935           for (c = 0; c < coneSize; ++c) {
1936             if (cone[c] == f) break;
1937           }
1938           supportRef[s] = cStartNew + (support[s] - cStart)*4 + (ornt[c] < 0 ? (c+1-r)%3 : (c+r)%3);
1939         }
1940         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
1941 #if defined(PETSC_USE_DEBUG)
1942         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
1943         for (p = 0; p < supportSize; ++p) {
1944           if ((supportRef[p] < cStartNew) || (supportRef[p] >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", supportRef[p], cStartNew, cEndNew);
1945         }
1946 #endif
1947       }
1948     }
1949     /* Interior faces have 2 vertices and 2 cells */
1950     for (c = cStart; c < cEnd; ++c) {
1951       const PetscInt *cone;
1952 
1953       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
1954       for (r = 0; r < 3; ++r) {
1955         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*3 + r;
1956         PetscInt       coneNew[2];
1957         PetscInt       supportNew[2];
1958 
1959         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r]       - fStart);
1960         coneNew[1] = vStartNew + (vEnd - vStart) + (cone[(r+1)%3] - fStart);
1961         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
1962 #if defined(PETSC_USE_DEBUG)
1963         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
1964         for (p = 0; p < 2; ++p) {
1965           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);
1966         }
1967 #endif
1968         supportNew[0] = (c - cStart)*4 + (r+1)%3;
1969         supportNew[1] = (c - cStart)*4 + 3;
1970         ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
1971 #if defined(PETSC_USE_DEBUG)
1972         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
1973         for (p = 0; p < 2; ++p) {
1974           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);
1975         }
1976 #endif
1977       }
1978     }
1979     /* Old vertices have identical supports */
1980     for (v = vStart; v < vEnd; ++v) {
1981       const PetscInt  newp = vStartNew + (v - vStart);
1982       const PetscInt *support, *cone;
1983       PetscInt        size, s;
1984 
1985       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
1986       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
1987       for (s = 0; s < size; ++s) {
1988         PetscInt r = 0;
1989 
1990         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
1991         if (cone[1] == v) r = 1;
1992         supportRef[s] = fStartNew + (support[s] - fStart)*2 + r;
1993       }
1994       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
1995 #if defined(PETSC_USE_DEBUG)
1996       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", newp, vStartNew, vEndNew);
1997       for (p = 0; p < size; ++p) {
1998         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);
1999       }
2000 #endif
2001     }
2002     /* Face vertices have 2 + cells*2 supports */
2003     for (f = fStart; f < fEnd; ++f) {
2004       const PetscInt  newp = vStartNew + (vEnd - vStart) + (f - fStart);
2005       const PetscInt *cone, *support;
2006       PetscInt        size, s;
2007 
2008       ierr          = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
2009       ierr          = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
2010       supportRef[0] = fStartNew + (f - fStart)*2 + 0;
2011       supportRef[1] = fStartNew + (f - fStart)*2 + 1;
2012       for (s = 0; s < size; ++s) {
2013         PetscInt r = 0;
2014 
2015         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
2016         if      (cone[1] == f) r = 1;
2017         else if (cone[2] == f) r = 2;
2018         supportRef[2+s*2+0] = fStartNew + (fEnd - fStart)*2 + (support[s] - cStart)*3 + (r+2)%3;
2019         supportRef[2+s*2+1] = fStartNew + (fEnd - fStart)*2 + (support[s] - cStart)*3 + r;
2020       }
2021       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
2022 #if defined(PETSC_USE_DEBUG)
2023       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", newp, vStartNew, vEndNew);
2024       for (p = 0; p < 2+size*2; ++p) {
2025         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);
2026       }
2027 #endif
2028     }
2029     ierr = PetscFree(supportRef);CHKERRQ(ierr);
2030     break;
2031   case REFINER_SIMPLEX_TO_HEX_2D:
2032     /*
2033      2
2034      |\
2035      | \
2036      |  \
2037      |   \
2038      | C  \
2039      |     \
2040      2      1
2041      |\    / \
2042      | 2  1   \
2043      |  \/     \
2044      |   |      \
2045      |A  |   B   \
2046      |   0        \
2047      |   |         \
2048      0---0----------1
2049      */
2050     /* All cells have 4 faces */
2051     for (c = cStart; c < cEnd; ++c) {
2052       const PetscInt  newp = cStartNew + (c - cStart)*3;
2053       const PetscInt *cone, *ornt;
2054       PetscInt        coneNew[4], orntNew[4];
2055 
2056       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
2057       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
2058       /* A quad */
2059       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
2060       orntNew[0] = ornt[0];
2061       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 0;
2062       orntNew[1] = 0;
2063       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 2;
2064       orntNew[2] = -2;
2065       coneNew[3] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
2066       orntNew[3] = ornt[2];
2067       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
2068       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
2069 #if defined(PETSC_USE_DEBUG)
2070       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);
2071       for (p = 0; p < 4; ++p) {
2072         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);
2073       }
2074 #endif
2075       /* B quad */
2076       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
2077       orntNew[0] = ornt[0];
2078       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
2079       orntNew[1] = ornt[1];
2080       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 1;
2081       orntNew[2] = 0;
2082       coneNew[3] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 0;
2083       orntNew[3] = -2;
2084       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
2085       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
2086 #if defined(PETSC_USE_DEBUG)
2087       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);
2088       for (p = 0; p < 4; ++p) {
2089         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);
2090       }
2091 #endif
2092       /* C quad */
2093       coneNew[0] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
2094       orntNew[0] = ornt[1];
2095       coneNew[1] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
2096       orntNew[1] = ornt[2];
2097       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 2;
2098       orntNew[2] = 0;
2099       coneNew[3] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 1;
2100       orntNew[3] = -2;
2101       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
2102       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
2103 #if defined(PETSC_USE_DEBUG)
2104       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);
2105       for (p = 0; p < 4; ++p) {
2106         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);
2107       }
2108 #endif
2109     }
2110     /* Split faces have 2 vertices and the same cells as the parent */
2111     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
2112     ierr = PetscMalloc1(2 + maxSupportSize*2, &supportRef);CHKERRQ(ierr);
2113     for (f = fStart; f < fEnd; ++f) {
2114       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);
2115 
2116       for (r = 0; r < 2; ++r) {
2117         const PetscInt  newp = fStartNew + (f - fStart)*2 + r;
2118         const PetscInt *cone, *ornt, *support;
2119         PetscInt        coneNew[2], coneSize, c, supportSize, s;
2120 
2121         ierr             = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
2122         coneNew[0]       = vStartNew + (cone[0] - vStart);
2123         coneNew[1]       = vStartNew + (cone[1] - vStart);
2124         coneNew[(r+1)%2] = newv;
2125         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2126 #if defined(PETSC_USE_DEBUG)
2127         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
2128         for (p = 0; p < 2; ++p) {
2129           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);
2130         }
2131 #endif
2132         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
2133         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
2134         for (s = 0; s < supportSize; ++s) {
2135           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
2136           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
2137           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
2138           for (c = 0; c < coneSize; ++c) {
2139             if (cone[c] == f) break;
2140           }
2141           supportRef[s] = cStartNew + (support[s] - cStart)*3 + (ornt[c] < 0 ? (c+1-r)%3 : (c+r)%3);
2142         }
2143         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
2144 #if defined(PETSC_USE_DEBUG)
2145         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
2146         for (p = 0; p < supportSize; ++p) {
2147           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);
2148         }
2149 #endif
2150       }
2151     }
2152     /* Interior faces have 2 vertices and 2 cells */
2153     for (c = cStart; c < cEnd; ++c) {
2154       const PetscInt *cone;
2155 
2156       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
2157       for (r = 0; r < 3; ++r) {
2158         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*3 + r;
2159         PetscInt       coneNew[2];
2160         PetscInt       supportNew[2];
2161 
2162         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r] - fStart);
2163         coneNew[1] = vStartNew + (vEnd - vStart) + (fEnd    - fStart) + (c - cStart);
2164         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2165 #if defined(PETSC_USE_DEBUG)
2166         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
2167         for (p = 0; p < 2; ++p) {
2168           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);
2169         }
2170 #endif
2171         supportNew[0] = (c - cStart)*3 + r%3;
2172         supportNew[1] = (c - cStart)*3 + (r+1)%3;
2173         ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
2174 #if defined(PETSC_USE_DEBUG)
2175         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
2176         for (p = 0; p < 2; ++p) {
2177           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);
2178         }
2179 #endif
2180       }
2181     }
2182     /* Old vertices have identical supports */
2183     for (v = vStart; v < vEnd; ++v) {
2184       const PetscInt  newp = vStartNew + (v - vStart);
2185       const PetscInt *support, *cone;
2186       PetscInt        size, s;
2187 
2188       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
2189       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
2190       for (s = 0; s < size; ++s) {
2191         PetscInt r = 0;
2192 
2193         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
2194         if (cone[1] == v) r = 1;
2195         supportRef[s] = fStartNew + (support[s] - fStart)*2 + r;
2196       }
2197       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
2198 #if defined(PETSC_USE_DEBUG)
2199       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", newp, vStartNew, vEndNew);
2200       for (p = 0; p < size; ++p) {
2201         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);
2202       }
2203 #endif
2204     }
2205     /* Split-face vertices have cells + 2 supports */
2206     for (f = fStart; f < fEnd; ++f) {
2207       const PetscInt  newp = vStartNew + (vEnd - vStart) + (f - fStart);
2208       const PetscInt *cone, *support;
2209       PetscInt        size, s;
2210 
2211       ierr          = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
2212       ierr          = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
2213       supportRef[0] = fStartNew + (f - fStart)*2 + 0;
2214       supportRef[1] = fStartNew + (f - fStart)*2 + 1;
2215       for (s = 0; s < size; ++s) {
2216         PetscInt r = 0;
2217 
2218         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
2219         if      (cone[1] == f) r = 1;
2220         else if (cone[2] == f) r = 2;
2221         supportRef[2+s+0] = fStartNew + (fEnd - fStart)*2 + (support[s] - cStart)*3 + r;
2222       }
2223       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
2224 #if defined(PETSC_USE_DEBUG)
2225       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", newp, vStartNew, vEndNew);
2226       for (p = 0; p < 2+size; ++p) {
2227         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);
2228       }
2229 #endif
2230     }
2231     /* Interior vertices have 3 supports */
2232     for (c = cStart; c < cEnd; ++c) {
2233       const PetscInt newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + c - cStart;
2234 
2235       supportRef[0] = fStartNew + (fEnd - fStart)*2 + (c - cStart)*3 + 0;
2236       supportRef[1] = fStartNew + (fEnd - fStart)*2 + (c - cStart)*3 + 1;
2237       supportRef[2] = fStartNew + (fEnd - fStart)*2 + (c - cStart)*3 + 2;
2238       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
2239     }
2240     ierr = PetscFree(supportRef);CHKERRQ(ierr);
2241     break;
2242   case REFINER_HYBRID_SIMPLEX_TO_HEX_2D:
2243     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
2244     cMax = PetscMin(cEnd, cMax);
2245     for (c = cStart; c < cMax; ++c) {
2246       const PetscInt  newp = cStartNew + (c - cStart)*3;
2247       const PetscInt *cone, *ornt;
2248       PetscInt        coneNew[4], orntNew[4];
2249 
2250       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
2251       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
2252       /* A quad */
2253       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
2254       orntNew[0] = ornt[0];
2255       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 0;
2256       orntNew[1] = 0;
2257       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 2;
2258       orntNew[2] = -2;
2259       coneNew[3] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
2260       orntNew[3] = ornt[2];
2261       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
2262       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
2263 #if defined(PETSC_USE_DEBUG)
2264       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);
2265       for (p = 0; p < 4; ++p) {
2266         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);
2267       }
2268 #endif
2269       /* B quad */
2270       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
2271       orntNew[0] = ornt[0];
2272       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
2273       orntNew[1] = ornt[1];
2274       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 1;
2275       orntNew[2] = 0;
2276       coneNew[3] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 0;
2277       orntNew[3] = -2;
2278       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
2279       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
2280 #if defined(PETSC_USE_DEBUG)
2281       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);
2282       for (p = 0; p < 4; ++p) {
2283         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);
2284       }
2285 #endif
2286       /* C quad */
2287       coneNew[0] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
2288       orntNew[0] = ornt[1];
2289       coneNew[1] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
2290       orntNew[1] = ornt[2];
2291       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 2;
2292       orntNew[2] = 0;
2293       coneNew[3] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 1;
2294       orntNew[3] = -2;
2295       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
2296       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
2297 #if defined(PETSC_USE_DEBUG)
2298       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);
2299       for (p = 0; p < 4; ++p) {
2300         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);
2301       }
2302 #endif
2303     }
2304     /*
2305      2---------1---------3
2306      |         |         |
2307      |    D    1    C    |
2308      |         |         |
2309      2----2----0----3----3
2310      |         |         |
2311      |    A    0    B    |
2312      |         |         |
2313      0---------0---------1
2314      */
2315     /* Parent cells are input as prisms but children are quads, since the mesh is no longer hybrid */
2316     for (c = cMax; c < cEnd; ++c) {
2317       const PetscInt  newp  = cStartNew + (cMax - cStart)*3 + (c - cMax)*4;
2318       const PetscInt  newpt = (cMax - cStart)*3 + (c - cMax)*4;
2319       const PetscInt *cone, *ornt;
2320       PetscInt        coneNew[4], orntNew[4];
2321 
2322       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
2323       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
2324       /* A quad */
2325       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
2326       orntNew[0] = ornt[0];
2327       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + newpt + 0;
2328       orntNew[1] = 0;
2329       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + newpt + 2;
2330       orntNew[2] = -2;
2331       coneNew[3] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
2332       orntNew[3] = ornt[2] < 0 ? 0 : -2;
2333       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
2334       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
2335 #if defined(PETSC_USE_DEBUG)
2336       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);
2337       for (p = 0; p < 4; ++p) {
2338         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);
2339       }
2340 #endif
2341       /* B quad */
2342       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
2343       orntNew[0] = ornt[0];
2344       coneNew[1] = fStartNew + (cone[3] - fStart)*2 + (ornt[3] < 0 ? 1 : 0);
2345       orntNew[1] = ornt[3];
2346       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + newpt + 3;
2347       orntNew[2] = 0;
2348       coneNew[3] = fStartNew + (fEnd    - fStart)*2 + newpt + 0;
2349       orntNew[3] = -2;
2350       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
2351       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
2352 #if defined(PETSC_USE_DEBUG)
2353       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);
2354       for (p = 0; p < 4; ++p) {
2355         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);
2356       }
2357 #endif
2358       /* C quad */
2359       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + newpt + 3;
2360       orntNew[0] = -2;
2361       coneNew[1] = fStartNew + (cone[3] - fStart)*2 + (ornt[3] < 0 ? 0 : 1);
2362       orntNew[1] = ornt[3];
2363       coneNew[2] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
2364       orntNew[2] = ornt[1] < 0 ? 0 : -2;
2365       coneNew[3] = fStartNew + (fEnd    - fStart)*2 + newpt + 1;
2366       orntNew[3] = 0;
2367       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
2368       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
2369 #if defined(PETSC_USE_DEBUG)
2370       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);
2371       for (p = 0; p < 4; ++p) {
2372         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);
2373       }
2374 #endif
2375       /* D quad */
2376       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + newpt + 2;
2377       orntNew[0] = 0;
2378       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + newpt + 1;
2379       orntNew[1] = -2;
2380       coneNew[2] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
2381       orntNew[2] = ornt[1] < 0 ? 0 : -2;
2382       coneNew[3] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
2383       orntNew[3] = ornt[2] < 0 ? 0 : -2;
2384       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
2385       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
2386 #if defined(PETSC_USE_DEBUG)
2387       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);
2388       for (p = 0; p < 4; ++p) {
2389         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);
2390       }
2391 #endif
2392     }
2393     /* Split faces have 2 vertices and the same cells as the parent */
2394     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
2395     ierr = PetscMalloc1(2 + maxSupportSize*2, &supportRef);CHKERRQ(ierr);
2396     for (f = fStart; f < fEnd; ++f) {
2397       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);
2398 
2399       for (r = 0; r < 2; ++r) {
2400         const PetscInt  newp = fStartNew + (f - fStart)*2 + r;
2401         const PetscInt *cone, *ornt, *support;
2402         PetscInt        coneNew[2], coneSize, c, supportSize, s;
2403 
2404         ierr             = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
2405         coneNew[0]       = vStartNew + (cone[0] - vStart);
2406         coneNew[1]       = vStartNew + (cone[1] - vStart);
2407         coneNew[(r+1)%2] = newv;
2408         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2409 #if defined(PETSC_USE_DEBUG)
2410         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
2411         for (p = 0; p < 2; ++p) {
2412           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);
2413         }
2414 #endif
2415         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
2416         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
2417         for (s = 0; s < supportSize; ++s) {
2418           const PetscInt p2q[4][2] = { {0, 1},
2419                                        {3, 2},
2420                                        {0, 3},
2421                                        {1, 2} };
2422 
2423           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
2424           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
2425           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
2426           for (c = 0; c < coneSize; ++c) {
2427             if (cone[c] == f) break;
2428           }
2429           if (coneSize == 3)      supportRef[s] = cStartNew + (support[s] - cStart)*3 + (ornt[c] < 0 ? (c+1-r)%3 : (c+r)%3);
2430           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]);
2431           else SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected cone size %D", coneSize);
2432         }
2433         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
2434 #if defined(PETSC_USE_DEBUG)
2435         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
2436         for (p = 0; p < supportSize; ++p) {
2437           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);
2438         }
2439 #endif
2440       }
2441     }
2442     /* Interior faces have 2 vertices and 2 cells */
2443     for (c = cStart; c < cMax; ++c) {
2444       const PetscInt *cone;
2445 
2446       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
2447       for (r = 0; r < 3; ++r) {
2448         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*3 + r;
2449         PetscInt       coneNew[2];
2450         PetscInt       supportNew[2];
2451 
2452         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r] - fStart);
2453         coneNew[1] = vStartNew + (vEnd - vStart) + (fEnd    - fStart) + (c - cStart);
2454         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2455 #if defined(PETSC_USE_DEBUG)
2456         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
2457         for (p = 0; p < 2; ++p) {
2458           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);
2459         }
2460 #endif
2461         supportNew[0] = (c - cStart)*3 + r%3;
2462         supportNew[1] = (c - cStart)*3 + (r+1)%3;
2463         ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
2464 #if defined(PETSC_USE_DEBUG)
2465         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
2466         for (p = 0; p < 2; ++p) {
2467           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);
2468         }
2469 #endif
2470       }
2471     }
2472     /* Hybrid interior faces have 2 vertices and 2 cells */
2473     for (c = cMax; c < cEnd; ++c) {
2474       const PetscInt *cone;
2475       PetscInt        coneNew[2], supportNew[2];
2476 
2477       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
2478       for (r = 0; r < 4; ++r) {
2479         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (cMax - cStart)*3 + (c - cMax)*4 + r;
2480 
2481         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r] - fStart);
2482         coneNew[1] = vStartNew + (vEnd - vStart) + (fEnd    - fStart) + (cMax - cStart) + (c - cMax);
2483 	ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2484 #if defined(PETSC_USE_DEBUG)
2485         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
2486         for (p = 0; p < 2; ++p) {
2487           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);
2488         }
2489 #endif
2490         if (r==0) {
2491           supportNew[0] = (cMax - cStart)*3 + (c - cMax)*4 + 0;
2492           supportNew[1] = (cMax - cStart)*3 + (c - cMax)*4 + 1;
2493         } else if (r==1) {
2494           supportNew[0] = (cMax - cStart)*3 + (c - cMax)*4 + 2;
2495           supportNew[1] = (cMax - cStart)*3 + (c - cMax)*4 + 3;
2496         } else if (r==2) {
2497           supportNew[0] = (cMax - cStart)*3 + (c - cMax)*4 + 0;
2498           supportNew[1] = (cMax - cStart)*3 + (c - cMax)*4 + 3;
2499         } else {
2500           supportNew[0] = (cMax - cStart)*3 + (c - cMax)*4 + 1;
2501           supportNew[1] = (cMax - cStart)*3 + (c - cMax)*4 + 2;
2502         }
2503         ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
2504 #if defined(PETSC_USE_DEBUG)
2505         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
2506         for (p = 0; p < 2; ++p) {
2507           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);
2508         }
2509 #endif
2510       }
2511     }
2512     /* Old vertices have identical supports */
2513     for (v = vStart; v < vEnd; ++v) {
2514       const PetscInt  newp = vStartNew + (v - vStart);
2515       const PetscInt *support, *cone;
2516       PetscInt        size, s;
2517 
2518       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
2519       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
2520       for (s = 0; s < size; ++s) {
2521         PetscInt r = 0;
2522 
2523         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
2524         if (cone[1] == v) r = 1;
2525         supportRef[s] = fStartNew + (support[s] - fStart)*2 + r;
2526       }
2527       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
2528 #if defined(PETSC_USE_DEBUG)
2529       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", newp, vStartNew, vEndNew);
2530       for (p = 0; p < size; ++p) {
2531         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);
2532       }
2533 #endif
2534     }
2535     /* Split-face vertices have cells + 2 supports */
2536     for (f = fStart; f < fEnd; ++f) {
2537       const PetscInt  newp = vStartNew + (vEnd - vStart) + (f - fStart);
2538       const PetscInt *cone, *support;
2539       PetscInt        size, s;
2540 
2541       ierr          = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
2542       ierr          = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
2543       supportRef[0] = fStartNew + (f - fStart)*2 + 0;
2544       supportRef[1] = fStartNew + (f - fStart)*2 + 1;
2545       for (s = 0; s < size; ++s) {
2546         PetscInt r = 0, coneSize;
2547 
2548         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
2549         ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
2550         if (coneSize == 3) {
2551           if      (cone[1] == f) r = 1;
2552           else if (cone[2] == f) r = 2;
2553           supportRef[2+s] = fStartNew + (fEnd - fStart)*2 + (support[s] - cStart)*3 + r;
2554         } else if (coneSize == 4) {
2555           if      (cone[1] == f) r = 1;
2556           else if (cone[2] == f) r = 2;
2557           else if (cone[3] == f) r = 3;
2558           supportRef[2+s] = fStartNew + (fEnd - fStart)*2 + (cMax - cStart)*3 + (support[s] - cMax)*4 + r;
2559         } else SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected cone size %D", coneSize);
2560       }
2561       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
2562 #if defined(PETSC_USE_DEBUG)
2563       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", newp, vStartNew, vEndNew);
2564       for (p = 0; p < 2+size; ++p) {
2565         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);
2566       }
2567 #endif
2568     }
2569     /* Interior vertices have 3 supports */
2570     for (c = cStart; c < cMax; ++c) {
2571       const PetscInt newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + c - cStart;
2572 
2573       supportRef[0] = fStartNew + (fEnd - fStart)*2 + (c - cStart)*3 + 0;
2574       supportRef[1] = fStartNew + (fEnd - fStart)*2 + (c - cStart)*3 + 1;
2575       supportRef[2] = fStartNew + (fEnd - fStart)*2 + (c - cStart)*3 + 2;
2576       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
2577     }
2578     /* Hybrid interior vertices have 4 supports */
2579     for (c = cMax; c < cEnd; ++c) {
2580       const PetscInt newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + c - cStart;
2581 
2582       supportRef[0] = fStartNew + (fEnd - fStart)*2 + (cMax - cStart)*3 + (c - cMax)*4 + 0;
2583       supportRef[1] = fStartNew + (fEnd - fStart)*2 + (cMax - cStart)*3 + (c - cMax)*4 + 1;
2584       supportRef[2] = fStartNew + (fEnd - fStart)*2 + (cMax - cStart)*3 + (c - cMax)*4 + 2;
2585       supportRef[3] = fStartNew + (fEnd - fStart)*2 + (cMax - cStart)*3 + (c - cMax)*4 + 3;
2586       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
2587     }
2588     ierr = PetscFree(supportRef);CHKERRQ(ierr);
2589     break;
2590   case REFINER_HEX_2D:
2591     /*
2592      3---------2---------2
2593      |         |         |
2594      |    D    2    C    |
2595      |         |         |
2596      3----3----0----1----1
2597      |         |         |
2598      |    A    0    B    |
2599      |         |         |
2600      0---------0---------1
2601      */
2602     /* All cells have 4 faces */
2603     for (c = cStart; c < cEnd; ++c) {
2604       const PetscInt  newp = (c - cStart)*4;
2605       const PetscInt *cone, *ornt;
2606       PetscInt        coneNew[4], orntNew[4];
2607 
2608       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
2609       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
2610       /* A quad */
2611       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
2612       orntNew[0] = ornt[0];
2613       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 0;
2614       orntNew[1] = 0;
2615       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 3;
2616       orntNew[2] = -2;
2617       coneNew[3] = fStartNew + (cone[3] - fStart)*2 + (ornt[3] < 0 ? 0 : 1);
2618       orntNew[3] = ornt[3];
2619       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
2620       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
2621 #if defined(PETSC_USE_DEBUG)
2622       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);
2623       for (p = 0; p < 4; ++p) {
2624         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);
2625       }
2626 #endif
2627       /* B quad */
2628       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
2629       orntNew[0] = ornt[0];
2630       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
2631       orntNew[1] = ornt[1];
2632       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 1;
2633       orntNew[2] = -2;
2634       coneNew[3] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 0;
2635       orntNew[3] = -2;
2636       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
2637       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
2638 #if defined(PETSC_USE_DEBUG)
2639       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);
2640       for (p = 0; p < 4; ++p) {
2641         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);
2642       }
2643 #endif
2644       /* C quad */
2645       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 1;
2646       orntNew[0] = 0;
2647       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
2648       orntNew[1] = ornt[1];
2649       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
2650       orntNew[2] = ornt[2];
2651       coneNew[3] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 2;
2652       orntNew[3] = -2;
2653       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
2654       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
2655 #if defined(PETSC_USE_DEBUG)
2656       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);
2657       for (p = 0; p < 4; ++p) {
2658         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);
2659       }
2660 #endif
2661       /* D quad */
2662       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 3;
2663       orntNew[0] = 0;
2664       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 2;
2665       orntNew[1] = 0;
2666       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
2667       orntNew[2] = ornt[2];
2668       coneNew[3] = fStartNew + (cone[3] - fStart)*2 + (ornt[3] < 0 ? 1 : 0);
2669       orntNew[3] = ornt[3];
2670       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
2671       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
2672 #if defined(PETSC_USE_DEBUG)
2673       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);
2674       for (p = 0; p < 4; ++p) {
2675         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);
2676       }
2677 #endif
2678     }
2679     /* Split faces have 2 vertices and the same cells as the parent */
2680     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
2681     ierr = PetscMalloc1(2 + maxSupportSize*2, &supportRef);CHKERRQ(ierr);
2682     for (f = fStart; f < fEnd; ++f) {
2683       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);
2684 
2685       for (r = 0; r < 2; ++r) {
2686         const PetscInt  newp = fStartNew + (f - fStart)*2 + r;
2687         const PetscInt *cone, *ornt, *support;
2688         PetscInt        coneNew[2], coneSize, c, supportSize, s;
2689 
2690         ierr             = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
2691         coneNew[0]       = vStartNew + (cone[0] - vStart);
2692         coneNew[1]       = vStartNew + (cone[1] - vStart);
2693         coneNew[(r+1)%2] = newv;
2694         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2695 #if defined(PETSC_USE_DEBUG)
2696         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
2697         for (p = 0; p < 2; ++p) {
2698           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);
2699         }
2700 #endif
2701         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
2702         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
2703         for (s = 0; s < supportSize; ++s) {
2704           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
2705           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
2706           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
2707           for (c = 0; c < coneSize; ++c) {
2708             if (cone[c] == f) break;
2709           }
2710           supportRef[s] = cStartNew + (support[s] - cStart)*4 + (ornt[c] < 0 ? (c+1-r)%4 : (c+r)%4);
2711         }
2712         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
2713 #if defined(PETSC_USE_DEBUG)
2714         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
2715         for (p = 0; p < supportSize; ++p) {
2716           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);
2717         }
2718 #endif
2719       }
2720     }
2721     /* Interior faces have 2 vertices and 2 cells */
2722     for (c = cStart; c < cEnd; ++c) {
2723       const PetscInt *cone;
2724       PetscInt        coneNew[2], supportNew[2];
2725 
2726       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
2727       for (r = 0; r < 4; ++r) {
2728         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*4 + r;
2729 
2730 	if (r==1 || r==2) {
2731           coneNew[0] = vStartNew + (vEnd - vStart) + (fEnd    - fStart) + (c - cStart);
2732           coneNew[1] = vStartNew + (vEnd - vStart) + (cone[r] - fStart);
2733 	} else {
2734           coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r] - fStart);
2735           coneNew[1] = vStartNew + (vEnd - vStart) + (fEnd    - fStart) + (c - cStart);
2736 	}
2737 	ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2738 #if defined(PETSC_USE_DEBUG)
2739         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
2740         for (p = 0; p < 2; ++p) {
2741           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);
2742         }
2743 #endif
2744         supportNew[0] = (c - cStart)*4 + r;
2745         supportNew[1] = (c - cStart)*4 + (r+1)%4;
2746         ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
2747 #if defined(PETSC_USE_DEBUG)
2748         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
2749         for (p = 0; p < 2; ++p) {
2750           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);
2751         }
2752 #endif
2753       }
2754     }
2755     /* Old vertices have identical supports */
2756     for (v = vStart; v < vEnd; ++v) {
2757       const PetscInt  newp = vStartNew + (v - vStart);
2758       const PetscInt *support, *cone;
2759       PetscInt        size, s;
2760 
2761       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
2762       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
2763       for (s = 0; s < size; ++s) {
2764         PetscInt r = 0;
2765 
2766         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
2767         if (cone[1] == v) r = 1;
2768         supportRef[s] = fStartNew + (support[s] - fStart)*2 + r;
2769       }
2770       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
2771 #if defined(PETSC_USE_DEBUG)
2772       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", newp, vStartNew, vEndNew);
2773       for (p = 0; p < size; ++p) {
2774         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);
2775       }
2776 #endif
2777     }
2778     /* Face vertices have 2 + cells supports */
2779     for (f = fStart; f < fEnd; ++f) {
2780       const PetscInt  newp = vStartNew + (vEnd - vStart) + (f - fStart);
2781       const PetscInt *cone, *support;
2782       PetscInt        size, s;
2783 
2784       ierr          = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
2785       ierr          = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
2786       supportRef[0] = fStartNew + (f - fStart)*2 + 0;
2787       supportRef[1] = fStartNew + (f - fStart)*2 + 1;
2788       for (s = 0; s < size; ++s) {
2789         PetscInt r = 0;
2790 
2791         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
2792         if      (cone[1] == f) r = 1;
2793         else if (cone[2] == f) r = 2;
2794         else if (cone[3] == f) r = 3;
2795         supportRef[2+s] = fStartNew + (fEnd - fStart)*2 + (support[s] - cStart)*4 + r;
2796       }
2797       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
2798 #if defined(PETSC_USE_DEBUG)
2799       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", newp, vStartNew, vEndNew);
2800       for (p = 0; p < 2+size; ++p) {
2801         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);
2802       }
2803 #endif
2804     }
2805     /* Cell vertices have 4 supports */
2806     for (c = cStart; c < cEnd; ++c) {
2807       const PetscInt newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (c - cStart);
2808       PetscInt       supportNew[4];
2809 
2810       for (r = 0; r < 4; ++r) {
2811         supportNew[r] = fStartNew + (fEnd - fStart)*2 + (c - cStart)*4 + r;
2812       }
2813       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
2814     }
2815     ierr = PetscFree(supportRef);CHKERRQ(ierr);
2816     break;
2817   case REFINER_HYBRID_SIMPLEX_2D:
2818     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
2819     cMax = PetscMin(cEnd, cMax);
2820     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
2821     fMax = PetscMin(fEnd, fMax);
2822     ierr = DMPlexGetHybridBounds(rdm, &cMaxNew, &fMaxNew, NULL, NULL);CHKERRQ(ierr);
2823     /* Interior cells have 3 faces */
2824     for (c = cStart; c < cMax; ++c) {
2825       const PetscInt  newp = cStartNew + (c - cStart)*4;
2826       const PetscInt *cone, *ornt;
2827       PetscInt        coneNew[3], orntNew[3];
2828 
2829       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
2830       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
2831       /* A triangle */
2832       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
2833       orntNew[0] = ornt[0];
2834       coneNew[1] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 2;
2835       orntNew[1] = -2;
2836       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
2837       orntNew[2] = ornt[2];
2838       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
2839       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
2840 #if defined(PETSC_USE_DEBUG)
2841       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);
2842       for (p = 0; p < 3; ++p) {
2843         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);
2844       }
2845 #endif
2846       /* B triangle */
2847       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
2848       orntNew[0] = ornt[0];
2849       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
2850       orntNew[1] = ornt[1];
2851       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 0;
2852       orntNew[2] = -2;
2853       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
2854       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
2855 #if defined(PETSC_USE_DEBUG)
2856       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);
2857       for (p = 0; p < 3; ++p) {
2858         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);
2859       }
2860 #endif
2861       /* C triangle */
2862       coneNew[0] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 1;
2863       orntNew[0] = -2;
2864       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
2865       orntNew[1] = ornt[1];
2866       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
2867       orntNew[2] = ornt[2];
2868       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
2869       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
2870 #if defined(PETSC_USE_DEBUG)
2871       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);
2872       for (p = 0; p < 3; ++p) {
2873         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);
2874       }
2875 #endif
2876       /* D triangle */
2877       coneNew[0] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 0;
2878       orntNew[0] = 0;
2879       coneNew[1] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 1;
2880       orntNew[1] = 0;
2881       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 2;
2882       orntNew[2] = 0;
2883       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
2884       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
2885 #if defined(PETSC_USE_DEBUG)
2886       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);
2887       for (p = 0; p < 3; ++p) {
2888         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);
2889       }
2890 #endif
2891     }
2892     /*
2893      2----3----3
2894      |         |
2895      |    B    |
2896      |         |
2897      0----4--- 1
2898      |         |
2899      |    A    |
2900      |         |
2901      0----2----1
2902      */
2903     /* Hybrid cells have 4 faces */
2904     for (c = cMax; c < cEnd; ++c) {
2905       const PetscInt  newp = cStartNew + (cMax - cStart)*4 + (c - cMax)*2;
2906       const PetscInt *cone, *ornt;
2907       PetscInt        coneNew[4], orntNew[4], r;
2908 
2909       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
2910       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
2911       r    = (ornt[0] < 0 ? 1 : 0);
2912       /* A quad */
2913       coneNew[0]   = fStartNew + (cone[0] - fStart)*2 + r;
2914       orntNew[0]   = ornt[0];
2915       coneNew[1]   = fStartNew + (cone[1] - fStart)*2 + r;
2916       orntNew[1]   = ornt[1];
2917       coneNew[2+r] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (cone[2+r] - fMax);
2918       orntNew[2+r] = 0;
2919       coneNew[3-r] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (fEnd    - fMax) + (c - cMax);
2920       orntNew[3-r] = 0;
2921       ierr = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
2922       ierr = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
2923 #if defined(PETSC_USE_DEBUG)
2924       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);
2925       for (p = 0; p < 4; ++p) {
2926         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);
2927       }
2928 #endif
2929       /* B quad */
2930       coneNew[0]   = fStartNew + (cone[0] - fStart)*2 + 1-r;
2931       orntNew[0]   = ornt[0];
2932       coneNew[1]   = fStartNew + (cone[1] - fStart)*2 + 1-r;
2933       orntNew[1]   = ornt[1];
2934       coneNew[2+r] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (fEnd    - fMax) + (c - cMax);
2935       orntNew[2+r] = 0;
2936       coneNew[3-r] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (cone[3-r] - fMax);
2937       orntNew[3-r] = 0;
2938       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
2939       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
2940 #if defined(PETSC_USE_DEBUG)
2941       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);
2942       for (p = 0; p < 4; ++p) {
2943         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);
2944       }
2945 #endif
2946     }
2947     /* Interior split faces have 2 vertices and the same cells as the parent */
2948     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
2949     ierr = PetscMalloc1(2 + maxSupportSize*2, &supportRef);CHKERRQ(ierr);
2950     for (f = fStart; f < fMax; ++f) {
2951       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);
2952 
2953       for (r = 0; r < 2; ++r) {
2954         const PetscInt  newp = fStartNew + (f - fStart)*2 + r;
2955         const PetscInt *cone, *ornt, *support;
2956         PetscInt        coneNew[2], coneSize, c, supportSize, s;
2957 
2958         ierr             = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
2959         coneNew[0]       = vStartNew + (cone[0] - vStart);
2960         coneNew[1]       = vStartNew + (cone[1] - vStart);
2961         coneNew[(r+1)%2] = newv;
2962         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2963 #if defined(PETSC_USE_DEBUG)
2964         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
2965         for (p = 0; p < 2; ++p) {
2966           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);
2967         }
2968 #endif
2969         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
2970         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
2971         for (s = 0; s < supportSize; ++s) {
2972           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
2973           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
2974           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
2975           for (c = 0; c < coneSize; ++c) if (cone[c] == f) break;
2976           if (support[s] >= cMax) {
2977             supportRef[s] = cStartNew + (cMax - cStart)*4 + (support[s] - cMax)*2 + (ornt[c] < 0 ? 1-r : r);
2978           } else {
2979             supportRef[s] = cStartNew + (support[s] - cStart)*4 + (ornt[c] < 0 ? (c+1-r)%3 : (c+r)%3);
2980           }
2981         }
2982         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
2983 #if defined(PETSC_USE_DEBUG)
2984         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
2985         for (p = 0; p < supportSize; ++p) {
2986           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);
2987         }
2988 #endif
2989       }
2990     }
2991     /* Interior cell faces have 2 vertices and 2 cells */
2992     for (c = cStart; c < cMax; ++c) {
2993       const PetscInt *cone;
2994 
2995       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
2996       for (r = 0; r < 3; ++r) {
2997         const PetscInt newp = fStartNew + (fMax - fStart)*2 + (c - cStart)*3 + r;
2998         PetscInt       coneNew[2];
2999         PetscInt       supportNew[2];
3000 
3001         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r]       - fStart);
3002         coneNew[1] = vStartNew + (vEnd - vStart) + (cone[(r+1)%3] - fStart);
3003         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3004 #if defined(PETSC_USE_DEBUG)
3005         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
3006         for (p = 0; p < 2; ++p) {
3007           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);
3008         }
3009 #endif
3010         supportNew[0] = (c - cStart)*4 + (r+1)%3;
3011         supportNew[1] = (c - cStart)*4 + 3;
3012         ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3013 #if defined(PETSC_USE_DEBUG)
3014         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
3015         for (p = 0; p < 2; ++p) {
3016           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);
3017         }
3018 #endif
3019       }
3020     }
3021     /* Interior hybrid faces have 2 vertices and the same cells */
3022     for (f = fMax; f < fEnd; ++f) {
3023       const PetscInt  newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (f - fMax);
3024       const PetscInt *cone, *ornt;
3025       const PetscInt *support;
3026       PetscInt        coneNew[2];
3027       PetscInt        supportNew[2];
3028       PetscInt        size, s, r;
3029 
3030       ierr       = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
3031       coneNew[0] = vStartNew + (cone[0] - vStart);
3032       coneNew[1] = vStartNew + (cone[1] - vStart);
3033       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3034 #if defined(PETSC_USE_DEBUG)
3035       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
3036       for (p = 0; p < 2; ++p) {
3037         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);
3038       }
3039 #endif
3040       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
3041       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
3042       for (s = 0; s < size; ++s) {
3043         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
3044         ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
3045         for (r = 0; r < 2; ++r) {
3046           if (cone[r+2] == f) break;
3047         }
3048         supportNew[s] = (cMax - cStart)*4 + (support[s] - cMax)*2 + (ornt[0] < 0 ? 1-r : r);
3049       }
3050       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3051 #if defined(PETSC_USE_DEBUG)
3052       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
3053       for (p = 0; p < size; ++p) {
3054         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);
3055       }
3056 #endif
3057     }
3058     /* Cell hybrid faces have 2 vertices and 2 cells */
3059     for (c = cMax; c < cEnd; ++c) {
3060       const PetscInt  newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (fEnd - fMax) + (c - cMax);
3061       const PetscInt *cone;
3062       PetscInt        coneNew[2];
3063       PetscInt        supportNew[2];
3064 
3065       ierr       = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
3066       coneNew[0] = vStartNew + (vEnd - vStart) + (cone[0] - fStart);
3067       coneNew[1] = vStartNew + (vEnd - vStart) + (cone[1] - fStart);
3068       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3069 #if defined(PETSC_USE_DEBUG)
3070       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
3071       for (p = 0; p < 2; ++p) {
3072         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);
3073       }
3074 #endif
3075       supportNew[0] = (cMax - cStart)*4 + (c - cMax)*2 + 0;
3076       supportNew[1] = (cMax - cStart)*4 + (c - cMax)*2 + 1;
3077       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3078 #if defined(PETSC_USE_DEBUG)
3079       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
3080       for (p = 0; p < 2; ++p) {
3081         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);
3082       }
3083 #endif
3084     }
3085     /* Old vertices have identical supports */
3086     for (v = vStart; v < vEnd; ++v) {
3087       const PetscInt  newp = vStartNew + (v - vStart);
3088       const PetscInt *support, *cone;
3089       PetscInt        size, s;
3090 
3091       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
3092       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
3093       for (s = 0; s < size; ++s) {
3094         if (support[s] >= fMax) {
3095           supportRef[s] = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (support[s] - fMax);
3096         } else {
3097           PetscInt r = 0;
3098 
3099           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
3100           if (cone[1] == v) r = 1;
3101           supportRef[s] = fStartNew + (support[s] - fStart)*2 + r;
3102         }
3103       }
3104       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
3105 #if defined(PETSC_USE_DEBUG)
3106       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", newp, vStartNew, vEndNew);
3107       for (p = 0; p < size; ++p) {
3108         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);
3109       }
3110 #endif
3111     }
3112     /* Face vertices have 2 + (2 interior, 1 hybrid) supports */
3113     for (f = fStart; f < fMax; ++f) {
3114       const PetscInt  newp = vStartNew + (vEnd - vStart) + (f - fStart);
3115       const PetscInt *cone, *support;
3116       PetscInt        size, newSize = 2, s;
3117 
3118       ierr          = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
3119       ierr          = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
3120       supportRef[0] = fStartNew + (f - fStart)*2 + 0;
3121       supportRef[1] = fStartNew + (f - fStart)*2 + 1;
3122       for (s = 0; s < size; ++s) {
3123         PetscInt r = 0;
3124 
3125         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
3126         if (support[s] >= cMax) {
3127           supportRef[newSize+0] = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (fEnd - fMax) + (support[s] - cMax);
3128 
3129           newSize += 1;
3130         } else {
3131           if      (cone[1] == f) r = 1;
3132           else if (cone[2] == f) r = 2;
3133           supportRef[newSize+0] = fStartNew + (fMax - fStart)*2 + (support[s] - cStart)*3 + (r+2)%3;
3134           supportRef[newSize+1] = fStartNew + (fMax - fStart)*2 + (support[s] - cStart)*3 + r;
3135 
3136           newSize += 2;
3137         }
3138       }
3139       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
3140 #if defined(PETSC_USE_DEBUG)
3141       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", newp, vStartNew, vEndNew);
3142       for (p = 0; p < newSize; ++p) {
3143         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);
3144       }
3145 #endif
3146     }
3147     ierr = PetscFree(supportRef);CHKERRQ(ierr);
3148     break;
3149   case REFINER_HYBRID_HEX_2D:
3150     /* Hybrid Hex 2D */
3151     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
3152     cMax = PetscMin(cEnd, cMax);
3153     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
3154     fMax = PetscMin(fEnd, fMax);
3155     ierr = DMPlexGetHybridBounds(rdm, &cMaxNew, &fMaxNew, NULL, NULL);CHKERRQ(ierr);
3156     /* Interior cells have 4 faces */
3157     for (c = cStart; c < cMax; ++c) {
3158       const PetscInt  newp = cStartNew + (c - cStart)*4;
3159       const PetscInt *cone, *ornt;
3160       PetscInt        coneNew[4], orntNew[4];
3161 
3162       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
3163       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
3164       /* A quad */
3165       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
3166       orntNew[0] = ornt[0];
3167       coneNew[1] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*4 + 0;
3168       orntNew[1] = 0;
3169       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*4 + 3;
3170       orntNew[2] = -2;
3171       coneNew[3] = fStartNew + (cone[3] - fStart)*2 + (ornt[3] < 0 ? 0 : 1);
3172       orntNew[3] = ornt[3];
3173       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
3174       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
3175 #if defined(PETSC_USE_DEBUG)
3176       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);
3177       for (p = 0; p < 4; ++p) {
3178         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);
3179       }
3180 #endif
3181       /* B quad */
3182       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
3183       orntNew[0] = ornt[0];
3184       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
3185       orntNew[1] = ornt[1];
3186       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*4 + 1;
3187       orntNew[2] = 0;
3188       coneNew[3] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*4 + 0;
3189       orntNew[3] = -2;
3190       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
3191       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
3192 #if defined(PETSC_USE_DEBUG)
3193       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);
3194       for (p = 0; p < 4; ++p) {
3195         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);
3196       }
3197 #endif
3198       /* C quad */
3199       coneNew[0] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*4 + 1;
3200       orntNew[0] = -2;
3201       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
3202       orntNew[1] = ornt[1];
3203       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
3204       orntNew[2] = ornt[2];
3205       coneNew[3] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*4 + 2;
3206       orntNew[3] = 0;
3207       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
3208       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
3209 #if defined(PETSC_USE_DEBUG)
3210       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);
3211       for (p = 0; p < 4; ++p) {
3212         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);
3213       }
3214 #endif
3215       /* D quad */
3216       coneNew[0] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*4 + 3;
3217       orntNew[0] = 0;
3218       coneNew[1] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*4 + 2;
3219       orntNew[1] = -2;
3220       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
3221       orntNew[2] = ornt[2];
3222       coneNew[3] = fStartNew + (cone[3] - fStart)*2 + (ornt[3] < 0 ? 1 : 0);
3223       orntNew[3] = ornt[3];
3224       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
3225       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
3226 #if defined(PETSC_USE_DEBUG)
3227       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);
3228       for (p = 0; p < 4; ++p) {
3229         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);
3230       }
3231 #endif
3232     }
3233     /*
3234      2----3----3
3235      |         |
3236      |    B    |
3237      |         |
3238      0----4--- 1
3239      |         |
3240      |    A    |
3241      |         |
3242      0----2----1
3243      */
3244     /* Hybrid cells have 4 faces */
3245     for (c = cMax; c < cEnd; ++c) {
3246       const PetscInt  newp = cStartNew + (cMax - cStart)*4 + (c - cMax)*2;
3247       const PetscInt *cone, *ornt;
3248       PetscInt        coneNew[4], orntNew[4];
3249 
3250       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
3251       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
3252       /* A quad */
3253       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
3254       orntNew[0] = ornt[0];
3255       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
3256       orntNew[1] = ornt[1];
3257       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*4 + (cone[2] - fMax);
3258       orntNew[2] = 0;
3259       coneNew[3] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*4 + (fEnd    - fMax) + (c - cMax);
3260       orntNew[3] = 0;
3261       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
3262       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
3263 #if defined(PETSC_USE_DEBUG)
3264       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);
3265       for (p = 0; p < 4; ++p) {
3266         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);
3267       }
3268 #endif
3269       /* B quad */
3270       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
3271       orntNew[0] = ornt[0];
3272       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
3273       orntNew[1] = ornt[1];
3274       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*4 + (fEnd    - fMax) + (c - cMax);
3275       orntNew[2] = 0;
3276       coneNew[3] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*4 + (cone[3] - fMax);
3277       orntNew[3] = 0;
3278       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
3279       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
3280 #if defined(PETSC_USE_DEBUG)
3281       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);
3282       for (p = 0; p < 4; ++p) {
3283         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);
3284       }
3285 #endif
3286     }
3287     /* Interior split faces have 2 vertices and the same cells as the parent */
3288     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
3289     ierr = PetscMalloc1(2 + maxSupportSize*2, &supportRef);CHKERRQ(ierr);
3290     for (f = fStart; f < fMax; ++f) {
3291       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);
3292 
3293       for (r = 0; r < 2; ++r) {
3294         const PetscInt  newp = fStartNew + (f - fStart)*2 + r;
3295         const PetscInt *cone, *ornt, *support;
3296         PetscInt        coneNew[2], coneSize, c, supportSize, s;
3297 
3298         ierr             = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
3299         coneNew[0]       = vStartNew + (cone[0] - vStart);
3300         coneNew[1]       = vStartNew + (cone[1] - vStart);
3301         coneNew[(r+1)%2] = newv;
3302         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3303 #if defined(PETSC_USE_DEBUG)
3304         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
3305         for (p = 0; p < 2; ++p) {
3306           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);
3307         }
3308 #endif
3309         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
3310         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
3311         for (s = 0; s < supportSize; ++s) {
3312           if (support[s] >= cMax) {
3313             supportRef[s] = cStartNew + (cMax - cStart)*4 + (support[s] - cMax)*2 + r;
3314           } else {
3315             ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
3316             ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
3317             ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
3318             for (c = 0; c < coneSize; ++c) {
3319               if (cone[c] == f) break;
3320             }
3321             supportRef[s] = cStartNew + (support[s] - cStart)*4 + (ornt[c] < 0 ? (c+1-r)%4 : (c+r)%4);
3322           }
3323         }
3324         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
3325 #if defined(PETSC_USE_DEBUG)
3326         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
3327         for (p = 0; p < supportSize; ++p) {
3328           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);
3329         }
3330 #endif
3331       }
3332     }
3333     /* Interior cell faces have 2 vertices and 2 cells */
3334     for (c = cStart; c < cMax; ++c) {
3335       const PetscInt *cone;
3336 
3337       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
3338       for (r = 0; r < 4; ++r) {
3339         const PetscInt newp = fStartNew + (fMax - fStart)*2 + (c - cStart)*4 + r;
3340         PetscInt       coneNew[2], supportNew[2];
3341 
3342         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r] - fStart);
3343         coneNew[1] = vStartNew + (vEnd - vStart) + (fMax    - fStart) + (c - cStart);
3344         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3345 #if defined(PETSC_USE_DEBUG)
3346         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
3347         for (p = 0; p < 2; ++p) {
3348           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);
3349         }
3350 #endif
3351         supportNew[0] = (c - cStart)*4 + r;
3352         supportNew[1] = (c - cStart)*4 + (r+1)%4;
3353         ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3354 #if defined(PETSC_USE_DEBUG)
3355         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
3356         for (p = 0; p < 2; ++p) {
3357           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);
3358         }
3359 #endif
3360       }
3361     }
3362     /* Hybrid faces have 2 vertices and the same cells */
3363     for (f = fMax; f < fEnd; ++f) {
3364       const PetscInt  newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*4 + (f - fMax);
3365       const PetscInt *cone, *support;
3366       PetscInt        coneNew[2], supportNew[2];
3367       PetscInt        size, s, r;
3368 
3369       ierr       = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
3370       coneNew[0] = vStartNew + (cone[0] - vStart);
3371       coneNew[1] = vStartNew + (cone[1] - vStart);
3372       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3373 #if defined(PETSC_USE_DEBUG)
3374       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
3375       for (p = 0; p < 2; ++p) {
3376         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);
3377       }
3378 #endif
3379       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
3380       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
3381       for (s = 0; s < size; ++s) {
3382         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
3383         for (r = 0; r < 2; ++r) {
3384           if (cone[r+2] == f) break;
3385         }
3386         supportNew[s] = (cMax - cStart)*4 + (support[s] - cMax)*2 + r;
3387       }
3388       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3389 #if defined(PETSC_USE_DEBUG)
3390       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
3391       for (p = 0; p < size; ++p) {
3392         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);
3393       }
3394 #endif
3395     }
3396     /* Cell hybrid faces have 2 vertices and 2 cells */
3397     for (c = cMax; c < cEnd; ++c) {
3398       const PetscInt  newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*4 + (fEnd - fMax) + (c - cMax);
3399       const PetscInt *cone;
3400       PetscInt        coneNew[2], supportNew[2];
3401 
3402       ierr       = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
3403       coneNew[0] = vStartNew + (vEnd - vStart) + (cone[0] - fStart);
3404       coneNew[1] = vStartNew + (vEnd - vStart) + (cone[1] - fStart);
3405       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3406 #if defined(PETSC_USE_DEBUG)
3407       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
3408       for (p = 0; p < 2; ++p) {
3409         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);
3410       }
3411 #endif
3412       supportNew[0] = (cMax - cStart)*4 + (c - cMax)*2 + 0;
3413       supportNew[1] = (cMax - cStart)*4 + (c - cMax)*2 + 1;
3414       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3415 #if defined(PETSC_USE_DEBUG)
3416       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
3417       for (p = 0; p < 2; ++p) {
3418         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);
3419       }
3420 #endif
3421     }
3422     /* Old vertices have identical supports */
3423     for (v = vStart; v < vEnd; ++v) {
3424       const PetscInt  newp = vStartNew + (v - vStart);
3425       const PetscInt *support, *cone;
3426       PetscInt        size, s;
3427 
3428       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
3429       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
3430       for (s = 0; s < size; ++s) {
3431         if (support[s] >= fMax) {
3432           supportRef[s] = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*4 + (support[s] - fMax);
3433         } else {
3434           PetscInt r = 0;
3435 
3436           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
3437           if (cone[1] == v) r = 1;
3438           supportRef[s] = fStartNew + (support[s] - fStart)*2 + r;
3439         }
3440       }
3441       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
3442 #if defined(PETSC_USE_DEBUG)
3443       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", newp, vStartNew, vEndNew);
3444       for (p = 0; p < size; ++p) {
3445         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);
3446       }
3447 #endif
3448     }
3449     /* Face vertices have 2 + cells supports */
3450     for (f = fStart; f < fMax; ++f) {
3451       const PetscInt  newp = vStartNew + (vEnd - vStart) + (f - fStart);
3452       const PetscInt *cone, *support;
3453       PetscInt        size, s;
3454 
3455       ierr          = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
3456       ierr          = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
3457       supportRef[0] = fStartNew + (f - fStart)*2 + 0;
3458       supportRef[1] = fStartNew + (f - fStart)*2 + 1;
3459       for (s = 0; s < size; ++s) {
3460         PetscInt r = 0;
3461 
3462         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
3463         if (support[s] >= cMax) {
3464           supportRef[2+s] = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*4 + (fEnd - fMax) + (support[s] - cMax);
3465         } else {
3466           if      (cone[1] == f) r = 1;
3467           else if (cone[2] == f) r = 2;
3468           else if (cone[3] == f) r = 3;
3469           supportRef[2+s] = fStartNew + (fMax - fStart)*2 + (support[s] - cStart)*4 + r;
3470         }
3471       }
3472       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
3473 #if defined(PETSC_USE_DEBUG)
3474       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", newp, vStartNew, vEndNew);
3475       for (p = 0; p < 2+size; ++p) {
3476         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);
3477       }
3478 #endif
3479     }
3480     /* Cell vertices have 4 supports */
3481     for (c = cStart; c < cMax; ++c) {
3482       const PetscInt newp = vStartNew + (vEnd - vStart) + (fMax - fStart) + (c - cStart);
3483       PetscInt       supportNew[4];
3484 
3485       for (r = 0; r < 4; ++r) {
3486         supportNew[r] = fStartNew + (fMax - fStart)*2 + (c - cStart)*4 + r;
3487       }
3488       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3489     }
3490     ierr = PetscFree(supportRef);CHKERRQ(ierr);
3491     break;
3492   case REFINER_SIMPLEX_3D:
3493     /* All cells have 4 faces: Tet face order is prescribed in DMPlexGetFaces_Internal() */
3494     ierr = DMPlexGetRawFaces_Internal(dm, 3, 4, cellInd, NULL, NULL, &faces);CHKERRQ(ierr);
3495     for (c = cStart; c < cEnd; ++c) {
3496       const PetscInt  newp = cStartNew + (c - cStart)*8;
3497       const PetscInt *cone, *ornt;
3498       PetscInt        coneNew[4], orntNew[4];
3499 
3500       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
3501       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
3502       /* A tetrahedron: {0, a, c, d} */
3503       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetTriSubface_Static(ornt[0], 0); /* A */
3504       orntNew[0] = ornt[0];
3505       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetTriSubface_Static(ornt[1], 0); /* A */
3506       orntNew[1] = ornt[1];
3507       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetTriSubface_Static(ornt[2], 0); /* A */
3508       orntNew[2] = ornt[2];
3509       coneNew[3] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 0;
3510       orntNew[3] = 0;
3511       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
3512       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
3513 #if defined(PETSC_USE_DEBUG)
3514       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);
3515       for (p = 0; p < 4; ++p) {
3516         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);
3517       }
3518 #endif
3519       /* B tetrahedron: {a, 1, b, e} */
3520       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetTriSubface_Static(ornt[0], 1); /* B */
3521       orntNew[0] = ornt[0];
3522       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetTriSubface_Static(ornt[1], 2); /* C */
3523       orntNew[1] = ornt[1];
3524       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 1;
3525       orntNew[2] = 0;
3526       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetTriSubface_Static(ornt[3], 1); /* B */
3527       orntNew[3] = ornt[3];
3528       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
3529       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
3530 #if defined(PETSC_USE_DEBUG)
3531       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);
3532       for (p = 0; p < 4; ++p) {
3533         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);
3534       }
3535 #endif
3536       /* C tetrahedron: {c, b, 2, f} */
3537       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetTriSubface_Static(ornt[0], 2); /* C */
3538       orntNew[0] = ornt[0];
3539       coneNew[1] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 2;
3540       orntNew[1] = 0;
3541       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetTriSubface_Static(ornt[2], 1); /* B */
3542       orntNew[2] = ornt[2];
3543       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetTriSubface_Static(ornt[3], 0); /* A */
3544       orntNew[3] = ornt[3];
3545       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
3546       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
3547 #if defined(PETSC_USE_DEBUG)
3548       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);
3549       for (p = 0; p < 4; ++p) {
3550         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);
3551       }
3552 #endif
3553       /* D tetrahedron: {d, e, f, 3} */
3554       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 3;
3555       orntNew[0] = 0;
3556       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetTriSubface_Static(ornt[1], 1); /* B */
3557       orntNew[1] = ornt[1];
3558       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetTriSubface_Static(ornt[2], 2); /* C */
3559       orntNew[2] = ornt[2];
3560       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetTriSubface_Static(ornt[3], 2); /* C */
3561       orntNew[3] = ornt[3];
3562       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
3563       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
3564 #if defined(PETSC_USE_DEBUG)
3565       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);
3566       for (p = 0; p < 4; ++p) {
3567         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);
3568       }
3569 #endif
3570       /* A' tetrahedron: {c, d, a, f} */
3571       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 0;
3572       orntNew[0] = -3;
3573       coneNew[1] = fStartNew + (cone[2] - fStart)*4 + 3;
3574       orntNew[1] = ornt[2] < 0 ? -(GetTriMidEdge_Static(ornt[2], 0)+1) : GetTriMidEdge_Static(ornt[2], 0);
3575       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 5;
3576       orntNew[2] = 0;
3577       coneNew[3] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 4;
3578       orntNew[3] = 2;
3579       ierr       = DMPlexSetCone(rdm, newp+4, coneNew);CHKERRQ(ierr);
3580       ierr       = DMPlexSetConeOrientation(rdm, newp+4, orntNew);CHKERRQ(ierr);
3581 #if defined(PETSC_USE_DEBUG)
3582       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);
3583       for (p = 0; p < 4; ++p) {
3584         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);
3585       }
3586 #endif
3587       /* B' tetrahedron: {e, b, a, f} */
3588       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 1;
3589       orntNew[0] = -2;
3590       coneNew[1] = fStartNew + (cone[3] - fStart)*4 + 3;
3591       orntNew[1] = ornt[3] < 0 ? -(GetTriMidEdge_Static(ornt[3], 1)+1) : GetTriMidEdge_Static(ornt[3], 1);
3592       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 6;
3593       orntNew[2] = 0;
3594       coneNew[3] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 7;
3595       orntNew[3] = 0;
3596       ierr       = DMPlexSetCone(rdm, newp+5, coneNew);CHKERRQ(ierr);
3597       ierr       = DMPlexSetConeOrientation(rdm, newp+5, orntNew);CHKERRQ(ierr);
3598 #if defined(PETSC_USE_DEBUG)
3599       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);
3600       for (p = 0; p < 4; ++p) {
3601         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);
3602       }
3603 #endif
3604       /* C' tetrahedron: {f, a, c, b} */
3605       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 5;
3606       orntNew[0] = -2;
3607       coneNew[1] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 7;
3608       orntNew[1] = -2;
3609       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 2;
3610       orntNew[2] = -1;
3611       coneNew[3] = fStartNew + (cone[0] - fStart)*4 + 3;
3612       orntNew[3] = ornt[0] < 0 ? -(GetTriMidEdge_Static(ornt[0], 2)+1) : GetTriMidEdge_Static(ornt[0], 2);
3613       ierr       = DMPlexSetCone(rdm, newp+6, coneNew);CHKERRQ(ierr);
3614       ierr       = DMPlexSetConeOrientation(rdm, newp+6, orntNew);CHKERRQ(ierr);
3615 #if defined(PETSC_USE_DEBUG)
3616       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);
3617       for (p = 0; p < 4; ++p) {
3618         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);
3619       }
3620 #endif
3621       /* D' tetrahedron: {f, a, e, d} */
3622       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 6;
3623       orntNew[0] = -2;
3624       coneNew[1] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 4;
3625       orntNew[1] = -1;
3626       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 3;
3627       orntNew[2] = -2;
3628       coneNew[3] = fStartNew + (cone[1] - fStart)*4 + 3;
3629       orntNew[3] = ornt[1] < 0 ? -(GetTriMidEdge_Static(ornt[1], 1)+1) : GetTriMidEdge_Static(ornt[1], 1);
3630       ierr       = DMPlexSetCone(rdm, newp+7, coneNew);CHKERRQ(ierr);
3631       ierr       = DMPlexSetConeOrientation(rdm, newp+7, orntNew);CHKERRQ(ierr);
3632 #if defined(PETSC_USE_DEBUG)
3633       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);
3634       for (p = 0; p < 4; ++p) {
3635         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);
3636       }
3637 #endif
3638     }
3639     /* Split faces have 3 edges and the same cells as the parent */
3640     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
3641     ierr = PetscMalloc1(2 + maxSupportSize*3, &supportRef);CHKERRQ(ierr);
3642     for (f = fStart; f < fEnd; ++f) {
3643       const PetscInt  newp = fStartNew + (f - fStart)*4;
3644       const PetscInt *cone, *ornt, *support;
3645       PetscInt        coneNew[3], orntNew[3], coneSize, supportSize, s;
3646 
3647       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
3648       ierr = DMPlexGetConeOrientation(dm, f, &ornt);CHKERRQ(ierr);
3649       /* A triangle */
3650       coneNew[0] = eStartNew + (cone[0] - eStart)*2 + (ornt[0] < 0 ? 1 : 0);
3651       orntNew[0] = ornt[0];
3652       coneNew[1] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 2;
3653       orntNew[1] = -2;
3654       coneNew[2] = eStartNew + (cone[2] - eStart)*2 + (ornt[2] < 0 ? 0 : 1);
3655       orntNew[2] = ornt[2];
3656       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
3657       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
3658 #if defined(PETSC_USE_DEBUG)
3659       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);
3660       for (p = 0; p < 3; ++p) {
3661         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);
3662       }
3663 #endif
3664       /* B triangle */
3665       coneNew[0] = eStartNew + (cone[0] - eStart)*2 + (ornt[0] < 0 ? 0 : 1);
3666       orntNew[0] = ornt[0];
3667       coneNew[1] = eStartNew + (cone[1] - eStart)*2 + (ornt[1] < 0 ? 1 : 0);
3668       orntNew[1] = ornt[1];
3669       coneNew[2] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 0;
3670       orntNew[2] = -2;
3671       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
3672       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
3673 #if defined(PETSC_USE_DEBUG)
3674       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);
3675       for (p = 0; p < 3; ++p) {
3676         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);
3677       }
3678 #endif
3679       /* C triangle */
3680       coneNew[0] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 1;
3681       orntNew[0] = -2;
3682       coneNew[1] = eStartNew + (cone[1] - eStart)*2 + (ornt[1] < 0 ? 0 : 1);
3683       orntNew[1] = ornt[1];
3684       coneNew[2] = eStartNew + (cone[2] - eStart)*2 + (ornt[2] < 0 ? 1 : 0);
3685       orntNew[2] = ornt[2];
3686       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
3687       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
3688 #if defined(PETSC_USE_DEBUG)
3689       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);
3690       for (p = 0; p < 3; ++p) {
3691         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);
3692       }
3693 #endif
3694       /* D triangle */
3695       coneNew[0] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 0;
3696       orntNew[0] = 0;
3697       coneNew[1] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 1;
3698       orntNew[1] = 0;
3699       coneNew[2] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 2;
3700       orntNew[2] = 0;
3701       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
3702       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
3703 #if defined(PETSC_USE_DEBUG)
3704       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);
3705       for (p = 0; p < 3; ++p) {
3706         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);
3707       }
3708 #endif
3709       ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
3710       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
3711       for (r = 0; r < 4; ++r) {
3712         for (s = 0; s < supportSize; ++s) {
3713           PetscInt subf;
3714           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
3715           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
3716           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
3717           for (c = 0; c < coneSize; ++c) {
3718             if (cone[c] == f) break;
3719           }
3720           subf = GetTriSubfaceInverse_Static(ornt[c], r);
3721           supportRef[s] = cStartNew + (support[s] - cStart)*8 + (r==3 ? (c+2)%4 + 4 : faces[c*3+subf]);
3722         }
3723         ierr = DMPlexSetSupport(rdm, newp+r, supportRef);CHKERRQ(ierr);
3724 #if defined(PETSC_USE_DEBUG)
3725         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);
3726         for (p = 0; p < supportSize; ++p) {
3727           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);
3728         }
3729 #endif
3730       }
3731     }
3732     /* Interior faces have 3 edges and 2 cells */
3733     for (c = cStart; c < cEnd; ++c) {
3734       PetscInt        newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*8;
3735       const PetscInt *cone, *ornt;
3736       PetscInt        coneNew[3], orntNew[3];
3737       PetscInt        supportNew[2];
3738 
3739       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
3740       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
3741       /* Face A: {c, a, d} */
3742       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*3 + GetTriMidEdge_Static(ornt[0], 2);
3743       orntNew[0] = ornt[0] < 0 ? -2 : 0;
3744       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*3 + GetTriMidEdge_Static(ornt[1], 2);
3745       orntNew[1] = ornt[1] < 0 ? -2 : 0;
3746       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*3 + GetTriMidEdge_Static(ornt[2], 2);
3747       orntNew[2] = ornt[2] < 0 ? -2 : 0;
3748       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3749       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3750 #if defined(PETSC_USE_DEBUG)
3751       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
3752       for (p = 0; p < 3; ++p) {
3753         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);
3754       }
3755 #endif
3756       supportNew[0] = (c - cStart)*8 + 0;
3757       supportNew[1] = (c - cStart)*8 + 0+4;
3758       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3759 #if defined(PETSC_USE_DEBUG)
3760       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
3761       for (p = 0; p < 2; ++p) {
3762         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);
3763       }
3764 #endif
3765       ++newp;
3766       /* Face B: {a, b, e} */
3767       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*3 + GetTriMidEdge_Static(ornt[0], 0);
3768       orntNew[0] = ornt[0] < 0 ? -2 : 0;
3769       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*3 + GetTriMidEdge_Static(ornt[3], 0);
3770       orntNew[1] = ornt[3] < 0 ? -2 : 0;
3771       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*3 + GetTriMidEdge_Static(ornt[1], 1);
3772       orntNew[2] = ornt[1] < 0 ? -2 : 0;
3773       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3774       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3775 #if defined(PETSC_USE_DEBUG)
3776       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
3777       for (p = 0; p < 3; ++p) {
3778         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);
3779       }
3780 #endif
3781       supportNew[0] = (c - cStart)*8 + 1;
3782       supportNew[1] = (c - cStart)*8 + 1+4;
3783       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3784 #if defined(PETSC_USE_DEBUG)
3785       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
3786       for (p = 0; p < 2; ++p) {
3787         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);
3788       }
3789 #endif
3790       ++newp;
3791       /* Face C: {c, f, b} */
3792       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*3 + GetTriMidEdge_Static(ornt[2], 0);
3793       orntNew[0] = ornt[2] < 0 ? -2 : 0;
3794       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*3 + GetTriMidEdge_Static(ornt[3], 2);
3795       orntNew[1] = ornt[3] < 0 ? -2 : 0;
3796       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*3 + GetTriMidEdge_Static(ornt[0], 1);
3797       orntNew[2] = ornt[0] < 0 ? -2 : 0;
3798       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3799       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3800 #if defined(PETSC_USE_DEBUG)
3801       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
3802       for (p = 0; p < 3; ++p) {
3803         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);
3804       }
3805 #endif
3806       supportNew[0] = (c - cStart)*8 + 2;
3807       supportNew[1] = (c - cStart)*8 + 2+4;
3808       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3809 #if defined(PETSC_USE_DEBUG)
3810       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
3811       for (p = 0; p < 2; ++p) {
3812         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);
3813       }
3814 #endif
3815       ++newp;
3816       /* Face D: {d, e, f} */
3817       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*3 + GetTriMidEdge_Static(ornt[1], 0);
3818       orntNew[0] = ornt[1] < 0 ? -2 : 0;
3819       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*3 + GetTriMidEdge_Static(ornt[3], 1);
3820       orntNew[1] = ornt[3] < 0 ? -2 : 0;
3821       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*3 + GetTriMidEdge_Static(ornt[2], 1);
3822       orntNew[2] = ornt[2] < 0 ? -2 : 0;
3823       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3824       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3825 #if defined(PETSC_USE_DEBUG)
3826       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
3827       for (p = 0; p < 3; ++p) {
3828         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);
3829       }
3830 #endif
3831       supportNew[0] = (c - cStart)*8 + 3;
3832       supportNew[1] = (c - cStart)*8 + 3+4;
3833       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3834 #if defined(PETSC_USE_DEBUG)
3835       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
3836       for (p = 0; p < 2; ++p) {
3837         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);
3838       }
3839 #endif
3840       ++newp;
3841       /* Face E: {d, f, a} */
3842       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*3 + GetTriMidEdge_Static(ornt[2], 1);
3843       orntNew[0] = ornt[2] < 0 ? 0 : -2;
3844       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart);
3845       orntNew[1] = -2;
3846       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*3 + GetTriMidEdge_Static(ornt[1], 2);
3847       orntNew[2] = ornt[1] < 0 ? -2 : 0;
3848       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3849       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3850 #if defined(PETSC_USE_DEBUG)
3851       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
3852       for (p = 0; p < 3; ++p) {
3853         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);
3854       }
3855 #endif
3856       supportNew[0] = (c - cStart)*8 + 0+4;
3857       supportNew[1] = (c - cStart)*8 + 3+4;
3858       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3859 #if defined(PETSC_USE_DEBUG)
3860       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
3861       for (p = 0; p < 2; ++p) {
3862         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);
3863       }
3864 #endif
3865       ++newp;
3866       /* Face F: {c, a, f} */
3867       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*3 + GetTriMidEdge_Static(ornt[0], 2);
3868       orntNew[0] = ornt[0] < 0 ? -2 : 0;
3869       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart);
3870       orntNew[1] = 0;
3871       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*3 + GetTriMidEdge_Static(ornt[2], 0);
3872       orntNew[2] = ornt[2] < 0 ? 0 : -2;
3873       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3874       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3875 #if defined(PETSC_USE_DEBUG)
3876       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
3877       for (p = 0; p < 3; ++p) {
3878         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);
3879       }
3880 #endif
3881       supportNew[0] = (c - cStart)*8 + 0+4;
3882       supportNew[1] = (c - cStart)*8 + 2+4;
3883       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3884 #if defined(PETSC_USE_DEBUG)
3885       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
3886       for (p = 0; p < 2; ++p) {
3887         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);
3888       }
3889 #endif
3890       ++newp;
3891       /* Face G: {e, a, f} */
3892       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*3 + GetTriMidEdge_Static(ornt[1], 1);
3893       orntNew[0] = ornt[1] < 0 ? -2 : 0;
3894       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart);
3895       orntNew[1] = 0;
3896       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*3 + GetTriMidEdge_Static(ornt[3], 1);
3897       orntNew[2] = ornt[3] < 0 ? 0 : -2;
3898       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3899       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3900 #if defined(PETSC_USE_DEBUG)
3901       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
3902       for (p = 0; p < 3; ++p) {
3903         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);
3904       }
3905 #endif
3906       supportNew[0] = (c - cStart)*8 + 1+4;
3907       supportNew[1] = (c - cStart)*8 + 3+4;
3908       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3909 #if defined(PETSC_USE_DEBUG)
3910       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
3911       for (p = 0; p < 2; ++p) {
3912         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);
3913       }
3914 #endif
3915       ++newp;
3916       /* Face H: {a, b, f} */
3917       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*3 + GetTriMidEdge_Static(ornt[0], 0);
3918       orntNew[0] = ornt[0] < 0 ? -2 : 0;
3919       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*3 + GetTriMidEdge_Static(ornt[3], 2);
3920       orntNew[1] = ornt[3] < 0 ? 0 : -2;
3921       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart);
3922       orntNew[2] = -2;
3923       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3924       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3925 #if defined(PETSC_USE_DEBUG)
3926       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
3927       for (p = 0; p < 3; ++p) {
3928         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);
3929       }
3930 #endif
3931       supportNew[0] = (c - cStart)*8 + 1+4;
3932       supportNew[1] = (c - cStart)*8 + 2+4;
3933       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3934 #if defined(PETSC_USE_DEBUG)
3935       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
3936       for (p = 0; p < 2; ++p) {
3937         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);
3938       }
3939 #endif
3940       ++newp;
3941     }
3942     /* Split Edges have 2 vertices and the same faces as the parent */
3943     for (e = eStart; e < eEnd; ++e) {
3944       const PetscInt newv = vStartNew + (vEnd - vStart) + (e - eStart);
3945 
3946       for (r = 0; r < 2; ++r) {
3947         const PetscInt  newp = eStartNew + (e - eStart)*2 + r;
3948         const PetscInt *cone, *ornt, *support;
3949         PetscInt        coneNew[2], coneSize, c, supportSize, s;
3950 
3951         ierr             = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
3952         coneNew[0]       = vStartNew + (cone[0] - vStart);
3953         coneNew[1]       = vStartNew + (cone[1] - vStart);
3954         coneNew[(r+1)%2] = newv;
3955         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3956 #if defined(PETSC_USE_DEBUG)
3957         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eEndNew);
3958         for (p = 0; p < 2; ++p) {
3959           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);
3960         }
3961 #endif
3962         ierr = DMPlexGetSupportSize(dm, e, &supportSize);CHKERRQ(ierr);
3963         ierr = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
3964         for (s = 0; s < supportSize; ++s) {
3965           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
3966           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
3967           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
3968           for (c = 0; c < coneSize; ++c) {
3969             if (cone[c] == e) break;
3970           }
3971           supportRef[s] = fStartNew + (support[s] - fStart)*4 + (c + (ornt[c] < 0 ? 1-r : r))%3;
3972         }
3973         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
3974 #if defined(PETSC_USE_DEBUG)
3975         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eEndNew);
3976         for (p = 0; p < supportSize; ++p) {
3977           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);
3978         }
3979 #endif
3980       }
3981     }
3982     /* Face edges have 2 vertices and 2+cells*(1/2) faces */
3983     for (f = fStart; f < fEnd; ++f) {
3984       const PetscInt *cone, *ornt, *support;
3985       PetscInt        coneSize, supportSize, s;
3986 
3987       ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
3988       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
3989       for (r = 0; r < 3; ++r) {
3990         const PetscInt  newp = eStartNew + (eEnd - eStart)*2 + (f - fStart)*3 + r;
3991         PetscInt        coneNew[2], intFaces = 0, er, eint[4] = {1, 0, 2, 0};
3992         PetscInt        fint[24] = { 1,  7, -1, -1,  0,  5,
3993                                     -1, -1,  1,  6,  0,  4,
3994                                      2,  5,  3,  4, -1, -1,
3995                                     -1, -1,  3,  6,  2,  7};
3996 
3997         ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
3998         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[(r+0)%3] - eStart);
3999         coneNew[1] = vStartNew + (vEnd - vStart) + (cone[(r+1)%3] - eStart);
4000         ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4001 #if defined(PETSC_USE_DEBUG)
4002         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eEndNew);
4003         for (p = 0; p < 2; ++p) {
4004           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);
4005         }
4006 #endif
4007         supportRef[0] = fStartNew + (f - fStart)*4 + (r+1)%3;
4008         supportRef[1] = fStartNew + (f - fStart)*4 + 3;
4009         for (s = 0; s < supportSize; ++s) {
4010           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
4011           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
4012           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
4013           for (c = 0; c < coneSize; ++c) {if (cone[c] == f) break;}
4014           /* Here we want to determine whether edge newp contains a vertex which is part of the cross-tet edge */
4015           er = GetTriMidEdgeInverse_Static(ornt[c], r);
4016           if (er == eint[c]) {
4017             supportRef[2+intFaces++] = fStartNew + (fEnd - fStart)*4 + (support[s] - cStart)*8 + (c + 2)%4;
4018           } else {
4019             supportRef[2+intFaces++] = fStartNew + (fEnd - fStart)*4 + (support[s] - cStart)*8 + fint[(c*3 + er)*2 + 0];
4020             supportRef[2+intFaces++] = fStartNew + (fEnd - fStart)*4 + (support[s] - cStart)*8 + fint[(c*3 + er)*2 + 1];
4021           }
4022         }
4023         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
4024 #if defined(PETSC_USE_DEBUG)
4025         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eEndNew);
4026         for (p = 0; p < intFaces; ++p) {
4027           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);
4028         }
4029 #endif
4030       }
4031     }
4032     /* Interior edges have 2 vertices and 4 faces */
4033     for (c = cStart; c < cEnd; ++c) {
4034       const PetscInt  newp = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart);
4035       const PetscInt *cone, *ornt, *fcone;
4036       PetscInt        coneNew[2], supportNew[4], find;
4037 
4038       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
4039       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
4040       ierr = DMPlexGetCone(dm, cone[0], &fcone);CHKERRQ(ierr);
4041       find = GetTriEdge_Static(ornt[0], 0);
4042       coneNew[0] = vStartNew + (vEnd - vStart) + (fcone[find] - eStart);
4043       ierr = DMPlexGetCone(dm, cone[2], &fcone);CHKERRQ(ierr);
4044       find = GetTriEdge_Static(ornt[2], 1);
4045       coneNew[1] = vStartNew + (vEnd - vStart) + (fcone[find] - eStart);
4046       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4047 #if defined(PETSC_USE_DEBUG)
4048       if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eEndNew);
4049       for (p = 0; p < 2; ++p) {
4050         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);
4051       }
4052 #endif
4053       supportNew[0] = fStartNew + (fEnd - fStart)*4 + (c - cStart)*8 + 4;
4054       supportNew[1] = fStartNew + (fEnd - fStart)*4 + (c - cStart)*8 + 5;
4055       supportNew[2] = fStartNew + (fEnd - fStart)*4 + (c - cStart)*8 + 6;
4056       supportNew[3] = fStartNew + (fEnd - fStart)*4 + (c - cStart)*8 + 7;
4057       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
4058 #if defined(PETSC_USE_DEBUG)
4059       if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eEndNew);
4060       for (p = 0; p < 4; ++p) {
4061         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);
4062       }
4063 #endif
4064     }
4065     /* Old vertices have identical supports */
4066     for (v = vStart; v < vEnd; ++v) {
4067       const PetscInt  newp = vStartNew + (v - vStart);
4068       const PetscInt *support, *cone;
4069       PetscInt        size, s;
4070 
4071       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
4072       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
4073       for (s = 0; s < size; ++s) {
4074         PetscInt r = 0;
4075 
4076         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
4077         if (cone[1] == v) r = 1;
4078         supportRef[s] = eStartNew + (support[s] - eStart)*2 + r;
4079       }
4080       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
4081 #if defined(PETSC_USE_DEBUG)
4082       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", newp, vStartNew, vEndNew);
4083       for (p = 0; p < size; ++p) {
4084         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);
4085       }
4086 #endif
4087     }
4088     /* Edge vertices have 2 + face*2 + 0/1 supports */
4089     for (e = eStart; e < eEnd; ++e) {
4090       const PetscInt  newp = vStartNew + (vEnd - vStart) + (e - eStart);
4091       const PetscInt *cone, *support;
4092       PetscInt       *star = NULL, starSize, cellSize = 0, coneSize, size, s;
4093 
4094       ierr          = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
4095       ierr          = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
4096       supportRef[0] = eStartNew + (e - eStart)*2 + 0;
4097       supportRef[1] = eStartNew + (e - eStart)*2 + 1;
4098       for (s = 0; s < size; ++s) {
4099         PetscInt r = 0;
4100 
4101         ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
4102         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
4103         for (r = 0; r < coneSize; ++r) {if (cone[r] == e) break;}
4104         supportRef[2+s*2+0] = eStartNew + (eEnd - eStart)*2 + (support[s] - fStart)*3 + (r+0)%3;
4105         supportRef[2+s*2+1] = eStartNew + (eEnd - eStart)*2 + (support[s] - fStart)*3 + (r+2)%3;
4106       }
4107       ierr = DMPlexGetTransitiveClosure(dm, e, PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
4108       for (s = 0; s < starSize*2; s += 2) {
4109         const PetscInt *cone, *ornt;
4110         PetscInt        e01, e23;
4111 
4112         if ((star[s] >= cStart) && (star[s] < cEnd)) {
4113           /* Check edge 0-1 */
4114           ierr = DMPlexGetCone(dm, star[s], &cone);CHKERRQ(ierr);
4115           ierr = DMPlexGetConeOrientation(dm, star[s], &ornt);CHKERRQ(ierr);
4116           ierr = DMPlexGetCone(dm, cone[0], &cone);CHKERRQ(ierr);
4117           e01  = cone[GetTriEdge_Static(ornt[0], 0)];
4118           /* Check edge 2-3 */
4119           ierr = DMPlexGetCone(dm, star[s], &cone);CHKERRQ(ierr);
4120           ierr = DMPlexGetConeOrientation(dm, star[s], &ornt);CHKERRQ(ierr);
4121           ierr = DMPlexGetCone(dm, cone[2], &cone);CHKERRQ(ierr);
4122           e23  = cone[GetTriEdge_Static(ornt[2], 1)];
4123           if ((e01 == e) || (e23 == e)) {supportRef[2+size*2+cellSize++] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (star[s] - cStart);}
4124         }
4125       }
4126       ierr = DMPlexRestoreTransitiveClosure(dm, e, PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
4127       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
4128 #if defined(PETSC_USE_DEBUG)
4129       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", newp, vStartNew, vEndNew);
4130       for (p = 0; p < 2+size*2+cellSize; ++p) {
4131         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);
4132       }
4133 #endif
4134     }
4135     ierr = PetscFree(supportRef);CHKERRQ(ierr);
4136     ierr = DMPlexRestoreFaces_Internal(dm, 3, cStart, NULL, NULL, &faces);CHKERRQ(ierr);
4137     break;
4138   case REFINER_HYBRID_SIMPLEX_3D:
4139     ierr = DMPlexGetHybridBounds(rdm, &cMaxNew, &fMaxNew, &eMaxNew, NULL);CHKERRQ(ierr);
4140     /* Interior cells have 4 faces: Tet face order is prescribed in DMPlexGetFaces_Internal() */
4141     ierr = DMPlexGetRawFaces_Internal(dm, 3, 4, cellInd, NULL, NULL, &faces);CHKERRQ(ierr);
4142     for (c = cStart; c < cMax; ++c) {
4143       const PetscInt  newp = cStartNew + (c - cStart)*8;
4144       const PetscInt *cone, *ornt;
4145       PetscInt        coneNew[4], orntNew[4];
4146 
4147       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
4148       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
4149       /* A tetrahedron: {0, a, c, d} */
4150       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetTriSubface_Static(ornt[0], 0); /* A */
4151       orntNew[0] = ornt[0];
4152       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetTriSubface_Static(ornt[1], 0); /* A */
4153       orntNew[1] = ornt[1];
4154       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetTriSubface_Static(ornt[2], 0); /* A */
4155       orntNew[2] = ornt[2];
4156       coneNew[3] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 0;
4157       orntNew[3] = 0;
4158       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
4159       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
4160 #if defined(PETSC_USE_DEBUG)
4161       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);
4162       for (p = 0; p < 4; ++p) {
4163         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);
4164       }
4165 #endif
4166       /* B tetrahedron: {a, 1, b, e} */
4167       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetTriSubface_Static(ornt[0], 1); /* B */
4168       orntNew[0] = ornt[0];
4169       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetTriSubface_Static(ornt[1], 2); /* C */
4170       orntNew[1] = ornt[1];
4171       coneNew[2] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 1;
4172       orntNew[2] = 0;
4173       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetTriSubface_Static(ornt[3], 1); /* B */
4174       orntNew[3] = ornt[3];
4175       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
4176       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
4177 #if defined(PETSC_USE_DEBUG)
4178       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);
4179       for (p = 0; p < 4; ++p) {
4180         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);
4181       }
4182 #endif
4183       /* C tetrahedron: {c, b, 2, f} */
4184       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetTriSubface_Static(ornt[0], 2); /* C */
4185       orntNew[0] = ornt[0];
4186       coneNew[1] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 2;
4187       orntNew[1] = 0;
4188       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetTriSubface_Static(ornt[2], 1); /* B */
4189       orntNew[2] = ornt[2];
4190       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetTriSubface_Static(ornt[3], 0); /* A */
4191       orntNew[3] = ornt[3];
4192       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
4193       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
4194 #if defined(PETSC_USE_DEBUG)
4195       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);
4196       for (p = 0; p < 4; ++p) {
4197         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);
4198       }
4199 #endif
4200       /* D tetrahedron: {d, e, f, 3} */
4201       coneNew[0] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 3;
4202       orntNew[0] = 0;
4203       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetTriSubface_Static(ornt[1], 1); /* B */
4204       orntNew[1] = ornt[1];
4205       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetTriSubface_Static(ornt[2], 2); /* C */
4206       orntNew[2] = ornt[2];
4207       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetTriSubface_Static(ornt[3], 2); /* C */
4208       orntNew[3] = ornt[3];
4209       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
4210       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
4211 #if defined(PETSC_USE_DEBUG)
4212       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);
4213       for (p = 0; p < 4; ++p) {
4214         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);
4215       }
4216 #endif
4217       /* A' tetrahedron: {d, a, c, f} */
4218       coneNew[0] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 0;
4219       orntNew[0] = -3;
4220       coneNew[1] = fStartNew + (cone[2] - fStart)*4 + 3;
4221       orntNew[1] = ornt[2] < 0 ? -(GetTriMidEdge_Static(ornt[2], 0)+1) : GetTriMidEdge_Static(ornt[2], 0);
4222       coneNew[2] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 5;
4223       orntNew[2] = 0;
4224       coneNew[3] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 4;
4225       orntNew[3] = 2;
4226       ierr       = DMPlexSetCone(rdm, newp+4, coneNew);CHKERRQ(ierr);
4227       ierr       = DMPlexSetConeOrientation(rdm, newp+4, orntNew);CHKERRQ(ierr);
4228 #if defined(PETSC_USE_DEBUG)
4229       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);
4230       for (p = 0; p < 4; ++p) {
4231         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);
4232       }
4233 #endif
4234       /* B' tetrahedron: {e, b, a, f} */
4235       coneNew[0] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 1;
4236       orntNew[0] = -3;
4237       coneNew[1] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 6;
4238       orntNew[1] = 1;
4239       coneNew[2] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 7;
4240       orntNew[2] = 0;
4241       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + 3;
4242       orntNew[3] = ornt[3] < 0 ? -(GetTriMidEdge_Static(ornt[3], 0)+1) : GetTriMidEdge_Static(ornt[3], 0);
4243       ierr       = DMPlexSetCone(rdm, newp+5, coneNew);CHKERRQ(ierr);
4244       ierr       = DMPlexSetConeOrientation(rdm, newp+5, orntNew);CHKERRQ(ierr);
4245 #if defined(PETSC_USE_DEBUG)
4246       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);
4247       for (p = 0; p < 4; ++p) {
4248         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);
4249       }
4250 #endif
4251       /* C' tetrahedron: {b, f, c, a} */
4252       coneNew[0] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 2;
4253       orntNew[0] = -3;
4254       coneNew[1] = fStartNew + (cone[0] - fStart)*4 + 3;
4255       orntNew[1] = ornt[0] < 0 ? -(GetTriMidEdge_Static(ornt[0], 2)+1) : GetTriMidEdge_Static(ornt[0], 2);
4256       coneNew[2] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 5;
4257       orntNew[2] = -3;
4258       coneNew[3] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 7;
4259       orntNew[3] = -2;
4260       ierr       = DMPlexSetCone(rdm, newp+6, coneNew);CHKERRQ(ierr);
4261       ierr       = DMPlexSetConeOrientation(rdm, newp+6, orntNew);CHKERRQ(ierr);
4262 #if defined(PETSC_USE_DEBUG)
4263       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);
4264       for (p = 0; p < 4; ++p) {
4265         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);
4266       }
4267 #endif
4268       /* D' tetrahedron: {f, e, d, a} */
4269       coneNew[0] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 3;
4270       orntNew[0] = -3;
4271       coneNew[1] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 4;
4272       orntNew[1] = -3;
4273       coneNew[2] = fStartNew + (cone[1] - fStart)*4 + 3;
4274       orntNew[2] = ornt[1] < 0 ? -(GetTriMidEdge_Static(ornt[1], 0)+1) : GetTriMidEdge_Static(ornt[1], 0);
4275       coneNew[3] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 6;
4276       orntNew[3] = -3;
4277       ierr       = DMPlexSetCone(rdm, newp+7, coneNew);CHKERRQ(ierr);
4278       ierr       = DMPlexSetConeOrientation(rdm, newp+7, orntNew);CHKERRQ(ierr);
4279 #if defined(PETSC_USE_DEBUG)
4280       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);
4281       for (p = 0; p < 4; ++p) {
4282         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);
4283       }
4284 #endif
4285     }
4286     /* Hybrid cells have 5 faces */
4287     for (c = cMax; c < cEnd; ++c) {
4288       const PetscInt  newp = cStartNew + (cMax - cStart)*8 + (c - cMax)*4;
4289       const PetscInt *cone, *ornt, *fornt;
4290       PetscInt        coneNew[5], orntNew[5], o, of, i;
4291 
4292       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
4293       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
4294       ierr = DMPlexGetConeOrientation(dm, cone[0], &fornt);CHKERRQ(ierr);
4295       o = ornt[0] < 0 ? -1 : 1;
4296       for (r = 0; r < 3; ++r) {
4297         coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetTriSubface_Static(ornt[0], r);
4298         orntNew[0] = ornt[0];
4299         coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetTriSubface_Static(ornt[1], r);
4300         orntNew[1] = ornt[1];
4301         of = fornt[GetTriEdge_Static(ornt[0], r)]       < 0 ? -1 : 1;
4302         i  = GetTriEdgeInverse_Static(ornt[0], r)       + 2;
4303         coneNew[i] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (cone[2+GetTriEdge_Static(ornt[0], r)]       - fMax)*2 + (o*of < 0 ? 1 : 0);
4304         orntNew[i] = 0;
4305         i  = GetTriEdgeInverse_Static(ornt[0], (r+1)%3) + 2;
4306         coneNew[i] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (c - cMax)*3 + GetTriSubface_Static(ornt[0], r);
4307         orntNew[i] = 0;
4308         of = fornt[GetTriEdge_Static(ornt[0], (r+2)%3)] < 0 ? -1 : 1;
4309         i  = GetTriEdgeInverse_Static(ornt[0], (r+2)%3) + 2;
4310         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);
4311         orntNew[i] = 0;
4312         ierr = DMPlexSetCone(rdm, newp+r, coneNew);CHKERRQ(ierr);
4313         ierr = DMPlexSetConeOrientation(rdm, newp+r, orntNew);CHKERRQ(ierr);
4314 #if defined(PETSC_USE_DEBUG)
4315         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);
4316         for (p = 0; p < 2; ++p) {
4317           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);
4318         }
4319         for (p = 2; p < 5; ++p) {
4320           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);
4321         }
4322 #endif
4323       }
4324       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + 3;
4325       orntNew[0] = 0;
4326       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + 3;
4327       orntNew[1] = 0;
4328       coneNew[2] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (c - cMax)*3 + 1;
4329       orntNew[2] = 0;
4330       coneNew[3] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (c - cMax)*3 + 2;
4331       orntNew[3] = 0;
4332       coneNew[4] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (c - cMax)*3 + 0;
4333       orntNew[4] = 0;
4334       ierr = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
4335       ierr = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
4336 #if defined(PETSC_USE_DEBUG)
4337       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);
4338       for (p = 0; p < 2; ++p) {
4339         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);
4340       }
4341       for (p = 2; p < 5; ++p) {
4342         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);
4343       }
4344 #endif
4345     }
4346     /* Split faces have 3 edges and the same cells as the parent */
4347     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
4348     ierr = PetscMalloc1(2 + maxSupportSize*2, &supportRef);CHKERRQ(ierr);
4349     for (f = fStart; f < fMax; ++f) {
4350       const PetscInt  newp = fStartNew + (f - fStart)*4;
4351       const PetscInt *cone, *ornt, *support;
4352       PetscInt        coneNew[3], orntNew[3], coneSize, supportSize, s;
4353 
4354       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
4355       ierr = DMPlexGetConeOrientation(dm, f, &ornt);CHKERRQ(ierr);
4356       /* A triangle */
4357       coneNew[0] = eStartNew + (cone[0] - eStart)*2 + (ornt[0] < 0 ? 1 : 0);
4358       orntNew[0] = ornt[0];
4359       coneNew[1] = eStartNew + (eMax    - eStart)*2 + (f - fStart)*3 + 2;
4360       orntNew[1] = -2;
4361       coneNew[2] = eStartNew + (cone[2] - eStart)*2 + (ornt[2] < 0 ? 0 : 1);
4362       orntNew[2] = ornt[2];
4363       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
4364       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
4365 #if defined(PETSC_USE_DEBUG)
4366       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);
4367       for (p = 0; p < 3; ++p) {
4368         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);
4369       }
4370 #endif
4371       /* B triangle */
4372       coneNew[0] = eStartNew + (cone[0] - eStart)*2 + (ornt[0] < 0 ? 0 : 1);
4373       orntNew[0] = ornt[0];
4374       coneNew[1] = eStartNew + (cone[1] - eStart)*2 + (ornt[1] < 0 ? 1 : 0);
4375       orntNew[1] = ornt[1];
4376       coneNew[2] = eStartNew + (eMax    - eStart)*2 + (f - fStart)*3 + 0;
4377       orntNew[2] = -2;
4378       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
4379       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
4380 #if defined(PETSC_USE_DEBUG)
4381       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);
4382       for (p = 0; p < 3; ++p) {
4383         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);
4384       }
4385 #endif
4386       /* C triangle */
4387       coneNew[0] = eStartNew + (eMax    - eStart)*2 + (f - fStart)*3 + 1;
4388       orntNew[0] = -2;
4389       coneNew[1] = eStartNew + (cone[1] - eStart)*2 + (ornt[1] < 0 ? 0 : 1);
4390       orntNew[1] = ornt[1];
4391       coneNew[2] = eStartNew + (cone[2] - eStart)*2 + (ornt[2] < 0 ? 1 : 0);
4392       orntNew[2] = ornt[2];
4393       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
4394       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
4395 #if defined(PETSC_USE_DEBUG)
4396       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);
4397       for (p = 0; p < 3; ++p) {
4398         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);
4399       }
4400 #endif
4401       /* D triangle */
4402       coneNew[0] = eStartNew + (eMax    - eStart)*2 + (f - fStart)*3 + 0;
4403       orntNew[0] = 0;
4404       coneNew[1] = eStartNew + (eMax    - eStart)*2 + (f - fStart)*3 + 1;
4405       orntNew[1] = 0;
4406       coneNew[2] = eStartNew + (eMax    - eStart)*2 + (f - fStart)*3 + 2;
4407       orntNew[2] = 0;
4408       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
4409       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
4410 #if defined(PETSC_USE_DEBUG)
4411       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);
4412       for (p = 0; p < 3; ++p) {
4413         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);
4414       }
4415 #endif
4416       ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
4417       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
4418       for (r = 0; r < 4; ++r) {
4419         for (s = 0; s < supportSize; ++s) {
4420           PetscInt subf;
4421           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
4422           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
4423           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
4424           for (c = 0; c < coneSize; ++c) {
4425             if (cone[c] == f) break;
4426           }
4427           subf = GetTriSubfaceInverse_Static(ornt[c], r);
4428           if (support[s] < cMax) {
4429             supportRef[s] = cStartNew + (support[s] - cStart)*8 + (r==3 ? (c+2)%4 + 4 : faces[c*3+subf]);
4430           } else {
4431             supportRef[s] = cStartNew + (cMax - cStart)*8 + (support[s] - cMax)*4 + (r==3 ? r : subf);
4432           }
4433         }
4434         ierr = DMPlexSetSupport(rdm, newp+r, supportRef);CHKERRQ(ierr);
4435 #if defined(PETSC_USE_DEBUG)
4436         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);
4437         for (p = 0; p < supportSize; ++p) {
4438           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);
4439         }
4440 #endif
4441       }
4442     }
4443     /* Interior cell faces have 3 edges and 2 cells */
4444     for (c = cStart; c < cMax; ++c) {
4445       PetscInt        newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*8;
4446       const PetscInt *cone, *ornt;
4447       PetscInt        coneNew[3], orntNew[3];
4448       PetscInt        supportNew[2];
4449 
4450       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
4451       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
4452       /* Face A: {c, a, d} */
4453       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*3 + GetTriMidEdge_Static(ornt[0], 2);
4454       orntNew[0] = ornt[0] < 0 ? -2 : 0;
4455       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*3 + GetTriMidEdge_Static(ornt[1], 2);
4456       orntNew[1] = ornt[1] < 0 ? -2 : 0;
4457       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*3 + GetTriMidEdge_Static(ornt[2], 2);
4458       orntNew[2] = ornt[2] < 0 ? -2 : 0;
4459       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4460       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4461 #if defined(PETSC_USE_DEBUG)
4462       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fMaxNew);
4463       for (p = 0; p < 3; ++p) {
4464         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);
4465       }
4466 #endif
4467       supportNew[0] = (c - cStart)*8 + 0;
4468       supportNew[1] = (c - cStart)*8 + 0+4;
4469       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
4470 #if defined(PETSC_USE_DEBUG)
4471       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fMaxNew);
4472       for (p = 0; p < 2; ++p) {
4473         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);
4474       }
4475 #endif
4476       ++newp;
4477       /* Face B: {a, b, e} */
4478       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*3 + GetTriMidEdge_Static(ornt[0], 0);
4479       orntNew[0] = ornt[0] < 0 ? -2 : 0;
4480       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*3 + GetTriMidEdge_Static(ornt[3], 0);
4481       orntNew[1] = ornt[3] < 0 ? -2 : 0;
4482       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*3 + GetTriMidEdge_Static(ornt[1], 1);
4483       orntNew[2] = ornt[1] < 0 ? -2 : 0;
4484       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4485       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4486 #if defined(PETSC_USE_DEBUG)
4487       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);
4488       for (p = 0; p < 3; ++p) {
4489         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);
4490       }
4491 #endif
4492       supportNew[0] = (c - cStart)*8 + 1;
4493       supportNew[1] = (c - cStart)*8 + 1+4;
4494       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
4495 #if defined(PETSC_USE_DEBUG)
4496       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fMaxNew);
4497       for (p = 0; p < 2; ++p) {
4498         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);
4499       }
4500 #endif
4501       ++newp;
4502       /* Face C: {c, f, b} */
4503       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*3 + GetTriMidEdge_Static(ornt[2], 0);
4504       orntNew[0] = ornt[2] < 0 ? -2 : 0;
4505       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*3 + GetTriMidEdge_Static(ornt[3], 2);
4506       orntNew[1] = ornt[3] < 0 ? -2 : 0;
4507       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*3 + GetTriMidEdge_Static(ornt[0], 1);
4508       orntNew[2] = ornt[0] < 0 ? -2 : 0;
4509       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4510       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4511 #if defined(PETSC_USE_DEBUG)
4512       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fMaxNew);
4513       for (p = 0; p < 3; ++p) {
4514         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);
4515       }
4516 #endif
4517       supportNew[0] = (c - cStart)*8 + 2;
4518       supportNew[1] = (c - cStart)*8 + 2+4;
4519       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
4520 #if defined(PETSC_USE_DEBUG)
4521       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fMaxNew);
4522       for (p = 0; p < 2; ++p) {
4523         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);
4524       }
4525 #endif
4526       ++newp;
4527       /* Face D: {d, e, f} */
4528       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*3 + GetTriMidEdge_Static(ornt[1], 0);
4529       orntNew[0] = ornt[1] < 0 ? -2 : 0;
4530       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*3 + GetTriMidEdge_Static(ornt[3], 1);
4531       orntNew[1] = ornt[3] < 0 ? -2 : 0;
4532       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*3 + GetTriMidEdge_Static(ornt[2], 1);
4533       orntNew[2] = ornt[2] < 0 ? -2 : 0;
4534       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4535       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4536 #if defined(PETSC_USE_DEBUG)
4537       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fMaxNew);
4538       for (p = 0; p < 3; ++p) {
4539         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);
4540       }
4541 #endif
4542       supportNew[0] = (c - cStart)*8 + 3;
4543       supportNew[1] = (c - cStart)*8 + 3+4;
4544       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
4545 #if defined(PETSC_USE_DEBUG)
4546       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fMaxNew);
4547       for (p = 0; p < 2; ++p) {
4548         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);
4549       }
4550 #endif
4551       ++newp;
4552       /* Face E: {d, f, a} */
4553       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*3 + GetTriMidEdge_Static(ornt[2], 1);
4554       orntNew[0] = ornt[2] < 0 ? 0 : -2;
4555       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart);
4556       orntNew[1] = -2;
4557       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*3 + GetTriMidEdge_Static(ornt[1], 2);
4558       orntNew[2] = ornt[1] < 0 ? -2 : 0;
4559       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4560       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4561 #if defined(PETSC_USE_DEBUG)
4562       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fMaxNew);
4563       for (p = 0; p < 3; ++p) {
4564         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);
4565       }
4566 #endif
4567       supportNew[0] = (c - cStart)*8 + 0+4;
4568       supportNew[1] = (c - cStart)*8 + 3+4;
4569       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
4570 #if defined(PETSC_USE_DEBUG)
4571       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fMaxNew);
4572       for (p = 0; p < 2; ++p) {
4573         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);
4574       }
4575 #endif
4576       ++newp;
4577       /* Face F: {c, a, f} */
4578       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*3 + GetTriMidEdge_Static(ornt[0], 2);
4579       orntNew[0] = ornt[0] < 0 ? -2 : 0;
4580       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart);
4581       orntNew[1] = 0;
4582       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*3 + GetTriMidEdge_Static(ornt[2], 0);
4583       orntNew[2] = ornt[2] < 0 ? 0 : -2;
4584       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4585       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4586 #if defined(PETSC_USE_DEBUG)
4587       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fMaxNew);
4588       for (p = 0; p < 3; ++p) {
4589         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);
4590       }
4591 #endif
4592       supportNew[0] = (c - cStart)*8 + 0+4;
4593       supportNew[1] = (c - cStart)*8 + 2+4;
4594       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
4595 #if defined(PETSC_USE_DEBUG)
4596       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fMaxNew);
4597       for (p = 0; p < 2; ++p) {
4598         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);
4599       }
4600 #endif
4601       ++newp;
4602       /* Face G: {e, a, f} */
4603       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*3 + GetTriMidEdge_Static(ornt[1], 1);
4604       orntNew[0] = ornt[1] < 0 ? -2 : 0;
4605       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart);
4606       orntNew[1] = 0;
4607       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*3 + GetTriMidEdge_Static(ornt[3], 1);
4608       orntNew[2] = ornt[3] < 0 ? 0 : -2;
4609       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4610       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4611 #if defined(PETSC_USE_DEBUG)
4612       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fMaxNew);
4613       for (p = 0; p < 3; ++p) {
4614         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);
4615       }
4616 #endif
4617       supportNew[0] = (c - cStart)*8 + 1+4;
4618       supportNew[1] = (c - cStart)*8 + 3+4;
4619       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
4620 #if defined(PETSC_USE_DEBUG)
4621       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fMaxNew);
4622       for (p = 0; p < 2; ++p) {
4623         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);
4624       }
4625 #endif
4626       ++newp;
4627       /* Face H: {a, b, f} */
4628       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*3 + GetTriMidEdge_Static(ornt[0], 0);
4629       orntNew[0] = ornt[0] < 0 ? -2 : 0;
4630       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*3 + GetTriMidEdge_Static(ornt[3], 2);
4631       orntNew[1] = ornt[3] < 0 ? 0 : -2;
4632       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart);
4633       orntNew[2] = -2;
4634       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4635       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4636 #if defined(PETSC_USE_DEBUG)
4637       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fMaxNew);
4638       for (p = 0; p < 3; ++p) {
4639         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);
4640       }
4641 #endif
4642       supportNew[0] = (c - cStart)*8 + 1+4;
4643       supportNew[1] = (c - cStart)*8 + 2+4;
4644       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
4645 #if defined(PETSC_USE_DEBUG)
4646       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fMaxNew);
4647       for (p = 0; p < 2; ++p) {
4648         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);
4649       }
4650 #endif
4651       ++newp;
4652     }
4653     /* Hybrid split faces have 4 edges and same cells */
4654     for (f = fMax; f < fEnd; ++f) {
4655       const PetscInt *cone, *ornt, *support;
4656       PetscInt        coneNew[4], orntNew[4];
4657       PetscInt        supportNew[2], size, s, c;
4658 
4659       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
4660       ierr = DMPlexGetConeOrientation(dm, f, &ornt);CHKERRQ(ierr);
4661       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
4662       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
4663       for (r = 0; r < 2; ++r) {
4664         const PetscInt newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (f - fMax)*2 + r;
4665 
4666         coneNew[0]   = eStartNew + (cone[0] - eStart)*2 + (ornt[0] < 0 ? 1-r : r);
4667         orntNew[0]   = ornt[0];
4668         coneNew[1]   = eStartNew + (cone[1] - eStart)*2 + (ornt[1] < 0 ? 1-r : r);
4669         orntNew[1]   = ornt[1];
4670         coneNew[2+r] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (cone[2+r] - eMax);
4671         orntNew[2+r] = 0;
4672         coneNew[3-r] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (eEnd      - eMax) + (f - fMax);
4673         orntNew[3-r] = 0;
4674         ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4675         ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4676 #if defined(PETSC_USE_DEBUG)
4677         if ((newp < fMaxNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a hybrid face [%D, %D)", newp, fMaxNew, fEndNew);
4678         for (p = 0; p < 2; ++p) {
4679           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);
4680         }
4681         for (p = 2; p < 4; ++p) {
4682           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);
4683         }
4684 #endif
4685         for (s = 0; s < size; ++s) {
4686           const PetscInt *coneCell, *orntCell, *fornt;
4687           PetscInt        o, of;
4688 
4689           ierr = DMPlexGetCone(dm, support[s], &coneCell);CHKERRQ(ierr);
4690           ierr = DMPlexGetConeOrientation(dm, support[s], &orntCell);CHKERRQ(ierr);
4691           o = orntCell[0] < 0 ? -1 : 1;
4692           for (c = 2; c < 5; ++c) if (coneCell[c] == f) break;
4693           if (c >= 5) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Could not find face %D in cone of cell %D", f, support[s]);
4694           ierr = DMPlexGetConeOrientation(dm, coneCell[0], &fornt);CHKERRQ(ierr);
4695           of = fornt[c-2] < 0 ? -1 : 1;
4696           supportNew[s] = cStartNew + (cMax - cStart)*8 + (support[s] - cMax)*4 + (GetTriEdgeInverse_Static(orntCell[0], c-2) + (o*of < 0 ? 1-r : r))%3;
4697         }
4698         ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
4699 #if defined(PETSC_USE_DEBUG)
4700         if ((newp < fMaxNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a hybrid face [%D, %D)", newp, fMaxNew, fEndNew);
4701         for (p = 0; p < size; ++p) {
4702           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);
4703         }
4704 #endif
4705       }
4706     }
4707     /* Hybrid cell faces have 4 edges and 2 cells */
4708     for (c = cMax; c < cEnd; ++c) {
4709       PetscInt        newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (c - cMax)*3;
4710       const PetscInt *cone, *ornt;
4711       PetscInt        coneNew[4], orntNew[4];
4712       PetscInt        supportNew[2];
4713 
4714       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
4715       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
4716       for (r = 0; r < 3; ++r) {
4717         coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*3 + (r+2)%3;
4718         orntNew[0] = 0;
4719         coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*3 + (r+2)%3;
4720         orntNew[1] = 0;
4721         coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (eEnd - eMax) + (cone[2+(r+2)%3] - fMax);
4722         orntNew[2] = 0;
4723         coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (eEnd - eMax) + (cone[2+r]       - fMax);
4724         orntNew[3] = 0;
4725         ierr = DMPlexSetCone(rdm, newp+r, coneNew);CHKERRQ(ierr);
4726         ierr = DMPlexSetConeOrientation(rdm, newp+r, orntNew);CHKERRQ(ierr);
4727 #if defined(PETSC_USE_DEBUG)
4728         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);
4729         for (p = 0; p < 2; ++p) {
4730           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);
4731         }
4732         for (p = 2; p < 4; ++p) {
4733           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);
4734         }
4735 #endif
4736         supportNew[0] = cStartNew + (cMax - cStart)*8 + (c - cMax)*4 + GetTriSubface_Static(ornt[0], r);
4737         supportNew[1] = cStartNew + (cMax - cStart)*8 + (c - cMax)*4 + 3;
4738         ierr          = DMPlexSetSupport(rdm, newp+r, supportNew);CHKERRQ(ierr);
4739 #if defined(PETSC_USE_DEBUG)
4740         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);
4741         for (p = 0; p < 2; ++p) {
4742           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);
4743         }
4744 #endif
4745       }
4746     }
4747     /* Interior split edges have 2 vertices and the same faces as the parent */
4748     for (e = eStart; e < eMax; ++e) {
4749       const PetscInt newv = vStartNew + (vEnd - vStart) + (e - eStart);
4750 
4751       for (r = 0; r < 2; ++r) {
4752         const PetscInt  newp = eStartNew + (e - eStart)*2 + r;
4753         const PetscInt *cone, *ornt, *support;
4754         PetscInt        coneNew[2], coneSize, c, supportSize, s;
4755 
4756         ierr             = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
4757         coneNew[0]       = vStartNew + (cone[0] - vStart);
4758         coneNew[1]       = vStartNew + (cone[1] - vStart);
4759         coneNew[(r+1)%2] = newv;
4760         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4761 #if defined(PETSC_USE_DEBUG)
4762         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eMaxNew);
4763         for (p = 0; p < 2; ++p) {
4764           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);
4765         }
4766 #endif
4767         ierr = DMPlexGetSupportSize(dm, e, &supportSize);CHKERRQ(ierr);
4768         ierr = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
4769         for (s = 0; s < supportSize; ++s) {
4770           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
4771           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
4772           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
4773           for (c = 0; c < coneSize; ++c) if (cone[c] == e) break;
4774           if (support[s] < fMax) {
4775             supportRef[s] = fStartNew + (support[s] - fStart)*4 + (c + (ornt[c] < 0 ? 1-r : r))%3;
4776           } else {
4777             supportRef[s] = fStartNew + (fMax       - fStart)*4 + (cMax - cStart)*8 + (support[s] - fMax)*2 + (ornt[c] < 0 ? 1-r : r);
4778           }
4779         }
4780         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
4781 #if defined(PETSC_USE_DEBUG)
4782         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eMaxNew);
4783         for (p = 0; p < supportSize; ++p) {
4784           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);
4785         }
4786 #endif
4787       }
4788     }
4789     /* Interior face edges have 2 vertices and 2+cells*(1/2) faces */
4790     for (f = fStart; f < fMax; ++f) {
4791       const PetscInt *cone, *ornt, *support;
4792       PetscInt        coneSize, supportSize, s;
4793 
4794       ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
4795       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
4796       for (r = 0; r < 3; ++r) {
4797         const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (f - fStart)*3 + r;
4798         PetscInt        coneNew[2], intFaces = 0, er, eint[4] = {1, 0, 2, 0};
4799         PetscInt        fint[24] = { 1,  7, -1, -1,  0,  5,
4800                                     -1, -1,  1,  6,  0,  4,
4801                                      2,  5,  3,  4, -1, -1,
4802                                     -1, -1,  3,  6,  2,  7};
4803 
4804         ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
4805         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[(r+0)%3] - eStart);
4806         coneNew[1] = vStartNew + (vEnd - vStart) + (cone[(r+1)%3] - eStart);
4807         ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4808 #if defined(PETSC_USE_DEBUG)
4809         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eMaxNew);
4810         for (p = 0; p < 2; ++p) {
4811           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);
4812         }
4813 #endif
4814         supportRef[0] = fStartNew + (f - fStart)*4 + (r+1)%3;
4815         supportRef[1] = fStartNew + (f - fStart)*4 + 3;
4816         for (s = 0; s < supportSize; ++s) {
4817           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
4818           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
4819           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
4820           for (c = 0; c < coneSize; ++c) {if (cone[c] == f) break;}
4821           if (support[s] < cMax) {
4822             /* Here we want to determine whether edge newp contains a vertex which is part of the cross-tet edge */
4823             er = GetTriMidEdgeInverse_Static(ornt[c], r);
4824             if (er == eint[c]) {
4825               supportRef[2+intFaces++] = fStartNew + (fMax - fStart)*4 + (support[s] - cStart)*8 + (c + 2)%4;
4826             } else {
4827               supportRef[2+intFaces++] = fStartNew + (fMax - fStart)*4 + (support[s] - cStart)*8 + fint[(c*3 + er)*2 + 0];
4828               supportRef[2+intFaces++] = fStartNew + (fMax - fStart)*4 + (support[s] - cStart)*8 + fint[(c*3 + er)*2 + 1];
4829             }
4830           } else {
4831             supportRef[2+intFaces++] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (support[s] - cMax)*3 + (r + 1)%3;
4832           }
4833         }
4834         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
4835 #if defined(PETSC_USE_DEBUG)
4836         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eMaxNew);
4837         for (p = 0; p < intFaces; ++p) {
4838           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);
4839         }
4840 #endif
4841       }
4842     }
4843     /* Interior cell edges have 2 vertices and 4 faces */
4844     for (c = cStart; c < cMax; ++c) {
4845       const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart);
4846       const PetscInt *cone, *ornt, *fcone;
4847       PetscInt        coneNew[2], supportNew[4], find;
4848 
4849       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
4850       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
4851       ierr = DMPlexGetCone(dm, cone[0], &fcone);CHKERRQ(ierr);
4852       find = GetTriEdge_Static(ornt[0], 0);
4853       coneNew[0] = vStartNew + (vEnd - vStart) + (fcone[find] - eStart);
4854       ierr = DMPlexGetCone(dm, cone[2], &fcone);CHKERRQ(ierr);
4855       find = GetTriEdge_Static(ornt[2], 1);
4856       coneNew[1] = vStartNew + (vEnd - vStart) + (fcone[find] - eStart);
4857       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4858 #if defined(PETSC_USE_DEBUG)
4859       if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eMaxNew);
4860       for (p = 0; p < 2; ++p) {
4861         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);
4862       }
4863 #endif
4864       supportNew[0] = fStartNew + (fMax - fStart)*4 + (c - cStart)*8 + 4;
4865       supportNew[1] = fStartNew + (fMax - fStart)*4 + (c - cStart)*8 + 5;
4866       supportNew[2] = fStartNew + (fMax - fStart)*4 + (c - cStart)*8 + 6;
4867       supportNew[3] = fStartNew + (fMax - fStart)*4 + (c - cStart)*8 + 7;
4868       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
4869 #if defined(PETSC_USE_DEBUG)
4870       if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eMaxNew);
4871       for (p = 0; p < 4; ++p) {
4872         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);
4873       }
4874 #endif
4875     }
4876     /* Hybrid edges have two vertices and the same faces */
4877     for (e = eMax; e < eEnd; ++e) {
4878       const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (e - eMax);
4879       const PetscInt *cone, *support, *fcone;
4880       PetscInt        coneNew[2], size, fsize, s;
4881 
4882       ierr = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
4883       ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
4884       ierr = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
4885       coneNew[0] = vStartNew + (cone[0] - vStart);
4886       coneNew[1] = vStartNew + (cone[1] - vStart);
4887       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4888 #if defined(PETSC_USE_DEBUG)
4889       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a hybrid edge [%D, %D)", newp, eMaxNew, eEndNew);
4890       for (p = 0; p < 2; ++p) {
4891         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);
4892       }
4893 #endif
4894       for (s = 0; s < size; ++s) {
4895         ierr = DMPlexGetConeSize(dm, support[s], &fsize);CHKERRQ(ierr);
4896         ierr = DMPlexGetCone(dm, support[s], &fcone);CHKERRQ(ierr);
4897         for (c = 0; c < fsize; ++c) if (fcone[c] == e) break;
4898         if ((c < 2) || (c > 3)) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Edge %D not found in cone of face %D", e, support[s]);
4899         supportRef[s] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (support[s] - fMax)*2 + c-2;
4900       }
4901       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
4902 #if defined(PETSC_USE_DEBUG)
4903       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a hybrid edge [%D, %D)", newp, eMaxNew, eEndNew);
4904       for (p = 0; p < size; ++p) {
4905         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);
4906       }
4907 #endif
4908     }
4909     /* Hybrid face edges have 2 vertices and 2+2*cells faces */
4910     for (f = fMax; f < fEnd; ++f) {
4911       const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (eEnd - eMax) + (f - fMax);
4912       const PetscInt *cone, *support, *ccone, *cornt;
4913       PetscInt        coneNew[2], size, csize, s;
4914 
4915       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
4916       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
4917       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
4918       coneNew[0] = vStartNew + (vEnd - vStart) + (cone[0] - eStart);
4919       coneNew[1] = vStartNew + (vEnd - vStart) + (cone[1] - eStart);
4920       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4921 #if defined(PETSC_USE_DEBUG)
4922       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a hybrid edge [%D, %D)", newp, eMaxNew, eEndNew);
4923       for (p = 0; p < 2; ++p) {
4924         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);
4925       }
4926 #endif
4927       supportRef[0] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (f - fMax)*2 + 0;
4928       supportRef[1] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (f - fMax)*2 + 1;
4929       for (s = 0; s < size; ++s) {
4930         ierr = DMPlexGetConeSize(dm, support[s], &csize);CHKERRQ(ierr);
4931         ierr = DMPlexGetCone(dm, support[s], &ccone);CHKERRQ(ierr);
4932         ierr = DMPlexGetConeOrientation(dm, support[s], &cornt);CHKERRQ(ierr);
4933         for (c = 0; c < csize; ++c) if (ccone[c] == f) break;
4934         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]);
4935         supportRef[2+s*2+0] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (support[s] - cMax)*3 + c-2;
4936         supportRef[2+s*2+1] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (support[s] - cMax)*3 + (c-1)%3;
4937       }
4938       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
4939 #if defined(PETSC_USE_DEBUG)
4940       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a hybrid edge [%D, %D)", newp, eMaxNew, eEndNew);
4941       for (p = 0; p < 2+size*2; ++p) {
4942         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);
4943       }
4944 #endif
4945     }
4946     /* Interior vertices have identical supports */
4947     for (v = vStart; v < vEnd; ++v) {
4948       const PetscInt  newp = vStartNew + (v - vStart);
4949       const PetscInt *support, *cone;
4950       PetscInt        size, s;
4951 
4952       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
4953       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
4954       for (s = 0; s < size; ++s) {
4955         PetscInt r = 0;
4956 
4957         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
4958         if (cone[1] == v) r = 1;
4959         if (support[s] < eMax) supportRef[s] = eStartNew + (support[s] - eStart)*2 + r;
4960         else                   supportRef[s] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (support[s] - eMax);
4961       }
4962       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
4963 #if defined(PETSC_USE_DEBUG)
4964       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", newp, vStartNew, vEndNew);
4965       for (p = 0; p < size; ++p) {
4966         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);
4967       }
4968 #endif
4969     }
4970     /* Interior edge vertices have 2 + interior face*2 + hybrid face + cells*0/1 supports */
4971     for (e = eStart; e < eMax; ++e) {
4972       const PetscInt  newp = vStartNew + (vEnd - vStart) + (e - eStart);
4973       const PetscInt *cone, *support;
4974       PetscInt       *star = NULL, starSize, faceSize = 0, cellSize = 0, coneSize, size, s;
4975 
4976       ierr          = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
4977       ierr          = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
4978       supportRef[0] = eStartNew + (e - eStart)*2 + 0;
4979       supportRef[1] = eStartNew + (e - eStart)*2 + 1;
4980       for (s = 0; s < size; ++s) {
4981         PetscInt r = 0;
4982 
4983         if (support[s] < fMax) {
4984           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
4985           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
4986           for (r = 0; r < coneSize; ++r) {if (cone[r] == e) break;}
4987           supportRef[2+faceSize+0] = eStartNew + (eMax - eStart)*2 + (support[s] - fStart)*3 + (r+0)%3;
4988           supportRef[2+faceSize+1] = eStartNew + (eMax - eStart)*2 + (support[s] - fStart)*3 + (r+2)%3;
4989           faceSize += 2;
4990         } else {
4991           supportRef[2+faceSize+0] = eStartNew + (eMax - eStart)*2 + (fMax       - fStart)*3 + (cMax - cStart) + (eEnd - eMax) + (support[s] - fMax);
4992           ++faceSize;
4993         }
4994       }
4995       ierr = DMPlexGetTransitiveClosure(dm, e, PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
4996       for (s = 0; s < starSize*2; s += 2) {
4997         const PetscInt *cone, *ornt;
4998         PetscInt        e01, e23;
4999 
5000         if ((star[s] >= cStart) && (star[s] < cMax)) {
5001           /* Check edge 0-1 */
5002           ierr = DMPlexGetCone(dm, star[s], &cone);CHKERRQ(ierr);
5003           ierr = DMPlexGetConeOrientation(dm, star[s], &ornt);CHKERRQ(ierr);
5004           ierr = DMPlexGetCone(dm, cone[0], &cone);CHKERRQ(ierr);
5005           e01  = cone[GetTriEdge_Static(ornt[0], 0)];
5006           /* Check edge 2-3 */
5007           ierr = DMPlexGetCone(dm, star[s], &cone);CHKERRQ(ierr);
5008           ierr = DMPlexGetConeOrientation(dm, star[s], &ornt);CHKERRQ(ierr);
5009           ierr = DMPlexGetCone(dm, cone[2], &cone);CHKERRQ(ierr);
5010           e23  = cone[GetTriEdge_Static(ornt[2], 1)];
5011           if ((e01 == e) || (e23 == e)) {supportRef[2+faceSize+cellSize++] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (star[s] - cStart);}
5012         }
5013       }
5014       ierr = DMPlexRestoreTransitiveClosure(dm, e, PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
5015       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
5016 #if defined(PETSC_USE_DEBUG)
5017       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", newp, vStartNew, vEndNew);
5018       for (p = 0; p < 2+faceSize+cellSize; ++p) {
5019         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);
5020       }
5021 #endif
5022     }
5023     ierr = PetscFree(supportRef);CHKERRQ(ierr);
5024     ierr = DMPlexRestoreFaces_Internal(dm, 3, cStart, NULL, NULL, &faces);CHKERRQ(ierr);
5025     break;
5026   case REFINER_SIMPLEX_TO_HEX_3D:
5027     ierr = DMPlexGetRawFaces_Internal(dm, 3, 4, cellInd, NULL, NULL, &faces);CHKERRQ(ierr);
5028     /* All cells have 6 faces */
5029     for (c = cStart; c < cEnd; ++c) {
5030       const PetscInt  newp = cStartNew + (c - cStart)*4;
5031       const PetscInt *cone, *ornt;
5032       PetscInt        coneNew[6];
5033       PetscInt        orntNew[6];
5034 
5035       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
5036       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
5037       /* A hex */
5038       coneNew[0] = fStartNew + (cone[0] - fStart)*3 + GetTriSubface_Static(ornt[0], 0); /* B */
5039       orntNew[0] = ornt[0] < 0 ? -1 : 1;
5040       coneNew[1] = fStartNew + (fEnd    - fStart)*3 + (c - cStart)*6 + 3;               /* T */
5041       orntNew[1] = -4;
5042       coneNew[2] = fStartNew + (cone[2] - fStart)*3 + GetTriSubface_Static(ornt[2], 0); /* F */
5043       orntNew[2] = ornt[2] < 0 ? -1 : 1;
5044       coneNew[3] = fStartNew + (fEnd    - fStart)*3 + (c - cStart)*6 + 0;               /* K */
5045       orntNew[3] = -1;
5046       coneNew[4] = fStartNew + (fEnd    - fStart)*3 + (c - cStart)*6 + 2;               /* R */
5047       orntNew[4] = 0;
5048       coneNew[5] = fStartNew + (cone[1] - fStart)*3 + GetTriSubface_Static(ornt[1], 0); /* L */
5049       orntNew[5] = ornt[1] < 0 ? -1 : 1;
5050       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
5051       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
5052 #if defined(PETSC_USE_DEBUG)
5053       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);
5054       for (p = 0; p < 6; ++p) {
5055         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);
5056       }
5057 #endif
5058       /* B hex */
5059       coneNew[0] = fStartNew + (cone[0] - fStart)*3 + GetTriSubface_Static(ornt[0], 1); /* B */
5060       orntNew[0] = ornt[0] < 0 ? -2 : 0;
5061       coneNew[1] = fStartNew + (fEnd    - fStart)*3 + (c - cStart)*6 + 4;               /* T */
5062       orntNew[1] = 0;
5063       coneNew[2] = fStartNew + (fEnd    - fStart)*3 + (c - cStart)*6 + 0;               /* F */
5064       orntNew[2] = 0;
5065       coneNew[3] = fStartNew + (cone[3] - fStart)*3 + GetTriSubface_Static(ornt[3], 1); /* K */
5066       orntNew[3] = ornt[3] < 0 ? -2 : 0;
5067       coneNew[4] = fStartNew + (fEnd    - fStart)*3 + (c - cStart)*6 + 1;               /* R */
5068       orntNew[4] = 0;
5069       coneNew[5] = fStartNew + (cone[1] - fStart)*3 + GetTriSubface_Static(ornt[1], 2); /* L */
5070       orntNew[5] = ornt[1] < 0 ? -4 : 2;
5071       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
5072       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
5073 #if defined(PETSC_USE_DEBUG)
5074       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);
5075       for (p = 0; p < 6; ++p) {
5076         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);
5077       }
5078 #endif
5079       /* C hex */
5080       coneNew[0] = fStartNew + (cone[0] - fStart)*3 + GetTriSubface_Static(ornt[0], 2); /* B */
5081       orntNew[0] = ornt[0] < 0 ? -4 : 2;
5082       coneNew[1] = fStartNew + (fEnd    - fStart)*3 + (c - cStart)*6 + 5;               /* T */
5083       orntNew[1] = -4;
5084       coneNew[2] = fStartNew + (cone[2] - fStart)*3 + GetTriSubface_Static(ornt[2], 1); /* F */
5085       orntNew[2] = ornt[2] < 0 ? -2 : 0;
5086       coneNew[3] = fStartNew + (fEnd    - fStart)*3 + (c - cStart)*6 + 1;               /* K */
5087       orntNew[3] = -1;
5088       coneNew[4] = fStartNew + (cone[3] - fStart)*3 + GetTriSubface_Static(ornt[3], 0); /* R */
5089       orntNew[4] = ornt[3] < 0 ? -1 : 1;
5090       coneNew[5] = fStartNew + (fEnd    - fStart)*3 + (c - cStart)*6 + 2;               /* L */
5091       orntNew[5] = -4;
5092       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
5093       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
5094 #if defined(PETSC_USE_DEBUG)
5095       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);
5096       for (p = 0; p < 6; ++p) {
5097         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);
5098       }
5099 #endif
5100       /* D hex */
5101       coneNew[0] = fStartNew + (fEnd    - fStart)*3 + (c - cStart)*6 + 3;               /* B */
5102       orntNew[0] = 0;
5103       coneNew[1] = fStartNew + (cone[3] - fStart)*3 + GetTriSubface_Static(ornt[3], 2); /* T */
5104       orntNew[1] = ornt[3] < 0 ? -1 : 1;
5105       coneNew[2] = fStartNew + (cone[2] - fStart)*3 + GetTriSubface_Static(ornt[2], 2); /* F */
5106       orntNew[2] = ornt[2] < 0 ? -4 : 2;
5107       coneNew[3] = fStartNew + (fEnd    - fStart)*3 + (c - cStart)*6 + 4;               /* K */
5108       orntNew[3] = -1;
5109       coneNew[4] = fStartNew + (fEnd    - fStart)*3 + (c - cStart)*6 + 5;               /* R */
5110       orntNew[4] = 0;
5111       coneNew[5] = fStartNew + (cone[1] - fStart)*3 + GetTriSubface_Static(ornt[1], 1); /* L */
5112       orntNew[5] = ornt[1] < 0 ? -2 : 0;
5113       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
5114       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
5115 #if defined(PETSC_USE_DEBUG)
5116       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);
5117       for (p = 0; p < 6; ++p) {
5118         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);
5119       }
5120 #endif
5121     }
5122     /* Split faces have 4 edges and the same cells as the parent */
5123     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
5124     ierr = PetscMalloc1(2 + maxSupportSize*2, &supportRef);CHKERRQ(ierr);
5125     for (f = fStart; f < fEnd; ++f) {
5126       const PetscInt  newp = fStartNew + (f - fStart)*3;
5127       const PetscInt *cone, *ornt, *support;
5128       PetscInt        coneNew[4], orntNew[4], coneSize, supportSize, s;
5129 
5130       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
5131       ierr = DMPlexGetConeOrientation(dm, f, &ornt);CHKERRQ(ierr);
5132       /* A quad */
5133       coneNew[0] = eStartNew + (cone[2] - eStart)*2 + (ornt[2] < 0 ? 0 : 1);
5134       orntNew[0] = ornt[2];
5135       coneNew[1] = eStartNew + (cone[0] - eStart)*2 + (ornt[0] < 0 ? 1 : 0);
5136       orntNew[1] = ornt[0];
5137       coneNew[2] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 0;
5138       orntNew[2] = 0;
5139       coneNew[3] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 2;
5140       orntNew[3] = -2;
5141       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
5142       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
5143 #if defined(PETSC_USE_DEBUG)
5144       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);
5145       for (p = 0; p < 4; ++p) {
5146         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);
5147       }
5148 #endif
5149       /* B quad */
5150       coneNew[0] = eStartNew + (cone[0] - eStart)*2 + (ornt[0] < 0 ? 0 : 1);
5151       orntNew[0] = ornt[0];
5152       coneNew[1] = eStartNew + (cone[1] - eStart)*2 + (ornt[1] < 0 ? 1 : 0);
5153       orntNew[1] = ornt[1];
5154       coneNew[2] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 1;
5155       orntNew[2] = 0;
5156       coneNew[3] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 0;
5157       orntNew[3] = -2;
5158       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
5159       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
5160 #if defined(PETSC_USE_DEBUG)
5161       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);
5162       for (p = 0; p < 4; ++p) {
5163         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);
5164       }
5165 #endif
5166       /* C quad */
5167       coneNew[0] = eStartNew + (cone[1] - eStart)*2 + (ornt[1] < 0 ? 0 : 1);
5168       orntNew[0] = ornt[1];
5169       coneNew[1] = eStartNew + (cone[2] - eStart)*2 + (ornt[2] < 0 ? 1 : 0);
5170       orntNew[1] = ornt[2];
5171       coneNew[2] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 2;
5172       orntNew[2] = 0;
5173       coneNew[3] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 1;
5174       orntNew[3] = -2;
5175       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
5176       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
5177 #if defined(PETSC_USE_DEBUG)
5178       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);
5179       for (p = 0; p < 4; ++p) {
5180         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);
5181       }
5182 #endif
5183       ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
5184       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
5185       for (r = 0; r < 3; ++r) {
5186         for (s = 0; s < supportSize; ++s) {
5187           PetscInt subf;
5188           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
5189           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
5190           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
5191           for (c = 0; c < coneSize; ++c) {
5192             if (cone[c] == f) break;
5193           }
5194           subf = GetTriSubfaceInverse_Static(ornt[c], r);
5195           supportRef[s] = cStartNew + (support[s] - cStart)*4 + faces[c*3+subf];
5196         }
5197         ierr = DMPlexSetSupport(rdm, newp+r, supportRef);CHKERRQ(ierr);
5198 #if defined(PETSC_USE_DEBUG)
5199         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);
5200         for (p = 0; p < supportSize; ++p) {
5201           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);
5202         }
5203 #endif
5204       }
5205     }
5206     /* Interior faces have 4 edges and 2 cells */
5207     for (c = cStart; c < cEnd; ++c) {
5208       PetscInt        newp = fStartNew + (fEnd - fStart)*3 + (c - cStart)*6;
5209       const PetscInt *cone, *ornt;
5210       PetscInt        coneNew[4], orntNew[4];
5211       PetscInt        supportNew[2];
5212 
5213       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
5214       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
5215       /* Face {a, g, m, h} */
5216       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*3 + GetTriInteriorEdge_Static(ornt[0],0);
5217       orntNew[0] = 0;
5218       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + 0;
5219       orntNew[1] = 0;
5220       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + 1;
5221       orntNew[2] = -2;
5222       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*3 + GetTriInteriorEdge_Static(ornt[1],2);
5223       orntNew[3] = -2;
5224       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5225       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
5226 #if defined(PETSC_USE_DEBUG)
5227       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
5228       for (p = 0; p < 4; ++p) {
5229         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);
5230       }
5231 #endif
5232       supportNew[0] = (c - cStart)*4 + 0;
5233       supportNew[1] = (c - cStart)*4 + 1;
5234       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
5235 #if defined(PETSC_USE_DEBUG)
5236       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
5237       for (p = 0; p < 2; ++p) {
5238         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);
5239       }
5240 #endif
5241       ++newp;
5242       /* Face {g, b, l , m} */
5243       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*3 + GetTriInteriorEdge_Static(ornt[0],1);
5244       orntNew[0] = -2;
5245       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*3 + GetTriInteriorEdge_Static(ornt[3],0);
5246       orntNew[1] = 0;
5247       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + 3;
5248       orntNew[2] = 0;
5249       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + 0;
5250       orntNew[3] = -2;
5251       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5252       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
5253 #if defined(PETSC_USE_DEBUG)
5254       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
5255       for (p = 0; p < 4; ++p) {
5256         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);
5257       }
5258 #endif
5259       supportNew[0] = (c - cStart)*4 + 1;
5260       supportNew[1] = (c - cStart)*4 + 2;
5261       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
5262 #if defined(PETSC_USE_DEBUG)
5263       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
5264       for (p = 0; p < 2; ++p) {
5265         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);
5266       }
5267 #endif
5268       ++newp;
5269       /* Face {c, g, m, i} */
5270       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*3 + GetTriInteriorEdge_Static(ornt[0],2);
5271       orntNew[0] = 0;
5272       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + 0;
5273       orntNew[1] = 0;
5274       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + 2;
5275       orntNew[2] = -2;
5276       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*3 + GetTriInteriorEdge_Static(ornt[2],0);
5277       orntNew[3] = -2;
5278       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5279       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
5280 #if defined(PETSC_USE_DEBUG)
5281       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
5282       for (p = 0; p < 4; ++p) {
5283         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);
5284       }
5285 #endif
5286       supportNew[0] = (c - cStart)*4 + 0;
5287       supportNew[1] = (c - cStart)*4 + 2;
5288       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
5289 #if defined(PETSC_USE_DEBUG)
5290       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
5291       for (p = 0; p < 2; ++p) {
5292         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);
5293       }
5294 #endif
5295       ++newp;
5296       /* Face {d, h, m, i} */
5297       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*3 + GetTriInteriorEdge_Static(ornt[1],0);
5298       orntNew[0] = 0;
5299       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + 1;
5300       orntNew[1] = 0;
5301       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + 2;
5302       orntNew[2] = -2;
5303       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*3 + GetTriInteriorEdge_Static(ornt[2],2);
5304       orntNew[3] = -2;
5305       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5306       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
5307 #if defined(PETSC_USE_DEBUG)
5308       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
5309       for (p = 0; p < 4; ++p) {
5310         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);
5311       }
5312 #endif
5313       supportNew[0] = (c - cStart)*4 + 0;
5314       supportNew[1] = (c - cStart)*4 + 3;
5315       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
5316 #if defined(PETSC_USE_DEBUG)
5317       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
5318       for (p = 0; p < 2; ++p) {
5319         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);
5320       }
5321 #endif
5322       ++newp;
5323       /* Face {h, m, l, e} */
5324       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + 1;
5325       orntNew[0] = 0;
5326       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + 3;
5327       orntNew[1] = -2;
5328       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*3 + GetTriInteriorEdge_Static(ornt[3],1);
5329       orntNew[2] = -2;
5330       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*3 + GetTriInteriorEdge_Static(ornt[1],1);
5331       orntNew[3] = 0;
5332       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5333       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
5334 #if defined(PETSC_USE_DEBUG)
5335       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
5336       for (p = 0; p < 4; ++p) {
5337         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);
5338       }
5339 #endif
5340       supportNew[0] = (c - cStart)*4 + 1;
5341       supportNew[1] = (c - cStart)*4 + 3;
5342       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
5343 #if defined(PETSC_USE_DEBUG)
5344       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
5345       for (p = 0; p < 2; ++p) {
5346         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);
5347       }
5348 #endif
5349       ++newp;
5350       /* Face {i, m, l, f} */
5351       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + 2;
5352       orntNew[0] = 0;
5353       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + 3;
5354       orntNew[1] = -2;
5355       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*3 + GetTriInteriorEdge_Static(ornt[3],2);
5356       orntNew[2] = -2;
5357       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*3 + GetTriInteriorEdge_Static(ornt[2],1);
5358       orntNew[3] = 0;
5359       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5360       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
5361 #if defined(PETSC_USE_DEBUG)
5362       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
5363       for (p = 0; p < 4; ++p) {
5364         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);
5365       }
5366 #endif
5367       supportNew[0] = (c - cStart)*4 + 2;
5368       supportNew[1] = (c - cStart)*4 + 3;
5369       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
5370 #if defined(PETSC_USE_DEBUG)
5371       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
5372       for (p = 0; p < 2; ++p) {
5373         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);
5374       }
5375 #endif
5376       ++newp;
5377     }
5378     /* Split Edges have 2 vertices and the same faces as the parent */
5379     for (e = eStart; e < eEnd; ++e) {
5380       const PetscInt newv = vStartNew + (vEnd - vStart) + (e - eStart);
5381 
5382       for (r = 0; r < 2; ++r) {
5383         const PetscInt  newp = eStartNew + (e - eStart)*2 + r;
5384         const PetscInt *cone, *ornt, *support;
5385         PetscInt        coneNew[2], coneSize, c, supportSize, s;
5386 
5387         ierr             = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
5388         coneNew[0]       = vStartNew + (cone[0] - vStart);
5389         coneNew[1]       = vStartNew + (cone[1] - vStart);
5390         coneNew[(r+1)%2] = newv;
5391         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5392 #if defined(PETSC_USE_DEBUG)
5393         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eEndNew);
5394         for (p = 0; p < 2; ++p) {
5395           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);
5396         }
5397 #endif
5398         ierr = DMPlexGetSupportSize(dm, e, &supportSize);CHKERRQ(ierr);
5399         ierr = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
5400         for (s = 0; s < supportSize; ++s) {
5401           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
5402           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
5403           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
5404           for (c = 0; c < coneSize; ++c) {
5405             if (cone[c] == e) break;
5406           }
5407           supportRef[s] = fStartNew + (support[s] - fStart)*3 + (c + (ornt[c] < 0 ? 1-r : r))%3;
5408         }
5409         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
5410 #if defined(PETSC_USE_DEBUG)
5411         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eEndNew);
5412         for (p = 0; p < supportSize; ++p) {
5413           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);
5414         }
5415 #endif
5416       }
5417     }
5418     /* Face edges have 2 vertices and 2 + cell faces supports */
5419     for (f = fStart; f < fEnd; ++f) {
5420       const PetscInt *cone, *ornt, *support;
5421       PetscInt        coneSize, supportSize, s;
5422 
5423       ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
5424       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
5425       for (r = 0; r < 3; ++r) {
5426         const PetscInt  newp = eStartNew + (eEnd - eStart)*2 + (f - fStart)*3 + r;
5427         PetscInt        coneNew[2];
5428         PetscInt        fint[4][3] = { {0, 1, 2},
5429                                        {3, 4, 0},
5430                                        {2, 5, 3},
5431                                        {1, 4, 5} };
5432 
5433         ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
5434         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r] - eStart);
5435         coneNew[1] = vStartNew + (vEnd - vStart) + (eEnd - eStart) + f - fStart;
5436         ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5437 #if defined(PETSC_USE_DEBUG)
5438         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eEndNew);
5439         for (p = 0; p < 2; ++p) {
5440           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);
5441         }
5442 #endif
5443         supportRef[0] = fStartNew + (f - fStart)*3 + (r+0)%3;
5444         supportRef[1] = fStartNew + (f - fStart)*3 + (r+1)%3;
5445         for (s = 0; s < supportSize; ++s) {
5446           PetscInt er;
5447           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
5448           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
5449           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
5450           for (c = 0; c < coneSize; ++c) {if (cone[c] == f) break;}
5451           er = GetTriInteriorEdgeInverse_Static(ornt[c], r);
5452           supportRef[2+s] = fStartNew + (fEnd - fStart)*3 + (support[s] - cStart)*6 + fint[c][er];
5453         }
5454         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
5455 #if defined(PETSC_USE_DEBUG)
5456         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eEndNew);
5457         for (p = 0; p < supportSize + 2; ++p) {
5458           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);
5459         }
5460 #endif
5461       }
5462     }
5463     /* Interior cell edges have 2 vertices and 3 faces */
5464     for (c = cStart; c < cEnd; ++c) {
5465       const PetscInt *cone;
5466       PetscInt       fint[4][3] = { {0,1,2},
5467                                     {0,3,4},
5468                                     {2,3,5},
5469                                     {1,4,5} } ;
5470 
5471       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
5472       for (r = 0; r < 4; r++) {
5473         PetscInt       coneNew[2], supportNew[3];
5474         const PetscInt newp = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + r;
5475 
5476         coneNew[0] = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (cone[r] - fStart);
5477         coneNew[1] = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (fEnd -fStart) + c - cStart;
5478         ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5479 #if defined(PETSC_USE_DEBUG)
5480         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eEndNew);
5481         for (p = 0; p < 2; ++p) {
5482           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);
5483         }
5484 #endif
5485         supportNew[0] = fStartNew + (fEnd - fStart)*3 + (c - cStart)*6 + fint[r][0];
5486         supportNew[1] = fStartNew + (fEnd - fStart)*3 + (c - cStart)*6 + fint[r][1];
5487         supportNew[2] = fStartNew + (fEnd - fStart)*3 + (c - cStart)*6 + fint[r][2];
5488         ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
5489 #if defined(PETSC_USE_DEBUG)
5490         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eEndNew);
5491         for (p = 0; p < 3; ++p) {
5492           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);
5493         }
5494 #endif
5495       }
5496     }
5497     /* Old vertices have identical supports */
5498     for (v = vStart; v < vEnd; ++v) {
5499       const PetscInt  newp = vStartNew + (v - vStart);
5500       const PetscInt *support, *cone;
5501       PetscInt        size, s;
5502 
5503       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
5504       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
5505       for (s = 0; s < size; ++s) {
5506         PetscInt r = 0;
5507 
5508         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
5509         if (cone[1] == v) r = 1;
5510         supportRef[s] = eStartNew + (support[s] - eStart)*2 + r;
5511       }
5512       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
5513 #if defined(PETSC_USE_DEBUG)
5514       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", newp, vStartNew, vEndNew);
5515       for (p = 0; p < size; ++p) {
5516         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);
5517       }
5518 #endif
5519     }
5520     /* Edge vertices have 2 + faces supports */
5521     for (e = eStart; e < eEnd; ++e) {
5522       const PetscInt  newp = vStartNew + (vEnd - vStart) + (e - eStart);
5523       const PetscInt *cone, *support;
5524       PetscInt        size, s;
5525 
5526       ierr          = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
5527       ierr          = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
5528       supportRef[0] = eStartNew + (e - eStart)*2 + 0;
5529       supportRef[1] = eStartNew + (e - eStart)*2 + 1;
5530       for (s = 0; s < size; ++s) {
5531         PetscInt r = 0, coneSize;
5532 
5533         ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
5534         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
5535         for (r = 0; r < coneSize; ++r) {if (cone[r] == e) break;}
5536         supportRef[2+s] = eStartNew + (eEnd - eStart)*2 + (support[s] - fStart)*3 + r;
5537       }
5538       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
5539 #if defined(PETSC_USE_DEBUG)
5540       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", newp, vStartNew, vEndNew);
5541       for (p = 0; p < 2+size; ++p) {
5542         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);
5543       }
5544 #endif
5545     }
5546     /* Face vertices have 3 + cells supports */
5547     for (f = fStart; f < fEnd; ++f) {
5548       const PetscInt  newp = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (f - fStart);
5549       const PetscInt *cone, *support;
5550       PetscInt        size, s;
5551 
5552       ierr          = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
5553       ierr          = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
5554       supportRef[0] = eStartNew + (eEnd - eStart)*2 + (f - fStart)*3 + 0;
5555       supportRef[1] = eStartNew + (eEnd - eStart)*2 + (f - fStart)*3 + 1;
5556       supportRef[2] = eStartNew + (eEnd - eStart)*2 + (f - fStart)*3 + 2;
5557       for (s = 0; s < size; ++s) {
5558         PetscInt r = 0, coneSize;
5559 
5560         ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
5561         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
5562         for (r = 0; r < coneSize; ++r) {if (cone[r] == f) break;}
5563         supportRef[3+s] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (support[s] - cStart)*4 + r;
5564       }
5565       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
5566 #if defined(PETSC_USE_DEBUG)
5567       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", newp, vStartNew, vEndNew);
5568       for (p = 0; p < 3+size; ++p) {
5569         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);
5570       }
5571 #endif
5572     }
5573     /* Interior cell vertices have 4 supports */
5574     for (c = cStart; c < cEnd; ++c) {
5575       const PetscInt  newp = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (fEnd - fStart) + c - cStart;
5576       supportRef[0] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + 0;
5577       supportRef[1] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + 1;
5578       supportRef[2] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + 2;
5579       supportRef[3] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + 3;
5580       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
5581 #if defined(PETSC_USE_DEBUG)
5582       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", newp, vStartNew, vEndNew);
5583       for (p = 0; p < 4; ++p) {
5584         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);
5585       }
5586 #endif
5587     }
5588     ierr = PetscFree(supportRef);CHKERRQ(ierr);
5589     ierr = DMPlexRestoreFaces_Internal(dm, 3, cStart, NULL, NULL, &faces);CHKERRQ(ierr);
5590     break;
5591   case REFINER_HYBRID_SIMPLEX_TO_HEX_3D:
5592     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
5593     cMax = PetscMin(cEnd, cMax);
5594     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
5595     fMax = PetscMin(fEnd, fMax);
5596     if (eMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
5597     eMax = PetscMin(eEnd, eMax);
5598     ierr = DMPlexGetRawFaces_Internal(dm, 3, 4, cellInd, NULL, NULL, &faces);CHKERRQ(ierr);
5599     /* All cells have 6 faces */
5600     for (c = cStart; c < cMax; ++c) {
5601       const PetscInt  newp = cStartNew + (c - cStart)*4;
5602       const PetscInt *cone, *ornt;
5603       PetscInt        coneNew[6];
5604       PetscInt        orntNew[6];
5605 
5606       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
5607 #if defined(PETSC_USE_DEBUG)
5608       for (p = 0; p < 4; ++p) {
5609         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);
5610       }
5611 #endif
5612       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
5613       /* A hex */
5614       coneNew[0] = fStartNew + (cone[0] - fStart)*3 + GetTriSubface_Static(ornt[0], 0); /* B */
5615       orntNew[0] = ornt[0] < 0 ? -1 : 1;
5616       coneNew[1] = fStartNew + (fMax    - fStart)*3 + (c - cStart)*6 + 3;               /* T */
5617       orntNew[1] = -4;
5618       coneNew[2] = fStartNew + (cone[2] - fStart)*3 + GetTriSubface_Static(ornt[2], 0); /* F */
5619       orntNew[2] = ornt[2] < 0 ? -1 : 1;
5620       coneNew[3] = fStartNew + (fMax    - fStart)*3 + (c - cStart)*6 + 0;               /* K */
5621       orntNew[3] = -1;
5622       coneNew[4] = fStartNew + (fMax    - fStart)*3 + (c - cStart)*6 + 2;               /* R */
5623       orntNew[4] = 0;
5624       coneNew[5] = fStartNew + (cone[1] - fStart)*3 + GetTriSubface_Static(ornt[1], 0); /* L */
5625       orntNew[5] = ornt[1] < 0 ? -1 : 1;
5626       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
5627       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
5628 #if defined(PETSC_USE_DEBUG)
5629       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);
5630       for (p = 0; p < 6; ++p) {
5631         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);
5632       }
5633 #endif
5634       /* B hex */
5635       coneNew[0] = fStartNew + (cone[0] - fStart)*3 + GetTriSubface_Static(ornt[0], 1); /* B */
5636       orntNew[0] = ornt[0] < 0 ? -2 : 0;
5637       coneNew[1] = fStartNew + (fMax    - fStart)*3 + (c - cStart)*6 + 4;               /* T */
5638       orntNew[1] = 0;
5639       coneNew[2] = fStartNew + (fMax    - fStart)*3 + (c - cStart)*6 + 0;               /* F */
5640       orntNew[2] = 0;
5641       coneNew[3] = fStartNew + (cone[3] - fStart)*3 + GetTriSubface_Static(ornt[3], 1); /* K */
5642       orntNew[3] = ornt[3] < 0 ? -2 : 0;
5643       coneNew[4] = fStartNew + (fMax    - fStart)*3 + (c - cStart)*6 + 1;               /* R */
5644       orntNew[4] = 0;
5645       coneNew[5] = fStartNew + (cone[1] - fStart)*3 + GetTriSubface_Static(ornt[1], 2); /* L */
5646       orntNew[5] = ornt[1] < 0 ? -4 : 2;
5647       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
5648       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
5649 #if defined(PETSC_USE_DEBUG)
5650       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);
5651       for (p = 0; p < 6; ++p) {
5652         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);
5653       }
5654 #endif
5655       /* C hex */
5656       coneNew[0] = fStartNew + (cone[0] - fStart)*3 + GetTriSubface_Static(ornt[0], 2); /* B */
5657       orntNew[0] = ornt[0] < 0 ? -4 : 2;
5658       coneNew[1] = fStartNew + (fMax    - fStart)*3 + (c - cStart)*6 + 5;               /* T */
5659       orntNew[1] = -4;
5660       coneNew[2] = fStartNew + (cone[2] - fStart)*3 + GetTriSubface_Static(ornt[2], 1); /* F */
5661       orntNew[2] = ornt[2] < 0 ? -2 : 0;
5662       coneNew[3] = fStartNew + (fMax    - fStart)*3 + (c - cStart)*6 + 1;               /* K */
5663       orntNew[3] = -1;
5664       coneNew[4] = fStartNew + (cone[3] - fStart)*3 + GetTriSubface_Static(ornt[3], 0); /* R */
5665       orntNew[4] = ornt[3] < 0 ? -1 : 1;
5666       coneNew[5] = fStartNew + (fMax    - fStart)*3 + (c - cStart)*6 + 2;               /* L */
5667       orntNew[5] = -4;
5668       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
5669       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
5670 #if defined(PETSC_USE_DEBUG)
5671       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);
5672       for (p = 0; p < 6; ++p) {
5673         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);
5674       }
5675 #endif
5676       /* D hex */
5677       coneNew[0] = fStartNew + (fMax    - fStart)*3 + (c - cStart)*6 + 3;               /* B */
5678       orntNew[0] = 0;
5679       coneNew[1] = fStartNew + (cone[3] - fStart)*3 + GetTriSubface_Static(ornt[3], 2); /* T */
5680       orntNew[1] = ornt[3] < 0 ? -1 : 1;
5681       coneNew[2] = fStartNew + (cone[2] - fStart)*3 + GetTriSubface_Static(ornt[2], 2); /* F */
5682       orntNew[2] = ornt[2] < 0 ? -4 : 2;
5683       coneNew[3] = fStartNew + (fMax    - fStart)*3 + (c - cStart)*6 + 4;               /* K */
5684       orntNew[3] = -1;
5685       coneNew[4] = fStartNew + (fMax    - fStart)*3 + (c - cStart)*6 + 5;               /* R */
5686       orntNew[4] = 0;
5687       coneNew[5] = fStartNew + (cone[1] - fStart)*3 + GetTriSubface_Static(ornt[1], 1); /* L */
5688       orntNew[5] = ornt[1] < 0 ? -2 : 0;
5689       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
5690       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
5691 #if defined(PETSC_USE_DEBUG)
5692       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);
5693       for (p = 0; p < 6; ++p) {
5694         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);
5695       }
5696 #endif
5697     }
5698     for (c = cMax; c < cEnd; ++c) {
5699       const PetscInt  newp = cStartNew + (cMax - cStart)*4 + (c - cMax)*3;
5700       const PetscInt *cone, *ornt;
5701       PetscInt        coneNew[6], orntNew[6];
5702       PetscInt        o, of, cf;
5703 
5704       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
5705 #if defined(PETSC_USE_DEBUG)
5706       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);
5707       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);
5708       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);
5709       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);
5710       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);
5711 #endif
5712       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
5713       o    = ornt[0] < 0 ? -1 : 1;
5714       o    = 1;
5715       /* A hex */
5716       coneNew[0] = fStartNew + (cone[0] - fStart)*3 + GetTriSubface_Static(ornt[0], 0);                            /* B */
5717       orntNew[0] = ornt[0] < 0 ? -1 :  1;
5718       coneNew[1] = fStartNew + (cone[1] - fStart)*3 + GetTriSubface_Static(ornt[1], 0);                            /* T */
5719       orntNew[1] = ornt[1] < 0 ?  1 : -1;
5720       cf         = 2;
5721       of         = ornt[2+cf] < 0 ? -1 : 1;
5722       coneNew[2] = fStartNew + (fMax - fStart)*3 + (cMax - cStart)*6 + (cone[2+cf] - fMax)*2 + (o*of < 0 ? 0 : 1); /* F */
5723       orntNew[2] = o*of < 0 ? 0 : -1;
5724       coneNew[3] = fStartNew + (fMax - fStart)*3 + (cMax - cStart)*6 + (fEnd - fMax)*2 + (c - cMax)*3 + 0;         /* K */
5725       orntNew[3] = -1;
5726       coneNew[4] = fStartNew + (fMax - fStart)*3 + (cMax - cStart)*6 + (fEnd - fMax)*2 + (c - cMax)*3 + 2;         /* R */
5727       orntNew[4] = 0;
5728       cf         = 0;
5729       of         = ornt[2+cf] < 0 ? -1 : 1;
5730       coneNew[5] = fStartNew + (fMax - fStart)*3 + (cMax - cStart)*6 + (cone[2+cf] - fMax)*2 + (o*of < 0 ? 1 : 0); /* L */
5731       orntNew[5] = o*of < 0 ? 1 : -4;
5732       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
5733       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
5734 #if defined(PETSC_USE_DEBUG)
5735       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);
5736       for (p = 0; p < 6; ++p) {
5737         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);
5738       }
5739 #endif
5740       /* B hex */
5741       coneNew[0] = fStartNew + (cone[0] - fStart)*3 + GetTriSubface_Static(ornt[0], 1);                            /* B */
5742       orntNew[0] = ornt[0] < 0 ? -2 :  0;
5743       coneNew[1] = fStartNew + (cone[1] - fStart)*3 + GetTriSubface_Static(ornt[1], 1);                            /* T */
5744       orntNew[1] = ornt[1] < 0 ?  2 : -4;
5745       coneNew[2] = fStartNew + (fMax - fStart)*3 + (cMax - cStart)*6 + (fEnd - fMax)*2 + (c - cMax)*3 + 0;         /* F */
5746       orntNew[2] = 0;
5747       cf         = 1;
5748       of         = ornt[2+cf] < 0 ? -1 : 1;
5749       coneNew[3] = fStartNew + (fMax - fStart)*3 + (cMax - cStart)*6 + (cone[2+cf] - fMax)*2 + (o*of < 0 ? 1 : 0); /* K */
5750       orntNew[3] = o*of < 0 ? 0 : -1;
5751       coneNew[4] = fStartNew + (fMax - fStart)*3 + (cMax - cStart)*6 + (fEnd - fMax)*2 + (c - cMax)*3 + 1;         /* R */
5752       orntNew[4] = -1;
5753       cf         = 0;
5754       of         = ornt[2+cf] < 0 ? -1 : 1;
5755       coneNew[5] = fStartNew + (fMax - fStart)*3 + (cMax - cStart)*6 + (cone[2+cf] - fMax)*2 + (o*of < 0 ? 0 : 1); /* L */
5756       orntNew[5] = o*of < 0 ? 1 : -4;
5757       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
5758       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
5759 #if defined(PETSC_USE_DEBUG)
5760       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);
5761       for (p = 0; p < 6; ++p) {
5762         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);
5763       }
5764 #endif
5765       /* C hex */
5766       coneNew[0] = fStartNew + (cone[0] - fStart)*3 + GetTriSubface_Static(ornt[0], 2);                            /* B */
5767       orntNew[0] = ornt[0] < 0 ? -4 : 2;
5768       coneNew[1] = fStartNew + (cone[1] - fStart)*3 + GetTriSubface_Static(ornt[1], 2);                            /* T */
5769       orntNew[1] = ornt[1] < 0 ? 0 : -2;
5770       cf         = 2;
5771       of         = ornt[2+cf] < 0 ? -1 : 1;
5772       coneNew[2] = fStartNew + (fMax - fStart)*3 + (cMax - cStart)*6 + (cone[2+cf] - fMax)*2 + (o*of < 0 ? 1 : 0); /* F */
5773       orntNew[2] = o*of < 0 ? 0 : -1;
5774       coneNew[3] = fStartNew + (fMax - fStart)*3 + (cMax - cStart)*6 + (fEnd - fMax)*2 + (c - cMax)*3 + 1;         /* K */
5775       orntNew[3] = 0;
5776       cf         = 1;
5777       of         = ornt[2+cf] < 0 ? -1 : 1;
5778       coneNew[4] = fStartNew + (fMax - fStart)*3 + (cMax - cStart)*6 + (cone[2+cf] - fMax)*2 + (o*of < 0 ? 0 : 1); /* R */
5779       orntNew[4] = o*of < 0 ? 0 : -1;
5780       coneNew[5] = fStartNew + (fMax - fStart)*3 + (cMax - cStart)*6 + (fEnd - fMax)*2 + (c - cMax)*3 + 2;         /* L */
5781       orntNew[5] = -4;
5782       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
5783       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
5784 #if defined(PETSC_USE_DEBUG)
5785       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);
5786       for (p = 0; p < 6; ++p) {
5787         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);
5788       }
5789 #endif
5790     }
5791 
5792     /* Split faces have 4 edges and the same cells as the parent */
5793     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
5794     ierr = PetscMalloc1(2 + maxSupportSize*2, &supportRef);CHKERRQ(ierr);
5795     for (f = fStart; f < fMax; ++f) {
5796       const PetscInt  newp = fStartNew + (f - fStart)*3;
5797       const PetscInt *cone, *ornt, *support;
5798       PetscInt        coneNew[4], orntNew[4], coneSize, supportSize, s;
5799 
5800       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
5801 #if defined(PETSC_USE_DEBUG)
5802       for (p = 0; p < 3; ++p) {
5803         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);
5804       }
5805 #endif
5806       ierr = DMPlexGetConeOrientation(dm, f, &ornt);CHKERRQ(ierr);
5807       /* A quad */
5808       coneNew[0] = eStartNew + (cone[2] - eStart)*2 + (ornt[2] < 0 ? 0 : 1);
5809       orntNew[0] = ornt[2];
5810       coneNew[1] = eStartNew + (cone[0] - eStart)*2 + (ornt[0] < 0 ? 1 : 0);
5811       orntNew[1] = ornt[0];
5812       coneNew[2] = eStartNew + (eMax    - eStart)*2 + (f - fStart)*3 + 0;
5813       orntNew[2] = 0;
5814       coneNew[3] = eStartNew + (eMax    - eStart)*2 + (f - fStart)*3 + 2;
5815       orntNew[3] = -2;
5816       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
5817       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
5818 #if defined(PETSC_USE_DEBUG)
5819       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);
5820       for (p = 0; p < 4; ++p) {
5821         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);
5822       }
5823 #endif
5824       /* B quad */
5825       coneNew[0] = eStartNew + (cone[0] - eStart)*2 + (ornt[0] < 0 ? 0 : 1);
5826       orntNew[0] = ornt[0];
5827       coneNew[1] = eStartNew + (cone[1] - eStart)*2 + (ornt[1] < 0 ? 1 : 0);
5828       orntNew[1] = ornt[1];
5829       coneNew[2] = eStartNew + (eMax    - eStart)*2 + (f - fStart)*3 + 1;
5830       orntNew[2] = 0;
5831       coneNew[3] = eStartNew + (eMax    - eStart)*2 + (f - fStart)*3 + 0;
5832       orntNew[3] = -2;
5833       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
5834       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
5835 #if defined(PETSC_USE_DEBUG)
5836       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);
5837       for (p = 0; p < 4; ++p) {
5838         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);
5839       }
5840 #endif
5841       /* C quad */
5842       coneNew[0] = eStartNew + (cone[1] - eStart)*2 + (ornt[1] < 0 ? 0 : 1);
5843       orntNew[0] = ornt[1];
5844       coneNew[1] = eStartNew + (cone[2] - eStart)*2 + (ornt[2] < 0 ? 1 : 0);
5845       orntNew[1] = ornt[2];
5846       coneNew[2] = eStartNew + (eMax    - eStart)*2 + (f - fStart)*3 + 2;
5847       orntNew[2] = 0;
5848       coneNew[3] = eStartNew + (eMax    - eStart)*2 + (f - fStart)*3 + 1;
5849       orntNew[3] = -2;
5850       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
5851       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
5852 #if defined(PETSC_USE_DEBUG)
5853       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);
5854       for (p = 0; p < 4; ++p) {
5855         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);
5856       }
5857 #endif
5858       ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
5859       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
5860       for (r = 0; r < 3; ++r) {
5861         for (s = 0; s < supportSize; ++s) {
5862           PetscInt subf;
5863 
5864           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
5865           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);
5866           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);
5867           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
5868           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
5869           for (c = 0; c < coneSize; ++c) {
5870             if (cone[c] == f) break;
5871           }
5872           subf = GetTriSubfaceInverse_Static(ornt[c], r);
5873           if (coneSize == 4) {
5874             supportRef[s] = cStartNew + (support[s] - cStart)*4 + faces[c*3+subf];
5875           } else if (coneSize == 5) {
5876             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);
5877             supportRef[s] = cStartNew + (cMax - cStart)*4 + (support[s] - cMax)*3 + subf;
5878           } else SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected conesize %D for cell %D (cMax %D)", coneSize, support[s], cMax);
5879         }
5880         ierr = DMPlexSetSupport(rdm, newp+r, supportRef);CHKERRQ(ierr);
5881 #if defined(PETSC_USE_DEBUG)
5882         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);
5883         for (p = 0; p < supportSize; ++p) {
5884           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);
5885         }
5886 #endif
5887       }
5888     }
5889     /* Interior faces have 4 edges and 2 cells */
5890     for (c = cStart; c < cMax; ++c) {
5891       PetscInt        newp = fStartNew + (fMax - fStart)*3 + (c - cStart)*6;
5892       const PetscInt *cone, *ornt;
5893       PetscInt        coneNew[4], orntNew[4];
5894       PetscInt        supportNew[2];
5895 
5896       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
5897 #if defined(PETSC_USE_DEBUG)
5898       for (p = 0; p < 4; ++p) {
5899         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);
5900       }
5901 #endif
5902       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
5903       /* Face {a, g, m, h} */
5904       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*3 + GetTriInteriorEdge_Static(ornt[0],0);
5905       orntNew[0] = 0;
5906       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart)*4 + 0;
5907       orntNew[1] = 0;
5908       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart)*4 + 1;
5909       orntNew[2] = -2;
5910       coneNew[3] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*3 + GetTriInteriorEdge_Static(ornt[1],2);
5911       orntNew[3] = -2;
5912       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5913       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
5914 #if defined(PETSC_USE_DEBUG)
5915       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
5916       for (p = 0; p < 4; ++p) {
5917         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);
5918       }
5919 #endif
5920       supportNew[0] = cStartNew + (c - cStart)*4 + 0;
5921       supportNew[1] = cStartNew + (c - cStart)*4 + 1;
5922       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
5923 #if defined(PETSC_USE_DEBUG)
5924       for (p = 0; p < 2; ++p) {
5925         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);
5926       }
5927 #endif
5928       ++newp;
5929       /* Face {g, b, l , m} */
5930       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*3 + GetTriInteriorEdge_Static(ornt[0],1);
5931       orntNew[0] = -2;
5932       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*3 + GetTriInteriorEdge_Static(ornt[3],0);
5933       orntNew[1] = 0;
5934       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart)*4 + 3;
5935       orntNew[2] = 0;
5936       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart)*4 + 0;
5937       orntNew[3] = -2;
5938       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5939       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
5940 #if defined(PETSC_USE_DEBUG)
5941       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
5942       for (p = 0; p < 4; ++p) {
5943         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);
5944       }
5945 #endif
5946       supportNew[0] = cStartNew + (c - cStart)*4 + 1;
5947       supportNew[1] = cStartNew + (c - cStart)*4 + 2;
5948       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
5949 #if defined(PETSC_USE_DEBUG)
5950       for (p = 0; p < 2; ++p) {
5951         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);
5952       }
5953 #endif
5954       ++newp;
5955       /* Face {c, g, m, i} */
5956       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*3 + GetTriInteriorEdge_Static(ornt[0],2);
5957       orntNew[0] = 0;
5958       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart)*4 + 0;
5959       orntNew[1] = 0;
5960       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart)*4 + 2;
5961       orntNew[2] = -2;
5962       coneNew[3] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*3 + GetTriInteriorEdge_Static(ornt[2],0);
5963       orntNew[3] = -2;
5964       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5965       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
5966 #if defined(PETSC_USE_DEBUG)
5967       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
5968       for (p = 0; p < 4; ++p) {
5969         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);
5970       }
5971 #endif
5972       supportNew[0] = cStartNew + (c - cStart)*4 + 0;
5973       supportNew[1] = cStartNew + (c - cStart)*4 + 2;
5974       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
5975 #if defined(PETSC_USE_DEBUG)
5976       for (p = 0; p < 2; ++p) {
5977         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);
5978       }
5979 #endif
5980       ++newp;
5981       /* Face {d, h, m, i} */
5982       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*3 + GetTriInteriorEdge_Static(ornt[1],0);
5983       orntNew[0] = 0;
5984       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart)*4 + 1;
5985       orntNew[1] = 0;
5986       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart)*4 + 2;
5987       orntNew[2] = -2;
5988       coneNew[3] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*3 + GetTriInteriorEdge_Static(ornt[2],2);
5989       orntNew[3] = -2;
5990       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5991       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
5992 #if defined(PETSC_USE_DEBUG)
5993       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
5994       for (p = 0; p < 4; ++p) {
5995         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);
5996       }
5997 #endif
5998       supportNew[0] = cStartNew + (c - cStart)*4 + 0;
5999       supportNew[1] = cStartNew + (c - cStart)*4 + 3;
6000       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
6001 #if defined(PETSC_USE_DEBUG)
6002       for (p = 0; p < 2; ++p) {
6003         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);
6004       }
6005 #endif
6006       ++newp;
6007       /* Face {h, m, l, e} */
6008       coneNew[0] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart)*4 + 1;
6009       orntNew[0] = 0;
6010       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart)*4 + 3;
6011       orntNew[1] = -2;
6012       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*3 + GetTriInteriorEdge_Static(ornt[3],1);
6013       orntNew[2] = -2;
6014       coneNew[3] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*3 + GetTriInteriorEdge_Static(ornt[1],1);
6015       orntNew[3] = 0;
6016       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6017       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
6018 #if defined(PETSC_USE_DEBUG)
6019       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
6020       for (p = 0; p < 4; ++p) {
6021         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);
6022       }
6023 #endif
6024       supportNew[0] = cStartNew + (c - cStart)*4 + 1;
6025       supportNew[1] = cStartNew + (c - cStart)*4 + 3;
6026       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
6027 #if defined(PETSC_USE_DEBUG)
6028       for (p = 0; p < 2; ++p) {
6029         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);
6030       }
6031 #endif
6032       ++newp;
6033       /* Face {i, m, l, f} */
6034       coneNew[0] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart)*4 + 2;
6035       orntNew[0] = 0;
6036       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart)*4 + 3;
6037       orntNew[1] = -2;
6038       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*3 + GetTriInteriorEdge_Static(ornt[3],2);
6039       orntNew[2] = -2;
6040       coneNew[3] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*3 + GetTriInteriorEdge_Static(ornt[2],1);
6041       orntNew[3] = 0;
6042       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6043       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
6044 #if defined(PETSC_USE_DEBUG)
6045       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
6046       for (p = 0; p < 4; ++p) {
6047         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);
6048       }
6049 #endif
6050       supportNew[0] = cStartNew + (c - cStart)*4 + 2;
6051       supportNew[1] = cStartNew + (c - cStart)*4 + 3;
6052       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
6053 #if defined(PETSC_USE_DEBUG)
6054       for (p = 0; p < 2; ++p) {
6055         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);
6056       }
6057 #endif
6058       ++newp;
6059     }
6060     /* Hybrid split faces have 4 edges and same cells */
6061     for (f = fMax; f < fEnd; ++f) {
6062       const PetscInt *cone, *ornt, *support;
6063       PetscInt        coneNew[4], orntNew[4];
6064       PetscInt        size, s;
6065       const PetscInt  newp = fStartNew + (fMax - fStart)*3 + (cMax - cStart)*6 + (f - fMax)*2;
6066 
6067       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
6068 #if defined(PETSC_USE_DEBUG)
6069       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);
6070       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);
6071       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);
6072       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);
6073 #endif
6074       ierr = DMPlexGetConeOrientation(dm, f, &ornt);CHKERRQ(ierr);
6075       /* A face */
6076       coneNew[0] = eStartNew + (cone[0] - eStart)*2 + (ornt[0] < 0 ? 1 : 0);
6077       orntNew[0] = ornt[0];
6078       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart)*4 + (eEnd - eMax) + (f - fMax);
6079       orntNew[1] = 0;
6080       coneNew[2] = eStartNew + (cone[1] - eStart)*2 + (ornt[1] < 0 ? 1 : 0);
6081       orntNew[2] = ornt[1] < 0 ? 0 : -2;
6082       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart)*4 + (cone[2] - eMax);
6083       orntNew[3] = ornt[2] < 0 ? 0 : -2;
6084       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6085       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
6086 #if defined(PETSC_USE_DEBUG)
6087       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
6088       for (p = 0; p < 4; ++p) {
6089         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);
6090       }
6091 #endif
6092 
6093       /* B face */
6094       coneNew[0] = eStartNew + (cone[0] - eStart)*2 + (ornt[0] < 0 ? 0 : 1);
6095       orntNew[0] = ornt[0];
6096       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart)*4 + (cone[3] - eMax);
6097       orntNew[1] = ornt[3];
6098       coneNew[2] = eStartNew + (cone[1] - eStart)*2 + (ornt[1] < 0 ? 0 : 1);
6099       orntNew[2] = ornt[1] < 0 ? 0 : -2;
6100       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart)*4 + (eEnd - eMax) + (f - fMax);
6101       orntNew[3] = -2;
6102       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
6103       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
6104 #if defined(PETSC_USE_DEBUG)
6105       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);
6106       for (p = 0; p < 4; ++p) {
6107         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);
6108       }
6109 #endif
6110 
6111       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
6112       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
6113       for (r = 0; r < 2; ++r) {
6114         for (s = 0; s < size; ++s) {
6115           const PetscInt *coneCell, *orntCell;
6116           PetscInt        coneSize, o, of, c;
6117 
6118           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
6119           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);
6120           ierr = DMPlexGetCone(dm, support[s], &coneCell);CHKERRQ(ierr);
6121           ierr = DMPlexGetConeOrientation(dm, support[s], &orntCell);CHKERRQ(ierr);
6122           o = orntCell[0] < 0 ? -1 : 1;
6123           o = 1;
6124           for (c = 0; c < coneSize; ++c) if (coneCell[c] == f) break;
6125           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);
6126           if (c == coneSize) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Could not find face %D in cone of cell %D", f, support[s]);
6127           of = orntCell[c] < 0 ? -1 : 1;
6128           supportRef[s] = cStartNew + (cMax - cStart)*4 + (support[s] - cMax)*3 + (c-2 + (o*of < 0 ? 1-r : r))%3;
6129         }
6130         ierr = DMPlexSetSupport(rdm, newp + r, supportRef);CHKERRQ(ierr);
6131 #if defined(PETSC_USE_DEBUG)
6132         for (p = 0; p < size; ++p) {
6133           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);
6134         }
6135 #endif
6136       }
6137     }
6138     /* Interior hybrid faces have 4 edges and 2 cells */
6139     for (c = cMax; c < cEnd; ++c) {
6140       PetscInt        newp = fStartNew + (fMax - fStart)*3 + (cMax - cStart)*6 + (fEnd - fMax)*2 + (c - cMax)*3;
6141       const PetscInt *cone, *ornt;
6142       PetscInt        coneNew[4], orntNew[4];
6143       PetscInt        supportNew[2];
6144 
6145       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
6146 #if defined(PETSC_USE_DEBUG)
6147       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);
6148       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);
6149       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);
6150       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);
6151       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);
6152 #endif
6153       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
6154       /* Face {a, g, h, d} */
6155       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*3 + GetTriInteriorEdge_Static(ornt[0],0);
6156       orntNew[0] = 0;
6157       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart)*4 + (eEnd - eMax) + (fEnd - fMax) + c - cMax;
6158       orntNew[1] = 0;
6159       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*3 + GetTriInteriorEdge_Static(ornt[1],0);
6160       orntNew[2] = -2;
6161       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart)*4 + (eEnd - eMax) + (cone[2] - fMax);
6162       orntNew[3] = -2;
6163       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6164       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
6165 #if defined(PETSC_USE_DEBUG)
6166       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
6167       for (p = 0; p < 4; ++p) {
6168         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);
6169       }
6170 #endif
6171       supportNew[0] = cStartNew + (cMax - cStart)*4 + (c - cMax)*3 + 0;
6172       supportNew[1] = cStartNew + (cMax - cStart)*4 + (c - cMax)*3 + 1;
6173       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
6174 #if defined(PETSC_USE_DEBUG)
6175       for (p = 0; p < 2; ++p) {
6176         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);
6177       }
6178 #endif
6179       ++newp;
6180       /* Face {b, g, h, l} */
6181       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*3 + GetTriInteriorEdge_Static(ornt[0],1);
6182       orntNew[0] = 0;
6183       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart)*4 + (eEnd - eMax) + (fEnd - fMax) + c - cMax;
6184       orntNew[1] = 0;
6185       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*3 + GetTriInteriorEdge_Static(ornt[1],1);
6186       orntNew[2] = -2;
6187       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart)*4 + (eEnd - eMax) + (cone[3] - fMax);
6188       orntNew[3] = -2;
6189       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6190       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
6191 #if defined(PETSC_USE_DEBUG)
6192       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
6193       for (p = 0; p < 4; ++p) {
6194         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);
6195       }
6196 #endif
6197       supportNew[0] = cStartNew + (cMax - cStart)*4 + (c - cMax)*3 + 1;
6198       supportNew[1] = cStartNew + (cMax - cStart)*4 + (c - cMax)*3 + 2;
6199       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
6200 #if defined(PETSC_USE_DEBUG)
6201       for (p = 0; p < 2; ++p) {
6202         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);
6203       }
6204 #endif
6205       ++newp;
6206       /* Face {c, g, h, f} */
6207       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*3 + GetTriInteriorEdge_Static(ornt[0],2);
6208       orntNew[0] = 0;
6209       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart)*4 + (eEnd - eMax) + (fEnd - fMax) + c - cMax;
6210       orntNew[1] = 0;
6211       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*3 + GetTriInteriorEdge_Static(ornt[1],2);
6212       orntNew[2] = -2;
6213       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart)*4 + (eEnd - eMax) + (cone[4] - fMax);
6214       orntNew[3] = -2;
6215       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6216       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
6217 #if defined(PETSC_USE_DEBUG)
6218       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
6219       for (p = 0; p < 4; ++p) {
6220         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);
6221       }
6222 #endif
6223       supportNew[0] = cStartNew + (cMax - cStart)*4 + (c - cMax)*3 + 2;
6224       supportNew[1] = cStartNew + (cMax - cStart)*4 + (c - cMax)*3 + 0;
6225       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
6226 #if defined(PETSC_USE_DEBUG)
6227       for (p = 0; p < 2; ++p) {
6228         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);
6229       }
6230 #endif
6231     }
6232     /* Face edges have 2 vertices and 2 + cell faces supports */
6233     for (f = fStart; f < fMax; ++f) {
6234       const PetscInt *cone, *ornt, *support;
6235       PetscInt        coneSize, supportSize, s;
6236 
6237       ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
6238       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
6239       for (r = 0; r < 3; ++r) {
6240         const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (f - fStart)*3 + r;
6241         PetscInt        coneNew[2];
6242         PetscInt        fint[4][3] = { {0, 1, 2},
6243                                        {3, 4, 0},
6244                                        {2, 5, 3},
6245                                        {1, 4, 5} };
6246 
6247         ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
6248         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);
6249         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r] - eStart);
6250         coneNew[1] = vStartNew + (vEnd - vStart) + (eMax - eStart) + f - fStart;
6251         ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6252 #if defined(PETSC_USE_DEBUG)
6253         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eEndNew);
6254         for (p = 0; p < 2; ++p) {
6255           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);
6256         }
6257 #endif
6258         supportRef[0] = fStartNew + (f - fStart)*3 + (r+0)%3;
6259         supportRef[1] = fStartNew + (f - fStart)*3 + (r+1)%3;
6260         for (s = 0; s < supportSize; ++s) {
6261           PetscInt er;
6262 
6263           supportRef[2+s] = -1;
6264           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
6265           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);
6266           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);
6267           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6268           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
6269           for (c = 0; c < coneSize; ++c) {if (cone[c] == f) break;}
6270           er = GetTriInteriorEdgeInverse_Static(ornt[c], r);
6271           if (coneSize == 4) {
6272             supportRef[2+s] = fStartNew + (fMax - fStart)*3 + (support[s] - cStart)*6 + fint[c][er];
6273           } else if (coneSize == 5) {
6274             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);
6275             supportRef[2+s] = fStartNew + (fMax - fStart)*3 + (cMax - cStart)*6 + (fEnd - fMax)*2 + (support[s] - cMax)*3 + er;
6276           }
6277         }
6278         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6279 #if defined(PETSC_USE_DEBUG)
6280         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eEndNew);
6281         for (p = 0; p < supportSize + 2; ++p) {
6282           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);
6283         }
6284 #endif
6285       }
6286     }
6287     /* Interior cell edges have 2 vertices and 3 faces */
6288     for (c = cStart; c < cMax; ++c) {
6289       const PetscInt *cone;
6290       PetscInt       fint[4][3] = { {0,1,2},
6291                                     {0,3,4},
6292                                     {2,3,5},
6293                                     {1,4,5} } ;
6294 
6295       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
6296       for (r = 0; r < 4; r++) {
6297         PetscInt       coneNew[2], supportNew[3];
6298         const PetscInt newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart)*4 + r;
6299 
6300         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);
6301         coneNew[0] = vStartNew + (vEnd - vStart) + (eMax - eStart) + (cone[r] - fStart);
6302         coneNew[1] = vStartNew + (vEnd - vStart) + (eMax - eStart) + (fMax     -fStart) + c - cStart;
6303         ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6304 #if defined(PETSC_USE_DEBUG)
6305         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eEndNew);
6306         for (p = 0; p < 2; ++p) {
6307           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);
6308         }
6309 #endif
6310         supportNew[0] = fStartNew + (fMax - fStart)*3 + (c - cStart)*6 + fint[r][0];
6311         supportNew[1] = fStartNew + (fMax - fStart)*3 + (c - cStart)*6 + fint[r][1];
6312         supportNew[2] = fStartNew + (fMax - fStart)*3 + (c - cStart)*6 + fint[r][2];
6313         ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
6314 #if defined(PETSC_USE_DEBUG)
6315         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eEndNew);
6316         for (p = 0; p < 3; ++p) {
6317           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);
6318         }
6319 #endif
6320       }
6321     }
6322     /* Hybrid edges have two vertices and the same faces */
6323     for (e = eMax; e < eEnd; ++e) {
6324       const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart)*4 + (e - eMax);
6325       const PetscInt *cone, *support, *fcone;
6326       PetscInt        coneNew[2], size, fsize, s;
6327 
6328       ierr = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
6329       ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
6330       ierr = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
6331       coneNew[0] = vStartNew + (cone[0] - vStart);
6332       coneNew[1] = vStartNew + (cone[1] - vStart);
6333       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6334 #if defined(PETSC_USE_DEBUG)
6335       if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is a edge [%D, %D)", newp, eStartNew, eEndNew);
6336       for (p = 0; p < 2; ++p) {
6337         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);
6338       }
6339 #endif
6340       for (s = 0; s < size; ++s) {
6341         ierr = DMPlexGetConeSize(dm, support[s], &fsize);CHKERRQ(ierr);
6342         ierr = DMPlexGetCone(dm, support[s], &fcone);CHKERRQ(ierr);
6343         for (c = 0; c < fsize; ++c) if (fcone[c] == e) break;
6344         if ((c < 2) || (c > 3)) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Edge %D not found in cone of face %D", e, support[s]);
6345         supportRef[s] = fStartNew + (fMax - fStart)*3 + (cMax - cStart)*6 + (support[s] - fMax)*2 + c-2;
6346       }
6347       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6348 #if defined(PETSC_USE_DEBUG)
6349       for (p = 0; p < size; ++p) {
6350         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);
6351       }
6352 #endif
6353     }
6354     /* Hybrid face edges have 2 vertices and 2 + cell faces supports */
6355     for (f = fMax; f < fEnd; ++f) {
6356       const PetscInt *cone, *ornt, *support;
6357       PetscInt        coneSize, supportSize;
6358       const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart)*4 + (eEnd - eMax) + f - fMax;
6359       PetscInt        coneNew[2], s;
6360 
6361       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
6362 #if defined(PETSC_USE_DEBUG)
6363       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);
6364       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);
6365 #endif
6366       coneNew[0] = vStartNew + (vEnd - vStart) + (cone[0] - eStart);
6367       coneNew[1] = vStartNew + (vEnd - vStart) + (cone[1] - eStart);
6368       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6369 #if defined(PETSC_USE_DEBUG)
6370       if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eEndNew);
6371       for (p = 0; p < 2; ++p) {
6372         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);
6373       }
6374 #endif
6375       supportRef[0] = fStartNew + (fMax - fStart)*3 + (cMax - cStart)*6 + (f- fMax)*2 + 0;
6376       supportRef[1] = fStartNew + (fMax - fStart)*3 + (cMax - cStart)*6 + (f- fMax)*2 + 1;
6377       ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
6378       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
6379       for (s = 0; s < supportSize; ++s) {
6380         ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
6381         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);
6382         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6383         ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
6384         for (c = 0; c < coneSize; ++c) {if (cone[c] == f) break;}
6385         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);
6386         supportRef[2+s] = fStartNew + (fMax - fStart)*3 + (cMax - cStart)*6 + (fEnd - fMax)*2 + (support[s] - cMax)*3 + c - 2;
6387       }
6388       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6389 #if defined(PETSC_USE_DEBUG)
6390       if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eEndNew);
6391       for (p = 0; p < supportSize + 2; ++p) {
6392         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);
6393       }
6394 #endif
6395     }
6396     /* Hybrid cell edges have 2 vertices and 3 faces */
6397     for (c = cMax; c < cEnd; ++c) {
6398       PetscInt       coneNew[2], supportNew[3];
6399       const PetscInt newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart)*4 + (eEnd - eMax) + (fEnd - fMax) + c - cMax;
6400       const PetscInt *cone;
6401 
6402       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
6403 #if defined(PETSC_USE_DEBUG)
6404       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);
6405       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);
6406 #endif
6407       coneNew[0] = vStartNew + (vEnd - vStart) + (eMax - eStart) + (cone[0] - fStart);
6408       coneNew[1] = vStartNew + (vEnd - vStart) + (eMax - eStart) + (cone[1] - fStart);
6409       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6410 #if defined(PETSC_USE_DEBUG)
6411       if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eEndNew);
6412       for (p = 0; p < 2; ++p) {
6413         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);
6414       }
6415 #endif
6416       supportNew[0] = fStartNew + (fMax - fStart)*3 + (cMax - cStart)*6 + (fEnd - fMax)*2 + (c - cMax)*3 + 0;
6417       supportNew[1] = fStartNew + (fMax - fStart)*3 + (cMax - cStart)*6 + (fEnd - fMax)*2 + (c - cMax)*3 + 1;
6418       supportNew[2] = fStartNew + (fMax - fStart)*3 + (cMax - cStart)*6 + (fEnd - fMax)*2 + (c - cMax)*3 + 2;
6419       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
6420 #if defined(PETSC_USE_DEBUG)
6421       if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eEndNew);
6422       for (p = 0; p < 3; ++p) {
6423         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);
6424       }
6425 #endif
6426     }
6427     /* Old vertices have identical supports */
6428     for (v = vStart; v < vEnd; ++v) {
6429       const PetscInt  newp = vStartNew + (v - vStart);
6430       const PetscInt *support, *cone;
6431       PetscInt        size, s;
6432 
6433       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
6434       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
6435       for (s = 0; s < size; ++s) {
6436         const PetscInt e = support[s];
6437 
6438         supportRef[s] = -1;
6439         if (eStart <= e) {
6440           if (e < eMax) {
6441             ierr = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
6442             supportRef[s] = eStartNew + (e - eStart)*2 + (cone[1] == v ? 1 : 0);
6443           } else if (e < eEnd) {
6444             supportRef[s] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart)*4 + e - eMax;
6445           } else SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", e, eStart, eEnd);
6446         } else SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", e, eStart, eEnd);
6447       }
6448       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6449 #if defined(PETSC_USE_DEBUG)
6450       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", newp, vStartNew, vEndNew);
6451       for (p = 0; p < size; ++p) {
6452         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);
6453       }
6454 #endif
6455     }
6456     /* Interior edge vertices have 2 + faces supports */
6457     for (e = eStart; e < eMax; ++e) {
6458       const PetscInt  newp = vStartNew + (vEnd - vStart) + (e - eStart);
6459       const PetscInt *cone, *support;
6460       PetscInt        size, s;
6461 
6462       ierr          = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
6463       ierr          = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
6464       supportRef[0] = eStartNew + (e - eStart)*2 + 0;
6465       supportRef[1] = eStartNew + (e - eStart)*2 + 1;
6466       for (s = 0; s < size; ++s) {
6467         PetscInt r, coneSize;
6468 
6469         supportRef[2+s] = -1;
6470         ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
6471         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);
6472         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);
6473         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6474         for (r = 0; r < coneSize; ++r) {if (cone[r] == e) break;}
6475         if (coneSize == 3) supportRef[2+s] = eStartNew + (eMax - eStart)*2 + (support[s] - fStart)*3 + r;
6476         else if (coneSize == 4) {
6477           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);
6478           supportRef[2+s] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart)*4 + (eEnd - eMax) + support[s] - fMax;
6479         } else SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected conesize %D for face %D (fMax %D)", coneSize, support[s], fMax);
6480       }
6481       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6482 #if defined(PETSC_USE_DEBUG)
6483       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", newp, vStartNew, vEndNew);
6484       for (p = 0; p < 2+size; ++p) {
6485         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);
6486       }
6487 #endif
6488     }
6489     /* Split Edges have 2 vertices and the same faces as the parent */
6490     for (e = eStart; e < eMax; ++e) {
6491       const PetscInt newv = vStartNew + (vEnd - vStart) + (e - eStart);
6492 
6493       for (r = 0; r < 2; ++r) {
6494         const PetscInt  newp = eStartNew + (e - eStart)*2 + r;
6495         const PetscInt *cone, *ornt, *support;
6496         PetscInt        coneNew[2], coneSize, c, supportSize, s;
6497 
6498         ierr             = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
6499         coneNew[0]       = vStartNew + (cone[0] - vStart);
6500         coneNew[1]       = vStartNew + (cone[1] - vStart);
6501         coneNew[(r+1)%2] = newv;
6502         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6503 #if defined(PETSC_USE_DEBUG)
6504         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eEndNew);
6505         for (p = 0; p < 2; ++p) {
6506           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);
6507         }
6508 #endif
6509         ierr = DMPlexGetSupportSize(dm, e, &supportSize);CHKERRQ(ierr);
6510         ierr = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
6511         for (s = 0; s < supportSize; ++s) {
6512           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
6513           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);
6514           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);
6515           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6516           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
6517           for (c = 0; c < coneSize; ++c) {
6518             if (cone[c] == e) break;
6519           }
6520           if (coneSize == 3) supportRef[s] = fStartNew + (support[s] - fStart)*3 + (c + (ornt[c] < 0 ? 1-r : r))%3;
6521           else if (coneSize == 4) {
6522             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);
6523             supportRef[s] = fStartNew + (fMax - fStart)*3 + (cMax - cStart)*6 + (support[s] - fMax)*2 + (ornt[c] < 0 ? 1-r : r);
6524           } else SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected conesize %D for face %D (fMax %D)", coneSize, support[s], fMax);
6525         }
6526         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6527 #if defined(PETSC_USE_DEBUG)
6528         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eEndNew);
6529         for (p = 0; p < supportSize; ++p) {
6530           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);
6531         }
6532 #endif
6533       }
6534     }
6535     /* Face vertices have 3 + cells supports */
6536     for (f = fStart; f < fMax; ++f) {
6537       const PetscInt  newp = vStartNew + (vEnd - vStart) + (eMax - eStart) + (f - fStart);
6538       const PetscInt *cone, *support;
6539       PetscInt        size, s;
6540 
6541       ierr          = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
6542       ierr          = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
6543       supportRef[0] = eStartNew + (eMax - eStart)*2 + (f - fStart)*3 + 0;
6544       supportRef[1] = eStartNew + (eMax - eStart)*2 + (f - fStart)*3 + 1;
6545       supportRef[2] = eStartNew + (eMax - eStart)*2 + (f - fStart)*3 + 2;
6546       for (s = 0; s < size; ++s) {
6547         PetscInt r, coneSize;
6548 
6549         supportRef[3+s] = -1;
6550         ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
6551         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);
6552         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);
6553         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6554         for (r = 0; r < coneSize; ++r) {if (cone[r] == f) break;}
6555         if (coneSize == 4) supportRef[3+s] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (support[s] - cStart)*4 + r;
6556         else if (coneSize == 5) {
6557           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);
6558           supportRef[3+s] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart)*4 + (eEnd - eMax) + (fEnd - fMax) + support[s] - cMax;
6559         }
6560       }
6561       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6562 #if defined(PETSC_USE_DEBUG)
6563       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", newp, vStartNew, vEndNew);
6564       for (p = 0; p < 3+size; ++p) {
6565         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);
6566       }
6567 #endif
6568     }
6569     /* Interior cell vertices have 4 supports */
6570     for (c = cStart; c < cMax; ++c) {
6571       const PetscInt  newp = vStartNew + (vEnd - vStart) + (eMax - eStart) + (fMax - fStart) + c - cStart;
6572 
6573       supportRef[0] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart)*4 + 0;
6574       supportRef[1] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart)*4 + 1;
6575       supportRef[2] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart)*4 + 2;
6576       supportRef[3] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart)*4 + 3;
6577       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6578 #if defined(PETSC_USE_DEBUG)
6579       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", newp, vStartNew, vEndNew);
6580       for (p = 0; p < 4; ++p) {
6581         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);
6582       }
6583 #endif
6584     }
6585     ierr = PetscFree(supportRef);CHKERRQ(ierr);
6586     ierr = DMPlexRestoreFaces_Internal(dm, 3, cStart, NULL, NULL, &faces);CHKERRQ(ierr);
6587     break;
6588   case REFINER_HEX_3D:
6589     /*
6590      Bottom (viewed from top)    Top
6591      1---------2---------2       7---------2---------6
6592      |         |         |       |         |         |
6593      |    B    2    C    |       |    H    2    G    |
6594      |         |         |       |         |         |
6595      3----3----0----1----1       3----3----0----1----1
6596      |         |         |       |         |         |
6597      |    A    0    D    |       |    E    0    F    |
6598      |         |         |       |         |         |
6599      0---------0---------3       4---------0---------5
6600      */
6601     /* All cells have 6 faces: Bottom, Top, Front, Back, Right, Left */
6602     for (c = cStart; c < cEnd; ++c) {
6603       const PetscInt  newp = (c - cStart)*8;
6604       const PetscInt *cone, *ornt;
6605       PetscInt        coneNew[6], orntNew[6];
6606 
6607       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
6608       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
6609       /* A hex */
6610       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], 0);
6611       orntNew[0] = ornt[0];
6612       coneNew[1] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  8; /* AE */
6613       orntNew[1] = 0;
6614       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetQuadSubface_Static(ornt[2], 0);
6615       orntNew[2] = ornt[2];
6616       coneNew[3] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  3; /* AB */
6617       orntNew[3] = 0;
6618       coneNew[4] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  0; /* AD */
6619       orntNew[4] = 0;
6620       coneNew[5] = fStartNew + (cone[5] - fStart)*4 + GetQuadSubface_Static(ornt[5], 0);
6621       orntNew[5] = ornt[5];
6622       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
6623       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
6624 #if defined(PETSC_USE_DEBUG)
6625       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);
6626       for (p = 0; p < 6; ++p) {
6627         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);
6628       }
6629 #endif
6630       /* B hex */
6631       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], 1);
6632       orntNew[0] = ornt[0];
6633       coneNew[1] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 + 11; /* BH */
6634       orntNew[1] = 0;
6635       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  3; /* AB */
6636       orntNew[2] = -1;
6637       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetQuadSubface_Static(ornt[3], 1);
6638       orntNew[3] = ornt[3];
6639       coneNew[4] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  2; /* BC */
6640       orntNew[4] = 0;
6641       coneNew[5] = fStartNew + (cone[5] - fStart)*4 + GetQuadSubface_Static(ornt[5], 3);
6642       orntNew[5] = ornt[5];
6643       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
6644       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
6645 #if defined(PETSC_USE_DEBUG)
6646       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);
6647       for (p = 0; p < 6; ++p) {
6648         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);
6649       }
6650 #endif
6651       /* C hex */
6652       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], 2);
6653       orntNew[0] = ornt[0];
6654       coneNew[1] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 + 10; /* CG */
6655       orntNew[1] = 0;
6656       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  1; /* CD */
6657       orntNew[2] = -1;
6658       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetQuadSubface_Static(ornt[3], 0);
6659       orntNew[3] = ornt[3];
6660       coneNew[4] = fStartNew + (cone[4] - fStart)*4 + GetQuadSubface_Static(ornt[4], 1);
6661       orntNew[4] = ornt[4];
6662       coneNew[5] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  2; /* BC */
6663       orntNew[5] = -4;
6664       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
6665       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
6666 #if defined(PETSC_USE_DEBUG)
6667       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);
6668       for (p = 0; p < 6; ++p) {
6669         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);
6670       }
6671 #endif
6672       /* D hex */
6673       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], 3);
6674       orntNew[0] = ornt[0];
6675       coneNew[1] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  9; /* DF */
6676       orntNew[1] = 0;
6677       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetQuadSubface_Static(ornt[2], 1);
6678       orntNew[2] = ornt[2];
6679       coneNew[3] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  1; /* CD */
6680       orntNew[3] = 0;
6681       coneNew[4] = fStartNew + (cone[4] - fStart)*4 + GetQuadSubface_Static(ornt[4], 0);
6682       orntNew[4] = ornt[4];
6683       coneNew[5] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  0; /* AD */
6684       orntNew[5] = -4;
6685       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
6686       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
6687 #if defined(PETSC_USE_DEBUG)
6688       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);
6689       for (p = 0; p < 6; ++p) {
6690         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);
6691       }
6692 #endif
6693       /* E hex */
6694       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  8; /* AE */
6695       orntNew[0] = -4;
6696       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], 0);
6697       orntNew[1] = ornt[1];
6698       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetQuadSubface_Static(ornt[2], 3);
6699       orntNew[2] = ornt[2];
6700       coneNew[3] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  7; /* EH */
6701       orntNew[3] = 0;
6702       coneNew[4] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  4; /* EF */
6703       orntNew[4] = -1;
6704       coneNew[5] = fStartNew + (cone[5] - fStart)*4 + GetQuadSubface_Static(ornt[5], 1);
6705       orntNew[5] = ornt[5];
6706       ierr       = DMPlexSetCone(rdm, newp+4, coneNew);CHKERRQ(ierr);
6707       ierr       = DMPlexSetConeOrientation(rdm, newp+4, orntNew);CHKERRQ(ierr);
6708 #if defined(PETSC_USE_DEBUG)
6709       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);
6710       for (p = 0; p < 6; ++p) {
6711         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);
6712       }
6713 #endif
6714       /* F hex */
6715       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  9; /* DF */
6716       orntNew[0] = -4;
6717       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], 1);
6718       orntNew[1] = ornt[1];
6719       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetQuadSubface_Static(ornt[2], 2);
6720       orntNew[2] = ornt[2];
6721       coneNew[3] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  5; /* FG */
6722       orntNew[3] = -1;
6723       coneNew[4] = fStartNew + (cone[4] - fStart)*4 + GetQuadSubface_Static(ornt[4], 3);
6724       orntNew[4] = ornt[4];
6725       coneNew[5] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  4; /* EF */
6726       orntNew[5] = 1;
6727       ierr       = DMPlexSetCone(rdm, newp+5, coneNew);CHKERRQ(ierr);
6728       ierr       = DMPlexSetConeOrientation(rdm, newp+5, orntNew);CHKERRQ(ierr);
6729 #if defined(PETSC_USE_DEBUG)
6730       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);
6731       for (p = 0; p < 6; ++p) {
6732         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);
6733       }
6734 #endif
6735       /* G hex */
6736       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 + 10; /* CG */
6737       orntNew[0] = -4;
6738       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], 2);
6739       orntNew[1] = ornt[1];
6740       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  5; /* FG */
6741       orntNew[2] = 0;
6742       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetQuadSubface_Static(ornt[3], 3);
6743       orntNew[3] = ornt[3];
6744       coneNew[4] = fStartNew + (cone[4] - fStart)*4 + GetQuadSubface_Static(ornt[4], 2);
6745       orntNew[4] = ornt[4];
6746       coneNew[5] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  6; /* GH */
6747       orntNew[5] = -3;
6748       ierr       = DMPlexSetCone(rdm, newp+6, coneNew);CHKERRQ(ierr);
6749       ierr       = DMPlexSetConeOrientation(rdm, newp+6, orntNew);CHKERRQ(ierr);
6750 #if defined(PETSC_USE_DEBUG)
6751       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);
6752       for (p = 0; p < 6; ++p) {
6753         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);
6754       }
6755 #endif
6756       /* H hex */
6757       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 + 11; /* BH */
6758       orntNew[0] = -4;
6759       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], 3);
6760       orntNew[1] = ornt[1];
6761       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  7; /* EH */
6762       orntNew[2] = -1;
6763       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetQuadSubface_Static(ornt[3], 2);
6764       orntNew[3] = ornt[3];
6765       coneNew[4] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  6; /* GH */
6766       orntNew[4] = 3;
6767       coneNew[5] = fStartNew + (cone[5] - fStart)*4 + GetQuadSubface_Static(ornt[5], 2);
6768       orntNew[5] = ornt[5];
6769       ierr       = DMPlexSetCone(rdm, newp+7, coneNew);CHKERRQ(ierr);
6770       ierr       = DMPlexSetConeOrientation(rdm, newp+7, orntNew);CHKERRQ(ierr);
6771 #if defined(PETSC_USE_DEBUG)
6772       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);
6773       for (p = 0; p < 6; ++p) {
6774         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);
6775       }
6776 #endif
6777     }
6778     /* Split faces have 4 edges and the same cells as the parent */
6779     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
6780     ierr = PetscMalloc1(4 + maxSupportSize*2, &supportRef);CHKERRQ(ierr);
6781     for (f = fStart; f < fEnd; ++f) {
6782       for (r = 0; r < 4; ++r) {
6783         /* TODO: This can come from GetFaces_Internal() */
6784         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};
6785         const PetscInt  newp = fStartNew + (f - fStart)*4 + r;
6786         const PetscInt *cone, *ornt, *support;
6787         PetscInt        coneNew[4], orntNew[4], coneSize, c, supportSize, s;
6788 
6789         ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
6790         ierr = DMPlexGetConeOrientation(dm, f, &ornt);CHKERRQ(ierr);
6791         coneNew[(r+3)%4] = eStartNew + (cone[(r+3)%4] - eStart)*2 + (ornt[(r+3)%4] < 0 ? 0 : 1);
6792         orntNew[(r+3)%4] = ornt[(r+3)%4];
6793         coneNew[(r+0)%4] = eStartNew + (cone[r]       - eStart)*2 + (ornt[r] < 0 ? 1 : 0);
6794         orntNew[(r+0)%4] = ornt[r];
6795         coneNew[(r+1)%4] = eStartNew + (eEnd - eStart)*2 + (f - fStart)*4 + r;
6796         orntNew[(r+1)%4] = 0;
6797         coneNew[(r+2)%4] = eStartNew + (eEnd - eStart)*2 + (f - fStart)*4 + (r+3)%4;
6798         orntNew[(r+2)%4] = -2;
6799         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6800         ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
6801 #if defined(PETSC_USE_DEBUG)
6802         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
6803         for (p = 0; p < 4; ++p) {
6804           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);
6805         }
6806 #endif
6807         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
6808         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
6809         for (s = 0; s < supportSize; ++s) {
6810           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
6811           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6812           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
6813           for (c = 0; c < coneSize; ++c) {
6814             if (cone[c] == f) break;
6815           }
6816           supportRef[s] = cStartNew + (support[s] - cStart)*8 + newCells[c*4+GetQuadSubfaceInverse_Static(ornt[c], r)];
6817         }
6818         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6819 #if defined(PETSC_USE_DEBUG)
6820         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
6821         for (p = 0; p < supportSize; ++p) {
6822           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);
6823         }
6824 #endif
6825       }
6826     }
6827     /* Interior faces have 4 edges and 2 cells */
6828     for (c = cStart; c < cEnd; ++c) {
6829       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};
6830       const PetscInt *cone, *ornt;
6831       PetscInt        newp, coneNew[4], orntNew[4], supportNew[2];
6832 
6833       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
6834       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
6835       /* A-D face */
6836       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 0;
6837       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*4 + GetQuadEdge_Static(ornt[0], 3);
6838       orntNew[0] = 0;
6839       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 0;
6840       orntNew[1] = 0;
6841       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 2;
6842       orntNew[2] = -2;
6843       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*4 + GetQuadEdge_Static(ornt[2], 0);
6844       orntNew[3] = -2;
6845       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6846       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
6847 #if defined(PETSC_USE_DEBUG)
6848       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
6849       for (p = 0; p < 4; ++p) {
6850         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);
6851       }
6852 #endif
6853       /* C-D face */
6854       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 1;
6855       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*4 + GetQuadEdge_Static(ornt[0], 2);
6856       orntNew[0] = 0;
6857       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 0;
6858       orntNew[1] = 0;
6859       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 4;
6860       orntNew[2] = -2;
6861       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (cone[4] - fStart)*4 + GetQuadEdge_Static(ornt[4], 0);
6862       orntNew[3] = -2;
6863       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6864       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
6865 #if defined(PETSC_USE_DEBUG)
6866       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
6867       for (p = 0; p < 4; ++p) {
6868         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);
6869       }
6870 #endif
6871       /* B-C face */
6872       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 2;
6873       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*4 + GetQuadEdge_Static(ornt[0], 1);
6874       orntNew[0] = -2;
6875       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*4 + GetQuadEdge_Static(ornt[3], 0);
6876       orntNew[1] = 0;
6877       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 3;
6878       orntNew[2] = 0;
6879       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 0;
6880       orntNew[3] = -2;
6881       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6882       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
6883 #if defined(PETSC_USE_DEBUG)
6884       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
6885       for (p = 0; p < 4; ++p) {
6886         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);
6887       }
6888 #endif
6889       /* A-B face */
6890       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 3;
6891       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*4 + GetQuadEdge_Static(ornt[0], 0);
6892       orntNew[0] = -2;
6893       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[5] - fStart)*4 + GetQuadEdge_Static(ornt[5], 3);
6894       orntNew[1] = 0;
6895       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 5;
6896       orntNew[2] = 0;
6897       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 0;
6898       orntNew[3] = -2;
6899       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6900       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
6901 #if defined(PETSC_USE_DEBUG)
6902       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
6903       for (p = 0; p < 4; ++p) {
6904         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);
6905       }
6906 #endif
6907       /* E-F face */
6908       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 4;
6909       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 2;
6910       orntNew[0] = -2;
6911       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*4 + GetQuadEdge_Static(ornt[2], 2);
6912       orntNew[1] = -2;
6913       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*4 + GetQuadEdge_Static(ornt[1], 0);
6914       orntNew[2] = 0;
6915       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 1;
6916       orntNew[3] = 0;
6917       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6918       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
6919 #if defined(PETSC_USE_DEBUG)
6920       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
6921       for (p = 0; p < 4; ++p) {
6922         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);
6923       }
6924 #endif
6925       /* F-G face */
6926       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 5;
6927       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 4;
6928       orntNew[0] = -2;
6929       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[4] - fStart)*4 + GetQuadEdge_Static(ornt[4], 2);
6930       orntNew[1] = -2;
6931       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*4 + GetQuadEdge_Static(ornt[1], 1);
6932       orntNew[2] = 0;
6933       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 1;
6934       orntNew[3] = 0;
6935       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6936       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
6937 #if defined(PETSC_USE_DEBUG)
6938       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
6939       for (p = 0; p < 4; ++p) {
6940         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);
6941       }
6942 #endif
6943       /* G-H face */
6944       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 6;
6945       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*4 + GetQuadEdge_Static(ornt[3], 2);
6946       orntNew[0] = -2;
6947       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*4 + GetQuadEdge_Static(ornt[1], 2);
6948       orntNew[1] = 0;
6949       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 1;
6950       orntNew[2] = 0;
6951       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 3;
6952       orntNew[3] = -2;
6953       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6954       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
6955 #if defined(PETSC_USE_DEBUG)
6956       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
6957       for (p = 0; p < 4; ++p) {
6958         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);
6959       }
6960 #endif
6961       /* E-H face */
6962       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 7;
6963       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 5;
6964       orntNew[0] = -2;
6965       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[5] - fStart)*4 + GetQuadEdge_Static(ornt[5], 1);
6966       orntNew[1] = -2;
6967       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*4 + GetQuadEdge_Static(ornt[1], 3);
6968       orntNew[2] = 0;
6969       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 1;
6970       orntNew[3] = 0;
6971       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6972       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
6973 #if defined(PETSC_USE_DEBUG)
6974       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
6975       for (p = 0; p < 4; ++p) {
6976         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);
6977       }
6978 #endif
6979       /* A-E face */
6980       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 8;
6981       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*4 + GetQuadEdge_Static(ornt[2], 3);
6982       orntNew[0] = 0;
6983       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 2;
6984       orntNew[1] = 0;
6985       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 5;
6986       orntNew[2] = -2;
6987       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (cone[5] - fStart)*4 + GetQuadEdge_Static(ornt[5], 0);
6988       orntNew[3] = -2;
6989       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6990       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
6991 #if defined(PETSC_USE_DEBUG)
6992       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
6993       for (p = 0; p < 4; ++p) {
6994         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);
6995       }
6996 #endif
6997       /* D-F face */
6998       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 9;
6999       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*4 + GetQuadEdge_Static(ornt[2], 1);
7000       orntNew[0] = -2;
7001       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[4] - fStart)*4 + GetQuadEdge_Static(ornt[4], 3);
7002       orntNew[1] = 0;
7003       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 4;
7004       orntNew[2] = 0;
7005       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 2;
7006       orntNew[3] = -2;
7007       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
7008       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
7009 #if defined(PETSC_USE_DEBUG)
7010       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
7011       for (p = 0; p < 4; ++p) {
7012         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);
7013       }
7014 #endif
7015       /* C-G face */
7016       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 10;
7017       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 4;
7018       orntNew[0] = -2;
7019       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[4] - fStart)*4 + GetQuadEdge_Static(ornt[4], 1);
7020       orntNew[1] = -2;
7021       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*4 + GetQuadEdge_Static(ornt[3], 3);
7022       orntNew[2] = 0;
7023       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 3;
7024       orntNew[3] = 0;
7025       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
7026       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
7027 #if defined(PETSC_USE_DEBUG)
7028       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
7029       for (p = 0; p < 4; ++p) {
7030         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);
7031       }
7032 #endif
7033       /* B-H face */
7034       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 11;
7035       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 5;
7036       orntNew[0] = 0;
7037       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 3;
7038       orntNew[1] = -2;
7039       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*4 + GetQuadEdge_Static(ornt[3], 1);
7040       orntNew[2] = -2;
7041       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (cone[5] - fStart)*4 + GetQuadEdge_Static(ornt[5], 2);
7042       orntNew[3] = 0;
7043       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
7044       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
7045 #if defined(PETSC_USE_DEBUG)
7046       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
7047       for (p = 0; p < 4; ++p) {
7048         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);
7049       }
7050 #endif
7051       for (r = 0; r < 12; ++r) {
7052         newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + r;
7053         supportNew[0] = cStartNew + (c - cStart)*8 + newCells[r*2+0];
7054         supportNew[1] = cStartNew + (c - cStart)*8 + newCells[r*2+1];
7055         ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
7056 #if defined(PETSC_USE_DEBUG)
7057         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
7058         for (p = 0; p < 2; ++p) {
7059           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);
7060         }
7061 #endif
7062       }
7063     }
7064     /* Split edges have 2 vertices and the same faces as the parent */
7065     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
7066     for (e = eStart; e < eEnd; ++e) {
7067       const PetscInt newv = vStartNew + (vEnd - vStart) + (e - eStart);
7068 
7069       for (r = 0; r < 2; ++r) {
7070         const PetscInt  newp = eStartNew + (e - eStart)*2 + r;
7071         const PetscInt *cone, *ornt, *support;
7072         PetscInt        coneNew[2], coneSize, c, supportSize, s;
7073 
7074         ierr             = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
7075         coneNew[0]       = vStartNew + (cone[0] - vStart);
7076         coneNew[1]       = vStartNew + (cone[1] - vStart);
7077         coneNew[(r+1)%2] = newv;
7078         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
7079 #if defined(PETSC_USE_DEBUG)
7080         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eEndNew);
7081         for (p = 0; p < 2; ++p) {
7082           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);
7083         }
7084 #endif
7085         ierr = DMPlexGetSupportSize(dm, e, &supportSize);CHKERRQ(ierr);
7086         ierr = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
7087         for (s = 0; s < supportSize; ++s) {
7088           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
7089           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
7090           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
7091           for (c = 0; c < coneSize; ++c) {
7092             if (cone[c] == e) break;
7093           }
7094           supportRef[s] = fStartNew + (support[s] - fStart)*4 + (ornt[c] < 0 ? (c+1-r)%4 : (c+r)%4);
7095         }
7096         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
7097 #if defined(PETSC_USE_DEBUG)
7098         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eEndNew);
7099         for (p = 0; p < supportSize; ++p) {
7100           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);
7101         }
7102 #endif
7103       }
7104     }
7105     /* Face edges have 2 vertices and 2+cells faces */
7106     for (f = fStart; f < fEnd; ++f) {
7107       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};
7108       const PetscInt  newv = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (f - fStart);
7109       const PetscInt *cone, *coneCell, *orntCell, *support;
7110       PetscInt        coneNew[2], coneSize, c, supportSize, s;
7111 
7112       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
7113       for (r = 0; r < 4; ++r) {
7114         const PetscInt newp = eStartNew + (eEnd - eStart)*2 + (f - fStart)*4 + r;
7115 
7116         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r] - eStart);
7117         coneNew[1] = newv;
7118         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
7119 #if defined(PETSC_USE_DEBUG)
7120         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eEndNew);
7121         for (p = 0; p < 2; ++p) {
7122           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);
7123         }
7124 #endif
7125         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
7126         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
7127         supportRef[0] = fStartNew + (f - fStart)*4 + r;
7128         supportRef[1] = fStartNew + (f - fStart)*4 + (r+1)%4;
7129         for (s = 0; s < supportSize; ++s) {
7130           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
7131           ierr = DMPlexGetCone(dm, support[s], &coneCell);CHKERRQ(ierr);
7132           ierr = DMPlexGetConeOrientation(dm, support[s], &orntCell);CHKERRQ(ierr);
7133           for (c = 0; c < coneSize; ++c) if (coneCell[c] == f) break;
7134           supportRef[2+s] = fStartNew + (fEnd - fStart)*4 + (support[s] - cStart)*12 + newFaces[c*4 + GetQuadEdgeInverse_Static(orntCell[c], r)];
7135         }
7136         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
7137 #if defined(PETSC_USE_DEBUG)
7138         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eEndNew);
7139         for (p = 0; p < 2+supportSize; ++p) {
7140           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);
7141         }
7142 #endif
7143       }
7144     }
7145     /* Cell edges have 2 vertices and 4 faces */
7146     for (c = cStart; c < cEnd; ++c) {
7147       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};
7148       const PetscInt  newv = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (fEnd - fStart) + (c - cStart);
7149       const PetscInt *cone;
7150       PetscInt        coneNew[2], supportNew[4];
7151 
7152       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
7153       for (r = 0; r < 6; ++r) {
7154         const PetscInt newp = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*4 + (c - cStart)*6 + r;
7155 
7156         coneNew[0] = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (cone[r] - fStart);
7157         coneNew[1] = newv;
7158         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
7159 #if defined(PETSC_USE_DEBUG)
7160         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eEndNew);
7161         for (p = 0; p < 2; ++p) {
7162           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);
7163         }
7164 #endif
7165         for (f = 0; f < 4; ++f) supportNew[f] = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + newFaces[r*4+f];
7166         ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
7167 #if defined(PETSC_USE_DEBUG)
7168         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eEndNew);
7169         for (p = 0; p < 4; ++p) {
7170           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);
7171         }
7172 #endif
7173       }
7174     }
7175     /* Old vertices have identical supports */
7176     for (v = vStart; v < vEnd; ++v) {
7177       const PetscInt  newp = vStartNew + (v - vStart);
7178       const PetscInt *support, *cone;
7179       PetscInt        size, s;
7180 
7181       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
7182       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
7183       for (s = 0; s < size; ++s) {
7184         PetscInt r = 0;
7185 
7186         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
7187         if (cone[1] == v) r = 1;
7188         supportRef[s] = eStartNew + (support[s] - eStart)*2 + r;
7189       }
7190       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
7191 #if defined(PETSC_USE_DEBUG)
7192       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", newp, vStartNew, vEndNew);
7193       for (p = 0; p < size; ++p) {
7194         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);
7195       }
7196 #endif
7197     }
7198     /* Edge vertices have 2 + faces supports */
7199     for (e = eStart; e < eEnd; ++e) {
7200       const PetscInt  newp = vStartNew + (vEnd - vStart) + (e - eStart);
7201       const PetscInt *cone, *support;
7202       PetscInt        size, s;
7203 
7204       ierr          = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
7205       ierr          = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
7206       supportRef[0] = eStartNew + (e - eStart)*2 + 0;
7207       supportRef[1] = eStartNew + (e - eStart)*2 + 1;
7208       for (s = 0; s < size; ++s) {
7209         PetscInt r;
7210 
7211         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
7212         for (r = 0; r < 4; ++r) if (cone[r] == e) break;
7213         supportRef[2+s] = eStartNew + (eEnd - eStart)*2 + (support[s] - fStart)*4 + r;
7214       }
7215       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
7216 #if defined(PETSC_USE_DEBUG)
7217       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", newp, vStartNew, vEndNew);
7218       for (p = 0; p < 2+size; ++p) {
7219         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);
7220       }
7221 #endif
7222     }
7223     /* Face vertices have 4 + cells supports */
7224     for (f = fStart; f < fEnd; ++f) {
7225       const PetscInt  newp = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (f - fStart);
7226       const PetscInt *cone, *support;
7227       PetscInt        size, s;
7228 
7229       ierr          = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
7230       ierr          = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
7231       for (r = 0; r < 4; ++r) supportRef[r] = eStartNew + (eEnd - eStart)*2 +  (f - fStart)*4 + r;
7232       for (s = 0; s < size; ++s) {
7233         PetscInt r;
7234 
7235         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
7236         for (r = 0; r < 6; ++r) if (cone[r] == f) break;
7237         supportRef[4+s] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*4 + (support[s] - cStart)*6 + r;
7238       }
7239       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
7240 #if defined(PETSC_USE_DEBUG)
7241       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", newp, vStartNew, vEndNew);
7242       for (p = 0; p < 4+size; ++p) {
7243         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);
7244       }
7245 #endif
7246     }
7247     /* Cell vertices have 6 supports */
7248     for (c = cStart; c < cEnd; ++c) {
7249       const PetscInt newp = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (fEnd - fStart) + (c - cStart);
7250       PetscInt       supportNew[6];
7251 
7252       for (r = 0; r < 6; ++r) {
7253         supportNew[r] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*4 + (c - cStart)*6 + r;
7254       }
7255       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
7256     }
7257     ierr = PetscFree(supportRef);CHKERRQ(ierr);
7258     break;
7259   case REFINER_HYBRID_HEX_3D:
7260     ierr = DMPlexGetHybridBounds(rdm, &cMaxNew, &fMaxNew, &eMaxNew, NULL);CHKERRQ(ierr);
7261     /*
7262      Bottom (viewed from top)    Top
7263      1---------2---------2       7---------2---------6
7264      |         |         |       |         |         |
7265      |    B    2    C    |       |    H    2    G    |
7266      |         |         |       |         |         |
7267      3----3----0----1----1       3----3----0----1----1
7268      |         |         |       |         |         |
7269      |    A    0    D    |       |    E    0    F    |
7270      |         |         |       |         |         |
7271      0---------0---------3       4---------0---------5
7272      */
7273     /* Interior cells have 6 faces: Bottom, Top, Front, Back, Right, Left */
7274     for (c = cStart; c < cMax; ++c) {
7275       const PetscInt  newp = (c - cStart)*8;
7276       const PetscInt *cone, *ornt;
7277       PetscInt        coneNew[6], orntNew[6];
7278 
7279       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
7280       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
7281       /* A hex */
7282       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], 0);
7283       orntNew[0] = ornt[0];
7284       coneNew[1] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  8; /* AE */
7285       orntNew[1] = 0;
7286       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetQuadSubface_Static(ornt[2], 0);
7287       orntNew[2] = ornt[2];
7288       coneNew[3] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  3; /* AB */
7289       orntNew[3] = 0;
7290       coneNew[4] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  0; /* AD */
7291       orntNew[4] = 0;
7292       coneNew[5] = fStartNew + (cone[5] - fStart)*4 + GetQuadSubface_Static(ornt[5], 0);
7293       orntNew[5] = ornt[5];
7294       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
7295       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
7296 #if defined(PETSC_USE_DEBUG)
7297       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);
7298       for (p = 0; p < 6; ++p) {
7299         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);
7300       }
7301 #endif
7302       /* B hex */
7303       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], 1);
7304       orntNew[0] = ornt[0];
7305       coneNew[1] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 + 11; /* BH */
7306       orntNew[1] = 0;
7307       coneNew[2] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  3; /* AB */
7308       orntNew[2] = -1;
7309       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetQuadSubface_Static(ornt[3], 1);
7310       orntNew[3] = ornt[3];
7311       coneNew[4] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  2; /* BC */
7312       orntNew[4] = 0;
7313       coneNew[5] = fStartNew + (cone[5] - fStart)*4 + GetQuadSubface_Static(ornt[5], 3);
7314       orntNew[5] = ornt[5];
7315       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
7316       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
7317 #if defined(PETSC_USE_DEBUG)
7318       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);
7319       for (p = 0; p < 6; ++p) {
7320         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);
7321       }
7322 #endif
7323       /* C hex */
7324       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], 2);
7325       orntNew[0] = ornt[0];
7326       coneNew[1] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 + 10; /* CG */
7327       orntNew[1] = 0;
7328       coneNew[2] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  1; /* CD */
7329       orntNew[2] = -1;
7330       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetQuadSubface_Static(ornt[3], 0);
7331       orntNew[3] = ornt[3];
7332       coneNew[4] = fStartNew + (cone[4] - fStart)*4 + GetQuadSubface_Static(ornt[4], 1);
7333       orntNew[4] = ornt[4];
7334       coneNew[5] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  2; /* BC */
7335       orntNew[5] = -4;
7336       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
7337       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
7338 #if defined(PETSC_USE_DEBUG)
7339       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);
7340       for (p = 0; p < 6; ++p) {
7341         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);
7342       }
7343 #endif
7344       /* D hex */
7345       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], 3);
7346       orntNew[0] = ornt[0];
7347       coneNew[1] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  9; /* DF */
7348       orntNew[1] = 0;
7349       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetQuadSubface_Static(ornt[2], 1);
7350       orntNew[2] = ornt[2];
7351       coneNew[3] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  1; /* CD */
7352       orntNew[3] = 0;
7353       coneNew[4] = fStartNew + (cone[4] - fStart)*4 + GetQuadSubface_Static(ornt[4], 0);
7354       orntNew[4] = ornt[4];
7355       coneNew[5] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  0; /* AD */
7356       orntNew[5] = -4;
7357       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
7358       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
7359 #if defined(PETSC_USE_DEBUG)
7360       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);
7361       for (p = 0; p < 6; ++p) {
7362         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);
7363       }
7364 #endif
7365       /* E hex */
7366       coneNew[0] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  8; /* AE */
7367       orntNew[0] = -4;
7368       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], 0);
7369       orntNew[1] = ornt[1];
7370       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetQuadSubface_Static(ornt[2], 3);
7371       orntNew[2] = ornt[2];
7372       coneNew[3] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  7; /* EH */
7373       orntNew[3] = 0;
7374       coneNew[4] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  4; /* EF */
7375       orntNew[4] = -1;
7376       coneNew[5] = fStartNew + (cone[5] - fStart)*4 + GetQuadSubface_Static(ornt[5], 1);
7377       orntNew[5] = ornt[5];
7378       ierr       = DMPlexSetCone(rdm, newp+4, coneNew);CHKERRQ(ierr);
7379       ierr       = DMPlexSetConeOrientation(rdm, newp+4, orntNew);CHKERRQ(ierr);
7380 #if defined(PETSC_USE_DEBUG)
7381       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);
7382       for (p = 0; p < 6; ++p) {
7383         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);
7384       }
7385 #endif
7386       /* F hex */
7387       coneNew[0] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  9; /* DF */
7388       orntNew[0] = -4;
7389       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], 1);
7390       orntNew[1] = ornt[1];
7391       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetQuadSubface_Static(ornt[2], 2);
7392       orntNew[2] = ornt[2];
7393       coneNew[3] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  5; /* FG */
7394       orntNew[3] = -1;
7395       coneNew[4] = fStartNew + (cone[4] - fStart)*4 + GetQuadSubface_Static(ornt[4], 3);
7396       orntNew[4] = ornt[4];
7397       coneNew[5] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  4; /* EF */
7398       orntNew[5] = 1;
7399       ierr       = DMPlexSetCone(rdm, newp+5, coneNew);CHKERRQ(ierr);
7400       ierr       = DMPlexSetConeOrientation(rdm, newp+5, orntNew);CHKERRQ(ierr);
7401 #if defined(PETSC_USE_DEBUG)
7402       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);
7403       for (p = 0; p < 6; ++p) {
7404         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);
7405       }
7406 #endif
7407       /* G hex */
7408       coneNew[0] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 + 10; /* CG */
7409       orntNew[0] = -4;
7410       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], 2);
7411       orntNew[1] = ornt[1];
7412       coneNew[2] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  5; /* FG */
7413       orntNew[2] = 0;
7414       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetQuadSubface_Static(ornt[3], 3);
7415       orntNew[3] = ornt[3];
7416       coneNew[4] = fStartNew + (cone[4] - fStart)*4 + GetQuadSubface_Static(ornt[4], 2);
7417       orntNew[4] = ornt[4];
7418       coneNew[5] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  6; /* GH */
7419       orntNew[5] = -3;
7420       ierr       = DMPlexSetCone(rdm, newp+6, coneNew);CHKERRQ(ierr);
7421       ierr       = DMPlexSetConeOrientation(rdm, newp+6, orntNew);CHKERRQ(ierr);
7422 #if defined(PETSC_USE_DEBUG)
7423       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);
7424       for (p = 0; p < 6; ++p) {
7425         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);
7426       }
7427 #endif
7428       /* H hex */
7429       coneNew[0] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 + 11; /* BH */
7430       orntNew[0] = -4;
7431       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], 3);
7432       orntNew[1] = ornt[1];
7433       coneNew[2] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  7; /* EH */
7434       orntNew[2] = -1;
7435       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetQuadSubface_Static(ornt[3], 2);
7436       orntNew[3] = ornt[3];
7437       coneNew[4] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  6; /* GH */
7438       orntNew[4] = 3;
7439       coneNew[5] = fStartNew + (cone[5] - fStart)*4 + GetQuadSubface_Static(ornt[5], 2);
7440       orntNew[5] = ornt[5];
7441       ierr       = DMPlexSetCone(rdm, newp+7, coneNew);CHKERRQ(ierr);
7442       ierr       = DMPlexSetConeOrientation(rdm, newp+7, orntNew);CHKERRQ(ierr);
7443 #if defined(PETSC_USE_DEBUG)
7444       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);
7445       for (p = 0; p < 6; ++p) {
7446         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);
7447       }
7448 #endif
7449     }
7450     /* Hybrid cells have 6 faces: Front, Back, Sides */
7451     /*
7452      3---------2---------2
7453      |         |         |
7454      |    D    2    C    |
7455      |         |         |
7456      3----3----0----1----1
7457      |         |         |
7458      |    A    0    B    |
7459      |         |         |
7460      0---------0---------1
7461      */
7462     for (c = cMax; c < cEnd; ++c) {
7463       const PetscInt  newp = (cMax - cStart)*8 + (c - cMax)*4;
7464       const PetscInt *cone, *ornt, *fornt;
7465       PetscInt        coneNew[6], orntNew[6], o, of, i;
7466 
7467       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
7468       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
7469       ierr = DMPlexGetConeOrientation(dm, cone[0], &fornt);CHKERRQ(ierr);
7470       o = ornt[0] < 0 ? -1 : 1;
7471       for (r = 0; r < 4; ++r) {
7472         PetscInt subfA = GetQuadSubface_Static(ornt[0], r);
7473         PetscInt edgeA = GetQuadEdge_Static(ornt[0], r);
7474         PetscInt edgeB = GetQuadEdge_Static(ornt[0], (r+3)%4);
7475         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]);
7476         coneNew[0]         = fStartNew + (cone[0] - fStart)*4 + subfA;
7477         orntNew[0]         = ornt[0];
7478         coneNew[1]         = fStartNew + (cone[1] - fStart)*4 + subfA;
7479         orntNew[1]         = ornt[0];
7480         of = fornt[edgeA] < 0 ? -1 : 1;
7481         i  = GetQuadEdgeInverse_Static(ornt[0], r) + 2;
7482         coneNew[i] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (cone[2+edgeA] - fMax)*2 + (o*of < 0 ? 1 : 0);
7483         orntNew[i] = ornt[edgeA];
7484         i  = GetQuadEdgeInverse_Static(ornt[0], (r+1)%4) + 2;
7485         coneNew[i] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd          - fMax)*2 + (c - cMax)*4 + edgeA;
7486         orntNew[i] = 0;
7487         i  = GetQuadEdgeInverse_Static(ornt[0], (r+2)%4) + 2;
7488         coneNew[i] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd          - fMax)*2 + (c - cMax)*4 + edgeB;
7489         orntNew[i] = -2;
7490         of = fornt[edgeB] < 0 ? -1 : 1;
7491         i  = GetQuadEdgeInverse_Static(ornt[0], (r+3)%4) + 2;
7492         coneNew[i] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (cone[2+edgeB] - fMax)*2 + (o*of < 0 ? 0 : 1);
7493         orntNew[i] = ornt[edgeB];
7494         ierr       = DMPlexSetCone(rdm, newp+r, coneNew);CHKERRQ(ierr);
7495         ierr       = DMPlexSetConeOrientation(rdm, newp+r, orntNew);CHKERRQ(ierr);
7496 #if defined(PETSC_USE_DEBUG)
7497         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);
7498         for (p = 0; p < 2; ++p) {
7499           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);
7500         }
7501         for (p = 2; p < 6; ++p) {
7502           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);
7503         }
7504 #endif
7505       }
7506     }
7507     /* Interior split faces have 4 edges and the same cells as the parent */
7508     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
7509     ierr = PetscMalloc1(4 + maxSupportSize*2, &supportRef);CHKERRQ(ierr);
7510     for (f = fStart; f < fMax; ++f) {
7511       for (r = 0; r < 4; ++r) {
7512         /* TODO: This can come from GetFaces_Internal() */
7513         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};
7514         const PetscInt  newp = fStartNew + (f - fStart)*4 + r;
7515         const PetscInt *cone, *ornt, *support;
7516         PetscInt        coneNew[4], orntNew[4], coneSize, c, supportSize, s;
7517 
7518         ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
7519         ierr = DMPlexGetConeOrientation(dm, f, &ornt);CHKERRQ(ierr);
7520         coneNew[(r+3)%4] = eStartNew + (cone[(r+3)%4] - eStart)*2 + (ornt[(r+3)%4] < 0 ? 0 : 1);
7521         orntNew[(r+3)%4] = ornt[(r+3)%4];
7522         coneNew[(r+0)%4] = eStartNew + (cone[r]       - eStart)*2 + (ornt[r] < 0 ? 1 : 0);
7523         orntNew[(r+0)%4] = ornt[r];
7524         coneNew[(r+1)%4] = eStartNew + (eMax - eStart)*2 + (f - fStart)*4 + r;
7525         orntNew[(r+1)%4] = 0;
7526         coneNew[(r+2)%4] = eStartNew + (eMax - eStart)*2 + (f - fStart)*4 + (r+3)%4;
7527         orntNew[(r+2)%4] = -2;
7528         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
7529         ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
7530 #if defined(PETSC_USE_DEBUG)
7531         if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fMaxNew);
7532         for (p = 0; p < 4; ++p) {
7533           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);
7534         }
7535 #endif
7536         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
7537         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
7538         for (s = 0; s < supportSize; ++s) {
7539           PetscInt subf;
7540           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
7541           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
7542           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
7543           for (c = 0; c < coneSize; ++c) {
7544             if (cone[c] == f) break;
7545           }
7546           subf = GetQuadSubfaceInverse_Static(ornt[c], r);
7547           if (support[s] < cMax) {
7548             supportRef[s] = cStartNew + (support[s] - cStart)*8 + newCells[c*4+subf];
7549           } else {
7550             supportRef[s] = cStartNew + (cMax       - cStart)*8 + (support[s] - cMax)*4 + subf;
7551           }
7552         }
7553         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
7554 #if defined(PETSC_USE_DEBUG)
7555         if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fMaxNew);
7556         for (p = 0; p < supportSize; ++p) {
7557           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);
7558         }
7559 #endif
7560       }
7561     }
7562     /* Interior cell faces have 4 edges and 2 cells */
7563     for (c = cStart; c < cMax; ++c) {
7564       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};
7565       const PetscInt *cone, *ornt;
7566       PetscInt        newp, coneNew[4], orntNew[4], supportNew[2];
7567 
7568       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
7569       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
7570       /* A-D face */
7571       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 0;
7572       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*4 + GetQuadEdge_Static(ornt[0], 3);
7573       orntNew[0] = 0;
7574       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 0;
7575       orntNew[1] = 0;
7576       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 2;
7577       orntNew[2] = -2;
7578       coneNew[3] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*4 + GetQuadEdge_Static(ornt[2], 0);
7579       orntNew[3] = -2;
7580       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
7581       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
7582 #if defined(PETSC_USE_DEBUG)
7583       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fMaxNew);
7584       for (p = 0; p < 4; ++p) {
7585         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);
7586       }
7587 #endif
7588       /* C-D face */
7589       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 1;
7590       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*4 + GetQuadEdge_Static(ornt[0], 2);
7591       orntNew[0] = 0;
7592       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 0;
7593       orntNew[1] = 0;
7594       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 4;
7595       orntNew[2] = -2;
7596       coneNew[3] = eStartNew + (eMax - eStart)*2 + (cone[4] - fStart)*4 + GetQuadEdge_Static(ornt[4], 0);
7597       orntNew[3] = -2;
7598       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
7599       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
7600 #if defined(PETSC_USE_DEBUG)
7601       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fMaxNew);
7602       for (p = 0; p < 4; ++p) {
7603         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);
7604       }
7605 #endif
7606       /* B-C face */
7607       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 2;
7608       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*4 + GetQuadEdge_Static(ornt[0], 1);
7609       orntNew[0] = -2;
7610       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*4 + GetQuadEdge_Static(ornt[3], 0);
7611       orntNew[1] = 0;
7612       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 3;
7613       orntNew[2] = 0;
7614       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 0;
7615       orntNew[3] = -2;
7616       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
7617       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
7618 #if defined(PETSC_USE_DEBUG)
7619       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fMaxNew);
7620       for (p = 0; p < 4; ++p) {
7621         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);
7622       }
7623 #endif
7624       /* A-B face */
7625       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 3;
7626       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*4 + GetQuadEdge_Static(ornt[0], 0);
7627       orntNew[0] = -2;
7628       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[5] - fStart)*4 + GetQuadEdge_Static(ornt[5], 3);
7629       orntNew[1] = 0;
7630       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 5;
7631       orntNew[2] = 0;
7632       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 0;
7633       orntNew[3] = -2;
7634       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
7635       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
7636 #if defined(PETSC_USE_DEBUG)
7637       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fMaxNew);
7638       for (p = 0; p < 4; ++p) {
7639         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);
7640       }
7641 #endif
7642       /* E-F face */
7643       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 4;
7644       coneNew[0] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 2;
7645       orntNew[0] = -2;
7646       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*4 + GetQuadEdge_Static(ornt[2], 2);
7647       orntNew[1] = -2;
7648       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*4 + GetQuadEdge_Static(ornt[1], 0);
7649       orntNew[2] = 0;
7650       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 1;
7651       orntNew[3] = 0;
7652       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
7653       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
7654 #if defined(PETSC_USE_DEBUG)
7655       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fMaxNew);
7656       for (p = 0; p < 4; ++p) {
7657         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);
7658       }
7659 #endif
7660       /* F-G face */
7661       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 5;
7662       coneNew[0] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 4;
7663       orntNew[0] = -2;
7664       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[4] - fStart)*4 + GetQuadEdge_Static(ornt[4], 2);
7665       orntNew[1] = -2;
7666       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*4 + GetQuadEdge_Static(ornt[1], 1);
7667       orntNew[2] = 0;
7668       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 1;
7669       orntNew[3] = 0;
7670       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
7671       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
7672 #if defined(PETSC_USE_DEBUG)
7673       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fMaxNew);
7674       for (p = 0; p < 4; ++p) {
7675         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);
7676       }
7677 #endif
7678       /* G-H face */
7679       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 6;
7680       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*4 + GetQuadEdge_Static(ornt[3], 2);
7681       orntNew[0] = -2;
7682       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*4 + GetQuadEdge_Static(ornt[1], 2);
7683       orntNew[1] = 0;
7684       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 1;
7685       orntNew[2] = 0;
7686       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 3;
7687       orntNew[3] = -2;
7688       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
7689       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
7690 #if defined(PETSC_USE_DEBUG)
7691       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fMaxNew);
7692       for (p = 0; p < 4; ++p) {
7693         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);
7694       }
7695 #endif
7696       /* E-H face */
7697       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 7;
7698       coneNew[0] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 5;
7699       orntNew[0] = -2;
7700       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[5] - fStart)*4 + GetQuadEdge_Static(ornt[5], 1);
7701       orntNew[1] = -2;
7702       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*4 + GetQuadEdge_Static(ornt[1], 3);
7703       orntNew[2] = 0;
7704       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 1;
7705       orntNew[3] = 0;
7706       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
7707       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
7708 #if defined(PETSC_USE_DEBUG)
7709       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fMaxNew);
7710       for (p = 0; p < 4; ++p) {
7711         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);
7712       }
7713 #endif
7714       /* A-E face */
7715       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 8;
7716       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*4 + GetQuadEdge_Static(ornt[2], 3);
7717       orntNew[0] = 0;
7718       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 2;
7719       orntNew[1] = 0;
7720       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 5;
7721       orntNew[2] = -2;
7722       coneNew[3] = eStartNew + (eMax - eStart)*2 + (cone[5] - fStart)*4 + GetQuadEdge_Static(ornt[5], 0);
7723       orntNew[3] = -2;
7724       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
7725       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
7726 #if defined(PETSC_USE_DEBUG)
7727       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fMaxNew);
7728       for (p = 0; p < 4; ++p) {
7729         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);
7730       }
7731 #endif
7732       /* D-F face */
7733       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 9;
7734       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*4 + GetQuadEdge_Static(ornt[2], 1);
7735       orntNew[0] = -2;
7736       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[4] - fStart)*4 + GetQuadEdge_Static(ornt[4], 3);
7737       orntNew[1] = 0;
7738       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 4;
7739       orntNew[2] = 0;
7740       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 2;
7741       orntNew[3] = -2;
7742       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
7743       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
7744 #if defined(PETSC_USE_DEBUG)
7745       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fMaxNew);
7746       for (p = 0; p < 4; ++p) {
7747         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);
7748       }
7749 #endif
7750       /* C-G face */
7751       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 10;
7752       coneNew[0] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 4;
7753       orntNew[0] = -2;
7754       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[4] - fStart)*4 + GetQuadEdge_Static(ornt[4], 1);
7755       orntNew[1] = -2;
7756       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*4 + GetQuadEdge_Static(ornt[3], 3);
7757       orntNew[2] = 0;
7758       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 3;
7759       orntNew[3] = 0;
7760       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
7761       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
7762 #if defined(PETSC_USE_DEBUG)
7763       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fMaxNew);
7764       for (p = 0; p < 4; ++p) {
7765         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);
7766       }
7767 #endif
7768       /* B-H face */
7769       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 11;
7770       coneNew[0] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 5;
7771       orntNew[0] = 0;
7772       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 3;
7773       orntNew[1] = -2;
7774       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*4 + GetQuadEdge_Static(ornt[3], 1);
7775       orntNew[2] = -2;
7776       coneNew[3] = eStartNew + (eMax - eStart)*2 + (cone[5] - fStart)*4 + GetQuadEdge_Static(ornt[5], 2);
7777       orntNew[3] = 0;
7778       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
7779       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
7780 #if defined(PETSC_USE_DEBUG)
7781       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fMaxNew);
7782       for (p = 0; p < 4; ++p) {
7783         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);
7784       }
7785 #endif
7786       for (r = 0; r < 12; ++r) {
7787         newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + r;
7788         supportNew[0] = cStartNew + (c - cStart)*8 + newCells[r*2+0];
7789         supportNew[1] = cStartNew + (c - cStart)*8 + newCells[r*2+1];
7790         ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
7791 #if defined(PETSC_USE_DEBUG)
7792         if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fMaxNew);
7793         for (p = 0; p < 2; ++p) {
7794           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);
7795         }
7796 #endif
7797       }
7798     }
7799     /* Hybrid split faces have 4 edges and same cells */
7800     for (f = fMax; f < fEnd; ++f) {
7801       const PetscInt *cone, *ornt, *support;
7802       PetscInt        coneNew[4], orntNew[4];
7803       PetscInt        supportNew[2], size, s, c;
7804 
7805       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
7806       ierr = DMPlexGetConeOrientation(dm, f, &ornt);CHKERRQ(ierr);
7807       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
7808       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
7809       for (r = 0; r < 2; ++r) {
7810         const PetscInt newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (f - fMax)*2 + r;
7811 
7812         coneNew[0]   = eStartNew + (cone[0] - eStart)*2 + (ornt[0] < 0 ? 1-r : r);
7813         orntNew[0]   = ornt[0];
7814         coneNew[1]   = eStartNew + (cone[1] - eStart)*2 + (ornt[1] < 0 ? 1-r : r);
7815         orntNew[1]   = ornt[1];
7816         coneNew[2+r] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (cone[2+r] - eMax);
7817         orntNew[2+r] = 0;
7818         coneNew[3-r] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (eEnd      - eMax) + (f - fMax);
7819         orntNew[3-r] = 0;
7820         ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
7821         ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
7822 #if defined(PETSC_USE_DEBUG)
7823         if ((newp < fMaxNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a hybrid face [%D, %D)", newp, fMaxNew, fEndNew);
7824         for (p = 0; p < 2; ++p) {
7825           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);
7826         }
7827         for (p = 2; p < 4; ++p) {
7828           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);
7829         }
7830 #endif
7831         for (s = 0; s < size; ++s) {
7832           const PetscInt *coneCell, *orntCell, *fornt;
7833           PetscInt        o, of;
7834 
7835           ierr = DMPlexGetCone(dm, support[s], &coneCell);CHKERRQ(ierr);
7836           ierr = DMPlexGetConeOrientation(dm, support[s], &orntCell);CHKERRQ(ierr);
7837           o = orntCell[0] < 0 ? -1 : 1;
7838           for (c = 2; c < 6; ++c) if (coneCell[c] == f) break;
7839           if (c >= 6) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Could not find face %D in cone of cell %D", f, support[s]);
7840           ierr = DMPlexGetConeOrientation(dm, coneCell[0], &fornt);CHKERRQ(ierr);
7841           of = fornt[c-2] < 0 ? -1 : 1;
7842           supportNew[s] = cStartNew + (cMax - cStart)*8 + (support[s] - cMax)*4 + (GetQuadEdgeInverse_Static(orntCell[0], c-2) + (o*of < 0 ? 1-r : r))%4;
7843         }
7844         ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
7845 #if defined(PETSC_USE_DEBUG)
7846         if ((newp < fMaxNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a hybrid face [%D, %D)", newp, fMaxNew, fEndNew);
7847         for (p = 0; p < size; ++p) {
7848           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);
7849         }
7850 #endif
7851       }
7852     }
7853     /* Hybrid cell faces have 4 edges and 2 cells */
7854     for (c = cMax; c < cEnd; ++c) {
7855       PetscInt        newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd - fMax)*2 + (c - cMax)*4;
7856       const PetscInt *cone, *ornt;
7857       PetscInt        coneNew[4], orntNew[4];
7858       PetscInt        supportNew[2];
7859 
7860       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
7861       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
7862       for (r = 0; r < 4; ++r) {
7863 #if 0
7864         coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], r);
7865         orntNew[0] = 0;
7866         coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], r);
7867         orntNew[1] = 0;
7868         coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (eEnd - eMax) + (cone[2+GetQuadEdge_Static(ornt[0], r)] - fMax);
7869         orntNew[2] = 0;
7870         coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (eEnd - eMax) + (fEnd                                   - fMax) + (c - cMax);
7871         orntNew[3] = 0;
7872 #else
7873         coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*4 + r;
7874         orntNew[0] = 0;
7875         coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*4 + r;
7876         orntNew[1] = 0;
7877         coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (eEnd - eMax) + (cone[2+r] - fMax);
7878         orntNew[2] = 0;
7879         coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (eEnd - eMax) + (fEnd      - fMax) + (c - cMax);
7880         orntNew[3] = 0;
7881 #endif
7882         ierr = DMPlexSetCone(rdm, newp+r, coneNew);CHKERRQ(ierr);
7883         ierr = DMPlexSetConeOrientation(rdm, newp+r, orntNew);CHKERRQ(ierr);
7884 #if defined(PETSC_USE_DEBUG)
7885         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);
7886         for (p = 0; p < 2; ++p) {
7887           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);
7888         }
7889         for (p = 2; p < 4; ++p) {
7890           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);
7891         }
7892 #endif
7893         supportNew[0] = cStartNew + (cMax - cStart)*8 + (c - cMax)*4 + GetQuadSubface_Static(ornt[0], r);
7894         supportNew[1] = cStartNew + (cMax - cStart)*8 + (c - cMax)*4 + GetQuadSubface_Static(ornt[0], (r+1)%4);
7895         ierr          = DMPlexSetSupport(rdm, newp+r, supportNew);CHKERRQ(ierr);
7896 #if defined(PETSC_USE_DEBUG)
7897         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);
7898         for (p = 0; p < 2; ++p) {
7899           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);
7900         }
7901 #endif
7902       }
7903     }
7904     /* Interior split edges have 2 vertices and the same faces as the parent */
7905     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
7906     for (e = eStart; e < eMax; ++e) {
7907       const PetscInt newv = vStartNew + (vEnd - vStart) + (e - eStart);
7908 
7909       for (r = 0; r < 2; ++r) {
7910         const PetscInt  newp = eStartNew + (e - eStart)*2 + r;
7911         const PetscInt *cone, *ornt, *support;
7912         PetscInt        coneNew[2], coneSize, c, supportSize, s;
7913 
7914         ierr             = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
7915         coneNew[0]       = vStartNew + (cone[0] - vStart);
7916         coneNew[1]       = vStartNew + (cone[1] - vStart);
7917         coneNew[(r+1)%2] = newv;
7918         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
7919 #if defined(PETSC_USE_DEBUG)
7920         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eMaxNew);
7921         for (p = 0; p < 2; ++p) {
7922           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);
7923         }
7924 #endif
7925         ierr = DMPlexGetSupportSize(dm, e, &supportSize);CHKERRQ(ierr);
7926         ierr = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
7927         for (s = 0; s < supportSize; ++s) {
7928           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
7929           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
7930           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
7931           for (c = 0; c < coneSize; ++c) {
7932             if (cone[c] == e) break;
7933           }
7934           if (support[s] < fMax) {
7935             supportRef[s] = fStartNew + (support[s] - fStart)*4 + (c + (ornt[c] < 0 ? 1-r : r))%4;
7936           } else {
7937             supportRef[s] = fStartNew + (fMax       - fStart)*4 + (cMax - cStart)*12 + (support[s] - fMax)*2 + (ornt[c] < 0 ? 1-r : r);
7938           }
7939         }
7940         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
7941 #if defined(PETSC_USE_DEBUG)
7942         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eMaxNew);
7943         for (p = 0; p < supportSize; ++p) {
7944           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);
7945         }
7946 #endif
7947       }
7948     }
7949     /* Interior face edges have 2 vertices and 2+cells faces */
7950     for (f = fStart; f < fMax; ++f) {
7951       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};
7952       const PetscInt  newv = vStartNew + (vEnd - vStart) + (eMax - eStart) + (f - fStart);
7953       const PetscInt *cone, *coneCell, *orntCell, *support;
7954       PetscInt        coneNew[2], coneSize, c, supportSize, s;
7955 
7956       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
7957       for (r = 0; r < 4; ++r) {
7958         const PetscInt newp = eStartNew + (eMax - eStart)*2 + (f - fStart)*4 + r;
7959 
7960         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r] - eStart);
7961         coneNew[1] = newv;
7962         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
7963 #if defined(PETSC_USE_DEBUG)
7964         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eMaxNew);
7965         for (p = 0; p < 2; ++p) {
7966           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);
7967         }
7968 #endif
7969         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
7970         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
7971         supportRef[0] = fStartNew + (f - fStart)*4 + r;
7972         supportRef[1] = fStartNew + (f - fStart)*4 + (r+1)%4;
7973         for (s = 0; s < supportSize; ++s) {
7974           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
7975           ierr = DMPlexGetCone(dm, support[s], &coneCell);CHKERRQ(ierr);
7976           ierr = DMPlexGetConeOrientation(dm, support[s], &orntCell);CHKERRQ(ierr);
7977           for (c = 0; c < coneSize; ++c) if (coneCell[c] == f) break;
7978           if (support[s] < cMax) {
7979             supportRef[2+s] = fStartNew + (fMax - fStart)*4 + (support[s] - cStart)*12 + newFaces[c*4 + GetQuadEdgeInverse_Static(orntCell[c], r)];
7980           } else {
7981             supportRef[2+s] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd - fMax)*2 + (support[s] - cMax)*4 + r;
7982           }
7983         }
7984         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
7985 #if defined(PETSC_USE_DEBUG)
7986         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eMaxNew);
7987         for (p = 0; p < 2+supportSize; ++p) {
7988           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);
7989         }
7990 #endif
7991       }
7992     }
7993     /* Interior cell edges have 2 vertices and 4 faces */
7994     for (c = cStart; c < cMax; ++c) {
7995       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};
7996       const PetscInt  newv = vStartNew + (vEnd - vStart) + (eMax - eStart) + (fMax - fStart) + (c - cStart);
7997       const PetscInt *cone;
7998       PetscInt        coneNew[2], supportNew[4];
7999 
8000       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
8001       for (r = 0; r < 6; ++r) {
8002         const PetscInt newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (c - cStart)*6 + r;
8003 
8004         coneNew[0] = vStartNew + (vEnd - vStart) + (eMax - eStart) + (cone[r] - fStart);
8005         coneNew[1] = newv;
8006         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
8007 #if defined(PETSC_USE_DEBUG)
8008         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eMaxNew);
8009         for (p = 0; p < 2; ++p) {
8010           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);
8011         }
8012 #endif
8013         for (f = 0; f < 4; ++f) supportNew[f] = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + newFaces[r*4+f];
8014         ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
8015 #if defined(PETSC_USE_DEBUG)
8016         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eMaxNew);
8017         for (p = 0; p < 4; ++p) {
8018           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);
8019         }
8020 #endif
8021       }
8022     }
8023     /* Hybrid edges have two vertices and the same faces */
8024     for (e = eMax; e < eEnd; ++e) {
8025       const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (e - eMax);
8026       const PetscInt *cone, *support, *fcone;
8027       PetscInt        coneNew[2], size, fsize, s;
8028 
8029       ierr = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
8030       ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
8031       ierr = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
8032       coneNew[0] = vStartNew + (cone[0] - vStart);
8033       coneNew[1] = vStartNew + (cone[1] - vStart);
8034       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
8035 #if defined(PETSC_USE_DEBUG)
8036       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a hybrid edge [%D, %D)", newp, eMaxNew, eEndNew);
8037       for (p = 0; p < 2; ++p) {
8038         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);
8039       }
8040 #endif
8041       for (s = 0; s < size; ++s) {
8042         ierr = DMPlexGetConeSize(dm, support[s], &fsize);CHKERRQ(ierr);
8043         ierr = DMPlexGetCone(dm, support[s], &fcone);CHKERRQ(ierr);
8044         for (c = 0; c < fsize; ++c) if (fcone[c] == e) break;
8045         if ((c < 2) || (c > 3)) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Edge %D not found in cone of face %D", e, support[s]);
8046         supportRef[s] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (support[s] - fMax)*2 + c-2;
8047       }
8048       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
8049 #if defined(PETSC_USE_DEBUG)
8050       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a hybrid edge [%D, %D)", newp, eMaxNew, eEndNew);
8051       for (p = 0; p < size; ++p) {
8052         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);
8053       }
8054 #endif
8055     }
8056     /* Hybrid face edges have 2 vertices and 2+cells faces */
8057     for (f = fMax; f < fEnd; ++f) {
8058       const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (eEnd - eMax) + (f - fMax);
8059       const PetscInt *cone, *support, *ccone, *cornt;
8060       PetscInt        coneNew[2], size, csize, s;
8061 
8062       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
8063       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
8064       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
8065       coneNew[0] = vStartNew + (vEnd - vStart) + (cone[0] - eStart);
8066       coneNew[1] = vStartNew + (vEnd - vStart) + (cone[1] - eStart);
8067       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
8068 #if defined(PETSC_USE_DEBUG)
8069       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a hybrid edge [%D, %D)", newp, eMaxNew, eEndNew);
8070       for (p = 0; p < 2; ++p) {
8071         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);
8072       }
8073 #endif
8074       supportRef[0] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (f - fMax)*2 + 0;
8075       supportRef[1] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (f - fMax)*2 + 1;
8076       for (s = 0; s < size; ++s) {
8077         ierr = DMPlexGetConeSize(dm, support[s], &csize);CHKERRQ(ierr);
8078         ierr = DMPlexGetCone(dm, support[s], &ccone);CHKERRQ(ierr);
8079         ierr = DMPlexGetConeOrientation(dm, support[s], &cornt);CHKERRQ(ierr);
8080         for (c = 0; c < csize; ++c) if (ccone[c] == f) break;
8081         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]);
8082         supportRef[2+s] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd - fMax)*2 + (support[s] - cMax)*4 + c-2;
8083       }
8084       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
8085 #if defined(PETSC_USE_DEBUG)
8086       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a hybrid edge [%D, %D)", newp, eMaxNew, eEndNew);
8087       for (p = 0; p < 2+size; ++p) {
8088         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);
8089       }
8090 #endif
8091     }
8092     /* Hybrid cell edges have 2 vertices and 4 faces */
8093     for (c = cMax; c < cEnd; ++c) {
8094       const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (eEnd - eMax) + (fEnd - fMax) + (c - cMax);
8095       const PetscInt *cone, *support;
8096       PetscInt        coneNew[2], size;
8097 
8098       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
8099       ierr = DMPlexGetSupportSize(dm, c, &size);CHKERRQ(ierr);
8100       ierr = DMPlexGetSupport(dm, c, &support);CHKERRQ(ierr);
8101       coneNew[0] = vStartNew + (vEnd - vStart) + (eMax - eStart) + (cone[0] - fStart);
8102       coneNew[1] = vStartNew + (vEnd - vStart) + (eMax - eStart) + (cone[1] - fStart);
8103       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
8104 #if defined(PETSC_USE_DEBUG)
8105       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a hybrid edge [%D, %D)", newp, eMaxNew, eEndNew);
8106       for (p = 0; p < 2; ++p) {
8107         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);
8108       }
8109 #endif
8110       supportRef[0] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd - fMax)*2 + (c - cMax)*4 + 0;
8111       supportRef[1] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd - fMax)*2 + (c - cMax)*4 + 1;
8112       supportRef[2] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd - fMax)*2 + (c - cMax)*4 + 2;
8113       supportRef[3] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd - fMax)*2 + (c - cMax)*4 + 3;
8114       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
8115 #if defined(PETSC_USE_DEBUG)
8116       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a hybrid edge [%D, %D)", newp, eMaxNew, eEndNew);
8117       for (p = 0; p < 4; ++p) {
8118         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);
8119       }
8120 #endif
8121     }
8122     /* Interior vertices have identical supports */
8123     for (v = vStart; v < vEnd; ++v) {
8124       const PetscInt  newp = vStartNew + (v - vStart);
8125       const PetscInt *support, *cone;
8126       PetscInt        size, s;
8127 
8128       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
8129       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
8130       for (s = 0; s < size; ++s) {
8131         PetscInt r = 0;
8132 
8133         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
8134         if (cone[1] == v) r = 1;
8135         if (support[s] < eMax) supportRef[s] = eStartNew + (support[s] - eStart)*2 + r;
8136         else                   supportRef[s] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (support[s] - eMax);
8137       }
8138       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
8139 #if defined(PETSC_USE_DEBUG)
8140       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", newp, vStartNew, vEndNew);
8141       for (p = 0; p < size; ++p) {
8142         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);
8143       }
8144 #endif
8145     }
8146     /* Interior edge vertices have 2 + faces supports */
8147     for (e = eStart; e < eMax; ++e) {
8148       const PetscInt  newp = vStartNew + (vEnd - vStart) + (e - eStart);
8149       const PetscInt *cone, *support;
8150       PetscInt        size, s;
8151 
8152       ierr          = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
8153       ierr          = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
8154       supportRef[0] = eStartNew + (e - eStart)*2 + 0;
8155       supportRef[1] = eStartNew + (e - eStart)*2 + 1;
8156       for (s = 0; s < size; ++s) {
8157         PetscInt r;
8158 
8159         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
8160         for (r = 0; r < 4; ++r) if (cone[r] == e) break;
8161         if (support[s] < fMax) {
8162           supportRef[2+s] = eStartNew + (eMax - eStart)*2 + (support[s] - fStart)*4 + r;
8163         } else {
8164           supportRef[2+s] = eStartNew + (eMax - eStart)*2 + (fMax       - fStart)*4 + (cMax - cStart)*6 + (eEnd - eMax) + (support[s] - fMax);
8165         }
8166       }
8167       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
8168 #if defined(PETSC_USE_DEBUG)
8169       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", newp, vStartNew, vEndNew);
8170       for (p = 0; p < 2+size; ++p) {
8171         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);
8172       }
8173 #endif
8174     }
8175     /* Interior face vertices have 4 + cells supports */
8176     for (f = fStart; f < fMax; ++f) {
8177       const PetscInt  newp = vStartNew + (vEnd - vStart) + (eMax - eStart) + (f - fStart);
8178       const PetscInt *cone, *support;
8179       PetscInt        size, s;
8180 
8181       ierr          = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
8182       ierr          = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
8183       for (r = 0; r < 4; ++r) supportRef[r] = eStartNew + (eMax - eStart)*2 +  (f - fStart)*4 + r;
8184       for (s = 0; s < size; ++s) {
8185         PetscInt r;
8186 
8187         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
8188         for (r = 0; r < 6; ++r) if (cone[r] == f) break;
8189         if (support[s] < cMax) {
8190           supportRef[4+s] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (support[s] - cStart)*6 + r;
8191         } else {
8192           supportRef[4+s] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax       - cStart)*6 + (eEnd - eMax) + (fEnd - fMax) + (support[s] - cMax);
8193         }
8194       }
8195       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
8196 #if defined(PETSC_USE_DEBUG)
8197       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", newp, vStartNew, vEndNew);
8198       for (p = 0; p < 4+size; ++p) {
8199         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);
8200       }
8201 #endif
8202     }
8203     /* Cell vertices have 6 supports */
8204     for (c = cStart; c < cMax; ++c) {
8205       const PetscInt newp = vStartNew + (vEnd - vStart) + (eMax - eStart) + (fMax - fStart) + (c - cStart);
8206       PetscInt       supportNew[6];
8207 
8208       for (r = 0; r < 6; ++r) {
8209         supportNew[r] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (c - cStart)*6 + r;
8210       }
8211       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
8212     }
8213     ierr = PetscFree(supportRef);CHKERRQ(ierr);
8214     break;
8215   default:
8216     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %s", CellRefiners[refiner]);
8217   }
8218   PetscFunctionReturn(0);
8219 }
8220 
8221 static PetscErrorCode CellRefinerSetCoordinates(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
8222 {
8223   PetscSection          coordSection, coordSectionNew;
8224   Vec                   coordinates, coordinatesNew;
8225   PetscScalar          *coords, *coordsNew;
8226   const PetscInt        numVertices = depthSize ? depthSize[0] : 0;
8227   PetscInt              dim, spaceDim, depth, bs, coordSizeNew, cStart, cEnd, cMax;
8228   PetscInt              c, vStart, vStartNew, vEnd, v, eStart, eEnd, eMax, e, fStart, fEnd, fMax, f;
8229   PetscInt              cStartNew, cEndNew, vEndNew, *parentId = NULL;
8230   VecType               vtype;
8231   PetscBool             isperiodic, localize = PETSC_FALSE, needcoords = PETSC_FALSE;
8232   const PetscReal      *maxCell, *L;
8233   const DMBoundaryType *bd;
8234   PetscErrorCode        ierr;
8235 
8236   PetscFunctionBegin;
8237   ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr);
8238   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
8239   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
8240   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
8241   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
8242   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
8243   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, NULL);CHKERRQ(ierr);
8244   if (cMax < 0) cMax = cEnd;
8245   if (fMax < 0) fMax = fEnd;
8246   if (eMax < 0) eMax = eEnd;
8247   ierr = GetDepthStart_Private(depth, depthSize, &cStartNew, NULL, NULL, &vStartNew);CHKERRQ(ierr);
8248   ierr = GetDepthEnd_Private(depth, depthSize, &cEndNew, NULL, NULL, &vEndNew);CHKERRQ(ierr);
8249   ierr = DMGetPeriodicity(dm, &isperiodic, &maxCell, &L, &bd);CHKERRQ(ierr);
8250   /* Determine if we need to localize coordinates when generating them */
8251   if (isperiodic && !maxCell) {
8252     ierr = DMGetCoordinatesLocalized(dm, &localize);CHKERRQ(ierr);
8253     if (!localize) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_USER,"Cannot refine if coordinates have not been localized");
8254   }
8255   if (isperiodic) {
8256     ierr = PetscOptionsBegin(PetscObjectComm((PetscObject)dm),((PetscObject)dm)->prefix,"DMPlex coords refinement options","DM");CHKERRQ(ierr);
8257     ierr = PetscOptionsBool("-dm_plex_refine_localize","Automatically localize from parent cells",NULL,localize,&localize,NULL);CHKERRQ(ierr);
8258     ierr = PetscOptionsEnd();CHKERRQ(ierr);
8259     if (localize) {
8260       ierr = DMLocalizeCoordinates(dm);CHKERRQ(ierr);
8261     }
8262   }
8263   ierr = DMSetPeriodicity(rdm, isperiodic,  maxCell,  L,  bd);CHKERRQ(ierr);
8264 
8265   ierr = DMGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
8266   ierr = PetscSectionGetFieldComponents(coordSection, 0, &spaceDim);CHKERRQ(ierr);
8267   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)dm), &coordSectionNew);CHKERRQ(ierr);
8268   ierr = PetscSectionSetNumFields(coordSectionNew, 1);CHKERRQ(ierr);
8269   ierr = PetscSectionSetFieldComponents(coordSectionNew, 0, spaceDim);CHKERRQ(ierr);
8270 
8271   if (localize) {
8272     PetscInt p, r, newp, *pi;
8273 
8274     /* New coordinates will be already localized on the cell */
8275     ierr = PetscSectionSetChart(coordSectionNew, 0, vStartNew+numVertices);CHKERRQ(ierr);
8276 
8277     /* We need the parentId to properly localize coordinates */
8278     ierr = PetscMalloc1(cEndNew-cStartNew,&pi);CHKERRQ(ierr);
8279     switch (refiner) {
8280     case REFINER_NOOP:
8281       break;
8282     case REFINER_SIMPLEX_1D:
8283       for (p = cStart; p < cEnd; ++p) {
8284         for (r = 0; r < 2; ++r) {
8285           newp     = (p - cStart)*2 + r;
8286           pi[newp] = p;
8287         }
8288       }
8289       break;
8290     case REFINER_SIMPLEX_2D:
8291       for (p = cStart; p < cEnd; ++p) {
8292         for (r = 0; r < 4; ++r) {
8293           newp     = (p - cStart)*4 + r;
8294           pi[newp] = p;
8295         }
8296       }
8297       break;
8298     case REFINER_HEX_2D:
8299       for (p = cStart; p < cEnd; ++p) {
8300         for (r = 0; r < 4; ++r) {
8301           newp     = (p - cStart)*4 + r;
8302           pi[newp] = p;
8303         }
8304       }
8305       break;
8306     case REFINER_SIMPLEX_TO_HEX_2D:
8307       for (p = cStart; p < cEnd; ++p) {
8308         for (r = 0; r < 3; ++r) {
8309           newp     = (p - cStart)*3 + r;
8310           pi[newp] = p;
8311         }
8312       }
8313       break;
8314     case REFINER_HYBRID_SIMPLEX_TO_HEX_2D:
8315       for (p = cStart; p < cMax; ++p) {
8316         for (r = 0; r < 3; ++r) {
8317           newp     = (p - cStart)*3 + r;
8318           pi[newp] = p;
8319         }
8320       }
8321       for (p = cMax; p < cEnd; ++p) {
8322         for (r = 0; r < 4; ++r) {
8323           newp     = (cMax - cStart)*3 + (p - cMax)*4 + r;
8324           pi[newp] = p;
8325         }
8326       }
8327       /* The refiner needs midpoint vertices on hybrid edges and hybrid cells */
8328       cMax = cEnd;
8329       eMax = eEnd;
8330       break;
8331     case REFINER_HYBRID_SIMPLEX_2D:
8332       for (p = cStart; p < cMax; ++p) {
8333         for (r = 0; r < 4; ++r) {
8334           newp     = (p - cStart)*4 + r;
8335           pi[newp] = p;
8336         }
8337       }
8338       for (p = cMax; p < cEnd; ++p) {
8339         for (r = 0; r < 2; ++r) {
8340           newp     = (cMax - cStart)*4 + (p - cMax)*2 + r;
8341           pi[newp] = p;
8342         }
8343       }
8344       break;
8345     case REFINER_HYBRID_HEX_2D:
8346       for (p = cStart; p < cMax; ++p) {
8347         for (r = 0; r < 4; ++r) {
8348           newp     = (p - cStart)*4 + r;
8349           pi[newp] = p;
8350         }
8351       }
8352       for (p = cMax; p < cEnd; ++p) {
8353         for (r = 0; r < 2; ++r) {
8354           newp     = (cMax - cStart)*4 + (p - cMax)*2 + r;
8355           pi[newp] = p;
8356         }
8357       }
8358       break;
8359     case REFINER_SIMPLEX_3D:
8360       for (p = cStart; p < cEnd; ++p) {
8361         for (r = 0; r < 8; ++r) {
8362           newp     = (p - cStart)*8 + r;
8363           pi[newp] = p;
8364         }
8365       }
8366       break;
8367     case REFINER_HYBRID_SIMPLEX_3D:
8368       for (p = cStart; p < cMax; ++p) {
8369         for (r = 0; r < 8; ++r) {
8370           newp     = (p - cStart)*8 + r;
8371           pi[newp] = p;
8372         }
8373       }
8374       for (p = cMax; p < cEnd; ++p) {
8375         for (r = 0; r < 4; ++r) {
8376           newp     = (cMax - cStart)*8 + (p - cMax)*4 + r;
8377           pi[newp] = p;
8378         }
8379       }
8380       break;
8381     case REFINER_SIMPLEX_TO_HEX_3D:
8382       for (p = cStart; p < cEnd; ++p) {
8383         for (r = 0; r < 4; ++r) {
8384           newp     = (p - cStart)*4 + r;
8385           pi[newp] = p;
8386         }
8387       }
8388       break;
8389     case REFINER_HYBRID_SIMPLEX_TO_HEX_3D:
8390       for (p = cStart; p < cMax; ++p) {
8391         for (r = 0; r < 4; ++r) {
8392           newp     = (p - cStart)*4 + r;
8393           pi[newp] = p;
8394         }
8395       }
8396       for (p = cMax; p < cEnd; ++p) {
8397         for (r = 0; r < 3; ++r) {
8398           newp     = (cMax - cStart)*4 + (p - cMax)*3 + r;
8399           pi[newp] = p;
8400         }
8401       }
8402       break;
8403     case REFINER_HEX_3D:
8404       for (p = cStart; p < cEnd; ++p) {
8405         for (r = 0; r < 8; ++r) {
8406           newp = (p - cStart)*8 + r;
8407           pi[newp] = p;
8408         }
8409       }
8410       break;
8411     case REFINER_HYBRID_HEX_3D:
8412       for (p = cStart; p < cMax; ++p) {
8413         for (r = 0; r < 8; ++r) {
8414           newp = (p - cStart)*8 + r;
8415           pi[newp] = p;
8416         }
8417       }
8418       for (p = cMax; p < cEnd; ++p) {
8419         for (r = 0; r < 4; ++r) {
8420           newp = (cMax - cStart)*8 + (p - cMax)*4 + r;
8421           pi[newp] = p;
8422         }
8423       }
8424       break;
8425     default:
8426       SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %s", CellRefiners[refiner]);
8427     }
8428     parentId = pi;
8429   } else {
8430     /* The refiner needs midpoint vertices on hybrid edges and hybrid cells */
8431     if (REFINER_HYBRID_SIMPLEX_TO_HEX_2D == refiner) { cMax = cEnd; eMax = eEnd; }
8432     ierr = PetscSectionSetChart(coordSectionNew, vStartNew, vStartNew+numVertices);CHKERRQ(ierr);
8433   }
8434 
8435   /* All vertices have the spaceDim coordinates */
8436   if (localize) {
8437     PetscInt c;
8438 
8439     for (c = cStartNew; c < cEndNew; ++c) {
8440       PetscInt *cone = NULL;
8441       PetscInt  closureSize, coneSize = 0, p, pdof;
8442 
8443       ierr = PetscSectionGetDof(coordSection, parentId[c], &pdof); CHKERRQ(ierr);
8444       if (pdof) { /* localize on all cells that are refinement of a localized parent cell */
8445         ierr = DMPlexGetTransitiveClosure(rdm, c, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
8446         for (p = 0; p < closureSize*2; p += 2) {
8447           const PetscInt point = cone[p];
8448           if ((point >= vStartNew) && (point < vEndNew)) coneSize++;
8449         }
8450         ierr = DMPlexRestoreTransitiveClosure(rdm, c, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
8451         ierr = PetscSectionSetDof(coordSectionNew, c, coneSize*spaceDim);CHKERRQ(ierr);
8452         ierr = PetscSectionSetFieldDof(coordSectionNew, c, 0, coneSize*spaceDim);CHKERRQ(ierr);
8453       }
8454     }
8455   }
8456   for (v = vStartNew; v < vStartNew+numVertices; ++v) {
8457     ierr = PetscSectionSetDof(coordSectionNew, v, spaceDim);CHKERRQ(ierr);
8458     ierr = PetscSectionSetFieldDof(coordSectionNew, v, 0, spaceDim);CHKERRQ(ierr);
8459   }
8460   ierr = PetscSectionSetUp(coordSectionNew);CHKERRQ(ierr);
8461   ierr = DMSetCoordinateSection(rdm, PETSC_DETERMINE, coordSectionNew);CHKERRQ(ierr);
8462   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
8463   ierr = PetscSectionGetStorageSize(coordSectionNew, &coordSizeNew);CHKERRQ(ierr);
8464   ierr = VecCreate(PETSC_COMM_SELF, &coordinatesNew);CHKERRQ(ierr);
8465   ierr = PetscObjectSetName((PetscObject) coordinatesNew, "coordinates");CHKERRQ(ierr);
8466   ierr = VecSetSizes(coordinatesNew, coordSizeNew, PETSC_DETERMINE);CHKERRQ(ierr);
8467   ierr = VecGetBlockSize(coordinates, &bs);CHKERRQ(ierr);
8468   ierr = VecSetBlockSize(coordinatesNew, bs);CHKERRQ(ierr);
8469   ierr = VecGetType(coordinates, &vtype);CHKERRQ(ierr);
8470   ierr = VecSetType(coordinatesNew, vtype);CHKERRQ(ierr);
8471   ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
8472   ierr = VecGetArray(coordinatesNew, &coordsNew);CHKERRQ(ierr);
8473 
8474   switch (refiner) {
8475   case REFINER_NOOP: break;
8476   case REFINER_HYBRID_SIMPLEX_TO_HEX_3D:
8477   case REFINER_SIMPLEX_TO_HEX_3D:
8478   case REFINER_HEX_3D:
8479   case REFINER_HYBRID_HEX_3D:
8480     /* Face vertices have the average of corner coordinates */
8481     for (f = fStart; f < fMax; ++f) {
8482       const PetscInt newv = vStartNew + (vEnd - vStart) + (eMax - eStart) + (f - fStart);
8483       PetscInt      *cone = NULL;
8484       PetscInt       closureSize, coneSize = 0, off[8], offnew, p, d;
8485 
8486       ierr = DMPlexGetTransitiveClosure(dm, f, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
8487       for (p = 0; p < closureSize*2; p += 2) {
8488         const PetscInt point = cone[p];
8489         if ((point >= vStart) && (point < vEnd)) cone[coneSize++] = point;
8490       }
8491       if (localize) {
8492         const PetscInt *support = NULL;
8493         PetscInt       *rStar = NULL;
8494         PetscInt        supportSize, rStarSize, coff, s, ccoff[8];
8495         PetscBool       cellfound = PETSC_FALSE;
8496 
8497         ierr = DMPlexGetTransitiveClosure(rdm, newv, PETSC_FALSE, &rStarSize, &rStar);CHKERRQ(ierr);
8498         ierr = DMPlexGetSupportSize(dm,f,&supportSize);CHKERRQ(ierr);
8499         ierr = DMPlexGetSupport(dm,f,&support);CHKERRQ(ierr);
8500         /* Compute average of coordinates for each cell sharing the face */
8501         for (s = 0; s < supportSize; ++s) {
8502           PetscScalar     coordsNewAux[3] = { 0.0, 0.0, 0.0 };
8503           PetscInt       *cellCone = NULL;
8504           PetscInt        cellClosureSize, cellConeSize = 0, cdof;
8505           const PetscInt  cell = support[s];
8506           PetscBool       copyoff = PETSC_FALSE;
8507 
8508           ierr = DMPlexGetTransitiveClosure(dm, cell, PETSC_TRUE, &cellClosureSize, &cellCone);CHKERRQ(ierr);
8509           for (p = 0; p < cellClosureSize*2; p += 2) {
8510             const PetscInt point = cellCone[p];
8511             if ((point >= vStart) && (point < vEnd)) cellCone[cellConeSize++] = point;
8512           }
8513           ierr = PetscSectionGetDof(coordSection, cell, &cdof);CHKERRQ(ierr);
8514           if (!cdof) { /* the parent cell does not have localized coordinates */
8515             cellfound = PETSC_TRUE;
8516             for (v = 0; v < coneSize; ++v) {
8517               ierr = PetscSectionGetOffset(coordSection, cone[v], &off[v]);CHKERRQ(ierr);
8518               for (d = 0; d < spaceDim; ++d) coordsNewAux[d] += coords[off[v]+d];
8519             }
8520             for (d = 0; d < spaceDim; ++d) coordsNewAux[d] /= coneSize;
8521           } else {
8522             ierr = PetscSectionGetOffset(coordSection, cell, &coff);CHKERRQ(ierr);
8523             for (p = 0; p < coneSize; ++p) {
8524               const PetscInt tv = cone[p];
8525               PetscInt       cv, voff;
8526               PetscBool      locv = PETSC_TRUE;
8527 
8528               for (cv = 0; cv < cellConeSize; ++cv) {
8529                 if (cellCone[cv] == tv) {
8530                   ccoff[p] = spaceDim*cv + coff;
8531                   break;
8532                 }
8533               }
8534               if (cv == cellConeSize) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Unable to map vertex %D",tv);
8535 
8536               ierr = PetscSectionGetOffset(coordSection, cone[p], &voff);CHKERRQ(ierr);
8537               for (d = 0; d < spaceDim; ++d) {
8538                 coordsNewAux[d] += coords[ccoff[p]+d];
8539                 if (!cellfound && coords[voff+d] != coords[ccoff[p]+d]) locv = PETSC_FALSE;
8540               }
8541               if (locv && !cellfound) {
8542                 cellfound = PETSC_TRUE;
8543                 copyoff   = PETSC_TRUE;
8544               }
8545             }
8546             for (d = 0; d < spaceDim; ++d) coordsNewAux[d] /= coneSize;
8547 
8548             /* Found a valid face for the "vertex" part of the Section (physical space)
8549                i.e., a face that has at least one corner in the physical space */
8550             if (copyoff) for (p = 0; p < coneSize; ++p) off[p] = ccoff[p];
8551           }
8552 
8553           /* Localize new coordinates on each refined cell */
8554           for (v = 0; v < rStarSize*2; v += 2) {
8555             if ((rStar[v] >= cStartNew) && (rStar[v] < cEndNew) && parentId[rStar[v]-cStartNew] == cell) {
8556               PetscInt       *rcone = NULL, rclosureSize, lid, rcdof, rcoff;
8557               const PetscInt  rcell = rStar[v];
8558 
8559               ierr = PetscSectionGetDof(coordSectionNew, rcell, &rcdof);CHKERRQ(ierr);
8560               if (!rcdof) continue;
8561               ierr = PetscSectionGetOffset(coordSectionNew, rcell, &rcoff);CHKERRQ(ierr);
8562               ierr = DMPlexGetTransitiveClosure(rdm, rcell, PETSC_TRUE, &rclosureSize, &rcone);CHKERRQ(ierr);
8563               for (p = 0, lid = 0; p < rclosureSize*2; p += 2) {
8564                 if (rcone[p] == newv) {
8565                   for (d = 0; d < spaceDim; d++) coordsNew[rcoff + lid*spaceDim + d] = coordsNewAux[d];
8566                   break;
8567                 }
8568                 if (rcone[p] >= vStartNew && rcone[p] < vEndNew) lid++;
8569               }
8570               ierr = DMPlexRestoreTransitiveClosure(rdm, rcell, PETSC_TRUE, &rclosureSize, &rcone);CHKERRQ(ierr);
8571               if (p == closureSize*2) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Unable to map new vertex %D",newv);
8572             }
8573           }
8574           ierr = DMPlexRestoreTransitiveClosure(dm, cell, PETSC_TRUE, &cellClosureSize, &cellCone);CHKERRQ(ierr);
8575         }
8576         ierr = DMPlexRestoreTransitiveClosure(rdm, newv, PETSC_FALSE, &rStarSize, &rStar);CHKERRQ(ierr);
8577         if (!cellfound) {
8578           /* Could not find a valid face for the vertex part, we will get this vertex later (final reduction) */
8579           needcoords = PETSC_TRUE;
8580           coneSize   = 0;
8581         }
8582       } else {
8583         for (v = 0; v < coneSize; ++v) {
8584           ierr = PetscSectionGetOffset(coordSection, cone[v], &off[v]);CHKERRQ(ierr);
8585         }
8586       }
8587       ierr = PetscSectionGetOffset(coordSectionNew, newv, &offnew);CHKERRQ(ierr);
8588       if (coneSize) {
8589         for (d = 0; d < spaceDim; ++d) coordsNew[offnew+d] = 0.0;
8590         for (v = 0; v < coneSize; ++v) {ierr = DMLocalizeAddCoordinate_Internal(dm, spaceDim, &coords[off[0]], &coords[off[v]], &coordsNew[offnew]);CHKERRQ(ierr);}
8591         for (d = 0; d < spaceDim; ++d) coordsNew[offnew+d] /= coneSize;
8592       } else {
8593         for (d = 0; d < spaceDim; ++d) coordsNew[offnew+d] = PETSC_MIN_REAL;
8594       }
8595       ierr = DMPlexRestoreTransitiveClosure(dm, f, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
8596     }
8597   case REFINER_HYBRID_SIMPLEX_TO_HEX_2D:
8598   case REFINER_SIMPLEX_TO_HEX_2D:
8599   case REFINER_HEX_2D:
8600   case REFINER_HYBRID_HEX_2D:
8601   case REFINER_SIMPLEX_1D:
8602     /* Cell vertices have the average of corner coordinates */
8603     for (c = cStart; c < cMax; ++c) {
8604       const PetscInt newv = vStartNew + (vEnd - vStart) + (dim > 1 ? (eMax - eStart) : 0) + (c - cStart) + (dim > 2 ? (fMax - fStart) : 0);
8605       PetscInt      *cone = NULL;
8606       PetscInt       closureSize, coneSize = 0, off[8], offnew, p, d, cdof = 0;
8607 
8608       ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
8609       for (p = 0; p < closureSize*2; p += 2) {
8610         const PetscInt point = cone[p];
8611         if ((point >= vStart) && (point < vEnd)) cone[coneSize++] = point;
8612       }
8613       if (localize) {
8614         ierr = PetscSectionGetDof(coordSection, c, &cdof);CHKERRQ(ierr);
8615       }
8616       if (cdof) {
8617         PetscInt coff;
8618 
8619         ierr = PetscSectionGetOffset(coordSection, c, &coff);CHKERRQ(ierr);
8620         for (v = 0; v < coneSize; ++v) off[v] = spaceDim*v + coff;
8621       } else {
8622         for (v = 0; v < coneSize; ++v) {
8623           ierr = PetscSectionGetOffset(coordSection, cone[v], &off[v]);CHKERRQ(ierr);
8624         }
8625       }
8626       ierr = PetscSectionGetOffset(coordSectionNew, newv, &offnew);CHKERRQ(ierr);
8627       for (d = 0; d < spaceDim; ++d) coordsNew[offnew+d] = 0.0;
8628       for (v = 0; v < coneSize; ++v) {ierr = DMLocalizeAddCoordinate_Internal(dm, spaceDim, &coords[off[0]], &coords[off[v]], &coordsNew[offnew]);CHKERRQ(ierr);}
8629       for (d = 0; d < spaceDim; ++d) coordsNew[offnew+d] /= coneSize;
8630       ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
8631 
8632       /* Localize new coordinates on each refined cell */
8633       if (cdof) {
8634         PetscInt *rStar = NULL, rStarSize;
8635 
8636         ierr = DMPlexGetTransitiveClosure(rdm, newv, PETSC_FALSE, &rStarSize, &rStar);CHKERRQ(ierr);
8637         for (v = 0; v < rStarSize*2; v += 2) {
8638           if ((rStar[v] >= cStartNew) && (rStar[v] < cEndNew)) {
8639             PetscInt *cone = NULL, closureSize, lid, coff, rc, rcdof;
8640 
8641             rc   = rStar[v];
8642             ierr = PetscSectionGetDof(coordSectionNew, rc, &rcdof);CHKERRQ(ierr);
8643             if (!rcdof) continue;
8644             ierr = PetscSectionGetOffset(coordSectionNew, rc, &coff);CHKERRQ(ierr);
8645             ierr = DMPlexGetTransitiveClosure(rdm, rc, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
8646             for (p = 0, lid = 0; p < closureSize*2; p += 2) {
8647               if (cone[p] == newv) {
8648                 for (d = 0; d < spaceDim; d++) coordsNew[coff + lid*spaceDim + d] = coordsNew[offnew + d];
8649                 break;
8650               }
8651               if (cone[p] >= vStartNew && cone[p] < vEndNew) lid++;
8652             }
8653             if (p == closureSize*2) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Unable to map new vertex %D",newv);
8654             ierr = DMPlexRestoreTransitiveClosure(rdm, rc, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
8655           }
8656         }
8657         ierr = DMPlexRestoreTransitiveClosure(rdm, newv, PETSC_FALSE, &rStarSize, &rStar);CHKERRQ(ierr);
8658       }
8659     }
8660   case REFINER_SIMPLEX_2D:
8661   case REFINER_HYBRID_SIMPLEX_2D:
8662   case REFINER_SIMPLEX_3D:
8663   case REFINER_HYBRID_SIMPLEX_3D:
8664     /* Edge vertices have the average of endpoint coordinates */
8665     for (e = eStart; e < eMax; ++e) {
8666       const PetscInt  newv = vStartNew + (vEnd - vStart) + (e - eStart);
8667       const PetscInt *cone;
8668       PetscInt        coneSize, offA, offB, offnew, d;
8669 
8670       ierr = DMPlexGetConeSize(dm, e, &coneSize);CHKERRQ(ierr);
8671       if (coneSize != 2) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Edge %D cone should have two vertices, not %D", e, coneSize);
8672       ierr = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
8673       if (localize) {
8674         PetscInt   coff, toffA = -1, toffB = -1, voffA, voffB;
8675         PetscInt  *eStar = NULL, eStarSize;
8676         PetscInt  *rStar = NULL, rStarSize;
8677         PetscBool  cellfound = PETSC_FALSE;
8678 
8679         offA = offB = -1;
8680         ierr = PetscSectionGetOffset(coordSection, cone[0], &voffA);CHKERRQ(ierr);
8681         ierr = PetscSectionGetOffset(coordSection, cone[1], &voffB);CHKERRQ(ierr);
8682         ierr = DMPlexGetTransitiveClosure(dm, e, PETSC_FALSE, &eStarSize, &eStar);CHKERRQ(ierr);
8683         ierr = DMPlexGetTransitiveClosure(rdm, newv, PETSC_FALSE, &rStarSize, &rStar);CHKERRQ(ierr);
8684         for (v = 0; v < eStarSize*2; v += 2) {
8685           if ((eStar[v] >= cStart) && (eStar[v] < cEnd)) {
8686             PetscScalar     coordsNewAux[3] = {0., 0., 0.};
8687             PetscInt       *cellCone = NULL;
8688             PetscInt        cellClosureSize, s, cv, cdof;
8689             PetscBool       locvA = PETSC_TRUE, locvB = PETSC_TRUE;
8690             const PetscInt  cell = eStar[v];
8691 
8692             ierr = PetscSectionGetDof(coordSection, cell, &cdof);CHKERRQ(ierr);
8693             if (!cdof) {
8694               /* Found a valid edge for the "vertex" part of the Section */
8695               offA = voffA;
8696               offB = voffB;
8697               cellfound = PETSC_TRUE;
8698             } else {
8699               ierr = PetscSectionGetOffset(coordSection, cell, &coff);CHKERRQ(ierr);
8700               ierr = DMPlexGetTransitiveClosure(dm, cell, PETSC_TRUE, &cellClosureSize, &cellCone);CHKERRQ(ierr);
8701               for (s = 0, cv = 0; s < cellClosureSize*2; s += 2) {
8702                 const PetscInt point = cellCone[s];
8703                 if ((point >= vStart) && (point < vEnd)) {
8704                   if (point == cone[0]) toffA = spaceDim*cv + coff;
8705                   else if (point == cone[1]) toffB = spaceDim*cv + coff;
8706                   cv++;
8707                 }
8708               }
8709               ierr = DMPlexRestoreTransitiveClosure(dm, cell, PETSC_TRUE, &cellClosureSize, &cellCone);CHKERRQ(ierr);
8710               for (d = 0; d < spaceDim; ++d) {
8711                 coordsNewAux[d] = 0.5*(coords[toffA+d] + coords[toffB+d]);
8712                 if (coords[toffA+d] != coords[voffA+d]) locvA = PETSC_FALSE;
8713                 if (coords[toffB+d] != coords[voffB+d]) locvB = PETSC_FALSE;
8714               }
8715               /* Found a valid edge for the "vertex" part of the Section */
8716               if (!cellfound && (locvA || locvB)) {
8717                 cellfound = PETSC_TRUE;
8718                 offA = toffA;
8719                 offB = toffB;
8720               }
8721             }
8722 
8723             /* Localize new coordinates on each refined cell */
8724             for (s = 0; s < rStarSize*2; s += 2) {
8725               if ((rStar[s] >= cStartNew) && (rStar[s] < cEndNew) && parentId[rStar[s]-cStartNew] == cell) {
8726                 PetscInt       *rcone = NULL, rclosureSize, lid, p, rcdof;
8727                 const PetscInt  rcell = rStar[s];
8728 
8729                 ierr = PetscSectionGetDof(coordSectionNew, rcell, &rcdof);CHKERRQ(ierr);
8730                 if (!rcdof) continue;
8731                 ierr = PetscSectionGetOffset(coordSectionNew, rcell, &coff);CHKERRQ(ierr);
8732                 ierr = DMPlexGetTransitiveClosure(rdm, rcell, PETSC_TRUE, &rclosureSize, &rcone);CHKERRQ(ierr);
8733                 for (p = 0, lid = 0; p < rclosureSize*2; p += 2) {
8734                   if (rcone[p] == newv) {
8735                     for (d = 0; d < spaceDim; d++) coordsNew[coff + lid*spaceDim + d] = coordsNewAux[d];
8736                     break;
8737                   }
8738                   if (rcone[p] >= vStartNew && rcone[p] < vEndNew) lid++;
8739                 }
8740                 ierr = DMPlexRestoreTransitiveClosure(rdm, rcell, PETSC_TRUE, &rclosureSize, &rcone);CHKERRQ(ierr);
8741                 if (p == rclosureSize*2) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Unable to map new vertex %D",newv);
8742               }
8743             }
8744           }
8745         }
8746         ierr = DMPlexRestoreTransitiveClosure(dm, e, PETSC_FALSE, &eStarSize, &eStar);CHKERRQ(ierr);
8747         ierr = DMPlexRestoreTransitiveClosure(rdm, newv, PETSC_FALSE, &rStarSize, &rStar);CHKERRQ(ierr);
8748         if (!cellfound) {
8749           /* Could not find a valid edge for the vertex part, we will get this vertex later (final reduction) */
8750           needcoords = PETSC_TRUE;
8751         }
8752       } else {
8753         ierr = PetscSectionGetOffset(coordSection, cone[0], &offA);CHKERRQ(ierr);
8754         ierr = PetscSectionGetOffset(coordSection, cone[1], &offB);CHKERRQ(ierr);
8755       }
8756       ierr = PetscSectionGetOffset(coordSectionNew, newv, &offnew);CHKERRQ(ierr);
8757       if (offA != -1 && offB != -1) {
8758         ierr = DMLocalizeCoordinate_Internal(dm, spaceDim, &coords[offA], &coords[offB], &coordsNew[offnew]);CHKERRQ(ierr);
8759         for (d = 0; d < spaceDim; ++d) {
8760           coordsNew[offnew+d] = 0.5*(coords[offA+d] + coordsNew[offnew+d]);
8761         }
8762       } else {
8763         for (d = 0; d < spaceDim; ++d) coordsNew[offnew+d] = PETSC_MIN_REAL;
8764       }
8765     }
8766     /* Old vertices have the same coordinates */
8767     for (v = vStart; v < vEnd; ++v) {
8768       const PetscInt newv = vStartNew + (v - vStart);
8769       PetscInt       off, offnew, d;
8770 
8771       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
8772       ierr = PetscSectionGetOffset(coordSectionNew, newv, &offnew);CHKERRQ(ierr);
8773       for (d = 0; d < spaceDim; ++d) {
8774         coordsNew[offnew+d] = coords[off+d];
8775       }
8776 
8777       /* Localize new coordinates on each refined cell */
8778       if (localize) {
8779         PetscInt  p;
8780         PetscInt *rStar = NULL, rStarSize;
8781 
8782         ierr = DMPlexGetTransitiveClosure(rdm, newv, PETSC_FALSE, &rStarSize, &rStar);CHKERRQ(ierr);
8783         for (p = 0; p < rStarSize*2; p += 2) {
8784           if ((rStar[p] >= cStartNew) && (rStar[p] < cEndNew)) {
8785             PetscScalar  ocoords[3] = {0,0,0}; /* dummy values for compiler warnings about uninitialized values */
8786             PetscInt    *cone = NULL, closureSize, lid, coff, s, oc, cdof;
8787 
8788             c    = rStar[p];
8789             oc   = parentId[c-cStartNew];
8790             ierr = PetscSectionGetDof(coordSectionNew, c, &cdof);CHKERRQ(ierr);
8791             if (!cdof) continue;
8792             ierr = PetscSectionGetDof(coordSection, oc, &cdof);CHKERRQ(ierr);
8793             if (!cdof) continue;
8794             ierr = PetscSectionGetOffset(coordSection, oc, &coff);CHKERRQ(ierr);
8795             ierr = DMPlexGetTransitiveClosure(dm, oc, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
8796             for (s = 0, lid = 0; s < closureSize*2; s += 2) {
8797               if (cone[s] == v) {
8798                 for (d = 0; d < spaceDim; d++) ocoords[d] = coords[coff + lid*spaceDim + d];
8799                 break;
8800               }
8801               if (cone[s] >= vStart && cone[s] < vEnd) lid++;
8802             }
8803             if (s == closureSize*2) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Unable to map old vertex %D",v);
8804             ierr = DMPlexRestoreTransitiveClosure(dm, oc, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
8805 
8806             ierr = PetscSectionGetOffset(coordSectionNew, c, &coff);CHKERRQ(ierr);
8807             ierr = DMPlexGetTransitiveClosure(rdm, c, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
8808             for (s = 0, lid = 0; s < closureSize*2; s += 2) {
8809               if (cone[s] == newv) {
8810                 for (d = 0; d < spaceDim; d++) coordsNew[coff + lid*spaceDim + d] = ocoords[d];
8811                 break;
8812               }
8813               if (cone[s] >= vStartNew && cone[s] < vEndNew) lid++;
8814             }
8815             if (s == closureSize*2) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Unable to map new vertex %D",newv);
8816             ierr = DMPlexRestoreTransitiveClosure(rdm, c, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
8817           }
8818         }
8819         ierr = DMPlexRestoreTransitiveClosure(rdm, newv, PETSC_FALSE, &rStarSize, &rStar);CHKERRQ(ierr);
8820       }
8821     }
8822     break;
8823   default:
8824     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %s", CellRefiners[refiner]);
8825   }
8826   ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
8827   ierr = VecRestoreArray(coordinatesNew, &coordsNew);CHKERRQ(ierr);
8828   ierr = DMSetCoordinatesLocal(rdm, coordinatesNew);CHKERRQ(ierr);
8829 
8830   /* Final reduction (if needed) if we are localizing */
8831   if (localize) {
8832     PetscBool gred;
8833 
8834     ierr = MPIU_Allreduce(&needcoords, &gred, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject)rdm));CHKERRQ(ierr);
8835     if (gred) {
8836       DM                 cdm;
8837       Vec                aux;
8838       PetscSF            sf;
8839       const PetscScalar *lArray;
8840       PetscScalar       *gArray;
8841 #if defined(PETSC_USE_COMPLEX)
8842       PetscInt          i, ln, gn;
8843       PetscReal         *lrArray;
8844       PetscReal         *grArray;
8845 #endif
8846 
8847       ierr = DMGetCoordinateDM(rdm, &cdm);CHKERRQ(ierr);
8848       ierr = DMCreateGlobalVector(cdm, &aux);CHKERRQ(ierr);
8849       ierr = DMGetSectionSF(cdm, &sf);CHKERRQ(ierr);
8850       ierr = VecGetArrayRead(coordinatesNew, &lArray);CHKERRQ(ierr);
8851       ierr = VecSet(aux, PETSC_MIN_REAL);CHKERRQ(ierr);
8852       ierr = VecGetArray(aux, &gArray);CHKERRQ(ierr);
8853 #if defined(PETSC_USE_COMPLEX)
8854       ierr = VecGetLocalSize(aux, &gn);CHKERRQ(ierr);
8855       ierr = VecGetLocalSize(coordinatesNew, &ln);CHKERRQ(ierr);
8856       ierr = PetscMalloc2(ln,&lrArray,gn,&grArray);CHKERRQ(ierr);
8857       for (i=0;i<ln;i++) lrArray[i] = PetscRealPart(lArray[i]);
8858       for (i=0;i<gn;i++) grArray[i] = PetscRealPart(gArray[i]);
8859       ierr = PetscSFReduceBegin(sf, MPIU_REAL, lrArray, grArray, MPIU_MAX);CHKERRQ(ierr);
8860       ierr = PetscSFReduceEnd(sf, MPIU_REAL, lrArray, grArray, MPIU_MAX);CHKERRQ(ierr);
8861       for (i=0;i<gn;i++) gArray[i] = grArray[i];
8862       ierr = PetscFree2(lrArray,grArray);CHKERRQ(ierr);
8863 #else
8864       ierr = PetscSFReduceBegin(sf, MPIU_SCALAR, lArray, gArray, MPIU_MAX);CHKERRQ(ierr);
8865       ierr = PetscSFReduceEnd(sf, MPIU_SCALAR, lArray, gArray, MPIU_MAX);CHKERRQ(ierr);
8866 #endif
8867       ierr = VecRestoreArrayRead(coordinatesNew, &lArray);CHKERRQ(ierr);
8868       ierr = VecRestoreArray(aux, &gArray);CHKERRQ(ierr);
8869       ierr = DMGlobalToLocalBegin(cdm, aux, INSERT_VALUES, coordinatesNew);CHKERRQ(ierr);
8870       ierr = DMGlobalToLocalEnd(cdm, aux, INSERT_VALUES, coordinatesNew);CHKERRQ(ierr);
8871       ierr = VecDestroy(&aux);CHKERRQ(ierr);
8872     }
8873   }
8874   ierr = VecDestroy(&coordinatesNew);CHKERRQ(ierr);
8875   ierr = PetscSectionDestroy(&coordSectionNew);CHKERRQ(ierr);
8876   ierr = PetscFree(parentId);CHKERRQ(ierr);
8877   PetscFunctionReturn(0);
8878 }
8879 
8880 /*@
8881   DMPlexCreateProcessSF - Create an SF which just has process connectivity
8882 
8883   Collective on dm
8884 
8885   Input Parameters:
8886 + dm      - The DM
8887 - sfPoint - The PetscSF which encodes point connectivity
8888 
8889   Output Parameters:
8890 + processRanks - A list of process neighbors, or NULL
8891 - sfProcess    - An SF encoding the process connectivity, or NULL
8892 
8893   Level: developer
8894 
8895 .seealso: PetscSFCreate(), DMPlexCreateTwoSidedProcessSF()
8896 @*/
8897 PetscErrorCode DMPlexCreateProcessSF(DM dm, PetscSF sfPoint, IS *processRanks, PetscSF *sfProcess)
8898 {
8899   PetscInt           numRoots, numLeaves, l;
8900   const PetscInt    *localPoints;
8901   const PetscSFNode *remotePoints;
8902   PetscInt          *localPointsNew;
8903   PetscSFNode       *remotePointsNew;
8904   PetscInt          *ranks, *ranksNew;
8905   PetscMPIInt        size;
8906   PetscErrorCode     ierr;
8907 
8908   PetscFunctionBegin;
8909   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8910   PetscValidHeaderSpecific(sfPoint, PETSCSF_CLASSID, 2);
8911   if (processRanks) {PetscValidPointer(processRanks, 3);}
8912   if (sfProcess)    {PetscValidPointer(sfProcess, 4);}
8913   ierr = MPI_Comm_size(PetscObjectComm((PetscObject) dm), &size);CHKERRQ(ierr);
8914   ierr = PetscSFGetGraph(sfPoint, &numRoots, &numLeaves, &localPoints, &remotePoints);CHKERRQ(ierr);
8915   ierr = PetscMalloc1(numLeaves, &ranks);CHKERRQ(ierr);
8916   for (l = 0; l < numLeaves; ++l) {
8917     ranks[l] = remotePoints[l].rank;
8918   }
8919   ierr = PetscSortRemoveDupsInt(&numLeaves, ranks);CHKERRQ(ierr);
8920   ierr = PetscMalloc1(numLeaves, &ranksNew);CHKERRQ(ierr);
8921   ierr = PetscMalloc1(numLeaves, &localPointsNew);CHKERRQ(ierr);
8922   ierr = PetscMalloc1(numLeaves, &remotePointsNew);CHKERRQ(ierr);
8923   for (l = 0; l < numLeaves; ++l) {
8924     ranksNew[l]              = ranks[l];
8925     localPointsNew[l]        = l;
8926     remotePointsNew[l].index = 0;
8927     remotePointsNew[l].rank  = ranksNew[l];
8928   }
8929   ierr = PetscFree(ranks);CHKERRQ(ierr);
8930   if (processRanks) {ierr = ISCreateGeneral(PetscObjectComm((PetscObject)dm), numLeaves, ranksNew, PETSC_OWN_POINTER, processRanks);CHKERRQ(ierr);}
8931   else              {ierr = PetscFree(ranksNew);CHKERRQ(ierr);}
8932   if (sfProcess) {
8933     ierr = PetscSFCreate(PetscObjectComm((PetscObject)dm), sfProcess);CHKERRQ(ierr);
8934     ierr = PetscObjectSetName((PetscObject) *sfProcess, "Process SF");CHKERRQ(ierr);
8935     ierr = PetscSFSetFromOptions(*sfProcess);CHKERRQ(ierr);
8936     ierr = PetscSFSetGraph(*sfProcess, size, numLeaves, localPointsNew, PETSC_OWN_POINTER, remotePointsNew, PETSC_OWN_POINTER);CHKERRQ(ierr);
8937   }
8938   PetscFunctionReturn(0);
8939 }
8940 
8941 static PetscErrorCode CellRefinerCreateSF(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
8942 {
8943   PetscSF            sf, sfNew, sfProcess;
8944   IS                 processRanks;
8945   MPI_Datatype       depthType;
8946   PetscInt           numRoots, numLeaves, numLeavesNew = 0, l, m;
8947   const PetscInt    *localPoints, *neighbors;
8948   const PetscSFNode *remotePoints;
8949   PetscInt          *localPointsNew;
8950   PetscSFNode       *remotePointsNew;
8951   PetscInt          *depthSizeOld, *rdepthSize, *rdepthSizeOld, *rdepthMaxOld, *rvStart, *rvStartNew, *reStart, *reStartNew, *rfStart, *rfStartNew, *rcStart, *rcStartNew;
8952   PetscInt           ldepth, depth, numNeighbors, pStartNew, pEndNew, cStart, cEnd, cMax, vStart, vEnd, vMax, fStart, fEnd, fMax, eStart, eEnd, eMax, r, n;
8953   PetscInt           cStartNew = 0, vStartNew = 0, fStartNew = 0, eStartNew = 0;
8954   PetscErrorCode     ierr;
8955 
8956   PetscFunctionBegin;
8957   ierr = DMPlexGetChart(rdm, &pStartNew, &pEndNew);CHKERRQ(ierr);
8958   ierr = DMPlexGetDepth(dm, &ldepth);CHKERRQ(ierr);
8959   ierr = MPIU_Allreduce(&ldepth, &depth, 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject) dm));CHKERRQ(ierr);
8960   if ((ldepth >= 0) && (depth != ldepth)) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Inconsistent Plex depth %D != %D", ldepth, depth);
8961   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
8962   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
8963   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
8964   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
8965   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
8966   cMax = cMax < 0 ? cEnd : cMax;
8967   fMax = fMax < 0 ? fEnd : fMax;
8968   eMax = eMax < 0 ? eEnd : eMax;
8969   if (refiner) {ierr = GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);CHKERRQ(ierr);}
8970   ierr = DMGetPointSF(dm, &sf);CHKERRQ(ierr);
8971   ierr = DMGetPointSF(rdm, &sfNew);CHKERRQ(ierr);
8972   /* Calculate size of new SF */
8973   ierr = PetscSFGetGraph(sf, &numRoots, &numLeaves, &localPoints, &remotePoints);CHKERRQ(ierr);
8974   if (numRoots < 0) PetscFunctionReturn(0);
8975   for (l = 0; l < numLeaves; ++l) {
8976     const PetscInt p = localPoints[l];
8977 
8978     switch (refiner) {
8979     case REFINER_SIMPLEX_1D:
8980       if ((p >= vStart) && (p < vEnd)) {
8981         /* Interior vertices stay the same */
8982         ++numLeavesNew;
8983       } else if ((p >= cStart && p < cMax)) {
8984         /* Interior cells add new cells and interior vertices */
8985         numLeavesNew += 2 + 1;
8986       }
8987       break;
8988     case REFINER_SIMPLEX_2D:
8989     case REFINER_HYBRID_SIMPLEX_2D:
8990       if ((p >= vStart) && (p < vEnd)) {
8991         /* Interior vertices stay the same */
8992         ++numLeavesNew;
8993       } else if ((p >= fStart) && (p < fMax)) {
8994         /* Interior faces add new faces and vertex */
8995         numLeavesNew += 2 + 1;
8996       } else if ((p >= fMax) && (p < fEnd)) {
8997         /* Hybrid faces stay the same */
8998         ++numLeavesNew;
8999       } else if ((p >= cStart) && (p < cMax)) {
9000         /* Interior cells add new cells and interior faces */
9001         numLeavesNew += 4 + 3;
9002       } else if ((p >= cMax) && (p < cEnd)) {
9003         /* Hybrid cells add new cells and hybrid face */
9004         numLeavesNew += 2 + 1;
9005       }
9006       break;
9007     case REFINER_HYBRID_SIMPLEX_TO_HEX_2D:
9008     case REFINER_SIMPLEX_TO_HEX_2D:
9009       if ((p >= vStart) && (p < vEnd)) {
9010         /* Interior vertices stay the same */
9011         ++numLeavesNew;
9012       } else if ((p >= fStart) && (p < fEnd)) {
9013         /* Interior faces add new faces and vertex */
9014         numLeavesNew += 2 + 1;
9015       } else if ((p >= cStart) && (p < cMax)) {
9016         /* Interior cells add new cells, interior faces, and vertex */
9017         numLeavesNew += 3 + 3 + 1;
9018       } else if ((p >= cMax) && (p < cEnd)) {
9019         /* Hybrid cells add new cells, interior faces, and vertex */
9020         numLeavesNew += 4 + 4 + 1;
9021       }
9022       break;
9023     case REFINER_HEX_2D:
9024     case REFINER_HYBRID_HEX_2D:
9025       if ((p >= vStart) && (p < vEnd)) {
9026         /* Interior vertices stay the same */
9027         ++numLeavesNew;
9028       } else if ((p >= fStart) && (p < fMax)) {
9029         /* Interior faces add new faces and vertex */
9030         numLeavesNew += 2 + 1;
9031       } else if ((p >= fMax) && (p < fEnd)) {
9032         /* Hybrid faces stay the same */
9033         ++numLeavesNew;
9034       } else if ((p >= cStart) && (p < cMax)) {
9035         /* Interior cells add new cells, interior faces, and vertex */
9036         numLeavesNew += 4 + 4 + 1;
9037       } else if ((p >= cMax) && (p < cEnd)) {
9038         /* Hybrid cells add new cells and hybrid face */
9039         numLeavesNew += 2 + 1;
9040       }
9041       break;
9042     case REFINER_SIMPLEX_3D:
9043     case REFINER_HYBRID_SIMPLEX_3D:
9044       if ((p >= vStart) && (p < vEnd)) {
9045         /* Interior vertices stay the same */
9046         ++numLeavesNew;
9047       } else if ((p >= eStart) && (p < eMax)) {
9048         /* Interior edges add new edges and vertex */
9049         numLeavesNew += 2 + 1;
9050       } else if ((p >= eMax) && (p < eEnd)) {
9051         /* Hybrid edges stay the same */
9052         ++numLeavesNew;
9053       } else if ((p >= fStart) && (p < fMax)) {
9054         /* Interior faces add new faces and edges */
9055         numLeavesNew += 4 + 3;
9056       } else if ((p >= fMax) && (p < fEnd)) {
9057         /* Hybrid faces add new faces and edges */
9058         numLeavesNew += 2 + 1;
9059       } else if ((p >= cStart) && (p < cMax)) {
9060         /* Interior cells add new cells, faces, and edges */
9061         numLeavesNew += 8 + 8 + 1;
9062       } else if ((p >= cMax) && (p < cEnd)) {
9063         /* Hybrid cells add new cells and faces */
9064         numLeavesNew += 4 + 3;
9065       }
9066       break;
9067     case REFINER_HYBRID_SIMPLEX_TO_HEX_3D:
9068     case REFINER_SIMPLEX_TO_HEX_3D:
9069       if ((p >= vStart) && (p < vEnd)) {
9070         /* Interior vertices stay the same */
9071         ++numLeavesNew;
9072       } else if ((p >= eStart) && (p < eMax)) {
9073         /* Interior edges add new edges and vertex */
9074         numLeavesNew += 2 + 1;
9075       } else if ((p >= eMax) && (p < eEnd)) {
9076         /* Hybrid edges stay the same */
9077         ++numLeavesNew;
9078       } else if ((p >= fStart) && (p < fMax)) {
9079         /* Interior faces add new faces, edges and a vertex */
9080         numLeavesNew += 3 + 3 + 1;
9081       } else if ((p >= fMax) && (p < fEnd)) {
9082         /* Hybrid faces add new faces and an edge */
9083         numLeavesNew += 2 + 1;
9084       } else if ((p >= cStart) && (p < cMax)) {
9085         /* Interior cells add new cells, faces, edges and a vertex */
9086         numLeavesNew += 4 + 6 + 4 + 1;
9087       } else if ((p >= cMax) && (p < cEnd)) {
9088         /* Hybrid cells add new cells, faces and an edge */
9089         numLeavesNew += 3 + 3 + 1;
9090       }
9091       break;
9092     case REFINER_HEX_3D:
9093     case REFINER_HYBRID_HEX_3D:
9094       if ((p >= vStart) && (p < vEnd)) {
9095         /* Old vertices stay the same */
9096         ++numLeavesNew;
9097       } else if ((p >= eStart) && (p < eMax)) {
9098         /* Interior edges add new edges, and vertex */
9099         numLeavesNew += 2 + 1;
9100       } else if ((p >= eMax) && (p < eEnd)) {
9101         /* Hybrid edges stay the same */
9102         ++numLeavesNew;
9103       } else if ((p >= fStart) && (p < fMax)) {
9104         /* Interior faces add new faces, edges, and vertex */
9105         numLeavesNew += 4 + 4 + 1;
9106       } else if ((p >= fMax) && (p < fEnd)) {
9107         /* Hybrid faces add new faces and edges */
9108         numLeavesNew += 2 + 1;
9109       } else if ((p >= cStart) && (p < cMax)) {
9110         /* Interior cells add new cells, faces, edges, and vertex */
9111         numLeavesNew += 8 + 12 + 6 + 1;
9112       } else if ((p >= cStart) && (p < cEnd)) {
9113         /* Hybrid cells add new cells, faces, and edges */
9114         numLeavesNew += 4 + 4 + 1;
9115       }
9116       break;
9117     default:
9118       SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %s", CellRefiners[refiner]);
9119     }
9120   }
9121   /* Communicate depthSizes for each remote rank */
9122   ierr = DMPlexCreateProcessSF(dm, sf, &processRanks, &sfProcess);CHKERRQ(ierr);
9123   ierr = ISGetLocalSize(processRanks, &numNeighbors);CHKERRQ(ierr);
9124   ierr = PetscMalloc5((depth+1)*numNeighbors,&rdepthSize,numNeighbors,&rvStartNew,numNeighbors,&reStartNew,numNeighbors,&rfStartNew,numNeighbors,&rcStartNew);CHKERRQ(ierr);
9125   ierr = PetscMalloc7(depth+1,&depthSizeOld,(depth+1)*numNeighbors,&rdepthSizeOld,(depth+1)*numNeighbors,&rdepthMaxOld,numNeighbors,&rvStart,numNeighbors,&reStart,numNeighbors,&rfStart,numNeighbors,&rcStart);CHKERRQ(ierr);
9126   ierr = MPI_Type_contiguous(depth+1, MPIU_INT, &depthType);CHKERRQ(ierr);
9127   ierr = MPI_Type_commit(&depthType);CHKERRQ(ierr);
9128   ierr = PetscSFBcastBegin(sfProcess, depthType, depthSize, rdepthSize);CHKERRQ(ierr);
9129   ierr = PetscSFBcastEnd(sfProcess, depthType, depthSize, rdepthSize);CHKERRQ(ierr);
9130   for (n = 0; n < numNeighbors; ++n) {
9131     ierr = GetDepthStart_Private(depth, &rdepthSize[n*(depth+1)], &rcStartNew[n], &rfStartNew[n], &reStartNew[n], &rvStartNew[n]);CHKERRQ(ierr);
9132   }
9133   depthSizeOld[depth]   = cMax;
9134   depthSizeOld[0]       = vMax;
9135   depthSizeOld[depth-1] = fMax;
9136   depthSizeOld[1]       = eMax;
9137 
9138   ierr = PetscSFBcastBegin(sfProcess, depthType, depthSizeOld, rdepthMaxOld);CHKERRQ(ierr);
9139   ierr = PetscSFBcastEnd(sfProcess, depthType, depthSizeOld, rdepthMaxOld);CHKERRQ(ierr);
9140 
9141   depthSizeOld[depth]   = cEnd - cStart;
9142   depthSizeOld[0]       = vEnd - vStart;
9143   depthSizeOld[depth-1] = fEnd - fStart;
9144   depthSizeOld[1]       = eEnd - eStart;
9145 
9146   ierr = PetscSFBcastBegin(sfProcess, depthType, depthSizeOld, rdepthSizeOld);CHKERRQ(ierr);
9147   ierr = PetscSFBcastEnd(sfProcess, depthType, depthSizeOld, rdepthSizeOld);CHKERRQ(ierr);
9148   for (n = 0; n < numNeighbors; ++n) {
9149     ierr = GetDepthStart_Private(depth, &rdepthSizeOld[n*(depth+1)], &rcStart[n], &rfStart[n], &reStart[n], &rvStart[n]);CHKERRQ(ierr);
9150     rdepthMaxOld[n*(depth+1)+depth]   = rdepthMaxOld[n*(depth+1)+depth]   < 0 ? rdepthSizeOld[n*(depth+1)+depth]  +rcStart[n]: rdepthMaxOld[n*(depth+1)+depth];
9151     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];
9152     rdepthMaxOld[n*(depth+1)+1]       = rdepthMaxOld[n*(depth+1)+1]       < 0 ? rdepthSizeOld[n*(depth+1)+1]      +reStart[n]: rdepthMaxOld[n*(depth+1)+1];
9153   }
9154   ierr = MPI_Type_free(&depthType);CHKERRQ(ierr);
9155   ierr = PetscSFDestroy(&sfProcess);CHKERRQ(ierr);
9156   /* Calculate new point SF */
9157   ierr = PetscMalloc1(numLeavesNew, &localPointsNew);CHKERRQ(ierr);
9158   ierr = PetscMalloc1(numLeavesNew, &remotePointsNew);CHKERRQ(ierr);
9159   ierr = ISGetIndices(processRanks, &neighbors);CHKERRQ(ierr);
9160   for (l = 0, m = 0; l < numLeaves; ++l) {
9161     PetscInt    p     = localPoints[l];
9162     PetscInt    rp    = remotePoints[l].index, n;
9163     PetscMPIInt rrank = remotePoints[l].rank;
9164 
9165     ierr = PetscFindInt(rrank, numNeighbors, neighbors, &n);CHKERRQ(ierr);
9166     if (n < 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Could not locate remote rank %D", rrank);
9167     switch (refiner) {
9168     case REFINER_SIMPLEX_1D:
9169       if ((p >= vStart) && (p < vEnd)) {
9170         /* Old vertices stay the same */
9171         localPointsNew[m]        = vStartNew     + (p  - vStart);
9172         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
9173         remotePointsNew[m].rank  = rrank;
9174         ++m;
9175       } else if ((p >= cStart) && (p < cMax)) {
9176         /* Old interior cells add new cells and vertex */
9177         for (r = 0; r < 2; ++r, ++m) {
9178           localPointsNew[m]        = cStartNew     + (p  - cStart)*2     + r;
9179           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*2 + r;
9180           remotePointsNew[m].rank  = rrank;
9181         }
9182         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - cStart);
9183         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - rcStart[n]);
9184         remotePointsNew[m].rank  = rrank;
9185         ++m;
9186       }
9187       break;
9188     case REFINER_SIMPLEX_2D:
9189     case REFINER_HYBRID_SIMPLEX_2D:
9190       if ((p >= vStart) && (p < vEnd)) {
9191         /* Old vertices stay the same */
9192         localPointsNew[m]        = vStartNew     + (p  - vStart);
9193         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
9194         remotePointsNew[m].rank  = rrank;
9195         ++m;
9196       } else if ((p >= fStart) && (p < fMax)) {
9197         /* Old interior faces add new faces and vertex */
9198         for (r = 0; r < 2; ++r, ++m) {
9199           localPointsNew[m]        = fStartNew     + (p  - fStart)*2     + r;
9200           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*2 + r;
9201           remotePointsNew[m].rank  = rrank;
9202         }
9203         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - fStart);
9204         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - rfStart[n]);
9205         remotePointsNew[m].rank  = rrank;
9206         ++m;
9207       } else if ((p >= fMax) && (p < fEnd)) {
9208         /* Old hybrid faces stay the same */
9209         localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (p  - fMax);
9210         remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*2 + (rp - rdepthMaxOld[n*(depth+1)+depth-1]);
9211         remotePointsNew[m].rank  = rrank;
9212         ++m;
9213       } else if ((p >= cStart) && (p < cMax)) {
9214         /* Old interior cells add new cells and interior faces */
9215         for (r = 0; r < 4; ++r, ++m) {
9216           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
9217           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
9218           remotePointsNew[m].rank  = rrank;
9219         }
9220         for (r = 0; r < 3; ++r, ++m) {
9221           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (p  - cStart)*3     + r;
9222           remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*2 + (rp - rcStart[n])*3 + r;
9223           remotePointsNew[m].rank  = rrank;
9224         }
9225       } else if ((p >= cMax) && (p < cEnd)) {
9226         /* Old hybrid cells add new cells and hybrid face */
9227         for (r = 0; r < 2; ++r, ++m) {
9228           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
9229           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
9230           remotePointsNew[m].rank  = rrank;
9231         }
9232         localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (cMax                            - cStart)*3     + (p  - cMax);
9233         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]);
9234         remotePointsNew[m].rank  = rrank;
9235         ++m;
9236       }
9237       break;
9238     case REFINER_HYBRID_SIMPLEX_TO_HEX_2D:
9239     case REFINER_SIMPLEX_TO_HEX_2D:
9240       if ((p >= vStart) && (p < vEnd)) {
9241         /* Old vertices stay the same */
9242         localPointsNew[m]        = vStartNew     + (p  - vStart);
9243         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
9244         remotePointsNew[m].rank  = rrank;
9245         ++m;
9246       } else if ((p >= fStart) && (p < fEnd)) {
9247         /* Old interior faces add new faces and vertex */
9248         for (r = 0; r < 2; ++r, ++m) {
9249           localPointsNew[m]        = fStartNew     + (p  - fStart)*2     + r;
9250           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*2 + r;
9251           remotePointsNew[m].rank  = rrank;
9252         }
9253         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - fStart);
9254         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - rfStart[n]);
9255         remotePointsNew[m].rank  = rrank;
9256         ++m;
9257       } else if ((p >= cStart) && (p < cMax)) {
9258         /* Old interior cells add new cells, interior faces, and a vertex */
9259         for (r = 0; r < 3; ++r, ++m) {
9260           localPointsNew[m]        = cStartNew     + (p  - cStart)*3     + r;
9261           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*3 + r;
9262           remotePointsNew[m].rank  = rrank;
9263         }
9264         for (r = 0; r < 3; ++r, ++m) {
9265           localPointsNew[m]        = fStartNew     + (fEnd - fStart)*2                    + (p  - cStart)*3     + r;
9266           remotePointsNew[m].index = rfStartNew[n] + rdepthSizeOld[n*(depth+1)+depth-1]*2 + (rp - rcStart[n])*3 + r;
9267           remotePointsNew[m].rank  = rrank;
9268         }
9269         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (fEnd - fStart)                    + (p  - cStart);
9270         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + rdepthSizeOld[n*(depth+1)+depth-1] + (rp - rcStart[n]);
9271         remotePointsNew[m].rank  = rrank;
9272         ++m;
9273       } else if ((p >= cMax) && (p < cEnd)) {
9274         /* Old interior hybrid cells add new cells, interior faces, and a vertex */
9275         for (r = 0; r < 4; ++r, ++m) {
9276           localPointsNew[m]        = cStartNew     + (cMax  - cStart)*3                               + (p  - cMax)*4 + r;
9277           remotePointsNew[m].index = rcStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth] - rcStart[n])*3 + (rp - rdepthMaxOld[n*(depth+1)+depth])*4 + r;
9278           remotePointsNew[m].rank  = rrank;
9279         }
9280         for (r = 0; r < 4; ++r, ++m) {
9281           localPointsNew[m]        = fStartNew     + (fEnd - fStart)*2                    + (cMax  - cStart)*3                               + (p - cMax)*4 + r;
9282           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;
9283           remotePointsNew[m].rank  = rrank;
9284         }
9285         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (fEnd - fStart)                    + (p  - cStart);
9286         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + rdepthSizeOld[n*(depth+1)+depth-1] + (rp - rcStart[n]);
9287         remotePointsNew[m].rank  = rrank;
9288         ++m;
9289       }
9290       break;
9291     case REFINER_HEX_2D:
9292     case REFINER_HYBRID_HEX_2D:
9293       if ((p >= vStart) && (p < vEnd)) {
9294         /* Old vertices stay the same */
9295         localPointsNew[m]        = vStartNew     + (p  - vStart);
9296         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
9297         remotePointsNew[m].rank  = rrank;
9298         ++m;
9299       } else if ((p >= fStart) && (p < fMax)) {
9300         /* Old interior faces add new faces and vertex */
9301         for (r = 0; r < 2; ++r, ++m) {
9302           localPointsNew[m]        = fStartNew     + (p  - fStart)*2     + r;
9303           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*2 + r;
9304           remotePointsNew[m].rank  = rrank;
9305         }
9306         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - fStart);
9307         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - rfStart[n]);
9308         remotePointsNew[m].rank  = rrank;
9309         ++m;
9310       } else if ((p >= fMax) && (p < fEnd)) {
9311         /* Old hybrid faces stay the same */
9312         localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (p  - fMax);
9313         remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*2 + (rp - rdepthMaxOld[n*(depth+1)+depth-1]);
9314         remotePointsNew[m].rank  = rrank;
9315         ++m;
9316       } else if ((p >= cStart) && (p < cMax)) {
9317         /* Old interior cells add new cells, interior faces, and vertex */
9318         for (r = 0; r < 4; ++r, ++m) {
9319           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
9320           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
9321           remotePointsNew[m].rank  = rrank;
9322         }
9323         for (r = 0; r < 4; ++r, ++m) {
9324           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (p  - cStart)*4     + r;
9325           remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*2 + (rp - rcStart[n])*4 + r;
9326           remotePointsNew[m].rank  = rrank;
9327         }
9328         localPointsNew[m]        = vStartNew     + (vEnd - vStart)               + (fMax                              - fStart)     + (p  - cStart);
9329         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0]  + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n]) + (rp - rcStart[n]);
9330         remotePointsNew[m].rank  = rrank;
9331         ++m;
9332       } else if ((p >= cStart) && (p < cMax)) {
9333         /* Old hybrid cells add new cells and hybrid face */
9334         for (r = 0; r < 2; ++r, ++m) {
9335           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r; /* TODO: is this a bug? */
9336           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r; /* TODO: is this a bug? */
9337           remotePointsNew[m].rank  = rrank;
9338         }
9339         localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (cMax                            - cStart)*4     + (p  - cMax);
9340         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]);
9341         remotePointsNew[m].rank  = rrank;
9342         ++m;
9343       }
9344       break;
9345     case REFINER_SIMPLEX_3D:
9346     case REFINER_HYBRID_SIMPLEX_3D:
9347       if ((p >= vStart) && (p < vEnd)) {
9348         /* Interior vertices stay the same */
9349         localPointsNew[m]        = vStartNew     + (p  - vStart);
9350         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
9351         remotePointsNew[m].rank  = rrank;
9352         ++m;
9353       } else if ((p >= eStart) && (p < eMax)) {
9354         /* Interior edges add new edges and vertex */
9355         for (r = 0; r < 2; ++r, ++m) {
9356           localPointsNew[m]        = eStartNew     + (p  - eStart)*2     + r;
9357           remotePointsNew[m].index = reStartNew[n] + (rp - reStart[n])*2 + r;
9358           remotePointsNew[m].rank  = rrank;
9359         }
9360         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - eStart);
9361         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - reStart[n]);
9362         remotePointsNew[m].rank  = rrank;
9363         ++m;
9364       } else if ((p >= eMax) && (p < eEnd)) {
9365         /* Hybrid edges stay the same */
9366         localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (fMax                              - fStart)*3     + (cMax                            - cStart)     + (p  - eMax);
9367         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]);
9368         remotePointsNew[m].rank  = rrank;
9369         ++m;
9370       } else if ((p >= fStart) && (p < fMax)) {
9371         /* Interior faces add new faces and edges */
9372         for (r = 0; r < 4; ++r, ++m) {
9373           localPointsNew[m]        = fStartNew     + (p  - fStart)*4     + r;
9374           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*4 + r;
9375           remotePointsNew[m].rank  = rrank;
9376         }
9377         for (r = 0; r < 3; ++r, ++m) {
9378           localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (p  - fStart)*3     + r;
9379           remotePointsNew[m].index = reStartNew[n] + (rdepthMaxOld[n*(depth+1)+1] - reStart[n])*2 + (rp - rfStart[n])*3 + r;
9380           remotePointsNew[m].rank  = rrank;
9381         }
9382       } else if ((p >= fMax) && (p < fEnd)) {
9383         /* Hybrid faces add new faces and edges */
9384         for (r = 0; r < 2; ++r, ++m) {
9385           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*4     + (cMax                            - cStart)*8     + (p  - fMax)*2                              + r;
9386           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;
9387           remotePointsNew[m].rank  = rrank;
9388         }
9389         localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (fMax                              - fStart)*3     + (cMax                            - cStart)     + (eEnd                                    - eMax)                        + (p  - fMax);
9390         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]);
9391         remotePointsNew[m].rank  = rrank;
9392         ++m;
9393       } else if ((p >= cStart) && (p < cMax)) {
9394         /* Interior cells add new cells, faces, and edges */
9395         for (r = 0; r < 8; ++r, ++m) {
9396           localPointsNew[m]        = cStartNew     + (p  - cStart)*8     + r;
9397           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*8 + r;
9398           remotePointsNew[m].rank  = rrank;
9399         }
9400         for (r = 0; r < 8; ++r, ++m) {
9401           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*4     + (p  - cStart)*8     + r;
9402           remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*4 + (rp - rcStart[n])*8 + r;
9403           remotePointsNew[m].rank  = rrank;
9404         }
9405         localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (fMax                              - fStart)*3     + (p  - cStart)*1     + 0;
9406         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;
9407         remotePointsNew[m].rank  = rrank;
9408         ++m;
9409       } else if ((p >= cMax) && (p < cEnd)) {
9410         /* Hybrid cells add new cells and faces */
9411         for (r = 0; r < 4; ++r, ++m) {
9412           localPointsNew[m]        = cStartNew     + (cMax                            - cStart)*8     + (p  - cMax)*4                            + r;
9413           remotePointsNew[m].index = rcStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth] - rcStart[n])*8 + (rp - rdepthMaxOld[n*(depth+1)+depth])*4 + r;
9414           remotePointsNew[m].rank  = rrank;
9415         }
9416         for (r = 0; r < 3; ++r, ++m) {
9417           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*4     + (cMax                            - cStart)*8     + (fEnd                                          - fMax)*2                              + (p  - cMax)*3                            + r;
9418           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;
9419           remotePointsNew[m].rank  = rrank;
9420         }
9421       }
9422       break;
9423     case REFINER_HYBRID_SIMPLEX_TO_HEX_3D:
9424     case REFINER_SIMPLEX_TO_HEX_3D:
9425       if ((p >= vStart) && (p < vEnd)) {
9426         /* Interior vertices stay the same */
9427         localPointsNew[m]        = vStartNew     + (p  - vStart);
9428         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
9429         remotePointsNew[m].rank  = rrank;
9430         ++m;
9431       } else if ((p >= eStart) && (p < eMax)) {
9432         /* Interior edges add new edges and vertex */
9433         for (r = 0; r < 2; ++r, ++m) {
9434           localPointsNew[m]        = eStartNew     + (p  - eStart)*2     + r;
9435           remotePointsNew[m].index = reStartNew[n] + (rp - reStart[n])*2 + r;
9436           remotePointsNew[m].rank  = rrank;
9437         }
9438         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - eStart);
9439         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - reStart[n]);
9440         remotePointsNew[m].rank  = rrank;
9441         ++m;
9442       } else if ((p >= eMax) && (p < eEnd)) {
9443         /* Hybrid edges stay the same */
9444         localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (fMax                              - fStart)*3     + (cMax                            - cStart)*4     + (p  - eMax);
9445         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]);
9446         remotePointsNew[m].rank  = rrank;
9447         ++m;
9448       } else if ((p >= fStart) && (p < fMax)) {
9449         /* Interior faces add new faces, edges and a vertex */
9450         for (r = 0; r < 3; ++r, ++m) {
9451           localPointsNew[m]        = fStartNew     + (p  - fStart)*3     + r;
9452           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*3 + r;
9453           remotePointsNew[m].rank  = rrank;
9454         }
9455         for (r = 0; r < 3; ++r, ++m) {
9456           localPointsNew[m]        = eStartNew     + (eMax - eStart)*2                            + (p  - fStart)*3     + r;
9457           remotePointsNew[m].index = reStartNew[n] + (rdepthMaxOld[n*(depth+1)+1] - reStart[n])*2 + (rp - rfStart[n])*3 + r;
9458           remotePointsNew[m].rank  = rrank;
9459         }
9460         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (eMax - eStart)                            + (p - fStart);
9461         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rdepthMaxOld[n*(depth+1)+1] - reStart[n]) + (rp - rfStart[n]);
9462         remotePointsNew[m].rank  = rrank;
9463         ++m;
9464       } else if ((p >= fMax) && (p < fEnd)) {
9465         /* Interior hybrid faces add new faces and an edge */
9466         for (r = 0; r < 2; ++r, ++m) {
9467           localPointsNew[m]        = fStartNew     + (fMax - fStart)*3                                 + (cMax - cStart)*6                                + (p  - fMax)*2 + r;
9468           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;
9469           remotePointsNew[m].rank  = rrank;
9470         }
9471         localPointsNew[m]        = eStartNew     + (eMax - eStart)*2                            + (fMax - fStart)*3                                 + (cMax - cStart)*4                                + (eEnd - eMax)                                                           + (p  - fMax);
9472         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]);
9473         remotePointsNew[m].rank  = rrank;
9474         ++m;
9475       } else if ((p >= cStart) && (p < cMax)) {
9476         /* Interior cells add new cells, faces, edges, and a vertex */
9477         for (r = 0; r < 4; ++r, ++m) {
9478           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
9479           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
9480           remotePointsNew[m].rank  = rrank;
9481         }
9482         for (r = 0; r < 6; ++r, ++m) {
9483           localPointsNew[m]        = fStartNew     + (fMax - fStart)*3                                 + (p  - cStart)*6     + r;
9484           remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1]- rfStart[n])*3 + (rp - rcStart[n])*6 + r;
9485           remotePointsNew[m].rank  = rrank;
9486         }
9487         for (r = 0; r < 4; ++r, ++m) {
9488           localPointsNew[m]        = eStartNew     + (eMax - eStart)*2                           + (fMax - fStart)*3                                 + (p  - cStart)*4 + r;
9489           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;
9490           remotePointsNew[m].rank  = rrank;
9491         }
9492         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (eMax - eStart)                           + (fMax - fStart)                                 + (p  - cStart);
9493         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]);
9494         remotePointsNew[m].rank  = rrank;
9495         ++m;
9496       } else if ((p >= cMax) && (p < cEnd)) {
9497         /* Interior hybrid cells add new cells, faces and an edge */
9498         for (r = 0; r < 3; ++r, ++m) {
9499           localPointsNew[m]        = cStartNew     + (cMax                            - cStart)*4     + (p  - cMax)*3                            + r;
9500           remotePointsNew[m].index = rcStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth] - rcStart[n])*4 + (rp - rdepthMaxOld[n*(depth+1)+depth])*3 + r;
9501           remotePointsNew[m].rank  = rrank;
9502         }
9503         for (r = 0; r < 3; ++r, ++m) {
9504           localPointsNew[m]        = fStartNew     + (fMax - fStart)*3                                 + (cMax - cStart)*6                                + (fEnd  - fMax)*2                                                                      + (p  - cMax)*3 + r;
9505           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;
9506           remotePointsNew[m].rank  = rrank;
9507         }
9508         localPointsNew[m]        = eStartNew     + (eMax - eStart)*2                           + (fMax - fStart)*3                                 + (cMax - cStart)*4                                + (eEnd  - eMax)                                                          + (fEnd  - fMax)                                                                      + (p  - cMax);
9509         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]);
9510         remotePointsNew[m].rank  = rrank;
9511         ++m;
9512       }
9513       break;
9514     case REFINER_HEX_3D:
9515     case REFINER_HYBRID_HEX_3D:
9516       if ((p >= vStart) && (p < vEnd)) {
9517         /* Interior vertices stay the same */
9518         localPointsNew[m]        = vStartNew     + (p  - vStart);
9519         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
9520         remotePointsNew[m].rank  = rrank;
9521         ++m;
9522       } else if ((p >= eStart) && (p < eMax)) {
9523         /* Interior edges add new edges and vertex */
9524         for (r = 0; r < 2; ++r, ++m) {
9525           localPointsNew[m]        = eStartNew     + (p  - eStart)*2     + r;
9526           remotePointsNew[m].index = reStartNew[n] + (rp - reStart[n])*2 + r;
9527           remotePointsNew[m].rank  = rrank;
9528         }
9529         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - eStart);
9530         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - reStart[n]);
9531         remotePointsNew[m].rank  = rrank;
9532         ++m;
9533       } else if ((p >= eMax) && (p < eEnd)) {
9534         /* Hybrid edges stay the same */
9535         localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (fMax                              - fStart)*4     + (cMax                            - cStart)*6     + (p  - eMax);
9536         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]);
9537         remotePointsNew[m].rank  = rrank;
9538         ++m;
9539       } else if ((p >= fStart) && (p < fMax)) {
9540         /* Interior faces add new faces, edges, and vertex */
9541         for (r = 0; r < 4; ++r, ++m) {
9542           localPointsNew[m]        = fStartNew     + (p  - fStart)*4     + r;
9543           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*4 + r;
9544           remotePointsNew[m].rank  = rrank;
9545         }
9546         for (r = 0; r < 4; ++r, ++m) {
9547           localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (p  - fStart)*4     + r;
9548           remotePointsNew[m].index = reStartNew[n] + (rdepthMaxOld[n*(depth+1)+1] - reStart[n])*2 + (rp - rfStart[n])*4 + r;
9549           remotePointsNew[m].rank  = rrank;
9550         }
9551         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (eMax                        - eStart)     + (p  - fStart);
9552         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rdepthMaxOld[n*(depth+1)+1] - reStart[n]) + (rp - rfStart[n]);
9553         remotePointsNew[m].rank  = rrank;
9554         ++m;
9555       } else if ((p >= fMax) && (p < fEnd)) {
9556         /* Hybrid faces add new faces and edges */
9557         for (r = 0; r < 2; ++r, ++m) {
9558           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*4     + (cMax                            - cStart)*12     + (p  - fMax)*2                              + r;
9559           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;
9560           remotePointsNew[m].rank  = rrank;
9561         }
9562         localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (fMax                              - fStart)*4     + (cMax                            - cStart)*6     + (eEnd                                    - eMax)                        + (p  - fMax);
9563         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]);
9564         remotePointsNew[m].rank  = rrank;
9565         ++m;
9566       } else if ((p >= cStart) && (p < cMax)) {
9567         /* Interior cells add new cells, faces, edges, and vertex */
9568         for (r = 0; r < 8; ++r, ++m) {
9569           localPointsNew[m]        = cStartNew     + (p  - cStart)*8     + r;
9570           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*8 + r;
9571           remotePointsNew[m].rank  = rrank;
9572         }
9573         for (r = 0; r < 12; ++r, ++m) {
9574           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*4     + (p  - cStart)*12     + r;
9575           remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*4 + (rp - rcStart[n])*12 + r;
9576           remotePointsNew[m].rank  = rrank;
9577         }
9578         for (r = 0; r < 6; ++r, ++m) {
9579           localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (fMax                              - fStart)*4     + (p  - cStart)*6     + r;
9580           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;
9581           remotePointsNew[m].rank  = rrank;
9582         }
9583         for (r = 0; r < 1; ++r, ++m) {
9584           localPointsNew[m]        = vStartNew     + (eMax                        - eStart)     + (fMax                              - fStart)     + (p  - cStart)     + r;
9585           remotePointsNew[m].index = rvStartNew[n] + (rdepthMaxOld[n*(depth+1)+1] - reStart[n]) + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n]) + (rp - rcStart[n]) + r;
9586           remotePointsNew[m].rank  = rrank;
9587         }
9588       } else if ((p >= cMax) && (p < cEnd)) {
9589         /* Hybrid cells add new cells, faces, and edges */
9590         for (r = 0; r < 4; ++r, ++m) {
9591           localPointsNew[m]        = cStartNew     + (cMax                            - cStart)*8     + (p  - cMax)*4                            + r;
9592           remotePointsNew[m].index = rcStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth] - rcStart[n])*8 + (rp - rdepthMaxOld[n*(depth+1)+depth])*4 + r;
9593           remotePointsNew[m].rank  = rrank;
9594         }
9595         for (r = 0; r < 4; ++r, ++m) {
9596           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*4     + (cMax                            - cStart)*12     + (fEnd                                          - fMax)*2                              + (p  - cMax)*4                            + r;
9597           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;
9598           remotePointsNew[m].rank  = rrank;
9599         }
9600         localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (fMax                              - fStart)*4     + (cMax                            - cStart)*6     + (eEnd                                    - eMax)                        + (fEnd                                          - fMax)                              + (p  - cMax);
9601         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]);
9602         remotePointsNew[m].rank  = rrank;
9603         ++m;
9604       }
9605       break;
9606     default:
9607       SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %s", CellRefiners[refiner]);
9608     }
9609   }
9610   if (m != numLeavesNew) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Number of leaf point %D should be %D", m, numLeavesNew);
9611   ierr = ISRestoreIndices(processRanks, &neighbors);CHKERRQ(ierr);
9612   ierr = ISDestroy(&processRanks);CHKERRQ(ierr);
9613   {
9614     PetscSFNode *rp, *rtmp;
9615     PetscInt    *lp, *idx, *ltmp, i;
9616 
9617     /* SF needs sorted leaves to correct calculate Gather */
9618     ierr = PetscMalloc1(numLeavesNew,&idx);CHKERRQ(ierr);
9619     ierr = PetscMalloc1(numLeavesNew, &lp);CHKERRQ(ierr);
9620     ierr = PetscMalloc1(numLeavesNew, &rp);CHKERRQ(ierr);
9621     for (i = 0; i < numLeavesNew; ++i) {
9622       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);
9623       idx[i] = i;
9624     }
9625     ierr = PetscSortIntWithPermutation(numLeavesNew, localPointsNew, idx);CHKERRQ(ierr);
9626     for (i = 0; i < numLeavesNew; ++i) {
9627       lp[i] = localPointsNew[idx[i]];
9628       rp[i] = remotePointsNew[idx[i]];
9629     }
9630     ltmp            = localPointsNew;
9631     localPointsNew  = lp;
9632     rtmp            = remotePointsNew;
9633     remotePointsNew = rp;
9634     ierr = PetscFree(idx);CHKERRQ(ierr);
9635     ierr = PetscFree(ltmp);CHKERRQ(ierr);
9636     ierr = PetscFree(rtmp);CHKERRQ(ierr);
9637   }
9638   ierr = PetscSFSetGraph(sfNew, pEndNew-pStartNew, numLeavesNew, localPointsNew, PETSC_OWN_POINTER, remotePointsNew, PETSC_OWN_POINTER);CHKERRQ(ierr);
9639   ierr = PetscFree5(rdepthSize,rvStartNew,reStartNew,rfStartNew,rcStartNew);CHKERRQ(ierr);
9640   ierr = PetscFree7(depthSizeOld,rdepthSizeOld,rdepthMaxOld,rvStart,reStart,rfStart,rcStart);CHKERRQ(ierr);
9641   PetscFunctionReturn(0);
9642 }
9643 
9644 static PetscErrorCode CellRefinerCreateLabels(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
9645 {
9646   PetscInt       numLabels, l;
9647   PetscInt       depth, newp, cStart, cEnd, cMax, vStart, vEnd, vMax, fStart, fEnd, fMax, eStart, eEnd, eMax, r;
9648   PetscInt       cStartNew = 0, vStartNew = 0, fStartNew = 0, eStartNew = 0;
9649   PetscErrorCode ierr;
9650 
9651   PetscFunctionBegin;
9652   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
9653   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
9654   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
9655   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
9656   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
9657   if (refiner) {ierr = GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);CHKERRQ(ierr);}
9658   ierr = DMGetNumLabels(dm, &numLabels);CHKERRQ(ierr);
9659   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
9660   switch (refiner) {
9661   case REFINER_NOOP:
9662   case REFINER_SIMPLEX_1D:
9663   case REFINER_SIMPLEX_2D:
9664   case REFINER_SIMPLEX_TO_HEX_2D:
9665   case REFINER_HEX_2D:
9666   case REFINER_SIMPLEX_3D:
9667   case REFINER_HEX_3D:
9668   case REFINER_SIMPLEX_TO_HEX_3D:
9669     break;
9670   case REFINER_HYBRID_SIMPLEX_TO_HEX_3D:
9671   case REFINER_HYBRID_SIMPLEX_3D:
9672   case REFINER_HYBRID_HEX_3D:
9673     if (eMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No edge maximum specified in hybrid mesh");
9674   case REFINER_HYBRID_SIMPLEX_2D:
9675   case REFINER_HYBRID_HEX_2D:
9676     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
9677   case REFINER_HYBRID_SIMPLEX_TO_HEX_2D:
9678     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
9679     break;
9680   default:
9681     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %s", CellRefiners[refiner]);
9682   }
9683   cMax = cMax < 0 ? cEnd : cMax;
9684   fMax = fMax < 0 ? fEnd : fMax;
9685   eMax = eMax < 0 ? eEnd : eMax;
9686   for (l = 0; l < numLabels; ++l) {
9687     DMLabel         label, labelNew;
9688     const char     *lname;
9689     PetscBool       isDepth;
9690     IS              valueIS;
9691     const PetscInt *values;
9692     PetscInt        defVal;
9693     PetscInt        numValues, val;
9694 
9695     ierr = DMGetLabelName(dm, l, &lname);CHKERRQ(ierr);
9696     ierr = PetscStrcmp(lname, "depth", &isDepth);CHKERRQ(ierr);
9697     if (isDepth) continue;
9698     ierr = DMCreateLabel(rdm, lname);CHKERRQ(ierr);
9699     ierr = DMGetLabel(dm, lname, &label);CHKERRQ(ierr);
9700     ierr = DMGetLabel(rdm, lname, &labelNew);CHKERRQ(ierr);
9701     ierr = DMLabelGetDefaultValue(label,&defVal);CHKERRQ(ierr);
9702     ierr = DMLabelSetDefaultValue(labelNew,defVal);CHKERRQ(ierr);
9703     ierr = DMLabelGetValueIS(label, &valueIS);CHKERRQ(ierr);
9704     ierr = ISGetLocalSize(valueIS, &numValues);CHKERRQ(ierr);
9705     ierr = ISGetIndices(valueIS, &values);CHKERRQ(ierr);
9706     for (val = 0; val < numValues; ++val) {
9707       IS              pointIS;
9708       const PetscInt *points;
9709       PetscInt        numPoints, n;
9710 
9711       ierr = DMLabelGetStratumIS(label, values[val], &pointIS);CHKERRQ(ierr);
9712       ierr = ISGetLocalSize(pointIS, &numPoints);CHKERRQ(ierr);
9713       ierr = ISGetIndices(pointIS, &points);CHKERRQ(ierr);
9714       /* Ensure refined label is created with same number of strata as
9715        * original (even if no entries here). */
9716       ierr = DMLabelAddStratum(labelNew, values[val]);CHKERRQ(ierr);
9717       for (n = 0; n < numPoints; ++n) {
9718         const PetscInt p = points[n];
9719         switch (refiner) {
9720         case REFINER_SIMPLEX_1D:
9721           if ((p >= vStart) && (p < vEnd)) {
9722             /* Old vertices stay the same */
9723             newp = vStartNew + (p - vStart);
9724             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9725           } else if ((p >= cStart) && (p < cEnd)) {
9726             /* Old cells add new cells and vertex */
9727             newp = vStartNew + (vEnd - vStart) + (p - cStart);
9728             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9729             for (r = 0; r < 2; ++r) {
9730               newp = cStartNew + (p - cStart)*2 + r;
9731               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9732             }
9733           }
9734           break;
9735         case REFINER_SIMPLEX_2D:
9736           if ((p >= vStart) && (p < vEnd)) {
9737             /* Old vertices stay the same */
9738             newp = vStartNew + (p - vStart);
9739             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9740           } else if ((p >= fStart) && (p < fEnd)) {
9741             /* Old faces add new faces and vertex */
9742             newp = vStartNew + (vEnd - vStart) + (p - fStart);
9743             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9744             for (r = 0; r < 2; ++r) {
9745               newp = fStartNew + (p - fStart)*2 + r;
9746               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9747             }
9748           } else if ((p >= cStart) && (p < cEnd)) {
9749             /* Old cells add new cells and interior faces */
9750             for (r = 0; r < 4; ++r) {
9751               newp = cStartNew + (p - cStart)*4 + r;
9752               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9753             }
9754             for (r = 0; r < 3; ++r) {
9755               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*3 + r;
9756               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9757             }
9758           }
9759           break;
9760         case REFINER_HYBRID_SIMPLEX_TO_HEX_2D:
9761         case REFINER_SIMPLEX_TO_HEX_2D:
9762           if ((p >= vStart) && (p < vEnd)) {
9763             /* Old vertices stay the same */
9764             newp = vStartNew + (p - vStart);
9765             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9766           } else if ((p >= fStart) && (p < fEnd)) {
9767             /* Old faces add new faces and vertex */
9768             newp = vStartNew + (vEnd - vStart) + (p - fStart);
9769             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9770             for (r = 0; r < 2; ++r) {
9771               newp = fStartNew + (p - fStart)*2 + r;
9772               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9773             }
9774           } else if ((p >= cStart) && (p < cMax)) {
9775             /* Old cells add new cells, interior faces, and a vertex */
9776             for (r = 0; r < 3; ++r) {
9777               newp = cStartNew + (p - cStart)*3 + r;
9778               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9779             }
9780             for (r = 0; r < 3; ++r) {
9781               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*3 + r;
9782               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9783             }
9784             newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + p;
9785             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9786           } else if ((p >= cMax) && (p < cEnd)) {
9787             /* Old hybrid cells add new cells, interior faces, and a vertex */
9788             for (r = 0; r < 4; ++r) {
9789               newp = cStartNew + (cMax - cStart)*3 + (p - cMax)*4 + r;
9790               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9791             }
9792             for (r = 0; r < 4; ++r) {
9793               newp = fStartNew + (fEnd - fStart)*2 + (cMax - cStart)*3 + (p - cMax)*4 + r;
9794               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9795             }
9796             newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + p;
9797             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9798           }
9799           break;
9800         case REFINER_HEX_2D:
9801           if ((p >= vStart) && (p < vEnd)) {
9802             /* Old vertices stay the same */
9803             newp = vStartNew + (p - vStart);
9804             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9805           } else if ((p >= fStart) && (p < fEnd)) {
9806             /* Old faces add new faces and vertex */
9807             newp = vStartNew + (vEnd - vStart) + (p - fStart);
9808             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9809             for (r = 0; r < 2; ++r) {
9810               newp = fStartNew + (p - fStart)*2 + r;
9811               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9812             }
9813           } else if ((p >= cStart) && (p < cEnd)) {
9814             /* Old cells add new cells and interior faces and vertex */
9815             for (r = 0; r < 4; ++r) {
9816               newp = cStartNew + (p - cStart)*4 + r;
9817               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9818             }
9819             for (r = 0; r < 4; ++r) {
9820               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*4 + r;
9821               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9822             }
9823             newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (p - cStart);
9824             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9825           }
9826           break;
9827         case REFINER_HYBRID_SIMPLEX_2D:
9828           if ((p >= vStart) && (p < vEnd)) {
9829             /* Old vertices stay the same */
9830             newp = vStartNew + (p - vStart);
9831             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9832           } else if ((p >= fStart) && (p < fMax)) {
9833             /* Old interior faces add new faces and vertex */
9834             newp = vStartNew + (vEnd - vStart) + (p - fStart);
9835             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9836             for (r = 0; r < 2; ++r) {
9837               newp = fStartNew + (p - fStart)*2 + r;
9838               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9839             }
9840           } else if ((p >= fMax) && (p < fEnd)) {
9841             /* Old hybrid faces stay the same */
9842             newp = fStartNew + (fMax - fStart)*2 + (p - fMax);
9843             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9844           } else if ((p >= cStart) && (p < cMax)) {
9845             /* Old interior cells add new cells and interior faces */
9846             for (r = 0; r < 4; ++r) {
9847               newp = cStartNew + (p - cStart)*4 + r;
9848               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9849             }
9850             for (r = 0; r < 3; ++r) {
9851               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*3 + r;
9852               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9853             }
9854           } else if ((p >= cMax) && (p < cEnd)) {
9855             /* Old hybrid cells add new cells and hybrid face */
9856             for (r = 0; r < 2; ++r) {
9857               newp = cStartNew + (cMax - cStart)*4 + (p - cMax)*2 + r;
9858               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9859             }
9860             newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (p - cMax);
9861             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9862           }
9863           break;
9864         case REFINER_HYBRID_HEX_2D:
9865           if ((p >= vStart) && (p < vEnd)) {
9866             /* Old vertices stay the same */
9867             newp = vStartNew + (p - vStart);
9868             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9869           } else if ((p >= fStart) && (p < fMax)) {
9870             /* Old interior faces add new faces and vertex */
9871             newp = vStartNew + (vEnd - vStart) + (p - fStart);
9872             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9873             for (r = 0; r < 2; ++r) {
9874               newp = fStartNew + (p - fStart)*2 + r;
9875               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9876             }
9877           } else if ((p >= fMax) && (p < fEnd)) {
9878             /* Old hybrid faces stay the same */
9879             newp = fStartNew + (fMax - fStart)*2 + (p - fMax);
9880             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9881           } else if ((p >= cStart) && (p < cMax)) {
9882             /* Old interior cells add new cells, interior faces, and vertex */
9883             for (r = 0; r < 4; ++r) {
9884               newp = cStartNew + (p - cStart)*4 + r;
9885               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9886             }
9887             for (r = 0; r < 4; ++r) {
9888               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*4 + r;
9889               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9890             }
9891             newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (p - cStart);
9892             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9893           } else if ((p >= cMax) && (p < cEnd)) {
9894             /* Old hybrid cells add new cells and hybrid face */
9895             for (r = 0; r < 2; ++r) {
9896               newp = cStartNew + (cMax - cStart)*4 + (p - cMax)*2 + r;
9897               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9898             }
9899             newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*4 + (p - cMax);
9900             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9901           }
9902           break;
9903         case REFINER_SIMPLEX_3D:
9904           if ((p >= vStart) && (p < vEnd)) {
9905             /* Old vertices stay the same */
9906             newp = vStartNew + (p - vStart);
9907             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9908           } else if ((p >= eStart) && (p < eEnd)) {
9909             /* Old edges add new edges and vertex */
9910             for (r = 0; r < 2; ++r) {
9911               newp = eStartNew + (p - eStart)*2 + r;
9912               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9913             }
9914             newp = vStartNew + (vEnd - vStart) + (p - eStart);
9915             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9916           } else if ((p >= fStart) && (p < fEnd)) {
9917             /* Old faces add new faces and edges */
9918             for (r = 0; r < 4; ++r) {
9919               newp = fStartNew + (p - fStart)*4 + r;
9920               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9921             }
9922             for (r = 0; r < 3; ++r) {
9923               newp = eStartNew + (eEnd - eStart)*2 + (p - fStart)*3 + r;
9924               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9925             }
9926           } else if ((p >= cStart) && (p < cEnd)) {
9927             /* Old cells add new cells and interior faces and edges */
9928             for (r = 0; r < 8; ++r) {
9929               newp = cStartNew + (p - cStart)*8 + r;
9930               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9931             }
9932             for (r = 0; r < 8; ++r) {
9933               newp = fStartNew + (fEnd - fStart)*4 + (p - cStart)*8 + r;
9934               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9935             }
9936             for (r = 0; r < 1; ++r) {
9937               newp = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (p - cStart)*1 + r;
9938               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9939             }
9940           }
9941           break;
9942         case REFINER_HYBRID_SIMPLEX_TO_HEX_3D:
9943         case REFINER_SIMPLEX_TO_HEX_3D:
9944           if ((p >= vStart) && (p < vEnd)) {
9945             /* Old vertices stay the same */
9946             newp = vStartNew + (p - vStart);
9947             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9948           } else if ((p >= eStart) && (p < eMax)) {
9949             /* Interior edges add new edges and vertex */
9950             for (r = 0; r < 2; ++r) {
9951               newp = eStartNew + (p - eStart)*2 + r;
9952               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9953             }
9954             newp = vStartNew + (vEnd - vStart) + (p - eStart);
9955             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9956           } else if ((p >= eMax) && (p < eEnd)) {
9957             /* Hybrid edges stay the same */
9958             newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart)*4 + p - eMax;
9959             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9960           } else if ((p >= fStart) && (p < fMax)) {
9961             /* Old faces add new faces, edges and a vertex */
9962             for (r = 0; r < 3; ++r) {
9963               newp = fStartNew + (p - fStart)*3 + r;
9964               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9965             }
9966             for (r = 0; r < 3; ++r) {
9967               newp = eStartNew + (eMax - eStart)*2 + (p - fStart)*3 + r;
9968               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9969             }
9970           } else if ((p >= fMax) && (p < fEnd)) {
9971             /* Old hybrid faces add new faces and an edge */
9972             for (r = 0; r < 2; ++r) {
9973               newp = fStartNew + (fMax - fStart)*3 + (cMax - cStart)*6 + (p - fMax)*2 + r;
9974               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9975             }
9976             newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart)*4 + (eEnd - eMax) + (p - fMax);
9977             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9978           } else if ((p >= cStart) && (p < cMax)) {
9979             /* Old cells add new cells and interior faces and edges and a vertex */
9980             for (r = 0; r < 4; ++r) {
9981               newp = cStartNew + (p - cStart)*4 + r;
9982               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9983             }
9984             for (r = 0; r < 6; ++r) {
9985               newp = fStartNew + (fMax - fStart)*3 + (p - cStart)*6 + r;
9986               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9987             }
9988             for (r = 0; r < 4; ++r) {
9989               newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (p - cStart)*4 + r;
9990               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9991             }
9992             newp = vStartNew + (vEnd - vStart) + (eMax - eStart) + (fMax - fStart) + p - cStart;
9993             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9994           } else if ((p >= cMax) && (p < cEnd)) {
9995             /* Old hybrid cells add new cells and interior faces and an edge */
9996             for (r = 0; r < 3; ++r) {
9997               newp = cStartNew + (cMax - cStart)*4 + (p - cMax)*3 + r;
9998               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9999             }
10000             for (r = 0; r < 3; ++r) {
10001               newp = fStartNew + (fMax - fStart)*3 + (cMax - cStart)*6 + (fEnd - fMax)*2 + (p - cMax)*3 + r;
10002               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
10003             }
10004             newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart)*4 + (eEnd - eMax) + (fEnd - fMax) + p - cMax;
10005             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
10006           }
10007           break;
10008         case REFINER_HYBRID_SIMPLEX_3D:
10009           if ((p >= vStart) && (p < vEnd)) {
10010             /* Interior vertices stay the same */
10011             newp = vStartNew + (p - vStart);
10012             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
10013           } else if ((p >= eStart) && (p < eMax)) {
10014             /* Interior edges add new edges and vertex */
10015             for (r = 0; r < 2; ++r) {
10016               newp = eStartNew + (p - eStart)*2 + r;
10017               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
10018             }
10019             newp = vStartNew + (vEnd - vStart) + (p - eStart);
10020             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
10021           } else if ((p >= eMax) && (p < eEnd)) {
10022             /* Hybrid edges stay the same */
10023             newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (p - eMax);
10024             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
10025           } else if ((p >= fStart) && (p < fMax)) {
10026             /* Interior faces add new faces and edges */
10027             for (r = 0; r < 4; ++r) {
10028               newp = fStartNew + (p - fStart)*4 + r;
10029               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
10030             }
10031             for (r = 0; r < 3; ++r) {
10032               newp = eStartNew + (eMax - eStart)*2 + (p - fStart)*3 + r;
10033               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
10034             }
10035           } else if ((p >= fMax) && (p < fEnd)) {
10036             /* Hybrid faces add new faces and edges */
10037             for (r = 0; r < 2; ++r) {
10038               newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (p - fMax)*2 + r;
10039               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
10040             }
10041             newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (p - fMax);
10042             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
10043           } else if ((p >= cStart) && (p < cMax)) {
10044             /* Interior cells add new cells, faces, and edges */
10045             for (r = 0; r < 8; ++r) {
10046               newp = cStartNew + (p - cStart)*8 + r;
10047               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
10048             }
10049             for (r = 0; r < 8; ++r) {
10050               newp = fStartNew + (fMax - fStart)*4 + (p - cStart)*8 + r;
10051               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
10052             }
10053             newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (p - cStart);
10054             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
10055           } else if ((p >= cMax) && (p < cEnd)) {
10056             /* Hybrid cells add new cells and faces */
10057             for (r = 0; r < 4; ++r) {
10058               newp = cStartNew + (cMax - cStart)*8 + (p - cMax)*4 + r;
10059               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
10060             }
10061             for (r = 0; r < 3; ++r) {
10062               newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (p - cMax)*3 + r;
10063               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
10064             }
10065           }
10066           break;
10067         case REFINER_HEX_3D:
10068           if ((p >= vStart) && (p < vEnd)) {
10069             /* Old vertices stay the same */
10070             newp = vStartNew + (p - vStart);
10071             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
10072           } else if ((p >= eStart) && (p < eEnd)) {
10073             /* Old edges add new edges and vertex */
10074             for (r = 0; r < 2; ++r) {
10075               newp = eStartNew + (p - eStart)*2 + r;
10076               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
10077             }
10078             newp = vStartNew + (vEnd - vStart) + (p - eStart);
10079             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
10080           } else if ((p >= fStart) && (p < fEnd)) {
10081             /* Old faces add new faces, edges, and vertex */
10082             for (r = 0; r < 4; ++r) {
10083               newp = fStartNew + (p - fStart)*4 + r;
10084               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
10085             }
10086             for (r = 0; r < 4; ++r) {
10087               newp = eStartNew + (eEnd - eStart)*2 + (p - fStart)*4 + r;
10088               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
10089             }
10090             newp = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (p - fStart);
10091             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
10092           } else if ((p >= cStart) && (p < cEnd)) {
10093             /* Old cells add new cells, faces, edges, and vertex */
10094             for (r = 0; r < 8; ++r) {
10095               newp = cStartNew + (p - cStart)*8 + r;
10096               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
10097             }
10098             for (r = 0; r < 12; ++r) {
10099               newp = fStartNew + (fEnd - fStart)*4 + (p - cStart)*12 + r;
10100               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
10101             }
10102             for (r = 0; r < 6; ++r) {
10103               newp = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*4 + (p - cStart)*6 + r;
10104               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
10105             }
10106             newp = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (fEnd - fStart) + (p - cStart);
10107             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
10108           }
10109           break;
10110         case REFINER_HYBRID_HEX_3D:
10111           if ((p >= vStart) && (p < vEnd)) {
10112             /* Interior vertices stay the same */
10113             newp = vStartNew + (p - vStart);
10114             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
10115           } else if ((p >= eStart) && (p < eMax)) {
10116             /* Interior edges add new edges and vertex */
10117             for (r = 0; r < 2; ++r) {
10118               newp = eStartNew + (p - eStart)*2 + r;
10119               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
10120             }
10121             newp = vStartNew + (vEnd - vStart) + (p - eStart);
10122             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
10123           } else if ((p >= eMax) && (p < eEnd)) {
10124             /* Hybrid edges stay the same */
10125             newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (p - eMax);
10126             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
10127           } else if ((p >= fStart) && (p < fMax)) {
10128             /* Interior faces add new faces, edges, and vertex */
10129             for (r = 0; r < 4; ++r) {
10130               newp = fStartNew + (p - fStart)*4 + r;
10131               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
10132             }
10133             for (r = 0; r < 4; ++r) {
10134               newp = eStartNew + (eMax - eStart)*2 + (p - fStart)*4 + r;
10135               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
10136             }
10137             newp = vStartNew + (vEnd - vStart) + (eMax - eStart) + (p - fStart);
10138             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
10139           } else if ((p >= fMax) && (p < fEnd)) {
10140             /* Hybrid faces add new faces and edges */
10141             for (r = 0; r < 2; ++r) {
10142               newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (p - fMax)*2 + r;
10143               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
10144             }
10145             newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (p - fMax);
10146             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
10147           } else if ((p >= cStart) && (p < cMax)) {
10148             /* Interior cells add new cells, faces, edges, and vertex */
10149             for (r = 0; r < 8; ++r) {
10150               newp = cStartNew + (p - cStart)*8 + r;
10151               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
10152             }
10153             for (r = 0; r < 12; ++r) {
10154               newp = fStartNew + (fMax - fStart)*4 + (p - cStart)*12 + r;
10155               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
10156             }
10157             for (r = 0; r < 6; ++r) {
10158               newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (p - cStart)*6 + r;
10159               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
10160             }
10161             newp = vStartNew + (vEnd - vStart) + (eMax - eStart) + (fMax - fStart) + (p - cStart);
10162             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
10163           } else if ((p >= cMax) && (p < cEnd)) {
10164             /* Hybrid cells add new cells, faces, and edges */
10165             for (r = 0; r < 4; ++r) {
10166               newp = cStartNew + (cMax - cStart)*8 + (p - cMax)*4 + r;
10167               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
10168             }
10169             for (r = 0; r < 4; ++r) {
10170               newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd - fMax)*2 + (p - cMax)*4 + r;
10171               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
10172             }
10173             newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (fEnd - fMax) + (p - cMax);
10174             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
10175           }
10176           break;
10177         default:
10178           SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %s", CellRefiners[refiner]);
10179         }
10180       }
10181       ierr = ISRestoreIndices(pointIS, &points);CHKERRQ(ierr);
10182       ierr = ISDestroy(&pointIS);CHKERRQ(ierr);
10183     }
10184     ierr = ISRestoreIndices(valueIS, &values);CHKERRQ(ierr);
10185     ierr = ISDestroy(&valueIS);CHKERRQ(ierr);
10186   }
10187   PetscFunctionReturn(0);
10188 }
10189 
10190 /* This will only work for interpolated meshes */
10191 PetscErrorCode DMPlexRefineUniform_Internal(DM dm, CellRefiner cellRefiner, DM *dmRefined)
10192 {
10193   DM             rdm;
10194   PetscInt      *depthSize;
10195   PetscInt       dim, embedDim, depth = 0, d, pStart = 0, pEnd = 0;
10196   PetscErrorCode ierr;
10197 
10198   PetscFunctionBegin;
10199   ierr = DMCreate(PetscObjectComm((PetscObject)dm), &rdm);CHKERRQ(ierr);
10200   ierr = DMSetType(rdm, DMPLEX);CHKERRQ(ierr);
10201   ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr);
10202   ierr = DMSetDimension(rdm, dim);CHKERRQ(ierr);
10203   ierr = DMGetCoordinateDim(dm, &embedDim);CHKERRQ(ierr);
10204   ierr = DMSetCoordinateDim(rdm, embedDim);CHKERRQ(ierr);
10205   /* Calculate number of new points of each depth */
10206   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
10207   if (depth >= 0 && dim != depth) SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "Mesh must be interpolated for regular refinement");
10208   ierr = PetscMalloc1(depth+1, &depthSize);CHKERRQ(ierr);
10209   ierr = PetscMemzero(depthSize, (depth+1) * sizeof(PetscInt));CHKERRQ(ierr);
10210   ierr = CellRefinerGetSizes(cellRefiner, dm, depthSize);CHKERRQ(ierr);
10211   /* Step 1: Set chart */
10212   for (d = 0; d <= depth; ++d) pEnd += depthSize[d];
10213   ierr = DMPlexSetChart(rdm, pStart, pEnd);CHKERRQ(ierr);
10214   /* Step 2: Set cone/support sizes (automatically stratifies) */
10215   ierr = CellRefinerSetConeSizes(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
10216   /* Step 3: Setup refined DM */
10217   ierr = DMSetUp(rdm);CHKERRQ(ierr);
10218   /* Step 4: Set cones and supports (automatically symmetrizes) */
10219   ierr = CellRefinerSetCones(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
10220   /* Step 5: Create pointSF */
10221   ierr = CellRefinerCreateSF(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
10222   /* Step 6: Create labels */
10223   ierr = CellRefinerCreateLabels(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
10224   /* Step 7: Set coordinates */
10225   ierr = CellRefinerSetCoordinates(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
10226   ierr = PetscFree(depthSize);CHKERRQ(ierr);
10227 
10228   *dmRefined = rdm;
10229   PetscFunctionReturn(0);
10230 }
10231 
10232 /*@
10233   DMPlexCreateCoarsePointIS - Creates an IS covering the coarse DM chart with the fine points as data
10234 
10235   Input Parameter:
10236 . dm - The coarse DM
10237 
10238   Output Parameter:
10239 . fpointIS - The IS of all the fine points which exist in the original coarse mesh
10240 
10241   Level: developer
10242 
10243 .seealso: DMRefine(), DMPlexSetRefinementUniform(), DMPlexCreateSubpointIS()
10244 @*/
10245 PetscErrorCode DMPlexCreateCoarsePointIS(DM dm, IS *fpointIS)
10246 {
10247   CellRefiner    cellRefiner;
10248   PetscInt      *depthSize, *fpoints;
10249   PetscInt       cStartNew = 0, vStartNew = 0, fStartNew = 0, eStartNew = 0;
10250   PetscInt       depth, pStart, pEnd, p, vStart, vEnd, v;
10251   PetscErrorCode ierr;
10252 
10253   PetscFunctionBegin;
10254   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
10255   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
10256   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
10257   ierr = DMPlexGetCellRefiner_Internal(dm, &cellRefiner);CHKERRQ(ierr);
10258   ierr = PetscMalloc1(depth+1, &depthSize);CHKERRQ(ierr);
10259   ierr = CellRefinerGetSizes(cellRefiner, dm, depthSize);CHKERRQ(ierr);
10260   if (cellRefiner) {ierr = GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);CHKERRQ(ierr);}
10261   ierr = PetscMalloc1(pEnd-pStart,&fpoints);CHKERRQ(ierr);
10262   for (p = 0; p < pEnd-pStart; ++p) fpoints[p] = -1;
10263   switch (cellRefiner) {
10264   case REFINER_SIMPLEX_1D:
10265   case REFINER_SIMPLEX_2D:
10266   case REFINER_HYBRID_SIMPLEX_2D:
10267   case REFINER_HEX_2D:
10268   case REFINER_HYBRID_HEX_2D:
10269   case REFINER_SIMPLEX_3D:
10270   case REFINER_HYBRID_SIMPLEX_3D:
10271   case REFINER_HEX_3D:
10272   case REFINER_HYBRID_HEX_3D:
10273     for (v = vStart; v < vEnd; ++v) fpoints[v-pStart] = vStartNew + (v - vStart);
10274     break;
10275   default:
10276     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %s", CellRefiners[cellRefiner]);
10277   }
10278   ierr = ISCreateGeneral(PETSC_COMM_SELF, pEnd-pStart, fpoints, PETSC_OWN_POINTER, fpointIS);CHKERRQ(ierr);
10279   ierr = PetscFree(depthSize);CHKERRQ(ierr);
10280   PetscFunctionReturn(0);
10281 }
10282 
10283 /*@
10284   DMPlexSetRefinementUniform - Set the flag for uniform refinement
10285 
10286   Input Parameters:
10287 + dm - The DM
10288 - refinementUniform - The flag for uniform refinement
10289 
10290   Level: developer
10291 
10292 .seealso: DMRefine(), DMPlexGetRefinementUniform(), DMPlexGetRefinementLimit(), DMPlexSetRefinementLimit()
10293 @*/
10294 PetscErrorCode DMPlexSetRefinementUniform(DM dm, PetscBool refinementUniform)
10295 {
10296   DM_Plex *mesh = (DM_Plex*) dm->data;
10297 
10298   PetscFunctionBegin;
10299   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
10300   mesh->refinementUniform = refinementUniform;
10301   PetscFunctionReturn(0);
10302 }
10303 
10304 /*@
10305   DMPlexGetRefinementUniform - Retrieve the flag for uniform refinement
10306 
10307   Input Parameter:
10308 . dm - The DM
10309 
10310   Output Parameter:
10311 . refinementUniform - The flag for uniform refinement
10312 
10313   Level: developer
10314 
10315 .seealso: DMRefine(), DMPlexSetRefinementUniform(), DMPlexGetRefinementLimit(), DMPlexSetRefinementLimit()
10316 @*/
10317 PetscErrorCode DMPlexGetRefinementUniform(DM dm, PetscBool *refinementUniform)
10318 {
10319   DM_Plex *mesh = (DM_Plex*) dm->data;
10320 
10321   PetscFunctionBegin;
10322   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
10323   PetscValidPointer(refinementUniform,  2);
10324   *refinementUniform = mesh->refinementUniform;
10325   PetscFunctionReturn(0);
10326 }
10327 
10328 /*@
10329   DMPlexSetRefinementLimit - Set the maximum cell volume for refinement
10330 
10331   Input Parameters:
10332 + dm - The DM
10333 - refinementLimit - The maximum cell volume in the refined mesh
10334 
10335   Level: developer
10336 
10337 .seealso: DMRefine(), DMPlexGetRefinementLimit(), DMPlexGetRefinementUniform(), DMPlexSetRefinementUniform()
10338 @*/
10339 PetscErrorCode DMPlexSetRefinementLimit(DM dm, PetscReal refinementLimit)
10340 {
10341   DM_Plex *mesh = (DM_Plex*) dm->data;
10342 
10343   PetscFunctionBegin;
10344   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
10345   mesh->refinementLimit = refinementLimit;
10346   PetscFunctionReturn(0);
10347 }
10348 
10349 /*@
10350   DMPlexGetRefinementLimit - Retrieve the maximum cell volume for refinement
10351 
10352   Input Parameter:
10353 . dm - The DM
10354 
10355   Output Parameter:
10356 . refinementLimit - The maximum cell volume in the refined mesh
10357 
10358   Level: developer
10359 
10360 .seealso: DMRefine(), DMPlexSetRefinementLimit(), DMPlexGetRefinementUniform(), DMPlexSetRefinementUniform()
10361 @*/
10362 PetscErrorCode DMPlexGetRefinementLimit(DM dm, PetscReal *refinementLimit)
10363 {
10364   DM_Plex *mesh = (DM_Plex*) dm->data;
10365 
10366   PetscFunctionBegin;
10367   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
10368   PetscValidPointer(refinementLimit,  2);
10369   /* if (mesh->refinementLimit < 0) = getMaxVolume()/2.0; */
10370   *refinementLimit = mesh->refinementLimit;
10371   PetscFunctionReturn(0);
10372 }
10373 
10374 /*@
10375   DMPlexSetRefinementFunction - Set the function giving the maximum cell volume for refinement
10376 
10377   Input Parameters:
10378 + dm - The DM
10379 - refinementFunc - Function giving the maximum cell volume in the refined mesh
10380 
10381   Note: The calling sequence is refinementFunc(coords, limit)
10382 $ coords - Coordinates of the current point, usually a cell centroid
10383 $ limit  - The maximum cell volume for a cell containing this point
10384 
10385   Level: developer
10386 
10387 .seealso: DMRefine(), DMPlexGetRefinementFunction(), DMPlexGetRefinementUniform(), DMPlexSetRefinementUniform(), DMPlexGetRefinementLimit(), DMPlexSetRefinementLimit()
10388 @*/
10389 PetscErrorCode DMPlexSetRefinementFunction(DM dm, PetscErrorCode (*refinementFunc)(const PetscReal [], PetscReal *))
10390 {
10391   DM_Plex *mesh = (DM_Plex*) dm->data;
10392 
10393   PetscFunctionBegin;
10394   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
10395   mesh->refinementFunc = refinementFunc;
10396   PetscFunctionReturn(0);
10397 }
10398 
10399 /*@
10400   DMPlexGetRefinementFunction - Get the function giving the maximum cell volume for refinement
10401 
10402   Input Parameter:
10403 . dm - The DM
10404 
10405   Output Parameter:
10406 . refinementFunc - Function giving the maximum cell volume in the refined mesh
10407 
10408   Note: The calling sequence is refinementFunc(coords, limit)
10409 $ coords - Coordinates of the current point, usually a cell centroid
10410 $ limit  - The maximum cell volume for a cell containing this point
10411 
10412   Level: developer
10413 
10414 .seealso: DMRefine(), DMPlexSetRefinementFunction(), DMPlexGetRefinementUniform(), DMPlexSetRefinementUniform(), DMPlexGetRefinementLimit(), DMPlexSetRefinementLimit()
10415 @*/
10416 PetscErrorCode DMPlexGetRefinementFunction(DM dm, PetscErrorCode (**refinementFunc)(const PetscReal [], PetscReal *))
10417 {
10418   DM_Plex *mesh = (DM_Plex*) dm->data;
10419 
10420   PetscFunctionBegin;
10421   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
10422   PetscValidPointer(refinementFunc,  2);
10423   *refinementFunc = mesh->refinementFunc;
10424   PetscFunctionReturn(0);
10425 }
10426 
10427 PetscErrorCode DMPlexGetCellRefiner_Internal(DM dm, CellRefiner *cellRefiner)
10428 {
10429   PetscInt       dim, cStart, cEnd, coneSize, cMax, fMax;
10430   PetscErrorCode ierr;
10431 
10432   PetscFunctionBegin;
10433   ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr);
10434   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
10435   if (cEnd <= cStart) {*cellRefiner = REFINER_NOOP; PetscFunctionReturn(0);}
10436   ierr = DMPlexGetConeSize(dm, cStart, &coneSize);CHKERRQ(ierr);
10437   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, NULL, NULL);CHKERRQ(ierr);
10438   switch (dim) {
10439   case 1:
10440     switch (coneSize) {
10441     case 2:
10442       *cellRefiner = REFINER_SIMPLEX_1D;
10443       break;
10444     default:
10445       SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown coneSize %D in dimension %D for cell refiner", coneSize, dim);
10446     }
10447     break;
10448   case 2:
10449     switch (coneSize) {
10450     case 3:
10451       if (cMax >= 0) *cellRefiner = REFINER_HYBRID_SIMPLEX_2D;
10452       else *cellRefiner = REFINER_SIMPLEX_2D;
10453       break;
10454     case 4:
10455       if (cMax >= 0 && fMax >= 0) *cellRefiner = REFINER_HYBRID_HEX_2D;
10456       else *cellRefiner = REFINER_HEX_2D;
10457       break;
10458     default:
10459       SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown coneSize %D in dimension %D for cell refiner", coneSize, dim);
10460     }
10461     break;
10462   case 3:
10463     switch (coneSize) {
10464     case 4:
10465       if (cMax >= 0) *cellRefiner = REFINER_HYBRID_SIMPLEX_3D;
10466       else *cellRefiner = REFINER_SIMPLEX_3D;
10467       break;
10468     case 5:
10469       if (cMax == 0) *cellRefiner = REFINER_HYBRID_SIMPLEX_3D;
10470       else SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown coneSize %D in dimension %D for cell refiner", coneSize, dim);
10471       break;
10472     case 6:
10473       if (cMax >= 0) *cellRefiner = REFINER_HYBRID_HEX_3D;
10474       else *cellRefiner = REFINER_HEX_3D;
10475       break;
10476     default:
10477       SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown coneSize %D in dimension %D for cell refiner", coneSize, dim);
10478     }
10479     break;
10480   default:
10481     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown dimension %D for cell refiner", dim);
10482   }
10483   PetscFunctionReturn(0);
10484 }
10485 
10486 PetscErrorCode DMRefine_Plex(DM dm, MPI_Comm comm, DM *dmRefined)
10487 {
10488   PetscBool      isUniform;
10489   PetscErrorCode ierr;
10490 
10491   PetscFunctionBegin;
10492   ierr = DMPlexGetRefinementUniform(dm, &isUniform);CHKERRQ(ierr);
10493   if (isUniform) {
10494     CellRefiner cellRefiner;
10495     PetscBool   localized;
10496 
10497     ierr = DMGetCoordinatesLocalized(dm, &localized);CHKERRQ(ierr);
10498     ierr = DMPlexGetCellRefiner_Internal(dm, &cellRefiner);CHKERRQ(ierr);
10499     ierr = DMPlexRefineUniform_Internal(dm, cellRefiner, dmRefined);CHKERRQ(ierr);
10500     ierr = DMPlexSetRegularRefinement(*dmRefined, PETSC_TRUE);CHKERRQ(ierr);
10501     ierr = DMCopyBoundary(dm, *dmRefined);CHKERRQ(ierr);
10502     if (localized) {ierr = DMLocalizeCoordinates(*dmRefined);CHKERRQ(ierr);}
10503   } else {
10504     ierr = DMPlexRefine_Internal(dm, NULL, dmRefined);CHKERRQ(ierr);
10505   }
10506   PetscFunctionReturn(0);
10507 }
10508 
10509 PetscErrorCode DMRefineHierarchy_Plex(DM dm, PetscInt nlevels, DM dmRefined[])
10510 {
10511   DM             cdm = dm;
10512   PetscInt       r;
10513   PetscBool      isUniform, localized;
10514   PetscErrorCode ierr;
10515 
10516   PetscFunctionBegin;
10517   ierr = DMPlexGetRefinementUniform(dm, &isUniform);CHKERRQ(ierr);
10518   ierr = DMGetCoordinatesLocalized(dm, &localized);CHKERRQ(ierr);
10519   if (isUniform) {
10520     for (r = 0; r < nlevels; ++r) {
10521       CellRefiner cellRefiner;
10522 
10523       ierr = DMPlexGetCellRefiner_Internal(cdm, &cellRefiner);CHKERRQ(ierr);
10524       ierr = DMPlexRefineUniform_Internal(cdm, cellRefiner, &dmRefined[r]);CHKERRQ(ierr);
10525       ierr = DMSetCoarsenLevel(dmRefined[r], cdm->leveldown);CHKERRQ(ierr);
10526       ierr = DMSetRefineLevel(dmRefined[r], cdm->levelup+1);CHKERRQ(ierr);
10527       ierr = DMCopyBoundary(cdm, dmRefined[r]);CHKERRQ(ierr);
10528       if (localized) {ierr = DMLocalizeCoordinates(dmRefined[r]);CHKERRQ(ierr);}
10529       ierr = DMSetCoarseDM(dmRefined[r], cdm);CHKERRQ(ierr);
10530       ierr = DMPlexSetRegularRefinement(dmRefined[r], PETSC_TRUE);CHKERRQ(ierr);
10531       cdm  = dmRefined[r];
10532     }
10533   } else {
10534     for (r = 0; r < nlevels; ++r) {
10535       ierr = DMRefine(cdm, PetscObjectComm((PetscObject) dm), &dmRefined[r]);CHKERRQ(ierr);
10536       ierr = DMCopyBoundary(cdm, dmRefined[r]);CHKERRQ(ierr);
10537       if (localized) {ierr = DMLocalizeCoordinates(dmRefined[r]);CHKERRQ(ierr);}
10538       ierr = DMSetCoarseDM(dmRefined[r], cdm);CHKERRQ(ierr);
10539       cdm  = dmRefined[r];
10540     }
10541   }
10542   PetscFunctionReturn(0);
10543 }
10544