xref: /petsc/src/dm/impls/plex/plexrefine.c (revision 02c9f0b548ed2228330a66acd2df0a92dd2a8bb1)
1 #include <petsc/private/dmpleximpl.h>   /*I      "petscdmplex.h"   I*/
2 #include <petscsf.h>
3 
4 const char * const CellRefiners[] = {"NOOP", "SIMPLEX_1D", "SIMPLEX_2D", "HYBRID_SIMPLEX_2D", "SIMPLEX_TO_HEX_2D", "HYBRID_SIMPLEX_TO_HEX_2D", "HEX_2D", "HYBRID_HEX_2D",
5                                      "SIMPLEX_3D", "HYBRID_SIMPLEX_3D", "SIMPLEX_TO_HEX_3D", "HYBRID_SIMPLEX_TO_HEX_3D", "HEX_3D", "HYBRID_HEX_3D", "CellRefiners", "REFINER_", 0};
6 
7 PETSC_STATIC_INLINE PetscErrorCode GetDepthStart_Private(PetscInt depth, PetscInt depthSize[], PetscInt *cStart, PetscInt *fStart, PetscInt *eStart, PetscInt *vStart)
8 {
9   PetscFunctionBegin;
10   if (cStart) *cStart = 0;
11   if (vStart) *vStart = depth < 0 ? 0 : depthSize[depth];
12   if (fStart) *fStart = depth < 0 ? 0 : depthSize[depth] + depthSize[0];
13   if (eStart) *eStart = depth < 0 ? 0 : depthSize[depth] + depthSize[0] + depthSize[depth-1];
14   PetscFunctionReturn(0);
15 }
16 
17 PETSC_STATIC_INLINE PetscErrorCode GetDepthEnd_Private(PetscInt depth, PetscInt depthSize[], PetscInt *cEnd, PetscInt *fEnd, PetscInt *eEnd, PetscInt *vEnd)
18 {
19   PetscFunctionBegin;
20   if (cEnd) *cEnd = depth < 0 ? 0 : depthSize[depth];
21   if (vEnd) *vEnd = depth < 0 ? 0 : depthSize[depth] + depthSize[0];
22   if (fEnd) *fEnd = depth < 0 ? 0 : depthSize[depth] + depthSize[0] + depthSize[depth-1];
23   if (eEnd) *eEnd = depth < 0 ? 0 : depthSize[depth] + depthSize[0] + depthSize[depth-1] + depthSize[1];
24   PetscFunctionReturn(0);
25 }
26 
27 /*
28   Note that j and invj are non-square:
29          v0 + j x_face = x_cell
30     invj (x_cell - v0) = x_face
31 */
32 PetscErrorCode CellRefinerGetAffineFaceTransforms_Internal(CellRefiner refiner, PetscInt *numFaces, PetscReal *v0[], PetscReal *jac[], PetscReal *invjac[], PetscReal *detj[])
33 {
34   PetscReal     *v = NULL, *j = NULL, *invj = NULL, *dj = NULL;
35   PetscInt       cdim, fdim;
36   PetscErrorCode ierr;
37 
38   PetscFunctionBegin;
39   switch (refiner) {
40   case REFINER_NOOP: break;
41   case REFINER_SIMPLEX_2D:
42     /*
43      2
44      |\
45      | \
46      |  \
47      |   \
48      |    \
49      |     \
50      |      \
51      2       1
52      |        \
53      |         \
54      |          \
55      0---0-------1
56      */
57     cdim = 2;
58     fdim = 1;
59     if (numFaces) *numFaces = 3;
60     if (v0) {
61       ierr = PetscMalloc1(3*cdim,      &v);CHKERRQ(ierr);
62       ierr = PetscMalloc1(3*cdim*fdim, &j);CHKERRQ(ierr);
63       ierr = PetscMalloc1(3*cdim*fdim, &invj);CHKERRQ(ierr);
64       ierr = PetscMalloc1(3,           &dj);CHKERRQ(ierr);
65       /* 0 */
66       v[0+0] =  0.0; v[0+1] = -1.0;
67       j[0+0] =  1.0;
68       j[0+1] =  0.0;
69       invj[0+0] = 1.0; invj[0+1] = 0.0;
70       dj[0]  = 1.0;
71       /* 1 */
72       v[2+0] =  0.0; v[2+1] =  0.0;
73       j[2+0] = -1.0;
74       j[2+1] =  1.0;
75       invj[2+0] = -0.5; invj[2+1] = 0.5;
76       dj[1]  = 1.414213562373095;
77       /* 2 */
78       v[4+0] = -1.0; v[4+1] =  0.0;
79       j[4+0] =  0.0;
80       j[4+1] = -1.0;
81       invj[4+0] = 0.0; invj[4+1] = -1.0;
82       dj[2]  = 1.0;
83     }
84     break;
85   case REFINER_HEX_2D:
86     /*
87      3---------2---------2
88      |                   |
89      |                   |
90      |                   |
91      3                   1
92      |                   |
93      |                   |
94      |                   |
95      0---------0---------1
96      */
97     cdim = 2;
98     fdim = 1;
99     if (numFaces) *numFaces = 4;
100     if (v0) {
101       ierr = PetscMalloc1(4*cdim,      &v);CHKERRQ(ierr);
102       ierr = PetscMalloc1(4*cdim*fdim, &j);CHKERRQ(ierr);
103       ierr = PetscMalloc1(4*cdim*fdim, &invj);CHKERRQ(ierr);
104       ierr = PetscMalloc1(4,           &dj);CHKERRQ(ierr);
105       /* 0 */
106       v[0+0] =  0.0; v[0+1] = -1.0;
107       j[0+0] =  1.0;
108       j[0+1] =  0.0;
109       invj[0+0] =  1.0; invj[0+1] =  0.0;
110       dj[0]  = 1.0;
111       /* 1 */
112       v[2+0] =  1.0; v[2+1] =  0.0;
113       j[2+0] =  0.0;
114       j[2+1] =  1.0;
115       invj[2+0] =  0.0; invj[2+1] =  1.0;
116       dj[1]  = 1.0;
117       /* 2 */
118       v[4+0] =  0.0; v[4+1] = 1.0;
119       j[4+0] = -1.0;
120       j[4+1] =  0.0;
121       invj[4+0] = -1.0; invj[4+1] =  0.0;
122       dj[2]  = 1.0;
123       /* 3 */
124       v[6+0] = -1.0; v[6+1] =  0.0;
125       j[6+0] =  0.0;
126       j[6+1] = -1.0;
127       invj[6+0] =  0.0; invj[6+1] = -1.0;
128       dj[3]  = 1.0;
129     }
130     break;
131   default:
132     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %s", CellRefiners[refiner]);
133   }
134   if (v0)     {*v0     = v;}
135   else        {ierr = PetscFree(v);CHKERRQ(ierr);}
136   if (jac)    {*jac    = j;}
137   else        {ierr = PetscFree(j);CHKERRQ(ierr);}
138   if (invjac) {*invjac = invj;}
139   else        {ierr = PetscFree(invj);CHKERRQ(ierr);}
140   if (invjac) {*invjac = invj;}
141   else        {ierr = PetscFree(invj);CHKERRQ(ierr);}
142   if (detj)   {*detj   = dj;}
143   else        {ierr = PetscFree(dj);CHKERRQ(ierr);}
144   PetscFunctionReturn(0);
145 }
146 
147 /* Gets the affine map from the original cell to each subcell */
148 PetscErrorCode CellRefinerGetAffineTransforms_Internal(CellRefiner refiner, PetscInt *numSubcells, PetscReal *v0[], PetscReal *jac[], PetscReal *invjac[])
149 {
150   PetscReal     *v = NULL, *j = NULL, *invj = NULL, detJ;
151   PetscInt       dim, s;
152   PetscErrorCode ierr;
153 
154   PetscFunctionBegin;
155   switch (refiner) {
156   case REFINER_NOOP: break;
157   case REFINER_SIMPLEX_2D:
158     /*
159      2
160      |\
161      | \
162      |  \
163      |   \
164      | C  \
165      |     \
166      |      \
167      2---1---1
168      |\  D  / \
169      | 2   0   \
170      |A \ /  B  \
171      0---0-------1
172      */
173     dim = 2;
174     if (numSubcells) *numSubcells = 4;
175     if (v0) {
176       ierr = PetscMalloc3(4*dim,&v,4*dim*dim,&j,4*dim*dim,&invj);CHKERRQ(ierr);
177       /* A */
178       v[0+0] = -1.0; v[0+1] = -1.0;
179       j[0+0] =  0.5; j[0+1] =  0.0;
180       j[0+2] =  0.0; j[0+3] =  0.5;
181       /* B */
182       v[2+0] =  0.0; v[2+1] = -1.0;
183       j[4+0] =  0.5; j[4+1] =  0.0;
184       j[4+2] =  0.0; j[4+3] =  0.5;
185       /* C */
186       v[4+0] = -1.0; v[4+1] =  0.0;
187       j[8+0] =  0.5; j[8+1] =  0.0;
188       j[8+2] =  0.0; j[8+3] =  0.5;
189       /* D */
190       v[6+0]  =  0.0; v[6+1]  = -1.0;
191       j[12+0] =  0.0; j[12+1] = -0.5;
192       j[12+2] =  0.5; j[12+3] =  0.5;
193       for (s = 0; s < 4; ++s) {
194         DMPlex_Det2D_Internal(&detJ, &j[s*dim*dim]);
195         DMPlex_Invert2D_Internal(&invj[s*dim*dim], &j[s*dim*dim], detJ);
196       }
197     }
198     break;
199   case REFINER_HEX_2D:
200     /*
201      3---------2---------2
202      |         |         |
203      |    D    2    C    |
204      |         |         |
205      3----3----0----1----1
206      |         |         |
207      |    A    0    B    |
208      |         |         |
209      0---------0---------1
210      */
211     dim = 2;
212     if (numSubcells) *numSubcells = 4;
213     if (v0) {
214       ierr = PetscMalloc3(4*dim,&v,4*dim*dim,&j,4*dim*dim,&invj);CHKERRQ(ierr);
215       /* A */
216       v[0+0] = -1.0; v[0+1] = -1.0;
217       j[0+0] =  0.5; j[0+1] =  0.0;
218       j[0+2] =  0.0; j[0+3] =  0.5;
219       /* B */
220       v[2+0] =  0.0; v[2+1] = -1.0;
221       j[4+0] =  0.5; j[4+1] =  0.0;
222       j[4+2] =  0.0; j[4+3] =  0.5;
223       /* C */
224       v[4+0] =  0.0; v[4+1] =  0.0;
225       j[8+0] =  0.5; j[8+1] =  0.0;
226       j[8+2] =  0.0; j[8+3] =  0.5;
227       /* D */
228       v[6+0]  = -1.0; v[6+1]  =  0.0;
229       j[12+0] =  0.5; j[12+1] =  0.0;
230       j[12+2] =  0.0; j[12+3] =  0.5;
231       for (s = 0; s < 4; ++s) {
232         DMPlex_Det2D_Internal(&detJ, &j[s*dim*dim]);
233         DMPlex_Invert2D_Internal(&invj[s*dim*dim], &j[s*dim*dim], detJ);
234       }
235     }
236     break;
237   case REFINER_HEX_3D:
238     /*
239      Bottom (viewed from top)    Top
240      1---------2---------2       7---------2---------6
241      |         |         |       |         |         |
242      |    B    2    C    |       |    H    2    G    |
243      |         |         |       |         |         |
244      3----3----0----1----1       3----3----0----1----1
245      |         |         |       |         |         |
246      |    A    0    D    |       |    E    0    F    |
247      |         |         |       |         |         |
248      0---------0---------3       4---------0---------5
249      */
250     break;
251     dim = 3;
252     if (numSubcells) *numSubcells = 8;
253     if (v0) {
254       ierr = PetscMalloc3(4*dim,&v,4*dim*dim,&j,4*dim*dim,&invj);CHKERRQ(ierr);
255       /* A */
256       v[0+0] = -1.0; v[0+1] = -1.0; v[0+2] = -1.0;
257       j[0+0] =  0.5; j[0+1] =  0.0; j[0+2] =  0.0;
258       j[0+3] =  0.0; j[0+4] =  0.5; j[0+5] =  0.0;
259       j[0+6] =  0.0; j[0+7] =  0.0; j[0+8] =  0.5;
260       /* B */
261       v[3+0] = -1.0; v[3+1] =  0.0; v[3+2] = -1.0;
262       j[9+0] =  0.5; j[9+1] =  0.0; j[9+2] =  0.0;
263       j[9+3] =  0.0; j[9+4] =  0.5; j[9+5] =  0.0;
264       j[9+6] =  0.0; j[9+7] =  0.0; j[9+8] =  0.5;
265       /* C */
266       v[6+0] =  0.0; v[6+1] =  0.0; v[6+2] = -1.0;
267       j[18+0] = 0.5; j[18+1] = 0.0; j[18+2] = 0.0;
268       j[18+3] = 0.0; j[18+4] = 0.5; j[18+5] = 0.0;
269       j[18+6] = 0.0; j[18+7] = 0.0; j[18+8] = 0.5;
270       /* D */
271       v[9+0] =  0.0; v[9+1] = -1.0; v[9+2] = -1.0;
272       j[27+0] = 0.5; j[27+1] = 0.0; j[27+2] = 0.0;
273       j[27+3] = 0.0; j[27+4] = 0.5; j[27+5] = 0.0;
274       j[27+6] = 0.0; j[27+7] = 0.0; j[27+8] = 0.5;
275       /* E */
276       v[12+0] = -1.0; v[12+1] = -1.0; v[12+2] =  0.0;
277       j[36+0] =  0.5; j[36+1] =  0.0; j[36+2] =  0.0;
278       j[36+3] =  0.0; j[36+4] =  0.5; j[36+5] =  0.0;
279       j[36+6] =  0.0; j[36+7] =  0.0; j[36+8] =  0.5;
280       /* F */
281       v[15+0] =  0.0; v[15+1] = -1.0; v[15+2] =  0.0;
282       j[45+0] =  0.5; j[45+1] =  0.0; j[45+2] =  0.0;
283       j[45+3] =  0.0; j[45+4] =  0.5; j[45+5] =  0.0;
284       j[45+6] =  0.0; j[45+7] =  0.0; j[45+8] =  0.5;
285       /* G */
286       v[18+0] =  0.0; v[18+1] =  0.0; v[18+2] =  0.0;
287       j[54+0] =  0.5; j[54+1] =  0.0; j[54+2] =  0.0;
288       j[54+3] =  0.0; j[54+4] =  0.5; j[54+5] =  0.0;
289       j[54+6] =  0.0; j[54+7] =  0.0; j[54+8] =  0.5;
290       /* H */
291       v[21+0] = -1.0; v[21+1] =  0.0; v[21+2] =  0.0;
292       j[63+0] =  0.5; j[63+1] =  0.0; j[63+2] =  0.0;
293       j[63+3] =  0.0; j[63+4] =  0.5; j[63+5] =  0.0;
294       j[63+6] =  0.0; j[63+7] =  0.0; j[63+8] =  0.5;
295       for (s = 0; s < 8; ++s) {
296         DMPlex_Det3D_Internal(&detJ, &j[s*dim*dim]);
297         DMPlex_Invert3D_Internal(&invj[s*dim*dim], &j[s*dim*dim], detJ);
298       }
299     }
300   default:
301     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %s", CellRefiners[refiner]);
302   }
303   if (v0) {*v0 = v; *jac = j; *invjac = invj;}
304   PetscFunctionReturn(0);
305 }
306 
307 PetscErrorCode CellRefinerRestoreAffineTransforms_Internal(CellRefiner refiner, PetscInt *numSubcells, PetscReal *v0[], PetscReal *jac[], PetscReal *invjac[])
308 {
309   PetscErrorCode ierr;
310 
311   PetscFunctionBegin;
312   ierr = PetscFree3(*v0,*jac,*invjac);CHKERRQ(ierr);
313   PetscFunctionReturn(0);
314 }
315 
316 /* Should this be here or in the DualSpace somehow? */
317 PetscErrorCode CellRefinerInCellTest_Internal(CellRefiner refiner, const PetscReal point[], PetscBool *inside)
318 {
319   PetscReal sum = 0.0;
320   PetscInt  d;
321 
322   PetscFunctionBegin;
323   *inside = PETSC_TRUE;
324   switch (refiner) {
325   case REFINER_NOOP: break;
326   case REFINER_SIMPLEX_2D:
327     for (d = 0; d < 2; ++d) {
328       if (point[d] < -1.0) {*inside = PETSC_FALSE; break;}
329       sum += point[d];
330     }
331     if (sum > 1.0e-10) {*inside = PETSC_FALSE; break;}
332     break;
333   case REFINER_HEX_2D:
334     for (d = 0; d < 2; ++d) if ((point[d] < -1.00000000001) || (point[d] > 1.000000000001)) {*inside = PETSC_FALSE; break;}
335     break;
336   default:
337     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %s", CellRefiners[refiner]);
338   }
339   PetscFunctionReturn(0);
340 }
341 
342 static PetscErrorCode CellRefinerGetSizes(CellRefiner refiner, DM dm, PetscInt depthSize[])
343 {
344   PetscInt       cStart, cEnd, cMax, vStart, vEnd, vMax, fStart, fEnd, fMax, eStart, eEnd, eMax;
345   PetscErrorCode ierr;
346 
347   PetscFunctionBegin;
348   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
349   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
350   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
351   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
352   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
353   switch (refiner) {
354   case REFINER_NOOP:
355     break;
356   case REFINER_SIMPLEX_1D:
357     depthSize[0] = vEnd - vStart + cEnd - cStart;         /* Add a vertex on every cell. */
358     depthSize[1] = 2*(cEnd - cStart);                     /* Split every cell in 2. */
359     break;
360   case REFINER_SIMPLEX_2D:
361     depthSize[0] = vEnd - vStart + fEnd - fStart;         /* Add a vertex on every face */
362     depthSize[1] = 2*(fEnd - fStart) + 3*(cEnd - cStart); /* Every face is split into 2 faces and 3 faces are added for each cell */
363     depthSize[2] = 4*(cEnd - cStart);                     /* Every cell split into 4 cells */
364     break;
365   case REFINER_HYBRID_SIMPLEX_2D:
366     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
367     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
368     depthSize[0] = vEnd - vStart + fMax - fStart;                                         /* Add a vertex on every face, but not hybrid faces */
369     depthSize[1] = 2*(fMax - fStart) + 3*(cMax - cStart) + (fEnd - fMax) + (cEnd - cMax); /* Every interior face is split into 2 faces, 3 faces are added for each interior cell, and one in each hybrid cell */
370     depthSize[2] = 4*(cMax - cStart) + 2*(cEnd - cMax);                                   /* Interior cells split into 4 cells, hybrid cells split into 2 cells */
371     break;
372   case REFINER_SIMPLEX_TO_HEX_2D:
373     depthSize[0] = vEnd - vStart + fEnd - fStart + cEnd - cStart; /* Add a vertex on every face and cell */
374     depthSize[1] = 2*(fEnd - fStart) + 3*(cEnd - cStart);         /* Every face is split into 2 faces and 3 faces are added for each cell */
375     depthSize[2] = 3*(cEnd - cStart);                             /* Every cell split into 3 cells */
376     break;
377   case REFINER_HYBRID_SIMPLEX_TO_HEX_2D:
378     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
379     depthSize[0] = vEnd - vStart + fEnd - fStart + cEnd - cStart;           /* Add a vertex on every face and cell */
380     depthSize[1] = 2*(fEnd - fStart) + 3*(cMax - cStart) + 4*(cEnd - cMax); /* Every face is split into 2 faces and 3 faces are added for each cell. 4 for each hybrid cell */
381     depthSize[2] = 3*(cMax - cStart) + 4*(cEnd - cMax);                     /* Every cell split into 3 cells, hybrid cells split in 4 */
382     break;
383   case REFINER_HEX_2D:
384     depthSize[0] = vEnd - vStart + fEnd - fStart + cEnd - cStart; /* Add a vertex on every face and cell */
385     depthSize[1] = 2*(fEnd - fStart) + 4*(cEnd - cStart);         /* Every face is split into 2 faces and 4 faces are added for each cell */
386     depthSize[2] = 4*(cEnd - cStart);                             /* Every cell split into 4 cells */
387     break;
388   case REFINER_HYBRID_HEX_2D:
389     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
390     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
391     /* Quadrilateral */
392     depthSize[0] = vEnd - vStart + fMax - fStart + cMax - cStart;                 /* Add a vertex on every face and cell */
393     depthSize[1] = 2*(fMax - fStart) + 4*(cMax - cStart);                         /* Every face is split into 2 faces, and 4 faces are added for each cell */
394     depthSize[2] = 4*(cMax - cStart);                                             /* Every cell split into 4 cells */
395     /* Segment Prisms */
396     depthSize[0] += 0;                                                            /* No hybrid vertices */
397     depthSize[1] +=   (fEnd - fMax)  +   (cEnd - cMax);                           /* Every hybrid face remains and 1 faces is added for each hybrid cell */
398     depthSize[2] += 2*(cEnd - cMax);                                              /* Every hybrid cell split into 2 cells */
399     break;
400   case REFINER_SIMPLEX_3D:
401     depthSize[0] =    vEnd - vStart  +    eEnd - eStart;                    /* Add a vertex on every edge */
402     depthSize[1] = 2*(eEnd - eStart) + 3*(fEnd - fStart) + (cEnd - cStart); /* Every edge is split into 2 edges, 3 edges are added for each face, and 1 edge for each cell */
403     depthSize[2] = 4*(fEnd - fStart) + 8*(cEnd - cStart);                   /* Every face split into 4 faces and 8 faces are added for each cell */
404     depthSize[3] = 8*(cEnd - cStart);                                       /* Every cell split into 8 cells */
405     break;
406   case REFINER_HYBRID_SIMPLEX_3D:
407     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
408     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
409     if (eMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No edge maximum specified in hybrid mesh");
410     /* Tetrahedra */
411     depthSize[0]  =    vEnd - vStart  +    eMax - eStart;                    /* Add a vertex on every interior edge */
412     depthSize[1]  = 2*(eMax - eStart) + 3*(fMax - fStart) + (cMax - cStart); /* Every interior edge split into 2 edges, 3 edges added for each interior face, 1 edge for each interior cell */
413     depthSize[2]  = 4*(fMax - fStart) + 8*(cMax - cStart);                   /* Every interior face split into 4 faces, 8 faces added for each interior cell */
414     depthSize[3]  = 8*(cMax - cStart);                                       /* Every interior cell split into 8 cells */
415     /* Triangular Prisms */
416     depthSize[0] += 0;                                                       /* No hybrid vertices */
417     depthSize[1] +=   (eEnd - eMax)   +   (fEnd - fMax);                     /* Every hybrid edge remains, 1 edge for every hybrid face */
418     depthSize[2] += 2*(fEnd - fMax)   + 3*(cEnd - cMax);                     /* Every hybrid face split into 2 faces and 3 faces are added for each hybrid cell */
419     depthSize[3] += 4*(cEnd - cMax);                                         /* Every hybrid cell split into 4 cells */
420     break;
421   case REFINER_SIMPLEX_TO_HEX_3D:
422     depthSize[0] = vEnd - vStart + fEnd - fStart + eEnd - eStart + cEnd - cStart; /* Add a vertex on every face, edge and cell */
423     depthSize[1] = 2*(eEnd - eStart) + 3*(fEnd - fStart) + 4*(cEnd - cStart);     /* Every edge is split into 2 edges, 3 edges are added for each face, and 4 for each cell */
424     depthSize[2] = 3*(fEnd - fStart) + 6*(cEnd - cStart);                         /* Every face is split into 3 faces and 6 faces are added for each cell */
425     depthSize[3] = 4*(cEnd - cStart);                                             /* Every cell split into 4 cells */
426     break;
427   case REFINER_HYBRID_SIMPLEX_TO_HEX_3D:
428     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
429     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
430     if (eMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No edge maximum specified in hybrid mesh");
431     /* Tetrahedra */
432     depthSize[0]  =    vEnd - vStart  +    eMax - eStart  + fMax - fStart + cMax - cStart; /* Add a vertex on every interior edge, face and cell */
433     depthSize[1]  = 2*(eMax - eStart) + 3*(fMax - fStart) + 4*(cMax - cStart);             /* Every interior edge split into 2 edges, 3 edges added for each interior face, 4 edges for each interior cell */
434     depthSize[2]  = 3*(fMax - fStart) + 6*(cMax - cStart);                                 /* Every interior face split into 3 faces, 6 faces added for each interior cell */
435     depthSize[3]  = 4*(cMax - cStart);                                                     /* Every interior cell split into 8 cells */
436     /* Triangular Prisms */
437     depthSize[0] += 0;                                                 /* No hybrid vertices */
438     depthSize[1] +=   (eEnd - eMax) +   (fEnd - fMax) + (cEnd - cMax); /* Every hybrid edge remains, 1 edge for every hybrid face and cell */
439     depthSize[2] += 2*(fEnd - fMax) + 3*(cEnd - cMax);                 /* Every hybrid face split into 2 faces and 3 faces are added for each hybrid cell */
440     depthSize[3] += 3*(cEnd - cMax);                                   /* Every hybrid cell split into 3 cells */
441     break;
442   case REFINER_HEX_3D:
443     depthSize[0] = vEnd - vStart + eEnd - eStart + fEnd - fStart + cEnd - cStart; /* Add a vertex on every edge, face and cell */
444     depthSize[1] = 2*(eEnd - eStart) +  4*(fEnd - fStart) + 6*(cEnd - cStart);    /* Every edge is split into 2 edge, 4 edges are added for each face, and 6 edges for each cell */
445     depthSize[2] = 4*(fEnd - fStart) + 12*(cEnd - cStart);                        /* Every face is split into 4 faces, and 12 faces are added for each cell */
446     depthSize[3] = 8*(cEnd - cStart);                                             /* Every cell split into 8 cells */
447     break;
448   case REFINER_HYBRID_HEX_3D:
449     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
450     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
451     if (eMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No edge maximum specified in hybrid mesh");
452     /* Hexahedra */
453     depthSize[0] = vEnd - vStart + eMax - eStart + fMax - fStart + cMax - cStart; /* Add a vertex on every edge, face and cell */
454     depthSize[1] = 2*(eMax - eStart) +  4*(fMax - fStart) + 6*(cMax - cStart);    /* Every edge is split into 2 edge, 4 edges are added for each face, and 6 edges for each cell */
455     depthSize[2] = 4*(fMax - fStart) + 12*(cMax - cStart);                        /* Every face is split into 4 faces, and 12 faces are added for each cell */
456     depthSize[3] = 8*(cMax - cStart);                                             /* Every cell split into 8 cells */
457     /* Quadrilateral Prisms */
458     depthSize[0] += 0;                                                            /* No hybrid vertices */
459     depthSize[1] +=   (eEnd - eMax)   +   (fEnd - fMax)   +   (cEnd - cMax);      /* Every hybrid edge remains, 1 edge for every hybrid face and hybrid cell */
460     depthSize[2] += 2*(fEnd - fMax)   + 4*(cEnd - cMax);                          /* Every hybrid face split into 2 faces and 4 faces are added for each hybrid cell */
461     depthSize[3] += 4*(cEnd - cMax);                                              /* Every hybrid cell split into 4 cells */
462     break;
463   default:
464     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %s", CellRefiners[refiner]);
465   }
466   PetscFunctionReturn(0);
467 }
468 
469 /* Return triangle edge for orientation o, if it is r for o == 0 */
470 PETSC_STATIC_INLINE PetscInt GetTriEdge_Static(PetscInt o, PetscInt r) {
471   return (o < 0 ? 2-(o+r) : o+r)%3;
472 }
473 PETSC_STATIC_INLINE PetscInt GetTriEdgeInverse_Static(PetscInt o, PetscInt s) {
474   return (o < 0 ? 2-(o+s) : 3+s-o)%3;
475 }
476 
477 /* Return triangle subface for orientation o, if it is r for o == 0 */
478 PETSC_STATIC_INLINE PetscInt GetTriSubface_Static(PetscInt o, PetscInt r) {
479   return (o < 0 ? 3-(o+r) : o+r)%3;
480 }
481 PETSC_STATIC_INLINE PetscInt GetTriSubfaceInverse_Static(PetscInt o, PetscInt s) {
482   return (o < 0 ? 3-(o+s) : 3+s-o)%3;
483 }
484 
485 /* Return the interior edge number connecting the midpoints of the triangle edges r
486    and r+1 in the transitive closure for triangle orientation o */
487 PETSC_STATIC_INLINE PetscInt GetTriMidEdge_Static(PetscInt o, PetscInt r) {
488   return (o < 0 ? 1-(o+r) : o+r)%3;
489 }
490 PETSC_STATIC_INLINE PetscInt GetTriMidEdgeInverse_Static(PetscInt o, PetscInt s) {
491   return (o < 0 ? 1-(o+s) : 3+s-o)%3;
492 }
493 
494 /* Return the interior edge number connecting the midpoint of the triangle edge r
495    (in the transitive closure) and the vertex in the interior of the face for triangle orientation o */
496 PETSC_STATIC_INLINE PetscInt GetTriInteriorEdge_Static(PetscInt o, PetscInt r) {
497   return (o < 0 ? 2-(o+r) : o+r)%3;
498 }
499 PETSC_STATIC_INLINE PetscInt GetTriInteriorEdgeInverse_Static(PetscInt o, PetscInt s) {
500   return (o < 0 ? 2-(o+s) : 3+s-o)%3;
501 }
502 
503 /* Return quad edge for orientation o, if it is r for o == 0 */
504 PETSC_STATIC_INLINE PetscInt GetQuadEdge_Static(PetscInt o, PetscInt r) {
505   return (o < 0 ? 3-(o+r) : o+r)%4;
506 }
507 PETSC_STATIC_INLINE PetscInt GetQuadEdgeInverse_Static(PetscInt o, PetscInt s) {
508   return (o < 0 ? 3-(o+s) : 4+s-o)%4;
509 }
510 
511 /* Return quad subface for orientation o, if it is r for o == 0 */
512 PETSC_STATIC_INLINE PetscInt GetQuadSubface_Static(PetscInt o, PetscInt r) {
513   return (o < 0 ? 4-(o+r) : o+r)%4;
514 }
515 PETSC_STATIC_INLINE PetscInt GetQuadSubfaceInverse_Static(PetscInt o, PetscInt s) {
516   return (o < 0 ? 4-(o+s) : 4+s-o)%4;
517 }
518 
519 static PetscErrorCode DMLabelSetStratumBounds(DMLabel label, PetscInt value, PetscInt cStart, PetscInt cEnd)
520 {
521   IS             cIS;
522   PetscErrorCode ierr;
523 
524   PetscFunctionBegin;
525   ierr = ISCreateStride(PETSC_COMM_SELF, cEnd - cStart, cStart, 1, &cIS);CHKERRQ(ierr);
526   ierr = DMLabelSetStratumIS(label, value, cIS);CHKERRQ(ierr);
527   ierr = ISDestroy(&cIS);CHKERRQ(ierr);
528   PetscFunctionReturn(0);
529 }
530 
531 static PetscErrorCode CellRefinerSetConeSizes(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
532 {
533   PetscInt       depth, cStart, cStartNew, cEnd, cEndNew, cMax, c, vStart, vStartNew, vEnd, vEndNew, vMax, v, fStart, fStartNew, fEnd, fEndNew, fMax, f, eStart, eStartNew, eEnd, eEndNew, eMax, e, r;
534   DMLabel        depthLabel, celltypeLabel;
535   PetscErrorCode ierr;
536 
537   PetscFunctionBegin;
538   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
539   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
540   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
541   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
542   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
543   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
544   ierr = GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);CHKERRQ(ierr);
545   ierr = GetDepthEnd_Private(depth, depthSize, &cEndNew, &fEndNew, &eEndNew, &vEndNew);CHKERRQ(ierr);
546   ierr = DMCreateLabel(rdm,"depth");CHKERRQ(ierr);
547   ierr = DMPlexGetDepthLabel(rdm,&depthLabel);CHKERRQ(ierr);
548   ierr = DMLabelSetStratumBounds(depthLabel, 0, vStartNew, vEndNew);CHKERRQ(ierr);
549   if (depth > 2) ierr = DMLabelSetStratumBounds(depthLabel, 1, eStartNew, eEndNew);CHKERRQ(ierr);
550   if (depth > 1) ierr = DMLabelSetStratumBounds(depthLabel, depth - 1, fStartNew, fEndNew);CHKERRQ(ierr);
551   if (depth > 0) ierr = DMLabelSetStratumBounds(depthLabel, depth, cStartNew, cEndNew);CHKERRQ(ierr);
552   {
553     DM_Plex *plex = (DM_Plex *) rdm->data;
554     ierr = PetscObjectStateGet((PetscObject) depthLabel, &plex->depthState);CHKERRQ(ierr);
555   }
556   if (!refiner) PetscFunctionReturn(0);
557   switch (refiner) {
558   case REFINER_SIMPLEX_1D:
559     /* All cells have 2 vertices */
560     for (c = cStart; c < cEnd; ++c) {
561       for (r = 0; r < 2; ++r) {
562         const PetscInt newp = cStartNew + (c - cStart)*2 + r;
563 
564         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
565       }
566     }
567     /* Old vertices have identical supports */
568     for (v = vStart; v < vEnd; ++v) {
569       const PetscInt newp = vStartNew + (v - vStart);
570       PetscInt       size;
571 
572       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
573       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
574     }
575     /* Cell vertices have support 2 */
576     for (c = cStart; c < cEnd; ++c) {
577       const PetscInt newp = vStartNew + (vEnd - vStart) + (c - cStart);
578 
579       ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
580     }
581     break;
582   case REFINER_SIMPLEX_2D:
583     /* All cells have 3 faces */
584     for (c = cStart; c < cEnd; ++c) {
585       for (r = 0; r < 4; ++r) {
586         const PetscInt newp = (c - cStart)*4 + r;
587 
588         ierr = DMPlexSetConeSize(rdm, newp, 3);CHKERRQ(ierr);
589       }
590     }
591     /* Split faces have 2 vertices and the same cells as the parent */
592     for (f = fStart; f < fEnd; ++f) {
593       for (r = 0; r < 2; ++r) {
594         const PetscInt newp = fStartNew + (f - fStart)*2 + r;
595         PetscInt       size;
596 
597         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
598         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
599         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
600       }
601     }
602     /* Interior faces have 2 vertices and 2 cells */
603     for (c = cStart; c < cEnd; ++c) {
604       for (r = 0; r < 3; ++r) {
605         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*3 + r;
606 
607         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
608         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
609       }
610     }
611     /* Old vertices have identical supports */
612     for (v = vStart; v < vEnd; ++v) {
613       const PetscInt newp = vStartNew + (v - vStart);
614       PetscInt       size;
615 
616       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
617       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
618     }
619     /* Face vertices have 2 + cells*2 supports */
620     for (f = fStart; f < fEnd; ++f) {
621       const PetscInt newp = vStartNew + (vEnd - vStart) + (f - fStart);
622       PetscInt       size;
623 
624       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
625       ierr = DMPlexSetSupportSize(rdm, newp, 2 + size*2);CHKERRQ(ierr);
626     }
627     break;
628   case REFINER_SIMPLEX_TO_HEX_2D:
629     /* All cells have 4 faces */
630     for (c = cStart; c < cEnd; ++c) {
631       for (r = 0; r < 3; ++r) {
632         const PetscInt newp = (c - cStart)*3 + r;
633 
634         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
635       }
636     }
637     /* Split faces have 2 vertices and the same cells as the parent */
638     for (f = fStart; f < fEnd; ++f) {
639       for (r = 0; r < 2; ++r) {
640         const PetscInt newp = fStartNew + (f - fStart)*2 + r;
641         PetscInt       size;
642 
643         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
644         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
645         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
646       }
647     }
648     /* Interior faces have 2 vertices and 2 cells */
649     for (c = cStart; c < cEnd; ++c) {
650       for (r = 0; r < 3; ++r) {
651         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*3 + r;
652 
653         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
654         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
655       }
656     }
657     /* Old vertices have identical supports */
658     for (v = vStart; v < vEnd; ++v) {
659       const PetscInt newp = vStartNew + (v - vStart);
660       PetscInt       size;
661 
662       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
663       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
664     }
665     /* Split-face vertices have cells + 2 supports */
666     for (f = fStart; f < fEnd; ++f) {
667       const PetscInt newp = vStartNew + (vEnd - vStart) + (f - fStart);
668       PetscInt       size;
669 
670       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
671       ierr = DMPlexSetSupportSize(rdm, newp, size + 2);CHKERRQ(ierr);
672     }
673     /* Interior vertices have 3 supports */
674     for (c = cStart; c < cEnd; ++c) {
675       const PetscInt newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + c - cStart;
676 
677       ierr = DMPlexSetSupportSize(rdm, newp, 3);CHKERRQ(ierr);
678     }
679     break;
680   case REFINER_HYBRID_SIMPLEX_TO_HEX_2D:
681     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
682     /* the mesh is no longer hybrid */
683     cMax = PetscMin(cEnd, cMax);
684     /* All cells have 4 faces */
685     for (c = cStart; c < cMax; ++c) {
686       for (r = 0; r < 3; ++r) {
687         const PetscInt newp = (c - cStart)*3 + r;
688 
689         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
690       }
691     }
692     for (c = cMax; c < cEnd; ++c) {
693       for (r = 0; r < 4; ++r) {
694         const PetscInt newp = (cMax - cStart)*3 + (c - cMax)*4 + r;
695 
696         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
697       }
698     }
699     /* Split faces have 2 vertices and the same cells as the parent */
700     for (f = fStart; f < fEnd; ++f) {
701       for (r = 0; r < 2; ++r) {
702         const PetscInt newp = fStartNew + (f - fStart)*2 + r;
703         PetscInt       size;
704 
705         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
706         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
707         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
708       }
709     }
710     /* Interior faces have 2 vertices and 2 cells */
711     for (c = cStart; c < cMax; ++c) {
712       for (r = 0; r < 3; ++r) {
713         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*3 + r;
714 
715         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
716         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
717       }
718     }
719     /* Hybrid interior faces have 2 vertices and 2 cells */
720     for (c = cMax; c < cEnd; ++c) {
721       for (r = 0; r < 4; ++r) {
722         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (cMax - cStart)*3 + (c - cMax)*4 + r;
723 
724         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
725         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
726       }
727     }
728     /* Old vertices have identical supports */
729     for (v = vStart; v < vEnd; ++v) {
730       const PetscInt newp = vStartNew + (v - vStart);
731       PetscInt       size;
732 
733       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
734       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
735     }
736     /* Split-face vertices have cells + 2 supports */
737     for (f = fStart; f < fEnd; ++f) {
738       const PetscInt newp = vStartNew + (vEnd - vStart) + (f - fStart);
739       PetscInt       size;
740 
741       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
742       ierr = DMPlexSetSupportSize(rdm, newp, size + 2);CHKERRQ(ierr);
743     }
744     /* Interior vertices have 3 supports */
745     for (c = cStart; c < cMax; ++c) {
746       const PetscInt newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + c - cStart;
747 
748       ierr = DMPlexSetSupportSize(rdm, newp, 3);CHKERRQ(ierr);
749     }
750     /* Hybrid interior vertices have 4 supports */
751     for (c = cMax; c < cEnd; ++c) {
752       const PetscInt newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + c - cStart;
753 
754       ierr = DMPlexSetSupportSize(rdm, newp, 4);CHKERRQ(ierr);
755     }
756     break;
757   case REFINER_HEX_2D:
758     /* All cells have 4 faces */
759     for (c = cStart; c < cEnd; ++c) {
760       for (r = 0; r < 4; ++r) {
761         const PetscInt newp = cStartNew + (c - cStart)*4 + r;
762 
763         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
764       }
765     }
766     /* Split faces have 2 vertices and the same cells as the parent */
767     for (f = fStart; f < fEnd; ++f) {
768       for (r = 0; r < 2; ++r) {
769         const PetscInt newp = fStartNew + (f - fStart)*2 + r;
770         PetscInt       size;
771 
772         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
773         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
774         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
775       }
776     }
777     /* Interior faces have 2 vertices and 2 cells */
778     for (c = cStart; c < cEnd; ++c) {
779       for (r = 0; r < 4; ++r) {
780         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*4 + r;
781 
782         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
783         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
784       }
785     }
786     /* Old vertices have identical supports */
787     for (v = vStart; v < vEnd; ++v) {
788       const PetscInt newp = vStartNew + (v - vStart);
789       PetscInt       size;
790 
791       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
792       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
793     }
794     /* Face vertices have 2 + cells supports */
795     for (f = fStart; f < fEnd; ++f) {
796       const PetscInt newp = vStartNew + (vEnd - vStart) + (f - fStart);
797       PetscInt       size;
798 
799       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
800       ierr = DMPlexSetSupportSize(rdm, newp, 2 + size);CHKERRQ(ierr);
801     }
802     /* Cell vertices have 4 supports */
803     for (c = cStart; c < cEnd; ++c) {
804       const PetscInt newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (c - cStart);
805 
806       ierr = DMPlexSetSupportSize(rdm, newp, 4);CHKERRQ(ierr);
807     }
808     break;
809   case REFINER_HYBRID_SIMPLEX_2D:
810     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
811     cMax = PetscMin(cEnd, cMax);
812     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
813     fMax = PetscMin(fEnd, fMax);
814     ierr = DMPlexSetHybridBounds(rdm, cStartNew + (cMax - cStart)*4, fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3, PETSC_DETERMINE, PETSC_DETERMINE);CHKERRQ(ierr);
815     /* Interior cells have 3 faces */
816     for (c = cStart; c < cMax; ++c) {
817       for (r = 0; r < 4; ++r) {
818         const PetscInt newp = cStartNew + (c - cStart)*4 + r;
819 
820         ierr = DMPlexSetConeSize(rdm, newp, 3);CHKERRQ(ierr);
821       }
822     }
823     /* Hybrid cells have 4 faces */
824     for (c = cMax; c < cEnd; ++c) {
825       for (r = 0; r < 2; ++r) {
826         const PetscInt newp = cStartNew + (cMax - cStart)*4 + (c - cMax)*2 + r;
827 
828         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
829       }
830     }
831     /* Interior split faces have 2 vertices and the same cells as the parent */
832     for (f = fStart; f < fMax; ++f) {
833       for (r = 0; r < 2; ++r) {
834         const PetscInt newp = fStartNew + (f - fStart)*2 + r;
835         PetscInt       size;
836 
837         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
838         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
839         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
840       }
841     }
842     /* Interior cell faces have 2 vertices and 2 cells */
843     for (c = cStart; c < cMax; ++c) {
844       for (r = 0; r < 3; ++r) {
845         const PetscInt newp = fStartNew + (fMax - fStart)*2 + (c - cStart)*3 + r;
846 
847         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
848         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
849       }
850     }
851     /* Hybrid faces have 2 vertices and the same cells */
852     for (f = fMax; f < fEnd; ++f) {
853       const PetscInt newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (f - fMax);
854       PetscInt       size;
855 
856       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
857       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
858       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
859     }
860     /* Hybrid cell faces have 2 vertices and 2 cells */
861     for (c = cMax; c < cEnd; ++c) {
862       const PetscInt newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (fEnd - fMax) + (c - cMax);
863 
864       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
865       ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
866     }
867     /* Old vertices have identical supports */
868     for (v = vStart; v < vEnd; ++v) {
869       const PetscInt newp = vStartNew + (v - vStart);
870       PetscInt       size;
871 
872       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
873       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
874     }
875     /* Face vertices have 2 + (2 interior, 1 hybrid) supports */
876     for (f = fStart; f < fMax; ++f) {
877       const PetscInt newp = vStartNew + (vEnd - vStart) + (f - fStart);
878       const PetscInt *support;
879       PetscInt       size, newSize = 2, s;
880 
881       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
882       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
883       for (s = 0; s < size; ++s) {
884         if (support[s] >= cMax) newSize += 1;
885         else newSize += 2;
886       }
887       ierr = DMPlexSetSupportSize(rdm, newp, newSize);CHKERRQ(ierr);
888     }
889     break;
890   case REFINER_HYBRID_HEX_2D:
891     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
892     cMax = PetscMin(cEnd, cMax);
893     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
894     fMax = PetscMin(fEnd, fMax);
895     ierr = DMPlexSetHybridBounds(rdm, cStartNew + (cMax - cStart)*4, fStartNew + (fMax - fStart)*2 + (cMax - cStart)*4, PETSC_DETERMINE, PETSC_DETERMINE);CHKERRQ(ierr);
896     /* Interior cells have 4 faces */
897     for (c = cStart; c < cMax; ++c) {
898       for (r = 0; r < 4; ++r) {
899         const PetscInt newp = cStartNew + (c - cStart)*4 + r;
900 
901         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
902       }
903     }
904     /* Hybrid cells have 4 faces */
905     for (c = cMax; c < cEnd; ++c) {
906       for (r = 0; r < 2; ++r) {
907         const PetscInt newp = cStartNew + (cMax - cStart)*4 + (c - cMax)*2 + r;
908 
909         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
910       }
911     }
912     /* Interior split faces have 2 vertices and the same cells as the parent */
913     for (f = fStart; f < fMax; ++f) {
914       for (r = 0; r < 2; ++r) {
915         const PetscInt newp = fStartNew + (f - fStart)*2 + r;
916         PetscInt       size;
917 
918         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
919         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
920         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
921       }
922     }
923     /* Interior cell faces have 2 vertices and 2 cells */
924     for (c = cStart; c < cMax; ++c) {
925       for (r = 0; r < 4; ++r) {
926         const PetscInt newp = fStartNew + (fMax - fStart)*2 + (c - cStart)*4 + r;
927 
928         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
929         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
930       }
931     }
932     /* Hybrid faces have 2 vertices and the same cells */
933     for (f = fMax; f < fEnd; ++f) {
934       const PetscInt newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*4 + (f - fMax);
935       PetscInt       size;
936 
937       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
938       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
939       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
940     }
941     /* Hybrid cell faces have 2 vertices and 2 cells */
942     for (c = cMax; c < cEnd; ++c) {
943       const PetscInt newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*4 + (fEnd - fMax) + (c - cMax);
944 
945       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
946       ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
947     }
948     /* Old vertices have identical supports */
949     for (v = vStart; v < vEnd; ++v) {
950       const PetscInt newp = vStartNew + (v - vStart);
951       PetscInt       size;
952 
953       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
954       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
955     }
956     /* Face vertices have 2 + cells supports */
957     for (f = fStart; f < fMax; ++f) {
958       const PetscInt newp = vStartNew + (vEnd - vStart) + (f - fStart);
959       PetscInt       size;
960 
961       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
962       ierr = DMPlexSetSupportSize(rdm, newp, 2 + size);CHKERRQ(ierr);
963     }
964     /* Cell vertices have 4 supports */
965     for (c = cStart; c < cMax; ++c) {
966       const PetscInt newp = vStartNew + (vEnd - vStart) + (fMax - fStart) + (c - cStart);
967 
968       ierr = DMPlexSetSupportSize(rdm, newp, 4);CHKERRQ(ierr);
969     }
970     break;
971   case REFINER_SIMPLEX_3D:
972     /* All cells have 4 faces */
973     for (c = cStart; c < cEnd; ++c) {
974       for (r = 0; r < 8; ++r) {
975         const PetscInt newp = cStartNew + (c - cStart)*8 + r;
976 
977         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
978       }
979     }
980     /* Split faces have 3 edges and the same cells as the parent */
981     for (f = fStart; f < fEnd; ++f) {
982       for (r = 0; r < 4; ++r) {
983         const PetscInt newp = fStartNew + (f - fStart)*4 + r;
984         PetscInt       size;
985 
986         ierr = DMPlexSetConeSize(rdm, newp, 3);CHKERRQ(ierr);
987         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
988         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
989       }
990     }
991     /* Interior cell faces have 3 edges and 2 cells */
992     for (c = cStart; c < cEnd; ++c) {
993       for (r = 0; r < 8; ++r) {
994         const PetscInt newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*8 + r;
995 
996         ierr = DMPlexSetConeSize(rdm, newp, 3);CHKERRQ(ierr);
997         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
998       }
999     }
1000     /* Split edges have 2 vertices and the same faces */
1001     for (e = eStart; e < eEnd; ++e) {
1002       for (r = 0; r < 2; ++r) {
1003         const PetscInt newp = eStartNew + (e - eStart)*2 + r;
1004         PetscInt       size;
1005 
1006         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
1007         ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
1008         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
1009       }
1010     }
1011     /* Face edges have 2 vertices and 2+cells*(1/2) faces */
1012     for (f = fStart; f < fEnd; ++f) {
1013       for (r = 0; r < 3; ++r) {
1014         const PetscInt  newp = eStartNew + (eEnd - eStart)*2 + (f - fStart)*3 + r;
1015         const PetscInt *cone, *ornt, *support, eint[4] = {1, 0, 2, 0};
1016         PetscInt        coneSize, c, supportSize, s, er, intFaces = 0;
1017 
1018         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
1019         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
1020         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
1021         for (s = 0; s < supportSize; ++s) {
1022           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
1023           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
1024           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
1025           for (c = 0; c < coneSize; ++c) {if (cone[c] == f) break;}
1026           /* Here we want to determine whether edge newp contains a vertex which is part of the cross-tet edge */
1027           er = GetTriMidEdgeInverse_Static(ornt[c], r);
1028           if (er == eint[c]) {
1029             intFaces += 1;
1030           } else {
1031             intFaces += 2;
1032           }
1033         }
1034         ierr = DMPlexSetSupportSize(rdm, newp, 2+intFaces);CHKERRQ(ierr);
1035       }
1036     }
1037     /* Interior cell edges have 2 vertices and 4 faces */
1038     for (c = cStart; c < cEnd; ++c) {
1039       const PetscInt newp = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart);
1040 
1041       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
1042       ierr = DMPlexSetSupportSize(rdm, newp, 4);CHKERRQ(ierr);
1043     }
1044     /* Old vertices have identical supports */
1045     for (v = vStart; v < vEnd; ++v) {
1046       const PetscInt newp = vStartNew + (v - vStart);
1047       PetscInt       size;
1048 
1049       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
1050       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
1051     }
1052     /* Edge vertices have 2 + faces*2 + cells*0/1 supports */
1053     for (e = eStart; e < eEnd; ++e) {
1054       const PetscInt newp = vStartNew + (vEnd - vStart) + (e - eStart);
1055       PetscInt       size, *star = NULL, starSize, s, cellSize = 0;
1056 
1057       ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
1058       ierr = DMPlexGetTransitiveClosure(dm, e, PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
1059       for (s = 0; s < starSize*2; s += 2) {
1060         const PetscInt *cone, *ornt;
1061         PetscInt        e01, e23;
1062 
1063         if ((star[s] >= cStart) && (star[s] < cEnd)) {
1064           /* Check edge 0-1 */
1065           ierr = DMPlexGetCone(dm, star[s], &cone);CHKERRQ(ierr);
1066           ierr = DMPlexGetConeOrientation(dm, star[s], &ornt);CHKERRQ(ierr);
1067           ierr = DMPlexGetCone(dm, cone[0], &cone);CHKERRQ(ierr);
1068           e01  = cone[GetTriEdge_Static(ornt[0], 0)];
1069           /* Check edge 2-3 */
1070           ierr = DMPlexGetCone(dm, star[s], &cone);CHKERRQ(ierr);
1071           ierr = DMPlexGetConeOrientation(dm, star[s], &ornt);CHKERRQ(ierr);
1072           ierr = DMPlexGetCone(dm, cone[2], &cone);CHKERRQ(ierr);
1073           e23  = cone[GetTriEdge_Static(ornt[2], 1)];
1074           if ((e01 == e) || (e23 == e)) ++cellSize;
1075         }
1076       }
1077       ierr = DMPlexRestoreTransitiveClosure(dm, e, PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
1078       ierr = DMPlexSetSupportSize(rdm, newp, 2 + size*2 + cellSize);CHKERRQ(ierr);
1079     }
1080     break;
1081   case REFINER_HYBRID_SIMPLEX_3D:
1082     ierr = DMPlexSetHybridBounds(rdm, cStartNew + 8*(cMax-cStart), fStartNew + 4*(fMax - fStart) + 8*(cMax - cStart),
1083                                  eStartNew + 2*(eMax - eStart) + 3*(fMax - fStart) + (cMax - cStart), PETSC_DETERMINE);CHKERRQ(ierr);
1084     /* Interior cells have 4 faces */
1085     for (c = cStart; c < cMax; ++c) {
1086       for (r = 0; r < 8; ++r) {
1087         const PetscInt newp = cStartNew + (c - cStart)*8 + r;
1088 
1089         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
1090       }
1091     }
1092     /* Hybrid cells have 5 faces */
1093     for (c = cMax; c < cEnd; ++c) {
1094       for (r = 0; r < 4; ++r) {
1095         const PetscInt newp = cStartNew + (cMax - cStart)*8 + (c - cMax)*4 + r;
1096 
1097         ierr = DMPlexSetConeSize(rdm, newp, 5);CHKERRQ(ierr);
1098       }
1099     }
1100     /* Interior split faces have 3 edges and the same cells as the parent */
1101     for (f = fStart; f < fMax; ++f) {
1102       for (r = 0; r < 4; ++r) {
1103         const PetscInt newp = fStartNew + (f - fStart)*4 + r;
1104         PetscInt       size;
1105 
1106         ierr = DMPlexSetConeSize(rdm, newp, 3);CHKERRQ(ierr);
1107         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
1108         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
1109       }
1110     }
1111     /* Interior cell faces have 3 edges and 2 cells */
1112     for (c = cStart; c < cMax; ++c) {
1113       for (r = 0; r < 8; ++r) {
1114         const PetscInt newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*8 + r;
1115 
1116         ierr = DMPlexSetConeSize(rdm, newp, 3);CHKERRQ(ierr);
1117         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
1118       }
1119     }
1120     /* Hybrid split faces have 4 edges and the same cells as the parent */
1121     for (f = fMax; f < fEnd; ++f) {
1122       for (r = 0; r < 2; ++r) {
1123         const PetscInt newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (f - fMax)*2 + r;
1124         PetscInt       size;
1125 
1126         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
1127         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
1128         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
1129       }
1130     }
1131     /* Hybrid cells faces have 4 edges and 2 cells */
1132     for (c = cMax; c < cEnd; ++c) {
1133       for (r = 0; r < 3; ++r) {
1134         const PetscInt newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (c - cMax)*3 + r;
1135 
1136         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
1137         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
1138       }
1139     }
1140     /* Interior split edges have 2 vertices and the same faces */
1141     for (e = eStart; e < eMax; ++e) {
1142       for (r = 0; r < 2; ++r) {
1143         const PetscInt newp = eStartNew + (e - eStart)*2 + r;
1144         PetscInt       size;
1145 
1146         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
1147         ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
1148         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
1149       }
1150     }
1151     /* Interior face edges have 2 vertices and 2+cells*(1/2) faces */
1152     for (f = fStart; f < fMax; ++f) {
1153       for (r = 0; r < 3; ++r) {
1154         const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (f - fStart)*3 + r;
1155         const PetscInt *cone, *ornt, *support, eint[4] = {1, 0, 2, 0};
1156         PetscInt        coneSize, c, supportSize, s, er, intFaces = 0;
1157 
1158         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
1159         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
1160         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
1161         for (s = 0; s < supportSize; ++s) {
1162           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
1163           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
1164           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
1165           for (c = 0; c < coneSize; ++c) {if (cone[c] == f) break;}
1166           if (support[s] < cMax) {
1167             /* Here we want to determine whether edge newp contains a vertex which is part of the cross-tet edge */
1168             er = GetTriMidEdgeInverse_Static(ornt[c], r);
1169             if (er == eint[c]) {
1170               intFaces += 1;
1171             } else {
1172               intFaces += 2;
1173             }
1174           } else {
1175             intFaces += 1;
1176           }
1177         }
1178         ierr = DMPlexSetSupportSize(rdm, newp, 2+intFaces);CHKERRQ(ierr);
1179       }
1180     }
1181     /* Interior cell edges have 2 vertices and 4 faces */
1182     for (c = cStart; c < cMax; ++c) {
1183       const PetscInt newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart);
1184 
1185       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
1186       ierr = DMPlexSetSupportSize(rdm, newp, 4);CHKERRQ(ierr);
1187     }
1188     /* Hybrid edges have 2 vertices and the same faces */
1189     for (e = eMax; e < eEnd; ++e) {
1190       const PetscInt newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (e - eMax);
1191       PetscInt       size;
1192 
1193       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
1194       ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
1195       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
1196     }
1197     /* Hybrid face edges have 2 vertices and 2+2*cells faces */
1198     for (f = fMax; f < fEnd; ++f) {
1199       const PetscInt newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (eEnd - eMax) + (f - fMax);
1200       PetscInt       size;
1201 
1202       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
1203       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
1204       ierr = DMPlexSetSupportSize(rdm, newp, 2+2*size);CHKERRQ(ierr);
1205     }
1206     /* Interior vertices have identical supports */
1207     for (v = vStart; v < vEnd; ++v) {
1208       const PetscInt newp = vStartNew + (v - vStart);
1209       PetscInt       size;
1210 
1211       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
1212       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
1213     }
1214     /* Interior edge vertices have 2 + interior face*2 + hybrid face + cells*0/1 supports */
1215     for (e = eStart; e < eMax; ++e) {
1216       const PetscInt  newp = vStartNew + (vEnd - vStart) + (e - eStart);
1217       const PetscInt *support;
1218       PetscInt        size, *star = NULL, starSize, s, faceSize = 0, cellSize = 0;
1219 
1220       ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
1221       ierr = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
1222       for (s = 0; s < size; ++s) {
1223         if (support[s] < fMax) faceSize += 2;
1224         else                   faceSize += 1;
1225       }
1226       ierr = DMPlexGetTransitiveClosure(dm, e, PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
1227       for (s = 0; s < starSize*2; s += 2) {
1228         const PetscInt *cone, *ornt;
1229         PetscInt        e01, e23;
1230 
1231         if ((star[s] >= cStart) && (star[s] < cMax)) {
1232           /* Check edge 0-1 */
1233           ierr = DMPlexGetCone(dm, star[s], &cone);CHKERRQ(ierr);
1234           ierr = DMPlexGetConeOrientation(dm, star[s], &ornt);CHKERRQ(ierr);
1235           ierr = DMPlexGetCone(dm, cone[0], &cone);CHKERRQ(ierr);
1236           e01  = cone[GetTriEdge_Static(ornt[0], 0)];
1237           /* Check edge 2-3 */
1238           ierr = DMPlexGetCone(dm, star[s], &cone);CHKERRQ(ierr);
1239           ierr = DMPlexGetConeOrientation(dm, star[s], &ornt);CHKERRQ(ierr);
1240           ierr = DMPlexGetCone(dm, cone[2], &cone);CHKERRQ(ierr);
1241           e23  = cone[GetTriEdge_Static(ornt[2], 1)];
1242           if ((e01 == e) || (e23 == e)) ++cellSize;
1243         }
1244       }
1245       ierr = DMPlexRestoreTransitiveClosure(dm, e, PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
1246       ierr = DMPlexSetSupportSize(rdm, newp, 2 + faceSize + cellSize);CHKERRQ(ierr);
1247     }
1248     break;
1249   case REFINER_SIMPLEX_TO_HEX_3D:
1250     /* All cells have 6 faces */
1251     for (c = cStart; c < cEnd; ++c) {
1252       for (r = 0; r < 4; ++r) {
1253         const PetscInt newp = cStartNew + (c - cStart)*4 + r;
1254 
1255         ierr = DMPlexSetConeSize(rdm, newp, 6);CHKERRQ(ierr);
1256       }
1257     }
1258     /* Split faces have 4 edges and the same cells as the parent */
1259     for (f = fStart; f < fEnd; ++f) {
1260       for (r = 0; r < 3; ++r) {
1261         const PetscInt newp = fStartNew + (f - fStart)*3 + r;
1262         PetscInt       size;
1263 
1264         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
1265         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
1266         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
1267       }
1268     }
1269     /* Interior cell faces have 4 edges and 2 cells */
1270     for (c = cStart; c < cEnd; ++c) {
1271       for (r = 0; r < 6; ++r) {
1272         const PetscInt newp = fStartNew + (fEnd - fStart)*3 + (c - cStart)*6 + r;
1273 
1274         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
1275         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
1276       }
1277     }
1278     /* Split edges have 2 vertices and the same faces */
1279     for (e = eStart; e < eEnd; ++e) {
1280       for (r = 0; r < 2; ++r) {
1281         const PetscInt newp = eStartNew + (e - eStart)*2 + r;
1282         PetscInt       size;
1283 
1284         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
1285         ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
1286         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
1287       }
1288     }
1289     /* Face edges have 2 vertices and 2 + cell faces supports */
1290     for (f = fStart; f < fEnd; ++f) {
1291       for (r = 0; r < 3; ++r) {
1292         const PetscInt  newp = eStartNew + (eEnd - eStart)*2 + (f - fStart)*3 + r;
1293         PetscInt        size;
1294 
1295         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
1296         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
1297         ierr = DMPlexSetSupportSize(rdm, newp, 2+size);CHKERRQ(ierr);
1298       }
1299     }
1300     /* Interior cell edges have 2 vertices and 3 faces */
1301     for (c = cStart; c < cEnd; ++c) {
1302       for (r = 0; r < 4; ++r) {
1303         const PetscInt newp = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + r;
1304 
1305         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
1306         ierr = DMPlexSetSupportSize(rdm, newp, 3);CHKERRQ(ierr);
1307       }
1308     }
1309     /* Old vertices have identical supports */
1310     for (v = vStart; v < vEnd; ++v) {
1311       const PetscInt newp = vStartNew + (v - vStart);
1312       PetscInt       size;
1313 
1314       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
1315       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
1316     }
1317     /* Edge vertices have 2 + faces supports */
1318     for (e = eStart; e < eEnd; ++e) {
1319       const PetscInt newp = vStartNew + (vEnd - vStart) + (e - eStart);
1320       PetscInt       size;
1321 
1322       ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
1323       ierr = DMPlexSetSupportSize(rdm, newp, 2 + size);CHKERRQ(ierr);
1324     }
1325     /* Face vertices have 3 + cells supports */
1326     for (f = fStart; f < fEnd; ++f) {
1327       const PetscInt newp = vStartNew + (vEnd - vStart) + (eEnd - eStart) + f - fStart;
1328       PetscInt       size;
1329 
1330       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
1331       ierr = DMPlexSetSupportSize(rdm, newp, 3 + size);CHKERRQ(ierr);
1332     }
1333     /* Interior cell vertices have 4 supports */
1334     for (c = cStart; c < cEnd; ++c) {
1335       const PetscInt newp = vStartNew + (vEnd - vStart) + (eEnd - eStart) + fEnd - fStart + c - cStart;
1336 
1337       ierr = DMPlexSetSupportSize(rdm, newp, 4);CHKERRQ(ierr);
1338     }
1339     break;
1340   case REFINER_HYBRID_SIMPLEX_TO_HEX_3D:
1341     /* the mesh is no longer hybrid */
1342     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
1343     cMax = PetscMin(cEnd, cMax);
1344     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
1345     fMax = PetscMin(fEnd, fMax);
1346     if (eMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No edge maximum specified in hybrid mesh");
1347     eMax = PetscMin(eEnd, eMax);
1348     /* All cells have 6 faces */
1349     for (c = cStart; c < cMax; ++c) {
1350       for (r = 0; r < 4; ++r) {
1351         const PetscInt newp = cStartNew + (c - cStart)*4 + r;
1352 
1353         ierr = DMPlexSetConeSize(rdm, newp, 6);CHKERRQ(ierr);
1354       }
1355     }
1356     for (c = cMax; c < cEnd; ++c) {
1357       for (r = 0; r < 3; ++r) {
1358         const PetscInt newp = cStartNew + (cMax - cStart)*4 + (c - cMax)*3 + r;
1359 
1360         ierr = DMPlexSetConeSize(rdm, newp, 6);CHKERRQ(ierr);
1361       }
1362     }
1363     /* Interior split faces have 4 edges and the same cells as the parent */
1364     for (f = fStart; f < fMax; ++f) {
1365       for (r = 0; r < 3; ++r) {
1366         const PetscInt newp = fStartNew + (f - fStart)*3 + r;
1367         PetscInt       size;
1368 
1369         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
1370         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
1371         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
1372       }
1373     }
1374     /* Interior cell faces have 4 edges and 2 cells */
1375     for (c = cStart; c < cMax; ++c) {
1376       for (r = 0; r < 6; ++r) {
1377         const PetscInt newp = fStartNew + (fMax - fStart)*3 + (c - cStart)*6 + r;
1378 
1379         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
1380         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
1381       }
1382     }
1383     /* Hybrid split faces have 4 edges and the same cells as the parent */
1384     for (f = fMax; f < fEnd; ++f) {
1385       for (r = 0; r < 2; ++r) {
1386         const PetscInt newp = fStartNew + (fMax - fStart)*3 + (cMax - cStart)*6 + (f - fMax)*2 + r;
1387         PetscInt       size;
1388 
1389         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
1390         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
1391         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
1392       }
1393     }
1394     /* Hybrid cell faces have 4 edges and 2 cells */
1395     for (c = cMax; c < cEnd; ++c) {
1396       for (r = 0; r < 3; ++r) {
1397         const PetscInt newp = fStartNew + (fMax - fStart)*3 + (cMax - cStart)*6 + (fEnd - fMax)*2 + (c - cMax)*3 + r;
1398 
1399         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
1400         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
1401       }
1402     }
1403     /* Interior split edges have 2 vertices and the same faces */
1404     for (e = eStart; e < eMax; ++e) {
1405       for (r = 0; r < 2; ++r) {
1406         const PetscInt newp = eStartNew + (e - eStart)*2 + r;
1407         PetscInt       size;
1408 
1409         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
1410         ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
1411         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
1412       }
1413     }
1414     /* Interior face edges have 2 vertices and 2 + cell faces supports */
1415     for (f = fStart; f < fMax; ++f) {
1416       for (r = 0; r < 3; ++r) {
1417         const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (f - fStart)*3 + r;
1418         PetscInt        size;
1419 
1420         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
1421         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
1422         ierr = DMPlexSetSupportSize(rdm, newp, 2+size);CHKERRQ(ierr);
1423       }
1424     }
1425     /* Interior cell edges have 2 vertices and 3 faces */
1426     for (c = cStart; c < cMax; ++c) {
1427       for (r = 0; r < 4; ++r) {
1428         const PetscInt newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart)*4 + r;
1429 
1430         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
1431         ierr = DMPlexSetSupportSize(rdm, newp, 3);CHKERRQ(ierr);
1432       }
1433     }
1434     /* Hybrid edges have 2 vertices and the same faces */
1435     for (e = eMax; e < eEnd; ++e) {
1436       const PetscInt newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart)*4 + (e - eMax);
1437       PetscInt       size;
1438 
1439       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
1440       ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
1441       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
1442     }
1443     /* Hybrid face edges have 2 vertices and 2+cells faces */
1444     for (f = fMax; f < fEnd; ++f) {
1445       const PetscInt newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart)*4 + (eEnd - eMax) + (f - fMax);
1446       PetscInt        size;
1447 
1448       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
1449       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
1450       ierr = DMPlexSetSupportSize(rdm, newp, 2+size);CHKERRQ(ierr);
1451     }
1452     /* Hybrid cell edges have 2 vertices and 3 faces */
1453     for (c = cMax; c < cEnd; ++c) {
1454       const PetscInt newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart)*4 + (eEnd - eMax) + (fEnd - fMax) + (c - cMax);
1455 
1456       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
1457       ierr = DMPlexSetSupportSize(rdm, newp, 3);CHKERRQ(ierr);
1458     }
1459     /* Old vertices have identical supports */
1460     for (v = vStart; v < vEnd; ++v) {
1461       const PetscInt newp = vStartNew + (v - vStart);
1462       PetscInt       size;
1463 
1464       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
1465       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
1466     }
1467     /* Interior edge vertices have 2 + faces supports */
1468     for (e = eStart; e < eMax; ++e) {
1469       const PetscInt newp = vStartNew + (vEnd - vStart) + (e - eStart);
1470       PetscInt       size;
1471 
1472       ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
1473       ierr = DMPlexSetSupportSize(rdm, newp, 2 + size);CHKERRQ(ierr);
1474     }
1475     /* Interior face vertices have 3 + cells supports */
1476     for (f = fStart; f < fMax; ++f) {
1477       const PetscInt newp = vStartNew + (vEnd - vStart) + (eMax - eStart) + f - fStart;
1478       PetscInt       size;
1479 
1480       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
1481       ierr = DMPlexSetSupportSize(rdm, newp, 3 + size);CHKERRQ(ierr);
1482     }
1483     /* Interior cell vertices have 4 supports */
1484     for (c = cStart; c < cMax; ++c) {
1485       const PetscInt newp = vStartNew + (vEnd - vStart) + (eMax - eStart) + (fMax - fStart) + c - cStart;
1486 
1487       ierr = DMPlexSetSupportSize(rdm, newp, 4);CHKERRQ(ierr);
1488     }
1489     break;
1490   case REFINER_HEX_3D:
1491     /* All cells have 6 faces */
1492     for (c = cStart; c < cEnd; ++c) {
1493       for (r = 0; r < 8; ++r) {
1494         const PetscInt newp = (c - cStart)*8 + r;
1495 
1496         ierr = DMPlexSetConeSize(rdm, newp, 6);CHKERRQ(ierr);
1497       }
1498     }
1499     /* Split faces have 4 edges and the same cells as the parent */
1500     for (f = fStart; f < fEnd; ++f) {
1501       for (r = 0; r < 4; ++r) {
1502         const PetscInt newp = fStartNew + (f - fStart)*4 + r;
1503         PetscInt       size;
1504 
1505         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
1506         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
1507         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
1508       }
1509     }
1510     /* Interior faces have 4 edges and 2 cells */
1511     for (c = cStart; c < cEnd; ++c) {
1512       for (r = 0; r < 12; ++r) {
1513         const PetscInt newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + r;
1514 
1515         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
1516         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
1517       }
1518     }
1519     /* Split edges have 2 vertices and the same faces as the parent */
1520     for (e = eStart; e < eEnd; ++e) {
1521       for (r = 0; r < 2; ++r) {
1522         const PetscInt newp = eStartNew + (e - eStart)*2 + r;
1523         PetscInt       size;
1524 
1525         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
1526         ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
1527         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
1528       }
1529     }
1530     /* Face edges have 2 vertices and 2+cells faces */
1531     for (f = fStart; f < fEnd; ++f) {
1532       for (r = 0; r < 4; ++r) {
1533         const PetscInt newp = eStartNew + (eEnd - eStart)*2 + (f - fStart)*4 + r;
1534         PetscInt       size;
1535 
1536         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
1537         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
1538         ierr = DMPlexSetSupportSize(rdm, newp, 2+size);CHKERRQ(ierr);
1539       }
1540     }
1541     /* Cell edges have 2 vertices and 4 faces */
1542     for (c = cStart; c < cEnd; ++c) {
1543       for (r = 0; r < 6; ++r) {
1544         const PetscInt newp = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*4 + (c - cStart)*6 + r;
1545 
1546         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
1547         ierr = DMPlexSetSupportSize(rdm, newp, 4);CHKERRQ(ierr);
1548       }
1549     }
1550     /* Old vertices have identical supports */
1551     for (v = vStart; v < vEnd; ++v) {
1552       const PetscInt newp = vStartNew + (v - vStart);
1553       PetscInt       size;
1554 
1555       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
1556       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
1557     }
1558     /* Edge vertices have 2 + faces supports */
1559     for (e = eStart; e < eEnd; ++e) {
1560       const PetscInt newp = vStartNew + (vEnd - vStart) + (e - eStart);
1561       PetscInt       size;
1562 
1563       ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
1564       ierr = DMPlexSetSupportSize(rdm, newp, 2 + size);CHKERRQ(ierr);
1565     }
1566     /* Face vertices have 4 + cells supports */
1567     for (f = fStart; f < fEnd; ++f) {
1568       const PetscInt newp = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (f - fStart);
1569       PetscInt       size;
1570 
1571       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
1572       ierr = DMPlexSetSupportSize(rdm, newp, 4 + size);CHKERRQ(ierr);
1573     }
1574     /* Cell vertices have 6 supports */
1575     for (c = cStart; c < cEnd; ++c) {
1576       const PetscInt newp = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (fEnd - fStart) + (c - cStart);
1577 
1578       ierr = DMPlexSetSupportSize(rdm, newp, 6);CHKERRQ(ierr);
1579     }
1580     break;
1581   case REFINER_HYBRID_HEX_3D:
1582     ierr = DMPlexSetHybridBounds(rdm, cStartNew + 8*(cMax-cStart), fStartNew + 4*(fMax - fStart) + 12*(cMax - cStart),
1583                                  eStartNew + 2*(eMax - eStart) + 4*(fMax - fStart) + 6*(cMax - cStart), PETSC_DETERMINE);CHKERRQ(ierr);
1584     /* Interior cells have 6 faces */
1585     for (c = cStart; c < cMax; ++c) {
1586       for (r = 0; r < 8; ++r) {
1587         const PetscInt newp = cStartNew + (c - cStart)*8 + r;
1588 
1589         ierr = DMPlexSetConeSize(rdm, newp, 6);CHKERRQ(ierr);
1590       }
1591     }
1592     /* Hybrid cells have 6 faces */
1593     for (c = cMax; c < cEnd; ++c) {
1594       for (r = 0; r < 4; ++r) {
1595         const PetscInt newp = cStartNew + (cMax - cStart)*8 + (c - cMax)*4 + r;
1596 
1597         ierr = DMPlexSetConeSize(rdm, newp, 6);CHKERRQ(ierr);
1598       }
1599     }
1600     /* Interior split faces have 4 edges and the same cells as the parent */
1601     for (f = fStart; f < fMax; ++f) {
1602       for (r = 0; r < 4; ++r) {
1603         const PetscInt newp = fStartNew + (f - fStart)*4 + r;
1604         PetscInt       size;
1605 
1606         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
1607         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
1608         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
1609       }
1610     }
1611     /* Interior cell faces have 4 edges and 2 cells */
1612     for (c = cStart; c < cMax; ++c) {
1613       for (r = 0; r < 12; ++r) {
1614         const PetscInt newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + r;
1615 
1616         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
1617         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
1618       }
1619     }
1620     /* Hybrid split faces have 4 edges and the same cells as the parent */
1621     for (f = fMax; f < fEnd; ++f) {
1622       for (r = 0; r < 2; ++r) {
1623         const PetscInt newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (f - fMax)*2 + r;
1624         PetscInt       size;
1625 
1626         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
1627         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
1628         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
1629       }
1630     }
1631     /* Hybrid cells faces have 4 edges and 2 cells */
1632     for (c = cMax; c < cEnd; ++c) {
1633       for (r = 0; r < 4; ++r) {
1634         const PetscInt newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd - fMax)*2 + (c - cMax)*4 + r;
1635 
1636         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
1637         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
1638       }
1639     }
1640     /* Interior split edges have 2 vertices and the same faces as the parent */
1641     for (e = eStart; e < eMax; ++e) {
1642       for (r = 0; r < 2; ++r) {
1643         const PetscInt newp = eStartNew + (e - eStart)*2 + r;
1644         PetscInt       size;
1645 
1646         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
1647         ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
1648         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
1649       }
1650     }
1651     /* Interior face edges have 2 vertices and 2+cells faces */
1652     for (f = fStart; f < fMax; ++f) {
1653       for (r = 0; r < 4; ++r) {
1654         const PetscInt newp = eStartNew + (eMax - eStart)*2 + (f - fStart)*4 + r;
1655         PetscInt       size;
1656 
1657         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
1658         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
1659         ierr = DMPlexSetSupportSize(rdm, newp, 2+size);CHKERRQ(ierr);
1660       }
1661     }
1662     /* Interior cell edges have 2 vertices and 4 faces */
1663     for (c = cStart; c < cMax; ++c) {
1664       for (r = 0; r < 6; ++r) {
1665         const PetscInt newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (c - cStart)*6 + r;
1666 
1667         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
1668         ierr = DMPlexSetSupportSize(rdm, newp, 4);CHKERRQ(ierr);
1669       }
1670     }
1671     /* Hybrid edges have 2 vertices and the same faces */
1672     for (e = eMax; e < eEnd; ++e) {
1673       const PetscInt newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (e - eMax);
1674       PetscInt       size;
1675 
1676       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
1677       ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
1678       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
1679     }
1680     /* Hybrid face edges have 2 vertices and 2+cells faces */
1681     for (f = fMax; f < fEnd; ++f) {
1682       const PetscInt newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (eEnd - eMax) + (f - fMax);
1683       PetscInt       size;
1684 
1685       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
1686       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
1687       ierr = DMPlexSetSupportSize(rdm, newp, 2+size);CHKERRQ(ierr);
1688     }
1689     /* Hybrid cell edges have 2 vertices and 4 faces */
1690     for (c = cMax; c < cEnd; ++c) {
1691       const PetscInt newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (eEnd - eMax) + (fEnd - fMax) + (c - cMax);
1692 
1693       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
1694       ierr = DMPlexSetSupportSize(rdm, newp, 4);CHKERRQ(ierr);
1695     }
1696     /* Interior vertices have identical supports */
1697     for (v = vStart; v < vEnd; ++v) {
1698       const PetscInt newp = vStartNew + (v - vStart);
1699       PetscInt       size;
1700 
1701       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
1702       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
1703     }
1704     /* Interior edge vertices have 2 + faces supports */
1705     for (e = eStart; e < eMax; ++e) {
1706       const PetscInt newp = vStartNew + (vEnd - vStart) + (e - eStart);
1707       PetscInt       size;
1708 
1709       ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
1710       ierr = DMPlexSetSupportSize(rdm, newp, 2 + size);CHKERRQ(ierr);
1711     }
1712     /* Interior face vertices have 4 + cells supports */
1713     for (f = fStart; f < fMax; ++f) {
1714       const PetscInt newp = vStartNew + (vEnd - vStart) + (eMax - eStart) + (f - fStart);
1715       PetscInt       size;
1716 
1717       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
1718       ierr = DMPlexSetSupportSize(rdm, newp, 4 + size);CHKERRQ(ierr);
1719     }
1720     /* Interior cell vertices have 6 supports */
1721     for (c = cStart; c < cMax; ++c) {
1722       const PetscInt newp = vStartNew + (vEnd - vStart) + (eMax - eStart) + (fMax - fStart) + (c - cStart);
1723 
1724       ierr = DMPlexSetSupportSize(rdm, newp, 6);CHKERRQ(ierr);
1725     }
1726     break;
1727   default:
1728     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %s", CellRefiners[refiner]);
1729   }
1730   {
1731     DM_Plex *plex = (DM_Plex *) rdm->data;
1732 
1733     ierr = DMPlexGetCellTypeLabel(rdm, &celltypeLabel);CHKERRQ(ierr);
1734     ierr = PetscObjectStateGet((PetscObject) celltypeLabel, &plex->celltypeState);CHKERRQ(ierr);
1735   }
1736   PetscFunctionReturn(0);
1737 }
1738 
1739 static PetscErrorCode CellRefinerSetCones(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
1740 {
1741   const PetscInt *faces, cellInd[4] = {0, 1, 2, 3};
1742   PetscInt        cStart,    cEnd,    cMax,    vStart,    vEnd, vMax, fStart,    fEnd,    fMax,    eStart,    eEnd,    eMax;
1743   PetscInt        cStartNew, cEndNew, cMaxNew, vStartNew, vEndNew,    fStartNew, fEndNew, fMaxNew, eStartNew, eEndNew, eMaxNew;
1744   PetscInt        depth, maxSupportSize, *supportRef, c, f, e, v, r;
1745 #if defined(PETSC_USE_DEBUG)
1746   PetscInt        p;
1747 #endif
1748   PetscErrorCode  ierr;
1749 
1750   PetscFunctionBegin;
1751   if (!refiner) PetscFunctionReturn(0);
1752   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
1753   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
1754   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
1755   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
1756   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
1757   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
1758   ierr = GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);CHKERRQ(ierr);
1759   ierr = GetDepthEnd_Private(depth, depthSize, &cEndNew, &fEndNew, &eEndNew, &vEndNew);CHKERRQ(ierr);
1760   switch (refiner) {
1761   case REFINER_SIMPLEX_1D:
1762     /* Max support size of refined mesh is 2 */
1763     ierr = PetscMalloc1(2, &supportRef);CHKERRQ(ierr);
1764     /* All cells have 2 vertices */
1765     for (c = cStart; c < cEnd; ++c) {
1766       const PetscInt  newv = vStartNew + (vEnd - vStart) + (c - cStart);
1767 
1768       for (r = 0; r < 2; ++r) {
1769         const PetscInt newp = cStartNew + (c - cStart)*2 + r;
1770         const PetscInt *cone;
1771         PetscInt        coneNew[2];
1772 
1773         ierr             = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
1774         coneNew[0]       = vStartNew + (cone[0] - vStart);
1775         coneNew[1]       = vStartNew + (cone[1] - vStart);
1776         coneNew[(r+1)%2] = newv;
1777         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
1778 #if defined(PETSC_USE_DEBUG)
1779         if ((newp < cStartNew) || (newp >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", newp, cStartNew, cEndNew);
1780         for (p = 0; p < 2; ++p) {
1781           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);
1782         }
1783 #endif
1784       }
1785     }
1786     /* Old vertices have identical supports */
1787     for (v = vStart; v < vEnd; ++v) {
1788       const PetscInt  newp = vStartNew + (v - vStart);
1789       const PetscInt *support, *cone;
1790       PetscInt        size, s;
1791 
1792       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
1793       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
1794       for (s = 0; s < size; ++s) {
1795         PetscInt r = 0;
1796 
1797         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
1798         if (cone[1] == v) r = 1;
1799         supportRef[s] = cStartNew + (support[s] - cStart)*2 + r;
1800       }
1801       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
1802 #if defined(PETSC_USE_DEBUG)
1803       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", newp, vStartNew, vEndNew);
1804       for (p = 0; p < size; ++p) {
1805         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);
1806       }
1807 #endif
1808     }
1809     /* Cell vertices have support of 2 cells */
1810     for (c = cStart; c < cEnd; ++c) {
1811       const PetscInt  newp = vStartNew + (vEnd - vStart) + (c - cStart);
1812 
1813       supportRef[0] = cStartNew + (c - cStart)*2 + 0;
1814       supportRef[1] = cStartNew + (c - cStart)*2 + 1;
1815       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
1816 #if defined(PETSC_USE_DEBUG)
1817       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", newp, vStartNew, vEndNew);
1818       for (p = 0; p < 2; ++p) {
1819         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);
1820       }
1821 #endif
1822     }
1823     ierr = PetscFree(supportRef);CHKERRQ(ierr);
1824     break;
1825   case REFINER_SIMPLEX_2D:
1826     /*
1827      2
1828      |\
1829      | \
1830      |  \
1831      |   \
1832      | C  \
1833      |     \
1834      |      \
1835      2---1---1
1836      |\  D  / \
1837      | 2   0   \
1838      |A \ /  B  \
1839      0---0-------1
1840      */
1841     /* All cells have 3 faces */
1842     for (c = cStart; c < cEnd; ++c) {
1843       const PetscInt  newp = cStartNew + (c - cStart)*4;
1844       const PetscInt *cone, *ornt;
1845       PetscInt        coneNew[3], orntNew[3];
1846 
1847       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
1848       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
1849       /* A triangle */
1850       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
1851       orntNew[0] = ornt[0];
1852       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 2;
1853       orntNew[1] = -2;
1854       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
1855       orntNew[2] = ornt[2];
1856       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
1857       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
1858 #if defined(PETSC_USE_DEBUG)
1859       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);
1860       for (p = 0; p < 3; ++p) {
1861         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);
1862       }
1863 #endif
1864       /* B triangle */
1865       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
1866       orntNew[0] = ornt[0];
1867       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
1868       orntNew[1] = ornt[1];
1869       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 0;
1870       orntNew[2] = -2;
1871       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
1872       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
1873 #if defined(PETSC_USE_DEBUG)
1874       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);
1875       for (p = 0; p < 3; ++p) {
1876         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);
1877       }
1878 #endif
1879       /* C triangle */
1880       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 1;
1881       orntNew[0] = -2;
1882       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
1883       orntNew[1] = ornt[1];
1884       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
1885       orntNew[2] = ornt[2];
1886       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
1887       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
1888 #if defined(PETSC_USE_DEBUG)
1889       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);
1890       for (p = 0; p < 3; ++p) {
1891         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);
1892       }
1893 #endif
1894       /* D triangle */
1895       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 0;
1896       orntNew[0] = 0;
1897       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 1;
1898       orntNew[1] = 0;
1899       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 2;
1900       orntNew[2] = 0;
1901       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
1902       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
1903 #if defined(PETSC_USE_DEBUG)
1904       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);
1905       for (p = 0; p < 3; ++p) {
1906         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);
1907       }
1908 #endif
1909     }
1910     /* Split faces have 2 vertices and the same cells as the parent */
1911     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
1912     ierr = PetscMalloc1(2 + maxSupportSize*2, &supportRef);CHKERRQ(ierr);
1913     for (f = fStart; f < fEnd; ++f) {
1914       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);
1915 
1916       for (r = 0; r < 2; ++r) {
1917         const PetscInt  newp = fStartNew + (f - fStart)*2 + r;
1918         const PetscInt *cone, *ornt, *support;
1919         PetscInt        coneNew[2], coneSize, c, supportSize, s;
1920 
1921         ierr             = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
1922         coneNew[0]       = vStartNew + (cone[0] - vStart);
1923         coneNew[1]       = vStartNew + (cone[1] - vStart);
1924         coneNew[(r+1)%2] = newv;
1925         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
1926 #if defined(PETSC_USE_DEBUG)
1927         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
1928         for (p = 0; p < 2; ++p) {
1929           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);
1930         }
1931 #endif
1932         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
1933         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
1934         for (s = 0; s < supportSize; ++s) {
1935           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
1936           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
1937           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
1938           for (c = 0; c < coneSize; ++c) {
1939             if (cone[c] == f) break;
1940           }
1941           supportRef[s] = cStartNew + (support[s] - cStart)*4 + (ornt[c] < 0 ? (c+1-r)%3 : (c+r)%3);
1942         }
1943         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
1944 #if defined(PETSC_USE_DEBUG)
1945         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
1946         for (p = 0; p < supportSize; ++p) {
1947           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);
1948         }
1949 #endif
1950       }
1951     }
1952     /* Interior faces have 2 vertices and 2 cells */
1953     for (c = cStart; c < cEnd; ++c) {
1954       const PetscInt *cone;
1955 
1956       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
1957       for (r = 0; r < 3; ++r) {
1958         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*3 + r;
1959         PetscInt       coneNew[2];
1960         PetscInt       supportNew[2];
1961 
1962         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r]       - fStart);
1963         coneNew[1] = vStartNew + (vEnd - vStart) + (cone[(r+1)%3] - fStart);
1964         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
1965 #if defined(PETSC_USE_DEBUG)
1966         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
1967         for (p = 0; p < 2; ++p) {
1968           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);
1969         }
1970 #endif
1971         supportNew[0] = (c - cStart)*4 + (r+1)%3;
1972         supportNew[1] = (c - cStart)*4 + 3;
1973         ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
1974 #if defined(PETSC_USE_DEBUG)
1975         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
1976         for (p = 0; p < 2; ++p) {
1977           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);
1978         }
1979 #endif
1980       }
1981     }
1982     /* Old vertices have identical supports */
1983     for (v = vStart; v < vEnd; ++v) {
1984       const PetscInt  newp = vStartNew + (v - vStart);
1985       const PetscInt *support, *cone;
1986       PetscInt        size, s;
1987 
1988       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
1989       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
1990       for (s = 0; s < size; ++s) {
1991         PetscInt r = 0;
1992 
1993         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
1994         if (cone[1] == v) r = 1;
1995         supportRef[s] = fStartNew + (support[s] - fStart)*2 + r;
1996       }
1997       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
1998 #if defined(PETSC_USE_DEBUG)
1999       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", newp, vStartNew, vEndNew);
2000       for (p = 0; p < size; ++p) {
2001         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);
2002       }
2003 #endif
2004     }
2005     /* Face vertices have 2 + cells*2 supports */
2006     for (f = fStart; f < fEnd; ++f) {
2007       const PetscInt  newp = vStartNew + (vEnd - vStart) + (f - fStart);
2008       const PetscInt *cone, *support;
2009       PetscInt        size, s;
2010 
2011       ierr          = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
2012       ierr          = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
2013       supportRef[0] = fStartNew + (f - fStart)*2 + 0;
2014       supportRef[1] = fStartNew + (f - fStart)*2 + 1;
2015       for (s = 0; s < size; ++s) {
2016         PetscInt r = 0;
2017 
2018         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
2019         if      (cone[1] == f) r = 1;
2020         else if (cone[2] == f) r = 2;
2021         supportRef[2+s*2+0] = fStartNew + (fEnd - fStart)*2 + (support[s] - cStart)*3 + (r+2)%3;
2022         supportRef[2+s*2+1] = fStartNew + (fEnd - fStart)*2 + (support[s] - cStart)*3 + r;
2023       }
2024       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
2025 #if defined(PETSC_USE_DEBUG)
2026       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", newp, vStartNew, vEndNew);
2027       for (p = 0; p < 2+size*2; ++p) {
2028         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);
2029       }
2030 #endif
2031     }
2032     ierr = PetscFree(supportRef);CHKERRQ(ierr);
2033     break;
2034   case REFINER_SIMPLEX_TO_HEX_2D:
2035     /*
2036      2
2037      |\
2038      | \
2039      |  \
2040      |   \
2041      | C  \
2042      |     \
2043      2      1
2044      |\    / \
2045      | 2  1   \
2046      |  \/     \
2047      |   |      \
2048      |A  |   B   \
2049      |   0        \
2050      |   |         \
2051      0---0----------1
2052      */
2053     /* All cells have 4 faces */
2054     for (c = cStart; c < cEnd; ++c) {
2055       const PetscInt  newp = cStartNew + (c - cStart)*3;
2056       const PetscInt *cone, *ornt;
2057       PetscInt        coneNew[4], orntNew[4];
2058 
2059       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
2060       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
2061       /* A quad */
2062       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
2063       orntNew[0] = ornt[0];
2064       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 0;
2065       orntNew[1] = 0;
2066       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 2;
2067       orntNew[2] = -2;
2068       coneNew[3] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
2069       orntNew[3] = ornt[2];
2070       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
2071       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
2072 #if defined(PETSC_USE_DEBUG)
2073       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);
2074       for (p = 0; p < 4; ++p) {
2075         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);
2076       }
2077 #endif
2078       /* B quad */
2079       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
2080       orntNew[0] = ornt[0];
2081       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
2082       orntNew[1] = ornt[1];
2083       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 1;
2084       orntNew[2] = 0;
2085       coneNew[3] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 0;
2086       orntNew[3] = -2;
2087       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
2088       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
2089 #if defined(PETSC_USE_DEBUG)
2090       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);
2091       for (p = 0; p < 4; ++p) {
2092         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);
2093       }
2094 #endif
2095       /* C quad */
2096       coneNew[0] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
2097       orntNew[0] = ornt[1];
2098       coneNew[1] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
2099       orntNew[1] = ornt[2];
2100       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 2;
2101       orntNew[2] = 0;
2102       coneNew[3] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 1;
2103       orntNew[3] = -2;
2104       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
2105       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
2106 #if defined(PETSC_USE_DEBUG)
2107       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);
2108       for (p = 0; p < 4; ++p) {
2109         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);
2110       }
2111 #endif
2112     }
2113     /* Split faces have 2 vertices and the same cells as the parent */
2114     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
2115     ierr = PetscMalloc1(2 + maxSupportSize*2, &supportRef);CHKERRQ(ierr);
2116     for (f = fStart; f < fEnd; ++f) {
2117       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);
2118 
2119       for (r = 0; r < 2; ++r) {
2120         const PetscInt  newp = fStartNew + (f - fStart)*2 + r;
2121         const PetscInt *cone, *ornt, *support;
2122         PetscInt        coneNew[2], coneSize, c, supportSize, s;
2123 
2124         ierr             = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
2125         coneNew[0]       = vStartNew + (cone[0] - vStart);
2126         coneNew[1]       = vStartNew + (cone[1] - vStart);
2127         coneNew[(r+1)%2] = newv;
2128         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2129 #if defined(PETSC_USE_DEBUG)
2130         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
2131         for (p = 0; p < 2; ++p) {
2132           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);
2133         }
2134 #endif
2135         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
2136         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
2137         for (s = 0; s < supportSize; ++s) {
2138           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
2139           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
2140           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
2141           for (c = 0; c < coneSize; ++c) {
2142             if (cone[c] == f) break;
2143           }
2144           supportRef[s] = cStartNew + (support[s] - cStart)*3 + (ornt[c] < 0 ? (c+1-r)%3 : (c+r)%3);
2145         }
2146         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
2147 #if defined(PETSC_USE_DEBUG)
2148         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
2149         for (p = 0; p < supportSize; ++p) {
2150           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);
2151         }
2152 #endif
2153       }
2154     }
2155     /* Interior faces have 2 vertices and 2 cells */
2156     for (c = cStart; c < cEnd; ++c) {
2157       const PetscInt *cone;
2158 
2159       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
2160       for (r = 0; r < 3; ++r) {
2161         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*3 + r;
2162         PetscInt       coneNew[2];
2163         PetscInt       supportNew[2];
2164 
2165         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r] - fStart);
2166         coneNew[1] = vStartNew + (vEnd - vStart) + (fEnd    - fStart) + (c - cStart);
2167         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2168 #if defined(PETSC_USE_DEBUG)
2169         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
2170         for (p = 0; p < 2; ++p) {
2171           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);
2172         }
2173 #endif
2174         supportNew[0] = (c - cStart)*3 + r%3;
2175         supportNew[1] = (c - cStart)*3 + (r+1)%3;
2176         ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
2177 #if defined(PETSC_USE_DEBUG)
2178         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
2179         for (p = 0; p < 2; ++p) {
2180           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);
2181         }
2182 #endif
2183       }
2184     }
2185     /* Old vertices have identical supports */
2186     for (v = vStart; v < vEnd; ++v) {
2187       const PetscInt  newp = vStartNew + (v - vStart);
2188       const PetscInt *support, *cone;
2189       PetscInt        size, s;
2190 
2191       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
2192       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
2193       for (s = 0; s < size; ++s) {
2194         PetscInt r = 0;
2195 
2196         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
2197         if (cone[1] == v) r = 1;
2198         supportRef[s] = fStartNew + (support[s] - fStart)*2 + r;
2199       }
2200       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
2201 #if defined(PETSC_USE_DEBUG)
2202       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", newp, vStartNew, vEndNew);
2203       for (p = 0; p < size; ++p) {
2204         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);
2205       }
2206 #endif
2207     }
2208     /* Split-face vertices have cells + 2 supports */
2209     for (f = fStart; f < fEnd; ++f) {
2210       const PetscInt  newp = vStartNew + (vEnd - vStart) + (f - fStart);
2211       const PetscInt *cone, *support;
2212       PetscInt        size, s;
2213 
2214       ierr          = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
2215       ierr          = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
2216       supportRef[0] = fStartNew + (f - fStart)*2 + 0;
2217       supportRef[1] = fStartNew + (f - fStart)*2 + 1;
2218       for (s = 0; s < size; ++s) {
2219         PetscInt r = 0;
2220 
2221         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
2222         if      (cone[1] == f) r = 1;
2223         else if (cone[2] == f) r = 2;
2224         supportRef[2+s+0] = fStartNew + (fEnd - fStart)*2 + (support[s] - cStart)*3 + r;
2225       }
2226       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
2227 #if defined(PETSC_USE_DEBUG)
2228       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", newp, vStartNew, vEndNew);
2229       for (p = 0; p < 2+size; ++p) {
2230         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);
2231       }
2232 #endif
2233     }
2234     /* Interior vertices have 3 supports */
2235     for (c = cStart; c < cEnd; ++c) {
2236       const PetscInt newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + c - cStart;
2237 
2238       supportRef[0] = fStartNew + (fEnd - fStart)*2 + (c - cStart)*3 + 0;
2239       supportRef[1] = fStartNew + (fEnd - fStart)*2 + (c - cStart)*3 + 1;
2240       supportRef[2] = fStartNew + (fEnd - fStart)*2 + (c - cStart)*3 + 2;
2241       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
2242     }
2243     ierr = PetscFree(supportRef);CHKERRQ(ierr);
2244     break;
2245   case REFINER_HYBRID_SIMPLEX_TO_HEX_2D:
2246     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
2247     cMax = PetscMin(cEnd, cMax);
2248     for (c = cStart; c < cMax; ++c) {
2249       const PetscInt  newp = cStartNew + (c - cStart)*3;
2250       const PetscInt *cone, *ornt;
2251       PetscInt        coneNew[4], orntNew[4];
2252 
2253       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
2254       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
2255       /* A quad */
2256       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
2257       orntNew[0] = ornt[0];
2258       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 0;
2259       orntNew[1] = 0;
2260       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 2;
2261       orntNew[2] = -2;
2262       coneNew[3] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
2263       orntNew[3] = ornt[2];
2264       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
2265       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
2266 #if defined(PETSC_USE_DEBUG)
2267       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);
2268       for (p = 0; p < 4; ++p) {
2269         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);
2270       }
2271 #endif
2272       /* B quad */
2273       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
2274       orntNew[0] = ornt[0];
2275       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
2276       orntNew[1] = ornt[1];
2277       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 1;
2278       orntNew[2] = 0;
2279       coneNew[3] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 0;
2280       orntNew[3] = -2;
2281       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
2282       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
2283 #if defined(PETSC_USE_DEBUG)
2284       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);
2285       for (p = 0; p < 4; ++p) {
2286         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);
2287       }
2288 #endif
2289       /* C quad */
2290       coneNew[0] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
2291       orntNew[0] = ornt[1];
2292       coneNew[1] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
2293       orntNew[1] = ornt[2];
2294       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 2;
2295       orntNew[2] = 0;
2296       coneNew[3] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 1;
2297       orntNew[3] = -2;
2298       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
2299       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
2300 #if defined(PETSC_USE_DEBUG)
2301       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);
2302       for (p = 0; p < 4; ++p) {
2303         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);
2304       }
2305 #endif
2306     }
2307     /*
2308      2---------1---------3
2309      |         |         |
2310      |    D    1    C    |
2311      |         |         |
2312      2----2----0----3----3
2313      |         |         |
2314      |    A    0    B    |
2315      |         |         |
2316      0---------0---------1
2317      */
2318     /* Parent cells are input as prisms but children are quads, since the mesh is no longer hybrid */
2319     for (c = cMax; c < cEnd; ++c) {
2320       const PetscInt  newp  = cStartNew + (cMax - cStart)*3 + (c - cMax)*4;
2321       const PetscInt  newpt = (cMax - cStart)*3 + (c - cMax)*4;
2322       const PetscInt *cone, *ornt;
2323       PetscInt        coneNew[4], orntNew[4];
2324 
2325       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
2326       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
2327       /* A quad */
2328       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
2329       orntNew[0] = ornt[0];
2330       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + newpt + 0;
2331       orntNew[1] = 0;
2332       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + newpt + 2;
2333       orntNew[2] = -2;
2334       coneNew[3] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
2335       orntNew[3] = ornt[2] < 0 ? 0 : -2;
2336       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
2337       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
2338 #if defined(PETSC_USE_DEBUG)
2339       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);
2340       for (p = 0; p < 4; ++p) {
2341         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);
2342       }
2343 #endif
2344       /* B quad */
2345       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
2346       orntNew[0] = ornt[0];
2347       coneNew[1] = fStartNew + (cone[3] - fStart)*2 + (ornt[3] < 0 ? 1 : 0);
2348       orntNew[1] = ornt[3];
2349       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + newpt + 3;
2350       orntNew[2] = 0;
2351       coneNew[3] = fStartNew + (fEnd    - fStart)*2 + newpt + 0;
2352       orntNew[3] = -2;
2353       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
2354       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
2355 #if defined(PETSC_USE_DEBUG)
2356       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);
2357       for (p = 0; p < 4; ++p) {
2358         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);
2359       }
2360 #endif
2361       /* C quad */
2362       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + newpt + 3;
2363       orntNew[0] = -2;
2364       coneNew[1] = fStartNew + (cone[3] - fStart)*2 + (ornt[3] < 0 ? 0 : 1);
2365       orntNew[1] = ornt[3];
2366       coneNew[2] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
2367       orntNew[2] = ornt[1] < 0 ? 0 : -2;
2368       coneNew[3] = fStartNew + (fEnd    - fStart)*2 + newpt + 1;
2369       orntNew[3] = 0;
2370       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
2371       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
2372 #if defined(PETSC_USE_DEBUG)
2373       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);
2374       for (p = 0; p < 4; ++p) {
2375         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);
2376       }
2377 #endif
2378       /* D quad */
2379       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + newpt + 2;
2380       orntNew[0] = 0;
2381       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + newpt + 1;
2382       orntNew[1] = -2;
2383       coneNew[2] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
2384       orntNew[2] = ornt[1] < 0 ? 0 : -2;
2385       coneNew[3] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
2386       orntNew[3] = ornt[2] < 0 ? 0 : -2;
2387       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
2388       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
2389 #if defined(PETSC_USE_DEBUG)
2390       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);
2391       for (p = 0; p < 4; ++p) {
2392         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);
2393       }
2394 #endif
2395     }
2396     /* Split faces have 2 vertices and the same cells as the parent */
2397     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
2398     ierr = PetscMalloc1(2 + maxSupportSize*2, &supportRef);CHKERRQ(ierr);
2399     for (f = fStart; f < fEnd; ++f) {
2400       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);
2401 
2402       for (r = 0; r < 2; ++r) {
2403         const PetscInt  newp = fStartNew + (f - fStart)*2 + r;
2404         const PetscInt *cone, *ornt, *support;
2405         PetscInt        coneNew[2], coneSize, c, supportSize, s;
2406 
2407         ierr             = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
2408         coneNew[0]       = vStartNew + (cone[0] - vStart);
2409         coneNew[1]       = vStartNew + (cone[1] - vStart);
2410         coneNew[(r+1)%2] = newv;
2411         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2412 #if defined(PETSC_USE_DEBUG)
2413         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
2414         for (p = 0; p < 2; ++p) {
2415           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);
2416         }
2417 #endif
2418         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
2419         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
2420         for (s = 0; s < supportSize; ++s) {
2421           const PetscInt p2q[4][2] = { {0, 1},
2422                                        {3, 2},
2423                                        {0, 3},
2424                                        {1, 2} };
2425 
2426           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
2427           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
2428           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
2429           for (c = 0; c < coneSize; ++c) {
2430             if (cone[c] == f) break;
2431           }
2432           if (coneSize == 3)      supportRef[s] = cStartNew + (support[s] - cStart)*3 + (ornt[c] < 0 ? (c+1-r)%3 : (c+r)%3);
2433           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]);
2434           else SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected cone size %D", coneSize);
2435         }
2436         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
2437 #if defined(PETSC_USE_DEBUG)
2438         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
2439         for (p = 0; p < supportSize; ++p) {
2440           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);
2441         }
2442 #endif
2443       }
2444     }
2445     /* Interior faces have 2 vertices and 2 cells */
2446     for (c = cStart; c < cMax; ++c) {
2447       const PetscInt *cone;
2448 
2449       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
2450       for (r = 0; r < 3; ++r) {
2451         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*3 + r;
2452         PetscInt       coneNew[2];
2453         PetscInt       supportNew[2];
2454 
2455         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r] - fStart);
2456         coneNew[1] = vStartNew + (vEnd - vStart) + (fEnd    - fStart) + (c - cStart);
2457         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2458 #if defined(PETSC_USE_DEBUG)
2459         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
2460         for (p = 0; p < 2; ++p) {
2461           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);
2462         }
2463 #endif
2464         supportNew[0] = (c - cStart)*3 + r%3;
2465         supportNew[1] = (c - cStart)*3 + (r+1)%3;
2466         ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
2467 #if defined(PETSC_USE_DEBUG)
2468         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
2469         for (p = 0; p < 2; ++p) {
2470           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);
2471         }
2472 #endif
2473       }
2474     }
2475     /* Hybrid interior faces have 2 vertices and 2 cells */
2476     for (c = cMax; c < cEnd; ++c) {
2477       const PetscInt *cone;
2478       PetscInt        coneNew[2], supportNew[2];
2479 
2480       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
2481       for (r = 0; r < 4; ++r) {
2482         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (cMax - cStart)*3 + (c - cMax)*4 + r;
2483 
2484         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r] - fStart);
2485         coneNew[1] = vStartNew + (vEnd - vStart) + (fEnd    - fStart) + (cMax - cStart) + (c - cMax);
2486 	ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2487 #if defined(PETSC_USE_DEBUG)
2488         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
2489         for (p = 0; p < 2; ++p) {
2490           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);
2491         }
2492 #endif
2493         if (r==0) {
2494           supportNew[0] = (cMax - cStart)*3 + (c - cMax)*4 + 0;
2495           supportNew[1] = (cMax - cStart)*3 + (c - cMax)*4 + 1;
2496         } else if (r==1) {
2497           supportNew[0] = (cMax - cStart)*3 + (c - cMax)*4 + 2;
2498           supportNew[1] = (cMax - cStart)*3 + (c - cMax)*4 + 3;
2499         } else if (r==2) {
2500           supportNew[0] = (cMax - cStart)*3 + (c - cMax)*4 + 0;
2501           supportNew[1] = (cMax - cStart)*3 + (c - cMax)*4 + 3;
2502         } else {
2503           supportNew[0] = (cMax - cStart)*3 + (c - cMax)*4 + 1;
2504           supportNew[1] = (cMax - cStart)*3 + (c - cMax)*4 + 2;
2505         }
2506         ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
2507 #if defined(PETSC_USE_DEBUG)
2508         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
2509         for (p = 0; p < 2; ++p) {
2510           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);
2511         }
2512 #endif
2513       }
2514     }
2515     /* Old vertices have identical supports */
2516     for (v = vStart; v < vEnd; ++v) {
2517       const PetscInt  newp = vStartNew + (v - vStart);
2518       const PetscInt *support, *cone;
2519       PetscInt        size, s;
2520 
2521       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
2522       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
2523       for (s = 0; s < size; ++s) {
2524         PetscInt r = 0;
2525 
2526         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
2527         if (cone[1] == v) r = 1;
2528         supportRef[s] = fStartNew + (support[s] - fStart)*2 + r;
2529       }
2530       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
2531 #if defined(PETSC_USE_DEBUG)
2532       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", newp, vStartNew, vEndNew);
2533       for (p = 0; p < size; ++p) {
2534         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);
2535       }
2536 #endif
2537     }
2538     /* Split-face vertices have cells + 2 supports */
2539     for (f = fStart; f < fEnd; ++f) {
2540       const PetscInt  newp = vStartNew + (vEnd - vStart) + (f - fStart);
2541       const PetscInt *cone, *support;
2542       PetscInt        size, s;
2543 
2544       ierr          = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
2545       ierr          = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
2546       supportRef[0] = fStartNew + (f - fStart)*2 + 0;
2547       supportRef[1] = fStartNew + (f - fStart)*2 + 1;
2548       for (s = 0; s < size; ++s) {
2549         PetscInt r = 0, coneSize;
2550 
2551         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
2552         ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
2553         if (coneSize == 3) {
2554           if      (cone[1] == f) r = 1;
2555           else if (cone[2] == f) r = 2;
2556           supportRef[2+s] = fStartNew + (fEnd - fStart)*2 + (support[s] - cStart)*3 + r;
2557         } else if (coneSize == 4) {
2558           if      (cone[1] == f) r = 1;
2559           else if (cone[2] == f) r = 2;
2560           else if (cone[3] == f) r = 3;
2561           supportRef[2+s] = fStartNew + (fEnd - fStart)*2 + (cMax - cStart)*3 + (support[s] - cMax)*4 + r;
2562         } else SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected cone size %D", coneSize);
2563       }
2564       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
2565 #if defined(PETSC_USE_DEBUG)
2566       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", newp, vStartNew, vEndNew);
2567       for (p = 0; p < 2+size; ++p) {
2568         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);
2569       }
2570 #endif
2571     }
2572     /* Interior vertices have 3 supports */
2573     for (c = cStart; c < cMax; ++c) {
2574       const PetscInt newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + c - cStart;
2575 
2576       supportRef[0] = fStartNew + (fEnd - fStart)*2 + (c - cStart)*3 + 0;
2577       supportRef[1] = fStartNew + (fEnd - fStart)*2 + (c - cStart)*3 + 1;
2578       supportRef[2] = fStartNew + (fEnd - fStart)*2 + (c - cStart)*3 + 2;
2579       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
2580     }
2581     /* Hybrid interior vertices have 4 supports */
2582     for (c = cMax; c < cEnd; ++c) {
2583       const PetscInt newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + c - cStart;
2584 
2585       supportRef[0] = fStartNew + (fEnd - fStart)*2 + (cMax - cStart)*3 + (c - cMax)*4 + 0;
2586       supportRef[1] = fStartNew + (fEnd - fStart)*2 + (cMax - cStart)*3 + (c - cMax)*4 + 1;
2587       supportRef[2] = fStartNew + (fEnd - fStart)*2 + (cMax - cStart)*3 + (c - cMax)*4 + 2;
2588       supportRef[3] = fStartNew + (fEnd - fStart)*2 + (cMax - cStart)*3 + (c - cMax)*4 + 3;
2589       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
2590     }
2591     ierr = PetscFree(supportRef);CHKERRQ(ierr);
2592     break;
2593   case REFINER_HEX_2D:
2594     /*
2595      3---------2---------2
2596      |         |         |
2597      |    D    2    C    |
2598      |         |         |
2599      3----3----0----1----1
2600      |         |         |
2601      |    A    0    B    |
2602      |         |         |
2603      0---------0---------1
2604      */
2605     /* All cells have 4 faces */
2606     for (c = cStart; c < cEnd; ++c) {
2607       const PetscInt  newp = (c - cStart)*4;
2608       const PetscInt *cone, *ornt;
2609       PetscInt        coneNew[4], orntNew[4];
2610 
2611       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
2612       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
2613       /* A quad */
2614       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
2615       orntNew[0] = ornt[0];
2616       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 0;
2617       orntNew[1] = 0;
2618       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 3;
2619       orntNew[2] = -2;
2620       coneNew[3] = fStartNew + (cone[3] - fStart)*2 + (ornt[3] < 0 ? 0 : 1);
2621       orntNew[3] = ornt[3];
2622       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
2623       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
2624 #if defined(PETSC_USE_DEBUG)
2625       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);
2626       for (p = 0; p < 4; ++p) {
2627         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);
2628       }
2629 #endif
2630       /* B quad */
2631       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
2632       orntNew[0] = ornt[0];
2633       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
2634       orntNew[1] = ornt[1];
2635       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 1;
2636       orntNew[2] = -2;
2637       coneNew[3] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 0;
2638       orntNew[3] = -2;
2639       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
2640       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
2641 #if defined(PETSC_USE_DEBUG)
2642       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);
2643       for (p = 0; p < 4; ++p) {
2644         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);
2645       }
2646 #endif
2647       /* C quad */
2648       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 1;
2649       orntNew[0] = 0;
2650       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
2651       orntNew[1] = ornt[1];
2652       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
2653       orntNew[2] = ornt[2];
2654       coneNew[3] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 2;
2655       orntNew[3] = -2;
2656       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
2657       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
2658 #if defined(PETSC_USE_DEBUG)
2659       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);
2660       for (p = 0; p < 4; ++p) {
2661         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);
2662       }
2663 #endif
2664       /* D quad */
2665       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 3;
2666       orntNew[0] = 0;
2667       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 2;
2668       orntNew[1] = 0;
2669       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
2670       orntNew[2] = ornt[2];
2671       coneNew[3] = fStartNew + (cone[3] - fStart)*2 + (ornt[3] < 0 ? 1 : 0);
2672       orntNew[3] = ornt[3];
2673       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
2674       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
2675 #if defined(PETSC_USE_DEBUG)
2676       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);
2677       for (p = 0; p < 4; ++p) {
2678         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);
2679       }
2680 #endif
2681     }
2682     /* Split faces have 2 vertices and the same cells as the parent */
2683     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
2684     ierr = PetscMalloc1(2 + maxSupportSize*2, &supportRef);CHKERRQ(ierr);
2685     for (f = fStart; f < fEnd; ++f) {
2686       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);
2687 
2688       for (r = 0; r < 2; ++r) {
2689         const PetscInt  newp = fStartNew + (f - fStart)*2 + r;
2690         const PetscInt *cone, *ornt, *support;
2691         PetscInt        coneNew[2], coneSize, c, supportSize, s;
2692 
2693         ierr             = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
2694         coneNew[0]       = vStartNew + (cone[0] - vStart);
2695         coneNew[1]       = vStartNew + (cone[1] - vStart);
2696         coneNew[(r+1)%2] = newv;
2697         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2698 #if defined(PETSC_USE_DEBUG)
2699         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
2700         for (p = 0; p < 2; ++p) {
2701           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);
2702         }
2703 #endif
2704         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
2705         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
2706         for (s = 0; s < supportSize; ++s) {
2707           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
2708           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
2709           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
2710           for (c = 0; c < coneSize; ++c) {
2711             if (cone[c] == f) break;
2712           }
2713           supportRef[s] = cStartNew + (support[s] - cStart)*4 + (ornt[c] < 0 ? (c+1-r)%4 : (c+r)%4);
2714         }
2715         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
2716 #if defined(PETSC_USE_DEBUG)
2717         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
2718         for (p = 0; p < supportSize; ++p) {
2719           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);
2720         }
2721 #endif
2722       }
2723     }
2724     /* Interior faces have 2 vertices and 2 cells */
2725     for (c = cStart; c < cEnd; ++c) {
2726       const PetscInt *cone;
2727       PetscInt        coneNew[2], supportNew[2];
2728 
2729       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
2730       for (r = 0; r < 4; ++r) {
2731         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*4 + r;
2732 
2733 	if (r==1 || r==2) {
2734           coneNew[0] = vStartNew + (vEnd - vStart) + (fEnd    - fStart) + (c - cStart);
2735           coneNew[1] = vStartNew + (vEnd - vStart) + (cone[r] - fStart);
2736 	} else {
2737           coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r] - fStart);
2738           coneNew[1] = vStartNew + (vEnd - vStart) + (fEnd    - fStart) + (c - cStart);
2739 	}
2740 	ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2741 #if defined(PETSC_USE_DEBUG)
2742         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
2743         for (p = 0; p < 2; ++p) {
2744           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);
2745         }
2746 #endif
2747         supportNew[0] = (c - cStart)*4 + r;
2748         supportNew[1] = (c - cStart)*4 + (r+1)%4;
2749         ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
2750 #if defined(PETSC_USE_DEBUG)
2751         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
2752         for (p = 0; p < 2; ++p) {
2753           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);
2754         }
2755 #endif
2756       }
2757     }
2758     /* Old vertices have identical supports */
2759     for (v = vStart; v < vEnd; ++v) {
2760       const PetscInt  newp = vStartNew + (v - vStart);
2761       const PetscInt *support, *cone;
2762       PetscInt        size, s;
2763 
2764       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
2765       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
2766       for (s = 0; s < size; ++s) {
2767         PetscInt r = 0;
2768 
2769         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
2770         if (cone[1] == v) r = 1;
2771         supportRef[s] = fStartNew + (support[s] - fStart)*2 + r;
2772       }
2773       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
2774 #if defined(PETSC_USE_DEBUG)
2775       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", newp, vStartNew, vEndNew);
2776       for (p = 0; p < size; ++p) {
2777         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);
2778       }
2779 #endif
2780     }
2781     /* Face vertices have 2 + cells supports */
2782     for (f = fStart; f < fEnd; ++f) {
2783       const PetscInt  newp = vStartNew + (vEnd - vStart) + (f - fStart);
2784       const PetscInt *cone, *support;
2785       PetscInt        size, s;
2786 
2787       ierr          = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
2788       ierr          = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
2789       supportRef[0] = fStartNew + (f - fStart)*2 + 0;
2790       supportRef[1] = fStartNew + (f - fStart)*2 + 1;
2791       for (s = 0; s < size; ++s) {
2792         PetscInt r = 0;
2793 
2794         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
2795         if      (cone[1] == f) r = 1;
2796         else if (cone[2] == f) r = 2;
2797         else if (cone[3] == f) r = 3;
2798         supportRef[2+s] = fStartNew + (fEnd - fStart)*2 + (support[s] - cStart)*4 + r;
2799       }
2800       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
2801 #if defined(PETSC_USE_DEBUG)
2802       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", newp, vStartNew, vEndNew);
2803       for (p = 0; p < 2+size; ++p) {
2804         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);
2805       }
2806 #endif
2807     }
2808     /* Cell vertices have 4 supports */
2809     for (c = cStart; c < cEnd; ++c) {
2810       const PetscInt newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (c - cStart);
2811       PetscInt       supportNew[4];
2812 
2813       for (r = 0; r < 4; ++r) {
2814         supportNew[r] = fStartNew + (fEnd - fStart)*2 + (c - cStart)*4 + r;
2815       }
2816       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
2817     }
2818     ierr = PetscFree(supportRef);CHKERRQ(ierr);
2819     break;
2820   case REFINER_HYBRID_SIMPLEX_2D:
2821     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
2822     cMax = PetscMin(cEnd, cMax);
2823     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
2824     fMax = PetscMin(fEnd, fMax);
2825     ierr = DMPlexGetHybridBounds(rdm, &cMaxNew, &fMaxNew, NULL, NULL);CHKERRQ(ierr);
2826     /* Interior cells have 3 faces */
2827     for (c = cStart; c < cMax; ++c) {
2828       const PetscInt  newp = cStartNew + (c - cStart)*4;
2829       const PetscInt *cone, *ornt;
2830       PetscInt        coneNew[3], orntNew[3];
2831 
2832       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
2833       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
2834       /* A triangle */
2835       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
2836       orntNew[0] = ornt[0];
2837       coneNew[1] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 2;
2838       orntNew[1] = -2;
2839       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
2840       orntNew[2] = ornt[2];
2841       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
2842       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
2843 #if defined(PETSC_USE_DEBUG)
2844       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);
2845       for (p = 0; p < 3; ++p) {
2846         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);
2847       }
2848 #endif
2849       /* B triangle */
2850       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
2851       orntNew[0] = ornt[0];
2852       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
2853       orntNew[1] = ornt[1];
2854       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 0;
2855       orntNew[2] = -2;
2856       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
2857       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
2858 #if defined(PETSC_USE_DEBUG)
2859       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);
2860       for (p = 0; p < 3; ++p) {
2861         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);
2862       }
2863 #endif
2864       /* C triangle */
2865       coneNew[0] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 1;
2866       orntNew[0] = -2;
2867       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
2868       orntNew[1] = ornt[1];
2869       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
2870       orntNew[2] = ornt[2];
2871       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
2872       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
2873 #if defined(PETSC_USE_DEBUG)
2874       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);
2875       for (p = 0; p < 3; ++p) {
2876         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);
2877       }
2878 #endif
2879       /* D triangle */
2880       coneNew[0] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 0;
2881       orntNew[0] = 0;
2882       coneNew[1] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 1;
2883       orntNew[1] = 0;
2884       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 2;
2885       orntNew[2] = 0;
2886       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
2887       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
2888 #if defined(PETSC_USE_DEBUG)
2889       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);
2890       for (p = 0; p < 3; ++p) {
2891         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);
2892       }
2893 #endif
2894     }
2895     /*
2896      2----3----3
2897      |         |
2898      |    B    |
2899      |         |
2900      0----4--- 1
2901      |         |
2902      |    A    |
2903      |         |
2904      0----2----1
2905      */
2906     /* Hybrid cells have 4 faces */
2907     for (c = cMax; c < cEnd; ++c) {
2908       const PetscInt  newp = cStartNew + (cMax - cStart)*4 + (c - cMax)*2;
2909       const PetscInt *cone, *ornt;
2910       PetscInt        coneNew[4], orntNew[4], r;
2911 
2912       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
2913       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
2914       r    = (ornt[0] < 0 ? 1 : 0);
2915       /* A quad */
2916       coneNew[0]   = fStartNew + (cone[0] - fStart)*2 + r;
2917       orntNew[0]   = ornt[0];
2918       coneNew[1]   = fStartNew + (cone[1] - fStart)*2 + r;
2919       orntNew[1]   = ornt[1];
2920       coneNew[2+r] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (cone[2+r] - fMax);
2921       orntNew[2+r] = 0;
2922       coneNew[3-r] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (fEnd    - fMax) + (c - cMax);
2923       orntNew[3-r] = 0;
2924       ierr = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
2925       ierr = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
2926 #if defined(PETSC_USE_DEBUG)
2927       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);
2928       for (p = 0; p < 4; ++p) {
2929         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);
2930       }
2931 #endif
2932       /* B quad */
2933       coneNew[0]   = fStartNew + (cone[0] - fStart)*2 + 1-r;
2934       orntNew[0]   = ornt[0];
2935       coneNew[1]   = fStartNew + (cone[1] - fStart)*2 + 1-r;
2936       orntNew[1]   = ornt[1];
2937       coneNew[2+r] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (fEnd    - fMax) + (c - cMax);
2938       orntNew[2+r] = 0;
2939       coneNew[3-r] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (cone[3-r] - fMax);
2940       orntNew[3-r] = 0;
2941       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
2942       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
2943 #if defined(PETSC_USE_DEBUG)
2944       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);
2945       for (p = 0; p < 4; ++p) {
2946         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);
2947       }
2948 #endif
2949     }
2950     /* Interior split faces have 2 vertices and the same cells as the parent */
2951     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
2952     ierr = PetscMalloc1(2 + maxSupportSize*2, &supportRef);CHKERRQ(ierr);
2953     for (f = fStart; f < fMax; ++f) {
2954       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);
2955 
2956       for (r = 0; r < 2; ++r) {
2957         const PetscInt  newp = fStartNew + (f - fStart)*2 + r;
2958         const PetscInt *cone, *ornt, *support;
2959         PetscInt        coneNew[2], coneSize, c, supportSize, s;
2960 
2961         ierr             = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
2962         coneNew[0]       = vStartNew + (cone[0] - vStart);
2963         coneNew[1]       = vStartNew + (cone[1] - vStart);
2964         coneNew[(r+1)%2] = newv;
2965         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2966 #if defined(PETSC_USE_DEBUG)
2967         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
2968         for (p = 0; p < 2; ++p) {
2969           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);
2970         }
2971 #endif
2972         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
2973         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
2974         for (s = 0; s < supportSize; ++s) {
2975           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
2976           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
2977           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
2978           for (c = 0; c < coneSize; ++c) if (cone[c] == f) break;
2979           if (support[s] >= cMax) {
2980             supportRef[s] = cStartNew + (cMax - cStart)*4 + (support[s] - cMax)*2 + (ornt[c] < 0 ? 1-r : r);
2981           } else {
2982             supportRef[s] = cStartNew + (support[s] - cStart)*4 + (ornt[c] < 0 ? (c+1-r)%3 : (c+r)%3);
2983           }
2984         }
2985         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
2986 #if defined(PETSC_USE_DEBUG)
2987         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
2988         for (p = 0; p < supportSize; ++p) {
2989           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);
2990         }
2991 #endif
2992       }
2993     }
2994     /* Interior cell faces have 2 vertices and 2 cells */
2995     for (c = cStart; c < cMax; ++c) {
2996       const PetscInt *cone;
2997 
2998       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
2999       for (r = 0; r < 3; ++r) {
3000         const PetscInt newp = fStartNew + (fMax - fStart)*2 + (c - cStart)*3 + r;
3001         PetscInt       coneNew[2];
3002         PetscInt       supportNew[2];
3003 
3004         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r]       - fStart);
3005         coneNew[1] = vStartNew + (vEnd - vStart) + (cone[(r+1)%3] - fStart);
3006         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3007 #if defined(PETSC_USE_DEBUG)
3008         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
3009         for (p = 0; p < 2; ++p) {
3010           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);
3011         }
3012 #endif
3013         supportNew[0] = (c - cStart)*4 + (r+1)%3;
3014         supportNew[1] = (c - cStart)*4 + 3;
3015         ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3016 #if defined(PETSC_USE_DEBUG)
3017         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
3018         for (p = 0; p < 2; ++p) {
3019           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);
3020         }
3021 #endif
3022       }
3023     }
3024     /* Interior hybrid faces have 2 vertices and the same cells */
3025     for (f = fMax; f < fEnd; ++f) {
3026       const PetscInt  newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (f - fMax);
3027       const PetscInt *cone, *ornt;
3028       const PetscInt *support;
3029       PetscInt        coneNew[2];
3030       PetscInt        supportNew[2];
3031       PetscInt        size, s, r;
3032 
3033       ierr       = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
3034       coneNew[0] = vStartNew + (cone[0] - vStart);
3035       coneNew[1] = vStartNew + (cone[1] - vStart);
3036       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3037 #if defined(PETSC_USE_DEBUG)
3038       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
3039       for (p = 0; p < 2; ++p) {
3040         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);
3041       }
3042 #endif
3043       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
3044       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
3045       for (s = 0; s < size; ++s) {
3046         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
3047         ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
3048         for (r = 0; r < 2; ++r) {
3049           if (cone[r+2] == f) break;
3050         }
3051         supportNew[s] = (cMax - cStart)*4 + (support[s] - cMax)*2 + (ornt[0] < 0 ? 1-r : r);
3052       }
3053       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3054 #if defined(PETSC_USE_DEBUG)
3055       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
3056       for (p = 0; p < size; ++p) {
3057         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);
3058       }
3059 #endif
3060     }
3061     /* Cell hybrid faces have 2 vertices and 2 cells */
3062     for (c = cMax; c < cEnd; ++c) {
3063       const PetscInt  newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (fEnd - fMax) + (c - cMax);
3064       const PetscInt *cone;
3065       PetscInt        coneNew[2];
3066       PetscInt        supportNew[2];
3067 
3068       ierr       = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
3069       coneNew[0] = vStartNew + (vEnd - vStart) + (cone[0] - fStart);
3070       coneNew[1] = vStartNew + (vEnd - vStart) + (cone[1] - fStart);
3071       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3072 #if defined(PETSC_USE_DEBUG)
3073       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
3074       for (p = 0; p < 2; ++p) {
3075         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);
3076       }
3077 #endif
3078       supportNew[0] = (cMax - cStart)*4 + (c - cMax)*2 + 0;
3079       supportNew[1] = (cMax - cStart)*4 + (c - cMax)*2 + 1;
3080       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3081 #if defined(PETSC_USE_DEBUG)
3082       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
3083       for (p = 0; p < 2; ++p) {
3084         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);
3085       }
3086 #endif
3087     }
3088     /* Old vertices have identical supports */
3089     for (v = vStart; v < vEnd; ++v) {
3090       const PetscInt  newp = vStartNew + (v - vStart);
3091       const PetscInt *support, *cone;
3092       PetscInt        size, s;
3093 
3094       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
3095       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
3096       for (s = 0; s < size; ++s) {
3097         if (support[s] >= fMax) {
3098           supportRef[s] = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (support[s] - fMax);
3099         } else {
3100           PetscInt r = 0;
3101 
3102           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
3103           if (cone[1] == v) r = 1;
3104           supportRef[s] = fStartNew + (support[s] - fStart)*2 + r;
3105         }
3106       }
3107       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
3108 #if defined(PETSC_USE_DEBUG)
3109       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", newp, vStartNew, vEndNew);
3110       for (p = 0; p < size; ++p) {
3111         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);
3112       }
3113 #endif
3114     }
3115     /* Face vertices have 2 + (2 interior, 1 hybrid) supports */
3116     for (f = fStart; f < fMax; ++f) {
3117       const PetscInt  newp = vStartNew + (vEnd - vStart) + (f - fStart);
3118       const PetscInt *cone, *support;
3119       PetscInt        size, newSize = 2, s;
3120 
3121       ierr          = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
3122       ierr          = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
3123       supportRef[0] = fStartNew + (f - fStart)*2 + 0;
3124       supportRef[1] = fStartNew + (f - fStart)*2 + 1;
3125       for (s = 0; s < size; ++s) {
3126         PetscInt r = 0;
3127 
3128         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
3129         if (support[s] >= cMax) {
3130           supportRef[newSize+0] = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (fEnd - fMax) + (support[s] - cMax);
3131 
3132           newSize += 1;
3133         } else {
3134           if      (cone[1] == f) r = 1;
3135           else if (cone[2] == f) r = 2;
3136           supportRef[newSize+0] = fStartNew + (fMax - fStart)*2 + (support[s] - cStart)*3 + (r+2)%3;
3137           supportRef[newSize+1] = fStartNew + (fMax - fStart)*2 + (support[s] - cStart)*3 + r;
3138 
3139           newSize += 2;
3140         }
3141       }
3142       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
3143 #if defined(PETSC_USE_DEBUG)
3144       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", newp, vStartNew, vEndNew);
3145       for (p = 0; p < newSize; ++p) {
3146         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);
3147       }
3148 #endif
3149     }
3150     ierr = PetscFree(supportRef);CHKERRQ(ierr);
3151     break;
3152   case REFINER_HYBRID_HEX_2D:
3153     /* Hybrid Hex 2D */
3154     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
3155     cMax = PetscMin(cEnd, cMax);
3156     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
3157     fMax = PetscMin(fEnd, fMax);
3158     ierr = DMPlexGetHybridBounds(rdm, &cMaxNew, &fMaxNew, NULL, NULL);CHKERRQ(ierr);
3159     /* Interior cells have 4 faces */
3160     for (c = cStart; c < cMax; ++c) {
3161       const PetscInt  newp = cStartNew + (c - cStart)*4;
3162       const PetscInt *cone, *ornt;
3163       PetscInt        coneNew[4], orntNew[4];
3164 
3165       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
3166       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
3167       /* A quad */
3168       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
3169       orntNew[0] = ornt[0];
3170       coneNew[1] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*4 + 0;
3171       orntNew[1] = 0;
3172       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*4 + 3;
3173       orntNew[2] = -2;
3174       coneNew[3] = fStartNew + (cone[3] - fStart)*2 + (ornt[3] < 0 ? 0 : 1);
3175       orntNew[3] = ornt[3];
3176       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
3177       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
3178 #if defined(PETSC_USE_DEBUG)
3179       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);
3180       for (p = 0; p < 4; ++p) {
3181         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);
3182       }
3183 #endif
3184       /* B quad */
3185       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
3186       orntNew[0] = ornt[0];
3187       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
3188       orntNew[1] = ornt[1];
3189       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*4 + 1;
3190       orntNew[2] = 0;
3191       coneNew[3] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*4 + 0;
3192       orntNew[3] = -2;
3193       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
3194       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
3195 #if defined(PETSC_USE_DEBUG)
3196       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);
3197       for (p = 0; p < 4; ++p) {
3198         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);
3199       }
3200 #endif
3201       /* C quad */
3202       coneNew[0] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*4 + 1;
3203       orntNew[0] = -2;
3204       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
3205       orntNew[1] = ornt[1];
3206       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
3207       orntNew[2] = ornt[2];
3208       coneNew[3] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*4 + 2;
3209       orntNew[3] = 0;
3210       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
3211       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
3212 #if defined(PETSC_USE_DEBUG)
3213       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);
3214       for (p = 0; p < 4; ++p) {
3215         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);
3216       }
3217 #endif
3218       /* D quad */
3219       coneNew[0] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*4 + 3;
3220       orntNew[0] = 0;
3221       coneNew[1] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*4 + 2;
3222       orntNew[1] = -2;
3223       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
3224       orntNew[2] = ornt[2];
3225       coneNew[3] = fStartNew + (cone[3] - fStart)*2 + (ornt[3] < 0 ? 1 : 0);
3226       orntNew[3] = ornt[3];
3227       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
3228       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
3229 #if defined(PETSC_USE_DEBUG)
3230       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);
3231       for (p = 0; p < 4; ++p) {
3232         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);
3233       }
3234 #endif
3235     }
3236     /*
3237      2----3----3
3238      |         |
3239      |    B    |
3240      |         |
3241      0----4--- 1
3242      |         |
3243      |    A    |
3244      |         |
3245      0----2----1
3246      */
3247     /* Hybrid cells have 4 faces */
3248     for (c = cMax; c < cEnd; ++c) {
3249       const PetscInt  newp = cStartNew + (cMax - cStart)*4 + (c - cMax)*2;
3250       const PetscInt *cone, *ornt;
3251       PetscInt        coneNew[4], orntNew[4];
3252 
3253       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
3254       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
3255       /* A quad */
3256       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
3257       orntNew[0] = ornt[0];
3258       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
3259       orntNew[1] = ornt[1];
3260       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*4 + (cone[2] - fMax);
3261       orntNew[2] = 0;
3262       coneNew[3] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*4 + (fEnd    - fMax) + (c - cMax);
3263       orntNew[3] = 0;
3264       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
3265       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
3266 #if defined(PETSC_USE_DEBUG)
3267       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);
3268       for (p = 0; p < 4; ++p) {
3269         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);
3270       }
3271 #endif
3272       /* B quad */
3273       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
3274       orntNew[0] = ornt[0];
3275       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
3276       orntNew[1] = ornt[1];
3277       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*4 + (fEnd    - fMax) + (c - cMax);
3278       orntNew[2] = 0;
3279       coneNew[3] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*4 + (cone[3] - fMax);
3280       orntNew[3] = 0;
3281       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
3282       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
3283 #if defined(PETSC_USE_DEBUG)
3284       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);
3285       for (p = 0; p < 4; ++p) {
3286         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);
3287       }
3288 #endif
3289     }
3290     /* Interior split faces have 2 vertices and the same cells as the parent */
3291     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
3292     ierr = PetscMalloc1(2 + maxSupportSize*2, &supportRef);CHKERRQ(ierr);
3293     for (f = fStart; f < fMax; ++f) {
3294       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);
3295 
3296       for (r = 0; r < 2; ++r) {
3297         const PetscInt  newp = fStartNew + (f - fStart)*2 + r;
3298         const PetscInt *cone, *ornt, *support;
3299         PetscInt        coneNew[2], coneSize, c, supportSize, s;
3300 
3301         ierr             = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
3302         coneNew[0]       = vStartNew + (cone[0] - vStart);
3303         coneNew[1]       = vStartNew + (cone[1] - vStart);
3304         coneNew[(r+1)%2] = newv;
3305         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3306 #if defined(PETSC_USE_DEBUG)
3307         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
3308         for (p = 0; p < 2; ++p) {
3309           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);
3310         }
3311 #endif
3312         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
3313         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
3314         for (s = 0; s < supportSize; ++s) {
3315           if (support[s] >= cMax) {
3316             supportRef[s] = cStartNew + (cMax - cStart)*4 + (support[s] - cMax)*2 + r;
3317           } else {
3318             ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
3319             ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
3320             ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
3321             for (c = 0; c < coneSize; ++c) {
3322               if (cone[c] == f) break;
3323             }
3324             supportRef[s] = cStartNew + (support[s] - cStart)*4 + (ornt[c] < 0 ? (c+1-r)%4 : (c+r)%4);
3325           }
3326         }
3327         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
3328 #if defined(PETSC_USE_DEBUG)
3329         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
3330         for (p = 0; p < supportSize; ++p) {
3331           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);
3332         }
3333 #endif
3334       }
3335     }
3336     /* Interior cell faces have 2 vertices and 2 cells */
3337     for (c = cStart; c < cMax; ++c) {
3338       const PetscInt *cone;
3339 
3340       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
3341       for (r = 0; r < 4; ++r) {
3342         const PetscInt newp = fStartNew + (fMax - fStart)*2 + (c - cStart)*4 + r;
3343         PetscInt       coneNew[2], supportNew[2];
3344 
3345         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r] - fStart);
3346         coneNew[1] = vStartNew + (vEnd - vStart) + (fMax    - fStart) + (c - cStart);
3347         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3348 #if defined(PETSC_USE_DEBUG)
3349         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
3350         for (p = 0; p < 2; ++p) {
3351           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);
3352         }
3353 #endif
3354         supportNew[0] = (c - cStart)*4 + r;
3355         supportNew[1] = (c - cStart)*4 + (r+1)%4;
3356         ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3357 #if defined(PETSC_USE_DEBUG)
3358         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
3359         for (p = 0; p < 2; ++p) {
3360           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);
3361         }
3362 #endif
3363       }
3364     }
3365     /* Hybrid faces have 2 vertices and the same cells */
3366     for (f = fMax; f < fEnd; ++f) {
3367       const PetscInt  newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*4 + (f - fMax);
3368       const PetscInt *cone, *support;
3369       PetscInt        coneNew[2], supportNew[2];
3370       PetscInt        size, s, r;
3371 
3372       ierr       = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
3373       coneNew[0] = vStartNew + (cone[0] - vStart);
3374       coneNew[1] = vStartNew + (cone[1] - vStart);
3375       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3376 #if defined(PETSC_USE_DEBUG)
3377       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
3378       for (p = 0; p < 2; ++p) {
3379         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);
3380       }
3381 #endif
3382       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
3383       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
3384       for (s = 0; s < size; ++s) {
3385         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
3386         for (r = 0; r < 2; ++r) {
3387           if (cone[r+2] == f) break;
3388         }
3389         supportNew[s] = (cMax - cStart)*4 + (support[s] - cMax)*2 + r;
3390       }
3391       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3392 #if defined(PETSC_USE_DEBUG)
3393       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
3394       for (p = 0; p < size; ++p) {
3395         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);
3396       }
3397 #endif
3398     }
3399     /* Cell hybrid faces have 2 vertices and 2 cells */
3400     for (c = cMax; c < cEnd; ++c) {
3401       const PetscInt  newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*4 + (fEnd - fMax) + (c - cMax);
3402       const PetscInt *cone;
3403       PetscInt        coneNew[2], supportNew[2];
3404 
3405       ierr       = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
3406       coneNew[0] = vStartNew + (vEnd - vStart) + (cone[0] - fStart);
3407       coneNew[1] = vStartNew + (vEnd - vStart) + (cone[1] - fStart);
3408       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3409 #if defined(PETSC_USE_DEBUG)
3410       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
3411       for (p = 0; p < 2; ++p) {
3412         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);
3413       }
3414 #endif
3415       supportNew[0] = (cMax - cStart)*4 + (c - cMax)*2 + 0;
3416       supportNew[1] = (cMax - cStart)*4 + (c - cMax)*2 + 1;
3417       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3418 #if defined(PETSC_USE_DEBUG)
3419       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
3420       for (p = 0; p < 2; ++p) {
3421         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);
3422       }
3423 #endif
3424     }
3425     /* Old vertices have identical supports */
3426     for (v = vStart; v < vEnd; ++v) {
3427       const PetscInt  newp = vStartNew + (v - vStart);
3428       const PetscInt *support, *cone;
3429       PetscInt        size, s;
3430 
3431       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
3432       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
3433       for (s = 0; s < size; ++s) {
3434         if (support[s] >= fMax) {
3435           supportRef[s] = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*4 + (support[s] - fMax);
3436         } else {
3437           PetscInt r = 0;
3438 
3439           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
3440           if (cone[1] == v) r = 1;
3441           supportRef[s] = fStartNew + (support[s] - fStart)*2 + r;
3442         }
3443       }
3444       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
3445 #if defined(PETSC_USE_DEBUG)
3446       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", newp, vStartNew, vEndNew);
3447       for (p = 0; p < size; ++p) {
3448         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);
3449       }
3450 #endif
3451     }
3452     /* Face vertices have 2 + cells supports */
3453     for (f = fStart; f < fMax; ++f) {
3454       const PetscInt  newp = vStartNew + (vEnd - vStart) + (f - fStart);
3455       const PetscInt *cone, *support;
3456       PetscInt        size, s;
3457 
3458       ierr          = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
3459       ierr          = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
3460       supportRef[0] = fStartNew + (f - fStart)*2 + 0;
3461       supportRef[1] = fStartNew + (f - fStart)*2 + 1;
3462       for (s = 0; s < size; ++s) {
3463         PetscInt r = 0;
3464 
3465         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
3466         if (support[s] >= cMax) {
3467           supportRef[2+s] = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*4 + (fEnd - fMax) + (support[s] - cMax);
3468         } else {
3469           if      (cone[1] == f) r = 1;
3470           else if (cone[2] == f) r = 2;
3471           else if (cone[3] == f) r = 3;
3472           supportRef[2+s] = fStartNew + (fMax - fStart)*2 + (support[s] - cStart)*4 + r;
3473         }
3474       }
3475       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
3476 #if defined(PETSC_USE_DEBUG)
3477       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", newp, vStartNew, vEndNew);
3478       for (p = 0; p < 2+size; ++p) {
3479         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);
3480       }
3481 #endif
3482     }
3483     /* Cell vertices have 4 supports */
3484     for (c = cStart; c < cMax; ++c) {
3485       const PetscInt newp = vStartNew + (vEnd - vStart) + (fMax - fStart) + (c - cStart);
3486       PetscInt       supportNew[4];
3487 
3488       for (r = 0; r < 4; ++r) {
3489         supportNew[r] = fStartNew + (fMax - fStart)*2 + (c - cStart)*4 + r;
3490       }
3491       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3492     }
3493     ierr = PetscFree(supportRef);CHKERRQ(ierr);
3494     break;
3495   case REFINER_SIMPLEX_3D:
3496     /* All cells have 4 faces: Tet face order is prescribed in DMPlexGetFaces_Internal() */
3497     ierr = DMPlexGetRawFaces_Internal(dm, DM_POLYTOPE_TETRAHEDRON, cellInd, NULL, NULL, &faces);CHKERRQ(ierr);
3498     for (c = cStart; c < cEnd; ++c) {
3499       const PetscInt  newp = cStartNew + (c - cStart)*8;
3500       const PetscInt *cone, *ornt;
3501       PetscInt        coneNew[4], orntNew[4];
3502 
3503       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
3504       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
3505       /* A tetrahedron: {0, a, c, d} */
3506       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetTriSubface_Static(ornt[0], 0); /* A */
3507       orntNew[0] = ornt[0];
3508       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetTriSubface_Static(ornt[1], 0); /* A */
3509       orntNew[1] = ornt[1];
3510       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetTriSubface_Static(ornt[2], 0); /* A */
3511       orntNew[2] = ornt[2];
3512       coneNew[3] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 0;
3513       orntNew[3] = 0;
3514       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
3515       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
3516 #if defined(PETSC_USE_DEBUG)
3517       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);
3518       for (p = 0; p < 4; ++p) {
3519         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);
3520       }
3521 #endif
3522       /* B tetrahedron: {a, 1, b, e} */
3523       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetTriSubface_Static(ornt[0], 1); /* B */
3524       orntNew[0] = ornt[0];
3525       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetTriSubface_Static(ornt[1], 2); /* C */
3526       orntNew[1] = ornt[1];
3527       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 1;
3528       orntNew[2] = 0;
3529       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetTriSubface_Static(ornt[3], 1); /* B */
3530       orntNew[3] = ornt[3];
3531       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
3532       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
3533 #if defined(PETSC_USE_DEBUG)
3534       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);
3535       for (p = 0; p < 4; ++p) {
3536         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);
3537       }
3538 #endif
3539       /* C tetrahedron: {c, b, 2, f} */
3540       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetTriSubface_Static(ornt[0], 2); /* C */
3541       orntNew[0] = ornt[0];
3542       coneNew[1] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 2;
3543       orntNew[1] = 0;
3544       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetTriSubface_Static(ornt[2], 1); /* B */
3545       orntNew[2] = ornt[2];
3546       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetTriSubface_Static(ornt[3], 0); /* A */
3547       orntNew[3] = ornt[3];
3548       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
3549       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
3550 #if defined(PETSC_USE_DEBUG)
3551       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);
3552       for (p = 0; p < 4; ++p) {
3553         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);
3554       }
3555 #endif
3556       /* D tetrahedron: {d, e, f, 3} */
3557       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 3;
3558       orntNew[0] = 0;
3559       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetTriSubface_Static(ornt[1], 1); /* B */
3560       orntNew[1] = ornt[1];
3561       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetTriSubface_Static(ornt[2], 2); /* C */
3562       orntNew[2] = ornt[2];
3563       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetTriSubface_Static(ornt[3], 2); /* C */
3564       orntNew[3] = ornt[3];
3565       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
3566       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
3567 #if defined(PETSC_USE_DEBUG)
3568       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);
3569       for (p = 0; p < 4; ++p) {
3570         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);
3571       }
3572 #endif
3573       /* A' tetrahedron: {c, d, a, f} */
3574       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 0;
3575       orntNew[0] = -3;
3576       coneNew[1] = fStartNew + (cone[2] - fStart)*4 + 3;
3577       orntNew[1] = ornt[2] < 0 ? -(GetTriMidEdge_Static(ornt[2], 0)+1) : GetTriMidEdge_Static(ornt[2], 0);
3578       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 5;
3579       orntNew[2] = 0;
3580       coneNew[3] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 4;
3581       orntNew[3] = 2;
3582       ierr       = DMPlexSetCone(rdm, newp+4, coneNew);CHKERRQ(ierr);
3583       ierr       = DMPlexSetConeOrientation(rdm, newp+4, orntNew);CHKERRQ(ierr);
3584 #if defined(PETSC_USE_DEBUG)
3585       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);
3586       for (p = 0; p < 4; ++p) {
3587         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);
3588       }
3589 #endif
3590       /* B' tetrahedron: {e, b, a, f} */
3591       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 1;
3592       orntNew[0] = -2;
3593       coneNew[1] = fStartNew + (cone[3] - fStart)*4 + 3;
3594       orntNew[1] = ornt[3] < 0 ? -(GetTriMidEdge_Static(ornt[3], 1)+1) : GetTriMidEdge_Static(ornt[3], 1);
3595       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 6;
3596       orntNew[2] = 0;
3597       coneNew[3] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 7;
3598       orntNew[3] = 0;
3599       ierr       = DMPlexSetCone(rdm, newp+5, coneNew);CHKERRQ(ierr);
3600       ierr       = DMPlexSetConeOrientation(rdm, newp+5, orntNew);CHKERRQ(ierr);
3601 #if defined(PETSC_USE_DEBUG)
3602       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);
3603       for (p = 0; p < 4; ++p) {
3604         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);
3605       }
3606 #endif
3607       /* C' tetrahedron: {f, a, c, b} */
3608       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 5;
3609       orntNew[0] = -2;
3610       coneNew[1] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 7;
3611       orntNew[1] = -2;
3612       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 2;
3613       orntNew[2] = -1;
3614       coneNew[3] = fStartNew + (cone[0] - fStart)*4 + 3;
3615       orntNew[3] = ornt[0] < 0 ? -(GetTriMidEdge_Static(ornt[0], 2)+1) : GetTriMidEdge_Static(ornt[0], 2);
3616       ierr       = DMPlexSetCone(rdm, newp+6, coneNew);CHKERRQ(ierr);
3617       ierr       = DMPlexSetConeOrientation(rdm, newp+6, orntNew);CHKERRQ(ierr);
3618 #if defined(PETSC_USE_DEBUG)
3619       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);
3620       for (p = 0; p < 4; ++p) {
3621         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);
3622       }
3623 #endif
3624       /* D' tetrahedron: {f, a, e, d} */
3625       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 6;
3626       orntNew[0] = -2;
3627       coneNew[1] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 4;
3628       orntNew[1] = -1;
3629       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 3;
3630       orntNew[2] = -2;
3631       coneNew[3] = fStartNew + (cone[1] - fStart)*4 + 3;
3632       orntNew[3] = ornt[1] < 0 ? -(GetTriMidEdge_Static(ornt[1], 1)+1) : GetTriMidEdge_Static(ornt[1], 1);
3633       ierr       = DMPlexSetCone(rdm, newp+7, coneNew);CHKERRQ(ierr);
3634       ierr       = DMPlexSetConeOrientation(rdm, newp+7, orntNew);CHKERRQ(ierr);
3635 #if defined(PETSC_USE_DEBUG)
3636       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);
3637       for (p = 0; p < 4; ++p) {
3638         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);
3639       }
3640 #endif
3641     }
3642     /* Split faces have 3 edges and the same cells as the parent */
3643     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
3644     ierr = PetscMalloc1(2 + maxSupportSize*3, &supportRef);CHKERRQ(ierr);
3645     for (f = fStart; f < fEnd; ++f) {
3646       const PetscInt  newp = fStartNew + (f - fStart)*4;
3647       const PetscInt *cone, *ornt, *support;
3648       PetscInt        coneNew[3], orntNew[3], coneSize, supportSize, s;
3649 
3650       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
3651       ierr = DMPlexGetConeOrientation(dm, f, &ornt);CHKERRQ(ierr);
3652       /* A triangle */
3653       coneNew[0] = eStartNew + (cone[0] - eStart)*2 + (ornt[0] < 0 ? 1 : 0);
3654       orntNew[0] = ornt[0];
3655       coneNew[1] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 2;
3656       orntNew[1] = -2;
3657       coneNew[2] = eStartNew + (cone[2] - eStart)*2 + (ornt[2] < 0 ? 0 : 1);
3658       orntNew[2] = ornt[2];
3659       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
3660       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
3661 #if defined(PETSC_USE_DEBUG)
3662       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);
3663       for (p = 0; p < 3; ++p) {
3664         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);
3665       }
3666 #endif
3667       /* B triangle */
3668       coneNew[0] = eStartNew + (cone[0] - eStart)*2 + (ornt[0] < 0 ? 0 : 1);
3669       orntNew[0] = ornt[0];
3670       coneNew[1] = eStartNew + (cone[1] - eStart)*2 + (ornt[1] < 0 ? 1 : 0);
3671       orntNew[1] = ornt[1];
3672       coneNew[2] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 0;
3673       orntNew[2] = -2;
3674       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
3675       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
3676 #if defined(PETSC_USE_DEBUG)
3677       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);
3678       for (p = 0; p < 3; ++p) {
3679         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);
3680       }
3681 #endif
3682       /* C triangle */
3683       coneNew[0] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 1;
3684       orntNew[0] = -2;
3685       coneNew[1] = eStartNew + (cone[1] - eStart)*2 + (ornt[1] < 0 ? 0 : 1);
3686       orntNew[1] = ornt[1];
3687       coneNew[2] = eStartNew + (cone[2] - eStart)*2 + (ornt[2] < 0 ? 1 : 0);
3688       orntNew[2] = ornt[2];
3689       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
3690       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
3691 #if defined(PETSC_USE_DEBUG)
3692       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);
3693       for (p = 0; p < 3; ++p) {
3694         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);
3695       }
3696 #endif
3697       /* D triangle */
3698       coneNew[0] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 0;
3699       orntNew[0] = 0;
3700       coneNew[1] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 1;
3701       orntNew[1] = 0;
3702       coneNew[2] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 2;
3703       orntNew[2] = 0;
3704       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
3705       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
3706 #if defined(PETSC_USE_DEBUG)
3707       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);
3708       for (p = 0; p < 3; ++p) {
3709         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);
3710       }
3711 #endif
3712       ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
3713       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
3714       for (r = 0; r < 4; ++r) {
3715         for (s = 0; s < supportSize; ++s) {
3716           PetscInt subf;
3717           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
3718           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
3719           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
3720           for (c = 0; c < coneSize; ++c) {
3721             if (cone[c] == f) break;
3722           }
3723           subf = GetTriSubfaceInverse_Static(ornt[c], r);
3724           supportRef[s] = cStartNew + (support[s] - cStart)*8 + (r==3 ? (c+2)%4 + 4 : faces[c*3+subf]);
3725         }
3726         ierr = DMPlexSetSupport(rdm, newp+r, supportRef);CHKERRQ(ierr);
3727 #if defined(PETSC_USE_DEBUG)
3728         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);
3729         for (p = 0; p < supportSize; ++p) {
3730           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);
3731         }
3732 #endif
3733       }
3734     }
3735     /* Interior faces have 3 edges and 2 cells */
3736     for (c = cStart; c < cEnd; ++c) {
3737       PetscInt        newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*8;
3738       const PetscInt *cone, *ornt;
3739       PetscInt        coneNew[3], orntNew[3];
3740       PetscInt        supportNew[2];
3741 
3742       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
3743       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
3744       /* Face A: {c, a, d} */
3745       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*3 + GetTriMidEdge_Static(ornt[0], 2);
3746       orntNew[0] = ornt[0] < 0 ? -2 : 0;
3747       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*3 + GetTriMidEdge_Static(ornt[1], 2);
3748       orntNew[1] = ornt[1] < 0 ? -2 : 0;
3749       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*3 + GetTriMidEdge_Static(ornt[2], 2);
3750       orntNew[2] = ornt[2] < 0 ? -2 : 0;
3751       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3752       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3753 #if defined(PETSC_USE_DEBUG)
3754       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
3755       for (p = 0; p < 3; ++p) {
3756         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);
3757       }
3758 #endif
3759       supportNew[0] = (c - cStart)*8 + 0;
3760       supportNew[1] = (c - cStart)*8 + 0+4;
3761       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3762 #if defined(PETSC_USE_DEBUG)
3763       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
3764       for (p = 0; p < 2; ++p) {
3765         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);
3766       }
3767 #endif
3768       ++newp;
3769       /* Face B: {a, b, e} */
3770       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*3 + GetTriMidEdge_Static(ornt[0], 0);
3771       orntNew[0] = ornt[0] < 0 ? -2 : 0;
3772       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*3 + GetTriMidEdge_Static(ornt[3], 0);
3773       orntNew[1] = ornt[3] < 0 ? -2 : 0;
3774       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*3 + GetTriMidEdge_Static(ornt[1], 1);
3775       orntNew[2] = ornt[1] < 0 ? -2 : 0;
3776       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3777       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3778 #if defined(PETSC_USE_DEBUG)
3779       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
3780       for (p = 0; p < 3; ++p) {
3781         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);
3782       }
3783 #endif
3784       supportNew[0] = (c - cStart)*8 + 1;
3785       supportNew[1] = (c - cStart)*8 + 1+4;
3786       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3787 #if defined(PETSC_USE_DEBUG)
3788       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
3789       for (p = 0; p < 2; ++p) {
3790         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);
3791       }
3792 #endif
3793       ++newp;
3794       /* Face C: {c, f, b} */
3795       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*3 + GetTriMidEdge_Static(ornt[2], 0);
3796       orntNew[0] = ornt[2] < 0 ? -2 : 0;
3797       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*3 + GetTriMidEdge_Static(ornt[3], 2);
3798       orntNew[1] = ornt[3] < 0 ? -2 : 0;
3799       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*3 + GetTriMidEdge_Static(ornt[0], 1);
3800       orntNew[2] = ornt[0] < 0 ? -2 : 0;
3801       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3802       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3803 #if defined(PETSC_USE_DEBUG)
3804       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
3805       for (p = 0; p < 3; ++p) {
3806         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);
3807       }
3808 #endif
3809       supportNew[0] = (c - cStart)*8 + 2;
3810       supportNew[1] = (c - cStart)*8 + 2+4;
3811       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3812 #if defined(PETSC_USE_DEBUG)
3813       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
3814       for (p = 0; p < 2; ++p) {
3815         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);
3816       }
3817 #endif
3818       ++newp;
3819       /* Face D: {d, e, f} */
3820       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*3 + GetTriMidEdge_Static(ornt[1], 0);
3821       orntNew[0] = ornt[1] < 0 ? -2 : 0;
3822       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*3 + GetTriMidEdge_Static(ornt[3], 1);
3823       orntNew[1] = ornt[3] < 0 ? -2 : 0;
3824       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*3 + GetTriMidEdge_Static(ornt[2], 1);
3825       orntNew[2] = ornt[2] < 0 ? -2 : 0;
3826       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3827       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3828 #if defined(PETSC_USE_DEBUG)
3829       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
3830       for (p = 0; p < 3; ++p) {
3831         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);
3832       }
3833 #endif
3834       supportNew[0] = (c - cStart)*8 + 3;
3835       supportNew[1] = (c - cStart)*8 + 3+4;
3836       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3837 #if defined(PETSC_USE_DEBUG)
3838       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
3839       for (p = 0; p < 2; ++p) {
3840         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);
3841       }
3842 #endif
3843       ++newp;
3844       /* Face E: {d, f, a} */
3845       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*3 + GetTriMidEdge_Static(ornt[2], 1);
3846       orntNew[0] = ornt[2] < 0 ? 0 : -2;
3847       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart);
3848       orntNew[1] = -2;
3849       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*3 + GetTriMidEdge_Static(ornt[1], 2);
3850       orntNew[2] = ornt[1] < 0 ? -2 : 0;
3851       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3852       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3853 #if defined(PETSC_USE_DEBUG)
3854       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
3855       for (p = 0; p < 3; ++p) {
3856         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);
3857       }
3858 #endif
3859       supportNew[0] = (c - cStart)*8 + 0+4;
3860       supportNew[1] = (c - cStart)*8 + 3+4;
3861       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3862 #if defined(PETSC_USE_DEBUG)
3863       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
3864       for (p = 0; p < 2; ++p) {
3865         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);
3866       }
3867 #endif
3868       ++newp;
3869       /* Face F: {c, a, f} */
3870       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*3 + GetTriMidEdge_Static(ornt[0], 2);
3871       orntNew[0] = ornt[0] < 0 ? -2 : 0;
3872       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart);
3873       orntNew[1] = 0;
3874       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*3 + GetTriMidEdge_Static(ornt[2], 0);
3875       orntNew[2] = ornt[2] < 0 ? 0 : -2;
3876       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3877       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3878 #if defined(PETSC_USE_DEBUG)
3879       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
3880       for (p = 0; p < 3; ++p) {
3881         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);
3882       }
3883 #endif
3884       supportNew[0] = (c - cStart)*8 + 0+4;
3885       supportNew[1] = (c - cStart)*8 + 2+4;
3886       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3887 #if defined(PETSC_USE_DEBUG)
3888       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
3889       for (p = 0; p < 2; ++p) {
3890         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);
3891       }
3892 #endif
3893       ++newp;
3894       /* Face G: {e, a, f} */
3895       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*3 + GetTriMidEdge_Static(ornt[1], 1);
3896       orntNew[0] = ornt[1] < 0 ? -2 : 0;
3897       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart);
3898       orntNew[1] = 0;
3899       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*3 + GetTriMidEdge_Static(ornt[3], 1);
3900       orntNew[2] = ornt[3] < 0 ? 0 : -2;
3901       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3902       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3903 #if defined(PETSC_USE_DEBUG)
3904       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
3905       for (p = 0; p < 3; ++p) {
3906         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);
3907       }
3908 #endif
3909       supportNew[0] = (c - cStart)*8 + 1+4;
3910       supportNew[1] = (c - cStart)*8 + 3+4;
3911       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3912 #if defined(PETSC_USE_DEBUG)
3913       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
3914       for (p = 0; p < 2; ++p) {
3915         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);
3916       }
3917 #endif
3918       ++newp;
3919       /* Face H: {a, b, f} */
3920       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*3 + GetTriMidEdge_Static(ornt[0], 0);
3921       orntNew[0] = ornt[0] < 0 ? -2 : 0;
3922       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*3 + GetTriMidEdge_Static(ornt[3], 2);
3923       orntNew[1] = ornt[3] < 0 ? 0 : -2;
3924       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart);
3925       orntNew[2] = -2;
3926       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3927       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3928 #if defined(PETSC_USE_DEBUG)
3929       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
3930       for (p = 0; p < 3; ++p) {
3931         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);
3932       }
3933 #endif
3934       supportNew[0] = (c - cStart)*8 + 1+4;
3935       supportNew[1] = (c - cStart)*8 + 2+4;
3936       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3937 #if defined(PETSC_USE_DEBUG)
3938       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
3939       for (p = 0; p < 2; ++p) {
3940         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);
3941       }
3942 #endif
3943       ++newp;
3944     }
3945     /* Split Edges have 2 vertices and the same faces as the parent */
3946     for (e = eStart; e < eEnd; ++e) {
3947       const PetscInt newv = vStartNew + (vEnd - vStart) + (e - eStart);
3948 
3949       for (r = 0; r < 2; ++r) {
3950         const PetscInt  newp = eStartNew + (e - eStart)*2 + r;
3951         const PetscInt *cone, *ornt, *support;
3952         PetscInt        coneNew[2], coneSize, c, supportSize, s;
3953 
3954         ierr             = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
3955         coneNew[0]       = vStartNew + (cone[0] - vStart);
3956         coneNew[1]       = vStartNew + (cone[1] - vStart);
3957         coneNew[(r+1)%2] = newv;
3958         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3959 #if defined(PETSC_USE_DEBUG)
3960         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eEndNew);
3961         for (p = 0; p < 2; ++p) {
3962           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);
3963         }
3964 #endif
3965         ierr = DMPlexGetSupportSize(dm, e, &supportSize);CHKERRQ(ierr);
3966         ierr = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
3967         for (s = 0; s < supportSize; ++s) {
3968           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
3969           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
3970           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
3971           for (c = 0; c < coneSize; ++c) {
3972             if (cone[c] == e) break;
3973           }
3974           supportRef[s] = fStartNew + (support[s] - fStart)*4 + (c + (ornt[c] < 0 ? 1-r : r))%3;
3975         }
3976         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
3977 #if defined(PETSC_USE_DEBUG)
3978         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eEndNew);
3979         for (p = 0; p < supportSize; ++p) {
3980           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);
3981         }
3982 #endif
3983       }
3984     }
3985     /* Face edges have 2 vertices and 2+cells*(1/2) faces */
3986     for (f = fStart; f < fEnd; ++f) {
3987       const PetscInt *cone, *ornt, *support;
3988       PetscInt        coneSize, supportSize, s;
3989 
3990       ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
3991       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
3992       for (r = 0; r < 3; ++r) {
3993         const PetscInt  newp = eStartNew + (eEnd - eStart)*2 + (f - fStart)*3 + r;
3994         PetscInt        coneNew[2], intFaces = 0, er, eint[4] = {1, 0, 2, 0};
3995         PetscInt        fint[24] = { 1,  7, -1, -1,  0,  5,
3996                                     -1, -1,  1,  6,  0,  4,
3997                                      2,  5,  3,  4, -1, -1,
3998                                     -1, -1,  3,  6,  2,  7};
3999 
4000         ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
4001         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[(r+0)%3] - eStart);
4002         coneNew[1] = vStartNew + (vEnd - vStart) + (cone[(r+1)%3] - eStart);
4003         ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4004 #if defined(PETSC_USE_DEBUG)
4005         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eEndNew);
4006         for (p = 0; p < 2; ++p) {
4007           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);
4008         }
4009 #endif
4010         supportRef[0] = fStartNew + (f - fStart)*4 + (r+1)%3;
4011         supportRef[1] = fStartNew + (f - fStart)*4 + 3;
4012         for (s = 0; s < supportSize; ++s) {
4013           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
4014           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
4015           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
4016           for (c = 0; c < coneSize; ++c) {if (cone[c] == f) break;}
4017           /* Here we want to determine whether edge newp contains a vertex which is part of the cross-tet edge */
4018           er = GetTriMidEdgeInverse_Static(ornt[c], r);
4019           if (er == eint[c]) {
4020             supportRef[2+intFaces++] = fStartNew + (fEnd - fStart)*4 + (support[s] - cStart)*8 + (c + 2)%4;
4021           } else {
4022             supportRef[2+intFaces++] = fStartNew + (fEnd - fStart)*4 + (support[s] - cStart)*8 + fint[(c*3 + er)*2 + 0];
4023             supportRef[2+intFaces++] = fStartNew + (fEnd - fStart)*4 + (support[s] - cStart)*8 + fint[(c*3 + er)*2 + 1];
4024           }
4025         }
4026         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
4027 #if defined(PETSC_USE_DEBUG)
4028         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eEndNew);
4029         for (p = 0; p < intFaces; ++p) {
4030           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);
4031         }
4032 #endif
4033       }
4034     }
4035     /* Interior edges have 2 vertices and 4 faces */
4036     for (c = cStart; c < cEnd; ++c) {
4037       const PetscInt  newp = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart);
4038       const PetscInt *cone, *ornt, *fcone;
4039       PetscInt        coneNew[2], supportNew[4], find;
4040 
4041       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
4042       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
4043       ierr = DMPlexGetCone(dm, cone[0], &fcone);CHKERRQ(ierr);
4044       find = GetTriEdge_Static(ornt[0], 0);
4045       coneNew[0] = vStartNew + (vEnd - vStart) + (fcone[find] - eStart);
4046       ierr = DMPlexGetCone(dm, cone[2], &fcone);CHKERRQ(ierr);
4047       find = GetTriEdge_Static(ornt[2], 1);
4048       coneNew[1] = vStartNew + (vEnd - vStart) + (fcone[find] - eStart);
4049       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4050 #if defined(PETSC_USE_DEBUG)
4051       if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eEndNew);
4052       for (p = 0; p < 2; ++p) {
4053         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);
4054       }
4055 #endif
4056       supportNew[0] = fStartNew + (fEnd - fStart)*4 + (c - cStart)*8 + 4;
4057       supportNew[1] = fStartNew + (fEnd - fStart)*4 + (c - cStart)*8 + 5;
4058       supportNew[2] = fStartNew + (fEnd - fStart)*4 + (c - cStart)*8 + 6;
4059       supportNew[3] = fStartNew + (fEnd - fStart)*4 + (c - cStart)*8 + 7;
4060       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
4061 #if defined(PETSC_USE_DEBUG)
4062       if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eEndNew);
4063       for (p = 0; p < 4; ++p) {
4064         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);
4065       }
4066 #endif
4067     }
4068     /* Old vertices have identical supports */
4069     for (v = vStart; v < vEnd; ++v) {
4070       const PetscInt  newp = vStartNew + (v - vStart);
4071       const PetscInt *support, *cone;
4072       PetscInt        size, s;
4073 
4074       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
4075       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
4076       for (s = 0; s < size; ++s) {
4077         PetscInt r = 0;
4078 
4079         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
4080         if (cone[1] == v) r = 1;
4081         supportRef[s] = eStartNew + (support[s] - eStart)*2 + r;
4082       }
4083       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
4084 #if defined(PETSC_USE_DEBUG)
4085       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", newp, vStartNew, vEndNew);
4086       for (p = 0; p < size; ++p) {
4087         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);
4088       }
4089 #endif
4090     }
4091     /* Edge vertices have 2 + face*2 + 0/1 supports */
4092     for (e = eStart; e < eEnd; ++e) {
4093       const PetscInt  newp = vStartNew + (vEnd - vStart) + (e - eStart);
4094       const PetscInt *cone, *support;
4095       PetscInt       *star = NULL, starSize, cellSize = 0, coneSize, size, s;
4096 
4097       ierr          = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
4098       ierr          = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
4099       supportRef[0] = eStartNew + (e - eStart)*2 + 0;
4100       supportRef[1] = eStartNew + (e - eStart)*2 + 1;
4101       for (s = 0; s < size; ++s) {
4102         PetscInt r = 0;
4103 
4104         ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
4105         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
4106         for (r = 0; r < coneSize; ++r) {if (cone[r] == e) break;}
4107         supportRef[2+s*2+0] = eStartNew + (eEnd - eStart)*2 + (support[s] - fStart)*3 + (r+0)%3;
4108         supportRef[2+s*2+1] = eStartNew + (eEnd - eStart)*2 + (support[s] - fStart)*3 + (r+2)%3;
4109       }
4110       ierr = DMPlexGetTransitiveClosure(dm, e, PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
4111       for (s = 0; s < starSize*2; s += 2) {
4112         const PetscInt *cone, *ornt;
4113         PetscInt        e01, e23;
4114 
4115         if ((star[s] >= cStart) && (star[s] < cEnd)) {
4116           /* Check edge 0-1 */
4117           ierr = DMPlexGetCone(dm, star[s], &cone);CHKERRQ(ierr);
4118           ierr = DMPlexGetConeOrientation(dm, star[s], &ornt);CHKERRQ(ierr);
4119           ierr = DMPlexGetCone(dm, cone[0], &cone);CHKERRQ(ierr);
4120           e01  = cone[GetTriEdge_Static(ornt[0], 0)];
4121           /* Check edge 2-3 */
4122           ierr = DMPlexGetCone(dm, star[s], &cone);CHKERRQ(ierr);
4123           ierr = DMPlexGetConeOrientation(dm, star[s], &ornt);CHKERRQ(ierr);
4124           ierr = DMPlexGetCone(dm, cone[2], &cone);CHKERRQ(ierr);
4125           e23  = cone[GetTriEdge_Static(ornt[2], 1)];
4126           if ((e01 == e) || (e23 == e)) {supportRef[2+size*2+cellSize++] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (star[s] - cStart);}
4127         }
4128       }
4129       ierr = DMPlexRestoreTransitiveClosure(dm, e, PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
4130       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
4131 #if defined(PETSC_USE_DEBUG)
4132       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", newp, vStartNew, vEndNew);
4133       for (p = 0; p < 2+size*2+cellSize; ++p) {
4134         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);
4135       }
4136 #endif
4137     }
4138     ierr = PetscFree(supportRef);CHKERRQ(ierr);
4139     ierr = DMPlexRestoreFaces_Internal(dm, cStart, NULL, NULL, &faces);CHKERRQ(ierr);
4140     break;
4141   case REFINER_HYBRID_SIMPLEX_3D:
4142     ierr = DMPlexGetHybridBounds(rdm, &cMaxNew, &fMaxNew, &eMaxNew, NULL);CHKERRQ(ierr);
4143     /* Interior cells have 4 faces: Tet face order is prescribed in DMPlexGetFaces_Internal() */
4144     ierr = DMPlexGetRawFaces_Internal(dm, DM_POLYTOPE_TETRAHEDRON, cellInd, NULL, NULL, &faces);CHKERRQ(ierr);
4145     for (c = cStart; c < cMax; ++c) {
4146       const PetscInt  newp = cStartNew + (c - cStart)*8;
4147       const PetscInt *cone, *ornt;
4148       PetscInt        coneNew[4], orntNew[4];
4149 
4150       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
4151       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
4152       /* A tetrahedron: {0, a, c, d} */
4153       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetTriSubface_Static(ornt[0], 0); /* A */
4154       orntNew[0] = ornt[0];
4155       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetTriSubface_Static(ornt[1], 0); /* A */
4156       orntNew[1] = ornt[1];
4157       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetTriSubface_Static(ornt[2], 0); /* A */
4158       orntNew[2] = ornt[2];
4159       coneNew[3] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 0;
4160       orntNew[3] = 0;
4161       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
4162       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
4163 #if defined(PETSC_USE_DEBUG)
4164       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);
4165       for (p = 0; p < 4; ++p) {
4166         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);
4167       }
4168 #endif
4169       /* B tetrahedron: {a, 1, b, e} */
4170       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetTriSubface_Static(ornt[0], 1); /* B */
4171       orntNew[0] = ornt[0];
4172       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetTriSubface_Static(ornt[1], 2); /* C */
4173       orntNew[1] = ornt[1];
4174       coneNew[2] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 1;
4175       orntNew[2] = 0;
4176       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetTriSubface_Static(ornt[3], 1); /* B */
4177       orntNew[3] = ornt[3];
4178       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
4179       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
4180 #if defined(PETSC_USE_DEBUG)
4181       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);
4182       for (p = 0; p < 4; ++p) {
4183         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);
4184       }
4185 #endif
4186       /* C tetrahedron: {c, b, 2, f} */
4187       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetTriSubface_Static(ornt[0], 2); /* C */
4188       orntNew[0] = ornt[0];
4189       coneNew[1] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 2;
4190       orntNew[1] = 0;
4191       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetTriSubface_Static(ornt[2], 1); /* B */
4192       orntNew[2] = ornt[2];
4193       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetTriSubface_Static(ornt[3], 0); /* A */
4194       orntNew[3] = ornt[3];
4195       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
4196       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
4197 #if defined(PETSC_USE_DEBUG)
4198       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);
4199       for (p = 0; p < 4; ++p) {
4200         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);
4201       }
4202 #endif
4203       /* D tetrahedron: {d, e, f, 3} */
4204       coneNew[0] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 3;
4205       orntNew[0] = 0;
4206       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetTriSubface_Static(ornt[1], 1); /* B */
4207       orntNew[1] = ornt[1];
4208       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetTriSubface_Static(ornt[2], 2); /* C */
4209       orntNew[2] = ornt[2];
4210       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetTriSubface_Static(ornt[3], 2); /* C */
4211       orntNew[3] = ornt[3];
4212       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
4213       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
4214 #if defined(PETSC_USE_DEBUG)
4215       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);
4216       for (p = 0; p < 4; ++p) {
4217         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);
4218       }
4219 #endif
4220       /* A' tetrahedron: {d, a, c, f} */
4221       coneNew[0] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 0;
4222       orntNew[0] = -3;
4223       coneNew[1] = fStartNew + (cone[2] - fStart)*4 + 3;
4224       orntNew[1] = ornt[2] < 0 ? -(GetTriMidEdge_Static(ornt[2], 0)+1) : GetTriMidEdge_Static(ornt[2], 0);
4225       coneNew[2] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 5;
4226       orntNew[2] = 0;
4227       coneNew[3] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 4;
4228       orntNew[3] = 2;
4229       ierr       = DMPlexSetCone(rdm, newp+4, coneNew);CHKERRQ(ierr);
4230       ierr       = DMPlexSetConeOrientation(rdm, newp+4, orntNew);CHKERRQ(ierr);
4231 #if defined(PETSC_USE_DEBUG)
4232       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);
4233       for (p = 0; p < 4; ++p) {
4234         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);
4235       }
4236 #endif
4237       /* B' tetrahedron: {e, b, a, f} */
4238       coneNew[0] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 1;
4239       orntNew[0] = -3;
4240       coneNew[1] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 6;
4241       orntNew[1] = 1;
4242       coneNew[2] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 7;
4243       orntNew[2] = 0;
4244       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + 3;
4245       orntNew[3] = ornt[3] < 0 ? -(GetTriMidEdge_Static(ornt[3], 0)+1) : GetTriMidEdge_Static(ornt[3], 0);
4246       ierr       = DMPlexSetCone(rdm, newp+5, coneNew);CHKERRQ(ierr);
4247       ierr       = DMPlexSetConeOrientation(rdm, newp+5, orntNew);CHKERRQ(ierr);
4248 #if defined(PETSC_USE_DEBUG)
4249       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);
4250       for (p = 0; p < 4; ++p) {
4251         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);
4252       }
4253 #endif
4254       /* C' tetrahedron: {b, f, c, a} */
4255       coneNew[0] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 2;
4256       orntNew[0] = -3;
4257       coneNew[1] = fStartNew + (cone[0] - fStart)*4 + 3;
4258       orntNew[1] = ornt[0] < 0 ? -(GetTriMidEdge_Static(ornt[0], 2)+1) : GetTriMidEdge_Static(ornt[0], 2);
4259       coneNew[2] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 5;
4260       orntNew[2] = -3;
4261       coneNew[3] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 7;
4262       orntNew[3] = -2;
4263       ierr       = DMPlexSetCone(rdm, newp+6, coneNew);CHKERRQ(ierr);
4264       ierr       = DMPlexSetConeOrientation(rdm, newp+6, orntNew);CHKERRQ(ierr);
4265 #if defined(PETSC_USE_DEBUG)
4266       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);
4267       for (p = 0; p < 4; ++p) {
4268         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);
4269       }
4270 #endif
4271       /* D' tetrahedron: {f, e, d, a} */
4272       coneNew[0] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 3;
4273       orntNew[0] = -3;
4274       coneNew[1] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 4;
4275       orntNew[1] = -3;
4276       coneNew[2] = fStartNew + (cone[1] - fStart)*4 + 3;
4277       orntNew[2] = ornt[1] < 0 ? -(GetTriMidEdge_Static(ornt[1], 0)+1) : GetTriMidEdge_Static(ornt[1], 0);
4278       coneNew[3] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 6;
4279       orntNew[3] = -3;
4280       ierr       = DMPlexSetCone(rdm, newp+7, coneNew);CHKERRQ(ierr);
4281       ierr       = DMPlexSetConeOrientation(rdm, newp+7, orntNew);CHKERRQ(ierr);
4282 #if defined(PETSC_USE_DEBUG)
4283       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);
4284       for (p = 0; p < 4; ++p) {
4285         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);
4286       }
4287 #endif
4288     }
4289     /* Hybrid cells have 5 faces */
4290     for (c = cMax; c < cEnd; ++c) {
4291       const PetscInt  newp = cStartNew + (cMax - cStart)*8 + (c - cMax)*4;
4292       const PetscInt *cone, *ornt, *fornt;
4293       PetscInt        coneNew[5], orntNew[5], o, of, i;
4294 
4295       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
4296       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
4297       ierr = DMPlexGetConeOrientation(dm, cone[0], &fornt);CHKERRQ(ierr);
4298       o = ornt[0] < 0 ? -1 : 1;
4299       for (r = 0; r < 3; ++r) {
4300         coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetTriSubface_Static(ornt[0], r);
4301         orntNew[0] = ornt[0];
4302         coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetTriSubface_Static(ornt[1], r);
4303         orntNew[1] = ornt[1];
4304         of = fornt[GetTriEdge_Static(ornt[0], r)]       < 0 ? -1 : 1;
4305         i  = GetTriEdgeInverse_Static(ornt[0], r)       + 2;
4306         coneNew[i] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (cone[2+GetTriEdge_Static(ornt[0], r)]       - fMax)*2 + (o*of < 0 ? 1 : 0);
4307         orntNew[i] = 0;
4308         i  = GetTriEdgeInverse_Static(ornt[0], (r+1)%3) + 2;
4309         coneNew[i] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (c - cMax)*3 + GetTriSubface_Static(ornt[0], r);
4310         orntNew[i] = 0;
4311         of = fornt[GetTriEdge_Static(ornt[0], (r+2)%3)] < 0 ? -1 : 1;
4312         i  = GetTriEdgeInverse_Static(ornt[0], (r+2)%3) + 2;
4313         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);
4314         orntNew[i] = 0;
4315         ierr = DMPlexSetCone(rdm, newp+r, coneNew);CHKERRQ(ierr);
4316         ierr = DMPlexSetConeOrientation(rdm, newp+r, orntNew);CHKERRQ(ierr);
4317 #if defined(PETSC_USE_DEBUG)
4318         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);
4319         for (p = 0; p < 2; ++p) {
4320           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);
4321         }
4322         for (p = 2; p < 5; ++p) {
4323           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);
4324         }
4325 #endif
4326       }
4327       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + 3;
4328       orntNew[0] = 0;
4329       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + 3;
4330       orntNew[1] = 0;
4331       coneNew[2] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (c - cMax)*3 + 1;
4332       orntNew[2] = 0;
4333       coneNew[3] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (c - cMax)*3 + 2;
4334       orntNew[3] = 0;
4335       coneNew[4] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (c - cMax)*3 + 0;
4336       orntNew[4] = 0;
4337       ierr = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
4338       ierr = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
4339 #if defined(PETSC_USE_DEBUG)
4340       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);
4341       for (p = 0; p < 2; ++p) {
4342         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);
4343       }
4344       for (p = 2; p < 5; ++p) {
4345         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);
4346       }
4347 #endif
4348     }
4349     /* Split faces have 3 edges and the same cells as the parent */
4350     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
4351     ierr = PetscMalloc1(2 + maxSupportSize*2, &supportRef);CHKERRQ(ierr);
4352     for (f = fStart; f < fMax; ++f) {
4353       const PetscInt  newp = fStartNew + (f - fStart)*4;
4354       const PetscInt *cone, *ornt, *support;
4355       PetscInt        coneNew[3], orntNew[3], coneSize, supportSize, s;
4356 
4357       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
4358       ierr = DMPlexGetConeOrientation(dm, f, &ornt);CHKERRQ(ierr);
4359       /* A triangle */
4360       coneNew[0] = eStartNew + (cone[0] - eStart)*2 + (ornt[0] < 0 ? 1 : 0);
4361       orntNew[0] = ornt[0];
4362       coneNew[1] = eStartNew + (eMax    - eStart)*2 + (f - fStart)*3 + 2;
4363       orntNew[1] = -2;
4364       coneNew[2] = eStartNew + (cone[2] - eStart)*2 + (ornt[2] < 0 ? 0 : 1);
4365       orntNew[2] = ornt[2];
4366       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
4367       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
4368 #if defined(PETSC_USE_DEBUG)
4369       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);
4370       for (p = 0; p < 3; ++p) {
4371         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);
4372       }
4373 #endif
4374       /* B triangle */
4375       coneNew[0] = eStartNew + (cone[0] - eStart)*2 + (ornt[0] < 0 ? 0 : 1);
4376       orntNew[0] = ornt[0];
4377       coneNew[1] = eStartNew + (cone[1] - eStart)*2 + (ornt[1] < 0 ? 1 : 0);
4378       orntNew[1] = ornt[1];
4379       coneNew[2] = eStartNew + (eMax    - eStart)*2 + (f - fStart)*3 + 0;
4380       orntNew[2] = -2;
4381       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
4382       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
4383 #if defined(PETSC_USE_DEBUG)
4384       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);
4385       for (p = 0; p < 3; ++p) {
4386         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);
4387       }
4388 #endif
4389       /* C triangle */
4390       coneNew[0] = eStartNew + (eMax    - eStart)*2 + (f - fStart)*3 + 1;
4391       orntNew[0] = -2;
4392       coneNew[1] = eStartNew + (cone[1] - eStart)*2 + (ornt[1] < 0 ? 0 : 1);
4393       orntNew[1] = ornt[1];
4394       coneNew[2] = eStartNew + (cone[2] - eStart)*2 + (ornt[2] < 0 ? 1 : 0);
4395       orntNew[2] = ornt[2];
4396       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
4397       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
4398 #if defined(PETSC_USE_DEBUG)
4399       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);
4400       for (p = 0; p < 3; ++p) {
4401         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);
4402       }
4403 #endif
4404       /* D triangle */
4405       coneNew[0] = eStartNew + (eMax    - eStart)*2 + (f - fStart)*3 + 0;
4406       orntNew[0] = 0;
4407       coneNew[1] = eStartNew + (eMax    - eStart)*2 + (f - fStart)*3 + 1;
4408       orntNew[1] = 0;
4409       coneNew[2] = eStartNew + (eMax    - eStart)*2 + (f - fStart)*3 + 2;
4410       orntNew[2] = 0;
4411       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
4412       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
4413 #if defined(PETSC_USE_DEBUG)
4414       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);
4415       for (p = 0; p < 3; ++p) {
4416         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);
4417       }
4418 #endif
4419       ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
4420       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
4421       for (r = 0; r < 4; ++r) {
4422         for (s = 0; s < supportSize; ++s) {
4423           PetscInt subf;
4424           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
4425           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
4426           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
4427           for (c = 0; c < coneSize; ++c) {
4428             if (cone[c] == f) break;
4429           }
4430           subf = GetTriSubfaceInverse_Static(ornt[c], r);
4431           if (support[s] < cMax) {
4432             supportRef[s] = cStartNew + (support[s] - cStart)*8 + (r==3 ? (c+2)%4 + 4 : faces[c*3+subf]);
4433           } else {
4434             supportRef[s] = cStartNew + (cMax - cStart)*8 + (support[s] - cMax)*4 + (r==3 ? r : subf);
4435           }
4436         }
4437         ierr = DMPlexSetSupport(rdm, newp+r, supportRef);CHKERRQ(ierr);
4438 #if defined(PETSC_USE_DEBUG)
4439         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);
4440         for (p = 0; p < supportSize; ++p) {
4441           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);
4442         }
4443 #endif
4444       }
4445     }
4446     /* Interior cell faces have 3 edges and 2 cells */
4447     for (c = cStart; c < cMax; ++c) {
4448       PetscInt        newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*8;
4449       const PetscInt *cone, *ornt;
4450       PetscInt        coneNew[3], orntNew[3];
4451       PetscInt        supportNew[2];
4452 
4453       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
4454       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
4455       /* Face A: {c, a, d} */
4456       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*3 + GetTriMidEdge_Static(ornt[0], 2);
4457       orntNew[0] = ornt[0] < 0 ? -2 : 0;
4458       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*3 + GetTriMidEdge_Static(ornt[1], 2);
4459       orntNew[1] = ornt[1] < 0 ? -2 : 0;
4460       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*3 + GetTriMidEdge_Static(ornt[2], 2);
4461       orntNew[2] = ornt[2] < 0 ? -2 : 0;
4462       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4463       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4464 #if defined(PETSC_USE_DEBUG)
4465       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fMaxNew);
4466       for (p = 0; p < 3; ++p) {
4467         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);
4468       }
4469 #endif
4470       supportNew[0] = (c - cStart)*8 + 0;
4471       supportNew[1] = (c - cStart)*8 + 0+4;
4472       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
4473 #if defined(PETSC_USE_DEBUG)
4474       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fMaxNew);
4475       for (p = 0; p < 2; ++p) {
4476         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);
4477       }
4478 #endif
4479       ++newp;
4480       /* Face B: {a, b, e} */
4481       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*3 + GetTriMidEdge_Static(ornt[0], 0);
4482       orntNew[0] = ornt[0] < 0 ? -2 : 0;
4483       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*3 + GetTriMidEdge_Static(ornt[3], 0);
4484       orntNew[1] = ornt[3] < 0 ? -2 : 0;
4485       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*3 + GetTriMidEdge_Static(ornt[1], 1);
4486       orntNew[2] = ornt[1] < 0 ? -2 : 0;
4487       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4488       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4489 #if defined(PETSC_USE_DEBUG)
4490       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);
4491       for (p = 0; p < 3; ++p) {
4492         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);
4493       }
4494 #endif
4495       supportNew[0] = (c - cStart)*8 + 1;
4496       supportNew[1] = (c - cStart)*8 + 1+4;
4497       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
4498 #if defined(PETSC_USE_DEBUG)
4499       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fMaxNew);
4500       for (p = 0; p < 2; ++p) {
4501         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);
4502       }
4503 #endif
4504       ++newp;
4505       /* Face C: {c, f, b} */
4506       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*3 + GetTriMidEdge_Static(ornt[2], 0);
4507       orntNew[0] = ornt[2] < 0 ? -2 : 0;
4508       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*3 + GetTriMidEdge_Static(ornt[3], 2);
4509       orntNew[1] = ornt[3] < 0 ? -2 : 0;
4510       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*3 + GetTriMidEdge_Static(ornt[0], 1);
4511       orntNew[2] = ornt[0] < 0 ? -2 : 0;
4512       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4513       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4514 #if defined(PETSC_USE_DEBUG)
4515       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fMaxNew);
4516       for (p = 0; p < 3; ++p) {
4517         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);
4518       }
4519 #endif
4520       supportNew[0] = (c - cStart)*8 + 2;
4521       supportNew[1] = (c - cStart)*8 + 2+4;
4522       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
4523 #if defined(PETSC_USE_DEBUG)
4524       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fMaxNew);
4525       for (p = 0; p < 2; ++p) {
4526         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);
4527       }
4528 #endif
4529       ++newp;
4530       /* Face D: {d, e, f} */
4531       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*3 + GetTriMidEdge_Static(ornt[1], 0);
4532       orntNew[0] = ornt[1] < 0 ? -2 : 0;
4533       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*3 + GetTriMidEdge_Static(ornt[3], 1);
4534       orntNew[1] = ornt[3] < 0 ? -2 : 0;
4535       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*3 + GetTriMidEdge_Static(ornt[2], 1);
4536       orntNew[2] = ornt[2] < 0 ? -2 : 0;
4537       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4538       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4539 #if defined(PETSC_USE_DEBUG)
4540       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fMaxNew);
4541       for (p = 0; p < 3; ++p) {
4542         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);
4543       }
4544 #endif
4545       supportNew[0] = (c - cStart)*8 + 3;
4546       supportNew[1] = (c - cStart)*8 + 3+4;
4547       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
4548 #if defined(PETSC_USE_DEBUG)
4549       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fMaxNew);
4550       for (p = 0; p < 2; ++p) {
4551         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);
4552       }
4553 #endif
4554       ++newp;
4555       /* Face E: {d, f, a} */
4556       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*3 + GetTriMidEdge_Static(ornt[2], 1);
4557       orntNew[0] = ornt[2] < 0 ? 0 : -2;
4558       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart);
4559       orntNew[1] = -2;
4560       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*3 + GetTriMidEdge_Static(ornt[1], 2);
4561       orntNew[2] = ornt[1] < 0 ? -2 : 0;
4562       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4563       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4564 #if defined(PETSC_USE_DEBUG)
4565       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fMaxNew);
4566       for (p = 0; p < 3; ++p) {
4567         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);
4568       }
4569 #endif
4570       supportNew[0] = (c - cStart)*8 + 0+4;
4571       supportNew[1] = (c - cStart)*8 + 3+4;
4572       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
4573 #if defined(PETSC_USE_DEBUG)
4574       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fMaxNew);
4575       for (p = 0; p < 2; ++p) {
4576         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);
4577       }
4578 #endif
4579       ++newp;
4580       /* Face F: {c, a, f} */
4581       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*3 + GetTriMidEdge_Static(ornt[0], 2);
4582       orntNew[0] = ornt[0] < 0 ? -2 : 0;
4583       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart);
4584       orntNew[1] = 0;
4585       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*3 + GetTriMidEdge_Static(ornt[2], 0);
4586       orntNew[2] = ornt[2] < 0 ? 0 : -2;
4587       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4588       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4589 #if defined(PETSC_USE_DEBUG)
4590       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fMaxNew);
4591       for (p = 0; p < 3; ++p) {
4592         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);
4593       }
4594 #endif
4595       supportNew[0] = (c - cStart)*8 + 0+4;
4596       supportNew[1] = (c - cStart)*8 + 2+4;
4597       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
4598 #if defined(PETSC_USE_DEBUG)
4599       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fMaxNew);
4600       for (p = 0; p < 2; ++p) {
4601         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);
4602       }
4603 #endif
4604       ++newp;
4605       /* Face G: {e, a, f} */
4606       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*3 + GetTriMidEdge_Static(ornt[1], 1);
4607       orntNew[0] = ornt[1] < 0 ? -2 : 0;
4608       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart);
4609       orntNew[1] = 0;
4610       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*3 + GetTriMidEdge_Static(ornt[3], 1);
4611       orntNew[2] = ornt[3] < 0 ? 0 : -2;
4612       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4613       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4614 #if defined(PETSC_USE_DEBUG)
4615       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fMaxNew);
4616       for (p = 0; p < 3; ++p) {
4617         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);
4618       }
4619 #endif
4620       supportNew[0] = (c - cStart)*8 + 1+4;
4621       supportNew[1] = (c - cStart)*8 + 3+4;
4622       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
4623 #if defined(PETSC_USE_DEBUG)
4624       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fMaxNew);
4625       for (p = 0; p < 2; ++p) {
4626         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);
4627       }
4628 #endif
4629       ++newp;
4630       /* Face H: {a, b, f} */
4631       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*3 + GetTriMidEdge_Static(ornt[0], 0);
4632       orntNew[0] = ornt[0] < 0 ? -2 : 0;
4633       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*3 + GetTriMidEdge_Static(ornt[3], 2);
4634       orntNew[1] = ornt[3] < 0 ? 0 : -2;
4635       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart);
4636       orntNew[2] = -2;
4637       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4638       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4639 #if defined(PETSC_USE_DEBUG)
4640       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fMaxNew);
4641       for (p = 0; p < 3; ++p) {
4642         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);
4643       }
4644 #endif
4645       supportNew[0] = (c - cStart)*8 + 1+4;
4646       supportNew[1] = (c - cStart)*8 + 2+4;
4647       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
4648 #if defined(PETSC_USE_DEBUG)
4649       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fMaxNew);
4650       for (p = 0; p < 2; ++p) {
4651         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);
4652       }
4653 #endif
4654       ++newp;
4655     }
4656     /* Hybrid split faces have 4 edges and same cells */
4657     for (f = fMax; f < fEnd; ++f) {
4658       const PetscInt *cone, *ornt, *support;
4659       PetscInt        coneNew[4], orntNew[4];
4660       PetscInt        supportNew[2], size, s, c;
4661 
4662       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
4663       ierr = DMPlexGetConeOrientation(dm, f, &ornt);CHKERRQ(ierr);
4664       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
4665       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
4666       for (r = 0; r < 2; ++r) {
4667         const PetscInt newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (f - fMax)*2 + r;
4668 
4669         coneNew[0]   = eStartNew + (cone[0] - eStart)*2 + (ornt[0] < 0 ? 1-r : r);
4670         orntNew[0]   = ornt[0];
4671         coneNew[1]   = eStartNew + (cone[1] - eStart)*2 + (ornt[1] < 0 ? 1-r : r);
4672         orntNew[1]   = ornt[1];
4673         coneNew[2+r] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (cone[2+r] - eMax);
4674         orntNew[2+r] = 0;
4675         coneNew[3-r] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (eEnd      - eMax) + (f - fMax);
4676         orntNew[3-r] = 0;
4677         ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4678         ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4679 #if defined(PETSC_USE_DEBUG)
4680         if ((newp < fMaxNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a hybrid face [%D, %D)", newp, fMaxNew, fEndNew);
4681         for (p = 0; p < 2; ++p) {
4682           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);
4683         }
4684         for (p = 2; p < 4; ++p) {
4685           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);
4686         }
4687 #endif
4688         for (s = 0; s < size; ++s) {
4689           const PetscInt *coneCell, *orntCell, *fornt;
4690           PetscInt        o, of;
4691 
4692           ierr = DMPlexGetCone(dm, support[s], &coneCell);CHKERRQ(ierr);
4693           ierr = DMPlexGetConeOrientation(dm, support[s], &orntCell);CHKERRQ(ierr);
4694           o = orntCell[0] < 0 ? -1 : 1;
4695           for (c = 2; c < 5; ++c) if (coneCell[c] == f) break;
4696           if (c >= 5) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Could not find face %D in cone of cell %D", f, support[s]);
4697           ierr = DMPlexGetConeOrientation(dm, coneCell[0], &fornt);CHKERRQ(ierr);
4698           of = fornt[c-2] < 0 ? -1 : 1;
4699           supportNew[s] = cStartNew + (cMax - cStart)*8 + (support[s] - cMax)*4 + (GetTriEdgeInverse_Static(orntCell[0], c-2) + (o*of < 0 ? 1-r : r))%3;
4700         }
4701         ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
4702 #if defined(PETSC_USE_DEBUG)
4703         if ((newp < fMaxNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a hybrid face [%D, %D)", newp, fMaxNew, fEndNew);
4704         for (p = 0; p < size; ++p) {
4705           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);
4706         }
4707 #endif
4708       }
4709     }
4710     /* Hybrid cell faces have 4 edges and 2 cells */
4711     for (c = cMax; c < cEnd; ++c) {
4712       PetscInt        newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (c - cMax)*3;
4713       const PetscInt *cone, *ornt;
4714       PetscInt        coneNew[4], orntNew[4];
4715       PetscInt        supportNew[2];
4716 
4717       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
4718       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
4719       for (r = 0; r < 3; ++r) {
4720         coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*3 + (r+2)%3;
4721         orntNew[0] = 0;
4722         coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*3 + (r+2)%3;
4723         orntNew[1] = 0;
4724         coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (eEnd - eMax) + (cone[2+(r+2)%3] - fMax);
4725         orntNew[2] = 0;
4726         coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (eEnd - eMax) + (cone[2+r]       - fMax);
4727         orntNew[3] = 0;
4728         ierr = DMPlexSetCone(rdm, newp+r, coneNew);CHKERRQ(ierr);
4729         ierr = DMPlexSetConeOrientation(rdm, newp+r, orntNew);CHKERRQ(ierr);
4730 #if defined(PETSC_USE_DEBUG)
4731         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);
4732         for (p = 0; p < 2; ++p) {
4733           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);
4734         }
4735         for (p = 2; p < 4; ++p) {
4736           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);
4737         }
4738 #endif
4739         supportNew[0] = cStartNew + (cMax - cStart)*8 + (c - cMax)*4 + GetTriSubface_Static(ornt[0], r);
4740         supportNew[1] = cStartNew + (cMax - cStart)*8 + (c - cMax)*4 + 3;
4741         ierr          = DMPlexSetSupport(rdm, newp+r, supportNew);CHKERRQ(ierr);
4742 #if defined(PETSC_USE_DEBUG)
4743         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);
4744         for (p = 0; p < 2; ++p) {
4745           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);
4746         }
4747 #endif
4748       }
4749     }
4750     /* Interior split edges have 2 vertices and the same faces as the parent */
4751     for (e = eStart; e < eMax; ++e) {
4752       const PetscInt newv = vStartNew + (vEnd - vStart) + (e - eStart);
4753 
4754       for (r = 0; r < 2; ++r) {
4755         const PetscInt  newp = eStartNew + (e - eStart)*2 + r;
4756         const PetscInt *cone, *ornt, *support;
4757         PetscInt        coneNew[2], coneSize, c, supportSize, s;
4758 
4759         ierr             = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
4760         coneNew[0]       = vStartNew + (cone[0] - vStart);
4761         coneNew[1]       = vStartNew + (cone[1] - vStart);
4762         coneNew[(r+1)%2] = newv;
4763         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4764 #if defined(PETSC_USE_DEBUG)
4765         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eMaxNew);
4766         for (p = 0; p < 2; ++p) {
4767           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);
4768         }
4769 #endif
4770         ierr = DMPlexGetSupportSize(dm, e, &supportSize);CHKERRQ(ierr);
4771         ierr = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
4772         for (s = 0; s < supportSize; ++s) {
4773           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
4774           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
4775           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
4776           for (c = 0; c < coneSize; ++c) if (cone[c] == e) break;
4777           if (support[s] < fMax) {
4778             supportRef[s] = fStartNew + (support[s] - fStart)*4 + (c + (ornt[c] < 0 ? 1-r : r))%3;
4779           } else {
4780             supportRef[s] = fStartNew + (fMax       - fStart)*4 + (cMax - cStart)*8 + (support[s] - fMax)*2 + (ornt[c] < 0 ? 1-r : r);
4781           }
4782         }
4783         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
4784 #if defined(PETSC_USE_DEBUG)
4785         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eMaxNew);
4786         for (p = 0; p < supportSize; ++p) {
4787           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);
4788         }
4789 #endif
4790       }
4791     }
4792     /* Interior face edges have 2 vertices and 2+cells*(1/2) faces */
4793     for (f = fStart; f < fMax; ++f) {
4794       const PetscInt *cone, *ornt, *support;
4795       PetscInt        coneSize, supportSize, s;
4796 
4797       ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
4798       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
4799       for (r = 0; r < 3; ++r) {
4800         const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (f - fStart)*3 + r;
4801         PetscInt        coneNew[2], intFaces = 0, er, eint[4] = {1, 0, 2, 0};
4802         PetscInt        fint[24] = { 1,  7, -1, -1,  0,  5,
4803                                     -1, -1,  1,  6,  0,  4,
4804                                      2,  5,  3,  4, -1, -1,
4805                                     -1, -1,  3,  6,  2,  7};
4806 
4807         ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
4808         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[(r+0)%3] - eStart);
4809         coneNew[1] = vStartNew + (vEnd - vStart) + (cone[(r+1)%3] - eStart);
4810         ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4811 #if defined(PETSC_USE_DEBUG)
4812         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eMaxNew);
4813         for (p = 0; p < 2; ++p) {
4814           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);
4815         }
4816 #endif
4817         supportRef[0] = fStartNew + (f - fStart)*4 + (r+1)%3;
4818         supportRef[1] = fStartNew + (f - fStart)*4 + 3;
4819         for (s = 0; s < supportSize; ++s) {
4820           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
4821           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
4822           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
4823           for (c = 0; c < coneSize; ++c) {if (cone[c] == f) break;}
4824           if (support[s] < cMax) {
4825             /* Here we want to determine whether edge newp contains a vertex which is part of the cross-tet edge */
4826             er = GetTriMidEdgeInverse_Static(ornt[c], r);
4827             if (er == eint[c]) {
4828               supportRef[2+intFaces++] = fStartNew + (fMax - fStart)*4 + (support[s] - cStart)*8 + (c + 2)%4;
4829             } else {
4830               supportRef[2+intFaces++] = fStartNew + (fMax - fStart)*4 + (support[s] - cStart)*8 + fint[(c*3 + er)*2 + 0];
4831               supportRef[2+intFaces++] = fStartNew + (fMax - fStart)*4 + (support[s] - cStart)*8 + fint[(c*3 + er)*2 + 1];
4832             }
4833           } else {
4834             supportRef[2+intFaces++] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (support[s] - cMax)*3 + (r + 1)%3;
4835           }
4836         }
4837         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
4838 #if defined(PETSC_USE_DEBUG)
4839         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eMaxNew);
4840         for (p = 0; p < intFaces; ++p) {
4841           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);
4842         }
4843 #endif
4844       }
4845     }
4846     /* Interior cell edges have 2 vertices and 4 faces */
4847     for (c = cStart; c < cMax; ++c) {
4848       const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart);
4849       const PetscInt *cone, *ornt, *fcone;
4850       PetscInt        coneNew[2], supportNew[4], find;
4851 
4852       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
4853       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
4854       ierr = DMPlexGetCone(dm, cone[0], &fcone);CHKERRQ(ierr);
4855       find = GetTriEdge_Static(ornt[0], 0);
4856       coneNew[0] = vStartNew + (vEnd - vStart) + (fcone[find] - eStart);
4857       ierr = DMPlexGetCone(dm, cone[2], &fcone);CHKERRQ(ierr);
4858       find = GetTriEdge_Static(ornt[2], 1);
4859       coneNew[1] = vStartNew + (vEnd - vStart) + (fcone[find] - eStart);
4860       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4861 #if defined(PETSC_USE_DEBUG)
4862       if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eMaxNew);
4863       for (p = 0; p < 2; ++p) {
4864         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);
4865       }
4866 #endif
4867       supportNew[0] = fStartNew + (fMax - fStart)*4 + (c - cStart)*8 + 4;
4868       supportNew[1] = fStartNew + (fMax - fStart)*4 + (c - cStart)*8 + 5;
4869       supportNew[2] = fStartNew + (fMax - fStart)*4 + (c - cStart)*8 + 6;
4870       supportNew[3] = fStartNew + (fMax - fStart)*4 + (c - cStart)*8 + 7;
4871       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
4872 #if defined(PETSC_USE_DEBUG)
4873       if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eMaxNew);
4874       for (p = 0; p < 4; ++p) {
4875         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);
4876       }
4877 #endif
4878     }
4879     /* Hybrid edges have two vertices and the same faces */
4880     for (e = eMax; e < eEnd; ++e) {
4881       const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (e - eMax);
4882       const PetscInt *cone, *support, *fcone;
4883       PetscInt        coneNew[2], size, fsize, s;
4884 
4885       ierr = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
4886       ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
4887       ierr = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
4888       coneNew[0] = vStartNew + (cone[0] - vStart);
4889       coneNew[1] = vStartNew + (cone[1] - vStart);
4890       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4891 #if defined(PETSC_USE_DEBUG)
4892       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a hybrid edge [%D, %D)", newp, eMaxNew, eEndNew);
4893       for (p = 0; p < 2; ++p) {
4894         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);
4895       }
4896 #endif
4897       for (s = 0; s < size; ++s) {
4898         ierr = DMPlexGetConeSize(dm, support[s], &fsize);CHKERRQ(ierr);
4899         ierr = DMPlexGetCone(dm, support[s], &fcone);CHKERRQ(ierr);
4900         for (c = 0; c < fsize; ++c) if (fcone[c] == e) break;
4901         if ((c < 2) || (c > 3)) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Edge %D not found in cone of face %D", e, support[s]);
4902         supportRef[s] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (support[s] - fMax)*2 + c-2;
4903       }
4904       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
4905 #if defined(PETSC_USE_DEBUG)
4906       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a hybrid edge [%D, %D)", newp, eMaxNew, eEndNew);
4907       for (p = 0; p < size; ++p) {
4908         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);
4909       }
4910 #endif
4911     }
4912     /* Hybrid face edges have 2 vertices and 2+2*cells faces */
4913     for (f = fMax; f < fEnd; ++f) {
4914       const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (eEnd - eMax) + (f - fMax);
4915       const PetscInt *cone, *support, *ccone, *cornt;
4916       PetscInt        coneNew[2], size, csize, s;
4917 
4918       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
4919       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
4920       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
4921       coneNew[0] = vStartNew + (vEnd - vStart) + (cone[0] - eStart);
4922       coneNew[1] = vStartNew + (vEnd - vStart) + (cone[1] - eStart);
4923       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4924 #if defined(PETSC_USE_DEBUG)
4925       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a hybrid edge [%D, %D)", newp, eMaxNew, eEndNew);
4926       for (p = 0; p < 2; ++p) {
4927         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);
4928       }
4929 #endif
4930       supportRef[0] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (f - fMax)*2 + 0;
4931       supportRef[1] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (f - fMax)*2 + 1;
4932       for (s = 0; s < size; ++s) {
4933         ierr = DMPlexGetConeSize(dm, support[s], &csize);CHKERRQ(ierr);
4934         ierr = DMPlexGetCone(dm, support[s], &ccone);CHKERRQ(ierr);
4935         ierr = DMPlexGetConeOrientation(dm, support[s], &cornt);CHKERRQ(ierr);
4936         for (c = 0; c < csize; ++c) if (ccone[c] == f) break;
4937         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]);
4938         supportRef[2+s*2+0] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (support[s] - cMax)*3 + c-2;
4939         supportRef[2+s*2+1] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (support[s] - cMax)*3 + (c-1)%3;
4940       }
4941       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
4942 #if defined(PETSC_USE_DEBUG)
4943       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a hybrid edge [%D, %D)", newp, eMaxNew, eEndNew);
4944       for (p = 0; p < 2+size*2; ++p) {
4945         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);
4946       }
4947 #endif
4948     }
4949     /* Interior vertices have identical supports */
4950     for (v = vStart; v < vEnd; ++v) {
4951       const PetscInt  newp = vStartNew + (v - vStart);
4952       const PetscInt *support, *cone;
4953       PetscInt        size, s;
4954 
4955       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
4956       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
4957       for (s = 0; s < size; ++s) {
4958         PetscInt r = 0;
4959 
4960         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
4961         if (cone[1] == v) r = 1;
4962         if (support[s] < eMax) supportRef[s] = eStartNew + (support[s] - eStart)*2 + r;
4963         else                   supportRef[s] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (support[s] - eMax);
4964       }
4965       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
4966 #if defined(PETSC_USE_DEBUG)
4967       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", newp, vStartNew, vEndNew);
4968       for (p = 0; p < size; ++p) {
4969         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);
4970       }
4971 #endif
4972     }
4973     /* Interior edge vertices have 2 + interior face*2 + hybrid face + cells*0/1 supports */
4974     for (e = eStart; e < eMax; ++e) {
4975       const PetscInt  newp = vStartNew + (vEnd - vStart) + (e - eStart);
4976       const PetscInt *cone, *support;
4977       PetscInt       *star = NULL, starSize, faceSize = 0, cellSize = 0, coneSize, size, s;
4978 
4979       ierr          = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
4980       ierr          = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
4981       supportRef[0] = eStartNew + (e - eStart)*2 + 0;
4982       supportRef[1] = eStartNew + (e - eStart)*2 + 1;
4983       for (s = 0; s < size; ++s) {
4984         PetscInt r = 0;
4985 
4986         if (support[s] < fMax) {
4987           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
4988           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
4989           for (r = 0; r < coneSize; ++r) {if (cone[r] == e) break;}
4990           supportRef[2+faceSize+0] = eStartNew + (eMax - eStart)*2 + (support[s] - fStart)*3 + (r+0)%3;
4991           supportRef[2+faceSize+1] = eStartNew + (eMax - eStart)*2 + (support[s] - fStart)*3 + (r+2)%3;
4992           faceSize += 2;
4993         } else {
4994           supportRef[2+faceSize+0] = eStartNew + (eMax - eStart)*2 + (fMax       - fStart)*3 + (cMax - cStart) + (eEnd - eMax) + (support[s] - fMax);
4995           ++faceSize;
4996         }
4997       }
4998       ierr = DMPlexGetTransitiveClosure(dm, e, PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
4999       for (s = 0; s < starSize*2; s += 2) {
5000         const PetscInt *cone, *ornt;
5001         PetscInt        e01, e23;
5002 
5003         if ((star[s] >= cStart) && (star[s] < cMax)) {
5004           /* Check edge 0-1 */
5005           ierr = DMPlexGetCone(dm, star[s], &cone);CHKERRQ(ierr);
5006           ierr = DMPlexGetConeOrientation(dm, star[s], &ornt);CHKERRQ(ierr);
5007           ierr = DMPlexGetCone(dm, cone[0], &cone);CHKERRQ(ierr);
5008           e01  = cone[GetTriEdge_Static(ornt[0], 0)];
5009           /* Check edge 2-3 */
5010           ierr = DMPlexGetCone(dm, star[s], &cone);CHKERRQ(ierr);
5011           ierr = DMPlexGetConeOrientation(dm, star[s], &ornt);CHKERRQ(ierr);
5012           ierr = DMPlexGetCone(dm, cone[2], &cone);CHKERRQ(ierr);
5013           e23  = cone[GetTriEdge_Static(ornt[2], 1)];
5014           if ((e01 == e) || (e23 == e)) {supportRef[2+faceSize+cellSize++] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (star[s] - cStart);}
5015         }
5016       }
5017       ierr = DMPlexRestoreTransitiveClosure(dm, e, PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
5018       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
5019 #if defined(PETSC_USE_DEBUG)
5020       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", newp, vStartNew, vEndNew);
5021       for (p = 0; p < 2+faceSize+cellSize; ++p) {
5022         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);
5023       }
5024 #endif
5025     }
5026     ierr = PetscFree(supportRef);CHKERRQ(ierr);
5027     ierr = DMPlexRestoreFaces_Internal(dm, cStart, NULL, NULL, &faces);CHKERRQ(ierr);
5028     break;
5029   case REFINER_SIMPLEX_TO_HEX_3D:
5030     ierr = DMPlexGetRawFaces_Internal(dm, DM_POLYTOPE_TETRAHEDRON, cellInd, NULL, NULL, &faces);CHKERRQ(ierr);
5031     /* All cells have 6 faces */
5032     for (c = cStart; c < cEnd; ++c) {
5033       const PetscInt  newp = cStartNew + (c - cStart)*4;
5034       const PetscInt *cone, *ornt;
5035       PetscInt        coneNew[6];
5036       PetscInt        orntNew[6];
5037 
5038       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
5039       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
5040       /* A hex */
5041       coneNew[0] = fStartNew + (cone[0] - fStart)*3 + GetTriSubface_Static(ornt[0], 0); /* B */
5042       orntNew[0] = ornt[0] < 0 ? -1 : 1;
5043       coneNew[1] = fStartNew + (fEnd    - fStart)*3 + (c - cStart)*6 + 3;               /* T */
5044       orntNew[1] = -4;
5045       coneNew[2] = fStartNew + (cone[2] - fStart)*3 + GetTriSubface_Static(ornt[2], 0); /* F */
5046       orntNew[2] = ornt[2] < 0 ? -1 : 1;
5047       coneNew[3] = fStartNew + (fEnd    - fStart)*3 + (c - cStart)*6 + 0;               /* K */
5048       orntNew[3] = -1;
5049       coneNew[4] = fStartNew + (fEnd    - fStart)*3 + (c - cStart)*6 + 2;               /* R */
5050       orntNew[4] = 0;
5051       coneNew[5] = fStartNew + (cone[1] - fStart)*3 + GetTriSubface_Static(ornt[1], 0); /* L */
5052       orntNew[5] = ornt[1] < 0 ? -1 : 1;
5053       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
5054       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
5055 #if defined(PETSC_USE_DEBUG)
5056       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);
5057       for (p = 0; p < 6; ++p) {
5058         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);
5059       }
5060 #endif
5061       /* B hex */
5062       coneNew[0] = fStartNew + (cone[0] - fStart)*3 + GetTriSubface_Static(ornt[0], 1); /* B */
5063       orntNew[0] = ornt[0] < 0 ? -2 : 0;
5064       coneNew[1] = fStartNew + (fEnd    - fStart)*3 + (c - cStart)*6 + 4;               /* T */
5065       orntNew[1] = 0;
5066       coneNew[2] = fStartNew + (fEnd    - fStart)*3 + (c - cStart)*6 + 0;               /* F */
5067       orntNew[2] = 0;
5068       coneNew[3] = fStartNew + (cone[3] - fStart)*3 + GetTriSubface_Static(ornt[3], 1); /* K */
5069       orntNew[3] = ornt[3] < 0 ? -2 : 0;
5070       coneNew[4] = fStartNew + (fEnd    - fStart)*3 + (c - cStart)*6 + 1;               /* R */
5071       orntNew[4] = 0;
5072       coneNew[5] = fStartNew + (cone[1] - fStart)*3 + GetTriSubface_Static(ornt[1], 2); /* L */
5073       orntNew[5] = ornt[1] < 0 ? -4 : 2;
5074       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
5075       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
5076 #if defined(PETSC_USE_DEBUG)
5077       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);
5078       for (p = 0; p < 6; ++p) {
5079         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);
5080       }
5081 #endif
5082       /* C hex */
5083       coneNew[0] = fStartNew + (cone[0] - fStart)*3 + GetTriSubface_Static(ornt[0], 2); /* B */
5084       orntNew[0] = ornt[0] < 0 ? -4 : 2;
5085       coneNew[1] = fStartNew + (fEnd    - fStart)*3 + (c - cStart)*6 + 5;               /* T */
5086       orntNew[1] = -4;
5087       coneNew[2] = fStartNew + (cone[2] - fStart)*3 + GetTriSubface_Static(ornt[2], 1); /* F */
5088       orntNew[2] = ornt[2] < 0 ? -2 : 0;
5089       coneNew[3] = fStartNew + (fEnd    - fStart)*3 + (c - cStart)*6 + 1;               /* K */
5090       orntNew[3] = -1;
5091       coneNew[4] = fStartNew + (cone[3] - fStart)*3 + GetTriSubface_Static(ornt[3], 0); /* R */
5092       orntNew[4] = ornt[3] < 0 ? -1 : 1;
5093       coneNew[5] = fStartNew + (fEnd    - fStart)*3 + (c - cStart)*6 + 2;               /* L */
5094       orntNew[5] = -4;
5095       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
5096       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
5097 #if defined(PETSC_USE_DEBUG)
5098       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);
5099       for (p = 0; p < 6; ++p) {
5100         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);
5101       }
5102 #endif
5103       /* D hex */
5104       coneNew[0] = fStartNew + (fEnd    - fStart)*3 + (c - cStart)*6 + 3;               /* B */
5105       orntNew[0] = 0;
5106       coneNew[1] = fStartNew + (cone[3] - fStart)*3 + GetTriSubface_Static(ornt[3], 2); /* T */
5107       orntNew[1] = ornt[3] < 0 ? -1 : 1;
5108       coneNew[2] = fStartNew + (cone[2] - fStart)*3 + GetTriSubface_Static(ornt[2], 2); /* F */
5109       orntNew[2] = ornt[2] < 0 ? -4 : 2;
5110       coneNew[3] = fStartNew + (fEnd    - fStart)*3 + (c - cStart)*6 + 4;               /* K */
5111       orntNew[3] = -1;
5112       coneNew[4] = fStartNew + (fEnd    - fStart)*3 + (c - cStart)*6 + 5;               /* R */
5113       orntNew[4] = 0;
5114       coneNew[5] = fStartNew + (cone[1] - fStart)*3 + GetTriSubface_Static(ornt[1], 1); /* L */
5115       orntNew[5] = ornt[1] < 0 ? -2 : 0;
5116       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
5117       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
5118 #if defined(PETSC_USE_DEBUG)
5119       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);
5120       for (p = 0; p < 6; ++p) {
5121         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);
5122       }
5123 #endif
5124     }
5125     /* Split faces have 4 edges and the same cells as the parent */
5126     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
5127     ierr = PetscMalloc1(2 + maxSupportSize*2, &supportRef);CHKERRQ(ierr);
5128     for (f = fStart; f < fEnd; ++f) {
5129       const PetscInt  newp = fStartNew + (f - fStart)*3;
5130       const PetscInt *cone, *ornt, *support;
5131       PetscInt        coneNew[4], orntNew[4], coneSize, supportSize, s;
5132 
5133       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
5134       ierr = DMPlexGetConeOrientation(dm, f, &ornt);CHKERRQ(ierr);
5135       /* A quad */
5136       coneNew[0] = eStartNew + (cone[2] - eStart)*2 + (ornt[2] < 0 ? 0 : 1);
5137       orntNew[0] = ornt[2];
5138       coneNew[1] = eStartNew + (cone[0] - eStart)*2 + (ornt[0] < 0 ? 1 : 0);
5139       orntNew[1] = ornt[0];
5140       coneNew[2] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 0;
5141       orntNew[2] = 0;
5142       coneNew[3] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 2;
5143       orntNew[3] = -2;
5144       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
5145       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
5146 #if defined(PETSC_USE_DEBUG)
5147       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);
5148       for (p = 0; p < 4; ++p) {
5149         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);
5150       }
5151 #endif
5152       /* B quad */
5153       coneNew[0] = eStartNew + (cone[0] - eStart)*2 + (ornt[0] < 0 ? 0 : 1);
5154       orntNew[0] = ornt[0];
5155       coneNew[1] = eStartNew + (cone[1] - eStart)*2 + (ornt[1] < 0 ? 1 : 0);
5156       orntNew[1] = ornt[1];
5157       coneNew[2] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 1;
5158       orntNew[2] = 0;
5159       coneNew[3] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 0;
5160       orntNew[3] = -2;
5161       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
5162       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
5163 #if defined(PETSC_USE_DEBUG)
5164       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);
5165       for (p = 0; p < 4; ++p) {
5166         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);
5167       }
5168 #endif
5169       /* C quad */
5170       coneNew[0] = eStartNew + (cone[1] - eStart)*2 + (ornt[1] < 0 ? 0 : 1);
5171       orntNew[0] = ornt[1];
5172       coneNew[1] = eStartNew + (cone[2] - eStart)*2 + (ornt[2] < 0 ? 1 : 0);
5173       orntNew[1] = ornt[2];
5174       coneNew[2] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 2;
5175       orntNew[2] = 0;
5176       coneNew[3] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 1;
5177       orntNew[3] = -2;
5178       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
5179       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
5180 #if defined(PETSC_USE_DEBUG)
5181       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);
5182       for (p = 0; p < 4; ++p) {
5183         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);
5184       }
5185 #endif
5186       ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
5187       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
5188       for (r = 0; r < 3; ++r) {
5189         for (s = 0; s < supportSize; ++s) {
5190           PetscInt subf;
5191           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
5192           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
5193           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
5194           for (c = 0; c < coneSize; ++c) {
5195             if (cone[c] == f) break;
5196           }
5197           subf = GetTriSubfaceInverse_Static(ornt[c], r);
5198           supportRef[s] = cStartNew + (support[s] - cStart)*4 + faces[c*3+subf];
5199         }
5200         ierr = DMPlexSetSupport(rdm, newp+r, supportRef);CHKERRQ(ierr);
5201 #if defined(PETSC_USE_DEBUG)
5202         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);
5203         for (p = 0; p < supportSize; ++p) {
5204           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);
5205         }
5206 #endif
5207       }
5208     }
5209     /* Interior faces have 4 edges and 2 cells */
5210     for (c = cStart; c < cEnd; ++c) {
5211       PetscInt        newp = fStartNew + (fEnd - fStart)*3 + (c - cStart)*6;
5212       const PetscInt *cone, *ornt;
5213       PetscInt        coneNew[4], orntNew[4];
5214       PetscInt        supportNew[2];
5215 
5216       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
5217       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
5218       /* Face {a, g, m, h} */
5219       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*3 + GetTriInteriorEdge_Static(ornt[0],0);
5220       orntNew[0] = 0;
5221       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + 0;
5222       orntNew[1] = 0;
5223       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + 1;
5224       orntNew[2] = -2;
5225       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*3 + GetTriInteriorEdge_Static(ornt[1],2);
5226       orntNew[3] = -2;
5227       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5228       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
5229 #if defined(PETSC_USE_DEBUG)
5230       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
5231       for (p = 0; p < 4; ++p) {
5232         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);
5233       }
5234 #endif
5235       supportNew[0] = (c - cStart)*4 + 0;
5236       supportNew[1] = (c - cStart)*4 + 1;
5237       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
5238 #if defined(PETSC_USE_DEBUG)
5239       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
5240       for (p = 0; p < 2; ++p) {
5241         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);
5242       }
5243 #endif
5244       ++newp;
5245       /* Face {g, b, l , m} */
5246       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*3 + GetTriInteriorEdge_Static(ornt[0],1);
5247       orntNew[0] = -2;
5248       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*3 + GetTriInteriorEdge_Static(ornt[3],0);
5249       orntNew[1] = 0;
5250       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + 3;
5251       orntNew[2] = 0;
5252       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + 0;
5253       orntNew[3] = -2;
5254       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5255       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
5256 #if defined(PETSC_USE_DEBUG)
5257       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
5258       for (p = 0; p < 4; ++p) {
5259         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);
5260       }
5261 #endif
5262       supportNew[0] = (c - cStart)*4 + 1;
5263       supportNew[1] = (c - cStart)*4 + 2;
5264       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
5265 #if defined(PETSC_USE_DEBUG)
5266       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
5267       for (p = 0; p < 2; ++p) {
5268         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);
5269       }
5270 #endif
5271       ++newp;
5272       /* Face {c, g, m, i} */
5273       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*3 + GetTriInteriorEdge_Static(ornt[0],2);
5274       orntNew[0] = 0;
5275       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + 0;
5276       orntNew[1] = 0;
5277       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + 2;
5278       orntNew[2] = -2;
5279       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*3 + GetTriInteriorEdge_Static(ornt[2],0);
5280       orntNew[3] = -2;
5281       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5282       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
5283 #if defined(PETSC_USE_DEBUG)
5284       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
5285       for (p = 0; p < 4; ++p) {
5286         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);
5287       }
5288 #endif
5289       supportNew[0] = (c - cStart)*4 + 0;
5290       supportNew[1] = (c - cStart)*4 + 2;
5291       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
5292 #if defined(PETSC_USE_DEBUG)
5293       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
5294       for (p = 0; p < 2; ++p) {
5295         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);
5296       }
5297 #endif
5298       ++newp;
5299       /* Face {d, h, m, i} */
5300       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*3 + GetTriInteriorEdge_Static(ornt[1],0);
5301       orntNew[0] = 0;
5302       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + 1;
5303       orntNew[1] = 0;
5304       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + 2;
5305       orntNew[2] = -2;
5306       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*3 + GetTriInteriorEdge_Static(ornt[2],2);
5307       orntNew[3] = -2;
5308       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5309       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
5310 #if defined(PETSC_USE_DEBUG)
5311       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
5312       for (p = 0; p < 4; ++p) {
5313         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);
5314       }
5315 #endif
5316       supportNew[0] = (c - cStart)*4 + 0;
5317       supportNew[1] = (c - cStart)*4 + 3;
5318       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
5319 #if defined(PETSC_USE_DEBUG)
5320       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
5321       for (p = 0; p < 2; ++p) {
5322         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);
5323       }
5324 #endif
5325       ++newp;
5326       /* Face {h, m, l, e} */
5327       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + 1;
5328       orntNew[0] = 0;
5329       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + 3;
5330       orntNew[1] = -2;
5331       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*3 + GetTriInteriorEdge_Static(ornt[3],1);
5332       orntNew[2] = -2;
5333       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*3 + GetTriInteriorEdge_Static(ornt[1],1);
5334       orntNew[3] = 0;
5335       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5336       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
5337 #if defined(PETSC_USE_DEBUG)
5338       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
5339       for (p = 0; p < 4; ++p) {
5340         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);
5341       }
5342 #endif
5343       supportNew[0] = (c - cStart)*4 + 1;
5344       supportNew[1] = (c - cStart)*4 + 3;
5345       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
5346 #if defined(PETSC_USE_DEBUG)
5347       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
5348       for (p = 0; p < 2; ++p) {
5349         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);
5350       }
5351 #endif
5352       ++newp;
5353       /* Face {i, m, l, f} */
5354       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + 2;
5355       orntNew[0] = 0;
5356       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + 3;
5357       orntNew[1] = -2;
5358       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*3 + GetTriInteriorEdge_Static(ornt[3],2);
5359       orntNew[2] = -2;
5360       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*3 + GetTriInteriorEdge_Static(ornt[2],1);
5361       orntNew[3] = 0;
5362       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5363       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
5364 #if defined(PETSC_USE_DEBUG)
5365       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
5366       for (p = 0; p < 4; ++p) {
5367         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);
5368       }
5369 #endif
5370       supportNew[0] = (c - cStart)*4 + 2;
5371       supportNew[1] = (c - cStart)*4 + 3;
5372       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
5373 #if defined(PETSC_USE_DEBUG)
5374       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
5375       for (p = 0; p < 2; ++p) {
5376         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);
5377       }
5378 #endif
5379       ++newp;
5380     }
5381     /* Split Edges have 2 vertices and the same faces as the parent */
5382     for (e = eStart; e < eEnd; ++e) {
5383       const PetscInt newv = vStartNew + (vEnd - vStart) + (e - eStart);
5384 
5385       for (r = 0; r < 2; ++r) {
5386         const PetscInt  newp = eStartNew + (e - eStart)*2 + r;
5387         const PetscInt *cone, *ornt, *support;
5388         PetscInt        coneNew[2], coneSize, c, supportSize, s;
5389 
5390         ierr             = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
5391         coneNew[0]       = vStartNew + (cone[0] - vStart);
5392         coneNew[1]       = vStartNew + (cone[1] - vStart);
5393         coneNew[(r+1)%2] = newv;
5394         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5395 #if defined(PETSC_USE_DEBUG)
5396         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eEndNew);
5397         for (p = 0; p < 2; ++p) {
5398           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);
5399         }
5400 #endif
5401         ierr = DMPlexGetSupportSize(dm, e, &supportSize);CHKERRQ(ierr);
5402         ierr = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
5403         for (s = 0; s < supportSize; ++s) {
5404           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
5405           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
5406           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
5407           for (c = 0; c < coneSize; ++c) {
5408             if (cone[c] == e) break;
5409           }
5410           supportRef[s] = fStartNew + (support[s] - fStart)*3 + (c + (ornt[c] < 0 ? 1-r : r))%3;
5411         }
5412         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
5413 #if defined(PETSC_USE_DEBUG)
5414         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eEndNew);
5415         for (p = 0; p < supportSize; ++p) {
5416           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);
5417         }
5418 #endif
5419       }
5420     }
5421     /* Face edges have 2 vertices and 2 + cell faces supports */
5422     for (f = fStart; f < fEnd; ++f) {
5423       const PetscInt *cone, *ornt, *support;
5424       PetscInt        coneSize, supportSize, s;
5425 
5426       ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
5427       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
5428       for (r = 0; r < 3; ++r) {
5429         const PetscInt  newp = eStartNew + (eEnd - eStart)*2 + (f - fStart)*3 + r;
5430         PetscInt        coneNew[2];
5431         PetscInt        fint[4][3] = { {0, 1, 2},
5432                                        {3, 4, 0},
5433                                        {2, 5, 3},
5434                                        {1, 4, 5} };
5435 
5436         ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
5437         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r] - eStart);
5438         coneNew[1] = vStartNew + (vEnd - vStart) + (eEnd - eStart) + f - fStart;
5439         ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5440 #if defined(PETSC_USE_DEBUG)
5441         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eEndNew);
5442         for (p = 0; p < 2; ++p) {
5443           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);
5444         }
5445 #endif
5446         supportRef[0] = fStartNew + (f - fStart)*3 + (r+0)%3;
5447         supportRef[1] = fStartNew + (f - fStart)*3 + (r+1)%3;
5448         for (s = 0; s < supportSize; ++s) {
5449           PetscInt er;
5450           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
5451           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
5452           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
5453           for (c = 0; c < coneSize; ++c) {if (cone[c] == f) break;}
5454           er = GetTriInteriorEdgeInverse_Static(ornt[c], r);
5455           supportRef[2+s] = fStartNew + (fEnd - fStart)*3 + (support[s] - cStart)*6 + fint[c][er];
5456         }
5457         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
5458 #if defined(PETSC_USE_DEBUG)
5459         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eEndNew);
5460         for (p = 0; p < supportSize + 2; ++p) {
5461           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);
5462         }
5463 #endif
5464       }
5465     }
5466     /* Interior cell edges have 2 vertices and 3 faces */
5467     for (c = cStart; c < cEnd; ++c) {
5468       const PetscInt *cone;
5469       PetscInt       fint[4][3] = { {0,1,2},
5470                                     {0,3,4},
5471                                     {2,3,5},
5472                                     {1,4,5} } ;
5473 
5474       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
5475       for (r = 0; r < 4; r++) {
5476         PetscInt       coneNew[2], supportNew[3];
5477         const PetscInt newp = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + r;
5478 
5479         coneNew[0] = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (cone[r] - fStart);
5480         coneNew[1] = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (fEnd -fStart) + c - cStart;
5481         ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5482 #if defined(PETSC_USE_DEBUG)
5483         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eEndNew);
5484         for (p = 0; p < 2; ++p) {
5485           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);
5486         }
5487 #endif
5488         supportNew[0] = fStartNew + (fEnd - fStart)*3 + (c - cStart)*6 + fint[r][0];
5489         supportNew[1] = fStartNew + (fEnd - fStart)*3 + (c - cStart)*6 + fint[r][1];
5490         supportNew[2] = fStartNew + (fEnd - fStart)*3 + (c - cStart)*6 + fint[r][2];
5491         ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
5492 #if defined(PETSC_USE_DEBUG)
5493         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eEndNew);
5494         for (p = 0; p < 3; ++p) {
5495           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);
5496         }
5497 #endif
5498       }
5499     }
5500     /* Old vertices have identical supports */
5501     for (v = vStart; v < vEnd; ++v) {
5502       const PetscInt  newp = vStartNew + (v - vStart);
5503       const PetscInt *support, *cone;
5504       PetscInt        size, s;
5505 
5506       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
5507       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
5508       for (s = 0; s < size; ++s) {
5509         PetscInt r = 0;
5510 
5511         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
5512         if (cone[1] == v) r = 1;
5513         supportRef[s] = eStartNew + (support[s] - eStart)*2 + r;
5514       }
5515       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
5516 #if defined(PETSC_USE_DEBUG)
5517       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", newp, vStartNew, vEndNew);
5518       for (p = 0; p < size; ++p) {
5519         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);
5520       }
5521 #endif
5522     }
5523     /* Edge vertices have 2 + faces supports */
5524     for (e = eStart; e < eEnd; ++e) {
5525       const PetscInt  newp = vStartNew + (vEnd - vStart) + (e - eStart);
5526       const PetscInt *cone, *support;
5527       PetscInt        size, s;
5528 
5529       ierr          = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
5530       ierr          = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
5531       supportRef[0] = eStartNew + (e - eStart)*2 + 0;
5532       supportRef[1] = eStartNew + (e - eStart)*2 + 1;
5533       for (s = 0; s < size; ++s) {
5534         PetscInt r = 0, coneSize;
5535 
5536         ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
5537         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
5538         for (r = 0; r < coneSize; ++r) {if (cone[r] == e) break;}
5539         supportRef[2+s] = eStartNew + (eEnd - eStart)*2 + (support[s] - fStart)*3 + r;
5540       }
5541       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
5542 #if defined(PETSC_USE_DEBUG)
5543       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", newp, vStartNew, vEndNew);
5544       for (p = 0; p < 2+size; ++p) {
5545         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);
5546       }
5547 #endif
5548     }
5549     /* Face vertices have 3 + cells supports */
5550     for (f = fStart; f < fEnd; ++f) {
5551       const PetscInt  newp = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (f - fStart);
5552       const PetscInt *cone, *support;
5553       PetscInt        size, s;
5554 
5555       ierr          = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
5556       ierr          = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
5557       supportRef[0] = eStartNew + (eEnd - eStart)*2 + (f - fStart)*3 + 0;
5558       supportRef[1] = eStartNew + (eEnd - eStart)*2 + (f - fStart)*3 + 1;
5559       supportRef[2] = eStartNew + (eEnd - eStart)*2 + (f - fStart)*3 + 2;
5560       for (s = 0; s < size; ++s) {
5561         PetscInt r = 0, coneSize;
5562 
5563         ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
5564         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
5565         for (r = 0; r < coneSize; ++r) {if (cone[r] == f) break;}
5566         supportRef[3+s] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (support[s] - cStart)*4 + r;
5567       }
5568       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
5569 #if defined(PETSC_USE_DEBUG)
5570       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", newp, vStartNew, vEndNew);
5571       for (p = 0; p < 3+size; ++p) {
5572         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);
5573       }
5574 #endif
5575     }
5576     /* Interior cell vertices have 4 supports */
5577     for (c = cStart; c < cEnd; ++c) {
5578       const PetscInt  newp = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (fEnd - fStart) + c - cStart;
5579       supportRef[0] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + 0;
5580       supportRef[1] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + 1;
5581       supportRef[2] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + 2;
5582       supportRef[3] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + 3;
5583       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
5584 #if defined(PETSC_USE_DEBUG)
5585       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", newp, vStartNew, vEndNew);
5586       for (p = 0; p < 4; ++p) {
5587         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);
5588       }
5589 #endif
5590     }
5591     ierr = PetscFree(supportRef);CHKERRQ(ierr);
5592     ierr = DMPlexRestoreFaces_Internal(dm, cStart, NULL, NULL, &faces);CHKERRQ(ierr);
5593     break;
5594   case REFINER_HYBRID_SIMPLEX_TO_HEX_3D:
5595     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
5596     cMax = PetscMin(cEnd, cMax);
5597     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
5598     fMax = PetscMin(fEnd, fMax);
5599     if (eMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
5600     eMax = PetscMin(eEnd, eMax);
5601     ierr = DMPlexGetRawFaces_Internal(dm, DM_POLYTOPE_TETRAHEDRON, cellInd, NULL, NULL, &faces);CHKERRQ(ierr);
5602     /* All cells have 6 faces */
5603     for (c = cStart; c < cMax; ++c) {
5604       const PetscInt  newp = cStartNew + (c - cStart)*4;
5605       const PetscInt *cone, *ornt;
5606       PetscInt        coneNew[6];
5607       PetscInt        orntNew[6];
5608 
5609       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
5610 #if defined(PETSC_USE_DEBUG)
5611       for (p = 0; p < 4; ++p) {
5612         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);
5613       }
5614 #endif
5615       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
5616       /* A hex */
5617       coneNew[0] = fStartNew + (cone[0] - fStart)*3 + GetTriSubface_Static(ornt[0], 0); /* B */
5618       orntNew[0] = ornt[0] < 0 ? -1 : 1;
5619       coneNew[1] = fStartNew + (fMax    - fStart)*3 + (c - cStart)*6 + 3;               /* T */
5620       orntNew[1] = -4;
5621       coneNew[2] = fStartNew + (cone[2] - fStart)*3 + GetTriSubface_Static(ornt[2], 0); /* F */
5622       orntNew[2] = ornt[2] < 0 ? -1 : 1;
5623       coneNew[3] = fStartNew + (fMax    - fStart)*3 + (c - cStart)*6 + 0;               /* K */
5624       orntNew[3] = -1;
5625       coneNew[4] = fStartNew + (fMax    - fStart)*3 + (c - cStart)*6 + 2;               /* R */
5626       orntNew[4] = 0;
5627       coneNew[5] = fStartNew + (cone[1] - fStart)*3 + GetTriSubface_Static(ornt[1], 0); /* L */
5628       orntNew[5] = ornt[1] < 0 ? -1 : 1;
5629       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
5630       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
5631 #if defined(PETSC_USE_DEBUG)
5632       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);
5633       for (p = 0; p < 6; ++p) {
5634         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);
5635       }
5636 #endif
5637       /* B hex */
5638       coneNew[0] = fStartNew + (cone[0] - fStart)*3 + GetTriSubface_Static(ornt[0], 1); /* B */
5639       orntNew[0] = ornt[0] < 0 ? -2 : 0;
5640       coneNew[1] = fStartNew + (fMax    - fStart)*3 + (c - cStart)*6 + 4;               /* T */
5641       orntNew[1] = 0;
5642       coneNew[2] = fStartNew + (fMax    - fStart)*3 + (c - cStart)*6 + 0;               /* F */
5643       orntNew[2] = 0;
5644       coneNew[3] = fStartNew + (cone[3] - fStart)*3 + GetTriSubface_Static(ornt[3], 1); /* K */
5645       orntNew[3] = ornt[3] < 0 ? -2 : 0;
5646       coneNew[4] = fStartNew + (fMax    - fStart)*3 + (c - cStart)*6 + 1;               /* R */
5647       orntNew[4] = 0;
5648       coneNew[5] = fStartNew + (cone[1] - fStart)*3 + GetTriSubface_Static(ornt[1], 2); /* L */
5649       orntNew[5] = ornt[1] < 0 ? -4 : 2;
5650       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
5651       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
5652 #if defined(PETSC_USE_DEBUG)
5653       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);
5654       for (p = 0; p < 6; ++p) {
5655         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);
5656       }
5657 #endif
5658       /* C hex */
5659       coneNew[0] = fStartNew + (cone[0] - fStart)*3 + GetTriSubface_Static(ornt[0], 2); /* B */
5660       orntNew[0] = ornt[0] < 0 ? -4 : 2;
5661       coneNew[1] = fStartNew + (fMax    - fStart)*3 + (c - cStart)*6 + 5;               /* T */
5662       orntNew[1] = -4;
5663       coneNew[2] = fStartNew + (cone[2] - fStart)*3 + GetTriSubface_Static(ornt[2], 1); /* F */
5664       orntNew[2] = ornt[2] < 0 ? -2 : 0;
5665       coneNew[3] = fStartNew + (fMax    - fStart)*3 + (c - cStart)*6 + 1;               /* K */
5666       orntNew[3] = -1;
5667       coneNew[4] = fStartNew + (cone[3] - fStart)*3 + GetTriSubface_Static(ornt[3], 0); /* R */
5668       orntNew[4] = ornt[3] < 0 ? -1 : 1;
5669       coneNew[5] = fStartNew + (fMax    - fStart)*3 + (c - cStart)*6 + 2;               /* L */
5670       orntNew[5] = -4;
5671       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
5672       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
5673 #if defined(PETSC_USE_DEBUG)
5674       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);
5675       for (p = 0; p < 6; ++p) {
5676         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);
5677       }
5678 #endif
5679       /* D hex */
5680       coneNew[0] = fStartNew + (fMax    - fStart)*3 + (c - cStart)*6 + 3;               /* B */
5681       orntNew[0] = 0;
5682       coneNew[1] = fStartNew + (cone[3] - fStart)*3 + GetTriSubface_Static(ornt[3], 2); /* T */
5683       orntNew[1] = ornt[3] < 0 ? -1 : 1;
5684       coneNew[2] = fStartNew + (cone[2] - fStart)*3 + GetTriSubface_Static(ornt[2], 2); /* F */
5685       orntNew[2] = ornt[2] < 0 ? -4 : 2;
5686       coneNew[3] = fStartNew + (fMax    - fStart)*3 + (c - cStart)*6 + 4;               /* K */
5687       orntNew[3] = -1;
5688       coneNew[4] = fStartNew + (fMax    - fStart)*3 + (c - cStart)*6 + 5;               /* R */
5689       orntNew[4] = 0;
5690       coneNew[5] = fStartNew + (cone[1] - fStart)*3 + GetTriSubface_Static(ornt[1], 1); /* L */
5691       orntNew[5] = ornt[1] < 0 ? -2 : 0;
5692       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
5693       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
5694 #if defined(PETSC_USE_DEBUG)
5695       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);
5696       for (p = 0; p < 6; ++p) {
5697         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);
5698       }
5699 #endif
5700     }
5701     for (c = cMax; c < cEnd; ++c) {
5702       const PetscInt  newp = cStartNew + (cMax - cStart)*4 + (c - cMax)*3;
5703       const PetscInt *cone, *ornt;
5704       PetscInt        coneNew[6], orntNew[6];
5705       PetscInt        o, of, cf;
5706 
5707       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
5708 #if defined(PETSC_USE_DEBUG)
5709       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);
5710       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);
5711       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);
5712       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);
5713       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);
5714 #endif
5715       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
5716       o    = ornt[0] < 0 ? -1 : 1;
5717       o    = 1;
5718       /* A hex */
5719       coneNew[0] = fStartNew + (cone[0] - fStart)*3 + GetTriSubface_Static(ornt[0], 0);                            /* B */
5720       orntNew[0] = ornt[0] < 0 ? -1 :  1;
5721       coneNew[1] = fStartNew + (cone[1] - fStart)*3 + GetTriSubface_Static(ornt[1], 0);                            /* T */
5722       orntNew[1] = ornt[1] < 0 ?  1 : -1;
5723       cf         = 2;
5724       of         = ornt[2+cf] < 0 ? -1 : 1;
5725       coneNew[2] = fStartNew + (fMax - fStart)*3 + (cMax - cStart)*6 + (cone[2+cf] - fMax)*2 + (o*of < 0 ? 0 : 1); /* F */
5726       orntNew[2] = o*of < 0 ? 0 : -1;
5727       coneNew[3] = fStartNew + (fMax - fStart)*3 + (cMax - cStart)*6 + (fEnd - fMax)*2 + (c - cMax)*3 + 0;         /* K */
5728       orntNew[3] = -1;
5729       coneNew[4] = fStartNew + (fMax - fStart)*3 + (cMax - cStart)*6 + (fEnd - fMax)*2 + (c - cMax)*3 + 2;         /* R */
5730       orntNew[4] = 0;
5731       cf         = 0;
5732       of         = ornt[2+cf] < 0 ? -1 : 1;
5733       coneNew[5] = fStartNew + (fMax - fStart)*3 + (cMax - cStart)*6 + (cone[2+cf] - fMax)*2 + (o*of < 0 ? 1 : 0); /* L */
5734       orntNew[5] = o*of < 0 ? 1 : -4;
5735       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
5736       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
5737 #if defined(PETSC_USE_DEBUG)
5738       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);
5739       for (p = 0; p < 6; ++p) {
5740         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);
5741       }
5742 #endif
5743       /* B hex */
5744       coneNew[0] = fStartNew + (cone[0] - fStart)*3 + GetTriSubface_Static(ornt[0], 1);                            /* B */
5745       orntNew[0] = ornt[0] < 0 ? -2 :  0;
5746       coneNew[1] = fStartNew + (cone[1] - fStart)*3 + GetTriSubface_Static(ornt[1], 1);                            /* T */
5747       orntNew[1] = ornt[1] < 0 ?  2 : -4;
5748       coneNew[2] = fStartNew + (fMax - fStart)*3 + (cMax - cStart)*6 + (fEnd - fMax)*2 + (c - cMax)*3 + 0;         /* F */
5749       orntNew[2] = 0;
5750       cf         = 1;
5751       of         = ornt[2+cf] < 0 ? -1 : 1;
5752       coneNew[3] = fStartNew + (fMax - fStart)*3 + (cMax - cStart)*6 + (cone[2+cf] - fMax)*2 + (o*of < 0 ? 1 : 0); /* K */
5753       orntNew[3] = o*of < 0 ? 0 : -1;
5754       coneNew[4] = fStartNew + (fMax - fStart)*3 + (cMax - cStart)*6 + (fEnd - fMax)*2 + (c - cMax)*3 + 1;         /* R */
5755       orntNew[4] = -1;
5756       cf         = 0;
5757       of         = ornt[2+cf] < 0 ? -1 : 1;
5758       coneNew[5] = fStartNew + (fMax - fStart)*3 + (cMax - cStart)*6 + (cone[2+cf] - fMax)*2 + (o*of < 0 ? 0 : 1); /* L */
5759       orntNew[5] = o*of < 0 ? 1 : -4;
5760       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
5761       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
5762 #if defined(PETSC_USE_DEBUG)
5763       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);
5764       for (p = 0; p < 6; ++p) {
5765         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);
5766       }
5767 #endif
5768       /* C hex */
5769       coneNew[0] = fStartNew + (cone[0] - fStart)*3 + GetTriSubface_Static(ornt[0], 2);                            /* B */
5770       orntNew[0] = ornt[0] < 0 ? -4 : 2;
5771       coneNew[1] = fStartNew + (cone[1] - fStart)*3 + GetTriSubface_Static(ornt[1], 2);                            /* T */
5772       orntNew[1] = ornt[1] < 0 ? 0 : -2;
5773       cf         = 2;
5774       of         = ornt[2+cf] < 0 ? -1 : 1;
5775       coneNew[2] = fStartNew + (fMax - fStart)*3 + (cMax - cStart)*6 + (cone[2+cf] - fMax)*2 + (o*of < 0 ? 1 : 0); /* F */
5776       orntNew[2] = o*of < 0 ? 0 : -1;
5777       coneNew[3] = fStartNew + (fMax - fStart)*3 + (cMax - cStart)*6 + (fEnd - fMax)*2 + (c - cMax)*3 + 1;         /* K */
5778       orntNew[3] = 0;
5779       cf         = 1;
5780       of         = ornt[2+cf] < 0 ? -1 : 1;
5781       coneNew[4] = fStartNew + (fMax - fStart)*3 + (cMax - cStart)*6 + (cone[2+cf] - fMax)*2 + (o*of < 0 ? 0 : 1); /* R */
5782       orntNew[4] = o*of < 0 ? 0 : -1;
5783       coneNew[5] = fStartNew + (fMax - fStart)*3 + (cMax - cStart)*6 + (fEnd - fMax)*2 + (c - cMax)*3 + 2;         /* L */
5784       orntNew[5] = -4;
5785       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
5786       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
5787 #if defined(PETSC_USE_DEBUG)
5788       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);
5789       for (p = 0; p < 6; ++p) {
5790         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);
5791       }
5792 #endif
5793     }
5794 
5795     /* Split faces have 4 edges and the same cells as the parent */
5796     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
5797     ierr = PetscMalloc1(2 + maxSupportSize*2, &supportRef);CHKERRQ(ierr);
5798     for (f = fStart; f < fMax; ++f) {
5799       const PetscInt  newp = fStartNew + (f - fStart)*3;
5800       const PetscInt *cone, *ornt, *support;
5801       PetscInt        coneNew[4], orntNew[4], coneSize, supportSize, s;
5802 
5803       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
5804 #if defined(PETSC_USE_DEBUG)
5805       for (p = 0; p < 3; ++p) {
5806         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);
5807       }
5808 #endif
5809       ierr = DMPlexGetConeOrientation(dm, f, &ornt);CHKERRQ(ierr);
5810       /* A quad */
5811       coneNew[0] = eStartNew + (cone[2] - eStart)*2 + (ornt[2] < 0 ? 0 : 1);
5812       orntNew[0] = ornt[2];
5813       coneNew[1] = eStartNew + (cone[0] - eStart)*2 + (ornt[0] < 0 ? 1 : 0);
5814       orntNew[1] = ornt[0];
5815       coneNew[2] = eStartNew + (eMax    - eStart)*2 + (f - fStart)*3 + 0;
5816       orntNew[2] = 0;
5817       coneNew[3] = eStartNew + (eMax    - eStart)*2 + (f - fStart)*3 + 2;
5818       orntNew[3] = -2;
5819       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
5820       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
5821 #if defined(PETSC_USE_DEBUG)
5822       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);
5823       for (p = 0; p < 4; ++p) {
5824         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);
5825       }
5826 #endif
5827       /* B quad */
5828       coneNew[0] = eStartNew + (cone[0] - eStart)*2 + (ornt[0] < 0 ? 0 : 1);
5829       orntNew[0] = ornt[0];
5830       coneNew[1] = eStartNew + (cone[1] - eStart)*2 + (ornt[1] < 0 ? 1 : 0);
5831       orntNew[1] = ornt[1];
5832       coneNew[2] = eStartNew + (eMax    - eStart)*2 + (f - fStart)*3 + 1;
5833       orntNew[2] = 0;
5834       coneNew[3] = eStartNew + (eMax    - eStart)*2 + (f - fStart)*3 + 0;
5835       orntNew[3] = -2;
5836       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
5837       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
5838 #if defined(PETSC_USE_DEBUG)
5839       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);
5840       for (p = 0; p < 4; ++p) {
5841         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);
5842       }
5843 #endif
5844       /* C quad */
5845       coneNew[0] = eStartNew + (cone[1] - eStart)*2 + (ornt[1] < 0 ? 0 : 1);
5846       orntNew[0] = ornt[1];
5847       coneNew[1] = eStartNew + (cone[2] - eStart)*2 + (ornt[2] < 0 ? 1 : 0);
5848       orntNew[1] = ornt[2];
5849       coneNew[2] = eStartNew + (eMax    - eStart)*2 + (f - fStart)*3 + 2;
5850       orntNew[2] = 0;
5851       coneNew[3] = eStartNew + (eMax    - eStart)*2 + (f - fStart)*3 + 1;
5852       orntNew[3] = -2;
5853       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
5854       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
5855 #if defined(PETSC_USE_DEBUG)
5856       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);
5857       for (p = 0; p < 4; ++p) {
5858         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);
5859       }
5860 #endif
5861       ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
5862       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
5863       for (r = 0; r < 3; ++r) {
5864         for (s = 0; s < supportSize; ++s) {
5865           PetscInt subf;
5866 
5867           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
5868           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);
5869           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);
5870           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
5871           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
5872           for (c = 0; c < coneSize; ++c) {
5873             if (cone[c] == f) break;
5874           }
5875           subf = GetTriSubfaceInverse_Static(ornt[c], r);
5876           if (coneSize == 4) {
5877             supportRef[s] = cStartNew + (support[s] - cStart)*4 + faces[c*3+subf];
5878           } else if (coneSize == 5) {
5879             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);
5880             supportRef[s] = cStartNew + (cMax - cStart)*4 + (support[s] - cMax)*3 + subf;
5881           } else SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected conesize %D for cell %D (cMax %D)", coneSize, support[s], cMax);
5882         }
5883         ierr = DMPlexSetSupport(rdm, newp+r, supportRef);CHKERRQ(ierr);
5884 #if defined(PETSC_USE_DEBUG)
5885         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);
5886         for (p = 0; p < supportSize; ++p) {
5887           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);
5888         }
5889 #endif
5890       }
5891     }
5892     /* Interior faces have 4 edges and 2 cells */
5893     for (c = cStart; c < cMax; ++c) {
5894       PetscInt        newp = fStartNew + (fMax - fStart)*3 + (c - cStart)*6;
5895       const PetscInt *cone, *ornt;
5896       PetscInt        coneNew[4], orntNew[4];
5897       PetscInt        supportNew[2];
5898 
5899       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
5900 #if defined(PETSC_USE_DEBUG)
5901       for (p = 0; p < 4; ++p) {
5902         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);
5903       }
5904 #endif
5905       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
5906       /* Face {a, g, m, h} */
5907       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*3 + GetTriInteriorEdge_Static(ornt[0],0);
5908       orntNew[0] = 0;
5909       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart)*4 + 0;
5910       orntNew[1] = 0;
5911       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart)*4 + 1;
5912       orntNew[2] = -2;
5913       coneNew[3] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*3 + GetTriInteriorEdge_Static(ornt[1],2);
5914       orntNew[3] = -2;
5915       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5916       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
5917 #if defined(PETSC_USE_DEBUG)
5918       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
5919       for (p = 0; p < 4; ++p) {
5920         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);
5921       }
5922 #endif
5923       supportNew[0] = cStartNew + (c - cStart)*4 + 0;
5924       supportNew[1] = cStartNew + (c - cStart)*4 + 1;
5925       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
5926 #if defined(PETSC_USE_DEBUG)
5927       for (p = 0; p < 2; ++p) {
5928         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);
5929       }
5930 #endif
5931       ++newp;
5932       /* Face {g, b, l , m} */
5933       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*3 + GetTriInteriorEdge_Static(ornt[0],1);
5934       orntNew[0] = -2;
5935       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*3 + GetTriInteriorEdge_Static(ornt[3],0);
5936       orntNew[1] = 0;
5937       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart)*4 + 3;
5938       orntNew[2] = 0;
5939       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart)*4 + 0;
5940       orntNew[3] = -2;
5941       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5942       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
5943 #if defined(PETSC_USE_DEBUG)
5944       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
5945       for (p = 0; p < 4; ++p) {
5946         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);
5947       }
5948 #endif
5949       supportNew[0] = cStartNew + (c - cStart)*4 + 1;
5950       supportNew[1] = cStartNew + (c - cStart)*4 + 2;
5951       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
5952 #if defined(PETSC_USE_DEBUG)
5953       for (p = 0; p < 2; ++p) {
5954         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);
5955       }
5956 #endif
5957       ++newp;
5958       /* Face {c, g, m, i} */
5959       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*3 + GetTriInteriorEdge_Static(ornt[0],2);
5960       orntNew[0] = 0;
5961       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart)*4 + 0;
5962       orntNew[1] = 0;
5963       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart)*4 + 2;
5964       orntNew[2] = -2;
5965       coneNew[3] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*3 + GetTriInteriorEdge_Static(ornt[2],0);
5966       orntNew[3] = -2;
5967       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5968       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
5969 #if defined(PETSC_USE_DEBUG)
5970       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
5971       for (p = 0; p < 4; ++p) {
5972         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);
5973       }
5974 #endif
5975       supportNew[0] = cStartNew + (c - cStart)*4 + 0;
5976       supportNew[1] = cStartNew + (c - cStart)*4 + 2;
5977       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
5978 #if defined(PETSC_USE_DEBUG)
5979       for (p = 0; p < 2; ++p) {
5980         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);
5981       }
5982 #endif
5983       ++newp;
5984       /* Face {d, h, m, i} */
5985       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*3 + GetTriInteriorEdge_Static(ornt[1],0);
5986       orntNew[0] = 0;
5987       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart)*4 + 1;
5988       orntNew[1] = 0;
5989       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart)*4 + 2;
5990       orntNew[2] = -2;
5991       coneNew[3] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*3 + GetTriInteriorEdge_Static(ornt[2],2);
5992       orntNew[3] = -2;
5993       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5994       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
5995 #if defined(PETSC_USE_DEBUG)
5996       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
5997       for (p = 0; p < 4; ++p) {
5998         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);
5999       }
6000 #endif
6001       supportNew[0] = cStartNew + (c - cStart)*4 + 0;
6002       supportNew[1] = cStartNew + (c - cStart)*4 + 3;
6003       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
6004 #if defined(PETSC_USE_DEBUG)
6005       for (p = 0; p < 2; ++p) {
6006         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);
6007       }
6008 #endif
6009       ++newp;
6010       /* Face {h, m, l, e} */
6011       coneNew[0] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart)*4 + 1;
6012       orntNew[0] = 0;
6013       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart)*4 + 3;
6014       orntNew[1] = -2;
6015       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*3 + GetTriInteriorEdge_Static(ornt[3],1);
6016       orntNew[2] = -2;
6017       coneNew[3] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*3 + GetTriInteriorEdge_Static(ornt[1],1);
6018       orntNew[3] = 0;
6019       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6020       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
6021 #if defined(PETSC_USE_DEBUG)
6022       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
6023       for (p = 0; p < 4; ++p) {
6024         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);
6025       }
6026 #endif
6027       supportNew[0] = cStartNew + (c - cStart)*4 + 1;
6028       supportNew[1] = cStartNew + (c - cStart)*4 + 3;
6029       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
6030 #if defined(PETSC_USE_DEBUG)
6031       for (p = 0; p < 2; ++p) {
6032         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);
6033       }
6034 #endif
6035       ++newp;
6036       /* Face {i, m, l, f} */
6037       coneNew[0] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart)*4 + 2;
6038       orntNew[0] = 0;
6039       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart)*4 + 3;
6040       orntNew[1] = -2;
6041       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*3 + GetTriInteriorEdge_Static(ornt[3],2);
6042       orntNew[2] = -2;
6043       coneNew[3] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*3 + GetTriInteriorEdge_Static(ornt[2],1);
6044       orntNew[3] = 0;
6045       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6046       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
6047 #if defined(PETSC_USE_DEBUG)
6048       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
6049       for (p = 0; p < 4; ++p) {
6050         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);
6051       }
6052 #endif
6053       supportNew[0] = cStartNew + (c - cStart)*4 + 2;
6054       supportNew[1] = cStartNew + (c - cStart)*4 + 3;
6055       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
6056 #if defined(PETSC_USE_DEBUG)
6057       for (p = 0; p < 2; ++p) {
6058         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);
6059       }
6060 #endif
6061       ++newp;
6062     }
6063     /* Hybrid split faces have 4 edges and same cells */
6064     for (f = fMax; f < fEnd; ++f) {
6065       const PetscInt *cone, *ornt, *support;
6066       PetscInt        coneNew[4], orntNew[4];
6067       PetscInt        size, s;
6068       const PetscInt  newp = fStartNew + (fMax - fStart)*3 + (cMax - cStart)*6 + (f - fMax)*2;
6069 
6070       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
6071 #if defined(PETSC_USE_DEBUG)
6072       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);
6073       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);
6074       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);
6075       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);
6076 #endif
6077       ierr = DMPlexGetConeOrientation(dm, f, &ornt);CHKERRQ(ierr);
6078       /* A face */
6079       coneNew[0] = eStartNew + (cone[0] - eStart)*2 + (ornt[0] < 0 ? 1 : 0);
6080       orntNew[0] = ornt[0];
6081       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart)*4 + (eEnd - eMax) + (f - fMax);
6082       orntNew[1] = 0;
6083       coneNew[2] = eStartNew + (cone[1] - eStart)*2 + (ornt[1] < 0 ? 1 : 0);
6084       orntNew[2] = ornt[1] < 0 ? 0 : -2;
6085       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart)*4 + (cone[2] - eMax);
6086       orntNew[3] = ornt[2] < 0 ? 0 : -2;
6087       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6088       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
6089 #if defined(PETSC_USE_DEBUG)
6090       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
6091       for (p = 0; p < 4; ++p) {
6092         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);
6093       }
6094 #endif
6095 
6096       /* B face */
6097       coneNew[0] = eStartNew + (cone[0] - eStart)*2 + (ornt[0] < 0 ? 0 : 1);
6098       orntNew[0] = ornt[0];
6099       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart)*4 + (cone[3] - eMax);
6100       orntNew[1] = ornt[3];
6101       coneNew[2] = eStartNew + (cone[1] - eStart)*2 + (ornt[1] < 0 ? 0 : 1);
6102       orntNew[2] = ornt[1] < 0 ? 0 : -2;
6103       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart)*4 + (eEnd - eMax) + (f - fMax);
6104       orntNew[3] = -2;
6105       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
6106       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
6107 #if defined(PETSC_USE_DEBUG)
6108       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);
6109       for (p = 0; p < 4; ++p) {
6110         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);
6111       }
6112 #endif
6113 
6114       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
6115       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
6116       for (r = 0; r < 2; ++r) {
6117         for (s = 0; s < size; ++s) {
6118           const PetscInt *coneCell, *orntCell;
6119           PetscInt        coneSize, o, of, c;
6120 
6121           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
6122           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);
6123           ierr = DMPlexGetCone(dm, support[s], &coneCell);CHKERRQ(ierr);
6124           ierr = DMPlexGetConeOrientation(dm, support[s], &orntCell);CHKERRQ(ierr);
6125           o = orntCell[0] < 0 ? -1 : 1;
6126           o = 1;
6127           for (c = 0; c < coneSize; ++c) if (coneCell[c] == f) break;
6128           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);
6129           if (c == coneSize) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Could not find face %D in cone of cell %D", f, support[s]);
6130           of = orntCell[c] < 0 ? -1 : 1;
6131           supportRef[s] = cStartNew + (cMax - cStart)*4 + (support[s] - cMax)*3 + (c-2 + (o*of < 0 ? 1-r : r))%3;
6132         }
6133         ierr = DMPlexSetSupport(rdm, newp + r, supportRef);CHKERRQ(ierr);
6134 #if defined(PETSC_USE_DEBUG)
6135         for (p = 0; p < size; ++p) {
6136           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);
6137         }
6138 #endif
6139       }
6140     }
6141     /* Interior hybrid faces have 4 edges and 2 cells */
6142     for (c = cMax; c < cEnd; ++c) {
6143       PetscInt        newp = fStartNew + (fMax - fStart)*3 + (cMax - cStart)*6 + (fEnd - fMax)*2 + (c - cMax)*3;
6144       const PetscInt *cone, *ornt;
6145       PetscInt        coneNew[4], orntNew[4];
6146       PetscInt        supportNew[2];
6147 
6148       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
6149 #if defined(PETSC_USE_DEBUG)
6150       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);
6151       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);
6152       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);
6153       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);
6154       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);
6155 #endif
6156       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
6157       /* Face {a, g, h, d} */
6158       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*3 + GetTriInteriorEdge_Static(ornt[0],0);
6159       orntNew[0] = 0;
6160       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart)*4 + (eEnd - eMax) + (fEnd - fMax) + c - cMax;
6161       orntNew[1] = 0;
6162       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*3 + GetTriInteriorEdge_Static(ornt[1],0);
6163       orntNew[2] = -2;
6164       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart)*4 + (eEnd - eMax) + (cone[2] - fMax);
6165       orntNew[3] = -2;
6166       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6167       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
6168 #if defined(PETSC_USE_DEBUG)
6169       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
6170       for (p = 0; p < 4; ++p) {
6171         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);
6172       }
6173 #endif
6174       supportNew[0] = cStartNew + (cMax - cStart)*4 + (c - cMax)*3 + 0;
6175       supportNew[1] = cStartNew + (cMax - cStart)*4 + (c - cMax)*3 + 1;
6176       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
6177 #if defined(PETSC_USE_DEBUG)
6178       for (p = 0; p < 2; ++p) {
6179         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);
6180       }
6181 #endif
6182       ++newp;
6183       /* Face {b, g, h, l} */
6184       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*3 + GetTriInteriorEdge_Static(ornt[0],1);
6185       orntNew[0] = 0;
6186       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart)*4 + (eEnd - eMax) + (fEnd - fMax) + c - cMax;
6187       orntNew[1] = 0;
6188       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*3 + GetTriInteriorEdge_Static(ornt[1],1);
6189       orntNew[2] = -2;
6190       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart)*4 + (eEnd - eMax) + (cone[3] - fMax);
6191       orntNew[3] = -2;
6192       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6193       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
6194 #if defined(PETSC_USE_DEBUG)
6195       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
6196       for (p = 0; p < 4; ++p) {
6197         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);
6198       }
6199 #endif
6200       supportNew[0] = cStartNew + (cMax - cStart)*4 + (c - cMax)*3 + 1;
6201       supportNew[1] = cStartNew + (cMax - cStart)*4 + (c - cMax)*3 + 2;
6202       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
6203 #if defined(PETSC_USE_DEBUG)
6204       for (p = 0; p < 2; ++p) {
6205         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);
6206       }
6207 #endif
6208       ++newp;
6209       /* Face {c, g, h, f} */
6210       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*3 + GetTriInteriorEdge_Static(ornt[0],2);
6211       orntNew[0] = 0;
6212       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart)*4 + (eEnd - eMax) + (fEnd - fMax) + c - cMax;
6213       orntNew[1] = 0;
6214       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*3 + GetTriInteriorEdge_Static(ornt[1],2);
6215       orntNew[2] = -2;
6216       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart)*4 + (eEnd - eMax) + (cone[4] - fMax);
6217       orntNew[3] = -2;
6218       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6219       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
6220 #if defined(PETSC_USE_DEBUG)
6221       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
6222       for (p = 0; p < 4; ++p) {
6223         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);
6224       }
6225 #endif
6226       supportNew[0] = cStartNew + (cMax - cStart)*4 + (c - cMax)*3 + 2;
6227       supportNew[1] = cStartNew + (cMax - cStart)*4 + (c - cMax)*3 + 0;
6228       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
6229 #if defined(PETSC_USE_DEBUG)
6230       for (p = 0; p < 2; ++p) {
6231         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);
6232       }
6233 #endif
6234     }
6235     /* Face edges have 2 vertices and 2 + cell faces supports */
6236     for (f = fStart; f < fMax; ++f) {
6237       const PetscInt *cone, *ornt, *support;
6238       PetscInt        coneSize, supportSize, s;
6239 
6240       ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
6241       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
6242       for (r = 0; r < 3; ++r) {
6243         const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (f - fStart)*3 + r;
6244         PetscInt        coneNew[2];
6245         PetscInt        fint[4][3] = { {0, 1, 2},
6246                                        {3, 4, 0},
6247                                        {2, 5, 3},
6248                                        {1, 4, 5} };
6249 
6250         ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
6251         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);
6252         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r] - eStart);
6253         coneNew[1] = vStartNew + (vEnd - vStart) + (eMax - eStart) + f - fStart;
6254         ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6255 #if defined(PETSC_USE_DEBUG)
6256         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eEndNew);
6257         for (p = 0; p < 2; ++p) {
6258           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);
6259         }
6260 #endif
6261         supportRef[0] = fStartNew + (f - fStart)*3 + (r+0)%3;
6262         supportRef[1] = fStartNew + (f - fStart)*3 + (r+1)%3;
6263         for (s = 0; s < supportSize; ++s) {
6264           PetscInt er;
6265 
6266           supportRef[2+s] = -1;
6267           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
6268           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);
6269           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);
6270           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6271           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
6272           for (c = 0; c < coneSize; ++c) {if (cone[c] == f) break;}
6273           er = GetTriInteriorEdgeInverse_Static(ornt[c], r);
6274           if (coneSize == 4) {
6275             supportRef[2+s] = fStartNew + (fMax - fStart)*3 + (support[s] - cStart)*6 + fint[c][er];
6276           } else if (coneSize == 5) {
6277             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);
6278             supportRef[2+s] = fStartNew + (fMax - fStart)*3 + (cMax - cStart)*6 + (fEnd - fMax)*2 + (support[s] - cMax)*3 + er;
6279           }
6280         }
6281         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6282 #if defined(PETSC_USE_DEBUG)
6283         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eEndNew);
6284         for (p = 0; p < supportSize + 2; ++p) {
6285           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);
6286         }
6287 #endif
6288       }
6289     }
6290     /* Interior cell edges have 2 vertices and 3 faces */
6291     for (c = cStart; c < cMax; ++c) {
6292       const PetscInt *cone;
6293       PetscInt       fint[4][3] = { {0,1,2},
6294                                     {0,3,4},
6295                                     {2,3,5},
6296                                     {1,4,5} } ;
6297 
6298       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
6299       for (r = 0; r < 4; r++) {
6300         PetscInt       coneNew[2], supportNew[3];
6301         const PetscInt newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart)*4 + r;
6302 
6303         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);
6304         coneNew[0] = vStartNew + (vEnd - vStart) + (eMax - eStart) + (cone[r] - fStart);
6305         coneNew[1] = vStartNew + (vEnd - vStart) + (eMax - eStart) + (fMax     -fStart) + c - cStart;
6306         ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6307 #if defined(PETSC_USE_DEBUG)
6308         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eEndNew);
6309         for (p = 0; p < 2; ++p) {
6310           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);
6311         }
6312 #endif
6313         supportNew[0] = fStartNew + (fMax - fStart)*3 + (c - cStart)*6 + fint[r][0];
6314         supportNew[1] = fStartNew + (fMax - fStart)*3 + (c - cStart)*6 + fint[r][1];
6315         supportNew[2] = fStartNew + (fMax - fStart)*3 + (c - cStart)*6 + fint[r][2];
6316         ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
6317 #if defined(PETSC_USE_DEBUG)
6318         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eEndNew);
6319         for (p = 0; p < 3; ++p) {
6320           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);
6321         }
6322 #endif
6323       }
6324     }
6325     /* Hybrid edges have two vertices and the same faces */
6326     for (e = eMax; e < eEnd; ++e) {
6327       const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart)*4 + (e - eMax);
6328       const PetscInt *cone, *support, *fcone;
6329       PetscInt        coneNew[2], size, fsize, s;
6330 
6331       ierr = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
6332       ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
6333       ierr = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
6334       coneNew[0] = vStartNew + (cone[0] - vStart);
6335       coneNew[1] = vStartNew + (cone[1] - vStart);
6336       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6337 #if defined(PETSC_USE_DEBUG)
6338       if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is a edge [%D, %D)", newp, eStartNew, eEndNew);
6339       for (p = 0; p < 2; ++p) {
6340         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);
6341       }
6342 #endif
6343       for (s = 0; s < size; ++s) {
6344         ierr = DMPlexGetConeSize(dm, support[s], &fsize);CHKERRQ(ierr);
6345         ierr = DMPlexGetCone(dm, support[s], &fcone);CHKERRQ(ierr);
6346         for (c = 0; c < fsize; ++c) if (fcone[c] == e) break;
6347         if ((c < 2) || (c > 3)) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Edge %D not found in cone of face %D", e, support[s]);
6348         supportRef[s] = fStartNew + (fMax - fStart)*3 + (cMax - cStart)*6 + (support[s] - fMax)*2 + c-2;
6349       }
6350       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6351 #if defined(PETSC_USE_DEBUG)
6352       for (p = 0; p < size; ++p) {
6353         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);
6354       }
6355 #endif
6356     }
6357     /* Hybrid face edges have 2 vertices and 2 + cell faces supports */
6358     for (f = fMax; f < fEnd; ++f) {
6359       const PetscInt *cone, *ornt, *support;
6360       PetscInt        coneSize, supportSize;
6361       const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart)*4 + (eEnd - eMax) + f - fMax;
6362       PetscInt        coneNew[2], s;
6363 
6364       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
6365 #if defined(PETSC_USE_DEBUG)
6366       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);
6367       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);
6368 #endif
6369       coneNew[0] = vStartNew + (vEnd - vStart) + (cone[0] - eStart);
6370       coneNew[1] = vStartNew + (vEnd - vStart) + (cone[1] - eStart);
6371       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6372 #if defined(PETSC_USE_DEBUG)
6373       if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eEndNew);
6374       for (p = 0; p < 2; ++p) {
6375         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);
6376       }
6377 #endif
6378       supportRef[0] = fStartNew + (fMax - fStart)*3 + (cMax - cStart)*6 + (f- fMax)*2 + 0;
6379       supportRef[1] = fStartNew + (fMax - fStart)*3 + (cMax - cStart)*6 + (f- fMax)*2 + 1;
6380       ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
6381       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
6382       for (s = 0; s < supportSize; ++s) {
6383         ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
6384         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);
6385         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6386         ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
6387         for (c = 0; c < coneSize; ++c) {if (cone[c] == f) break;}
6388         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);
6389         supportRef[2+s] = fStartNew + (fMax - fStart)*3 + (cMax - cStart)*6 + (fEnd - fMax)*2 + (support[s] - cMax)*3 + c - 2;
6390       }
6391       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6392 #if defined(PETSC_USE_DEBUG)
6393       if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eEndNew);
6394       for (p = 0; p < supportSize + 2; ++p) {
6395         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);
6396       }
6397 #endif
6398     }
6399     /* Hybrid cell edges have 2 vertices and 3 faces */
6400     for (c = cMax; c < cEnd; ++c) {
6401       PetscInt       coneNew[2], supportNew[3];
6402       const PetscInt newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart)*4 + (eEnd - eMax) + (fEnd - fMax) + c - cMax;
6403       const PetscInt *cone;
6404 
6405       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
6406 #if defined(PETSC_USE_DEBUG)
6407       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);
6408       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);
6409 #endif
6410       coneNew[0] = vStartNew + (vEnd - vStart) + (eMax - eStart) + (cone[0] - fStart);
6411       coneNew[1] = vStartNew + (vEnd - vStart) + (eMax - eStart) + (cone[1] - fStart);
6412       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6413 #if defined(PETSC_USE_DEBUG)
6414       if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eEndNew);
6415       for (p = 0; p < 2; ++p) {
6416         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);
6417       }
6418 #endif
6419       supportNew[0] = fStartNew + (fMax - fStart)*3 + (cMax - cStart)*6 + (fEnd - fMax)*2 + (c - cMax)*3 + 0;
6420       supportNew[1] = fStartNew + (fMax - fStart)*3 + (cMax - cStart)*6 + (fEnd - fMax)*2 + (c - cMax)*3 + 1;
6421       supportNew[2] = fStartNew + (fMax - fStart)*3 + (cMax - cStart)*6 + (fEnd - fMax)*2 + (c - cMax)*3 + 2;
6422       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
6423 #if defined(PETSC_USE_DEBUG)
6424       if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eEndNew);
6425       for (p = 0; p < 3; ++p) {
6426         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);
6427       }
6428 #endif
6429     }
6430     /* Old vertices have identical supports */
6431     for (v = vStart; v < vEnd; ++v) {
6432       const PetscInt  newp = vStartNew + (v - vStart);
6433       const PetscInt *support, *cone;
6434       PetscInt        size, s;
6435 
6436       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
6437       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
6438       for (s = 0; s < size; ++s) {
6439         const PetscInt e = support[s];
6440 
6441         supportRef[s] = -1;
6442         if (eStart <= e) {
6443           if (e < eMax) {
6444             ierr = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
6445             supportRef[s] = eStartNew + (e - eStart)*2 + (cone[1] == v ? 1 : 0);
6446           } else if (e < eEnd) {
6447             supportRef[s] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart)*4 + e - eMax;
6448           } else SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", e, eStart, eEnd);
6449         } else SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", e, eStart, eEnd);
6450       }
6451       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6452 #if defined(PETSC_USE_DEBUG)
6453       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", newp, vStartNew, vEndNew);
6454       for (p = 0; p < size; ++p) {
6455         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);
6456       }
6457 #endif
6458     }
6459     /* Interior edge vertices have 2 + faces supports */
6460     for (e = eStart; e < eMax; ++e) {
6461       const PetscInt  newp = vStartNew + (vEnd - vStart) + (e - eStart);
6462       const PetscInt *cone, *support;
6463       PetscInt        size, s;
6464 
6465       ierr          = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
6466       ierr          = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
6467       supportRef[0] = eStartNew + (e - eStart)*2 + 0;
6468       supportRef[1] = eStartNew + (e - eStart)*2 + 1;
6469       for (s = 0; s < size; ++s) {
6470         PetscInt r, coneSize;
6471 
6472         supportRef[2+s] = -1;
6473         ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
6474         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);
6475         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);
6476         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6477         for (r = 0; r < coneSize; ++r) {if (cone[r] == e) break;}
6478         if (coneSize == 3) supportRef[2+s] = eStartNew + (eMax - eStart)*2 + (support[s] - fStart)*3 + r;
6479         else if (coneSize == 4) {
6480           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);
6481           supportRef[2+s] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart)*4 + (eEnd - eMax) + support[s] - fMax;
6482         } else SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected conesize %D for face %D (fMax %D)", coneSize, support[s], fMax);
6483       }
6484       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6485 #if defined(PETSC_USE_DEBUG)
6486       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", newp, vStartNew, vEndNew);
6487       for (p = 0; p < 2+size; ++p) {
6488         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);
6489       }
6490 #endif
6491     }
6492     /* Split Edges have 2 vertices and the same faces as the parent */
6493     for (e = eStart; e < eMax; ++e) {
6494       const PetscInt newv = vStartNew + (vEnd - vStart) + (e - eStart);
6495 
6496       for (r = 0; r < 2; ++r) {
6497         const PetscInt  newp = eStartNew + (e - eStart)*2 + r;
6498         const PetscInt *cone, *ornt, *support;
6499         PetscInt        coneNew[2], coneSize, c, supportSize, s;
6500 
6501         ierr             = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
6502         coneNew[0]       = vStartNew + (cone[0] - vStart);
6503         coneNew[1]       = vStartNew + (cone[1] - vStart);
6504         coneNew[(r+1)%2] = newv;
6505         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6506 #if defined(PETSC_USE_DEBUG)
6507         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eEndNew);
6508         for (p = 0; p < 2; ++p) {
6509           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);
6510         }
6511 #endif
6512         ierr = DMPlexGetSupportSize(dm, e, &supportSize);CHKERRQ(ierr);
6513         ierr = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
6514         for (s = 0; s < supportSize; ++s) {
6515           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
6516           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);
6517           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);
6518           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6519           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
6520           for (c = 0; c < coneSize; ++c) {
6521             if (cone[c] == e) break;
6522           }
6523           if (coneSize == 3) supportRef[s] = fStartNew + (support[s] - fStart)*3 + (c + (ornt[c] < 0 ? 1-r : r))%3;
6524           else if (coneSize == 4) {
6525             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);
6526             supportRef[s] = fStartNew + (fMax - fStart)*3 + (cMax - cStart)*6 + (support[s] - fMax)*2 + (ornt[c] < 0 ? 1-r : r);
6527           } else SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected conesize %D for face %D (fMax %D)", coneSize, support[s], fMax);
6528         }
6529         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6530 #if defined(PETSC_USE_DEBUG)
6531         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eEndNew);
6532         for (p = 0; p < supportSize; ++p) {
6533           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);
6534         }
6535 #endif
6536       }
6537     }
6538     /* Face vertices have 3 + cells supports */
6539     for (f = fStart; f < fMax; ++f) {
6540       const PetscInt  newp = vStartNew + (vEnd - vStart) + (eMax - eStart) + (f - fStart);
6541       const PetscInt *cone, *support;
6542       PetscInt        size, s;
6543 
6544       ierr          = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
6545       ierr          = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
6546       supportRef[0] = eStartNew + (eMax - eStart)*2 + (f - fStart)*3 + 0;
6547       supportRef[1] = eStartNew + (eMax - eStart)*2 + (f - fStart)*3 + 1;
6548       supportRef[2] = eStartNew + (eMax - eStart)*2 + (f - fStart)*3 + 2;
6549       for (s = 0; s < size; ++s) {
6550         PetscInt r, coneSize;
6551 
6552         supportRef[3+s] = -1;
6553         ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
6554         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);
6555         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);
6556         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6557         for (r = 0; r < coneSize; ++r) {if (cone[r] == f) break;}
6558         if (coneSize == 4) supportRef[3+s] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (support[s] - cStart)*4 + r;
6559         else if (coneSize == 5) {
6560           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);
6561           supportRef[3+s] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart)*4 + (eEnd - eMax) + (fEnd - fMax) + support[s] - cMax;
6562         }
6563       }
6564       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6565 #if defined(PETSC_USE_DEBUG)
6566       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", newp, vStartNew, vEndNew);
6567       for (p = 0; p < 3+size; ++p) {
6568         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);
6569       }
6570 #endif
6571     }
6572     /* Interior cell vertices have 4 supports */
6573     for (c = cStart; c < cMax; ++c) {
6574       const PetscInt  newp = vStartNew + (vEnd - vStart) + (eMax - eStart) + (fMax - fStart) + c - cStart;
6575 
6576       supportRef[0] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart)*4 + 0;
6577       supportRef[1] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart)*4 + 1;
6578       supportRef[2] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart)*4 + 2;
6579       supportRef[3] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart)*4 + 3;
6580       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6581 #if defined(PETSC_USE_DEBUG)
6582       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", newp, vStartNew, vEndNew);
6583       for (p = 0; p < 4; ++p) {
6584         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);
6585       }
6586 #endif
6587     }
6588     ierr = PetscFree(supportRef);CHKERRQ(ierr);
6589     ierr = DMPlexRestoreFaces_Internal(dm, cStart, NULL, NULL, &faces);CHKERRQ(ierr);
6590     break;
6591   case REFINER_HEX_3D:
6592     /*
6593      Bottom (viewed from top)    Top
6594      1---------2---------2       7---------2---------6
6595      |         |         |       |         |         |
6596      |    B    2    C    |       |    H    2    G    |
6597      |         |         |       |         |         |
6598      3----3----0----1----1       3----3----0----1----1
6599      |         |         |       |         |         |
6600      |    A    0    D    |       |    E    0    F    |
6601      |         |         |       |         |         |
6602      0---------0---------3       4---------0---------5
6603      */
6604     /* All cells have 6 faces: Bottom, Top, Front, Back, Right, Left */
6605     for (c = cStart; c < cEnd; ++c) {
6606       const PetscInt  newp = (c - cStart)*8;
6607       const PetscInt *cone, *ornt;
6608       PetscInt        coneNew[6], orntNew[6];
6609 
6610       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
6611       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
6612       /* A hex */
6613       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], 0);
6614       orntNew[0] = ornt[0];
6615       coneNew[1] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  8; /* AE */
6616       orntNew[1] = 0;
6617       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetQuadSubface_Static(ornt[2], 0);
6618       orntNew[2] = ornt[2];
6619       coneNew[3] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  3; /* AB */
6620       orntNew[3] = 0;
6621       coneNew[4] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  0; /* AD */
6622       orntNew[4] = 0;
6623       coneNew[5] = fStartNew + (cone[5] - fStart)*4 + GetQuadSubface_Static(ornt[5], 0);
6624       orntNew[5] = ornt[5];
6625       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
6626       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
6627 #if defined(PETSC_USE_DEBUG)
6628       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);
6629       for (p = 0; p < 6; ++p) {
6630         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);
6631       }
6632 #endif
6633       /* B hex */
6634       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], 1);
6635       orntNew[0] = ornt[0];
6636       coneNew[1] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 + 11; /* BH */
6637       orntNew[1] = 0;
6638       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  3; /* AB */
6639       orntNew[2] = -1;
6640       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetQuadSubface_Static(ornt[3], 1);
6641       orntNew[3] = ornt[3];
6642       coneNew[4] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  2; /* BC */
6643       orntNew[4] = 0;
6644       coneNew[5] = fStartNew + (cone[5] - fStart)*4 + GetQuadSubface_Static(ornt[5], 3);
6645       orntNew[5] = ornt[5];
6646       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
6647       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
6648 #if defined(PETSC_USE_DEBUG)
6649       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);
6650       for (p = 0; p < 6; ++p) {
6651         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);
6652       }
6653 #endif
6654       /* C hex */
6655       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], 2);
6656       orntNew[0] = ornt[0];
6657       coneNew[1] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 + 10; /* CG */
6658       orntNew[1] = 0;
6659       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  1; /* CD */
6660       orntNew[2] = -1;
6661       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetQuadSubface_Static(ornt[3], 0);
6662       orntNew[3] = ornt[3];
6663       coneNew[4] = fStartNew + (cone[4] - fStart)*4 + GetQuadSubface_Static(ornt[4], 1);
6664       orntNew[4] = ornt[4];
6665       coneNew[5] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  2; /* BC */
6666       orntNew[5] = -4;
6667       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
6668       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
6669 #if defined(PETSC_USE_DEBUG)
6670       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);
6671       for (p = 0; p < 6; ++p) {
6672         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);
6673       }
6674 #endif
6675       /* D hex */
6676       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], 3);
6677       orntNew[0] = ornt[0];
6678       coneNew[1] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  9; /* DF */
6679       orntNew[1] = 0;
6680       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetQuadSubface_Static(ornt[2], 1);
6681       orntNew[2] = ornt[2];
6682       coneNew[3] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  1; /* CD */
6683       orntNew[3] = 0;
6684       coneNew[4] = fStartNew + (cone[4] - fStart)*4 + GetQuadSubface_Static(ornt[4], 0);
6685       orntNew[4] = ornt[4];
6686       coneNew[5] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  0; /* AD */
6687       orntNew[5] = -4;
6688       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
6689       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
6690 #if defined(PETSC_USE_DEBUG)
6691       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);
6692       for (p = 0; p < 6; ++p) {
6693         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);
6694       }
6695 #endif
6696       /* E hex */
6697       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  8; /* AE */
6698       orntNew[0] = -4;
6699       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], 0);
6700       orntNew[1] = ornt[1];
6701       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetQuadSubface_Static(ornt[2], 3);
6702       orntNew[2] = ornt[2];
6703       coneNew[3] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  7; /* EH */
6704       orntNew[3] = 0;
6705       coneNew[4] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  4; /* EF */
6706       orntNew[4] = -1;
6707       coneNew[5] = fStartNew + (cone[5] - fStart)*4 + GetQuadSubface_Static(ornt[5], 1);
6708       orntNew[5] = ornt[5];
6709       ierr       = DMPlexSetCone(rdm, newp+4, coneNew);CHKERRQ(ierr);
6710       ierr       = DMPlexSetConeOrientation(rdm, newp+4, orntNew);CHKERRQ(ierr);
6711 #if defined(PETSC_USE_DEBUG)
6712       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);
6713       for (p = 0; p < 6; ++p) {
6714         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);
6715       }
6716 #endif
6717       /* F hex */
6718       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  9; /* DF */
6719       orntNew[0] = -4;
6720       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], 1);
6721       orntNew[1] = ornt[1];
6722       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetQuadSubface_Static(ornt[2], 2);
6723       orntNew[2] = ornt[2];
6724       coneNew[3] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  5; /* FG */
6725       orntNew[3] = -1;
6726       coneNew[4] = fStartNew + (cone[4] - fStart)*4 + GetQuadSubface_Static(ornt[4], 3);
6727       orntNew[4] = ornt[4];
6728       coneNew[5] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  4; /* EF */
6729       orntNew[5] = 1;
6730       ierr       = DMPlexSetCone(rdm, newp+5, coneNew);CHKERRQ(ierr);
6731       ierr       = DMPlexSetConeOrientation(rdm, newp+5, orntNew);CHKERRQ(ierr);
6732 #if defined(PETSC_USE_DEBUG)
6733       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);
6734       for (p = 0; p < 6; ++p) {
6735         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);
6736       }
6737 #endif
6738       /* G hex */
6739       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 + 10; /* CG */
6740       orntNew[0] = -4;
6741       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], 2);
6742       orntNew[1] = ornt[1];
6743       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  5; /* FG */
6744       orntNew[2] = 0;
6745       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetQuadSubface_Static(ornt[3], 3);
6746       orntNew[3] = ornt[3];
6747       coneNew[4] = fStartNew + (cone[4] - fStart)*4 + GetQuadSubface_Static(ornt[4], 2);
6748       orntNew[4] = ornt[4];
6749       coneNew[5] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  6; /* GH */
6750       orntNew[5] = -3;
6751       ierr       = DMPlexSetCone(rdm, newp+6, coneNew);CHKERRQ(ierr);
6752       ierr       = DMPlexSetConeOrientation(rdm, newp+6, orntNew);CHKERRQ(ierr);
6753 #if defined(PETSC_USE_DEBUG)
6754       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);
6755       for (p = 0; p < 6; ++p) {
6756         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);
6757       }
6758 #endif
6759       /* H hex */
6760       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 + 11; /* BH */
6761       orntNew[0] = -4;
6762       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], 3);
6763       orntNew[1] = ornt[1];
6764       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  7; /* EH */
6765       orntNew[2] = -1;
6766       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetQuadSubface_Static(ornt[3], 2);
6767       orntNew[3] = ornt[3];
6768       coneNew[4] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  6; /* GH */
6769       orntNew[4] = 3;
6770       coneNew[5] = fStartNew + (cone[5] - fStart)*4 + GetQuadSubface_Static(ornt[5], 2);
6771       orntNew[5] = ornt[5];
6772       ierr       = DMPlexSetCone(rdm, newp+7, coneNew);CHKERRQ(ierr);
6773       ierr       = DMPlexSetConeOrientation(rdm, newp+7, orntNew);CHKERRQ(ierr);
6774 #if defined(PETSC_USE_DEBUG)
6775       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);
6776       for (p = 0; p < 6; ++p) {
6777         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);
6778       }
6779 #endif
6780     }
6781     /* Split faces have 4 edges and the same cells as the parent */
6782     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
6783     ierr = PetscMalloc1(4 + maxSupportSize*2, &supportRef);CHKERRQ(ierr);
6784     for (f = fStart; f < fEnd; ++f) {
6785       for (r = 0; r < 4; ++r) {
6786         /* TODO: This can come from GetFaces_Internal() */
6787         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};
6788         const PetscInt  newp = fStartNew + (f - fStart)*4 + r;
6789         const PetscInt *cone, *ornt, *support;
6790         PetscInt        coneNew[4], orntNew[4], coneSize, c, supportSize, s;
6791 
6792         ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
6793         ierr = DMPlexGetConeOrientation(dm, f, &ornt);CHKERRQ(ierr);
6794         coneNew[(r+3)%4] = eStartNew + (cone[(r+3)%4] - eStart)*2 + (ornt[(r+3)%4] < 0 ? 0 : 1);
6795         orntNew[(r+3)%4] = ornt[(r+3)%4];
6796         coneNew[(r+0)%4] = eStartNew + (cone[r]       - eStart)*2 + (ornt[r] < 0 ? 1 : 0);
6797         orntNew[(r+0)%4] = ornt[r];
6798         coneNew[(r+1)%4] = eStartNew + (eEnd - eStart)*2 + (f - fStart)*4 + r;
6799         orntNew[(r+1)%4] = 0;
6800         coneNew[(r+2)%4] = eStartNew + (eEnd - eStart)*2 + (f - fStart)*4 + (r+3)%4;
6801         orntNew[(r+2)%4] = -2;
6802         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6803         ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
6804 #if defined(PETSC_USE_DEBUG)
6805         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
6806         for (p = 0; p < 4; ++p) {
6807           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);
6808         }
6809 #endif
6810         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
6811         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
6812         for (s = 0; s < supportSize; ++s) {
6813           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
6814           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6815           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
6816           for (c = 0; c < coneSize; ++c) {
6817             if (cone[c] == f) break;
6818           }
6819           supportRef[s] = cStartNew + (support[s] - cStart)*8 + newCells[c*4+GetQuadSubfaceInverse_Static(ornt[c], r)];
6820         }
6821         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6822 #if defined(PETSC_USE_DEBUG)
6823         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
6824         for (p = 0; p < supportSize; ++p) {
6825           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);
6826         }
6827 #endif
6828       }
6829     }
6830     /* Interior faces have 4 edges and 2 cells */
6831     for (c = cStart; c < cEnd; ++c) {
6832       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};
6833       const PetscInt *cone, *ornt;
6834       PetscInt        newp, coneNew[4], orntNew[4], supportNew[2];
6835 
6836       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
6837       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
6838       /* A-D face */
6839       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 0;
6840       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*4 + GetQuadEdge_Static(ornt[0], 3);
6841       orntNew[0] = 0;
6842       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 0;
6843       orntNew[1] = 0;
6844       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 2;
6845       orntNew[2] = -2;
6846       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*4 + GetQuadEdge_Static(ornt[2], 0);
6847       orntNew[3] = -2;
6848       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6849       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
6850 #if defined(PETSC_USE_DEBUG)
6851       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
6852       for (p = 0; p < 4; ++p) {
6853         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);
6854       }
6855 #endif
6856       /* C-D face */
6857       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 1;
6858       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*4 + GetQuadEdge_Static(ornt[0], 2);
6859       orntNew[0] = 0;
6860       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 0;
6861       orntNew[1] = 0;
6862       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 4;
6863       orntNew[2] = -2;
6864       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (cone[4] - fStart)*4 + GetQuadEdge_Static(ornt[4], 0);
6865       orntNew[3] = -2;
6866       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6867       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
6868 #if defined(PETSC_USE_DEBUG)
6869       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
6870       for (p = 0; p < 4; ++p) {
6871         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);
6872       }
6873 #endif
6874       /* B-C face */
6875       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 2;
6876       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*4 + GetQuadEdge_Static(ornt[0], 1);
6877       orntNew[0] = -2;
6878       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*4 + GetQuadEdge_Static(ornt[3], 0);
6879       orntNew[1] = 0;
6880       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 3;
6881       orntNew[2] = 0;
6882       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 0;
6883       orntNew[3] = -2;
6884       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6885       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
6886 #if defined(PETSC_USE_DEBUG)
6887       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
6888       for (p = 0; p < 4; ++p) {
6889         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);
6890       }
6891 #endif
6892       /* A-B face */
6893       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 3;
6894       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*4 + GetQuadEdge_Static(ornt[0], 0);
6895       orntNew[0] = -2;
6896       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[5] - fStart)*4 + GetQuadEdge_Static(ornt[5], 3);
6897       orntNew[1] = 0;
6898       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 5;
6899       orntNew[2] = 0;
6900       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 0;
6901       orntNew[3] = -2;
6902       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6903       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
6904 #if defined(PETSC_USE_DEBUG)
6905       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
6906       for (p = 0; p < 4; ++p) {
6907         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);
6908       }
6909 #endif
6910       /* E-F face */
6911       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 4;
6912       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 2;
6913       orntNew[0] = -2;
6914       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*4 + GetQuadEdge_Static(ornt[2], 2);
6915       orntNew[1] = -2;
6916       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*4 + GetQuadEdge_Static(ornt[1], 0);
6917       orntNew[2] = 0;
6918       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 1;
6919       orntNew[3] = 0;
6920       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6921       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
6922 #if defined(PETSC_USE_DEBUG)
6923       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
6924       for (p = 0; p < 4; ++p) {
6925         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);
6926       }
6927 #endif
6928       /* F-G face */
6929       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 5;
6930       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 4;
6931       orntNew[0] = -2;
6932       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[4] - fStart)*4 + GetQuadEdge_Static(ornt[4], 2);
6933       orntNew[1] = -2;
6934       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*4 + GetQuadEdge_Static(ornt[1], 1);
6935       orntNew[2] = 0;
6936       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 1;
6937       orntNew[3] = 0;
6938       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6939       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
6940 #if defined(PETSC_USE_DEBUG)
6941       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
6942       for (p = 0; p < 4; ++p) {
6943         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);
6944       }
6945 #endif
6946       /* G-H face */
6947       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 6;
6948       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*4 + GetQuadEdge_Static(ornt[3], 2);
6949       orntNew[0] = -2;
6950       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*4 + GetQuadEdge_Static(ornt[1], 2);
6951       orntNew[1] = 0;
6952       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 1;
6953       orntNew[2] = 0;
6954       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 3;
6955       orntNew[3] = -2;
6956       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6957       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
6958 #if defined(PETSC_USE_DEBUG)
6959       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
6960       for (p = 0; p < 4; ++p) {
6961         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);
6962       }
6963 #endif
6964       /* E-H face */
6965       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 7;
6966       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 5;
6967       orntNew[0] = -2;
6968       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[5] - fStart)*4 + GetQuadEdge_Static(ornt[5], 1);
6969       orntNew[1] = -2;
6970       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*4 + GetQuadEdge_Static(ornt[1], 3);
6971       orntNew[2] = 0;
6972       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 1;
6973       orntNew[3] = 0;
6974       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6975       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
6976 #if defined(PETSC_USE_DEBUG)
6977       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
6978       for (p = 0; p < 4; ++p) {
6979         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);
6980       }
6981 #endif
6982       /* A-E face */
6983       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 8;
6984       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*4 + GetQuadEdge_Static(ornt[2], 3);
6985       orntNew[0] = 0;
6986       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 2;
6987       orntNew[1] = 0;
6988       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 5;
6989       orntNew[2] = -2;
6990       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (cone[5] - fStart)*4 + GetQuadEdge_Static(ornt[5], 0);
6991       orntNew[3] = -2;
6992       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6993       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
6994 #if defined(PETSC_USE_DEBUG)
6995       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
6996       for (p = 0; p < 4; ++p) {
6997         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);
6998       }
6999 #endif
7000       /* D-F face */
7001       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 9;
7002       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*4 + GetQuadEdge_Static(ornt[2], 1);
7003       orntNew[0] = -2;
7004       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[4] - fStart)*4 + GetQuadEdge_Static(ornt[4], 3);
7005       orntNew[1] = 0;
7006       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 4;
7007       orntNew[2] = 0;
7008       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 2;
7009       orntNew[3] = -2;
7010       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
7011       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
7012 #if defined(PETSC_USE_DEBUG)
7013       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
7014       for (p = 0; p < 4; ++p) {
7015         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);
7016       }
7017 #endif
7018       /* C-G face */
7019       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 10;
7020       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 4;
7021       orntNew[0] = -2;
7022       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[4] - fStart)*4 + GetQuadEdge_Static(ornt[4], 1);
7023       orntNew[1] = -2;
7024       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*4 + GetQuadEdge_Static(ornt[3], 3);
7025       orntNew[2] = 0;
7026       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 3;
7027       orntNew[3] = 0;
7028       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
7029       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
7030 #if defined(PETSC_USE_DEBUG)
7031       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
7032       for (p = 0; p < 4; ++p) {
7033         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);
7034       }
7035 #endif
7036       /* B-H face */
7037       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 11;
7038       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 5;
7039       orntNew[0] = 0;
7040       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 3;
7041       orntNew[1] = -2;
7042       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*4 + GetQuadEdge_Static(ornt[3], 1);
7043       orntNew[2] = -2;
7044       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (cone[5] - fStart)*4 + GetQuadEdge_Static(ornt[5], 2);
7045       orntNew[3] = 0;
7046       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
7047       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
7048 #if defined(PETSC_USE_DEBUG)
7049       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
7050       for (p = 0; p < 4; ++p) {
7051         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);
7052       }
7053 #endif
7054       for (r = 0; r < 12; ++r) {
7055         newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + r;
7056         supportNew[0] = cStartNew + (c - cStart)*8 + newCells[r*2+0];
7057         supportNew[1] = cStartNew + (c - cStart)*8 + newCells[r*2+1];
7058         ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
7059 #if defined(PETSC_USE_DEBUG)
7060         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
7061         for (p = 0; p < 2; ++p) {
7062           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);
7063         }
7064 #endif
7065       }
7066     }
7067     /* Split edges have 2 vertices and the same faces as the parent */
7068     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
7069     for (e = eStart; e < eEnd; ++e) {
7070       const PetscInt newv = vStartNew + (vEnd - vStart) + (e - eStart);
7071 
7072       for (r = 0; r < 2; ++r) {
7073         const PetscInt  newp = eStartNew + (e - eStart)*2 + r;
7074         const PetscInt *cone, *ornt, *support;
7075         PetscInt        coneNew[2], coneSize, c, supportSize, s;
7076 
7077         ierr             = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
7078         coneNew[0]       = vStartNew + (cone[0] - vStart);
7079         coneNew[1]       = vStartNew + (cone[1] - vStart);
7080         coneNew[(r+1)%2] = newv;
7081         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
7082 #if defined(PETSC_USE_DEBUG)
7083         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eEndNew);
7084         for (p = 0; p < 2; ++p) {
7085           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);
7086         }
7087 #endif
7088         ierr = DMPlexGetSupportSize(dm, e, &supportSize);CHKERRQ(ierr);
7089         ierr = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
7090         for (s = 0; s < supportSize; ++s) {
7091           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
7092           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
7093           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
7094           for (c = 0; c < coneSize; ++c) {
7095             if (cone[c] == e) break;
7096           }
7097           supportRef[s] = fStartNew + (support[s] - fStart)*4 + (ornt[c] < 0 ? (c+1-r)%4 : (c+r)%4);
7098         }
7099         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
7100 #if defined(PETSC_USE_DEBUG)
7101         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eEndNew);
7102         for (p = 0; p < supportSize; ++p) {
7103           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);
7104         }
7105 #endif
7106       }
7107     }
7108     /* Face edges have 2 vertices and 2+cells faces */
7109     for (f = fStart; f < fEnd; ++f) {
7110       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};
7111       const PetscInt  newv = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (f - fStart);
7112       const PetscInt *cone, *coneCell, *orntCell, *support;
7113       PetscInt        coneNew[2], coneSize, c, supportSize, s;
7114 
7115       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
7116       for (r = 0; r < 4; ++r) {
7117         const PetscInt newp = eStartNew + (eEnd - eStart)*2 + (f - fStart)*4 + r;
7118 
7119         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r] - eStart);
7120         coneNew[1] = newv;
7121         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
7122 #if defined(PETSC_USE_DEBUG)
7123         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eEndNew);
7124         for (p = 0; p < 2; ++p) {
7125           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);
7126         }
7127 #endif
7128         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
7129         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
7130         supportRef[0] = fStartNew + (f - fStart)*4 + r;
7131         supportRef[1] = fStartNew + (f - fStart)*4 + (r+1)%4;
7132         for (s = 0; s < supportSize; ++s) {
7133           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
7134           ierr = DMPlexGetCone(dm, support[s], &coneCell);CHKERRQ(ierr);
7135           ierr = DMPlexGetConeOrientation(dm, support[s], &orntCell);CHKERRQ(ierr);
7136           for (c = 0; c < coneSize; ++c) if (coneCell[c] == f) break;
7137           supportRef[2+s] = fStartNew + (fEnd - fStart)*4 + (support[s] - cStart)*12 + newFaces[c*4 + GetQuadEdgeInverse_Static(orntCell[c], r)];
7138         }
7139         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
7140 #if defined(PETSC_USE_DEBUG)
7141         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eEndNew);
7142         for (p = 0; p < 2+supportSize; ++p) {
7143           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);
7144         }
7145 #endif
7146       }
7147     }
7148     /* Cell edges have 2 vertices and 4 faces */
7149     for (c = cStart; c < cEnd; ++c) {
7150       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};
7151       const PetscInt  newv = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (fEnd - fStart) + (c - cStart);
7152       const PetscInt *cone;
7153       PetscInt        coneNew[2], supportNew[4];
7154 
7155       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
7156       for (r = 0; r < 6; ++r) {
7157         const PetscInt newp = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*4 + (c - cStart)*6 + r;
7158 
7159         coneNew[0] = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (cone[r] - fStart);
7160         coneNew[1] = newv;
7161         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
7162 #if defined(PETSC_USE_DEBUG)
7163         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eEndNew);
7164         for (p = 0; p < 2; ++p) {
7165           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);
7166         }
7167 #endif
7168         for (f = 0; f < 4; ++f) supportNew[f] = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + newFaces[r*4+f];
7169         ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
7170 #if defined(PETSC_USE_DEBUG)
7171         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eEndNew);
7172         for (p = 0; p < 4; ++p) {
7173           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);
7174         }
7175 #endif
7176       }
7177     }
7178     /* Old vertices have identical supports */
7179     for (v = vStart; v < vEnd; ++v) {
7180       const PetscInt  newp = vStartNew + (v - vStart);
7181       const PetscInt *support, *cone;
7182       PetscInt        size, s;
7183 
7184       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
7185       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
7186       for (s = 0; s < size; ++s) {
7187         PetscInt r = 0;
7188 
7189         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
7190         if (cone[1] == v) r = 1;
7191         supportRef[s] = eStartNew + (support[s] - eStart)*2 + r;
7192       }
7193       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
7194 #if defined(PETSC_USE_DEBUG)
7195       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", newp, vStartNew, vEndNew);
7196       for (p = 0; p < size; ++p) {
7197         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);
7198       }
7199 #endif
7200     }
7201     /* Edge vertices have 2 + faces supports */
7202     for (e = eStart; e < eEnd; ++e) {
7203       const PetscInt  newp = vStartNew + (vEnd - vStart) + (e - eStart);
7204       const PetscInt *cone, *support;
7205       PetscInt        size, s;
7206 
7207       ierr          = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
7208       ierr          = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
7209       supportRef[0] = eStartNew + (e - eStart)*2 + 0;
7210       supportRef[1] = eStartNew + (e - eStart)*2 + 1;
7211       for (s = 0; s < size; ++s) {
7212         PetscInt r;
7213 
7214         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
7215         for (r = 0; r < 4; ++r) if (cone[r] == e) break;
7216         supportRef[2+s] = eStartNew + (eEnd - eStart)*2 + (support[s] - fStart)*4 + r;
7217       }
7218       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
7219 #if defined(PETSC_USE_DEBUG)
7220       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", newp, vStartNew, vEndNew);
7221       for (p = 0; p < 2+size; ++p) {
7222         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);
7223       }
7224 #endif
7225     }
7226     /* Face vertices have 4 + cells supports */
7227     for (f = fStart; f < fEnd; ++f) {
7228       const PetscInt  newp = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (f - fStart);
7229       const PetscInt *cone, *support;
7230       PetscInt        size, s;
7231 
7232       ierr          = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
7233       ierr          = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
7234       for (r = 0; r < 4; ++r) supportRef[r] = eStartNew + (eEnd - eStart)*2 +  (f - fStart)*4 + r;
7235       for (s = 0; s < size; ++s) {
7236         PetscInt r;
7237 
7238         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
7239         for (r = 0; r < 6; ++r) if (cone[r] == f) break;
7240         supportRef[4+s] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*4 + (support[s] - cStart)*6 + r;
7241       }
7242       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
7243 #if defined(PETSC_USE_DEBUG)
7244       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", newp, vStartNew, vEndNew);
7245       for (p = 0; p < 4+size; ++p) {
7246         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);
7247       }
7248 #endif
7249     }
7250     /* Cell vertices have 6 supports */
7251     for (c = cStart; c < cEnd; ++c) {
7252       const PetscInt newp = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (fEnd - fStart) + (c - cStart);
7253       PetscInt       supportNew[6];
7254 
7255       for (r = 0; r < 6; ++r) {
7256         supportNew[r] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*4 + (c - cStart)*6 + r;
7257       }
7258       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
7259     }
7260     ierr = PetscFree(supportRef);CHKERRQ(ierr);
7261     break;
7262   case REFINER_HYBRID_HEX_3D:
7263     ierr = DMPlexGetHybridBounds(rdm, &cMaxNew, &fMaxNew, &eMaxNew, NULL);CHKERRQ(ierr);
7264     /*
7265      Bottom (viewed from top)    Top
7266      1---------2---------2       7---------2---------6
7267      |         |         |       |         |         |
7268      |    B    2    C    |       |    H    2    G    |
7269      |         |         |       |         |         |
7270      3----3----0----1----1       3----3----0----1----1
7271      |         |         |       |         |         |
7272      |    A    0    D    |       |    E    0    F    |
7273      |         |         |       |         |         |
7274      0---------0---------3       4---------0---------5
7275      */
7276     /* Interior cells have 6 faces: Bottom, Top, Front, Back, Right, Left */
7277     for (c = cStart; c < cMax; ++c) {
7278       const PetscInt  newp = (c - cStart)*8;
7279       const PetscInt *cone, *ornt;
7280       PetscInt        coneNew[6], orntNew[6];
7281 
7282       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
7283       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
7284       /* A hex */
7285       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], 0);
7286       orntNew[0] = ornt[0];
7287       coneNew[1] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  8; /* AE */
7288       orntNew[1] = 0;
7289       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetQuadSubface_Static(ornt[2], 0);
7290       orntNew[2] = ornt[2];
7291       coneNew[3] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  3; /* AB */
7292       orntNew[3] = 0;
7293       coneNew[4] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  0; /* AD */
7294       orntNew[4] = 0;
7295       coneNew[5] = fStartNew + (cone[5] - fStart)*4 + GetQuadSubface_Static(ornt[5], 0);
7296       orntNew[5] = ornt[5];
7297       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
7298       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
7299 #if defined(PETSC_USE_DEBUG)
7300       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);
7301       for (p = 0; p < 6; ++p) {
7302         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);
7303       }
7304 #endif
7305       /* B hex */
7306       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], 1);
7307       orntNew[0] = ornt[0];
7308       coneNew[1] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 + 11; /* BH */
7309       orntNew[1] = 0;
7310       coneNew[2] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  3; /* AB */
7311       orntNew[2] = -1;
7312       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetQuadSubface_Static(ornt[3], 1);
7313       orntNew[3] = ornt[3];
7314       coneNew[4] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  2; /* BC */
7315       orntNew[4] = 0;
7316       coneNew[5] = fStartNew + (cone[5] - fStart)*4 + GetQuadSubface_Static(ornt[5], 3);
7317       orntNew[5] = ornt[5];
7318       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
7319       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
7320 #if defined(PETSC_USE_DEBUG)
7321       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);
7322       for (p = 0; p < 6; ++p) {
7323         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);
7324       }
7325 #endif
7326       /* C hex */
7327       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], 2);
7328       orntNew[0] = ornt[0];
7329       coneNew[1] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 + 10; /* CG */
7330       orntNew[1] = 0;
7331       coneNew[2] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  1; /* CD */
7332       orntNew[2] = -1;
7333       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetQuadSubface_Static(ornt[3], 0);
7334       orntNew[3] = ornt[3];
7335       coneNew[4] = fStartNew + (cone[4] - fStart)*4 + GetQuadSubface_Static(ornt[4], 1);
7336       orntNew[4] = ornt[4];
7337       coneNew[5] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  2; /* BC */
7338       orntNew[5] = -4;
7339       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
7340       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
7341 #if defined(PETSC_USE_DEBUG)
7342       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);
7343       for (p = 0; p < 6; ++p) {
7344         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);
7345       }
7346 #endif
7347       /* D hex */
7348       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], 3);
7349       orntNew[0] = ornt[0];
7350       coneNew[1] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  9; /* DF */
7351       orntNew[1] = 0;
7352       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetQuadSubface_Static(ornt[2], 1);
7353       orntNew[2] = ornt[2];
7354       coneNew[3] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  1; /* CD */
7355       orntNew[3] = 0;
7356       coneNew[4] = fStartNew + (cone[4] - fStart)*4 + GetQuadSubface_Static(ornt[4], 0);
7357       orntNew[4] = ornt[4];
7358       coneNew[5] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  0; /* AD */
7359       orntNew[5] = -4;
7360       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
7361       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
7362 #if defined(PETSC_USE_DEBUG)
7363       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);
7364       for (p = 0; p < 6; ++p) {
7365         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);
7366       }
7367 #endif
7368       /* E hex */
7369       coneNew[0] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  8; /* AE */
7370       orntNew[0] = -4;
7371       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], 0);
7372       orntNew[1] = ornt[1];
7373       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetQuadSubface_Static(ornt[2], 3);
7374       orntNew[2] = ornt[2];
7375       coneNew[3] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  7; /* EH */
7376       orntNew[3] = 0;
7377       coneNew[4] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  4; /* EF */
7378       orntNew[4] = -1;
7379       coneNew[5] = fStartNew + (cone[5] - fStart)*4 + GetQuadSubface_Static(ornt[5], 1);
7380       orntNew[5] = ornt[5];
7381       ierr       = DMPlexSetCone(rdm, newp+4, coneNew);CHKERRQ(ierr);
7382       ierr       = DMPlexSetConeOrientation(rdm, newp+4, orntNew);CHKERRQ(ierr);
7383 #if defined(PETSC_USE_DEBUG)
7384       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);
7385       for (p = 0; p < 6; ++p) {
7386         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);
7387       }
7388 #endif
7389       /* F hex */
7390       coneNew[0] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  9; /* DF */
7391       orntNew[0] = -4;
7392       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], 1);
7393       orntNew[1] = ornt[1];
7394       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetQuadSubface_Static(ornt[2], 2);
7395       orntNew[2] = ornt[2];
7396       coneNew[3] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  5; /* FG */
7397       orntNew[3] = -1;
7398       coneNew[4] = fStartNew + (cone[4] - fStart)*4 + GetQuadSubface_Static(ornt[4], 3);
7399       orntNew[4] = ornt[4];
7400       coneNew[5] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  4; /* EF */
7401       orntNew[5] = 1;
7402       ierr       = DMPlexSetCone(rdm, newp+5, coneNew);CHKERRQ(ierr);
7403       ierr       = DMPlexSetConeOrientation(rdm, newp+5, orntNew);CHKERRQ(ierr);
7404 #if defined(PETSC_USE_DEBUG)
7405       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);
7406       for (p = 0; p < 6; ++p) {
7407         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);
7408       }
7409 #endif
7410       /* G hex */
7411       coneNew[0] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 + 10; /* CG */
7412       orntNew[0] = -4;
7413       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], 2);
7414       orntNew[1] = ornt[1];
7415       coneNew[2] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  5; /* FG */
7416       orntNew[2] = 0;
7417       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetQuadSubface_Static(ornt[3], 3);
7418       orntNew[3] = ornt[3];
7419       coneNew[4] = fStartNew + (cone[4] - fStart)*4 + GetQuadSubface_Static(ornt[4], 2);
7420       orntNew[4] = ornt[4];
7421       coneNew[5] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  6; /* GH */
7422       orntNew[5] = -3;
7423       ierr       = DMPlexSetCone(rdm, newp+6, coneNew);CHKERRQ(ierr);
7424       ierr       = DMPlexSetConeOrientation(rdm, newp+6, orntNew);CHKERRQ(ierr);
7425 #if defined(PETSC_USE_DEBUG)
7426       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);
7427       for (p = 0; p < 6; ++p) {
7428         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);
7429       }
7430 #endif
7431       /* H hex */
7432       coneNew[0] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 + 11; /* BH */
7433       orntNew[0] = -4;
7434       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], 3);
7435       orntNew[1] = ornt[1];
7436       coneNew[2] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  7; /* EH */
7437       orntNew[2] = -1;
7438       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetQuadSubface_Static(ornt[3], 2);
7439       orntNew[3] = ornt[3];
7440       coneNew[4] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  6; /* GH */
7441       orntNew[4] = 3;
7442       coneNew[5] = fStartNew + (cone[5] - fStart)*4 + GetQuadSubface_Static(ornt[5], 2);
7443       orntNew[5] = ornt[5];
7444       ierr       = DMPlexSetCone(rdm, newp+7, coneNew);CHKERRQ(ierr);
7445       ierr       = DMPlexSetConeOrientation(rdm, newp+7, orntNew);CHKERRQ(ierr);
7446 #if defined(PETSC_USE_DEBUG)
7447       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);
7448       for (p = 0; p < 6; ++p) {
7449         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);
7450       }
7451 #endif
7452     }
7453     /* Hybrid cells have 6 faces: Front, Back, Sides */
7454     /*
7455      3---------2---------2
7456      |         |         |
7457      |    D    2    C    |
7458      |         |         |
7459      3----3----0----1----1
7460      |         |         |
7461      |    A    0    B    |
7462      |         |         |
7463      0---------0---------1
7464      */
7465     for (c = cMax; c < cEnd; ++c) {
7466       const PetscInt  newp = (cMax - cStart)*8 + (c - cMax)*4;
7467       const PetscInt *cone, *ornt, *fornt;
7468       PetscInt        coneNew[6], orntNew[6], o, of, i;
7469 
7470       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
7471       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
7472       ierr = DMPlexGetConeOrientation(dm, cone[0], &fornt);CHKERRQ(ierr);
7473       o = ornt[0] < 0 ? -1 : 1;
7474       for (r = 0; r < 4; ++r) {
7475         PetscInt subfA = GetQuadSubface_Static(ornt[0], r);
7476         PetscInt edgeA = GetQuadEdge_Static(ornt[0], r);
7477         PetscInt edgeB = GetQuadEdge_Static(ornt[0], (r+3)%4);
7478         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]);
7479         coneNew[0]         = fStartNew + (cone[0] - fStart)*4 + subfA;
7480         orntNew[0]         = ornt[0];
7481         coneNew[1]         = fStartNew + (cone[1] - fStart)*4 + subfA;
7482         orntNew[1]         = ornt[0];
7483         of = fornt[edgeA] < 0 ? -1 : 1;
7484         i  = GetQuadEdgeInverse_Static(ornt[0], r) + 2;
7485         coneNew[i] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (cone[2+edgeA] - fMax)*2 + (o*of < 0 ? 1 : 0);
7486         orntNew[i] = ornt[edgeA];
7487         i  = GetQuadEdgeInverse_Static(ornt[0], (r+1)%4) + 2;
7488         coneNew[i] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd          - fMax)*2 + (c - cMax)*4 + edgeA;
7489         orntNew[i] = 0;
7490         i  = GetQuadEdgeInverse_Static(ornt[0], (r+2)%4) + 2;
7491         coneNew[i] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd          - fMax)*2 + (c - cMax)*4 + edgeB;
7492         orntNew[i] = -2;
7493         of = fornt[edgeB] < 0 ? -1 : 1;
7494         i  = GetQuadEdgeInverse_Static(ornt[0], (r+3)%4) + 2;
7495         coneNew[i] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (cone[2+edgeB] - fMax)*2 + (o*of < 0 ? 0 : 1);
7496         orntNew[i] = ornt[edgeB];
7497         ierr       = DMPlexSetCone(rdm, newp+r, coneNew);CHKERRQ(ierr);
7498         ierr       = DMPlexSetConeOrientation(rdm, newp+r, orntNew);CHKERRQ(ierr);
7499 #if defined(PETSC_USE_DEBUG)
7500         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);
7501         for (p = 0; p < 2; ++p) {
7502           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);
7503         }
7504         for (p = 2; p < 6; ++p) {
7505           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);
7506         }
7507 #endif
7508       }
7509     }
7510     /* Interior split faces have 4 edges and the same cells as the parent */
7511     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
7512     ierr = PetscMalloc1(4 + maxSupportSize*2, &supportRef);CHKERRQ(ierr);
7513     for (f = fStart; f < fMax; ++f) {
7514       for (r = 0; r < 4; ++r) {
7515         /* TODO: This can come from GetFaces_Internal() */
7516         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};
7517         const PetscInt  newp = fStartNew + (f - fStart)*4 + r;
7518         const PetscInt *cone, *ornt, *support;
7519         PetscInt        coneNew[4], orntNew[4], coneSize, c, supportSize, s;
7520 
7521         ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
7522         ierr = DMPlexGetConeOrientation(dm, f, &ornt);CHKERRQ(ierr);
7523         coneNew[(r+3)%4] = eStartNew + (cone[(r+3)%4] - eStart)*2 + (ornt[(r+3)%4] < 0 ? 0 : 1);
7524         orntNew[(r+3)%4] = ornt[(r+3)%4];
7525         coneNew[(r+0)%4] = eStartNew + (cone[r]       - eStart)*2 + (ornt[r] < 0 ? 1 : 0);
7526         orntNew[(r+0)%4] = ornt[r];
7527         coneNew[(r+1)%4] = eStartNew + (eMax - eStart)*2 + (f - fStart)*4 + r;
7528         orntNew[(r+1)%4] = 0;
7529         coneNew[(r+2)%4] = eStartNew + (eMax - eStart)*2 + (f - fStart)*4 + (r+3)%4;
7530         orntNew[(r+2)%4] = -2;
7531         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
7532         ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
7533 #if defined(PETSC_USE_DEBUG)
7534         if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fMaxNew);
7535         for (p = 0; p < 4; ++p) {
7536           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);
7537         }
7538 #endif
7539         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
7540         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
7541         for (s = 0; s < supportSize; ++s) {
7542           PetscInt subf;
7543           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
7544           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
7545           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
7546           for (c = 0; c < coneSize; ++c) {
7547             if (cone[c] == f) break;
7548           }
7549           subf = GetQuadSubfaceInverse_Static(ornt[c], r);
7550           if (support[s] < cMax) {
7551             supportRef[s] = cStartNew + (support[s] - cStart)*8 + newCells[c*4+subf];
7552           } else {
7553             supportRef[s] = cStartNew + (cMax       - cStart)*8 + (support[s] - cMax)*4 + subf;
7554           }
7555         }
7556         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
7557 #if defined(PETSC_USE_DEBUG)
7558         if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fMaxNew);
7559         for (p = 0; p < supportSize; ++p) {
7560           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);
7561         }
7562 #endif
7563       }
7564     }
7565     /* Interior cell faces have 4 edges and 2 cells */
7566     for (c = cStart; c < cMax; ++c) {
7567       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};
7568       const PetscInt *cone, *ornt;
7569       PetscInt        newp, coneNew[4], orntNew[4], supportNew[2];
7570 
7571       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
7572       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
7573       /* A-D face */
7574       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 0;
7575       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*4 + GetQuadEdge_Static(ornt[0], 3);
7576       orntNew[0] = 0;
7577       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 0;
7578       orntNew[1] = 0;
7579       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 2;
7580       orntNew[2] = -2;
7581       coneNew[3] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*4 + GetQuadEdge_Static(ornt[2], 0);
7582       orntNew[3] = -2;
7583       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
7584       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
7585 #if defined(PETSC_USE_DEBUG)
7586       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fMaxNew);
7587       for (p = 0; p < 4; ++p) {
7588         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);
7589       }
7590 #endif
7591       /* C-D face */
7592       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 1;
7593       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*4 + GetQuadEdge_Static(ornt[0], 2);
7594       orntNew[0] = 0;
7595       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 0;
7596       orntNew[1] = 0;
7597       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 4;
7598       orntNew[2] = -2;
7599       coneNew[3] = eStartNew + (eMax - eStart)*2 + (cone[4] - fStart)*4 + GetQuadEdge_Static(ornt[4], 0);
7600       orntNew[3] = -2;
7601       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
7602       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
7603 #if defined(PETSC_USE_DEBUG)
7604       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fMaxNew);
7605       for (p = 0; p < 4; ++p) {
7606         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);
7607       }
7608 #endif
7609       /* B-C face */
7610       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 2;
7611       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*4 + GetQuadEdge_Static(ornt[0], 1);
7612       orntNew[0] = -2;
7613       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*4 + GetQuadEdge_Static(ornt[3], 0);
7614       orntNew[1] = 0;
7615       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 3;
7616       orntNew[2] = 0;
7617       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 0;
7618       orntNew[3] = -2;
7619       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
7620       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
7621 #if defined(PETSC_USE_DEBUG)
7622       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fMaxNew);
7623       for (p = 0; p < 4; ++p) {
7624         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);
7625       }
7626 #endif
7627       /* A-B face */
7628       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 3;
7629       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*4 + GetQuadEdge_Static(ornt[0], 0);
7630       orntNew[0] = -2;
7631       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[5] - fStart)*4 + GetQuadEdge_Static(ornt[5], 3);
7632       orntNew[1] = 0;
7633       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 5;
7634       orntNew[2] = 0;
7635       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 0;
7636       orntNew[3] = -2;
7637       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
7638       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
7639 #if defined(PETSC_USE_DEBUG)
7640       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fMaxNew);
7641       for (p = 0; p < 4; ++p) {
7642         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);
7643       }
7644 #endif
7645       /* E-F face */
7646       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 4;
7647       coneNew[0] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 2;
7648       orntNew[0] = -2;
7649       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*4 + GetQuadEdge_Static(ornt[2], 2);
7650       orntNew[1] = -2;
7651       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*4 + GetQuadEdge_Static(ornt[1], 0);
7652       orntNew[2] = 0;
7653       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 1;
7654       orntNew[3] = 0;
7655       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
7656       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
7657 #if defined(PETSC_USE_DEBUG)
7658       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fMaxNew);
7659       for (p = 0; p < 4; ++p) {
7660         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);
7661       }
7662 #endif
7663       /* F-G face */
7664       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 5;
7665       coneNew[0] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 4;
7666       orntNew[0] = -2;
7667       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[4] - fStart)*4 + GetQuadEdge_Static(ornt[4], 2);
7668       orntNew[1] = -2;
7669       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*4 + GetQuadEdge_Static(ornt[1], 1);
7670       orntNew[2] = 0;
7671       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 1;
7672       orntNew[3] = 0;
7673       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
7674       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
7675 #if defined(PETSC_USE_DEBUG)
7676       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fMaxNew);
7677       for (p = 0; p < 4; ++p) {
7678         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);
7679       }
7680 #endif
7681       /* G-H face */
7682       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 6;
7683       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*4 + GetQuadEdge_Static(ornt[3], 2);
7684       orntNew[0] = -2;
7685       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*4 + GetQuadEdge_Static(ornt[1], 2);
7686       orntNew[1] = 0;
7687       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 1;
7688       orntNew[2] = 0;
7689       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 3;
7690       orntNew[3] = -2;
7691       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
7692       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
7693 #if defined(PETSC_USE_DEBUG)
7694       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fMaxNew);
7695       for (p = 0; p < 4; ++p) {
7696         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);
7697       }
7698 #endif
7699       /* E-H face */
7700       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 7;
7701       coneNew[0] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 5;
7702       orntNew[0] = -2;
7703       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[5] - fStart)*4 + GetQuadEdge_Static(ornt[5], 1);
7704       orntNew[1] = -2;
7705       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*4 + GetQuadEdge_Static(ornt[1], 3);
7706       orntNew[2] = 0;
7707       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 1;
7708       orntNew[3] = 0;
7709       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
7710       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
7711 #if defined(PETSC_USE_DEBUG)
7712       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fMaxNew);
7713       for (p = 0; p < 4; ++p) {
7714         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);
7715       }
7716 #endif
7717       /* A-E face */
7718       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 8;
7719       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*4 + GetQuadEdge_Static(ornt[2], 3);
7720       orntNew[0] = 0;
7721       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 2;
7722       orntNew[1] = 0;
7723       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 5;
7724       orntNew[2] = -2;
7725       coneNew[3] = eStartNew + (eMax - eStart)*2 + (cone[5] - fStart)*4 + GetQuadEdge_Static(ornt[5], 0);
7726       orntNew[3] = -2;
7727       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
7728       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
7729 #if defined(PETSC_USE_DEBUG)
7730       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fMaxNew);
7731       for (p = 0; p < 4; ++p) {
7732         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);
7733       }
7734 #endif
7735       /* D-F face */
7736       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 9;
7737       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*4 + GetQuadEdge_Static(ornt[2], 1);
7738       orntNew[0] = -2;
7739       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[4] - fStart)*4 + GetQuadEdge_Static(ornt[4], 3);
7740       orntNew[1] = 0;
7741       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 4;
7742       orntNew[2] = 0;
7743       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 2;
7744       orntNew[3] = -2;
7745       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
7746       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
7747 #if defined(PETSC_USE_DEBUG)
7748       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fMaxNew);
7749       for (p = 0; p < 4; ++p) {
7750         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);
7751       }
7752 #endif
7753       /* C-G face */
7754       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 10;
7755       coneNew[0] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 4;
7756       orntNew[0] = -2;
7757       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[4] - fStart)*4 + GetQuadEdge_Static(ornt[4], 1);
7758       orntNew[1] = -2;
7759       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*4 + GetQuadEdge_Static(ornt[3], 3);
7760       orntNew[2] = 0;
7761       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 3;
7762       orntNew[3] = 0;
7763       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
7764       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
7765 #if defined(PETSC_USE_DEBUG)
7766       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fMaxNew);
7767       for (p = 0; p < 4; ++p) {
7768         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);
7769       }
7770 #endif
7771       /* B-H face */
7772       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 11;
7773       coneNew[0] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 5;
7774       orntNew[0] = 0;
7775       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 3;
7776       orntNew[1] = -2;
7777       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*4 + GetQuadEdge_Static(ornt[3], 1);
7778       orntNew[2] = -2;
7779       coneNew[3] = eStartNew + (eMax - eStart)*2 + (cone[5] - fStart)*4 + GetQuadEdge_Static(ornt[5], 2);
7780       orntNew[3] = 0;
7781       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
7782       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
7783 #if defined(PETSC_USE_DEBUG)
7784       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fMaxNew);
7785       for (p = 0; p < 4; ++p) {
7786         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);
7787       }
7788 #endif
7789       for (r = 0; r < 12; ++r) {
7790         newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + r;
7791         supportNew[0] = cStartNew + (c - cStart)*8 + newCells[r*2+0];
7792         supportNew[1] = cStartNew + (c - cStart)*8 + newCells[r*2+1];
7793         ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
7794 #if defined(PETSC_USE_DEBUG)
7795         if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fMaxNew);
7796         for (p = 0; p < 2; ++p) {
7797           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);
7798         }
7799 #endif
7800       }
7801     }
7802     /* Hybrid split faces have 4 edges and same cells */
7803     for (f = fMax; f < fEnd; ++f) {
7804       const PetscInt *cone, *ornt, *support;
7805       PetscInt        coneNew[4], orntNew[4];
7806       PetscInt        supportNew[2], size, s, c;
7807 
7808       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
7809       ierr = DMPlexGetConeOrientation(dm, f, &ornt);CHKERRQ(ierr);
7810       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
7811       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
7812       for (r = 0; r < 2; ++r) {
7813         const PetscInt newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (f - fMax)*2 + r;
7814 
7815         coneNew[0]   = eStartNew + (cone[0] - eStart)*2 + (ornt[0] < 0 ? 1-r : r);
7816         orntNew[0]   = ornt[0];
7817         coneNew[1]   = eStartNew + (cone[1] - eStart)*2 + (ornt[1] < 0 ? 1-r : r);
7818         orntNew[1]   = ornt[1];
7819         coneNew[2+r] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (cone[2+r] - eMax);
7820         orntNew[2+r] = 0;
7821         coneNew[3-r] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (eEnd      - eMax) + (f - fMax);
7822         orntNew[3-r] = 0;
7823         ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
7824         ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
7825 #if defined(PETSC_USE_DEBUG)
7826         if ((newp < fMaxNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a hybrid face [%D, %D)", newp, fMaxNew, fEndNew);
7827         for (p = 0; p < 2; ++p) {
7828           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);
7829         }
7830         for (p = 2; p < 4; ++p) {
7831           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);
7832         }
7833 #endif
7834         for (s = 0; s < size; ++s) {
7835           const PetscInt *coneCell, *orntCell, *fornt;
7836           PetscInt        o, of;
7837 
7838           ierr = DMPlexGetCone(dm, support[s], &coneCell);CHKERRQ(ierr);
7839           ierr = DMPlexGetConeOrientation(dm, support[s], &orntCell);CHKERRQ(ierr);
7840           o = orntCell[0] < 0 ? -1 : 1;
7841           for (c = 2; c < 6; ++c) if (coneCell[c] == f) break;
7842           if (c >= 6) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Could not find face %D in cone of cell %D", f, support[s]);
7843           ierr = DMPlexGetConeOrientation(dm, coneCell[0], &fornt);CHKERRQ(ierr);
7844           of = fornt[c-2] < 0 ? -1 : 1;
7845           supportNew[s] = cStartNew + (cMax - cStart)*8 + (support[s] - cMax)*4 + (GetQuadEdgeInverse_Static(orntCell[0], c-2) + (o*of < 0 ? 1-r : r))%4;
7846         }
7847         ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
7848 #if defined(PETSC_USE_DEBUG)
7849         if ((newp < fMaxNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a hybrid face [%D, %D)", newp, fMaxNew, fEndNew);
7850         for (p = 0; p < size; ++p) {
7851           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);
7852         }
7853 #endif
7854       }
7855     }
7856     /* Hybrid cell faces have 4 edges and 2 cells */
7857     for (c = cMax; c < cEnd; ++c) {
7858       PetscInt        newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd - fMax)*2 + (c - cMax)*4;
7859       const PetscInt *cone, *ornt;
7860       PetscInt        coneNew[4], orntNew[4];
7861       PetscInt        supportNew[2];
7862 
7863       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
7864       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
7865       for (r = 0; r < 4; ++r) {
7866 #if 0
7867         coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], r);
7868         orntNew[0] = 0;
7869         coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], r);
7870         orntNew[1] = 0;
7871         coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (eEnd - eMax) + (cone[2+GetQuadEdge_Static(ornt[0], r)] - fMax);
7872         orntNew[2] = 0;
7873         coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (eEnd - eMax) + (fEnd                                   - fMax) + (c - cMax);
7874         orntNew[3] = 0;
7875 #else
7876         coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*4 + r;
7877         orntNew[0] = 0;
7878         coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*4 + r;
7879         orntNew[1] = 0;
7880         coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (eEnd - eMax) + (cone[2+r] - fMax);
7881         orntNew[2] = 0;
7882         coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (eEnd - eMax) + (fEnd      - fMax) + (c - cMax);
7883         orntNew[3] = 0;
7884 #endif
7885         ierr = DMPlexSetCone(rdm, newp+r, coneNew);CHKERRQ(ierr);
7886         ierr = DMPlexSetConeOrientation(rdm, newp+r, orntNew);CHKERRQ(ierr);
7887 #if defined(PETSC_USE_DEBUG)
7888         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);
7889         for (p = 0; p < 2; ++p) {
7890           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);
7891         }
7892         for (p = 2; p < 4; ++p) {
7893           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);
7894         }
7895 #endif
7896         supportNew[0] = cStartNew + (cMax - cStart)*8 + (c - cMax)*4 + GetQuadSubface_Static(ornt[0], r);
7897         supportNew[1] = cStartNew + (cMax - cStart)*8 + (c - cMax)*4 + GetQuadSubface_Static(ornt[0], (r+1)%4);
7898         ierr          = DMPlexSetSupport(rdm, newp+r, supportNew);CHKERRQ(ierr);
7899 #if defined(PETSC_USE_DEBUG)
7900         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);
7901         for (p = 0; p < 2; ++p) {
7902           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);
7903         }
7904 #endif
7905       }
7906     }
7907     /* Interior split edges have 2 vertices and the same faces as the parent */
7908     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
7909     for (e = eStart; e < eMax; ++e) {
7910       const PetscInt newv = vStartNew + (vEnd - vStart) + (e - eStart);
7911 
7912       for (r = 0; r < 2; ++r) {
7913         const PetscInt  newp = eStartNew + (e - eStart)*2 + r;
7914         const PetscInt *cone, *ornt, *support;
7915         PetscInt        coneNew[2], coneSize, c, supportSize, s;
7916 
7917         ierr             = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
7918         coneNew[0]       = vStartNew + (cone[0] - vStart);
7919         coneNew[1]       = vStartNew + (cone[1] - vStart);
7920         coneNew[(r+1)%2] = newv;
7921         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
7922 #if defined(PETSC_USE_DEBUG)
7923         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eMaxNew);
7924         for (p = 0; p < 2; ++p) {
7925           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);
7926         }
7927 #endif
7928         ierr = DMPlexGetSupportSize(dm, e, &supportSize);CHKERRQ(ierr);
7929         ierr = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
7930         for (s = 0; s < supportSize; ++s) {
7931           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
7932           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
7933           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
7934           for (c = 0; c < coneSize; ++c) {
7935             if (cone[c] == e) break;
7936           }
7937           if (support[s] < fMax) {
7938             supportRef[s] = fStartNew + (support[s] - fStart)*4 + (c + (ornt[c] < 0 ? 1-r : r))%4;
7939           } else {
7940             supportRef[s] = fStartNew + (fMax       - fStart)*4 + (cMax - cStart)*12 + (support[s] - fMax)*2 + (ornt[c] < 0 ? 1-r : r);
7941           }
7942         }
7943         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
7944 #if defined(PETSC_USE_DEBUG)
7945         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eMaxNew);
7946         for (p = 0; p < supportSize; ++p) {
7947           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);
7948         }
7949 #endif
7950       }
7951     }
7952     /* Interior face edges have 2 vertices and 2+cells faces */
7953     for (f = fStart; f < fMax; ++f) {
7954       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};
7955       const PetscInt  newv = vStartNew + (vEnd - vStart) + (eMax - eStart) + (f - fStart);
7956       const PetscInt *cone, *coneCell, *orntCell, *support;
7957       PetscInt        coneNew[2], coneSize, c, supportSize, s;
7958 
7959       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
7960       for (r = 0; r < 4; ++r) {
7961         const PetscInt newp = eStartNew + (eMax - eStart)*2 + (f - fStart)*4 + r;
7962 
7963         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r] - eStart);
7964         coneNew[1] = newv;
7965         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
7966 #if defined(PETSC_USE_DEBUG)
7967         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eMaxNew);
7968         for (p = 0; p < 2; ++p) {
7969           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);
7970         }
7971 #endif
7972         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
7973         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
7974         supportRef[0] = fStartNew + (f - fStart)*4 + r;
7975         supportRef[1] = fStartNew + (f - fStart)*4 + (r+1)%4;
7976         for (s = 0; s < supportSize; ++s) {
7977           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
7978           ierr = DMPlexGetCone(dm, support[s], &coneCell);CHKERRQ(ierr);
7979           ierr = DMPlexGetConeOrientation(dm, support[s], &orntCell);CHKERRQ(ierr);
7980           for (c = 0; c < coneSize; ++c) if (coneCell[c] == f) break;
7981           if (support[s] < cMax) {
7982             supportRef[2+s] = fStartNew + (fMax - fStart)*4 + (support[s] - cStart)*12 + newFaces[c*4 + GetQuadEdgeInverse_Static(orntCell[c], r)];
7983           } else {
7984             supportRef[2+s] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd - fMax)*2 + (support[s] - cMax)*4 + r;
7985           }
7986         }
7987         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
7988 #if defined(PETSC_USE_DEBUG)
7989         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eMaxNew);
7990         for (p = 0; p < 2+supportSize; ++p) {
7991           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);
7992         }
7993 #endif
7994       }
7995     }
7996     /* Interior cell edges have 2 vertices and 4 faces */
7997     for (c = cStart; c < cMax; ++c) {
7998       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};
7999       const PetscInt  newv = vStartNew + (vEnd - vStart) + (eMax - eStart) + (fMax - fStart) + (c - cStart);
8000       const PetscInt *cone;
8001       PetscInt        coneNew[2], supportNew[4];
8002 
8003       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
8004       for (r = 0; r < 6; ++r) {
8005         const PetscInt newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (c - cStart)*6 + r;
8006 
8007         coneNew[0] = vStartNew + (vEnd - vStart) + (eMax - eStart) + (cone[r] - fStart);
8008         coneNew[1] = newv;
8009         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
8010 #if defined(PETSC_USE_DEBUG)
8011         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eMaxNew);
8012         for (p = 0; p < 2; ++p) {
8013           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);
8014         }
8015 #endif
8016         for (f = 0; f < 4; ++f) supportNew[f] = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + newFaces[r*4+f];
8017         ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
8018 #if defined(PETSC_USE_DEBUG)
8019         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eMaxNew);
8020         for (p = 0; p < 4; ++p) {
8021           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);
8022         }
8023 #endif
8024       }
8025     }
8026     /* Hybrid edges have two vertices and the same faces */
8027     for (e = eMax; e < eEnd; ++e) {
8028       const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (e - eMax);
8029       const PetscInt *cone, *support, *fcone;
8030       PetscInt        coneNew[2], size, fsize, s;
8031 
8032       ierr = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
8033       ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
8034       ierr = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
8035       coneNew[0] = vStartNew + (cone[0] - vStart);
8036       coneNew[1] = vStartNew + (cone[1] - vStart);
8037       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
8038 #if defined(PETSC_USE_DEBUG)
8039       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a hybrid edge [%D, %D)", newp, eMaxNew, eEndNew);
8040       for (p = 0; p < 2; ++p) {
8041         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);
8042       }
8043 #endif
8044       for (s = 0; s < size; ++s) {
8045         ierr = DMPlexGetConeSize(dm, support[s], &fsize);CHKERRQ(ierr);
8046         ierr = DMPlexGetCone(dm, support[s], &fcone);CHKERRQ(ierr);
8047         for (c = 0; c < fsize; ++c) if (fcone[c] == e) break;
8048         if ((c < 2) || (c > 3)) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Edge %D not found in cone of face %D", e, support[s]);
8049         supportRef[s] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (support[s] - fMax)*2 + c-2;
8050       }
8051       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
8052 #if defined(PETSC_USE_DEBUG)
8053       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a hybrid edge [%D, %D)", newp, eMaxNew, eEndNew);
8054       for (p = 0; p < size; ++p) {
8055         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);
8056       }
8057 #endif
8058     }
8059     /* Hybrid face edges have 2 vertices and 2+cells faces */
8060     for (f = fMax; f < fEnd; ++f) {
8061       const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (eEnd - eMax) + (f - fMax);
8062       const PetscInt *cone, *support, *ccone, *cornt;
8063       PetscInt        coneNew[2], size, csize, s;
8064 
8065       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
8066       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
8067       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
8068       coneNew[0] = vStartNew + (vEnd - vStart) + (cone[0] - eStart);
8069       coneNew[1] = vStartNew + (vEnd - vStart) + (cone[1] - eStart);
8070       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
8071 #if defined(PETSC_USE_DEBUG)
8072       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a hybrid edge [%D, %D)", newp, eMaxNew, eEndNew);
8073       for (p = 0; p < 2; ++p) {
8074         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);
8075       }
8076 #endif
8077       supportRef[0] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (f - fMax)*2 + 0;
8078       supportRef[1] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (f - fMax)*2 + 1;
8079       for (s = 0; s < size; ++s) {
8080         ierr = DMPlexGetConeSize(dm, support[s], &csize);CHKERRQ(ierr);
8081         ierr = DMPlexGetCone(dm, support[s], &ccone);CHKERRQ(ierr);
8082         ierr = DMPlexGetConeOrientation(dm, support[s], &cornt);CHKERRQ(ierr);
8083         for (c = 0; c < csize; ++c) if (ccone[c] == f) break;
8084         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]);
8085         supportRef[2+s] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd - fMax)*2 + (support[s] - cMax)*4 + c-2;
8086       }
8087       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
8088 #if defined(PETSC_USE_DEBUG)
8089       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a hybrid edge [%D, %D)", newp, eMaxNew, eEndNew);
8090       for (p = 0; p < 2+size; ++p) {
8091         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);
8092       }
8093 #endif
8094     }
8095     /* Hybrid cell edges have 2 vertices and 4 faces */
8096     for (c = cMax; c < cEnd; ++c) {
8097       const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (eEnd - eMax) + (fEnd - fMax) + (c - cMax);
8098       const PetscInt *cone, *support;
8099       PetscInt        coneNew[2], size;
8100 
8101       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
8102       ierr = DMPlexGetSupportSize(dm, c, &size);CHKERRQ(ierr);
8103       ierr = DMPlexGetSupport(dm, c, &support);CHKERRQ(ierr);
8104       coneNew[0] = vStartNew + (vEnd - vStart) + (eMax - eStart) + (cone[0] - fStart);
8105       coneNew[1] = vStartNew + (vEnd - vStart) + (eMax - eStart) + (cone[1] - fStart);
8106       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
8107 #if defined(PETSC_USE_DEBUG)
8108       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a hybrid edge [%D, %D)", newp, eMaxNew, eEndNew);
8109       for (p = 0; p < 2; ++p) {
8110         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);
8111       }
8112 #endif
8113       supportRef[0] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd - fMax)*2 + (c - cMax)*4 + 0;
8114       supportRef[1] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd - fMax)*2 + (c - cMax)*4 + 1;
8115       supportRef[2] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd - fMax)*2 + (c - cMax)*4 + 2;
8116       supportRef[3] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd - fMax)*2 + (c - cMax)*4 + 3;
8117       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
8118 #if defined(PETSC_USE_DEBUG)
8119       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a hybrid edge [%D, %D)", newp, eMaxNew, eEndNew);
8120       for (p = 0; p < 4; ++p) {
8121         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);
8122       }
8123 #endif
8124     }
8125     /* Interior vertices have identical supports */
8126     for (v = vStart; v < vEnd; ++v) {
8127       const PetscInt  newp = vStartNew + (v - vStart);
8128       const PetscInt *support, *cone;
8129       PetscInt        size, s;
8130 
8131       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
8132       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
8133       for (s = 0; s < size; ++s) {
8134         PetscInt r = 0;
8135 
8136         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
8137         if (cone[1] == v) r = 1;
8138         if (support[s] < eMax) supportRef[s] = eStartNew + (support[s] - eStart)*2 + r;
8139         else                   supportRef[s] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (support[s] - eMax);
8140       }
8141       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
8142 #if defined(PETSC_USE_DEBUG)
8143       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", newp, vStartNew, vEndNew);
8144       for (p = 0; p < size; ++p) {
8145         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);
8146       }
8147 #endif
8148     }
8149     /* Interior edge vertices have 2 + faces supports */
8150     for (e = eStart; e < eMax; ++e) {
8151       const PetscInt  newp = vStartNew + (vEnd - vStart) + (e - eStart);
8152       const PetscInt *cone, *support;
8153       PetscInt        size, s;
8154 
8155       ierr          = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
8156       ierr          = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
8157       supportRef[0] = eStartNew + (e - eStart)*2 + 0;
8158       supportRef[1] = eStartNew + (e - eStart)*2 + 1;
8159       for (s = 0; s < size; ++s) {
8160         PetscInt r;
8161 
8162         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
8163         for (r = 0; r < 4; ++r) if (cone[r] == e) break;
8164         if (support[s] < fMax) {
8165           supportRef[2+s] = eStartNew + (eMax - eStart)*2 + (support[s] - fStart)*4 + r;
8166         } else {
8167           supportRef[2+s] = eStartNew + (eMax - eStart)*2 + (fMax       - fStart)*4 + (cMax - cStart)*6 + (eEnd - eMax) + (support[s] - fMax);
8168         }
8169       }
8170       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
8171 #if defined(PETSC_USE_DEBUG)
8172       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", newp, vStartNew, vEndNew);
8173       for (p = 0; p < 2+size; ++p) {
8174         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);
8175       }
8176 #endif
8177     }
8178     /* Interior face vertices have 4 + cells supports */
8179     for (f = fStart; f < fMax; ++f) {
8180       const PetscInt  newp = vStartNew + (vEnd - vStart) + (eMax - eStart) + (f - fStart);
8181       const PetscInt *cone, *support;
8182       PetscInt        size, s;
8183 
8184       ierr          = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
8185       ierr          = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
8186       for (r = 0; r < 4; ++r) supportRef[r] = eStartNew + (eMax - eStart)*2 +  (f - fStart)*4 + r;
8187       for (s = 0; s < size; ++s) {
8188         PetscInt r;
8189 
8190         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
8191         for (r = 0; r < 6; ++r) if (cone[r] == f) break;
8192         if (support[s] < cMax) {
8193           supportRef[4+s] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (support[s] - cStart)*6 + r;
8194         } else {
8195           supportRef[4+s] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax       - cStart)*6 + (eEnd - eMax) + (fEnd - fMax) + (support[s] - cMax);
8196         }
8197       }
8198       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
8199 #if defined(PETSC_USE_DEBUG)
8200       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", newp, vStartNew, vEndNew);
8201       for (p = 0; p < 4+size; ++p) {
8202         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);
8203       }
8204 #endif
8205     }
8206     /* Cell vertices have 6 supports */
8207     for (c = cStart; c < cMax; ++c) {
8208       const PetscInt newp = vStartNew + (vEnd - vStart) + (eMax - eStart) + (fMax - fStart) + (c - cStart);
8209       PetscInt       supportNew[6];
8210 
8211       for (r = 0; r < 6; ++r) {
8212         supportNew[r] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (c - cStart)*6 + r;
8213       }
8214       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
8215     }
8216     ierr = PetscFree(supportRef);CHKERRQ(ierr);
8217     break;
8218   default:
8219     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %s", CellRefiners[refiner]);
8220   }
8221   PetscFunctionReturn(0);
8222 }
8223 
8224 static PetscErrorCode CellRefinerSetCoordinates(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
8225 {
8226   PetscSection          coordSection, coordSectionNew;
8227   Vec                   coordinates, coordinatesNew;
8228   PetscScalar          *coords, *coordsNew;
8229   const PetscInt        numVertices = depthSize ? depthSize[0] : 0;
8230   PetscInt              dim, spaceDim, depth, bs, coordSizeNew, cStart, cEnd, cMax;
8231   PetscInt              c, vStart, vStartNew, vEnd, v, eStart, eEnd, eMax, e, fStart, fEnd, fMax, f;
8232   PetscInt              cStartNew, cEndNew, vEndNew, *parentId = NULL;
8233   VecType               vtype;
8234   PetscBool             isperiodic, localize = PETSC_FALSE, needcoords = PETSC_FALSE;
8235   const PetscReal      *maxCell, *L;
8236   const DMBoundaryType *bd;
8237   PetscErrorCode        ierr;
8238 
8239   PetscFunctionBegin;
8240   ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr);
8241   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
8242   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
8243   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
8244   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
8245   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
8246   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, NULL);CHKERRQ(ierr);
8247   if (cMax < 0) cMax = cEnd;
8248   if (fMax < 0) fMax = fEnd;
8249   if (eMax < 0) eMax = eEnd;
8250   ierr = GetDepthStart_Private(depth, depthSize, &cStartNew, NULL, NULL, &vStartNew);CHKERRQ(ierr);
8251   ierr = GetDepthEnd_Private(depth, depthSize, &cEndNew, NULL, NULL, &vEndNew);CHKERRQ(ierr);
8252   ierr = DMGetPeriodicity(dm, &isperiodic, &maxCell, &L, &bd);CHKERRQ(ierr);
8253   /* Determine if we need to localize coordinates when generating them */
8254   if (isperiodic && !maxCell) {
8255     ierr = DMGetCoordinatesLocalized(dm, &localize);CHKERRQ(ierr);
8256     if (!localize) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_USER,"Cannot refine if coordinates have not been localized");
8257   }
8258   if (isperiodic) {
8259     ierr = PetscOptionsBegin(PetscObjectComm((PetscObject)dm),((PetscObject)dm)->prefix,"DMPlex coords refinement options","DM");CHKERRQ(ierr);
8260     ierr = PetscOptionsBool("-dm_plex_refine_localize","Automatically localize from parent cells",NULL,localize,&localize,NULL);CHKERRQ(ierr);
8261     ierr = PetscOptionsEnd();CHKERRQ(ierr);
8262     if (localize) {
8263       ierr = DMLocalizeCoordinates(dm);CHKERRQ(ierr);
8264     }
8265   }
8266   ierr = DMSetPeriodicity(rdm, isperiodic,  maxCell,  L,  bd);CHKERRQ(ierr);
8267 
8268   ierr = DMGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
8269   ierr = PetscSectionGetFieldComponents(coordSection, 0, &spaceDim);CHKERRQ(ierr);
8270   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)dm), &coordSectionNew);CHKERRQ(ierr);
8271   ierr = PetscSectionSetNumFields(coordSectionNew, 1);CHKERRQ(ierr);
8272   ierr = PetscSectionSetFieldComponents(coordSectionNew, 0, spaceDim);CHKERRQ(ierr);
8273 
8274   if (localize) {
8275     PetscInt p, r, newp, *pi;
8276 
8277     /* New coordinates will be already localized on the cell */
8278     ierr = PetscSectionSetChart(coordSectionNew, 0, vStartNew+numVertices);CHKERRQ(ierr);
8279 
8280     /* We need the parentId to properly localize coordinates */
8281     ierr = PetscMalloc1(cEndNew-cStartNew,&pi);CHKERRQ(ierr);
8282     switch (refiner) {
8283     case REFINER_NOOP:
8284       break;
8285     case REFINER_SIMPLEX_1D:
8286       for (p = cStart; p < cEnd; ++p) {
8287         for (r = 0; r < 2; ++r) {
8288           newp     = (p - cStart)*2 + r;
8289           pi[newp] = p;
8290         }
8291       }
8292       break;
8293     case REFINER_SIMPLEX_2D:
8294       for (p = cStart; p < cEnd; ++p) {
8295         for (r = 0; r < 4; ++r) {
8296           newp     = (p - cStart)*4 + r;
8297           pi[newp] = p;
8298         }
8299       }
8300       break;
8301     case REFINER_HEX_2D:
8302       for (p = cStart; p < cEnd; ++p) {
8303         for (r = 0; r < 4; ++r) {
8304           newp     = (p - cStart)*4 + r;
8305           pi[newp] = p;
8306         }
8307       }
8308       break;
8309     case REFINER_SIMPLEX_TO_HEX_2D:
8310       for (p = cStart; p < cEnd; ++p) {
8311         for (r = 0; r < 3; ++r) {
8312           newp     = (p - cStart)*3 + r;
8313           pi[newp] = p;
8314         }
8315       }
8316       break;
8317     case REFINER_HYBRID_SIMPLEX_TO_HEX_2D:
8318       for (p = cStart; p < cMax; ++p) {
8319         for (r = 0; r < 3; ++r) {
8320           newp     = (p - cStart)*3 + r;
8321           pi[newp] = p;
8322         }
8323       }
8324       for (p = cMax; p < cEnd; ++p) {
8325         for (r = 0; r < 4; ++r) {
8326           newp     = (cMax - cStart)*3 + (p - cMax)*4 + r;
8327           pi[newp] = p;
8328         }
8329       }
8330       /* The refiner needs midpoint vertices on hybrid edges and hybrid cells */
8331       cMax = cEnd;
8332       eMax = eEnd;
8333       break;
8334     case REFINER_HYBRID_SIMPLEX_2D:
8335       for (p = cStart; p < cMax; ++p) {
8336         for (r = 0; r < 4; ++r) {
8337           newp     = (p - cStart)*4 + r;
8338           pi[newp] = p;
8339         }
8340       }
8341       for (p = cMax; p < cEnd; ++p) {
8342         for (r = 0; r < 2; ++r) {
8343           newp     = (cMax - cStart)*4 + (p - cMax)*2 + r;
8344           pi[newp] = p;
8345         }
8346       }
8347       break;
8348     case REFINER_HYBRID_HEX_2D:
8349       for (p = cStart; p < cMax; ++p) {
8350         for (r = 0; r < 4; ++r) {
8351           newp     = (p - cStart)*4 + r;
8352           pi[newp] = p;
8353         }
8354       }
8355       for (p = cMax; p < cEnd; ++p) {
8356         for (r = 0; r < 2; ++r) {
8357           newp     = (cMax - cStart)*4 + (p - cMax)*2 + r;
8358           pi[newp] = p;
8359         }
8360       }
8361       break;
8362     case REFINER_SIMPLEX_3D:
8363       for (p = cStart; p < cEnd; ++p) {
8364         for (r = 0; r < 8; ++r) {
8365           newp     = (p - cStart)*8 + r;
8366           pi[newp] = p;
8367         }
8368       }
8369       break;
8370     case REFINER_HYBRID_SIMPLEX_3D:
8371       for (p = cStart; p < cMax; ++p) {
8372         for (r = 0; r < 8; ++r) {
8373           newp     = (p - cStart)*8 + r;
8374           pi[newp] = p;
8375         }
8376       }
8377       for (p = cMax; p < cEnd; ++p) {
8378         for (r = 0; r < 4; ++r) {
8379           newp     = (cMax - cStart)*8 + (p - cMax)*4 + r;
8380           pi[newp] = p;
8381         }
8382       }
8383       break;
8384     case REFINER_SIMPLEX_TO_HEX_3D:
8385       for (p = cStart; p < cEnd; ++p) {
8386         for (r = 0; r < 4; ++r) {
8387           newp     = (p - cStart)*4 + r;
8388           pi[newp] = p;
8389         }
8390       }
8391       break;
8392     case REFINER_HYBRID_SIMPLEX_TO_HEX_3D:
8393       for (p = cStart; p < cMax; ++p) {
8394         for (r = 0; r < 4; ++r) {
8395           newp     = (p - cStart)*4 + r;
8396           pi[newp] = p;
8397         }
8398       }
8399       for (p = cMax; p < cEnd; ++p) {
8400         for (r = 0; r < 3; ++r) {
8401           newp     = (cMax - cStart)*4 + (p - cMax)*3 + r;
8402           pi[newp] = p;
8403         }
8404       }
8405       break;
8406     case REFINER_HEX_3D:
8407       for (p = cStart; p < cEnd; ++p) {
8408         for (r = 0; r < 8; ++r) {
8409           newp = (p - cStart)*8 + r;
8410           pi[newp] = p;
8411         }
8412       }
8413       break;
8414     case REFINER_HYBRID_HEX_3D:
8415       for (p = cStart; p < cMax; ++p) {
8416         for (r = 0; r < 8; ++r) {
8417           newp = (p - cStart)*8 + r;
8418           pi[newp] = p;
8419         }
8420       }
8421       for (p = cMax; p < cEnd; ++p) {
8422         for (r = 0; r < 4; ++r) {
8423           newp = (cMax - cStart)*8 + (p - cMax)*4 + r;
8424           pi[newp] = p;
8425         }
8426       }
8427       break;
8428     default:
8429       SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %s", CellRefiners[refiner]);
8430     }
8431     parentId = pi;
8432   } else {
8433     /* The refiner needs midpoint vertices on hybrid edges and hybrid cells */
8434     if (REFINER_HYBRID_SIMPLEX_TO_HEX_2D == refiner) { cMax = cEnd; eMax = eEnd; }
8435     ierr = PetscSectionSetChart(coordSectionNew, vStartNew, vStartNew+numVertices);CHKERRQ(ierr);
8436   }
8437 
8438   /* All vertices have the spaceDim coordinates */
8439   if (localize) {
8440     PetscInt c;
8441 
8442     for (c = cStartNew; c < cEndNew; ++c) {
8443       PetscInt *cone = NULL;
8444       PetscInt  closureSize, coneSize = 0, p, pdof;
8445 
8446       ierr = PetscSectionGetDof(coordSection, parentId[c], &pdof); CHKERRQ(ierr);
8447       if (pdof) { /* localize on all cells that are refinement of a localized parent cell */
8448         ierr = DMPlexGetTransitiveClosure(rdm, c, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
8449         for (p = 0; p < closureSize*2; p += 2) {
8450           const PetscInt point = cone[p];
8451           if ((point >= vStartNew) && (point < vEndNew)) coneSize++;
8452         }
8453         ierr = DMPlexRestoreTransitiveClosure(rdm, c, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
8454         ierr = PetscSectionSetDof(coordSectionNew, c, coneSize*spaceDim);CHKERRQ(ierr);
8455         ierr = PetscSectionSetFieldDof(coordSectionNew, c, 0, coneSize*spaceDim);CHKERRQ(ierr);
8456       }
8457     }
8458   }
8459   for (v = vStartNew; v < vStartNew+numVertices; ++v) {
8460     ierr = PetscSectionSetDof(coordSectionNew, v, spaceDim);CHKERRQ(ierr);
8461     ierr = PetscSectionSetFieldDof(coordSectionNew, v, 0, spaceDim);CHKERRQ(ierr);
8462   }
8463   ierr = PetscSectionSetUp(coordSectionNew);CHKERRQ(ierr);
8464   ierr = DMSetCoordinateSection(rdm, PETSC_DETERMINE, coordSectionNew);CHKERRQ(ierr);
8465   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
8466   ierr = PetscSectionGetStorageSize(coordSectionNew, &coordSizeNew);CHKERRQ(ierr);
8467   ierr = VecCreate(PETSC_COMM_SELF, &coordinatesNew);CHKERRQ(ierr);
8468   ierr = PetscObjectSetName((PetscObject) coordinatesNew, "coordinates");CHKERRQ(ierr);
8469   ierr = VecSetSizes(coordinatesNew, coordSizeNew, PETSC_DETERMINE);CHKERRQ(ierr);
8470   ierr = VecGetBlockSize(coordinates, &bs);CHKERRQ(ierr);
8471   ierr = VecSetBlockSize(coordinatesNew, bs);CHKERRQ(ierr);
8472   ierr = VecGetType(coordinates, &vtype);CHKERRQ(ierr);
8473   ierr = VecSetType(coordinatesNew, vtype);CHKERRQ(ierr);
8474   ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
8475   ierr = VecGetArray(coordinatesNew, &coordsNew);CHKERRQ(ierr);
8476 
8477   switch (refiner) {
8478   case REFINER_NOOP: break;
8479   case REFINER_HYBRID_SIMPLEX_TO_HEX_3D:
8480   case REFINER_SIMPLEX_TO_HEX_3D:
8481   case REFINER_HEX_3D:
8482   case REFINER_HYBRID_HEX_3D:
8483     /* Face vertices have the average of corner coordinates */
8484     for (f = fStart; f < fMax; ++f) {
8485       const PetscInt newv = vStartNew + (vEnd - vStart) + (eMax - eStart) + (f - fStart);
8486       PetscInt      *cone = NULL;
8487       PetscInt       closureSize, coneSize = 0, off[8], offnew, p, d;
8488 
8489       ierr = DMPlexGetTransitiveClosure(dm, f, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
8490       for (p = 0; p < closureSize*2; p += 2) {
8491         const PetscInt point = cone[p];
8492         if ((point >= vStart) && (point < vEnd)) cone[coneSize++] = point;
8493       }
8494       if (localize) {
8495         const PetscInt *support = NULL;
8496         PetscInt       *rStar = NULL;
8497         PetscInt        supportSize, rStarSize, coff, s, ccoff[8];
8498         PetscBool       cellfound = PETSC_FALSE;
8499 
8500         ierr = DMPlexGetTransitiveClosure(rdm, newv, PETSC_FALSE, &rStarSize, &rStar);CHKERRQ(ierr);
8501         ierr = DMPlexGetSupportSize(dm,f,&supportSize);CHKERRQ(ierr);
8502         ierr = DMPlexGetSupport(dm,f,&support);CHKERRQ(ierr);
8503         /* Compute average of coordinates for each cell sharing the face */
8504         for (s = 0; s < supportSize; ++s) {
8505           PetscScalar     coordsNewAux[3] = { 0.0, 0.0, 0.0 };
8506           PetscInt       *cellCone = NULL;
8507           PetscInt        cellClosureSize, cellConeSize = 0, cdof;
8508           const PetscInt  cell = support[s];
8509           PetscBool       copyoff = PETSC_FALSE;
8510 
8511           ierr = DMPlexGetTransitiveClosure(dm, cell, PETSC_TRUE, &cellClosureSize, &cellCone);CHKERRQ(ierr);
8512           for (p = 0; p < cellClosureSize*2; p += 2) {
8513             const PetscInt point = cellCone[p];
8514             if ((point >= vStart) && (point < vEnd)) cellCone[cellConeSize++] = point;
8515           }
8516           ierr = PetscSectionGetDof(coordSection, cell, &cdof);CHKERRQ(ierr);
8517           if (!cdof) { /* the parent cell does not have localized coordinates */
8518             cellfound = PETSC_TRUE;
8519             for (v = 0; v < coneSize; ++v) {
8520               ierr = PetscSectionGetOffset(coordSection, cone[v], &off[v]);CHKERRQ(ierr);
8521               for (d = 0; d < spaceDim; ++d) coordsNewAux[d] += coords[off[v]+d];
8522             }
8523             for (d = 0; d < spaceDim; ++d) coordsNewAux[d] /= coneSize;
8524           } else {
8525             ierr = PetscSectionGetOffset(coordSection, cell, &coff);CHKERRQ(ierr);
8526             for (p = 0; p < coneSize; ++p) {
8527               const PetscInt tv = cone[p];
8528               PetscInt       cv, voff;
8529               PetscBool      locv = PETSC_TRUE;
8530 
8531               for (cv = 0; cv < cellConeSize; ++cv) {
8532                 if (cellCone[cv] == tv) {
8533                   ccoff[p] = spaceDim*cv + coff;
8534                   break;
8535                 }
8536               }
8537               if (cv == cellConeSize) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Unable to map vertex %D",tv);
8538 
8539               ierr = PetscSectionGetOffset(coordSection, cone[p], &voff);CHKERRQ(ierr);
8540               for (d = 0; d < spaceDim; ++d) {
8541                 coordsNewAux[d] += coords[ccoff[p]+d];
8542                 if (!cellfound && coords[voff+d] != coords[ccoff[p]+d]) locv = PETSC_FALSE;
8543               }
8544               if (locv && !cellfound) {
8545                 cellfound = PETSC_TRUE;
8546                 copyoff   = PETSC_TRUE;
8547               }
8548             }
8549             for (d = 0; d < spaceDim; ++d) coordsNewAux[d] /= coneSize;
8550 
8551             /* Found a valid face for the "vertex" part of the Section (physical space)
8552                i.e., a face that has at least one corner in the physical space */
8553             if (copyoff) for (p = 0; p < coneSize; ++p) off[p] = ccoff[p];
8554           }
8555 
8556           /* Localize new coordinates on each refined cell */
8557           for (v = 0; v < rStarSize*2; v += 2) {
8558             if ((rStar[v] >= cStartNew) && (rStar[v] < cEndNew) && parentId[rStar[v]-cStartNew] == cell) {
8559               PetscInt       *rcone = NULL, rclosureSize, lid, rcdof, rcoff;
8560               const PetscInt  rcell = rStar[v];
8561 
8562               ierr = PetscSectionGetDof(coordSectionNew, rcell, &rcdof);CHKERRQ(ierr);
8563               if (!rcdof) continue;
8564               ierr = PetscSectionGetOffset(coordSectionNew, rcell, &rcoff);CHKERRQ(ierr);
8565               ierr = DMPlexGetTransitiveClosure(rdm, rcell, PETSC_TRUE, &rclosureSize, &rcone);CHKERRQ(ierr);
8566               for (p = 0, lid = 0; p < rclosureSize*2; p += 2) {
8567                 if (rcone[p] == newv) {
8568                   for (d = 0; d < spaceDim; d++) coordsNew[rcoff + lid*spaceDim + d] = coordsNewAux[d];
8569                   break;
8570                 }
8571                 if (rcone[p] >= vStartNew && rcone[p] < vEndNew) lid++;
8572               }
8573               ierr = DMPlexRestoreTransitiveClosure(rdm, rcell, PETSC_TRUE, &rclosureSize, &rcone);CHKERRQ(ierr);
8574               if (p == closureSize*2) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Unable to map new vertex %D",newv);
8575             }
8576           }
8577           ierr = DMPlexRestoreTransitiveClosure(dm, cell, PETSC_TRUE, &cellClosureSize, &cellCone);CHKERRQ(ierr);
8578         }
8579         ierr = DMPlexRestoreTransitiveClosure(rdm, newv, PETSC_FALSE, &rStarSize, &rStar);CHKERRQ(ierr);
8580         if (!cellfound) {
8581           /* Could not find a valid face for the vertex part, we will get this vertex later (final reduction) */
8582           needcoords = PETSC_TRUE;
8583           coneSize   = 0;
8584         }
8585       } else {
8586         for (v = 0; v < coneSize; ++v) {
8587           ierr = PetscSectionGetOffset(coordSection, cone[v], &off[v]);CHKERRQ(ierr);
8588         }
8589       }
8590       ierr = PetscSectionGetOffset(coordSectionNew, newv, &offnew);CHKERRQ(ierr);
8591       if (coneSize) {
8592         for (d = 0; d < spaceDim; ++d) coordsNew[offnew+d] = 0.0;
8593         for (v = 0; v < coneSize; ++v) {ierr = DMLocalizeAddCoordinate_Internal(dm, spaceDim, &coords[off[0]], &coords[off[v]], &coordsNew[offnew]);CHKERRQ(ierr);}
8594         for (d = 0; d < spaceDim; ++d) coordsNew[offnew+d] /= coneSize;
8595       } else {
8596         for (d = 0; d < spaceDim; ++d) coordsNew[offnew+d] = PETSC_MIN_REAL;
8597       }
8598       ierr = DMPlexRestoreTransitiveClosure(dm, f, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
8599     }
8600   case REFINER_HYBRID_SIMPLEX_TO_HEX_2D:
8601   case REFINER_SIMPLEX_TO_HEX_2D:
8602   case REFINER_HEX_2D:
8603   case REFINER_HYBRID_HEX_2D:
8604   case REFINER_SIMPLEX_1D:
8605     /* Cell vertices have the average of corner coordinates */
8606     for (c = cStart; c < cMax; ++c) {
8607       const PetscInt newv = vStartNew + (vEnd - vStart) + (dim > 1 ? (eMax - eStart) : 0) + (c - cStart) + (dim > 2 ? (fMax - fStart) : 0);
8608       PetscInt      *cone = NULL;
8609       PetscInt       closureSize, coneSize = 0, off[8], offnew, p, d, cdof = 0;
8610 
8611       ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
8612       for (p = 0; p < closureSize*2; p += 2) {
8613         const PetscInt point = cone[p];
8614         if ((point >= vStart) && (point < vEnd)) cone[coneSize++] = point;
8615       }
8616       if (localize) {
8617         ierr = PetscSectionGetDof(coordSection, c, &cdof);CHKERRQ(ierr);
8618       }
8619       if (cdof) {
8620         PetscInt coff;
8621 
8622         ierr = PetscSectionGetOffset(coordSection, c, &coff);CHKERRQ(ierr);
8623         for (v = 0; v < coneSize; ++v) off[v] = spaceDim*v + coff;
8624       } else {
8625         for (v = 0; v < coneSize; ++v) {
8626           ierr = PetscSectionGetOffset(coordSection, cone[v], &off[v]);CHKERRQ(ierr);
8627         }
8628       }
8629       ierr = PetscSectionGetOffset(coordSectionNew, newv, &offnew);CHKERRQ(ierr);
8630       for (d = 0; d < spaceDim; ++d) coordsNew[offnew+d] = 0.0;
8631       for (v = 0; v < coneSize; ++v) {ierr = DMLocalizeAddCoordinate_Internal(dm, spaceDim, &coords[off[0]], &coords[off[v]], &coordsNew[offnew]);CHKERRQ(ierr);}
8632       for (d = 0; d < spaceDim; ++d) coordsNew[offnew+d] /= coneSize;
8633       ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
8634 
8635       /* Localize new coordinates on each refined cell */
8636       if (cdof) {
8637         PetscInt *rStar = NULL, rStarSize;
8638 
8639         ierr = DMPlexGetTransitiveClosure(rdm, newv, PETSC_FALSE, &rStarSize, &rStar);CHKERRQ(ierr);
8640         for (v = 0; v < rStarSize*2; v += 2) {
8641           if ((rStar[v] >= cStartNew) && (rStar[v] < cEndNew)) {
8642             PetscInt *cone = NULL, closureSize, lid, coff, rc, rcdof;
8643 
8644             rc   = rStar[v];
8645             ierr = PetscSectionGetDof(coordSectionNew, rc, &rcdof);CHKERRQ(ierr);
8646             if (!rcdof) continue;
8647             ierr = PetscSectionGetOffset(coordSectionNew, rc, &coff);CHKERRQ(ierr);
8648             ierr = DMPlexGetTransitiveClosure(rdm, rc, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
8649             for (p = 0, lid = 0; p < closureSize*2; p += 2) {
8650               if (cone[p] == newv) {
8651                 for (d = 0; d < spaceDim; d++) coordsNew[coff + lid*spaceDim + d] = coordsNew[offnew + d];
8652                 break;
8653               }
8654               if (cone[p] >= vStartNew && cone[p] < vEndNew) lid++;
8655             }
8656             if (p == closureSize*2) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Unable to map new vertex %D",newv);
8657             ierr = DMPlexRestoreTransitiveClosure(rdm, rc, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
8658           }
8659         }
8660         ierr = DMPlexRestoreTransitiveClosure(rdm, newv, PETSC_FALSE, &rStarSize, &rStar);CHKERRQ(ierr);
8661       }
8662     }
8663   case REFINER_SIMPLEX_2D:
8664   case REFINER_HYBRID_SIMPLEX_2D:
8665   case REFINER_SIMPLEX_3D:
8666   case REFINER_HYBRID_SIMPLEX_3D:
8667     /* Edge vertices have the average of endpoint coordinates */
8668     for (e = eStart; e < eMax; ++e) {
8669       const PetscInt  newv = vStartNew + (vEnd - vStart) + (e - eStart);
8670       const PetscInt *cone;
8671       PetscInt        coneSize, offA, offB, offnew, d;
8672 
8673       ierr = DMPlexGetConeSize(dm, e, &coneSize);CHKERRQ(ierr);
8674       if (coneSize != 2) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Edge %D cone should have two vertices, not %D", e, coneSize);
8675       ierr = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
8676       if (localize) {
8677         PetscInt   coff, toffA = -1, toffB = -1, voffA, voffB;
8678         PetscInt  *eStar = NULL, eStarSize;
8679         PetscInt  *rStar = NULL, rStarSize;
8680         PetscBool  cellfound = PETSC_FALSE;
8681 
8682         offA = offB = -1;
8683         ierr = PetscSectionGetOffset(coordSection, cone[0], &voffA);CHKERRQ(ierr);
8684         ierr = PetscSectionGetOffset(coordSection, cone[1], &voffB);CHKERRQ(ierr);
8685         ierr = DMPlexGetTransitiveClosure(dm, e, PETSC_FALSE, &eStarSize, &eStar);CHKERRQ(ierr);
8686         ierr = DMPlexGetTransitiveClosure(rdm, newv, PETSC_FALSE, &rStarSize, &rStar);CHKERRQ(ierr);
8687         for (v = 0; v < eStarSize*2; v += 2) {
8688           if ((eStar[v] >= cStart) && (eStar[v] < cEnd)) {
8689             PetscScalar     coordsNewAux[3] = {0., 0., 0.};
8690             PetscInt       *cellCone = NULL;
8691             PetscInt        cellClosureSize, s, cv, cdof;
8692             PetscBool       locvA = PETSC_TRUE, locvB = PETSC_TRUE;
8693             const PetscInt  cell = eStar[v];
8694 
8695             ierr = PetscSectionGetDof(coordSection, cell, &cdof);CHKERRQ(ierr);
8696             if (!cdof) {
8697               /* Found a valid edge for the "vertex" part of the Section */
8698               offA = voffA;
8699               offB = voffB;
8700               cellfound = PETSC_TRUE;
8701             } else {
8702               ierr = PetscSectionGetOffset(coordSection, cell, &coff);CHKERRQ(ierr);
8703               ierr = DMPlexGetTransitiveClosure(dm, cell, PETSC_TRUE, &cellClosureSize, &cellCone);CHKERRQ(ierr);
8704               for (s = 0, cv = 0; s < cellClosureSize*2; s += 2) {
8705                 const PetscInt point = cellCone[s];
8706                 if ((point >= vStart) && (point < vEnd)) {
8707                   if (point == cone[0]) toffA = spaceDim*cv + coff;
8708                   else if (point == cone[1]) toffB = spaceDim*cv + coff;
8709                   cv++;
8710                 }
8711               }
8712               ierr = DMPlexRestoreTransitiveClosure(dm, cell, PETSC_TRUE, &cellClosureSize, &cellCone);CHKERRQ(ierr);
8713               for (d = 0; d < spaceDim; ++d) {
8714                 coordsNewAux[d] = 0.5*(coords[toffA+d] + coords[toffB+d]);
8715                 if (coords[toffA+d] != coords[voffA+d]) locvA = PETSC_FALSE;
8716                 if (coords[toffB+d] != coords[voffB+d]) locvB = PETSC_FALSE;
8717               }
8718               /* Found a valid edge for the "vertex" part of the Section */
8719               if (!cellfound && (locvA || locvB)) {
8720                 cellfound = PETSC_TRUE;
8721                 offA = toffA;
8722                 offB = toffB;
8723               }
8724             }
8725 
8726             /* Localize new coordinates on each refined cell */
8727             for (s = 0; s < rStarSize*2; s += 2) {
8728               if ((rStar[s] >= cStartNew) && (rStar[s] < cEndNew) && parentId[rStar[s]-cStartNew] == cell) {
8729                 PetscInt       *rcone = NULL, rclosureSize, lid, p, rcdof;
8730                 const PetscInt  rcell = rStar[s];
8731 
8732                 ierr = PetscSectionGetDof(coordSectionNew, rcell, &rcdof);CHKERRQ(ierr);
8733                 if (!rcdof) continue;
8734                 ierr = PetscSectionGetOffset(coordSectionNew, rcell, &coff);CHKERRQ(ierr);
8735                 ierr = DMPlexGetTransitiveClosure(rdm, rcell, PETSC_TRUE, &rclosureSize, &rcone);CHKERRQ(ierr);
8736                 for (p = 0, lid = 0; p < rclosureSize*2; p += 2) {
8737                   if (rcone[p] == newv) {
8738                     for (d = 0; d < spaceDim; d++) coordsNew[coff + lid*spaceDim + d] = coordsNewAux[d];
8739                     break;
8740                   }
8741                   if (rcone[p] >= vStartNew && rcone[p] < vEndNew) lid++;
8742                 }
8743                 ierr = DMPlexRestoreTransitiveClosure(rdm, rcell, PETSC_TRUE, &rclosureSize, &rcone);CHKERRQ(ierr);
8744                 if (p == rclosureSize*2) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Unable to map new vertex %D",newv);
8745               }
8746             }
8747           }
8748         }
8749         ierr = DMPlexRestoreTransitiveClosure(dm, e, PETSC_FALSE, &eStarSize, &eStar);CHKERRQ(ierr);
8750         ierr = DMPlexRestoreTransitiveClosure(rdm, newv, PETSC_FALSE, &rStarSize, &rStar);CHKERRQ(ierr);
8751         if (!cellfound) {
8752           /* Could not find a valid edge for the vertex part, we will get this vertex later (final reduction) */
8753           needcoords = PETSC_TRUE;
8754         }
8755       } else {
8756         ierr = PetscSectionGetOffset(coordSection, cone[0], &offA);CHKERRQ(ierr);
8757         ierr = PetscSectionGetOffset(coordSection, cone[1], &offB);CHKERRQ(ierr);
8758       }
8759       ierr = PetscSectionGetOffset(coordSectionNew, newv, &offnew);CHKERRQ(ierr);
8760       if (offA != -1 && offB != -1) {
8761         ierr = DMLocalizeCoordinate_Internal(dm, spaceDim, &coords[offA], &coords[offB], &coordsNew[offnew]);CHKERRQ(ierr);
8762         for (d = 0; d < spaceDim; ++d) {
8763           coordsNew[offnew+d] = 0.5*(coords[offA+d] + coordsNew[offnew+d]);
8764           ierr = DMPlexSnapToGeomModel(dm, e, &coordsNew[offnew], &coordsNew[offnew]);CHKERRQ(ierr);
8765         }
8766       } else {
8767         for (d = 0; d < spaceDim; ++d) coordsNew[offnew+d] = PETSC_MIN_REAL;
8768       }
8769     }
8770     /* Old vertices have the same coordinates */
8771     for (v = vStart; v < vEnd; ++v) {
8772       const PetscInt newv = vStartNew + (v - vStart);
8773       PetscInt       off, offnew, d;
8774 
8775       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
8776       ierr = PetscSectionGetOffset(coordSectionNew, newv, &offnew);CHKERRQ(ierr);
8777       for (d = 0; d < spaceDim; ++d) {
8778         coordsNew[offnew+d] = coords[off+d];
8779       }
8780 
8781       /* Localize new coordinates on each refined cell */
8782       if (localize) {
8783         PetscInt  p;
8784         PetscInt *rStar = NULL, rStarSize;
8785 
8786         ierr = DMPlexGetTransitiveClosure(rdm, newv, PETSC_FALSE, &rStarSize, &rStar);CHKERRQ(ierr);
8787         for (p = 0; p < rStarSize*2; p += 2) {
8788           if ((rStar[p] >= cStartNew) && (rStar[p] < cEndNew)) {
8789             PetscScalar  ocoords[3] = {0,0,0}; /* dummy values for compiler warnings about uninitialized values */
8790             PetscInt    *cone = NULL, closureSize, lid, coff, s, oc, cdof;
8791 
8792             c    = rStar[p];
8793             oc   = parentId[c-cStartNew];
8794             ierr = PetscSectionGetDof(coordSectionNew, c, &cdof);CHKERRQ(ierr);
8795             if (!cdof) continue;
8796             ierr = PetscSectionGetDof(coordSection, oc, &cdof);CHKERRQ(ierr);
8797             if (!cdof) continue;
8798             ierr = PetscSectionGetOffset(coordSection, oc, &coff);CHKERRQ(ierr);
8799             ierr = DMPlexGetTransitiveClosure(dm, oc, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
8800             for (s = 0, lid = 0; s < closureSize*2; s += 2) {
8801               if (cone[s] == v) {
8802                 for (d = 0; d < spaceDim; d++) ocoords[d] = coords[coff + lid*spaceDim + d];
8803                 break;
8804               }
8805               if (cone[s] >= vStart && cone[s] < vEnd) lid++;
8806             }
8807             if (s == closureSize*2) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Unable to map old vertex %D",v);
8808             ierr = DMPlexRestoreTransitiveClosure(dm, oc, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
8809 
8810             ierr = PetscSectionGetOffset(coordSectionNew, c, &coff);CHKERRQ(ierr);
8811             ierr = DMPlexGetTransitiveClosure(rdm, c, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
8812             for (s = 0, lid = 0; s < closureSize*2; s += 2) {
8813               if (cone[s] == newv) {
8814                 for (d = 0; d < spaceDim; d++) coordsNew[coff + lid*spaceDim + d] = ocoords[d];
8815                 break;
8816               }
8817               if (cone[s] >= vStartNew && cone[s] < vEndNew) lid++;
8818             }
8819             if (s == closureSize*2) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Unable to map new vertex %D",newv);
8820             ierr = DMPlexRestoreTransitiveClosure(rdm, c, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
8821           }
8822         }
8823         ierr = DMPlexRestoreTransitiveClosure(rdm, newv, PETSC_FALSE, &rStarSize, &rStar);CHKERRQ(ierr);
8824       }
8825     }
8826     break;
8827   default:
8828     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %s", CellRefiners[refiner]);
8829   }
8830   ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
8831   ierr = VecRestoreArray(coordinatesNew, &coordsNew);CHKERRQ(ierr);
8832   ierr = DMSetCoordinatesLocal(rdm, coordinatesNew);CHKERRQ(ierr);
8833 
8834   /* Final reduction (if needed) if we are localizing */
8835   if (localize) {
8836     PetscBool gred;
8837 
8838     ierr = MPIU_Allreduce(&needcoords, &gred, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject)rdm));CHKERRQ(ierr);
8839     if (gred) {
8840       DM                 cdm;
8841       Vec                aux;
8842       PetscSF            sf;
8843       const PetscScalar *lArray;
8844       PetscScalar       *gArray;
8845 #if defined(PETSC_USE_COMPLEX)
8846       PetscInt          i, ln, gn;
8847       PetscReal         *lrArray;
8848       PetscReal         *grArray;
8849 #endif
8850 
8851       ierr = DMGetCoordinateDM(rdm, &cdm);CHKERRQ(ierr);
8852       ierr = DMCreateGlobalVector(cdm, &aux);CHKERRQ(ierr);
8853       ierr = DMGetSectionSF(cdm, &sf);CHKERRQ(ierr);
8854       ierr = VecGetArrayRead(coordinatesNew, &lArray);CHKERRQ(ierr);
8855       ierr = VecSet(aux, PETSC_MIN_REAL);CHKERRQ(ierr);
8856       ierr = VecGetArray(aux, &gArray);CHKERRQ(ierr);
8857 #if defined(PETSC_USE_COMPLEX)
8858       ierr = VecGetLocalSize(aux, &gn);CHKERRQ(ierr);
8859       ierr = VecGetLocalSize(coordinatesNew, &ln);CHKERRQ(ierr);
8860       ierr = PetscMalloc2(ln,&lrArray,gn,&grArray);CHKERRQ(ierr);
8861       for (i=0;i<ln;i++) lrArray[i] = PetscRealPart(lArray[i]);
8862       for (i=0;i<gn;i++) grArray[i] = PetscRealPart(gArray[i]);
8863       ierr = PetscSFReduceBegin(sf, MPIU_REAL, lrArray, grArray, MPIU_MAX);CHKERRQ(ierr);
8864       ierr = PetscSFReduceEnd(sf, MPIU_REAL, lrArray, grArray, MPIU_MAX);CHKERRQ(ierr);
8865       for (i=0;i<gn;i++) gArray[i] = grArray[i];
8866       ierr = PetscFree2(lrArray,grArray);CHKERRQ(ierr);
8867 #else
8868       ierr = PetscSFReduceBegin(sf, MPIU_SCALAR, lArray, gArray, MPIU_MAX);CHKERRQ(ierr);
8869       ierr = PetscSFReduceEnd(sf, MPIU_SCALAR, lArray, gArray, MPIU_MAX);CHKERRQ(ierr);
8870 #endif
8871       ierr = VecRestoreArrayRead(coordinatesNew, &lArray);CHKERRQ(ierr);
8872       ierr = VecRestoreArray(aux, &gArray);CHKERRQ(ierr);
8873       ierr = DMGlobalToLocalBegin(cdm, aux, INSERT_VALUES, coordinatesNew);CHKERRQ(ierr);
8874       ierr = DMGlobalToLocalEnd(cdm, aux, INSERT_VALUES, coordinatesNew);CHKERRQ(ierr);
8875       ierr = VecDestroy(&aux);CHKERRQ(ierr);
8876     }
8877   }
8878   ierr = VecDestroy(&coordinatesNew);CHKERRQ(ierr);
8879   ierr = PetscSectionDestroy(&coordSectionNew);CHKERRQ(ierr);
8880   ierr = PetscFree(parentId);CHKERRQ(ierr);
8881   PetscFunctionReturn(0);
8882 }
8883 
8884 /*@
8885   DMPlexCreateProcessSF - Create an SF which just has process connectivity
8886 
8887   Collective on dm
8888 
8889   Input Parameters:
8890 + dm      - The DM
8891 - sfPoint - The PetscSF which encodes point connectivity
8892 
8893   Output Parameters:
8894 + processRanks - A list of process neighbors, or NULL
8895 - sfProcess    - An SF encoding the process connectivity, or NULL
8896 
8897   Level: developer
8898 
8899 .seealso: PetscSFCreate(), DMPlexCreateTwoSidedProcessSF()
8900 @*/
8901 PetscErrorCode DMPlexCreateProcessSF(DM dm, PetscSF sfPoint, IS *processRanks, PetscSF *sfProcess)
8902 {
8903   PetscInt           numRoots, numLeaves, l;
8904   const PetscInt    *localPoints;
8905   const PetscSFNode *remotePoints;
8906   PetscInt          *localPointsNew;
8907   PetscSFNode       *remotePointsNew;
8908   PetscInt          *ranks, *ranksNew;
8909   PetscMPIInt        size;
8910   PetscErrorCode     ierr;
8911 
8912   PetscFunctionBegin;
8913   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8914   PetscValidHeaderSpecific(sfPoint, PETSCSF_CLASSID, 2);
8915   if (processRanks) {PetscValidPointer(processRanks, 3);}
8916   if (sfProcess)    {PetscValidPointer(sfProcess, 4);}
8917   ierr = MPI_Comm_size(PetscObjectComm((PetscObject) dm), &size);CHKERRQ(ierr);
8918   ierr = PetscSFGetGraph(sfPoint, &numRoots, &numLeaves, &localPoints, &remotePoints);CHKERRQ(ierr);
8919   ierr = PetscMalloc1(numLeaves, &ranks);CHKERRQ(ierr);
8920   for (l = 0; l < numLeaves; ++l) {
8921     ranks[l] = remotePoints[l].rank;
8922   }
8923   ierr = PetscSortRemoveDupsInt(&numLeaves, ranks);CHKERRQ(ierr);
8924   ierr = PetscMalloc1(numLeaves, &ranksNew);CHKERRQ(ierr);
8925   ierr = PetscMalloc1(numLeaves, &localPointsNew);CHKERRQ(ierr);
8926   ierr = PetscMalloc1(numLeaves, &remotePointsNew);CHKERRQ(ierr);
8927   for (l = 0; l < numLeaves; ++l) {
8928     ranksNew[l]              = ranks[l];
8929     localPointsNew[l]        = l;
8930     remotePointsNew[l].index = 0;
8931     remotePointsNew[l].rank  = ranksNew[l];
8932   }
8933   ierr = PetscFree(ranks);CHKERRQ(ierr);
8934   if (processRanks) {ierr = ISCreateGeneral(PetscObjectComm((PetscObject)dm), numLeaves, ranksNew, PETSC_OWN_POINTER, processRanks);CHKERRQ(ierr);}
8935   else              {ierr = PetscFree(ranksNew);CHKERRQ(ierr);}
8936   if (sfProcess) {
8937     ierr = PetscSFCreate(PetscObjectComm((PetscObject)dm), sfProcess);CHKERRQ(ierr);
8938     ierr = PetscObjectSetName((PetscObject) *sfProcess, "Process SF");CHKERRQ(ierr);
8939     ierr = PetscSFSetFromOptions(*sfProcess);CHKERRQ(ierr);
8940     ierr = PetscSFSetGraph(*sfProcess, size, numLeaves, localPointsNew, PETSC_OWN_POINTER, remotePointsNew, PETSC_OWN_POINTER);CHKERRQ(ierr);
8941   }
8942   PetscFunctionReturn(0);
8943 }
8944 
8945 static PetscErrorCode CellRefinerCreateSF(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
8946 {
8947   PetscSF            sf, sfNew, sfProcess;
8948   IS                 processRanks;
8949   MPI_Datatype       depthType;
8950   PetscInt           numRoots, numLeaves, numLeavesNew = 0, l, m;
8951   const PetscInt    *localPoints, *neighbors;
8952   const PetscSFNode *remotePoints;
8953   PetscInt          *localPointsNew;
8954   PetscSFNode       *remotePointsNew;
8955   PetscInt          *depthSizeOld, *rdepthSize, *rdepthSizeOld, *rdepthMaxOld, *rvStart, *rvStartNew, *reStart, *reStartNew, *rfStart, *rfStartNew, *rcStart, *rcStartNew;
8956   PetscInt           ldepth, depth, numNeighbors, pStartNew, pEndNew, cStart, cEnd, cMax, vStart, vEnd, vMax, fStart, fEnd, fMax, eStart, eEnd, eMax, r, n;
8957   PetscInt           cStartNew = 0, vStartNew = 0, fStartNew = 0, eStartNew = 0;
8958   PetscErrorCode     ierr;
8959 
8960   PetscFunctionBegin;
8961   ierr = DMPlexGetChart(rdm, &pStartNew, &pEndNew);CHKERRQ(ierr);
8962   ierr = DMPlexGetDepth(dm, &ldepth);CHKERRQ(ierr);
8963   ierr = MPIU_Allreduce(&ldepth, &depth, 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject) dm));CHKERRQ(ierr);
8964   if ((ldepth >= 0) && (depth != ldepth)) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Inconsistent Plex depth %D != %D", ldepth, depth);
8965   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
8966   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
8967   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
8968   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
8969   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
8970   cMax = cMax < 0 ? cEnd : cMax;
8971   fMax = fMax < 0 ? fEnd : fMax;
8972   eMax = eMax < 0 ? eEnd : eMax;
8973   if (refiner) {ierr = GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);CHKERRQ(ierr);}
8974   ierr = DMGetPointSF(dm, &sf);CHKERRQ(ierr);
8975   ierr = DMGetPointSF(rdm, &sfNew);CHKERRQ(ierr);
8976   /* Calculate size of new SF */
8977   ierr = PetscSFGetGraph(sf, &numRoots, &numLeaves, &localPoints, &remotePoints);CHKERRQ(ierr);
8978   if (numRoots < 0) PetscFunctionReturn(0);
8979   for (l = 0; l < numLeaves; ++l) {
8980     const PetscInt p = localPoints[l];
8981 
8982     switch (refiner) {
8983     case REFINER_SIMPLEX_1D:
8984       if ((p >= vStart) && (p < vEnd)) {
8985         /* Interior vertices stay the same */
8986         ++numLeavesNew;
8987       } else if ((p >= cStart && p < cMax)) {
8988         /* Interior cells add new cells and interior vertices */
8989         numLeavesNew += 2 + 1;
8990       }
8991       break;
8992     case REFINER_SIMPLEX_2D:
8993     case REFINER_HYBRID_SIMPLEX_2D:
8994       if ((p >= vStart) && (p < vEnd)) {
8995         /* Interior vertices stay the same */
8996         ++numLeavesNew;
8997       } else if ((p >= fStart) && (p < fMax)) {
8998         /* Interior faces add new faces and vertex */
8999         numLeavesNew += 2 + 1;
9000       } else if ((p >= fMax) && (p < fEnd)) {
9001         /* Hybrid faces stay the same */
9002         ++numLeavesNew;
9003       } else if ((p >= cStart) && (p < cMax)) {
9004         /* Interior cells add new cells and interior faces */
9005         numLeavesNew += 4 + 3;
9006       } else if ((p >= cMax) && (p < cEnd)) {
9007         /* Hybrid cells add new cells and hybrid face */
9008         numLeavesNew += 2 + 1;
9009       }
9010       break;
9011     case REFINER_HYBRID_SIMPLEX_TO_HEX_2D:
9012     case REFINER_SIMPLEX_TO_HEX_2D:
9013       if ((p >= vStart) && (p < vEnd)) {
9014         /* Interior vertices stay the same */
9015         ++numLeavesNew;
9016       } else if ((p >= fStart) && (p < fEnd)) {
9017         /* Interior faces add new faces and vertex */
9018         numLeavesNew += 2 + 1;
9019       } else if ((p >= cStart) && (p < cMax)) {
9020         /* Interior cells add new cells, interior faces, and vertex */
9021         numLeavesNew += 3 + 3 + 1;
9022       } else if ((p >= cMax) && (p < cEnd)) {
9023         /* Hybrid cells add new cells, interior faces, and vertex */
9024         numLeavesNew += 4 + 4 + 1;
9025       }
9026       break;
9027     case REFINER_HEX_2D:
9028     case REFINER_HYBRID_HEX_2D:
9029       if ((p >= vStart) && (p < vEnd)) {
9030         /* Interior vertices stay the same */
9031         ++numLeavesNew;
9032       } else if ((p >= fStart) && (p < fMax)) {
9033         /* Interior faces add new faces and vertex */
9034         numLeavesNew += 2 + 1;
9035       } else if ((p >= fMax) && (p < fEnd)) {
9036         /* Hybrid faces stay the same */
9037         ++numLeavesNew;
9038       } else if ((p >= cStart) && (p < cMax)) {
9039         /* Interior cells add new cells, interior faces, and vertex */
9040         numLeavesNew += 4 + 4 + 1;
9041       } else if ((p >= cMax) && (p < cEnd)) {
9042         /* Hybrid cells add new cells and hybrid face */
9043         numLeavesNew += 2 + 1;
9044       }
9045       break;
9046     case REFINER_SIMPLEX_3D:
9047     case REFINER_HYBRID_SIMPLEX_3D:
9048       if ((p >= vStart) && (p < vEnd)) {
9049         /* Interior vertices stay the same */
9050         ++numLeavesNew;
9051       } else if ((p >= eStart) && (p < eMax)) {
9052         /* Interior edges add new edges and vertex */
9053         numLeavesNew += 2 + 1;
9054       } else if ((p >= eMax) && (p < eEnd)) {
9055         /* Hybrid edges stay the same */
9056         ++numLeavesNew;
9057       } else if ((p >= fStart) && (p < fMax)) {
9058         /* Interior faces add new faces and edges */
9059         numLeavesNew += 4 + 3;
9060       } else if ((p >= fMax) && (p < fEnd)) {
9061         /* Hybrid faces add new faces and edges */
9062         numLeavesNew += 2 + 1;
9063       } else if ((p >= cStart) && (p < cMax)) {
9064         /* Interior cells add new cells, faces, and edges */
9065         numLeavesNew += 8 + 8 + 1;
9066       } else if ((p >= cMax) && (p < cEnd)) {
9067         /* Hybrid cells add new cells and faces */
9068         numLeavesNew += 4 + 3;
9069       }
9070       break;
9071     case REFINER_HYBRID_SIMPLEX_TO_HEX_3D:
9072     case REFINER_SIMPLEX_TO_HEX_3D:
9073       if ((p >= vStart) && (p < vEnd)) {
9074         /* Interior vertices stay the same */
9075         ++numLeavesNew;
9076       } else if ((p >= eStart) && (p < eMax)) {
9077         /* Interior edges add new edges and vertex */
9078         numLeavesNew += 2 + 1;
9079       } else if ((p >= eMax) && (p < eEnd)) {
9080         /* Hybrid edges stay the same */
9081         ++numLeavesNew;
9082       } else if ((p >= fStart) && (p < fMax)) {
9083         /* Interior faces add new faces, edges and a vertex */
9084         numLeavesNew += 3 + 3 + 1;
9085       } else if ((p >= fMax) && (p < fEnd)) {
9086         /* Hybrid faces add new faces and an edge */
9087         numLeavesNew += 2 + 1;
9088       } else if ((p >= cStart) && (p < cMax)) {
9089         /* Interior cells add new cells, faces, edges and a vertex */
9090         numLeavesNew += 4 + 6 + 4 + 1;
9091       } else if ((p >= cMax) && (p < cEnd)) {
9092         /* Hybrid cells add new cells, faces and an edge */
9093         numLeavesNew += 3 + 3 + 1;
9094       }
9095       break;
9096     case REFINER_HEX_3D:
9097     case REFINER_HYBRID_HEX_3D:
9098       if ((p >= vStart) && (p < vEnd)) {
9099         /* Old vertices stay the same */
9100         ++numLeavesNew;
9101       } else if ((p >= eStart) && (p < eMax)) {
9102         /* Interior edges add new edges, and vertex */
9103         numLeavesNew += 2 + 1;
9104       } else if ((p >= eMax) && (p < eEnd)) {
9105         /* Hybrid edges stay the same */
9106         ++numLeavesNew;
9107       } else if ((p >= fStart) && (p < fMax)) {
9108         /* Interior faces add new faces, edges, and vertex */
9109         numLeavesNew += 4 + 4 + 1;
9110       } else if ((p >= fMax) && (p < fEnd)) {
9111         /* Hybrid faces add new faces and edges */
9112         numLeavesNew += 2 + 1;
9113       } else if ((p >= cStart) && (p < cMax)) {
9114         /* Interior cells add new cells, faces, edges, and vertex */
9115         numLeavesNew += 8 + 12 + 6 + 1;
9116       } else if ((p >= cStart) && (p < cEnd)) {
9117         /* Hybrid cells add new cells, faces, and edges */
9118         numLeavesNew += 4 + 4 + 1;
9119       }
9120       break;
9121     default:
9122       SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %s", CellRefiners[refiner]);
9123     }
9124   }
9125   /* Communicate depthSizes for each remote rank */
9126   ierr = DMPlexCreateProcessSF(dm, sf, &processRanks, &sfProcess);CHKERRQ(ierr);
9127   ierr = ISGetLocalSize(processRanks, &numNeighbors);CHKERRQ(ierr);
9128   ierr = PetscMalloc5((depth+1)*numNeighbors,&rdepthSize,numNeighbors,&rvStartNew,numNeighbors,&reStartNew,numNeighbors,&rfStartNew,numNeighbors,&rcStartNew);CHKERRQ(ierr);
9129   ierr = PetscMalloc7(depth+1,&depthSizeOld,(depth+1)*numNeighbors,&rdepthSizeOld,(depth+1)*numNeighbors,&rdepthMaxOld,numNeighbors,&rvStart,numNeighbors,&reStart,numNeighbors,&rfStart,numNeighbors,&rcStart);CHKERRQ(ierr);
9130   ierr = MPI_Type_contiguous(depth+1, MPIU_INT, &depthType);CHKERRQ(ierr);
9131   ierr = MPI_Type_commit(&depthType);CHKERRQ(ierr);
9132   ierr = PetscSFBcastBegin(sfProcess, depthType, depthSize, rdepthSize);CHKERRQ(ierr);
9133   ierr = PetscSFBcastEnd(sfProcess, depthType, depthSize, rdepthSize);CHKERRQ(ierr);
9134   for (n = 0; n < numNeighbors; ++n) {
9135     ierr = GetDepthStart_Private(depth, &rdepthSize[n*(depth+1)], &rcStartNew[n], &rfStartNew[n], &reStartNew[n], &rvStartNew[n]);CHKERRQ(ierr);
9136   }
9137   depthSizeOld[depth]   = cMax;
9138   depthSizeOld[0]       = vMax;
9139   depthSizeOld[depth-1] = fMax;
9140   depthSizeOld[1]       = eMax;
9141 
9142   ierr = PetscSFBcastBegin(sfProcess, depthType, depthSizeOld, rdepthMaxOld);CHKERRQ(ierr);
9143   ierr = PetscSFBcastEnd(sfProcess, depthType, depthSizeOld, rdepthMaxOld);CHKERRQ(ierr);
9144 
9145   depthSizeOld[depth]   = cEnd - cStart;
9146   depthSizeOld[0]       = vEnd - vStart;
9147   depthSizeOld[depth-1] = fEnd - fStart;
9148   depthSizeOld[1]       = eEnd - eStart;
9149 
9150   ierr = PetscSFBcastBegin(sfProcess, depthType, depthSizeOld, rdepthSizeOld);CHKERRQ(ierr);
9151   ierr = PetscSFBcastEnd(sfProcess, depthType, depthSizeOld, rdepthSizeOld);CHKERRQ(ierr);
9152   for (n = 0; n < numNeighbors; ++n) {
9153     ierr = GetDepthStart_Private(depth, &rdepthSizeOld[n*(depth+1)], &rcStart[n], &rfStart[n], &reStart[n], &rvStart[n]);CHKERRQ(ierr);
9154     rdepthMaxOld[n*(depth+1)+depth]   = rdepthMaxOld[n*(depth+1)+depth]   < 0 ? rdepthSizeOld[n*(depth+1)+depth]  +rcStart[n]: rdepthMaxOld[n*(depth+1)+depth];
9155     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];
9156     rdepthMaxOld[n*(depth+1)+1]       = rdepthMaxOld[n*(depth+1)+1]       < 0 ? rdepthSizeOld[n*(depth+1)+1]      +reStart[n]: rdepthMaxOld[n*(depth+1)+1];
9157   }
9158   ierr = MPI_Type_free(&depthType);CHKERRQ(ierr);
9159   ierr = PetscSFDestroy(&sfProcess);CHKERRQ(ierr);
9160   /* Calculate new point SF */
9161   ierr = PetscMalloc1(numLeavesNew, &localPointsNew);CHKERRQ(ierr);
9162   ierr = PetscMalloc1(numLeavesNew, &remotePointsNew);CHKERRQ(ierr);
9163   ierr = ISGetIndices(processRanks, &neighbors);CHKERRQ(ierr);
9164   for (l = 0, m = 0; l < numLeaves; ++l) {
9165     PetscInt    p     = localPoints[l];
9166     PetscInt    rp    = remotePoints[l].index, n;
9167     PetscMPIInt rrank = remotePoints[l].rank;
9168 
9169     ierr = PetscFindInt(rrank, numNeighbors, neighbors, &n);CHKERRQ(ierr);
9170     if (n < 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Could not locate remote rank %D", rrank);
9171     switch (refiner) {
9172     case REFINER_SIMPLEX_1D:
9173       if ((p >= vStart) && (p < vEnd)) {
9174         /* Old vertices stay the same */
9175         localPointsNew[m]        = vStartNew     + (p  - vStart);
9176         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
9177         remotePointsNew[m].rank  = rrank;
9178         ++m;
9179       } else if ((p >= cStart) && (p < cMax)) {
9180         /* Old interior cells add new cells and vertex */
9181         for (r = 0; r < 2; ++r, ++m) {
9182           localPointsNew[m]        = cStartNew     + (p  - cStart)*2     + r;
9183           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*2 + r;
9184           remotePointsNew[m].rank  = rrank;
9185         }
9186         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - cStart);
9187         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - rcStart[n]);
9188         remotePointsNew[m].rank  = rrank;
9189         ++m;
9190       }
9191       break;
9192     case REFINER_SIMPLEX_2D:
9193     case REFINER_HYBRID_SIMPLEX_2D:
9194       if ((p >= vStart) && (p < vEnd)) {
9195         /* Old vertices stay the same */
9196         localPointsNew[m]        = vStartNew     + (p  - vStart);
9197         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
9198         remotePointsNew[m].rank  = rrank;
9199         ++m;
9200       } else if ((p >= fStart) && (p < fMax)) {
9201         /* Old interior faces add new faces and vertex */
9202         for (r = 0; r < 2; ++r, ++m) {
9203           localPointsNew[m]        = fStartNew     + (p  - fStart)*2     + r;
9204           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*2 + r;
9205           remotePointsNew[m].rank  = rrank;
9206         }
9207         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - fStart);
9208         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - rfStart[n]);
9209         remotePointsNew[m].rank  = rrank;
9210         ++m;
9211       } else if ((p >= fMax) && (p < fEnd)) {
9212         /* Old hybrid faces stay the same */
9213         localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (p  - fMax);
9214         remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*2 + (rp - rdepthMaxOld[n*(depth+1)+depth-1]);
9215         remotePointsNew[m].rank  = rrank;
9216         ++m;
9217       } else if ((p >= cStart) && (p < cMax)) {
9218         /* Old interior cells add new cells and interior faces */
9219         for (r = 0; r < 4; ++r, ++m) {
9220           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
9221           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
9222           remotePointsNew[m].rank  = rrank;
9223         }
9224         for (r = 0; r < 3; ++r, ++m) {
9225           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (p  - cStart)*3     + r;
9226           remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*2 + (rp - rcStart[n])*3 + r;
9227           remotePointsNew[m].rank  = rrank;
9228         }
9229       } else if ((p >= cMax) && (p < cEnd)) {
9230         /* Old hybrid cells add new cells and hybrid face */
9231         for (r = 0; r < 2; ++r, ++m) {
9232           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
9233           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
9234           remotePointsNew[m].rank  = rrank;
9235         }
9236         localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (cMax                            - cStart)*3     + (p  - cMax);
9237         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]);
9238         remotePointsNew[m].rank  = rrank;
9239         ++m;
9240       }
9241       break;
9242     case REFINER_HYBRID_SIMPLEX_TO_HEX_2D:
9243     case REFINER_SIMPLEX_TO_HEX_2D:
9244       if ((p >= vStart) && (p < vEnd)) {
9245         /* Old vertices stay the same */
9246         localPointsNew[m]        = vStartNew     + (p  - vStart);
9247         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
9248         remotePointsNew[m].rank  = rrank;
9249         ++m;
9250       } else if ((p >= fStart) && (p < fEnd)) {
9251         /* Old interior faces add new faces and vertex */
9252         for (r = 0; r < 2; ++r, ++m) {
9253           localPointsNew[m]        = fStartNew     + (p  - fStart)*2     + r;
9254           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*2 + r;
9255           remotePointsNew[m].rank  = rrank;
9256         }
9257         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - fStart);
9258         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - rfStart[n]);
9259         remotePointsNew[m].rank  = rrank;
9260         ++m;
9261       } else if ((p >= cStart) && (p < cMax)) {
9262         /* Old interior cells add new cells, interior faces, and a vertex */
9263         for (r = 0; r < 3; ++r, ++m) {
9264           localPointsNew[m]        = cStartNew     + (p  - cStart)*3     + r;
9265           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*3 + r;
9266           remotePointsNew[m].rank  = rrank;
9267         }
9268         for (r = 0; r < 3; ++r, ++m) {
9269           localPointsNew[m]        = fStartNew     + (fEnd - fStart)*2                    + (p  - cStart)*3     + r;
9270           remotePointsNew[m].index = rfStartNew[n] + rdepthSizeOld[n*(depth+1)+depth-1]*2 + (rp - rcStart[n])*3 + r;
9271           remotePointsNew[m].rank  = rrank;
9272         }
9273         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (fEnd - fStart)                    + (p  - cStart);
9274         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + rdepthSizeOld[n*(depth+1)+depth-1] + (rp - rcStart[n]);
9275         remotePointsNew[m].rank  = rrank;
9276         ++m;
9277       } else if ((p >= cMax) && (p < cEnd)) {
9278         /* Old interior hybrid cells add new cells, interior faces, and a vertex */
9279         for (r = 0; r < 4; ++r, ++m) {
9280           localPointsNew[m]        = cStartNew     + (cMax  - cStart)*3                               + (p  - cMax)*4 + r;
9281           remotePointsNew[m].index = rcStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth] - rcStart[n])*3 + (rp - rdepthMaxOld[n*(depth+1)+depth])*4 + r;
9282           remotePointsNew[m].rank  = rrank;
9283         }
9284         for (r = 0; r < 4; ++r, ++m) {
9285           localPointsNew[m]        = fStartNew     + (fEnd - fStart)*2                    + (cMax  - cStart)*3                               + (p - cMax)*4 + r;
9286           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;
9287           remotePointsNew[m].rank  = rrank;
9288         }
9289         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (fEnd - fStart)                    + (p  - cStart);
9290         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + rdepthSizeOld[n*(depth+1)+depth-1] + (rp - rcStart[n]);
9291         remotePointsNew[m].rank  = rrank;
9292         ++m;
9293       }
9294       break;
9295     case REFINER_HEX_2D:
9296     case REFINER_HYBRID_HEX_2D:
9297       if ((p >= vStart) && (p < vEnd)) {
9298         /* Old vertices stay the same */
9299         localPointsNew[m]        = vStartNew     + (p  - vStart);
9300         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
9301         remotePointsNew[m].rank  = rrank;
9302         ++m;
9303       } else if ((p >= fStart) && (p < fMax)) {
9304         /* Old interior faces add new faces and vertex */
9305         for (r = 0; r < 2; ++r, ++m) {
9306           localPointsNew[m]        = fStartNew     + (p  - fStart)*2     + r;
9307           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*2 + r;
9308           remotePointsNew[m].rank  = rrank;
9309         }
9310         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - fStart);
9311         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - rfStart[n]);
9312         remotePointsNew[m].rank  = rrank;
9313         ++m;
9314       } else if ((p >= fMax) && (p < fEnd)) {
9315         /* Old hybrid faces stay the same */
9316         localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (p  - fMax);
9317         remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*2 + (rp - rdepthMaxOld[n*(depth+1)+depth-1]);
9318         remotePointsNew[m].rank  = rrank;
9319         ++m;
9320       } else if ((p >= cStart) && (p < cMax)) {
9321         /* Old interior cells add new cells, interior faces, and vertex */
9322         for (r = 0; r < 4; ++r, ++m) {
9323           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
9324           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
9325           remotePointsNew[m].rank  = rrank;
9326         }
9327         for (r = 0; r < 4; ++r, ++m) {
9328           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (p  - cStart)*4     + r;
9329           remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*2 + (rp - rcStart[n])*4 + r;
9330           remotePointsNew[m].rank  = rrank;
9331         }
9332         localPointsNew[m]        = vStartNew     + (vEnd - vStart)               + (fMax                              - fStart)     + (p  - cStart);
9333         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0]  + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n]) + (rp - rcStart[n]);
9334         remotePointsNew[m].rank  = rrank;
9335         ++m;
9336       } else if ((p >= cStart) && (p < cMax)) {
9337         /* Old hybrid cells add new cells and hybrid face */
9338         for (r = 0; r < 2; ++r, ++m) {
9339           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r; /* TODO: is this a bug? */
9340           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r; /* TODO: is this a bug? */
9341           remotePointsNew[m].rank  = rrank;
9342         }
9343         localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (cMax                            - cStart)*4     + (p  - cMax);
9344         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]);
9345         remotePointsNew[m].rank  = rrank;
9346         ++m;
9347       }
9348       break;
9349     case REFINER_SIMPLEX_3D:
9350     case REFINER_HYBRID_SIMPLEX_3D:
9351       if ((p >= vStart) && (p < vEnd)) {
9352         /* Interior vertices stay the same */
9353         localPointsNew[m]        = vStartNew     + (p  - vStart);
9354         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
9355         remotePointsNew[m].rank  = rrank;
9356         ++m;
9357       } else if ((p >= eStart) && (p < eMax)) {
9358         /* Interior edges add new edges and vertex */
9359         for (r = 0; r < 2; ++r, ++m) {
9360           localPointsNew[m]        = eStartNew     + (p  - eStart)*2     + r;
9361           remotePointsNew[m].index = reStartNew[n] + (rp - reStart[n])*2 + r;
9362           remotePointsNew[m].rank  = rrank;
9363         }
9364         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - eStart);
9365         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - reStart[n]);
9366         remotePointsNew[m].rank  = rrank;
9367         ++m;
9368       } else if ((p >= eMax) && (p < eEnd)) {
9369         /* Hybrid edges stay the same */
9370         localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (fMax                              - fStart)*3     + (cMax                            - cStart)     + (p  - eMax);
9371         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]);
9372         remotePointsNew[m].rank  = rrank;
9373         ++m;
9374       } else if ((p >= fStart) && (p < fMax)) {
9375         /* Interior faces add new faces and edges */
9376         for (r = 0; r < 4; ++r, ++m) {
9377           localPointsNew[m]        = fStartNew     + (p  - fStart)*4     + r;
9378           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*4 + r;
9379           remotePointsNew[m].rank  = rrank;
9380         }
9381         for (r = 0; r < 3; ++r, ++m) {
9382           localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (p  - fStart)*3     + r;
9383           remotePointsNew[m].index = reStartNew[n] + (rdepthMaxOld[n*(depth+1)+1] - reStart[n])*2 + (rp - rfStart[n])*3 + r;
9384           remotePointsNew[m].rank  = rrank;
9385         }
9386       } else if ((p >= fMax) && (p < fEnd)) {
9387         /* Hybrid faces add new faces and edges */
9388         for (r = 0; r < 2; ++r, ++m) {
9389           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*4     + (cMax                            - cStart)*8     + (p  - fMax)*2                              + r;
9390           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;
9391           remotePointsNew[m].rank  = rrank;
9392         }
9393         localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (fMax                              - fStart)*3     + (cMax                            - cStart)     + (eEnd                                    - eMax)                        + (p  - fMax);
9394         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]);
9395         remotePointsNew[m].rank  = rrank;
9396         ++m;
9397       } else if ((p >= cStart) && (p < cMax)) {
9398         /* Interior cells add new cells, faces, and edges */
9399         for (r = 0; r < 8; ++r, ++m) {
9400           localPointsNew[m]        = cStartNew     + (p  - cStart)*8     + r;
9401           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*8 + r;
9402           remotePointsNew[m].rank  = rrank;
9403         }
9404         for (r = 0; r < 8; ++r, ++m) {
9405           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*4     + (p  - cStart)*8     + r;
9406           remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*4 + (rp - rcStart[n])*8 + r;
9407           remotePointsNew[m].rank  = rrank;
9408         }
9409         localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (fMax                              - fStart)*3     + (p  - cStart)*1     + 0;
9410         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;
9411         remotePointsNew[m].rank  = rrank;
9412         ++m;
9413       } else if ((p >= cMax) && (p < cEnd)) {
9414         /* Hybrid cells add new cells and faces */
9415         for (r = 0; r < 4; ++r, ++m) {
9416           localPointsNew[m]        = cStartNew     + (cMax                            - cStart)*8     + (p  - cMax)*4                            + r;
9417           remotePointsNew[m].index = rcStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth] - rcStart[n])*8 + (rp - rdepthMaxOld[n*(depth+1)+depth])*4 + r;
9418           remotePointsNew[m].rank  = rrank;
9419         }
9420         for (r = 0; r < 3; ++r, ++m) {
9421           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*4     + (cMax                            - cStart)*8     + (fEnd                                          - fMax)*2                              + (p  - cMax)*3                            + r;
9422           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;
9423           remotePointsNew[m].rank  = rrank;
9424         }
9425       }
9426       break;
9427     case REFINER_HYBRID_SIMPLEX_TO_HEX_3D:
9428     case REFINER_SIMPLEX_TO_HEX_3D:
9429       if ((p >= vStart) && (p < vEnd)) {
9430         /* Interior vertices stay the same */
9431         localPointsNew[m]        = vStartNew     + (p  - vStart);
9432         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
9433         remotePointsNew[m].rank  = rrank;
9434         ++m;
9435       } else if ((p >= eStart) && (p < eMax)) {
9436         /* Interior edges add new edges and vertex */
9437         for (r = 0; r < 2; ++r, ++m) {
9438           localPointsNew[m]        = eStartNew     + (p  - eStart)*2     + r;
9439           remotePointsNew[m].index = reStartNew[n] + (rp - reStart[n])*2 + r;
9440           remotePointsNew[m].rank  = rrank;
9441         }
9442         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - eStart);
9443         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - reStart[n]);
9444         remotePointsNew[m].rank  = rrank;
9445         ++m;
9446       } else if ((p >= eMax) && (p < eEnd)) {
9447         /* Hybrid edges stay the same */
9448         localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (fMax                              - fStart)*3     + (cMax                            - cStart)*4     + (p  - eMax);
9449         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]);
9450         remotePointsNew[m].rank  = rrank;
9451         ++m;
9452       } else if ((p >= fStart) && (p < fMax)) {
9453         /* Interior faces add new faces, edges and a vertex */
9454         for (r = 0; r < 3; ++r, ++m) {
9455           localPointsNew[m]        = fStartNew     + (p  - fStart)*3     + r;
9456           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*3 + r;
9457           remotePointsNew[m].rank  = rrank;
9458         }
9459         for (r = 0; r < 3; ++r, ++m) {
9460           localPointsNew[m]        = eStartNew     + (eMax - eStart)*2                            + (p  - fStart)*3     + r;
9461           remotePointsNew[m].index = reStartNew[n] + (rdepthMaxOld[n*(depth+1)+1] - reStart[n])*2 + (rp - rfStart[n])*3 + r;
9462           remotePointsNew[m].rank  = rrank;
9463         }
9464         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (eMax - eStart)                            + (p - fStart);
9465         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rdepthMaxOld[n*(depth+1)+1] - reStart[n]) + (rp - rfStart[n]);
9466         remotePointsNew[m].rank  = rrank;
9467         ++m;
9468       } else if ((p >= fMax) && (p < fEnd)) {
9469         /* Interior hybrid faces add new faces and an edge */
9470         for (r = 0; r < 2; ++r, ++m) {
9471           localPointsNew[m]        = fStartNew     + (fMax - fStart)*3                                 + (cMax - cStart)*6                                + (p  - fMax)*2 + r;
9472           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;
9473           remotePointsNew[m].rank  = rrank;
9474         }
9475         localPointsNew[m]        = eStartNew     + (eMax - eStart)*2                            + (fMax - fStart)*3                                 + (cMax - cStart)*4                                + (eEnd - eMax)                                                           + (p  - fMax);
9476         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]);
9477         remotePointsNew[m].rank  = rrank;
9478         ++m;
9479       } else if ((p >= cStart) && (p < cMax)) {
9480         /* Interior cells add new cells, faces, edges, and a vertex */
9481         for (r = 0; r < 4; ++r, ++m) {
9482           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
9483           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
9484           remotePointsNew[m].rank  = rrank;
9485         }
9486         for (r = 0; r < 6; ++r, ++m) {
9487           localPointsNew[m]        = fStartNew     + (fMax - fStart)*3                                 + (p  - cStart)*6     + r;
9488           remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1]- rfStart[n])*3 + (rp - rcStart[n])*6 + r;
9489           remotePointsNew[m].rank  = rrank;
9490         }
9491         for (r = 0; r < 4; ++r, ++m) {
9492           localPointsNew[m]        = eStartNew     + (eMax - eStart)*2                           + (fMax - fStart)*3                                 + (p  - cStart)*4 + r;
9493           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;
9494           remotePointsNew[m].rank  = rrank;
9495         }
9496         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (eMax - eStart)                           + (fMax - fStart)                                 + (p  - cStart);
9497         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]);
9498         remotePointsNew[m].rank  = rrank;
9499         ++m;
9500       } else if ((p >= cMax) && (p < cEnd)) {
9501         /* Interior hybrid cells add new cells, faces and an edge */
9502         for (r = 0; r < 3; ++r, ++m) {
9503           localPointsNew[m]        = cStartNew     + (cMax                            - cStart)*4     + (p  - cMax)*3                            + r;
9504           remotePointsNew[m].index = rcStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth] - rcStart[n])*4 + (rp - rdepthMaxOld[n*(depth+1)+depth])*3 + r;
9505           remotePointsNew[m].rank  = rrank;
9506         }
9507         for (r = 0; r < 3; ++r, ++m) {
9508           localPointsNew[m]        = fStartNew     + (fMax - fStart)*3                                 + (cMax - cStart)*6                                + (fEnd  - fMax)*2                                                                      + (p  - cMax)*3 + r;
9509           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;
9510           remotePointsNew[m].rank  = rrank;
9511         }
9512         localPointsNew[m]        = eStartNew     + (eMax - eStart)*2                           + (fMax - fStart)*3                                 + (cMax - cStart)*4                                + (eEnd  - eMax)                                                          + (fEnd  - fMax)                                                                      + (p  - cMax);
9513         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]);
9514         remotePointsNew[m].rank  = rrank;
9515         ++m;
9516       }
9517       break;
9518     case REFINER_HEX_3D:
9519     case REFINER_HYBRID_HEX_3D:
9520       if ((p >= vStart) && (p < vEnd)) {
9521         /* Interior vertices stay the same */
9522         localPointsNew[m]        = vStartNew     + (p  - vStart);
9523         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
9524         remotePointsNew[m].rank  = rrank;
9525         ++m;
9526       } else if ((p >= eStart) && (p < eMax)) {
9527         /* Interior edges add new edges and vertex */
9528         for (r = 0; r < 2; ++r, ++m) {
9529           localPointsNew[m]        = eStartNew     + (p  - eStart)*2     + r;
9530           remotePointsNew[m].index = reStartNew[n] + (rp - reStart[n])*2 + r;
9531           remotePointsNew[m].rank  = rrank;
9532         }
9533         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - eStart);
9534         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - reStart[n]);
9535         remotePointsNew[m].rank  = rrank;
9536         ++m;
9537       } else if ((p >= eMax) && (p < eEnd)) {
9538         /* Hybrid edges stay the same */
9539         localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (fMax                              - fStart)*4     + (cMax                            - cStart)*6     + (p  - eMax);
9540         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]);
9541         remotePointsNew[m].rank  = rrank;
9542         ++m;
9543       } else if ((p >= fStart) && (p < fMax)) {
9544         /* Interior faces add new faces, edges, and vertex */
9545         for (r = 0; r < 4; ++r, ++m) {
9546           localPointsNew[m]        = fStartNew     + (p  - fStart)*4     + r;
9547           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*4 + r;
9548           remotePointsNew[m].rank  = rrank;
9549         }
9550         for (r = 0; r < 4; ++r, ++m) {
9551           localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (p  - fStart)*4     + r;
9552           remotePointsNew[m].index = reStartNew[n] + (rdepthMaxOld[n*(depth+1)+1] - reStart[n])*2 + (rp - rfStart[n])*4 + r;
9553           remotePointsNew[m].rank  = rrank;
9554         }
9555         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (eMax                        - eStart)     + (p  - fStart);
9556         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rdepthMaxOld[n*(depth+1)+1] - reStart[n]) + (rp - rfStart[n]);
9557         remotePointsNew[m].rank  = rrank;
9558         ++m;
9559       } else if ((p >= fMax) && (p < fEnd)) {
9560         /* Hybrid faces add new faces and edges */
9561         for (r = 0; r < 2; ++r, ++m) {
9562           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*4     + (cMax                            - cStart)*12     + (p  - fMax)*2                              + r;
9563           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;
9564           remotePointsNew[m].rank  = rrank;
9565         }
9566         localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (fMax                              - fStart)*4     + (cMax                            - cStart)*6     + (eEnd                                    - eMax)                        + (p  - fMax);
9567         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]);
9568         remotePointsNew[m].rank  = rrank;
9569         ++m;
9570       } else if ((p >= cStart) && (p < cMax)) {
9571         /* Interior cells add new cells, faces, edges, and vertex */
9572         for (r = 0; r < 8; ++r, ++m) {
9573           localPointsNew[m]        = cStartNew     + (p  - cStart)*8     + r;
9574           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*8 + r;
9575           remotePointsNew[m].rank  = rrank;
9576         }
9577         for (r = 0; r < 12; ++r, ++m) {
9578           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*4     + (p  - cStart)*12     + r;
9579           remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*4 + (rp - rcStart[n])*12 + r;
9580           remotePointsNew[m].rank  = rrank;
9581         }
9582         for (r = 0; r < 6; ++r, ++m) {
9583           localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (fMax                              - fStart)*4     + (p  - cStart)*6     + r;
9584           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;
9585           remotePointsNew[m].rank  = rrank;
9586         }
9587         for (r = 0; r < 1; ++r, ++m) {
9588           localPointsNew[m]        = vStartNew     + (eMax                        - eStart)     + (fMax                              - fStart)     + (p  - cStart)     + r;
9589           remotePointsNew[m].index = rvStartNew[n] + (rdepthMaxOld[n*(depth+1)+1] - reStart[n]) + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n]) + (rp - rcStart[n]) + r;
9590           remotePointsNew[m].rank  = rrank;
9591         }
9592       } else if ((p >= cMax) && (p < cEnd)) {
9593         /* Hybrid cells add new cells, faces, and edges */
9594         for (r = 0; r < 4; ++r, ++m) {
9595           localPointsNew[m]        = cStartNew     + (cMax                            - cStart)*8     + (p  - cMax)*4                            + r;
9596           remotePointsNew[m].index = rcStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth] - rcStart[n])*8 + (rp - rdepthMaxOld[n*(depth+1)+depth])*4 + r;
9597           remotePointsNew[m].rank  = rrank;
9598         }
9599         for (r = 0; r < 4; ++r, ++m) {
9600           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*4     + (cMax                            - cStart)*12     + (fEnd                                          - fMax)*2                              + (p  - cMax)*4                            + r;
9601           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;
9602           remotePointsNew[m].rank  = rrank;
9603         }
9604         localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (fMax                              - fStart)*4     + (cMax                            - cStart)*6     + (eEnd                                    - eMax)                        + (fEnd                                          - fMax)                              + (p  - cMax);
9605         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]);
9606         remotePointsNew[m].rank  = rrank;
9607         ++m;
9608       }
9609       break;
9610     default:
9611       SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %s", CellRefiners[refiner]);
9612     }
9613   }
9614   if (m != numLeavesNew) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Number of leaf point %D should be %D", m, numLeavesNew);
9615   ierr = ISRestoreIndices(processRanks, &neighbors);CHKERRQ(ierr);
9616   ierr = ISDestroy(&processRanks);CHKERRQ(ierr);
9617   {
9618     PetscSFNode *rp, *rtmp;
9619     PetscInt    *lp, *idx, *ltmp, i;
9620 
9621     /* SF needs sorted leaves to correct calculate Gather */
9622     ierr = PetscMalloc1(numLeavesNew,&idx);CHKERRQ(ierr);
9623     ierr = PetscMalloc1(numLeavesNew, &lp);CHKERRQ(ierr);
9624     ierr = PetscMalloc1(numLeavesNew, &rp);CHKERRQ(ierr);
9625     for (i = 0; i < numLeavesNew; ++i) {
9626       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);
9627       idx[i] = i;
9628     }
9629     ierr = PetscSortIntWithPermutation(numLeavesNew, localPointsNew, idx);CHKERRQ(ierr);
9630     for (i = 0; i < numLeavesNew; ++i) {
9631       lp[i] = localPointsNew[idx[i]];
9632       rp[i] = remotePointsNew[idx[i]];
9633     }
9634     ltmp            = localPointsNew;
9635     localPointsNew  = lp;
9636     rtmp            = remotePointsNew;
9637     remotePointsNew = rp;
9638     ierr = PetscFree(idx);CHKERRQ(ierr);
9639     ierr = PetscFree(ltmp);CHKERRQ(ierr);
9640     ierr = PetscFree(rtmp);CHKERRQ(ierr);
9641   }
9642   ierr = PetscSFSetGraph(sfNew, pEndNew-pStartNew, numLeavesNew, localPointsNew, PETSC_OWN_POINTER, remotePointsNew, PETSC_OWN_POINTER);CHKERRQ(ierr);
9643   ierr = PetscFree5(rdepthSize,rvStartNew,reStartNew,rfStartNew,rcStartNew);CHKERRQ(ierr);
9644   ierr = PetscFree7(depthSizeOld,rdepthSizeOld,rdepthMaxOld,rvStart,reStart,rfStart,rcStart);CHKERRQ(ierr);
9645   PetscFunctionReturn(0);
9646 }
9647 
9648 static PetscErrorCode CellRefinerCreateLabels(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
9649 {
9650   PetscInt       numLabels, l;
9651   PetscInt       depth, newp, cStart, cEnd, cMax, vStart, vEnd, vMax, fStart, fEnd, fMax, eStart, eEnd, eMax, r;
9652   PetscInt       cStartNew = 0, vStartNew = 0, fStartNew = 0, eStartNew = 0;
9653   PetscErrorCode ierr;
9654 
9655   PetscFunctionBegin;
9656   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
9657   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
9658   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
9659   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
9660   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
9661   if (refiner) {ierr = GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);CHKERRQ(ierr);}
9662   ierr = DMGetNumLabels(dm, &numLabels);CHKERRQ(ierr);
9663   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
9664   switch (refiner) {
9665   case REFINER_NOOP:
9666   case REFINER_SIMPLEX_1D:
9667   case REFINER_SIMPLEX_2D:
9668   case REFINER_SIMPLEX_TO_HEX_2D:
9669   case REFINER_HEX_2D:
9670   case REFINER_SIMPLEX_3D:
9671   case REFINER_HEX_3D:
9672   case REFINER_SIMPLEX_TO_HEX_3D:
9673     break;
9674   case REFINER_HYBRID_SIMPLEX_TO_HEX_3D:
9675   case REFINER_HYBRID_SIMPLEX_3D:
9676   case REFINER_HYBRID_HEX_3D:
9677     if (eMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No edge maximum specified in hybrid mesh");
9678   case REFINER_HYBRID_SIMPLEX_2D:
9679   case REFINER_HYBRID_HEX_2D:
9680     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
9681   case REFINER_HYBRID_SIMPLEX_TO_HEX_2D:
9682     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
9683     break;
9684   default:
9685     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %s", CellRefiners[refiner]);
9686   }
9687   cMax = cMax < 0 ? cEnd : cMax;
9688   fMax = fMax < 0 ? fEnd : fMax;
9689   eMax = eMax < 0 ? eEnd : eMax;
9690   for (l = 0; l < numLabels; ++l) {
9691     DMLabel         label, labelNew;
9692     const char     *lname;
9693     PetscBool       isDepth, isCellType;
9694     IS              valueIS;
9695     const PetscInt *values;
9696     PetscInt        defVal;
9697     PetscInt        numValues, val;
9698 
9699     ierr = DMGetLabelName(dm, l, &lname);CHKERRQ(ierr);
9700     ierr = PetscStrcmp(lname, "depth", &isDepth);CHKERRQ(ierr);
9701     if (isDepth) continue;
9702     ierr = PetscStrcmp(lname, "celltype", &isCellType);CHKERRQ(ierr);
9703     if (isCellType) continue;
9704     ierr = DMCreateLabel(rdm, lname);CHKERRQ(ierr);
9705     ierr = DMGetLabel(dm, lname, &label);CHKERRQ(ierr);
9706     ierr = DMGetLabel(rdm, lname, &labelNew);CHKERRQ(ierr);
9707     ierr = DMLabelGetDefaultValue(label,&defVal);CHKERRQ(ierr);
9708     ierr = DMLabelSetDefaultValue(labelNew,defVal);CHKERRQ(ierr);
9709     ierr = DMLabelGetValueIS(label, &valueIS);CHKERRQ(ierr);
9710     ierr = ISGetLocalSize(valueIS, &numValues);CHKERRQ(ierr);
9711     ierr = ISGetIndices(valueIS, &values);CHKERRQ(ierr);
9712     for (val = 0; val < numValues; ++val) {
9713       IS              pointIS;
9714       const PetscInt *points;
9715       PetscInt        numPoints, n;
9716 
9717       ierr = DMLabelGetStratumIS(label, values[val], &pointIS);CHKERRQ(ierr);
9718       ierr = ISGetLocalSize(pointIS, &numPoints);CHKERRQ(ierr);
9719       ierr = ISGetIndices(pointIS, &points);CHKERRQ(ierr);
9720       /* Ensure refined label is created with same number of strata as
9721        * original (even if no entries here). */
9722       ierr = DMLabelAddStratum(labelNew, values[val]);CHKERRQ(ierr);
9723       for (n = 0; n < numPoints; ++n) {
9724         const PetscInt p = points[n];
9725         switch (refiner) {
9726         case REFINER_SIMPLEX_1D:
9727           if ((p >= vStart) && (p < vEnd)) {
9728             /* Old vertices stay the same */
9729             newp = vStartNew + (p - vStart);
9730             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9731           } else if ((p >= cStart) && (p < cEnd)) {
9732             /* Old cells add new cells and vertex */
9733             newp = vStartNew + (vEnd - vStart) + (p - cStart);
9734             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9735             for (r = 0; r < 2; ++r) {
9736               newp = cStartNew + (p - cStart)*2 + r;
9737               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9738             }
9739           }
9740           break;
9741         case REFINER_SIMPLEX_2D:
9742           if ((p >= vStart) && (p < vEnd)) {
9743             /* Old vertices stay the same */
9744             newp = vStartNew + (p - vStart);
9745             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9746           } else if ((p >= fStart) && (p < fEnd)) {
9747             /* Old faces add new faces and vertex */
9748             newp = vStartNew + (vEnd - vStart) + (p - fStart);
9749             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9750             for (r = 0; r < 2; ++r) {
9751               newp = fStartNew + (p - fStart)*2 + r;
9752               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9753             }
9754           } else if ((p >= cStart) && (p < cEnd)) {
9755             /* Old cells add new cells and interior faces */
9756             for (r = 0; r < 4; ++r) {
9757               newp = cStartNew + (p - cStart)*4 + r;
9758               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9759             }
9760             for (r = 0; r < 3; ++r) {
9761               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*3 + r;
9762               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9763             }
9764           }
9765           break;
9766         case REFINER_HYBRID_SIMPLEX_TO_HEX_2D:
9767         case REFINER_SIMPLEX_TO_HEX_2D:
9768           if ((p >= vStart) && (p < vEnd)) {
9769             /* Old vertices stay the same */
9770             newp = vStartNew + (p - vStart);
9771             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9772           } else if ((p >= fStart) && (p < fEnd)) {
9773             /* Old faces add new faces and vertex */
9774             newp = vStartNew + (vEnd - vStart) + (p - fStart);
9775             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9776             for (r = 0; r < 2; ++r) {
9777               newp = fStartNew + (p - fStart)*2 + r;
9778               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9779             }
9780           } else if ((p >= cStart) && (p < cMax)) {
9781             /* Old cells add new cells, interior faces, and a vertex */
9782             for (r = 0; r < 3; ++r) {
9783               newp = cStartNew + (p - cStart)*3 + r;
9784               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9785             }
9786             for (r = 0; r < 3; ++r) {
9787               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*3 + r;
9788               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9789             }
9790             newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + p;
9791             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9792           } else if ((p >= cMax) && (p < cEnd)) {
9793             /* Old hybrid cells add new cells, interior faces, and a vertex */
9794             for (r = 0; r < 4; ++r) {
9795               newp = cStartNew + (cMax - cStart)*3 + (p - cMax)*4 + r;
9796               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9797             }
9798             for (r = 0; r < 4; ++r) {
9799               newp = fStartNew + (fEnd - fStart)*2 + (cMax - cStart)*3 + (p - cMax)*4 + r;
9800               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9801             }
9802             newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + p;
9803             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9804           }
9805           break;
9806         case REFINER_HEX_2D:
9807           if ((p >= vStart) && (p < vEnd)) {
9808             /* Old vertices stay the same */
9809             newp = vStartNew + (p - vStart);
9810             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9811           } else if ((p >= fStart) && (p < fEnd)) {
9812             /* Old faces add new faces and vertex */
9813             newp = vStartNew + (vEnd - vStart) + (p - fStart);
9814             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9815             for (r = 0; r < 2; ++r) {
9816               newp = fStartNew + (p - fStart)*2 + r;
9817               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9818             }
9819           } else if ((p >= cStart) && (p < cEnd)) {
9820             /* Old cells add new cells and interior faces and vertex */
9821             for (r = 0; r < 4; ++r) {
9822               newp = cStartNew + (p - cStart)*4 + r;
9823               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9824             }
9825             for (r = 0; r < 4; ++r) {
9826               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*4 + r;
9827               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9828             }
9829             newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (p - cStart);
9830             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9831           }
9832           break;
9833         case REFINER_HYBRID_SIMPLEX_2D:
9834           if ((p >= vStart) && (p < vEnd)) {
9835             /* Old vertices stay the same */
9836             newp = vStartNew + (p - vStart);
9837             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9838           } else if ((p >= fStart) && (p < fMax)) {
9839             /* Old interior faces add new faces and vertex */
9840             newp = vStartNew + (vEnd - vStart) + (p - fStart);
9841             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9842             for (r = 0; r < 2; ++r) {
9843               newp = fStartNew + (p - fStart)*2 + r;
9844               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9845             }
9846           } else if ((p >= fMax) && (p < fEnd)) {
9847             /* Old hybrid faces stay the same */
9848             newp = fStartNew + (fMax - fStart)*2 + (p - fMax);
9849             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9850           } else if ((p >= cStart) && (p < cMax)) {
9851             /* Old interior cells add new cells and interior faces */
9852             for (r = 0; r < 4; ++r) {
9853               newp = cStartNew + (p - cStart)*4 + r;
9854               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9855             }
9856             for (r = 0; r < 3; ++r) {
9857               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*3 + r;
9858               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9859             }
9860           } else if ((p >= cMax) && (p < cEnd)) {
9861             /* Old hybrid cells add new cells and hybrid face */
9862             for (r = 0; r < 2; ++r) {
9863               newp = cStartNew + (cMax - cStart)*4 + (p - cMax)*2 + r;
9864               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9865             }
9866             newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (p - cMax);
9867             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9868           }
9869           break;
9870         case REFINER_HYBRID_HEX_2D:
9871           if ((p >= vStart) && (p < vEnd)) {
9872             /* Old vertices stay the same */
9873             newp = vStartNew + (p - vStart);
9874             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9875           } else if ((p >= fStart) && (p < fMax)) {
9876             /* Old interior faces add new faces and vertex */
9877             newp = vStartNew + (vEnd - vStart) + (p - fStart);
9878             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9879             for (r = 0; r < 2; ++r) {
9880               newp = fStartNew + (p - fStart)*2 + r;
9881               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9882             }
9883           } else if ((p >= fMax) && (p < fEnd)) {
9884             /* Old hybrid faces stay the same */
9885             newp = fStartNew + (fMax - fStart)*2 + (p - fMax);
9886             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9887           } else if ((p >= cStart) && (p < cMax)) {
9888             /* Old interior cells add new cells, interior faces, and vertex */
9889             for (r = 0; r < 4; ++r) {
9890               newp = cStartNew + (p - cStart)*4 + r;
9891               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9892             }
9893             for (r = 0; r < 4; ++r) {
9894               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*4 + r;
9895               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9896             }
9897             newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (p - cStart);
9898             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9899           } else if ((p >= cMax) && (p < cEnd)) {
9900             /* Old hybrid cells add new cells and hybrid face */
9901             for (r = 0; r < 2; ++r) {
9902               newp = cStartNew + (cMax - cStart)*4 + (p - cMax)*2 + r;
9903               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9904             }
9905             newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*4 + (p - cMax);
9906             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9907           }
9908           break;
9909         case REFINER_SIMPLEX_3D:
9910           if ((p >= vStart) && (p < vEnd)) {
9911             /* Old vertices stay the same */
9912             newp = vStartNew + (p - vStart);
9913             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9914           } else if ((p >= eStart) && (p < eEnd)) {
9915             /* Old edges add new edges and vertex */
9916             for (r = 0; r < 2; ++r) {
9917               newp = eStartNew + (p - eStart)*2 + r;
9918               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9919             }
9920             newp = vStartNew + (vEnd - vStart) + (p - eStart);
9921             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9922           } else if ((p >= fStart) && (p < fEnd)) {
9923             /* Old faces add new faces and edges */
9924             for (r = 0; r < 4; ++r) {
9925               newp = fStartNew + (p - fStart)*4 + r;
9926               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9927             }
9928             for (r = 0; r < 3; ++r) {
9929               newp = eStartNew + (eEnd - eStart)*2 + (p - fStart)*3 + r;
9930               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9931             }
9932           } else if ((p >= cStart) && (p < cEnd)) {
9933             /* Old cells add new cells and interior faces and edges */
9934             for (r = 0; r < 8; ++r) {
9935               newp = cStartNew + (p - cStart)*8 + r;
9936               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9937             }
9938             for (r = 0; r < 8; ++r) {
9939               newp = fStartNew + (fEnd - fStart)*4 + (p - cStart)*8 + r;
9940               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9941             }
9942             for (r = 0; r < 1; ++r) {
9943               newp = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (p - cStart)*1 + r;
9944               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9945             }
9946           }
9947           break;
9948         case REFINER_HYBRID_SIMPLEX_TO_HEX_3D:
9949         case REFINER_SIMPLEX_TO_HEX_3D:
9950           if ((p >= vStart) && (p < vEnd)) {
9951             /* Old vertices stay the same */
9952             newp = vStartNew + (p - vStart);
9953             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9954           } else if ((p >= eStart) && (p < eMax)) {
9955             /* Interior edges add new edges and vertex */
9956             for (r = 0; r < 2; ++r) {
9957               newp = eStartNew + (p - eStart)*2 + r;
9958               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9959             }
9960             newp = vStartNew + (vEnd - vStart) + (p - eStart);
9961             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9962           } else if ((p >= eMax) && (p < eEnd)) {
9963             /* Hybrid edges stay the same */
9964             newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart)*4 + p - eMax;
9965             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9966           } else if ((p >= fStart) && (p < fMax)) {
9967             /* Old faces add new faces, edges and a vertex */
9968             for (r = 0; r < 3; ++r) {
9969               newp = fStartNew + (p - fStart)*3 + r;
9970               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9971             }
9972             for (r = 0; r < 3; ++r) {
9973               newp = eStartNew + (eMax - eStart)*2 + (p - fStart)*3 + r;
9974               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9975             }
9976           } else if ((p >= fMax) && (p < fEnd)) {
9977             /* Old hybrid faces add new faces and an edge */
9978             for (r = 0; r < 2; ++r) {
9979               newp = fStartNew + (fMax - fStart)*3 + (cMax - cStart)*6 + (p - fMax)*2 + r;
9980               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9981             }
9982             newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart)*4 + (eEnd - eMax) + (p - fMax);
9983             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9984           } else if ((p >= cStart) && (p < cMax)) {
9985             /* Old cells add new cells and interior faces and edges and a vertex */
9986             for (r = 0; r < 4; ++r) {
9987               newp = cStartNew + (p - cStart)*4 + r;
9988               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9989             }
9990             for (r = 0; r < 6; ++r) {
9991               newp = fStartNew + (fMax - fStart)*3 + (p - cStart)*6 + r;
9992               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9993             }
9994             for (r = 0; r < 4; ++r) {
9995               newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (p - cStart)*4 + r;
9996               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9997             }
9998             newp = vStartNew + (vEnd - vStart) + (eMax - eStart) + (fMax - fStart) + p - cStart;
9999             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
10000           } else if ((p >= cMax) && (p < cEnd)) {
10001             /* Old hybrid cells add new cells and interior faces and an edge */
10002             for (r = 0; r < 3; ++r) {
10003               newp = cStartNew + (cMax - cStart)*4 + (p - cMax)*3 + r;
10004               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
10005             }
10006             for (r = 0; r < 3; ++r) {
10007               newp = fStartNew + (fMax - fStart)*3 + (cMax - cStart)*6 + (fEnd - fMax)*2 + (p - cMax)*3 + r;
10008               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
10009             }
10010             newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart)*4 + (eEnd - eMax) + (fEnd - fMax) + p - cMax;
10011             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
10012           }
10013           break;
10014         case REFINER_HYBRID_SIMPLEX_3D:
10015           if ((p >= vStart) && (p < vEnd)) {
10016             /* Interior vertices stay the same */
10017             newp = vStartNew + (p - vStart);
10018             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
10019           } else if ((p >= eStart) && (p < eMax)) {
10020             /* Interior edges add new edges and vertex */
10021             for (r = 0; r < 2; ++r) {
10022               newp = eStartNew + (p - eStart)*2 + r;
10023               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
10024             }
10025             newp = vStartNew + (vEnd - vStart) + (p - eStart);
10026             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
10027           } else if ((p >= eMax) && (p < eEnd)) {
10028             /* Hybrid edges stay the same */
10029             newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (p - eMax);
10030             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
10031           } else if ((p >= fStart) && (p < fMax)) {
10032             /* Interior faces add new faces and edges */
10033             for (r = 0; r < 4; ++r) {
10034               newp = fStartNew + (p - fStart)*4 + r;
10035               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
10036             }
10037             for (r = 0; r < 3; ++r) {
10038               newp = eStartNew + (eMax - eStart)*2 + (p - fStart)*3 + r;
10039               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
10040             }
10041           } else if ((p >= fMax) && (p < fEnd)) {
10042             /* Hybrid faces add new faces and edges */
10043             for (r = 0; r < 2; ++r) {
10044               newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (p - fMax)*2 + r;
10045               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
10046             }
10047             newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (p - fMax);
10048             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
10049           } else if ((p >= cStart) && (p < cMax)) {
10050             /* Interior cells add new cells, faces, and edges */
10051             for (r = 0; r < 8; ++r) {
10052               newp = cStartNew + (p - cStart)*8 + r;
10053               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
10054             }
10055             for (r = 0; r < 8; ++r) {
10056               newp = fStartNew + (fMax - fStart)*4 + (p - cStart)*8 + r;
10057               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
10058             }
10059             newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (p - cStart);
10060             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
10061           } else if ((p >= cMax) && (p < cEnd)) {
10062             /* Hybrid cells add new cells and faces */
10063             for (r = 0; r < 4; ++r) {
10064               newp = cStartNew + (cMax - cStart)*8 + (p - cMax)*4 + r;
10065               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
10066             }
10067             for (r = 0; r < 3; ++r) {
10068               newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (p - cMax)*3 + r;
10069               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
10070             }
10071           }
10072           break;
10073         case REFINER_HEX_3D:
10074           if ((p >= vStart) && (p < vEnd)) {
10075             /* Old vertices stay the same */
10076             newp = vStartNew + (p - vStart);
10077             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
10078           } else if ((p >= eStart) && (p < eEnd)) {
10079             /* Old edges add new edges and vertex */
10080             for (r = 0; r < 2; ++r) {
10081               newp = eStartNew + (p - eStart)*2 + r;
10082               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
10083             }
10084             newp = vStartNew + (vEnd - vStart) + (p - eStart);
10085             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
10086           } else if ((p >= fStart) && (p < fEnd)) {
10087             /* Old faces add new faces, edges, and vertex */
10088             for (r = 0; r < 4; ++r) {
10089               newp = fStartNew + (p - fStart)*4 + r;
10090               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
10091             }
10092             for (r = 0; r < 4; ++r) {
10093               newp = eStartNew + (eEnd - eStart)*2 + (p - fStart)*4 + r;
10094               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
10095             }
10096             newp = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (p - fStart);
10097             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
10098           } else if ((p >= cStart) && (p < cEnd)) {
10099             /* Old cells add new cells, faces, edges, and vertex */
10100             for (r = 0; r < 8; ++r) {
10101               newp = cStartNew + (p - cStart)*8 + r;
10102               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
10103             }
10104             for (r = 0; r < 12; ++r) {
10105               newp = fStartNew + (fEnd - fStart)*4 + (p - cStart)*12 + r;
10106               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
10107             }
10108             for (r = 0; r < 6; ++r) {
10109               newp = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*4 + (p - cStart)*6 + r;
10110               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
10111             }
10112             newp = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (fEnd - fStart) + (p - cStart);
10113             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
10114           }
10115           break;
10116         case REFINER_HYBRID_HEX_3D:
10117           if ((p >= vStart) && (p < vEnd)) {
10118             /* Interior vertices stay the same */
10119             newp = vStartNew + (p - vStart);
10120             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
10121           } else if ((p >= eStart) && (p < eMax)) {
10122             /* Interior edges add new edges and vertex */
10123             for (r = 0; r < 2; ++r) {
10124               newp = eStartNew + (p - eStart)*2 + r;
10125               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
10126             }
10127             newp = vStartNew + (vEnd - vStart) + (p - eStart);
10128             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
10129           } else if ((p >= eMax) && (p < eEnd)) {
10130             /* Hybrid edges stay the same */
10131             newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (p - eMax);
10132             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
10133           } else if ((p >= fStart) && (p < fMax)) {
10134             /* Interior faces add new faces, edges, and vertex */
10135             for (r = 0; r < 4; ++r) {
10136               newp = fStartNew + (p - fStart)*4 + r;
10137               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
10138             }
10139             for (r = 0; r < 4; ++r) {
10140               newp = eStartNew + (eMax - eStart)*2 + (p - fStart)*4 + r;
10141               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
10142             }
10143             newp = vStartNew + (vEnd - vStart) + (eMax - eStart) + (p - fStart);
10144             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
10145           } else if ((p >= fMax) && (p < fEnd)) {
10146             /* Hybrid faces add new faces and edges */
10147             for (r = 0; r < 2; ++r) {
10148               newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (p - fMax)*2 + r;
10149               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
10150             }
10151             newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (p - fMax);
10152             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
10153           } else if ((p >= cStart) && (p < cMax)) {
10154             /* Interior cells add new cells, faces, edges, and vertex */
10155             for (r = 0; r < 8; ++r) {
10156               newp = cStartNew + (p - cStart)*8 + r;
10157               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
10158             }
10159             for (r = 0; r < 12; ++r) {
10160               newp = fStartNew + (fMax - fStart)*4 + (p - cStart)*12 + r;
10161               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
10162             }
10163             for (r = 0; r < 6; ++r) {
10164               newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (p - cStart)*6 + r;
10165               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
10166             }
10167             newp = vStartNew + (vEnd - vStart) + (eMax - eStart) + (fMax - fStart) + (p - cStart);
10168             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
10169           } else if ((p >= cMax) && (p < cEnd)) {
10170             /* Hybrid cells add new cells, faces, and edges */
10171             for (r = 0; r < 4; ++r) {
10172               newp = cStartNew + (cMax - cStart)*8 + (p - cMax)*4 + r;
10173               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
10174             }
10175             for (r = 0; r < 4; ++r) {
10176               newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd - fMax)*2 + (p - cMax)*4 + r;
10177               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
10178             }
10179             newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (fEnd - fMax) + (p - cMax);
10180             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
10181           }
10182           break;
10183         default:
10184           SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %s", CellRefiners[refiner]);
10185         }
10186       }
10187       ierr = ISRestoreIndices(pointIS, &points);CHKERRQ(ierr);
10188       ierr = ISDestroy(&pointIS);CHKERRQ(ierr);
10189     }
10190     ierr = ISRestoreIndices(valueIS, &values);CHKERRQ(ierr);
10191     ierr = ISDestroy(&valueIS);CHKERRQ(ierr);
10192   }
10193   PetscFunctionReturn(0);
10194 }
10195 
10196 /* This will only work for interpolated meshes */
10197 PetscErrorCode DMPlexRefineUniform_Internal(DM dm, CellRefiner cellRefiner, DM *dmRefined)
10198 {
10199   DM             rdm;
10200   PetscInt      *depthSize;
10201   PetscInt       dim, embedDim, depth = 0, d, pStart = 0, pEnd = 0;
10202   PetscErrorCode ierr;
10203 
10204   PetscFunctionBegin;
10205   ierr = DMCreate(PetscObjectComm((PetscObject)dm), &rdm);CHKERRQ(ierr);
10206   ierr = DMSetType(rdm, DMPLEX);CHKERRQ(ierr);
10207   ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr);
10208   ierr = DMSetDimension(rdm, dim);CHKERRQ(ierr);
10209   ierr = DMGetCoordinateDim(dm, &embedDim);CHKERRQ(ierr);
10210   ierr = DMSetCoordinateDim(rdm, embedDim);CHKERRQ(ierr);
10211   /* Calculate number of new points of each depth */
10212   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
10213   if (depth >= 0 && dim != depth) SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "Mesh must be interpolated for regular refinement");
10214   ierr = PetscMalloc1(depth+1, &depthSize);CHKERRQ(ierr);
10215   ierr = PetscMemzero(depthSize, (depth+1) * sizeof(PetscInt));CHKERRQ(ierr);
10216   ierr = CellRefinerGetSizes(cellRefiner, dm, depthSize);CHKERRQ(ierr);
10217   /* Step 1: Set chart */
10218   for (d = 0; d <= depth; ++d) pEnd += depthSize[d];
10219   ierr = DMPlexSetChart(rdm, pStart, pEnd);CHKERRQ(ierr);
10220   /* Step 2: Set cone/support sizes (automatically stratifies) */
10221   ierr = CellRefinerSetConeSizes(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
10222   /* Step 3: Setup refined DM */
10223   ierr = DMSetUp(rdm);CHKERRQ(ierr);
10224   /* Step 4: Set cones and supports (automatically symmetrizes) */
10225   ierr = CellRefinerSetCones(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
10226   /* Step 5: Create pointSF */
10227   ierr = CellRefinerCreateSF(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
10228   /* Step 6: Create labels */
10229   ierr = CellRefinerCreateLabels(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
10230   /* Step 7: Set coordinates */
10231   ierr = CellRefinerSetCoordinates(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
10232   ierr = PetscFree(depthSize);CHKERRQ(ierr);
10233 
10234   *dmRefined = rdm;
10235   PetscFunctionReturn(0);
10236 }
10237 
10238 /*@
10239   DMPlexCreateCoarsePointIS - Creates an IS covering the coarse DM chart with the fine points as data
10240 
10241   Input Parameter:
10242 . dm - The coarse DM
10243 
10244   Output Parameter:
10245 . fpointIS - The IS of all the fine points which exist in the original coarse mesh
10246 
10247   Level: developer
10248 
10249 .seealso: DMRefine(), DMPlexSetRefinementUniform(), DMPlexCreateSubpointIS()
10250 @*/
10251 PetscErrorCode DMPlexCreateCoarsePointIS(DM dm, IS *fpointIS)
10252 {
10253   CellRefiner    cellRefiner;
10254   PetscInt      *depthSize, *fpoints;
10255   PetscInt       cStartNew = 0, vStartNew = 0, fStartNew = 0, eStartNew = 0;
10256   PetscInt       depth, pStart, pEnd, p, vStart, vEnd, v;
10257   PetscErrorCode ierr;
10258 
10259   PetscFunctionBegin;
10260   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
10261   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
10262   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
10263   ierr = DMPlexGetCellRefiner_Internal(dm, &cellRefiner);CHKERRQ(ierr);
10264   ierr = PetscMalloc1(depth+1, &depthSize);CHKERRQ(ierr);
10265   ierr = CellRefinerGetSizes(cellRefiner, dm, depthSize);CHKERRQ(ierr);
10266   if (cellRefiner) {ierr = GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);CHKERRQ(ierr);}
10267   ierr = PetscMalloc1(pEnd-pStart,&fpoints);CHKERRQ(ierr);
10268   for (p = 0; p < pEnd-pStart; ++p) fpoints[p] = -1;
10269   switch (cellRefiner) {
10270   case REFINER_SIMPLEX_1D:
10271   case REFINER_SIMPLEX_2D:
10272   case REFINER_HYBRID_SIMPLEX_2D:
10273   case REFINER_HEX_2D:
10274   case REFINER_HYBRID_HEX_2D:
10275   case REFINER_SIMPLEX_3D:
10276   case REFINER_HYBRID_SIMPLEX_3D:
10277   case REFINER_HEX_3D:
10278   case REFINER_HYBRID_HEX_3D:
10279     for (v = vStart; v < vEnd; ++v) fpoints[v-pStart] = vStartNew + (v - vStart);
10280     break;
10281   default:
10282     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %s", CellRefiners[cellRefiner]);
10283   }
10284   ierr = ISCreateGeneral(PETSC_COMM_SELF, pEnd-pStart, fpoints, PETSC_OWN_POINTER, fpointIS);CHKERRQ(ierr);
10285   ierr = PetscFree(depthSize);CHKERRQ(ierr);
10286   PetscFunctionReturn(0);
10287 }
10288 
10289 /*@
10290   DMPlexSetRefinementUniform - Set the flag for uniform refinement
10291 
10292   Input Parameters:
10293 + dm - The DM
10294 - refinementUniform - The flag for uniform refinement
10295 
10296   Level: developer
10297 
10298 .seealso: DMRefine(), DMPlexGetRefinementUniform(), DMPlexGetRefinementLimit(), DMPlexSetRefinementLimit()
10299 @*/
10300 PetscErrorCode DMPlexSetRefinementUniform(DM dm, PetscBool refinementUniform)
10301 {
10302   DM_Plex *mesh = (DM_Plex*) dm->data;
10303 
10304   PetscFunctionBegin;
10305   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
10306   mesh->refinementUniform = refinementUniform;
10307   PetscFunctionReturn(0);
10308 }
10309 
10310 /*@
10311   DMPlexGetRefinementUniform - Retrieve the flag for uniform refinement
10312 
10313   Input Parameter:
10314 . dm - The DM
10315 
10316   Output Parameter:
10317 . refinementUniform - The flag for uniform refinement
10318 
10319   Level: developer
10320 
10321 .seealso: DMRefine(), DMPlexSetRefinementUniform(), DMPlexGetRefinementLimit(), DMPlexSetRefinementLimit()
10322 @*/
10323 PetscErrorCode DMPlexGetRefinementUniform(DM dm, PetscBool *refinementUniform)
10324 {
10325   DM_Plex *mesh = (DM_Plex*) dm->data;
10326 
10327   PetscFunctionBegin;
10328   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
10329   PetscValidPointer(refinementUniform,  2);
10330   *refinementUniform = mesh->refinementUniform;
10331   PetscFunctionReturn(0);
10332 }
10333 
10334 /*@
10335   DMPlexSetRefinementLimit - Set the maximum cell volume for refinement
10336 
10337   Input Parameters:
10338 + dm - The DM
10339 - refinementLimit - The maximum cell volume in the refined mesh
10340 
10341   Level: developer
10342 
10343 .seealso: DMRefine(), DMPlexGetRefinementLimit(), DMPlexGetRefinementUniform(), DMPlexSetRefinementUniform()
10344 @*/
10345 PetscErrorCode DMPlexSetRefinementLimit(DM dm, PetscReal refinementLimit)
10346 {
10347   DM_Plex *mesh = (DM_Plex*) dm->data;
10348 
10349   PetscFunctionBegin;
10350   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
10351   mesh->refinementLimit = refinementLimit;
10352   PetscFunctionReturn(0);
10353 }
10354 
10355 /*@
10356   DMPlexGetRefinementLimit - Retrieve the maximum cell volume for refinement
10357 
10358   Input Parameter:
10359 . dm - The DM
10360 
10361   Output Parameter:
10362 . refinementLimit - The maximum cell volume in the refined mesh
10363 
10364   Level: developer
10365 
10366 .seealso: DMRefine(), DMPlexSetRefinementLimit(), DMPlexGetRefinementUniform(), DMPlexSetRefinementUniform()
10367 @*/
10368 PetscErrorCode DMPlexGetRefinementLimit(DM dm, PetscReal *refinementLimit)
10369 {
10370   DM_Plex *mesh = (DM_Plex*) dm->data;
10371 
10372   PetscFunctionBegin;
10373   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
10374   PetscValidPointer(refinementLimit,  2);
10375   /* if (mesh->refinementLimit < 0) = getMaxVolume()/2.0; */
10376   *refinementLimit = mesh->refinementLimit;
10377   PetscFunctionReturn(0);
10378 }
10379 
10380 /*@
10381   DMPlexSetRefinementFunction - Set the function giving the maximum cell volume for refinement
10382 
10383   Input Parameters:
10384 + dm - The DM
10385 - refinementFunc - Function giving the maximum cell volume in the refined mesh
10386 
10387   Note: The calling sequence is refinementFunc(coords, limit)
10388 $ coords - Coordinates of the current point, usually a cell centroid
10389 $ limit  - The maximum cell volume for a cell containing this point
10390 
10391   Level: developer
10392 
10393 .seealso: DMRefine(), DMPlexGetRefinementFunction(), DMPlexGetRefinementUniform(), DMPlexSetRefinementUniform(), DMPlexGetRefinementLimit(), DMPlexSetRefinementLimit()
10394 @*/
10395 PetscErrorCode DMPlexSetRefinementFunction(DM dm, PetscErrorCode (*refinementFunc)(const PetscReal [], PetscReal *))
10396 {
10397   DM_Plex *mesh = (DM_Plex*) dm->data;
10398 
10399   PetscFunctionBegin;
10400   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
10401   mesh->refinementFunc = refinementFunc;
10402   PetscFunctionReturn(0);
10403 }
10404 
10405 /*@
10406   DMPlexGetRefinementFunction - Get the function giving the maximum cell volume for refinement
10407 
10408   Input Parameter:
10409 . dm - The DM
10410 
10411   Output Parameter:
10412 . refinementFunc - Function giving the maximum cell volume in the refined mesh
10413 
10414   Note: The calling sequence is refinementFunc(coords, limit)
10415 $ coords - Coordinates of the current point, usually a cell centroid
10416 $ limit  - The maximum cell volume for a cell containing this point
10417 
10418   Level: developer
10419 
10420 .seealso: DMRefine(), DMPlexSetRefinementFunction(), DMPlexGetRefinementUniform(), DMPlexSetRefinementUniform(), DMPlexGetRefinementLimit(), DMPlexSetRefinementLimit()
10421 @*/
10422 PetscErrorCode DMPlexGetRefinementFunction(DM dm, PetscErrorCode (**refinementFunc)(const PetscReal [], PetscReal *))
10423 {
10424   DM_Plex *mesh = (DM_Plex*) dm->data;
10425 
10426   PetscFunctionBegin;
10427   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
10428   PetscValidPointer(refinementFunc,  2);
10429   *refinementFunc = mesh->refinementFunc;
10430   PetscFunctionReturn(0);
10431 }
10432 
10433 PetscErrorCode DMPlexGetCellRefiner_Internal(DM dm, CellRefiner *cellRefiner)
10434 {
10435   DMPolytopeType ct;
10436   PetscInt       dim, cStart, cEnd, cMax, fMax;
10437   PetscErrorCode ierr;
10438 
10439   PetscFunctionBegin;
10440   ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr);
10441   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
10442   if (cEnd <= cStart) {*cellRefiner = REFINER_NOOP; PetscFunctionReturn(0);}
10443   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, NULL, NULL);CHKERRQ(ierr);
10444   /* TODO Must tag hybrid cells with correct cell types */
10445   ierr = DMPlexGetCellType(dm, cStart, &ct);CHKERRQ(ierr);
10446   switch (ct) {
10447     case DM_POLYTOPE_SEGMENT:       *cellRefiner = REFINER_SIMPLEX_1D; break;
10448     case DM_POLYTOPE_TRIANGLE:      if (cMax >= 0) {*cellRefiner = REFINER_HYBRID_SIMPLEX_2D; break;}
10449                                     else           {*cellRefiner = REFINER_SIMPLEX_2D; break;}
10450     case DM_POLYTOPE_QUADRILATERAL: if (cMax >= 0) {*cellRefiner = REFINER_HYBRID_HEX_2D; break;} /* Why did this have fMax >= 0 ??? */
10451                                     else           {*cellRefiner = REFINER_HEX_2D; break;}
10452     case DM_POLYTOPE_TETRAHEDRON:   if (cMax >= 0) {*cellRefiner = REFINER_HYBRID_SIMPLEX_3D; break;}
10453                                     else           {*cellRefiner = REFINER_SIMPLEX_3D; break;}
10454     case DM_POLYTOPE_HEXAHEDRON:    if (cMax >= 0) {*cellRefiner = REFINER_HYBRID_HEX_3D; break;}
10455                                     else           {*cellRefiner = REFINER_HEX_3D; break;}
10456     case DM_POLYTOPE_SEG_PRISM_TENSOR:  *cellRefiner = REFINER_HYBRID_SIMPLEX_2D; break;
10457     case DM_POLYTOPE_TRI_PRISM_TENSOR:  *cellRefiner = REFINER_HYBRID_SIMPLEX_3D; break;
10458     case DM_POLYTOPE_QUAD_PRISM_TENSOR: *cellRefiner = REFINER_HYBRID_HEX_3D; break;
10459     default: SETERRQ2(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_OUTOFRANGE, "No cell refiner for cell %D with type %s", cStart, DMPolytopeTypes[ct]);
10460   }
10461   PetscFunctionReturn(0);
10462 }
10463 
10464 PetscErrorCode DMRefine_Plex(DM dm, MPI_Comm comm, DM *dmRefined)
10465 {
10466   PetscBool      isUniform;
10467   PetscErrorCode ierr;
10468 
10469   PetscFunctionBegin;
10470   ierr = DMPlexGetRefinementUniform(dm, &isUniform);CHKERRQ(ierr);
10471   if (isUniform) {
10472     CellRefiner cellRefiner;
10473     PetscBool   localized;
10474 
10475     ierr = DMGetCoordinatesLocalized(dm, &localized);CHKERRQ(ierr);
10476     ierr = DMPlexGetCellRefiner_Internal(dm, &cellRefiner);CHKERRQ(ierr);
10477     ierr = DMPlexRefineUniform_Internal(dm, cellRefiner, dmRefined);CHKERRQ(ierr);
10478     ierr = DMPlexSetRegularRefinement(*dmRefined, PETSC_TRUE);CHKERRQ(ierr);
10479     ierr = DMCopyBoundary(dm, *dmRefined);CHKERRQ(ierr);
10480     if (localized) {ierr = DMLocalizeCoordinates(*dmRefined);CHKERRQ(ierr);}
10481   } else {
10482     ierr = DMPlexRefine_Internal(dm, NULL, dmRefined);CHKERRQ(ierr);
10483   }
10484   PetscFunctionReturn(0);
10485 }
10486 
10487 PetscErrorCode DMRefineHierarchy_Plex(DM dm, PetscInt nlevels, DM dmRefined[])
10488 {
10489   DM             cdm = dm;
10490   PetscInt       r;
10491   PetscBool      isUniform, localized;
10492   PetscErrorCode ierr;
10493 
10494   PetscFunctionBegin;
10495   ierr = DMPlexGetRefinementUniform(dm, &isUniform);CHKERRQ(ierr);
10496   ierr = DMGetCoordinatesLocalized(dm, &localized);CHKERRQ(ierr);
10497   if (isUniform) {
10498     for (r = 0; r < nlevels; ++r) {
10499       CellRefiner cellRefiner;
10500 
10501       ierr = DMPlexGetCellRefiner_Internal(cdm, &cellRefiner);CHKERRQ(ierr);
10502       ierr = DMPlexRefineUniform_Internal(cdm, cellRefiner, &dmRefined[r]);CHKERRQ(ierr);
10503       ierr = DMSetCoarsenLevel(dmRefined[r], cdm->leveldown);CHKERRQ(ierr);
10504       ierr = DMSetRefineLevel(dmRefined[r], cdm->levelup+1);CHKERRQ(ierr);
10505       ierr = DMCopyBoundary(cdm, dmRefined[r]);CHKERRQ(ierr);
10506       if (localized) {ierr = DMLocalizeCoordinates(dmRefined[r]);CHKERRQ(ierr);}
10507       ierr = DMSetCoarseDM(dmRefined[r], cdm);CHKERRQ(ierr);
10508       ierr = DMPlexSetRegularRefinement(dmRefined[r], PETSC_TRUE);CHKERRQ(ierr);
10509       cdm  = dmRefined[r];
10510     }
10511   } else {
10512     for (r = 0; r < nlevels; ++r) {
10513       ierr = DMRefine(cdm, PetscObjectComm((PetscObject) dm), &dmRefined[r]);CHKERRQ(ierr);
10514       ierr = DMCopyBoundary(cdm, dmRefined[r]);CHKERRQ(ierr);
10515       if (localized) {ierr = DMLocalizeCoordinates(dmRefined[r]);CHKERRQ(ierr);}
10516       ierr = DMSetCoarseDM(dmRefined[r], cdm);CHKERRQ(ierr);
10517       cdm  = dmRefined[r];
10518     }
10519   }
10520   PetscFunctionReturn(0);
10521 }
10522