Actual source code: plexrefine.c

petsc-master 2020-02-18
Report Typos and Errors
  1:  #include <petsc/private/dmpleximpl.h>
  2:  #include <petscsf.h>

  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};

  7: PETSC_STATIC_INLINE PetscErrorCode GetDepthStart_Private(PetscInt depth, PetscInt depthSize[], PetscInt *cStart, PetscInt *fStart, PetscInt *eStart, PetscInt *vStart)
  8: {
 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:   return(0);
 15: }

 17: PETSC_STATIC_INLINE PetscErrorCode GetDepthEnd_Private(PetscInt depth, PetscInt depthSize[], PetscInt *cEnd, PetscInt *fEnd, PetscInt *eEnd, PetscInt *vEnd)
 18: {
 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:   return(0);
 25: }

 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;

 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:       PetscMalloc1(3*cdim,      &v);
 62:       PetscMalloc1(3*cdim*fdim, &j);
 63:       PetscMalloc1(3*cdim*fdim, &invj);
 64:       PetscMalloc1(3,           &dj);
 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:       PetscMalloc1(4*cdim,      &v);
102:       PetscMalloc1(4*cdim*fdim, &j);
103:       PetscMalloc1(4*cdim*fdim, &invj);
104:       PetscMalloc1(4,           &dj);
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        {PetscFree(v);}
136:   if (jac)    {*jac    = j;}
137:   else        {PetscFree(j);}
138:   if (invjac) {*invjac = invj;}
139:   else        {PetscFree(invj);}
140:   if (invjac) {*invjac = invj;}
141:   else        {PetscFree(invj);}
142:   if (detj)   {*detj   = dj;}
143:   else        {PetscFree(dj);}
144:   return(0);
145: }

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;

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:       PetscMalloc3(4*dim,&v,4*dim*dim,&j,4*dim*dim,&invj);
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:       PetscMalloc3(4*dim,&v,4*dim*dim,&j,4*dim*dim,&invj);
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:       PetscMalloc3(8*dim,&v,8*dim*dim,&j,8*dim*dim,&invj);
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:   return(0);
305: }

307: PetscErrorCode CellRefinerRestoreAffineTransforms_Internal(CellRefiner refiner, PetscInt *numSubcells, PetscReal *v0[], PetscReal *jac[], PetscReal *invjac[])
308: {

312:   PetscFree3(*v0,*jac,*invjac);
313:   return(0);
314: }

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;

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:   return(0);
343: }

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;

351:   DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);
352:   DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);
353:   DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);
354:   DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);
355:   DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);
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:   return(0);
470: }

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: }

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: }

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: }

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: }

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: }

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: }

522: static PetscErrorCode DMLabelSetStratumBounds(DMLabel label, PetscInt value, PetscInt cStart, PetscInt cEnd)
523: {
524:   IS             cIS;

528:   ISCreateStride(PETSC_COMM_SELF, cEnd - cStart, cStart, 1, &cIS);
529:   DMLabelSetStratumIS(label, value, cIS);
530:   ISDestroy(&cIS);
531:   return(0);
532: }

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;

541:   DMPlexGetDepth(dm, &depth);
542:   DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);
543:   DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);
544:   DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);
545:   DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);
546:   DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);
547:   GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);
548:   GetDepthEnd_Private(depth, depthSize, &cEndNew, &fEndNew, &eEndNew, &vEndNew);
549:   DMCreateLabel(rdm,"depth");
550:   DMPlexGetDepthLabel(rdm,&depthLabel);
551:   DMLabelSetStratumBounds(depthLabel, 0, vStartNew, vEndNew);
552:   if (depth > 2) DMLabelSetStratumBounds(depthLabel, 1, eStartNew, eEndNew);
553:   if (depth > 1) DMLabelSetStratumBounds(depthLabel, depth - 1, fStartNew, fEndNew);
554:   if (depth > 0) DMLabelSetStratumBounds(depthLabel, depth, cStartNew, cEndNew);
555:   {
556:     DM_Plex *plex = (DM_Plex *) rdm->data;
557:     PetscObjectStateGet((PetscObject) depthLabel, &plex->depthState);
558:   }
559:   if (!refiner) return(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;

567:         DMPlexSetConeSize(rdm, newp, 2);
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;

575:       DMPlexGetSupportSize(dm, v, &size);
576:       DMPlexSetSupportSize(rdm, newp, size);
577:     }
578:     /* Cell vertices have support 2 */
579:     for (c = cStart; c < cEnd; ++c) {
580:       const PetscInt newp = vStartNew + (vEnd - vStart) + (c - cStart);

582:       DMPlexSetSupportSize(rdm, newp, 2);
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;

591:         DMPlexSetConeSize(rdm, newp, 3);
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;

600:         DMPlexSetConeSize(rdm, newp, 2);
601:         DMPlexGetSupportSize(dm, f, &size);
602:         DMPlexSetSupportSize(rdm, newp, size);
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;

610:         DMPlexSetConeSize(rdm, newp, 2);
611:         DMPlexSetSupportSize(rdm, newp, 2);
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;

619:       DMPlexGetSupportSize(dm, v, &size);
620:       DMPlexSetSupportSize(rdm, newp, size);
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;

627:       DMPlexGetSupportSize(dm, f, &size);
628:       DMPlexSetSupportSize(rdm, newp, 2 + size*2);
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;

637:         DMPlexSetConeSize(rdm, newp, 4);
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;

646:         DMPlexSetConeSize(rdm, newp, 2);
647:         DMPlexGetSupportSize(dm, f, &size);
648:         DMPlexSetSupportSize(rdm, newp, size);
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;

656:         DMPlexSetConeSize(rdm, newp, 2);
657:         DMPlexSetSupportSize(rdm, newp, 2);
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;

665:       DMPlexGetSupportSize(dm, v, &size);
666:       DMPlexSetSupportSize(rdm, newp, size);
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;

673:       DMPlexGetSupportSize(dm, f, &size);
674:       DMPlexSetSupportSize(rdm, newp, size + 2);
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;

680:       DMPlexSetSupportSize(rdm, newp, 3);
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;

692:         DMPlexSetConeSize(rdm, newp, 4);
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;

699:         DMPlexSetConeSize(rdm, newp, 4);
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;

708:         DMPlexSetConeSize(rdm, newp, 2);
709:         DMPlexGetSupportSize(dm, f, &size);
710:         DMPlexSetSupportSize(rdm, newp, size);
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;

718:         DMPlexSetConeSize(rdm, newp, 2);
719:         DMPlexSetSupportSize(rdm, newp, 2);
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;

727:         DMPlexSetConeSize(rdm, newp, 2);
728:         DMPlexSetSupportSize(rdm, newp, 2);
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;

736:       DMPlexGetSupportSize(dm, v, &size);
737:       DMPlexSetSupportSize(rdm, newp, size);
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;

744:       DMPlexGetSupportSize(dm, f, &size);
745:       DMPlexSetSupportSize(rdm, newp, size + 2);
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;

751:       DMPlexSetSupportSize(rdm, newp, 3);
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;

757:       DMPlexSetSupportSize(rdm, newp, 4);
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;

766:         DMPlexSetConeSize(rdm, newp, 4);
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;

775:         DMPlexSetConeSize(rdm, newp, 2);
776:         DMPlexGetSupportSize(dm, f, &size);
777:         DMPlexSetSupportSize(rdm, newp, size);
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;

785:         DMPlexSetConeSize(rdm, newp, 2);
786:         DMPlexSetSupportSize(rdm, newp, 2);
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;

794:       DMPlexGetSupportSize(dm, v, &size);
795:       DMPlexSetSupportSize(rdm, newp, size);
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;

802:       DMPlexGetSupportSize(dm, f, &size);
803:       DMPlexSetSupportSize(rdm, newp, 2 + size);
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);

809:       DMPlexSetSupportSize(rdm, newp, 4);
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:     DMPlexSetHybridBounds(rdm, cStartNew + (cMax - cStart)*4, fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3, PETSC_DETERMINE, PETSC_DETERMINE);
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;

823:         DMPlexSetConeSize(rdm, newp, 3);
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;

831:         DMPlexSetConeSize(rdm, newp, 4);
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;

840:         DMPlexSetConeSize(rdm, newp, 2);
841:         DMPlexGetSupportSize(dm, f, &size);
842:         DMPlexSetSupportSize(rdm, newp, size);
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;

850:         DMPlexSetConeSize(rdm, newp, 2);
851:         DMPlexSetSupportSize(rdm, newp, 2);
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;

859:       DMPlexSetConeSize(rdm, newp, 2);
860:       DMPlexGetSupportSize(dm, f, &size);
861:       DMPlexSetSupportSize(rdm, newp, size);
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);

867:       DMPlexSetConeSize(rdm, newp, 2);
868:       DMPlexSetSupportSize(rdm, newp, 2);
869:     }
870:     /* Old vertices have identical supports */
871:     for (v = vStart; v < vEnd; ++v) {
872:       const PetscInt newp = vStartNew + (v - vStart);
873:       PetscInt       size;

875:       DMPlexGetSupportSize(dm, v, &size);
876:       DMPlexSetSupportSize(rdm, newp, size);
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;

884:       DMPlexGetSupportSize(dm, f, &size);
885:       DMPlexGetSupport(dm, f, &support);
886:       for (s = 0; s < size; ++s) {
887:         if (support[s] >= cMax) newSize += 1;
888:         else newSize += 2;
889:       }
890:       DMPlexSetSupportSize(rdm, newp, newSize);
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:     DMPlexSetHybridBounds(rdm, cStartNew + (cMax - cStart)*4, fStartNew + (fMax - fStart)*2 + (cMax - cStart)*4, PETSC_DETERMINE, PETSC_DETERMINE);
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;

904:         DMPlexSetConeSize(rdm, newp, 4);
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;

912:         DMPlexSetConeSize(rdm, newp, 4);
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;

921:         DMPlexSetConeSize(rdm, newp, 2);
922:         DMPlexGetSupportSize(dm, f, &size);
923:         DMPlexSetSupportSize(rdm, newp, size);
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;

931:         DMPlexSetConeSize(rdm, newp, 2);
932:         DMPlexSetSupportSize(rdm, newp, 2);
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;

940:       DMPlexSetConeSize(rdm, newp, 2);
941:       DMPlexGetSupportSize(dm, f, &size);
942:       DMPlexSetSupportSize(rdm, newp, size);
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);

948:       DMPlexSetConeSize(rdm, newp, 2);
949:       DMPlexSetSupportSize(rdm, newp, 2);
950:     }
951:     /* Old vertices have identical supports */
952:     for (v = vStart; v < vEnd; ++v) {
953:       const PetscInt newp = vStartNew + (v - vStart);
954:       PetscInt       size;

956:       DMPlexGetSupportSize(dm, v, &size);
957:       DMPlexSetSupportSize(rdm, newp, size);
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;

964:       DMPlexGetSupportSize(dm, f, &size);
965:       DMPlexSetSupportSize(rdm, newp, 2 + size);
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);

971:       DMPlexSetSupportSize(rdm, newp, 4);
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;

980:         DMPlexSetConeSize(rdm, newp, 4);
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;

989:         DMPlexSetConeSize(rdm, newp, 3);
990:         DMPlexGetSupportSize(dm, f, &size);
991:         DMPlexSetSupportSize(rdm, newp, size);
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;

999:         DMPlexSetConeSize(rdm, newp, 3);
1000:         DMPlexSetSupportSize(rdm, newp, 2);
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;

1009:         DMPlexSetConeSize(rdm, newp, 2);
1010:         DMPlexGetSupportSize(dm, e, &size);
1011:         DMPlexSetSupportSize(rdm, newp, size);
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;

1021:         DMPlexSetConeSize(rdm, newp, 2);
1022:         DMPlexGetSupportSize(dm, f, &supportSize);
1023:         DMPlexGetSupport(dm, f, &support);
1024:         for (s = 0; s < supportSize; ++s) {
1025:           DMPlexGetConeSize(dm, support[s], &coneSize);
1026:           DMPlexGetCone(dm, support[s], &cone);
1027:           DMPlexGetConeOrientation(dm, support[s], &ornt);
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:         DMPlexSetSupportSize(rdm, newp, 2+intFaces);
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);

1044:       DMPlexSetConeSize(rdm, newp, 2);
1045:       DMPlexSetSupportSize(rdm, newp, 4);
1046:     }
1047:     /* Old vertices have identical supports */
1048:     for (v = vStart; v < vEnd; ++v) {
1049:       const PetscInt newp = vStartNew + (v - vStart);
1050:       PetscInt       size;

1052:       DMPlexGetSupportSize(dm, v, &size);
1053:       DMPlexSetSupportSize(rdm, newp, size);
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;

1060:       DMPlexGetSupportSize(dm, e, &size);
1061:       DMPlexGetTransitiveClosure(dm, e, PETSC_FALSE, &starSize, &star);
1062:       for (s = 0; s < starSize*2; s += 2) {
1063:         const PetscInt *cone, *ornt;
1064:         PetscInt        e01, e23;

1066:         if ((star[s] >= cStart) && (star[s] < cEnd)) {
1067:           /* Check edge 0-1 */
1068:           DMPlexGetCone(dm, star[s], &cone);
1069:           DMPlexGetConeOrientation(dm, star[s], &ornt);
1070:           DMPlexGetCone(dm, cone[0], &cone);
1071:           e01  = cone[GetTriEdge_Static(ornt[0], 0)];
1072:           /* Check edge 2-3 */
1073:           DMPlexGetCone(dm, star[s], &cone);
1074:           DMPlexGetConeOrientation(dm, star[s], &ornt);
1075:           DMPlexGetCone(dm, cone[2], &cone);
1076:           e23  = cone[GetTriEdge_Static(ornt[2], 1)];
1077:           if ((e01 == e) || (e23 == e)) ++cellSize;
1078:         }
1079:       }
1080:       DMPlexRestoreTransitiveClosure(dm, e, PETSC_FALSE, &starSize, &star);
1081:       DMPlexSetSupportSize(rdm, newp, 2 + size*2 + cellSize);
1082:     }
1083:     break;
1084:   case REFINER_HYBRID_SIMPLEX_3D:
1085:     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);
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;

1092:         DMPlexSetConeSize(rdm, newp, 4);
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;

1100:         DMPlexSetConeSize(rdm, newp, 5);
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;

1109:         DMPlexSetConeSize(rdm, newp, 3);
1110:         DMPlexGetSupportSize(dm, f, &size);
1111:         DMPlexSetSupportSize(rdm, newp, size);
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;

1119:         DMPlexSetConeSize(rdm, newp, 3);
1120:         DMPlexSetSupportSize(rdm, newp, 2);
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;

1129:         DMPlexSetConeSize(rdm, newp, 4);
1130:         DMPlexGetSupportSize(dm, f, &size);
1131:         DMPlexSetSupportSize(rdm, newp, size);
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;

1139:         DMPlexSetConeSize(rdm, newp, 4);
1140:         DMPlexSetSupportSize(rdm, newp, 2);
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;

1149:         DMPlexSetConeSize(rdm, newp, 2);
1150:         DMPlexGetSupportSize(dm, e, &size);
1151:         DMPlexSetSupportSize(rdm, newp, size);
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;

1161:         DMPlexSetConeSize(rdm, newp, 2);
1162:         DMPlexGetSupportSize(dm, f, &supportSize);
1163:         DMPlexGetSupport(dm, f, &support);
1164:         for (s = 0; s < supportSize; ++s) {
1165:           DMPlexGetConeSize(dm, support[s], &coneSize);
1166:           DMPlexGetCone(dm, support[s], &cone);
1167:           DMPlexGetConeOrientation(dm, support[s], &ornt);
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:         DMPlexSetSupportSize(rdm, newp, 2+intFaces);
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);

1188:       DMPlexSetConeSize(rdm, newp, 2);
1189:       DMPlexSetSupportSize(rdm, newp, 4);
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;

1196:       DMPlexSetConeSize(rdm, newp, 2);
1197:       DMPlexGetSupportSize(dm, e, &size);
1198:       DMPlexSetSupportSize(rdm, newp, size);
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;

1205:       DMPlexSetConeSize(rdm, newp, 2);
1206:       DMPlexGetSupportSize(dm, f, &size);
1207:       DMPlexSetSupportSize(rdm, newp, 2+2*size);
1208:     }
1209:     /* Interior vertices have identical supports */
1210:     for (v = vStart; v < vEnd; ++v) {
1211:       const PetscInt newp = vStartNew + (v - vStart);
1212:       PetscInt       size;

1214:       DMPlexGetSupportSize(dm, v, &size);
1215:       DMPlexSetSupportSize(rdm, newp, size);
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;

1223:       DMPlexGetSupportSize(dm, e, &size);
1224:       DMPlexGetSupport(dm, e, &support);
1225:       for (s = 0; s < size; ++s) {
1226:         if (support[s] < fMax) faceSize += 2;
1227:         else                   faceSize += 1;
1228:       }
1229:       DMPlexGetTransitiveClosure(dm, e, PETSC_FALSE, &starSize, &star);
1230:       for (s = 0; s < starSize*2; s += 2) {
1231:         const PetscInt *cone, *ornt;
1232:         PetscInt        e01, e23;

1234:         if ((star[s] >= cStart) && (star[s] < cMax)) {
1235:           /* Check edge 0-1 */
1236:           DMPlexGetCone(dm, star[s], &cone);
1237:           DMPlexGetConeOrientation(dm, star[s], &ornt);
1238:           DMPlexGetCone(dm, cone[0], &cone);
1239:           e01  = cone[GetTriEdge_Static(ornt[0], 0)];
1240:           /* Check edge 2-3 */
1241:           DMPlexGetCone(dm, star[s], &cone);
1242:           DMPlexGetConeOrientation(dm, star[s], &ornt);
1243:           DMPlexGetCone(dm, cone[2], &cone);
1244:           e23  = cone[GetTriEdge_Static(ornt[2], 1)];
1245:           if ((e01 == e) || (e23 == e)) ++cellSize;
1246:         }
1247:       }
1248:       DMPlexRestoreTransitiveClosure(dm, e, PETSC_FALSE, &starSize, &star);
1249:       DMPlexSetSupportSize(rdm, newp, 2 + faceSize + cellSize);
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;

1258:         DMPlexSetConeSize(rdm, newp, 6);
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;

1267:         DMPlexSetConeSize(rdm, newp, 4);
1268:         DMPlexGetSupportSize(dm, f, &size);
1269:         DMPlexSetSupportSize(rdm, newp, size);
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;

1277:         DMPlexSetConeSize(rdm, newp, 4);
1278:         DMPlexSetSupportSize(rdm, newp, 2);
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;

1287:         DMPlexSetConeSize(rdm, newp, 2);
1288:         DMPlexGetSupportSize(dm, e, &size);
1289:         DMPlexSetSupportSize(rdm, newp, size);
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;

1298:         DMPlexSetConeSize(rdm, newp, 2);
1299:         DMPlexGetSupportSize(dm, f, &size);
1300:         DMPlexSetSupportSize(rdm, newp, 2+size);
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;

1308:         DMPlexSetConeSize(rdm, newp, 2);
1309:         DMPlexSetSupportSize(rdm, newp, 3);
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;

1317:       DMPlexGetSupportSize(dm, v, &size);
1318:       DMPlexSetSupportSize(rdm, newp, size);
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;

1325:       DMPlexGetSupportSize(dm, e, &size);
1326:       DMPlexSetSupportSize(rdm, newp, 2 + size);
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;

1333:       DMPlexGetSupportSize(dm, f, &size);
1334:       DMPlexSetSupportSize(rdm, newp, 3 + size);
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;

1340:       DMPlexSetSupportSize(rdm, newp, 4);
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;

1356:         DMPlexSetConeSize(rdm, newp, 6);
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;

1363:         DMPlexSetConeSize(rdm, newp, 6);
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;

1372:         DMPlexSetConeSize(rdm, newp, 4);
1373:         DMPlexGetSupportSize(dm, f, &size);
1374:         DMPlexSetSupportSize(rdm, newp, size);
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;

1382:         DMPlexSetConeSize(rdm, newp, 4);
1383:         DMPlexSetSupportSize(rdm, newp, 2);
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;

1392:         DMPlexSetConeSize(rdm, newp, 4);
1393:         DMPlexGetSupportSize(dm, f, &size);
1394:         DMPlexSetSupportSize(rdm, newp, size);
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;

1402:         DMPlexSetConeSize(rdm, newp, 4);
1403:         DMPlexSetSupportSize(rdm, newp, 2);
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;

1412:         DMPlexSetConeSize(rdm, newp, 2);
1413:         DMPlexGetSupportSize(dm, e, &size);
1414:         DMPlexSetSupportSize(rdm, newp, size);
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;

1423:         DMPlexSetConeSize(rdm, newp, 2);
1424:         DMPlexGetSupportSize(dm, f, &size);
1425:         DMPlexSetSupportSize(rdm, newp, 2+size);
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;

1433:         DMPlexSetConeSize(rdm, newp, 2);
1434:         DMPlexSetSupportSize(rdm, newp, 3);
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;

1442:       DMPlexSetConeSize(rdm, newp, 2);
1443:       DMPlexGetSupportSize(dm, e, &size);
1444:       DMPlexSetSupportSize(rdm, newp, size);
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;

1451:       DMPlexSetConeSize(rdm, newp, 2);
1452:       DMPlexGetSupportSize(dm, f, &size);
1453:       DMPlexSetSupportSize(rdm, newp, 2+size);
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);

1459:       DMPlexSetConeSize(rdm, newp, 2);
1460:       DMPlexSetSupportSize(rdm, newp, 3);
1461:     }
1462:     /* Old vertices have identical supports */
1463:     for (v = vStart; v < vEnd; ++v) {
1464:       const PetscInt newp = vStartNew + (v - vStart);
1465:       PetscInt       size;

1467:       DMPlexGetSupportSize(dm, v, &size);
1468:       DMPlexSetSupportSize(rdm, newp, size);
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;

1475:       DMPlexGetSupportSize(dm, e, &size);
1476:       DMPlexSetSupportSize(rdm, newp, 2 + size);
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;

1483:       DMPlexGetSupportSize(dm, f, &size);
1484:       DMPlexSetSupportSize(rdm, newp, 3 + size);
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;

1490:       DMPlexSetSupportSize(rdm, newp, 4);
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;

1499:         DMPlexSetConeSize(rdm, newp, 6);
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;

1508:         DMPlexSetConeSize(rdm, newp, 4);
1509:         DMPlexGetSupportSize(dm, f, &size);
1510:         DMPlexSetSupportSize(rdm, newp, size);
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;

1518:         DMPlexSetConeSize(rdm, newp, 4);
1519:         DMPlexSetSupportSize(rdm, newp, 2);
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;

1528:         DMPlexSetConeSize(rdm, newp, 2);
1529:         DMPlexGetSupportSize(dm, e, &size);
1530:         DMPlexSetSupportSize(rdm, newp, size);
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;

1539:         DMPlexSetConeSize(rdm, newp, 2);
1540:         DMPlexGetSupportSize(dm, f, &size);
1541:         DMPlexSetSupportSize(rdm, newp, 2+size);
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;

1549:         DMPlexSetConeSize(rdm, newp, 2);
1550:         DMPlexSetSupportSize(rdm, newp, 4);
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;

1558:       DMPlexGetSupportSize(dm, v, &size);
1559:       DMPlexSetSupportSize(rdm, newp, size);
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;

1566:       DMPlexGetSupportSize(dm, e, &size);
1567:       DMPlexSetSupportSize(rdm, newp, 2 + size);
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;

1574:       DMPlexGetSupportSize(dm, f, &size);
1575:       DMPlexSetSupportSize(rdm, newp, 4 + size);
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);

1581:       DMPlexSetSupportSize(rdm, newp, 6);
1582:     }
1583:     break;
1584:   case REFINER_HYBRID_HEX_3D:
1585:     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);
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;

1592:         DMPlexSetConeSize(rdm, newp, 6);
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;

1600:         DMPlexSetConeSize(rdm, newp, 6);
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;

1609:         DMPlexSetConeSize(rdm, newp, 4);
1610:         DMPlexGetSupportSize(dm, f, &size);
1611:         DMPlexSetSupportSize(rdm, newp, size);
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;

1619:         DMPlexSetConeSize(rdm, newp, 4);
1620:         DMPlexSetSupportSize(rdm, newp, 2);
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;

1629:         DMPlexSetConeSize(rdm, newp, 4);
1630:         DMPlexGetSupportSize(dm, f, &size);
1631:         DMPlexSetSupportSize(rdm, newp, size);
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;

1639:         DMPlexSetConeSize(rdm, newp, 4);
1640:         DMPlexSetSupportSize(rdm, newp, 2);
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;

1649:         DMPlexSetConeSize(rdm, newp, 2);
1650:         DMPlexGetSupportSize(dm, e, &size);
1651:         DMPlexSetSupportSize(rdm, newp, size);
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;

1660:         DMPlexSetConeSize(rdm, newp, 2);
1661:         DMPlexGetSupportSize(dm, f, &size);
1662:         DMPlexSetSupportSize(rdm, newp, 2+size);
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;

1670:         DMPlexSetConeSize(rdm, newp, 2);
1671:         DMPlexSetSupportSize(rdm, newp, 4);
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;

1679:       DMPlexSetConeSize(rdm, newp, 2);
1680:       DMPlexGetSupportSize(dm, e, &size);
1681:       DMPlexSetSupportSize(rdm, newp, size);
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;

1688:       DMPlexSetConeSize(rdm, newp, 2);
1689:       DMPlexGetSupportSize(dm, f, &size);
1690:       DMPlexSetSupportSize(rdm, newp, 2+size);
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);

1696:       DMPlexSetConeSize(rdm, newp, 2);
1697:       DMPlexSetSupportSize(rdm, newp, 4);
1698:     }
1699:     /* Interior vertices have identical supports */
1700:     for (v = vStart; v < vEnd; ++v) {
1701:       const PetscInt newp = vStartNew + (v - vStart);
1702:       PetscInt       size;

1704:       DMPlexGetSupportSize(dm, v, &size);
1705:       DMPlexSetSupportSize(rdm, newp, size);
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;

1712:       DMPlexGetSupportSize(dm, e, &size);
1713:       DMPlexSetSupportSize(rdm, newp, 2 + size);
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;

1720:       DMPlexGetSupportSize(dm, f, &size);
1721:       DMPlexSetSupportSize(rdm, newp, 4 + size);
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);

1727:       DMPlexSetSupportSize(rdm, newp, 6);
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;

1736:     DMPlexGetCellTypeLabel(rdm, &celltypeLabel);
1737:     PetscObjectStateGet((PetscObject) celltypeLabel, &plex->celltypeState);
1738:   }
1739:   return(0);
1740: }

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;

1754:   if (!refiner) return(0);
1755:   DMPlexGetDepth(dm, &depth);
1756:   DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);
1757:   DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);
1758:   DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);
1759:   DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);
1760:   DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);
1761:   GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);
1762:   GetDepthEnd_Private(depth, depthSize, &cEndNew, &fEndNew, &eEndNew, &vEndNew);
1763:   switch (refiner) {
1764:   case REFINER_SIMPLEX_1D:
1765:     /* Max support size of refined mesh is 2 */
1766:     PetscMalloc1(2, &supportRef);
1767:     /* All cells have 2 vertices */
1768:     for (c = cStart; c < cEnd; ++c) {
1769:       const PetscInt  newv = vStartNew + (vEnd - vStart) + (c - cStart);

1771:       for (r = 0; r < 2; ++r) {
1772:         const PetscInt newp = cStartNew + (c - cStart)*2 + r;
1773:         const PetscInt *cone;
1774:         PetscInt        coneNew[2];

1776:         DMPlexGetCone(dm, c, &cone);
1777:         coneNew[0]       = vStartNew + (cone[0] - vStart);
1778:         coneNew[1]       = vStartNew + (cone[1] - vStart);
1779:         coneNew[(r+1)%2] = newv;
1780:         DMPlexSetCone(rdm, newp, coneNew);
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;

1795:       DMPlexGetSupportSize(dm, v, &size);
1796:       DMPlexGetSupport(dm, v, &support);
1797:       for (s = 0; s < size; ++s) {
1798:         PetscInt r = 0;

1800:         DMPlexGetCone(dm, support[s], &cone);
1801:         if (cone[1] == v) r = 1;
1802:         supportRef[s] = cStartNew + (support[s] - cStart)*2 + r;
1803:       }
1804:       DMPlexSetSupport(rdm, newp, supportRef);
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);

1816:       supportRef[0] = cStartNew + (c - cStart)*2 + 0;
1817:       supportRef[1] = cStartNew + (c - cStart)*2 + 1;
1818:       DMPlexSetSupport(rdm, newp, supportRef);
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:     PetscFree(supportRef);
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];

1850:       DMPlexGetCone(dm, c, &cone);
1851:       DMPlexGetConeOrientation(dm, c, &ornt);
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:       DMPlexSetCone(rdm, newp+0, coneNew);
1860:       DMPlexSetConeOrientation(rdm, newp+0, orntNew);
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:       DMPlexSetCone(rdm, newp+1, coneNew);
1875:       DMPlexSetConeOrientation(rdm, newp+1, orntNew);
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:       DMPlexSetCone(rdm, newp+2, coneNew);
1890:       DMPlexSetConeOrientation(rdm, newp+2, orntNew);
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:       DMPlexSetCone(rdm, newp+3, coneNew);
1905:       DMPlexSetConeOrientation(rdm, newp+3, orntNew);
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:     DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);
1915:     PetscMalloc1(2 + maxSupportSize*2, &supportRef);
1916:     for (f = fStart; f < fEnd; ++f) {
1917:       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);

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;

1924:         DMPlexGetCone(dm, f, &cone);
1925:         coneNew[0]       = vStartNew + (cone[0] - vStart);
1926:         coneNew[1]       = vStartNew + (cone[1] - vStart);
1927:         coneNew[(r+1)%2] = newv;
1928:         DMPlexSetCone(rdm, newp, coneNew);
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:         DMPlexGetSupportSize(dm, f, &supportSize);
1936:         DMPlexGetSupport(dm, f, &support);
1937:         for (s = 0; s < supportSize; ++s) {
1938:           DMPlexGetConeSize(dm, support[s], &coneSize);
1939:           DMPlexGetCone(dm, support[s], &cone);
1940:           DMPlexGetConeOrientation(dm, support[s], &ornt);
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:         DMPlexSetSupport(rdm, newp, supportRef);
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;

1959:       DMPlexGetCone(dm, c, &cone);
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];

1965:         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r]       - fStart);
1966:         coneNew[1] = vStartNew + (vEnd - vStart) + (cone[(r+1)%3] - fStart);
1967:         DMPlexSetCone(rdm, newp, coneNew);
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:         DMPlexSetSupport(rdm, newp, supportNew);
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;

1991:       DMPlexGetSupportSize(dm, v, &size);
1992:       DMPlexGetSupport(dm, v, &support);
1993:       for (s = 0; s < size; ++s) {
1994:         PetscInt r = 0;

1996:         DMPlexGetCone(dm, support[s], &cone);
1997:         if (cone[1] == v) r = 1;
1998:         supportRef[s] = fStartNew + (support[s] - fStart)*2 + r;
1999:       }
2000:       DMPlexSetSupport(rdm, newp, supportRef);
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;

2014:       DMPlexGetSupportSize(dm, f, &size);
2015:       DMPlexGetSupport(dm, f, &support);
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;

2021:         DMPlexGetCone(dm, support[s], &cone);
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:       DMPlexSetSupport(rdm, newp, supportRef);
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:     PetscFree(supportRef);
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];

2062:       DMPlexGetCone(dm, c, &cone);
2063:       DMPlexGetConeOrientation(dm, c, &ornt);
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:       DMPlexSetCone(rdm, newp+0, coneNew);
2074:       DMPlexSetConeOrientation(rdm, newp+0, orntNew);
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:       DMPlexSetCone(rdm, newp+1, coneNew);
2091:       DMPlexSetConeOrientation(rdm, newp+1, orntNew);
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:       DMPlexSetCone(rdm, newp+2, coneNew);
2108:       DMPlexSetConeOrientation(rdm, newp+2, orntNew);
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:     DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);
2118:     PetscMalloc1(2 + maxSupportSize*2, &supportRef);
2119:     for (f = fStart; f < fEnd; ++f) {
2120:       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);

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;

2127:         DMPlexGetCone(dm, f, &cone);
2128:         coneNew[0]       = vStartNew + (cone[0] - vStart);
2129:         coneNew[1]       = vStartNew + (cone[1] - vStart);
2130:         coneNew[(r+1)%2] = newv;
2131:         DMPlexSetCone(rdm, newp, coneNew);
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:         DMPlexGetSupportSize(dm, f, &supportSize);
2139:         DMPlexGetSupport(dm, f, &support);
2140:         for (s = 0; s < supportSize; ++s) {
2141:           DMPlexGetConeSize(dm, support[s], &coneSize);
2142:           DMPlexGetCone(dm, support[s], &cone);
2143:           DMPlexGetConeOrientation(dm, support[s], &ornt);
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:         DMPlexSetSupport(rdm, newp, supportRef);
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;

2162:       DMPlexGetCone(dm, c, &cone);
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];

2168:         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r] - fStart);
2169:         coneNew[1] = vStartNew + (vEnd - vStart) + (fEnd    - fStart) + (c - cStart);
2170:         DMPlexSetCone(rdm, newp, coneNew);
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:         DMPlexSetSupport(rdm, newp, supportNew);
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;

2194:       DMPlexGetSupportSize(dm, v, &size);
2195:       DMPlexGetSupport(dm, v, &support);
2196:       for (s = 0; s < size; ++s) {
2197:         PetscInt r = 0;

2199:         DMPlexGetCone(dm, support[s], &cone);
2200:         if (cone[1] == v) r = 1;
2201:         supportRef[s] = fStartNew + (support[s] - fStart)*2 + r;
2202:       }
2203:       DMPlexSetSupport(rdm, newp, supportRef);
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;

2217:       DMPlexGetSupportSize(dm, f, &size);
2218:       DMPlexGetSupport(dm, f, &support);
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;

2224:         DMPlexGetCone(dm, support[s], &cone);
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:       DMPlexSetSupport(rdm, newp, supportRef);
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;

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:       DMPlexSetSupport(rdm, newp, supportRef);
2245:     }
2246:     PetscFree(supportRef);
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];

2256:       DMPlexGetCone(dm, c, &cone);
2257:       DMPlexGetConeOrientation(dm, c, &ornt);
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:       DMPlexSetCone(rdm, newp+0, coneNew);
2268:       DMPlexSetConeOrientation(rdm, newp+0, orntNew);
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:       DMPlexSetCone(rdm, newp+1, coneNew);
2285:       DMPlexSetConeOrientation(rdm, newp+1, orntNew);
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:       DMPlexSetCone(rdm, newp+2, coneNew);
2302:       DMPlexSetConeOrientation(rdm, newp+2, orntNew);
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];

2328:       DMPlexGetCone(dm, c, &cone);
2329:       DMPlexGetConeOrientation(dm, c, &ornt);
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:       DMPlexSetCone(rdm, newp+0, coneNew);
2340:       DMPlexSetConeOrientation(rdm, newp+0, orntNew);
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:       DMPlexSetCone(rdm, newp+1, coneNew);
2357:       DMPlexSetConeOrientation(rdm, newp+1, orntNew);
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:       DMPlexSetCone(rdm, newp+2, coneNew);
2374:       DMPlexSetConeOrientation(rdm, newp+2, orntNew);
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:       DMPlexSetCone(rdm, newp+3, coneNew);
2391:       DMPlexSetConeOrientation(rdm, newp+3, orntNew);
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:     DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);
2401:     PetscMalloc1(2 + maxSupportSize*2, &supportRef);
2402:     for (f = fStart; f < fEnd; ++f) {
2403:       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);

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;

2410:         DMPlexGetCone(dm, f, &cone);
2411:         coneNew[0]       = vStartNew + (cone[0] - vStart);
2412:         coneNew[1]       = vStartNew + (cone[1] - vStart);
2413:         coneNew[(r+1)%2] = newv;
2414:         DMPlexSetCone(rdm, newp, coneNew);
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:         DMPlexGetSupportSize(dm, f, &supportSize);
2422:         DMPlexGetSupport(dm, f, &support);
2423:         for (s = 0; s < supportSize; ++s) {
2424:           const PetscInt p2q[4][2] = { {0, 1},
2425:                                        {3, 2},
2426:                                        {0, 3},
2427:                                        {1, 2} };

2429:           DMPlexGetConeSize(dm, support[s], &coneSize);
2430:           DMPlexGetCone(dm, support[s], &cone);
2431:           DMPlexGetConeOrientation(dm, support[s], &ornt);
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:         DMPlexSetSupport(rdm, newp, supportRef);
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;

2452:       DMPlexGetCone(dm, c, &cone);
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];

2458:         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r] - fStart);
2459:         coneNew[1] = vStartNew + (vEnd - vStart) + (fEnd    - fStart) + (c - cStart);
2460:         DMPlexSetCone(rdm, newp, coneNew);
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:         DMPlexSetSupport(rdm, newp, supportNew);
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];

2483:       DMPlexGetCone(dm, c, &cone);
2484:       for (r = 0; r < 4; ++r) {
2485:         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (cMax - cStart)*3 + (c - cMax)*4 + r;

2487:         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r] - fStart);
2488:         coneNew[1] = vStartNew + (vEnd - vStart) + (fEnd    - fStart) + (cMax - cStart) + (c - cMax);
2489:         DMPlexSetCone(rdm, newp, coneNew);
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:         DMPlexSetSupport(rdm, newp, supportNew);
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;

2524:       DMPlexGetSupportSize(dm, v, &size);
2525:       DMPlexGetSupport(dm, v, &support);
2526:       for (s = 0; s < size; ++s) {
2527:         PetscInt r = 0;

2529:         DMPlexGetCone(dm, support[s], &cone);
2530:         if (cone[1] == v) r = 1;
2531:         supportRef[s] = fStartNew + (support[s] - fStart)*2 + r;
2532:       }
2533:       DMPlexSetSupport(rdm, newp, supportRef);
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;

2547:       DMPlexGetSupportSize(dm, f, &size);
2548:       DMPlexGetSupport(dm, f, &support);
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;

2554:         DMPlexGetCone(dm, support[s], &cone);
2555:         DMPlexGetConeSize(dm, support[s], &coneSize);
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:       DMPlexSetSupport(rdm, newp, supportRef);
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;

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:       DMPlexSetSupport(rdm, newp, supportRef);
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;

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:       DMPlexSetSupport(rdm, newp, supportRef);
2593:     }
2594:     PetscFree(supportRef);
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];

2614:       DMPlexGetCone(dm, c, &cone);
2615:       DMPlexGetConeOrientation(dm, c, &ornt);
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:       DMPlexSetCone(rdm, newp+0, coneNew);
2626:       DMPlexSetConeOrientation(rdm, newp+0, orntNew);
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:       DMPlexSetCone(rdm, newp+1, coneNew);
2643:       DMPlexSetConeOrientation(rdm, newp+1, orntNew);
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:       DMPlexSetCone(rdm, newp+2, coneNew);
2660:       DMPlexSetConeOrientation(rdm, newp+2, orntNew);
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:       DMPlexSetCone(rdm, newp+3, coneNew);
2677:       DMPlexSetConeOrientation(rdm, newp+3, orntNew);
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:     DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);
2687:     PetscMalloc1(2 + maxSupportSize*2, &supportRef);
2688:     for (f = fStart; f < fEnd; ++f) {
2689:       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);

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;

2696:         DMPlexGetCone(dm, f, &cone);
2697:         coneNew[0]       = vStartNew + (cone[0] - vStart);
2698:         coneNew[1]       = vStartNew + (cone[1] - vStart);
2699:         coneNew[(r+1)%2] = newv;
2700:         DMPlexSetCone(rdm, newp, coneNew);
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:         DMPlexGetSupportSize(dm, f, &supportSize);
2708:         DMPlexGetSupport(dm, f, &support);
2709:         for (s = 0; s < supportSize; ++s) {
2710:           DMPlexGetConeSize(dm, support[s], &coneSize);
2711:           DMPlexGetCone(dm, support[s], &cone);
2712:           DMPlexGetConeOrientation(dm, support[s], &ornt);
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:         DMPlexSetSupport(rdm, newp, supportRef);
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];

2732:       DMPlexGetCone(dm, c, &cone);
2733:       for (r = 0; r < 4; ++r) {
2734:         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*4 + r;

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:         DMPlexSetCone(rdm, newp, coneNew);
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:         DMPlexSetSupport(rdm, newp, supportNew);
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;

2767:       DMPlexGetSupportSize(dm, v, &size);
2768:       DMPlexGetSupport(dm, v, &support);
2769:       for (s = 0; s < size; ++s) {
2770:         PetscInt r = 0;

2772:         DMPlexGetCone(dm, support[s], &cone);
2773:         if (cone[1] == v) r = 1;
2774:         supportRef[s] = fStartNew + (support[s] - fStart)*2 + r;
2775:       }
2776:       DMPlexSetSupport(rdm, newp, supportRef);
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;

2790:       DMPlexGetSupportSize(dm, f, &size);
2791:       DMPlexGetSupport(dm, f, &support);
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;

2797:         DMPlexGetCone(dm, support[s], &cone);
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:       DMPlexSetSupport(rdm, newp, supportRef);
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];

2816:       for (r = 0; r < 4; ++r) {
2817:         supportNew[r] = fStartNew + (fEnd - fStart)*2 + (c - cStart)*4 + r;
2818:       }
2819:       DMPlexSetSupport(rdm, newp, supportNew);
2820:     }
2821:     PetscFree(supportRef);
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:     DMPlexGetHybridBounds(rdm, &cMaxNew, &fMaxNew, NULL, NULL);
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];

2835:       DMPlexGetCone(dm, c, &cone);
2836:       DMPlexGetConeOrientation(dm, c, &ornt);
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:       DMPlexSetCone(rdm, newp+0, coneNew);
2845:       DMPlexSetConeOrientation(rdm, newp+0, orntNew);
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:       DMPlexSetCone(rdm, newp+1, coneNew);
2860:       DMPlexSetConeOrientation(rdm, newp+1, orntNew);
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:       DMPlexSetCone(rdm, newp+2, coneNew);
2875:       DMPlexSetConeOrientation(rdm, newp+2, orntNew);
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:       DMPlexSetCone(rdm, newp+3, coneNew);
2890:       DMPlexSetConeOrientation(rdm, newp+3, orntNew);
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;

2915:       DMPlexGetCone(dm, c, &cone);
2916:       DMPlexGetConeOrientation(dm, c, &ornt);
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:       DMPlexSetCone(rdm, newp+0, coneNew);
2928:       DMPlexSetConeOrientation(rdm, newp+0, orntNew);
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:       DMPlexSetCone(rdm, newp+1, coneNew);
2945:       DMPlexSetConeOrientation(rdm, newp+1, orntNew);
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:     DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);
2955:     PetscMalloc1(2 + maxSupportSize*2, &supportRef);
2956:     for (f = fStart; f < fMax; ++f) {
2957:       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);

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;

2964:         DMPlexGetCone(dm, f, &cone);
2965:         coneNew[0]       = vStartNew + (cone[0] - vStart);
2966:         coneNew[1]       = vStartNew + (cone[1] - vStart);
2967:         coneNew[(r+1)%2] = newv;
2968:         DMPlexSetCone(rdm, newp, coneNew);
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:         DMPlexGetSupportSize(dm, f, &supportSize);
2976:         DMPlexGetSupport(dm, f, &support);
2977:         for (s = 0; s < supportSize; ++s) {
2978:           DMPlexGetConeSize(dm, support[s], &coneSize);
2979:           DMPlexGetCone(dm, support[s], &cone);
2980:           DMPlexGetConeOrientation(dm, support[s], &ornt);
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:         DMPlexSetSupport(rdm, newp, supportRef);
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;

3001:       DMPlexGetCone(dm, c, &cone);
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];

3007:         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r]       - fStart);
3008:         coneNew[1] = vStartNew + (vEnd - vStart) + (cone[(r+1)%3] - fStart);
3009:         DMPlexSetCone(rdm, newp, coneNew);
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:         DMPlexSetSupport(rdm, newp, supportNew);
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;

3036:       DMPlexGetCone(dm, f, &cone);
3037:       coneNew[0] = vStartNew + (cone[0] - vStart);
3038:       coneNew[1] = vStartNew + (cone[1] - vStart);
3039:       DMPlexSetCone(rdm, newp, coneNew);
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:       DMPlexGetSupportSize(dm, f, &size);
3047:       DMPlexGetSupport(dm, f, &support);
3048:       for (s = 0; s < size; ++s) {
3049:         DMPlexGetCone(dm, support[s], &cone);
3050:         DMPlexGetConeOrientation(dm, support[s], &ornt);
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:       DMPlexSetSupport(rdm, newp, supportNew);
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];

3071:       DMPlexGetCone(dm, c, &cone);
3072:       coneNew[0] = vStartNew + (vEnd - vStart) + (cone[0] - fStart);
3073:       coneNew[1] = vStartNew + (vEnd - vStart) + (cone[1] - fStart);
3074:       DMPlexSetCone(rdm, newp, coneNew);
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:       DMPlexSetSupport(rdm, newp, supportNew);
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;

3097:       DMPlexGetSupportSize(dm, v, &size);
3098:       DMPlexGetSupport(dm, v, &support);
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;

3105:           DMPlexGetCone(dm, support[s], &cone);
3106:           if (cone[1] == v) r = 1;
3107:           supportRef[s] = fStartNew + (support[s] - fStart)*2 + r;
3108:         }
3109:       }
3110:       DMPlexSetSupport(rdm, newp, supportRef);
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;

3124:       DMPlexGetSupportSize(dm, f, &size);
3125:       DMPlexGetSupport(dm, f, &support);
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;

3131:         DMPlexGetCone(dm, support[s], &cone);
3132:         if (support[s] >= cMax) {
3133:           supportRef[newSize+0] = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (fEnd - fMax) + (support[s] - cMax);

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;

3142:           newSize += 2;
3143:         }
3144:       }
3145:       DMPlexSetSupport(rdm, newp, supportRef);
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:     PetscFree(supportRef);
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:     DMPlexGetHybridBounds(rdm, &cMaxNew, &fMaxNew, NULL, NULL);
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];

3168:       DMPlexGetCone(dm, c, &cone);
3169:       DMPlexGetConeOrientation(dm, c, &ornt);
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:       DMPlexSetCone(rdm, newp+0, coneNew);
3180:       DMPlexSetConeOrientation(rdm, newp+0, orntNew);
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:       DMPlexSetCone(rdm, newp+1, coneNew);
3197:       DMPlexSetConeOrientation(rdm, newp+1, orntNew);
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:       DMPlexSetCone(rdm, newp+2, coneNew);
3214:       DMPlexSetConeOrientation(rdm, newp+2, orntNew);
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:       DMPlexSetCone(rdm, newp+3, coneNew);
3231:       DMPlexSetConeOrientation(rdm, newp+3, orntNew);
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];

3256:       DMPlexGetCone(dm, c, &cone);
3257:       DMPlexGetConeOrientation(dm, c, &ornt);
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:       DMPlexSetCone(rdm, newp+0, coneNew);
3268:       DMPlexSetConeOrientation(rdm, newp+0, orntNew);
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:       DMPlexSetCone(rdm, newp+1, coneNew);
3285:       DMPlexSetConeOrientation(rdm, newp+1, orntNew);
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:     DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);
3295:     PetscMalloc1(2 + maxSupportSize*2, &supportRef);
3296:     for (f = fStart; f < fMax; ++f) {
3297:       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);

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;

3304:         DMPlexGetCone(dm, f, &cone);
3305:         coneNew[0]       = vStartNew + (cone[0] - vStart);
3306:         coneNew[1]       = vStartNew + (cone[1] - vStart);
3307:         coneNew[(r+1)%2] = newv;
3308:         DMPlexSetCone(rdm, newp, coneNew);
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:         DMPlexGetSupportSize(dm, f, &supportSize);
3316:         DMPlexGetSupport(dm, f, &support);
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:             DMPlexGetConeSize(dm, support[s], &coneSize);
3322:             DMPlexGetCone(dm, support[s], &cone);
3323:             DMPlexGetConeOrientation(dm, support[s], &ornt);
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:         DMPlexSetSupport(rdm, newp, supportRef);
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;

3343:       DMPlexGetCone(dm, c, &cone);
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];

3348:         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r] - fStart);
3349:         coneNew[1] = vStartNew + (vEnd - vStart) + (fMax    - fStart) + (c - cStart);
3350:         DMPlexSetCone(rdm, newp, coneNew);
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:         DMPlexSetSupport(rdm, newp, supportNew);
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;

3375:       DMPlexGetCone(dm, f, &cone);
3376:       coneNew[0] = vStartNew + (cone[0] - vStart);
3377:       coneNew[1] = vStartNew + (cone[1] - vStart);
3378:       DMPlexSetCone(rdm, newp, coneNew);
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:       DMPlexGetSupportSize(dm, f, &size);
3386:       DMPlexGetSupport(dm, f, &support);
3387:       for (s = 0; s < size; ++s) {
3388:         DMPlexGetCone(dm, support[s], &cone);
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:       DMPlexSetSupport(rdm, newp, supportNew);
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];

3408:       DMPlexGetCone(dm, c, &cone);
3409:       coneNew[0] = vStartNew + (vEnd - vStart) + (cone[0] - fStart);
3410:       coneNew[1] = vStartNew + (vEnd - vStart) + (cone[1] - fStart);
3411:       DMPlexSetCone(rdm, newp, coneNew);
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:       DMPlexSetSupport(rdm, newp, supportNew);
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;

3434:       DMPlexGetSupportSize(dm, v, &size);
3435:       DMPlexGetSupport(dm, v, &support);
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;

3442:           DMPlexGetCone(dm, support[s], &cone);
3443:           if (cone[1] == v) r = 1;
3444:           supportRef[s] = fStartNew + (support[s] - fStart)*2 + r;
3445:         }
3446:       }
3447:       DMPlexSetSupport(rdm, newp, supportRef);
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;

3461:       DMPlexGetSupportSize(dm, f, &size);
3462:       DMPlexGetSupport(dm, f, &support);
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;

3468:         DMPlexGetCone(dm, support[s], &cone);
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:       DMPlexSetSupport(rdm, newp, supportRef);
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];

3491:       for (r = 0; r < 4; ++r) {
3492:         supportNew[r] = fStartNew + (fMax - fStart)*2 + (c - cStart)*4 + r;
3493:       }
3494:       DMPlexSetSupport(rdm, newp, supportNew);
3495:     }
3496:     PetscFree(supportRef);
3497:     break;
3498:   case REFINER_SIMPLEX_3D:
3499:     /* All cells have 4 faces: Tet face order is prescribed in DMPlexGetFaces_Internal() */
3500:     DMPlexGetRawFaces_Internal(dm, DM_POLYTOPE_TETRAHEDRON, cellInd, NULL, NULL, &faces);
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];

3506:       DMPlexGetCone(dm, c, &cone);
3507:       DMPlexGetConeOrientation(dm, c, &ornt);
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:       DMPlexSetCone(rdm, newp+0, coneNew);
3518:       DMPlexSetConeOrientation(rdm, newp+0, orntNew);
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:       DMPlexSetCone(rdm, newp+1, coneNew);
3535:       DMPlexSetConeOrientation(rdm, newp+1, orntNew);
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:       DMPlexSetCone(rdm, newp+2, coneNew);
3552:       DMPlexSetConeOrientation(rdm, newp+2, orntNew);
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:       DMPlexSetCone(rdm, newp+3, coneNew);
3569:       DMPlexSetConeOrientation(rdm, newp+3, orntNew);
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:       DMPlexSetCone(rdm, newp+4, coneNew);
3586:       DMPlexSetConeOrientation(rdm, newp+4, orntNew);
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:       DMPlexSetCone(rdm, newp+5, coneNew);
3603:       DMPlexSetConeOrientation(rdm, newp+5, orntNew);
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:       DMPlexSetCone(rdm, newp+6, coneNew);
3620:       DMPlexSetConeOrientation(rdm, newp+6, orntNew);
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:       DMPlexSetCone(rdm, newp+7, coneNew);
3637:       DMPlexSetConeOrientation(rdm, newp+7, orntNew);
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:     DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);
3647:     PetscMalloc1(2 + maxSupportSize*3, &supportRef);
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;

3653:       DMPlexGetCone(dm, f, &cone);
3654:       DMPlexGetConeOrientation(dm, f, &ornt);
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:       DMPlexSetCone(rdm, newp+0, coneNew);
3663:       DMPlexSetConeOrientation(rdm, newp+0, orntNew);
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:       DMPlexSetCone(rdm, newp+1, coneNew);
3678:       DMPlexSetConeOrientation(rdm, newp+1, orntNew);
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:       DMPlexSetCone(rdm, newp+2, coneNew);
3693:       DMPlexSetConeOrientation(rdm, newp+2, orntNew);
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:       DMPlexSetCone(rdm, newp+3, coneNew);
3708:       DMPlexSetConeOrientation(rdm, newp+3, orntNew);
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:       DMPlexGetSupportSize(dm, f, &supportSize);
3716:       DMPlexGetSupport(dm, f, &support);
3717:       for (r = 0; r < 4; ++r) {
3718:         for (s = 0; s < supportSize; ++s) {
3719:           PetscInt subf;
3720:           DMPlexGetConeSize(dm, support[s], &coneSize);
3721:           DMPlexGetCone(dm, support[s], &cone);
3722:           DMPlexGetConeOrientation(dm, support[s], &ornt);
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:         DMPlexSetSupport(rdm, newp+r, supportRef);
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];

3745:       DMPlexGetCone(dm, c, &cone);
3746:       DMPlexGetConeOrientation(dm, c, &ornt);
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:       DMPlexSetCone(rdm, newp, coneNew);
3755:       DMPlexSetConeOrientation(rdm, newp, orntNew);
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:       DMPlexSetSupport(rdm, newp, supportNew);
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:       DMPlexSetCone(rdm, newp, coneNew);
3780:       DMPlexSetConeOrientation(rdm, newp, orntNew);
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:       DMPlexSetSupport(rdm, newp, supportNew);
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:       DMPlexSetCone(rdm, newp, coneNew);
3805:       DMPlexSetConeOrientation(rdm, newp, orntNew);
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:       DMPlexSetSupport(rdm, newp, supportNew);
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:       DMPlexSetCone(rdm, newp, coneNew);
3830:       DMPlexSetConeOrientation(rdm, newp, orntNew);
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:       DMPlexSetSupport(rdm, newp, supportNew);
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:       DMPlexSetCone(rdm, newp, coneNew);
3855:       DMPlexSetConeOrientation(rdm, newp, orntNew);
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:       DMPlexSetSupport(rdm, newp, supportNew);
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:       DMPlexSetCone(rdm, newp, coneNew);
3880:       DMPlexSetConeOrientation(rdm, newp, orntNew);
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:       DMPlexSetSupport(rdm, newp, supportNew);
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:       DMPlexSetCone(rdm, newp, coneNew);
3905:       DMPlexSetConeOrientation(rdm, newp, orntNew);
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:       DMPlexSetSupport(rdm, newp, supportNew);
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:       DMPlexSetCone(rdm, newp, coneNew);
3930:       DMPlexSetConeOrientation(rdm, newp, orntNew);
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:       DMPlexSetSupport(rdm, newp, supportNew);
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);

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;

3957:         DMPlexGetCone(dm, e, &cone);
3958:         coneNew[0]       = vStartNew + (cone[0] - vStart);
3959:         coneNew[1]       = vStartNew + (cone[1] - vStart);
3960:         coneNew[(r+1)%2] = newv;
3961:         DMPlexSetCone(rdm, newp, coneNew);
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:         DMPlexGetSupportSize(dm, e, &supportSize);
3969:         DMPlexGetSupport(dm, e, &support);
3970:         for (s = 0; s < supportSize; ++s) {
3971:           DMPlexGetConeSize(dm, support[s], &coneSize);
3972:           DMPlexGetCone(dm, support[s], &cone);
3973:           DMPlexGetConeOrientation(dm, support[s], &ornt);
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:         DMPlexSetSupport(rdm, newp, supportRef);
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;

3993:       DMPlexGetSupportSize(dm, f, &supportSize);
3994:       DMPlexGetSupport(dm, f, &support);
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};

4003:         DMPlexGetCone(dm, f, &cone);
4004:         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[(r+0)%3] - eStart);
4005:         coneNew[1] = vStartNew + (vEnd - vStart) + (cone[(r+1)%3] - eStart);
4006:         DMPlexSetCone(rdm, newp, coneNew);
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:           DMPlexGetConeSize(dm, support[s], &coneSize);
4017:           DMPlexGetCone(dm, support[s], &cone);
4018:           DMPlexGetConeOrientation(dm, support[s], &ornt);
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:         DMPlexSetSupport(rdm, newp, supportRef);
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;

4044:       DMPlexGetCone(dm, c, &cone);
4045:       DMPlexGetConeOrientation(dm, c, &ornt);
4046:       DMPlexGetCone(dm, cone[0], &fcone);
4047:       find = GetTriEdge_Static(ornt[0], 0);
4048:       coneNew[0] = vStartNew + (vEnd - vStart) + (fcone[find] - eStart);
4049:       DMPlexGetCone(dm, cone[2], &fcone);
4050:       find = GetTriEdge_Static(ornt[2], 1);
4051:       coneNew[1] = vStartNew + (vEnd - vStart) + (fcone[find] - eStart);
4052:       DMPlexSetCone(rdm, newp, coneNew);
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:       DMPlexSetSupport(rdm, newp, supportNew);
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;

4077:       DMPlexGetSupportSize(dm, v, &size);
4078:       DMPlexGetSupport(dm, v, &support);
4079:       for (s = 0; s < size; ++s) {
4080:         PetscInt r = 0;

4082:         DMPlexGetCone(dm, support[s], &cone);
4083:         if (cone[1] == v) r = 1;
4084:         supportRef[s] = eStartNew + (support[s] - eStart)*2 + r;
4085:       }
4086:       DMPlexSetSupport(rdm, newp, supportRef);
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;

4100:       DMPlexGetSupportSize(dm, e, &size);
4101:       DMPlexGetSupport(dm, e, &support);
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;

4107:         DMPlexGetConeSize(dm, support[s], &coneSize);
4108:         DMPlexGetCone(dm, support[s], &cone);
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:       DMPlexGetTransitiveClosure(dm, e, PETSC_FALSE, &starSize, &star);
4114:       for (s = 0; s < starSize*2; s += 2) {
4115:         const PetscInt *cone, *ornt;
4116:         PetscInt        e01, e23;

4118:         if ((star[s] >= cStart) && (star[s] < cEnd)) {
4119:           /* Check edge 0-1 */
4120:           DMPlexGetCone(dm, star[s], &cone);
4121:           DMPlexGetConeOrientation(dm, star[s], &ornt);
4122:           DMPlexGetCone(dm, cone[0], &cone);
4123:           e01  = cone[GetTriEdge_Static(ornt[0], 0)];
4124:           /* Check edge 2-3 */
4125:           DMPlexGetCone(dm, star[s], &cone);
4126:           DMPlexGetConeOrientation(dm, star[s], &ornt);
4127:           DMPlexGetCone(dm, cone[2], &cone);
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:       DMPlexRestoreTransitiveClosure(dm, e, PETSC_FALSE, &starSize, &star);
4133:       DMPlexSetSupport(rdm, newp, supportRef);
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:     PetscFree(supportRef);
4142:     DMPlexRestoreFaces_Internal(dm, cStart, NULL, NULL, &faces);
4143:     break;
4144:   case REFINER_HYBRID_SIMPLEX_3D:
4145:     DMPlexGetHybridBounds(rdm, &cMaxNew, &fMaxNew, &eMaxNew, NULL);
4146:     /* Interior cells have 4 faces: Tet face order is prescribed in DMPlexGetFaces_Internal() */
4147:     DMPlexGetRawFaces_Internal(dm, DM_POLYTOPE_TETRAHEDRON, cellInd, NULL, NULL, &faces);
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];

4153:       DMPlexGetCone(dm, c, &cone);
4154:       DMPlexGetConeOrientation(dm, c, &ornt);
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:       DMPlexSetCone(rdm, newp+0, coneNew);
4165:       DMPlexSetConeOrientation(rdm, newp+0, orntNew);
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:       DMPlexSetCone(rdm, newp+1, coneNew);
4182:       DMPlexSetConeOrientation(rdm, newp+1, orntNew);
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:       DMPlexSetCone(rdm, newp+2, coneNew);
4199:       DMPlexSetConeOrientation(rdm, newp+2, orntNew);
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:       DMPlexSetCone(rdm, newp+3, coneNew);
4216:       DMPlexSetConeOrientation(rdm, newp+3, orntNew);
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:       DMPlexSetCone(rdm, newp+4, coneNew);
4233:       DMPlexSetConeOrientation(rdm, newp+4, orntNew);
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:       DMPlexSetCone(rdm, newp+5, coneNew);
4250:       DMPlexSetConeOrientation(rdm, newp+5, orntNew);
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:       DMPlexSetCone(rdm, newp+6, coneNew);
4267:       DMPlexSetConeOrientation(rdm, newp+6, orntNew);
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:       DMPlexSetCone(rdm, newp+7, coneNew);
4284:       DMPlexSetConeOrientation(rdm, newp+7, orntNew);
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;

4298:       DMPlexGetCone(dm, c, &cone);
4299:       DMPlexGetConeOrientation(dm, c, &ornt);
4300:       DMPlexGetConeOrientation(dm, cone[0], &fornt);
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:         DMPlexSetCone(rdm, newp+r, coneNew);
4319:         DMPlexSetConeOrientation(rdm, newp+r, orntNew);
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:       DMPlexSetCone(rdm, newp+3, coneNew);
4341:       DMPlexSetConeOrientation(rdm, newp+3, orntNew);
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:     DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);
4354:     PetscMalloc1(2 + maxSupportSize*2, &supportRef);
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;

4360:       DMPlexGetCone(dm, f, &cone);
4361:       DMPlexGetConeOrientation(dm, f, &ornt);
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:       DMPlexSetCone(rdm, newp+0, coneNew);
4370:       DMPlexSetConeOrientation(rdm, newp+0, orntNew);
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:       DMPlexSetCone(rdm, newp+1, coneNew);
4385:       DMPlexSetConeOrientation(rdm, newp+1, orntNew);
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:       DMPlexSetCone(rdm, newp+2, coneNew);
4400:       DMPlexSetConeOrientation(rdm, newp+2, orntNew);
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:       DMPlexSetCone(rdm, newp+3, coneNew);
4415:       DMPlexSetConeOrientation(rdm, newp+3, orntNew);
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:       DMPlexGetSupportSize(dm, f, &supportSize);
4423:       DMPlexGetSupport(dm, f, &support);
4424:       for (r = 0; r < 4; ++r) {
4425:         for (s = 0; s < supportSize; ++s) {
4426:           PetscInt subf;
4427:           DMPlexGetConeSize(dm, support[s], &coneSize);
4428:           DMPlexGetCone(dm, support[s], &cone);
4429:           DMPlexGetConeOrientation(dm, support[s], &ornt);
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:         DMPlexSetSupport(rdm, newp+r, supportRef);
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];

4456:       DMPlexGetCone(dm, c, &cone);
4457:       DMPlexGetConeOrientation(dm, c, &ornt);
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:       DMPlexSetCone(rdm, newp, coneNew);
4466:       DMPlexSetConeOrientation(rdm, newp, orntNew);
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:       DMPlexSetSupport(rdm, newp, supportNew);
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:       DMPlexSetCone(rdm, newp, coneNew);
4491:       DMPlexSetConeOrientation(rdm, newp, orntNew);
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:       DMPlexSetSupport(rdm, newp, supportNew);
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:       DMPlexSetCone(rdm, newp, coneNew);
4516:       DMPlexSetConeOrientation(rdm, newp, orntNew);
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:       DMPlexSetSupport(rdm, newp, supportNew);
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:       DMPlexSetCone(rdm, newp, coneNew);
4541:       DMPlexSetConeOrientation(rdm, newp, orntNew);
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:       DMPlexSetSupport(rdm, newp, supportNew);
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:       DMPlexSetCone(rdm, newp, coneNew);
4566:       DMPlexSetConeOrientation(rdm, newp, orntNew);
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:       DMPlexSetSupport(rdm, newp, supportNew);
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:       DMPlexSetCone(rdm, newp, coneNew);
4591:       DMPlexSetConeOrientation(rdm, newp, orntNew);
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:       DMPlexSetSupport(rdm, newp, supportNew);
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:       DMPlexSetCone(rdm, newp, coneNew);
4616:       DMPlexSetConeOrientation(rdm, newp, orntNew);
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:       DMPlexSetSupport(rdm, newp, supportNew);
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:       DMPlexSetCone(rdm, newp, coneNew);
4641:       DMPlexSetConeOrientation(rdm, newp, orntNew);
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:       DMPlexSetSupport(rdm, newp, supportNew);
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;

4665:       DMPlexGetCone(dm, f, &cone);
4666:       DMPlexGetConeOrientation(dm, f, &ornt);
4667:       DMPlexGetSupportSize(dm, f, &size);
4668:       DMPlexGetSupport(dm, f, &support);
4669:       for (r = 0; r < 2; ++r) {
4670:         const PetscInt newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (f - fMax)*2 + r;

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:         DMPlexSetCone(rdm, newp, coneNew);
4681:         DMPlexSetConeOrientation(rdm, newp, orntNew);
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;

4695:           DMPlexGetCone(dm, support[s], &coneCell);
4696:           DMPlexGetConeOrientation(dm, support[s], &orntCell);
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:           DMPlexGetConeOrientation(dm, coneCell[0], &fornt);
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:         DMPlexSetSupport(rdm, newp, supportNew);
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];

4720:       DMPlexGetCone(dm, c, &cone);
4721:       DMPlexGetConeOrientation(dm, c, &ornt);
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:         DMPlexSetCone(rdm, newp+r, coneNew);
4732:         DMPlexSetConeOrientation(rdm, newp+r, orntNew);
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:         DMPlexSetSupport(rdm, newp+r, supportNew);
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);

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;

4762:         DMPlexGetCone(dm, e, &cone);
4763:         coneNew[0]       = vStartNew + (cone[0] - vStart);
4764:         coneNew[1]       = vStartNew + (cone[1] - vStart);
4765:         coneNew[(r+1)%2] = newv;
4766:         DMPlexSetCone(rdm, newp, coneNew);
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:         DMPlexGetSupportSize(dm, e, &supportSize);
4774:         DMPlexGetSupport(dm, e, &support);
4775:         for (s = 0; s < supportSize; ++s) {
4776:           DMPlexGetConeSize(dm, support[s], &coneSize);
4777:           DMPlexGetCone(dm, support[s], &cone);
4778:           DMPlexGetConeOrientation(dm, support[s], &ornt);
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:         DMPlexSetSupport(rdm, newp, supportRef);
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;

4800:       DMPlexGetSupportSize(dm, f, &supportSize);
4801:       DMPlexGetSupport(dm, f, &support);
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};

4810:         DMPlexGetCone(dm, f, &cone);
4811:         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[(r+0)%3] - eStart);
4812:         coneNew[1] = vStartNew + (vEnd - vStart) + (cone[(r+1)%3] - eStart);
4813:         DMPlexSetCone(rdm, newp, coneNew);
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:           DMPlexGetConeSize(dm, support[s], &coneSize);
4824:           DMPlexGetCone(dm, support[s], &cone);
4825:           DMPlexGetConeOrientation(dm, support[s], &ornt);
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:         DMPlexSetSupport(rdm, newp, supportRef);
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;

4855:       DMPlexGetCone(dm, c, &cone);
4856:       DMPlexGetConeOrientation(dm, c, &ornt);
4857:       DMPlexGetCone(dm, cone[0], &fcone);
4858:       find = GetTriEdge_Static(ornt[0], 0);
4859:       coneNew[0] = vStartNew + (vEnd - vStart) + (fcone[find] - eStart);
4860:       DMPlexGetCone(dm, cone[2], &fcone);
4861:       find = GetTriEdge_Static(ornt[2], 1);
4862:       coneNew[1] = vStartNew + (vEnd - vStart) + (fcone[find] - eStart);
4863:       DMPlexSetCone(rdm, newp, coneNew);
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:       DMPlexSetSupport(rdm, newp, supportNew);
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;

4888:       DMPlexGetCone(dm, e, &cone);
4889:       DMPlexGetSupportSize(dm, e, &size);
4890:       DMPlexGetSupport(dm, e, &support);
4891:       coneNew[0] = vStartNew + (cone[0] - vStart);
4892:       coneNew[1] = vStartNew + (cone[1] - vStart);
4893:       DMPlexSetCone(rdm, newp, coneNew);
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:         DMPlexGetConeSize(dm, support[s], &fsize);
4902:         DMPlexGetCone(dm, support[s], &fcone);
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:       DMPlexSetSupport(rdm, newp, supportRef);
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;

4921:       DMPlexGetCone(dm, f, &cone);
4922:       DMPlexGetSupportSize(dm, f, &size);
4923:       DMPlexGetSupport(dm, f, &support);
4924:       coneNew[0] = vStartNew + (vEnd - vStart) + (cone[0] - eStart);
4925:       coneNew[1] = vStartNew + (vEnd - vStart) + (cone[1] - eStart);
4926:       DMPlexSetCone(rdm, newp, coneNew);
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:         DMPlexGetConeSize(dm, support[s], &csize);
4937:         DMPlexGetCone(dm, support[s], &ccone);
4938:         DMPlexGetConeOrientation(dm, support[s], &cornt);
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:       DMPlexSetSupport(rdm, newp, supportRef);
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;

4958:       DMPlexGetSupportSize(dm, v, &size);
4959:       DMPlexGetSupport(dm, v, &support);
4960:       for (s = 0; s < size; ++s) {
4961:         PetscInt r = 0;

4963:         DMPlexGetCone(dm, support[s], &cone);
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:       DMPlexSetSupport(rdm, newp, supportRef);
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;

4982:       DMPlexGetSupportSize(dm, e, &size);
4983:       DMPlexGetSupport(dm, e, &support);
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;

4989:         if (support[s] < fMax) {
4990:           DMPlexGetConeSize(dm, support[s], &coneSize);
4991:           DMPlexGetCone(dm, support[s], &cone);
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:       DMPlexGetTransitiveClosure(dm, e, PETSC_FALSE, &starSize, &star);
5002:       for (s = 0; s < starSize*2; s += 2) {
5003:         const PetscInt *cone, *ornt;
5004:         PetscInt        e01, e23;

5006:         if ((star[s] >= cStart) && (star[s] < cMax)) {
5007:           /* Check edge 0-1 */
5008:           DMPlexGetCone(dm, star[s], &cone);
5009:           DMPlexGetConeOrientation(dm, star[s], &ornt);
5010:           DMPlexGetCone(dm, cone[0], &cone);
5011:           e01  = cone[GetTriEdge_Static(ornt[0], 0)];
5012:           /* Check edge 2-3 */
5013:           DMPlexGetCone(dm, star[s], &cone);
5014:           DMPlexGetConeOrientation(dm, star[s], &ornt);
5015:           DMPlexGetCone(dm, cone[2], &cone);
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:       DMPlexRestoreTransitiveClosure(dm, e, PETSC_FALSE, &starSize, &star);
5021:       DMPlexSetSupport(rdm, newp, supportRef);
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:     PetscFree(supportRef);
5030:     DMPlexRestoreFaces_Internal(dm, cStart, NULL, NULL, &faces);
5031:     break;
5032:   case REFINER_SIMPLEX_TO_HEX_3D:
5033:     DMPlexGetRawFaces_Internal(dm, DM_POLYTOPE_TETRAHEDRON, cellInd, NULL, NULL, &faces);
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];

5041:       DMPlexGetCone(dm, c, &cone);
5042:       DMPlexGetConeOrientation(dm, c, &ornt);
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:       DMPlexSetCone(rdm, newp+0, coneNew);
5057:       DMPlexSetConeOrientation(rdm, newp+0, orntNew);
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:       DMPlexSetCone(rdm, newp+1, coneNew);
5078:       DMPlexSetConeOrientation(rdm, newp+1, orntNew);
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:       DMPlexSetCone(rdm, newp+2, coneNew);
5099:       DMPlexSetConeOrientation(rdm, newp+2, orntNew);
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:       DMPlexSetCone(rdm, newp+3, coneNew);
5120:       DMPlexSetConeOrientation(rdm, newp+3, orntNew);
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:     DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);
5130:     PetscMalloc1(2 + maxSupportSize*2, &supportRef);
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;

5136:       DMPlexGetCone(dm, f, &cone);
5137:       DMPlexGetConeOrientation(dm, f, &ornt);
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:       DMPlexSetCone(rdm, newp+0, coneNew);
5148:       DMPlexSetConeOrientation(rdm, newp+0, orntNew);
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:       DMPlexSetCone(rdm, newp+1, coneNew);
5165:       DMPlexSetConeOrientation(rdm, newp+1, orntNew);
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:       DMPlexSetCone(rdm, newp+2, coneNew);
5182:       DMPlexSetConeOrientation(rdm, newp+2, orntNew);
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:       DMPlexGetSupportSize(dm, f, &supportSize);
5190:       DMPlexGetSupport(dm, f, &support);
5191:       for (r = 0; r < 3; ++r) {
5192:         for (s = 0; s < supportSize; ++s) {
5193:           PetscInt subf;
5194:           DMPlexGetConeSize(dm, support[s], &coneSize);
5195:           DMPlexGetCone(dm, support[s], &cone);
5196:           DMPlexGetConeOrientation(dm, support[s], &ornt);
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:         DMPlexSetSupport(rdm, newp+r, supportRef);
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];

5219:       DMPlexGetCone(dm, c, &cone);
5220:       DMPlexGetConeOrientation(dm, c, &ornt);
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:       DMPlexSetCone(rdm, newp, coneNew);
5231:       DMPlexSetConeOrientation(rdm, newp, orntNew);
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:       DMPlexSetSupport(rdm, newp, supportNew);
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:       DMPlexSetCone(rdm, newp, coneNew);
5258:       DMPlexSetConeOrientation(rdm, newp, orntNew);
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:       DMPlexSetSupport(rdm, newp, supportNew);
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:       DMPlexSetCone(rdm, newp, coneNew);
5285:       DMPlexSetConeOrientation(rdm, newp, orntNew);
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:       DMPlexSetSupport(rdm, newp, supportNew);
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:       DMPlexSetCone(rdm, newp, coneNew);
5312:       DMPlexSetConeOrientation(rdm, newp, orntNew);
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:       DMPlexSetSupport(rdm, newp, supportNew);
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:       DMPlexSetCone(rdm, newp, coneNew);
5339:       DMPlexSetConeOrientation(rdm, newp, orntNew);
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:       DMPlexSetSupport(rdm, newp, supportNew);
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:       DMPlexSetCone(rdm, newp, coneNew);
5366:       DMPlexSetConeOrientation(rdm, newp, orntNew);
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:       DMPlexSetSupport(rdm, newp, supportNew);
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);

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;

5393:         DMPlexGetCone(dm, e, &cone);
5394:         coneNew[0]       = vStartNew + (cone[0] - vStart);
5395:         coneNew[1]       = vStartNew + (cone[1] - vStart);
5396:         coneNew[(r+1)%2] = newv;
5397:         DMPlexSetCone(rdm, newp, coneNew);
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:         DMPlexGetSupportSize(dm, e, &supportSize);
5405:         DMPlexGetSupport(dm, e, &support);
5406:         for (s = 0; s < supportSize; ++s) {
5407:           DMPlexGetConeSize(dm, support[s], &coneSize);
5408:           DMPlexGetCone(dm, support[s], &cone);
5409:           DMPlexGetConeOrientation(dm, support[s], &ornt);
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:         DMPlexSetSupport(rdm, newp, supportRef);
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;

5429:       DMPlexGetSupportSize(dm, f, &supportSize);
5430:       DMPlexGetSupport(dm, f, &support);
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} };

5439:         DMPlexGetCone(dm, f, &cone);
5440:         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r] - eStart);
5441:         coneNew[1] = vStartNew + (vEnd - vStart) + (eEnd - eStart) + f - fStart;
5442:         DMPlexSetCone(rdm, newp, coneNew);
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:           DMPlexGetConeSize(dm, support[s], &coneSize);
5454:           DMPlexGetCone(dm, support[s], &cone);
5455:           DMPlexGetConeOrientation(dm, support[s], &ornt);
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:         DMPlexSetSupport(rdm, newp, supportRef);
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} } ;

5477:       DMPlexGetCone(dm, c, &cone);
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;

5482:         coneNew[0] = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (cone[r] - fStart);
5483:         coneNew[1] = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (fEnd -fStart) + c - cStart;
5484:         DMPlexSetCone(rdm, newp, coneNew);
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:         DMPlexSetSupport(rdm, newp, supportNew);
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;

5509:       DMPlexGetSupportSize(dm, v, &size);
5510:       DMPlexGetSupport(dm, v, &support);
5511:       for (s = 0; s < size; ++s) {
5512:         PetscInt r = 0;

5514:         DMPlexGetCone(dm, support[s], &cone);
5515:         if (cone[1] == v) r = 1;
5516:         supportRef[s] = eStartNew + (support[s] - eStart)*2 + r;
5517:       }
5518:       DMPlexSetSupport(rdm, newp, supportRef);
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;

5532:       DMPlexGetSupportSize(dm, e, &size);
5533:       DMPlexGetSupport(dm, e, &support);
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;

5539:         DMPlexGetConeSize(dm, support[s], &coneSize);
5540:         DMPlexGetCone(dm, support[s], &cone);
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:       DMPlexSetSupport(rdm, newp, supportRef);
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;

5558:       DMPlexGetSupportSize(dm, f, &size);
5559:       DMPlexGetSupport(dm, f, &support);
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;

5566:         DMPlexGetConeSize(dm, support[s], &coneSize);
5567:         DMPlexGetCone(dm, support[s], &cone);
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:       DMPlexSetSupport(rdm, newp, supportRef);
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:       DMPlexSetSupport(rdm, newp, supportRef);
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:     PetscFree(supportRef);
5595:     DMPlexRestoreFaces_Internal(dm, cStart, NULL, NULL, &faces);
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:     DMPlexGetRawFaces_Internal(dm, DM_POLYTOPE_TETRAHEDRON, cellInd, NULL, NULL, &faces);
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];

5612:       DMPlexGetCone(dm, c, &cone);
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:       DMPlexGetConeOrientation(dm, c, &ornt);
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:       DMPlexSetCone(rdm, newp+0, coneNew);
5633:       DMPlexSetConeOrientation(rdm, newp+0, orntNew);
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:       DMPlexSetCone(rdm, newp+1, coneNew);
5654:       DMPlexSetConeOrientation(rdm, newp+1, orntNew);
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:       DMPlexSetCone(rdm, newp+2, coneNew);
5675:       DMPlexSetConeOrientation(rdm, newp+2, orntNew);
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:       DMPlexSetCone(rdm, newp+3, coneNew);
5696:       DMPlexSetConeOrientation(rdm, newp+3, orntNew);
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;

5710:       DMPlexGetCone(dm, c, &cone);
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:       DMPlexGetConeOrientation(dm, c, &ornt);
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:       DMPlexSetCone(rdm, newp+0, coneNew);
5739:       DMPlexSetConeOrientation(rdm, newp+0, orntNew);
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:       DMPlexSetCone(rdm, newp+1, coneNew);
5764:       DMPlexSetConeOrientation(rdm, newp+1, orntNew);
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:       DMPlexSetCone(rdm, newp+2, coneNew);
5789:       DMPlexSetConeOrientation(rdm, newp+2, orntNew);
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:     }

5798:     /* Split faces have 4 edges and the same cells as the parent */
5799:     DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);
5800:     PetscMalloc1(2 + maxSupportSize*2, &supportRef);
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;

5806:       DMPlexGetCone(dm, f, &cone);
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:       DMPlexGetConeOrientation(dm, f, &ornt);
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:       DMPlexSetCone(rdm, newp+0, coneNew);
5823:       DMPlexSetConeOrientation(rdm, newp+0, orntNew);
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:       DMPlexSetCone(rdm, newp+1, coneNew);
5840:       DMPlexSetConeOrientation(rdm, newp+1, orntNew);
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:       DMPlexSetCone(rdm, newp+2, coneNew);
5857:       DMPlexSetConeOrientation(rdm, newp+2, orntNew);
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:       DMPlexGetSupportSize(dm, f, &supportSize);
5865:       DMPlexGetSupport(dm, f, &support);
5866:       for (r = 0; r < 3; ++r) {
5867:         for (s = 0; s < supportSize; ++s) {
5868:           PetscInt subf;

5870:           DMPlexGetConeSize(dm, support[s], &coneSize);
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:           DMPlexGetCone(dm, support[s], &cone);
5874:           DMPlexGetConeOrientation(dm, support[s], &ornt);
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:         DMPlexSetSupport(rdm, newp+r, supportRef);
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];

5902:       DMPlexGetCone(dm, c, &cone);
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:       DMPlexGetConeOrientation(dm, c, &ornt);
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:       DMPlexSetCone(rdm, newp, coneNew);
5919:       DMPlexSetConeOrientation(rdm, newp, orntNew);
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:       DMPlexSetSupport(rdm, newp, supportNew);
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:       DMPlexSetCone(rdm, newp, coneNew);
5945:       DMPlexSetConeOrientation(rdm, newp, orntNew);
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:       DMPlexSetSupport(rdm, newp, supportNew);
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:       DMPlexSetCone(rdm, newp, coneNew);
5971:       DMPlexSetConeOrientation(rdm, newp, orntNew);
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:       DMPlexSetSupport(rdm, newp, supportNew);
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:       DMPlexSetCone(rdm, newp, coneNew);
5997:       DMPlexSetConeOrientation(rdm, newp, orntNew);
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:       DMPlexSetSupport(rdm, newp, supportNew);
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:       DMPlexSetCone(rdm, newp, coneNew);
6023:       DMPlexSetConeOrientation(rdm, newp, orntNew);
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:       DMPlexSetSupport(rdm, newp, supportNew);
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:       DMPlexSetCone(rdm, newp, coneNew);
6049:       DMPlexSetConeOrientation(rdm, newp, orntNew);
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:       DMPlexSetSupport(rdm, newp, supportNew);
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;

6073:       DMPlexGetCone(dm, f, &cone);
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:       DMPlexGetConeOrientation(dm, f, &ornt);
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:       DMPlexSetCone(rdm, newp, coneNew);
6091:       DMPlexSetConeOrientation(rdm, newp, orntNew);
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

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:       DMPlexSetCone(rdm, newp+1, coneNew);
6109:       DMPlexSetConeOrientation(rdm, newp+1, orntNew);
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

6117:       DMPlexGetSupportSize(dm, f, &size);
6118:       DMPlexGetSupport(dm, f, &support);
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;

6124:           DMPlexGetConeSize(dm, support[s], &coneSize);
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:           DMPlexGetCone(dm, support[s], &coneCell);
6127:           DMPlexGetConeOrientation(dm, support[s], &orntCell);
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:         DMPlexSetSupport(rdm, newp + r, supportRef);
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];

6151:       DMPlexGetCone(dm, c, &cone);
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:       DMPlexGetConeOrientation(dm, c, &ornt);
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:       DMPlexSetCone(rdm, newp, coneNew);
6170:       DMPlexSetConeOrientation(rdm, newp, orntNew);
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:       DMPlexSetSupport(rdm, newp, supportNew);
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:       DMPlexSetCone(rdm, newp, coneNew);
6196:       DMPlexSetConeOrientation(rdm, newp, orntNew);
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:       DMPlexSetSupport(rdm, newp, supportNew);
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:       DMPlexSetCone(rdm, newp, coneNew);
6222:       DMPlexSetConeOrientation(rdm, newp, orntNew);
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:       DMPlexSetSupport(rdm, newp, supportNew);
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;

6243:       DMPlexGetSupportSize(dm, f, &supportSize);
6244:       DMPlexGetSupport(dm, f, &support);
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} };

6253:         DMPlexGetCone(dm, f, &cone);
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:         DMPlexSetCone(rdm, newp, coneNew);
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;

6269:           supportRef[2+s] = -1;
6270:           DMPlexGetConeSize(dm, support[s], &coneSize);
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:           DMPlexGetCone(dm, support[s], &cone);
6274:           DMPlexGetConeOrientation(dm, support[s], &ornt);
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:         DMPlexSetSupport(rdm, newp, supportRef);
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} } ;

6301:       DMPlexGetCone(dm, c, &cone);
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;

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:         DMPlexSetCone(rdm, newp, coneNew);
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:         DMPlexSetSupport(rdm, newp, supportNew);
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;

6334:       DMPlexGetCone(dm, e, &cone);
6335:       DMPlexGetSupportSize(dm, e, &size);
6336:       DMPlexGetSupport(dm, e, &support);
6337:       coneNew[0] = vStartNew + (cone[0] - vStart);
6338:       coneNew[1] = vStartNew + (cone[1] - vStart);
6339:       DMPlexSetCone(rdm, newp, coneNew);
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:         DMPlexGetConeSize(dm, support[s], &fsize);
6348:         DMPlexGetCone(dm, support[s], &fcone);
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:       DMPlexSetSupport(rdm, newp, supportRef);
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;

6367:       DMPlexGetCone(dm, f, &cone);
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:       DMPlexSetCone(rdm, newp, coneNew);
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:       DMPlexGetSupportSize(dm, f, &supportSize);
6384:       DMPlexGetSupport(dm, f, &support);
6385:       for (s = 0; s < supportSize; ++s) {
6386:         DMPlexGetConeSize(dm, support[s], &coneSize);
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:         DMPlexGetCone(dm, support[s], &cone);
6389:         DMPlexGetConeOrientation(dm, support[s], &ornt);
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:       DMPlexSetSupport(rdm, newp, supportRef);
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;

6408:       DMPlexGetCone(dm, c, &cone);
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:       DMPlexSetCone(rdm, newp, coneNew);
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:       DMPlexSetSupport(rdm, newp, supportNew);
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;

6439:       DMPlexGetSupportSize(dm, v, &size);
6440:       DMPlexGetSupport(dm, v, &support);
6441:       for (s = 0; s < size; ++s) {
6442:         const PetscInt e = support[s];

6444:         supportRef[s] = -1;
6445:         if (eStart <= e) {
6446:           if (e < eMax) {
6447:             DMPlexGetCone(dm, e, &cone);
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:       DMPlexSetSupport(rdm, newp, supportRef);
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;

6468:       DMPlexGetSupportSize(dm, e, &size);
6469:       DMPlexGetSupport(dm, e, &support);
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;

6475:         supportRef[2+s] = -1;
6476:         DMPlexGetConeSize(dm, support[s], &coneSize);
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:         DMPlexGetCone(dm, support[s], &cone);
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:       DMPlexSetSupport(rdm, newp, supportRef);
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);

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;

6504:         DMPlexGetCone(dm, e, &cone);
6505:         coneNew[0]       = vStartNew + (cone[0] - vStart);
6506:         coneNew[1]       = vStartNew + (cone[1] - vStart);
6507:         coneNew[(r+1)%2] = newv;
6508:         DMPlexSetCone(rdm, newp, coneNew);
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:         DMPlexGetSupportSize(dm, e, &supportSize);
6516:         DMPlexGetSupport(dm, e, &support);
6517:         for (s = 0; s < supportSize; ++s) {
6518:           DMPlexGetConeSize(dm, support[s], &coneSize);
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:           DMPlexGetCone(dm, support[s], &cone);
6522:           DMPlexGetConeOrientation(dm, support[s], &ornt);
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:         DMPlexSetSupport(rdm, newp, supportRef);
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;

6547:       DMPlexGetSupportSize(dm, f, &size);
6548:       DMPlexGetSupport(dm, f, &support);
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;

6555:         supportRef[3+s] = -1;
6556:         DMPlexGetConeSize(dm, support[s], &coneSize);
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:         DMPlexGetCone(dm, support[s], &cone);
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:       DMPlexSetSupport(rdm, newp, supportRef);
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;

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:       DMPlexSetSupport(rdm, newp, supportRef);
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:     PetscFree(supportRef);
6592:     DMPlexRestoreFaces_Internal(dm, cStart, NULL, NULL, &faces);
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];

6613:       DMPlexGetCone(dm, c, &cone);
6614:       DMPlexGetConeOrientation(dm, c, &ornt);
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:       DMPlexSetCone(rdm, newp+0, coneNew);
6629:       DMPlexSetConeOrientation(rdm, newp+0, orntNew);
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:       DMPlexSetCone(rdm, newp+1, coneNew);
6650:       DMPlexSetConeOrientation(rdm, newp+1, orntNew);
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:       DMPlexSetCone(rdm, newp+2, coneNew);
6671:       DMPlexSetConeOrientation(rdm, newp+2, orntNew);
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:       DMPlexSetCone(rdm, newp+3, coneNew);
6692:       DMPlexSetConeOrientation(rdm, newp+3, orntNew);
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:       DMPlexSetCone(rdm, newp+4, coneNew);
6713:       DMPlexSetConeOrientation(rdm, newp+4, orntNew);
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:       DMPlexSetCone(rdm, newp+5, coneNew);
6734:       DMPlexSetConeOrientation(rdm, newp+5, orntNew);
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:       DMPlexSetCone(rdm, newp+6, coneNew);
6755:       DMPlexSetConeOrientation(rdm, newp+6, orntNew);
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:       DMPlexSetCone(rdm, newp+7, coneNew);
6776:       DMPlexSetConeOrientation(rdm, newp+7, orntNew);
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:     DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);
6786:     PetscMalloc1(4 + maxSupportSize*2, &supportRef);
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;

6795:         DMPlexGetCone(dm, f, &cone);
6796:         DMPlexGetConeOrientation(dm, f, &ornt);
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:         DMPlexSetCone(rdm, newp, coneNew);
6806:         DMPlexSetConeOrientation(rdm, newp, orntNew);
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:         DMPlexGetSupportSize(dm, f, &supportSize);
6814:         DMPlexGetSupport(dm, f, &support);
6815:         for (s = 0; s < supportSize; ++s) {
6816:           DMPlexGetConeSize(dm, support[s], &coneSize);
6817:           DMPlexGetCone(dm, support[s], &cone);
6818:           DMPlexGetConeOrientation(dm, support[s], &ornt);
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:         DMPlexSetSupport(rdm, newp, supportRef);
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];

6839:       DMPlexGetCone(dm, c, &cone);
6840:       DMPlexGetConeOrientation(dm, c, &ornt);
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:       DMPlexSetCone(rdm, newp, coneNew);
6852:       DMPlexSetConeOrientation(rdm, newp, orntNew);
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:       DMPlexSetCone(rdm, newp, coneNew);
6870:       DMPlexSetConeOrientation(rdm, newp, orntNew);
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:       DMPlexSetCone(rdm, newp, coneNew);
6888:       DMPlexSetConeOrientation(rdm, newp, orntNew);
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:       DMPlexSetCone(rdm, newp, coneNew);
6906:       DMPlexSetConeOrientation(rdm, newp, orntNew);
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:       DMPlexSetCone(rdm, newp, coneNew);
6924:       DMPlexSetConeOrientation(rdm, newp, orntNew);
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:       DMPlexSetCone(rdm, newp, coneNew);
6942:       DMPlexSetConeOrientation(rdm, newp, orntNew);
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:       DMPlexSetCone(rdm, newp, coneNew);
6960:       DMPlexSetConeOrientation(rdm, newp, orntNew);
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:       DMPlexSetCone(rdm, newp, coneNew);
6978:       DMPlexSetConeOrientation(rdm, newp, orntNew);
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:       DMPlexSetCone(rdm, newp, coneNew);
6996:       DMPlexSetConeOrientation(rdm, newp, orntNew);
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:       DMPlexSetCone(rdm, newp, coneNew);
7014:       DMPlexSetConeOrientation(rdm, newp, orntNew);
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:       DMPlexSetCone(rdm, newp, coneNew);
7032:       DMPlexSetConeOrientation(rdm, newp, orntNew);
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:       DMPlexSetCone(rdm, newp, coneNew);
7050:       DMPlexSetConeOrientation(rdm, newp, orntNew);
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:         DMPlexSetSupport(rdm, newp, supportNew);
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:     DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);
7072:     for (e = eStart; e < eEnd; ++e) {
7073:       const PetscInt newv = vStartNew + (vEnd - vStart) + (e - eStart);

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;

7080:         DMPlexGetCone(dm, e, &cone);
7081:         coneNew[0]       = vStartNew + (cone[0] - vStart);
7082:         coneNew[1]       = vStartNew + (cone[1] - vStart);
7083:         coneNew[(r+1)%2] = newv;
7084:         DMPlexSetCone(rdm, newp, coneNew);
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:         DMPlexGetSupportSize(dm, e, &supportSize);
7092:         DMPlexGetSupport(dm, e, &support);
7093:         for (s = 0; s < supportSize; ++s) {
7094:           DMPlexGetConeSize(dm, support[s], &coneSize);
7095:           DMPlexGetCone(dm, support[s], &cone);
7096:           DMPlexGetConeOrientation(dm, support[s], &ornt);
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:         DMPlexSetSupport(rdm, newp, supportRef);
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;

7118:       DMPlexGetCone(dm, f, &cone);
7119:       for (r = 0; r < 4; ++r) {
7120:         const PetscInt newp = eStartNew + (eEnd - eStart)*2 + (f - fStart)*4 + r;

7122:         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r] - eStart);
7123:         coneNew[1] = newv;
7124:         DMPlexSetCone(rdm, newp, coneNew);
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:         DMPlexGetSupportSize(dm, f, &supportSize);
7132:         DMPlexGetSupport(dm, f, &support);
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:           DMPlexGetConeSize(dm, support[s], &coneSize);
7137:           DMPlexGetCone(dm, support[s], &coneCell);
7138:           DMPlexGetConeOrientation(dm, support[s], &orntCell);
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:         DMPlexSetSupport(rdm, newp, supportRef);
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];

7158:       DMPlexGetCone(dm, c, &cone);
7159:       for (r = 0; r < 6; ++r) {
7160:         const PetscInt newp = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*4 + (c - cStart)*6 + r;

7162:         coneNew[0] = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (cone[r] - fStart);
7163:         coneNew[1] = newv;
7164:         DMPlexSetCone(rdm, newp, coneNew);
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:         DMPlexSetSupport(rdm, newp, supportNew);
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;

7187:       DMPlexGetSupportSize(dm, v, &size);
7188:       DMPlexGetSupport(dm, v, &support);
7189:       for (s = 0; s < size; ++s) {
7190:         PetscInt r = 0;

7192:         DMPlexGetCone(dm, support[s], &cone);
7193:         if (cone[1] == v) r = 1;
7194:         supportRef[s] = eStartNew + (support[s] - eStart)*2 + r;
7195:       }
7196:       DMPlexSetSupport(rdm, newp, supportRef);
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;

7210:       DMPlexGetSupportSize(dm, e, &size);
7211:       DMPlexGetSupport(dm, e, &support);
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;

7217:         DMPlexGetCone(dm, support[s], &cone);
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:       DMPlexSetSupport(rdm, newp, supportRef);
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;

7235:       DMPlexGetSupportSize(dm, f, &size);
7236:       DMPlexGetSupport(dm, f, &support);
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;

7241:         DMPlexGetCone(dm, support[s], &cone);
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:       DMPlexSetSupport(rdm, newp, supportRef);
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];

7258:       for (r = 0; r < 6; ++r) {
7259:         supportNew[r] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*4 + (c - cStart)*6 + r;
7260:       }
7261:       DMPlexSetSupport(rdm, newp, supportNew);
7262:     }
7263:     PetscFree(supportRef);
7264:     break;
7265:   case REFINER_HYBRID_HEX_3D:
7266:     DMPlexGetHybridBounds(rdm, &cMaxNew, &fMaxNew, &eMaxNew, NULL);
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];

7285:       DMPlexGetCone(dm, c, &cone);
7286:       DMPlexGetConeOrientation(dm, c, &ornt);
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:       DMPlexSetCone(rdm, newp+0, coneNew);
7301:       DMPlexSetConeOrientation(rdm, newp+0, orntNew);
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:       DMPlexSetCone(rdm, newp+1, coneNew);
7322:       DMPlexSetConeOrientation(rdm, newp+1, orntNew);
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:       DMPlexSetCone(rdm, newp+2, coneNew);
7343:       DMPlexSetConeOrientation(rdm, newp+2, orntNew);
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:       DMPlexSetCone(rdm, newp+3, coneNew);
7364:       DMPlexSetConeOrientation(rdm, newp+3, orntNew);
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:       DMPlexSetCone(rdm, newp+4, coneNew);
7385:       DMPlexSetConeOrientation(rdm, newp+4, orntNew);
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:       DMPlexSetCone(rdm, newp+5, coneNew);
7406:       DMPlexSetConeOrientation(rdm, newp+5, orntNew);
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:       DMPlexSetCone(rdm, newp+6, coneNew);
7427:       DMPlexSetConeOrientation(rdm, newp+6, orntNew);
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:       DMPlexSetCone(rdm, newp+7, coneNew);
7448:       DMPlexSetConeOrientation(rdm, newp+7, orntNew);
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;

7473:       DMPlexGetCone(dm, c, &cone);
7474:       DMPlexGetConeOrientation(dm, c, &ornt);
7475:       DMPlexGetConeOrientation(dm, cone[0], &fornt);
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:         DMPlexSetCone(rdm, newp+r, coneNew);
7501:         DMPlexSetConeOrientation(rdm, newp+r, orntNew);
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:     DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);
7515:     PetscMalloc1(4 + maxSupportSize*2, &supportRef);
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;

7524:         DMPlexGetCone(dm, f, &cone);
7525:         DMPlexGetConeOrientation(dm, f, &ornt);
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:         DMPlexSetCone(rdm, newp, coneNew);
7535:         DMPlexSetConeOrientation(rdm, newp, orntNew);
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:         DMPlexGetSupportSize(dm, f, &supportSize);
7543:         DMPlexGetSupport(dm, f, &support);
7544:         for (s = 0; s < supportSize; ++s) {
7545:           PetscInt subf;
7546:           DMPlexGetConeSize(dm, support[s], &coneSize);
7547:           DMPlexGetCone(dm, support[s], &cone);
7548:           DMPlexGetConeOrientation(dm, support[s], &ornt);
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:         DMPlexSetSupport(rdm, newp, supportRef);
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];

7574:       DMPlexGetCone(dm, c, &cone);
7575:       DMPlexGetConeOrientation(dm, c, &ornt);
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:       DMPlexSetCone(rdm, newp, coneNew);
7587:       DMPlexSetConeOrientation(rdm, newp, orntNew);
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:       DMPlexSetCone(rdm, newp, coneNew);
7605:       DMPlexSetConeOrientation(rdm, newp, orntNew);
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:       DMPlexSetCone(rdm, newp, coneNew);
7623:       DMPlexSetConeOrientation(rdm, newp, orntNew);
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:       DMPlexSetCone(rdm, newp, coneNew);
7641:       DMPlexSetConeOrientation(rdm, newp, orntNew);
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:       DMPlexSetCone(rdm, newp, coneNew);
7659:       DMPlexSetConeOrientation(rdm, newp, orntNew);
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:       DMPlexSetCone(rdm, newp, coneNew);
7677:       DMPlexSetConeOrientation(rdm, newp, orntNew);
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:       DMPlexSetCone(rdm, newp, coneNew);
7695:       DMPlexSetConeOrientation(rdm, newp, orntNew);
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:       DMPlexSetCone(rdm, newp, coneNew);
7713:       DMPlexSetConeOrientation(rdm, newp, orntNew);
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:       DMPlexSetCone(rdm, newp, coneNew);
7731:       DMPlexSetConeOrientation(rdm, newp, orntNew);
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:       DMPlexSetCone(rdm, newp, coneNew);
7749:       DMPlexSetConeOrientation(rdm, newp, orntNew);
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:       DMPlexSetCone(rdm, newp, coneNew);
7767:       DMPlexSetConeOrientation(rdm, newp, orntNew);
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:       DMPlexSetCone(rdm, newp, coneNew);
7785:       DMPlexSetConeOrientation(rdm, newp, orntNew);
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:         DMPlexSetSupport(rdm, newp, supportNew);
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;

7811:       DMPlexGetCone(dm, f, &cone);
7812:       DMPlexGetConeOrientation(dm, f, &ornt);
7813:       DMPlexGetSupportSize(dm, f, &size);
7814:       DMPlexGetSupport(dm, f, &support);
7815:       for (r = 0; r < 2; ++r) {
7816:         const PetscInt newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (f - fMax)*2 + r;

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:         DMPlexSetCone(rdm, newp, coneNew);
7827:         DMPlexSetConeOrientation(rdm, newp, orntNew);
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;

7841:           DMPlexGetCone(dm, support[s], &coneCell);
7842:           DMPlexGetConeOrientation(dm, support[s], &orntCell);
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:           DMPlexGetConeOrientation(dm, coneCell[0], &fornt);
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:         DMPlexSetSupport(rdm, newp, supportNew);
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];

7866:       DMPlexGetCone(dm, c, &cone);
7867:       DMPlexGetConeOrientation(dm, c, &ornt);
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:         DMPlexSetCone(rdm, newp+r, coneNew);
7889:         DMPlexSetConeOrientation(rdm, newp+r, orntNew);
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:         DMPlexSetSupport(rdm, newp+r, supportNew);
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:     DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);
7912:     for (e = eStart; e < eMax; ++e) {
7913:       const PetscInt newv = vStartNew + (vEnd - vStart) + (e - eStart);

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;

7920:         DMPlexGetCone(dm, e, &cone);
7921:         coneNew[0]       = vStartNew + (cone[0] - vStart);
7922:         coneNew[1]       = vStartNew + (cone[1] - vStart);
7923:         coneNew[(r+1)%2] = newv;
7924:         DMPlexSetCone(rdm, newp, coneNew);
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:         DMPlexGetSupportSize(dm, e, &supportSize);
7932:         DMPlexGetSupport(dm, e, &support);
7933:         for (s = 0; s < supportSize; ++s) {
7934:           DMPlexGetConeSize(dm, support[s], &coneSize);
7935:           DMPlexGetCone(dm, support[s], &cone);
7936:           DMPlexGetConeOrientation(dm, support[s], &ornt);
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:         DMPlexSetSupport(rdm, newp, supportRef);
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;

7962:       DMPlexGetCone(dm, f, &cone);
7963:       for (r = 0; r < 4; ++r) {
7964:         const PetscInt newp = eStartNew + (eMax - eStart)*2 + (f - fStart)*4 + r;

7966:         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r] - eStart);
7967:         coneNew[1] = newv;
7968:         DMPlexSetCone(rdm, newp, coneNew);
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:         DMPlexGetSupportSize(dm, f, &supportSize);
7976:         DMPlexGetSupport(dm, f, &support);
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:           DMPlexGetConeSize(dm, support[s], &coneSize);
7981:           DMPlexGetCone(dm, support[s], &coneCell);
7982:           DMPlexGetConeOrientation(dm, support[s], &orntCell);
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:         DMPlexSetSupport(rdm, newp, supportRef);
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];

8006:       DMPlexGetCone(dm, c, &cone);
8007:       for (r = 0; r < 6; ++r) {
8008:         const PetscInt newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (c - cStart)*6 + r;

8010:         coneNew[0] = vStartNew + (vEnd - vStart) + (eMax - eStart) + (cone[r] - fStart);
8011:         coneNew[1] = newv;
8012:         DMPlexSetCone(rdm, newp, coneNew);
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:         DMPlexSetSupport(rdm, newp, supportNew);
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;

8035:       DMPlexGetCone(dm, e, &cone);
8036:       DMPlexGetSupportSize(dm, e, &size);
8037:       DMPlexGetSupport(dm, e, &support);
8038:       coneNew[0] = vStartNew + (cone[0] - vStart);
8039:       coneNew[1] = vStartNew + (cone[1] - vStart);
8040:       DMPlexSetCone(rdm, newp, coneNew);
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:         DMPlexGetConeSize(dm, support[s], &fsize);
8049:         DMPlexGetCone(dm, support[s], &fcone);
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:       DMPlexSetSupport(rdm, newp, supportRef);
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;

8068:       DMPlexGetCone(dm, f, &cone);
8069:       DMPlexGetSupportSize(dm, f, &size);
8070:       DMPlexGetSupport(dm, f, &support);
8071:       coneNew[0] = vStartNew + (vEnd - vStart) + (cone[0] - eStart);
8072:       coneNew[1] = vStartNew + (vEnd - vStart) + (cone[1] - eStart);
8073:       DMPlexSetCone(rdm, newp, coneNew);
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:         DMPlexGetConeSize(dm, support[s], &csize);
8084:         DMPlexGetCone(dm, support[s], &ccone);
8085:         DMPlexGetConeOrientation(dm, support[s], &cornt);
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:       DMPlexSetSupport(rdm, newp, supportRef);
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;

8104:       DMPlexGetCone(dm, c, &cone);
8105:       DMPlexGetSupportSize(dm, c, &size);
8106:       DMPlexGetSupport(dm, c, &support);
8107:       coneNew[0] = vStartNew + (vEnd - vStart) + (eMax - eStart) + (cone[0] - fStart);
8108:       coneNew[1] = vStartNew + (vEnd - vStart) + (eMax - eStart) + (cone[1] - fStart);
8109:       DMPlexSetCone(rdm, newp, coneNew);
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:       DMPlexSetSupport(rdm, newp, supportRef);
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 */