xref: /petsc/src/dm/impls/plex/plexrefine.c (revision c4762a1b19cd2af06abeed90e8f9d34fb975dd94)
1 #include <petsc/private/dmpleximpl.h>   /*I      "petscdmplex.h"   I*/
2 #include <petscsf.h>
3 
4 const char * const CellRefiners[] = {"NOOP", "SIMPLEX_1D", "SIMPLEX_2D", "HYBRID_SIMPLEX_2D", "SIMPLEX_TO_HEX_2D", "HYBRID_SIMPLEX_TO_HEX_2D", "HEX_2D", "HYBRID_HEX_2D",
5                                      "SIMPLEX_3D", "HYBRID_SIMPLEX_3D", "SIMPLEX_TO_HEX_3D", "HYBRID_SIMPLEX_TO_HEX_3D", "HEX_3D", "HYBRID_HEX_3D", "CellRefiners", "REFINER_", 0};
6 
7 PETSC_STATIC_INLINE PetscErrorCode GetDepthStart_Private(PetscInt depth, PetscInt depthSize[], PetscInt *cStart, PetscInt *fStart, PetscInt *eStart, PetscInt *vStart)
8 {
9   PetscFunctionBegin;
10   if (cStart) *cStart = 0;
11   if (vStart) *vStart = depth < 0 ? 0 : depthSize[depth];
12   if (fStart) *fStart = depth < 0 ? 0 : depthSize[depth] + depthSize[0];
13   if (eStart) *eStart = depth < 0 ? 0 : depthSize[depth] + depthSize[0] + depthSize[depth-1];
14   PetscFunctionReturn(0);
15 }
16 
17 PETSC_STATIC_INLINE PetscErrorCode GetDepthEnd_Private(PetscInt depth, PetscInt depthSize[], PetscInt *cEnd, PetscInt *fEnd, PetscInt *eEnd, PetscInt *vEnd)
18 {
19   PetscFunctionBegin;
20   if (cEnd) *cEnd = depth < 0 ? 0 : depthSize[depth];
21   if (vEnd) *vEnd = depth < 0 ? 0 : depthSize[depth] + depthSize[0];
22   if (fEnd) *fEnd = depth < 0 ? 0 : depthSize[depth] + depthSize[0] + depthSize[depth-1];
23   if (eEnd) *eEnd = depth < 0 ? 0 : depthSize[depth] + depthSize[0] + depthSize[depth-1] + depthSize[1];
24   PetscFunctionReturn(0);
25 }
26 
27 /*
28   Note that j and invj are non-square:
29          v0 + j x_face = x_cell
30     invj (x_cell - v0) = x_face
31 */
32 PetscErrorCode CellRefinerGetAffineFaceTransforms_Internal(CellRefiner refiner, PetscInt *numFaces, PetscReal *v0[], PetscReal *jac[], PetscReal *invjac[], PetscReal *detj[])
33 {
34   PetscReal     *v = NULL, *j = NULL, *invj = NULL, *dj = NULL;
35   PetscInt       cdim, fdim;
36   PetscErrorCode ierr;
37 
38   PetscFunctionBegin;
39   switch (refiner) {
40   case REFINER_NOOP: break;
41   case REFINER_SIMPLEX_2D:
42     /*
43      2
44      |\
45      | \
46      |  \
47      |   \
48      |    \
49      |     \
50      |      \
51      2       1
52      |        \
53      |         \
54      |          \
55      0---0-------1
56      */
57     cdim = 2;
58     fdim = 1;
59     if (numFaces) *numFaces = 3;
60     if (v0) {
61       ierr = PetscMalloc1(3*cdim,      &v);CHKERRQ(ierr);
62       ierr = PetscMalloc1(3*cdim*fdim, &j);CHKERRQ(ierr);
63       ierr = PetscMalloc1(3*cdim*fdim, &invj);CHKERRQ(ierr);
64       ierr = PetscMalloc1(3,           &dj);CHKERRQ(ierr);
65       /* 0 */
66       v[0+0] =  0.0; v[0+1] = -1.0;
67       j[0+0] =  1.0;
68       j[0+1] =  0.0;
69       invj[0+0] = 1.0; invj[0+1] = 0.0;
70       dj[0]  = 1.0;
71       /* 1 */
72       v[2+0] =  0.0; v[2+1] =  0.0;
73       j[2+0] = -1.0;
74       j[2+1] =  1.0;
75       invj[2+0] = -0.5; invj[2+1] = 0.5;
76       dj[1]  = 1.414213562373095;
77       /* 2 */
78       v[4+0] = -1.0; v[4+1] =  0.0;
79       j[4+0] =  0.0;
80       j[4+1] = -1.0;
81       invj[4+0] = 0.0; invj[4+1] = -1.0;
82       dj[2]  = 1.0;
83     }
84     break;
85   case REFINER_HEX_2D:
86     /*
87      3---------2---------2
88      |                   |
89      |                   |
90      |                   |
91      3                   1
92      |                   |
93      |                   |
94      |                   |
95      0---------0---------1
96      */
97     cdim = 2;
98     fdim = 1;
99     if (numFaces) *numFaces = 4;
100     if (v0) {
101       ierr = PetscMalloc1(4*cdim,      &v);CHKERRQ(ierr);
102       ierr = PetscMalloc1(4*cdim*fdim, &j);CHKERRQ(ierr);
103       ierr = PetscMalloc1(4*cdim*fdim, &invj);CHKERRQ(ierr);
104       ierr = PetscMalloc1(4,           &dj);CHKERRQ(ierr);
105       /* 0 */
106       v[0+0] =  0.0; v[0+1] = -1.0;
107       j[0+0] =  1.0;
108       j[0+1] =  0.0;
109       invj[0+0] =  1.0; invj[0+1] =  0.0;
110       dj[0]  = 1.0;
111       /* 1 */
112       v[2+0] =  1.0; v[2+1] =  0.0;
113       j[2+0] =  0.0;
114       j[2+1] =  1.0;
115       invj[2+0] =  0.0; invj[2+1] =  1.0;
116       dj[1]  = 1.0;
117       /* 2 */
118       v[4+0] =  0.0; v[4+1] = 1.0;
119       j[4+0] = -1.0;
120       j[4+1] =  0.0;
121       invj[4+0] = -1.0; invj[4+1] =  0.0;
122       dj[2]  = 1.0;
123       /* 3 */
124       v[6+0] = -1.0; v[6+1] =  0.0;
125       j[6+0] =  0.0;
126       j[6+1] = -1.0;
127       invj[6+0] =  0.0; invj[6+1] = -1.0;
128       dj[3]  = 1.0;
129     }
130     break;
131   default:
132     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %s", CellRefiners[refiner]);
133   }
134   if (v0)     {*v0     = v;}
135   else        {ierr = PetscFree(v);CHKERRQ(ierr);}
136   if (jac)    {*jac    = j;}
137   else        {ierr = PetscFree(j);CHKERRQ(ierr);}
138   if (invjac) {*invjac = invj;}
139   else        {ierr = PetscFree(invj);CHKERRQ(ierr);}
140   if (invjac) {*invjac = invj;}
141   else        {ierr = PetscFree(invj);CHKERRQ(ierr);}
142   if (detj)   {*detj   = dj;}
143   else        {ierr = PetscFree(dj);CHKERRQ(ierr);}
144   PetscFunctionReturn(0);
145 }
146 
147 /* Gets the affine map from the original cell to each subcell */
148 PetscErrorCode CellRefinerGetAffineTransforms_Internal(CellRefiner refiner, PetscInt *numSubcells, PetscReal *v0[], PetscReal *jac[], PetscReal *invjac[])
149 {
150   PetscReal     *v = NULL, *j = NULL, *invj = NULL, detJ;
151   PetscInt       dim, s;
152   PetscErrorCode ierr;
153 
154   PetscFunctionBegin;
155   switch (refiner) {
156   case REFINER_NOOP: break;
157   case REFINER_SIMPLEX_2D:
158     /*
159      2
160      |\
161      | \
162      |  \
163      |   \
164      | C  \
165      |     \
166      |      \
167      2---1---1
168      |\  D  / \
169      | 2   0   \
170      |A \ /  B  \
171      0---0-------1
172      */
173     dim = 2;
174     if (numSubcells) *numSubcells = 4;
175     if (v0) {
176       ierr = PetscMalloc3(4*dim,&v,4*dim*dim,&j,4*dim*dim,&invj);CHKERRQ(ierr);
177       /* A */
178       v[0+0] = -1.0; v[0+1] = -1.0;
179       j[0+0] =  0.5; j[0+1] =  0.0;
180       j[0+2] =  0.0; j[0+3] =  0.5;
181       /* B */
182       v[2+0] =  0.0; v[2+1] = -1.0;
183       j[4+0] =  0.5; j[4+1] =  0.0;
184       j[4+2] =  0.0; j[4+3] =  0.5;
185       /* C */
186       v[4+0] = -1.0; v[4+1] =  0.0;
187       j[8+0] =  0.5; j[8+1] =  0.0;
188       j[8+2] =  0.0; j[8+3] =  0.5;
189       /* D */
190       v[6+0]  =  0.0; v[6+1]  = -1.0;
191       j[12+0] =  0.0; j[12+1] = -0.5;
192       j[12+2] =  0.5; j[12+3] =  0.5;
193       for (s = 0; s < 4; ++s) {
194         DMPlex_Det2D_Internal(&detJ, &j[s*dim*dim]);
195         DMPlex_Invert2D_Internal(&invj[s*dim*dim], &j[s*dim*dim], detJ);
196       }
197     }
198     break;
199   case REFINER_HEX_2D:
200     /*
201      3---------2---------2
202      |         |         |
203      |    D    2    C    |
204      |         |         |
205      3----3----0----1----1
206      |         |         |
207      |    A    0    B    |
208      |         |         |
209      0---------0---------1
210      */
211     dim = 2;
212     if (numSubcells) *numSubcells = 4;
213     if (v0) {
214       ierr = PetscMalloc3(4*dim,&v,4*dim*dim,&j,4*dim*dim,&invj);CHKERRQ(ierr);
215       /* A */
216       v[0+0] = -1.0; v[0+1] = -1.0;
217       j[0+0] =  0.5; j[0+1] =  0.0;
218       j[0+2] =  0.0; j[0+3] =  0.5;
219       /* B */
220       v[2+0] =  0.0; v[2+1] = -1.0;
221       j[4+0] =  0.5; j[4+1] =  0.0;
222       j[4+2] =  0.0; j[4+3] =  0.5;
223       /* C */
224       v[4+0] =  0.0; v[4+1] =  0.0;
225       j[8+0] =  0.5; j[8+1] =  0.0;
226       j[8+2] =  0.0; j[8+3] =  0.5;
227       /* D */
228       v[6+0]  = -1.0; v[6+1]  =  0.0;
229       j[12+0] =  0.5; j[12+1] =  0.0;
230       j[12+2] =  0.0; j[12+3] =  0.5;
231       for (s = 0; s < 4; ++s) {
232         DMPlex_Det2D_Internal(&detJ, &j[s*dim*dim]);
233         DMPlex_Invert2D_Internal(&invj[s*dim*dim], &j[s*dim*dim], detJ);
234       }
235     }
236     break;
237   case REFINER_HEX_3D:
238     /*
239      Bottom (viewed from top)    Top
240      1---------2---------2       7---------2---------6
241      |         |         |       |         |         |
242      |    B    2    C    |       |    H    2    G    |
243      |         |         |       |         |         |
244      3----3----0----1----1       3----3----0----1----1
245      |         |         |       |         |         |
246      |    A    0    D    |       |    E    0    F    |
247      |         |         |       |         |         |
248      0---------0---------3       4---------0---------5
249      */
250     dim = 3;
251     if (numSubcells) *numSubcells = 8;
252     if (v0) {
253       ierr = PetscMalloc3(8*dim,&v,8*dim*dim,&j,8*dim*dim,&invj);CHKERRQ(ierr);
254       /* A */
255       v[0+0] = -1.0; v[0+1] = -1.0; v[0+2] = -1.0;
256       j[0+0] =  0.5; j[0+1] =  0.0; j[0+2] =  0.0;
257       j[0+3] =  0.0; j[0+4] =  0.5; j[0+5] =  0.0;
258       j[0+6] =  0.0; j[0+7] =  0.0; j[0+8] =  0.5;
259       /* B */
260       v[3+0] = -1.0; v[3+1] =  0.0; v[3+2] = -1.0;
261       j[9+0] =  0.5; j[9+1] =  0.0; j[9+2] =  0.0;
262       j[9+3] =  0.0; j[9+4] =  0.5; j[9+5] =  0.0;
263       j[9+6] =  0.0; j[9+7] =  0.0; j[9+8] =  0.5;
264       /* C */
265       v[6+0] =  0.0; v[6+1] =  0.0; v[6+2] = -1.0;
266       j[18+0] = 0.5; j[18+1] = 0.0; j[18+2] = 0.0;
267       j[18+3] = 0.0; j[18+4] = 0.5; j[18+5] = 0.0;
268       j[18+6] = 0.0; j[18+7] = 0.0; j[18+8] = 0.5;
269       /* D */
270       v[9+0] =  0.0; v[9+1] = -1.0; v[9+2] = -1.0;
271       j[27+0] = 0.5; j[27+1] = 0.0; j[27+2] = 0.0;
272       j[27+3] = 0.0; j[27+4] = 0.5; j[27+5] = 0.0;
273       j[27+6] = 0.0; j[27+7] = 0.0; j[27+8] = 0.5;
274       /* E */
275       v[12+0] = -1.0; v[12+1] = -1.0; v[12+2] =  0.0;
276       j[36+0] =  0.5; j[36+1] =  0.0; j[36+2] =  0.0;
277       j[36+3] =  0.0; j[36+4] =  0.5; j[36+5] =  0.0;
278       j[36+6] =  0.0; j[36+7] =  0.0; j[36+8] =  0.5;
279       /* F */
280       v[15+0] =  0.0; v[15+1] = -1.0; v[15+2] =  0.0;
281       j[45+0] =  0.5; j[45+1] =  0.0; j[45+2] =  0.0;
282       j[45+3] =  0.0; j[45+4] =  0.5; j[45+5] =  0.0;
283       j[45+6] =  0.0; j[45+7] =  0.0; j[45+8] =  0.5;
284       /* G */
285       v[18+0] =  0.0; v[18+1] =  0.0; v[18+2] =  0.0;
286       j[54+0] =  0.5; j[54+1] =  0.0; j[54+2] =  0.0;
287       j[54+3] =  0.0; j[54+4] =  0.5; j[54+5] =  0.0;
288       j[54+6] =  0.0; j[54+7] =  0.0; j[54+8] =  0.5;
289       /* H */
290       v[21+0] = -1.0; v[21+1] =  0.0; v[21+2] =  0.0;
291       j[63+0] =  0.5; j[63+1] =  0.0; j[63+2] =  0.0;
292       j[63+3] =  0.0; j[63+4] =  0.5; j[63+5] =  0.0;
293       j[63+6] =  0.0; j[63+7] =  0.0; j[63+8] =  0.5;
294       for (s = 0; s < 8; ++s) {
295         DMPlex_Det3D_Internal(&detJ, &j[s*dim*dim]);
296         DMPlex_Invert3D_Internal(&invj[s*dim*dim], &j[s*dim*dim], detJ);
297       }
298     }
299     break;
300   default:
301     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %s", CellRefiners[refiner]);
302   }
303   if (v0) {*v0 = v; *jac = j; *invjac = invj;}
304   PetscFunctionReturn(0);
305 }
306 
307 PetscErrorCode CellRefinerRestoreAffineTransforms_Internal(CellRefiner refiner, PetscInt *numSubcells, PetscReal *v0[], PetscReal *jac[], PetscReal *invjac[])
308 {
309   PetscErrorCode ierr;
310 
311   PetscFunctionBegin;
312   ierr = PetscFree3(*v0,*jac,*invjac);CHKERRQ(ierr);
313   PetscFunctionReturn(0);
314 }
315 
316 /* Should this be here or in the DualSpace somehow? */
317 PetscErrorCode CellRefinerInCellTest_Internal(CellRefiner refiner, const PetscReal point[], PetscBool *inside)
318 {
319   PetscReal sum = 0.0;
320   PetscInt  d;
321 
322   PetscFunctionBegin;
323   *inside = PETSC_TRUE;
324   switch (refiner) {
325   case REFINER_NOOP: break;
326   case REFINER_SIMPLEX_2D:
327     for (d = 0; d < 2; ++d) {
328       if (point[d] < -1.0) {*inside = PETSC_FALSE; break;}
329       sum += point[d];
330     }
331     if (sum > 1.0e-10) {*inside = PETSC_FALSE; break;}
332     break;
333   case REFINER_HEX_2D:
334     for (d = 0; d < 2; ++d) if ((point[d] < -1.00000000001) || (point[d] > 1.000000000001)) {*inside = PETSC_FALSE; break;}
335     break;
336   case REFINER_HEX_3D:
337     for (d = 0; d < 3; d++) if (PetscAbsReal(point[d]) > 1 + PETSC_SMALL) {*inside = PETSC_FALSE; break;}
338     break;
339   default:
340     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %s", CellRefiners[refiner]);
341   }
342   PetscFunctionReturn(0);
343 }
344 
345 static PetscErrorCode CellRefinerGetSizes(CellRefiner refiner, DM dm, PetscInt depthSize[])
346 {
347   PetscInt       cStart, cEnd, cMax, vStart, vEnd, vMax, fStart, fEnd, fMax, eStart, eEnd, eMax;
348   PetscErrorCode ierr;
349 
350   PetscFunctionBegin;
351   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
352   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
353   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
354   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
355   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
356   switch (refiner) {
357   case REFINER_NOOP:
358     break;
359   case REFINER_SIMPLEX_1D:
360     depthSize[0] = vEnd - vStart + cEnd - cStart;         /* Add a vertex on every cell. */
361     depthSize[1] = 2*(cEnd - cStart);                     /* Split every cell in 2. */
362     break;
363   case REFINER_SIMPLEX_2D:
364     depthSize[0] = vEnd - vStart + fEnd - fStart;         /* Add a vertex on every face */
365     depthSize[1] = 2*(fEnd - fStart) + 3*(cEnd - cStart); /* Every face is split into 2 faces and 3 faces are added for each cell */
366     depthSize[2] = 4*(cEnd - cStart);                     /* Every cell split into 4 cells */
367     break;
368   case REFINER_HYBRID_SIMPLEX_2D:
369     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
370     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
371     depthSize[0] = vEnd - vStart + fMax - fStart;                                         /* Add a vertex on every face, but not hybrid faces */
372     depthSize[1] = 2*(fMax - fStart) + 3*(cMax - cStart) + (fEnd - fMax) + (cEnd - cMax); /* Every interior face is split into 2 faces, 3 faces are added for each interior cell, and one in each hybrid cell */
373     depthSize[2] = 4*(cMax - cStart) + 2*(cEnd - cMax);                                   /* Interior cells split into 4 cells, hybrid cells split into 2 cells */
374     break;
375   case REFINER_SIMPLEX_TO_HEX_2D:
376     depthSize[0] = vEnd - vStart + fEnd - fStart + cEnd - cStart; /* Add a vertex on every face and cell */
377     depthSize[1] = 2*(fEnd - fStart) + 3*(cEnd - cStart);         /* Every face is split into 2 faces and 3 faces are added for each cell */
378     depthSize[2] = 3*(cEnd - cStart);                             /* Every cell split into 3 cells */
379     break;
380   case REFINER_HYBRID_SIMPLEX_TO_HEX_2D:
381     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
382     depthSize[0] = vEnd - vStart + fEnd - fStart + cEnd - cStart;           /* Add a vertex on every face and cell */
383     depthSize[1] = 2*(fEnd - fStart) + 3*(cMax - cStart) + 4*(cEnd - cMax); /* Every face is split into 2 faces and 3 faces are added for each cell. 4 for each hybrid cell */
384     depthSize[2] = 3*(cMax - cStart) + 4*(cEnd - cMax);                     /* Every cell split into 3 cells, hybrid cells split in 4 */
385     break;
386   case REFINER_HEX_2D:
387     depthSize[0] = vEnd - vStart + fEnd - fStart + cEnd - cStart; /* Add a vertex on every face and cell */
388     depthSize[1] = 2*(fEnd - fStart) + 4*(cEnd - cStart);         /* Every face is split into 2 faces and 4 faces are added for each cell */
389     depthSize[2] = 4*(cEnd - cStart);                             /* Every cell split into 4 cells */
390     break;
391   case REFINER_HYBRID_HEX_2D:
392     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
393     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
394     /* Quadrilateral */
395     depthSize[0] = vEnd - vStart + fMax - fStart + cMax - cStart;                 /* Add a vertex on every face and cell */
396     depthSize[1] = 2*(fMax - fStart) + 4*(cMax - cStart);                         /* Every face is split into 2 faces, and 4 faces are added for each cell */
397     depthSize[2] = 4*(cMax - cStart);                                             /* Every cell split into 4 cells */
398     /* Segment Prisms */
399     depthSize[0] += 0;                                                            /* No hybrid vertices */
400     depthSize[1] +=   (fEnd - fMax)  +   (cEnd - cMax);                           /* Every hybrid face remains and 1 faces is added for each hybrid cell */
401     depthSize[2] += 2*(cEnd - cMax);                                              /* Every hybrid cell split into 2 cells */
402     break;
403   case REFINER_SIMPLEX_3D:
404     depthSize[0] =    vEnd - vStart  +    eEnd - eStart;                    /* Add a vertex on every edge */
405     depthSize[1] = 2*(eEnd - eStart) + 3*(fEnd - fStart) + (cEnd - cStart); /* Every edge is split into 2 edges, 3 edges are added for each face, and 1 edge for each cell */
406     depthSize[2] = 4*(fEnd - fStart) + 8*(cEnd - cStart);                   /* Every face split into 4 faces and 8 faces are added for each cell */
407     depthSize[3] = 8*(cEnd - cStart);                                       /* Every cell split into 8 cells */
408     break;
409   case REFINER_HYBRID_SIMPLEX_3D:
410     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
411     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
412     if (eMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No edge maximum specified in hybrid mesh");
413     /* Tetrahedra */
414     depthSize[0]  =    vEnd - vStart  +    eMax - eStart;                    /* Add a vertex on every interior edge */
415     depthSize[1]  = 2*(eMax - eStart) + 3*(fMax - fStart) + (cMax - cStart); /* Every interior edge split into 2 edges, 3 edges added for each interior face, 1 edge for each interior cell */
416     depthSize[2]  = 4*(fMax - fStart) + 8*(cMax - cStart);                   /* Every interior face split into 4 faces, 8 faces added for each interior cell */
417     depthSize[3]  = 8*(cMax - cStart);                                       /* Every interior cell split into 8 cells */
418     /* Triangular Prisms */
419     depthSize[0] += 0;                                                       /* No hybrid vertices */
420     depthSize[1] +=   (eEnd - eMax)   +   (fEnd - fMax);                     /* Every hybrid edge remains, 1 edge for every hybrid face */
421     depthSize[2] += 2*(fEnd - fMax)   + 3*(cEnd - cMax);                     /* Every hybrid face split into 2 faces and 3 faces are added for each hybrid cell */
422     depthSize[3] += 4*(cEnd - cMax);                                         /* Every hybrid cell split into 4 cells */
423     break;
424   case REFINER_SIMPLEX_TO_HEX_3D:
425     depthSize[0] = vEnd - vStart + fEnd - fStart + eEnd - eStart + cEnd - cStart; /* Add a vertex on every face, edge and cell */
426     depthSize[1] = 2*(eEnd - eStart) + 3*(fEnd - fStart) + 4*(cEnd - cStart);     /* Every edge is split into 2 edges, 3 edges are added for each face, and 4 for each cell */
427     depthSize[2] = 3*(fEnd - fStart) + 6*(cEnd - cStart);                         /* Every face is split into 3 faces and 6 faces are added for each cell */
428     depthSize[3] = 4*(cEnd - cStart);                                             /* Every cell split into 4 cells */
429     break;
430   case REFINER_HYBRID_SIMPLEX_TO_HEX_3D:
431     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
432     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
433     if (eMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No edge maximum specified in hybrid mesh");
434     /* Tetrahedra */
435     depthSize[0]  =    vEnd - vStart  +    eMax - eStart  + fMax - fStart + cMax - cStart; /* Add a vertex on every interior edge, face and cell */
436     depthSize[1]  = 2*(eMax - eStart) + 3*(fMax - fStart) + 4*(cMax - cStart);             /* Every interior edge split into 2 edges, 3 edges added for each interior face, 4 edges for each interior cell */
437     depthSize[2]  = 3*(fMax - fStart) + 6*(cMax - cStart);                                 /* Every interior face split into 3 faces, 6 faces added for each interior cell */
438     depthSize[3]  = 4*(cMax - cStart);                                                     /* Every interior cell split into 8 cells */
439     /* Triangular Prisms */
440     depthSize[0] += 0;                                                 /* No hybrid vertices */
441     depthSize[1] +=   (eEnd - eMax) +   (fEnd - fMax) + (cEnd - cMax); /* Every hybrid edge remains, 1 edge for every hybrid face and cell */
442     depthSize[2] += 2*(fEnd - fMax) + 3*(cEnd - cMax);                 /* Every hybrid face split into 2 faces and 3 faces are added for each hybrid cell */
443     depthSize[3] += 3*(cEnd - cMax);                                   /* Every hybrid cell split into 3 cells */
444     break;
445   case REFINER_HEX_3D:
446     depthSize[0] = vEnd - vStart + eEnd - eStart + fEnd - fStart + cEnd - cStart; /* Add a vertex on every edge, face and cell */
447     depthSize[1] = 2*(eEnd - eStart) +  4*(fEnd - fStart) + 6*(cEnd - cStart);    /* Every edge is split into 2 edge, 4 edges are added for each face, and 6 edges for each cell */
448     depthSize[2] = 4*(fEnd - fStart) + 12*(cEnd - cStart);                        /* Every face is split into 4 faces, and 12 faces are added for each cell */
449     depthSize[3] = 8*(cEnd - cStart);                                             /* Every cell split into 8 cells */
450     break;
451   case REFINER_HYBRID_HEX_3D:
452     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
453     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
454     if (eMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No edge maximum specified in hybrid mesh");
455     /* Hexahedra */
456     depthSize[0] = vEnd - vStart + eMax - eStart + fMax - fStart + cMax - cStart; /* Add a vertex on every edge, face and cell */
457     depthSize[1] = 2*(eMax - eStart) +  4*(fMax - fStart) + 6*(cMax - cStart);    /* Every edge is split into 2 edge, 4 edges are added for each face, and 6 edges for each cell */
458     depthSize[2] = 4*(fMax - fStart) + 12*(cMax - cStart);                        /* Every face is split into 4 faces, and 12 faces are added for each cell */
459     depthSize[3] = 8*(cMax - cStart);                                             /* Every cell split into 8 cells */
460     /* Quadrilateral Prisms */
461     depthSize[0] += 0;                                                            /* No hybrid vertices */
462     depthSize[1] +=   (eEnd - eMax)   +   (fEnd - fMax)   +   (cEnd - cMax);      /* Every hybrid edge remains, 1 edge for every hybrid face and hybrid cell */
463     depthSize[2] += 2*(fEnd - fMax)   + 4*(cEnd - cMax);                          /* Every hybrid face split into 2 faces and 4 faces are added for each hybrid cell */
464     depthSize[3] += 4*(cEnd - cMax);                                              /* Every hybrid cell split into 4 cells */
465     break;
466   default:
467     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %s", CellRefiners[refiner]);
468   }
469   PetscFunctionReturn(0);
470 }
471 
472 /* Return triangle edge for orientation o, if it is r for o == 0 */
473 PETSC_STATIC_INLINE PetscInt GetTriEdge_Static(PetscInt o, PetscInt r) {
474   return (o < 0 ? 2-(o+r) : o+r)%3;
475 }
476 PETSC_STATIC_INLINE PetscInt GetTriEdgeInverse_Static(PetscInt o, PetscInt s) {
477   return (o < 0 ? 2-(o+s) : 3+s-o)%3;
478 }
479 
480 /* Return triangle subface for orientation o, if it is r for o == 0 */
481 PETSC_STATIC_INLINE PetscInt GetTriSubface_Static(PetscInt o, PetscInt r) {
482   return (o < 0 ? 3-(o+r) : o+r)%3;
483 }
484 PETSC_STATIC_INLINE PetscInt GetTriSubfaceInverse_Static(PetscInt o, PetscInt s) {
485   return (o < 0 ? 3-(o+s) : 3+s-o)%3;
486 }
487 
488 /* Return the interior edge number connecting the midpoints of the triangle edges r
489    and r+1 in the transitive closure for triangle orientation o */
490 PETSC_STATIC_INLINE PetscInt GetTriMidEdge_Static(PetscInt o, PetscInt r) {
491   return (o < 0 ? 1-(o+r) : o+r)%3;
492 }
493 PETSC_STATIC_INLINE PetscInt GetTriMidEdgeInverse_Static(PetscInt o, PetscInt s) {
494   return (o < 0 ? 1-(o+s) : 3+s-o)%3;
495 }
496 
497 /* Return the interior edge number connecting the midpoint of the triangle edge r
498    (in the transitive closure) and the vertex in the interior of the face for triangle orientation o */
499 PETSC_STATIC_INLINE PetscInt GetTriInteriorEdge_Static(PetscInt o, PetscInt r) {
500   return (o < 0 ? 2-(o+r) : o+r)%3;
501 }
502 PETSC_STATIC_INLINE PetscInt GetTriInteriorEdgeInverse_Static(PetscInt o, PetscInt s) {
503   return (o < 0 ? 2-(o+s) : 3+s-o)%3;
504 }
505 
506 /* Return quad edge for orientation o, if it is r for o == 0 */
507 PETSC_STATIC_INLINE PetscInt GetQuadEdge_Static(PetscInt o, PetscInt r) {
508   return (o < 0 ? 3-(o+r) : o+r)%4;
509 }
510 PETSC_STATIC_INLINE PetscInt GetQuadEdgeInverse_Static(PetscInt o, PetscInt s) {
511   return (o < 0 ? 3-(o+s) : 4+s-o)%4;
512 }
513 
514 /* Return quad subface for orientation o, if it is r for o == 0 */
515 PETSC_STATIC_INLINE PetscInt GetQuadSubface_Static(PetscInt o, PetscInt r) {
516   return (o < 0 ? 4-(o+r) : o+r)%4;
517 }
518 PETSC_STATIC_INLINE PetscInt GetQuadSubfaceInverse_Static(PetscInt o, PetscInt s) {
519   return (o < 0 ? 4-(o+s) : 4+s-o)%4;
520 }
521 
522 static PetscErrorCode DMLabelSetStratumBounds(DMLabel label, PetscInt value, PetscInt cStart, PetscInt cEnd)
523 {
524   IS             cIS;
525   PetscErrorCode ierr;
526 
527   PetscFunctionBegin;
528   ierr = ISCreateStride(PETSC_COMM_SELF, cEnd - cStart, cStart, 1, &cIS);CHKERRQ(ierr);
529   ierr = DMLabelSetStratumIS(label, value, cIS);CHKERRQ(ierr);
530   ierr = ISDestroy(&cIS);CHKERRQ(ierr);
531   PetscFunctionReturn(0);
532 }
533 
534 static PetscErrorCode CellRefinerSetConeSizes(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
535 {
536   PetscInt       depth, cStart, cStartNew, cEnd, cEndNew, cMax, c, vStart, vStartNew, vEnd, vEndNew, vMax, v, fStart, fStartNew, fEnd, fEndNew, fMax, f, eStart, eStartNew, eEnd, eEndNew, eMax, e, r;
537   DMLabel        depthLabel, celltypeLabel;
538   PetscErrorCode ierr;
539 
540   PetscFunctionBegin;
541   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
542   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
543   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
544   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
545   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
546   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
547   ierr = GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);CHKERRQ(ierr);
548   ierr = GetDepthEnd_Private(depth, depthSize, &cEndNew, &fEndNew, &eEndNew, &vEndNew);CHKERRQ(ierr);
549   ierr = DMCreateLabel(rdm,"depth");CHKERRQ(ierr);
550   ierr = DMPlexGetDepthLabel(rdm,&depthLabel);CHKERRQ(ierr);
551   ierr = DMLabelSetStratumBounds(depthLabel, 0, vStartNew, vEndNew);CHKERRQ(ierr);
552   if (depth > 2) ierr = DMLabelSetStratumBounds(depthLabel, 1, eStartNew, eEndNew);CHKERRQ(ierr);
553   if (depth > 1) ierr = DMLabelSetStratumBounds(depthLabel, depth - 1, fStartNew, fEndNew);CHKERRQ(ierr);
554   if (depth > 0) ierr = DMLabelSetStratumBounds(depthLabel, depth, cStartNew, cEndNew);CHKERRQ(ierr);
555   {
556     DM_Plex *plex = (DM_Plex *) rdm->data;
557     ierr = PetscObjectStateGet((PetscObject) depthLabel, &plex->depthState);CHKERRQ(ierr);
558   }
559   if (!refiner) PetscFunctionReturn(0);
560   switch (refiner) {
561   case REFINER_SIMPLEX_1D:
562     /* All cells have 2 vertices */
563     for (c = cStart; c < cEnd; ++c) {
564       for (r = 0; r < 2; ++r) {
565         const PetscInt newp = cStartNew + (c - cStart)*2 + r;
566 
567         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
568       }
569     }
570     /* Old vertices have identical supports */
571     for (v = vStart; v < vEnd; ++v) {
572       const PetscInt newp = vStartNew + (v - vStart);
573       PetscInt       size;
574 
575       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
576       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
577     }
578     /* Cell vertices have support 2 */
579     for (c = cStart; c < cEnd; ++c) {
580       const PetscInt newp = vStartNew + (vEnd - vStart) + (c - cStart);
581 
582       ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
583     }
584     break;
585   case REFINER_SIMPLEX_2D:
586     /* All cells have 3 faces */
587     for (c = cStart; c < cEnd; ++c) {
588       for (r = 0; r < 4; ++r) {
589         const PetscInt newp = (c - cStart)*4 + r;
590 
591         ierr = DMPlexSetConeSize(rdm, newp, 3);CHKERRQ(ierr);
592       }
593     }
594     /* Split faces have 2 vertices and the same cells as the parent */
595     for (f = fStart; f < fEnd; ++f) {
596       for (r = 0; r < 2; ++r) {
597         const PetscInt newp = fStartNew + (f - fStart)*2 + r;
598         PetscInt       size;
599 
600         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
601         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
602         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
603       }
604     }
605     /* Interior faces have 2 vertices and 2 cells */
606     for (c = cStart; c < cEnd; ++c) {
607       for (r = 0; r < 3; ++r) {
608         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*3 + r;
609 
610         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
611         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
612       }
613     }
614     /* Old vertices have identical supports */
615     for (v = vStart; v < vEnd; ++v) {
616       const PetscInt newp = vStartNew + (v - vStart);
617       PetscInt       size;
618 
619       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
620       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
621     }
622     /* Face vertices have 2 + cells*2 supports */
623     for (f = fStart; f < fEnd; ++f) {
624       const PetscInt newp = vStartNew + (vEnd - vStart) + (f - fStart);
625       PetscInt       size;
626 
627       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
628       ierr = DMPlexSetSupportSize(rdm, newp, 2 + size*2);CHKERRQ(ierr);
629     }
630     break;
631   case REFINER_SIMPLEX_TO_HEX_2D:
632     /* All cells have 4 faces */
633     for (c = cStart; c < cEnd; ++c) {
634       for (r = 0; r < 3; ++r) {
635         const PetscInt newp = (c - cStart)*3 + r;
636 
637         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
638       }
639     }
640     /* Split faces have 2 vertices and the same cells as the parent */
641     for (f = fStart; f < fEnd; ++f) {
642       for (r = 0; r < 2; ++r) {
643         const PetscInt newp = fStartNew + (f - fStart)*2 + r;
644         PetscInt       size;
645 
646         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
647         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
648         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
649       }
650     }
651     /* Interior faces have 2 vertices and 2 cells */
652     for (c = cStart; c < cEnd; ++c) {
653       for (r = 0; r < 3; ++r) {
654         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*3 + r;
655 
656         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
657         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
658       }
659     }
660     /* Old vertices have identical supports */
661     for (v = vStart; v < vEnd; ++v) {
662       const PetscInt newp = vStartNew + (v - vStart);
663       PetscInt       size;
664 
665       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
666       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
667     }
668     /* Split-face vertices have cells + 2 supports */
669     for (f = fStart; f < fEnd; ++f) {
670       const PetscInt newp = vStartNew + (vEnd - vStart) + (f - fStart);
671       PetscInt       size;
672 
673       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
674       ierr = DMPlexSetSupportSize(rdm, newp, size + 2);CHKERRQ(ierr);
675     }
676     /* Interior vertices have 3 supports */
677     for (c = cStart; c < cEnd; ++c) {
678       const PetscInt newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + c - cStart;
679 
680       ierr = DMPlexSetSupportSize(rdm, newp, 3);CHKERRQ(ierr);
681     }
682     break;
683   case REFINER_HYBRID_SIMPLEX_TO_HEX_2D:
684     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
685     /* the mesh is no longer hybrid */
686     cMax = PetscMin(cEnd, cMax);
687     /* All cells have 4 faces */
688     for (c = cStart; c < cMax; ++c) {
689       for (r = 0; r < 3; ++r) {
690         const PetscInt newp = (c - cStart)*3 + r;
691 
692         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
693       }
694     }
695     for (c = cMax; c < cEnd; ++c) {
696       for (r = 0; r < 4; ++r) {
697         const PetscInt newp = (cMax - cStart)*3 + (c - cMax)*4 + r;
698 
699         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
700       }
701     }
702     /* Split faces have 2 vertices and the same cells as the parent */
703     for (f = fStart; f < fEnd; ++f) {
704       for (r = 0; r < 2; ++r) {
705         const PetscInt newp = fStartNew + (f - fStart)*2 + r;
706         PetscInt       size;
707 
708         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
709         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
710         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
711       }
712     }
713     /* Interior faces have 2 vertices and 2 cells */
714     for (c = cStart; c < cMax; ++c) {
715       for (r = 0; r < 3; ++r) {
716         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*3 + r;
717 
718         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
719         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
720       }
721     }
722     /* Hybrid interior faces have 2 vertices and 2 cells */
723     for (c = cMax; c < cEnd; ++c) {
724       for (r = 0; r < 4; ++r) {
725         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (cMax - cStart)*3 + (c - cMax)*4 + r;
726 
727         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
728         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
729       }
730     }
731     /* Old vertices have identical supports */
732     for (v = vStart; v < vEnd; ++v) {
733       const PetscInt newp = vStartNew + (v - vStart);
734       PetscInt       size;
735 
736       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
737       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
738     }
739     /* Split-face vertices have cells + 2 supports */
740     for (f = fStart; f < fEnd; ++f) {
741       const PetscInt newp = vStartNew + (vEnd - vStart) + (f - fStart);
742       PetscInt       size;
743 
744       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
745       ierr = DMPlexSetSupportSize(rdm, newp, size + 2);CHKERRQ(ierr);
746     }
747     /* Interior vertices have 3 supports */
748     for (c = cStart; c < cMax; ++c) {
749       const PetscInt newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + c - cStart;
750 
751       ierr = DMPlexSetSupportSize(rdm, newp, 3);CHKERRQ(ierr);
752     }
753     /* Hybrid interior vertices have 4 supports */
754     for (c = cMax; c < cEnd; ++c) {
755       const PetscInt newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + c - cStart;
756 
757       ierr = DMPlexSetSupportSize(rdm, newp, 4);CHKERRQ(ierr);
758     }
759     break;
760   case REFINER_HEX_2D:
761     /* All cells have 4 faces */
762     for (c = cStart; c < cEnd; ++c) {
763       for (r = 0; r < 4; ++r) {
764         const PetscInt newp = cStartNew + (c - cStart)*4 + r;
765 
766         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
767       }
768     }
769     /* Split faces have 2 vertices and the same cells as the parent */
770     for (f = fStart; f < fEnd; ++f) {
771       for (r = 0; r < 2; ++r) {
772         const PetscInt newp = fStartNew + (f - fStart)*2 + r;
773         PetscInt       size;
774 
775         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
776         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
777         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
778       }
779     }
780     /* Interior faces have 2 vertices and 2 cells */
781     for (c = cStart; c < cEnd; ++c) {
782       for (r = 0; r < 4; ++r) {
783         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*4 + r;
784 
785         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
786         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
787       }
788     }
789     /* Old vertices have identical supports */
790     for (v = vStart; v < vEnd; ++v) {
791       const PetscInt newp = vStartNew + (v - vStart);
792       PetscInt       size;
793 
794       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
795       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
796     }
797     /* Face vertices have 2 + cells supports */
798     for (f = fStart; f < fEnd; ++f) {
799       const PetscInt newp = vStartNew + (vEnd - vStart) + (f - fStart);
800       PetscInt       size;
801 
802       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
803       ierr = DMPlexSetSupportSize(rdm, newp, 2 + size);CHKERRQ(ierr);
804     }
805     /* Cell vertices have 4 supports */
806     for (c = cStart; c < cEnd; ++c) {
807       const PetscInt newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (c - cStart);
808 
809       ierr = DMPlexSetSupportSize(rdm, newp, 4);CHKERRQ(ierr);
810     }
811     break;
812   case REFINER_HYBRID_SIMPLEX_2D:
813     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
814     cMax = PetscMin(cEnd, cMax);
815     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
816     fMax = PetscMin(fEnd, fMax);
817     ierr = DMPlexSetHybridBounds(rdm, cStartNew + (cMax - cStart)*4, fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3, PETSC_DETERMINE, PETSC_DETERMINE);CHKERRQ(ierr);
818     /* Interior cells have 3 faces */
819     for (c = cStart; c < cMax; ++c) {
820       for (r = 0; r < 4; ++r) {
821         const PetscInt newp = cStartNew + (c - cStart)*4 + r;
822 
823         ierr = DMPlexSetConeSize(rdm, newp, 3);CHKERRQ(ierr);
824       }
825     }
826     /* Hybrid cells have 4 faces */
827     for (c = cMax; c < cEnd; ++c) {
828       for (r = 0; r < 2; ++r) {
829         const PetscInt newp = cStartNew + (cMax - cStart)*4 + (c - cMax)*2 + r;
830 
831         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
832       }
833     }
834     /* Interior split faces have 2 vertices and the same cells as the parent */
835     for (f = fStart; f < fMax; ++f) {
836       for (r = 0; r < 2; ++r) {
837         const PetscInt newp = fStartNew + (f - fStart)*2 + r;
838         PetscInt       size;
839 
840         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
841         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
842         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
843       }
844     }
845     /* Interior cell faces have 2 vertices and 2 cells */
846     for (c = cStart; c < cMax; ++c) {
847       for (r = 0; r < 3; ++r) {
848         const PetscInt newp = fStartNew + (fMax - fStart)*2 + (c - cStart)*3 + r;
849 
850         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
851         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
852       }
853     }
854     /* Hybrid faces have 2 vertices and the same cells */
855     for (f = fMax; f < fEnd; ++f) {
856       const PetscInt newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (f - fMax);
857       PetscInt       size;
858 
859       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
860       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
861       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
862     }
863     /* Hybrid cell faces have 2 vertices and 2 cells */
864     for (c = cMax; c < cEnd; ++c) {
865       const PetscInt newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (fEnd - fMax) + (c - cMax);
866 
867       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
868       ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
869     }
870     /* Old vertices have identical supports */
871     for (v = vStart; v < vEnd; ++v) {
872       const PetscInt newp = vStartNew + (v - vStart);
873       PetscInt       size;
874 
875       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
876       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
877     }
878     /* Face vertices have 2 + (2 interior, 1 hybrid) supports */
879     for (f = fStart; f < fMax; ++f) {
880       const PetscInt newp = vStartNew + (vEnd - vStart) + (f - fStart);
881       const PetscInt *support;
882       PetscInt       size, newSize = 2, s;
883 
884       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
885       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
886       for (s = 0; s < size; ++s) {
887         if (support[s] >= cMax) newSize += 1;
888         else newSize += 2;
889       }
890       ierr = DMPlexSetSupportSize(rdm, newp, newSize);CHKERRQ(ierr);
891     }
892     break;
893   case REFINER_HYBRID_HEX_2D:
894     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
895     cMax = PetscMin(cEnd, cMax);
896     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
897     fMax = PetscMin(fEnd, fMax);
898     ierr = DMPlexSetHybridBounds(rdm, cStartNew + (cMax - cStart)*4, fStartNew + (fMax - fStart)*2 + (cMax - cStart)*4, PETSC_DETERMINE, PETSC_DETERMINE);CHKERRQ(ierr);
899     /* Interior cells have 4 faces */
900     for (c = cStart; c < cMax; ++c) {
901       for (r = 0; r < 4; ++r) {
902         const PetscInt newp = cStartNew + (c - cStart)*4 + r;
903 
904         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
905       }
906     }
907     /* Hybrid cells have 4 faces */
908     for (c = cMax; c < cEnd; ++c) {
909       for (r = 0; r < 2; ++r) {
910         const PetscInt newp = cStartNew + (cMax - cStart)*4 + (c - cMax)*2 + r;
911 
912         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
913       }
914     }
915     /* Interior split faces have 2 vertices and the same cells as the parent */
916     for (f = fStart; f < fMax; ++f) {
917       for (r = 0; r < 2; ++r) {
918         const PetscInt newp = fStartNew + (f - fStart)*2 + r;
919         PetscInt       size;
920 
921         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
922         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
923         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
924       }
925     }
926     /* Interior cell faces have 2 vertices and 2 cells */
927     for (c = cStart; c < cMax; ++c) {
928       for (r = 0; r < 4; ++r) {
929         const PetscInt newp = fStartNew + (fMax - fStart)*2 + (c - cStart)*4 + r;
930 
931         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
932         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
933       }
934     }
935     /* Hybrid faces have 2 vertices and the same cells */
936     for (f = fMax; f < fEnd; ++f) {
937       const PetscInt newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*4 + (f - fMax);
938       PetscInt       size;
939 
940       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
941       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
942       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
943     }
944     /* Hybrid cell faces have 2 vertices and 2 cells */
945     for (c = cMax; c < cEnd; ++c) {
946       const PetscInt newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*4 + (fEnd - fMax) + (c - cMax);
947 
948       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
949       ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
950     }
951     /* Old vertices have identical supports */
952     for (v = vStart; v < vEnd; ++v) {
953       const PetscInt newp = vStartNew + (v - vStart);
954       PetscInt       size;
955 
956       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
957       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
958     }
959     /* Face vertices have 2 + cells supports */
960     for (f = fStart; f < fMax; ++f) {
961       const PetscInt newp = vStartNew + (vEnd - vStart) + (f - fStart);
962       PetscInt       size;
963 
964       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
965       ierr = DMPlexSetSupportSize(rdm, newp, 2 + size);CHKERRQ(ierr);
966     }
967     /* Cell vertices have 4 supports */
968     for (c = cStart; c < cMax; ++c) {
969       const PetscInt newp = vStartNew + (vEnd - vStart) + (fMax - fStart) + (c - cStart);
970 
971       ierr = DMPlexSetSupportSize(rdm, newp, 4);CHKERRQ(ierr);
972     }
973     break;
974   case REFINER_SIMPLEX_3D:
975     /* All cells have 4 faces */
976     for (c = cStart; c < cEnd; ++c) {
977       for (r = 0; r < 8; ++r) {
978         const PetscInt newp = cStartNew + (c - cStart)*8 + r;
979 
980         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
981       }
982     }
983     /* Split faces have 3 edges and the same cells as the parent */
984     for (f = fStart; f < fEnd; ++f) {
985       for (r = 0; r < 4; ++r) {
986         const PetscInt newp = fStartNew + (f - fStart)*4 + r;
987         PetscInt       size;
988 
989         ierr = DMPlexSetConeSize(rdm, newp, 3);CHKERRQ(ierr);
990         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
991         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
992       }
993     }
994     /* Interior cell faces have 3 edges and 2 cells */
995     for (c = cStart; c < cEnd; ++c) {
996       for (r = 0; r < 8; ++r) {
997         const PetscInt newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*8 + r;
998 
999         ierr = DMPlexSetConeSize(rdm, newp, 3);CHKERRQ(ierr);
1000         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
1001       }
1002     }
1003     /* Split edges have 2 vertices and the same faces */
1004     for (e = eStart; e < eEnd; ++e) {
1005       for (r = 0; r < 2; ++r) {
1006         const PetscInt newp = eStartNew + (e - eStart)*2 + r;
1007         PetscInt       size;
1008 
1009         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
1010         ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
1011         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
1012       }
1013     }
1014     /* Face edges have 2 vertices and 2+cells*(1/2) faces */
1015     for (f = fStart; f < fEnd; ++f) {
1016       for (r = 0; r < 3; ++r) {
1017         const PetscInt  newp = eStartNew + (eEnd - eStart)*2 + (f - fStart)*3 + r;
1018         const PetscInt *cone, *ornt, *support, eint[4] = {1, 0, 2, 0};
1019         PetscInt        coneSize, c, supportSize, s, er, intFaces = 0;
1020 
1021         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
1022         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
1023         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
1024         for (s = 0; s < supportSize; ++s) {
1025           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
1026           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
1027           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
1028           for (c = 0; c < coneSize; ++c) {if (cone[c] == f) break;}
1029           /* Here we want to determine whether edge newp contains a vertex which is part of the cross-tet edge */
1030           er = GetTriMidEdgeInverse_Static(ornt[c], r);
1031           if (er == eint[c]) {
1032             intFaces += 1;
1033           } else {
1034             intFaces += 2;
1035           }
1036         }
1037         ierr = DMPlexSetSupportSize(rdm, newp, 2+intFaces);CHKERRQ(ierr);
1038       }
1039     }
1040     /* Interior cell edges have 2 vertices and 4 faces */
1041     for (c = cStart; c < cEnd; ++c) {
1042       const PetscInt newp = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart);
1043 
1044       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
1045       ierr = DMPlexSetSupportSize(rdm, newp, 4);CHKERRQ(ierr);
1046     }
1047     /* Old vertices have identical supports */
1048     for (v = vStart; v < vEnd; ++v) {
1049       const PetscInt newp = vStartNew + (v - vStart);
1050       PetscInt       size;
1051 
1052       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
1053       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
1054     }
1055     /* Edge vertices have 2 + faces*2 + cells*0/1 supports */
1056     for (e = eStart; e < eEnd; ++e) {
1057       const PetscInt newp = vStartNew + (vEnd - vStart) + (e - eStart);
1058       PetscInt       size, *star = NULL, starSize, s, cellSize = 0;
1059 
1060       ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
1061       ierr = DMPlexGetTransitiveClosure(dm, e, PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
1062       for (s = 0; s < starSize*2; s += 2) {
1063         const PetscInt *cone, *ornt;
1064         PetscInt        e01, e23;
1065 
1066         if ((star[s] >= cStart) && (star[s] < cEnd)) {
1067           /* Check edge 0-1 */
1068           ierr = DMPlexGetCone(dm, star[s], &cone);CHKERRQ(ierr);
1069           ierr = DMPlexGetConeOrientation(dm, star[s], &ornt);CHKERRQ(ierr);
1070           ierr = DMPlexGetCone(dm, cone[0], &cone);CHKERRQ(ierr);
1071           e01  = cone[GetTriEdge_Static(ornt[0], 0)];
1072           /* Check edge 2-3 */
1073           ierr = DMPlexGetCone(dm, star[s], &cone);CHKERRQ(ierr);
1074           ierr = DMPlexGetConeOrientation(dm, star[s], &ornt);CHKERRQ(ierr);
1075           ierr = DMPlexGetCone(dm, cone[2], &cone);CHKERRQ(ierr);
1076           e23  = cone[GetTriEdge_Static(ornt[2], 1)];
1077           if ((e01 == e) || (e23 == e)) ++cellSize;
1078         }
1079       }
1080       ierr = DMPlexRestoreTransitiveClosure(dm, e, PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
1081       ierr = DMPlexSetSupportSize(rdm, newp, 2 + size*2 + cellSize);CHKERRQ(ierr);
1082     }
1083     break;
1084   case REFINER_HYBRID_SIMPLEX_3D:
1085     ierr = DMPlexSetHybridBounds(rdm, cStartNew + 8*(cMax-cStart), fStartNew + 4*(fMax - fStart) + 8*(cMax - cStart),
1086                                  eStartNew + 2*(eMax - eStart) + 3*(fMax - fStart) + (cMax - cStart), PETSC_DETERMINE);CHKERRQ(ierr);
1087     /* Interior cells have 4 faces */
1088     for (c = cStart; c < cMax; ++c) {
1089       for (r = 0; r < 8; ++r) {
1090         const PetscInt newp = cStartNew + (c - cStart)*8 + r;
1091 
1092         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
1093       }
1094     }
1095     /* Hybrid cells have 5 faces */
1096     for (c = cMax; c < cEnd; ++c) {
1097       for (r = 0; r < 4; ++r) {
1098         const PetscInt newp = cStartNew + (cMax - cStart)*8 + (c - cMax)*4 + r;
1099 
1100         ierr = DMPlexSetConeSize(rdm, newp, 5);CHKERRQ(ierr);
1101       }
1102     }
1103     /* Interior split faces have 3 edges and the same cells as the parent */
1104     for (f = fStart; f < fMax; ++f) {
1105       for (r = 0; r < 4; ++r) {
1106         const PetscInt newp = fStartNew + (f - fStart)*4 + r;
1107         PetscInt       size;
1108 
1109         ierr = DMPlexSetConeSize(rdm, newp, 3);CHKERRQ(ierr);
1110         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
1111         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
1112       }
1113     }
1114     /* Interior cell faces have 3 edges and 2 cells */
1115     for (c = cStart; c < cMax; ++c) {
1116       for (r = 0; r < 8; ++r) {
1117         const PetscInt newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*8 + r;
1118 
1119         ierr = DMPlexSetConeSize(rdm, newp, 3);CHKERRQ(ierr);
1120         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
1121       }
1122     }
1123     /* Hybrid split faces have 4 edges and the same cells as the parent */
1124     for (f = fMax; f < fEnd; ++f) {
1125       for (r = 0; r < 2; ++r) {
1126         const PetscInt newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (f - fMax)*2 + r;
1127         PetscInt       size;
1128 
1129         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
1130         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
1131         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
1132       }
1133     }
1134     /* Hybrid cells faces have 4 edges and 2 cells */
1135     for (c = cMax; c < cEnd; ++c) {
1136       for (r = 0; r < 3; ++r) {
1137         const PetscInt newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (c - cMax)*3 + r;
1138 
1139         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
1140         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
1141       }
1142     }
1143     /* Interior split edges have 2 vertices and the same faces */
1144     for (e = eStart; e < eMax; ++e) {
1145       for (r = 0; r < 2; ++r) {
1146         const PetscInt newp = eStartNew + (e - eStart)*2 + r;
1147         PetscInt       size;
1148 
1149         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
1150         ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
1151         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
1152       }
1153     }
1154     /* Interior face edges have 2 vertices and 2+cells*(1/2) faces */
1155     for (f = fStart; f < fMax; ++f) {
1156       for (r = 0; r < 3; ++r) {
1157         const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (f - fStart)*3 + r;
1158         const PetscInt *cone, *ornt, *support, eint[4] = {1, 0, 2, 0};
1159         PetscInt        coneSize, c, supportSize, s, er, intFaces = 0;
1160 
1161         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
1162         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
1163         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
1164         for (s = 0; s < supportSize; ++s) {
1165           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
1166           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
1167           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
1168           for (c = 0; c < coneSize; ++c) {if (cone[c] == f) break;}
1169           if (support[s] < cMax) {
1170             /* Here we want to determine whether edge newp contains a vertex which is part of the cross-tet edge */
1171             er = GetTriMidEdgeInverse_Static(ornt[c], r);
1172             if (er == eint[c]) {
1173               intFaces += 1;
1174             } else {
1175               intFaces += 2;
1176             }
1177           } else {
1178             intFaces += 1;
1179           }
1180         }
1181         ierr = DMPlexSetSupportSize(rdm, newp, 2+intFaces);CHKERRQ(ierr);
1182       }
1183     }
1184     /* Interior cell edges have 2 vertices and 4 faces */
1185     for (c = cStart; c < cMax; ++c) {
1186       const PetscInt newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart);
1187 
1188       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
1189       ierr = DMPlexSetSupportSize(rdm, newp, 4);CHKERRQ(ierr);
1190     }
1191     /* Hybrid edges have 2 vertices and the same faces */
1192     for (e = eMax; e < eEnd; ++e) {
1193       const PetscInt newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (e - eMax);
1194       PetscInt       size;
1195 
1196       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
1197       ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
1198       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
1199     }
1200     /* Hybrid face edges have 2 vertices and 2+2*cells faces */
1201     for (f = fMax; f < fEnd; ++f) {
1202       const PetscInt newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (eEnd - eMax) + (f - fMax);
1203       PetscInt       size;
1204 
1205       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
1206       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
1207       ierr = DMPlexSetSupportSize(rdm, newp, 2+2*size);CHKERRQ(ierr);
1208     }
1209     /* Interior vertices have identical supports */
1210     for (v = vStart; v < vEnd; ++v) {
1211       const PetscInt newp = vStartNew + (v - vStart);
1212       PetscInt       size;
1213 
1214       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
1215       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
1216     }
1217     /* Interior edge vertices have 2 + interior face*2 + hybrid face + cells*0/1 supports */
1218     for (e = eStart; e < eMax; ++e) {
1219       const PetscInt  newp = vStartNew + (vEnd - vStart) + (e - eStart);
1220       const PetscInt *support;
1221       PetscInt        size, *star = NULL, starSize, s, faceSize = 0, cellSize = 0;
1222 
1223       ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
1224       ierr = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
1225       for (s = 0; s < size; ++s) {
1226         if (support[s] < fMax) faceSize += 2;
1227         else                   faceSize += 1;
1228       }
1229       ierr = DMPlexGetTransitiveClosure(dm, e, PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
1230       for (s = 0; s < starSize*2; s += 2) {
1231         const PetscInt *cone, *ornt;
1232         PetscInt        e01, e23;
1233 
1234         if ((star[s] >= cStart) && (star[s] < cMax)) {
1235           /* Check edge 0-1 */
1236           ierr = DMPlexGetCone(dm, star[s], &cone);CHKERRQ(ierr);
1237           ierr = DMPlexGetConeOrientation(dm, star[s], &ornt);CHKERRQ(ierr);
1238           ierr = DMPlexGetCone(dm, cone[0], &cone);CHKERRQ(ierr);
1239           e01  = cone[GetTriEdge_Static(ornt[0], 0)];
1240           /* Check edge 2-3 */
1241           ierr = DMPlexGetCone(dm, star[s], &cone);CHKERRQ(ierr);
1242           ierr = DMPlexGetConeOrientation(dm, star[s], &ornt);CHKERRQ(ierr);
1243           ierr = DMPlexGetCone(dm, cone[2], &cone);CHKERRQ(ierr);
1244           e23  = cone[GetTriEdge_Static(ornt[2], 1)];
1245           if ((e01 == e) || (e23 == e)) ++cellSize;
1246         }
1247       }
1248       ierr = DMPlexRestoreTransitiveClosure(dm, e, PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
1249       ierr = DMPlexSetSupportSize(rdm, newp, 2 + faceSize + cellSize);CHKERRQ(ierr);
1250     }
1251     break;
1252   case REFINER_SIMPLEX_TO_HEX_3D:
1253     /* All cells have 6 faces */
1254     for (c = cStart; c < cEnd; ++c) {
1255       for (r = 0; r < 4; ++r) {
1256         const PetscInt newp = cStartNew + (c - cStart)*4 + r;
1257 
1258         ierr = DMPlexSetConeSize(rdm, newp, 6);CHKERRQ(ierr);
1259       }
1260     }
1261     /* Split faces have 4 edges and the same cells as the parent */
1262     for (f = fStart; f < fEnd; ++f) {
1263       for (r = 0; r < 3; ++r) {
1264         const PetscInt newp = fStartNew + (f - fStart)*3 + r;
1265         PetscInt       size;
1266 
1267         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
1268         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
1269         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
1270       }
1271     }
1272     /* Interior cell faces have 4 edges and 2 cells */
1273     for (c = cStart; c < cEnd; ++c) {
1274       for (r = 0; r < 6; ++r) {
1275         const PetscInt newp = fStartNew + (fEnd - fStart)*3 + (c - cStart)*6 + r;
1276 
1277         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
1278         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
1279       }
1280     }
1281     /* Split edges have 2 vertices and the same faces */
1282     for (e = eStart; e < eEnd; ++e) {
1283       for (r = 0; r < 2; ++r) {
1284         const PetscInt newp = eStartNew + (e - eStart)*2 + r;
1285         PetscInt       size;
1286 
1287         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
1288         ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
1289         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
1290       }
1291     }
1292     /* Face edges have 2 vertices and 2 + cell faces supports */
1293     for (f = fStart; f < fEnd; ++f) {
1294       for (r = 0; r < 3; ++r) {
1295         const PetscInt  newp = eStartNew + (eEnd - eStart)*2 + (f - fStart)*3 + r;
1296         PetscInt        size;
1297 
1298         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
1299         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
1300         ierr = DMPlexSetSupportSize(rdm, newp, 2+size);CHKERRQ(ierr);
1301       }
1302     }
1303     /* Interior cell edges have 2 vertices and 3 faces */
1304     for (c = cStart; c < cEnd; ++c) {
1305       for (r = 0; r < 4; ++r) {
1306         const PetscInt newp = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + r;
1307 
1308         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
1309         ierr = DMPlexSetSupportSize(rdm, newp, 3);CHKERRQ(ierr);
1310       }
1311     }
1312     /* Old vertices have identical supports */
1313     for (v = vStart; v < vEnd; ++v) {
1314       const PetscInt newp = vStartNew + (v - vStart);
1315       PetscInt       size;
1316 
1317       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
1318       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
1319     }
1320     /* Edge vertices have 2 + faces supports */
1321     for (e = eStart; e < eEnd; ++e) {
1322       const PetscInt newp = vStartNew + (vEnd - vStart) + (e - eStart);
1323       PetscInt       size;
1324 
1325       ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
1326       ierr = DMPlexSetSupportSize(rdm, newp, 2 + size);CHKERRQ(ierr);
1327     }
1328     /* Face vertices have 3 + cells supports */
1329     for (f = fStart; f < fEnd; ++f) {
1330       const PetscInt newp = vStartNew + (vEnd - vStart) + (eEnd - eStart) + f - fStart;
1331       PetscInt       size;
1332 
1333       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
1334       ierr = DMPlexSetSupportSize(rdm, newp, 3 + size);CHKERRQ(ierr);
1335     }
1336     /* Interior cell vertices have 4 supports */
1337     for (c = cStart; c < cEnd; ++c) {
1338       const PetscInt newp = vStartNew + (vEnd - vStart) + (eEnd - eStart) + fEnd - fStart + c - cStart;
1339 
1340       ierr = DMPlexSetSupportSize(rdm, newp, 4);CHKERRQ(ierr);
1341     }
1342     break;
1343   case REFINER_HYBRID_SIMPLEX_TO_HEX_3D:
1344     /* the mesh is no longer hybrid */
1345     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
1346     cMax = PetscMin(cEnd, cMax);
1347     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
1348     fMax = PetscMin(fEnd, fMax);
1349     if (eMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No edge maximum specified in hybrid mesh");
1350     eMax = PetscMin(eEnd, eMax);
1351     /* All cells have 6 faces */
1352     for (c = cStart; c < cMax; ++c) {
1353       for (r = 0; r < 4; ++r) {
1354         const PetscInt newp = cStartNew + (c - cStart)*4 + r;
1355 
1356         ierr = DMPlexSetConeSize(rdm, newp, 6);CHKERRQ(ierr);
1357       }
1358     }
1359     for (c = cMax; c < cEnd; ++c) {
1360       for (r = 0; r < 3; ++r) {
1361         const PetscInt newp = cStartNew + (cMax - cStart)*4 + (c - cMax)*3 + r;
1362 
1363         ierr = DMPlexSetConeSize(rdm, newp, 6);CHKERRQ(ierr);
1364       }
1365     }
1366     /* Interior split faces have 4 edges and the same cells as the parent */
1367     for (f = fStart; f < fMax; ++f) {
1368       for (r = 0; r < 3; ++r) {
1369         const PetscInt newp = fStartNew + (f - fStart)*3 + r;
1370         PetscInt       size;
1371 
1372         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
1373         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
1374         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
1375       }
1376     }
1377     /* Interior cell faces have 4 edges and 2 cells */
1378     for (c = cStart; c < cMax; ++c) {
1379       for (r = 0; r < 6; ++r) {
1380         const PetscInt newp = fStartNew + (fMax - fStart)*3 + (c - cStart)*6 + r;
1381 
1382         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
1383         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
1384       }
1385     }
1386     /* Hybrid split faces have 4 edges and the same cells as the parent */
1387     for (f = fMax; f < fEnd; ++f) {
1388       for (r = 0; r < 2; ++r) {
1389         const PetscInt newp = fStartNew + (fMax - fStart)*3 + (cMax - cStart)*6 + (f - fMax)*2 + r;
1390         PetscInt       size;
1391 
1392         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
1393         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
1394         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
1395       }
1396     }
1397     /* Hybrid cell faces have 4 edges and 2 cells */
1398     for (c = cMax; c < cEnd; ++c) {
1399       for (r = 0; r < 3; ++r) {
1400         const PetscInt newp = fStartNew + (fMax - fStart)*3 + (cMax - cStart)*6 + (fEnd - fMax)*2 + (c - cMax)*3 + r;
1401 
1402         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
1403         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
1404       }
1405     }
1406     /* Interior split edges have 2 vertices and the same faces */
1407     for (e = eStart; e < eMax; ++e) {
1408       for (r = 0; r < 2; ++r) {
1409         const PetscInt newp = eStartNew + (e - eStart)*2 + r;
1410         PetscInt       size;
1411 
1412         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
1413         ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
1414         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
1415       }
1416     }
1417     /* Interior face edges have 2 vertices and 2 + cell faces supports */
1418     for (f = fStart; f < fMax; ++f) {
1419       for (r = 0; r < 3; ++r) {
1420         const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (f - fStart)*3 + r;
1421         PetscInt        size;
1422 
1423         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
1424         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
1425         ierr = DMPlexSetSupportSize(rdm, newp, 2+size);CHKERRQ(ierr);
1426       }
1427     }
1428     /* Interior cell edges have 2 vertices and 3 faces */
1429     for (c = cStart; c < cMax; ++c) {
1430       for (r = 0; r < 4; ++r) {
1431         const PetscInt newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart)*4 + r;
1432 
1433         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
1434         ierr = DMPlexSetSupportSize(rdm, newp, 3);CHKERRQ(ierr);
1435       }
1436     }
1437     /* Hybrid edges have 2 vertices and the same faces */
1438     for (e = eMax; e < eEnd; ++e) {
1439       const PetscInt newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart)*4 + (e - eMax);
1440       PetscInt       size;
1441 
1442       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
1443       ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
1444       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
1445     }
1446     /* Hybrid face edges have 2 vertices and 2+cells faces */
1447     for (f = fMax; f < fEnd; ++f) {
1448       const PetscInt newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart)*4 + (eEnd - eMax) + (f - fMax);
1449       PetscInt        size;
1450 
1451       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
1452       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
1453       ierr = DMPlexSetSupportSize(rdm, newp, 2+size);CHKERRQ(ierr);
1454     }
1455     /* Hybrid cell edges have 2 vertices and 3 faces */
1456     for (c = cMax; c < cEnd; ++c) {
1457       const PetscInt newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart)*4 + (eEnd - eMax) + (fEnd - fMax) + (c - cMax);
1458 
1459       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
1460       ierr = DMPlexSetSupportSize(rdm, newp, 3);CHKERRQ(ierr);
1461     }
1462     /* Old vertices have identical supports */
1463     for (v = vStart; v < vEnd; ++v) {
1464       const PetscInt newp = vStartNew + (v - vStart);
1465       PetscInt       size;
1466 
1467       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
1468       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
1469     }
1470     /* Interior edge vertices have 2 + faces supports */
1471     for (e = eStart; e < eMax; ++e) {
1472       const PetscInt newp = vStartNew + (vEnd - vStart) + (e - eStart);
1473       PetscInt       size;
1474 
1475       ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
1476       ierr = DMPlexSetSupportSize(rdm, newp, 2 + size);CHKERRQ(ierr);
1477     }
1478     /* Interior face vertices have 3 + cells supports */
1479     for (f = fStart; f < fMax; ++f) {
1480       const PetscInt newp = vStartNew + (vEnd - vStart) + (eMax - eStart) + f - fStart;
1481       PetscInt       size;
1482 
1483       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
1484       ierr = DMPlexSetSupportSize(rdm, newp, 3 + size);CHKERRQ(ierr);
1485     }
1486     /* Interior cell vertices have 4 supports */
1487     for (c = cStart; c < cMax; ++c) {
1488       const PetscInt newp = vStartNew + (vEnd - vStart) + (eMax - eStart) + (fMax - fStart) + c - cStart;
1489 
1490       ierr = DMPlexSetSupportSize(rdm, newp, 4);CHKERRQ(ierr);
1491     }
1492     break;
1493   case REFINER_HEX_3D:
1494     /* All cells have 6 faces */
1495     for (c = cStart; c < cEnd; ++c) {
1496       for (r = 0; r < 8; ++r) {
1497         const PetscInt newp = (c - cStart)*8 + r;
1498 
1499         ierr = DMPlexSetConeSize(rdm, newp, 6);CHKERRQ(ierr);
1500       }
1501     }
1502     /* Split faces have 4 edges and the same cells as the parent */
1503     for (f = fStart; f < fEnd; ++f) {
1504       for (r = 0; r < 4; ++r) {
1505         const PetscInt newp = fStartNew + (f - fStart)*4 + r;
1506         PetscInt       size;
1507 
1508         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
1509         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
1510         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
1511       }
1512     }
1513     /* Interior faces have 4 edges and 2 cells */
1514     for (c = cStart; c < cEnd; ++c) {
1515       for (r = 0; r < 12; ++r) {
1516         const PetscInt newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + r;
1517 
1518         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
1519         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
1520       }
1521     }
1522     /* Split edges have 2 vertices and the same faces as the parent */
1523     for (e = eStart; e < eEnd; ++e) {
1524       for (r = 0; r < 2; ++r) {
1525         const PetscInt newp = eStartNew + (e - eStart)*2 + r;
1526         PetscInt       size;
1527 
1528         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
1529         ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
1530         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
1531       }
1532     }
1533     /* Face edges have 2 vertices and 2+cells faces */
1534     for (f = fStart; f < fEnd; ++f) {
1535       for (r = 0; r < 4; ++r) {
1536         const PetscInt newp = eStartNew + (eEnd - eStart)*2 + (f - fStart)*4 + r;
1537         PetscInt       size;
1538 
1539         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
1540         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
1541         ierr = DMPlexSetSupportSize(rdm, newp, 2+size);CHKERRQ(ierr);
1542       }
1543     }
1544     /* Cell edges have 2 vertices and 4 faces */
1545     for (c = cStart; c < cEnd; ++c) {
1546       for (r = 0; r < 6; ++r) {
1547         const PetscInt newp = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*4 + (c - cStart)*6 + r;
1548 
1549         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
1550         ierr = DMPlexSetSupportSize(rdm, newp, 4);CHKERRQ(ierr);
1551       }
1552     }
1553     /* Old vertices have identical supports */
1554     for (v = vStart; v < vEnd; ++v) {
1555       const PetscInt newp = vStartNew + (v - vStart);
1556       PetscInt       size;
1557 
1558       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
1559       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
1560     }
1561     /* Edge vertices have 2 + faces supports */
1562     for (e = eStart; e < eEnd; ++e) {
1563       const PetscInt newp = vStartNew + (vEnd - vStart) + (e - eStart);
1564       PetscInt       size;
1565 
1566       ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
1567       ierr = DMPlexSetSupportSize(rdm, newp, 2 + size);CHKERRQ(ierr);
1568     }
1569     /* Face vertices have 4 + cells supports */
1570     for (f = fStart; f < fEnd; ++f) {
1571       const PetscInt newp = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (f - fStart);
1572       PetscInt       size;
1573 
1574       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
1575       ierr = DMPlexSetSupportSize(rdm, newp, 4 + size);CHKERRQ(ierr);
1576     }
1577     /* Cell vertices have 6 supports */
1578     for (c = cStart; c < cEnd; ++c) {
1579       const PetscInt newp = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (fEnd - fStart) + (c - cStart);
1580 
1581       ierr = DMPlexSetSupportSize(rdm, newp, 6);CHKERRQ(ierr);
1582     }
1583     break;
1584   case REFINER_HYBRID_HEX_3D:
1585     ierr = DMPlexSetHybridBounds(rdm, cStartNew + 8*(cMax-cStart), fStartNew + 4*(fMax - fStart) + 12*(cMax - cStart),
1586                                  eStartNew + 2*(eMax - eStart) + 4*(fMax - fStart) + 6*(cMax - cStart), PETSC_DETERMINE);CHKERRQ(ierr);
1587     /* Interior cells have 6 faces */
1588     for (c = cStart; c < cMax; ++c) {
1589       for (r = 0; r < 8; ++r) {
1590         const PetscInt newp = cStartNew + (c - cStart)*8 + r;
1591 
1592         ierr = DMPlexSetConeSize(rdm, newp, 6);CHKERRQ(ierr);
1593       }
1594     }
1595     /* Hybrid cells have 6 faces */
1596     for (c = cMax; c < cEnd; ++c) {
1597       for (r = 0; r < 4; ++r) {
1598         const PetscInt newp = cStartNew + (cMax - cStart)*8 + (c - cMax)*4 + r;
1599 
1600         ierr = DMPlexSetConeSize(rdm, newp, 6);CHKERRQ(ierr);
1601       }
1602     }
1603     /* Interior split faces have 4 edges and the same cells as the parent */
1604     for (f = fStart; f < fMax; ++f) {
1605       for (r = 0; r < 4; ++r) {
1606         const PetscInt newp = fStartNew + (f - fStart)*4 + r;
1607         PetscInt       size;
1608 
1609         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
1610         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
1611         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
1612       }
1613     }
1614     /* Interior cell faces have 4 edges and 2 cells */
1615     for (c = cStart; c < cMax; ++c) {
1616       for (r = 0; r < 12; ++r) {
1617         const PetscInt newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + r;
1618 
1619         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
1620         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
1621       }
1622     }
1623     /* Hybrid split faces have 4 edges and the same cells as the parent */
1624     for (f = fMax; f < fEnd; ++f) {
1625       for (r = 0; r < 2; ++r) {
1626         const PetscInt newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (f - fMax)*2 + r;
1627         PetscInt       size;
1628 
1629         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
1630         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
1631         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
1632       }
1633     }
1634     /* Hybrid cells faces have 4 edges and 2 cells */
1635     for (c = cMax; c < cEnd; ++c) {
1636       for (r = 0; r < 4; ++r) {
1637         const PetscInt newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd - fMax)*2 + (c - cMax)*4 + r;
1638 
1639         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
1640         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
1641       }
1642     }
1643     /* Interior split edges have 2 vertices and the same faces as the parent */
1644     for (e = eStart; e < eMax; ++e) {
1645       for (r = 0; r < 2; ++r) {
1646         const PetscInt newp = eStartNew + (e - eStart)*2 + r;
1647         PetscInt       size;
1648 
1649         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
1650         ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
1651         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
1652       }
1653     }
1654     /* Interior face edges have 2 vertices and 2+cells faces */
1655     for (f = fStart; f < fMax; ++f) {
1656       for (r = 0; r < 4; ++r) {
1657         const PetscInt newp = eStartNew + (eMax - eStart)*2 + (f - fStart)*4 + r;
1658         PetscInt       size;
1659 
1660         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
1661         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
1662         ierr = DMPlexSetSupportSize(rdm, newp, 2+size);CHKERRQ(ierr);
1663       }
1664     }
1665     /* Interior cell edges have 2 vertices and 4 faces */
1666     for (c = cStart; c < cMax; ++c) {
1667       for (r = 0; r < 6; ++r) {
1668         const PetscInt newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (c - cStart)*6 + r;
1669 
1670         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
1671         ierr = DMPlexSetSupportSize(rdm, newp, 4);CHKERRQ(ierr);
1672       }
1673     }
1674     /* Hybrid edges have 2 vertices and the same faces */
1675     for (e = eMax; e < eEnd; ++e) {
1676       const PetscInt newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (e - eMax);
1677       PetscInt       size;
1678 
1679       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
1680       ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
1681       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
1682     }
1683     /* Hybrid face edges have 2 vertices and 2+cells faces */
1684     for (f = fMax; f < fEnd; ++f) {
1685       const PetscInt newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (eEnd - eMax) + (f - fMax);
1686       PetscInt       size;
1687 
1688       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
1689       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
1690       ierr = DMPlexSetSupportSize(rdm, newp, 2+size);CHKERRQ(ierr);
1691     }
1692     /* Hybrid cell edges have 2 vertices and 4 faces */
1693     for (c = cMax; c < cEnd; ++c) {
1694       const PetscInt newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (eEnd - eMax) + (fEnd - fMax) + (c - cMax);
1695 
1696       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
1697       ierr = DMPlexSetSupportSize(rdm, newp, 4);CHKERRQ(ierr);
1698     }
1699     /* Interior vertices have identical supports */
1700     for (v = vStart; v < vEnd; ++v) {
1701       const PetscInt newp = vStartNew + (v - vStart);
1702       PetscInt       size;
1703 
1704       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
1705       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
1706     }
1707     /* Interior edge vertices have 2 + faces supports */
1708     for (e = eStart; e < eMax; ++e) {
1709       const PetscInt newp = vStartNew + (vEnd - vStart) + (e - eStart);
1710       PetscInt       size;
1711 
1712       ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
1713       ierr = DMPlexSetSupportSize(rdm, newp, 2 + size);CHKERRQ(ierr);
1714     }
1715     /* Interior face vertices have 4 + cells supports */
1716     for (f = fStart; f < fMax; ++f) {
1717       const PetscInt newp = vStartNew + (vEnd - vStart) + (eMax - eStart) + (f - fStart);
1718       PetscInt       size;
1719 
1720       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
1721       ierr = DMPlexSetSupportSize(rdm, newp, 4 + size);CHKERRQ(ierr);
1722     }
1723     /* Interior cell vertices have 6 supports */
1724     for (c = cStart; c < cMax; ++c) {
1725       const PetscInt newp = vStartNew + (vEnd - vStart) + (eMax - eStart) + (fMax - fStart) + (c - cStart);
1726 
1727       ierr = DMPlexSetSupportSize(rdm, newp, 6);CHKERRQ(ierr);
1728     }
1729     break;
1730   default:
1731     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %s", CellRefiners[refiner]);
1732   }
1733   {
1734     DM_Plex *plex = (DM_Plex *) rdm->data;
1735 
1736     ierr = DMPlexGetCellTypeLabel(rdm, &celltypeLabel);CHKERRQ(ierr);
1737     ierr = PetscObjectStateGet((PetscObject) celltypeLabel, &plex->celltypeState);CHKERRQ(ierr);
1738   }
1739   PetscFunctionReturn(0);
1740 }
1741 
1742 static PetscErrorCode CellRefinerSetCones(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
1743 {
1744   const PetscInt *faces, cellInd[4] = {0, 1, 2, 3};
1745   PetscInt        cStart,    cEnd,    cMax,    vStart,    vEnd, vMax, fStart,    fEnd,    fMax,    eStart,    eEnd,    eMax;
1746   PetscInt        cStartNew, cEndNew, cMaxNew, vStartNew, vEndNew,    fStartNew, fEndNew, fMaxNew, eStartNew, eEndNew, eMaxNew;
1747   PetscInt        depth, maxSupportSize, *supportRef, c, f, e, v, r;
1748 #if defined(PETSC_USE_DEBUG)
1749   PetscInt        p;
1750 #endif
1751   PetscErrorCode  ierr;
1752 
1753   PetscFunctionBegin;
1754   if (!refiner) PetscFunctionReturn(0);
1755   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
1756   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
1757   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
1758   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
1759   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
1760   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
1761   ierr = GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);CHKERRQ(ierr);
1762   ierr = GetDepthEnd_Private(depth, depthSize, &cEndNew, &fEndNew, &eEndNew, &vEndNew);CHKERRQ(ierr);
1763   switch (refiner) {
1764   case REFINER_SIMPLEX_1D:
1765     /* Max support size of refined mesh is 2 */
1766     ierr = PetscMalloc1(2, &supportRef);CHKERRQ(ierr);
1767     /* All cells have 2 vertices */
1768     for (c = cStart; c < cEnd; ++c) {
1769       const PetscInt  newv = vStartNew + (vEnd - vStart) + (c - cStart);
1770 
1771       for (r = 0; r < 2; ++r) {
1772         const PetscInt newp = cStartNew + (c - cStart)*2 + r;
1773         const PetscInt *cone;
1774         PetscInt        coneNew[2];
1775 
1776         ierr             = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
1777         coneNew[0]       = vStartNew + (cone[0] - vStart);
1778         coneNew[1]       = vStartNew + (cone[1] - vStart);
1779         coneNew[(r+1)%2] = newv;
1780         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
1781 #if defined(PETSC_USE_DEBUG)
1782         if ((newp < cStartNew) || (newp >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", newp, cStartNew, cEndNew);
1783         for (p = 0; p < 2; ++p) {
1784           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);
1785         }
1786 #endif
1787       }
1788     }
1789     /* Old vertices have identical supports */
1790     for (v = vStart; v < vEnd; ++v) {
1791       const PetscInt  newp = vStartNew + (v - vStart);
1792       const PetscInt *support, *cone;
1793       PetscInt        size, s;
1794 
1795       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
1796       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
1797       for (s = 0; s < size; ++s) {
1798         PetscInt r = 0;
1799 
1800         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
1801         if (cone[1] == v) r = 1;
1802         supportRef[s] = cStartNew + (support[s] - cStart)*2 + r;
1803       }
1804       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
1805 #if defined(PETSC_USE_DEBUG)
1806       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", newp, vStartNew, vEndNew);
1807       for (p = 0; p < size; ++p) {
1808         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);
1809       }
1810 #endif
1811     }
1812     /* Cell vertices have support of 2 cells */
1813     for (c = cStart; c < cEnd; ++c) {
1814       const PetscInt  newp = vStartNew + (vEnd - vStart) + (c - cStart);
1815 
1816       supportRef[0] = cStartNew + (c - cStart)*2 + 0;
1817       supportRef[1] = cStartNew + (c - cStart)*2 + 1;
1818       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
1819 #if defined(PETSC_USE_DEBUG)
1820       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", newp, vStartNew, vEndNew);
1821       for (p = 0; p < 2; ++p) {
1822         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);
1823       }
1824 #endif
1825     }
1826     ierr = PetscFree(supportRef);CHKERRQ(ierr);
1827     break;
1828   case REFINER_SIMPLEX_2D:
1829     /*
1830      2
1831      |\
1832      | \
1833      |  \
1834      |   \
1835      | C  \
1836      |     \
1837      |      \
1838      2---1---1
1839      |\  D  / \
1840      | 2   0   \
1841      |A \ /  B  \
1842      0---0-------1
1843      */
1844     /* All cells have 3 faces */
1845     for (c = cStart; c < cEnd; ++c) {
1846       const PetscInt  newp = cStartNew + (c - cStart)*4;
1847       const PetscInt *cone, *ornt;
1848       PetscInt        coneNew[3], orntNew[3];
1849 
1850       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
1851       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
1852       /* A triangle */
1853       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
1854       orntNew[0] = ornt[0];
1855       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 2;
1856       orntNew[1] = -2;
1857       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
1858       orntNew[2] = ornt[2];
1859       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
1860       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
1861 #if defined(PETSC_USE_DEBUG)
1862       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);
1863       for (p = 0; p < 3; ++p) {
1864         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);
1865       }
1866 #endif
1867       /* B triangle */
1868       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
1869       orntNew[0] = ornt[0];
1870       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
1871       orntNew[1] = ornt[1];
1872       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 0;
1873       orntNew[2] = -2;
1874       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
1875       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
1876 #if defined(PETSC_USE_DEBUG)
1877       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);
1878       for (p = 0; p < 3; ++p) {
1879         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);
1880       }
1881 #endif
1882       /* C triangle */
1883       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 1;
1884       orntNew[0] = -2;
1885       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
1886       orntNew[1] = ornt[1];
1887       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
1888       orntNew[2] = ornt[2];
1889       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
1890       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
1891 #if defined(PETSC_USE_DEBUG)
1892       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);
1893       for (p = 0; p < 3; ++p) {
1894         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);
1895       }
1896 #endif
1897       /* D triangle */
1898       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 0;
1899       orntNew[0] = 0;
1900       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 1;
1901       orntNew[1] = 0;
1902       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 2;
1903       orntNew[2] = 0;
1904       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
1905       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
1906 #if defined(PETSC_USE_DEBUG)
1907       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);
1908       for (p = 0; p < 3; ++p) {
1909         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);
1910       }
1911 #endif
1912     }
1913     /* Split faces have 2 vertices and the same cells as the parent */
1914     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
1915     ierr = PetscMalloc1(2 + maxSupportSize*2, &supportRef);CHKERRQ(ierr);
1916     for (f = fStart; f < fEnd; ++f) {
1917       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);
1918 
1919       for (r = 0; r < 2; ++r) {
1920         const PetscInt  newp = fStartNew + (f - fStart)*2 + r;
1921         const PetscInt *cone, *ornt, *support;
1922         PetscInt        coneNew[2], coneSize, c, supportSize, s;
1923 
1924         ierr             = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
1925         coneNew[0]       = vStartNew + (cone[0] - vStart);
1926         coneNew[1]       = vStartNew + (cone[1] - vStart);
1927         coneNew[(r+1)%2] = newv;
1928         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
1929 #if defined(PETSC_USE_DEBUG)
1930         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
1931         for (p = 0; p < 2; ++p) {
1932           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);
1933         }
1934 #endif
1935         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
1936         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
1937         for (s = 0; s < supportSize; ++s) {
1938           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
1939           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
1940           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
1941           for (c = 0; c < coneSize; ++c) {
1942             if (cone[c] == f) break;
1943           }
1944           supportRef[s] = cStartNew + (support[s] - cStart)*4 + (ornt[c] < 0 ? (c+1-r)%3 : (c+r)%3);
1945         }
1946         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
1947 #if defined(PETSC_USE_DEBUG)
1948         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
1949         for (p = 0; p < supportSize; ++p) {
1950           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);
1951         }
1952 #endif
1953       }
1954     }
1955     /* Interior faces have 2 vertices and 2 cells */
1956     for (c = cStart; c < cEnd; ++c) {
1957       const PetscInt *cone;
1958 
1959       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
1960       for (r = 0; r < 3; ++r) {
1961         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*3 + r;
1962         PetscInt       coneNew[2];
1963         PetscInt       supportNew[2];
1964 
1965         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r]       - fStart);
1966         coneNew[1] = vStartNew + (vEnd - vStart) + (cone[(r+1)%3] - fStart);
1967         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
1968 #if defined(PETSC_USE_DEBUG)
1969         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
1970         for (p = 0; p < 2; ++p) {
1971           if ((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);
1972         }
1973 #endif
1974         supportNew[0] = (c - cStart)*4 + (r+1)%3;
1975         supportNew[1] = (c - cStart)*4 + 3;
1976         ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
1977 #if defined(PETSC_USE_DEBUG)
1978         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
1979         for (p = 0; p < 2; ++p) {
1980           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);
1981         }
1982 #endif
1983       }
1984     }
1985     /* Old vertices have identical supports */
1986     for (v = vStart; v < vEnd; ++v) {
1987       const PetscInt  newp = vStartNew + (v - vStart);
1988       const PetscInt *support, *cone;
1989       PetscInt        size, s;
1990 
1991       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
1992       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
1993       for (s = 0; s < size; ++s) {
1994         PetscInt r = 0;
1995 
1996         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
1997         if (cone[1] == v) r = 1;
1998         supportRef[s] = fStartNew + (support[s] - fStart)*2 + r;
1999       }
2000       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
2001 #if defined(PETSC_USE_DEBUG)
2002       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", newp, vStartNew, vEndNew);
2003       for (p = 0; p < size; ++p) {
2004         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);
2005       }
2006 #endif
2007     }
2008     /* Face vertices have 2 + cells*2 supports */
2009     for (f = fStart; f < fEnd; ++f) {
2010       const PetscInt  newp = vStartNew + (vEnd - vStart) + (f - fStart);
2011       const PetscInt *cone, *support;
2012       PetscInt        size, s;
2013 
2014       ierr          = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
2015       ierr          = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
2016       supportRef[0] = fStartNew + (f - fStart)*2 + 0;
2017       supportRef[1] = fStartNew + (f - fStart)*2 + 1;
2018       for (s = 0; s < size; ++s) {
2019         PetscInt r = 0;
2020 
2021         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
2022         if      (cone[1] == f) r = 1;
2023         else if (cone[2] == f) r = 2;
2024         supportRef[2+s*2+0] = fStartNew + (fEnd - fStart)*2 + (support[s] - cStart)*3 + (r+2)%3;
2025         supportRef[2+s*2+1] = fStartNew + (fEnd - fStart)*2 + (support[s] - cStart)*3 + r;
2026       }
2027       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
2028 #if defined(PETSC_USE_DEBUG)
2029       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", newp, vStartNew, vEndNew);
2030       for (p = 0; p < 2+size*2; ++p) {
2031         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);
2032       }
2033 #endif
2034     }
2035     ierr = PetscFree(supportRef);CHKERRQ(ierr);
2036     break;
2037   case REFINER_SIMPLEX_TO_HEX_2D:
2038     /*
2039      2
2040      |\
2041      | \
2042      |  \
2043      |   \
2044      | C  \
2045      |     \
2046      2      1
2047      |\    / \
2048      | 2  1   \
2049      |  \/     \
2050      |   |      \
2051      |A  |   B   \
2052      |   0        \
2053      |   |         \
2054      0---0----------1
2055      */
2056     /* All cells have 4 faces */
2057     for (c = cStart; c < cEnd; ++c) {
2058       const PetscInt  newp = cStartNew + (c - cStart)*3;
2059       const PetscInt *cone, *ornt;
2060       PetscInt        coneNew[4], orntNew[4];
2061 
2062       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
2063       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
2064       /* A quad */
2065       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
2066       orntNew[0] = ornt[0];
2067       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 0;
2068       orntNew[1] = 0;
2069       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 2;
2070       orntNew[2] = -2;
2071       coneNew[3] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
2072       orntNew[3] = ornt[2];
2073       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
2074       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
2075 #if defined(PETSC_USE_DEBUG)
2076       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);
2077       for (p = 0; p < 4; ++p) {
2078         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);
2079       }
2080 #endif
2081       /* B quad */
2082       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
2083       orntNew[0] = ornt[0];
2084       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
2085       orntNew[1] = ornt[1];
2086       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 1;
2087       orntNew[2] = 0;
2088       coneNew[3] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 0;
2089       orntNew[3] = -2;
2090       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
2091       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
2092 #if defined(PETSC_USE_DEBUG)
2093       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);
2094       for (p = 0; p < 4; ++p) {
2095         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);
2096       }
2097 #endif
2098       /* C quad */
2099       coneNew[0] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
2100       orntNew[0] = ornt[1];
2101       coneNew[1] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
2102       orntNew[1] = ornt[2];
2103       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 2;
2104       orntNew[2] = 0;
2105       coneNew[3] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 1;
2106       orntNew[3] = -2;
2107       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
2108       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
2109 #if defined(PETSC_USE_DEBUG)
2110       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);
2111       for (p = 0; p < 4; ++p) {
2112         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);
2113       }
2114 #endif
2115     }
2116     /* Split faces have 2 vertices and the same cells as the parent */
2117     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
2118     ierr = PetscMalloc1(2 + maxSupportSize*2, &supportRef);CHKERRQ(ierr);
2119     for (f = fStart; f < fEnd; ++f) {
2120       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);
2121 
2122       for (r = 0; r < 2; ++r) {
2123         const PetscInt  newp = fStartNew + (f - fStart)*2 + r;
2124         const PetscInt *cone, *ornt, *support;
2125         PetscInt        coneNew[2], coneSize, c, supportSize, s;
2126 
2127         ierr             = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
2128         coneNew[0]       = vStartNew + (cone[0] - vStart);
2129         coneNew[1]       = vStartNew + (cone[1] - vStart);
2130         coneNew[(r+1)%2] = newv;
2131         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2132 #if defined(PETSC_USE_DEBUG)
2133         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
2134         for (p = 0; p < 2; ++p) {
2135           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);
2136         }
2137 #endif
2138         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
2139         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
2140         for (s = 0; s < supportSize; ++s) {
2141           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
2142           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
2143           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
2144           for (c = 0; c < coneSize; ++c) {
2145             if (cone[c] == f) break;
2146           }
2147           supportRef[s] = cStartNew + (support[s] - cStart)*3 + (ornt[c] < 0 ? (c+1-r)%3 : (c+r)%3);
2148         }
2149         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
2150 #if defined(PETSC_USE_DEBUG)
2151         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
2152         for (p = 0; p < supportSize; ++p) {
2153           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);
2154         }
2155 #endif
2156       }
2157     }
2158     /* Interior faces have 2 vertices and 2 cells */
2159     for (c = cStart; c < cEnd; ++c) {
2160       const PetscInt *cone;
2161 
2162       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
2163       for (r = 0; r < 3; ++r) {
2164         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*3 + r;
2165         PetscInt       coneNew[2];
2166         PetscInt       supportNew[2];
2167 
2168         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r] - fStart);
2169         coneNew[1] = vStartNew + (vEnd - vStart) + (fEnd    - fStart) + (c - cStart);
2170         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2171 #if defined(PETSC_USE_DEBUG)
2172         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
2173         for (p = 0; p < 2; ++p) {
2174           if ((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);
2175         }
2176 #endif
2177         supportNew[0] = (c - cStart)*3 + r%3;
2178         supportNew[1] = (c - cStart)*3 + (r+1)%3;
2179         ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
2180 #if defined(PETSC_USE_DEBUG)
2181         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
2182         for (p = 0; p < 2; ++p) {
2183           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);
2184         }
2185 #endif
2186       }
2187     }
2188     /* Old vertices have identical supports */
2189     for (v = vStart; v < vEnd; ++v) {
2190       const PetscInt  newp = vStartNew + (v - vStart);
2191       const PetscInt *support, *cone;
2192       PetscInt        size, s;
2193 
2194       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
2195       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
2196       for (s = 0; s < size; ++s) {
2197         PetscInt r = 0;
2198 
2199         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
2200         if (cone[1] == v) r = 1;
2201         supportRef[s] = fStartNew + (support[s] - fStart)*2 + r;
2202       }
2203       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
2204 #if defined(PETSC_USE_DEBUG)
2205       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", newp, vStartNew, vEndNew);
2206       for (p = 0; p < size; ++p) {
2207         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);
2208       }
2209 #endif
2210     }
2211     /* Split-face vertices have cells + 2 supports */
2212     for (f = fStart; f < fEnd; ++f) {
2213       const PetscInt  newp = vStartNew + (vEnd - vStart) + (f - fStart);
2214       const PetscInt *cone, *support;
2215       PetscInt        size, s;
2216 
2217       ierr          = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
2218       ierr          = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
2219       supportRef[0] = fStartNew + (f - fStart)*2 + 0;
2220       supportRef[1] = fStartNew + (f - fStart)*2 + 1;
2221       for (s = 0; s < size; ++s) {
2222         PetscInt r = 0;
2223 
2224         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
2225         if      (cone[1] == f) r = 1;
2226         else if (cone[2] == f) r = 2;
2227         supportRef[2+s+0] = fStartNew + (fEnd - fStart)*2 + (support[s] - cStart)*3 + r;
2228       }
2229       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
2230 #if defined(PETSC_USE_DEBUG)
2231       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", newp, vStartNew, vEndNew);
2232       for (p = 0; p < 2+size; ++p) {
2233         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);
2234       }
2235 #endif
2236     }
2237     /* Interior vertices have 3 supports */
2238     for (c = cStart; c < cEnd; ++c) {
2239       const PetscInt newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + c - cStart;
2240 
2241       supportRef[0] = fStartNew + (fEnd - fStart)*2 + (c - cStart)*3 + 0;
2242       supportRef[1] = fStartNew + (fEnd - fStart)*2 + (c - cStart)*3 + 1;
2243       supportRef[2] = fStartNew + (fEnd - fStart)*2 + (c - cStart)*3 + 2;
2244       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
2245     }
2246     ierr = PetscFree(supportRef);CHKERRQ(ierr);
2247     break;
2248   case REFINER_HYBRID_SIMPLEX_TO_HEX_2D:
2249     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
2250     cMax = PetscMin(cEnd, cMax);
2251     for (c = cStart; c < cMax; ++c) {
2252       const PetscInt  newp = cStartNew + (c - cStart)*3;
2253       const PetscInt *cone, *ornt;
2254       PetscInt        coneNew[4], orntNew[4];
2255 
2256       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
2257       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
2258       /* A quad */
2259       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
2260       orntNew[0] = ornt[0];
2261       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 0;
2262       orntNew[1] = 0;
2263       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 2;
2264       orntNew[2] = -2;
2265       coneNew[3] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
2266       orntNew[3] = ornt[2];
2267       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
2268       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
2269 #if defined(PETSC_USE_DEBUG)
2270       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);
2271       for (p = 0; p < 4; ++p) {
2272         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);
2273       }
2274 #endif
2275       /* B quad */
2276       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
2277       orntNew[0] = ornt[0];
2278       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
2279       orntNew[1] = ornt[1];
2280       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 1;
2281       orntNew[2] = 0;
2282       coneNew[3] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 0;
2283       orntNew[3] = -2;
2284       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
2285       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
2286 #if defined(PETSC_USE_DEBUG)
2287       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);
2288       for (p = 0; p < 4; ++p) {
2289         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);
2290       }
2291 #endif
2292       /* C quad */
2293       coneNew[0] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
2294       orntNew[0] = ornt[1];
2295       coneNew[1] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
2296       orntNew[1] = ornt[2];
2297       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 2;
2298       orntNew[2] = 0;
2299       coneNew[3] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 1;
2300       orntNew[3] = -2;
2301       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
2302       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
2303 #if defined(PETSC_USE_DEBUG)
2304       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);
2305       for (p = 0; p < 4; ++p) {
2306         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);
2307       }
2308 #endif
2309     }
2310     /*
2311      2---------1---------3
2312      |         |         |
2313      |    D    1    C    |
2314      |         |         |
2315      2----2----0----3----3
2316      |         |         |
2317      |    A    0    B    |
2318      |         |         |
2319      0---------0---------1
2320      */
2321     /* Parent cells are input as prisms but children are quads, since the mesh is no longer hybrid */
2322     for (c = cMax; c < cEnd; ++c) {
2323       const PetscInt  newp  = cStartNew + (cMax - cStart)*3 + (c - cMax)*4;
2324       const PetscInt  newpt = (cMax - cStart)*3 + (c - cMax)*4;
2325       const PetscInt *cone, *ornt;
2326       PetscInt        coneNew[4], orntNew[4];
2327 
2328       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
2329       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
2330       /* A quad */
2331       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
2332       orntNew[0] = ornt[0];
2333       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + newpt + 0;
2334       orntNew[1] = 0;
2335       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + newpt + 2;
2336       orntNew[2] = -2;
2337       coneNew[3] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
2338       orntNew[3] = ornt[2] < 0 ? 0 : -2;
2339       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
2340       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
2341 #if defined(PETSC_USE_DEBUG)
2342       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);
2343       for (p = 0; p < 4; ++p) {
2344         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);
2345       }
2346 #endif
2347       /* B quad */
2348       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
2349       orntNew[0] = ornt[0];
2350       coneNew[1] = fStartNew + (cone[3] - fStart)*2 + (ornt[3] < 0 ? 1 : 0);
2351       orntNew[1] = ornt[3];
2352       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + newpt + 3;
2353       orntNew[2] = 0;
2354       coneNew[3] = fStartNew + (fEnd    - fStart)*2 + newpt + 0;
2355       orntNew[3] = -2;
2356       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
2357       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
2358 #if defined(PETSC_USE_DEBUG)
2359       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);
2360       for (p = 0; p < 4; ++p) {
2361         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);
2362       }
2363 #endif
2364       /* C quad */
2365       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + newpt + 3;
2366       orntNew[0] = -2;
2367       coneNew[1] = fStartNew + (cone[3] - fStart)*2 + (ornt[3] < 0 ? 0 : 1);
2368       orntNew[1] = ornt[3];
2369       coneNew[2] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
2370       orntNew[2] = ornt[1] < 0 ? 0 : -2;
2371       coneNew[3] = fStartNew + (fEnd    - fStart)*2 + newpt + 1;
2372       orntNew[3] = 0;
2373       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
2374       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
2375 #if defined(PETSC_USE_DEBUG)
2376       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);
2377       for (p = 0; p < 4; ++p) {
2378         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);
2379       }
2380 #endif
2381       /* D quad */
2382       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + newpt + 2;
2383       orntNew[0] = 0;
2384       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + newpt + 1;
2385       orntNew[1] = -2;
2386       coneNew[2] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
2387       orntNew[2] = ornt[1] < 0 ? 0 : -2;
2388       coneNew[3] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
2389       orntNew[3] = ornt[2] < 0 ? 0 : -2;
2390       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
2391       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
2392 #if defined(PETSC_USE_DEBUG)
2393       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);
2394       for (p = 0; p < 4; ++p) {
2395         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);
2396       }
2397 #endif
2398     }
2399     /* Split faces have 2 vertices and the same cells as the parent */
2400     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
2401     ierr = PetscMalloc1(2 + maxSupportSize*2, &supportRef);CHKERRQ(ierr);
2402     for (f = fStart; f < fEnd; ++f) {
2403       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);
2404 
2405       for (r = 0; r < 2; ++r) {
2406         const PetscInt  newp = fStartNew + (f - fStart)*2 + r;
2407         const PetscInt *cone, *ornt, *support;
2408         PetscInt        coneNew[2], coneSize, c, supportSize, s;
2409 
2410         ierr             = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
2411         coneNew[0]       = vStartNew + (cone[0] - vStart);
2412         coneNew[1]       = vStartNew + (cone[1] - vStart);
2413         coneNew[(r+1)%2] = newv;
2414         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2415 #if defined(PETSC_USE_DEBUG)
2416         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
2417         for (p = 0; p < 2; ++p) {
2418           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);
2419         }
2420 #endif
2421         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
2422         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
2423         for (s = 0; s < supportSize; ++s) {
2424           const PetscInt p2q[4][2] = { {0, 1},
2425                                        {3, 2},
2426                                        {0, 3},
2427                                        {1, 2} };
2428 
2429           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
2430           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
2431           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
2432           for (c = 0; c < coneSize; ++c) {
2433             if (cone[c] == f) break;
2434           }
2435           if (coneSize == 3)      supportRef[s] = cStartNew + (support[s] - cStart)*3 + (ornt[c] < 0 ? (c+1-r)%3 : (c+r)%3);
2436           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]);
2437           else SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected cone size %D", coneSize);
2438         }
2439         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
2440 #if defined(PETSC_USE_DEBUG)
2441         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
2442         for (p = 0; p < supportSize; ++p) {
2443           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);
2444         }
2445 #endif
2446       }
2447     }
2448     /* Interior faces have 2 vertices and 2 cells */
2449     for (c = cStart; c < cMax; ++c) {
2450       const PetscInt *cone;
2451 
2452       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
2453       for (r = 0; r < 3; ++r) {
2454         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*3 + r;
2455         PetscInt       coneNew[2];
2456         PetscInt       supportNew[2];
2457 
2458         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r] - fStart);
2459         coneNew[1] = vStartNew + (vEnd - vStart) + (fEnd    - fStart) + (c - cStart);
2460         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2461 #if defined(PETSC_USE_DEBUG)
2462         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
2463         for (p = 0; p < 2; ++p) {
2464           if ((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);
2465         }
2466 #endif
2467         supportNew[0] = (c - cStart)*3 + r%3;
2468         supportNew[1] = (c - cStart)*3 + (r+1)%3;
2469         ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
2470 #if defined(PETSC_USE_DEBUG)
2471         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
2472         for (p = 0; p < 2; ++p) {
2473           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);
2474         }
2475 #endif
2476       }
2477     }
2478     /* Hybrid interior faces have 2 vertices and 2 cells */
2479     for (c = cMax; c < cEnd; ++c) {
2480       const PetscInt *cone;
2481       PetscInt        coneNew[2], supportNew[2];
2482 
2483       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
2484       for (r = 0; r < 4; ++r) {
2485         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (cMax - cStart)*3 + (c - cMax)*4 + r;
2486 
2487         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r] - fStart);
2488         coneNew[1] = vStartNew + (vEnd - vStart) + (fEnd    - fStart) + (cMax - cStart) + (c - cMax);
2489 	ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2490 #if defined(PETSC_USE_DEBUG)
2491         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
2492         for (p = 0; p < 2; ++p) {
2493           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);
2494         }
2495 #endif
2496         if (r==0) {
2497           supportNew[0] = (cMax - cStart)*3 + (c - cMax)*4 + 0;
2498           supportNew[1] = (cMax - cStart)*3 + (c - cMax)*4 + 1;
2499         } else if (r==1) {
2500           supportNew[0] = (cMax - cStart)*3 + (c - cMax)*4 + 2;
2501           supportNew[1] = (cMax - cStart)*3 + (c - cMax)*4 + 3;
2502         } else if (r==2) {
2503           supportNew[0] = (cMax - cStart)*3 + (c - cMax)*4 + 0;
2504           supportNew[1] = (cMax - cStart)*3 + (c - cMax)*4 + 3;
2505         } else {
2506           supportNew[0] = (cMax - cStart)*3 + (c - cMax)*4 + 1;
2507           supportNew[1] = (cMax - cStart)*3 + (c - cMax)*4 + 2;
2508         }
2509         ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
2510 #if defined(PETSC_USE_DEBUG)
2511         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
2512         for (p = 0; p < 2; ++p) {
2513           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);
2514         }
2515 #endif
2516       }
2517     }
2518     /* Old vertices have identical supports */
2519     for (v = vStart; v < vEnd; ++v) {
2520       const PetscInt  newp = vStartNew + (v - vStart);
2521       const PetscInt *support, *cone;
2522       PetscInt        size, s;
2523 
2524       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
2525       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
2526       for (s = 0; s < size; ++s) {
2527         PetscInt r = 0;
2528 
2529         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
2530         if (cone[1] == v) r = 1;
2531         supportRef[s] = fStartNew + (support[s] - fStart)*2 + r;
2532       }
2533       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
2534 #if defined(PETSC_USE_DEBUG)
2535       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", newp, vStartNew, vEndNew);
2536       for (p = 0; p < size; ++p) {
2537         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);
2538       }
2539 #endif
2540     }
2541     /* Split-face vertices have cells + 2 supports */
2542     for (f = fStart; f < fEnd; ++f) {
2543       const PetscInt  newp = vStartNew + (vEnd - vStart) + (f - fStart);
2544       const PetscInt *cone, *support;
2545       PetscInt        size, s;
2546 
2547       ierr          = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
2548       ierr          = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
2549       supportRef[0] = fStartNew + (f - fStart)*2 + 0;
2550       supportRef[1] = fStartNew + (f - fStart)*2 + 1;
2551       for (s = 0; s < size; ++s) {
2552         PetscInt r = 0, coneSize;
2553 
2554         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
2555         ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
2556         if (coneSize == 3) {
2557           if      (cone[1] == f) r = 1;
2558           else if (cone[2] == f) r = 2;
2559           supportRef[2+s] = fStartNew + (fEnd - fStart)*2 + (support[s] - cStart)*3 + r;
2560         } else if (coneSize == 4) {
2561           if      (cone[1] == f) r = 1;
2562           else if (cone[2] == f) r = 2;
2563           else if (cone[3] == f) r = 3;
2564           supportRef[2+s] = fStartNew + (fEnd - fStart)*2 + (cMax - cStart)*3 + (support[s] - cMax)*4 + r;
2565         } else SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected cone size %D", coneSize);
2566       }
2567       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
2568 #if defined(PETSC_USE_DEBUG)
2569       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", newp, vStartNew, vEndNew);
2570       for (p = 0; p < 2+size; ++p) {
2571         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);
2572       }
2573 #endif
2574     }
2575     /* Interior vertices have 3 supports */
2576     for (c = cStart; c < cMax; ++c) {
2577       const PetscInt newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + c - cStart;
2578 
2579       supportRef[0] = fStartNew + (fEnd - fStart)*2 + (c - cStart)*3 + 0;
2580       supportRef[1] = fStartNew + (fEnd - fStart)*2 + (c - cStart)*3 + 1;
2581       supportRef[2] = fStartNew + (fEnd - fStart)*2 + (c - cStart)*3 + 2;
2582       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
2583     }
2584     /* Hybrid interior vertices have 4 supports */
2585     for (c = cMax; c < cEnd; ++c) {
2586       const PetscInt newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + c - cStart;
2587 
2588       supportRef[0] = fStartNew + (fEnd - fStart)*2 + (cMax - cStart)*3 + (c - cMax)*4 + 0;
2589       supportRef[1] = fStartNew + (fEnd - fStart)*2 + (cMax - cStart)*3 + (c - cMax)*4 + 1;
2590       supportRef[2] = fStartNew + (fEnd - fStart)*2 + (cMax - cStart)*3 + (c - cMax)*4 + 2;
2591       supportRef[3] = fStartNew + (fEnd - fStart)*2 + (cMax - cStart)*3 + (c - cMax)*4 + 3;
2592       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
2593     }
2594     ierr = PetscFree(supportRef);CHKERRQ(ierr);
2595     break;
2596   case REFINER_HEX_2D:
2597     /*
2598      3---------2---------2
2599      |         |         |
2600      |    D    2    C    |
2601      |         |         |
2602      3----3----0----1----1
2603      |         |         |
2604      |    A    0    B    |
2605      |         |         |
2606      0---------0---------1
2607      */
2608     /* All cells have 4 faces */
2609     for (c = cStart; c < cEnd; ++c) {
2610       const PetscInt  newp = (c - cStart)*4;
2611       const PetscInt *cone, *ornt;
2612       PetscInt        coneNew[4], orntNew[4];
2613 
2614       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
2615       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
2616       /* A quad */
2617       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
2618       orntNew[0] = ornt[0];
2619       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 0;
2620       orntNew[1] = 0;
2621       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 3;
2622       orntNew[2] = -2;
2623       coneNew[3] = fStartNew + (cone[3] - fStart)*2 + (ornt[3] < 0 ? 0 : 1);
2624       orntNew[3] = ornt[3];
2625       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
2626       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
2627 #if defined(PETSC_USE_DEBUG)
2628       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);
2629       for (p = 0; p < 4; ++p) {
2630         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);
2631       }
2632 #endif
2633       /* B quad */
2634       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
2635       orntNew[0] = ornt[0];
2636       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
2637       orntNew[1] = ornt[1];
2638       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 1;
2639       orntNew[2] = -2;
2640       coneNew[3] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 0;
2641       orntNew[3] = -2;
2642       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
2643       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
2644 #if defined(PETSC_USE_DEBUG)
2645       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);
2646       for (p = 0; p < 4; ++p) {
2647         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);
2648       }
2649 #endif
2650       /* C quad */
2651       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 1;
2652       orntNew[0] = 0;
2653       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
2654       orntNew[1] = ornt[1];
2655       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
2656       orntNew[2] = ornt[2];
2657       coneNew[3] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 2;
2658       orntNew[3] = -2;
2659       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
2660       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
2661 #if defined(PETSC_USE_DEBUG)
2662       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);
2663       for (p = 0; p < 4; ++p) {
2664         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);
2665       }
2666 #endif
2667       /* D quad */
2668       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 3;
2669       orntNew[0] = 0;
2670       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 2;
2671       orntNew[1] = 0;
2672       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
2673       orntNew[2] = ornt[2];
2674       coneNew[3] = fStartNew + (cone[3] - fStart)*2 + (ornt[3] < 0 ? 1 : 0);
2675       orntNew[3] = ornt[3];
2676       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
2677       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
2678 #if defined(PETSC_USE_DEBUG)
2679       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);
2680       for (p = 0; p < 4; ++p) {
2681         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);
2682       }
2683 #endif
2684     }
2685     /* Split faces have 2 vertices and the same cells as the parent */
2686     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
2687     ierr = PetscMalloc1(2 + maxSupportSize*2, &supportRef);CHKERRQ(ierr);
2688     for (f = fStart; f < fEnd; ++f) {
2689       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);
2690 
2691       for (r = 0; r < 2; ++r) {
2692         const PetscInt  newp = fStartNew + (f - fStart)*2 + r;
2693         const PetscInt *cone, *ornt, *support;
2694         PetscInt        coneNew[2], coneSize, c, supportSize, s;
2695 
2696         ierr             = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
2697         coneNew[0]       = vStartNew + (cone[0] - vStart);
2698         coneNew[1]       = vStartNew + (cone[1] - vStart);
2699         coneNew[(r+1)%2] = newv;
2700         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2701 #if defined(PETSC_USE_DEBUG)
2702         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
2703         for (p = 0; p < 2; ++p) {
2704           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);
2705         }
2706 #endif
2707         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
2708         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
2709         for (s = 0; s < supportSize; ++s) {
2710           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
2711           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
2712           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
2713           for (c = 0; c < coneSize; ++c) {
2714             if (cone[c] == f) break;
2715           }
2716           supportRef[s] = cStartNew + (support[s] - cStart)*4 + (ornt[c] < 0 ? (c+1-r)%4 : (c+r)%4);
2717         }
2718         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
2719 #if defined(PETSC_USE_DEBUG)
2720         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
2721         for (p = 0; p < supportSize; ++p) {
2722           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);
2723         }
2724 #endif
2725       }
2726     }
2727     /* Interior faces have 2 vertices and 2 cells */
2728     for (c = cStart; c < cEnd; ++c) {
2729       const PetscInt *cone;
2730       PetscInt        coneNew[2], supportNew[2];
2731 
2732       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
2733       for (r = 0; r < 4; ++r) {
2734         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*4 + r;
2735 
2736 	if (r==1 || r==2) {
2737           coneNew[0] = vStartNew + (vEnd - vStart) + (fEnd    - fStart) + (c - cStart);
2738           coneNew[1] = vStartNew + (vEnd - vStart) + (cone[r] - fStart);
2739 	} else {
2740           coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r] - fStart);
2741           coneNew[1] = vStartNew + (vEnd - vStart) + (fEnd    - fStart) + (c - cStart);
2742 	}
2743 	ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2744 #if defined(PETSC_USE_DEBUG)
2745         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
2746         for (p = 0; p < 2; ++p) {
2747           if ((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);
2748         }
2749 #endif
2750         supportNew[0] = (c - cStart)*4 + r;
2751         supportNew[1] = (c - cStart)*4 + (r+1)%4;
2752         ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
2753 #if defined(PETSC_USE_DEBUG)
2754         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
2755         for (p = 0; p < 2; ++p) {
2756           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);
2757         }
2758 #endif
2759       }
2760     }
2761     /* Old vertices have identical supports */
2762     for (v = vStart; v < vEnd; ++v) {
2763       const PetscInt  newp = vStartNew + (v - vStart);
2764       const PetscInt *support, *cone;
2765       PetscInt        size, s;
2766 
2767       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
2768       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
2769       for (s = 0; s < size; ++s) {
2770         PetscInt r = 0;
2771 
2772         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
2773         if (cone[1] == v) r = 1;
2774         supportRef[s] = fStartNew + (support[s] - fStart)*2 + r;
2775       }
2776       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
2777 #if defined(PETSC_USE_DEBUG)
2778       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", newp, vStartNew, vEndNew);
2779       for (p = 0; p < size; ++p) {
2780         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);
2781       }
2782 #endif
2783     }
2784     /* Face vertices have 2 + cells supports */
2785     for (f = fStart; f < fEnd; ++f) {
2786       const PetscInt  newp = vStartNew + (vEnd - vStart) + (f - fStart);
2787       const PetscInt *cone, *support;
2788       PetscInt        size, s;
2789 
2790       ierr          = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
2791       ierr          = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
2792       supportRef[0] = fStartNew + (f - fStart)*2 + 0;
2793       supportRef[1] = fStartNew + (f - fStart)*2 + 1;
2794       for (s = 0; s < size; ++s) {
2795         PetscInt r = 0;
2796 
2797         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
2798         if      (cone[1] == f) r = 1;
2799         else if (cone[2] == f) r = 2;
2800         else if (cone[3] == f) r = 3;
2801         supportRef[2+s] = fStartNew + (fEnd - fStart)*2 + (support[s] - cStart)*4 + r;
2802       }
2803       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
2804 #if defined(PETSC_USE_DEBUG)
2805       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", newp, vStartNew, vEndNew);
2806       for (p = 0; p < 2+size; ++p) {
2807         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);
2808       }
2809 #endif
2810     }
2811     /* Cell vertices have 4 supports */
2812     for (c = cStart; c < cEnd; ++c) {
2813       const PetscInt newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (c - cStart);
2814       PetscInt       supportNew[4];
2815 
2816       for (r = 0; r < 4; ++r) {
2817         supportNew[r] = fStartNew + (fEnd - fStart)*2 + (c - cStart)*4 + r;
2818       }
2819       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
2820     }
2821     ierr = PetscFree(supportRef);CHKERRQ(ierr);
2822     break;
2823   case REFINER_HYBRID_SIMPLEX_2D:
2824     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
2825     cMax = PetscMin(cEnd, cMax);
2826     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
2827     fMax = PetscMin(fEnd, fMax);
2828     ierr = DMPlexGetHybridBounds(rdm, &cMaxNew, &fMaxNew, NULL, NULL);CHKERRQ(ierr);
2829     /* Interior cells have 3 faces */
2830     for (c = cStart; c < cMax; ++c) {
2831       const PetscInt  newp = cStartNew + (c - cStart)*4;
2832       const PetscInt *cone, *ornt;
2833       PetscInt        coneNew[3], orntNew[3];
2834 
2835       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
2836       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
2837       /* A triangle */
2838       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
2839       orntNew[0] = ornt[0];
2840       coneNew[1] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 2;
2841       orntNew[1] = -2;
2842       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
2843       orntNew[2] = ornt[2];
2844       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
2845       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
2846 #if defined(PETSC_USE_DEBUG)
2847       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);
2848       for (p = 0; p < 3; ++p) {
2849         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);
2850       }
2851 #endif
2852       /* B triangle */
2853       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
2854       orntNew[0] = ornt[0];
2855       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
2856       orntNew[1] = ornt[1];
2857       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 0;
2858       orntNew[2] = -2;
2859       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
2860       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
2861 #if defined(PETSC_USE_DEBUG)
2862       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);
2863       for (p = 0; p < 3; ++p) {
2864         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);
2865       }
2866 #endif
2867       /* C triangle */
2868       coneNew[0] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 1;
2869       orntNew[0] = -2;
2870       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
2871       orntNew[1] = ornt[1];
2872       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
2873       orntNew[2] = ornt[2];
2874       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
2875       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
2876 #if defined(PETSC_USE_DEBUG)
2877       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);
2878       for (p = 0; p < 3; ++p) {
2879         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);
2880       }
2881 #endif
2882       /* D triangle */
2883       coneNew[0] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 0;
2884       orntNew[0] = 0;
2885       coneNew[1] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 1;
2886       orntNew[1] = 0;
2887       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 2;
2888       orntNew[2] = 0;
2889       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
2890       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
2891 #if defined(PETSC_USE_DEBUG)
2892       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);
2893       for (p = 0; p < 3; ++p) {
2894         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);
2895       }
2896 #endif
2897     }
2898     /*
2899      2----3----3
2900      |         |
2901      |    B    |
2902      |         |
2903      0----4--- 1
2904      |         |
2905      |    A    |
2906      |         |
2907      0----2----1
2908      */
2909     /* Hybrid cells have 4 faces */
2910     for (c = cMax; c < cEnd; ++c) {
2911       const PetscInt  newp = cStartNew + (cMax - cStart)*4 + (c - cMax)*2;
2912       const PetscInt *cone, *ornt;
2913       PetscInt        coneNew[4], orntNew[4], r;
2914 
2915       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
2916       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
2917       r    = (ornt[0] < 0 ? 1 : 0);
2918       /* A quad */
2919       coneNew[0]   = fStartNew + (cone[0] - fStart)*2 + r;
2920       orntNew[0]   = ornt[0];
2921       coneNew[1]   = fStartNew + (cone[1] - fStart)*2 + r;
2922       orntNew[1]   = ornt[1];
2923       coneNew[2+r] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (cone[2+r] - fMax);
2924       orntNew[2+r] = 0;
2925       coneNew[3-r] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (fEnd    - fMax) + (c - cMax);
2926       orntNew[3-r] = 0;
2927       ierr = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
2928       ierr = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
2929 #if defined(PETSC_USE_DEBUG)
2930       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);
2931       for (p = 0; p < 4; ++p) {
2932         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);
2933       }
2934 #endif
2935       /* B quad */
2936       coneNew[0]   = fStartNew + (cone[0] - fStart)*2 + 1-r;
2937       orntNew[0]   = ornt[0];
2938       coneNew[1]   = fStartNew + (cone[1] - fStart)*2 + 1-r;
2939       orntNew[1]   = ornt[1];
2940       coneNew[2+r] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (fEnd    - fMax) + (c - cMax);
2941       orntNew[2+r] = 0;
2942       coneNew[3-r] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (cone[3-r] - fMax);
2943       orntNew[3-r] = 0;
2944       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
2945       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
2946 #if defined(PETSC_USE_DEBUG)
2947       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);
2948       for (p = 0; p < 4; ++p) {
2949         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);
2950       }
2951 #endif
2952     }
2953     /* Interior split faces have 2 vertices and the same cells as the parent */
2954     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
2955     ierr = PetscMalloc1(2 + maxSupportSize*2, &supportRef);CHKERRQ(ierr);
2956     for (f = fStart; f < fMax; ++f) {
2957       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);
2958 
2959       for (r = 0; r < 2; ++r) {
2960         const PetscInt  newp = fStartNew + (f - fStart)*2 + r;
2961         const PetscInt *cone, *ornt, *support;
2962         PetscInt        coneNew[2], coneSize, c, supportSize, s;
2963 
2964         ierr             = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
2965         coneNew[0]       = vStartNew + (cone[0] - vStart);
2966         coneNew[1]       = vStartNew + (cone[1] - vStart);
2967         coneNew[(r+1)%2] = newv;
2968         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2969 #if defined(PETSC_USE_DEBUG)
2970         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
2971         for (p = 0; p < 2; ++p) {
2972           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);
2973         }
2974 #endif
2975         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
2976         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
2977         for (s = 0; s < supportSize; ++s) {
2978           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
2979           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
2980           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
2981           for (c = 0; c < coneSize; ++c) if (cone[c] == f) break;
2982           if (support[s] >= cMax) {
2983             supportRef[s] = cStartNew + (cMax - cStart)*4 + (support[s] - cMax)*2 + (ornt[c] < 0 ? 1-r : r);
2984           } else {
2985             supportRef[s] = cStartNew + (support[s] - cStart)*4 + (ornt[c] < 0 ? (c+1-r)%3 : (c+r)%3);
2986           }
2987         }
2988         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
2989 #if defined(PETSC_USE_DEBUG)
2990         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
2991         for (p = 0; p < supportSize; ++p) {
2992           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);
2993         }
2994 #endif
2995       }
2996     }
2997     /* Interior cell faces have 2 vertices and 2 cells */
2998     for (c = cStart; c < cMax; ++c) {
2999       const PetscInt *cone;
3000 
3001       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
3002       for (r = 0; r < 3; ++r) {
3003         const PetscInt newp = fStartNew + (fMax - fStart)*2 + (c - cStart)*3 + r;
3004         PetscInt       coneNew[2];
3005         PetscInt       supportNew[2];
3006 
3007         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r]       - fStart);
3008         coneNew[1] = vStartNew + (vEnd - vStart) + (cone[(r+1)%3] - fStart);
3009         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3010 #if defined(PETSC_USE_DEBUG)
3011         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
3012         for (p = 0; p < 2; ++p) {
3013           if ((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);
3014         }
3015 #endif
3016         supportNew[0] = (c - cStart)*4 + (r+1)%3;
3017         supportNew[1] = (c - cStart)*4 + 3;
3018         ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3019 #if defined(PETSC_USE_DEBUG)
3020         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
3021         for (p = 0; p < 2; ++p) {
3022           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);
3023         }
3024 #endif
3025       }
3026     }
3027     /* Interior hybrid faces have 2 vertices and the same cells */
3028     for (f = fMax; f < fEnd; ++f) {
3029       const PetscInt  newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (f - fMax);
3030       const PetscInt *cone, *ornt;
3031       const PetscInt *support;
3032       PetscInt        coneNew[2];
3033       PetscInt        supportNew[2];
3034       PetscInt        size, s, r;
3035 
3036       ierr       = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
3037       coneNew[0] = vStartNew + (cone[0] - vStart);
3038       coneNew[1] = vStartNew + (cone[1] - vStart);
3039       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3040 #if defined(PETSC_USE_DEBUG)
3041       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
3042       for (p = 0; p < 2; ++p) {
3043         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);
3044       }
3045 #endif
3046       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
3047       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
3048       for (s = 0; s < size; ++s) {
3049         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
3050         ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
3051         for (r = 0; r < 2; ++r) {
3052           if (cone[r+2] == f) break;
3053         }
3054         supportNew[s] = (cMax - cStart)*4 + (support[s] - cMax)*2 + (ornt[0] < 0 ? 1-r : r);
3055       }
3056       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3057 #if defined(PETSC_USE_DEBUG)
3058       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
3059       for (p = 0; p < size; ++p) {
3060         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);
3061       }
3062 #endif
3063     }
3064     /* Cell hybrid faces have 2 vertices and 2 cells */
3065     for (c = cMax; c < cEnd; ++c) {
3066       const PetscInt  newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (fEnd - fMax) + (c - cMax);
3067       const PetscInt *cone;
3068       PetscInt        coneNew[2];
3069       PetscInt        supportNew[2];
3070 
3071       ierr       = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
3072       coneNew[0] = vStartNew + (vEnd - vStart) + (cone[0] - fStart);
3073       coneNew[1] = vStartNew + (vEnd - vStart) + (cone[1] - fStart);
3074       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3075 #if defined(PETSC_USE_DEBUG)
3076       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
3077       for (p = 0; p < 2; ++p) {
3078         if ((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);
3079       }
3080 #endif
3081       supportNew[0] = (cMax - cStart)*4 + (c - cMax)*2 + 0;
3082       supportNew[1] = (cMax - cStart)*4 + (c - cMax)*2 + 1;
3083       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3084 #if defined(PETSC_USE_DEBUG)
3085       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
3086       for (p = 0; p < 2; ++p) {
3087         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);
3088       }
3089 #endif
3090     }
3091     /* Old vertices have identical supports */
3092     for (v = vStart; v < vEnd; ++v) {
3093       const PetscInt  newp = vStartNew + (v - vStart);
3094       const PetscInt *support, *cone;
3095       PetscInt        size, s;
3096 
3097       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
3098       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
3099       for (s = 0; s < size; ++s) {
3100         if (support[s] >= fMax) {
3101           supportRef[s] = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (support[s] - fMax);
3102         } else {
3103           PetscInt r = 0;
3104 
3105           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
3106           if (cone[1] == v) r = 1;
3107           supportRef[s] = fStartNew + (support[s] - fStart)*2 + r;
3108         }
3109       }
3110       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
3111 #if defined(PETSC_USE_DEBUG)
3112       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", newp, vStartNew, vEndNew);
3113       for (p = 0; p < size; ++p) {
3114         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);
3115       }
3116 #endif
3117     }
3118     /* Face vertices have 2 + (2 interior, 1 hybrid) supports */
3119     for (f = fStart; f < fMax; ++f) {
3120       const PetscInt  newp = vStartNew + (vEnd - vStart) + (f - fStart);
3121       const PetscInt *cone, *support;
3122       PetscInt        size, newSize = 2, s;
3123 
3124       ierr          = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
3125       ierr          = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
3126       supportRef[0] = fStartNew + (f - fStart)*2 + 0;
3127       supportRef[1] = fStartNew + (f - fStart)*2 + 1;
3128       for (s = 0; s < size; ++s) {
3129         PetscInt r = 0;
3130 
3131         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
3132         if (support[s] >= cMax) {
3133           supportRef[newSize+0] = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (fEnd - fMax) + (support[s] - cMax);
3134 
3135           newSize += 1;
3136         } else {
3137           if      (cone[1] == f) r = 1;
3138           else if (cone[2] == f) r = 2;
3139           supportRef[newSize+0] = fStartNew + (fMax - fStart)*2 + (support[s] - cStart)*3 + (r+2)%3;
3140           supportRef[newSize+1] = fStartNew + (fMax - fStart)*2 + (support[s] - cStart)*3 + r;
3141 
3142           newSize += 2;
3143         }
3144       }
3145       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
3146 #if defined(PETSC_USE_DEBUG)
3147       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", newp, vStartNew, vEndNew);
3148       for (p = 0; p < newSize; ++p) {
3149         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);
3150       }
3151 #endif
3152     }
3153     ierr = PetscFree(supportRef);CHKERRQ(ierr);
3154     break;
3155   case REFINER_HYBRID_HEX_2D:
3156     /* Hybrid Hex 2D */
3157     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
3158     cMax = PetscMin(cEnd, cMax);
3159     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
3160     fMax = PetscMin(fEnd, fMax);
3161     ierr = DMPlexGetHybridBounds(rdm, &cMaxNew, &fMaxNew, NULL, NULL);CHKERRQ(ierr);
3162     /* Interior cells have 4 faces */
3163     for (c = cStart; c < cMax; ++c) {
3164       const PetscInt  newp = cStartNew + (c - cStart)*4;
3165       const PetscInt *cone, *ornt;
3166       PetscInt        coneNew[4], orntNew[4];
3167 
3168       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
3169       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
3170       /* A quad */
3171       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
3172       orntNew[0] = ornt[0];
3173       coneNew[1] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*4 + 0;
3174       orntNew[1] = 0;
3175       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*4 + 3;
3176       orntNew[2] = -2;
3177       coneNew[3] = fStartNew + (cone[3] - fStart)*2 + (ornt[3] < 0 ? 0 : 1);
3178       orntNew[3] = ornt[3];
3179       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
3180       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
3181 #if defined(PETSC_USE_DEBUG)
3182       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);
3183       for (p = 0; p < 4; ++p) {
3184         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);
3185       }
3186 #endif
3187       /* B quad */
3188       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
3189       orntNew[0] = ornt[0];
3190       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
3191       orntNew[1] = ornt[1];
3192       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*4 + 1;
3193       orntNew[2] = 0;
3194       coneNew[3] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*4 + 0;
3195       orntNew[3] = -2;
3196       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
3197       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
3198 #if defined(PETSC_USE_DEBUG)
3199       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);
3200       for (p = 0; p < 4; ++p) {
3201         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);
3202       }
3203 #endif
3204       /* C quad */
3205       coneNew[0] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*4 + 1;
3206       orntNew[0] = -2;
3207       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
3208       orntNew[1] = ornt[1];
3209       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
3210       orntNew[2] = ornt[2];
3211       coneNew[3] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*4 + 2;
3212       orntNew[3] = 0;
3213       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
3214       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
3215 #if defined(PETSC_USE_DEBUG)
3216       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);
3217       for (p = 0; p < 4; ++p) {
3218         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);
3219       }
3220 #endif
3221       /* D quad */
3222       coneNew[0] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*4 + 3;
3223       orntNew[0] = 0;
3224       coneNew[1] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*4 + 2;
3225       orntNew[1] = -2;
3226       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
3227       orntNew[2] = ornt[2];
3228       coneNew[3] = fStartNew + (cone[3] - fStart)*2 + (ornt[3] < 0 ? 1 : 0);
3229       orntNew[3] = ornt[3];
3230       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
3231       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
3232 #if defined(PETSC_USE_DEBUG)
3233       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);
3234       for (p = 0; p < 4; ++p) {
3235         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);
3236       }
3237 #endif
3238     }
3239     /*
3240      2----3----3
3241      |         |
3242      |    B    |
3243      |         |
3244      0----4--- 1
3245      |         |
3246      |    A    |
3247      |         |
3248      0----2----1
3249      */
3250     /* Hybrid cells have 4 faces */
3251     for (c = cMax; c < cEnd; ++c) {
3252       const PetscInt  newp = cStartNew + (cMax - cStart)*4 + (c - cMax)*2;
3253       const PetscInt *cone, *ornt;
3254       PetscInt        coneNew[4], orntNew[4];
3255 
3256       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
3257       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
3258       /* A quad */
3259       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
3260       orntNew[0] = ornt[0];
3261       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
3262       orntNew[1] = ornt[1];
3263       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*4 + (cone[2] - fMax);
3264       orntNew[2] = 0;
3265       coneNew[3] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*4 + (fEnd    - fMax) + (c - cMax);
3266       orntNew[3] = 0;
3267       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
3268       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
3269 #if defined(PETSC_USE_DEBUG)
3270       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);
3271       for (p = 0; p < 4; ++p) {
3272         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);
3273       }
3274 #endif
3275       /* B quad */
3276       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
3277       orntNew[0] = ornt[0];
3278       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
3279       orntNew[1] = ornt[1];
3280       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*4 + (fEnd    - fMax) + (c - cMax);
3281       orntNew[2] = 0;
3282       coneNew[3] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*4 + (cone[3] - fMax);
3283       orntNew[3] = 0;
3284       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
3285       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
3286 #if defined(PETSC_USE_DEBUG)
3287       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);
3288       for (p = 0; p < 4; ++p) {
3289         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);
3290       }
3291 #endif
3292     }
3293     /* Interior split faces have 2 vertices and the same cells as the parent */
3294     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
3295     ierr = PetscMalloc1(2 + maxSupportSize*2, &supportRef);CHKERRQ(ierr);
3296     for (f = fStart; f < fMax; ++f) {
3297       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);
3298 
3299       for (r = 0; r < 2; ++r) {
3300         const PetscInt  newp = fStartNew + (f - fStart)*2 + r;
3301         const PetscInt *cone, *ornt, *support;
3302         PetscInt        coneNew[2], coneSize, c, supportSize, s;
3303 
3304         ierr             = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
3305         coneNew[0]       = vStartNew + (cone[0] - vStart);
3306         coneNew[1]       = vStartNew + (cone[1] - vStart);
3307         coneNew[(r+1)%2] = newv;
3308         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3309 #if defined(PETSC_USE_DEBUG)
3310         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
3311         for (p = 0; p < 2; ++p) {
3312           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);
3313         }
3314 #endif
3315         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
3316         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
3317         for (s = 0; s < supportSize; ++s) {
3318           if (support[s] >= cMax) {
3319             supportRef[s] = cStartNew + (cMax - cStart)*4 + (support[s] - cMax)*2 + r;
3320           } else {
3321             ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
3322             ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
3323             ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
3324             for (c = 0; c < coneSize; ++c) {
3325               if (cone[c] == f) break;
3326             }
3327             supportRef[s] = cStartNew + (support[s] - cStart)*4 + (ornt[c] < 0 ? (c+1-r)%4 : (c+r)%4);
3328           }
3329         }
3330         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
3331 #if defined(PETSC_USE_DEBUG)
3332         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
3333         for (p = 0; p < supportSize; ++p) {
3334           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);
3335         }
3336 #endif
3337       }
3338     }
3339     /* Interior cell faces have 2 vertices and 2 cells */
3340     for (c = cStart; c < cMax; ++c) {
3341       const PetscInt *cone;
3342 
3343       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
3344       for (r = 0; r < 4; ++r) {
3345         const PetscInt newp = fStartNew + (fMax - fStart)*2 + (c - cStart)*4 + r;
3346         PetscInt       coneNew[2], supportNew[2];
3347 
3348         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r] - fStart);
3349         coneNew[1] = vStartNew + (vEnd - vStart) + (fMax    - fStart) + (c - cStart);
3350         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3351 #if defined(PETSC_USE_DEBUG)
3352         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
3353         for (p = 0; p < 2; ++p) {
3354           if ((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);
3355         }
3356 #endif
3357         supportNew[0] = (c - cStart)*4 + r;
3358         supportNew[1] = (c - cStart)*4 + (r+1)%4;
3359         ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3360 #if defined(PETSC_USE_DEBUG)
3361         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
3362         for (p = 0; p < 2; ++p) {
3363           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);
3364         }
3365 #endif
3366       }
3367     }
3368     /* Hybrid faces have 2 vertices and the same cells */
3369     for (f = fMax; f < fEnd; ++f) {
3370       const PetscInt  newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*4 + (f - fMax);
3371       const PetscInt *cone, *support;
3372       PetscInt        coneNew[2], supportNew[2];
3373       PetscInt        size, s, r;
3374 
3375       ierr       = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
3376       coneNew[0] = vStartNew + (cone[0] - vStart);
3377       coneNew[1] = vStartNew + (cone[1] - vStart);
3378       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3379 #if defined(PETSC_USE_DEBUG)
3380       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
3381       for (p = 0; p < 2; ++p) {
3382         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);
3383       }
3384 #endif
3385       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
3386       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
3387       for (s = 0; s < size; ++s) {
3388         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
3389         for (r = 0; r < 2; ++r) {
3390           if (cone[r+2] == f) break;
3391         }
3392         supportNew[s] = (cMax - cStart)*4 + (support[s] - cMax)*2 + r;
3393       }
3394       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3395 #if defined(PETSC_USE_DEBUG)
3396       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
3397       for (p = 0; p < size; ++p) {
3398         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);
3399       }
3400 #endif
3401     }
3402     /* Cell hybrid faces have 2 vertices and 2 cells */
3403     for (c = cMax; c < cEnd; ++c) {
3404       const PetscInt  newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*4 + (fEnd - fMax) + (c - cMax);
3405       const PetscInt *cone;
3406       PetscInt        coneNew[2], supportNew[2];
3407 
3408       ierr       = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
3409       coneNew[0] = vStartNew + (vEnd - vStart) + (cone[0] - fStart);
3410       coneNew[1] = vStartNew + (vEnd - vStart) + (cone[1] - fStart);
3411       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3412 #if defined(PETSC_USE_DEBUG)
3413       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
3414       for (p = 0; p < 2; ++p) {
3415         if ((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);
3416       }
3417 #endif
3418       supportNew[0] = (cMax - cStart)*4 + (c - cMax)*2 + 0;
3419       supportNew[1] = (cMax - cStart)*4 + (c - cMax)*2 + 1;
3420       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3421 #if defined(PETSC_USE_DEBUG)
3422       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
3423       for (p = 0; p < 2; ++p) {
3424         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);
3425       }
3426 #endif
3427     }
3428     /* Old vertices have identical supports */
3429     for (v = vStart; v < vEnd; ++v) {
3430       const PetscInt  newp = vStartNew + (v - vStart);
3431       const PetscInt *support, *cone;
3432       PetscInt        size, s;
3433 
3434       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
3435       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
3436       for (s = 0; s < size; ++s) {
3437         if (support[s] >= fMax) {
3438           supportRef[s] = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*4 + (support[s] - fMax);
3439         } else {
3440           PetscInt r = 0;
3441 
3442           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
3443           if (cone[1] == v) r = 1;
3444           supportRef[s] = fStartNew + (support[s] - fStart)*2 + r;
3445         }
3446       }
3447       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
3448 #if defined(PETSC_USE_DEBUG)
3449       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", newp, vStartNew, vEndNew);
3450       for (p = 0; p < size; ++p) {
3451         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);
3452       }
3453 #endif
3454     }
3455     /* Face vertices have 2 + cells supports */
3456     for (f = fStart; f < fMax; ++f) {
3457       const PetscInt  newp = vStartNew + (vEnd - vStart) + (f - fStart);
3458       const PetscInt *cone, *support;
3459       PetscInt        size, s;
3460 
3461       ierr          = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
3462       ierr          = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
3463       supportRef[0] = fStartNew + (f - fStart)*2 + 0;
3464       supportRef[1] = fStartNew + (f - fStart)*2 + 1;
3465       for (s = 0; s < size; ++s) {
3466         PetscInt r = 0;
3467 
3468         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
3469         if (support[s] >= cMax) {
3470           supportRef[2+s] = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*4 + (fEnd - fMax) + (support[s] - cMax);
3471         } else {
3472           if      (cone[1] == f) r = 1;
3473           else if (cone[2] == f) r = 2;
3474           else if (cone[3] == f) r = 3;
3475           supportRef[2+s] = fStartNew + (fMax - fStart)*2 + (support[s] - cStart)*4 + r;
3476         }
3477       }
3478       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
3479 #if defined(PETSC_USE_DEBUG)
3480       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", newp, vStartNew, vEndNew);
3481       for (p = 0; p < 2+size; ++p) {
3482         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);
3483       }
3484 #endif
3485     }
3486     /* Cell vertices have 4 supports */
3487     for (c = cStart; c < cMax; ++c) {
3488       const PetscInt newp = vStartNew + (vEnd - vStart) + (fMax - fStart) + (c - cStart);
3489       PetscInt       supportNew[4];
3490 
3491       for (r = 0; r < 4; ++r) {
3492         supportNew[r] = fStartNew + (fMax - fStart)*2 + (c - cStart)*4 + r;
3493       }
3494       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3495     }
3496     ierr = PetscFree(supportRef);CHKERRQ(ierr);
3497     break;
3498   case REFINER_SIMPLEX_3D:
3499     /* All cells have 4 faces: Tet face order is prescribed in DMPlexGetFaces_Internal() */
3500     ierr = DMPlexGetRawFaces_Internal(dm, DM_POLYTOPE_TETRAHEDRON, cellInd, NULL, NULL, &faces);CHKERRQ(ierr);
3501     for (c = cStart; c < cEnd; ++c) {
3502       const PetscInt  newp = cStartNew + (c - cStart)*8;
3503       const PetscInt *cone, *ornt;
3504       PetscInt        coneNew[4], orntNew[4];
3505 
3506       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
3507       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
3508       /* A tetrahedron: {0, a, c, d} */
3509       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetTriSubface_Static(ornt[0], 0); /* A */
3510       orntNew[0] = ornt[0];
3511       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetTriSubface_Static(ornt[1], 0); /* A */
3512       orntNew[1] = ornt[1];
3513       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetTriSubface_Static(ornt[2], 0); /* A */
3514       orntNew[2] = ornt[2];
3515       coneNew[3] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 0;
3516       orntNew[3] = 0;
3517       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
3518       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
3519 #if defined(PETSC_USE_DEBUG)
3520       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);
3521       for (p = 0; p < 4; ++p) {
3522         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);
3523       }
3524 #endif
3525       /* B tetrahedron: {a, 1, b, e} */
3526       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetTriSubface_Static(ornt[0], 1); /* B */
3527       orntNew[0] = ornt[0];
3528       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetTriSubface_Static(ornt[1], 2); /* C */
3529       orntNew[1] = ornt[1];
3530       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 1;
3531       orntNew[2] = 0;
3532       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetTriSubface_Static(ornt[3], 1); /* B */
3533       orntNew[3] = ornt[3];
3534       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
3535       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
3536 #if defined(PETSC_USE_DEBUG)
3537       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);
3538       for (p = 0; p < 4; ++p) {
3539         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);
3540       }
3541 #endif
3542       /* C tetrahedron: {c, b, 2, f} */
3543       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetTriSubface_Static(ornt[0], 2); /* C */
3544       orntNew[0] = ornt[0];
3545       coneNew[1] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 2;
3546       orntNew[1] = 0;
3547       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetTriSubface_Static(ornt[2], 1); /* B */
3548       orntNew[2] = ornt[2];
3549       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetTriSubface_Static(ornt[3], 0); /* A */
3550       orntNew[3] = ornt[3];
3551       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
3552       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
3553 #if defined(PETSC_USE_DEBUG)
3554       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);
3555       for (p = 0; p < 4; ++p) {
3556         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);
3557       }
3558 #endif
3559       /* D tetrahedron: {d, e, f, 3} */
3560       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 3;
3561       orntNew[0] = 0;
3562       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetTriSubface_Static(ornt[1], 1); /* B */
3563       orntNew[1] = ornt[1];
3564       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetTriSubface_Static(ornt[2], 2); /* C */
3565       orntNew[2] = ornt[2];
3566       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetTriSubface_Static(ornt[3], 2); /* C */
3567       orntNew[3] = ornt[3];
3568       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
3569       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
3570 #if defined(PETSC_USE_DEBUG)
3571       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);
3572       for (p = 0; p < 4; ++p) {
3573         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);
3574       }
3575 #endif
3576       /* A' tetrahedron: {c, d, a, f} */
3577       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 0;
3578       orntNew[0] = -3;
3579       coneNew[1] = fStartNew + (cone[2] - fStart)*4 + 3;
3580       orntNew[1] = ornt[2] < 0 ? -(GetTriMidEdge_Static(ornt[2], 0)+1) : GetTriMidEdge_Static(ornt[2], 0);
3581       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 5;
3582       orntNew[2] = 0;
3583       coneNew[3] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 4;
3584       orntNew[3] = 2;
3585       ierr       = DMPlexSetCone(rdm, newp+4, coneNew);CHKERRQ(ierr);
3586       ierr       = DMPlexSetConeOrientation(rdm, newp+4, orntNew);CHKERRQ(ierr);
3587 #if defined(PETSC_USE_DEBUG)
3588       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);
3589       for (p = 0; p < 4; ++p) {
3590         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);
3591       }
3592 #endif
3593       /* B' tetrahedron: {e, b, a, f} */
3594       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 1;
3595       orntNew[0] = -2;
3596       coneNew[1] = fStartNew + (cone[3] - fStart)*4 + 3;
3597       orntNew[1] = ornt[3] < 0 ? -(GetTriMidEdge_Static(ornt[3], 1)+1) : GetTriMidEdge_Static(ornt[3], 1);
3598       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 6;
3599       orntNew[2] = 0;
3600       coneNew[3] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 7;
3601       orntNew[3] = 0;
3602       ierr       = DMPlexSetCone(rdm, newp+5, coneNew);CHKERRQ(ierr);
3603       ierr       = DMPlexSetConeOrientation(rdm, newp+5, orntNew);CHKERRQ(ierr);
3604 #if defined(PETSC_USE_DEBUG)
3605       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);
3606       for (p = 0; p < 4; ++p) {
3607         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);
3608       }
3609 #endif
3610       /* C' tetrahedron: {f, a, c, b} */
3611       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 5;
3612       orntNew[0] = -2;
3613       coneNew[1] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 7;
3614       orntNew[1] = -2;
3615       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 2;
3616       orntNew[2] = -1;
3617       coneNew[3] = fStartNew + (cone[0] - fStart)*4 + 3;
3618       orntNew[3] = ornt[0] < 0 ? -(GetTriMidEdge_Static(ornt[0], 2)+1) : GetTriMidEdge_Static(ornt[0], 2);
3619       ierr       = DMPlexSetCone(rdm, newp+6, coneNew);CHKERRQ(ierr);
3620       ierr       = DMPlexSetConeOrientation(rdm, newp+6, orntNew);CHKERRQ(ierr);
3621 #if defined(PETSC_USE_DEBUG)
3622       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);
3623       for (p = 0; p < 4; ++p) {
3624         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);
3625       }
3626 #endif
3627       /* D' tetrahedron: {f, a, e, d} */
3628       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 6;
3629       orntNew[0] = -2;
3630       coneNew[1] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 4;
3631       orntNew[1] = -1;
3632       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 3;
3633       orntNew[2] = -2;
3634       coneNew[3] = fStartNew + (cone[1] - fStart)*4 + 3;
3635       orntNew[3] = ornt[1] < 0 ? -(GetTriMidEdge_Static(ornt[1], 1)+1) : GetTriMidEdge_Static(ornt[1], 1);
3636       ierr       = DMPlexSetCone(rdm, newp+7, coneNew);CHKERRQ(ierr);
3637       ierr       = DMPlexSetConeOrientation(rdm, newp+7, orntNew);CHKERRQ(ierr);
3638 #if defined(PETSC_USE_DEBUG)
3639       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);
3640       for (p = 0; p < 4; ++p) {
3641         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);
3642       }
3643 #endif
3644     }
3645     /* Split faces have 3 edges and the same cells as the parent */
3646     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
3647     ierr = PetscMalloc1(2 + maxSupportSize*3, &supportRef);CHKERRQ(ierr);
3648     for (f = fStart; f < fEnd; ++f) {
3649       const PetscInt  newp = fStartNew + (f - fStart)*4;
3650       const PetscInt *cone, *ornt, *support;
3651       PetscInt        coneNew[3], orntNew[3], coneSize, supportSize, s;
3652 
3653       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
3654       ierr = DMPlexGetConeOrientation(dm, f, &ornt);CHKERRQ(ierr);
3655       /* A triangle */
3656       coneNew[0] = eStartNew + (cone[0] - eStart)*2 + (ornt[0] < 0 ? 1 : 0);
3657       orntNew[0] = ornt[0];
3658       coneNew[1] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 2;
3659       orntNew[1] = -2;
3660       coneNew[2] = eStartNew + (cone[2] - eStart)*2 + (ornt[2] < 0 ? 0 : 1);
3661       orntNew[2] = ornt[2];
3662       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
3663       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
3664 #if defined(PETSC_USE_DEBUG)
3665       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);
3666       for (p = 0; p < 3; ++p) {
3667         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);
3668       }
3669 #endif
3670       /* B triangle */
3671       coneNew[0] = eStartNew + (cone[0] - eStart)*2 + (ornt[0] < 0 ? 0 : 1);
3672       orntNew[0] = ornt[0];
3673       coneNew[1] = eStartNew + (cone[1] - eStart)*2 + (ornt[1] < 0 ? 1 : 0);
3674       orntNew[1] = ornt[1];
3675       coneNew[2] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 0;
3676       orntNew[2] = -2;
3677       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
3678       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
3679 #if defined(PETSC_USE_DEBUG)
3680       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);
3681       for (p = 0; p < 3; ++p) {
3682         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);
3683       }
3684 #endif
3685       /* C triangle */
3686       coneNew[0] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 1;
3687       orntNew[0] = -2;
3688       coneNew[1] = eStartNew + (cone[1] - eStart)*2 + (ornt[1] < 0 ? 0 : 1);
3689       orntNew[1] = ornt[1];
3690       coneNew[2] = eStartNew + (cone[2] - eStart)*2 + (ornt[2] < 0 ? 1 : 0);
3691       orntNew[2] = ornt[2];
3692       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
3693       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
3694 #if defined(PETSC_USE_DEBUG)
3695       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);
3696       for (p = 0; p < 3; ++p) {
3697         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);
3698       }
3699 #endif
3700       /* D triangle */
3701       coneNew[0] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 0;
3702       orntNew[0] = 0;
3703       coneNew[1] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 1;
3704       orntNew[1] = 0;
3705       coneNew[2] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 2;
3706       orntNew[2] = 0;
3707       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
3708       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
3709 #if defined(PETSC_USE_DEBUG)
3710       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);
3711       for (p = 0; p < 3; ++p) {
3712         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);
3713       }
3714 #endif
3715       ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
3716       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
3717       for (r = 0; r < 4; ++r) {
3718         for (s = 0; s < supportSize; ++s) {
3719           PetscInt subf;
3720           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
3721           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
3722           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
3723           for (c = 0; c < coneSize; ++c) {
3724             if (cone[c] == f) break;
3725           }
3726           subf = GetTriSubfaceInverse_Static(ornt[c], r);
3727           supportRef[s] = cStartNew + (support[s] - cStart)*8 + (r==3 ? (c+2)%4 + 4 : faces[c*3+subf]);
3728         }
3729         ierr = DMPlexSetSupport(rdm, newp+r, supportRef);CHKERRQ(ierr);
3730 #if defined(PETSC_USE_DEBUG)
3731         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);
3732         for (p = 0; p < supportSize; ++p) {
3733           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);
3734         }
3735 #endif
3736       }
3737     }
3738     /* Interior faces have 3 edges and 2 cells */
3739     for (c = cStart; c < cEnd; ++c) {
3740       PetscInt        newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*8;
3741       const PetscInt *cone, *ornt;
3742       PetscInt        coneNew[3], orntNew[3];
3743       PetscInt        supportNew[2];
3744 
3745       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
3746       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
3747       /* Face A: {c, a, d} */
3748       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*3 + GetTriMidEdge_Static(ornt[0], 2);
3749       orntNew[0] = ornt[0] < 0 ? -2 : 0;
3750       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*3 + GetTriMidEdge_Static(ornt[1], 2);
3751       orntNew[1] = ornt[1] < 0 ? -2 : 0;
3752       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*3 + GetTriMidEdge_Static(ornt[2], 2);
3753       orntNew[2] = ornt[2] < 0 ? -2 : 0;
3754       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3755       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3756 #if defined(PETSC_USE_DEBUG)
3757       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
3758       for (p = 0; p < 3; ++p) {
3759         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);
3760       }
3761 #endif
3762       supportNew[0] = (c - cStart)*8 + 0;
3763       supportNew[1] = (c - cStart)*8 + 0+4;
3764       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3765 #if defined(PETSC_USE_DEBUG)
3766       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
3767       for (p = 0; p < 2; ++p) {
3768         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);
3769       }
3770 #endif
3771       ++newp;
3772       /* Face B: {a, b, e} */
3773       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*3 + GetTriMidEdge_Static(ornt[0], 0);
3774       orntNew[0] = ornt[0] < 0 ? -2 : 0;
3775       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*3 + GetTriMidEdge_Static(ornt[3], 0);
3776       orntNew[1] = ornt[3] < 0 ? -2 : 0;
3777       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*3 + GetTriMidEdge_Static(ornt[1], 1);
3778       orntNew[2] = ornt[1] < 0 ? -2 : 0;
3779       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3780       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3781 #if defined(PETSC_USE_DEBUG)
3782       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
3783       for (p = 0; p < 3; ++p) {
3784         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);
3785       }
3786 #endif
3787       supportNew[0] = (c - cStart)*8 + 1;
3788       supportNew[1] = (c - cStart)*8 + 1+4;
3789       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3790 #if defined(PETSC_USE_DEBUG)
3791       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
3792       for (p = 0; p < 2; ++p) {
3793         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);
3794       }
3795 #endif
3796       ++newp;
3797       /* Face C: {c, f, b} */
3798       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*3 + GetTriMidEdge_Static(ornt[2], 0);
3799       orntNew[0] = ornt[2] < 0 ? -2 : 0;
3800       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*3 + GetTriMidEdge_Static(ornt[3], 2);
3801       orntNew[1] = ornt[3] < 0 ? -2 : 0;
3802       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*3 + GetTriMidEdge_Static(ornt[0], 1);
3803       orntNew[2] = ornt[0] < 0 ? -2 : 0;
3804       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3805       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3806 #if defined(PETSC_USE_DEBUG)
3807       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
3808       for (p = 0; p < 3; ++p) {
3809         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);
3810       }
3811 #endif
3812       supportNew[0] = (c - cStart)*8 + 2;
3813       supportNew[1] = (c - cStart)*8 + 2+4;
3814       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3815 #if defined(PETSC_USE_DEBUG)
3816       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
3817       for (p = 0; p < 2; ++p) {
3818         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);
3819       }
3820 #endif
3821       ++newp;
3822       /* Face D: {d, e, f} */
3823       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*3 + GetTriMidEdge_Static(ornt[1], 0);
3824       orntNew[0] = ornt[1] < 0 ? -2 : 0;
3825       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*3 + GetTriMidEdge_Static(ornt[3], 1);
3826       orntNew[1] = ornt[3] < 0 ? -2 : 0;
3827       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*3 + GetTriMidEdge_Static(ornt[2], 1);
3828       orntNew[2] = ornt[2] < 0 ? -2 : 0;
3829       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3830       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3831 #if defined(PETSC_USE_DEBUG)
3832       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
3833       for (p = 0; p < 3; ++p) {
3834         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);
3835       }
3836 #endif
3837       supportNew[0] = (c - cStart)*8 + 3;
3838       supportNew[1] = (c - cStart)*8 + 3+4;
3839       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3840 #if defined(PETSC_USE_DEBUG)
3841       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
3842       for (p = 0; p < 2; ++p) {
3843         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);
3844       }
3845 #endif
3846       ++newp;
3847       /* Face E: {d, f, a} */
3848       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*3 + GetTriMidEdge_Static(ornt[2], 1);
3849       orntNew[0] = ornt[2] < 0 ? 0 : -2;
3850       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart);
3851       orntNew[1] = -2;
3852       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*3 + GetTriMidEdge_Static(ornt[1], 2);
3853       orntNew[2] = ornt[1] < 0 ? -2 : 0;
3854       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3855       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3856 #if defined(PETSC_USE_DEBUG)
3857       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
3858       for (p = 0; p < 3; ++p) {
3859         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);
3860       }
3861 #endif
3862       supportNew[0] = (c - cStart)*8 + 0+4;
3863       supportNew[1] = (c - cStart)*8 + 3+4;
3864       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3865 #if defined(PETSC_USE_DEBUG)
3866       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
3867       for (p = 0; p < 2; ++p) {
3868         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);
3869       }
3870 #endif
3871       ++newp;
3872       /* Face F: {c, a, f} */
3873       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*3 + GetTriMidEdge_Static(ornt[0], 2);
3874       orntNew[0] = ornt[0] < 0 ? -2 : 0;
3875       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart);
3876       orntNew[1] = 0;
3877       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*3 + GetTriMidEdge_Static(ornt[2], 0);
3878       orntNew[2] = ornt[2] < 0 ? 0 : -2;
3879       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3880       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3881 #if defined(PETSC_USE_DEBUG)
3882       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
3883       for (p = 0; p < 3; ++p) {
3884         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);
3885       }
3886 #endif
3887       supportNew[0] = (c - cStart)*8 + 0+4;
3888       supportNew[1] = (c - cStart)*8 + 2+4;
3889       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3890 #if defined(PETSC_USE_DEBUG)
3891       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
3892       for (p = 0; p < 2; ++p) {
3893         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);
3894       }
3895 #endif
3896       ++newp;
3897       /* Face G: {e, a, f} */
3898       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*3 + GetTriMidEdge_Static(ornt[1], 1);
3899       orntNew[0] = ornt[1] < 0 ? -2 : 0;
3900       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart);
3901       orntNew[1] = 0;
3902       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*3 + GetTriMidEdge_Static(ornt[3], 1);
3903       orntNew[2] = ornt[3] < 0 ? 0 : -2;
3904       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3905       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3906 #if defined(PETSC_USE_DEBUG)
3907       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
3908       for (p = 0; p < 3; ++p) {
3909         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);
3910       }
3911 #endif
3912       supportNew[0] = (c - cStart)*8 + 1+4;
3913       supportNew[1] = (c - cStart)*8 + 3+4;
3914       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3915 #if defined(PETSC_USE_DEBUG)
3916       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
3917       for (p = 0; p < 2; ++p) {
3918         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);
3919       }
3920 #endif
3921       ++newp;
3922       /* Face H: {a, b, f} */
3923       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*3 + GetTriMidEdge_Static(ornt[0], 0);
3924       orntNew[0] = ornt[0] < 0 ? -2 : 0;
3925       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*3 + GetTriMidEdge_Static(ornt[3], 2);
3926       orntNew[1] = ornt[3] < 0 ? 0 : -2;
3927       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart);
3928       orntNew[2] = -2;
3929       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3930       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3931 #if defined(PETSC_USE_DEBUG)
3932       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
3933       for (p = 0; p < 3; ++p) {
3934         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);
3935       }
3936 #endif
3937       supportNew[0] = (c - cStart)*8 + 1+4;
3938       supportNew[1] = (c - cStart)*8 + 2+4;
3939       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3940 #if defined(PETSC_USE_DEBUG)
3941       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
3942       for (p = 0; p < 2; ++p) {
3943         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);
3944       }
3945 #endif
3946       ++newp;
3947     }
3948     /* Split Edges have 2 vertices and the same faces as the parent */
3949     for (e = eStart; e < eEnd; ++e) {
3950       const PetscInt newv = vStartNew + (vEnd - vStart) + (e - eStart);
3951 
3952       for (r = 0; r < 2; ++r) {
3953         const PetscInt  newp = eStartNew + (e - eStart)*2 + r;
3954         const PetscInt *cone, *ornt, *support;
3955         PetscInt        coneNew[2], coneSize, c, supportSize, s;
3956 
3957         ierr             = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
3958         coneNew[0]       = vStartNew + (cone[0] - vStart);
3959         coneNew[1]       = vStartNew + (cone[1] - vStart);
3960         coneNew[(r+1)%2] = newv;
3961         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3962 #if defined(PETSC_USE_DEBUG)
3963         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eEndNew);
3964         for (p = 0; p < 2; ++p) {
3965           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);
3966         }
3967 #endif
3968         ierr = DMPlexGetSupportSize(dm, e, &supportSize);CHKERRQ(ierr);
3969         ierr = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
3970         for (s = 0; s < supportSize; ++s) {
3971           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
3972           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
3973           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
3974           for (c = 0; c < coneSize; ++c) {
3975             if (cone[c] == e) break;
3976           }
3977           supportRef[s] = fStartNew + (support[s] - fStart)*4 + (c + (ornt[c] < 0 ? 1-r : r))%3;
3978         }
3979         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
3980 #if defined(PETSC_USE_DEBUG)
3981         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eEndNew);
3982         for (p = 0; p < supportSize; ++p) {
3983           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);
3984         }
3985 #endif
3986       }
3987     }
3988     /* Face edges have 2 vertices and 2+cells*(1/2) faces */
3989     for (f = fStart; f < fEnd; ++f) {
3990       const PetscInt *cone, *ornt, *support;
3991       PetscInt        coneSize, supportSize, s;
3992 
3993       ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
3994       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
3995       for (r = 0; r < 3; ++r) {
3996         const PetscInt  newp = eStartNew + (eEnd - eStart)*2 + (f - fStart)*3 + r;
3997         PetscInt        coneNew[2], intFaces = 0, er, eint[4] = {1, 0, 2, 0};
3998         PetscInt        fint[24] = { 1,  7, -1, -1,  0,  5,
3999                                     -1, -1,  1,  6,  0,  4,
4000                                      2,  5,  3,  4, -1, -1,
4001                                     -1, -1,  3,  6,  2,  7};
4002 
4003         ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
4004         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[(r+0)%3] - eStart);
4005         coneNew[1] = vStartNew + (vEnd - vStart) + (cone[(r+1)%3] - eStart);
4006         ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4007 #if defined(PETSC_USE_DEBUG)
4008         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eEndNew);
4009         for (p = 0; p < 2; ++p) {
4010           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);
4011         }
4012 #endif
4013         supportRef[0] = fStartNew + (f - fStart)*4 + (r+1)%3;
4014         supportRef[1] = fStartNew + (f - fStart)*4 + 3;
4015         for (s = 0; s < supportSize; ++s) {
4016           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
4017           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
4018           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
4019           for (c = 0; c < coneSize; ++c) {if (cone[c] == f) break;}
4020           /* Here we want to determine whether edge newp contains a vertex which is part of the cross-tet edge */
4021           er = GetTriMidEdgeInverse_Static(ornt[c], r);
4022           if (er == eint[c]) {
4023             supportRef[2+intFaces++] = fStartNew + (fEnd - fStart)*4 + (support[s] - cStart)*8 + (c + 2)%4;
4024           } else {
4025             supportRef[2+intFaces++] = fStartNew + (fEnd - fStart)*4 + (support[s] - cStart)*8 + fint[(c*3 + er)*2 + 0];
4026             supportRef[2+intFaces++] = fStartNew + (fEnd - fStart)*4 + (support[s] - cStart)*8 + fint[(c*3 + er)*2 + 1];
4027           }
4028         }
4029         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
4030 #if defined(PETSC_USE_DEBUG)
4031         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eEndNew);
4032         for (p = 0; p < intFaces; ++p) {
4033           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);
4034         }
4035 #endif
4036       }
4037     }
4038     /* Interior edges have 2 vertices and 4 faces */
4039     for (c = cStart; c < cEnd; ++c) {
4040       const PetscInt  newp = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart);
4041       const PetscInt *cone, *ornt, *fcone;
4042       PetscInt        coneNew[2], supportNew[4], find;
4043 
4044       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
4045       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
4046       ierr = DMPlexGetCone(dm, cone[0], &fcone);CHKERRQ(ierr);
4047       find = GetTriEdge_Static(ornt[0], 0);
4048       coneNew[0] = vStartNew + (vEnd - vStart) + (fcone[find] - eStart);
4049       ierr = DMPlexGetCone(dm, cone[2], &fcone);CHKERRQ(ierr);
4050       find = GetTriEdge_Static(ornt[2], 1);
4051       coneNew[1] = vStartNew + (vEnd - vStart) + (fcone[find] - eStart);
4052       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4053 #if defined(PETSC_USE_DEBUG)
4054       if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eEndNew);
4055       for (p = 0; p < 2; ++p) {
4056         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);
4057       }
4058 #endif
4059       supportNew[0] = fStartNew + (fEnd - fStart)*4 + (c - cStart)*8 + 4;
4060       supportNew[1] = fStartNew + (fEnd - fStart)*4 + (c - cStart)*8 + 5;
4061       supportNew[2] = fStartNew + (fEnd - fStart)*4 + (c - cStart)*8 + 6;
4062       supportNew[3] = fStartNew + (fEnd - fStart)*4 + (c - cStart)*8 + 7;
4063       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
4064 #if defined(PETSC_USE_DEBUG)
4065       if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eEndNew);
4066       for (p = 0; p < 4; ++p) {
4067         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);
4068       }
4069 #endif
4070     }
4071     /* Old vertices have identical supports */
4072     for (v = vStart; v < vEnd; ++v) {
4073       const PetscInt  newp = vStartNew + (v - vStart);
4074       const PetscInt *support, *cone;
4075       PetscInt        size, s;
4076 
4077       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
4078       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
4079       for (s = 0; s < size; ++s) {
4080         PetscInt r = 0;
4081 
4082         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
4083         if (cone[1] == v) r = 1;
4084         supportRef[s] = eStartNew + (support[s] - eStart)*2 + r;
4085       }
4086       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
4087 #if defined(PETSC_USE_DEBUG)
4088       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", newp, vStartNew, vEndNew);
4089       for (p = 0; p < size; ++p) {
4090         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);
4091       }
4092 #endif
4093     }
4094     /* Edge vertices have 2 + face*2 + 0/1 supports */
4095     for (e = eStart; e < eEnd; ++e) {
4096       const PetscInt  newp = vStartNew + (vEnd - vStart) + (e - eStart);
4097       const PetscInt *cone, *support;
4098       PetscInt       *star = NULL, starSize, cellSize = 0, coneSize, size, s;
4099 
4100       ierr          = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
4101       ierr          = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
4102       supportRef[0] = eStartNew + (e - eStart)*2 + 0;
4103       supportRef[1] = eStartNew + (e - eStart)*2 + 1;
4104       for (s = 0; s < size; ++s) {
4105         PetscInt r = 0;
4106 
4107         ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
4108         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
4109         for (r = 0; r < coneSize; ++r) {if (cone[r] == e) break;}
4110         supportRef[2+s*2+0] = eStartNew + (eEnd - eStart)*2 + (support[s] - fStart)*3 + (r+0)%3;
4111         supportRef[2+s*2+1] = eStartNew + (eEnd - eStart)*2 + (support[s] - fStart)*3 + (r+2)%3;
4112       }
4113       ierr = DMPlexGetTransitiveClosure(dm, e, PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
4114       for (s = 0; s < starSize*2; s += 2) {
4115         const PetscInt *cone, *ornt;
4116         PetscInt        e01, e23;
4117 
4118         if ((star[s] >= cStart) && (star[s] < cEnd)) {
4119           /* Check edge 0-1 */
4120           ierr = DMPlexGetCone(dm, star[s], &cone);CHKERRQ(ierr);
4121           ierr = DMPlexGetConeOrientation(dm, star[s], &ornt);CHKERRQ(ierr);
4122           ierr = DMPlexGetCone(dm, cone[0], &cone);CHKERRQ(ierr);
4123           e01  = cone[GetTriEdge_Static(ornt[0], 0)];
4124           /* Check edge 2-3 */
4125           ierr = DMPlexGetCone(dm, star[s], &cone);CHKERRQ(ierr);
4126           ierr = DMPlexGetConeOrientation(dm, star[s], &ornt);CHKERRQ(ierr);
4127           ierr = DMPlexGetCone(dm, cone[2], &cone);CHKERRQ(ierr);
4128           e23  = cone[GetTriEdge_Static(ornt[2], 1)];
4129           if ((e01 == e) || (e23 == e)) {supportRef[2+size*2+cellSize++] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (star[s] - cStart);}
4130         }
4131       }
4132       ierr = DMPlexRestoreTransitiveClosure(dm, e, PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
4133       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
4134 #if defined(PETSC_USE_DEBUG)
4135       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", newp, vStartNew, vEndNew);
4136       for (p = 0; p < 2+size*2+cellSize; ++p) {
4137         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);
4138       }
4139 #endif
4140     }
4141     ierr = PetscFree(supportRef);CHKERRQ(ierr);
4142     ierr = DMPlexRestoreFaces_Internal(dm, cStart, NULL, NULL, &faces);CHKERRQ(ierr);
4143     break;
4144   case REFINER_HYBRID_SIMPLEX_3D:
4145     ierr = DMPlexGetHybridBounds(rdm, &cMaxNew, &fMaxNew, &eMaxNew, NULL);CHKERRQ(ierr);
4146     /* Interior cells have 4 faces: Tet face order is prescribed in DMPlexGetFaces_Internal() */
4147     ierr = DMPlexGetRawFaces_Internal(dm, DM_POLYTOPE_TETRAHEDRON, cellInd, NULL, NULL, &faces);CHKERRQ(ierr);
4148     for (c = cStart; c < cMax; ++c) {
4149       const PetscInt  newp = cStartNew + (c - cStart)*8;
4150       const PetscInt *cone, *ornt;
4151       PetscInt        coneNew[4], orntNew[4];
4152 
4153       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
4154       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
4155       /* A tetrahedron: {0, a, c, d} */
4156       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetTriSubface_Static(ornt[0], 0); /* A */
4157       orntNew[0] = ornt[0];
4158       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetTriSubface_Static(ornt[1], 0); /* A */
4159       orntNew[1] = ornt[1];
4160       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetTriSubface_Static(ornt[2], 0); /* A */
4161       orntNew[2] = ornt[2];
4162       coneNew[3] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 0;
4163       orntNew[3] = 0;
4164       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
4165       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
4166 #if defined(PETSC_USE_DEBUG)
4167       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);
4168       for (p = 0; p < 4; ++p) {
4169         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);
4170       }
4171 #endif
4172       /* B tetrahedron: {a, 1, b, e} */
4173       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetTriSubface_Static(ornt[0], 1); /* B */
4174       orntNew[0] = ornt[0];
4175       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetTriSubface_Static(ornt[1], 2); /* C */
4176       orntNew[1] = ornt[1];
4177       coneNew[2] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 1;
4178       orntNew[2] = 0;
4179       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetTriSubface_Static(ornt[3], 1); /* B */
4180       orntNew[3] = ornt[3];
4181       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
4182       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
4183 #if defined(PETSC_USE_DEBUG)
4184       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);
4185       for (p = 0; p < 4; ++p) {
4186         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);
4187       }
4188 #endif
4189       /* C tetrahedron: {c, b, 2, f} */
4190       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetTriSubface_Static(ornt[0], 2); /* C */
4191       orntNew[0] = ornt[0];
4192       coneNew[1] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 2;
4193       orntNew[1] = 0;
4194       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetTriSubface_Static(ornt[2], 1); /* B */
4195       orntNew[2] = ornt[2];
4196       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetTriSubface_Static(ornt[3], 0); /* A */
4197       orntNew[3] = ornt[3];
4198       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
4199       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
4200 #if defined(PETSC_USE_DEBUG)
4201       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);
4202       for (p = 0; p < 4; ++p) {
4203         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);
4204       }
4205 #endif
4206       /* D tetrahedron: {d, e, f, 3} */
4207       coneNew[0] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 3;
4208       orntNew[0] = 0;
4209       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetTriSubface_Static(ornt[1], 1); /* B */
4210       orntNew[1] = ornt[1];
4211       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetTriSubface_Static(ornt[2], 2); /* C */
4212       orntNew[2] = ornt[2];
4213       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetTriSubface_Static(ornt[3], 2); /* C */
4214       orntNew[3] = ornt[3];
4215       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
4216       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
4217 #if defined(PETSC_USE_DEBUG)
4218       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);
4219       for (p = 0; p < 4; ++p) {
4220         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);
4221       }
4222 #endif
4223       /* A' tetrahedron: {d, a, c, f} */
4224       coneNew[0] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 0;
4225       orntNew[0] = -3;
4226       coneNew[1] = fStartNew + (cone[2] - fStart)*4 + 3;
4227       orntNew[1] = ornt[2] < 0 ? -(GetTriMidEdge_Static(ornt[2], 0)+1) : GetTriMidEdge_Static(ornt[2], 0);
4228       coneNew[2] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 5;
4229       orntNew[2] = 0;
4230       coneNew[3] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 4;
4231       orntNew[3] = 2;
4232       ierr       = DMPlexSetCone(rdm, newp+4, coneNew);CHKERRQ(ierr);
4233       ierr       = DMPlexSetConeOrientation(rdm, newp+4, orntNew);CHKERRQ(ierr);
4234 #if defined(PETSC_USE_DEBUG)
4235       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);
4236       for (p = 0; p < 4; ++p) {
4237         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);
4238       }
4239 #endif
4240       /* B' tetrahedron: {e, b, a, f} */
4241       coneNew[0] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 1;
4242       orntNew[0] = -3;
4243       coneNew[1] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 6;
4244       orntNew[1] = 1;
4245       coneNew[2] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 7;
4246       orntNew[2] = 0;
4247       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + 3;
4248       orntNew[3] = ornt[3] < 0 ? -(GetTriMidEdge_Static(ornt[3], 0)+1) : GetTriMidEdge_Static(ornt[3], 0);
4249       ierr       = DMPlexSetCone(rdm, newp+5, coneNew);CHKERRQ(ierr);
4250       ierr       = DMPlexSetConeOrientation(rdm, newp+5, orntNew);CHKERRQ(ierr);
4251 #if defined(PETSC_USE_DEBUG)
4252       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);
4253       for (p = 0; p < 4; ++p) {
4254         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);
4255       }
4256 #endif
4257       /* C' tetrahedron: {b, f, c, a} */
4258       coneNew[0] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 2;
4259       orntNew[0] = -3;
4260       coneNew[1] = fStartNew + (cone[0] - fStart)*4 + 3;
4261       orntNew[1] = ornt[0] < 0 ? -(GetTriMidEdge_Static(ornt[0], 2)+1) : GetTriMidEdge_Static(ornt[0], 2);
4262       coneNew[2] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 5;
4263       orntNew[2] = -3;
4264       coneNew[3] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 7;
4265       orntNew[3] = -2;
4266       ierr       = DMPlexSetCone(rdm, newp+6, coneNew);CHKERRQ(ierr);
4267       ierr       = DMPlexSetConeOrientation(rdm, newp+6, orntNew);CHKERRQ(ierr);
4268 #if defined(PETSC_USE_DEBUG)
4269       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);
4270       for (p = 0; p < 4; ++p) {
4271         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);
4272       }
4273 #endif
4274       /* D' tetrahedron: {f, e, d, a} */
4275       coneNew[0] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 3;
4276       orntNew[0] = -3;
4277       coneNew[1] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 4;
4278       orntNew[1] = -3;
4279       coneNew[2] = fStartNew + (cone[1] - fStart)*4 + 3;
4280       orntNew[2] = ornt[1] < 0 ? -(GetTriMidEdge_Static(ornt[1], 0)+1) : GetTriMidEdge_Static(ornt[1], 0);
4281       coneNew[3] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 6;
4282       orntNew[3] = -3;
4283       ierr       = DMPlexSetCone(rdm, newp+7, coneNew);CHKERRQ(ierr);
4284       ierr       = DMPlexSetConeOrientation(rdm, newp+7, orntNew);CHKERRQ(ierr);
4285 #if defined(PETSC_USE_DEBUG)
4286       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);
4287       for (p = 0; p < 4; ++p) {
4288         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);
4289       }
4290 #endif
4291     }
4292     /* Hybrid cells have 5 faces */
4293     for (c = cMax; c < cEnd; ++c) {
4294       const PetscInt  newp = cStartNew + (cMax - cStart)*8 + (c - cMax)*4;
4295       const PetscInt *cone, *ornt, *fornt;
4296       PetscInt        coneNew[5], orntNew[5], o, of, i;
4297 
4298       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
4299       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
4300       ierr = DMPlexGetConeOrientation(dm, cone[0], &fornt);CHKERRQ(ierr);
4301       o = ornt[0] < 0 ? -1 : 1;
4302       for (r = 0; r < 3; ++r) {
4303         coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetTriSubface_Static(ornt[0], r);
4304         orntNew[0] = ornt[0];
4305         coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetTriSubface_Static(ornt[1], r);
4306         orntNew[1] = ornt[1];
4307         of = fornt[GetTriEdge_Static(ornt[0], r)]       < 0 ? -1 : 1;
4308         i  = GetTriEdgeInverse_Static(ornt[0], r)       + 2;
4309         coneNew[i] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (cone[2+GetTriEdge_Static(ornt[0], r)]       - fMax)*2 + (o*of < 0 ? 1 : 0);
4310         orntNew[i] = 0;
4311         i  = GetTriEdgeInverse_Static(ornt[0], (r+1)%3) + 2;
4312         coneNew[i] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (c - cMax)*3 + GetTriSubface_Static(ornt[0], r);
4313         orntNew[i] = 0;
4314         of = fornt[GetTriEdge_Static(ornt[0], (r+2)%3)] < 0 ? -1 : 1;
4315         i  = GetTriEdgeInverse_Static(ornt[0], (r+2)%3) + 2;
4316         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);
4317         orntNew[i] = 0;
4318         ierr = DMPlexSetCone(rdm, newp+r, coneNew);CHKERRQ(ierr);
4319         ierr = DMPlexSetConeOrientation(rdm, newp+r, orntNew);CHKERRQ(ierr);
4320 #if defined(PETSC_USE_DEBUG)
4321         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);
4322         for (p = 0; p < 2; ++p) {
4323           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);
4324         }
4325         for (p = 2; p < 5; ++p) {
4326           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);
4327         }
4328 #endif
4329       }
4330       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + 3;
4331       orntNew[0] = 0;
4332       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + 3;
4333       orntNew[1] = 0;
4334       coneNew[2] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (c - cMax)*3 + 1;
4335       orntNew[2] = 0;
4336       coneNew[3] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (c - cMax)*3 + 2;
4337       orntNew[3] = 0;
4338       coneNew[4] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (c - cMax)*3 + 0;
4339       orntNew[4] = 0;
4340       ierr = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
4341       ierr = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
4342 #if defined(PETSC_USE_DEBUG)
4343       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);
4344       for (p = 0; p < 2; ++p) {
4345         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);
4346       }
4347       for (p = 2; p < 5; ++p) {
4348         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);
4349       }
4350 #endif
4351     }
4352     /* Split faces have 3 edges and the same cells as the parent */
4353     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
4354     ierr = PetscMalloc1(2 + maxSupportSize*2, &supportRef);CHKERRQ(ierr);
4355     for (f = fStart; f < fMax; ++f) {
4356       const PetscInt  newp = fStartNew + (f - fStart)*4;
4357       const PetscInt *cone, *ornt, *support;
4358       PetscInt        coneNew[3], orntNew[3], coneSize, supportSize, s;
4359 
4360       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
4361       ierr = DMPlexGetConeOrientation(dm, f, &ornt);CHKERRQ(ierr);
4362       /* A triangle */
4363       coneNew[0] = eStartNew + (cone[0] - eStart)*2 + (ornt[0] < 0 ? 1 : 0);
4364       orntNew[0] = ornt[0];
4365       coneNew[1] = eStartNew + (eMax    - eStart)*2 + (f - fStart)*3 + 2;
4366       orntNew[1] = -2;
4367       coneNew[2] = eStartNew + (cone[2] - eStart)*2 + (ornt[2] < 0 ? 0 : 1);
4368       orntNew[2] = ornt[2];
4369       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
4370       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
4371 #if defined(PETSC_USE_DEBUG)
4372       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);
4373       for (p = 0; p < 3; ++p) {
4374         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);
4375       }
4376 #endif
4377       /* B triangle */
4378       coneNew[0] = eStartNew + (cone[0] - eStart)*2 + (ornt[0] < 0 ? 0 : 1);
4379       orntNew[0] = ornt[0];
4380       coneNew[1] = eStartNew + (cone[1] - eStart)*2 + (ornt[1] < 0 ? 1 : 0);
4381       orntNew[1] = ornt[1];
4382       coneNew[2] = eStartNew + (eMax    - eStart)*2 + (f - fStart)*3 + 0;
4383       orntNew[2] = -2;
4384       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
4385       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
4386 #if defined(PETSC_USE_DEBUG)
4387       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);
4388       for (p = 0; p < 3; ++p) {
4389         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);
4390       }
4391 #endif
4392       /* C triangle */
4393       coneNew[0] = eStartNew + (eMax    - eStart)*2 + (f - fStart)*3 + 1;
4394       orntNew[0] = -2;
4395       coneNew[1] = eStartNew + (cone[1] - eStart)*2 + (ornt[1] < 0 ? 0 : 1);
4396       orntNew[1] = ornt[1];
4397       coneNew[2] = eStartNew + (cone[2] - eStart)*2 + (ornt[2] < 0 ? 1 : 0);
4398       orntNew[2] = ornt[2];
4399       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
4400       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
4401 #if defined(PETSC_USE_DEBUG)
4402       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);
4403       for (p = 0; p < 3; ++p) {
4404         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);
4405       }
4406 #endif
4407       /* D triangle */
4408       coneNew[0] = eStartNew + (eMax    - eStart)*2 + (f - fStart)*3 + 0;
4409       orntNew[0] = 0;
4410       coneNew[1] = eStartNew + (eMax    - eStart)*2 + (f - fStart)*3 + 1;
4411       orntNew[1] = 0;
4412       coneNew[2] = eStartNew + (eMax    - eStart)*2 + (f - fStart)*3 + 2;
4413       orntNew[2] = 0;
4414       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
4415       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
4416 #if defined(PETSC_USE_DEBUG)
4417       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);
4418       for (p = 0; p < 3; ++p) {
4419         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);
4420       }
4421 #endif
4422       ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
4423       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
4424       for (r = 0; r < 4; ++r) {
4425         for (s = 0; s < supportSize; ++s) {
4426           PetscInt subf;
4427           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
4428           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
4429           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
4430           for (c = 0; c < coneSize; ++c) {
4431             if (cone[c] == f) break;
4432           }
4433           subf = GetTriSubfaceInverse_Static(ornt[c], r);
4434           if (support[s] < cMax) {
4435             supportRef[s] = cStartNew + (support[s] - cStart)*8 + (r==3 ? (c+2)%4 + 4 : faces[c*3+subf]);
4436           } else {
4437             supportRef[s] = cStartNew + (cMax - cStart)*8 + (support[s] - cMax)*4 + (r==3 ? r : subf);
4438           }
4439         }
4440         ierr = DMPlexSetSupport(rdm, newp+r, supportRef);CHKERRQ(ierr);
4441 #if defined(PETSC_USE_DEBUG)
4442         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);
4443         for (p = 0; p < supportSize; ++p) {
4444           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);
4445         }
4446 #endif
4447       }
4448     }
4449     /* Interior cell faces have 3 edges and 2 cells */
4450     for (c = cStart; c < cMax; ++c) {
4451       PetscInt        newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*8;
4452       const PetscInt *cone, *ornt;
4453       PetscInt        coneNew[3], orntNew[3];
4454       PetscInt        supportNew[2];
4455 
4456       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
4457       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
4458       /* Face A: {c, a, d} */
4459       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*3 + GetTriMidEdge_Static(ornt[0], 2);
4460       orntNew[0] = ornt[0] < 0 ? -2 : 0;
4461       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*3 + GetTriMidEdge_Static(ornt[1], 2);
4462       orntNew[1] = ornt[1] < 0 ? -2 : 0;
4463       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*3 + GetTriMidEdge_Static(ornt[2], 2);
4464       orntNew[2] = ornt[2] < 0 ? -2 : 0;
4465       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4466       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4467 #if defined(PETSC_USE_DEBUG)
4468       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fMaxNew);
4469       for (p = 0; p < 3; ++p) {
4470         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);
4471       }
4472 #endif
4473       supportNew[0] = (c - cStart)*8 + 0;
4474       supportNew[1] = (c - cStart)*8 + 0+4;
4475       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
4476 #if defined(PETSC_USE_DEBUG)
4477       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fMaxNew);
4478       for (p = 0; p < 2; ++p) {
4479         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);
4480       }
4481 #endif
4482       ++newp;
4483       /* Face B: {a, b, e} */
4484       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*3 + GetTriMidEdge_Static(ornt[0], 0);
4485       orntNew[0] = ornt[0] < 0 ? -2 : 0;
4486       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*3 + GetTriMidEdge_Static(ornt[3], 0);
4487       orntNew[1] = ornt[3] < 0 ? -2 : 0;
4488       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*3 + GetTriMidEdge_Static(ornt[1], 1);
4489       orntNew[2] = ornt[1] < 0 ? -2 : 0;
4490       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4491       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4492 #if defined(PETSC_USE_DEBUG)
4493       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);
4494       for (p = 0; p < 3; ++p) {
4495         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);
4496       }
4497 #endif
4498       supportNew[0] = (c - cStart)*8 + 1;
4499       supportNew[1] = (c - cStart)*8 + 1+4;
4500       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
4501 #if defined(PETSC_USE_DEBUG)
4502       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fMaxNew);
4503       for (p = 0; p < 2; ++p) {
4504         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);
4505       }
4506 #endif
4507       ++newp;
4508       /* Face C: {c, f, b} */
4509       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*3 + GetTriMidEdge_Static(ornt[2], 0);
4510       orntNew[0] = ornt[2] < 0 ? -2 : 0;
4511       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*3 + GetTriMidEdge_Static(ornt[3], 2);
4512       orntNew[1] = ornt[3] < 0 ? -2 : 0;
4513       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*3 + GetTriMidEdge_Static(ornt[0], 1);
4514       orntNew[2] = ornt[0] < 0 ? -2 : 0;
4515       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4516       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4517 #if defined(PETSC_USE_DEBUG)
4518       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fMaxNew);
4519       for (p = 0; p < 3; ++p) {
4520         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);
4521       }
4522 #endif
4523       supportNew[0] = (c - cStart)*8 + 2;
4524       supportNew[1] = (c - cStart)*8 + 2+4;
4525       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
4526 #if defined(PETSC_USE_DEBUG)
4527       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fMaxNew);
4528       for (p = 0; p < 2; ++p) {
4529         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);
4530       }
4531 #endif
4532       ++newp;
4533       /* Face D: {d, e, f} */
4534       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*3 + GetTriMidEdge_Static(ornt[1], 0);
4535       orntNew[0] = ornt[1] < 0 ? -2 : 0;
4536       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*3 + GetTriMidEdge_Static(ornt[3], 1);
4537       orntNew[1] = ornt[3] < 0 ? -2 : 0;
4538       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*3 + GetTriMidEdge_Static(ornt[2], 1);
4539       orntNew[2] = ornt[2] < 0 ? -2 : 0;
4540       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4541       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4542 #if defined(PETSC_USE_DEBUG)
4543       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fMaxNew);
4544       for (p = 0; p < 3; ++p) {
4545         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);
4546       }
4547 #endif
4548       supportNew[0] = (c - cStart)*8 + 3;
4549       supportNew[1] = (c - cStart)*8 + 3+4;
4550       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
4551 #if defined(PETSC_USE_DEBUG)
4552       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fMaxNew);
4553       for (p = 0; p < 2; ++p) {
4554         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);
4555       }
4556 #endif
4557       ++newp;
4558       /* Face E: {d, f, a} */
4559       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*3 + GetTriMidEdge_Static(ornt[2], 1);
4560       orntNew[0] = ornt[2] < 0 ? 0 : -2;
4561       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart);
4562       orntNew[1] = -2;
4563       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*3 + GetTriMidEdge_Static(ornt[1], 2);
4564       orntNew[2] = ornt[1] < 0 ? -2 : 0;
4565       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4566       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4567 #if defined(PETSC_USE_DEBUG)
4568       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fMaxNew);
4569       for (p = 0; p < 3; ++p) {
4570         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);
4571       }
4572 #endif
4573       supportNew[0] = (c - cStart)*8 + 0+4;
4574       supportNew[1] = (c - cStart)*8 + 3+4;
4575       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
4576 #if defined(PETSC_USE_DEBUG)
4577       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fMaxNew);
4578       for (p = 0; p < 2; ++p) {
4579         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);
4580       }
4581 #endif
4582       ++newp;
4583       /* Face F: {c, a, f} */
4584       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*3 + GetTriMidEdge_Static(ornt[0], 2);
4585       orntNew[0] = ornt[0] < 0 ? -2 : 0;
4586       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart);
4587       orntNew[1] = 0;
4588       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*3 + GetTriMidEdge_Static(ornt[2], 0);
4589       orntNew[2] = ornt[2] < 0 ? 0 : -2;
4590       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4591       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4592 #if defined(PETSC_USE_DEBUG)
4593       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fMaxNew);
4594       for (p = 0; p < 3; ++p) {
4595         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);
4596       }
4597 #endif
4598       supportNew[0] = (c - cStart)*8 + 0+4;
4599       supportNew[1] = (c - cStart)*8 + 2+4;
4600       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
4601 #if defined(PETSC_USE_DEBUG)
4602       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fMaxNew);
4603       for (p = 0; p < 2; ++p) {
4604         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);
4605       }
4606 #endif
4607       ++newp;
4608       /* Face G: {e, a, f} */
4609       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*3 + GetTriMidEdge_Static(ornt[1], 1);
4610       orntNew[0] = ornt[1] < 0 ? -2 : 0;
4611       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart);
4612       orntNew[1] = 0;
4613       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*3 + GetTriMidEdge_Static(ornt[3], 1);
4614       orntNew[2] = ornt[3] < 0 ? 0 : -2;
4615       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4616       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4617 #if defined(PETSC_USE_DEBUG)
4618       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fMaxNew);
4619       for (p = 0; p < 3; ++p) {
4620         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);
4621       }
4622 #endif
4623       supportNew[0] = (c - cStart)*8 + 1+4;
4624       supportNew[1] = (c - cStart)*8 + 3+4;
4625       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
4626 #if defined(PETSC_USE_DEBUG)
4627       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fMaxNew);
4628       for (p = 0; p < 2; ++p) {
4629         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);
4630       }
4631 #endif
4632       ++newp;
4633       /* Face H: {a, b, f} */
4634       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*3 + GetTriMidEdge_Static(ornt[0], 0);
4635       orntNew[0] = ornt[0] < 0 ? -2 : 0;
4636       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*3 + GetTriMidEdge_Static(ornt[3], 2);
4637       orntNew[1] = ornt[3] < 0 ? 0 : -2;
4638       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart);
4639       orntNew[2] = -2;
4640       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4641       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4642 #if defined(PETSC_USE_DEBUG)
4643       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fMaxNew);
4644       for (p = 0; p < 3; ++p) {
4645         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);
4646       }
4647 #endif
4648       supportNew[0] = (c - cStart)*8 + 1+4;
4649       supportNew[1] = (c - cStart)*8 + 2+4;
4650       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
4651 #if defined(PETSC_USE_DEBUG)
4652       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fMaxNew);
4653       for (p = 0; p < 2; ++p) {
4654         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);
4655       }
4656 #endif
4657       ++newp;
4658     }
4659     /* Hybrid split faces have 4 edges and same cells */
4660     for (f = fMax; f < fEnd; ++f) {
4661       const PetscInt *cone, *ornt, *support;
4662       PetscInt        coneNew[4], orntNew[4];
4663       PetscInt        supportNew[2], size, s, c;
4664 
4665       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
4666       ierr = DMPlexGetConeOrientation(dm, f, &ornt);CHKERRQ(ierr);
4667       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
4668       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
4669       for (r = 0; r < 2; ++r) {
4670         const PetscInt newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (f - fMax)*2 + r;
4671 
4672         coneNew[0]   = eStartNew + (cone[0] - eStart)*2 + (ornt[0] < 0 ? 1-r : r);
4673         orntNew[0]   = ornt[0];
4674         coneNew[1]   = eStartNew + (cone[1] - eStart)*2 + (ornt[1] < 0 ? 1-r : r);
4675         orntNew[1]   = ornt[1];
4676         coneNew[2+r] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (cone[2+r] - eMax);
4677         orntNew[2+r] = 0;
4678         coneNew[3-r] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (eEnd      - eMax) + (f - fMax);
4679         orntNew[3-r] = 0;
4680         ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4681         ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4682 #if defined(PETSC_USE_DEBUG)
4683         if ((newp < fMaxNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a hybrid face [%D, %D)", newp, fMaxNew, fEndNew);
4684         for (p = 0; p < 2; ++p) {
4685           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);
4686         }
4687         for (p = 2; p < 4; ++p) {
4688           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);
4689         }
4690 #endif
4691         for (s = 0; s < size; ++s) {
4692           const PetscInt *coneCell, *orntCell, *fornt;
4693           PetscInt        o, of;
4694 
4695           ierr = DMPlexGetCone(dm, support[s], &coneCell);CHKERRQ(ierr);
4696           ierr = DMPlexGetConeOrientation(dm, support[s], &orntCell);CHKERRQ(ierr);
4697           o = orntCell[0] < 0 ? -1 : 1;
4698           for (c = 2; c < 5; ++c) if (coneCell[c] == f) break;
4699           if (c >= 5) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Could not find face %D in cone of cell %D", f, support[s]);
4700           ierr = DMPlexGetConeOrientation(dm, coneCell[0], &fornt);CHKERRQ(ierr);
4701           of = fornt[c-2] < 0 ? -1 : 1;
4702           supportNew[s] = cStartNew + (cMax - cStart)*8 + (support[s] - cMax)*4 + (GetTriEdgeInverse_Static(orntCell[0], c-2) + (o*of < 0 ? 1-r : r))%3;
4703         }
4704         ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
4705 #if defined(PETSC_USE_DEBUG)
4706         if ((newp < fMaxNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a hybrid face [%D, %D)", newp, fMaxNew, fEndNew);
4707         for (p = 0; p < size; ++p) {
4708           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);
4709         }
4710 #endif
4711       }
4712     }
4713     /* Hybrid cell faces have 4 edges and 2 cells */
4714     for (c = cMax; c < cEnd; ++c) {
4715       PetscInt        newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (c - cMax)*3;
4716       const PetscInt *cone, *ornt;
4717       PetscInt        coneNew[4], orntNew[4];
4718       PetscInt        supportNew[2];
4719 
4720       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
4721       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
4722       for (r = 0; r < 3; ++r) {
4723         coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*3 + (r+2)%3;
4724         orntNew[0] = 0;
4725         coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*3 + (r+2)%3;
4726         orntNew[1] = 0;
4727         coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (eEnd - eMax) + (cone[2+(r+2)%3] - fMax);
4728         orntNew[2] = 0;
4729         coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (eEnd - eMax) + (cone[2+r]       - fMax);
4730         orntNew[3] = 0;
4731         ierr = DMPlexSetCone(rdm, newp+r, coneNew);CHKERRQ(ierr);
4732         ierr = DMPlexSetConeOrientation(rdm, newp+r, orntNew);CHKERRQ(ierr);
4733 #if defined(PETSC_USE_DEBUG)
4734         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);
4735         for (p = 0; p < 2; ++p) {
4736           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);
4737         }
4738         for (p = 2; p < 4; ++p) {
4739           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);
4740         }
4741 #endif
4742         supportNew[0] = cStartNew + (cMax - cStart)*8 + (c - cMax)*4 + GetTriSubface_Static(ornt[0], r);
4743         supportNew[1] = cStartNew + (cMax - cStart)*8 + (c - cMax)*4 + 3;
4744         ierr          = DMPlexSetSupport(rdm, newp+r, supportNew);CHKERRQ(ierr);
4745 #if defined(PETSC_USE_DEBUG)
4746         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);
4747         for (p = 0; p < 2; ++p) {
4748           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);
4749         }
4750 #endif
4751       }
4752     }
4753     /* Interior split edges have 2 vertices and the same faces as the parent */
4754     for (e = eStart; e < eMax; ++e) {
4755       const PetscInt newv = vStartNew + (vEnd - vStart) + (e - eStart);
4756 
4757       for (r = 0; r < 2; ++r) {
4758         const PetscInt  newp = eStartNew + (e - eStart)*2 + r;
4759         const PetscInt *cone, *ornt, *support;
4760         PetscInt        coneNew[2], coneSize, c, supportSize, s;
4761 
4762         ierr             = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
4763         coneNew[0]       = vStartNew + (cone[0] - vStart);
4764         coneNew[1]       = vStartNew + (cone[1] - vStart);
4765         coneNew[(r+1)%2] = newv;
4766         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4767 #if defined(PETSC_USE_DEBUG)
4768         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eMaxNew);
4769         for (p = 0; p < 2; ++p) {
4770           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);
4771         }
4772 #endif
4773         ierr = DMPlexGetSupportSize(dm, e, &supportSize);CHKERRQ(ierr);
4774         ierr = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
4775         for (s = 0; s < supportSize; ++s) {
4776           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
4777           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
4778           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
4779           for (c = 0; c < coneSize; ++c) if (cone[c] == e) break;
4780           if (support[s] < fMax) {
4781             supportRef[s] = fStartNew + (support[s] - fStart)*4 + (c + (ornt[c] < 0 ? 1-r : r))%3;
4782           } else {
4783             supportRef[s] = fStartNew + (fMax       - fStart)*4 + (cMax - cStart)*8 + (support[s] - fMax)*2 + (ornt[c] < 0 ? 1-r : r);
4784           }
4785         }
4786         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
4787 #if defined(PETSC_USE_DEBUG)
4788         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eMaxNew);
4789         for (p = 0; p < supportSize; ++p) {
4790           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);
4791         }
4792 #endif
4793       }
4794     }
4795     /* Interior face edges have 2 vertices and 2+cells*(1/2) faces */
4796     for (f = fStart; f < fMax; ++f) {
4797       const PetscInt *cone, *ornt, *support;
4798       PetscInt        coneSize, supportSize, s;
4799 
4800       ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
4801       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
4802       for (r = 0; r < 3; ++r) {
4803         const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (f - fStart)*3 + r;
4804         PetscInt        coneNew[2], intFaces = 0, er, eint[4] = {1, 0, 2, 0};
4805         PetscInt        fint[24] = { 1,  7, -1, -1,  0,  5,
4806                                     -1, -1,  1,  6,  0,  4,
4807                                      2,  5,  3,  4, -1, -1,
4808                                     -1, -1,  3,  6,  2,  7};
4809 
4810         ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
4811         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[(r+0)%3] - eStart);
4812         coneNew[1] = vStartNew + (vEnd - vStart) + (cone[(r+1)%3] - eStart);
4813         ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4814 #if defined(PETSC_USE_DEBUG)
4815         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eMaxNew);
4816         for (p = 0; p < 2; ++p) {
4817           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);
4818         }
4819 #endif
4820         supportRef[0] = fStartNew + (f - fStart)*4 + (r+1)%3;
4821         supportRef[1] = fStartNew + (f - fStart)*4 + 3;
4822         for (s = 0; s < supportSize; ++s) {
4823           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
4824           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
4825           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
4826           for (c = 0; c < coneSize; ++c) {if (cone[c] == f) break;}
4827           if (support[s] < cMax) {
4828             /* Here we want to determine whether edge newp contains a vertex which is part of the cross-tet edge */
4829             er = GetTriMidEdgeInverse_Static(ornt[c], r);
4830             if (er == eint[c]) {
4831               supportRef[2+intFaces++] = fStartNew + (fMax - fStart)*4 + (support[s] - cStart)*8 + (c + 2)%4;
4832             } else {
4833               supportRef[2+intFaces++] = fStartNew + (fMax - fStart)*4 + (support[s] - cStart)*8 + fint[(c*3 + er)*2 + 0];
4834               supportRef[2+intFaces++] = fStartNew + (fMax - fStart)*4 + (support[s] - cStart)*8 + fint[(c*3 + er)*2 + 1];
4835             }
4836           } else {
4837             supportRef[2+intFaces++] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (support[s] - cMax)*3 + (r + 1)%3;
4838           }
4839         }
4840         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
4841 #if defined(PETSC_USE_DEBUG)
4842         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eMaxNew);
4843         for (p = 0; p < intFaces; ++p) {
4844           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);
4845         }
4846 #endif
4847       }
4848     }
4849     /* Interior cell edges have 2 vertices and 4 faces */
4850     for (c = cStart; c < cMax; ++c) {
4851       const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart);
4852       const PetscInt *cone, *ornt, *fcone;
4853       PetscInt        coneNew[2], supportNew[4], find;
4854 
4855       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
4856       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
4857       ierr = DMPlexGetCone(dm, cone[0], &fcone);CHKERRQ(ierr);
4858       find = GetTriEdge_Static(ornt[0], 0);
4859       coneNew[0] = vStartNew + (vEnd - vStart) + (fcone[find] - eStart);
4860       ierr = DMPlexGetCone(dm, cone[2], &fcone);CHKERRQ(ierr);
4861       find = GetTriEdge_Static(ornt[2], 1);
4862       coneNew[1] = vStartNew + (vEnd - vStart) + (fcone[find] - eStart);
4863       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4864 #if defined(PETSC_USE_DEBUG)
4865       if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eMaxNew);
4866       for (p = 0; p < 2; ++p) {
4867         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);
4868       }
4869 #endif
4870       supportNew[0] = fStartNew + (fMax - fStart)*4 + (c - cStart)*8 + 4;
4871       supportNew[1] = fStartNew + (fMax - fStart)*4 + (c - cStart)*8 + 5;
4872       supportNew[2] = fStartNew + (fMax - fStart)*4 + (c - cStart)*8 + 6;
4873       supportNew[3] = fStartNew + (fMax - fStart)*4 + (c - cStart)*8 + 7;
4874       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
4875 #if defined(PETSC_USE_DEBUG)
4876       if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eMaxNew);
4877       for (p = 0; p < 4; ++p) {
4878         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);
4879       }
4880 #endif
4881     }
4882     /* Hybrid edges have two vertices and the same faces */
4883     for (e = eMax; e < eEnd; ++e) {
4884       const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (e - eMax);
4885       const PetscInt *cone, *support, *fcone;
4886       PetscInt        coneNew[2], size, fsize, s;
4887 
4888       ierr = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
4889       ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
4890       ierr = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
4891       coneNew[0] = vStartNew + (cone[0] - vStart);
4892       coneNew[1] = vStartNew + (cone[1] - vStart);
4893       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4894 #if defined(PETSC_USE_DEBUG)
4895       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a hybrid edge [%D, %D)", newp, eMaxNew, eEndNew);
4896       for (p = 0; p < 2; ++p) {
4897         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);
4898       }
4899 #endif
4900       for (s = 0; s < size; ++s) {
4901         ierr = DMPlexGetConeSize(dm, support[s], &fsize);CHKERRQ(ierr);
4902         ierr = DMPlexGetCone(dm, support[s], &fcone);CHKERRQ(ierr);
4903         for (c = 0; c < fsize; ++c) if (fcone[c] == e) break;
4904         if ((c < 2) || (c > 3)) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Edge %D not found in cone of face %D", e, support[s]);
4905         supportRef[s] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (support[s] - fMax)*2 + c-2;
4906       }
4907       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
4908 #if defined(PETSC_USE_DEBUG)
4909       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a hybrid edge [%D, %D)", newp, eMaxNew, eEndNew);
4910       for (p = 0; p < size; ++p) {
4911         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);
4912       }
4913 #endif
4914     }
4915     /* Hybrid face edges have 2 vertices and 2+2*cells faces */
4916     for (f = fMax; f < fEnd; ++f) {
4917       const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (eEnd - eMax) + (f - fMax);
4918       const PetscInt *cone, *support, *ccone, *cornt;
4919       PetscInt        coneNew[2], size, csize, s;
4920 
4921       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
4922       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
4923       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
4924       coneNew[0] = vStartNew + (vEnd - vStart) + (cone[0] - eStart);
4925       coneNew[1] = vStartNew + (vEnd - vStart) + (cone[1] - eStart);
4926       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4927 #if defined(PETSC_USE_DEBUG)
4928       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a hybrid edge [%D, %D)", newp, eMaxNew, eEndNew);
4929       for (p = 0; p < 2; ++p) {
4930         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);
4931       }
4932 #endif
4933       supportRef[0] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (f - fMax)*2 + 0;
4934       supportRef[1] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (f - fMax)*2 + 1;
4935       for (s = 0; s < size; ++s) {
4936         ierr = DMPlexGetConeSize(dm, support[s], &csize);CHKERRQ(ierr);
4937         ierr = DMPlexGetCone(dm, support[s], &ccone);CHKERRQ(ierr);
4938         ierr = DMPlexGetConeOrientation(dm, support[s], &cornt);CHKERRQ(ierr);
4939         for (c = 0; c < csize; ++c) if (ccone[c] == f) break;
4940         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]);
4941         supportRef[2+s*2+0] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (support[s] - cMax)*3 + c-2;
4942         supportRef[2+s*2+1] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (support[s] - cMax)*3 + (c-1)%3;
4943       }
4944       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
4945 #if defined(PETSC_USE_DEBUG)
4946       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a hybrid edge [%D, %D)", newp, eMaxNew, eEndNew);
4947       for (p = 0; p < 2+size*2; ++p) {
4948         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);
4949       }
4950 #endif
4951     }
4952     /* Interior vertices have identical supports */
4953     for (v = vStart; v < vEnd; ++v) {
4954       const PetscInt  newp = vStartNew + (v - vStart);
4955       const PetscInt *support, *cone;
4956       PetscInt        size, s;
4957 
4958       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
4959       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
4960       for (s = 0; s < size; ++s) {
4961         PetscInt r = 0;
4962 
4963         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
4964         if (cone[1] == v) r = 1;
4965         if (support[s] < eMax) supportRef[s] = eStartNew + (support[s] - eStart)*2 + r;
4966         else                   supportRef[s] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (support[s] - eMax);
4967       }
4968       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
4969 #if defined(PETSC_USE_DEBUG)
4970       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", newp, vStartNew, vEndNew);
4971       for (p = 0; p < size; ++p) {
4972         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);
4973       }
4974 #endif
4975     }
4976     /* Interior edge vertices have 2 + interior face*2 + hybrid face + cells*0/1 supports */
4977     for (e = eStart; e < eMax; ++e) {
4978       const PetscInt  newp = vStartNew + (vEnd - vStart) + (e - eStart);
4979       const PetscInt *cone, *support;
4980       PetscInt       *star = NULL, starSize, faceSize = 0, cellSize = 0, coneSize, size, s;
4981 
4982       ierr          = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
4983       ierr          = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
4984       supportRef[0] = eStartNew + (e - eStart)*2 + 0;
4985       supportRef[1] = eStartNew + (e - eStart)*2 + 1;
4986       for (s = 0; s < size; ++s) {
4987         PetscInt r = 0;
4988 
4989         if (support[s] < fMax) {
4990           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
4991           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
4992           for (r = 0; r < coneSize; ++r) {if (cone[r] == e) break;}
4993           supportRef[2+faceSize+0] = eStartNew + (eMax - eStart)*2 + (support[s] - fStart)*3 + (r+0)%3;
4994           supportRef[2+faceSize+1] = eStartNew + (eMax - eStart)*2 + (support[s] - fStart)*3 + (r+2)%3;
4995           faceSize += 2;
4996         } else {
4997           supportRef[2+faceSize+0] = eStartNew + (eMax - eStart)*2 + (fMax       - fStart)*3 + (cMax - cStart) + (eEnd - eMax) + (support[s] - fMax);
4998           ++faceSize;
4999         }
5000       }
5001       ierr = DMPlexGetTransitiveClosure(dm, e, PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
5002       for (s = 0; s < starSize*2; s += 2) {
5003         const PetscInt *cone, *ornt;
5004         PetscInt        e01, e23;
5005 
5006         if ((star[s] >= cStart) && (star[s] < cMax)) {
5007           /* Check edge 0-1 */
5008           ierr = DMPlexGetCone(dm, star[s], &cone);CHKERRQ(ierr);
5009           ierr = DMPlexGetConeOrientation(dm, star[s], &ornt);CHKERRQ(ierr);
5010           ierr = DMPlexGetCone(dm, cone[0], &cone);CHKERRQ(ierr);
5011           e01  = cone[GetTriEdge_Static(ornt[0], 0)];
5012           /* Check edge 2-3 */
5013           ierr = DMPlexGetCone(dm, star[s], &cone);CHKERRQ(ierr);
5014           ierr = DMPlexGetConeOrientation(dm, star[s], &ornt);CHKERRQ(ierr);
5015           ierr = DMPlexGetCone(dm, cone[2], &cone);CHKERRQ(ierr);
5016           e23  = cone[GetTriEdge_Static(ornt[2], 1)];
5017           if ((e01 == e) || (e23 == e)) {supportRef[2+faceSize+cellSize++] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (star[s] - cStart);}
5018         }
5019       }
5020       ierr = DMPlexRestoreTransitiveClosure(dm, e, PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
5021       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
5022 #if defined(PETSC_USE_DEBUG)
5023       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", newp, vStartNew, vEndNew);
5024       for (p = 0; p < 2+faceSize+cellSize; ++p) {
5025         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);
5026       }
5027 #endif
5028     }
5029     ierr = PetscFree(supportRef);CHKERRQ(ierr);
5030     ierr = DMPlexRestoreFaces_Internal(dm, cStart, NULL, NULL, &faces);CHKERRQ(ierr);
5031     break;
5032   case REFINER_SIMPLEX_TO_HEX_3D:
5033     ierr = DMPlexGetRawFaces_Internal(dm, DM_POLYTOPE_TETRAHEDRON, cellInd, NULL, NULL, &faces);CHKERRQ(ierr);
5034     /* All cells have 6 faces */
5035     for (c = cStart; c < cEnd; ++c) {
5036       const PetscInt  newp = cStartNew + (c - cStart)*4;
5037       const PetscInt *cone, *ornt;
5038       PetscInt        coneNew[6];
5039       PetscInt        orntNew[6];
5040 
5041       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
5042       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
5043       /* A hex */
5044       coneNew[0] = fStartNew + (cone[0] - fStart)*3 + GetTriSubface_Static(ornt[0], 0); /* B */
5045       orntNew[0] = ornt[0] < 0 ? -1 : 1;
5046       coneNew[1] = fStartNew + (fEnd    - fStart)*3 + (c - cStart)*6 + 3;               /* T */
5047       orntNew[1] = -4;
5048       coneNew[2] = fStartNew + (cone[2] - fStart)*3 + GetTriSubface_Static(ornt[2], 0); /* F */
5049       orntNew[2] = ornt[2] < 0 ? -1 : 1;
5050       coneNew[3] = fStartNew + (fEnd    - fStart)*3 + (c - cStart)*6 + 0;               /* K */
5051       orntNew[3] = -1;
5052       coneNew[4] = fStartNew + (fEnd    - fStart)*3 + (c - cStart)*6 + 2;               /* R */
5053       orntNew[4] = 0;
5054       coneNew[5] = fStartNew + (cone[1] - fStart)*3 + GetTriSubface_Static(ornt[1], 0); /* L */
5055       orntNew[5] = ornt[1] < 0 ? -1 : 1;
5056       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
5057       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
5058 #if defined(PETSC_USE_DEBUG)
5059       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);
5060       for (p = 0; p < 6; ++p) {
5061         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);
5062       }
5063 #endif
5064       /* B hex */
5065       coneNew[0] = fStartNew + (cone[0] - fStart)*3 + GetTriSubface_Static(ornt[0], 1); /* B */
5066       orntNew[0] = ornt[0] < 0 ? -2 : 0;
5067       coneNew[1] = fStartNew + (fEnd    - fStart)*3 + (c - cStart)*6 + 4;               /* T */
5068       orntNew[1] = 0;
5069       coneNew[2] = fStartNew + (fEnd    - fStart)*3 + (c - cStart)*6 + 0;               /* F */
5070       orntNew[2] = 0;
5071       coneNew[3] = fStartNew + (cone[3] - fStart)*3 + GetTriSubface_Static(ornt[3], 1); /* K */
5072       orntNew[3] = ornt[3] < 0 ? -2 : 0;
5073       coneNew[4] = fStartNew + (fEnd    - fStart)*3 + (c - cStart)*6 + 1;               /* R */
5074       orntNew[4] = 0;
5075       coneNew[5] = fStartNew + (cone[1] - fStart)*3 + GetTriSubface_Static(ornt[1], 2); /* L */
5076       orntNew[5] = ornt[1] < 0 ? -4 : 2;
5077       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
5078       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
5079 #if defined(PETSC_USE_DEBUG)
5080       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);
5081       for (p = 0; p < 6; ++p) {
5082         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);
5083       }
5084 #endif
5085       /* C hex */
5086       coneNew[0] = fStartNew + (cone[0] - fStart)*3 + GetTriSubface_Static(ornt[0], 2); /* B */
5087       orntNew[0] = ornt[0] < 0 ? -4 : 2;
5088       coneNew[1] = fStartNew + (fEnd    - fStart)*3 + (c - cStart)*6 + 5;               /* T */
5089       orntNew[1] = -4;
5090       coneNew[2] = fStartNew + (cone[2] - fStart)*3 + GetTriSubface_Static(ornt[2], 1); /* F */
5091       orntNew[2] = ornt[2] < 0 ? -2 : 0;
5092       coneNew[3] = fStartNew + (fEnd    - fStart)*3 + (c - cStart)*6 + 1;               /* K */
5093       orntNew[3] = -1;
5094       coneNew[4] = fStartNew + (cone[3] - fStart)*3 + GetTriSubface_Static(ornt[3], 0); /* R */
5095       orntNew[4] = ornt[3] < 0 ? -1 : 1;
5096       coneNew[5] = fStartNew + (fEnd    - fStart)*3 + (c - cStart)*6 + 2;               /* L */
5097       orntNew[5] = -4;
5098       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
5099       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
5100 #if defined(PETSC_USE_DEBUG)
5101       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);
5102       for (p = 0; p < 6; ++p) {
5103         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);
5104       }
5105 #endif
5106       /* D hex */
5107       coneNew[0] = fStartNew + (fEnd    - fStart)*3 + (c - cStart)*6 + 3;               /* B */
5108       orntNew[0] = 0;
5109       coneNew[1] = fStartNew + (cone[3] - fStart)*3 + GetTriSubface_Static(ornt[3], 2); /* T */
5110       orntNew[1] = ornt[3] < 0 ? -1 : 1;
5111       coneNew[2] = fStartNew + (cone[2] - fStart)*3 + GetTriSubface_Static(ornt[2], 2); /* F */
5112       orntNew[2] = ornt[2] < 0 ? -4 : 2;
5113       coneNew[3] = fStartNew + (fEnd    - fStart)*3 + (c - cStart)*6 + 4;               /* K */
5114       orntNew[3] = -1;
5115       coneNew[4] = fStartNew + (fEnd    - fStart)*3 + (c - cStart)*6 + 5;               /* R */
5116       orntNew[4] = 0;
5117       coneNew[5] = fStartNew + (cone[1] - fStart)*3 + GetTriSubface_Static(ornt[1], 1); /* L */
5118       orntNew[5] = ornt[1] < 0 ? -2 : 0;
5119       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
5120       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
5121 #if defined(PETSC_USE_DEBUG)
5122       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);
5123       for (p = 0; p < 6; ++p) {
5124         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);
5125       }
5126 #endif
5127     }
5128     /* Split faces have 4 edges and the same cells as the parent */
5129     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
5130     ierr = PetscMalloc1(2 + maxSupportSize*2, &supportRef);CHKERRQ(ierr);
5131     for (f = fStart; f < fEnd; ++f) {
5132       const PetscInt  newp = fStartNew + (f - fStart)*3;
5133       const PetscInt *cone, *ornt, *support;
5134       PetscInt        coneNew[4], orntNew[4], coneSize, supportSize, s;
5135 
5136       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
5137       ierr = DMPlexGetConeOrientation(dm, f, &ornt);CHKERRQ(ierr);
5138       /* A quad */
5139       coneNew[0] = eStartNew + (cone[2] - eStart)*2 + (ornt[2] < 0 ? 0 : 1);
5140       orntNew[0] = ornt[2];
5141       coneNew[1] = eStartNew + (cone[0] - eStart)*2 + (ornt[0] < 0 ? 1 : 0);
5142       orntNew[1] = ornt[0];
5143       coneNew[2] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 0;
5144       orntNew[2] = 0;
5145       coneNew[3] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 2;
5146       orntNew[3] = -2;
5147       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
5148       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
5149 #if defined(PETSC_USE_DEBUG)
5150       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);
5151       for (p = 0; p < 4; ++p) {
5152         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);
5153       }
5154 #endif
5155       /* B quad */
5156       coneNew[0] = eStartNew + (cone[0] - eStart)*2 + (ornt[0] < 0 ? 0 : 1);
5157       orntNew[0] = ornt[0];
5158       coneNew[1] = eStartNew + (cone[1] - eStart)*2 + (ornt[1] < 0 ? 1 : 0);
5159       orntNew[1] = ornt[1];
5160       coneNew[2] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 1;
5161       orntNew[2] = 0;
5162       coneNew[3] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 0;
5163       orntNew[3] = -2;
5164       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
5165       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
5166 #if defined(PETSC_USE_DEBUG)
5167       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);
5168       for (p = 0; p < 4; ++p) {
5169         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);
5170       }
5171 #endif
5172       /* C quad */
5173       coneNew[0] = eStartNew + (cone[1] - eStart)*2 + (ornt[1] < 0 ? 0 : 1);
5174       orntNew[0] = ornt[1];
5175       coneNew[1] = eStartNew + (cone[2] - eStart)*2 + (ornt[2] < 0 ? 1 : 0);
5176       orntNew[1] = ornt[2];
5177       coneNew[2] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 2;
5178       orntNew[2] = 0;
5179       coneNew[3] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 1;
5180       orntNew[3] = -2;
5181       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
5182       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
5183 #if defined(PETSC_USE_DEBUG)
5184       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);
5185       for (p = 0; p < 4; ++p) {
5186         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);
5187       }
5188 #endif
5189       ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
5190       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
5191       for (r = 0; r < 3; ++r) {
5192         for (s = 0; s < supportSize; ++s) {
5193           PetscInt subf;
5194           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
5195           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
5196           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
5197           for (c = 0; c < coneSize; ++c) {
5198             if (cone[c] == f) break;
5199           }
5200           subf = GetTriSubfaceInverse_Static(ornt[c], r);
5201           supportRef[s] = cStartNew + (support[s] - cStart)*4 + faces[c*3+subf];
5202         }
5203         ierr = DMPlexSetSupport(rdm, newp+r, supportRef);CHKERRQ(ierr);
5204 #if defined(PETSC_USE_DEBUG)
5205         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);
5206         for (p = 0; p < supportSize; ++p) {
5207           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);
5208         }
5209 #endif
5210       }
5211     }
5212     /* Interior faces have 4 edges and 2 cells */
5213     for (c = cStart; c < cEnd; ++c) {
5214       PetscInt        newp = fStartNew + (fEnd - fStart)*3 + (c - cStart)*6;
5215       const PetscInt *cone, *ornt;
5216       PetscInt        coneNew[4], orntNew[4];
5217       PetscInt        supportNew[2];
5218 
5219       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
5220       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
5221       /* Face {a, g, m, h} */
5222       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*3 + GetTriInteriorEdge_Static(ornt[0],0);
5223       orntNew[0] = 0;
5224       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + 0;
5225       orntNew[1] = 0;
5226       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + 1;
5227       orntNew[2] = -2;
5228       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*3 + GetTriInteriorEdge_Static(ornt[1],2);
5229       orntNew[3] = -2;
5230       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5231       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
5232 #if defined(PETSC_USE_DEBUG)
5233       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
5234       for (p = 0; p < 4; ++p) {
5235         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);
5236       }
5237 #endif
5238       supportNew[0] = (c - cStart)*4 + 0;
5239       supportNew[1] = (c - cStart)*4 + 1;
5240       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
5241 #if defined(PETSC_USE_DEBUG)
5242       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
5243       for (p = 0; p < 2; ++p) {
5244         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);
5245       }
5246 #endif
5247       ++newp;
5248       /* Face {g, b, l , m} */
5249       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*3 + GetTriInteriorEdge_Static(ornt[0],1);
5250       orntNew[0] = -2;
5251       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*3 + GetTriInteriorEdge_Static(ornt[3],0);
5252       orntNew[1] = 0;
5253       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + 3;
5254       orntNew[2] = 0;
5255       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + 0;
5256       orntNew[3] = -2;
5257       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5258       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
5259 #if defined(PETSC_USE_DEBUG)
5260       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
5261       for (p = 0; p < 4; ++p) {
5262         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);
5263       }
5264 #endif
5265       supportNew[0] = (c - cStart)*4 + 1;
5266       supportNew[1] = (c - cStart)*4 + 2;
5267       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
5268 #if defined(PETSC_USE_DEBUG)
5269       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
5270       for (p = 0; p < 2; ++p) {
5271         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);
5272       }
5273 #endif
5274       ++newp;
5275       /* Face {c, g, m, i} */
5276       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*3 + GetTriInteriorEdge_Static(ornt[0],2);
5277       orntNew[0] = 0;
5278       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + 0;
5279       orntNew[1] = 0;
5280       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + 2;
5281       orntNew[2] = -2;
5282       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*3 + GetTriInteriorEdge_Static(ornt[2],0);
5283       orntNew[3] = -2;
5284       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5285       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
5286 #if defined(PETSC_USE_DEBUG)
5287       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
5288       for (p = 0; p < 4; ++p) {
5289         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);
5290       }
5291 #endif
5292       supportNew[0] = (c - cStart)*4 + 0;
5293       supportNew[1] = (c - cStart)*4 + 2;
5294       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
5295 #if defined(PETSC_USE_DEBUG)
5296       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
5297       for (p = 0; p < 2; ++p) {
5298         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);
5299       }
5300 #endif
5301       ++newp;
5302       /* Face {d, h, m, i} */
5303       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*3 + GetTriInteriorEdge_Static(ornt[1],0);
5304       orntNew[0] = 0;
5305       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + 1;
5306       orntNew[1] = 0;
5307       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + 2;
5308       orntNew[2] = -2;
5309       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*3 + GetTriInteriorEdge_Static(ornt[2],2);
5310       orntNew[3] = -2;
5311       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5312       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
5313 #if defined(PETSC_USE_DEBUG)
5314       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
5315       for (p = 0; p < 4; ++p) {
5316         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);
5317       }
5318 #endif
5319       supportNew[0] = (c - cStart)*4 + 0;
5320       supportNew[1] = (c - cStart)*4 + 3;
5321       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
5322 #if defined(PETSC_USE_DEBUG)
5323       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
5324       for (p = 0; p < 2; ++p) {
5325         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);
5326       }
5327 #endif
5328       ++newp;
5329       /* Face {h, m, l, e} */
5330       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + 1;
5331       orntNew[0] = 0;
5332       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + 3;
5333       orntNew[1] = -2;
5334       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*3 + GetTriInteriorEdge_Static(ornt[3],1);
5335       orntNew[2] = -2;
5336       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*3 + GetTriInteriorEdge_Static(ornt[1],1);
5337       orntNew[3] = 0;
5338       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5339       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
5340 #if defined(PETSC_USE_DEBUG)
5341       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
5342       for (p = 0; p < 4; ++p) {
5343         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);
5344       }
5345 #endif
5346       supportNew[0] = (c - cStart)*4 + 1;
5347       supportNew[1] = (c - cStart)*4 + 3;
5348       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
5349 #if defined(PETSC_USE_DEBUG)
5350       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
5351       for (p = 0; p < 2; ++p) {
5352         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);
5353       }
5354 #endif
5355       ++newp;
5356       /* Face {i, m, l, f} */
5357       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + 2;
5358       orntNew[0] = 0;
5359       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + 3;
5360       orntNew[1] = -2;
5361       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*3 + GetTriInteriorEdge_Static(ornt[3],2);
5362       orntNew[2] = -2;
5363       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*3 + GetTriInteriorEdge_Static(ornt[2],1);
5364       orntNew[3] = 0;
5365       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5366       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
5367 #if defined(PETSC_USE_DEBUG)
5368       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
5369       for (p = 0; p < 4; ++p) {
5370         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);
5371       }
5372 #endif
5373       supportNew[0] = (c - cStart)*4 + 2;
5374       supportNew[1] = (c - cStart)*4 + 3;
5375       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
5376 #if defined(PETSC_USE_DEBUG)
5377       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
5378       for (p = 0; p < 2; ++p) {
5379         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);
5380       }
5381 #endif
5382       ++newp;
5383     }
5384     /* Split Edges have 2 vertices and the same faces as the parent */
5385     for (e = eStart; e < eEnd; ++e) {
5386       const PetscInt newv = vStartNew + (vEnd - vStart) + (e - eStart);
5387 
5388       for (r = 0; r < 2; ++r) {
5389         const PetscInt  newp = eStartNew + (e - eStart)*2 + r;
5390         const PetscInt *cone, *ornt, *support;
5391         PetscInt        coneNew[2], coneSize, c, supportSize, s;
5392 
5393         ierr             = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
5394         coneNew[0]       = vStartNew + (cone[0] - vStart);
5395         coneNew[1]       = vStartNew + (cone[1] - vStart);
5396         coneNew[(r+1)%2] = newv;
5397         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5398 #if defined(PETSC_USE_DEBUG)
5399         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eEndNew);
5400         for (p = 0; p < 2; ++p) {
5401           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);
5402         }
5403 #endif
5404         ierr = DMPlexGetSupportSize(dm, e, &supportSize);CHKERRQ(ierr);
5405         ierr = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
5406         for (s = 0; s < supportSize; ++s) {
5407           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
5408           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
5409           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
5410           for (c = 0; c < coneSize; ++c) {
5411             if (cone[c] == e) break;
5412           }
5413           supportRef[s] = fStartNew + (support[s] - fStart)*3 + (c + (ornt[c] < 0 ? 1-r : r))%3;
5414         }
5415         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
5416 #if defined(PETSC_USE_DEBUG)
5417         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eEndNew);
5418         for (p = 0; p < supportSize; ++p) {
5419           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);
5420         }
5421 #endif
5422       }
5423     }
5424     /* Face edges have 2 vertices and 2 + cell faces supports */
5425     for (f = fStart; f < fEnd; ++f) {
5426       const PetscInt *cone, *ornt, *support;
5427       PetscInt        coneSize, supportSize, s;
5428 
5429       ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
5430       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
5431       for (r = 0; r < 3; ++r) {
5432         const PetscInt  newp = eStartNew + (eEnd - eStart)*2 + (f - fStart)*3 + r;
5433         PetscInt        coneNew[2];
5434         PetscInt        fint[4][3] = { {0, 1, 2},
5435                                        {3, 4, 0},
5436                                        {2, 5, 3},
5437                                        {1, 4, 5} };
5438 
5439         ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
5440         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r] - eStart);
5441         coneNew[1] = vStartNew + (vEnd - vStart) + (eEnd - eStart) + f - fStart;
5442         ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5443 #if defined(PETSC_USE_DEBUG)
5444         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eEndNew);
5445         for (p = 0; p < 2; ++p) {
5446           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);
5447         }
5448 #endif
5449         supportRef[0] = fStartNew + (f - fStart)*3 + (r+0)%3;
5450         supportRef[1] = fStartNew + (f - fStart)*3 + (r+1)%3;
5451         for (s = 0; s < supportSize; ++s) {
5452           PetscInt er;
5453           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
5454           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
5455           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
5456           for (c = 0; c < coneSize; ++c) {if (cone[c] == f) break;}
5457           er = GetTriInteriorEdgeInverse_Static(ornt[c], r);
5458           supportRef[2+s] = fStartNew + (fEnd - fStart)*3 + (support[s] - cStart)*6 + fint[c][er];
5459         }
5460         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
5461 #if defined(PETSC_USE_DEBUG)
5462         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eEndNew);
5463         for (p = 0; p < supportSize + 2; ++p) {
5464           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);
5465         }
5466 #endif
5467       }
5468     }
5469     /* Interior cell edges have 2 vertices and 3 faces */
5470     for (c = cStart; c < cEnd; ++c) {
5471       const PetscInt *cone;
5472       PetscInt       fint[4][3] = { {0,1,2},
5473                                     {0,3,4},
5474                                     {2,3,5},
5475                                     {1,4,5} } ;
5476 
5477       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
5478       for (r = 0; r < 4; r++) {
5479         PetscInt       coneNew[2], supportNew[3];
5480         const PetscInt newp = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + r;
5481 
5482         coneNew[0] = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (cone[r] - fStart);
5483         coneNew[1] = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (fEnd -fStart) + c - cStart;
5484         ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5485 #if defined(PETSC_USE_DEBUG)
5486         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eEndNew);
5487         for (p = 0; p < 2; ++p) {
5488           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);
5489         }
5490 #endif
5491         supportNew[0] = fStartNew + (fEnd - fStart)*3 + (c - cStart)*6 + fint[r][0];
5492         supportNew[1] = fStartNew + (fEnd - fStart)*3 + (c - cStart)*6 + fint[r][1];
5493         supportNew[2] = fStartNew + (fEnd - fStart)*3 + (c - cStart)*6 + fint[r][2];
5494         ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
5495 #if defined(PETSC_USE_DEBUG)
5496         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eEndNew);
5497         for (p = 0; p < 3; ++p) {
5498           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);
5499         }
5500 #endif
5501       }
5502     }
5503     /* Old vertices have identical supports */
5504     for (v = vStart; v < vEnd; ++v) {
5505       const PetscInt  newp = vStartNew + (v - vStart);
5506       const PetscInt *support, *cone;
5507       PetscInt        size, s;
5508 
5509       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
5510       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
5511       for (s = 0; s < size; ++s) {
5512         PetscInt r = 0;
5513 
5514         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
5515         if (cone[1] == v) r = 1;
5516         supportRef[s] = eStartNew + (support[s] - eStart)*2 + r;
5517       }
5518       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
5519 #if defined(PETSC_USE_DEBUG)
5520       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", newp, vStartNew, vEndNew);
5521       for (p = 0; p < size; ++p) {
5522         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);
5523       }
5524 #endif
5525     }
5526     /* Edge vertices have 2 + faces supports */
5527     for (e = eStart; e < eEnd; ++e) {
5528       const PetscInt  newp = vStartNew + (vEnd - vStart) + (e - eStart);
5529       const PetscInt *cone, *support;
5530       PetscInt        size, s;
5531 
5532       ierr          = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
5533       ierr          = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
5534       supportRef[0] = eStartNew + (e - eStart)*2 + 0;
5535       supportRef[1] = eStartNew + (e - eStart)*2 + 1;
5536       for (s = 0; s < size; ++s) {
5537         PetscInt r = 0, coneSize;
5538 
5539         ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
5540         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
5541         for (r = 0; r < coneSize; ++r) {if (cone[r] == e) break;}
5542         supportRef[2+s] = eStartNew + (eEnd - eStart)*2 + (support[s] - fStart)*3 + r;
5543       }
5544       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
5545 #if defined(PETSC_USE_DEBUG)
5546       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", newp, vStartNew, vEndNew);
5547       for (p = 0; p < 2+size; ++p) {
5548         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);
5549       }
5550 #endif
5551     }
5552     /* Face vertices have 3 + cells supports */
5553     for (f = fStart; f < fEnd; ++f) {
5554       const PetscInt  newp = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (f - fStart);
5555       const PetscInt *cone, *support;
5556       PetscInt        size, s;
5557 
5558       ierr          = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
5559       ierr          = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
5560       supportRef[0] = eStartNew + (eEnd - eStart)*2 + (f - fStart)*3 + 0;
5561       supportRef[1] = eStartNew + (eEnd - eStart)*2 + (f - fStart)*3 + 1;
5562       supportRef[2] = eStartNew + (eEnd - eStart)*2 + (f - fStart)*3 + 2;
5563       for (s = 0; s < size; ++s) {
5564         PetscInt r = 0, coneSize;
5565 
5566         ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
5567         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
5568         for (r = 0; r < coneSize; ++r) {if (cone[r] == f) break;}
5569         supportRef[3+s] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (support[s] - cStart)*4 + r;
5570       }
5571       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
5572 #if defined(PETSC_USE_DEBUG)
5573       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", newp, vStartNew, vEndNew);
5574       for (p = 0; p < 3+size; ++p) {
5575         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);
5576       }
5577 #endif
5578     }
5579     /* Interior cell vertices have 4 supports */
5580     for (c = cStart; c < cEnd; ++c) {
5581       const PetscInt  newp = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (fEnd - fStart) + c - cStart;
5582       supportRef[0] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + 0;
5583       supportRef[1] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + 1;
5584       supportRef[2] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + 2;
5585       supportRef[3] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + 3;
5586       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
5587 #if defined(PETSC_USE_DEBUG)
5588       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", newp, vStartNew, vEndNew);
5589       for (p = 0; p < 4; ++p) {
5590         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);
5591       }
5592 #endif
5593     }
5594     ierr = PetscFree(supportRef);CHKERRQ(ierr);
5595     ierr = DMPlexRestoreFaces_Internal(dm, cStart, NULL, NULL, &faces);CHKERRQ(ierr);
5596     break;
5597   case REFINER_HYBRID_SIMPLEX_TO_HEX_3D:
5598     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
5599     cMax = PetscMin(cEnd, cMax);
5600     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
5601     fMax = PetscMin(fEnd, fMax);
5602     if (eMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
5603     eMax = PetscMin(eEnd, eMax);
5604     ierr = DMPlexGetRawFaces_Internal(dm, DM_POLYTOPE_TETRAHEDRON, cellInd, NULL, NULL, &faces);CHKERRQ(ierr);
5605     /* All cells have 6 faces */
5606     for (c = cStart; c < cMax; ++c) {
5607       const PetscInt  newp = cStartNew + (c - cStart)*4;
5608       const PetscInt *cone, *ornt;
5609       PetscInt        coneNew[6];
5610       PetscInt        orntNew[6];
5611 
5612       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
5613 #if defined(PETSC_USE_DEBUG)
5614       for (p = 0; p < 4; ++p) {
5615         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);
5616       }
5617 #endif
5618       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
5619       /* A hex */
5620       coneNew[0] = fStartNew + (cone[0] - fStart)*3 + GetTriSubface_Static(ornt[0], 0); /* B */
5621       orntNew[0] = ornt[0] < 0 ? -1 : 1;
5622       coneNew[1] = fStartNew + (fMax    - fStart)*3 + (c - cStart)*6 + 3;               /* T */
5623       orntNew[1] = -4;
5624       coneNew[2] = fStartNew + (cone[2] - fStart)*3 + GetTriSubface_Static(ornt[2], 0); /* F */
5625       orntNew[2] = ornt[2] < 0 ? -1 : 1;
5626       coneNew[3] = fStartNew + (fMax    - fStart)*3 + (c - cStart)*6 + 0;               /* K */
5627       orntNew[3] = -1;
5628       coneNew[4] = fStartNew + (fMax    - fStart)*3 + (c - cStart)*6 + 2;               /* R */
5629       orntNew[4] = 0;
5630       coneNew[5] = fStartNew + (cone[1] - fStart)*3 + GetTriSubface_Static(ornt[1], 0); /* L */
5631       orntNew[5] = ornt[1] < 0 ? -1 : 1;
5632       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
5633       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
5634 #if defined(PETSC_USE_DEBUG)
5635       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);
5636       for (p = 0; p < 6; ++p) {
5637         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);
5638       }
5639 #endif
5640       /* B hex */
5641       coneNew[0] = fStartNew + (cone[0] - fStart)*3 + GetTriSubface_Static(ornt[0], 1); /* B */
5642       orntNew[0] = ornt[0] < 0 ? -2 : 0;
5643       coneNew[1] = fStartNew + (fMax    - fStart)*3 + (c - cStart)*6 + 4;               /* T */
5644       orntNew[1] = 0;
5645       coneNew[2] = fStartNew + (fMax    - fStart)*3 + (c - cStart)*6 + 0;               /* F */
5646       orntNew[2] = 0;
5647       coneNew[3] = fStartNew + (cone[3] - fStart)*3 + GetTriSubface_Static(ornt[3], 1); /* K */
5648       orntNew[3] = ornt[3] < 0 ? -2 : 0;
5649       coneNew[4] = fStartNew + (fMax    - fStart)*3 + (c - cStart)*6 + 1;               /* R */
5650       orntNew[4] = 0;
5651       coneNew[5] = fStartNew + (cone[1] - fStart)*3 + GetTriSubface_Static(ornt[1], 2); /* L */
5652       orntNew[5] = ornt[1] < 0 ? -4 : 2;
5653       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
5654       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
5655 #if defined(PETSC_USE_DEBUG)
5656       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);
5657       for (p = 0; p < 6; ++p) {
5658         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);
5659       }
5660 #endif
5661       /* C hex */
5662       coneNew[0] = fStartNew + (cone[0] - fStart)*3 + GetTriSubface_Static(ornt[0], 2); /* B */
5663       orntNew[0] = ornt[0] < 0 ? -4 : 2;
5664       coneNew[1] = fStartNew + (fMax    - fStart)*3 + (c - cStart)*6 + 5;               /* T */
5665       orntNew[1] = -4;
5666       coneNew[2] = fStartNew + (cone[2] - fStart)*3 + GetTriSubface_Static(ornt[2], 1); /* F */
5667       orntNew[2] = ornt[2] < 0 ? -2 : 0;
5668       coneNew[3] = fStartNew + (fMax    - fStart)*3 + (c - cStart)*6 + 1;               /* K */
5669       orntNew[3] = -1;
5670       coneNew[4] = fStartNew + (cone[3] - fStart)*3 + GetTriSubface_Static(ornt[3], 0); /* R */
5671       orntNew[4] = ornt[3] < 0 ? -1 : 1;
5672       coneNew[5] = fStartNew + (fMax    - fStart)*3 + (c - cStart)*6 + 2;               /* L */
5673       orntNew[5] = -4;
5674       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
5675       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
5676 #if defined(PETSC_USE_DEBUG)
5677       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);
5678       for (p = 0; p < 6; ++p) {
5679         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);
5680       }
5681 #endif
5682       /* D hex */
5683       coneNew[0] = fStartNew + (fMax    - fStart)*3 + (c - cStart)*6 + 3;               /* B */
5684       orntNew[0] = 0;
5685       coneNew[1] = fStartNew + (cone[3] - fStart)*3 + GetTriSubface_Static(ornt[3], 2); /* T */
5686       orntNew[1] = ornt[3] < 0 ? -1 : 1;
5687       coneNew[2] = fStartNew + (cone[2] - fStart)*3 + GetTriSubface_Static(ornt[2], 2); /* F */
5688       orntNew[2] = ornt[2] < 0 ? -4 : 2;
5689       coneNew[3] = fStartNew + (fMax    - fStart)*3 + (c - cStart)*6 + 4;               /* K */
5690       orntNew[3] = -1;
5691       coneNew[4] = fStartNew + (fMax    - fStart)*3 + (c - cStart)*6 + 5;               /* R */
5692       orntNew[4] = 0;
5693       coneNew[5] = fStartNew + (cone[1] - fStart)*3 + GetTriSubface_Static(ornt[1], 1); /* L */
5694       orntNew[5] = ornt[1] < 0 ? -2 : 0;
5695       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
5696       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
5697 #if defined(PETSC_USE_DEBUG)
5698       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);
5699       for (p = 0; p < 6; ++p) {
5700         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);
5701       }
5702 #endif
5703     }
5704     for (c = cMax; c < cEnd; ++c) {
5705       const PetscInt  newp = cStartNew + (cMax - cStart)*4 + (c - cMax)*3;
5706       const PetscInt *cone, *ornt;
5707       PetscInt        coneNew[6], orntNew[6];
5708       PetscInt        o, of, cf;
5709 
5710       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
5711 #if defined(PETSC_USE_DEBUG)
5712       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);
5713       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);
5714       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);
5715       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);
5716       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);
5717 #endif
5718       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
5719       o    = ornt[0] < 0 ? -1 : 1;
5720       o    = 1;
5721       /* A hex */
5722       coneNew[0] = fStartNew + (cone[0] - fStart)*3 + GetTriSubface_Static(ornt[0], 0);                            /* B */
5723       orntNew[0] = ornt[0] < 0 ? -1 :  1;
5724       coneNew[1] = fStartNew + (cone[1] - fStart)*3 + GetTriSubface_Static(ornt[1], 0);                            /* T */
5725       orntNew[1] = ornt[1] < 0 ?  1 : -1;
5726       cf         = 2;
5727       of         = ornt[2+cf] < 0 ? -1 : 1;
5728       coneNew[2] = fStartNew + (fMax - fStart)*3 + (cMax - cStart)*6 + (cone[2+cf] - fMax)*2 + (o*of < 0 ? 0 : 1); /* F */
5729       orntNew[2] = o*of < 0 ? 0 : -1;
5730       coneNew[3] = fStartNew + (fMax - fStart)*3 + (cMax - cStart)*6 + (fEnd - fMax)*2 + (c - cMax)*3 + 0;         /* K */
5731       orntNew[3] = -1;
5732       coneNew[4] = fStartNew + (fMax - fStart)*3 + (cMax - cStart)*6 + (fEnd - fMax)*2 + (c - cMax)*3 + 2;         /* R */
5733       orntNew[4] = 0;
5734       cf         = 0;
5735       of         = ornt[2+cf] < 0 ? -1 : 1;
5736       coneNew[5] = fStartNew + (fMax - fStart)*3 + (cMax - cStart)*6 + (cone[2+cf] - fMax)*2 + (o*of < 0 ? 1 : 0); /* L */
5737       orntNew[5] = o*of < 0 ? 1 : -4;
5738       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
5739       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
5740 #if defined(PETSC_USE_DEBUG)
5741       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);
5742       for (p = 0; p < 6; ++p) {
5743         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);
5744       }
5745 #endif
5746       /* B hex */
5747       coneNew[0] = fStartNew + (cone[0] - fStart)*3 + GetTriSubface_Static(ornt[0], 1);                            /* B */
5748       orntNew[0] = ornt[0] < 0 ? -2 :  0;
5749       coneNew[1] = fStartNew + (cone[1] - fStart)*3 + GetTriSubface_Static(ornt[1], 1);                            /* T */
5750       orntNew[1] = ornt[1] < 0 ?  2 : -4;
5751       coneNew[2] = fStartNew + (fMax - fStart)*3 + (cMax - cStart)*6 + (fEnd - fMax)*2 + (c - cMax)*3 + 0;         /* F */
5752       orntNew[2] = 0;
5753       cf         = 1;
5754       of         = ornt[2+cf] < 0 ? -1 : 1;
5755       coneNew[3] = fStartNew + (fMax - fStart)*3 + (cMax - cStart)*6 + (cone[2+cf] - fMax)*2 + (o*of < 0 ? 1 : 0); /* K */
5756       orntNew[3] = o*of < 0 ? 0 : -1;
5757       coneNew[4] = fStartNew + (fMax - fStart)*3 + (cMax - cStart)*6 + (fEnd - fMax)*2 + (c - cMax)*3 + 1;         /* R */
5758       orntNew[4] = -1;
5759       cf         = 0;
5760       of         = ornt[2+cf] < 0 ? -1 : 1;
5761       coneNew[5] = fStartNew + (fMax - fStart)*3 + (cMax - cStart)*6 + (cone[2+cf] - fMax)*2 + (o*of < 0 ? 0 : 1); /* L */
5762       orntNew[5] = o*of < 0 ? 1 : -4;
5763       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
5764       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
5765 #if defined(PETSC_USE_DEBUG)
5766       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);
5767       for (p = 0; p < 6; ++p) {
5768         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);
5769       }
5770 #endif
5771       /* C hex */
5772       coneNew[0] = fStartNew + (cone[0] - fStart)*3 + GetTriSubface_Static(ornt[0], 2);                            /* B */
5773       orntNew[0] = ornt[0] < 0 ? -4 : 2;
5774       coneNew[1] = fStartNew + (cone[1] - fStart)*3 + GetTriSubface_Static(ornt[1], 2);                            /* T */
5775       orntNew[1] = ornt[1] < 0 ? 0 : -2;
5776       cf         = 2;
5777       of         = ornt[2+cf] < 0 ? -1 : 1;
5778       coneNew[2] = fStartNew + (fMax - fStart)*3 + (cMax - cStart)*6 + (cone[2+cf] - fMax)*2 + (o*of < 0 ? 1 : 0); /* F */
5779       orntNew[2] = o*of < 0 ? 0 : -1;
5780       coneNew[3] = fStartNew + (fMax - fStart)*3 + (cMax - cStart)*6 + (fEnd - fMax)*2 + (c - cMax)*3 + 1;         /* K */
5781       orntNew[3] = 0;
5782       cf         = 1;
5783       of         = ornt[2+cf] < 0 ? -1 : 1;
5784       coneNew[4] = fStartNew + (fMax - fStart)*3 + (cMax - cStart)*6 + (cone[2+cf] - fMax)*2 + (o*of < 0 ? 0 : 1); /* R */
5785       orntNew[4] = o*of < 0 ? 0 : -1;
5786       coneNew[5] = fStartNew + (fMax - fStart)*3 + (cMax - cStart)*6 + (fEnd - fMax)*2 + (c - cMax)*3 + 2;         /* L */
5787       orntNew[5] = -4;
5788       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
5789       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
5790 #if defined(PETSC_USE_DEBUG)
5791       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);
5792       for (p = 0; p < 6; ++p) {
5793         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);
5794       }
5795 #endif
5796     }
5797 
5798     /* Split faces have 4 edges and the same cells as the parent */
5799     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
5800     ierr = PetscMalloc1(2 + maxSupportSize*2, &supportRef);CHKERRQ(ierr);
5801     for (f = fStart; f < fMax; ++f) {
5802       const PetscInt  newp = fStartNew + (f - fStart)*3;
5803       const PetscInt *cone, *ornt, *support;
5804       PetscInt        coneNew[4], orntNew[4], coneSize, supportSize, s;
5805 
5806       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
5807 #if defined(PETSC_USE_DEBUG)
5808       for (p = 0; p < 3; ++p) {
5809         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);
5810       }
5811 #endif
5812       ierr = DMPlexGetConeOrientation(dm, f, &ornt);CHKERRQ(ierr);
5813       /* A quad */
5814       coneNew[0] = eStartNew + (cone[2] - eStart)*2 + (ornt[2] < 0 ? 0 : 1);
5815       orntNew[0] = ornt[2];
5816       coneNew[1] = eStartNew + (cone[0] - eStart)*2 + (ornt[0] < 0 ? 1 : 0);
5817       orntNew[1] = ornt[0];
5818       coneNew[2] = eStartNew + (eMax    - eStart)*2 + (f - fStart)*3 + 0;
5819       orntNew[2] = 0;
5820       coneNew[3] = eStartNew + (eMax    - eStart)*2 + (f - fStart)*3 + 2;
5821       orntNew[3] = -2;
5822       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
5823       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
5824 #if defined(PETSC_USE_DEBUG)
5825       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);
5826       for (p = 0; p < 4; ++p) {
5827         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);
5828       }
5829 #endif
5830       /* B quad */
5831       coneNew[0] = eStartNew + (cone[0] - eStart)*2 + (ornt[0] < 0 ? 0 : 1);
5832       orntNew[0] = ornt[0];
5833       coneNew[1] = eStartNew + (cone[1] - eStart)*2 + (ornt[1] < 0 ? 1 : 0);
5834       orntNew[1] = ornt[1];
5835       coneNew[2] = eStartNew + (eMax    - eStart)*2 + (f - fStart)*3 + 1;
5836       orntNew[2] = 0;
5837       coneNew[3] = eStartNew + (eMax    - eStart)*2 + (f - fStart)*3 + 0;
5838       orntNew[3] = -2;
5839       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
5840       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
5841 #if defined(PETSC_USE_DEBUG)
5842       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);
5843       for (p = 0; p < 4; ++p) {
5844         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);
5845       }
5846 #endif
5847       /* C quad */
5848       coneNew[0] = eStartNew + (cone[1] - eStart)*2 + (ornt[1] < 0 ? 0 : 1);
5849       orntNew[0] = ornt[1];
5850       coneNew[1] = eStartNew + (cone[2] - eStart)*2 + (ornt[2] < 0 ? 1 : 0);
5851       orntNew[1] = ornt[2];
5852       coneNew[2] = eStartNew + (eMax    - eStart)*2 + (f - fStart)*3 + 2;
5853       orntNew[2] = 0;
5854       coneNew[3] = eStartNew + (eMax    - eStart)*2 + (f - fStart)*3 + 1;
5855       orntNew[3] = -2;
5856       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
5857       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
5858 #if defined(PETSC_USE_DEBUG)
5859       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);
5860       for (p = 0; p < 4; ++p) {
5861         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);
5862       }
5863 #endif
5864       ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
5865       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
5866       for (r = 0; r < 3; ++r) {
5867         for (s = 0; s < supportSize; ++s) {
5868           PetscInt subf;
5869 
5870           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
5871           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);
5872           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);
5873           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
5874           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
5875           for (c = 0; c < coneSize; ++c) {
5876             if (cone[c] == f) break;
5877           }
5878           subf = GetTriSubfaceInverse_Static(ornt[c], r);
5879           if (coneSize == 4) {
5880             supportRef[s] = cStartNew + (support[s] - cStart)*4 + faces[c*3+subf];
5881           } else if (coneSize == 5) {
5882             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);
5883             supportRef[s] = cStartNew + (cMax - cStart)*4 + (support[s] - cMax)*3 + subf;
5884           } else SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected conesize %D for cell %D (cMax %D)", coneSize, support[s], cMax);
5885         }
5886         ierr = DMPlexSetSupport(rdm, newp+r, supportRef);CHKERRQ(ierr);
5887 #if defined(PETSC_USE_DEBUG)
5888         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);
5889         for (p = 0; p < supportSize; ++p) {
5890           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);
5891         }
5892 #endif
5893       }
5894     }
5895     /* Interior faces have 4 edges and 2 cells */
5896     for (c = cStart; c < cMax; ++c) {
5897       PetscInt        newp = fStartNew + (fMax - fStart)*3 + (c - cStart)*6;
5898       const PetscInt *cone, *ornt;
5899       PetscInt        coneNew[4], orntNew[4];
5900       PetscInt        supportNew[2];
5901 
5902       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
5903 #if defined(PETSC_USE_DEBUG)
5904       for (p = 0; p < 4; ++p) {
5905         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);
5906       }
5907 #endif
5908       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
5909       /* Face {a, g, m, h} */
5910       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*3 + GetTriInteriorEdge_Static(ornt[0],0);
5911       orntNew[0] = 0;
5912       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart)*4 + 0;
5913       orntNew[1] = 0;
5914       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart)*4 + 1;
5915       orntNew[2] = -2;
5916       coneNew[3] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*3 + GetTriInteriorEdge_Static(ornt[1],2);
5917       orntNew[3] = -2;
5918       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5919       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
5920 #if defined(PETSC_USE_DEBUG)
5921       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
5922       for (p = 0; p < 4; ++p) {
5923         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);
5924       }
5925 #endif
5926       supportNew[0] = cStartNew + (c - cStart)*4 + 0;
5927       supportNew[1] = cStartNew + (c - cStart)*4 + 1;
5928       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
5929 #if defined(PETSC_USE_DEBUG)
5930       for (p = 0; p < 2; ++p) {
5931         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);
5932       }
5933 #endif
5934       ++newp;
5935       /* Face {g, b, l , m} */
5936       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*3 + GetTriInteriorEdge_Static(ornt[0],1);
5937       orntNew[0] = -2;
5938       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*3 + GetTriInteriorEdge_Static(ornt[3],0);
5939       orntNew[1] = 0;
5940       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart)*4 + 3;
5941       orntNew[2] = 0;
5942       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart)*4 + 0;
5943       orntNew[3] = -2;
5944       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5945       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
5946 #if defined(PETSC_USE_DEBUG)
5947       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
5948       for (p = 0; p < 4; ++p) {
5949         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);
5950       }
5951 #endif
5952       supportNew[0] = cStartNew + (c - cStart)*4 + 1;
5953       supportNew[1] = cStartNew + (c - cStart)*4 + 2;
5954       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
5955 #if defined(PETSC_USE_DEBUG)
5956       for (p = 0; p < 2; ++p) {
5957         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);
5958       }
5959 #endif
5960       ++newp;
5961       /* Face {c, g, m, i} */
5962       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*3 + GetTriInteriorEdge_Static(ornt[0],2);
5963       orntNew[0] = 0;
5964       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart)*4 + 0;
5965       orntNew[1] = 0;
5966       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart)*4 + 2;
5967       orntNew[2] = -2;
5968       coneNew[3] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*3 + GetTriInteriorEdge_Static(ornt[2],0);
5969       orntNew[3] = -2;
5970       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5971       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
5972 #if defined(PETSC_USE_DEBUG)
5973       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
5974       for (p = 0; p < 4; ++p) {
5975         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);
5976       }
5977 #endif
5978       supportNew[0] = cStartNew + (c - cStart)*4 + 0;
5979       supportNew[1] = cStartNew + (c - cStart)*4 + 2;
5980       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
5981 #if defined(PETSC_USE_DEBUG)
5982       for (p = 0; p < 2; ++p) {
5983         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);
5984       }
5985 #endif
5986       ++newp;
5987       /* Face {d, h, m, i} */
5988       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*3 + GetTriInteriorEdge_Static(ornt[1],0);
5989       orntNew[0] = 0;
5990       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart)*4 + 1;
5991       orntNew[1] = 0;
5992       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart)*4 + 2;
5993       orntNew[2] = -2;
5994       coneNew[3] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*3 + GetTriInteriorEdge_Static(ornt[2],2);
5995       orntNew[3] = -2;
5996       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5997       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
5998 #if defined(PETSC_USE_DEBUG)
5999       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
6000       for (p = 0; p < 4; ++p) {
6001         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);
6002       }
6003 #endif
6004       supportNew[0] = cStartNew + (c - cStart)*4 + 0;
6005       supportNew[1] = cStartNew + (c - cStart)*4 + 3;
6006       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
6007 #if defined(PETSC_USE_DEBUG)
6008       for (p = 0; p < 2; ++p) {
6009         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);
6010       }
6011 #endif
6012       ++newp;
6013       /* Face {h, m, l, e} */
6014       coneNew[0] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart)*4 + 1;
6015       orntNew[0] = 0;
6016       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart)*4 + 3;
6017       orntNew[1] = -2;
6018       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*3 + GetTriInteriorEdge_Static(ornt[3],1);
6019       orntNew[2] = -2;
6020       coneNew[3] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*3 + GetTriInteriorEdge_Static(ornt[1],1);
6021       orntNew[3] = 0;
6022       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6023       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
6024 #if defined(PETSC_USE_DEBUG)
6025       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
6026       for (p = 0; p < 4; ++p) {
6027         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);
6028       }
6029 #endif
6030       supportNew[0] = cStartNew + (c - cStart)*4 + 1;
6031       supportNew[1] = cStartNew + (c - cStart)*4 + 3;
6032       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
6033 #if defined(PETSC_USE_DEBUG)
6034       for (p = 0; p < 2; ++p) {
6035         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);
6036       }
6037 #endif
6038       ++newp;
6039       /* Face {i, m, l, f} */
6040       coneNew[0] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart)*4 + 2;
6041       orntNew[0] = 0;
6042       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart)*4 + 3;
6043       orntNew[1] = -2;
6044       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*3 + GetTriInteriorEdge_Static(ornt[3],2);
6045       orntNew[2] = -2;
6046       coneNew[3] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*3 + GetTriInteriorEdge_Static(ornt[2],1);
6047       orntNew[3] = 0;
6048       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6049       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
6050 #if defined(PETSC_USE_DEBUG)
6051       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
6052       for (p = 0; p < 4; ++p) {
6053         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);
6054       }
6055 #endif
6056       supportNew[0] = cStartNew + (c - cStart)*4 + 2;
6057       supportNew[1] = cStartNew + (c - cStart)*4 + 3;
6058       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
6059 #if defined(PETSC_USE_DEBUG)
6060       for (p = 0; p < 2; ++p) {
6061         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);
6062       }
6063 #endif
6064       ++newp;
6065     }
6066     /* Hybrid split faces have 4 edges and same cells */
6067     for (f = fMax; f < fEnd; ++f) {
6068       const PetscInt *cone, *ornt, *support;
6069       PetscInt        coneNew[4], orntNew[4];
6070       PetscInt        size, s;
6071       const PetscInt  newp = fStartNew + (fMax - fStart)*3 + (cMax - cStart)*6 + (f - fMax)*2;
6072 
6073       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
6074 #if defined(PETSC_USE_DEBUG)
6075       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);
6076       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);
6077       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);
6078       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);
6079 #endif
6080       ierr = DMPlexGetConeOrientation(dm, f, &ornt);CHKERRQ(ierr);
6081       /* A face */
6082       coneNew[0] = eStartNew + (cone[0] - eStart)*2 + (ornt[0] < 0 ? 1 : 0);
6083       orntNew[0] = ornt[0];
6084       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart)*4 + (eEnd - eMax) + (f - fMax);
6085       orntNew[1] = 0;
6086       coneNew[2] = eStartNew + (cone[1] - eStart)*2 + (ornt[1] < 0 ? 1 : 0);
6087       orntNew[2] = ornt[1] < 0 ? 0 : -2;
6088       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart)*4 + (cone[2] - eMax);
6089       orntNew[3] = ornt[2] < 0 ? 0 : -2;
6090       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6091       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
6092 #if defined(PETSC_USE_DEBUG)
6093       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
6094       for (p = 0; p < 4; ++p) {
6095         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);
6096       }
6097 #endif
6098 
6099       /* B face */
6100       coneNew[0] = eStartNew + (cone[0] - eStart)*2 + (ornt[0] < 0 ? 0 : 1);
6101       orntNew[0] = ornt[0];
6102       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart)*4 + (cone[3] - eMax);
6103       orntNew[1] = ornt[3];
6104       coneNew[2] = eStartNew + (cone[1] - eStart)*2 + (ornt[1] < 0 ? 0 : 1);
6105       orntNew[2] = ornt[1] < 0 ? 0 : -2;
6106       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart)*4 + (eEnd - eMax) + (f - fMax);
6107       orntNew[3] = -2;
6108       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
6109       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
6110 #if defined(PETSC_USE_DEBUG)
6111       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);
6112       for (p = 0; p < 4; ++p) {
6113         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);
6114       }
6115 #endif
6116 
6117       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
6118       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
6119       for (r = 0; r < 2; ++r) {
6120         for (s = 0; s < size; ++s) {
6121           const PetscInt *coneCell, *orntCell;
6122           PetscInt        coneSize, o, of, c;
6123 
6124           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
6125           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);
6126           ierr = DMPlexGetCone(dm, support[s], &coneCell);CHKERRQ(ierr);
6127           ierr = DMPlexGetConeOrientation(dm, support[s], &orntCell);CHKERRQ(ierr);
6128           o = orntCell[0] < 0 ? -1 : 1;
6129           o = 1;
6130           for (c = 0; c < coneSize; ++c) if (coneCell[c] == f) break;
6131           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);
6132           if (c == coneSize) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Could not find face %D in cone of cell %D", f, support[s]);
6133           of = orntCell[c] < 0 ? -1 : 1;
6134           supportRef[s] = cStartNew + (cMax - cStart)*4 + (support[s] - cMax)*3 + (c-2 + (o*of < 0 ? 1-r : r))%3;
6135         }
6136         ierr = DMPlexSetSupport(rdm, newp + r, supportRef);CHKERRQ(ierr);
6137 #if defined(PETSC_USE_DEBUG)
6138         for (p = 0; p < size; ++p) {
6139           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);
6140         }
6141 #endif
6142       }
6143     }
6144     /* Interior hybrid faces have 4 edges and 2 cells */
6145     for (c = cMax; c < cEnd; ++c) {
6146       PetscInt        newp = fStartNew + (fMax - fStart)*3 + (cMax - cStart)*6 + (fEnd - fMax)*2 + (c - cMax)*3;
6147       const PetscInt *cone, *ornt;
6148       PetscInt        coneNew[4], orntNew[4];
6149       PetscInt        supportNew[2];
6150 
6151       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
6152 #if defined(PETSC_USE_DEBUG)
6153       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);
6154       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);
6155       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);
6156       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);
6157       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);
6158 #endif
6159       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
6160       /* Face {a, g, h, d} */
6161       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*3 + GetTriInteriorEdge_Static(ornt[0],0);
6162       orntNew[0] = 0;
6163       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart)*4 + (eEnd - eMax) + (fEnd - fMax) + c - cMax;
6164       orntNew[1] = 0;
6165       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*3 + GetTriInteriorEdge_Static(ornt[1],0);
6166       orntNew[2] = -2;
6167       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart)*4 + (eEnd - eMax) + (cone[2] - fMax);
6168       orntNew[3] = -2;
6169       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6170       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
6171 #if defined(PETSC_USE_DEBUG)
6172       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
6173       for (p = 0; p < 4; ++p) {
6174         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);
6175       }
6176 #endif
6177       supportNew[0] = cStartNew + (cMax - cStart)*4 + (c - cMax)*3 + 0;
6178       supportNew[1] = cStartNew + (cMax - cStart)*4 + (c - cMax)*3 + 1;
6179       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
6180 #if defined(PETSC_USE_DEBUG)
6181       for (p = 0; p < 2; ++p) {
6182         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);
6183       }
6184 #endif
6185       ++newp;
6186       /* Face {b, g, h, l} */
6187       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*3 + GetTriInteriorEdge_Static(ornt[0],1);
6188       orntNew[0] = 0;
6189       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart)*4 + (eEnd - eMax) + (fEnd - fMax) + c - cMax;
6190       orntNew[1] = 0;
6191       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*3 + GetTriInteriorEdge_Static(ornt[1],1);
6192       orntNew[2] = -2;
6193       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart)*4 + (eEnd - eMax) + (cone[3] - fMax);
6194       orntNew[3] = -2;
6195       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6196       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
6197 #if defined(PETSC_USE_DEBUG)
6198       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
6199       for (p = 0; p < 4; ++p) {
6200         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);
6201       }
6202 #endif
6203       supportNew[0] = cStartNew + (cMax - cStart)*4 + (c - cMax)*3 + 1;
6204       supportNew[1] = cStartNew + (cMax - cStart)*4 + (c - cMax)*3 + 2;
6205       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
6206 #if defined(PETSC_USE_DEBUG)
6207       for (p = 0; p < 2; ++p) {
6208         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);
6209       }
6210 #endif
6211       ++newp;
6212       /* Face {c, g, h, f} */
6213       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*3 + GetTriInteriorEdge_Static(ornt[0],2);
6214       orntNew[0] = 0;
6215       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart)*4 + (eEnd - eMax) + (fEnd - fMax) + c - cMax;
6216       orntNew[1] = 0;
6217       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*3 + GetTriInteriorEdge_Static(ornt[1],2);
6218       orntNew[2] = -2;
6219       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart)*4 + (eEnd - eMax) + (cone[4] - fMax);
6220       orntNew[3] = -2;
6221       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6222       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
6223 #if defined(PETSC_USE_DEBUG)
6224       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
6225       for (p = 0; p < 4; ++p) {
6226         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);
6227       }
6228 #endif
6229       supportNew[0] = cStartNew + (cMax - cStart)*4 + (c - cMax)*3 + 2;
6230       supportNew[1] = cStartNew + (cMax - cStart)*4 + (c - cMax)*3 + 0;
6231       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
6232 #if defined(PETSC_USE_DEBUG)
6233       for (p = 0; p < 2; ++p) {
6234         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);
6235       }
6236 #endif
6237     }
6238     /* Face edges have 2 vertices and 2 + cell faces supports */
6239     for (f = fStart; f < fMax; ++f) {
6240       const PetscInt *cone, *ornt, *support;
6241       PetscInt        coneSize, supportSize, s;
6242 
6243       ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
6244       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
6245       for (r = 0; r < 3; ++r) {
6246         const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (f - fStart)*3 + r;
6247         PetscInt        coneNew[2];
6248         PetscInt        fint[4][3] = { {0, 1, 2},
6249                                        {3, 4, 0},
6250                                        {2, 5, 3},
6251                                        {1, 4, 5} };
6252 
6253         ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
6254         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);
6255         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r] - eStart);
6256         coneNew[1] = vStartNew + (vEnd - vStart) + (eMax - eStart) + f - fStart;
6257         ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6258 #if defined(PETSC_USE_DEBUG)
6259         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eEndNew);
6260         for (p = 0; p < 2; ++p) {
6261           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);
6262         }
6263 #endif
6264         supportRef[0] = fStartNew + (f - fStart)*3 + (r+0)%3;
6265         supportRef[1] = fStartNew + (f - fStart)*3 + (r+1)%3;
6266         for (s = 0; s < supportSize; ++s) {
6267           PetscInt er;
6268 
6269           supportRef[2+s] = -1;
6270           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
6271           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);
6272           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);
6273           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6274           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
6275           for (c = 0; c < coneSize; ++c) {if (cone[c] == f) break;}
6276           er = GetTriInteriorEdgeInverse_Static(ornt[c], r);
6277           if (coneSize == 4) {
6278             supportRef[2+s] = fStartNew + (fMax - fStart)*3 + (support[s] - cStart)*6 + fint[c][er];
6279           } else if (coneSize == 5) {
6280             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);
6281             supportRef[2+s] = fStartNew + (fMax - fStart)*3 + (cMax - cStart)*6 + (fEnd - fMax)*2 + (support[s] - cMax)*3 + er;
6282           }
6283         }
6284         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6285 #if defined(PETSC_USE_DEBUG)
6286         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eEndNew);
6287         for (p = 0; p < supportSize + 2; ++p) {
6288           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);
6289         }
6290 #endif
6291       }
6292     }
6293     /* Interior cell edges have 2 vertices and 3 faces */
6294     for (c = cStart; c < cMax; ++c) {
6295       const PetscInt *cone;
6296       PetscInt       fint[4][3] = { {0,1,2},
6297                                     {0,3,4},
6298                                     {2,3,5},
6299                                     {1,4,5} } ;
6300 
6301       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
6302       for (r = 0; r < 4; r++) {
6303         PetscInt       coneNew[2], supportNew[3];
6304         const PetscInt newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart)*4 + r;
6305 
6306         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);
6307         coneNew[0] = vStartNew + (vEnd - vStart) + (eMax - eStart) + (cone[r] - fStart);
6308         coneNew[1] = vStartNew + (vEnd - vStart) + (eMax - eStart) + (fMax     -fStart) + c - cStart;
6309         ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6310 #if defined(PETSC_USE_DEBUG)
6311         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eEndNew);
6312         for (p = 0; p < 2; ++p) {
6313           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);
6314         }
6315 #endif
6316         supportNew[0] = fStartNew + (fMax - fStart)*3 + (c - cStart)*6 + fint[r][0];
6317         supportNew[1] = fStartNew + (fMax - fStart)*3 + (c - cStart)*6 + fint[r][1];
6318         supportNew[2] = fStartNew + (fMax - fStart)*3 + (c - cStart)*6 + fint[r][2];
6319         ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
6320 #if defined(PETSC_USE_DEBUG)
6321         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eEndNew);
6322         for (p = 0; p < 3; ++p) {
6323           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);
6324         }
6325 #endif
6326       }
6327     }
6328     /* Hybrid edges have two vertices and the same faces */
6329     for (e = eMax; e < eEnd; ++e) {
6330       const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart)*4 + (e - eMax);
6331       const PetscInt *cone, *support, *fcone;
6332       PetscInt        coneNew[2], size, fsize, s;
6333 
6334       ierr = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
6335       ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
6336       ierr = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
6337       coneNew[0] = vStartNew + (cone[0] - vStart);
6338       coneNew[1] = vStartNew + (cone[1] - vStart);
6339       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6340 #if defined(PETSC_USE_DEBUG)
6341       if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is a edge [%D, %D)", newp, eStartNew, eEndNew);
6342       for (p = 0; p < 2; ++p) {
6343         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);
6344       }
6345 #endif
6346       for (s = 0; s < size; ++s) {
6347         ierr = DMPlexGetConeSize(dm, support[s], &fsize);CHKERRQ(ierr);
6348         ierr = DMPlexGetCone(dm, support[s], &fcone);CHKERRQ(ierr);
6349         for (c = 0; c < fsize; ++c) if (fcone[c] == e) break;
6350         if ((c < 2) || (c > 3)) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Edge %D not found in cone of face %D", e, support[s]);
6351         supportRef[s] = fStartNew + (fMax - fStart)*3 + (cMax - cStart)*6 + (support[s] - fMax)*2 + c-2;
6352       }
6353       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6354 #if defined(PETSC_USE_DEBUG)
6355       for (p = 0; p < size; ++p) {
6356         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);
6357       }
6358 #endif
6359     }
6360     /* Hybrid face edges have 2 vertices and 2 + cell faces supports */
6361     for (f = fMax; f < fEnd; ++f) {
6362       const PetscInt *cone, *ornt, *support;
6363       PetscInt        coneSize, supportSize;
6364       const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart)*4 + (eEnd - eMax) + f - fMax;
6365       PetscInt        coneNew[2], s;
6366 
6367       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
6368 #if defined(PETSC_USE_DEBUG)
6369       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);
6370       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);
6371 #endif
6372       coneNew[0] = vStartNew + (vEnd - vStart) + (cone[0] - eStart);
6373       coneNew[1] = vStartNew + (vEnd - vStart) + (cone[1] - eStart);
6374       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6375 #if defined(PETSC_USE_DEBUG)
6376       if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eEndNew);
6377       for (p = 0; p < 2; ++p) {
6378         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);
6379       }
6380 #endif
6381       supportRef[0] = fStartNew + (fMax - fStart)*3 + (cMax - cStart)*6 + (f- fMax)*2 + 0;
6382       supportRef[1] = fStartNew + (fMax - fStart)*3 + (cMax - cStart)*6 + (f- fMax)*2 + 1;
6383       ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
6384       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
6385       for (s = 0; s < supportSize; ++s) {
6386         ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
6387         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);
6388         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6389         ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
6390         for (c = 0; c < coneSize; ++c) {if (cone[c] == f) break;}
6391         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);
6392         supportRef[2+s] = fStartNew + (fMax - fStart)*3 + (cMax - cStart)*6 + (fEnd - fMax)*2 + (support[s] - cMax)*3 + c - 2;
6393       }
6394       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6395 #if defined(PETSC_USE_DEBUG)
6396       if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eEndNew);
6397       for (p = 0; p < supportSize + 2; ++p) {
6398         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);
6399       }
6400 #endif
6401     }
6402     /* Hybrid cell edges have 2 vertices and 3 faces */
6403     for (c = cMax; c < cEnd; ++c) {
6404       PetscInt       coneNew[2], supportNew[3];
6405       const PetscInt newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart)*4 + (eEnd - eMax) + (fEnd - fMax) + c - cMax;
6406       const PetscInt *cone;
6407 
6408       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
6409 #if defined(PETSC_USE_DEBUG)
6410       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);
6411       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);
6412 #endif
6413       coneNew[0] = vStartNew + (vEnd - vStart) + (eMax - eStart) + (cone[0] - fStart);
6414       coneNew[1] = vStartNew + (vEnd - vStart) + (eMax - eStart) + (cone[1] - fStart);
6415       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6416 #if defined(PETSC_USE_DEBUG)
6417       if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eEndNew);
6418       for (p = 0; p < 2; ++p) {
6419         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);
6420       }
6421 #endif
6422       supportNew[0] = fStartNew + (fMax - fStart)*3 + (cMax - cStart)*6 + (fEnd - fMax)*2 + (c - cMax)*3 + 0;
6423       supportNew[1] = fStartNew + (fMax - fStart)*3 + (cMax - cStart)*6 + (fEnd - fMax)*2 + (c - cMax)*3 + 1;
6424       supportNew[2] = fStartNew + (fMax - fStart)*3 + (cMax - cStart)*6 + (fEnd - fMax)*2 + (c - cMax)*3 + 2;
6425       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
6426 #if defined(PETSC_USE_DEBUG)
6427       if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eEndNew);
6428       for (p = 0; p < 3; ++p) {
6429         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);
6430       }
6431 #endif
6432     }
6433     /* Old vertices have identical supports */
6434     for (v = vStart; v < vEnd; ++v) {
6435       const PetscInt  newp = vStartNew + (v - vStart);
6436       const PetscInt *support, *cone;
6437       PetscInt        size, s;
6438 
6439       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
6440       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
6441       for (s = 0; s < size; ++s) {
6442         const PetscInt e = support[s];
6443 
6444         supportRef[s] = -1;
6445         if (eStart <= e) {
6446           if (e < eMax) {
6447             ierr = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
6448             supportRef[s] = eStartNew + (e - eStart)*2 + (cone[1] == v ? 1 : 0);
6449           } else if (e < eEnd) {
6450             supportRef[s] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart)*4 + e - eMax;
6451           } else SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", e, eStart, eEnd);
6452         } else SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", e, eStart, eEnd);
6453       }
6454       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6455 #if defined(PETSC_USE_DEBUG)
6456       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", newp, vStartNew, vEndNew);
6457       for (p = 0; p < size; ++p) {
6458         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);
6459       }
6460 #endif
6461     }
6462     /* Interior edge vertices have 2 + faces supports */
6463     for (e = eStart; e < eMax; ++e) {
6464       const PetscInt  newp = vStartNew + (vEnd - vStart) + (e - eStart);
6465       const PetscInt *cone, *support;
6466       PetscInt        size, s;
6467 
6468       ierr          = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
6469       ierr          = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
6470       supportRef[0] = eStartNew + (e - eStart)*2 + 0;
6471       supportRef[1] = eStartNew + (e - eStart)*2 + 1;
6472       for (s = 0; s < size; ++s) {
6473         PetscInt r, coneSize;
6474 
6475         supportRef[2+s] = -1;
6476         ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
6477         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);
6478         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);
6479         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6480         for (r = 0; r < coneSize; ++r) {if (cone[r] == e) break;}
6481         if (coneSize == 3) supportRef[2+s] = eStartNew + (eMax - eStart)*2 + (support[s] - fStart)*3 + r;
6482         else if (coneSize == 4) {
6483           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);
6484           supportRef[2+s] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart)*4 + (eEnd - eMax) + support[s] - fMax;
6485         } else SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected conesize %D for face %D (fMax %D)", coneSize, support[s], fMax);
6486       }
6487       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6488 #if defined(PETSC_USE_DEBUG)
6489       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", newp, vStartNew, vEndNew);
6490       for (p = 0; p < 2+size; ++p) {
6491         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);
6492       }
6493 #endif
6494     }
6495     /* Split Edges have 2 vertices and the same faces as the parent */
6496     for (e = eStart; e < eMax; ++e) {
6497       const PetscInt newv = vStartNew + (vEnd - vStart) + (e - eStart);
6498 
6499       for (r = 0; r < 2; ++r) {
6500         const PetscInt  newp = eStartNew + (e - eStart)*2 + r;
6501         const PetscInt *cone, *ornt, *support;
6502         PetscInt        coneNew[2], coneSize, c, supportSize, s;
6503 
6504         ierr             = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
6505         coneNew[0]       = vStartNew + (cone[0] - vStart);
6506         coneNew[1]       = vStartNew + (cone[1] - vStart);
6507         coneNew[(r+1)%2] = newv;
6508         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6509 #if defined(PETSC_USE_DEBUG)
6510         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eEndNew);
6511         for (p = 0; p < 2; ++p) {
6512           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);
6513         }
6514 #endif
6515         ierr = DMPlexGetSupportSize(dm, e, &supportSize);CHKERRQ(ierr);
6516         ierr = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
6517         for (s = 0; s < supportSize; ++s) {
6518           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
6519           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);
6520           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);
6521           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6522           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
6523           for (c = 0; c < coneSize; ++c) {
6524             if (cone[c] == e) break;
6525           }
6526           if (coneSize == 3) supportRef[s] = fStartNew + (support[s] - fStart)*3 + (c + (ornt[c] < 0 ? 1-r : r))%3;
6527           else if (coneSize == 4) {
6528             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);
6529             supportRef[s] = fStartNew + (fMax - fStart)*3 + (cMax - cStart)*6 + (support[s] - fMax)*2 + (ornt[c] < 0 ? 1-r : r);
6530           } else SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected conesize %D for face %D (fMax %D)", coneSize, support[s], fMax);
6531         }
6532         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6533 #if defined(PETSC_USE_DEBUG)
6534         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eEndNew);
6535         for (p = 0; p < supportSize; ++p) {
6536           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);
6537         }
6538 #endif
6539       }
6540     }
6541     /* Face vertices have 3 + cells supports */
6542     for (f = fStart; f < fMax; ++f) {
6543       const PetscInt  newp = vStartNew + (vEnd - vStart) + (eMax - eStart) + (f - fStart);
6544       const PetscInt *cone, *support;
6545       PetscInt        size, s;
6546 
6547       ierr          = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
6548       ierr          = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
6549       supportRef[0] = eStartNew + (eMax - eStart)*2 + (f - fStart)*3 + 0;
6550       supportRef[1] = eStartNew + (eMax - eStart)*2 + (f - fStart)*3 + 1;
6551       supportRef[2] = eStartNew + (eMax - eStart)*2 + (f - fStart)*3 + 2;
6552       for (s = 0; s < size; ++s) {
6553         PetscInt r, coneSize;
6554 
6555         supportRef[3+s] = -1;
6556         ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
6557         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);
6558         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);
6559         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6560         for (r = 0; r < coneSize; ++r) {if (cone[r] == f) break;}
6561         if (coneSize == 4) supportRef[3+s] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (support[s] - cStart)*4 + r;
6562         else if (coneSize == 5) {
6563           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);
6564           supportRef[3+s] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart)*4 + (eEnd - eMax) + (fEnd - fMax) + support[s] - cMax;
6565         }
6566       }
6567       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6568 #if defined(PETSC_USE_DEBUG)
6569       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", newp, vStartNew, vEndNew);
6570       for (p = 0; p < 3+size; ++p) {
6571         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);
6572       }
6573 #endif
6574     }
6575     /* Interior cell vertices have 4 supports */
6576     for (c = cStart; c < cMax; ++c) {
6577       const PetscInt  newp = vStartNew + (vEnd - vStart) + (eMax - eStart) + (fMax - fStart) + c - cStart;
6578 
6579       supportRef[0] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart)*4 + 0;
6580       supportRef[1] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart)*4 + 1;
6581       supportRef[2] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart)*4 + 2;
6582       supportRef[3] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart)*4 + 3;
6583       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6584 #if defined(PETSC_USE_DEBUG)
6585       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", newp, vStartNew, vEndNew);
6586       for (p = 0; p < 4; ++p) {
6587         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);
6588       }
6589 #endif
6590     }
6591     ierr = PetscFree(supportRef);CHKERRQ(ierr);
6592     ierr = DMPlexRestoreFaces_Internal(dm, cStart, NULL, NULL, &faces);CHKERRQ(ierr);
6593     break;
6594   case REFINER_HEX_3D:
6595     /*
6596      Bottom (viewed from top)    Top
6597      1---------2---------2       7---------2---------6
6598      |         |         |       |         |         |
6599      |    B    2    C    |       |    H    2    G    |
6600      |         |         |       |         |         |
6601      3----3----0----1----1       3----3----0----1----1
6602      |         |         |       |         |         |
6603      |    A    0    D    |       |    E    0    F    |
6604      |         |         |       |         |         |
6605      0---------0---------3       4---------0---------5
6606      */
6607     /* All cells have 6 faces: Bottom, Top, Front, Back, Right, Left */
6608     for (c = cStart; c < cEnd; ++c) {
6609       const PetscInt  newp = (c - cStart)*8;
6610       const PetscInt *cone, *ornt;
6611       PetscInt        coneNew[6], orntNew[6];
6612 
6613       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
6614       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
6615       /* A hex */
6616       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], 0);
6617       orntNew[0] = ornt[0];
6618       coneNew[1] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  8; /* AE */
6619       orntNew[1] = 0;
6620       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetQuadSubface_Static(ornt[2], 0);
6621       orntNew[2] = ornt[2];
6622       coneNew[3] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  3; /* AB */
6623       orntNew[3] = 0;
6624       coneNew[4] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  0; /* AD */
6625       orntNew[4] = 0;
6626       coneNew[5] = fStartNew + (cone[5] - fStart)*4 + GetQuadSubface_Static(ornt[5], 0);
6627       orntNew[5] = ornt[5];
6628       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
6629       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
6630 #if defined(PETSC_USE_DEBUG)
6631       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);
6632       for (p = 0; p < 6; ++p) {
6633         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);
6634       }
6635 #endif
6636       /* B hex */
6637       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], 1);
6638       orntNew[0] = ornt[0];
6639       coneNew[1] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 + 11; /* BH */
6640       orntNew[1] = 0;
6641       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  3; /* AB */
6642       orntNew[2] = -1;
6643       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetQuadSubface_Static(ornt[3], 1);
6644       orntNew[3] = ornt[3];
6645       coneNew[4] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  2; /* BC */
6646       orntNew[4] = 0;
6647       coneNew[5] = fStartNew + (cone[5] - fStart)*4 + GetQuadSubface_Static(ornt[5], 3);
6648       orntNew[5] = ornt[5];
6649       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
6650       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
6651 #if defined(PETSC_USE_DEBUG)
6652       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);
6653       for (p = 0; p < 6; ++p) {
6654         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);
6655       }
6656 #endif
6657       /* C hex */
6658       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], 2);
6659       orntNew[0] = ornt[0];
6660       coneNew[1] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 + 10; /* CG */
6661       orntNew[1] = 0;
6662       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  1; /* CD */
6663       orntNew[2] = -1;
6664       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetQuadSubface_Static(ornt[3], 0);
6665       orntNew[3] = ornt[3];
6666       coneNew[4] = fStartNew + (cone[4] - fStart)*4 + GetQuadSubface_Static(ornt[4], 1);
6667       orntNew[4] = ornt[4];
6668       coneNew[5] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  2; /* BC */
6669       orntNew[5] = -4;
6670       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
6671       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
6672 #if defined(PETSC_USE_DEBUG)
6673       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);
6674       for (p = 0; p < 6; ++p) {
6675         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);
6676       }
6677 #endif
6678       /* D hex */
6679       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], 3);
6680       orntNew[0] = ornt[0];
6681       coneNew[1] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  9; /* DF */
6682       orntNew[1] = 0;
6683       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetQuadSubface_Static(ornt[2], 1);
6684       orntNew[2] = ornt[2];
6685       coneNew[3] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  1; /* CD */
6686       orntNew[3] = 0;
6687       coneNew[4] = fStartNew + (cone[4] - fStart)*4 + GetQuadSubface_Static(ornt[4], 0);
6688       orntNew[4] = ornt[4];
6689       coneNew[5] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  0; /* AD */
6690       orntNew[5] = -4;
6691       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
6692       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
6693 #if defined(PETSC_USE_DEBUG)
6694       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);
6695       for (p = 0; p < 6; ++p) {
6696         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);
6697       }
6698 #endif
6699       /* E hex */
6700       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  8; /* AE */
6701       orntNew[0] = -4;
6702       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], 0);
6703       orntNew[1] = ornt[1];
6704       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetQuadSubface_Static(ornt[2], 3);
6705       orntNew[2] = ornt[2];
6706       coneNew[3] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  7; /* EH */
6707       orntNew[3] = 0;
6708       coneNew[4] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  4; /* EF */
6709       orntNew[4] = -1;
6710       coneNew[5] = fStartNew + (cone[5] - fStart)*4 + GetQuadSubface_Static(ornt[5], 1);
6711       orntNew[5] = ornt[5];
6712       ierr       = DMPlexSetCone(rdm, newp+4, coneNew);CHKERRQ(ierr);
6713       ierr       = DMPlexSetConeOrientation(rdm, newp+4, orntNew);CHKERRQ(ierr);
6714 #if defined(PETSC_USE_DEBUG)
6715       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);
6716       for (p = 0; p < 6; ++p) {
6717         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);
6718       }
6719 #endif
6720       /* F hex */
6721       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  9; /* DF */
6722       orntNew[0] = -4;
6723       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], 1);
6724       orntNew[1] = ornt[1];
6725       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetQuadSubface_Static(ornt[2], 2);
6726       orntNew[2] = ornt[2];
6727       coneNew[3] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  5; /* FG */
6728       orntNew[3] = -1;
6729       coneNew[4] = fStartNew + (cone[4] - fStart)*4 + GetQuadSubface_Static(ornt[4], 3);
6730       orntNew[4] = ornt[4];
6731       coneNew[5] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  4; /* EF */
6732       orntNew[5] = 1;
6733       ierr       = DMPlexSetCone(rdm, newp+5, coneNew);CHKERRQ(ierr);
6734       ierr       = DMPlexSetConeOrientation(rdm, newp+5, orntNew);CHKERRQ(ierr);
6735 #if defined(PETSC_USE_DEBUG)
6736       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);
6737       for (p = 0; p < 6; ++p) {
6738         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);
6739       }
6740 #endif
6741       /* G hex */
6742       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 + 10; /* CG */
6743       orntNew[0] = -4;
6744       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], 2);
6745       orntNew[1] = ornt[1];
6746       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  5; /* FG */
6747       orntNew[2] = 0;
6748       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetQuadSubface_Static(ornt[3], 3);
6749       orntNew[3] = ornt[3];
6750       coneNew[4] = fStartNew + (cone[4] - fStart)*4 + GetQuadSubface_Static(ornt[4], 2);
6751       orntNew[4] = ornt[4];
6752       coneNew[5] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  6; /* GH */
6753       orntNew[5] = -3;
6754       ierr       = DMPlexSetCone(rdm, newp+6, coneNew);CHKERRQ(ierr);
6755       ierr       = DMPlexSetConeOrientation(rdm, newp+6, orntNew);CHKERRQ(ierr);
6756 #if defined(PETSC_USE_DEBUG)
6757       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);
6758       for (p = 0; p < 6; ++p) {
6759         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);
6760       }
6761 #endif
6762       /* H hex */
6763       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 + 11; /* BH */
6764       orntNew[0] = -4;
6765       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], 3);
6766       orntNew[1] = ornt[1];
6767       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  7; /* EH */
6768       orntNew[2] = -1;
6769       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetQuadSubface_Static(ornt[3], 2);
6770       orntNew[3] = ornt[3];
6771       coneNew[4] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  6; /* GH */
6772       orntNew[4] = 3;
6773       coneNew[5] = fStartNew + (cone[5] - fStart)*4 + GetQuadSubface_Static(ornt[5], 2);
6774       orntNew[5] = ornt[5];
6775       ierr       = DMPlexSetCone(rdm, newp+7, coneNew);CHKERRQ(ierr);
6776       ierr       = DMPlexSetConeOrientation(rdm, newp+7, orntNew);CHKERRQ(ierr);
6777 #if defined(PETSC_USE_DEBUG)
6778       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);
6779       for (p = 0; p < 6; ++p) {
6780         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);
6781       }
6782 #endif
6783     }
6784     /* Split faces have 4 edges and the same cells as the parent */
6785     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
6786     ierr = PetscMalloc1(4 + maxSupportSize*2, &supportRef);CHKERRQ(ierr);
6787     for (f = fStart; f < fEnd; ++f) {
6788       for (r = 0; r < 4; ++r) {
6789         /* TODO: This can come from GetFaces_Internal() */
6790         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};
6791         const PetscInt  newp = fStartNew + (f - fStart)*4 + r;
6792         const PetscInt *cone, *ornt, *support;
6793         PetscInt        coneNew[4], orntNew[4], coneSize, c, supportSize, s;
6794 
6795         ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
6796         ierr = DMPlexGetConeOrientation(dm, f, &ornt);CHKERRQ(ierr);
6797         coneNew[(r+3)%4] = eStartNew + (cone[(r+3)%4] - eStart)*2 + (ornt[(r+3)%4] < 0 ? 0 : 1);
6798         orntNew[(r+3)%4] = ornt[(r+3)%4];
6799         coneNew[(r+0)%4] = eStartNew + (cone[r]       - eStart)*2 + (ornt[r] < 0 ? 1 : 0);
6800         orntNew[(r+0)%4] = ornt[r];
6801         coneNew[(r+1)%4] = eStartNew + (eEnd - eStart)*2 + (f - fStart)*4 + r;
6802         orntNew[(r+1)%4] = 0;
6803         coneNew[(r+2)%4] = eStartNew + (eEnd - eStart)*2 + (f - fStart)*4 + (r+3)%4;
6804         orntNew[(r+2)%4] = -2;
6805         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6806         ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
6807 #if defined(PETSC_USE_DEBUG)
6808         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
6809         for (p = 0; p < 4; ++p) {
6810           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);
6811         }
6812 #endif
6813         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
6814         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
6815         for (s = 0; s < supportSize; ++s) {
6816           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
6817           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6818           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
6819           for (c = 0; c < coneSize; ++c) {
6820             if (cone[c] == f) break;
6821           }
6822           supportRef[s] = cStartNew + (support[s] - cStart)*8 + newCells[c*4+GetQuadSubfaceInverse_Static(ornt[c], r)];
6823         }
6824         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6825 #if defined(PETSC_USE_DEBUG)
6826         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
6827         for (p = 0; p < supportSize; ++p) {
6828           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);
6829         }
6830 #endif
6831       }
6832     }
6833     /* Interior faces have 4 edges and 2 cells */
6834     for (c = cStart; c < cEnd; ++c) {
6835       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};
6836       const PetscInt *cone, *ornt;
6837       PetscInt        newp, coneNew[4], orntNew[4], supportNew[2];
6838 
6839       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
6840       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
6841       /* A-D face */
6842       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 0;
6843       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*4 + GetQuadEdge_Static(ornt[0], 3);
6844       orntNew[0] = 0;
6845       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 0;
6846       orntNew[1] = 0;
6847       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 2;
6848       orntNew[2] = -2;
6849       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*4 + GetQuadEdge_Static(ornt[2], 0);
6850       orntNew[3] = -2;
6851       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6852       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
6853 #if defined(PETSC_USE_DEBUG)
6854       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
6855       for (p = 0; p < 4; ++p) {
6856         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);
6857       }
6858 #endif
6859       /* C-D face */
6860       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 1;
6861       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*4 + GetQuadEdge_Static(ornt[0], 2);
6862       orntNew[0] = 0;
6863       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 0;
6864       orntNew[1] = 0;
6865       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 4;
6866       orntNew[2] = -2;
6867       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (cone[4] - fStart)*4 + GetQuadEdge_Static(ornt[4], 0);
6868       orntNew[3] = -2;
6869       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6870       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
6871 #if defined(PETSC_USE_DEBUG)
6872       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
6873       for (p = 0; p < 4; ++p) {
6874         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);
6875       }
6876 #endif
6877       /* B-C face */
6878       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 2;
6879       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*4 + GetQuadEdge_Static(ornt[0], 1);
6880       orntNew[0] = -2;
6881       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*4 + GetQuadEdge_Static(ornt[3], 0);
6882       orntNew[1] = 0;
6883       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 3;
6884       orntNew[2] = 0;
6885       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 0;
6886       orntNew[3] = -2;
6887       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6888       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
6889 #if defined(PETSC_USE_DEBUG)
6890       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
6891       for (p = 0; p < 4; ++p) {
6892         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);
6893       }
6894 #endif
6895       /* A-B face */
6896       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 3;
6897       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*4 + GetQuadEdge_Static(ornt[0], 0);
6898       orntNew[0] = -2;
6899       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[5] - fStart)*4 + GetQuadEdge_Static(ornt[5], 3);
6900       orntNew[1] = 0;
6901       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 5;
6902       orntNew[2] = 0;
6903       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 0;
6904       orntNew[3] = -2;
6905       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6906       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
6907 #if defined(PETSC_USE_DEBUG)
6908       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
6909       for (p = 0; p < 4; ++p) {
6910         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);
6911       }
6912 #endif
6913       /* E-F face */
6914       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 4;
6915       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 2;
6916       orntNew[0] = -2;
6917       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*4 + GetQuadEdge_Static(ornt[2], 2);
6918       orntNew[1] = -2;
6919       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*4 + GetQuadEdge_Static(ornt[1], 0);
6920       orntNew[2] = 0;
6921       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 1;
6922       orntNew[3] = 0;
6923       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6924       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
6925 #if defined(PETSC_USE_DEBUG)
6926       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
6927       for (p = 0; p < 4; ++p) {
6928         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);
6929       }
6930 #endif
6931       /* F-G face */
6932       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 5;
6933       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 4;
6934       orntNew[0] = -2;
6935       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[4] - fStart)*4 + GetQuadEdge_Static(ornt[4], 2);
6936       orntNew[1] = -2;
6937       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*4 + GetQuadEdge_Static(ornt[1], 1);
6938       orntNew[2] = 0;
6939       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 1;
6940       orntNew[3] = 0;
6941       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6942       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
6943 #if defined(PETSC_USE_DEBUG)
6944       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
6945       for (p = 0; p < 4; ++p) {
6946         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);
6947       }
6948 #endif
6949       /* G-H face */
6950       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 6;
6951       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*4 + GetQuadEdge_Static(ornt[3], 2);
6952       orntNew[0] = -2;
6953       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*4 + GetQuadEdge_Static(ornt[1], 2);
6954       orntNew[1] = 0;
6955       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 1;
6956       orntNew[2] = 0;
6957       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 3;
6958       orntNew[3] = -2;
6959       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6960       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
6961 #if defined(PETSC_USE_DEBUG)
6962       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
6963       for (p = 0; p < 4; ++p) {
6964         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);
6965       }
6966 #endif
6967       /* E-H face */
6968       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 7;
6969       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 5;
6970       orntNew[0] = -2;
6971       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[5] - fStart)*4 + GetQuadEdge_Static(ornt[5], 1);
6972       orntNew[1] = -2;
6973       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*4 + GetQuadEdge_Static(ornt[1], 3);
6974       orntNew[2] = 0;
6975       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 1;
6976       orntNew[3] = 0;
6977       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6978       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
6979 #if defined(PETSC_USE_DEBUG)
6980       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
6981       for (p = 0; p < 4; ++p) {
6982         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);
6983       }
6984 #endif
6985       /* A-E face */
6986       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 8;
6987       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*4 + GetQuadEdge_Static(ornt[2], 3);
6988       orntNew[0] = 0;
6989       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 2;
6990       orntNew[1] = 0;
6991       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 5;
6992       orntNew[2] = -2;
6993       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (cone[5] - fStart)*4 + GetQuadEdge_Static(ornt[5], 0);
6994       orntNew[3] = -2;
6995       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6996       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
6997 #if defined(PETSC_USE_DEBUG)
6998       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
6999       for (p = 0; p < 4; ++p) {
7000         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);
7001       }
7002 #endif
7003       /* D-F face */
7004       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 9;
7005       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*4 + GetQuadEdge_Static(ornt[2], 1);
7006       orntNew[0] = -2;
7007       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[4] - fStart)*4 + GetQuadEdge_Static(ornt[4], 3);
7008       orntNew[1] = 0;
7009       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 4;
7010       orntNew[2] = 0;
7011       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 2;
7012       orntNew[3] = -2;
7013       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
7014       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
7015 #if defined(PETSC_USE_DEBUG)
7016       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
7017       for (p = 0; p < 4; ++p) {
7018         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);
7019       }
7020 #endif
7021       /* C-G face */
7022       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 10;
7023       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 4;
7024       orntNew[0] = -2;
7025       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[4] - fStart)*4 + GetQuadEdge_Static(ornt[4], 1);
7026       orntNew[1] = -2;
7027       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*4 + GetQuadEdge_Static(ornt[3], 3);
7028       orntNew[2] = 0;
7029       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 3;
7030       orntNew[3] = 0;
7031       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
7032       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
7033 #if defined(PETSC_USE_DEBUG)
7034       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
7035       for (p = 0; p < 4; ++p) {
7036         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);
7037       }
7038 #endif
7039       /* B-H face */
7040       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 11;
7041       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 5;
7042       orntNew[0] = 0;
7043       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 3;
7044       orntNew[1] = -2;
7045       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*4 + GetQuadEdge_Static(ornt[3], 1);
7046       orntNew[2] = -2;
7047       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (cone[5] - fStart)*4 + GetQuadEdge_Static(ornt[5], 2);
7048       orntNew[3] = 0;
7049       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
7050       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
7051 #if defined(PETSC_USE_DEBUG)
7052       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
7053       for (p = 0; p < 4; ++p) {
7054         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);
7055       }
7056 #endif
7057       for (r = 0; r < 12; ++r) {
7058         newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + r;
7059         supportNew[0] = cStartNew + (c - cStart)*8 + newCells[r*2+0];
7060         supportNew[1] = cStartNew + (c - cStart)*8 + newCells[r*2+1];
7061         ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
7062 #if defined(PETSC_USE_DEBUG)
7063         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
7064         for (p = 0; p < 2; ++p) {
7065           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);
7066         }
7067 #endif
7068       }
7069     }
7070     /* Split edges have 2 vertices and the same faces as the parent */
7071     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
7072     for (e = eStart; e < eEnd; ++e) {
7073       const PetscInt newv = vStartNew + (vEnd - vStart) + (e - eStart);
7074 
7075       for (r = 0; r < 2; ++r) {
7076         const PetscInt  newp = eStartNew + (e - eStart)*2 + r;
7077         const PetscInt *cone, *ornt, *support;
7078         PetscInt        coneNew[2], coneSize, c, supportSize, s;
7079 
7080         ierr             = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
7081         coneNew[0]       = vStartNew + (cone[0] - vStart);
7082         coneNew[1]       = vStartNew + (cone[1] - vStart);
7083         coneNew[(r+1)%2] = newv;
7084         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
7085 #if defined(PETSC_USE_DEBUG)
7086         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eEndNew);
7087         for (p = 0; p < 2; ++p) {
7088           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);
7089         }
7090 #endif
7091         ierr = DMPlexGetSupportSize(dm, e, &supportSize);CHKERRQ(ierr);
7092         ierr = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
7093         for (s = 0; s < supportSize; ++s) {
7094           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
7095           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
7096           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
7097           for (c = 0; c < coneSize; ++c) {
7098             if (cone[c] == e) break;
7099           }
7100           supportRef[s] = fStartNew + (support[s] - fStart)*4 + (ornt[c] < 0 ? (c+1-r)%4 : (c+r)%4);
7101         }
7102         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
7103 #if defined(PETSC_USE_DEBUG)
7104         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eEndNew);
7105         for (p = 0; p < supportSize; ++p) {
7106           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);
7107         }
7108 #endif
7109       }
7110     }
7111     /* Face edges have 2 vertices and 2+cells faces */
7112     for (f = fStart; f < fEnd; ++f) {
7113       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};
7114       const PetscInt  newv = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (f - fStart);
7115       const PetscInt *cone, *coneCell, *orntCell, *support;
7116       PetscInt        coneNew[2], coneSize, c, supportSize, s;
7117 
7118       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
7119       for (r = 0; r < 4; ++r) {
7120         const PetscInt newp = eStartNew + (eEnd - eStart)*2 + (f - fStart)*4 + r;
7121 
7122         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r] - eStart);
7123         coneNew[1] = newv;
7124         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
7125 #if defined(PETSC_USE_DEBUG)
7126         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eEndNew);
7127         for (p = 0; p < 2; ++p) {
7128           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);
7129         }
7130 #endif
7131         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
7132         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
7133         supportRef[0] = fStartNew + (f - fStart)*4 + r;
7134         supportRef[1] = fStartNew + (f - fStart)*4 + (r+1)%4;
7135         for (s = 0; s < supportSize; ++s) {
7136           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
7137           ierr = DMPlexGetCone(dm, support[s], &coneCell);CHKERRQ(ierr);
7138           ierr = DMPlexGetConeOrientation(dm, support[s], &orntCell);CHKERRQ(ierr);
7139           for (c = 0; c < coneSize; ++c) if (coneCell[c] == f) break;
7140           supportRef[2+s] = fStartNew + (fEnd - fStart)*4 + (support[s] - cStart)*12 + newFaces[c*4 + GetQuadEdgeInverse_Static(orntCell[c], r)];
7141         }
7142         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
7143 #if defined(PETSC_USE_DEBUG)
7144         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eEndNew);
7145         for (p = 0; p < 2+supportSize; ++p) {
7146           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);
7147         }
7148 #endif
7149       }
7150     }
7151     /* Cell edges have 2 vertices and 4 faces */
7152     for (c = cStart; c < cEnd; ++c) {
7153       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};
7154       const PetscInt  newv = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (fEnd - fStart) + (c - cStart);
7155       const PetscInt *cone;
7156       PetscInt        coneNew[2], supportNew[4];
7157 
7158       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
7159       for (r = 0; r < 6; ++r) {
7160         const PetscInt newp = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*4 + (c - cStart)*6 + r;
7161 
7162         coneNew[0] = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (cone[r] - fStart);
7163         coneNew[1] = newv;
7164         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
7165 #if defined(PETSC_USE_DEBUG)
7166         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eEndNew);
7167         for (p = 0; p < 2; ++p) {
7168           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);
7169         }
7170 #endif
7171         for (f = 0; f < 4; ++f) supportNew[f] = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + newFaces[r*4+f];
7172         ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
7173 #if defined(PETSC_USE_DEBUG)
7174         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eEndNew);
7175         for (p = 0; p < 4; ++p) {
7176           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);
7177         }
7178 #endif
7179       }
7180     }
7181     /* Old vertices have identical supports */
7182     for (v = vStart; v < vEnd; ++v) {
7183       const PetscInt  newp = vStartNew + (v - vStart);
7184       const PetscInt *support, *cone;
7185       PetscInt        size, s;
7186 
7187       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
7188       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
7189       for (s = 0; s < size; ++s) {
7190         PetscInt r = 0;
7191 
7192         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
7193         if (cone[1] == v) r = 1;
7194         supportRef[s] = eStartNew + (support[s] - eStart)*2 + r;
7195       }
7196       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
7197 #if defined(PETSC_USE_DEBUG)
7198       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", newp, vStartNew, vEndNew);
7199       for (p = 0; p < size; ++p) {
7200         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);
7201       }
7202 #endif
7203     }
7204     /* Edge vertices have 2 + faces supports */
7205     for (e = eStart; e < eEnd; ++e) {
7206       const PetscInt  newp = vStartNew + (vEnd - vStart) + (e - eStart);
7207       const PetscInt *cone, *support;
7208       PetscInt        size, s;
7209 
7210       ierr          = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
7211       ierr          = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
7212       supportRef[0] = eStartNew + (e - eStart)*2 + 0;
7213       supportRef[1] = eStartNew + (e - eStart)*2 + 1;
7214       for (s = 0; s < size; ++s) {
7215         PetscInt r;
7216 
7217         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
7218         for (r = 0; r < 4; ++r) if (cone[r] == e) break;
7219         supportRef[2+s] = eStartNew + (eEnd - eStart)*2 + (support[s] - fStart)*4 + r;
7220       }
7221       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
7222 #if defined(PETSC_USE_DEBUG)
7223       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", newp, vStartNew, vEndNew);
7224       for (p = 0; p < 2+size; ++p) {
7225         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);
7226       }
7227 #endif
7228     }
7229     /* Face vertices have 4 + cells supports */
7230     for (f = fStart; f < fEnd; ++f) {
7231       const PetscInt  newp = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (f - fStart);
7232       const PetscInt *cone, *support;
7233       PetscInt        size, s;
7234 
7235       ierr          = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
7236       ierr          = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
7237       for (r = 0; r < 4; ++r) supportRef[r] = eStartNew + (eEnd - eStart)*2 +  (f - fStart)*4 + r;
7238       for (s = 0; s < size; ++s) {
7239         PetscInt r;
7240 
7241         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
7242         for (r = 0; r < 6; ++r) if (cone[r] == f) break;
7243         supportRef[4+s] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*4 + (support[s] - cStart)*6 + r;
7244       }
7245       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
7246 #if defined(PETSC_USE_DEBUG)
7247       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", newp, vStartNew, vEndNew);
7248       for (p = 0; p < 4+size; ++p) {
7249         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);
7250       }
7251 #endif
7252     }
7253     /* Cell vertices have 6 supports */
7254     for (c = cStart; c < cEnd; ++c) {
7255       const PetscInt newp = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (fEnd - fStart) + (c - cStart);
7256       PetscInt       supportNew[6];
7257 
7258       for (r = 0; r < 6; ++r) {
7259         supportNew[r] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*4 + (c - cStart)*6 + r;
7260       }
7261       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
7262     }
7263     ierr = PetscFree(supportRef);CHKERRQ(ierr);
7264     break;
7265   case REFINER_HYBRID_HEX_3D:
7266     ierr = DMPlexGetHybridBounds(rdm, &cMaxNew, &fMaxNew, &eMaxNew, NULL);CHKERRQ(ierr);
7267     /*
7268      Bottom (viewed from top)    Top
7269      1---------2---------2       7---------2---------6
7270      |         |         |       |         |         |
7271      |    B    2    C    |       |    H    2    G    |
7272      |         |         |       |         |         |
7273      3----3----0----1----1       3----3----0----1----1
7274      |         |         |       |         |         |
7275      |    A    0    D    |       |    E    0    F    |
7276      |         |         |       |         |         |
7277      0---------0---------3       4---------0---------5
7278      */
7279     /* Interior cells have 6 faces: Bottom, Top, Front, Back, Right, Left */
7280     for (c = cStart; c < cMax; ++c) {
7281       const PetscInt  newp = (c - cStart)*8;
7282       const PetscInt *cone, *ornt;
7283       PetscInt        coneNew[6], orntNew[6];
7284 
7285       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
7286       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
7287       /* A hex */
7288       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], 0);
7289       orntNew[0] = ornt[0];
7290       coneNew[1] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  8; /* AE */
7291       orntNew[1] = 0;
7292       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetQuadSubface_Static(ornt[2], 0);
7293       orntNew[2] = ornt[2];
7294       coneNew[3] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  3; /* AB */
7295       orntNew[3] = 0;
7296       coneNew[4] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  0; /* AD */
7297       orntNew[4] = 0;
7298       coneNew[5] = fStartNew + (cone[5] - fStart)*4 + GetQuadSubface_Static(ornt[5], 0);
7299       orntNew[5] = ornt[5];
7300       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
7301       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
7302 #if defined(PETSC_USE_DEBUG)
7303       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);
7304       for (p = 0; p < 6; ++p) {
7305         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);
7306       }
7307 #endif
7308       /* B hex */
7309       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], 1);
7310       orntNew[0] = ornt[0];
7311       coneNew[1] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 + 11; /* BH */
7312       orntNew[1] = 0;
7313       coneNew[2] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  3; /* AB */
7314       orntNew[2] = -1;
7315       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetQuadSubface_Static(ornt[3], 1);
7316       orntNew[3] = ornt[3];
7317       coneNew[4] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  2; /* BC */
7318       orntNew[4] = 0;
7319       coneNew[5] = fStartNew + (cone[5] - fStart)*4 + GetQuadSubface_Static(ornt[5], 3);
7320       orntNew[5] = ornt[5];
7321       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
7322       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
7323 #if defined(PETSC_USE_DEBUG)
7324       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);
7325       for (p = 0; p < 6; ++p) {
7326         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);
7327       }
7328 #endif
7329       /* C hex */
7330       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], 2);
7331       orntNew[0] = ornt[0];
7332       coneNew[1] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 + 10; /* CG */
7333       orntNew[1] = 0;
7334       coneNew[2] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  1; /* CD */
7335       orntNew[2] = -1;
7336       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetQuadSubface_Static(ornt[3], 0);
7337       orntNew[3] = ornt[3];
7338       coneNew[4] = fStartNew + (cone[4] - fStart)*4 + GetQuadSubface_Static(ornt[4], 1);
7339       orntNew[4] = ornt[4];
7340       coneNew[5] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  2; /* BC */
7341       orntNew[5] = -4;
7342       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
7343       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
7344 #if defined(PETSC_USE_DEBUG)
7345       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);
7346       for (p = 0; p < 6; ++p) {
7347         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);
7348       }
7349 #endif
7350       /* D hex */
7351       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], 3);
7352       orntNew[0] = ornt[0];
7353       coneNew[1] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  9; /* DF */
7354       orntNew[1] = 0;
7355       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetQuadSubface_Static(ornt[2], 1);
7356       orntNew[2] = ornt[2];
7357       coneNew[3] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  1; /* CD */
7358       orntNew[3] = 0;
7359       coneNew[4] = fStartNew + (cone[4] - fStart)*4 + GetQuadSubface_Static(ornt[4], 0);
7360       orntNew[4] = ornt[4];
7361       coneNew[5] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  0; /* AD */
7362       orntNew[5] = -4;
7363       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
7364       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
7365 #if defined(PETSC_USE_DEBUG)
7366       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);
7367       for (p = 0; p < 6; ++p) {
7368         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);
7369       }
7370 #endif
7371       /* E hex */
7372       coneNew[0] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  8; /* AE */
7373       orntNew[0] = -4;
7374       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], 0);
7375       orntNew[1] = ornt[1];
7376       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetQuadSubface_Static(ornt[2], 3);
7377       orntNew[2] = ornt[2];
7378       coneNew[3] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  7; /* EH */
7379       orntNew[3] = 0;
7380       coneNew[4] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  4; /* EF */
7381       orntNew[4] = -1;
7382       coneNew[5] = fStartNew + (cone[5] - fStart)*4 + GetQuadSubface_Static(ornt[5], 1);
7383       orntNew[5] = ornt[5];
7384       ierr       = DMPlexSetCone(rdm, newp+4, coneNew);CHKERRQ(ierr);
7385       ierr       = DMPlexSetConeOrientation(rdm, newp+4, orntNew);CHKERRQ(ierr);
7386 #if defined(PETSC_USE_DEBUG)
7387       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);
7388       for (p = 0; p < 6; ++p) {
7389         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);
7390       }
7391 #endif
7392       /* F hex */
7393       coneNew[0] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  9; /* DF */
7394       orntNew[0] = -4;
7395       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], 1);
7396       orntNew[1] = ornt[1];
7397       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetQuadSubface_Static(ornt[2], 2);
7398       orntNew[2] = ornt[2];
7399       coneNew[3] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  5; /* FG */
7400       orntNew[3] = -1;
7401       coneNew[4] = fStartNew + (cone[4] - fStart)*4 + GetQuadSubface_Static(ornt[4], 3);
7402       orntNew[4] = ornt[4];
7403       coneNew[5] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  4; /* EF */
7404       orntNew[5] = 1;
7405       ierr       = DMPlexSetCone(rdm, newp+5, coneNew);CHKERRQ(ierr);
7406       ierr       = DMPlexSetConeOrientation(rdm, newp+5, orntNew);CHKERRQ(ierr);
7407 #if defined(PETSC_USE_DEBUG)
7408       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);
7409       for (p = 0; p < 6; ++p) {
7410         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);
7411       }
7412 #endif
7413       /* G hex */
7414       coneNew[0] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 + 10; /* CG */
7415       orntNew[0] = -4;
7416       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], 2);
7417       orntNew[1] = ornt[1];
7418       coneNew[2] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  5; /* FG */
7419       orntNew[2] = 0;
7420       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetQuadSubface_Static(ornt[3], 3);
7421       orntNew[3] = ornt[3];
7422       coneNew[4] = fStartNew + (cone[4] - fStart)*4 + GetQuadSubface_Static(ornt[4], 2);
7423       orntNew[4] = ornt[4];
7424       coneNew[5] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  6; /* GH */
7425       orntNew[5] = -3;
7426       ierr       = DMPlexSetCone(rdm, newp+6, coneNew);CHKERRQ(ierr);
7427       ierr       = DMPlexSetConeOrientation(rdm, newp+6, orntNew);CHKERRQ(ierr);
7428 #if defined(PETSC_USE_DEBUG)
7429       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);
7430       for (p = 0; p < 6; ++p) {
7431         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);
7432       }
7433 #endif
7434       /* H hex */
7435       coneNew[0] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 + 11; /* BH */
7436       orntNew[0] = -4;
7437       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], 3);
7438       orntNew[1] = ornt[1];
7439       coneNew[2] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  7; /* EH */
7440       orntNew[2] = -1;
7441       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetQuadSubface_Static(ornt[3], 2);
7442       orntNew[3] = ornt[3];
7443       coneNew[4] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  6; /* GH */
7444       orntNew[4] = 3;
7445       coneNew[5] = fStartNew + (cone[5] - fStart)*4 + GetQuadSubface_Static(ornt[5], 2);
7446       orntNew[5] = ornt[5];
7447       ierr       = DMPlexSetCone(rdm, newp+7, coneNew);CHKERRQ(ierr);
7448       ierr       = DMPlexSetConeOrientation(rdm, newp+7, orntNew);CHKERRQ(ierr);
7449 #if defined(PETSC_USE_DEBUG)
7450       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);
7451       for (p = 0; p < 6; ++p) {
7452         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);
7453       }
7454 #endif
7455     }
7456     /* Hybrid cells have 6 faces: Front, Back, Sides */
7457     /*
7458      3---------2---------2
7459      |         |         |
7460      |    D    2    C    |
7461      |         |         |
7462      3----3----0----1----1
7463      |         |         |
7464      |    A    0    B    |
7465      |         |         |
7466      0---------0---------1
7467      */
7468     for (c = cMax; c < cEnd; ++c) {
7469       const PetscInt  newp = (cMax - cStart)*8 + (c - cMax)*4;
7470       const PetscInt *cone, *ornt, *fornt;
7471       PetscInt        coneNew[6], orntNew[6], o, of, i;
7472 
7473       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
7474       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
7475       ierr = DMPlexGetConeOrientation(dm, cone[0], &fornt);CHKERRQ(ierr);
7476       o = ornt[0] < 0 ? -1 : 1;
7477       for (r = 0; r < 4; ++r) {
7478         PetscInt subfA = GetQuadSubface_Static(ornt[0], r);
7479         PetscInt edgeA = GetQuadEdge_Static(ornt[0], r);
7480         PetscInt edgeB = GetQuadEdge_Static(ornt[0], (r+3)%4);
7481         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]);
7482         coneNew[0]         = fStartNew + (cone[0] - fStart)*4 + subfA;
7483         orntNew[0]         = ornt[0];
7484         coneNew[1]         = fStartNew + (cone[1] - fStart)*4 + subfA;
7485         orntNew[1]         = ornt[0];
7486         of = fornt[edgeA] < 0 ? -1 : 1;
7487         i  = GetQuadEdgeInverse_Static(ornt[0], r) + 2;
7488         coneNew[i] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (cone[2+edgeA] - fMax)*2 + (o*of < 0 ? 1 : 0);
7489         orntNew[i] = ornt[edgeA];
7490         i  = GetQuadEdgeInverse_Static(ornt[0], (r+1)%4) + 2;
7491         coneNew[i] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd          - fMax)*2 + (c - cMax)*4 + edgeA;
7492         orntNew[i] = 0;
7493         i  = GetQuadEdgeInverse_Static(ornt[0], (r+2)%4) + 2;
7494         coneNew[i] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd          - fMax)*2 + (c - cMax)*4 + edgeB;
7495         orntNew[i] = -2;
7496         of = fornt[edgeB] < 0 ? -1 : 1;
7497         i  = GetQuadEdgeInverse_Static(ornt[0], (r+3)%4) + 2;
7498         coneNew[i] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (cone[2+edgeB] - fMax)*2 + (o*of < 0 ? 0 : 1);
7499         orntNew[i] = ornt[edgeB];
7500         ierr       = DMPlexSetCone(rdm, newp+r, coneNew);CHKERRQ(ierr);
7501         ierr       = DMPlexSetConeOrientation(rdm, newp+r, orntNew);CHKERRQ(ierr);
7502 #if defined(PETSC_USE_DEBUG)
7503         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);
7504         for (p = 0; p < 2; ++p) {
7505           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);
7506         }
7507         for (p = 2; p < 6; ++p) {
7508           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);
7509         }
7510 #endif
7511       }
7512     }
7513     /* Interior split faces have 4 edges and the same cells as the parent */
7514     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
7515     ierr = PetscMalloc1(4 + maxSupportSize*2, &supportRef);CHKERRQ(ierr);
7516     for (f = fStart; f < fMax; ++f) {
7517       for (r = 0; r < 4; ++r) {
7518         /* TODO: This can come from GetFaces_Internal() */
7519         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};
7520         const PetscInt  newp = fStartNew + (f - fStart)*4 + r;
7521         const PetscInt *cone, *ornt, *support;
7522         PetscInt        coneNew[4], orntNew[4], coneSize, c, supportSize, s;
7523 
7524         ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
7525         ierr = DMPlexGetConeOrientation(dm, f, &ornt);CHKERRQ(ierr);
7526         coneNew[(r+3)%4] = eStartNew + (cone[(r+3)%4] - eStart)*2 + (ornt[(r+3)%4] < 0 ? 0 : 1);
7527         orntNew[(r+3)%4] = ornt[(r+3)%4];
7528         coneNew[(r+0)%4] = eStartNew + (cone[r]       - eStart)*2 + (ornt[r] < 0 ? 1 : 0);
7529         orntNew[(r+0)%4] = ornt[r];
7530         coneNew[(r+1)%4] = eStartNew + (eMax - eStart)*2 + (f - fStart)*4 + r;
7531         orntNew[(r+1)%4] = 0;
7532         coneNew[(r+2)%4] = eStartNew + (eMax - eStart)*2 + (f - fStart)*4 + (r+3)%4;
7533         orntNew[(r+2)%4] = -2;
7534         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
7535         ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
7536 #if defined(PETSC_USE_DEBUG)
7537         if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fMaxNew);
7538         for (p = 0; p < 4; ++p) {
7539           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);
7540         }
7541 #endif
7542         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
7543         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
7544         for (s = 0; s < supportSize; ++s) {
7545           PetscInt subf;
7546           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
7547           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
7548           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
7549           for (c = 0; c < coneSize; ++c) {
7550             if (cone[c] == f) break;
7551           }
7552           subf = GetQuadSubfaceInverse_Static(ornt[c], r);
7553           if (support[s] < cMax) {
7554             supportRef[s] = cStartNew + (support[s] - cStart)*8 + newCells[c*4+subf];
7555           } else {
7556             supportRef[s] = cStartNew + (cMax       - cStart)*8 + (support[s] - cMax)*4 + subf;
7557           }
7558         }
7559         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
7560 #if defined(PETSC_USE_DEBUG)
7561         if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fMaxNew);
7562         for (p = 0; p < supportSize; ++p) {
7563           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);
7564         }
7565 #endif
7566       }
7567     }
7568     /* Interior cell faces have 4 edges and 2 cells */
7569     for (c = cStart; c < cMax; ++c) {
7570       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};
7571       const PetscInt *cone, *ornt;
7572       PetscInt        newp, coneNew[4], orntNew[4], supportNew[2];
7573 
7574       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
7575       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
7576       /* A-D face */
7577       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 0;
7578       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*4 + GetQuadEdge_Static(ornt[0], 3);
7579       orntNew[0] = 0;
7580       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 0;
7581       orntNew[1] = 0;
7582       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 2;
7583       orntNew[2] = -2;
7584       coneNew[3] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*4 + GetQuadEdge_Static(ornt[2], 0);
7585       orntNew[3] = -2;
7586       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
7587       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
7588 #if defined(PETSC_USE_DEBUG)
7589       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fMaxNew);
7590       for (p = 0; p < 4; ++p) {
7591         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);
7592       }
7593 #endif
7594       /* C-D face */
7595       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 1;
7596       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*4 + GetQuadEdge_Static(ornt[0], 2);
7597       orntNew[0] = 0;
7598       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 0;
7599       orntNew[1] = 0;
7600       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 4;
7601       orntNew[2] = -2;
7602       coneNew[3] = eStartNew + (eMax - eStart)*2 + (cone[4] - fStart)*4 + GetQuadEdge_Static(ornt[4], 0);
7603       orntNew[3] = -2;
7604       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
7605       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
7606 #if defined(PETSC_USE_DEBUG)
7607       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fMaxNew);
7608       for (p = 0; p < 4; ++p) {
7609         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);
7610       }
7611 #endif
7612       /* B-C face */
7613       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 2;
7614       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*4 + GetQuadEdge_Static(ornt[0], 1);
7615       orntNew[0] = -2;
7616       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*4 + GetQuadEdge_Static(ornt[3], 0);
7617       orntNew[1] = 0;
7618       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 3;
7619       orntNew[2] = 0;
7620       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 0;
7621       orntNew[3] = -2;
7622       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
7623       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
7624 #if defined(PETSC_USE_DEBUG)
7625       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fMaxNew);
7626       for (p = 0; p < 4; ++p) {
7627         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);
7628       }
7629 #endif
7630       /* A-B face */
7631       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 3;
7632       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*4 + GetQuadEdge_Static(ornt[0], 0);
7633       orntNew[0] = -2;
7634       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[5] - fStart)*4 + GetQuadEdge_Static(ornt[5], 3);
7635       orntNew[1] = 0;
7636       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 5;
7637       orntNew[2] = 0;
7638       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 0;
7639       orntNew[3] = -2;
7640       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
7641       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
7642 #if defined(PETSC_USE_DEBUG)
7643       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fMaxNew);
7644       for (p = 0; p < 4; ++p) {
7645         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);
7646       }
7647 #endif
7648       /* E-F face */
7649       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 4;
7650       coneNew[0] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 2;
7651       orntNew[0] = -2;
7652       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*4 + GetQuadEdge_Static(ornt[2], 2);
7653       orntNew[1] = -2;
7654       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*4 + GetQuadEdge_Static(ornt[1], 0);
7655       orntNew[2] = 0;
7656       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 1;
7657       orntNew[3] = 0;
7658       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
7659       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
7660 #if defined(PETSC_USE_DEBUG)
7661       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fMaxNew);
7662       for (p = 0; p < 4; ++p) {
7663         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);
7664       }
7665 #endif
7666       /* F-G face */
7667       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 5;
7668       coneNew[0] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 4;
7669       orntNew[0] = -2;
7670       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[4] - fStart)*4 + GetQuadEdge_Static(ornt[4], 2);
7671       orntNew[1] = -2;
7672       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*4 + GetQuadEdge_Static(ornt[1], 1);
7673       orntNew[2] = 0;
7674       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 1;
7675       orntNew[3] = 0;
7676       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
7677       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
7678 #if defined(PETSC_USE_DEBUG)
7679       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fMaxNew);
7680       for (p = 0; p < 4; ++p) {
7681         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);
7682       }
7683 #endif
7684       /* G-H face */
7685       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 6;
7686       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*4 + GetQuadEdge_Static(ornt[3], 2);
7687       orntNew[0] = -2;
7688       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*4 + GetQuadEdge_Static(ornt[1], 2);
7689       orntNew[1] = 0;
7690       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 1;
7691       orntNew[2] = 0;
7692       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 3;
7693       orntNew[3] = -2;
7694       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
7695       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
7696 #if defined(PETSC_USE_DEBUG)
7697       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fMaxNew);
7698       for (p = 0; p < 4; ++p) {
7699         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);
7700       }
7701 #endif
7702       /* E-H face */
7703       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 7;
7704       coneNew[0] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 5;
7705       orntNew[0] = -2;
7706       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[5] - fStart)*4 + GetQuadEdge_Static(ornt[5], 1);
7707       orntNew[1] = -2;
7708       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*4 + GetQuadEdge_Static(ornt[1], 3);
7709       orntNew[2] = 0;
7710       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 1;
7711       orntNew[3] = 0;
7712       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
7713       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
7714 #if defined(PETSC_USE_DEBUG)
7715       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fMaxNew);
7716       for (p = 0; p < 4; ++p) {
7717         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);
7718       }
7719 #endif
7720       /* A-E face */
7721       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 8;
7722       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*4 + GetQuadEdge_Static(ornt[2], 3);
7723       orntNew[0] = 0;
7724       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 2;
7725       orntNew[1] = 0;
7726       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 5;
7727       orntNew[2] = -2;
7728       coneNew[3] = eStartNew + (eMax - eStart)*2 + (cone[5] - fStart)*4 + GetQuadEdge_Static(ornt[5], 0);
7729       orntNew[3] = -2;
7730       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
7731       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
7732 #if defined(PETSC_USE_DEBUG)
7733       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fMaxNew);
7734       for (p = 0; p < 4; ++p) {
7735         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);
7736       }
7737 #endif
7738       /* D-F face */
7739       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 9;
7740       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*4 + GetQuadEdge_Static(ornt[2], 1);
7741       orntNew[0] = -2;
7742       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[4] - fStart)*4 + GetQuadEdge_Static(ornt[4], 3);
7743       orntNew[1] = 0;
7744       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 4;
7745       orntNew[2] = 0;
7746       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 2;
7747       orntNew[3] = -2;
7748       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
7749       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
7750 #if defined(PETSC_USE_DEBUG)
7751       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fMaxNew);
7752       for (p = 0; p < 4; ++p) {
7753         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);
7754       }
7755 #endif
7756       /* C-G face */
7757       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 10;
7758       coneNew[0] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 4;
7759       orntNew[0] = -2;
7760       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[4] - fStart)*4 + GetQuadEdge_Static(ornt[4], 1);
7761       orntNew[1] = -2;
7762       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*4 + GetQuadEdge_Static(ornt[3], 3);
7763       orntNew[2] = 0;
7764       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 3;
7765       orntNew[3] = 0;
7766       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
7767       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
7768 #if defined(PETSC_USE_DEBUG)
7769       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fMaxNew);
7770       for (p = 0; p < 4; ++p) {
7771         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);
7772       }
7773 #endif
7774       /* B-H face */
7775       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 11;
7776       coneNew[0] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 5;
7777       orntNew[0] = 0;
7778       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 3;
7779       orntNew[1] = -2;
7780       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*4 + GetQuadEdge_Static(ornt[3], 1);
7781       orntNew[2] = -2;
7782       coneNew[3] = eStartNew + (eMax - eStart)*2 + (cone[5] - fStart)*4 + GetQuadEdge_Static(ornt[5], 2);
7783       orntNew[3] = 0;
7784       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
7785       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
7786 #if defined(PETSC_USE_DEBUG)
7787       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fMaxNew);
7788       for (p = 0; p < 4; ++p) {
7789         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);
7790       }
7791 #endif
7792       for (r = 0; r < 12; ++r) {
7793         newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + r;
7794         supportNew[0] = cStartNew + (c - cStart)*8 + newCells[r*2+0];
7795         supportNew[1] = cStartNew + (c - cStart)*8 + newCells[r*2+1];
7796         ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
7797 #if defined(PETSC_USE_DEBUG)
7798         if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fMaxNew);
7799         for (p = 0; p < 2; ++p) {
7800           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);
7801         }
7802 #endif
7803       }
7804     }
7805     /* Hybrid split faces have 4 edges and same cells */
7806     for (f = fMax; f < fEnd; ++f) {
7807       const PetscInt *cone, *ornt, *support;
7808       PetscInt        coneNew[4], orntNew[4];
7809       PetscInt        supportNew[2], size, s, c;
7810 
7811       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
7812       ierr = DMPlexGetConeOrientation(dm, f, &ornt);CHKERRQ(ierr);
7813       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
7814       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
7815       for (r = 0; r < 2; ++r) {
7816         const PetscInt newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (f - fMax)*2 + r;
7817 
7818         coneNew[0]   = eStartNew + (cone[0] - eStart)*2 + (ornt[0] < 0 ? 1-r : r);
7819         orntNew[0]   = ornt[0];
7820         coneNew[1]   = eStartNew + (cone[1] - eStart)*2 + (ornt[1] < 0 ? 1-r : r);
7821         orntNew[1]   = ornt[1];
7822         coneNew[2+r] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (cone[2+r] - eMax);
7823         orntNew[2+r] = 0;
7824         coneNew[3-r] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (eEnd      - eMax) + (f - fMax);
7825         orntNew[3-r] = 0;
7826         ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
7827         ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
7828 #if defined(PETSC_USE_DEBUG)
7829         if ((newp < fMaxNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a hybrid face [%D, %D)", newp, fMaxNew, fEndNew);
7830         for (p = 0; p < 2; ++p) {
7831           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);
7832         }
7833         for (p = 2; p < 4; ++p) {
7834           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);
7835         }
7836 #endif
7837         for (s = 0; s < size; ++s) {
7838           const PetscInt *coneCell, *orntCell, *fornt;
7839           PetscInt        o, of;
7840 
7841           ierr = DMPlexGetCone(dm, support[s], &coneCell);CHKERRQ(ierr);
7842           ierr = DMPlexGetConeOrientation(dm, support[s], &orntCell);CHKERRQ(ierr);
7843           o = orntCell[0] < 0 ? -1 : 1;
7844           for (c = 2; c < 6; ++c) if (coneCell[c] == f) break;
7845           if (c >= 6) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Could not find face %D in cone of cell %D", f, support[s]);
7846           ierr = DMPlexGetConeOrientation(dm, coneCell[0], &fornt);CHKERRQ(ierr);
7847           of = fornt[c-2] < 0 ? -1 : 1;
7848           supportNew[s] = cStartNew + (cMax - cStart)*8 + (support[s] - cMax)*4 + (GetQuadEdgeInverse_Static(orntCell[0], c-2) + (o*of < 0 ? 1-r : r))%4;
7849         }
7850         ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
7851 #if defined(PETSC_USE_DEBUG)
7852         if ((newp < fMaxNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a hybrid face [%D, %D)", newp, fMaxNew, fEndNew);
7853         for (p = 0; p < size; ++p) {
7854           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);
7855         }
7856 #endif
7857       }
7858     }
7859     /* Hybrid cell faces have 4 edges and 2 cells */
7860     for (c = cMax; c < cEnd; ++c) {
7861       PetscInt        newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd - fMax)*2 + (c - cMax)*4;
7862       const PetscInt *cone, *ornt;
7863       PetscInt        coneNew[4], orntNew[4];
7864       PetscInt        supportNew[2];
7865 
7866       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
7867       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
7868       for (r = 0; r < 4; ++r) {
7869 #if 0
7870         coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], r);
7871         orntNew[0] = 0;
7872         coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], r);
7873         orntNew[1] = 0;
7874         coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (eEnd - eMax) + (cone[2+GetQuadEdge_Static(ornt[0], r)] - fMax);
7875         orntNew[2] = 0;
7876         coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (eEnd - eMax) + (fEnd                                   - fMax) + (c - cMax);
7877         orntNew[3] = 0;
7878 #else
7879         coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*4 + r;
7880         orntNew[0] = 0;
7881         coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*4 + r;
7882         orntNew[1] = 0;
7883         coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (eEnd - eMax) + (cone[2+r] - fMax);
7884         orntNew[2] = 0;
7885         coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (eEnd - eMax) + (fEnd      - fMax) + (c - cMax);
7886         orntNew[3] = 0;
7887 #endif
7888         ierr = DMPlexSetCone(rdm, newp+r, coneNew);CHKERRQ(ierr);
7889         ierr = DMPlexSetConeOrientation(rdm, newp+r, orntNew);CHKERRQ(ierr);
7890 #if defined(PETSC_USE_DEBUG)
7891         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);
7892         for (p = 0; p < 2; ++p) {
7893           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);
7894         }
7895         for (p = 2; p < 4; ++p) {
7896           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);
7897         }
7898 #endif
7899         supportNew[0] = cStartNew + (cMax - cStart)*8 + (c - cMax)*4 + GetQuadSubface_Static(ornt[0], r);
7900         supportNew[1] = cStartNew + (cMax - cStart)*8 + (c - cMax)*4 + GetQuadSubface_Static(ornt[0], (r+1)%4);
7901         ierr          = DMPlexSetSupport(rdm, newp+r, supportNew);CHKERRQ(ierr);
7902 #if defined(PETSC_USE_DEBUG)
7903         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);
7904         for (p = 0; p < 2; ++p) {
7905           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);
7906         }
7907 #endif
7908       }
7909     }
7910     /* Interior split edges have 2 vertices and the same faces as the parent */
7911     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
7912     for (e = eStart; e < eMax; ++e) {
7913       const PetscInt newv = vStartNew + (vEnd - vStart) + (e - eStart);
7914 
7915       for (r = 0; r < 2; ++r) {
7916         const PetscInt  newp = eStartNew + (e - eStart)*2 + r;
7917         const PetscInt *cone, *ornt, *support;
7918         PetscInt        coneNew[2], coneSize, c, supportSize, s;
7919 
7920         ierr             = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
7921         coneNew[0]       = vStartNew + (cone[0] - vStart);
7922         coneNew[1]       = vStartNew + (cone[1] - vStart);
7923         coneNew[(r+1)%2] = newv;
7924         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
7925 #if defined(PETSC_USE_DEBUG)
7926         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eMaxNew);
7927         for (p = 0; p < 2; ++p) {
7928           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);
7929         }
7930 #endif
7931         ierr = DMPlexGetSupportSize(dm, e, &supportSize);CHKERRQ(ierr);
7932         ierr = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
7933         for (s = 0; s < supportSize; ++s) {
7934           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
7935           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
7936           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
7937           for (c = 0; c < coneSize; ++c) {
7938             if (cone[c] == e) break;
7939           }
7940           if (support[s] < fMax) {
7941             supportRef[s] = fStartNew + (support[s] - fStart)*4 + (c + (ornt[c] < 0 ? 1-r : r))%4;
7942           } else {
7943             supportRef[s] = fStartNew + (fMax       - fStart)*4 + (cMax - cStart)*12 + (support[s] - fMax)*2 + (ornt[c] < 0 ? 1-r : r);
7944           }
7945         }
7946         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
7947 #if defined(PETSC_USE_DEBUG)
7948         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eMaxNew);
7949         for (p = 0; p < supportSize; ++p) {
7950           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);
7951         }
7952 #endif
7953       }
7954     }
7955     /* Interior face edges have 2 vertices and 2+cells faces */
7956     for (f = fStart; f < fMax; ++f) {
7957       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};
7958       const PetscInt  newv = vStartNew + (vEnd - vStart) + (eMax - eStart) + (f - fStart);
7959       const PetscInt *cone, *coneCell, *orntCell, *support;
7960       PetscInt        coneNew[2], coneSize, c, supportSize, s;
7961 
7962       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
7963       for (r = 0; r < 4; ++r) {
7964         const PetscInt newp = eStartNew + (eMax - eStart)*2 + (f - fStart)*4 + r;
7965 
7966         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r] - eStart);
7967         coneNew[1] = newv;
7968         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
7969 #if defined(PETSC_USE_DEBUG)
7970         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eMaxNew);
7971         for (p = 0; p < 2; ++p) {
7972           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);
7973         }
7974 #endif
7975         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
7976         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
7977         supportRef[0] = fStartNew + (f - fStart)*4 + r;
7978         supportRef[1] = fStartNew + (f - fStart)*4 + (r+1)%4;
7979         for (s = 0; s < supportSize; ++s) {
7980           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
7981           ierr = DMPlexGetCone(dm, support[s], &coneCell);CHKERRQ(ierr);
7982           ierr = DMPlexGetConeOrientation(dm, support[s], &orntCell);CHKERRQ(ierr);
7983           for (c = 0; c < coneSize; ++c) if (coneCell[c] == f) break;
7984           if (support[s] < cMax) {
7985             supportRef[2+s] = fStartNew + (fMax - fStart)*4 + (support[s] - cStart)*12 + newFaces[c*4 + GetQuadEdgeInverse_Static(orntCell[c], r)];
7986           } else {
7987             supportRef[2+s] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd - fMax)*2 + (support[s] - cMax)*4 + r;
7988           }
7989         }
7990         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
7991 #if defined(PETSC_USE_DEBUG)
7992         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eMaxNew);
7993         for (p = 0; p < 2+supportSize; ++p) {
7994           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);
7995         }
7996 #endif
7997       }
7998     }
7999     /* Interior cell edges have 2 vertices and 4 faces */
8000     for (c = cStart; c < cMax; ++c) {
8001       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};
8002       const PetscInt  newv = vStartNew + (vEnd - vStart) + (eMax - eStart) + (fMax - fStart) + (c - cStart);
8003       const PetscInt *cone;
8004       PetscInt        coneNew[2], supportNew[4];
8005 
8006       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
8007       for (r = 0; r < 6; ++r) {
8008         const PetscInt newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (c - cStart)*6 + r;
8009 
8010         coneNew[0] = vStartNew + (vEnd - vStart) + (eMax - eStart) + (cone[r] - fStart);
8011         coneNew[1] = newv;
8012         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
8013 #if defined(PETSC_USE_DEBUG)
8014         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eMaxNew);
8015         for (p = 0; p < 2; ++p) {
8016           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);
8017         }
8018 #endif
8019         for (f = 0; f < 4; ++f) supportNew[f] = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + newFaces[r*4+f];
8020         ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
8021 #if defined(PETSC_USE_DEBUG)
8022         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eMaxNew);
8023         for (p = 0; p < 4; ++p) {
8024           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);
8025         }
8026 #endif
8027       }
8028     }
8029     /* Hybrid edges have two vertices and the same faces */
8030     for (e = eMax; e < eEnd; ++e) {
8031       const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (e - eMax);
8032       const PetscInt *cone, *support, *fcone;
8033       PetscInt        coneNew[2], size, fsize, s;
8034 
8035       ierr = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
8036       ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
8037       ierr = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
8038       coneNew[0] = vStartNew + (cone[0] - vStart);
8039       coneNew[1] = vStartNew + (cone[1] - vStart);
8040       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
8041 #if defined(PETSC_USE_DEBUG)
8042       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a hybrid edge [%D, %D)", newp, eMaxNew, eEndNew);
8043       for (p = 0; p < 2; ++p) {
8044         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);
8045       }
8046 #endif
8047       for (s = 0; s < size; ++s) {
8048         ierr = DMPlexGetConeSize(dm, support[s], &fsize);CHKERRQ(ierr);
8049         ierr = DMPlexGetCone(dm, support[s], &fcone);CHKERRQ(ierr);
8050         for (c = 0; c < fsize; ++c) if (fcone[c] == e) break;
8051         if ((c < 2) || (c > 3)) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Edge %D not found in cone of face %D", e, support[s]);
8052         supportRef[s] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (support[s] - fMax)*2 + c-2;
8053       }
8054       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
8055 #if defined(PETSC_USE_DEBUG)
8056       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a hybrid edge [%D, %D)", newp, eMaxNew, eEndNew);
8057       for (p = 0; p < size; ++p) {
8058         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);
8059       }
8060 #endif
8061     }
8062     /* Hybrid face edges have 2 vertices and 2+cells faces */
8063     for (f = fMax; f < fEnd; ++f) {
8064       const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (eEnd - eMax) + (f - fMax);
8065       const PetscInt *cone, *support, *ccone, *cornt;
8066       PetscInt        coneNew[2], size, csize, s;
8067 
8068       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
8069       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
8070       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
8071       coneNew[0] = vStartNew + (vEnd - vStart) + (cone[0] - eStart);
8072       coneNew[1] = vStartNew + (vEnd - vStart) + (cone[1] - eStart);
8073       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
8074 #if defined(PETSC_USE_DEBUG)
8075       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a hybrid edge [%D, %D)", newp, eMaxNew, eEndNew);
8076       for (p = 0; p < 2; ++p) {
8077         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);
8078       }
8079 #endif
8080       supportRef[0] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (f - fMax)*2 + 0;
8081       supportRef[1] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (f - fMax)*2 + 1;
8082       for (s = 0; s < size; ++s) {
8083         ierr = DMPlexGetConeSize(dm, support[s], &csize);CHKERRQ(ierr);
8084         ierr = DMPlexGetCone(dm, support[s], &ccone);CHKERRQ(ierr);
8085         ierr = DMPlexGetConeOrientation(dm, support[s], &cornt);CHKERRQ(ierr);
8086         for (c = 0; c < csize; ++c) if (ccone[c] == f) break;
8087         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]);
8088         supportRef[2+s] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd - fMax)*2 + (support[s] - cMax)*4 + c-2;
8089       }
8090       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
8091 #if defined(PETSC_USE_DEBUG)
8092       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a hybrid edge [%D, %D)", newp, eMaxNew, eEndNew);
8093       for (p = 0; p < 2+size; ++p) {
8094         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);
8095       }
8096 #endif
8097     }
8098     /* Hybrid cell edges have 2 vertices and 4 faces */
8099     for (c = cMax; c < cEnd; ++c) {
8100       const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (eEnd - eMax) + (fEnd - fMax) + (c - cMax);
8101       const PetscInt *cone, *support;
8102       PetscInt        coneNew[2], size;
8103 
8104       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
8105       ierr = DMPlexGetSupportSize(dm, c, &size);CHKERRQ(ierr);
8106       ierr = DMPlexGetSupport(dm, c, &support);CHKERRQ(ierr);
8107       coneNew[0] = vStartNew + (vEnd - vStart) + (eMax - eStart) + (cone[0] - fStart);
8108       coneNew[1] = vStartNew + (vEnd - vStart) + (eMax - eStart) + (cone[1] - fStart);
8109       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
8110 #if defined(PETSC_USE_DEBUG)
8111       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a hybrid edge [%D, %D)", newp, eMaxNew, eEndNew);
8112       for (p = 0; p < 2; ++p) {
8113         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);
8114       }
8115 #endif
8116       supportRef[0] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd - fMax)*2 + (c - cMax)*4 + 0;
8117       supportRef[1] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd - fMax)*2 + (c - cMax)*4 + 1;
8118       supportRef[2] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd - fMax)*2 + (c - cMax)*4 + 2;
8119       supportRef[3] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd - fMax)*2 + (c - cMax)*4 + 3;
8120       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
8121 #if defined(PETSC_USE_DEBUG)
8122       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a hybrid edge [%D, %D)", newp, eMaxNew, eEndNew);
8123       for (p = 0; p < 4; ++p) {
8124         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);
8125       }
8126 #endif
8127     }
8128     /* Interior vertices have identical supports */
8129     for (v = vStart; v < vEnd; ++v) {
8130       const PetscInt  newp = vStartNew + (v - vStart);
8131       const PetscInt *support, *cone;
8132       PetscInt        size, s;
8133 
8134       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
8135       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
8136       for (s = 0; s < size; ++s) {
8137         PetscInt r = 0;
8138 
8139         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
8140         if (cone[1] == v) r = 1;
8141         if (support[s] < eMax) supportRef[s] = eStartNew + (support[s] - eStart)*2 + r;
8142         else                   supportRef[s] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (support[s] - eMax);
8143       }
8144       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
8145 #if defined(PETSC_USE_DEBUG)
8146       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", newp, vStartNew, vEndNew);
8147       for (p = 0; p < size; ++p) {
8148         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);
8149       }
8150 #endif
8151     }
8152     /* Interior edge vertices have 2 + faces supports */
8153     for (e = eStart; e < eMax; ++e) {
8154       const PetscInt  newp = vStartNew + (vEnd - vStart) + (e - eStart);
8155       const PetscInt *cone, *support;
8156       PetscInt        size, s;
8157 
8158       ierr          = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
8159       ierr          = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
8160       supportRef[0] = eStartNew + (e - eStart)*2 + 0;
8161       supportRef[1] = eStartNew + (e - eStart)*2 + 1;
8162       for (s = 0; s < size; ++s) {
8163         PetscInt r;
8164 
8165         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
8166         for (r = 0; r < 4; ++r) if (cone[r] == e) break;
8167         if (support[s] < fMax) {
8168           supportRef[2+s] = eStartNew + (eMax - eStart)*2 + (support[s] - fStart)*4 + r;
8169         } else {
8170           supportRef[2+s] = eStartNew + (eMax - eStart)*2 + (fMax       - fStart)*4 + (cMax - cStart)*6 + (eEnd - eMax) + (support[s] - fMax);
8171         }
8172       }
8173       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
8174 #if defined(PETSC_USE_DEBUG)
8175       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", newp, vStartNew, vEndNew);
8176       for (p = 0; p < 2+size; ++p) {
8177         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);
8178       }
8179 #endif
8180     }
8181     /* Interior face vertices have 4 + cells supports */
8182     for (f = fStart; f < fMax; ++f) {
8183       const PetscInt  newp = vStartNew + (vEnd - vStart) + (eMax - eStart) + (f - fStart);
8184       const PetscInt *cone, *support;
8185       PetscInt        size, s;
8186 
8187       ierr          = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
8188       ierr          = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
8189       for (r = 0; r < 4; ++r) supportRef[r] = eStartNew + (eMax - eStart)*2 +  (f - fStart)*4 + r;
8190       for (s = 0; s < size; ++s) {
8191         PetscInt r;
8192 
8193         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
8194         for (r = 0; r < 6; ++r) if (cone[r] == f) break;
8195         if (support[s] < cMax) {
8196           supportRef[4+s] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (support[s] - cStart)*6 + r;
8197         } else {
8198           supportRef[4+s] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax       - cStart)*6 + (eEnd - eMax) + (fEnd - fMax) + (support[s] - cMax);
8199         }
8200       }
8201       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
8202 #if defined(PETSC_USE_DEBUG)
8203       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", newp, vStartNew, vEndNew);
8204       for (p = 0; p < 4+size; ++p) {
8205         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);
8206       }
8207 #endif
8208     }
8209     /* Cell vertices have 6 supports */
8210     for (c = cStart; c < cMax; ++c) {
8211       const PetscInt newp = vStartNew + (vEnd - vStart) + (eMax - eStart) + (fMax - fStart) + (c - cStart);
8212       PetscInt       supportNew[6];
8213 
8214       for (r = 0; r < 6; ++r) {
8215         supportNew[r] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (c - cStart)*6 + r;
8216       }
8217       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
8218     }
8219     ierr = PetscFree(supportRef);CHKERRQ(ierr);
8220     break;
8221   default:
8222     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %s", CellRefiners[refiner]);
8223   }
8224   PetscFunctionReturn(0);
8225 }
8226 
8227 static PetscErrorCode CellRefinerSetCoordinates(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
8228 {
8229   PetscSection          coordSection, coordSectionNew;
8230   Vec                   coordinates, coordinatesNew;
8231   PetscScalar          *coords, *coordsNew;
8232   const PetscInt        numVertices = depthSize ? depthSize[0] : 0;
8233   PetscInt              dim, spaceDim, depth, bs, coordSizeNew, cStart, cEnd, cMax;
8234   PetscInt              c, vStart, vStartNew, vEnd, v, eStart, eEnd, eMax, e, fStart, fEnd, fMax, f;
8235   PetscInt              cStartNew, cEndNew, vEndNew, *parentId = NULL;
8236   VecType               vtype;
8237   PetscBool             isperiodic, localize = PETSC_FALSE, needcoords = PETSC_FALSE;
8238   const PetscReal      *maxCell, *L;
8239   const DMBoundaryType *bd;
8240   PetscErrorCode        ierr;
8241 
8242   PetscFunctionBegin;
8243   ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr);
8244   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
8245   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
8246   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
8247   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
8248   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
8249   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, NULL);CHKERRQ(ierr);
8250   if (cMax < 0) cMax = cEnd;
8251   if (fMax < 0) fMax = fEnd;
8252   if (eMax < 0) eMax = eEnd;
8253   ierr = GetDepthStart_Private(depth, depthSize, &cStartNew, NULL, NULL, &vStartNew);CHKERRQ(ierr);
8254   ierr = GetDepthEnd_Private(depth, depthSize, &cEndNew, NULL, NULL, &vEndNew);CHKERRQ(ierr);
8255   ierr = DMGetPeriodicity(dm, &isperiodic, &maxCell, &L, &bd);CHKERRQ(ierr);
8256   /* Determine if we need to localize coordinates when generating them */
8257   if (isperiodic && !maxCell) {
8258     ierr = DMGetCoordinatesLocalized(dm, &localize);CHKERRQ(ierr);
8259     if (!localize) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_USER,"Cannot refine if coordinates have not been localized");
8260   }
8261   if (isperiodic) {
8262     ierr = PetscOptionsBegin(PetscObjectComm((PetscObject)dm),((PetscObject)dm)->prefix,"DMPlex coords refinement options","DM");CHKERRQ(ierr);
8263     ierr = PetscOptionsBool("-dm_plex_refine_localize","Automatically localize from parent cells",NULL,localize,&localize,NULL);CHKERRQ(ierr);
8264     ierr = PetscOptionsEnd();CHKERRQ(ierr);
8265     if (localize) {
8266       ierr = DMLocalizeCoordinates(dm);CHKERRQ(ierr);
8267     }
8268   }
8269   ierr = DMSetPeriodicity(rdm, isperiodic,  maxCell,  L,  bd);CHKERRQ(ierr);
8270 
8271   ierr = DMGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
8272   ierr = PetscSectionGetFieldComponents(coordSection, 0, &spaceDim);CHKERRQ(ierr);
8273   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)dm), &coordSectionNew);CHKERRQ(ierr);
8274   ierr = PetscSectionSetNumFields(coordSectionNew, 1);CHKERRQ(ierr);
8275   ierr = PetscSectionSetFieldComponents(coordSectionNew, 0, spaceDim);CHKERRQ(ierr);
8276 
8277   if (localize) {
8278     PetscInt p, r, newp, *pi;
8279 
8280     /* New coordinates will be already localized on the cell */
8281     ierr = PetscSectionSetChart(coordSectionNew, 0, vStartNew+numVertices);CHKERRQ(ierr);
8282 
8283     /* We need the parentId to properly localize coordinates */
8284     ierr = PetscMalloc1(cEndNew-cStartNew,&pi);CHKERRQ(ierr);
8285     switch (refiner) {
8286     case REFINER_NOOP:
8287       break;
8288     case REFINER_SIMPLEX_1D:
8289       for (p = cStart; p < cEnd; ++p) {
8290         for (r = 0; r < 2; ++r) {
8291           newp     = (p - cStart)*2 + r;
8292           pi[newp] = p;
8293         }
8294       }
8295       break;
8296     case REFINER_SIMPLEX_2D:
8297       for (p = cStart; p < cEnd; ++p) {
8298         for (r = 0; r < 4; ++r) {
8299           newp     = (p - cStart)*4 + r;
8300           pi[newp] = p;
8301         }
8302       }
8303       break;
8304     case REFINER_HEX_2D:
8305       for (p = cStart; p < cEnd; ++p) {
8306         for (r = 0; r < 4; ++r) {
8307           newp     = (p - cStart)*4 + r;
8308           pi[newp] = p;
8309         }
8310       }
8311       break;
8312     case REFINER_SIMPLEX_TO_HEX_2D:
8313       for (p = cStart; p < cEnd; ++p) {
8314         for (r = 0; r < 3; ++r) {
8315           newp     = (p - cStart)*3 + r;
8316           pi[newp] = p;
8317         }
8318       }
8319       break;
8320     case REFINER_HYBRID_SIMPLEX_TO_HEX_2D:
8321       for (p = cStart; p < cMax; ++p) {
8322         for (r = 0; r < 3; ++r) {
8323           newp     = (p - cStart)*3 + r;
8324           pi[newp] = p;
8325         }
8326       }
8327       for (p = cMax; p < cEnd; ++p) {
8328         for (r = 0; r < 4; ++r) {
8329           newp     = (cMax - cStart)*3 + (p - cMax)*4 + r;
8330           pi[newp] = p;
8331         }
8332       }
8333       /* The refiner needs midpoint vertices on hybrid edges and hybrid cells */
8334       cMax = cEnd;
8335       eMax = eEnd;
8336       break;
8337     case REFINER_HYBRID_SIMPLEX_2D:
8338       for (p = cStart; p < cMax; ++p) {
8339         for (r = 0; r < 4; ++r) {
8340           newp     = (p - cStart)*4 + r;
8341           pi[newp] = p;
8342         }
8343       }
8344       for (p = cMax; p < cEnd; ++p) {
8345         for (r = 0; r < 2; ++r) {
8346           newp     = (cMax - cStart)*4 + (p - cMax)*2 + r;
8347           pi[newp] = p;
8348         }
8349       }
8350       break;
8351     case REFINER_HYBRID_HEX_2D:
8352       for (p = cStart; p < cMax; ++p) {
8353         for (r = 0; r < 4; ++r) {
8354           newp     = (p - cStart)*4 + r;
8355           pi[newp] = p;
8356         }
8357       }
8358       for (p = cMax; p < cEnd; ++p) {
8359         for (r = 0; r < 2; ++r) {
8360           newp     = (cMax - cStart)*4 + (p - cMax)*2 + r;
8361           pi[newp] = p;
8362         }
8363       }
8364       break;
8365     case REFINER_SIMPLEX_3D:
8366       for (p = cStart; p < cEnd; ++p) {
8367         for (r = 0; r < 8; ++r) {
8368           newp     = (p - cStart)*8 + r;
8369           pi[newp] = p;
8370         }
8371       }
8372       break;
8373     case REFINER_HYBRID_SIMPLEX_3D:
8374       for (p = cStart; p < cMax; ++p) {
8375         for (r = 0; r < 8; ++r) {
8376           newp     = (p - cStart)*8 + r;
8377           pi[newp] = p;
8378         }
8379       }
8380       for (p = cMax; p < cEnd; ++p) {
8381         for (r = 0; r < 4; ++r) {
8382           newp     = (cMax - cStart)*8 + (p - cMax)*4 + r;
8383           pi[newp] = p;
8384         }
8385       }
8386       break;
8387     case REFINER_SIMPLEX_TO_HEX_3D:
8388       for (p = cStart; p < cEnd; ++p) {
8389         for (r = 0; r < 4; ++r) {
8390           newp     = (p - cStart)*4 + r;
8391           pi[newp] = p;
8392         }
8393       }
8394       break;
8395     case REFINER_HYBRID_SIMPLEX_TO_HEX_3D:
8396       for (p = cStart; p < cMax; ++p) {
8397         for (r = 0; r < 4; ++r) {
8398           newp     = (p - cStart)*4 + r;
8399           pi[newp] = p;
8400         }
8401       }
8402       for (p = cMax; p < cEnd; ++p) {
8403         for (r = 0; r < 3; ++r) {
8404           newp     = (cMax - cStart)*4 + (p - cMax)*3 + r;
8405           pi[newp] = p;
8406         }
8407       }
8408       break;
8409     case REFINER_HEX_3D:
8410       for (p = cStart; p < cEnd; ++p) {
8411         for (r = 0; r < 8; ++r) {
8412           newp = (p - cStart)*8 + r;
8413           pi[newp] = p;
8414         }
8415       }
8416       break;
8417     case REFINER_HYBRID_HEX_3D:
8418       for (p = cStart; p < cMax; ++p) {
8419         for (r = 0; r < 8; ++r) {
8420           newp = (p - cStart)*8 + r;
8421           pi[newp] = p;
8422         }
8423       }
8424       for (p = cMax; p < cEnd; ++p) {
8425         for (r = 0; r < 4; ++r) {
8426           newp = (cMax - cStart)*8 + (p - cMax)*4 + r;
8427           pi[newp] = p;
8428         }
8429       }
8430       break;
8431     default:
8432       SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %s", CellRefiners[refiner]);
8433     }
8434     parentId = pi;
8435   } else {
8436     /* The refiner needs midpoint vertices on hybrid edges and hybrid cells */
8437     if (REFINER_HYBRID_SIMPLEX_TO_HEX_2D == refiner) { cMax = cEnd; eMax = eEnd; }
8438     ierr = PetscSectionSetChart(coordSectionNew, vStartNew, vStartNew+numVertices);CHKERRQ(ierr);
8439   }
8440 
8441   /* All vertices have the spaceDim coordinates */
8442   if (localize) {
8443     PetscInt c;
8444 
8445     for (c = cStartNew; c < cEndNew; ++c) {
8446       PetscInt *cone = NULL;
8447       PetscInt  closureSize, coneSize = 0, p, pdof;
8448 
8449       ierr = PetscSectionGetDof(coordSection, parentId[c], &pdof); CHKERRQ(ierr);
8450       if (pdof) { /* localize on all cells that are refinement of a localized parent cell */
8451         ierr = DMPlexGetTransitiveClosure(rdm, c, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
8452         for (p = 0; p < closureSize*2; p += 2) {
8453           const PetscInt point = cone[p];
8454           if ((point >= vStartNew) && (point < vEndNew)) coneSize++;
8455         }
8456         ierr = DMPlexRestoreTransitiveClosure(rdm, c, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
8457         ierr = PetscSectionSetDof(coordSectionNew, c, coneSize*spaceDim);CHKERRQ(ierr);
8458         ierr = PetscSectionSetFieldDof(coordSectionNew, c, 0, coneSize*spaceDim);CHKERRQ(ierr);
8459       }
8460     }
8461   }
8462   for (v = vStartNew; v < vStartNew+numVertices; ++v) {
8463     ierr = PetscSectionSetDof(coordSectionNew, v, spaceDim);CHKERRQ(ierr);
8464     ierr = PetscSectionSetFieldDof(coordSectionNew, v, 0, spaceDim);CHKERRQ(ierr);
8465   }
8466   ierr = PetscSectionSetUp(coordSectionNew);CHKERRQ(ierr);
8467   ierr = DMSetCoordinateSection(rdm, PETSC_DETERMINE, coordSectionNew);CHKERRQ(ierr);
8468   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
8469   ierr = PetscSectionGetStorageSize(coordSectionNew, &coordSizeNew);CHKERRQ(ierr);
8470   ierr = VecCreate(PETSC_COMM_SELF, &coordinatesNew);CHKERRQ(ierr);
8471   ierr = PetscObjectSetName((PetscObject) coordinatesNew, "coordinates");CHKERRQ(ierr);
8472   ierr = VecSetSizes(coordinatesNew, coordSizeNew, PETSC_DETERMINE);CHKERRQ(ierr);
8473   ierr = VecGetBlockSize(coordinates, &bs);CHKERRQ(ierr);
8474   ierr = VecSetBlockSize(coordinatesNew, bs);CHKERRQ(ierr);
8475   ierr = VecGetType(coordinates, &vtype);CHKERRQ(ierr);
8476   ierr = VecSetType(coordinatesNew, vtype);CHKERRQ(ierr);
8477   ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
8478   ierr = VecGetArray(coordinatesNew, &coordsNew);CHKERRQ(ierr);
8479 
8480   switch (refiner) {
8481   case REFINER_NOOP: break;
8482   case REFINER_HYBRID_SIMPLEX_TO_HEX_3D:
8483   case REFINER_SIMPLEX_TO_HEX_3D:
8484   case REFINER_HEX_3D:
8485   case REFINER_HYBRID_HEX_3D:
8486     /* Face vertices have the average of corner coordinates */
8487     for (f = fStart; f < fMax; ++f) {
8488       const PetscInt newv = vStartNew + (vEnd - vStart) + (eMax - eStart) + (f - fStart);
8489       PetscInt      *cone = NULL;
8490       PetscInt       closureSize, coneSize = 0, off[8], offnew, p, d;
8491 
8492       ierr = DMPlexGetTransitiveClosure(dm, f, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
8493       for (p = 0; p < closureSize*2; p += 2) {
8494         const PetscInt point = cone[p];
8495         if ((point >= vStart) && (point < vEnd)) cone[coneSize++] = point;
8496       }
8497       if (localize) {
8498         const PetscInt *support = NULL;
8499         PetscInt       *rStar = NULL;
8500         PetscInt        supportSize, rStarSize, coff, s, ccoff[8];
8501         PetscBool       cellfound = PETSC_FALSE;
8502 
8503         ierr = DMPlexGetTransitiveClosure(rdm, newv, PETSC_FALSE, &rStarSize, &rStar);CHKERRQ(ierr);
8504         ierr = DMPlexGetSupportSize(dm,f,&supportSize);CHKERRQ(ierr);
8505         ierr = DMPlexGetSupport(dm,f,&support);CHKERRQ(ierr);
8506         /* Compute average of coordinates for each cell sharing the face */
8507         for (s = 0; s < supportSize; ++s) {
8508           PetscScalar     coordsNewAux[3] = { 0.0, 0.0, 0.0 };
8509           PetscInt       *cellCone = NULL;
8510           PetscInt        cellClosureSize, cellConeSize = 0, cdof;
8511           const PetscInt  cell = support[s];
8512           PetscBool       copyoff = PETSC_FALSE;
8513 
8514           ierr = DMPlexGetTransitiveClosure(dm, cell, PETSC_TRUE, &cellClosureSize, &cellCone);CHKERRQ(ierr);
8515           for (p = 0; p < cellClosureSize*2; p += 2) {
8516             const PetscInt point = cellCone[p];
8517             if ((point >= vStart) && (point < vEnd)) cellCone[cellConeSize++] = point;
8518           }
8519           ierr = PetscSectionGetDof(coordSection, cell, &cdof);CHKERRQ(ierr);
8520           if (!cdof) { /* the parent cell does not have localized coordinates */
8521             cellfound = PETSC_TRUE;
8522             for (v = 0; v < coneSize; ++v) {
8523               ierr = PetscSectionGetOffset(coordSection, cone[v], &off[v]);CHKERRQ(ierr);
8524               for (d = 0; d < spaceDim; ++d) coordsNewAux[d] += coords[off[v]+d];
8525             }
8526             for (d = 0; d < spaceDim; ++d) coordsNewAux[d] /= coneSize;
8527           } else {
8528             ierr = PetscSectionGetOffset(coordSection, cell, &coff);CHKERRQ(ierr);
8529             for (p = 0; p < coneSize; ++p) {
8530               const PetscInt tv = cone[p];
8531               PetscInt       cv, voff;
8532               PetscBool      locv = PETSC_TRUE;
8533 
8534               for (cv = 0; cv < cellConeSize; ++cv) {
8535                 if (cellCone[cv] == tv) {
8536                   ccoff[p] = spaceDim*cv + coff;
8537                   break;
8538                 }
8539               }
8540               if (cv == cellConeSize) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Unable to map vertex %D",tv);
8541 
8542               ierr = PetscSectionGetOffset(coordSection, cone[p], &voff);CHKERRQ(ierr);
8543               for (d = 0; d < spaceDim; ++d) {
8544                 coordsNewAux[d] += coords[ccoff[p]+d];
8545                 if (!cellfound && coords[voff+d] != coords[ccoff[p]+d]) locv = PETSC_FALSE;
8546               }
8547               if (locv && !cellfound) {
8548                 cellfound = PETSC_TRUE;
8549                 copyoff   = PETSC_TRUE;
8550               }
8551             }
8552             for (d = 0; d < spaceDim; ++d) coordsNewAux[d] /= coneSize;
8553 
8554             /* Found a valid face for the "vertex" part of the Section (physical space)
8555                i.e., a face that has at least one corner in the physical space */
8556             if (copyoff) for (p = 0; p < coneSize; ++p) off[p] = ccoff[p];
8557           }
8558 
8559           /* Localize new coordinates on each refined cell */
8560           for (v = 0; v < rStarSize*2; v += 2) {
8561             if ((rStar[v] >= cStartNew) && (rStar[v] < cEndNew) && parentId[rStar[v]-cStartNew] == cell) {
8562               PetscInt       *rcone = NULL, rclosureSize, lid, rcdof, rcoff;
8563               const PetscInt  rcell = rStar[v];
8564 
8565               ierr = PetscSectionGetDof(coordSectionNew, rcell, &rcdof);CHKERRQ(ierr);
8566               if (!rcdof) continue;
8567               ierr = PetscSectionGetOffset(coordSectionNew, rcell, &rcoff);CHKERRQ(ierr);
8568               ierr = DMPlexGetTransitiveClosure(rdm, rcell, PETSC_TRUE, &rclosureSize, &rcone);CHKERRQ(ierr);
8569               for (p = 0, lid = 0; p < rclosureSize*2; p += 2) {
8570                 if (rcone[p] == newv) {
8571                   for (d = 0; d < spaceDim; d++) coordsNew[rcoff + lid*spaceDim + d] = coordsNewAux[d];
8572                   break;
8573                 }
8574                 if (rcone[p] >= vStartNew && rcone[p] < vEndNew) lid++;
8575               }
8576               ierr = DMPlexRestoreTransitiveClosure(rdm, rcell, PETSC_TRUE, &rclosureSize, &rcone);CHKERRQ(ierr);
8577               if (p == closureSize*2) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Unable to map new vertex %D",newv);
8578             }
8579           }
8580           ierr = DMPlexRestoreTransitiveClosure(dm, cell, PETSC_TRUE, &cellClosureSize, &cellCone);CHKERRQ(ierr);
8581         }
8582         ierr = DMPlexRestoreTransitiveClosure(rdm, newv, PETSC_FALSE, &rStarSize, &rStar);CHKERRQ(ierr);
8583         if (!cellfound) {
8584           /* Could not find a valid face for the vertex part, we will get this vertex later (final reduction) */
8585           needcoords = PETSC_TRUE;
8586           coneSize   = 0;
8587         }
8588       } else {
8589         for (v = 0; v < coneSize; ++v) {
8590           ierr = PetscSectionGetOffset(coordSection, cone[v], &off[v]);CHKERRQ(ierr);
8591         }
8592       }
8593       ierr = PetscSectionGetOffset(coordSectionNew, newv, &offnew);CHKERRQ(ierr);
8594       if (coneSize) {
8595         for (d = 0; d < spaceDim; ++d) coordsNew[offnew+d] = 0.0;
8596         for (v = 0; v < coneSize; ++v) {ierr = DMLocalizeAddCoordinate_Internal(dm, spaceDim, &coords[off[0]], &coords[off[v]], &coordsNew[offnew]);CHKERRQ(ierr);}
8597         for (d = 0; d < spaceDim; ++d) coordsNew[offnew+d] /= coneSize;
8598       } else {
8599         for (d = 0; d < spaceDim; ++d) coordsNew[offnew+d] = PETSC_MIN_REAL;
8600       }
8601       ierr = DMPlexRestoreTransitiveClosure(dm, f, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
8602     }
8603   case REFINER_HYBRID_SIMPLEX_TO_HEX_2D:
8604   case REFINER_SIMPLEX_TO_HEX_2D:
8605   case REFINER_HEX_2D:
8606   case REFINER_HYBRID_HEX_2D:
8607   case REFINER_SIMPLEX_1D:
8608     /* Cell vertices have the average of corner coordinates */
8609     for (c = cStart; c < cMax; ++c) {
8610       const PetscInt newv = vStartNew + (vEnd - vStart) + (dim > 1 ? (eMax - eStart) : 0) + (c - cStart) + (dim > 2 ? (fMax - fStart) : 0);
8611       PetscInt      *cone = NULL;
8612       PetscInt       closureSize, coneSize = 0, off[8], offnew, p, d, cdof = 0;
8613 
8614       ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
8615       for (p = 0; p < closureSize*2; p += 2) {
8616         const PetscInt point = cone[p];
8617         if ((point >= vStart) && (point < vEnd)) cone[coneSize++] = point;
8618       }
8619       if (localize) {
8620         ierr = PetscSectionGetDof(coordSection, c, &cdof);CHKERRQ(ierr);
8621       }
8622       if (cdof) {
8623         PetscInt coff;
8624 
8625         ierr = PetscSectionGetOffset(coordSection, c, &coff);CHKERRQ(ierr);
8626         for (v = 0; v < coneSize; ++v) off[v] = spaceDim*v + coff;
8627       } else {
8628         for (v = 0; v < coneSize; ++v) {
8629           ierr = PetscSectionGetOffset(coordSection, cone[v], &off[v]);CHKERRQ(ierr);
8630         }
8631       }
8632       ierr = PetscSectionGetOffset(coordSectionNew, newv, &offnew);CHKERRQ(ierr);
8633       for (d = 0; d < spaceDim; ++d) coordsNew[offnew+d] = 0.0;
8634       for (v = 0; v < coneSize; ++v) {ierr = DMLocalizeAddCoordinate_Internal(dm, spaceDim, &coords[off[0]], &coords[off[v]], &coordsNew[offnew]);CHKERRQ(ierr);}
8635       for (d = 0; d < spaceDim; ++d) coordsNew[offnew+d] /= coneSize;
8636       ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
8637 
8638       /* Localize new coordinates on each refined cell */
8639       if (cdof) {
8640         PetscInt *rStar = NULL, rStarSize;
8641 
8642         ierr = DMPlexGetTransitiveClosure(rdm, newv, PETSC_FALSE, &rStarSize, &rStar);CHKERRQ(ierr);
8643         for (v = 0; v < rStarSize*2; v += 2) {
8644           if ((rStar[v] >= cStartNew) && (rStar[v] < cEndNew)) {
8645             PetscInt *cone = NULL, closureSize, lid, coff, rc, rcdof;
8646 
8647             rc   = rStar[v];
8648             ierr = PetscSectionGetDof(coordSectionNew, rc, &rcdof);CHKERRQ(ierr);
8649             if (!rcdof) continue;
8650             ierr = PetscSectionGetOffset(coordSectionNew, rc, &coff);CHKERRQ(ierr);
8651             ierr = DMPlexGetTransitiveClosure(rdm, rc, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
8652             for (p = 0, lid = 0; p < closureSize*2; p += 2) {
8653               if (cone[p] == newv) {
8654                 for (d = 0; d < spaceDim; d++) coordsNew[coff + lid*spaceDim + d] = coordsNew[offnew + d];
8655                 break;
8656               }
8657               if (cone[p] >= vStartNew && cone[p] < vEndNew) lid++;
8658             }
8659             if (p == closureSize*2) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Unable to map new vertex %D",newv);
8660             ierr = DMPlexRestoreTransitiveClosure(rdm, rc, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
8661           }
8662         }
8663         ierr = DMPlexRestoreTransitiveClosure(rdm, newv, PETSC_FALSE, &rStarSize, &rStar);CHKERRQ(ierr);
8664       }
8665     }
8666   case REFINER_SIMPLEX_2D:
8667   case REFINER_HYBRID_SIMPLEX_2D:
8668   case REFINER_SIMPLEX_3D:
8669   case REFINER_HYBRID_SIMPLEX_3D:
8670     /* Edge vertices have the average of endpoint coordinates */
8671     for (e = eStart; e < eMax; ++e) {
8672       const PetscInt  newv = vStartNew + (vEnd - vStart) + (e - eStart);
8673       const PetscInt *cone;
8674       PetscInt        coneSize, offA, offB, offnew, d;
8675 
8676       ierr = DMPlexGetConeSize(dm, e, &coneSize);CHKERRQ(ierr);
8677       if (coneSize != 2) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Edge %D cone should have two vertices, not %D", e, coneSize);
8678       ierr = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
8679       if (localize) {
8680         PetscInt   coff, toffA = -1, toffB = -1, voffA, voffB;
8681         PetscInt  *eStar = NULL, eStarSize;
8682         PetscInt  *rStar = NULL, rStarSize;
8683         PetscBool  cellfound = PETSC_FALSE;
8684 
8685         offA = offB = -1;
8686         ierr = PetscSectionGetOffset(coordSection, cone[0], &voffA);CHKERRQ(ierr);
8687         ierr = PetscSectionGetOffset(coordSection, cone[1], &voffB);CHKERRQ(ierr);
8688         ierr = DMPlexGetTransitiveClosure(dm, e, PETSC_FALSE, &eStarSize, &eStar);CHKERRQ(ierr);
8689         ierr = DMPlexGetTransitiveClosure(rdm, newv, PETSC_FALSE, &rStarSize, &rStar);CHKERRQ(ierr);
8690         for (v = 0; v < eStarSize*2; v += 2) {
8691           if ((eStar[v] >= cStart) && (eStar[v] < cEnd)) {
8692             PetscScalar     coordsNewAux[3] = {0., 0., 0.};
8693             PetscInt       *cellCone = NULL;
8694             PetscInt        cellClosureSize, s, cv, cdof;
8695             PetscBool       locvA = PETSC_TRUE, locvB = PETSC_TRUE;
8696             const PetscInt  cell = eStar[v];
8697 
8698             ierr = PetscSectionGetDof(coordSection, cell, &cdof);CHKERRQ(ierr);
8699             if (!cdof) {
8700               /* Found a valid edge for the "vertex" part of the Section */
8701               offA = voffA;
8702               offB = voffB;
8703               cellfound = PETSC_TRUE;
8704             } else {
8705               ierr = PetscSectionGetOffset(coordSection, cell, &coff);CHKERRQ(ierr);
8706               ierr = DMPlexGetTransitiveClosure(dm, cell, PETSC_TRUE, &cellClosureSize, &cellCone);CHKERRQ(ierr);
8707               for (s = 0, cv = 0; s < cellClosureSize*2; s += 2) {
8708                 const PetscInt point = cellCone[s];
8709                 if ((point >= vStart) && (point < vEnd)) {
8710                   if (point == cone[0]) toffA = spaceDim*cv + coff;
8711                   else if (point == cone[1]) toffB = spaceDim*cv + coff;
8712                   cv++;
8713                 }
8714               }
8715               ierr = DMPlexRestoreTransitiveClosure(dm, cell, PETSC_TRUE, &cellClosureSize, &cellCone);CHKERRQ(ierr);
8716               for (d = 0; d < spaceDim; ++d) {
8717                 coordsNewAux[d] = 0.5*(coords[toffA+d] + coords[toffB+d]);
8718                 if (coords[toffA+d] != coords[voffA+d]) locvA = PETSC_FALSE;
8719                 if (coords[toffB+d] != coords[voffB+d]) locvB = PETSC_FALSE;
8720               }
8721               /* Found a valid edge for the "vertex" part of the Section */
8722               if (!cellfound && (locvA || locvB)) {
8723                 cellfound = PETSC_TRUE;
8724                 offA = toffA;
8725                 offB = toffB;
8726               }
8727             }
8728 
8729             /* Localize new coordinates on each refined cell */
8730             for (s = 0; s < rStarSize*2; s += 2) {
8731               if ((rStar[s] >= cStartNew) && (rStar[s] < cEndNew) && parentId[rStar[s]-cStartNew] == cell) {
8732                 PetscInt       *rcone = NULL, rclosureSize, lid, p, rcdof;
8733                 const PetscInt  rcell = rStar[s];
8734 
8735                 ierr = PetscSectionGetDof(coordSectionNew, rcell, &rcdof);CHKERRQ(ierr);
8736                 if (!rcdof) continue;
8737                 ierr = PetscSectionGetOffset(coordSectionNew, rcell, &coff);CHKERRQ(ierr);
8738                 ierr = DMPlexGetTransitiveClosure(rdm, rcell, PETSC_TRUE, &rclosureSize, &rcone);CHKERRQ(ierr);
8739                 for (p = 0, lid = 0; p < rclosureSize*2; p += 2) {
8740                   if (rcone[p] == newv) {
8741                     for (d = 0; d < spaceDim; d++) coordsNew[coff + lid*spaceDim + d] = coordsNewAux[d];
8742                     break;
8743                   }
8744                   if (rcone[p] >= vStartNew && rcone[p] < vEndNew) lid++;
8745                 }
8746                 ierr = DMPlexRestoreTransitiveClosure(rdm, rcell, PETSC_TRUE, &rclosureSize, &rcone);CHKERRQ(ierr);
8747                 if (p == rclosureSize*2) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Unable to map new vertex %D",newv);
8748               }
8749             }
8750           }
8751         }
8752         ierr = DMPlexRestoreTransitiveClosure(dm, e, PETSC_FALSE, &eStarSize, &eStar);CHKERRQ(ierr);
8753         ierr = DMPlexRestoreTransitiveClosure(rdm, newv, PETSC_FALSE, &rStarSize, &rStar);CHKERRQ(ierr);
8754         if (!cellfound) {
8755           /* Could not find a valid edge for the vertex part, we will get this vertex later (final reduction) */
8756           needcoords = PETSC_TRUE;
8757         }
8758       } else {
8759         ierr = PetscSectionGetOffset(coordSection, cone[0], &offA);CHKERRQ(ierr);
8760         ierr = PetscSectionGetOffset(coordSection, cone[1], &offB);CHKERRQ(ierr);
8761       }
8762       ierr = PetscSectionGetOffset(coordSectionNew, newv, &offnew);CHKERRQ(ierr);
8763       if (offA != -1 && offB != -1) {
8764         ierr = DMLocalizeCoordinate_Internal(dm, spaceDim, &coords[offA], &coords[offB], &coordsNew[offnew]);CHKERRQ(ierr);
8765         for (d = 0; d < spaceDim; ++d) {
8766           coordsNew[offnew+d] = 0.5*(coords[offA+d] + coordsNew[offnew+d]);
8767           ierr = DMPlexSnapToGeomModel(dm, e, &coordsNew[offnew], &coordsNew[offnew]);CHKERRQ(ierr);
8768         }
8769       } else {
8770         for (d = 0; d < spaceDim; ++d) coordsNew[offnew+d] = PETSC_MIN_REAL;
8771       }
8772     }
8773     /* Old vertices have the same coordinates */
8774     for (v = vStart; v < vEnd; ++v) {
8775       const PetscInt newv = vStartNew + (v - vStart);
8776       PetscInt       off, offnew, d;
8777 
8778       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
8779       ierr = PetscSectionGetOffset(coordSectionNew, newv, &offnew);CHKERRQ(ierr);
8780       for (d = 0; d < spaceDim; ++d) {
8781         coordsNew[offnew+d] = coords[off+d];
8782       }
8783 
8784       /* Localize new coordinates on each refined cell */
8785       if (localize) {
8786         PetscInt  p;
8787         PetscInt *rStar = NULL, rStarSize;
8788 
8789         ierr = DMPlexGetTransitiveClosure(rdm, newv, PETSC_FALSE, &rStarSize, &rStar);CHKERRQ(ierr);
8790         for (p = 0; p < rStarSize*2; p += 2) {
8791           if ((rStar[p] >= cStartNew) && (rStar[p] < cEndNew)) {
8792             PetscScalar  ocoords[3] = {0,0,0}; /* dummy values for compiler warnings about uninitialized values */
8793             PetscInt    *cone = NULL, closureSize, lid, coff, s, oc, cdof;
8794 
8795             c    = rStar[p];
8796             oc   = parentId[c-cStartNew];
8797             ierr = PetscSectionGetDof(coordSectionNew, c, &cdof);CHKERRQ(ierr);
8798             if (!cdof) continue;
8799             ierr = PetscSectionGetDof(coordSection, oc, &cdof);CHKERRQ(ierr);
8800             if (!cdof) continue;
8801             ierr = PetscSectionGetOffset(coordSection, oc, &coff);CHKERRQ(ierr);
8802             ierr = DMPlexGetTransitiveClosure(dm, oc, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
8803             for (s = 0, lid = 0; s < closureSize*2; s += 2) {
8804               if (cone[s] == v) {
8805                 for (d = 0; d < spaceDim; d++) ocoords[d] = coords[coff + lid*spaceDim + d];
8806                 break;
8807               }
8808               if (cone[s] >= vStart && cone[s] < vEnd) lid++;
8809             }
8810             if (s == closureSize*2) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Unable to map old vertex %D",v);
8811             ierr = DMPlexRestoreTransitiveClosure(dm, oc, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
8812 
8813             ierr = PetscSectionGetOffset(coordSectionNew, c, &coff);CHKERRQ(ierr);
8814             ierr = DMPlexGetTransitiveClosure(rdm, c, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
8815             for (s = 0, lid = 0; s < closureSize*2; s += 2) {
8816               if (cone[s] == newv) {
8817                 for (d = 0; d < spaceDim; d++) coordsNew[coff + lid*spaceDim + d] = ocoords[d];
8818                 break;
8819               }
8820               if (cone[s] >= vStartNew && cone[s] < vEndNew) lid++;
8821             }
8822             if (s == closureSize*2) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Unable to map new vertex %D",newv);
8823             ierr = DMPlexRestoreTransitiveClosure(rdm, c, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
8824           }
8825         }
8826         ierr = DMPlexRestoreTransitiveClosure(rdm, newv, PETSC_FALSE, &rStarSize, &rStar);CHKERRQ(ierr);
8827       }
8828     }
8829     break;
8830   default:
8831     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %s", CellRefiners[refiner]);
8832   }
8833   ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
8834   ierr = VecRestoreArray(coordinatesNew, &coordsNew);CHKERRQ(ierr);
8835   ierr = DMSetCoordinatesLocal(rdm, coordinatesNew);CHKERRQ(ierr);
8836 
8837   /* Final reduction (if needed) if we are localizing */
8838   if (localize) {
8839     PetscBool gred;
8840 
8841     ierr = MPIU_Allreduce(&needcoords, &gred, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject)rdm));CHKERRQ(ierr);
8842     if (gred) {
8843       DM                 cdm;
8844       Vec                aux;
8845       PetscSF            sf;
8846       const PetscScalar *lArray;
8847       PetscScalar       *gArray;
8848 #if defined(PETSC_USE_COMPLEX)
8849       PetscInt          i, ln, gn;
8850       PetscReal         *lrArray;
8851       PetscReal         *grArray;
8852 #endif
8853 
8854       ierr = DMGetCoordinateDM(rdm, &cdm);CHKERRQ(ierr);
8855       ierr = DMCreateGlobalVector(cdm, &aux);CHKERRQ(ierr);
8856       ierr = DMGetSectionSF(cdm, &sf);CHKERRQ(ierr);
8857       ierr = VecGetArrayRead(coordinatesNew, &lArray);CHKERRQ(ierr);
8858       ierr = VecSet(aux, PETSC_MIN_REAL);CHKERRQ(ierr);
8859       ierr = VecGetArray(aux, &gArray);CHKERRQ(ierr);
8860 #if defined(PETSC_USE_COMPLEX)
8861       ierr = VecGetLocalSize(aux, &gn);CHKERRQ(ierr);
8862       ierr = VecGetLocalSize(coordinatesNew, &ln);CHKERRQ(ierr);
8863       ierr = PetscMalloc2(ln,&lrArray,gn,&grArray);CHKERRQ(ierr);
8864       for (i=0;i<ln;i++) lrArray[i] = PetscRealPart(lArray[i]);
8865       for (i=0;i<gn;i++) grArray[i] = PetscRealPart(gArray[i]);
8866       ierr = PetscSFReduceBegin(sf, MPIU_REAL, lrArray, grArray, MPIU_MAX);CHKERRQ(ierr);
8867       ierr = PetscSFReduceEnd(sf, MPIU_REAL, lrArray, grArray, MPIU_MAX);CHKERRQ(ierr);
8868       for (i=0;i<gn;i++) gArray[i] = grArray[i];
8869       ierr = PetscFree2(lrArray,grArray);CHKERRQ(ierr);
8870 #else
8871       ierr = PetscSFReduceBegin(sf, MPIU_SCALAR, lArray, gArray, MPIU_MAX);CHKERRQ(ierr);
8872       ierr = PetscSFReduceEnd(sf, MPIU_SCALAR, lArray, gArray, MPIU_MAX);CHKERRQ(ierr);
8873 #endif
8874       ierr = VecRestoreArrayRead(coordinatesNew, &lArray);CHKERRQ(ierr);
8875       ierr = VecRestoreArray(aux, &gArray);CHKERRQ(ierr);
8876       ierr = DMGlobalToLocalBegin(cdm, aux, INSERT_VALUES, coordinatesNew);CHKERRQ(ierr);
8877       ierr = DMGlobalToLocalEnd(cdm, aux, INSERT_VALUES, coordinatesNew);CHKERRQ(ierr);
8878       ierr = VecDestroy(&aux);CHKERRQ(ierr);
8879     }
8880   }
8881   ierr = VecDestroy(&coordinatesNew);CHKERRQ(ierr);
8882   ierr = PetscSectionDestroy(&coordSectionNew);CHKERRQ(ierr);
8883   ierr = PetscFree(parentId);CHKERRQ(ierr);
8884   PetscFunctionReturn(0);
8885 }
8886 
8887 /*@
8888   DMPlexCreateProcessSF - Create an SF which just has process connectivity
8889 
8890   Collective on dm
8891 
8892   Input Parameters:
8893 + dm      - The DM
8894 - sfPoint - The PetscSF which encodes point connectivity
8895 
8896   Output Parameters:
8897 + processRanks - A list of process neighbors, or NULL
8898 - sfProcess    - An SF encoding the process connectivity, or NULL
8899 
8900   Level: developer
8901 
8902 .seealso: PetscSFCreate(), DMPlexCreateTwoSidedProcessSF()
8903 @*/
8904 PetscErrorCode DMPlexCreateProcessSF(DM dm, PetscSF sfPoint, IS *processRanks, PetscSF *sfProcess)
8905 {
8906   PetscInt           numRoots, numLeaves, l;
8907   const PetscInt    *localPoints;
8908   const PetscSFNode *remotePoints;
8909   PetscInt          *localPointsNew;
8910   PetscSFNode       *remotePointsNew;
8911   PetscInt          *ranks, *ranksNew;
8912   PetscMPIInt        size;
8913   PetscErrorCode     ierr;
8914 
8915   PetscFunctionBegin;
8916   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8917   PetscValidHeaderSpecific(sfPoint, PETSCSF_CLASSID, 2);
8918   if (processRanks) {PetscValidPointer(processRanks, 3);}
8919   if (sfProcess)    {PetscValidPointer(sfProcess, 4);}
8920   ierr = MPI_Comm_size(PetscObjectComm((PetscObject) dm), &size);CHKERRQ(ierr);
8921   ierr = PetscSFGetGraph(sfPoint, &numRoots, &numLeaves, &localPoints, &remotePoints);CHKERRQ(ierr);
8922   ierr = PetscMalloc1(numLeaves, &ranks);CHKERRQ(ierr);
8923   for (l = 0; l < numLeaves; ++l) {
8924     ranks[l] = remotePoints[l].rank;
8925   }
8926   ierr = PetscSortRemoveDupsInt(&numLeaves, ranks);CHKERRQ(ierr);
8927   ierr = PetscMalloc1(numLeaves, &ranksNew);CHKERRQ(ierr);
8928   ierr = PetscMalloc1(numLeaves, &localPointsNew);CHKERRQ(ierr);
8929   ierr = PetscMalloc1(numLeaves, &remotePointsNew);CHKERRQ(ierr);
8930   for (l = 0; l < numLeaves; ++l) {
8931     ranksNew[l]              = ranks[l];
8932     localPointsNew[l]        = l;
8933     remotePointsNew[l].index = 0;
8934     remotePointsNew[l].rank  = ranksNew[l];
8935   }
8936   ierr = PetscFree(ranks);CHKERRQ(ierr);
8937   if (processRanks) {ierr = ISCreateGeneral(PetscObjectComm((PetscObject)dm), numLeaves, ranksNew, PETSC_OWN_POINTER, processRanks);CHKERRQ(ierr);}
8938   else              {ierr = PetscFree(ranksNew);CHKERRQ(ierr);}
8939   if (sfProcess) {
8940     ierr = PetscSFCreate(PetscObjectComm((PetscObject)dm), sfProcess);CHKERRQ(ierr);
8941     ierr = PetscObjectSetName((PetscObject) *sfProcess, "Process SF");CHKERRQ(ierr);
8942     ierr = PetscSFSetFromOptions(*sfProcess);CHKERRQ(ierr);
8943     ierr = PetscSFSetGraph(*sfProcess, size, numLeaves, localPointsNew, PETSC_OWN_POINTER, remotePointsNew, PETSC_OWN_POINTER);CHKERRQ(ierr);
8944   }
8945   PetscFunctionReturn(0);
8946 }
8947 
8948 static PetscErrorCode CellRefinerCreateSF(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
8949 {
8950   PetscSF            sf, sfNew, sfProcess;
8951   IS                 processRanks;
8952   MPI_Datatype       depthType;
8953   PetscInt           numRoots, numLeaves, numLeavesNew = 0, l, m;
8954   const PetscInt    *localPoints, *neighbors;
8955   const PetscSFNode *remotePoints;
8956   PetscInt          *localPointsNew;
8957   PetscSFNode       *remotePointsNew;
8958   PetscInt          *depthSizeOld, *rdepthSize, *rdepthSizeOld, *rdepthMaxOld, *rvStart, *rvStartNew, *reStart, *reStartNew, *rfStart, *rfStartNew, *rcStart, *rcStartNew;
8959   PetscInt           ldepth, depth, numNeighbors, pStartNew, pEndNew, cStart, cEnd, cMax, vStart, vEnd, vMax, fStart, fEnd, fMax, eStart, eEnd, eMax, r, n;
8960   PetscInt           cStartNew = 0, vStartNew = 0, fStartNew = 0, eStartNew = 0;
8961   PetscErrorCode     ierr;
8962 
8963   PetscFunctionBegin;
8964   ierr = DMPlexGetChart(rdm, &pStartNew, &pEndNew);CHKERRQ(ierr);
8965   ierr = DMPlexGetDepth(dm, &ldepth);CHKERRQ(ierr);
8966   ierr = MPIU_Allreduce(&ldepth, &depth, 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject) dm));CHKERRQ(ierr);
8967   if ((ldepth >= 0) && (depth != ldepth)) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Inconsistent Plex depth %D != %D", ldepth, depth);
8968   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
8969   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
8970   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
8971   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
8972   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
8973   cMax = cMax < 0 ? cEnd : cMax;
8974   fMax = fMax < 0 ? fEnd : fMax;
8975   eMax = eMax < 0 ? eEnd : eMax;
8976   if (refiner) {ierr = GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);CHKERRQ(ierr);}
8977   ierr = DMGetPointSF(dm, &sf);CHKERRQ(ierr);
8978   ierr = DMGetPointSF(rdm, &sfNew);CHKERRQ(ierr);
8979   /* Calculate size of new SF */
8980   ierr = PetscSFGetGraph(sf, &numRoots, &numLeaves, &localPoints, &remotePoints);CHKERRQ(ierr);
8981   if (numRoots < 0) PetscFunctionReturn(0);
8982   for (l = 0; l < numLeaves; ++l) {
8983     const PetscInt p = localPoints[l];
8984 
8985     switch (refiner) {
8986     case REFINER_SIMPLEX_1D:
8987       if ((p >= vStart) && (p < vEnd)) {
8988         /* Interior vertices stay the same */
8989         ++numLeavesNew;
8990       } else if ((p >= cStart && p < cMax)) {
8991         /* Interior cells add new cells and interior vertices */
8992         numLeavesNew += 2 + 1;
8993       }
8994       break;
8995     case REFINER_SIMPLEX_2D:
8996     case REFINER_HYBRID_SIMPLEX_2D:
8997       if ((p >= vStart) && (p < vEnd)) {
8998         /* Interior vertices stay the same */
8999         ++numLeavesNew;
9000       } else if ((p >= fStart) && (p < fMax)) {
9001         /* Interior faces add new faces and vertex */
9002         numLeavesNew += 2 + 1;
9003       } else if ((p >= fMax) && (p < fEnd)) {
9004         /* Hybrid faces stay the same */
9005         ++numLeavesNew;
9006       } else if ((p >= cStart) && (p < cMax)) {
9007         /* Interior cells add new cells and interior faces */
9008         numLeavesNew += 4 + 3;
9009       } else if ((p >= cMax) && (p < cEnd)) {
9010         /* Hybrid cells add new cells and hybrid face */
9011         numLeavesNew += 2 + 1;
9012       }
9013       break;
9014     case REFINER_HYBRID_SIMPLEX_TO_HEX_2D:
9015     case REFINER_SIMPLEX_TO_HEX_2D:
9016       if ((p >= vStart) && (p < vEnd)) {
9017         /* Interior vertices stay the same */
9018         ++numLeavesNew;
9019       } else if ((p >= fStart) && (p < fEnd)) {
9020         /* Interior faces add new faces and vertex */
9021         numLeavesNew += 2 + 1;
9022       } else if ((p >= cStart) && (p < cMax)) {
9023         /* Interior cells add new cells, interior faces, and vertex */
9024         numLeavesNew += 3 + 3 + 1;
9025       } else if ((p >= cMax) && (p < cEnd)) {
9026         /* Hybrid cells add new cells, interior faces, and vertex */
9027         numLeavesNew += 4 + 4 + 1;
9028       }
9029       break;
9030     case REFINER_HEX_2D:
9031     case REFINER_HYBRID_HEX_2D:
9032       if ((p >= vStart) && (p < vEnd)) {
9033         /* Interior vertices stay the same */
9034         ++numLeavesNew;
9035       } else if ((p >= fStart) && (p < fMax)) {
9036         /* Interior faces add new faces and vertex */
9037         numLeavesNew += 2 + 1;
9038       } else if ((p >= fMax) && (p < fEnd)) {
9039         /* Hybrid faces stay the same */
9040         ++numLeavesNew;
9041       } else if ((p >= cStart) && (p < cMax)) {
9042         /* Interior cells add new cells, interior faces, and vertex */
9043         numLeavesNew += 4 + 4 + 1;
9044       } else if ((p >= cMax) && (p < cEnd)) {
9045         /* Hybrid cells add new cells and hybrid face */
9046         numLeavesNew += 2 + 1;
9047       }
9048       break;
9049     case REFINER_SIMPLEX_3D:
9050     case REFINER_HYBRID_SIMPLEX_3D:
9051       if ((p >= vStart) && (p < vEnd)) {
9052         /* Interior vertices stay the same */
9053         ++numLeavesNew;
9054       } else if ((p >= eStart) && (p < eMax)) {
9055         /* Interior edges add new edges and vertex */
9056         numLeavesNew += 2 + 1;
9057       } else if ((p >= eMax) && (p < eEnd)) {
9058         /* Hybrid edges stay the same */
9059         ++numLeavesNew;
9060       } else if ((p >= fStart) && (p < fMax)) {
9061         /* Interior faces add new faces and edges */
9062         numLeavesNew += 4 + 3;
9063       } else if ((p >= fMax) && (p < fEnd)) {
9064         /* Hybrid faces add new faces and edges */
9065         numLeavesNew += 2 + 1;
9066       } else if ((p >= cStart) && (p < cMax)) {
9067         /* Interior cells add new cells, faces, and edges */
9068         numLeavesNew += 8 + 8 + 1;
9069       } else if ((p >= cMax) && (p < cEnd)) {
9070         /* Hybrid cells add new cells and faces */
9071         numLeavesNew += 4 + 3;
9072       }
9073       break;
9074     case REFINER_HYBRID_SIMPLEX_TO_HEX_3D:
9075     case REFINER_SIMPLEX_TO_HEX_3D:
9076       if ((p >= vStart) && (p < vEnd)) {
9077         /* Interior vertices stay the same */
9078         ++numLeavesNew;
9079       } else if ((p >= eStart) && (p < eMax)) {
9080         /* Interior edges add new edges and vertex */
9081         numLeavesNew += 2 + 1;
9082       } else if ((p >= eMax) && (p < eEnd)) {
9083         /* Hybrid edges stay the same */
9084         ++numLeavesNew;
9085       } else if ((p >= fStart) && (p < fMax)) {
9086         /* Interior faces add new faces, edges and a vertex */
9087         numLeavesNew += 3 + 3 + 1;
9088       } else if ((p >= fMax) && (p < fEnd)) {
9089         /* Hybrid faces add new faces and an edge */
9090         numLeavesNew += 2 + 1;
9091       } else if ((p >= cStart) && (p < cMax)) {
9092         /* Interior cells add new cells, faces, edges and a vertex */
9093         numLeavesNew += 4 + 6 + 4 + 1;
9094       } else if ((p >= cMax) && (p < cEnd)) {
9095         /* Hybrid cells add new cells, faces and an edge */
9096         numLeavesNew += 3 + 3 + 1;
9097       }
9098       break;
9099     case REFINER_HEX_3D:
9100     case REFINER_HYBRID_HEX_3D:
9101       if ((p >= vStart) && (p < vEnd)) {
9102         /* Old vertices stay the same */
9103         ++numLeavesNew;
9104       } else if ((p >= eStart) && (p < eMax)) {
9105         /* Interior edges add new edges, and vertex */
9106         numLeavesNew += 2 + 1;
9107       } else if ((p >= eMax) && (p < eEnd)) {
9108         /* Hybrid edges stay the same */
9109         ++numLeavesNew;
9110       } else if ((p >= fStart) && (p < fMax)) {
9111         /* Interior faces add new faces, edges, and vertex */
9112         numLeavesNew += 4 + 4 + 1;
9113       } else if ((p >= fMax) && (p < fEnd)) {
9114         /* Hybrid faces add new faces and edges */
9115         numLeavesNew += 2 + 1;
9116       } else if ((p >= cStart) && (p < cMax)) {
9117         /* Interior cells add new cells, faces, edges, and vertex */
9118         numLeavesNew += 8 + 12 + 6 + 1;
9119       } else if ((p >= cStart) && (p < cEnd)) {
9120         /* Hybrid cells add new cells, faces, and edges */
9121         numLeavesNew += 4 + 4 + 1;
9122       }
9123       break;
9124     default:
9125       SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %s", CellRefiners[refiner]);
9126     }
9127   }
9128   /* Communicate depthSizes for each remote rank */
9129   ierr = DMPlexCreateProcessSF(dm, sf, &processRanks, &sfProcess);CHKERRQ(ierr);
9130   ierr = ISGetLocalSize(processRanks, &numNeighbors);CHKERRQ(ierr);
9131   ierr = PetscMalloc5((depth+1)*numNeighbors,&rdepthSize,numNeighbors,&rvStartNew,numNeighbors,&reStartNew,numNeighbors,&rfStartNew,numNeighbors,&rcStartNew);CHKERRQ(ierr);
9132   ierr = PetscMalloc7(depth+1,&depthSizeOld,(depth+1)*numNeighbors,&rdepthSizeOld,(depth+1)*numNeighbors,&rdepthMaxOld,numNeighbors,&rvStart,numNeighbors,&reStart,numNeighbors,&rfStart,numNeighbors,&rcStart);CHKERRQ(ierr);
9133   ierr = MPI_Type_contiguous(depth+1, MPIU_INT, &depthType);CHKERRQ(ierr);
9134   ierr = MPI_Type_commit(&depthType);CHKERRQ(ierr);
9135   ierr = PetscSFBcastBegin(sfProcess, depthType, depthSize, rdepthSize);CHKERRQ(ierr);
9136   ierr = PetscSFBcastEnd(sfProcess, depthType, depthSize, rdepthSize);CHKERRQ(ierr);
9137   for (n = 0; n < numNeighbors; ++n) {
9138     ierr = GetDepthStart_Private(depth, &rdepthSize[n*(depth+1)], &rcStartNew[n], &rfStartNew[n], &reStartNew[n], &rvStartNew[n]);CHKERRQ(ierr);
9139   }
9140   depthSizeOld[depth]   = cMax;
9141   depthSizeOld[0]       = vMax;
9142   depthSizeOld[depth-1] = fMax;
9143   depthSizeOld[1]       = eMax;
9144 
9145   ierr = PetscSFBcastBegin(sfProcess, depthType, depthSizeOld, rdepthMaxOld);CHKERRQ(ierr);
9146   ierr = PetscSFBcastEnd(sfProcess, depthType, depthSizeOld, rdepthMaxOld);CHKERRQ(ierr);
9147 
9148   depthSizeOld[depth]   = cEnd - cStart;
9149   depthSizeOld[0]       = vEnd - vStart;
9150   depthSizeOld[depth-1] = fEnd - fStart;
9151   depthSizeOld[1]       = eEnd - eStart;
9152 
9153   ierr = PetscSFBcastBegin(sfProcess, depthType, depthSizeOld, rdepthSizeOld);CHKERRQ(ierr);
9154   ierr = PetscSFBcastEnd(sfProcess, depthType, depthSizeOld, rdepthSizeOld);CHKERRQ(ierr);
9155   for (n = 0; n < numNeighbors; ++n) {
9156     ierr = GetDepthStart_Private(depth, &rdepthSizeOld[n*(depth+1)], &rcStart[n], &rfStart[n], &reStart[n], &rvStart[n]);CHKERRQ(ierr);
9157     rdepthMaxOld[n*(depth+1)+depth]   = rdepthMaxOld[n*(depth+1)+depth]   < 0 ? rdepthSizeOld[n*(depth+1)+depth]  +rcStart[n]: rdepthMaxOld[n*(depth+1)+depth];
9158     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];
9159     rdepthMaxOld[n*(depth+1)+1]       = rdepthMaxOld[n*(depth+1)+1]       < 0 ? rdepthSizeOld[n*(depth+1)+1]      +reStart[n]: rdepthMaxOld[n*(depth+1)+1];
9160   }
9161   ierr = MPI_Type_free(&depthType);CHKERRQ(ierr);
9162   ierr = PetscSFDestroy(&sfProcess);CHKERRQ(ierr);
9163   /* Calculate new point SF */
9164   ierr = PetscMalloc1(numLeavesNew, &localPointsNew);CHKERRQ(ierr);
9165   ierr = PetscMalloc1(numLeavesNew, &remotePointsNew);CHKERRQ(ierr);
9166   ierr = ISGetIndices(processRanks, &neighbors);CHKERRQ(ierr);
9167   for (l = 0, m = 0; l < numLeaves; ++l) {
9168     PetscInt    p     = localPoints[l];
9169     PetscInt    rp    = remotePoints[l].index, n;
9170     PetscMPIInt rrank = remotePoints[l].rank;
9171 
9172     ierr = PetscFindInt(rrank, numNeighbors, neighbors, &n);CHKERRQ(ierr);
9173     if (n < 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Could not locate remote rank %D", rrank);
9174     switch (refiner) {
9175     case REFINER_SIMPLEX_1D:
9176       if ((p >= vStart) && (p < vEnd)) {
9177         /* Old vertices stay the same */
9178         localPointsNew[m]        = vStartNew     + (p  - vStart);
9179         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
9180         remotePointsNew[m].rank  = rrank;
9181         ++m;
9182       } else if ((p >= cStart) && (p < cMax)) {
9183         /* Old interior cells add new cells and vertex */
9184         for (r = 0; r < 2; ++r, ++m) {
9185           localPointsNew[m]        = cStartNew     + (p  - cStart)*2     + r;
9186           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*2 + r;
9187           remotePointsNew[m].rank  = rrank;
9188         }
9189         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - cStart);
9190         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - rcStart[n]);
9191         remotePointsNew[m].rank  = rrank;
9192         ++m;
9193       }
9194       break;
9195     case REFINER_SIMPLEX_2D:
9196     case REFINER_HYBRID_SIMPLEX_2D:
9197       if ((p >= vStart) && (p < vEnd)) {
9198         /* Old vertices stay the same */
9199         localPointsNew[m]        = vStartNew     + (p  - vStart);
9200         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
9201         remotePointsNew[m].rank  = rrank;
9202         ++m;
9203       } else if ((p >= fStart) && (p < fMax)) {
9204         /* Old interior faces add new faces and vertex */
9205         for (r = 0; r < 2; ++r, ++m) {
9206           localPointsNew[m]        = fStartNew     + (p  - fStart)*2     + r;
9207           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*2 + r;
9208           remotePointsNew[m].rank  = rrank;
9209         }
9210         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - fStart);
9211         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - rfStart[n]);
9212         remotePointsNew[m].rank  = rrank;
9213         ++m;
9214       } else if ((p >= fMax) && (p < fEnd)) {
9215         /* Old hybrid faces stay the same */
9216         localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (p  - fMax);
9217         remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*2 + (rp - rdepthMaxOld[n*(depth+1)+depth-1]);
9218         remotePointsNew[m].rank  = rrank;
9219         ++m;
9220       } else if ((p >= cStart) && (p < cMax)) {
9221         /* Old interior cells add new cells and interior faces */
9222         for (r = 0; r < 4; ++r, ++m) {
9223           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
9224           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
9225           remotePointsNew[m].rank  = rrank;
9226         }
9227         for (r = 0; r < 3; ++r, ++m) {
9228           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (p  - cStart)*3     + r;
9229           remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*2 + (rp - rcStart[n])*3 + r;
9230           remotePointsNew[m].rank  = rrank;
9231         }
9232       } else if ((p >= cMax) && (p < cEnd)) {
9233         /* Old hybrid cells add new cells and hybrid face */
9234         for (r = 0; r < 2; ++r, ++m) {
9235           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
9236           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
9237           remotePointsNew[m].rank  = rrank;
9238         }
9239         localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (cMax                            - cStart)*3     + (p  - cMax);
9240         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]);
9241         remotePointsNew[m].rank  = rrank;
9242         ++m;
9243       }
9244       break;
9245     case REFINER_HYBRID_SIMPLEX_TO_HEX_2D:
9246     case REFINER_SIMPLEX_TO_HEX_2D:
9247       if ((p >= vStart) && (p < vEnd)) {
9248         /* Old vertices stay the same */
9249         localPointsNew[m]        = vStartNew     + (p  - vStart);
9250         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
9251         remotePointsNew[m].rank  = rrank;
9252         ++m;
9253       } else if ((p >= fStart) && (p < fEnd)) {
9254         /* Old interior faces add new faces and vertex */
9255         for (r = 0; r < 2; ++r, ++m) {
9256           localPointsNew[m]        = fStartNew     + (p  - fStart)*2     + r;
9257           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*2 + r;
9258           remotePointsNew[m].rank  = rrank;
9259         }
9260         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - fStart);
9261         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - rfStart[n]);
9262         remotePointsNew[m].rank  = rrank;
9263         ++m;
9264       } else if ((p >= cStart) && (p < cMax)) {
9265         /* Old interior cells add new cells, interior faces, and a vertex */
9266         for (r = 0; r < 3; ++r, ++m) {
9267           localPointsNew[m]        = cStartNew     + (p  - cStart)*3     + r;
9268           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*3 + r;
9269           remotePointsNew[m].rank  = rrank;
9270         }
9271         for (r = 0; r < 3; ++r, ++m) {
9272           localPointsNew[m]        = fStartNew     + (fEnd - fStart)*2                    + (p  - cStart)*3     + r;
9273           remotePointsNew[m].index = rfStartNew[n] + rdepthSizeOld[n*(depth+1)+depth-1]*2 + (rp - rcStart[n])*3 + r;
9274           remotePointsNew[m].rank  = rrank;
9275         }
9276         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (fEnd - fStart)                    + (p  - cStart);
9277         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + rdepthSizeOld[n*(depth+1)+depth-1] + (rp - rcStart[n]);
9278         remotePointsNew[m].rank  = rrank;
9279         ++m;
9280       } else if ((p >= cMax) && (p < cEnd)) {
9281         /* Old interior hybrid cells add new cells, interior faces, and a vertex */
9282         for (r = 0; r < 4; ++r, ++m) {
9283           localPointsNew[m]        = cStartNew     + (cMax  - cStart)*3                               + (p  - cMax)*4 + r;
9284           remotePointsNew[m].index = rcStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth] - rcStart[n])*3 + (rp - rdepthMaxOld[n*(depth+1)+depth])*4 + r;
9285           remotePointsNew[m].rank  = rrank;
9286         }
9287         for (r = 0; r < 4; ++r, ++m) {
9288           localPointsNew[m]        = fStartNew     + (fEnd - fStart)*2                    + (cMax  - cStart)*3                               + (p - cMax)*4 + r;
9289           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;
9290           remotePointsNew[m].rank  = rrank;
9291         }
9292         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (fEnd - fStart)                    + (p  - cStart);
9293         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + rdepthSizeOld[n*(depth+1)+depth-1] + (rp - rcStart[n]);
9294         remotePointsNew[m].rank  = rrank;
9295         ++m;
9296       }
9297       break;
9298     case REFINER_HEX_2D:
9299     case REFINER_HYBRID_HEX_2D:
9300       if ((p >= vStart) && (p < vEnd)) {
9301         /* Old vertices stay the same */
9302         localPointsNew[m]        = vStartNew     + (p  - vStart);
9303         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
9304         remotePointsNew[m].rank  = rrank;
9305         ++m;
9306       } else if ((p >= fStart) && (p < fMax)) {
9307         /* Old interior faces add new faces and vertex */
9308         for (r = 0; r < 2; ++r, ++m) {
9309           localPointsNew[m]        = fStartNew     + (p  - fStart)*2     + r;
9310           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*2 + r;
9311           remotePointsNew[m].rank  = rrank;
9312         }
9313         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - fStart);
9314         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - rfStart[n]);
9315         remotePointsNew[m].rank  = rrank;
9316         ++m;
9317       } else if ((p >= fMax) && (p < fEnd)) {
9318         /* Old hybrid faces stay the same */
9319         localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (p  - fMax);
9320         remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*2 + (rp - rdepthMaxOld[n*(depth+1)+depth-1]);
9321         remotePointsNew[m].rank  = rrank;
9322         ++m;
9323       } else if ((p >= cStart) && (p < cMax)) {
9324         /* Old interior cells add new cells, interior faces, and vertex */
9325         for (r = 0; r < 4; ++r, ++m) {
9326           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
9327           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
9328           remotePointsNew[m].rank  = rrank;
9329         }
9330         for (r = 0; r < 4; ++r, ++m) {
9331           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (p  - cStart)*4     + r;
9332           remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*2 + (rp - rcStart[n])*4 + r;
9333           remotePointsNew[m].rank  = rrank;
9334         }
9335         localPointsNew[m]        = vStartNew     + (vEnd - vStart)               + (fMax                              - fStart)     + (p  - cStart);
9336         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0]  + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n]) + (rp - rcStart[n]);
9337         remotePointsNew[m].rank  = rrank;
9338         ++m;
9339       } else if ((p >= cStart) && (p < cMax)) {
9340         /* Old hybrid cells add new cells and hybrid face */
9341         for (r = 0; r < 2; ++r, ++m) {
9342           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r; /* TODO: is this a bug? */
9343           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r; /* TODO: is this a bug? */
9344           remotePointsNew[m].rank  = rrank;
9345         }
9346         localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (cMax                            - cStart)*4     + (p  - cMax);
9347         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]);
9348         remotePointsNew[m].rank  = rrank;
9349         ++m;
9350       }
9351       break;
9352     case REFINER_SIMPLEX_3D:
9353     case REFINER_HYBRID_SIMPLEX_3D:
9354       if ((p >= vStart) && (p < vEnd)) {
9355         /* Interior vertices stay the same */
9356         localPointsNew[m]        = vStartNew     + (p  - vStart);
9357         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
9358         remotePointsNew[m].rank  = rrank;
9359         ++m;
9360       } else if ((p >= eStart) && (p < eMax)) {
9361         /* Interior edges add new edges and vertex */
9362         for (r = 0; r < 2; ++r, ++m) {
9363           localPointsNew[m]        = eStartNew     + (p  - eStart)*2     + r;
9364           remotePointsNew[m].index = reStartNew[n] + (rp - reStart[n])*2 + r;
9365           remotePointsNew[m].rank  = rrank;
9366         }
9367         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - eStart);
9368         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - reStart[n]);
9369         remotePointsNew[m].rank  = rrank;
9370         ++m;
9371       } else if ((p >= eMax) && (p < eEnd)) {
9372         /* Hybrid edges stay the same */
9373         localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (fMax                              - fStart)*3     + (cMax                            - cStart)     + (p  - eMax);
9374         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]);
9375         remotePointsNew[m].rank  = rrank;
9376         ++m;
9377       } else if ((p >= fStart) && (p < fMax)) {
9378         /* Interior faces add new faces and edges */
9379         for (r = 0; r < 4; ++r, ++m) {
9380           localPointsNew[m]        = fStartNew     + (p  - fStart)*4     + r;
9381           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*4 + r;
9382           remotePointsNew[m].rank  = rrank;
9383         }
9384         for (r = 0; r < 3; ++r, ++m) {
9385           localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (p  - fStart)*3     + r;
9386           remotePointsNew[m].index = reStartNew[n] + (rdepthMaxOld[n*(depth+1)+1] - reStart[n])*2 + (rp - rfStart[n])*3 + r;
9387           remotePointsNew[m].rank  = rrank;
9388         }
9389       } else if ((p >= fMax) && (p < fEnd)) {
9390         /* Hybrid faces add new faces and edges */
9391         for (r = 0; r < 2; ++r, ++m) {
9392           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*4     + (cMax                            - cStart)*8     + (p  - fMax)*2                              + r;
9393           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;
9394           remotePointsNew[m].rank  = rrank;
9395         }
9396         localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (fMax                              - fStart)*3     + (cMax                            - cStart)     + (eEnd                                    - eMax)                        + (p  - fMax);
9397         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]);
9398         remotePointsNew[m].rank  = rrank;
9399         ++m;
9400       } else if ((p >= cStart) && (p < cMax)) {
9401         /* Interior cells add new cells, faces, and edges */
9402         for (r = 0; r < 8; ++r, ++m) {
9403           localPointsNew[m]        = cStartNew     + (p  - cStart)*8     + r;
9404           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*8 + r;
9405           remotePointsNew[m].rank  = rrank;
9406         }
9407         for (r = 0; r < 8; ++r, ++m) {
9408           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*4     + (p  - cStart)*8     + r;
9409           remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*4 + (rp - rcStart[n])*8 + r;
9410           remotePointsNew[m].rank  = rrank;
9411         }
9412         localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (fMax                              - fStart)*3     + (p  - cStart)*1     + 0;
9413         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;
9414         remotePointsNew[m].rank  = rrank;
9415         ++m;
9416       } else if ((p >= cMax) && (p < cEnd)) {
9417         /* Hybrid cells add new cells and faces */
9418         for (r = 0; r < 4; ++r, ++m) {
9419           localPointsNew[m]        = cStartNew     + (cMax                            - cStart)*8     + (p  - cMax)*4                            + r;
9420           remotePointsNew[m].index = rcStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth] - rcStart[n])*8 + (rp - rdepthMaxOld[n*(depth+1)+depth])*4 + r;
9421           remotePointsNew[m].rank  = rrank;
9422         }
9423         for (r = 0; r < 3; ++r, ++m) {
9424           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*4     + (cMax                            - cStart)*8     + (fEnd                                          - fMax)*2                              + (p  - cMax)*3                            + r;
9425           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;
9426           remotePointsNew[m].rank  = rrank;
9427         }
9428       }
9429       break;
9430     case REFINER_HYBRID_SIMPLEX_TO_HEX_3D:
9431     case REFINER_SIMPLEX_TO_HEX_3D:
9432       if ((p >= vStart) && (p < vEnd)) {
9433         /* Interior vertices stay the same */
9434         localPointsNew[m]        = vStartNew     + (p  - vStart);
9435         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
9436         remotePointsNew[m].rank  = rrank;
9437         ++m;
9438       } else if ((p >= eStart) && (p < eMax)) {
9439         /* Interior edges add new edges and vertex */
9440         for (r = 0; r < 2; ++r, ++m) {
9441           localPointsNew[m]        = eStartNew     + (p  - eStart)*2     + r;
9442           remotePointsNew[m].index = reStartNew[n] + (rp - reStart[n])*2 + r;
9443           remotePointsNew[m].rank  = rrank;
9444         }
9445         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - eStart);
9446         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - reStart[n]);
9447         remotePointsNew[m].rank  = rrank;
9448         ++m;
9449       } else if ((p >= eMax) && (p < eEnd)) {
9450         /* Hybrid edges stay the same */
9451         localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (fMax                              - fStart)*3     + (cMax                            - cStart)*4     + (p  - eMax);
9452         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]);
9453         remotePointsNew[m].rank  = rrank;
9454         ++m;
9455       } else if ((p >= fStart) && (p < fMax)) {
9456         /* Interior faces add new faces, edges and a vertex */
9457         for (r = 0; r < 3; ++r, ++m) {
9458           localPointsNew[m]        = fStartNew     + (p  - fStart)*3     + r;
9459           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*3 + r;
9460           remotePointsNew[m].rank  = rrank;
9461         }
9462         for (r = 0; r < 3; ++r, ++m) {
9463           localPointsNew[m]        = eStartNew     + (eMax - eStart)*2                            + (p  - fStart)*3     + r;
9464           remotePointsNew[m].index = reStartNew[n] + (rdepthMaxOld[n*(depth+1)+1] - reStart[n])*2 + (rp - rfStart[n])*3 + r;
9465           remotePointsNew[m].rank  = rrank;
9466         }
9467         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (eMax - eStart)                            + (p - fStart);
9468         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rdepthMaxOld[n*(depth+1)+1] - reStart[n]) + (rp - rfStart[n]);
9469         remotePointsNew[m].rank  = rrank;
9470         ++m;
9471       } else if ((p >= fMax) && (p < fEnd)) {
9472         /* Interior hybrid faces add new faces and an edge */
9473         for (r = 0; r < 2; ++r, ++m) {
9474           localPointsNew[m]        = fStartNew     + (fMax - fStart)*3                                 + (cMax - cStart)*6                                + (p  - fMax)*2 + r;
9475           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;
9476           remotePointsNew[m].rank  = rrank;
9477         }
9478         localPointsNew[m]        = eStartNew     + (eMax - eStart)*2                            + (fMax - fStart)*3                                 + (cMax - cStart)*4                                + (eEnd - eMax)                                                           + (p  - fMax);
9479         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]);
9480         remotePointsNew[m].rank  = rrank;
9481         ++m;
9482       } else if ((p >= cStart) && (p < cMax)) {
9483         /* Interior cells add new cells, faces, edges, and a vertex */
9484         for (r = 0; r < 4; ++r, ++m) {
9485           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
9486           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
9487           remotePointsNew[m].rank  = rrank;
9488         }
9489         for (r = 0; r < 6; ++r, ++m) {
9490           localPointsNew[m]        = fStartNew     + (fMax - fStart)*3                                 + (p  - cStart)*6     + r;
9491           remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1]- rfStart[n])*3 + (rp - rcStart[n])*6 + r;
9492           remotePointsNew[m].rank  = rrank;
9493         }
9494         for (r = 0; r < 4; ++r, ++m) {
9495           localPointsNew[m]        = eStartNew     + (eMax - eStart)*2                           + (fMax - fStart)*3                                 + (p  - cStart)*4 + r;
9496           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;
9497           remotePointsNew[m].rank  = rrank;
9498         }
9499         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (eMax - eStart)                           + (fMax - fStart)                                 + (p  - cStart);
9500         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]);
9501         remotePointsNew[m].rank  = rrank;
9502         ++m;
9503       } else if ((p >= cMax) && (p < cEnd)) {
9504         /* Interior hybrid cells add new cells, faces and an edge */
9505         for (r = 0; r < 3; ++r, ++m) {
9506           localPointsNew[m]        = cStartNew     + (cMax                            - cStart)*4     + (p  - cMax)*3                            + r;
9507           remotePointsNew[m].index = rcStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth] - rcStart[n])*4 + (rp - rdepthMaxOld[n*(depth+1)+depth])*3 + r;
9508           remotePointsNew[m].rank  = rrank;
9509         }
9510         for (r = 0; r < 3; ++r, ++m) {
9511           localPointsNew[m]        = fStartNew     + (fMax - fStart)*3                                 + (cMax - cStart)*6                                + (fEnd  - fMax)*2                                                                      + (p  - cMax)*3 + r;
9512           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;
9513           remotePointsNew[m].rank  = rrank;
9514         }
9515         localPointsNew[m]        = eStartNew     + (eMax - eStart)*2                           + (fMax - fStart)*3                                 + (cMax - cStart)*4                                + (eEnd  - eMax)                                                          + (fEnd  - fMax)                                                                      + (p  - cMax);
9516         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]);
9517         remotePointsNew[m].rank  = rrank;
9518         ++m;
9519       }
9520       break;
9521     case REFINER_HEX_3D:
9522     case REFINER_HYBRID_HEX_3D:
9523       if ((p >= vStart) && (p < vEnd)) {
9524         /* Interior vertices stay the same */
9525         localPointsNew[m]        = vStartNew     + (p  - vStart);
9526         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
9527         remotePointsNew[m].rank  = rrank;
9528         ++m;
9529       } else if ((p >= eStart) && (p < eMax)) {
9530         /* Interior edges add new edges and vertex */
9531         for (r = 0; r < 2; ++r, ++m) {
9532           localPointsNew[m]        = eStartNew     + (p  - eStart)*2     + r;
9533           remotePointsNew[m].index = reStartNew[n] + (rp - reStart[n])*2 + r;
9534           remotePointsNew[m].rank  = rrank;
9535         }
9536         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - eStart);
9537         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - reStart[n]);
9538         remotePointsNew[m].rank  = rrank;
9539         ++m;
9540       } else if ((p >= eMax) && (p < eEnd)) {
9541         /* Hybrid edges stay the same */
9542         localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (fMax                              - fStart)*4     + (cMax                            - cStart)*6     + (p  - eMax);
9543         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]);
9544         remotePointsNew[m].rank  = rrank;
9545         ++m;
9546       } else if ((p >= fStart) && (p < fMax)) {
9547         /* Interior faces add new faces, edges, and vertex */
9548         for (r = 0; r < 4; ++r, ++m) {
9549           localPointsNew[m]        = fStartNew     + (p  - fStart)*4     + r;
9550           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*4 + r;
9551           remotePointsNew[m].rank  = rrank;
9552         }
9553         for (r = 0; r < 4; ++r, ++m) {
9554           localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (p  - fStart)*4     + r;
9555           remotePointsNew[m].index = reStartNew[n] + (rdepthMaxOld[n*(depth+1)+1] - reStart[n])*2 + (rp - rfStart[n])*4 + r;
9556           remotePointsNew[m].rank  = rrank;
9557         }
9558         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (eMax                        - eStart)     + (p  - fStart);
9559         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rdepthMaxOld[n*(depth+1)+1] - reStart[n]) + (rp - rfStart[n]);
9560         remotePointsNew[m].rank  = rrank;
9561         ++m;
9562       } else if ((p >= fMax) && (p < fEnd)) {
9563         /* Hybrid faces add new faces and edges */
9564         for (r = 0; r < 2; ++r, ++m) {
9565           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*4     + (cMax                            - cStart)*12     + (p  - fMax)*2                              + r;
9566           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;
9567           remotePointsNew[m].rank  = rrank;
9568         }
9569         localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (fMax                              - fStart)*4     + (cMax                            - cStart)*6     + (eEnd                                    - eMax)                        + (p  - fMax);
9570         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]);
9571         remotePointsNew[m].rank  = rrank;
9572         ++m;
9573       } else if ((p >= cStart) && (p < cMax)) {
9574         /* Interior cells add new cells, faces, edges, and vertex */
9575         for (r = 0; r < 8; ++r, ++m) {
9576           localPointsNew[m]        = cStartNew     + (p  - cStart)*8     + r;
9577           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*8 + r;
9578           remotePointsNew[m].rank  = rrank;
9579         }
9580         for (r = 0; r < 12; ++r, ++m) {
9581           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*4     + (p  - cStart)*12     + r;
9582           remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*4 + (rp - rcStart[n])*12 + r;
9583           remotePointsNew[m].rank  = rrank;
9584         }
9585         for (r = 0; r < 6; ++r, ++m) {
9586           localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (fMax                              - fStart)*4     + (p  - cStart)*6     + r;
9587           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;
9588           remotePointsNew[m].rank  = rrank;
9589         }
9590         for (r = 0; r < 1; ++r, ++m) {
9591           localPointsNew[m]        = vStartNew     + (eMax                        - eStart)     + (fMax                              - fStart)     + (p  - cStart)     + r;
9592           remotePointsNew[m].index = rvStartNew[n] + (rdepthMaxOld[n*(depth+1)+1] - reStart[n]) + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n]) + (rp - rcStart[n]) + r;
9593           remotePointsNew[m].rank  = rrank;
9594         }
9595       } else if ((p >= cMax) && (p < cEnd)) {
9596         /* Hybrid cells add new cells, faces, and edges */
9597         for (r = 0; r < 4; ++r, ++m) {
9598           localPointsNew[m]        = cStartNew     + (cMax                            - cStart)*8     + (p  - cMax)*4                            + r;
9599           remotePointsNew[m].index = rcStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth] - rcStart[n])*8 + (rp - rdepthMaxOld[n*(depth+1)+depth])*4 + r;
9600           remotePointsNew[m].rank  = rrank;
9601         }
9602         for (r = 0; r < 4; ++r, ++m) {
9603           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*4     + (cMax                            - cStart)*12     + (fEnd                                          - fMax)*2                              + (p  - cMax)*4                            + r;
9604           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;
9605           remotePointsNew[m].rank  = rrank;
9606         }
9607         localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (fMax                              - fStart)*4     + (cMax                            - cStart)*6     + (eEnd                                    - eMax)                        + (fEnd                                          - fMax)                              + (p  - cMax);
9608         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]);
9609         remotePointsNew[m].rank  = rrank;
9610         ++m;
9611       }
9612       break;
9613     default:
9614       SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %s", CellRefiners[refiner]);
9615     }
9616   }
9617   if (m != numLeavesNew) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Number of leaf point %D should be %D", m, numLeavesNew);
9618   ierr = ISRestoreIndices(processRanks, &neighbors);CHKERRQ(ierr);
9619   ierr = ISDestroy(&processRanks);CHKERRQ(ierr);
9620   {
9621     PetscSFNode *rp, *rtmp;
9622     PetscInt    *lp, *idx, *ltmp, i;
9623 
9624     /* SF needs sorted leaves to correct calculate Gather */
9625     ierr = PetscMalloc1(numLeavesNew,&idx);CHKERRQ(ierr);
9626     ierr = PetscMalloc1(numLeavesNew, &lp);CHKERRQ(ierr);
9627     ierr = PetscMalloc1(numLeavesNew, &rp);CHKERRQ(ierr);
9628     for (i = 0; i < numLeavesNew; ++i) {
9629       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);
9630       idx[i] = i;
9631     }
9632     ierr = PetscSortIntWithPermutation(numLeavesNew, localPointsNew, idx);CHKERRQ(ierr);
9633     for (i = 0; i < numLeavesNew; ++i) {
9634       lp[i] = localPointsNew[idx[i]];
9635       rp[i] = remotePointsNew[idx[i]];
9636     }
9637     ltmp            = localPointsNew;
9638     localPointsNew  = lp;
9639     rtmp            = remotePointsNew;
9640     remotePointsNew = rp;
9641     ierr = PetscFree(idx);CHKERRQ(ierr);
9642     ierr = PetscFree(ltmp);CHKERRQ(ierr);
9643     ierr = PetscFree(rtmp);CHKERRQ(ierr);
9644   }
9645   ierr = PetscSFSetGraph(sfNew, pEndNew-pStartNew, numLeavesNew, localPointsNew, PETSC_OWN_POINTER, remotePointsNew, PETSC_OWN_POINTER);CHKERRQ(ierr);
9646   ierr = PetscFree5(rdepthSize,rvStartNew,reStartNew,rfStartNew,rcStartNew);CHKERRQ(ierr);
9647   ierr = PetscFree7(depthSizeOld,rdepthSizeOld,rdepthMaxOld,rvStart,reStart,rfStart,rcStart);CHKERRQ(ierr);
9648   PetscFunctionReturn(0);
9649 }
9650 
9651 static PetscErrorCode CellRefinerCreateLabels(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
9652 {
9653   PetscInt       numLabels, l;
9654   PetscInt       depth, newp, cStart, cEnd, cMax, vStart, vEnd, vMax, fStart, fEnd, fMax, eStart, eEnd, eMax, r;
9655   PetscInt       cStartNew = 0, vStartNew = 0, fStartNew = 0, eStartNew = 0;
9656   PetscErrorCode ierr;
9657 
9658   PetscFunctionBegin;
9659   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
9660   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
9661   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
9662   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
9663   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
9664   if (refiner) {ierr = GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);CHKERRQ(ierr);}
9665   ierr = DMGetNumLabels(dm, &numLabels);CHKERRQ(ierr);
9666   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
9667   switch (refiner) {
9668   case REFINER_NOOP:
9669   case REFINER_SIMPLEX_1D:
9670   case REFINER_SIMPLEX_2D:
9671   case REFINER_SIMPLEX_TO_HEX_2D:
9672   case REFINER_HEX_2D:
9673   case REFINER_SIMPLEX_3D:
9674   case REFINER_HEX_3D:
9675   case REFINER_SIMPLEX_TO_HEX_3D:
9676     break;
9677   case REFINER_HYBRID_SIMPLEX_TO_HEX_3D:
9678   case REFINER_HYBRID_SIMPLEX_3D:
9679   case REFINER_HYBRID_HEX_3D:
9680     if (eMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No edge maximum specified in hybrid mesh");
9681   case REFINER_HYBRID_SIMPLEX_2D:
9682   case REFINER_HYBRID_HEX_2D:
9683     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
9684   case REFINER_HYBRID_SIMPLEX_TO_HEX_2D:
9685     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
9686     break;
9687   default:
9688     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %s", CellRefiners[refiner]);
9689   }
9690   cMax = cMax < 0 ? cEnd : cMax;
9691   fMax = fMax < 0 ? fEnd : fMax;
9692   eMax = eMax < 0 ? eEnd : eMax;
9693   for (l = 0; l < numLabels; ++l) {
9694     DMLabel         label, labelNew;
9695     const char     *lname;
9696     PetscBool       isDepth, isCellType;
9697     IS              valueIS;
9698     const PetscInt *values;
9699     PetscInt        defVal;
9700     PetscInt        numValues, val;
9701 
9702     ierr = DMGetLabelName(dm, l, &lname);CHKERRQ(ierr);
9703     ierr = PetscStrcmp(lname, "depth", &isDepth);CHKERRQ(ierr);
9704     if (isDepth) continue;
9705     ierr = PetscStrcmp(lname, "celltype", &isCellType);CHKERRQ(ierr);
9706     if (isCellType) continue;
9707     ierr = DMCreateLabel(rdm, lname);CHKERRQ(ierr);
9708     ierr = DMGetLabel(dm, lname, &label);CHKERRQ(ierr);
9709     ierr = DMGetLabel(rdm, lname, &labelNew);CHKERRQ(ierr);
9710     ierr = DMLabelGetDefaultValue(label,&defVal);CHKERRQ(ierr);
9711     ierr = DMLabelSetDefaultValue(labelNew,defVal);CHKERRQ(ierr);
9712     ierr = DMLabelGetValueIS(label, &valueIS);CHKERRQ(ierr);
9713     ierr = ISGetLocalSize(valueIS, &numValues);CHKERRQ(ierr);
9714     ierr = ISGetIndices(valueIS, &values);CHKERRQ(ierr);
9715     for (val = 0; val < numValues; ++val) {
9716       IS              pointIS;
9717       const PetscInt *points;
9718       PetscInt        numPoints, n;
9719 
9720       ierr = DMLabelGetStratumIS(label, values[val], &pointIS);CHKERRQ(ierr);
9721       ierr = ISGetLocalSize(pointIS, &numPoints);CHKERRQ(ierr);
9722       ierr = ISGetIndices(pointIS, &points);CHKERRQ(ierr);
9723       /* Ensure refined label is created with same number of strata as
9724        * original (even if no entries here). */
9725       ierr = DMLabelAddStratum(labelNew, values[val]);CHKERRQ(ierr);
9726       for (n = 0; n < numPoints; ++n) {
9727         const PetscInt p = points[n];
9728         switch (refiner) {
9729         case REFINER_SIMPLEX_1D:
9730           if ((p >= vStart) && (p < vEnd)) {
9731             /* Old vertices stay the same */
9732             newp = vStartNew + (p - vStart);
9733             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9734           } else if ((p >= cStart) && (p < cEnd)) {
9735             /* Old cells add new cells and vertex */
9736             newp = vStartNew + (vEnd - vStart) + (p - cStart);
9737             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9738             for (r = 0; r < 2; ++r) {
9739               newp = cStartNew + (p - cStart)*2 + r;
9740               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9741             }
9742           }
9743           break;
9744         case REFINER_SIMPLEX_2D:
9745           if ((p >= vStart) && (p < vEnd)) {
9746             /* Old vertices stay the same */
9747             newp = vStartNew + (p - vStart);
9748             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9749           } else if ((p >= fStart) && (p < fEnd)) {
9750             /* Old faces add new faces and vertex */
9751             newp = vStartNew + (vEnd - vStart) + (p - fStart);
9752             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9753             for (r = 0; r < 2; ++r) {
9754               newp = fStartNew + (p - fStart)*2 + r;
9755               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9756             }
9757           } else if ((p >= cStart) && (p < cEnd)) {
9758             /* Old cells add new cells and interior faces */
9759             for (r = 0; r < 4; ++r) {
9760               newp = cStartNew + (p - cStart)*4 + r;
9761               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9762             }
9763             for (r = 0; r < 3; ++r) {
9764               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*3 + r;
9765               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9766             }
9767           }
9768           break;
9769         case REFINER_HYBRID_SIMPLEX_TO_HEX_2D:
9770         case REFINER_SIMPLEX_TO_HEX_2D:
9771           if ((p >= vStart) && (p < vEnd)) {
9772             /* Old vertices stay the same */
9773             newp = vStartNew + (p - vStart);
9774             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9775           } else if ((p >= fStart) && (p < fEnd)) {
9776             /* Old faces add new faces and vertex */
9777             newp = vStartNew + (vEnd - vStart) + (p - fStart);
9778             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9779             for (r = 0; r < 2; ++r) {
9780               newp = fStartNew + (p - fStart)*2 + r;
9781               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9782             }
9783           } else if ((p >= cStart) && (p < cMax)) {
9784             /* Old cells add new cells, interior faces, and a vertex */
9785             for (r = 0; r < 3; ++r) {
9786               newp = cStartNew + (p - cStart)*3 + r;
9787               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9788             }
9789             for (r = 0; r < 3; ++r) {
9790               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*3 + r;
9791               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9792             }
9793             newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + p;
9794             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9795           } else if ((p >= cMax) && (p < cEnd)) {
9796             /* Old hybrid cells add new cells, interior faces, and a vertex */
9797             for (r = 0; r < 4; ++r) {
9798               newp = cStartNew + (cMax - cStart)*3 + (p - cMax)*4 + r;
9799               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9800             }
9801             for (r = 0; r < 4; ++r) {
9802               newp = fStartNew + (fEnd - fStart)*2 + (cMax - cStart)*3 + (p - cMax)*4 + r;
9803               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9804             }
9805             newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + p;
9806             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9807           }
9808           break;
9809         case REFINER_HEX_2D:
9810           if ((p >= vStart) && (p < vEnd)) {
9811             /* Old vertices stay the same */
9812             newp = vStartNew + (p - vStart);
9813             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9814           } else if ((p >= fStart) && (p < fEnd)) {
9815             /* Old faces add new faces and vertex */
9816             newp = vStartNew + (vEnd - vStart) + (p - fStart);
9817             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9818             for (r = 0; r < 2; ++r) {
9819               newp = fStartNew + (p - fStart)*2 + r;
9820               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9821             }
9822           } else if ((p >= cStart) && (p < cEnd)) {
9823             /* Old cells add new cells and interior faces and vertex */
9824             for (r = 0; r < 4; ++r) {
9825               newp = cStartNew + (p - cStart)*4 + r;
9826               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9827             }
9828             for (r = 0; r < 4; ++r) {
9829               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*4 + r;
9830               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9831             }
9832             newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (p - cStart);
9833             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9834           }
9835           break;
9836         case REFINER_HYBRID_SIMPLEX_2D:
9837           if ((p >= vStart) && (p < vEnd)) {
9838             /* Old vertices stay the same */
9839             newp = vStartNew + (p - vStart);
9840             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9841           } else if ((p >= fStart) && (p < fMax)) {
9842             /* Old interior faces add new faces and vertex */
9843             newp = vStartNew + (vEnd - vStart) + (p - fStart);
9844             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9845             for (r = 0; r < 2; ++r) {
9846               newp = fStartNew + (p - fStart)*2 + r;
9847               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9848             }
9849           } else if ((p >= fMax) && (p < fEnd)) {
9850             /* Old hybrid faces stay the same */
9851             newp = fStartNew + (fMax - fStart)*2 + (p - fMax);
9852             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9853           } else if ((p >= cStart) && (p < cMax)) {
9854             /* Old interior cells add new cells and interior faces */
9855             for (r = 0; r < 4; ++r) {
9856               newp = cStartNew + (p - cStart)*4 + r;
9857               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9858             }
9859             for (r = 0; r < 3; ++r) {
9860               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*3 + r;
9861               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9862             }
9863           } else if ((p >= cMax) && (p < cEnd)) {
9864             /* Old hybrid cells add new cells and hybrid face */
9865             for (r = 0; r < 2; ++r) {
9866               newp = cStartNew + (cMax - cStart)*4 + (p - cMax)*2 + r;
9867               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9868             }
9869             newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (p - cMax);
9870             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9871           }
9872           break;
9873         case REFINER_HYBRID_HEX_2D:
9874           if ((p >= vStart) && (p < vEnd)) {
9875             /* Old vertices stay the same */
9876             newp = vStartNew + (p - vStart);
9877             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9878           } else if ((p >= fStart) && (p < fMax)) {
9879             /* Old interior faces add new faces and vertex */
9880             newp = vStartNew + (vEnd - vStart) + (p - fStart);
9881             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9882             for (r = 0; r < 2; ++r) {
9883               newp = fStartNew + (p - fStart)*2 + r;
9884               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9885             }
9886           } else if ((p >= fMax) && (p < fEnd)) {
9887             /* Old hybrid faces stay the same */
9888             newp = fStartNew + (fMax - fStart)*2 + (p - fMax);
9889             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9890           } else if ((p >= cStart) && (p < cMax)) {
9891             /* Old interior cells add new cells, interior faces, and vertex */
9892             for (r = 0; r < 4; ++r) {
9893               newp = cStartNew + (p - cStart)*4 + r;
9894               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9895             }
9896             for (r = 0; r < 4; ++r) {
9897               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*4 + r;
9898               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9899             }
9900             newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (p - cStart);
9901             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9902           } else if ((p >= cMax) && (p < cEnd)) {
9903             /* Old hybrid cells add new cells and hybrid face */
9904             for (r = 0; r < 2; ++r) {
9905               newp = cStartNew + (cMax - cStart)*4 + (p - cMax)*2 + r;
9906               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9907             }
9908             newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*4 + (p - cMax);
9909             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9910           }
9911           break;
9912         case REFINER_SIMPLEX_3D:
9913           if ((p >= vStart) && (p < vEnd)) {
9914             /* Old vertices stay the same */
9915             newp = vStartNew + (p - vStart);
9916             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9917           } else if ((p >= eStart) && (p < eEnd)) {
9918             /* Old edges add new edges and vertex */
9919             for (r = 0; r < 2; ++r) {
9920               newp = eStartNew + (p - eStart)*2 + r;
9921               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9922             }
9923             newp = vStartNew + (vEnd - vStart) + (p - eStart);
9924             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9925           } else if ((p >= fStart) && (p < fEnd)) {
9926             /* Old faces add new faces and edges */
9927             for (r = 0; r < 4; ++r) {
9928               newp = fStartNew + (p - fStart)*4 + r;
9929               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9930             }
9931             for (r = 0; r < 3; ++r) {
9932               newp = eStartNew + (eEnd - eStart)*2 + (p - fStart)*3 + r;
9933               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9934             }
9935           } else if ((p >= cStart) && (p < cEnd)) {
9936             /* Old cells add new cells and interior faces and edges */
9937             for (r = 0; r < 8; ++r) {
9938               newp = cStartNew + (p - cStart)*8 + r;
9939               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9940             }
9941             for (r = 0; r < 8; ++r) {
9942               newp = fStartNew + (fEnd - fStart)*4 + (p - cStart)*8 + r;
9943               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9944             }
9945             for (r = 0; r < 1; ++r) {
9946               newp = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (p - cStart)*1 + r;
9947               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9948             }
9949           }
9950           break;
9951         case REFINER_HYBRID_SIMPLEX_TO_HEX_3D:
9952         case REFINER_SIMPLEX_TO_HEX_3D:
9953           if ((p >= vStart) && (p < vEnd)) {
9954             /* Old vertices stay the same */
9955             newp = vStartNew + (p - vStart);
9956             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9957           } else if ((p >= eStart) && (p < eMax)) {
9958             /* Interior edges add new edges and vertex */
9959             for (r = 0; r < 2; ++r) {
9960               newp = eStartNew + (p - eStart)*2 + r;
9961               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9962             }
9963             newp = vStartNew + (vEnd - vStart) + (p - eStart);
9964             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9965           } else if ((p >= eMax) && (p < eEnd)) {
9966             /* Hybrid edges stay the same */
9967             newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart)*4 + p - eMax;
9968             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9969           } else if ((p >= fStart) && (p < fMax)) {
9970             /* Old faces add new faces, edges and a vertex */
9971             for (r = 0; r < 3; ++r) {
9972               newp = fStartNew + (p - fStart)*3 + r;
9973               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9974             }
9975             for (r = 0; r < 3; ++r) {
9976               newp = eStartNew + (eMax - eStart)*2 + (p - fStart)*3 + r;
9977               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9978             }
9979           } else if ((p >= fMax) && (p < fEnd)) {
9980             /* Old hybrid faces add new faces and an edge */
9981             for (r = 0; r < 2; ++r) {
9982               newp = fStartNew + (fMax - fStart)*3 + (cMax - cStart)*6 + (p - fMax)*2 + r;
9983               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9984             }
9985             newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart)*4 + (eEnd - eMax) + (p - fMax);
9986             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9987           } else if ((p >= cStart) && (p < cMax)) {
9988             /* Old cells add new cells and interior faces and edges and a vertex */
9989             for (r = 0; r < 4; ++r) {
9990               newp = cStartNew + (p - cStart)*4 + r;
9991               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9992             }
9993             for (r = 0; r < 6; ++r) {
9994               newp = fStartNew + (fMax - fStart)*3 + (p - cStart)*6 + r;
9995               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9996             }
9997             for (r = 0; r < 4; ++r) {
9998               newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (p - cStart)*4 + r;
9999               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
10000             }
10001             newp = vStartNew + (vEnd - vStart) + (eMax - eStart) + (fMax - fStart) + p - cStart;
10002             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
10003           } else if ((p >= cMax) && (p < cEnd)) {
10004             /* Old hybrid cells add new cells and interior faces and an edge */
10005             for (r = 0; r < 3; ++r) {
10006               newp = cStartNew + (cMax - cStart)*4 + (p - cMax)*3 + r;
10007               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
10008             }
10009             for (r = 0; r < 3; ++r) {
10010               newp = fStartNew + (fMax - fStart)*3 + (cMax - cStart)*6 + (fEnd - fMax)*2 + (p - cMax)*3 + r;
10011               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
10012             }
10013             newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart)*4 + (eEnd - eMax) + (fEnd - fMax) + p - cMax;
10014             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
10015           }
10016           break;
10017         case REFINER_HYBRID_SIMPLEX_3D:
10018           if ((p >= vStart) && (p < vEnd)) {
10019             /* Interior vertices stay the same */
10020             newp = vStartNew + (p - vStart);
10021             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
10022           } else if ((p >= eStart) && (p < eMax)) {
10023             /* Interior edges add new edges and vertex */
10024             for (r = 0; r < 2; ++r) {
10025               newp = eStartNew + (p - eStart)*2 + r;
10026               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
10027             }
10028             newp = vStartNew + (vEnd - vStart) + (p - eStart);
10029             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
10030           } else if ((p >= eMax) && (p < eEnd)) {
10031             /* Hybrid edges stay the same */
10032             newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (p - eMax);
10033             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
10034           } else if ((p >= fStart) && (p < fMax)) {
10035             /* Interior faces add new faces and edges */
10036             for (r = 0; r < 4; ++r) {
10037               newp = fStartNew + (p - fStart)*4 + r;
10038               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
10039             }
10040             for (r = 0; r < 3; ++r) {
10041               newp = eStartNew + (eMax - eStart)*2 + (p - fStart)*3 + r;
10042               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
10043             }
10044           } else if ((p >= fMax) && (p < fEnd)) {
10045             /* Hybrid faces add new faces and edges */
10046             for (r = 0; r < 2; ++r) {
10047               newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (p - fMax)*2 + r;
10048               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
10049             }
10050             newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (p - fMax);
10051             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
10052           } else if ((p >= cStart) && (p < cMax)) {
10053             /* Interior cells add new cells, faces, and edges */
10054             for (r = 0; r < 8; ++r) {
10055               newp = cStartNew + (p - cStart)*8 + r;
10056               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
10057             }
10058             for (r = 0; r < 8; ++r) {
10059               newp = fStartNew + (fMax - fStart)*4 + (p - cStart)*8 + r;
10060               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
10061             }
10062             newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (p - cStart);
10063             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
10064           } else if ((p >= cMax) && (p < cEnd)) {
10065             /* Hybrid cells add new cells and faces */
10066             for (r = 0; r < 4; ++r) {
10067               newp = cStartNew + (cMax - cStart)*8 + (p - cMax)*4 + r;
10068               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
10069             }
10070             for (r = 0; r < 3; ++r) {
10071               newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (p - cMax)*3 + r;
10072               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
10073             }
10074           }
10075           break;
10076         case REFINER_HEX_3D:
10077           if ((p >= vStart) && (p < vEnd)) {
10078             /* Old vertices stay the same */
10079             newp = vStartNew + (p - vStart);
10080             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
10081           } else if ((p >= eStart) && (p < eEnd)) {
10082             /* Old edges add new edges and vertex */
10083             for (r = 0; r < 2; ++r) {
10084               newp = eStartNew + (p - eStart)*2 + r;
10085               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
10086             }
10087             newp = vStartNew + (vEnd - vStart) + (p - eStart);
10088             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
10089           } else if ((p >= fStart) && (p < fEnd)) {
10090             /* Old faces add new faces, edges, and vertex */
10091             for (r = 0; r < 4; ++r) {
10092               newp = fStartNew + (p - fStart)*4 + r;
10093               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
10094             }
10095             for (r = 0; r < 4; ++r) {
10096               newp = eStartNew + (eEnd - eStart)*2 + (p - fStart)*4 + r;
10097               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
10098             }
10099             newp = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (p - fStart);
10100             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
10101           } else if ((p >= cStart) && (p < cEnd)) {
10102             /* Old cells add new cells, faces, edges, and vertex */
10103             for (r = 0; r < 8; ++r) {
10104               newp = cStartNew + (p - cStart)*8 + r;
10105               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
10106             }
10107             for (r = 0; r < 12; ++r) {
10108               newp = fStartNew + (fEnd - fStart)*4 + (p - cStart)*12 + r;
10109               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
10110             }
10111             for (r = 0; r < 6; ++r) {
10112               newp = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*4 + (p - cStart)*6 + r;
10113               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
10114             }
10115             newp = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (fEnd - fStart) + (p - cStart);
10116             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
10117           }
10118           break;
10119         case REFINER_HYBRID_HEX_3D:
10120           if ((p >= vStart) && (p < vEnd)) {
10121             /* Interior vertices stay the same */
10122             newp = vStartNew + (p - vStart);
10123             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
10124           } else if ((p >= eStart) && (p < eMax)) {
10125             /* Interior edges add new edges and vertex */
10126             for (r = 0; r < 2; ++r) {
10127               newp = eStartNew + (p - eStart)*2 + r;
10128               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
10129             }
10130             newp = vStartNew + (vEnd - vStart) + (p - eStart);
10131             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
10132           } else if ((p >= eMax) && (p < eEnd)) {
10133             /* Hybrid edges stay the same */
10134             newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (p - eMax);
10135             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
10136           } else if ((p >= fStart) && (p < fMax)) {
10137             /* Interior faces add new faces, edges, and vertex */
10138             for (r = 0; r < 4; ++r) {
10139               newp = fStartNew + (p - fStart)*4 + r;
10140               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
10141             }
10142             for (r = 0; r < 4; ++r) {
10143               newp = eStartNew + (eMax - eStart)*2 + (p - fStart)*4 + r;
10144               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
10145             }
10146             newp = vStartNew + (vEnd - vStart) + (eMax - eStart) + (p - fStart);
10147             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
10148           } else if ((p >= fMax) && (p < fEnd)) {
10149             /* Hybrid faces add new faces and edges */
10150             for (r = 0; r < 2; ++r) {
10151               newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (p - fMax)*2 + r;
10152               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
10153             }
10154             newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (p - fMax);
10155             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
10156           } else if ((p >= cStart) && (p < cMax)) {
10157             /* Interior cells add new cells, faces, edges, and vertex */
10158             for (r = 0; r < 8; ++r) {
10159               newp = cStartNew + (p - cStart)*8 + r;
10160               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
10161             }
10162             for (r = 0; r < 12; ++r) {
10163               newp = fStartNew + (fMax - fStart)*4 + (p - cStart)*12 + r;
10164               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
10165             }
10166             for (r = 0; r < 6; ++r) {
10167               newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (p - cStart)*6 + r;
10168               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
10169             }
10170             newp = vStartNew + (vEnd - vStart) + (eMax - eStart) + (fMax - fStart) + (p - cStart);
10171             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
10172           } else if ((p >= cMax) && (p < cEnd)) {
10173             /* Hybrid cells add new cells, faces, and edges */
10174             for (r = 0; r < 4; ++r) {
10175               newp = cStartNew + (cMax - cStart)*8 + (p - cMax)*4 + r;
10176               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
10177             }
10178             for (r = 0; r < 4; ++r) {
10179               newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd - fMax)*2 + (p - cMax)*4 + r;
10180               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
10181             }
10182             newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (fEnd - fMax) + (p - cMax);
10183             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
10184           }
10185           break;
10186         default:
10187           SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %s", CellRefiners[refiner]);
10188         }
10189       }
10190       ierr = ISRestoreIndices(pointIS, &points);CHKERRQ(ierr);
10191       ierr = ISDestroy(&pointIS);CHKERRQ(ierr);
10192     }
10193     ierr = ISRestoreIndices(valueIS, &values);CHKERRQ(ierr);
10194     ierr = ISDestroy(&valueIS);CHKERRQ(ierr);
10195   }
10196   PetscFunctionReturn(0);
10197 }
10198 
10199 /* This will only work for interpolated meshes */
10200 PetscErrorCode DMPlexRefineUniform_Internal(DM dm, CellRefiner cellRefiner, DM *dmRefined)
10201 {
10202   DM             rdm;
10203   PetscInt      *depthSize;
10204   PetscInt       dim, embedDim, depth = 0, d, pStart = 0, pEnd = 0;
10205   PetscErrorCode ierr;
10206 
10207   PetscFunctionBegin;
10208   ierr = DMCreate(PetscObjectComm((PetscObject)dm), &rdm);CHKERRQ(ierr);
10209   ierr = DMSetType(rdm, DMPLEX);CHKERRQ(ierr);
10210   ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr);
10211   ierr = DMSetDimension(rdm, dim);CHKERRQ(ierr);
10212   ierr = DMGetCoordinateDim(dm, &embedDim);CHKERRQ(ierr);
10213   ierr = DMSetCoordinateDim(rdm, embedDim);CHKERRQ(ierr);
10214   /* Calculate number of new points of each depth */
10215   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
10216   if (depth >= 0 && dim != depth) SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "Mesh must be interpolated for regular refinement");
10217   ierr = PetscMalloc1(depth+1, &depthSize);CHKERRQ(ierr);
10218   ierr = PetscMemzero(depthSize, (depth+1) * sizeof(PetscInt));CHKERRQ(ierr);
10219   ierr = CellRefinerGetSizes(cellRefiner, dm, depthSize);CHKERRQ(ierr);
10220   /* Step 1: Set chart */
10221   for (d = 0; d <= depth; ++d) pEnd += depthSize[d];
10222   ierr = DMPlexSetChart(rdm, pStart, pEnd);CHKERRQ(ierr);
10223   /* Step 2: Set cone/support sizes (automatically stratifies) */
10224   ierr = CellRefinerSetConeSizes(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
10225   /* Step 3: Setup refined DM */
10226   ierr = DMSetUp(rdm);CHKERRQ(ierr);
10227   /* Step 4: Set cones and supports (automatically symmetrizes) */
10228   ierr = CellRefinerSetCones(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
10229   /* Step 5: Create pointSF */
10230   ierr = CellRefinerCreateSF(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
10231   /* Step 6: Create labels */
10232   ierr = CellRefinerCreateLabels(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
10233   /* Step 7: Set coordinates */
10234   ierr = CellRefinerSetCoordinates(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
10235   ierr = PetscFree(depthSize);CHKERRQ(ierr);
10236 
10237   *dmRefined = rdm;
10238   PetscFunctionReturn(0);
10239 }
10240 
10241 /*@
10242   DMPlexCreateCoarsePointIS - Creates an IS covering the coarse DM chart with the fine points as data
10243 
10244   Input Parameter:
10245 . dm - The coarse DM
10246 
10247   Output Parameter:
10248 . fpointIS - The IS of all the fine points which exist in the original coarse mesh
10249 
10250   Level: developer
10251 
10252 .seealso: DMRefine(), DMPlexSetRefinementUniform(), DMPlexCreateSubpointIS()
10253 @*/
10254 PetscErrorCode DMPlexCreateCoarsePointIS(DM dm, IS *fpointIS)
10255 {
10256   CellRefiner    cellRefiner;
10257   PetscInt      *depthSize, *fpoints;
10258   PetscInt       cStartNew = 0, vStartNew = 0, fStartNew = 0, eStartNew = 0;
10259   PetscInt       depth, pStart, pEnd, p, vStart, vEnd, v;
10260   PetscErrorCode ierr;
10261 
10262   PetscFunctionBegin;
10263   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
10264   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
10265   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
10266   ierr = DMPlexGetCellRefiner_Internal(dm, &cellRefiner);CHKERRQ(ierr);
10267   ierr = PetscMalloc1(depth+1, &depthSize);CHKERRQ(ierr);
10268   ierr = CellRefinerGetSizes(cellRefiner, dm, depthSize);CHKERRQ(ierr);
10269   if (cellRefiner) {ierr = GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);CHKERRQ(ierr);}
10270   ierr = PetscMalloc1(pEnd-pStart,&fpoints);CHKERRQ(ierr);
10271   for (p = 0; p < pEnd-pStart; ++p) fpoints[p] = -1;
10272   switch (cellRefiner) {
10273   case REFINER_SIMPLEX_1D:
10274   case REFINER_SIMPLEX_2D:
10275   case REFINER_HYBRID_SIMPLEX_2D:
10276   case REFINER_HEX_2D:
10277   case REFINER_HYBRID_HEX_2D:
10278   case REFINER_SIMPLEX_3D:
10279   case REFINER_HYBRID_SIMPLEX_3D:
10280   case REFINER_HEX_3D:
10281   case REFINER_HYBRID_HEX_3D:
10282     for (v = vStart; v < vEnd; ++v) fpoints[v-pStart] = vStartNew + (v - vStart);
10283     break;
10284   default:
10285     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %s", CellRefiners[cellRefiner]);
10286   }
10287   ierr = ISCreateGeneral(PETSC_COMM_SELF, pEnd-pStart, fpoints, PETSC_OWN_POINTER, fpointIS);CHKERRQ(ierr);
10288   ierr = PetscFree(depthSize);CHKERRQ(ierr);
10289   PetscFunctionReturn(0);
10290 }
10291 
10292 /*@
10293   DMPlexSetRefinementUniform - Set the flag for uniform refinement
10294 
10295   Input Parameters:
10296 + dm - The DM
10297 - refinementUniform - The flag for uniform refinement
10298 
10299   Level: developer
10300 
10301 .seealso: DMRefine(), DMPlexGetRefinementUniform(), DMPlexGetRefinementLimit(), DMPlexSetRefinementLimit()
10302 @*/
10303 PetscErrorCode DMPlexSetRefinementUniform(DM dm, PetscBool refinementUniform)
10304 {
10305   DM_Plex *mesh = (DM_Plex*) dm->data;
10306 
10307   PetscFunctionBegin;
10308   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
10309   mesh->refinementUniform = refinementUniform;
10310   PetscFunctionReturn(0);
10311 }
10312 
10313 /*@
10314   DMPlexGetRefinementUniform - Retrieve the flag for uniform refinement
10315 
10316   Input Parameter:
10317 . dm - The DM
10318 
10319   Output Parameter:
10320 . refinementUniform - The flag for uniform refinement
10321 
10322   Level: developer
10323 
10324 .seealso: DMRefine(), DMPlexSetRefinementUniform(), DMPlexGetRefinementLimit(), DMPlexSetRefinementLimit()
10325 @*/
10326 PetscErrorCode DMPlexGetRefinementUniform(DM dm, PetscBool *refinementUniform)
10327 {
10328   DM_Plex *mesh = (DM_Plex*) dm->data;
10329 
10330   PetscFunctionBegin;
10331   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
10332   PetscValidPointer(refinementUniform,  2);
10333   *refinementUniform = mesh->refinementUniform;
10334   PetscFunctionReturn(0);
10335 }
10336 
10337 /*@
10338   DMPlexSetRefinementLimit - Set the maximum cell volume for refinement
10339 
10340   Input Parameters:
10341 + dm - The DM
10342 - refinementLimit - The maximum cell volume in the refined mesh
10343 
10344   Level: developer
10345 
10346 .seealso: DMRefine(), DMPlexGetRefinementLimit(), DMPlexGetRefinementUniform(), DMPlexSetRefinementUniform()
10347 @*/
10348 PetscErrorCode DMPlexSetRefinementLimit(DM dm, PetscReal refinementLimit)
10349 {
10350   DM_Plex *mesh = (DM_Plex*) dm->data;
10351 
10352   PetscFunctionBegin;
10353   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
10354   mesh->refinementLimit = refinementLimit;
10355   PetscFunctionReturn(0);
10356 }
10357 
10358 /*@
10359   DMPlexGetRefinementLimit - Retrieve the maximum cell volume for refinement
10360 
10361   Input Parameter:
10362 . dm - The DM
10363 
10364   Output Parameter:
10365 . refinementLimit - The maximum cell volume in the refined mesh
10366 
10367   Level: developer
10368 
10369 .seealso: DMRefine(), DMPlexSetRefinementLimit(), DMPlexGetRefinementUniform(), DMPlexSetRefinementUniform()
10370 @*/
10371 PetscErrorCode DMPlexGetRefinementLimit(DM dm, PetscReal *refinementLimit)
10372 {
10373   DM_Plex *mesh = (DM_Plex*) dm->data;
10374 
10375   PetscFunctionBegin;
10376   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
10377   PetscValidPointer(refinementLimit,  2);
10378   /* if (mesh->refinementLimit < 0) = getMaxVolume()/2.0; */
10379   *refinementLimit = mesh->refinementLimit;
10380   PetscFunctionReturn(0);
10381 }
10382 
10383 /*@
10384   DMPlexSetRefinementFunction - Set the function giving the maximum cell volume for refinement
10385 
10386   Input Parameters:
10387 + dm - The DM
10388 - refinementFunc - Function giving the maximum cell volume in the refined mesh
10389 
10390   Note: The calling sequence is refinementFunc(coords, limit)
10391 $ coords - Coordinates of the current point, usually a cell centroid
10392 $ limit  - The maximum cell volume for a cell containing this point
10393 
10394   Level: developer
10395 
10396 .seealso: DMRefine(), DMPlexGetRefinementFunction(), DMPlexGetRefinementUniform(), DMPlexSetRefinementUniform(), DMPlexGetRefinementLimit(), DMPlexSetRefinementLimit()
10397 @*/
10398 PetscErrorCode DMPlexSetRefinementFunction(DM dm, PetscErrorCode (*refinementFunc)(const PetscReal [], PetscReal *))
10399 {
10400   DM_Plex *mesh = (DM_Plex*) dm->data;
10401 
10402   PetscFunctionBegin;
10403   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
10404   mesh->refinementFunc = refinementFunc;
10405   PetscFunctionReturn(0);
10406 }
10407 
10408 /*@
10409   DMPlexGetRefinementFunction - Get the function giving the maximum cell volume for refinement
10410 
10411   Input Parameter:
10412 . dm - The DM
10413 
10414   Output Parameter:
10415 . refinementFunc - Function giving the maximum cell volume in the refined mesh
10416 
10417   Note: The calling sequence is refinementFunc(coords, limit)
10418 $ coords - Coordinates of the current point, usually a cell centroid
10419 $ limit  - The maximum cell volume for a cell containing this point
10420 
10421   Level: developer
10422 
10423 .seealso: DMRefine(), DMPlexSetRefinementFunction(), DMPlexGetRefinementUniform(), DMPlexSetRefinementUniform(), DMPlexGetRefinementLimit(), DMPlexSetRefinementLimit()
10424 @*/
10425 PetscErrorCode DMPlexGetRefinementFunction(DM dm, PetscErrorCode (**refinementFunc)(const PetscReal [], PetscReal *))
10426 {
10427   DM_Plex *mesh = (DM_Plex*) dm->data;
10428 
10429   PetscFunctionBegin;
10430   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
10431   PetscValidPointer(refinementFunc,  2);
10432   *refinementFunc = mesh->refinementFunc;
10433   PetscFunctionReturn(0);
10434 }
10435 
10436 PetscErrorCode DMPlexGetCellRefiner_Internal(DM dm, CellRefiner *cellRefiner)
10437 {
10438   DMPolytopeType ct;
10439   PetscInt       dim, cStart, cEnd, cMax, fMax;
10440   PetscErrorCode ierr;
10441 
10442   PetscFunctionBegin;
10443   ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr);
10444   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
10445   if (cEnd <= cStart) {*cellRefiner = REFINER_NOOP; PetscFunctionReturn(0);}
10446   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, NULL, NULL);CHKERRQ(ierr);
10447   /* TODO Must tag hybrid cells with correct cell types */
10448   ierr = DMPlexGetCellType(dm, cStart, &ct);CHKERRQ(ierr);
10449   switch (ct) {
10450     case DM_POLYTOPE_SEGMENT:       *cellRefiner = REFINER_SIMPLEX_1D; break;
10451     case DM_POLYTOPE_TRIANGLE:      if (cMax >= 0) {*cellRefiner = REFINER_HYBRID_SIMPLEX_2D; break;}
10452                                     else           {*cellRefiner = REFINER_SIMPLEX_2D; break;}
10453     case DM_POLYTOPE_QUADRILATERAL: if (cMax >= 0) {*cellRefiner = REFINER_HYBRID_HEX_2D; break;} /* Why did this have fMax >= 0 ??? */
10454                                     else           {*cellRefiner = REFINER_HEX_2D; break;}
10455     case DM_POLYTOPE_TETRAHEDRON:   if (cMax >= 0) {*cellRefiner = REFINER_HYBRID_SIMPLEX_3D; break;}
10456                                     else           {*cellRefiner = REFINER_SIMPLEX_3D; break;}
10457     case DM_POLYTOPE_HEXAHEDRON:    if (cMax >= 0) {*cellRefiner = REFINER_HYBRID_HEX_3D; break;}
10458                                     else           {*cellRefiner = REFINER_HEX_3D; break;}
10459     case DM_POLYTOPE_SEG_PRISM_TENSOR:  *cellRefiner = REFINER_HYBRID_SIMPLEX_2D; break;
10460     case DM_POLYTOPE_TRI_PRISM_TENSOR:  *cellRefiner = REFINER_HYBRID_SIMPLEX_3D; break;
10461     case DM_POLYTOPE_QUAD_PRISM_TENSOR: *cellRefiner = REFINER_HYBRID_HEX_3D; break;
10462     default: SETERRQ2(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_OUTOFRANGE, "No cell refiner for cell %D with type %s", cStart, DMPolytopeTypes[ct]);
10463   }
10464   PetscFunctionReturn(0);
10465 }
10466 
10467 PetscErrorCode DMRefine_Plex(DM dm, MPI_Comm comm, DM *dmRefined)
10468 {
10469   PetscBool      isUniform;
10470   PetscErrorCode ierr;
10471 
10472   PetscFunctionBegin;
10473   ierr = DMPlexGetRefinementUniform(dm, &isUniform);CHKERRQ(ierr);
10474   if (isUniform) {
10475     CellRefiner cellRefiner;
10476     PetscBool   localized;
10477 
10478     ierr = DMGetCoordinatesLocalized(dm, &localized);CHKERRQ(ierr);
10479     ierr = DMPlexGetCellRefiner_Internal(dm, &cellRefiner);CHKERRQ(ierr);
10480     ierr = DMPlexRefineUniform_Internal(dm, cellRefiner, dmRefined);CHKERRQ(ierr);
10481     ierr = DMPlexSetRegularRefinement(*dmRefined, PETSC_TRUE);CHKERRQ(ierr);
10482     ierr = DMCopyBoundary(dm, *dmRefined);CHKERRQ(ierr);
10483     if (localized) {ierr = DMLocalizeCoordinates(*dmRefined);CHKERRQ(ierr);}
10484   } else {
10485     ierr = DMPlexRefine_Internal(dm, NULL, dmRefined);CHKERRQ(ierr);
10486   }
10487   PetscFunctionReturn(0);
10488 }
10489 
10490 PetscErrorCode DMRefineHierarchy_Plex(DM dm, PetscInt nlevels, DM dmRefined[])
10491 {
10492   DM             cdm = dm;
10493   PetscInt       r;
10494   PetscBool      isUniform, localized;
10495   PetscErrorCode ierr;
10496 
10497   PetscFunctionBegin;
10498   ierr = DMPlexGetRefinementUniform(dm, &isUniform);CHKERRQ(ierr);
10499   ierr = DMGetCoordinatesLocalized(dm, &localized);CHKERRQ(ierr);
10500   if (isUniform) {
10501     for (r = 0; r < nlevels; ++r) {
10502       CellRefiner cellRefiner;
10503 
10504       ierr = DMPlexGetCellRefiner_Internal(cdm, &cellRefiner);CHKERRQ(ierr);
10505       ierr = DMPlexRefineUniform_Internal(cdm, cellRefiner, &dmRefined[r]);CHKERRQ(ierr);
10506       ierr = DMSetCoarsenLevel(dmRefined[r], cdm->leveldown);CHKERRQ(ierr);
10507       ierr = DMSetRefineLevel(dmRefined[r], cdm->levelup+1);CHKERRQ(ierr);
10508       ierr = DMCopyBoundary(cdm, dmRefined[r]);CHKERRQ(ierr);
10509       if (localized) {ierr = DMLocalizeCoordinates(dmRefined[r]);CHKERRQ(ierr);}
10510       ierr = DMSetCoarseDM(dmRefined[r], cdm);CHKERRQ(ierr);
10511       ierr = DMPlexSetRegularRefinement(dmRefined[r], PETSC_TRUE);CHKERRQ(ierr);
10512       cdm  = dmRefined[r];
10513     }
10514   } else {
10515     for (r = 0; r < nlevels; ++r) {
10516       ierr = DMRefine(cdm, PetscObjectComm((PetscObject) dm), &dmRefined[r]);CHKERRQ(ierr);
10517       ierr = DMCopyBoundary(cdm, dmRefined[r]);CHKERRQ(ierr);
10518       if (localized) {ierr = DMLocalizeCoordinates(dmRefined[r]);CHKERRQ(ierr);}
10519       ierr = DMSetCoarseDM(dmRefined[r], cdm);CHKERRQ(ierr);
10520       cdm  = dmRefined[r];
10521     }
10522   }
10523   PetscFunctionReturn(0);
10524 }
10525