Actual source code: plexrefine.c

petsc-3.12.5 2020-03-29
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;

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

1736: static PetscErrorCode CellRefinerSetCones(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
1737: {
1738:   const PetscInt *faces, cellInd[4] = {0, 1, 2, 3};
1739:   PetscInt        cStart,    cEnd,    cMax,    vStart,    vEnd, vMax, fStart,    fEnd,    fMax,    eStart,    eEnd,    eMax;
1740:   PetscInt        cStartNew, cEndNew, cMaxNew, vStartNew, vEndNew,    fStartNew, fEndNew, fMaxNew, eStartNew, eEndNew, eMaxNew;
1741:   PetscInt        depth, maxSupportSize, *supportRef, c, f, e, v, r;
1742: #if defined(PETSC_USE_DEBUG)
1743:   PetscInt        p;
1744: #endif
1745:   PetscErrorCode  ierr;

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

1765:       for (r = 0; r < 2; ++r) {
1766:         const PetscInt newp = cStartNew + (c - cStart)*2 + r;
1767:         const PetscInt *cone;
1768:         PetscInt        coneNew[2];

1770:         DMPlexGetCone(dm, c, &cone);
1771:         coneNew[0]       = vStartNew + (cone[0] - vStart);
1772:         coneNew[1]       = vStartNew + (cone[1] - vStart);
1773:         coneNew[(r+1)%2] = newv;
1774:         DMPlexSetCone(rdm, newp, coneNew);
1775: #if defined(PETSC_USE_DEBUG)
1776:         if ((newp < cStartNew) || (newp >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", newp, cStartNew, cEndNew);
1777:         for (p = 0; p < 2; ++p) {
1778:           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", coneNew[p], vStartNew, vEndNew);
1779:         }
1780: #endif
1781:       }
1782:     }
1783:     /* Old vertices have identical supports */
1784:     for (v = vStart; v < vEnd; ++v) {
1785:       const PetscInt  newp = vStartNew + (v - vStart);
1786:       const PetscInt *support, *cone;
1787:       PetscInt        size, s;

1789:       DMPlexGetSupportSize(dm, v, &size);
1790:       DMPlexGetSupport(dm, v, &support);
1791:       for (s = 0; s < size; ++s) {
1792:         PetscInt r = 0;

1794:         DMPlexGetCone(dm, support[s], &cone);
1795:         if (cone[1] == v) r = 1;
1796:         supportRef[s] = cStartNew + (support[s] - cStart)*2 + r;
1797:       }
1798:       DMPlexSetSupport(rdm, newp, supportRef);
1799: #if defined(PETSC_USE_DEBUG)
1800:       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", newp, vStartNew, vEndNew);
1801:       for (p = 0; p < size; ++p) {
1802:         if ((supportRef[p] < cStartNew) || (supportRef[p] >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", supportRef[p], cStartNew, cEndNew);
1803:       }
1804: #endif
1805:     }
1806:     /* Cell vertices have support of 2 cells */
1807:     for (c = cStart; c < cEnd; ++c) {
1808:       const PetscInt  newp = vStartNew + (vEnd - vStart) + (c - cStart);

1810:       supportRef[0] = cStartNew + (c - cStart)*2 + 0;
1811:       supportRef[1] = cStartNew + (c - cStart)*2 + 1;
1812:       DMPlexSetSupport(rdm, newp, supportRef);
1813: #if defined(PETSC_USE_DEBUG)
1814:       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", newp, vStartNew, vEndNew);
1815:       for (p = 0; p < 2; ++p) {
1816:         if ((supportRef[p] < cStartNew) || (supportRef[p] >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", supportRef[p], cStartNew, cEndNew);
1817:       }
1818: #endif
1819:     }
1820:     PetscFree(supportRef);
1821:     break;
1822:   case REFINER_SIMPLEX_2D:
1823:     /*
1824:      2
1825:      |\
1826:      | \
1827:      |  \
1828:      |   \
1829:      | C  \
1830:      |     \
1831:      |      \
1832:      2---1---1
1833:      |\  D  / \
1834:      | 2   0   \
1835:      |A \ /  B  \
1836:      0---0-------1
1837:      */
1838:     /* All cells have 3 faces */
1839:     for (c = cStart; c < cEnd; ++c) {
1840:       const PetscInt  newp = cStartNew + (c - cStart)*4;
1841:       const PetscInt *cone, *ornt;
1842:       PetscInt        coneNew[3], orntNew[3];

1844:       DMPlexGetCone(dm, c, &cone);
1845:       DMPlexGetConeOrientation(dm, c, &ornt);
1846:       /* A triangle */
1847:       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
1848:       orntNew[0] = ornt[0];
1849:       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 2;
1850:       orntNew[1] = -2;
1851:       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
1852:       orntNew[2] = ornt[2];
1853:       DMPlexSetCone(rdm, newp+0, coneNew);
1854:       DMPlexSetConeOrientation(rdm, newp+0, orntNew);
1855: #if defined(PETSC_USE_DEBUG)
1856:       if ((newp+0 < cStartNew) || (newp+0 >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", newp+0, cStartNew, cEndNew);
1857:       for (p = 0; p < 3; ++p) {
1858:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", coneNew[p], fStartNew, fEndNew);
1859:       }
1860: #endif
1861:       /* B triangle */
1862:       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
1863:       orntNew[0] = ornt[0];
1864:       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
1865:       orntNew[1] = ornt[1];
1866:       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 0;
1867:       orntNew[2] = -2;
1868:       DMPlexSetCone(rdm, newp+1, coneNew);
1869:       DMPlexSetConeOrientation(rdm, newp+1, orntNew);
1870: #if defined(PETSC_USE_DEBUG)
1871:       if ((newp+1 < cStartNew) || (newp+1 >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", newp+1, cStartNew, cEndNew);
1872:       for (p = 0; p < 3; ++p) {
1873:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", coneNew[p], fStartNew, fEndNew);
1874:       }
1875: #endif
1876:       /* C triangle */
1877:       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 1;
1878:       orntNew[0] = -2;
1879:       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
1880:       orntNew[1] = ornt[1];
1881:       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
1882:       orntNew[2] = ornt[2];
1883:       DMPlexSetCone(rdm, newp+2, coneNew);
1884:       DMPlexSetConeOrientation(rdm, newp+2, orntNew);
1885: #if defined(PETSC_USE_DEBUG)
1886:       if ((newp+2 < cStartNew) || (newp+2 >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", newp+2, cStartNew, cEndNew);
1887:       for (p = 0; p < 3; ++p) {
1888:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", coneNew[p], fStartNew, fEndNew);
1889:       }
1890: #endif
1891:       /* D triangle */
1892:       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 0;
1893:       orntNew[0] = 0;
1894:       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 1;
1895:       orntNew[1] = 0;
1896:       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 2;
1897:       orntNew[2] = 0;
1898:       DMPlexSetCone(rdm, newp+3, coneNew);
1899:       DMPlexSetConeOrientation(rdm, newp+3, orntNew);
1900: #if defined(PETSC_USE_DEBUG)
1901:       if ((newp+3 < cStartNew) || (newp+3 >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", newp+3, cStartNew, cEndNew);
1902:       for (p = 0; p < 3; ++p) {
1903:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", coneNew[p], fStartNew, fEndNew);
1904:       }
1905: #endif
1906:     }
1907:     /* Split faces have 2 vertices and the same cells as the parent */
1908:     DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);
1909:     PetscMalloc1(2 + maxSupportSize*2, &supportRef);
1910:     for (f = fStart; f < fEnd; ++f) {
1911:       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);

1913:       for (r = 0; r < 2; ++r) {
1914:         const PetscInt  newp = fStartNew + (f - fStart)*2 + r;
1915:         const PetscInt *cone, *ornt, *support;
1916:         PetscInt        coneNew[2], coneSize, c, supportSize, s;

1918:         DMPlexGetCone(dm, f, &cone);
1919:         coneNew[0]       = vStartNew + (cone[0] - vStart);
1920:         coneNew[1]       = vStartNew + (cone[1] - vStart);
1921:         coneNew[(r+1)%2] = newv;
1922:         DMPlexSetCone(rdm, newp, coneNew);
1923: #if defined(PETSC_USE_DEBUG)
1924:         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
1925:         for (p = 0; p < 2; ++p) {
1926:           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", coneNew[p], vStartNew, vEndNew);
1927:         }
1928: #endif
1929:         DMPlexGetSupportSize(dm, f, &supportSize);
1930:         DMPlexGetSupport(dm, f, &support);
1931:         for (s = 0; s < supportSize; ++s) {
1932:           DMPlexGetConeSize(dm, support[s], &coneSize);
1933:           DMPlexGetCone(dm, support[s], &cone);
1934:           DMPlexGetConeOrientation(dm, support[s], &ornt);
1935:           for (c = 0; c < coneSize; ++c) {
1936:             if (cone[c] == f) break;
1937:           }
1938:           supportRef[s] = cStartNew + (support[s] - cStart)*4 + (ornt[c] < 0 ? (c+1-r)%3 : (c+r)%3);
1939:         }
1940:         DMPlexSetSupport(rdm, newp, supportRef);
1941: #if defined(PETSC_USE_DEBUG)
1942:         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
1943:         for (p = 0; p < supportSize; ++p) {
1944:           if ((supportRef[p] < cStartNew) || (supportRef[p] >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", supportRef[p], cStartNew, cEndNew);
1945:         }
1946: #endif
1947:       }
1948:     }
1949:     /* Interior faces have 2 vertices and 2 cells */
1950:     for (c = cStart; c < cEnd; ++c) {
1951:       const PetscInt *cone;

1953:       DMPlexGetCone(dm, c, &cone);
1954:       for (r = 0; r < 3; ++r) {
1955:         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*3 + r;
1956:         PetscInt       coneNew[2];
1957:         PetscInt       supportNew[2];

1959:         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r]       - fStart);
1960:         coneNew[1] = vStartNew + (vEnd - vStart) + (cone[(r+1)%3] - fStart);
1961:         DMPlexSetCone(rdm, newp, coneNew);
1962: #if defined(PETSC_USE_DEBUG)
1963:         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
1964:         for (p = 0; p < 2; ++p) {
1965:           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", coneNew[p], vStartNew, vEndNew);
1966:         }
1967: #endif
1968:         supportNew[0] = (c - cStart)*4 + (r+1)%3;
1969:         supportNew[1] = (c - cStart)*4 + 3;
1970:         DMPlexSetSupport(rdm, newp, supportNew);
1971: #if defined(PETSC_USE_DEBUG)
1972:         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
1973:         for (p = 0; p < 2; ++p) {
1974:           if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", supportNew[p], cStartNew, cEndNew);
1975:         }
1976: #endif
1977:       }
1978:     }
1979:     /* Old vertices have identical supports */
1980:     for (v = vStart; v < vEnd; ++v) {
1981:       const PetscInt  newp = vStartNew + (v - vStart);
1982:       const PetscInt *support, *cone;
1983:       PetscInt        size, s;

1985:       DMPlexGetSupportSize(dm, v, &size);
1986:       DMPlexGetSupport(dm, v, &support);
1987:       for (s = 0; s < size; ++s) {
1988:         PetscInt r = 0;

1990:         DMPlexGetCone(dm, support[s], &cone);
1991:         if (cone[1] == v) r = 1;
1992:         supportRef[s] = fStartNew + (support[s] - fStart)*2 + r;
1993:       }
1994:       DMPlexSetSupport(rdm, newp, supportRef);
1995: #if defined(PETSC_USE_DEBUG)
1996:       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", newp, vStartNew, vEndNew);
1997:       for (p = 0; p < size; ++p) {
1998:         if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", supportRef[p], fStartNew, fEndNew);
1999:       }
2000: #endif
2001:     }
2002:     /* Face vertices have 2 + cells*2 supports */
2003:     for (f = fStart; f < fEnd; ++f) {
2004:       const PetscInt  newp = vStartNew + (vEnd - vStart) + (f - fStart);
2005:       const PetscInt *cone, *support;
2006:       PetscInt        size, s;

2008:       DMPlexGetSupportSize(dm, f, &size);
2009:       DMPlexGetSupport(dm, f, &support);
2010:       supportRef[0] = fStartNew + (f - fStart)*2 + 0;
2011:       supportRef[1] = fStartNew + (f - fStart)*2 + 1;
2012:       for (s = 0; s < size; ++s) {
2013:         PetscInt r = 0;

2015:         DMPlexGetCone(dm, support[s], &cone);
2016:         if      (cone[1] == f) r = 1;
2017:         else if (cone[2] == f) r = 2;
2018:         supportRef[2+s*2+0] = fStartNew + (fEnd - fStart)*2 + (support[s] - cStart)*3 + (r+2)%3;
2019:         supportRef[2+s*2+1] = fStartNew + (fEnd - fStart)*2 + (support[s] - cStart)*3 + r;
2020:       }
2021:       DMPlexSetSupport(rdm, newp, supportRef);
2022: #if defined(PETSC_USE_DEBUG)
2023:       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", newp, vStartNew, vEndNew);
2024:       for (p = 0; p < 2+size*2; ++p) {
2025:         if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", supportRef[p], fStartNew, fEndNew);
2026:       }
2027: #endif
2028:     }
2029:     PetscFree(supportRef);
2030:     break;
2031:   case REFINER_SIMPLEX_TO_HEX_2D:
2032:     /*
2033:      2
2034:      |\
2035:      | \
2036:      |  \
2037:      |   \
2038:      | C  \
2039:      |     \
2040:      2      1
2041:      |\    / \
2042:      | 2  1   \
2043:      |  \/     \
2044:      |   |      \
2045:      |A  |   B   \
2046:      |   0        \
2047:      |   |         \
2048:      0---0----------1
2049:      */
2050:     /* All cells have 4 faces */
2051:     for (c = cStart; c < cEnd; ++c) {
2052:       const PetscInt  newp = cStartNew + (c - cStart)*3;
2053:       const PetscInt *cone, *ornt;
2054:       PetscInt        coneNew[4], orntNew[4];

2056:       DMPlexGetCone(dm, c, &cone);
2057:       DMPlexGetConeOrientation(dm, c, &ornt);
2058:       /* A quad */
2059:       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
2060:       orntNew[0] = ornt[0];
2061:       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 0;
2062:       orntNew[1] = 0;
2063:       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 2;
2064:       orntNew[2] = -2;
2065:       coneNew[3] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
2066:       orntNew[3] = ornt[2];
2067:       DMPlexSetCone(rdm, newp+0, coneNew);
2068:       DMPlexSetConeOrientation(rdm, newp+0, orntNew);
2069: #if defined(PETSC_USE_DEBUG)
2070:       if ((newp+0 < cStartNew) || (newp+0 >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", newp+0, cStartNew, cEndNew);
2071:       for (p = 0; p < 4; ++p) {
2072:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", coneNew[p], fStartNew, fEndNew);
2073:       }
2074: #endif
2075:       /* B quad */
2076:       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
2077:       orntNew[0] = ornt[0];
2078:       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
2079:       orntNew[1] = ornt[1];
2080:       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 1;
2081:       orntNew[2] = 0;
2082:       coneNew[3] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 0;
2083:       orntNew[3] = -2;
2084:       DMPlexSetCone(rdm, newp+1, coneNew);
2085:       DMPlexSetConeOrientation(rdm, newp+1, orntNew);
2086: #if defined(PETSC_USE_DEBUG)
2087:       if ((newp+1 < cStartNew) || (newp+1 >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", newp+1, cStartNew, cEndNew);
2088:       for (p = 0; p < 4; ++p) {
2089:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", coneNew[p], fStartNew, fEndNew);
2090:       }
2091: #endif
2092:       /* C quad */
2093:       coneNew[0] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
2094:       orntNew[0] = ornt[1];
2095:       coneNew[1] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
2096:       orntNew[1] = ornt[2];
2097:       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 2;
2098:       orntNew[2] = 0;
2099:       coneNew[3] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 1;
2100:       orntNew[3] = -2;
2101:       DMPlexSetCone(rdm, newp+2, coneNew);
2102:       DMPlexSetConeOrientation(rdm, newp+2, orntNew);
2103: #if defined(PETSC_USE_DEBUG)
2104:       if ((newp+2 < cStartNew) || (newp+2 >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", newp+2, cStartNew, cEndNew);
2105:       for (p = 0; p < 4; ++p) {
2106:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", coneNew[p], fStartNew, fEndNew);
2107:       }
2108: #endif
2109:     }
2110:     /* Split faces have 2 vertices and the same cells as the parent */
2111:     DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);
2112:     PetscMalloc1(2 + maxSupportSize*2, &supportRef);
2113:     for (f = fStart; f < fEnd; ++f) {
2114:       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);

2116:       for (r = 0; r < 2; ++r) {
2117:         const PetscInt  newp = fStartNew + (f - fStart)*2 + r;
2118:         const PetscInt *cone, *ornt, *support;
2119:         PetscInt        coneNew[2], coneSize, c, supportSize, s;

2121:         DMPlexGetCone(dm, f, &cone);
2122:         coneNew[0]       = vStartNew + (cone[0] - vStart);
2123:         coneNew[1]       = vStartNew + (cone[1] - vStart);
2124:         coneNew[(r+1)%2] = newv;
2125:         DMPlexSetCone(rdm, newp, coneNew);
2126: #if defined(PETSC_USE_DEBUG)
2127:         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
2128:         for (p = 0; p < 2; ++p) {
2129:           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", coneNew[p], vStartNew, vEndNew);
2130:         }
2131: #endif
2132:         DMPlexGetSupportSize(dm, f, &supportSize);
2133:         DMPlexGetSupport(dm, f, &support);
2134:         for (s = 0; s < supportSize; ++s) {
2135:           DMPlexGetConeSize(dm, support[s], &coneSize);
2136:           DMPlexGetCone(dm, support[s], &cone);
2137:           DMPlexGetConeOrientation(dm, support[s], &ornt);
2138:           for (c = 0; c < coneSize; ++c) {
2139:             if (cone[c] == f) break;
2140:           }
2141:           supportRef[s] = cStartNew + (support[s] - cStart)*3 + (ornt[c] < 0 ? (c+1-r)%3 : (c+r)%3);
2142:         }
2143:         DMPlexSetSupport(rdm, newp, supportRef);
2144: #if defined(PETSC_USE_DEBUG)
2145:         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
2146:         for (p = 0; p < supportSize; ++p) {
2147:           if ((supportRef[p] < cStartNew) || (supportRef[p] >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", supportRef[p], cStartNew, cEndNew);
2148:         }
2149: #endif
2150:       }
2151:     }
2152:     /* Interior faces have 2 vertices and 2 cells */
2153:     for (c = cStart; c < cEnd; ++c) {
2154:       const PetscInt *cone;

2156:       DMPlexGetCone(dm, c, &cone);
2157:       for (r = 0; r < 3; ++r) {
2158:         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*3 + r;
2159:         PetscInt       coneNew[2];
2160:         PetscInt       supportNew[2];

2162:         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r] - fStart);
2163:         coneNew[1] = vStartNew + (vEnd - vStart) + (fEnd    - fStart) + (c - cStart);
2164:         DMPlexSetCone(rdm, newp, coneNew);
2165: #if defined(PETSC_USE_DEBUG)
2166:         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
2167:         for (p = 0; p < 2; ++p) {
2168:           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", coneNew[p], vStartNew, vEndNew);
2169:         }
2170: #endif
2171:         supportNew[0] = (c - cStart)*3 + r%3;
2172:         supportNew[1] = (c - cStart)*3 + (r+1)%3;
2173:         DMPlexSetSupport(rdm, newp, supportNew);
2174: #if defined(PETSC_USE_DEBUG)
2175:         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
2176:         for (p = 0; p < 2; ++p) {
2177:           if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", supportNew[p], cStartNew, cEndNew);
2178:         }
2179: #endif
2180:       }
2181:     }
2182:     /* Old vertices have identical supports */
2183:     for (v = vStart; v < vEnd; ++v) {
2184:       const PetscInt  newp = vStartNew + (v - vStart);
2185:       const PetscInt *support, *cone;
2186:       PetscInt        size, s;

2188:       DMPlexGetSupportSize(dm, v, &size);
2189:       DMPlexGetSupport(dm, v, &support);
2190:       for (s = 0; s < size; ++s) {
2191:         PetscInt r = 0;

2193:         DMPlexGetCone(dm, support[s], &cone);
2194:         if (cone[1] == v) r = 1;
2195:         supportRef[s] = fStartNew + (support[s] - fStart)*2 + r;
2196:       }
2197:       DMPlexSetSupport(rdm, newp, supportRef);
2198: #if defined(PETSC_USE_DEBUG)
2199:       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", newp, vStartNew, vEndNew);
2200:       for (p = 0; p < size; ++p) {
2201:         if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", supportRef[p], fStartNew, fEndNew);
2202:       }
2203: #endif
2204:     }
2205:     /* Split-face vertices have cells + 2 supports */
2206:     for (f = fStart; f < fEnd; ++f) {
2207:       const PetscInt  newp = vStartNew + (vEnd - vStart) + (f - fStart);
2208:       const PetscInt *cone, *support;
2209:       PetscInt        size, s;

2211:       DMPlexGetSupportSize(dm, f, &size);
2212:       DMPlexGetSupport(dm, f, &support);
2213:       supportRef[0] = fStartNew + (f - fStart)*2 + 0;
2214:       supportRef[1] = fStartNew + (f - fStart)*2 + 1;
2215:       for (s = 0; s < size; ++s) {
2216:         PetscInt r = 0;

2218:         DMPlexGetCone(dm, support[s], &cone);
2219:         if      (cone[1] == f) r = 1;
2220:         else if (cone[2] == f) r = 2;
2221:         supportRef[2+s+0] = fStartNew + (fEnd - fStart)*2 + (support[s] - cStart)*3 + r;
2222:       }
2223:       DMPlexSetSupport(rdm, newp, supportRef);
2224: #if defined(PETSC_USE_DEBUG)
2225:       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", newp, vStartNew, vEndNew);
2226:       for (p = 0; p < 2+size; ++p) {
2227:         if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", supportRef[p], fStartNew, fEndNew);
2228:       }
2229: #endif
2230:     }
2231:     /* Interior vertices have 3 supports */
2232:     for (c = cStart; c < cEnd; ++c) {
2233:       const PetscInt newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + c - cStart;

2235:       supportRef[0] = fStartNew + (fEnd - fStart)*2 + (c - cStart)*3 + 0;
2236:       supportRef[1] = fStartNew + (fEnd - fStart)*2 + (c - cStart)*3 + 1;
2237:       supportRef[2] = fStartNew + (fEnd - fStart)*2 + (c - cStart)*3 + 2;
2238:       DMPlexSetSupport(rdm, newp, supportRef);
2239:     }
2240:     PetscFree(supportRef);
2241:     break;
2242:   case REFINER_HYBRID_SIMPLEX_TO_HEX_2D:
2243:     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
2244:     cMax = PetscMin(cEnd, cMax);
2245:     for (c = cStart; c < cMax; ++c) {
2246:       const PetscInt  newp = cStartNew + (c - cStart)*3;
2247:       const PetscInt *cone, *ornt;
2248:       PetscInt        coneNew[4], orntNew[4];

2250:       DMPlexGetCone(dm, c, &cone);
2251:       DMPlexGetConeOrientation(dm, c, &ornt);
2252:       /* A quad */
2253:       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
2254:       orntNew[0] = ornt[0];
2255:       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 0;
2256:       orntNew[1] = 0;
2257:       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 2;
2258:       orntNew[2] = -2;
2259:       coneNew[3] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
2260:       orntNew[3] = ornt[2];
2261:       DMPlexSetCone(rdm, newp+0, coneNew);
2262:       DMPlexSetConeOrientation(rdm, newp+0, orntNew);
2263: #if defined(PETSC_USE_DEBUG)
2264:       if ((newp+0 < cStartNew) || (newp+0 >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", newp+0, cStartNew, cEndNew);
2265:       for (p = 0; p < 4; ++p) {
2266:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", coneNew[p], fStartNew, fEndNew);
2267:       }
2268: #endif
2269:       /* B quad */
2270:       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
2271:       orntNew[0] = ornt[0];
2272:       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
2273:       orntNew[1] = ornt[1];
2274:       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 1;
2275:       orntNew[2] = 0;
2276:       coneNew[3] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 0;
2277:       orntNew[3] = -2;
2278:       DMPlexSetCone(rdm, newp+1, coneNew);
2279:       DMPlexSetConeOrientation(rdm, newp+1, orntNew);
2280: #if defined(PETSC_USE_DEBUG)
2281:       if ((newp+1 < cStartNew) || (newp+1 >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", newp+1, cStartNew, cEndNew);
2282:       for (p = 0; p < 4; ++p) {
2283:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", coneNew[p], fStartNew, fEndNew);
2284:       }
2285: #endif
2286:       /* C quad */
2287:       coneNew[0] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
2288:       orntNew[0] = ornt[1];
2289:       coneNew[1] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
2290:       orntNew[1] = ornt[2];
2291:       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 2;
2292:       orntNew[2] = 0;
2293:       coneNew[3] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 1;
2294:       orntNew[3] = -2;
2295:       DMPlexSetCone(rdm, newp+2, coneNew);
2296:       DMPlexSetConeOrientation(rdm, newp+2, orntNew);
2297: #if defined(PETSC_USE_DEBUG)
2298:       if ((newp+2 < cStartNew) || (newp+2 >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", newp+2, cStartNew, cEndNew);
2299:       for (p = 0; p < 4; ++p) {
2300:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", coneNew[p], fStartNew, fEndNew);
2301:       }
2302: #endif
2303:     }
2304:     /*
2305:      2---------1---------3
2306:      |         |         |
2307:      |    D    1    C    |
2308:      |         |         |
2309:      2----2----0----3----3
2310:      |         |         |
2311:      |    A    0    B    |
2312:      |         |         |
2313:      0---------0---------1
2314:      */
2315:     /* Parent cells are input as prisms but children are quads, since the mesh is no longer hybrid */
2316:     for (c = cMax; c < cEnd; ++c) {
2317:       const PetscInt  newp  = cStartNew + (cMax - cStart)*3 + (c - cMax)*4;
2318:       const PetscInt  newpt = (cMax - cStart)*3 + (c - cMax)*4;
2319:       const PetscInt *cone, *ornt;
2320:       PetscInt        coneNew[4], orntNew[4];

2322:       DMPlexGetCone(dm, c, &cone);
2323:       DMPlexGetConeOrientation(dm, c, &ornt);
2324:       /* A quad */
2325:       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
2326:       orntNew[0] = ornt[0];
2327:       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + newpt + 0;
2328:       orntNew[1] = 0;
2329:       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + newpt + 2;
2330:       orntNew[2] = -2;
2331:       coneNew[3] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
2332:       orntNew[3] = ornt[2] < 0 ? 0 : -2;
2333:       DMPlexSetCone(rdm, newp+0, coneNew);
2334:       DMPlexSetConeOrientation(rdm, newp+0, orntNew);
2335: #if defined(PETSC_USE_DEBUG)
2336:       if ((newp+0 < cStartNew) || (newp+0 >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", newp+0, cStartNew, cEndNew);
2337:       for (p = 0; p < 4; ++p) {
2338:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", coneNew[p], fStartNew, fEndNew);
2339:       }
2340: #endif
2341:       /* B quad */
2342:       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
2343:       orntNew[0] = ornt[0];
2344:       coneNew[1] = fStartNew + (cone[3] - fStart)*2 + (ornt[3] < 0 ? 1 : 0);
2345:       orntNew[1] = ornt[3];
2346:       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + newpt + 3;
2347:       orntNew[2] = 0;
2348:       coneNew[3] = fStartNew + (fEnd    - fStart)*2 + newpt + 0;
2349:       orntNew[3] = -2;
2350:       DMPlexSetCone(rdm, newp+1, coneNew);
2351:       DMPlexSetConeOrientation(rdm, newp+1, orntNew);
2352: #if defined(PETSC_USE_DEBUG)
2353:       if ((newp+1 < cStartNew) || (newp+1 >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", newp+1, cStartNew, cEndNew);
2354:       for (p = 0; p < 4; ++p) {
2355:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", coneNew[p], fStartNew, fEndNew);
2356:       }
2357: #endif
2358:       /* C quad */
2359:       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + newpt + 3;
2360:       orntNew[0] = -2;
2361:       coneNew[1] = fStartNew + (cone[3] - fStart)*2 + (ornt[3] < 0 ? 0 : 1);
2362:       orntNew[1] = ornt[3];
2363:       coneNew[2] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
2364:       orntNew[2] = ornt[1] < 0 ? 0 : -2;
2365:       coneNew[3] = fStartNew + (fEnd    - fStart)*2 + newpt + 1;
2366:       orntNew[3] = 0;
2367:       DMPlexSetCone(rdm, newp+2, coneNew);
2368:       DMPlexSetConeOrientation(rdm, newp+2, orntNew);
2369: #if defined(PETSC_USE_DEBUG)
2370:       if ((newp+2 < cStartNew) || (newp+2 >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", newp+2, cStartNew, cEndNew);
2371:       for (p = 0; p < 4; ++p) {
2372:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", coneNew[p], fStartNew, fEndNew);
2373:       }
2374: #endif
2375:       /* D quad */
2376:       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + newpt + 2;
2377:       orntNew[0] = 0;
2378:       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + newpt + 1;
2379:       orntNew[1] = -2;
2380:       coneNew[2] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
2381:       orntNew[2] = ornt[1] < 0 ? 0 : -2;
2382:       coneNew[3] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
2383:       orntNew[3] = ornt[2] < 0 ? 0 : -2;
2384:       DMPlexSetCone(rdm, newp+3, coneNew);
2385:       DMPlexSetConeOrientation(rdm, newp+3, orntNew);
2386: #if defined(PETSC_USE_DEBUG)
2387:       if ((newp+3 < cStartNew) || (newp+3 >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", newp+3, cStartNew, cEndNew);
2388:       for (p = 0; p < 4; ++p) {
2389:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", coneNew[p], fStartNew, fEndNew);
2390:       }
2391: #endif
2392:     }
2393:     /* Split faces have 2 vertices and the same cells as the parent */
2394:     DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);
2395:     PetscMalloc1(2 + maxSupportSize*2, &supportRef);
2396:     for (f = fStart; f < fEnd; ++f) {
2397:       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);

2399:       for (r = 0; r < 2; ++r) {
2400:         const PetscInt  newp = fStartNew + (f - fStart)*2 + r;
2401:         const PetscInt *cone, *ornt, *support;
2402:         PetscInt        coneNew[2], coneSize, c, supportSize, s;

2404:         DMPlexGetCone(dm, f, &cone);
2405:         coneNew[0]       = vStartNew + (cone[0] - vStart);
2406:         coneNew[1]       = vStartNew + (cone[1] - vStart);
2407:         coneNew[(r+1)%2] = newv;
2408:         DMPlexSetCone(rdm, newp, coneNew);
2409: #if defined(PETSC_USE_DEBUG)
2410:         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
2411:         for (p = 0; p < 2; ++p) {
2412:           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", coneNew[p], vStartNew, vEndNew);
2413:         }
2414: #endif
2415:         DMPlexGetSupportSize(dm, f, &supportSize);
2416:         DMPlexGetSupport(dm, f, &support);
2417:         for (s = 0; s < supportSize; ++s) {
2418:           const PetscInt p2q[4][2] = { {0, 1},
2419:                                        {3, 2},
2420:                                        {0, 3},
2421:                                        {1, 2} };

2423:           DMPlexGetConeSize(dm, support[s], &coneSize);
2424:           DMPlexGetCone(dm, support[s], &cone);
2425:           DMPlexGetConeOrientation(dm, support[s], &ornt);
2426:           for (c = 0; c < coneSize; ++c) {
2427:             if (cone[c] == f) break;
2428:           }
2429:           if (coneSize == 3)      supportRef[s] = cStartNew + (support[s] - cStart)*3 + (ornt[c] < 0 ? (c+1-r)%3 : (c+r)%3);
2430:           else if (coneSize == 4) supportRef[s] = cStartNew + (cMax - cStart)*3 + (support[s] - cMax)*4 + (ornt[c] < 0 ? p2q[c][(r+1)%2] : p2q[c][r]);
2431:           else SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected cone size %D", coneSize);
2432:         }
2433:         DMPlexSetSupport(rdm, newp, supportRef);
2434: #if defined(PETSC_USE_DEBUG)
2435:         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
2436:         for (p = 0; p < supportSize; ++p) {
2437:           if ((supportRef[p] < cStartNew) || (supportRef[p] >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", supportRef[p], cStartNew, cEndNew);
2438:         }
2439: #endif
2440:       }
2441:     }
2442:     /* Interior faces have 2 vertices and 2 cells */
2443:     for (c = cStart; c < cMax; ++c) {
2444:       const PetscInt *cone;

2446:       DMPlexGetCone(dm, c, &cone);
2447:       for (r = 0; r < 3; ++r) {
2448:         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*3 + r;
2449:         PetscInt       coneNew[2];
2450:         PetscInt       supportNew[2];

2452:         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r] - fStart);
2453:         coneNew[1] = vStartNew + (vEnd - vStart) + (fEnd    - fStart) + (c - cStart);
2454:         DMPlexSetCone(rdm, newp, coneNew);
2455: #if defined(PETSC_USE_DEBUG)
2456:         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
2457:         for (p = 0; p < 2; ++p) {
2458:           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", coneNew[p], vStartNew, vEndNew);
2459:         }
2460: #endif
2461:         supportNew[0] = (c - cStart)*3 + r%3;
2462:         supportNew[1] = (c - cStart)*3 + (r+1)%3;
2463:         DMPlexSetSupport(rdm, newp, supportNew);
2464: #if defined(PETSC_USE_DEBUG)
2465:         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
2466:         for (p = 0; p < 2; ++p) {
2467:           if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", supportNew[p], cStartNew, cEndNew);
2468:         }
2469: #endif
2470:       }
2471:     }
2472:     /* Hybrid interior faces have 2 vertices and 2 cells */
2473:     for (c = cMax; c < cEnd; ++c) {
2474:       const PetscInt *cone;
2475:       PetscInt        coneNew[2], supportNew[2];

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

2481:         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r] - fStart);
2482:         coneNew[1] = vStartNew + (vEnd - vStart) + (fEnd    - fStart) + (cMax - cStart) + (c - cMax);
2483:         DMPlexSetCone(rdm, newp, coneNew);
2484: #if defined(PETSC_USE_DEBUG)
2485:         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
2486:         for (p = 0; p < 2; ++p) {
2487:           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", coneNew[p], vStartNew, vEndNew);
2488:         }
2489: #endif
2490:         if (r==0) {
2491:           supportNew[0] = (cMax - cStart)*3 + (c - cMax)*4 + 0;
2492:           supportNew[1] = (cMax - cStart)*3 + (c - cMax)*4 + 1;
2493:         } else if (r==1) {
2494:           supportNew[0] = (cMax - cStart)*3 + (c - cMax)*4 + 2;
2495:           supportNew[1] = (cMax - cStart)*3 + (c - cMax)*4 + 3;
2496:         } else if (r==2) {
2497:           supportNew[0] = (cMax - cStart)*3 + (c - cMax)*4 + 0;
2498:           supportNew[1] = (cMax - cStart)*3 + (c - cMax)*4 + 3;
2499:         } else {
2500:           supportNew[0] = (cMax - cStart)*3 + (c - cMax)*4 + 1;
2501:           supportNew[1] = (cMax - cStart)*3 + (c - cMax)*4 + 2;
2502:         }
2503:         DMPlexSetSupport(rdm, newp, supportNew);
2504: #if defined(PETSC_USE_DEBUG)
2505:         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
2506:         for (p = 0; p < 2; ++p) {
2507:           if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", supportNew[p], cStartNew, cEndNew);
2508:         }
2509: #endif
2510:       }
2511:     }
2512:     /* Old vertices have identical supports */
2513:     for (v = vStart; v < vEnd; ++v) {
2514:       const PetscInt  newp = vStartNew + (v - vStart);
2515:       const PetscInt *support, *cone;
2516:       PetscInt        size, s;

2518:       DMPlexGetSupportSize(dm, v, &size);
2519:       DMPlexGetSupport(dm, v, &support);
2520:       for (s = 0; s < size; ++s) {
2521:         PetscInt r = 0;

2523:         DMPlexGetCone(dm, support[s], &cone);
2524:         if (cone[1] == v) r = 1;
2525:         supportRef[s] = fStartNew + (support[s] - fStart)*2 + r;
2526:       }
2527:       DMPlexSetSupport(rdm, newp, supportRef);
2528: #if defined(PETSC_USE_DEBUG)
2529:       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", newp, vStartNew, vEndNew);
2530:       for (p = 0; p < size; ++p) {
2531:         if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", supportRef[p], fStartNew, fEndNew);
2532:       }
2533: #endif
2534:     }
2535:     /* Split-face vertices have cells + 2 supports */
2536:     for (f = fStart; f < fEnd; ++f) {
2537:       const PetscInt  newp = vStartNew + (vEnd - vStart) + (f - fStart);
2538:       const PetscInt *cone, *support;
2539:       PetscInt        size, s;

2541:       DMPlexGetSupportSize(dm, f, &size);
2542:       DMPlexGetSupport(dm, f, &support);
2543:       supportRef[0] = fStartNew + (f - fStart)*2 + 0;
2544:       supportRef[1] = fStartNew + (f - fStart)*2 + 1;
2545:       for (s = 0; s < size; ++s) {
2546:         PetscInt r = 0, coneSize;

2548:         DMPlexGetCone(dm, support[s], &cone);
2549:         DMPlexGetConeSize(dm, support[s], &coneSize);
2550:         if (coneSize == 3) {
2551:           if      (cone[1] == f) r = 1;
2552:           else if (cone[2] == f) r = 2;
2553:           supportRef[2+s] = fStartNew + (fEnd - fStart)*2 + (support[s] - cStart)*3 + r;
2554:         } else if (coneSize == 4) {
2555:           if      (cone[1] == f) r = 1;
2556:           else if (cone[2] == f) r = 2;
2557:           else if (cone[3] == f) r = 3;
2558:           supportRef[2+s] = fStartNew + (fEnd - fStart)*2 + (cMax - cStart)*3 + (support[s] - cMax)*4 + r;
2559:         } else SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected cone size %D", coneSize);
2560:       }
2561:       DMPlexSetSupport(rdm, newp, supportRef);
2562: #if defined(PETSC_USE_DEBUG)
2563:       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", newp, vStartNew, vEndNew);
2564:       for (p = 0; p < 2+size; ++p) {
2565:         if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", supportRef[p], fStartNew, fEndNew);
2566:       }
2567: #endif
2568:     }
2569:     /* Interior vertices have 3 supports */
2570:     for (c = cStart; c < cMax; ++c) {
2571:       const PetscInt newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + c - cStart;

2573:       supportRef[0] = fStartNew + (fEnd - fStart)*2 + (c - cStart)*3 + 0;
2574:       supportRef[1] = fStartNew + (fEnd - fStart)*2 + (c - cStart)*3 + 1;
2575:       supportRef[2] = fStartNew + (fEnd - fStart)*2 + (c - cStart)*3 + 2;
2576:       DMPlexSetSupport(rdm, newp, supportRef);
2577:     }
2578:     /* Hybrid interior vertices have 4 supports */
2579:     for (c = cMax; c < cEnd; ++c) {
2580:       const PetscInt newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + c - cStart;

2582:       supportRef[0] = fStartNew + (fEnd - fStart)*2 + (cMax - cStart)*3 + (c - cMax)*4 + 0;
2583:       supportRef[1] = fStartNew + (fEnd - fStart)*2 + (cMax - cStart)*3 + (c - cMax)*4 + 1;
2584:       supportRef[2] = fStartNew + (fEnd - fStart)*2 + (cMax - cStart)*3 + (c - cMax)*4 + 2;
2585:       supportRef[3] = fStartNew + (fEnd - fStart)*2 + (cMax - cStart)*3 + (c - cMax)*4 + 3;
2586:       DMPlexSetSupport(rdm, newp, supportRef);
2587:     }
2588:     PetscFree(supportRef);
2589:     break;
2590:   case REFINER_HEX_2D:
2591:     /*
2592:      3---------2---------2
2593:      |         |         |
2594:      |    D    2    C    |
2595:      |         |         |
2596:      3----3----0----1----1
2597:      |         |         |
2598:      |    A    0    B    |
2599:      |         |         |
2600:      0---------0---------1
2601:      */
2602:     /* All cells have 4 faces */
2603:     for (c = cStart; c < cEnd; ++c) {
2604:       const PetscInt  newp = (c - cStart)*4;
2605:       const PetscInt *cone, *ornt;
2606:       PetscInt        coneNew[4], orntNew[4];

2608:       DMPlexGetCone(dm, c, &cone);
2609:       DMPlexGetConeOrientation(dm, c, &ornt);
2610:       /* A quad */
2611:       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
2612:       orntNew[0] = ornt[0];
2613:       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 0;
2614:       orntNew[1] = 0;
2615:       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 3;
2616:       orntNew[2] = -2;
2617:       coneNew[3] = fStartNew + (cone[3] - fStart)*2 + (ornt[3] < 0 ? 0 : 1);
2618:       orntNew[3] = ornt[3];
2619:       DMPlexSetCone(rdm, newp+0, coneNew);
2620:       DMPlexSetConeOrientation(rdm, newp+0, orntNew);
2621: #if defined(PETSC_USE_DEBUG)
2622:       if ((newp+0 < cStartNew) || (newp+0 >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", newp+0, cStartNew, cEndNew);
2623:       for (p = 0; p < 4; ++p) {
2624:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", coneNew[p], fStartNew, fEndNew);
2625:       }
2626: #endif
2627:       /* B quad */
2628:       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
2629:       orntNew[0] = ornt[0];
2630:       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
2631:       orntNew[1] = ornt[1];
2632:       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 1;
2633:       orntNew[2] = -2;
2634:       coneNew[3] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 0;
2635:       orntNew[3] = -2;
2636:       DMPlexSetCone(rdm, newp+1, coneNew);
2637:       DMPlexSetConeOrientation(rdm, newp+1, orntNew);
2638: #if defined(PETSC_USE_DEBUG)
2639:       if ((newp+1 < cStartNew) || (newp+1 >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", newp+1, cStartNew, cEndNew);
2640:       for (p = 0; p < 4; ++p) {
2641:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", coneNew[p], fStartNew, fEndNew);
2642:       }
2643: #endif
2644:       /* C quad */
2645:       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 1;
2646:       orntNew[0] = 0;
2647:       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
2648:       orntNew[1] = ornt[1];
2649:       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
2650:       orntNew[2] = ornt[2];
2651:       coneNew[3] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 2;
2652:       orntNew[3] = -2;
2653:       DMPlexSetCone(rdm, newp+2, coneNew);
2654:       DMPlexSetConeOrientation(rdm, newp+2, orntNew);
2655: #if defined(PETSC_USE_DEBUG)
2656:       if ((newp+2 < cStartNew) || (newp+2 >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", newp+2, cStartNew, cEndNew);
2657:       for (p = 0; p < 4; ++p) {
2658:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", coneNew[p], fStartNew, fEndNew);
2659:       }
2660: #endif
2661:       /* D quad */
2662:       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 3;
2663:       orntNew[0] = 0;
2664:       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 2;
2665:       orntNew[1] = 0;
2666:       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
2667:       orntNew[2] = ornt[2];
2668:       coneNew[3] = fStartNew + (cone[3] - fStart)*2 + (ornt[3] < 0 ? 1 : 0);
2669:       orntNew[3] = ornt[3];
2670:       DMPlexSetCone(rdm, newp+3, coneNew);
2671:       DMPlexSetConeOrientation(rdm, newp+3, orntNew);
2672: #if defined(PETSC_USE_DEBUG)
2673:       if ((newp+3 < cStartNew) || (newp+3 >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", newp+3, cStartNew, cEndNew);
2674:       for (p = 0; p < 4; ++p) {
2675:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", coneNew[p], fStartNew, fEndNew);
2676:       }
2677: #endif
2678:     }
2679:     /* Split faces have 2 vertices and the same cells as the parent */
2680:     DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);
2681:     PetscMalloc1(2 + maxSupportSize*2, &supportRef);
2682:     for (f = fStart; f < fEnd; ++f) {
2683:       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);

2685:       for (r = 0; r < 2; ++r) {
2686:         const PetscInt  newp = fStartNew + (f - fStart)*2 + r;
2687:         const PetscInt *cone, *ornt, *support;
2688:         PetscInt        coneNew[2], coneSize, c, supportSize, s;

2690:         DMPlexGetCone(dm, f, &cone);
2691:         coneNew[0]       = vStartNew + (cone[0] - vStart);
2692:         coneNew[1]       = vStartNew + (cone[1] - vStart);
2693:         coneNew[(r+1)%2] = newv;
2694:         DMPlexSetCone(rdm, newp, coneNew);
2695: #if defined(PETSC_USE_DEBUG)
2696:         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
2697:         for (p = 0; p < 2; ++p) {
2698:           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", coneNew[p], vStartNew, vEndNew);
2699:         }
2700: #endif
2701:         DMPlexGetSupportSize(dm, f, &supportSize);
2702:         DMPlexGetSupport(dm, f, &support);
2703:         for (s = 0; s < supportSize; ++s) {
2704:           DMPlexGetConeSize(dm, support[s], &coneSize);
2705:           DMPlexGetCone(dm, support[s], &cone);
2706:           DMPlexGetConeOrientation(dm, support[s], &ornt);
2707:           for (c = 0; c < coneSize; ++c) {
2708:             if (cone[c] == f) break;
2709:           }
2710:           supportRef[s] = cStartNew + (support[s] - cStart)*4 + (ornt[c] < 0 ? (c+1-r)%4 : (c+r)%4);
2711:         }
2712:         DMPlexSetSupport(rdm, newp, supportRef);
2713: #if defined(PETSC_USE_DEBUG)
2714:         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
2715:         for (p = 0; p < supportSize; ++p) {
2716:           if ((supportRef[p] < cStartNew) || (supportRef[p] >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", supportRef[p], cStartNew, cEndNew);
2717:         }
2718: #endif
2719:       }
2720:     }
2721:     /* Interior faces have 2 vertices and 2 cells */
2722:     for (c = cStart; c < cEnd; ++c) {
2723:       const PetscInt *cone;
2724:       PetscInt        coneNew[2], supportNew[2];

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

2730:         if (r==1 || r==2) {
2731:           coneNew[0] = vStartNew + (vEnd - vStart) + (fEnd    - fStart) + (c - cStart);
2732:           coneNew[1] = vStartNew + (vEnd - vStart) + (cone[r] - fStart);
2733:         } else {
2734:           coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r] - fStart);
2735:           coneNew[1] = vStartNew + (vEnd - vStart) + (fEnd    - fStart) + (c - cStart);
2736:         }
2737:         DMPlexSetCone(rdm, newp, coneNew);
2738: #if defined(PETSC_USE_DEBUG)
2739:         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
2740:         for (p = 0; p < 2; ++p) {
2741:           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", coneNew[p], vStartNew, vEndNew);
2742:         }
2743: #endif
2744:         supportNew[0] = (c - cStart)*4 + r;
2745:         supportNew[1] = (c - cStart)*4 + (r+1)%4;
2746:         DMPlexSetSupport(rdm, newp, supportNew);
2747: #if defined(PETSC_USE_DEBUG)
2748:         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
2749:         for (p = 0; p < 2; ++p) {
2750:           if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", supportNew[p], cStartNew, cEndNew);
2751:         }
2752: #endif
2753:       }
2754:     }
2755:     /* Old vertices have identical supports */
2756:     for (v = vStart; v < vEnd; ++v) {
2757:       const PetscInt  newp = vStartNew + (v - vStart);
2758:       const PetscInt *support, *cone;
2759:       PetscInt        size, s;

2761:       DMPlexGetSupportSize(dm, v, &size);
2762:       DMPlexGetSupport(dm, v, &support);
2763:       for (s = 0; s < size; ++s) {
2764:         PetscInt r = 0;

2766:         DMPlexGetCone(dm, support[s], &cone);
2767:         if (cone[1] == v) r = 1;
2768:         supportRef[s] = fStartNew + (support[s] - fStart)*2 + r;
2769:       }
2770:       DMPlexSetSupport(rdm, newp, supportRef);
2771: #if defined(PETSC_USE_DEBUG)
2772:       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", newp, vStartNew, vEndNew);
2773:       for (p = 0; p < size; ++p) {
2774:         if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", supportRef[p], fStartNew, fEndNew);
2775:       }
2776: #endif
2777:     }
2778:     /* Face vertices have 2 + cells supports */
2779:     for (f = fStart; f < fEnd; ++f) {
2780:       const PetscInt  newp = vStartNew + (vEnd - vStart) + (f - fStart);
2781:       const PetscInt *cone, *support;
2782:       PetscInt        size, s;

2784:       DMPlexGetSupportSize(dm, f, &size);
2785:       DMPlexGetSupport(dm, f, &support);
2786:       supportRef[0] = fStartNew + (f - fStart)*2 + 0;
2787:       supportRef[1] = fStartNew + (f - fStart)*2 + 1;
2788:       for (s = 0; s < size; ++s) {
2789:         PetscInt r = 0;

2791:         DMPlexGetCone(dm, support[s], &cone);
2792:         if      (cone[1] == f) r = 1;
2793:         else if (cone[2] == f) r = 2;
2794:         else if (cone[3] == f) r = 3;
2795:         supportRef[2+s] = fStartNew + (fEnd - fStart)*2 + (support[s] - cStart)*4 + r;
2796:       }
2797:       DMPlexSetSupport(rdm, newp, supportRef);
2798: #if defined(PETSC_USE_DEBUG)
2799:       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", newp, vStartNew, vEndNew);
2800:       for (p = 0; p < 2+size; ++p) {
2801:         if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", supportRef[p], fStartNew, fEndNew);
2802:       }
2803: #endif
2804:     }
2805:     /* Cell vertices have 4 supports */
2806:     for (c = cStart; c < cEnd; ++c) {
2807:       const PetscInt newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (c - cStart);
2808:       PetscInt       supportNew[4];

2810:       for (r = 0; r < 4; ++r) {
2811:         supportNew[r] = fStartNew + (fEnd - fStart)*2 + (c - cStart)*4 + r;
2812:       }
2813:       DMPlexSetSupport(rdm, newp, supportNew);
2814:     }
2815:     PetscFree(supportRef);
2816:     break;
2817:   case REFINER_HYBRID_SIMPLEX_2D:
2818:     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
2819:     cMax = PetscMin(cEnd, cMax);
2820:     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
2821:     fMax = PetscMin(fEnd, fMax);
2822:     DMPlexGetHybridBounds(rdm, &cMaxNew, &fMaxNew, NULL, NULL);
2823:     /* Interior cells have 3 faces */
2824:     for (c = cStart; c < cMax; ++c) {
2825:       const PetscInt  newp = cStartNew + (c - cStart)*4;
2826:       const PetscInt *cone, *ornt;
2827:       PetscInt        coneNew[3], orntNew[3];

2829:       DMPlexGetCone(dm, c, &cone);
2830:       DMPlexGetConeOrientation(dm, c, &ornt);
2831:       /* A triangle */
2832:       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
2833:       orntNew[0] = ornt[0];
2834:       coneNew[1] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 2;
2835:       orntNew[1] = -2;
2836:       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
2837:       orntNew[2] = ornt[2];
2838:       DMPlexSetCone(rdm, newp+0, coneNew);
2839:       DMPlexSetConeOrientation(rdm, newp+0, orntNew);
2840: #if defined(PETSC_USE_DEBUG)
2841:       if ((newp+0 < cStartNew) || (newp+0 >= cMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an interior cell [%D, %D)", newp+0, cStartNew, cMaxNew);
2842:       for (p = 0; p < 3; ++p) {
2843:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an interior face [%D, %D)", coneNew[p], fStartNew, fMaxNew);
2844:       }
2845: #endif
2846:       /* B triangle */
2847:       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
2848:       orntNew[0] = ornt[0];
2849:       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
2850:       orntNew[1] = ornt[1];
2851:       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 0;
2852:       orntNew[2] = -2;
2853:       DMPlexSetCone(rdm, newp+1, coneNew);
2854:       DMPlexSetConeOrientation(rdm, newp+1, orntNew);
2855: #if defined(PETSC_USE_DEBUG)
2856:       if ((newp+1 < cStartNew) || (newp+1 >= cMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an interior cell [%D, %D)", newp+1, cStartNew, cMaxNew);
2857:       for (p = 0; p < 3; ++p) {
2858:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an interior face [%D, %D)", coneNew[p], fStartNew, fMaxNew);
2859:       }
2860: #endif
2861:       /* C triangle */
2862:       coneNew[0] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 1;
2863:       orntNew[0] = -2;
2864:       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
2865:       orntNew[1] = ornt[1];
2866:       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
2867:       orntNew[2] = ornt[2];
2868:       DMPlexSetCone(rdm, newp+2, coneNew);
2869:       DMPlexSetConeOrientation(rdm, newp+2, orntNew);
2870: #if defined(PETSC_USE_DEBUG)
2871:       if ((newp+2 < cStartNew) || (newp+2 >= cMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an interior cell [%D, %D)", newp+2, cStartNew, cMaxNew);
2872:       for (p = 0; p < 3; ++p) {
2873:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an interior face [%D, %D)", coneNew[p], fStartNew, fMaxNew);
2874:       }
2875: #endif
2876:       /* D triangle */
2877:       coneNew[0] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 0;
2878:       orntNew[0] = 0;
2879:       coneNew[1] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 1;
2880:       orntNew[1] = 0;
2881:       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 2;
2882:       orntNew[2] = 0;
2883:       DMPlexSetCone(rdm, newp+3, coneNew);
2884:       DMPlexSetConeOrientation(rdm, newp+3, orntNew);
2885: #if defined(PETSC_USE_DEBUG)
2886:       if ((newp+3 < cStartNew) || (newp+3 >= cMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an interior cell [%D, %D)", newp+3, cStartNew, cMaxNew);
2887:       for (p = 0; p < 3; ++p) {
2888:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an interior face [%D, %D)", coneNew[p], fStartNew, fMaxNew);
2889:       }
2890: #endif
2891:     }
2892:     /*
2893:      2----3----3
2894:      |         |
2895:      |    B    |
2896:      |         |
2897:      0----4--- 1
2898:      |         |
2899:      |    A    |
2900:      |         |
2901:      0----2----1
2902:      */
2903:     /* Hybrid cells have 4 faces */
2904:     for (c = cMax; c < cEnd; ++c) {
2905:       const PetscInt  newp = cStartNew + (cMax - cStart)*4 + (c - cMax)*2;
2906:       const PetscInt *cone, *ornt;
2907:       PetscInt        coneNew[4], orntNew[4], r;

2909:       DMPlexGetCone(dm, c, &cone);
2910:       DMPlexGetConeOrientation(dm, c, &ornt);
2911:       r    = (ornt[0] < 0 ? 1 : 0);
2912:       /* A quad */
2913:       coneNew[0]   = fStartNew + (cone[0] - fStart)*2 + r;
2914:       orntNew[0]   = ornt[0];
2915:       coneNew[1]   = fStartNew + (cone[1] - fStart)*2 + r;
2916:       orntNew[1]   = ornt[1];
2917:       coneNew[2+r] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (cone[2+r] - fMax);
2918:       orntNew[2+r] = 0;
2919:       coneNew[3-r] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (fEnd    - fMax) + (c - cMax);
2920:       orntNew[3-r] = 0;
2921:       DMPlexSetCone(rdm, newp+0, coneNew);
2922:       DMPlexSetConeOrientation(rdm, newp+0, orntNew);
2923: #if defined(PETSC_USE_DEBUG)
2924:       if ((newp+0 < cStartNew) || (newp+0 >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", newp+0, cStartNew, cEndNew);
2925:       for (p = 0; p < 4; ++p) {
2926:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", coneNew[p], fStartNew, fEndNew);
2927:       }
2928: #endif
2929:       /* B quad */
2930:       coneNew[0]   = fStartNew + (cone[0] - fStart)*2 + 1-r;
2931:       orntNew[0]   = ornt[0];
2932:       coneNew[1]   = fStartNew + (cone[1] - fStart)*2 + 1-r;
2933:       orntNew[1]   = ornt[1];
2934:       coneNew[2+r] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (fEnd    - fMax) + (c - cMax);
2935:       orntNew[2+r] = 0;
2936:       coneNew[3-r] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (cone[3-r] - fMax);
2937:       orntNew[3-r] = 0;
2938:       DMPlexSetCone(rdm, newp+1, coneNew);
2939:       DMPlexSetConeOrientation(rdm, newp+1, orntNew);
2940: #if defined(PETSC_USE_DEBUG)
2941:       if ((newp+1 < cStartNew) || (newp+1 >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", newp+1, cStartNew, cEndNew);
2942:       for (p = 0; p < 4; ++p) {
2943:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", coneNew[p], fStartNew, fEndNew);
2944:       }
2945: #endif
2946:     }
2947:     /* Interior split faces have 2 vertices and the same cells as the parent */
2948:     DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);
2949:     PetscMalloc1(2 + maxSupportSize*2, &supportRef);
2950:     for (f = fStart; f < fMax; ++f) {
2951:       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);

2953:       for (r = 0; r < 2; ++r) {
2954:         const PetscInt  newp = fStartNew + (f - fStart)*2 + r;
2955:         const PetscInt *cone, *ornt, *support;
2956:         PetscInt        coneNew[2], coneSize, c, supportSize, s;

2958:         DMPlexGetCone(dm, f, &cone);
2959:         coneNew[0]       = vStartNew + (cone[0] - vStart);
2960:         coneNew[1]       = vStartNew + (cone[1] - vStart);
2961:         coneNew[(r+1)%2] = newv;
2962:         DMPlexSetCone(rdm, newp, coneNew);
2963: #if defined(PETSC_USE_DEBUG)
2964:         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
2965:         for (p = 0; p < 2; ++p) {
2966:           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", coneNew[p], vStartNew, vEndNew);
2967:         }
2968: #endif
2969:         DMPlexGetSupportSize(dm, f, &supportSize);
2970:         DMPlexGetSupport(dm, f, &support);
2971:         for (s = 0; s < supportSize; ++s) {
2972:           DMPlexGetConeSize(dm, support[s], &coneSize);
2973:           DMPlexGetCone(dm, support[s], &cone);
2974:           DMPlexGetConeOrientation(dm, support[s], &ornt);
2975:           for (c = 0; c < coneSize; ++c) if (cone[c] == f) break;
2976:           if (support[s] >= cMax) {
2977:             supportRef[s] = cStartNew + (cMax - cStart)*4 + (support[s] - cMax)*2 + (ornt[c] < 0 ? 1-r : r);
2978:           } else {
2979:             supportRef[s] = cStartNew + (support[s] - cStart)*4 + (ornt[c] < 0 ? (c+1-r)%3 : (c+r)%3);
2980:           }
2981:         }
2982:         DMPlexSetSupport(rdm, newp, supportRef);
2983: #if defined(PETSC_USE_DEBUG)
2984:         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
2985:         for (p = 0; p < supportSize; ++p) {
2986:           if ((supportRef[p] < cStartNew) || (supportRef[p] >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", supportRef[p], cStartNew, cEndNew);
2987:         }
2988: #endif
2989:       }
2990:     }
2991:     /* Interior cell faces have 2 vertices and 2 cells */
2992:     for (c = cStart; c < cMax; ++c) {
2993:       const PetscInt *cone;

2995:       DMPlexGetCone(dm, c, &cone);
2996:       for (r = 0; r < 3; ++r) {
2997:         const PetscInt newp = fStartNew + (fMax - fStart)*2 + (c - cStart)*3 + r;
2998:         PetscInt       coneNew[2];
2999:         PetscInt       supportNew[2];

3001:         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r]       - fStart);
3002:         coneNew[1] = vStartNew + (vEnd - vStart) + (cone[(r+1)%3] - fStart);
3003:         DMPlexSetCone(rdm, newp, coneNew);
3004: #if defined(PETSC_USE_DEBUG)
3005:         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
3006:         for (p = 0; p < 2; ++p) {
3007:           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", coneNew[p], vStartNew, vEndNew);
3008:         }
3009: #endif
3010:         supportNew[0] = (c - cStart)*4 + (r+1)%3;
3011:         supportNew[1] = (c - cStart)*4 + 3;
3012:         DMPlexSetSupport(rdm, newp, supportNew);
3013: #if defined(PETSC_USE_DEBUG)
3014:         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
3015:         for (p = 0; p < 2; ++p) {
3016:           if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", supportNew[p], cStartNew, cEndNew);
3017:         }
3018: #endif
3019:       }
3020:     }
3021:     /* Interior hybrid faces have 2 vertices and the same cells */
3022:     for (f = fMax; f < fEnd; ++f) {
3023:       const PetscInt  newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (f - fMax);
3024:       const PetscInt *cone, *ornt;
3025:       const PetscInt *support;
3026:       PetscInt        coneNew[2];
3027:       PetscInt        supportNew[2];
3028:       PetscInt        size, s, r;

3030:       DMPlexGetCone(dm, f, &cone);
3031:       coneNew[0] = vStartNew + (cone[0] - vStart);
3032:       coneNew[1] = vStartNew + (cone[1] - vStart);
3033:       DMPlexSetCone(rdm, newp, coneNew);
3034: #if defined(PETSC_USE_DEBUG)
3035:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
3036:       for (p = 0; p < 2; ++p) {
3037:         if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", coneNew[p], vStartNew, vEndNew);
3038:       }
3039: #endif
3040:       DMPlexGetSupportSize(dm, f, &size);
3041:       DMPlexGetSupport(dm, f, &support);
3042:       for (s = 0; s < size; ++s) {
3043:         DMPlexGetCone(dm, support[s], &cone);
3044:         DMPlexGetConeOrientation(dm, support[s], &ornt);
3045:         for (r = 0; r < 2; ++r) {
3046:           if (cone[r+2] == f) break;
3047:         }
3048:         supportNew[s] = (cMax - cStart)*4 + (support[s] - cMax)*2 + (ornt[0] < 0 ? 1-r : r);
3049:       }
3050:       DMPlexSetSupport(rdm, newp, supportNew);
3051: #if defined(PETSC_USE_DEBUG)
3052:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
3053:       for (p = 0; p < size; ++p) {
3054:         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", supportNew[p], cStartNew, cEndNew);
3055:       }
3056: #endif
3057:     }
3058:     /* Cell hybrid faces have 2 vertices and 2 cells */
3059:     for (c = cMax; c < cEnd; ++c) {
3060:       const PetscInt  newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (fEnd - fMax) + (c - cMax);
3061:       const PetscInt *cone;
3062:       PetscInt        coneNew[2];
3063:       PetscInt        supportNew[2];

3065:       DMPlexGetCone(dm, c, &cone);
3066:       coneNew[0] = vStartNew + (vEnd - vStart) + (cone[0] - fStart);
3067:       coneNew[1] = vStartNew + (vEnd - vStart) + (cone[1] - fStart);
3068:       DMPlexSetCone(rdm, newp, coneNew);
3069: #if defined(PETSC_USE_DEBUG)
3070:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
3071:       for (p = 0; p < 2; ++p) {
3072:         if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", coneNew[p], vStartNew, vEndNew);
3073:       }
3074: #endif
3075:       supportNew[0] = (cMax - cStart)*4 + (c - cMax)*2 + 0;
3076:       supportNew[1] = (cMax - cStart)*4 + (c - cMax)*2 + 1;
3077:       DMPlexSetSupport(rdm, newp, supportNew);
3078: #if defined(PETSC_USE_DEBUG)
3079:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
3080:       for (p = 0; p < 2; ++p) {
3081:         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", supportNew[p], cStartNew, cEndNew);
3082:       }
3083: #endif
3084:     }
3085:     /* Old vertices have identical supports */
3086:     for (v = vStart; v < vEnd; ++v) {
3087:       const PetscInt  newp = vStartNew + (v - vStart);
3088:       const PetscInt *support, *cone;
3089:       PetscInt        size, s;

3091:       DMPlexGetSupportSize(dm, v, &size);
3092:       DMPlexGetSupport(dm, v, &support);
3093:       for (s = 0; s < size; ++s) {
3094:         if (support[s] >= fMax) {
3095:           supportRef[s] = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (support[s] - fMax);
3096:         } else {
3097:           PetscInt r = 0;

3099:           DMPlexGetCone(dm, support[s], &cone);
3100:           if (cone[1] == v) r = 1;
3101:           supportRef[s] = fStartNew + (support[s] - fStart)*2 + r;
3102:         }
3103:       }
3104:       DMPlexSetSupport(rdm, newp, supportRef);
3105: #if defined(PETSC_USE_DEBUG)
3106:       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", newp, vStartNew, vEndNew);
3107:       for (p = 0; p < size; ++p) {
3108:         if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", supportRef[p], fStartNew, fEndNew);
3109:       }
3110: #endif
3111:     }
3112:     /* Face vertices have 2 + (2 interior, 1 hybrid) supports */
3113:     for (f = fStart; f < fMax; ++f) {
3114:       const PetscInt  newp = vStartNew + (vEnd - vStart) + (f - fStart);
3115:       const PetscInt *cone, *support;
3116:       PetscInt        size, newSize = 2, s;

3118:       DMPlexGetSupportSize(dm, f, &size);
3119:       DMPlexGetSupport(dm, f, &support);
3120:       supportRef[0] = fStartNew + (f - fStart)*2 + 0;
3121:       supportRef[1] = fStartNew + (f - fStart)*2 + 1;
3122:       for (s = 0; s < size; ++s) {
3123:         PetscInt r = 0;

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

3129:           newSize += 1;
3130:         } else {
3131:           if      (cone[1] == f) r = 1;
3132:           else if (cone[2] == f) r = 2;
3133:           supportRef[newSize+0] = fStartNew + (fMax - fStart)*2 + (support[s] - cStart)*3 + (r+2)%3;
3134:           supportRef[newSize+1] = fStartNew + (fMax - fStart)*2 + (support[s] - cStart)*3 + r;

3136:           newSize += 2;
3137:         }
3138:       }
3139:       DMPlexSetSupport(rdm, newp, supportRef);
3140: #if defined(PETSC_USE_DEBUG)
3141:       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", newp, vStartNew, vEndNew);
3142:       for (p = 0; p < newSize; ++p) {
3143:         if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", supportRef[p], fStartNew, fEndNew);
3144:       }
3145: #endif
3146:     }
3147:     PetscFree(supportRef);
3148:     break;
3149:   case REFINER_HYBRID_HEX_2D:
3150:     /* Hybrid Hex 2D */
3151:     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
3152:     cMax = PetscMin(cEnd, cMax);
3153:     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
3154:     fMax = PetscMin(fEnd, fMax);
3155:     DMPlexGetHybridBounds(rdm, &cMaxNew, &fMaxNew, NULL, NULL);
3156:     /* Interior cells have 4 faces */
3157:     for (c = cStart; c < cMax; ++c) {
3158:       const PetscInt  newp = cStartNew + (c - cStart)*4;
3159:       const PetscInt *cone, *ornt;
3160:       PetscInt        coneNew[4], orntNew[4];

3162:       DMPlexGetCone(dm, c, &cone);
3163:       DMPlexGetConeOrientation(dm, c, &ornt);
3164:       /* A quad */
3165:       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
3166:       orntNew[0] = ornt[0];
3167:       coneNew[1] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*4 + 0;
3168:       orntNew[1] = 0;
3169:       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*4 + 3;
3170:       orntNew[2] = -2;
3171:       coneNew[3] = fStartNew + (cone[3] - fStart)*2 + (ornt[3] < 0 ? 0 : 1);
3172:       orntNew[3] = ornt[3];
3173:       DMPlexSetCone(rdm, newp+0, coneNew);
3174:       DMPlexSetConeOrientation(rdm, newp+0, orntNew);
3175: #if defined(PETSC_USE_DEBUG)
3176:       if ((newp+0 < cStartNew) || (newp+0 >= cMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an interior cell [%D, %D)", newp+0, cStartNew, cMaxNew);
3177:       for (p = 0; p < 4; ++p) {
3178:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an interior face [%D, %D)", coneNew[p], fStartNew, fMaxNew);
3179:       }
3180: #endif
3181:       /* B quad */
3182:       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
3183:       orntNew[0] = ornt[0];
3184:       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
3185:       orntNew[1] = ornt[1];
3186:       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*4 + 1;
3187:       orntNew[2] = 0;
3188:       coneNew[3] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*4 + 0;
3189:       orntNew[3] = -2;
3190:       DMPlexSetCone(rdm, newp+1, coneNew);
3191:       DMPlexSetConeOrientation(rdm, newp+1, orntNew);
3192: #if defined(PETSC_USE_DEBUG)
3193:       if ((newp+1 < cStartNew) || (newp+1 >= cMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an interior cell [%D, %D)", newp+1, cStartNew, cMaxNew);
3194:       for (p = 0; p < 4; ++p) {
3195:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an interior face [%D, %D)", coneNew[p], fStartNew, fMaxNew);
3196:       }
3197: #endif
3198:       /* C quad */
3199:       coneNew[0] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*4 + 1;
3200:       orntNew[0] = -2;
3201:       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
3202:       orntNew[1] = ornt[1];
3203:       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
3204:       orntNew[2] = ornt[2];
3205:       coneNew[3] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*4 + 2;
3206:       orntNew[3] = 0;
3207:       DMPlexSetCone(rdm, newp+2, coneNew);
3208:       DMPlexSetConeOrientation(rdm, newp+2, orntNew);
3209: #if defined(PETSC_USE_DEBUG)
3210:       if ((newp+2 < cStartNew) || (newp+2 >= cMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an interior cell [%D, %D)", newp+2, cStartNew, cMaxNew);
3211:       for (p = 0; p < 4; ++p) {
3212:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an interior face [%D, %D)", coneNew[p], fStartNew, fMaxNew);
3213:       }
3214: #endif
3215:       /* D quad */
3216:       coneNew[0] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*4 + 3;
3217:       orntNew[0] = 0;
3218:       coneNew[1] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*4 + 2;
3219:       orntNew[1] = -2;
3220:       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
3221:       orntNew[2] = ornt[2];
3222:       coneNew[3] = fStartNew + (cone[3] - fStart)*2 + (ornt[3] < 0 ? 1 : 0);
3223:       orntNew[3] = ornt[3];
3224:       DMPlexSetCone(rdm, newp+3, coneNew);
3225:       DMPlexSetConeOrientation(rdm, newp+3, orntNew);
3226: #if defined(PETSC_USE_DEBUG)
3227:       if ((newp+3 < cStartNew) || (newp+3 >= cMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an interior cell [%D, %D)", newp+3, cStartNew, cMaxNew);
3228:       for (p = 0; p < 4; ++p) {
3229:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an interior face [%D, %D)", coneNew[p], fStartNew, fMaxNew);
3230:       }
3231: #endif
3232:     }
3233:     /*
3234:      2----3----3
3235:      |         |
3236:      |    B    |
3237:      |         |
3238:      0----4--- 1
3239:      |         |
3240:      |    A    |
3241:      |         |
3242:      0----2----1
3243:      */
3244:     /* Hybrid cells have 4 faces */
3245:     for (c = cMax; c < cEnd; ++c) {
3246:       const PetscInt  newp = cStartNew + (cMax - cStart)*4 + (c - cMax)*2;
3247:       const PetscInt *cone, *ornt;
3248:       PetscInt        coneNew[4], orntNew[4];

3250:       DMPlexGetCone(dm, c, &cone);
3251:       DMPlexGetConeOrientation(dm, c, &ornt);
3252:       /* A quad */
3253:       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
3254:       orntNew[0] = ornt[0];
3255:       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
3256:       orntNew[1] = ornt[1];
3257:       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*4 + (cone[2] - fMax);
3258:       orntNew[2] = 0;
3259:       coneNew[3] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*4 + (fEnd    - fMax) + (c - cMax);
3260:       orntNew[3] = 0;
3261:       DMPlexSetCone(rdm, newp+0, coneNew);
3262:       DMPlexSetConeOrientation(rdm, newp+0, orntNew);
3263: #if defined(PETSC_USE_DEBUG)
3264:       if ((newp+0 < cStartNew) || (newp+0 >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", newp+0, cStartNew, cEndNew);
3265:       for (p = 0; p < 4; ++p) {
3266:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", coneNew[p], fStartNew, fEndNew);
3267:       }
3268: #endif
3269:       /* B quad */
3270:       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
3271:       orntNew[0] = ornt[0];
3272:       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
3273:       orntNew[1] = ornt[1];
3274:       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*4 + (fEnd    - fMax) + (c - cMax);
3275:       orntNew[2] = 0;
3276:       coneNew[3] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*4 + (cone[3] - fMax);
3277:       orntNew[3] = 0;
3278:       DMPlexSetCone(rdm, newp+1, coneNew);
3279:       DMPlexSetConeOrientation(rdm, newp+1, orntNew);
3280: #if defined(PETSC_USE_DEBUG)
3281:       if ((newp+1 < cStartNew) || (newp+1 >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", newp+1, cStartNew, cEndNew);
3282:       for (p = 0; p < 4; ++p) {
3283:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", coneNew[p], fStartNew, fEndNew);
3284:       }
3285: #endif
3286:     }
3287:     /* Interior split faces have 2 vertices and the same cells as the parent */
3288:     DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);
3289:     PetscMalloc1(2 + maxSupportSize*2, &supportRef);
3290:     for (f = fStart; f < fMax; ++f) {
3291:       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);

3293:       for (r = 0; r < 2; ++r) {
3294:         const PetscInt  newp = fStartNew + (f - fStart)*2 + r;
3295:         const PetscInt *cone, *ornt, *support;
3296:         PetscInt        coneNew[2], coneSize, c, supportSize, s;

3298:         DMPlexGetCone(dm, f, &cone);
3299:         coneNew[0]       = vStartNew + (cone[0] - vStart);
3300:         coneNew[1]       = vStartNew + (cone[1] - vStart);
3301:         coneNew[(r+1)%2] = newv;
3302:         DMPlexSetCone(rdm, newp, coneNew);
3303: #if defined(PETSC_USE_DEBUG)
3304:         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
3305:         for (p = 0; p < 2; ++p) {
3306:           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", coneNew[p], vStartNew, vEndNew);
3307:         }
3308: #endif
3309:         DMPlexGetSupportSize(dm, f, &supportSize);
3310:         DMPlexGetSupport(dm, f, &support);
3311:         for (s = 0; s < supportSize; ++s) {
3312:           if (support[s] >= cMax) {
3313:             supportRef[s] = cStartNew + (cMax - cStart)*4 + (support[s] - cMax)*2 + r;
3314:           } else {
3315:             DMPlexGetConeSize(dm, support[s], &coneSize);
3316:             DMPlexGetCone(dm, support[s], &cone);
3317:             DMPlexGetConeOrientation(dm, support[s], &ornt);
3318:             for (c = 0; c < coneSize; ++c) {
3319:               if (cone[c] == f) break;
3320:             }
3321:             supportRef[s] = cStartNew + (support[s] - cStart)*4 + (ornt[c] < 0 ? (c+1-r)%4 : (c+r)%4);
3322:           }
3323:         }
3324:         DMPlexSetSupport(rdm, newp, supportRef);
3325: #if defined(PETSC_USE_DEBUG)
3326:         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
3327:         for (p = 0; p < supportSize; ++p) {
3328:           if ((supportRef[p] < cStartNew) || (supportRef[p] >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", supportRef[p], cStartNew, cEndNew);
3329:         }
3330: #endif
3331:       }
3332:     }
3333:     /* Interior cell faces have 2 vertices and 2 cells */
3334:     for (c = cStart; c < cMax; ++c) {
3335:       const PetscInt *cone;

3337:       DMPlexGetCone(dm, c, &cone);
3338:       for (r = 0; r < 4; ++r) {
3339:         const PetscInt newp = fStartNew + (fMax - fStart)*2 + (c - cStart)*4 + r;
3340:         PetscInt       coneNew[2], supportNew[2];

3342:         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r] - fStart);
3343:         coneNew[1] = vStartNew + (vEnd - vStart) + (fMax    - fStart) + (c - cStart);
3344:         DMPlexSetCone(rdm, newp, coneNew);
3345: #if defined(PETSC_USE_DEBUG)
3346:         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
3347:         for (p = 0; p < 2; ++p) {
3348:           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", coneNew[p], vStartNew, vEndNew);
3349:         }
3350: #endif
3351:         supportNew[0] = (c - cStart)*4 + r;
3352:         supportNew[1] = (c - cStart)*4 + (r+1)%4;
3353:         DMPlexSetSupport(rdm, newp, supportNew);
3354: #if defined(PETSC_USE_DEBUG)
3355:         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
3356:         for (p = 0; p < 2; ++p) {
3357:           if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", supportNew[p], cStartNew, cEndNew);
3358:         }
3359: #endif
3360:       }
3361:     }
3362:     /* Hybrid faces have 2 vertices and the same cells */
3363:     for (f = fMax; f < fEnd; ++f) {
3364:       const PetscInt  newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*4 + (f - fMax);
3365:       const PetscInt *cone, *support;
3366:       PetscInt        coneNew[2], supportNew[2];
3367:       PetscInt        size, s, r;

3369:       DMPlexGetCone(dm, f, &cone);
3370:       coneNew[0] = vStartNew + (cone[0] - vStart);
3371:       coneNew[1] = vStartNew + (cone[1] - vStart);
3372:       DMPlexSetCone(rdm, newp, coneNew);
3373: #if defined(PETSC_USE_DEBUG)
3374:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
3375:       for (p = 0; p < 2; ++p) {
3376:         if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", coneNew[p], vStartNew, vEndNew);
3377:       }
3378: #endif
3379:       DMPlexGetSupportSize(dm, f, &size);
3380:       DMPlexGetSupport(dm, f, &support);
3381:       for (s = 0; s < size; ++s) {
3382:         DMPlexGetCone(dm, support[s], &cone);
3383:         for (r = 0; r < 2; ++r) {
3384:           if (cone[r+2] == f) break;
3385:         }
3386:         supportNew[s] = (cMax - cStart)*4 + (support[s] - cMax)*2 + r;
3387:       }
3388:       DMPlexSetSupport(rdm, newp, supportNew);
3389: #if defined(PETSC_USE_DEBUG)
3390:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
3391:       for (p = 0; p < size; ++p) {
3392:         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", supportNew[p], cStartNew, cEndNew);
3393:       }
3394: #endif
3395:     }
3396:     /* Cell hybrid faces have 2 vertices and 2 cells */
3397:     for (c = cMax; c < cEnd; ++c) {
3398:       const PetscInt  newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*4 + (fEnd - fMax) + (c - cMax);
3399:       const PetscInt *cone;
3400:       PetscInt        coneNew[2], supportNew[2];

3402:       DMPlexGetCone(dm, c, &cone);
3403:       coneNew[0] = vStartNew + (vEnd - vStart) + (cone[0] - fStart);
3404:       coneNew[1] = vStartNew + (vEnd - vStart) + (cone[1] - fStart);
3405:       DMPlexSetCone(rdm, newp, coneNew);
3406: #if defined(PETSC_USE_DEBUG)
3407:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
3408:       for (p = 0; p < 2; ++p) {
3409:         if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", coneNew[p], vStartNew, vEndNew);
3410:       }
3411: #endif
3412:       supportNew[0] = (cMax - cStart)*4 + (c - cMax)*2 + 0;
3413:       supportNew[1] = (cMax - cStart)*4 + (c - cMax)*2 + 1;
3414:       DMPlexSetSupport(rdm, newp, supportNew);
3415: #if defined(PETSC_USE_DEBUG)
3416:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
3417:       for (p = 0; p < 2; ++p) {
3418:         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", supportNew[p], cStartNew, cEndNew);
3419:       }
3420: #endif
3421:     }
3422:     /* Old vertices have identical supports */
3423:     for (v = vStart; v < vEnd; ++v) {
3424:       const PetscInt  newp = vStartNew + (v - vStart);
3425:       const PetscInt *support, *cone;
3426:       PetscInt        size, s;

3428:       DMPlexGetSupportSize(dm, v, &size);
3429:       DMPlexGetSupport(dm, v, &support);
3430:       for (s = 0; s < size; ++s) {
3431:         if (support[s] >= fMax) {
3432:           supportRef[s] = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*4 + (support[s] - fMax);
3433:         } else {
3434:           PetscInt r = 0;

3436:           DMPlexGetCone(dm, support[s], &cone);
3437:           if (cone[1] == v) r = 1;
3438:           supportRef[s] = fStartNew + (support[s] - fStart)*2 + r;
3439:         }
3440:       }
3441:       DMPlexSetSupport(rdm, newp, supportRef);
3442: #if defined(PETSC_USE_DEBUG)
3443:       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", newp, vStartNew, vEndNew);
3444:       for (p = 0; p < size; ++p) {
3445:         if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", supportRef[p], fStartNew, fEndNew);
3446:       }
3447: #endif
3448:     }
3449:     /* Face vertices have 2 + cells supports */
3450:     for (f = fStart; f < fMax; ++f) {
3451:       const PetscInt  newp = vStartNew + (vEnd - vStart) + (f - fStart);
3452:       const PetscInt *cone, *support;
3453:       PetscInt        size, s;

3455:       DMPlexGetSupportSize(dm, f, &size);
3456:       DMPlexGetSupport(dm, f, &support);
3457:       supportRef[0] = fStartNew + (f - fStart)*2 + 0;
3458:       supportRef[1] = fStartNew + (f - fStart)*2 + 1;
3459:       for (s = 0; s < size; ++s) {
3460:         PetscInt r = 0;

3462:         DMPlexGetCone(dm, support[s], &cone);
3463:         if (support[s] >= cMax) {
3464:           supportRef[2+s] = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*4 + (fEnd - fMax) + (support[s] - cMax);
3465:         } else {
3466:           if      (cone[1] == f) r = 1;
3467:           else if (cone[2] == f) r = 2;
3468:           else if (cone[3] == f) r = 3;
3469:           supportRef[2+s] = fStartNew + (fMax - fStart)*2 + (support[s] - cStart)*4 + r;
3470:         }
3471:       }
3472:       DMPlexSetSupport(rdm, newp, supportRef);
3473: #if defined(PETSC_USE_DEBUG)
3474:       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", newp, vStartNew, vEndNew);
3475:       for (p = 0; p < 2+size; ++p) {
3476:         if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", supportRef[p], fStartNew, fEndNew);
3477:       }
3478: #endif
3479:     }
3480:     /* Cell vertices have 4 supports */
3481:     for (c = cStart; c < cMax; ++c) {
3482:       const PetscInt newp = vStartNew + (vEnd - vStart) + (fMax - fStart) + (c - cStart);
3483:       PetscInt       supportNew[4];

3485:       for (r = 0; r < 4; ++r) {
3486:         supportNew[r] = fStartNew + (fMax - fStart)*2 + (c - cStart)*4 + r;
3487:       }
3488:       DMPlexSetSupport(rdm, newp, supportNew);
3489:     }
3490:     PetscFree(supportRef);
3491:     break;
3492:   case REFINER_SIMPLEX_3D:
3493:     /* All cells have 4 faces: Tet face order is prescribed in DMPlexGetFaces_Internal() */
3494:     DMPlexGetRawFaces_Internal(dm, 3, 4, cellInd, NULL, NULL, &faces);
3495:     for (c = cStart; c < cEnd; ++c) {
3496:       const PetscInt  newp = cStartNew + (c - cStart)*8;
3497:       const PetscInt *cone, *ornt;
3498:       PetscInt        coneNew[4], orntNew[4];

3500:       DMPlexGetCone(dm, c, &cone);
3501:       DMPlexGetConeOrientation(dm, c, &ornt);
3502:       /* A tetrahedron: {0, a, c, d} */
3503:       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetTriSubface_Static(ornt[0], 0); /* A */
3504:       orntNew[0] = ornt[0];
3505:       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetTriSubface_Static(ornt[1], 0); /* A */
3506:       orntNew[1] = ornt[1];
3507:       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetTriSubface_Static(ornt[2], 0); /* A */
3508:       orntNew[2] = ornt[2];
3509:       coneNew[3] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 0;
3510:       orntNew[3] = 0;
3511:       DMPlexSetCone(rdm, newp+0, coneNew);
3512:       DMPlexSetConeOrientation(rdm, newp+0, orntNew);
3513: #if defined(PETSC_USE_DEBUG)
3514:       if ((newp+0 < cStartNew) || (newp+0 >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", newp+0, cStartNew, cEndNew);
3515:       for (p = 0; p < 4; ++p) {
3516:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", coneNew[p], fStartNew, fEndNew);
3517:       }
3518: #endif
3519:       /* B tetrahedron: {a, 1, b, e} */
3520:       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetTriSubface_Static(ornt[0], 1); /* B */
3521:       orntNew[0] = ornt[0];
3522:       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetTriSubface_Static(ornt[1], 2); /* C */
3523:       orntNew[1] = ornt[1];
3524:       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 1;
3525:       orntNew[2] = 0;
3526:       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetTriSubface_Static(ornt[3], 1); /* B */
3527:       orntNew[3] = ornt[3];
3528:       DMPlexSetCone(rdm, newp+1, coneNew);
3529:       DMPlexSetConeOrientation(rdm, newp+1, orntNew);
3530: #if defined(PETSC_USE_DEBUG)
3531:       if ((newp+1 < cStartNew) || (newp+1 >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", newp+1, cStartNew, cEndNew);
3532:       for (p = 0; p < 4; ++p) {
3533:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", coneNew[p], fStartNew, fEndNew);
3534:       }
3535: #endif
3536:       /* C tetrahedron: {c, b, 2, f} */
3537:       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetTriSubface_Static(ornt[0], 2); /* C */
3538:       orntNew[0] = ornt[0];
3539:       coneNew[1] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 2;
3540:       orntNew[1] = 0;
3541:       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetTriSubface_Static(ornt[2], 1); /* B */
3542:       orntNew[2] = ornt[2];
3543:       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetTriSubface_Static(ornt[3], 0); /* A */
3544:       orntNew[3] = ornt[3];
3545:       DMPlexSetCone(rdm, newp+2, coneNew);
3546:       DMPlexSetConeOrientation(rdm, newp+2, orntNew);
3547: #if defined(PETSC_USE_DEBUG)
3548:       if ((newp+2 < cStartNew) || (newp+2 >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", newp+2, cStartNew, cEndNew);
3549:       for (p = 0; p < 4; ++p) {
3550:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", coneNew[p], fStartNew, fEndNew);
3551:       }
3552: #endif
3553:       /* D tetrahedron: {d, e, f, 3} */
3554:       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 3;
3555:       orntNew[0] = 0;
3556:       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetTriSubface_Static(ornt[1], 1); /* B */
3557:       orntNew[1] = ornt[1];
3558:       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetTriSubface_Static(ornt[2], 2); /* C */
3559:       orntNew[2] = ornt[2];
3560:       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetTriSubface_Static(ornt[3], 2); /* C */
3561:       orntNew[3] = ornt[3];
3562:       DMPlexSetCone(rdm, newp+3, coneNew);
3563:       DMPlexSetConeOrientation(rdm, newp+3, orntNew);
3564: #if defined(PETSC_USE_DEBUG)
3565:       if ((newp+3 < cStartNew) || (newp+3 >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", newp+3, cStartNew, cEndNew);
3566:       for (p = 0; p < 4; ++p) {
3567:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", coneNew[p], fStartNew, fEndNew);
3568:       }
3569: #endif
3570:       /* A' tetrahedron: {c, d, a, f} */
3571:       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 0;
3572:       orntNew[0] = -3;
3573:       coneNew[1] = fStartNew + (cone[2] - fStart)*4 + 3;
3574:       orntNew[1] = ornt[2] < 0 ? -(GetTriMidEdge_Static(ornt[2], 0)+1) : GetTriMidEdge_Static(ornt[2], 0);
3575:       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 5;
3576:       orntNew[2] = 0;
3577:       coneNew[3] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 4;
3578:       orntNew[3] = 2;
3579:       DMPlexSetCone(rdm, newp+4, coneNew);
3580:       DMPlexSetConeOrientation(rdm, newp+4, orntNew);
3581: #if defined(PETSC_USE_DEBUG)
3582:       if ((newp+4 < cStartNew) || (newp+4 >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", newp+4, cStartNew, cEndNew);
3583:       for (p = 0; p < 4; ++p) {
3584:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", coneNew[p], fStartNew, fEndNew);
3585:       }
3586: #endif
3587:       /* B' tetrahedron: {e, b, a, f} */
3588:       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 1;
3589:       orntNew[0] = -2;
3590:       coneNew[1] = fStartNew + (cone[3] - fStart)*4 + 3;
3591:       orntNew[1] = ornt[3] < 0 ? -(GetTriMidEdge_Static(ornt[3], 1)+1) : GetTriMidEdge_Static(ornt[3], 1);
3592:       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 6;
3593:       orntNew[2] = 0;
3594:       coneNew[3] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 7;
3595:       orntNew[3] = 0;
3596:       DMPlexSetCone(rdm, newp+5, coneNew);
3597:       DMPlexSetConeOrientation(rdm, newp+5, orntNew);
3598: #if defined(PETSC_USE_DEBUG)
3599:       if ((newp+5 < cStartNew) || (newp+5 >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", newp+5, cStartNew, cEndNew);
3600:       for (p = 0; p < 4; ++p) {
3601:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", coneNew[p], fStartNew, fEndNew);
3602:       }
3603: #endif
3604:       /* C' tetrahedron: {f, a, c, b} */
3605:       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 5;
3606:       orntNew[0] = -2;
3607:       coneNew[1] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 7;
3608:       orntNew[1] = -2;
3609:       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 2;
3610:       orntNew[2] = -1;
3611:       coneNew[3] = fStartNew + (cone[0] - fStart)*4 + 3;
3612:       orntNew[3] = ornt[0] < 0 ? -(GetTriMidEdge_Static(ornt[0], 2)+1) : GetTriMidEdge_Static(ornt[0], 2);
3613:       DMPlexSetCone(rdm, newp+6, coneNew);
3614:       DMPlexSetConeOrientation(rdm, newp+6, orntNew);
3615: #if defined(PETSC_USE_DEBUG)
3616:       if ((newp+6 < cStartNew) || (newp+6 >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", newp+6, cStartNew, cEndNew);
3617:       for (p = 0; p < 4; ++p) {
3618:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", coneNew[p], fStartNew, fEndNew);
3619:       }
3620: #endif
3621:       /* D' tetrahedron: {f, a, e, d} */
3622:       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 6;
3623:       orntNew[0] = -2;
3624:       coneNew[1] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 4;
3625:       orntNew[1] = -1;
3626:       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 3;
3627:       orntNew[2] = -2;
3628:       coneNew[3] = fStartNew + (cone[1] - fStart)*4 + 3;
3629:       orntNew[3] = ornt[1] < 0 ? -(GetTriMidEdge_Static(ornt[1], 1)+1) : GetTriMidEdge_Static(ornt[1], 1);
3630:       DMPlexSetCone(rdm, newp+7, coneNew);
3631:       DMPlexSetConeOrientation(rdm, newp+7, orntNew);
3632: #if defined(PETSC_USE_DEBUG)
3633:       if ((newp+7 < cStartNew) || (newp+7 >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", newp+7, cStartNew, cEndNew);
3634:       for (p = 0; p < 4; ++p) {
3635:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", coneNew[p], fStartNew, fEndNew);
3636:       }
3637: #endif
3638:     }
3639:     /* Split faces have 3 edges and the same cells as the parent */
3640:     DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);
3641:     PetscMalloc1(2 + maxSupportSize*3, &supportRef);
3642:     for (f = fStart; f < fEnd; ++f) {
3643:       const PetscInt  newp = fStartNew + (f - fStart)*4;
3644:       const PetscInt *cone, *ornt, *support;
3645:       PetscInt        coneNew[3], orntNew[3], coneSize, supportSize, s;

3647:       DMPlexGetCone(dm, f, &cone);
3648:       DMPlexGetConeOrientation(dm, f, &ornt);
3649:       /* A triangle */
3650:       coneNew[0] = eStartNew + (cone[0] - eStart)*2 + (ornt[0] < 0 ? 1 : 0);
3651:       orntNew[0] = ornt[0];
3652:       coneNew[1] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 2;
3653:       orntNew[1] = -2;
3654:       coneNew[2] = eStartNew + (cone[2] - eStart)*2 + (ornt[2] < 0 ? 0 : 1);
3655:       orntNew[2] = ornt[2];
3656:       DMPlexSetCone(rdm, newp+0, coneNew);
3657:       DMPlexSetConeOrientation(rdm, newp+0, orntNew);
3658: #if defined(PETSC_USE_DEBUG)
3659:       if ((newp+0 < fStartNew) || (newp+0 >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp+0, fStartNew, fEndNew);
3660:       for (p = 0; p < 3; ++p) {
3661:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", coneNew[p], eStartNew, eEndNew);
3662:       }
3663: #endif
3664:       /* B triangle */
3665:       coneNew[0] = eStartNew + (cone[0] - eStart)*2 + (ornt[0] < 0 ? 0 : 1);
3666:       orntNew[0] = ornt[0];
3667:       coneNew[1] = eStartNew + (cone[1] - eStart)*2 + (ornt[1] < 0 ? 1 : 0);
3668:       orntNew[1] = ornt[1];
3669:       coneNew[2] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 0;
3670:       orntNew[2] = -2;
3671:       DMPlexSetCone(rdm, newp+1, coneNew);
3672:       DMPlexSetConeOrientation(rdm, newp+1, orntNew);
3673: #if defined(PETSC_USE_DEBUG)
3674:       if ((newp+1 < fStartNew) || (newp+1 >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp+1, fStartNew, fEndNew);
3675:       for (p = 0; p < 3; ++p) {
3676:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", coneNew[p], eStartNew, eEndNew);
3677:       }
3678: #endif
3679:       /* C triangle */
3680:       coneNew[0] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 1;
3681:       orntNew[0] = -2;
3682:       coneNew[1] = eStartNew + (cone[1] - eStart)*2 + (ornt[1] < 0 ? 0 : 1);
3683:       orntNew[1] = ornt[1];
3684:       coneNew[2] = eStartNew + (cone[2] - eStart)*2 + (ornt[2] < 0 ? 1 : 0);
3685:       orntNew[2] = ornt[2];
3686:       DMPlexSetCone(rdm, newp+2, coneNew);
3687:       DMPlexSetConeOrientation(rdm, newp+2, orntNew);
3688: #if defined(PETSC_USE_DEBUG)
3689:       if ((newp+2 < fStartNew) || (newp+2 >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp+2, fStartNew, fEndNew);
3690:       for (p = 0; p < 3; ++p) {
3691:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", coneNew[p], eStartNew, eEndNew);
3692:       }
3693: #endif
3694:       /* D triangle */
3695:       coneNew[0] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 0;
3696:       orntNew[0] = 0;
3697:       coneNew[1] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 1;
3698:       orntNew[1] = 0;
3699:       coneNew[2] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 2;
3700:       orntNew[2] = 0;
3701:       DMPlexSetCone(rdm, newp+3, coneNew);
3702:       DMPlexSetConeOrientation(rdm, newp+3, orntNew);
3703: #if defined(PETSC_USE_DEBUG)
3704:       if ((newp+3 < fStartNew) || (newp+3 >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp+3, fStartNew, fEndNew);
3705:       for (p = 0; p < 3; ++p) {
3706:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", coneNew[p], eStartNew, eEndNew);
3707:       }
3708: #endif
3709:       DMPlexGetSupportSize(dm, f, &supportSize);
3710:       DMPlexGetSupport(dm, f, &support);
3711:       for (r = 0; r < 4; ++r) {
3712:         for (s = 0; s < supportSize; ++s) {
3713:           PetscInt subf;
3714:           DMPlexGetConeSize(dm, support[s], &coneSize);
3715:           DMPlexGetCone(dm, support[s], &cone);
3716:           DMPlexGetConeOrientation(dm, support[s], &ornt);
3717:           for (c = 0; c < coneSize; ++c) {
3718:             if (cone[c] == f) break;
3719:           }
3720:           subf = GetTriSubfaceInverse_Static(ornt[c], r);
3721:           supportRef[s] = cStartNew + (support[s] - cStart)*8 + (r==3 ? (c+2)%4 + 4 : faces[c*3+subf]);
3722:         }
3723:         DMPlexSetSupport(rdm, newp+r, supportRef);
3724: #if defined(PETSC_USE_DEBUG)
3725:         if ((newp+r < fStartNew) || (newp+r >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp+r, fStartNew, fEndNew);
3726:         for (p = 0; p < supportSize; ++p) {
3727:           if ((supportRef[p] < cStartNew) || (supportRef[p] >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", supportRef[p], cStartNew, cEndNew);
3728:         }
3729: #endif
3730:       }
3731:     }
3732:     /* Interior faces have 3 edges and 2 cells */
3733:     for (c = cStart; c < cEnd; ++c) {
3734:       PetscInt        newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*8;
3735:       const PetscInt *cone, *ornt;
3736:       PetscInt        coneNew[3], orntNew[3];
3737:       PetscInt        supportNew[2];

3739:       DMPlexGetCone(dm, c, &cone);
3740:       DMPlexGetConeOrientation(dm, c, &ornt);
3741:       /* Face A: {c, a, d} */
3742:       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*3 + GetTriMidEdge_Static(ornt[0], 2);
3743:       orntNew[0] = ornt[0] < 0 ? -2 : 0;
3744:       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*3 + GetTriMidEdge_Static(ornt[1], 2);
3745:       orntNew[1] = ornt[1] < 0 ? -2 : 0;
3746:       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*3 + GetTriMidEdge_Static(ornt[2], 2);
3747:       orntNew[2] = ornt[2] < 0 ? -2 : 0;
3748:       DMPlexSetCone(rdm, newp, coneNew);
3749:       DMPlexSetConeOrientation(rdm, newp, orntNew);
3750: #if defined(PETSC_USE_DEBUG)
3751:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
3752:       for (p = 0; p < 3; ++p) {
3753:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", coneNew[p], eStartNew, eEndNew);
3754:       }
3755: #endif
3756:       supportNew[0] = (c - cStart)*8 + 0;
3757:       supportNew[1] = (c - cStart)*8 + 0+4;
3758:       DMPlexSetSupport(rdm, newp, supportNew);
3759: #if defined(PETSC_USE_DEBUG)
3760:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
3761:       for (p = 0; p < 2; ++p) {
3762:         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", supportNew[p], cStartNew, cEndNew);
3763:       }
3764: #endif
3765:       ++newp;
3766:       /* Face B: {a, b, e} */
3767:       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*3 + GetTriMidEdge_Static(ornt[0], 0);
3768:       orntNew[0] = ornt[0] < 0 ? -2 : 0;
3769:       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*3 + GetTriMidEdge_Static(ornt[3], 0);
3770:       orntNew[1] = ornt[3] < 0 ? -2 : 0;
3771:       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*3 + GetTriMidEdge_Static(ornt[1], 1);
3772:       orntNew[2] = ornt[1] < 0 ? -2 : 0;
3773:       DMPlexSetCone(rdm, newp, coneNew);
3774:       DMPlexSetConeOrientation(rdm, newp, orntNew);
3775: #if defined(PETSC_USE_DEBUG)
3776:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
3777:       for (p = 0; p < 3; ++p) {
3778:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", coneNew[p], eStartNew, eEndNew);
3779:       }
3780: #endif
3781:       supportNew[0] = (c - cStart)*8 + 1;
3782:       supportNew[1] = (c - cStart)*8 + 1+4;
3783:       DMPlexSetSupport(rdm, newp, supportNew);
3784: #if defined(PETSC_USE_DEBUG)
3785:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
3786:       for (p = 0; p < 2; ++p) {
3787:         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", supportNew[p], cStartNew, cEndNew);
3788:       }
3789: #endif
3790:       ++newp;
3791:       /* Face C: {c, f, b} */
3792:       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*3 + GetTriMidEdge_Static(ornt[2], 0);
3793:       orntNew[0] = ornt[2] < 0 ? -2 : 0;
3794:       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*3 + GetTriMidEdge_Static(ornt[3], 2);
3795:       orntNew[1] = ornt[3] < 0 ? -2 : 0;
3796:       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*3 + GetTriMidEdge_Static(ornt[0], 1);
3797:       orntNew[2] = ornt[0] < 0 ? -2 : 0;
3798:       DMPlexSetCone(rdm, newp, coneNew);
3799:       DMPlexSetConeOrientation(rdm, newp, orntNew);
3800: #if defined(PETSC_USE_DEBUG)
3801:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
3802:       for (p = 0; p < 3; ++p) {
3803:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", coneNew[p], eStartNew, eEndNew);
3804:       }
3805: #endif
3806:       supportNew[0] = (c - cStart)*8 + 2;
3807:       supportNew[1] = (c - cStart)*8 + 2+4;
3808:       DMPlexSetSupport(rdm, newp, supportNew);
3809: #if defined(PETSC_USE_DEBUG)
3810:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
3811:       for (p = 0; p < 2; ++p) {
3812:         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", supportNew[p], cStartNew, cEndNew);
3813:       }
3814: #endif
3815:       ++newp;
3816:       /* Face D: {d, e, f} */
3817:       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*3 + GetTriMidEdge_Static(ornt[1], 0);
3818:       orntNew[0] = ornt[1] < 0 ? -2 : 0;
3819:       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*3 + GetTriMidEdge_Static(ornt[3], 1);
3820:       orntNew[1] = ornt[3] < 0 ? -2 : 0;
3821:       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*3 + GetTriMidEdge_Static(ornt[2], 1);
3822:       orntNew[2] = ornt[2] < 0 ? -2 : 0;
3823:       DMPlexSetCone(rdm, newp, coneNew);
3824:       DMPlexSetConeOrientation(rdm, newp, orntNew);
3825: #if defined(PETSC_USE_DEBUG)
3826:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
3827:       for (p = 0; p < 3; ++p) {
3828:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", coneNew[p], eStartNew, eEndNew);
3829:       }
3830: #endif
3831:       supportNew[0] = (c - cStart)*8 + 3;
3832:       supportNew[1] = (c - cStart)*8 + 3+4;
3833:       DMPlexSetSupport(rdm, newp, supportNew);
3834: #if defined(PETSC_USE_DEBUG)
3835:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
3836:       for (p = 0; p < 2; ++p) {
3837:         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", supportNew[p], cStartNew, cEndNew);
3838:       }
3839: #endif
3840:       ++newp;
3841:       /* Face E: {d, f, a} */
3842:       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*3 + GetTriMidEdge_Static(ornt[2], 1);
3843:       orntNew[0] = ornt[2] < 0 ? 0 : -2;
3844:       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart);
3845:       orntNew[1] = -2;
3846:       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*3 + GetTriMidEdge_Static(ornt[1], 2);
3847:       orntNew[2] = ornt[1] < 0 ? -2 : 0;
3848:       DMPlexSetCone(rdm, newp, coneNew);
3849:       DMPlexSetConeOrientation(rdm, newp, orntNew);
3850: #if defined(PETSC_USE_DEBUG)
3851:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
3852:       for (p = 0; p < 3; ++p) {
3853:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", coneNew[p], eStartNew, eEndNew);
3854:       }
3855: #endif
3856:       supportNew[0] = (c - cStart)*8 + 0+4;
3857:       supportNew[1] = (c - cStart)*8 + 3+4;
3858:       DMPlexSetSupport(rdm, newp, supportNew);
3859: #if defined(PETSC_USE_DEBUG)
3860:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
3861:       for (p = 0; p < 2; ++p) {
3862:         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", supportNew[p], cStartNew, cEndNew);
3863:       }
3864: #endif
3865:       ++newp;
3866:       /* Face F: {c, a, f} */
3867:       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*3 + GetTriMidEdge_Static(ornt[0], 2);
3868:       orntNew[0] = ornt[0] < 0 ? -2 : 0;
3869:       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart);
3870:       orntNew[1] = 0;
3871:       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*3 + GetTriMidEdge_Static(ornt[2], 0);
3872:       orntNew[2] = ornt[2] < 0 ? 0 : -2;
3873:       DMPlexSetCone(rdm, newp, coneNew);
3874:       DMPlexSetConeOrientation(rdm, newp, orntNew);
3875: #if defined(PETSC_USE_DEBUG)
3876:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
3877:       for (p = 0; p < 3; ++p) {
3878:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", coneNew[p], eStartNew, eEndNew);
3879:       }
3880: #endif
3881:       supportNew[0] = (c - cStart)*8 + 0+4;
3882:       supportNew[1] = (c - cStart)*8 + 2+4;
3883:       DMPlexSetSupport(rdm, newp, supportNew);
3884: #if defined(PETSC_USE_DEBUG)
3885:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
3886:       for (p = 0; p < 2; ++p) {
3887:         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", supportNew[p], cStartNew, cEndNew);
3888:       }
3889: #endif
3890:       ++newp;
3891:       /* Face G: {e, a, f} */
3892:       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*3 + GetTriMidEdge_Static(ornt[1], 1);
3893:       orntNew[0] = ornt[1] < 0 ? -2 : 0;
3894:       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart);
3895:       orntNew[1] = 0;
3896:       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*3 + GetTriMidEdge_Static(ornt[3], 1);
3897:       orntNew[2] = ornt[3] < 0 ? 0 : -2;
3898:       DMPlexSetCone(rdm, newp, coneNew);
3899:       DMPlexSetConeOrientation(rdm, newp, orntNew);
3900: #if defined(PETSC_USE_DEBUG)
3901:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
3902:       for (p = 0; p < 3; ++p) {
3903:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", coneNew[p], eStartNew, eEndNew);
3904:       }
3905: #endif
3906:       supportNew[0] = (c - cStart)*8 + 1+4;
3907:       supportNew[1] = (c - cStart)*8 + 3+4;
3908:       DMPlexSetSupport(rdm, newp, supportNew);
3909: #if defined(PETSC_USE_DEBUG)
3910:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
3911:       for (p = 0; p < 2; ++p) {
3912:         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", supportNew[p], cStartNew, cEndNew);
3913:       }
3914: #endif
3915:       ++newp;
3916:       /* Face H: {a, b, f} */
3917:       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*3 + GetTriMidEdge_Static(ornt[0], 0);
3918:       orntNew[0] = ornt[0] < 0 ? -2 : 0;
3919:       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*3 + GetTriMidEdge_Static(ornt[3], 2);
3920:       orntNew[1] = ornt[3] < 0 ? 0 : -2;
3921:       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart);
3922:       orntNew[2] = -2;
3923:       DMPlexSetCone(rdm, newp, coneNew);
3924:       DMPlexSetConeOrientation(rdm, newp, orntNew);
3925: #if defined(PETSC_USE_DEBUG)
3926:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
3927:       for (p = 0; p < 3; ++p) {
3928:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", coneNew[p], eStartNew, eEndNew);
3929:       }
3930: #endif
3931:       supportNew[0] = (c - cStart)*8 + 1+4;
3932:       supportNew[1] = (c - cStart)*8 + 2+4;
3933:       DMPlexSetSupport(rdm, newp, supportNew);
3934: #if defined(PETSC_USE_DEBUG)
3935:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
3936:       for (p = 0; p < 2; ++p) {
3937:         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", supportNew[p], cStartNew, cEndNew);
3938:       }
3939: #endif
3940:       ++newp;
3941:     }
3942:     /* Split Edges have 2 vertices and the same faces as the parent */
3943:     for (e = eStart; e < eEnd; ++e) {
3944:       const PetscInt newv = vStartNew + (vEnd - vStart) + (e - eStart);

3946:       for (r = 0; r < 2; ++r) {
3947:         const PetscInt  newp = eStartNew + (e - eStart)*2 + r;
3948:         const PetscInt *cone, *ornt, *support;
3949:         PetscInt        coneNew[2], coneSize, c, supportSize, s;

3951:         DMPlexGetCone(dm, e, &cone);
3952:         coneNew[0]       = vStartNew + (cone[0] - vStart);
3953:         coneNew[1]       = vStartNew + (cone[1] - vStart);
3954:         coneNew[(r+1)%2] = newv;
3955:         DMPlexSetCone(rdm, newp, coneNew);
3956: #if defined(PETSC_USE_DEBUG)
3957:         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eEndNew);
3958:         for (p = 0; p < 2; ++p) {
3959:           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", coneNew[p], vStartNew, vEndNew);
3960:         }
3961: #endif
3962:         DMPlexGetSupportSize(dm, e, &supportSize);
3963:         DMPlexGetSupport(dm, e, &support);
3964:         for (s = 0; s < supportSize; ++s) {
3965:           DMPlexGetConeSize(dm, support[s], &coneSize);
3966:           DMPlexGetCone(dm, support[s], &cone);
3967:           DMPlexGetConeOrientation(dm, support[s], &ornt);
3968:           for (c = 0; c < coneSize; ++c) {
3969:             if (cone[c] == e) break;
3970:           }
3971:           supportRef[s] = fStartNew + (support[s] - fStart)*4 + (c + (ornt[c] < 0 ? 1-r : r))%3;
3972:         }
3973:         DMPlexSetSupport(rdm, newp, supportRef);
3974: #if defined(PETSC_USE_DEBUG)
3975:         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eEndNew);
3976:         for (p = 0; p < supportSize; ++p) {
3977:           if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", supportRef[p], fStartNew, fEndNew);
3978:         }
3979: #endif
3980:       }
3981:     }
3982:     /* Face edges have 2 vertices and 2+cells*(1/2) faces */
3983:     for (f = fStart; f < fEnd; ++f) {
3984:       const PetscInt *cone, *ornt, *support;
3985:       PetscInt        coneSize, supportSize, s;

3987:       DMPlexGetSupportSize(dm, f, &supportSize);
3988:       DMPlexGetSupport(dm, f, &support);
3989:       for (r = 0; r < 3; ++r) {
3990:         const PetscInt  newp = eStartNew + (eEnd - eStart)*2 + (f - fStart)*3 + r;
3991:         PetscInt        coneNew[2], intFaces = 0, er, eint[4] = {1, 0, 2, 0};
3992:         PetscInt        fint[24] = { 1,  7, -1, -1,  0,  5,
3993:                                     -1, -1,  1,  6,  0,  4,
3994:                                      2,  5,  3,  4, -1, -1,
3995:                                     -1, -1,  3,  6,  2,  7};

3997:         DMPlexGetCone(dm, f, &cone);
3998:         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[(r+0)%3] - eStart);
3999:         coneNew[1] = vStartNew + (vEnd - vStart) + (cone[(r+1)%3] - eStart);
4000:         DMPlexSetCone(rdm, newp, coneNew);
4001: #if defined(PETSC_USE_DEBUG)
4002:         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eEndNew);
4003:         for (p = 0; p < 2; ++p) {
4004:           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", coneNew[p], vStartNew, vEndNew);
4005:         }
4006: #endif
4007:         supportRef[0] = fStartNew + (f - fStart)*4 + (r+1)%3;
4008:         supportRef[1] = fStartNew + (f - fStart)*4 + 3;
4009:         for (s = 0; s < supportSize; ++s) {
4010:           DMPlexGetConeSize(dm, support[s], &coneSize);
4011:           DMPlexGetCone(dm, support[s], &cone);
4012:           DMPlexGetConeOrientation(dm, support[s], &ornt);
4013:           for (c = 0; c < coneSize; ++c) {if (cone[c] == f) break;}
4014:           /* Here we want to determine whether edge newp contains a vertex which is part of the cross-tet edge */
4015:           er = GetTriMidEdgeInverse_Static(ornt[c], r);
4016:           if (er == eint[c]) {
4017:             supportRef[2+intFaces++] = fStartNew + (fEnd - fStart)*4 + (support[s] - cStart)*8 + (c + 2)%4;
4018:           } else {
4019:             supportRef[2+intFaces++] = fStartNew + (fEnd - fStart)*4 + (support[s] - cStart)*8 + fint[(c*3 + er)*2 + 0];
4020:             supportRef[2+intFaces++] = fStartNew + (fEnd - fStart)*4 + (support[s] - cStart)*8 + fint[(c*3 + er)*2 + 1];
4021:           }
4022:         }
4023:         DMPlexSetSupport(rdm, newp, supportRef);
4024: #if defined(PETSC_USE_DEBUG)
4025:         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eEndNew);
4026:         for (p = 0; p < intFaces; ++p) {
4027:           if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", supportRef[p], fStartNew, fEndNew);
4028:         }
4029: #endif
4030:       }
4031:     }
4032:     /* Interior edges have 2 vertices and 4 faces */
4033:     for (c = cStart; c < cEnd; ++c) {
4034:       const PetscInt  newp = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart);
4035:       const PetscInt *cone, *ornt, *fcone;
4036:       PetscInt        coneNew[2], supportNew[4], find;

4038:       DMPlexGetCone(dm, c, &cone);
4039:       DMPlexGetConeOrientation(dm, c, &ornt);
4040:       DMPlexGetCone(dm, cone[0], &fcone);
4041:       find = GetTriEdge_Static(ornt[0], 0);
4042:       coneNew[0] = vStartNew + (vEnd - vStart) + (fcone[find] - eStart);
4043:       DMPlexGetCone(dm, cone[2], &fcone);
4044:       find = GetTriEdge_Static(ornt[2], 1);
4045:       coneNew[1] = vStartNew + (vEnd - vStart) + (fcone[find] - eStart);
4046:       DMPlexSetCone(rdm, newp, coneNew);
4047: #if defined(PETSC_USE_DEBUG)
4048:       if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eEndNew);
4049:       for (p = 0; p < 2; ++p) {
4050:         if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", coneNew[p], vStartNew, vEndNew);
4051:       }
4052: #endif
4053:       supportNew[0] = fStartNew + (fEnd - fStart)*4 + (c - cStart)*8 + 4;
4054:       supportNew[1] = fStartNew + (fEnd - fStart)*4 + (c - cStart)*8 + 5;
4055:       supportNew[2] = fStartNew + (fEnd - fStart)*4 + (c - cStart)*8 + 6;
4056:       supportNew[3] = fStartNew + (fEnd - fStart)*4 + (c - cStart)*8 + 7;
4057:       DMPlexSetSupport(rdm, newp, supportNew);
4058: #if defined(PETSC_USE_DEBUG)
4059:       if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eEndNew);
4060:       for (p = 0; p < 4; ++p) {
4061:         if ((supportNew[p] < fStartNew) || (supportNew[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", supportNew[p], fStartNew, fEndNew);
4062:       }
4063: #endif
4064:     }
4065:     /* Old vertices have identical supports */
4066:     for (v = vStart; v < vEnd; ++v) {
4067:       const PetscInt  newp = vStartNew + (v - vStart);
4068:       const PetscInt *support, *cone;
4069:       PetscInt        size, s;

4071:       DMPlexGetSupportSize(dm, v, &size);
4072:       DMPlexGetSupport(dm, v, &support);
4073:       for (s = 0; s < size; ++s) {
4074:         PetscInt r = 0;

4076:         DMPlexGetCone(dm, support[s], &cone);
4077:         if (cone[1] == v) r = 1;
4078:         supportRef[s] = eStartNew + (support[s] - eStart)*2 + r;
4079:       }
4080:       DMPlexSetSupport(rdm, newp, supportRef);
4081: #if defined(PETSC_USE_DEBUG)
4082:       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", newp, vStartNew, vEndNew);
4083:       for (p = 0; p < size; ++p) {
4084:         if ((supportRef[p] < eStartNew) || (supportRef[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", supportRef[p], eStartNew, eEndNew);
4085:       }
4086: #endif
4087:     }
4088:     /* Edge vertices have 2 + face*2 + 0/1 supports */
4089:     for (e = eStart; e < eEnd; ++e) {
4090:       const PetscInt  newp = vStartNew + (vEnd - vStart) + (e - eStart);
4091:       const PetscInt *cone, *support;
4092:       PetscInt       *star = NULL, starSize, cellSize = 0, coneSize, size, s;

4094:       DMPlexGetSupportSize(dm, e, &size);
4095:       DMPlexGetSupport(dm, e, &support);
4096:       supportRef[0] = eStartNew + (e - eStart)*2 + 0;
4097:       supportRef[1] = eStartNew + (e - eStart)*2 + 1;
4098:       for (s = 0; s < size; ++s) {
4099:         PetscInt r = 0;

4101:         DMPlexGetConeSize(dm, support[s], &coneSize);
4102:         DMPlexGetCone(dm, support[s], &cone);
4103:         for (r = 0; r < coneSize; ++r) {if (cone[r] == e) break;}
4104:         supportRef[2+s*2+0] = eStartNew + (eEnd - eStart)*2 + (support[s] - fStart)*3 + (r+0)%3;
4105:         supportRef[2+s*2+1] = eStartNew + (eEnd - eStart)*2 + (support[s] - fStart)*3 + (r+2)%3;
4106:       }
4107:       DMPlexGetTransitiveClosure(dm, e, PETSC_FALSE, &starSize, &star);
4108:       for (s = 0; s < starSize*2; s += 2) {
4109:         const PetscInt *cone, *ornt;
4110:         PetscInt        e01, e23;

4112:         if ((star[s] >= cStart) && (star[s] < cEnd)) {
4113:           /* Check edge 0-1 */
4114:           DMPlexGetCone(dm, star[s], &cone);
4115:           DMPlexGetConeOrientation(dm, star[s], &ornt);
4116:           DMPlexGetCone(dm, cone[0], &cone);
4117:           e01  = cone[GetTriEdge_Static(ornt[0], 0)];
4118:           /* Check edge 2-3 */
4119:           DMPlexGetCone(dm, star[s], &cone);
4120:           DMPlexGetConeOrientation(dm, star[s], &ornt);
4121:           DMPlexGetCone(dm, cone[2], &cone);
4122:           e23  = cone[GetTriEdge_Static(ornt[2], 1)];
4123:           if ((e01 == e) || (e23 == e)) {supportRef[2+size*2+cellSize++] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (star[s] - cStart);}
4124:         }
4125:       }
4126:       DMPlexRestoreTransitiveClosure(dm, e, PETSC_FALSE, &starSize, &star);
4127:       DMPlexSetSupport(rdm, newp, supportRef);
4128: #if defined(PETSC_USE_DEBUG)
4129:       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", newp, vStartNew, vEndNew);
4130:       for (p = 0; p < 2+size*2+cellSize; ++p) {
4131:         if ((supportRef[p] < eStartNew) || (supportRef[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", supportRef[p], eStartNew, eEndNew);
4132:       }
4133: #endif
4134:     }
4135:     PetscFree(supportRef);
4136:     DMPlexRestoreFaces_Internal(dm, 3, cStart, NULL, NULL, &faces);
4137:     break;
4138:   case REFINER_HYBRID_SIMPLEX_3D:
4139:     DMPlexGetHybridBounds(rdm, &cMaxNew, &fMaxNew, &eMaxNew, NULL);
4140:     /* Interior cells have 4 faces: Tet face order is prescribed in DMPlexGetFaces_Internal() */
4141:     DMPlexGetRawFaces_Internal(dm, 3, 4, cellInd, NULL, NULL, &faces);
4142:     for (c = cStart; c < cMax; ++c) {
4143:       const PetscInt  newp = cStartNew + (c - cStart)*8;
4144:       const PetscInt *cone, *ornt;
4145:       PetscInt        coneNew[4], orntNew[4];

4147:       DMPlexGetCone(dm, c, &cone);
4148:       DMPlexGetConeOrientation(dm, c, &ornt);
4149:       /* A tetrahedron: {0, a, c, d} */
4150:       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetTriSubface_Static(ornt[0], 0); /* A */
4151:       orntNew[0] = ornt[0];
4152:       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetTriSubface_Static(ornt[1], 0); /* A */
4153:       orntNew[1] = ornt[1];
4154:       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetTriSubface_Static(ornt[2], 0); /* A */
4155:       orntNew[2] = ornt[2];
4156:       coneNew[3] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 0;
4157:       orntNew[3] = 0;
4158:       DMPlexSetCone(rdm, newp+0, coneNew);
4159:       DMPlexSetConeOrientation(rdm, newp+0, orntNew);
4160: #if defined(PETSC_USE_DEBUG)
4161:       if ((newp+0 < cStartNew) || (newp+0 >= cMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", newp+0, cStartNew, cMaxNew);
4162:       for (p = 0; p < 4; ++p) {
4163:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", coneNew[p], fStartNew, fMaxNew);
4164:       }
4165: #endif
4166:       /* B tetrahedron: {a, 1, b, e} */
4167:       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetTriSubface_Static(ornt[0], 1); /* B */
4168:       orntNew[0] = ornt[0];
4169:       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetTriSubface_Static(ornt[1], 2); /* C */
4170:       orntNew[1] = ornt[1];
4171:       coneNew[2] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 1;
4172:       orntNew[2] = 0;
4173:       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetTriSubface_Static(ornt[3], 1); /* B */
4174:       orntNew[3] = ornt[3];
4175:       DMPlexSetCone(rdm, newp+1, coneNew);
4176:       DMPlexSetConeOrientation(rdm, newp+1, orntNew);
4177: #if defined(PETSC_USE_DEBUG)
4178:       if ((newp+1 < cStartNew) || (newp+1 >= cMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", newp+1, cStartNew, cMaxNew);
4179:       for (p = 0; p < 4; ++p) {
4180:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", coneNew[p], fStartNew, fMaxNew);
4181:       }
4182: #endif
4183:       /* C tetrahedron: {c, b, 2, f} */
4184:       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetTriSubface_Static(ornt[0], 2); /* C */
4185:       orntNew[0] = ornt[0];
4186:       coneNew[1] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 2;
4187:       orntNew[1] = 0;
4188:       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetTriSubface_Static(ornt[2], 1); /* B */
4189:       orntNew[2] = ornt[2];
4190:       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetTriSubface_Static(ornt[3], 0); /* A */
4191:       orntNew[3] = ornt[3];
4192:       DMPlexSetCone(rdm, newp+2, coneNew);
4193:       DMPlexSetConeOrientation(rdm, newp+2, orntNew);
4194: #if defined(PETSC_USE_DEBUG)
4195:       if ((newp+2 < cStartNew) || (newp+2 >= cMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", newp+2, cStartNew, cMaxNew);
4196:       for (p = 0; p < 4; ++p) {
4197:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", coneNew[p], fStartNew, fMaxNew);
4198:       }
4199: #endif
4200:       /* D tetrahedron: {d, e, f, 3} */
4201:       coneNew[0] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 3;
4202:       orntNew[0] = 0;
4203:       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetTriSubface_Static(ornt[1], 1); /* B */
4204:       orntNew[1] = ornt[1];
4205:       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetTriSubface_Static(ornt[2], 2); /* C */
4206:       orntNew[2] = ornt[2];
4207:       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetTriSubface_Static(ornt[3], 2); /* C */
4208:       orntNew[3] = ornt[3];
4209:       DMPlexSetCone(rdm, newp+3, coneNew);
4210:       DMPlexSetConeOrientation(rdm, newp+3, orntNew);
4211: #if defined(PETSC_USE_DEBUG)
4212:       if ((newp+3 < cStartNew) || (newp+3 >= cMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", newp+3, cStartNew, cMaxNew);
4213:       for (p = 0; p < 4; ++p) {
4214:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", coneNew[p], fStartNew, fMaxNew);
4215:       }
4216: #endif
4217:       /* A' tetrahedron: {d, a, c, f} */
4218:       coneNew[0] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 0;
4219:       orntNew[0] = -3;
4220:       coneNew[1] = fStartNew + (cone[2] - fStart)*4 + 3;
4221:       orntNew[1] = ornt[2] < 0 ? -(GetTriMidEdge_Static(ornt[2], 0)+1) : GetTriMidEdge_Static(ornt[2], 0);
4222:       coneNew[2] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 5;
4223:       orntNew[2] = 0;
4224:       coneNew[3] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 4;
4225:       orntNew[3] = 2;
4226:       DMPlexSetCone(rdm, newp+4, coneNew);
4227:       DMPlexSetConeOrientation(rdm, newp+4, orntNew);
4228: #if defined(PETSC_USE_DEBUG)
4229:       if ((newp+4 < cStartNew) || (newp+4 >= cMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", newp+4, cStartNew, cMaxNew);
4230:       for (p = 0; p < 4; ++p) {
4231:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", coneNew[p], fStartNew, fMaxNew);
4232:       }
4233: #endif
4234:       /* B' tetrahedron: {e, b, a, f} */
4235:       coneNew[0] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 1;
4236:       orntNew[0] = -3;
4237:       coneNew[1] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 6;
4238:       orntNew[1] = 1;
4239:       coneNew[2] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 7;
4240:       orntNew[2] = 0;
4241:       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + 3;
4242:       orntNew[3] = ornt[3] < 0 ? -(GetTriMidEdge_Static(ornt[3], 0)+1) : GetTriMidEdge_Static(ornt[3], 0);
4243:       DMPlexSetCone(rdm, newp+5, coneNew);
4244:       DMPlexSetConeOrientation(rdm, newp+5, orntNew);
4245: #if defined(PETSC_USE_DEBUG)
4246:       if ((newp+5 < cStartNew) || (newp+5 >= cMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", newp+5, cStartNew, cMaxNew);
4247:       for (p = 0; p < 4; ++p) {
4248:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", coneNew[p], fStartNew, fMaxNew);
4249:       }
4250: #endif
4251:       /* C' tetrahedron: {b, f, c, a} */
4252:       coneNew[0] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 2;
4253:       orntNew[0] = -3;
4254:       coneNew[1] = fStartNew + (cone[0] - fStart)*4 + 3;
4255:       orntNew[1] = ornt[0] < 0 ? -(GetTriMidEdge_Static(ornt[0], 2)+1) : GetTriMidEdge_Static(ornt[0], 2);
4256:       coneNew[2] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 5;
4257:       orntNew[2] = -3;
4258:       coneNew[3] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 7;
4259:       orntNew[3] = -2;
4260:       DMPlexSetCone(rdm, newp+6, coneNew);
4261:       DMPlexSetConeOrientation(rdm, newp+6, orntNew);
4262: #if defined(PETSC_USE_DEBUG)
4263:       if ((newp+6 < cStartNew) || (newp+6 >= cMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", newp+6, cStartNew, cMaxNew);
4264:       for (p = 0; p < 4; ++p) {
4265:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", coneNew[p], fStartNew, fMaxNew);
4266:       }
4267: #endif
4268:       /* D' tetrahedron: {f, e, d, a} */
4269:       coneNew[0] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 3;
4270:       orntNew[0] = -3;
4271:       coneNew[1] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 4;
4272:       orntNew[1] = -3;
4273:       coneNew[2] = fStartNew + (cone[1] - fStart)*4 + 3;
4274:       orntNew[2] = ornt[1] < 0 ? -(GetTriMidEdge_Static(ornt[1], 0)+1) : GetTriMidEdge_Static(ornt[1], 0);
4275:       coneNew[3] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 6;
4276:       orntNew[3] = -3;
4277:       DMPlexSetCone(rdm, newp+7, coneNew);
4278:       DMPlexSetConeOrientation(rdm, newp+7, orntNew);
4279: #if defined(PETSC_USE_DEBUG)
4280:       if ((newp+7 < cStartNew) || (newp+7 >= cMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", newp+7, cStartNew, cMaxNew);
4281:       for (p = 0; p < 4; ++p) {
4282:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", coneNew[p], fStartNew, fMaxNew);
4283:       }
4284: #endif
4285:     }
4286:     /* Hybrid cells have 5 faces */
4287:     for (c = cMax; c < cEnd; ++c) {
4288:       const PetscInt  newp = cStartNew + (cMax - cStart)*8 + (c - cMax)*4;
4289:       const PetscInt *cone, *ornt, *fornt;
4290:       PetscInt        coneNew[5], orntNew[5], o, of, i;

4292:       DMPlexGetCone(dm, c, &cone);
4293:       DMPlexGetConeOrientation(dm, c, &ornt);
4294:       DMPlexGetConeOrientation(dm, cone[0], &fornt);
4295:       o = ornt[0] < 0 ? -1 : 1;
4296:       for (r = 0; r < 3; ++r) {
4297:         coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetTriSubface_Static(ornt[0], r);
4298:         orntNew[0] = ornt[0];
4299:         coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetTriSubface_Static(ornt[1], r);
4300:         orntNew[1] = ornt[1];
4301:         of = fornt[GetTriEdge_Static(ornt[0], r)]       < 0 ? -1 : 1;
4302:         i  = GetTriEdgeInverse_Static(ornt[0], r)       + 2;
4303:         coneNew[i] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (cone[2+GetTriEdge_Static(ornt[0], r)]       - fMax)*2 + (o*of < 0 ? 1 : 0);
4304:         orntNew[i] = 0;
4305:         i  = GetTriEdgeInverse_Static(ornt[0], (r+1)%3) + 2;
4306:         coneNew[i] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (c - cMax)*3 + GetTriSubface_Static(ornt[0], r);
4307:         orntNew[i] = 0;
4308:         of = fornt[GetTriEdge_Static(ornt[0], (r+2)%3)] < 0 ? -1 : 1;
4309:         i  = GetTriEdgeInverse_Static(ornt[0], (r+2)%3) + 2;
4310:         coneNew[i] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (cone[2+GetTriEdge_Static(ornt[0], (r+2)%3)] - fMax)*2 + (o*of < 0 ? 0 : 1);
4311:         orntNew[i] = 0;
4312:         DMPlexSetCone(rdm, newp+r, coneNew);
4313:         DMPlexSetConeOrientation(rdm, newp+r, orntNew);
4314: #if defined(PETSC_USE_DEBUG)
4315:         if ((newp+r < cMaxNew) || (newp+r >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a hybrid cell [%D, %D)", newp+r, cMaxNew, cEndNew);
4316:         for (p = 0; p < 2; ++p) {
4317:           if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", coneNew[p], fStartNew, fMaxNew);
4318:         }
4319:         for (p = 2; p < 5; ++p) {
4320:           if ((coneNew[p] < fMaxNew)   || (coneNew[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a hybrid face [%D, %D)", coneNew[p], fMaxNew, fEndNew);
4321:         }
4322: #endif
4323:       }
4324:       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + 3;
4325:       orntNew[0] = 0;
4326:       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + 3;
4327:       orntNew[1] = 0;
4328:       coneNew[2] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (c - cMax)*3 + 1;
4329:       orntNew[2] = 0;
4330:       coneNew[3] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (c - cMax)*3 + 2;
4331:       orntNew[3] = 0;
4332:       coneNew[4] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (c - cMax)*3 + 0;
4333:       orntNew[4] = 0;
4334:       DMPlexSetCone(rdm, newp+3, coneNew);
4335:       DMPlexSetConeOrientation(rdm, newp+3, orntNew);
4336: #if defined(PETSC_USE_DEBUG)
4337:       if ((newp+3 < cMaxNew) || (newp+3 >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a hybrid cell [%D, %D)", newp+3, cMaxNew, cEndNew);
4338:       for (p = 0; p < 2; ++p) {
4339:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", coneNew[p], fStartNew, fMaxNew);
4340:       }
4341:       for (p = 2; p < 5; ++p) {
4342:         if ((coneNew[p] < fMaxNew)   || (coneNew[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a hybrid face [%D, %D)", coneNew[p], fMaxNew, fEndNew);
4343:       }
4344: #endif
4345:     }
4346:     /* Split faces have 3 edges and the same cells as the parent */
4347:     DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);
4348:     PetscMalloc1(2 + maxSupportSize*2, &supportRef);
4349:     for (f = fStart; f < fMax; ++f) {
4350:       const PetscInt  newp = fStartNew + (f - fStart)*4;
4351:       const PetscInt *cone, *ornt, *support;
4352:       PetscInt        coneNew[3], orntNew[3], coneSize, supportSize, s;

4354:       DMPlexGetCone(dm, f, &cone);
4355:       DMPlexGetConeOrientation(dm, f, &ornt);
4356:       /* A triangle */
4357:       coneNew[0] = eStartNew + (cone[0] - eStart)*2 + (ornt[0] < 0 ? 1 : 0);
4358:       orntNew[0] = ornt[0];
4359:       coneNew[1] = eStartNew + (eMax    - eStart)*2 + (f - fStart)*3 + 2;
4360:       orntNew[1] = -2;
4361:       coneNew[2] = eStartNew + (cone[2] - eStart)*2 + (ornt[2] < 0 ? 0 : 1);
4362:       orntNew[2] = ornt[2];
4363:       DMPlexSetCone(rdm, newp+0, coneNew);
4364:       DMPlexSetConeOrientation(rdm, newp+0, orntNew);
4365: #if defined(PETSC_USE_DEBUG)
4366:       if ((newp+0 < fStartNew) || (newp+0 >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp+0, fStartNew, fMaxNew);
4367:       for (p = 0; p < 3; ++p) {
4368:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", coneNew[p], eStartNew, eMaxNew);
4369:       }
4370: #endif
4371:       /* B triangle */
4372:       coneNew[0] = eStartNew + (cone[0] - eStart)*2 + (ornt[0] < 0 ? 0 : 1);
4373:       orntNew[0] = ornt[0];
4374:       coneNew[1] = eStartNew + (cone[1] - eStart)*2 + (ornt[1] < 0 ? 1 : 0);
4375:       orntNew[1] = ornt[1];
4376:       coneNew[2] = eStartNew + (eMax    - eStart)*2 + (f - fStart)*3 + 0;
4377:       orntNew[2] = -2;
4378:       DMPlexSetCone(rdm, newp+1, coneNew);
4379:       DMPlexSetConeOrientation(rdm, newp+1, orntNew);
4380: #if defined(PETSC_USE_DEBUG)
4381:       if ((newp+1 < fStartNew) || (newp+1 >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp+1, fStartNew, fMaxNew);
4382:       for (p = 0; p < 3; ++p) {
4383:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", coneNew[p], eStartNew, eMaxNew);
4384:       }
4385: #endif
4386:       /* C triangle */
4387:       coneNew[0] = eStartNew + (eMax    - eStart)*2 + (f - fStart)*3 + 1;
4388:       orntNew[0] = -2;
4389:       coneNew[1] = eStartNew + (cone[1] - eStart)*2 + (ornt[1] < 0 ? 0 : 1);
4390:       orntNew[1] = ornt[1];
4391:       coneNew[2] = eStartNew + (cone[2] - eStart)*2 + (ornt[2] < 0 ? 1 : 0);
4392:       orntNew[2] = ornt[2];
4393:       DMPlexSetCone(rdm, newp+2, coneNew);
4394:       DMPlexSetConeOrientation(rdm, newp+2, orntNew);
4395: #if defined(PETSC_USE_DEBUG)
4396:       if ((newp+2 < fStartNew) || (newp+2 >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp+2, fStartNew, fMaxNew);
4397:       for (p = 0; p < 3; ++p) {
4398:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", coneNew[p], eStartNew, eMaxNew);
4399:       }
4400: #endif
4401:       /* D triangle */
4402:       coneNew[0] = eStartNew + (eMax    - eStart)*2 + (f - fStart)*3 + 0;
4403:       orntNew[0] = 0;
4404:       coneNew[1] = eStartNew + (eMax    - eStart)*2 + (f - fStart)*3 + 1;
4405:       orntNew[1] = 0;
4406:       coneNew[2] = eStartNew + (eMax    - eStart)*2 + (f - fStart)*3 + 2;
4407:       orntNew[2] = 0;
4408:       DMPlexSetCone(rdm, newp+3, coneNew);
4409:       DMPlexSetConeOrientation(rdm, newp+3, orntNew);
4410: #if defined(PETSC_USE_DEBUG)
4411:       if ((newp+3 < fStartNew) || (newp+3 >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp+3, fStartNew, fMaxNew);
4412:       for (p = 0; p < 3; ++p) {
4413:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", coneNew[p], eStartNew, eMaxNew);
4414:       }
4415: #endif
4416:       DMPlexGetSupportSize(dm, f, &supportSize);
4417:       DMPlexGetSupport(dm, f, &support);
4418:       for (r = 0; r < 4; ++r) {
4419:         for (s = 0; s < supportSize; ++s) {
4420:           PetscInt subf;
4421:           DMPlexGetConeSize(dm, support[s], &coneSize);
4422:           DMPlexGetCone(dm, support[s], &cone);
4423:           DMPlexGetConeOrientation(dm, support[s], &ornt);
4424:           for (c = 0; c < coneSize; ++c) {
4425:             if (cone[c] == f) break;
4426:           }
4427:           subf = GetTriSubfaceInverse_Static(ornt[c], r);
4428:           if (support[s] < cMax) {
4429:             supportRef[s] = cStartNew + (support[s] - cStart)*8 + (r==3 ? (c+2)%4 + 4 : faces[c*3+subf]);
4430:           } else {
4431:             supportRef[s] = cStartNew + (cMax - cStart)*8 + (support[s] - cMax)*4 + (r==3 ? r : subf);
4432:           }
4433:         }
4434:         DMPlexSetSupport(rdm, newp+r, supportRef);
4435: #if defined(PETSC_USE_DEBUG)
4436:         if ((newp+r < fStartNew) || (newp+r >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp+r, fStartNew, fMaxNew);
4437:         for (p = 0; p < supportSize; ++p) {
4438:           if ((supportRef[p] < cStartNew) || (supportRef[p] >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an interior or hybrid cell [%D, %D)", supportRef[p], cStartNew, cEndNew);
4439:         }
4440: #endif
4441:       }
4442:     }
4443:     /* Interior cell faces have 3 edges and 2 cells */
4444:     for (c = cStart; c < cMax; ++c) {
4445:       PetscInt        newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*8;
4446:       const PetscInt *cone, *ornt;
4447:       PetscInt        coneNew[3], orntNew[3];
4448:       PetscInt        supportNew[2];

4450:       DMPlexGetCone(dm, c, &cone);
4451:       DMPlexGetConeOrientation(dm, c, &ornt);
4452:       /* Face A: {c, a, d} */
4453:       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*3 + GetTriMidEdge_Static(ornt[0], 2);
4454:       orntNew[0] = ornt[0] < 0 ? -2 : 0;
4455:       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*3 + GetTriMidEdge_Static(ornt[1], 2);
4456:       orntNew[1] = ornt[1] < 0 ? -2 : 0;
4457:       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*3 + GetTriMidEdge_Static(ornt[2], 2);
4458:       orntNew[2] = ornt[2] < 0 ? -2 : 0;
4459:       DMPlexSetCone(rdm, newp, coneNew);
4460:       DMPlexSetConeOrientation(rdm, newp, orntNew);
4461: #if defined(PETSC_USE_DEBUG)
4462:       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fMaxNew);
4463:       for (p = 0; p < 3; ++p) {
4464:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", coneNew[p], eStartNew, eMaxNew);
4465:       }
4466: #endif
4467:       supportNew[0] = (c - cStart)*8 + 0;
4468:       supportNew[1] = (c - cStart)*8 + 0+4;
4469:       DMPlexSetSupport(rdm, newp, supportNew);
4470: #if defined(PETSC_USE_DEBUG)
4471:       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fMaxNew);
4472:       for (p = 0; p < 2; ++p) {
4473:         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", supportNew[p], cStartNew, cMaxNew);
4474:       }
4475: #endif
4476:       ++newp;
4477:       /* Face B: {a, b, e} */
4478:       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*3 + GetTriMidEdge_Static(ornt[0], 0);
4479:       orntNew[0] = ornt[0] < 0 ? -2 : 0;
4480:       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*3 + GetTriMidEdge_Static(ornt[3], 0);
4481:       orntNew[1] = ornt[3] < 0 ? -2 : 0;
4482:       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*3 + GetTriMidEdge_Static(ornt[1], 1);
4483:       orntNew[2] = ornt[1] < 0 ? -2 : 0;
4484:       DMPlexSetCone(rdm, newp, coneNew);
4485:       DMPlexSetConeOrientation(rdm, newp, orntNew);
4486: #if defined(PETSC_USE_DEBUG)
4487:       if ((newp+1 < fStartNew) || (newp+1 >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp+1, fStartNew, fMaxNew);
4488:       for (p = 0; p < 3; ++p) {
4489:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", coneNew[p], eStartNew, eMaxNew);
4490:       }
4491: #endif
4492:       supportNew[0] = (c - cStart)*8 + 1;
4493:       supportNew[1] = (c - cStart)*8 + 1+4;
4494:       DMPlexSetSupport(rdm, newp, supportNew);
4495: #if defined(PETSC_USE_DEBUG)
4496:       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fMaxNew);
4497:       for (p = 0; p < 2; ++p) {
4498:         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", supportNew[p], cStartNew, cMaxNew);
4499:       }
4500: #endif
4501:       ++newp;
4502:       /* Face C: {c, f, b} */
4503:       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*3 + GetTriMidEdge_Static(ornt[2], 0);
4504:       orntNew[0] = ornt[2] < 0 ? -2 : 0;
4505:       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*3 + GetTriMidEdge_Static(ornt[3], 2);
4506:       orntNew[1] = ornt[3] < 0 ? -2 : 0;
4507:       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*3 + GetTriMidEdge_Static(ornt[0], 1);
4508:       orntNew[2] = ornt[0] < 0 ? -2 : 0;
4509:       DMPlexSetCone(rdm, newp, coneNew);
4510:       DMPlexSetConeOrientation(rdm, newp, orntNew);
4511: #if defined(PETSC_USE_DEBUG)
4512:       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fMaxNew);
4513:       for (p = 0; p < 3; ++p) {
4514:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", coneNew[p], eStartNew, eMaxNew);
4515:       }
4516: #endif
4517:       supportNew[0] = (c - cStart)*8 + 2;
4518:       supportNew[1] = (c - cStart)*8 + 2+4;
4519:       DMPlexSetSupport(rdm, newp, supportNew);
4520: #if defined(PETSC_USE_DEBUG)
4521:       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fMaxNew);
4522:       for (p = 0; p < 2; ++p) {
4523:         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", supportNew[p], cStartNew, cMaxNew);
4524:       }
4525: #endif
4526:       ++newp;
4527:       /* Face D: {d, e, f} */
4528:       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*3 + GetTriMidEdge_Static(ornt[1], 0);
4529:       orntNew[0] = ornt[1] < 0 ? -2 : 0;
4530:       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*3 + GetTriMidEdge_Static(ornt[3], 1);
4531:       orntNew[1] = ornt[3] < 0 ? -2 : 0;
4532:       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*3 + GetTriMidEdge_Static(ornt[2], 1);
4533:       orntNew[2] = ornt[2] < 0 ? -2 : 0;
4534:       DMPlexSetCone(rdm, newp, coneNew);
4535:       DMPlexSetConeOrientation(rdm, newp, orntNew);
4536: #if defined(PETSC_USE_DEBUG)
4537:       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fMaxNew);
4538:       for (p = 0; p < 3; ++p) {
4539:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", coneNew[p], eStartNew, eMaxNew);
4540:       }
4541: #endif
4542:       supportNew[0] = (c - cStart)*8 + 3;
4543:       supportNew[1] = (c - cStart)*8 + 3+4;
4544:       DMPlexSetSupport(rdm, newp, supportNew);
4545: #if defined(PETSC_USE_DEBUG)
4546:       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fMaxNew);
4547:       for (p = 0; p < 2; ++p) {
4548:         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", supportNew[p], cStartNew, cMaxNew);
4549:       }
4550: #endif
4551:       ++newp;
4552:       /* Face E: {d, f, a} */
4553:       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*3 + GetTriMidEdge_Static(ornt[2], 1);
4554:       orntNew[0] = ornt[2] < 0 ? 0 : -2;
4555:       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart);
4556:       orntNew[1] = -2;
4557:       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*3 + GetTriMidEdge_Static(ornt[1], 2);
4558:       orntNew[2] = ornt[1] < 0 ? -2 : 0;
4559:       DMPlexSetCone(rdm, newp, coneNew);
4560:       DMPlexSetConeOrientation(rdm, newp, orntNew);
4561: #if defined(PETSC_USE_DEBUG)
4562:       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fMaxNew);
4563:       for (p = 0; p < 3; ++p) {
4564:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", coneNew[p], eStartNew, eMaxNew);
4565:       }
4566: #endif
4567:       supportNew[0] = (c - cStart)*8 + 0+4;
4568:       supportNew[1] = (c - cStart)*8 + 3+4;
4569:       DMPlexSetSupport(rdm, newp, supportNew);
4570: #if defined(PETSC_USE_DEBUG)
4571:       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fMaxNew);
4572:       for (p = 0; p < 2; ++p) {
4573:         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", supportNew[p], cStartNew, cMaxNew);
4574:       }
4575: #endif
4576:       ++newp;
4577:       /* Face F: {c, a, f} */
4578:       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*3 + GetTriMidEdge_Static(ornt[0], 2);
4579:       orntNew[0] = ornt[0] < 0 ? -2 : 0;
4580:       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart);
4581:       orntNew[1] = 0;
4582:       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*3 + GetTriMidEdge_Static(ornt[2], 0);
4583:       orntNew[2] = ornt[2] < 0 ? 0 : -2;
4584:       DMPlexSetCone(rdm, newp, coneNew);
4585:       DMPlexSetConeOrientation(rdm, newp, orntNew);
4586: #if defined(PETSC_USE_DEBUG)
4587:       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fMaxNew);
4588:       for (p = 0; p < 3; ++p) {
4589:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", coneNew[p], eStartNew, eMaxNew);
4590:       }
4591: #endif
4592:       supportNew[0] = (c - cStart)*8 + 0+4;
4593:       supportNew[1] = (c - cStart)*8 + 2+4;
4594:       DMPlexSetSupport(rdm, newp, supportNew);
4595: #if defined(PETSC_USE_DEBUG)
4596:       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fMaxNew);
4597:       for (p = 0; p < 2; ++p) {
4598:         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", supportNew[p], cStartNew, cMaxNew);
4599:       }
4600: #endif
4601:       ++newp;
4602:       /* Face G: {e, a, f} */
4603:       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*3 + GetTriMidEdge_Static(ornt[1], 1);
4604:       orntNew[0] = ornt[1] < 0 ? -2 : 0;
4605:       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart);
4606:       orntNew[1] = 0;
4607:       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*3 + GetTriMidEdge_Static(ornt[3], 1);
4608:       orntNew[2] = ornt[3] < 0 ? 0 : -2;
4609:       DMPlexSetCone(rdm, newp, coneNew);
4610:       DMPlexSetConeOrientation(rdm, newp, orntNew);
4611: #if defined(PETSC_USE_DEBUG)
4612:       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fMaxNew);
4613:       for (p = 0; p < 3; ++p) {
4614:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", coneNew[p], eStartNew, eMaxNew);
4615:       }
4616: #endif
4617:       supportNew[0] = (c - cStart)*8 + 1+4;
4618:       supportNew[1] = (c - cStart)*8 + 3+4;
4619:       DMPlexSetSupport(rdm, newp, supportNew);
4620: #if defined(PETSC_USE_DEBUG)
4621:       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fMaxNew);
4622:       for (p = 0; p < 2; ++p) {
4623:         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", supportNew[p], cStartNew, cMaxNew);
4624:       }
4625: #endif
4626:       ++newp;
4627:       /* Face H: {a, b, f} */
4628:       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*3 + GetTriMidEdge_Static(ornt[0], 0);
4629:       orntNew[0] = ornt[0] < 0 ? -2 : 0;
4630:       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*3 + GetTriMidEdge_Static(ornt[3], 2);
4631:       orntNew[1] = ornt[3] < 0 ? 0 : -2;
4632:       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart);
4633:       orntNew[2] = -2;
4634:       DMPlexSetCone(rdm, newp, coneNew);
4635:       DMPlexSetConeOrientation(rdm, newp, orntNew);
4636: #if defined(PETSC_USE_DEBUG)
4637:       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fMaxNew);
4638:       for (p = 0; p < 3; ++p) {
4639:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", coneNew[p], eStartNew, eMaxNew);
4640:       }
4641: #endif
4642:       supportNew[0] = (c - cStart)*8 + 1+4;
4643:       supportNew[1] = (c - cStart)*8 + 2+4;
4644:       DMPlexSetSupport(rdm, newp, supportNew);
4645: #if defined(PETSC_USE_DEBUG)
4646:       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fMaxNew);
4647:       for (p = 0; p < 2; ++p) {
4648:         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", supportNew[p], cStartNew, cMaxNew);
4649:       }
4650: #endif
4651:       ++newp;
4652:     }
4653:     /* Hybrid split faces have 4 edges and same cells */
4654:     for (f = fMax; f < fEnd; ++f) {
4655:       const PetscInt *cone, *ornt, *support;
4656:       PetscInt        coneNew[4], orntNew[4];
4657:       PetscInt        supportNew[2], size, s, c;

4659:       DMPlexGetCone(dm, f, &cone);
4660:       DMPlexGetConeOrientation(dm, f, &ornt);
4661:       DMPlexGetSupportSize(dm, f, &size);
4662:       DMPlexGetSupport(dm, f, &support);
4663:       for (r = 0; r < 2; ++r) {
4664:         const PetscInt newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (f - fMax)*2 + r;

4666:         coneNew[0]   = eStartNew + (cone[0] - eStart)*2 + (ornt[0] < 0 ? 1-r : r);
4667:         orntNew[0]   = ornt[0];
4668:         coneNew[1]   = eStartNew + (cone[1] - eStart)*2 + (ornt[1] < 0 ? 1-r : r);
4669:         orntNew[1]   = ornt[1];
4670:         coneNew[2+r] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (cone[2+r] - eMax);
4671:         orntNew[2+r] = 0;
4672:         coneNew[3-r] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (eEnd      - eMax) + (f - fMax);
4673:         orntNew[3-r] = 0;
4674:         DMPlexSetCone(rdm, newp, coneNew);
4675:         DMPlexSetConeOrientation(rdm, newp, orntNew);
4676: #if defined(PETSC_USE_DEBUG)
4677:         if ((newp < fMaxNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a hybrid face [%D, %D)", newp, fMaxNew, fEndNew);
4678:         for (p = 0; p < 2; ++p) {
4679:           if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", coneNew[p], eStartNew, eMaxNew);
4680:         }
4681:         for (p = 2; p < 4; ++p) {
4682:           if ((coneNew[p] < eMaxNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a hybrid edge [%D, %D)", coneNew[p], eMaxNew, eEndNew);
4683:         }
4684: #endif
4685:         for (s = 0; s < size; ++s) {
4686:           const PetscInt *coneCell, *orntCell, *fornt;
4687:           PetscInt        o, of;

4689:           DMPlexGetCone(dm, support[s], &coneCell);
4690:           DMPlexGetConeOrientation(dm, support[s], &orntCell);
4691:           o = orntCell[0] < 0 ? -1 : 1;
4692:           for (c = 2; c < 5; ++c) if (coneCell[c] == f) break;
4693:           if (c >= 5) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Could not find face %D in cone of cell %D", f, support[s]);
4694:           DMPlexGetConeOrientation(dm, coneCell[0], &fornt);
4695:           of = fornt[c-2] < 0 ? -1 : 1;
4696:           supportNew[s] = cStartNew + (cMax - cStart)*8 + (support[s] - cMax)*4 + (GetTriEdgeInverse_Static(orntCell[0], c-2) + (o*of < 0 ? 1-r : r))%3;
4697:         }
4698:         DMPlexSetSupport(rdm, newp, supportNew);
4699: #if defined(PETSC_USE_DEBUG)
4700:         if ((newp < fMaxNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a hybrid face [%D, %D)", newp, fMaxNew, fEndNew);
4701:         for (p = 0; p < size; ++p) {
4702:           if ((supportNew[p] < cMaxNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a hybrid cell [%D, %D)", supportNew[p], cMaxNew, cEndNew);
4703:         }
4704: #endif
4705:       }
4706:     }
4707:     /* Hybrid cell faces have 4 edges and 2 cells */
4708:     for (c = cMax; c < cEnd; ++c) {
4709:       PetscInt        newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (c - cMax)*3;
4710:       const PetscInt *cone, *ornt;
4711:       PetscInt        coneNew[4], orntNew[4];
4712:       PetscInt        supportNew[2];

4714:       DMPlexGetCone(dm, c, &cone);
4715:       DMPlexGetConeOrientation(dm, c, &ornt);
4716:       for (r = 0; r < 3; ++r) {
4717:         coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*3 + (r+2)%3;
4718:         orntNew[0] = 0;
4719:         coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*3 + (r+2)%3;
4720:         orntNew[1] = 0;
4721:         coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (eEnd - eMax) + (cone[2+(r+2)%3] - fMax);
4722:         orntNew[2] = 0;
4723:         coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (eEnd - eMax) + (cone[2+r]       - fMax);
4724:         orntNew[3] = 0;
4725:         DMPlexSetCone(rdm, newp+r, coneNew);
4726:         DMPlexSetConeOrientation(rdm, newp+r, orntNew);
4727: #if defined(PETSC_USE_DEBUG)
4728:         if ((newp+r < fMaxNew) || (newp+r >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a hybrid face [%D, %D)", newp+r, fMaxNew, fEndNew);
4729:         for (p = 0; p < 2; ++p) {
4730:           if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", coneNew[p], eStartNew, eMaxNew);
4731:         }
4732:         for (p = 2; p < 4; ++p) {
4733:           if ((coneNew[p] < eMaxNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a hybrid edge [%D, %D)", coneNew[p], eMaxNew, eEndNew);
4734:         }
4735: #endif
4736:         supportNew[0] = cStartNew + (cMax - cStart)*8 + (c - cMax)*4 + GetTriSubface_Static(ornt[0], r);
4737:         supportNew[1] = cStartNew + (cMax - cStart)*8 + (c - cMax)*4 + 3;
4738:         DMPlexSetSupport(rdm, newp+r, supportNew);
4739: #if defined(PETSC_USE_DEBUG)
4740:         if ((newp+r < fMaxNew) || (newp+r >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a hybrid face [%D, %D)", newp+r, fMaxNew, fEndNew);
4741:         for (p = 0; p < 2; ++p) {
4742:           if ((supportNew[p] < cMaxNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a hybrid cell [%D, %D)", supportNew[p], cMaxNew, cEndNew);
4743:         }
4744: #endif
4745:       }
4746:     }
4747:     /* Interior split edges have 2 vertices and the same faces as the parent */
4748:     for (e = eStart; e < eMax; ++e) {
4749:       const PetscInt newv = vStartNew + (vEnd - vStart) + (e - eStart);

4751:       for (r = 0; r < 2; ++r) {
4752:         const PetscInt  newp = eStartNew + (e - eStart)*2 + r;
4753:         const PetscInt *cone, *ornt, *support;
4754:         PetscInt        coneNew[2], coneSize, c, supportSize, s;

4756:         DMPlexGetCone(dm, e, &cone);
4757:         coneNew[0]       = vStartNew + (cone[0] - vStart);
4758:         coneNew[1]       = vStartNew + (cone[1] - vStart);
4759:         coneNew[(r+1)%2] = newv;
4760:         DMPlexSetCone(rdm, newp, coneNew);
4761: #if defined(PETSC_USE_DEBUG)
4762:         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eMaxNew);
4763:         for (p = 0; p < 2; ++p) {
4764:           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", coneNew[p], vStartNew, vEndNew);
4765:         }
4766: #endif
4767:         DMPlexGetSupportSize(dm, e, &supportSize);
4768:         DMPlexGetSupport(dm, e, &support);
4769:         for (s = 0; s < supportSize; ++s) {
4770:           DMPlexGetConeSize(dm, support[s], &coneSize);
4771:           DMPlexGetCone(dm, support[s], &cone);
4772:           DMPlexGetConeOrientation(dm, support[s], &ornt);
4773:           for (c = 0; c < coneSize; ++c) if (cone[c] == e) break;
4774:           if (support[s] < fMax) {
4775:             supportRef[s] = fStartNew + (support[s] - fStart)*4 + (c + (ornt[c] < 0 ? 1-r : r))%3;
4776:           } else {
4777:             supportRef[s] = fStartNew + (fMax       - fStart)*4 + (cMax - cStart)*8 + (support[s] - fMax)*2 + (ornt[c] < 0 ? 1-r : r);
4778:           }
4779:         }
4780:         DMPlexSetSupport(rdm, newp, supportRef);
4781: #if defined(PETSC_USE_DEBUG)
4782:         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eMaxNew);
4783:         for (p = 0; p < supportSize; ++p) {
4784:           if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an interior or hybrid face [%D, %D)", supportRef[p], fStartNew, fEndNew);
4785:         }
4786: #endif
4787:       }
4788:     }
4789:     /* Interior face edges have 2 vertices and 2+cells*(1/2) faces */
4790:     for (f = fStart; f < fMax; ++f) {
4791:       const PetscInt *cone, *ornt, *support;
4792:       PetscInt        coneSize, supportSize, s;

4794:       DMPlexGetSupportSize(dm, f, &supportSize);
4795:       DMPlexGetSupport(dm, f, &support);
4796:       for (r = 0; r < 3; ++r) {
4797:         const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (f - fStart)*3 + r;
4798:         PetscInt        coneNew[2], intFaces = 0, er, eint[4] = {1, 0, 2, 0};
4799:         PetscInt        fint[24] = { 1,  7, -1, -1,  0,  5,
4800:                                     -1, -1,  1,  6,  0,  4,
4801:                                      2,  5,  3,  4, -1, -1,
4802:                                     -1, -1,  3,  6,  2,  7};

4804:         DMPlexGetCone(dm, f, &cone);
4805:         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[(r+0)%3] - eStart);
4806:         coneNew[1] = vStartNew + (vEnd - vStart) + (cone[(r+1)%3] - eStart);
4807:         DMPlexSetCone(rdm, newp, coneNew);
4808: #if defined(PETSC_USE_DEBUG)
4809:         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eMaxNew);
4810:         for (p = 0; p < 2; ++p) {
4811:           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", coneNew[p], vStartNew, vEndNew);
4812:         }
4813: #endif
4814:         supportRef[0] = fStartNew + (f - fStart)*4 + (r+1)%3;
4815:         supportRef[1] = fStartNew + (f - fStart)*4 + 3;
4816:         for (s = 0; s < supportSize; ++s) {
4817:           DMPlexGetConeSize(dm, support[s], &coneSize);
4818:           DMPlexGetCone(dm, support[s], &cone);
4819:           DMPlexGetConeOrientation(dm, support[s], &ornt);
4820:           for (c = 0; c < coneSize; ++c) {if (cone[c] == f) break;}
4821:           if (support[s] < cMax) {
4822:             /* Here we want to determine whether edge newp contains a vertex which is part of the cross-tet edge */
4823:             er = GetTriMidEdgeInverse_Static(ornt[c], r);
4824:             if (er == eint[c]) {
4825:               supportRef[2+intFaces++] = fStartNew + (fMax - fStart)*4 + (support[s] - cStart)*8 + (c + 2)%4;
4826:             } else {
4827:               supportRef[2+intFaces++] = fStartNew + (fMax - fStart)*4 + (support[s] - cStart)*8 + fint[(c*3 + er)*2 + 0];
4828:               supportRef[2+intFaces++] = fStartNew + (fMax - fStart)*4 + (support[s] - cStart)*8 + fint[(c*3 + er)*2 + 1];
4829:             }
4830:           } else {
4831:             supportRef[2+intFaces++] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (support[s] - cMax)*3 + (r + 1)%3;
4832:           }
4833:         }
4834:         DMPlexSetSupport(rdm, newp, supportRef);
4835: #if defined(PETSC_USE_DEBUG)
4836:         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eMaxNew);
4837:         for (p = 0; p < intFaces; ++p) {
4838:           if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an interior or hybrid face [%D, %D)", supportRef[p], fStartNew, fEndNew);
4839:         }
4840: #endif
4841:       }
4842:     }
4843:     /* Interior cell edges have 2 vertices and 4 faces */
4844:     for (c = cStart; c < cMax; ++c) {
4845:       const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart);
4846:       const PetscInt *cone, *ornt, *fcone;
4847:       PetscInt        coneNew[2], supportNew[4], find;

4849:       DMPlexGetCone(dm, c, &cone);
4850:       DMPlexGetConeOrientation(dm, c, &ornt);
4851:       DMPlexGetCone(dm, cone[0], &fcone);
4852:       find = GetTriEdge_Static(ornt[0], 0);
4853:       coneNew[0] = vStartNew + (vEnd - vStart) + (fcone[find] - eStart);
4854:       DMPlexGetCone(dm, cone[2], &fcone);
4855:       find = GetTriEdge_Static(ornt[2], 1);
4856:       coneNew[1] = vStartNew + (vEnd - vStart) + (fcone[find] - eStart);
4857:       DMPlexSetCone(rdm, newp, coneNew);
4858: #if defined(PETSC_USE_DEBUG)
4859:       if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eMaxNew);
4860:       for (p = 0; p < 2; ++p) {
4861:         if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", coneNew[p], vStartNew, vEndNew);
4862:       }
4863: #endif
4864:       supportNew[0] = fStartNew + (fMax - fStart)*4 + (c - cStart)*8 + 4;
4865:       supportNew[1] = fStartNew + (fMax - fStart)*4 + (c - cStart)*8 + 5;
4866:       supportNew[2] = fStartNew + (fMax - fStart)*4 + (c - cStart)*8 + 6;
4867:       supportNew[3] = fStartNew + (fMax - fStart)*4 + (c - cStart)*8 + 7;
4868:       DMPlexSetSupport(rdm, newp, supportNew);
4869: #if defined(PETSC_USE_DEBUG)
4870:       if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eMaxNew);
4871:       for (p = 0; p < 4; ++p) {
4872:         if ((supportNew[p] < fStartNew) || (supportNew[p] >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", supportNew[p], fStartNew, fMaxNew);
4873:       }
4874: #endif
4875:     }
4876:     /* Hybrid edges have two vertices and the same faces */
4877:     for (e = eMax; e < eEnd; ++e) {
4878:       const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (e - eMax);
4879:       const PetscInt *cone, *support, *fcone;
4880:       PetscInt        coneNew[2], size, fsize, s;

4882:       DMPlexGetCone(dm, e, &cone);
4883:       DMPlexGetSupportSize(dm, e, &size);
4884:       DMPlexGetSupport(dm, e, &support);
4885:       coneNew[0] = vStartNew + (cone[0] - vStart);
4886:       coneNew[1] = vStartNew + (cone[1] - vStart);
4887:       DMPlexSetCone(rdm, newp, coneNew);
4888: #if defined(PETSC_USE_DEBUG)
4889:       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a hybrid edge [%D, %D)", newp, eMaxNew, eEndNew);
4890:       for (p = 0; p < 2; ++p) {
4891:         if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", coneNew[p], vStartNew, vEndNew);
4892:       }
4893: #endif
4894:       for (s = 0; s < size; ++s) {
4895:         DMPlexGetConeSize(dm, support[s], &fsize);
4896:         DMPlexGetCone(dm, support[s], &fcone);
4897:         for (c = 0; c < fsize; ++c) if (fcone[c] == e) break;
4898:         if ((c < 2) || (c > 3)) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Edge %D not found in cone of face %D", e, support[s]);
4899:         supportRef[s] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (support[s] - fMax)*2 + c-2;
4900:       }
4901:       DMPlexSetSupport(rdm, newp, supportRef);
4902: #if defined(PETSC_USE_DEBUG)
4903:       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a hybrid edge [%D, %D)", newp, eMaxNew, eEndNew);
4904:       for (p = 0; p < size; ++p) {
4905:         if ((supportRef[p] < fMaxNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a hybrid face [%D, %D)", supportRef[p], fMaxNew, fEndNew);
4906:       }
4907: #endif
4908:     }
4909:     /* Hybrid face edges have 2 vertices and 2+2*cells faces */
4910:     for (f = fMax; f < fEnd; ++f) {
4911:       const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (eEnd - eMax) + (f - fMax);
4912:       const PetscInt *cone, *support, *ccone, *cornt;
4913:       PetscInt        coneNew[2], size, csize, s;

4915:       DMPlexGetCone(dm, f, &cone);
4916:       DMPlexGetSupportSize(dm, f, &size);
4917:       DMPlexGetSupport(dm, f, &support);
4918:       coneNew[0] = vStartNew + (vEnd - vStart) + (cone[0] - eStart);
4919:       coneNew[1] = vStartNew + (vEnd - vStart) + (cone[1] - eStart);
4920:       DMPlexSetCone(rdm, newp, coneNew);
4921: #if defined(PETSC_USE_DEBUG)
4922:       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a hybrid edge [%D, %D)", newp, eMaxNew, eEndNew);
4923:       for (p = 0; p < 2; ++p) {
4924:         if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", coneNew[p], vStartNew, vEndNew);
4925:       }
4926: #endif
4927:       supportRef[0] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (f - fMax)*2 + 0;
4928:       supportRef[1] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (f - fMax)*2 + 1;
4929:       for (s = 0; s < size; ++s) {
4930:         DMPlexGetConeSize(dm, support[s], &csize);
4931:         DMPlexGetCone(dm, support[s], &ccone);
4932:         DMPlexGetConeOrientation(dm, support[s], &cornt);
4933:         for (c = 0; c < csize; ++c) if (ccone[c] == f) break;
4934:         if ((c < 2) || (c >= csize)) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Hybrid face %D is not in cone of hybrid cell %D", f, support[s]);
4935:         supportRef[2+s*2+0] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (support[s] - cMax)*3 + c-2;
4936:         supportRef[2+s*2+1] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (support[s] - cMax)*3 + (c-1)%3;
4937:       }
4938:       DMPlexSetSupport(rdm, newp, supportRef);
4939: #if defined(PETSC_USE_DEBUG)
4940:       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a hybrid edge [%D, %D)", newp, eMaxNew, eEndNew);
4941:       for (p = 0; p < 2+size*2; ++p) {
4942:         if ((supportRef[p] < fMaxNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a hybrid face [%D, %D)", supportRef[p], fMaxNew, fEndNew);
4943:       }
4944: #endif
4945:     }
4946:     /* Interior vertices have identical supports */
4947:     for (v = vStart; v < vEnd; ++v) {
4948:       const PetscInt  newp = vStartNew + (v - vStart);
4949:       const PetscInt *support, *cone;
4950:       PetscInt        size, s;

4952:       DMPlexGetSupportSize(dm, v, &size);
4953:       DMPlexGetSupport(dm, v, &support);
4954:       for (s = 0; s < size; ++s) {
4955:         PetscInt r = 0;

4957:         DMPlexGetCone(dm, support[s], &cone);
4958:         if (cone[1] == v) r = 1;
4959:         if (support[s] < eMax) supportRef[s] = eStartNew + (support[s] - eStart)*2 + r;
4960:         else                   supportRef[s] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (support[s] - eMax);
4961:       }
4962:       DMPlexSetSupport(rdm, newp, supportRef);
4963: #if defined(PETSC_USE_DEBUG)
4964:       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", newp, vStartNew, vEndNew);
4965:       for (p = 0; p < size; ++p) {
4966:         if ((supportRef[p] < eStartNew) || (supportRef[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an interior or hybrid edge [%D, %D)", supportRef[p], eStartNew, eEndNew);
4967:       }
4968: #endif
4969:     }
4970:     /* Interior edge vertices have 2 + interior face*2 + hybrid face + cells*0/1 supports */
4971:     for (e = eStart; e < eMax; ++e) {
4972:       const PetscInt  newp = vStartNew + (vEnd - vStart) + (e - eStart);
4973:       const PetscInt *cone, *support;
4974:       PetscInt       *star = NULL, starSize, faceSize = 0, cellSize = 0, coneSize, size, s;

4976:       DMPlexGetSupportSize(dm, e, &size);
4977:       DMPlexGetSupport(dm, e, &support);
4978:       supportRef[0] = eStartNew + (e - eStart)*2 + 0;
4979:       supportRef[1] = eStartNew + (e - eStart)*2 + 1;
4980:       for (s = 0; s < size; ++s) {
4981:         PetscInt r = 0;

4983:         if (support[s] < fMax) {
4984:           DMPlexGetConeSize(dm, support[s], &coneSize);
4985:           DMPlexGetCone(dm, support[s], &cone);
4986:           for (r = 0; r < coneSize; ++r) {if (cone[r] == e) break;}
4987:           supportRef[2+faceSize+0] = eStartNew + (eMax - eStart)*2 + (support[s] - fStart)*3 + (r+0)%3;
4988:           supportRef[2+faceSize+1] = eStartNew + (eMax - eStart)*2 + (support[s] - fStart)*3 + (r+2)%3;
4989:           faceSize += 2;
4990:         } else {
4991:           supportRef[2+faceSize+0] = eStartNew + (eMax - eStart)*2 + (fMax       - fStart)*3 + (cMax - cStart) + (eEnd - eMax) + (support[s] - fMax);
4992:           ++faceSize;
4993:         }
4994:       }
4995:       DMPlexGetTransitiveClosure(dm, e, PETSC_FALSE, &starSize, &star);
4996:       for (s = 0; s < starSize*2; s += 2) {
4997:         const PetscInt *cone, *ornt;
4998:         PetscInt        e01, e23;

5000:         if ((star[s] >= cStart) && (star[s] < cMax)) {
5001:           /* Check edge 0-1 */
5002:           DMPlexGetCone(dm, star[s], &cone);
5003:           DMPlexGetConeOrientation(dm, star[s], &ornt);
5004:           DMPlexGetCone(dm, cone[0], &cone);
5005:           e01  = cone[GetTriEdge_Static(ornt[0], 0)];
5006:           /* Check edge 2-3 */
5007:           DMPlexGetCone(dm, star[s], &cone);
5008:           DMPlexGetConeOrientation(dm, star[s], &ornt);
5009:           DMPlexGetCone(dm, cone[2], &cone);
5010:           e23  = cone[GetTriEdge_Static(ornt[2], 1)];
5011:           if ((e01 == e) || (e23 == e)) {supportRef[2+faceSize+cellSize++] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (star[s] - cStart);}
5012:         }
5013:       }
5014:       DMPlexRestoreTransitiveClosure(dm, e, PETSC_FALSE, &starSize, &star);
5015:       DMPlexSetSupport(rdm, newp, supportRef);
5016: #if defined(PETSC_USE_DEBUG)
5017:       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", newp, vStartNew, vEndNew);
5018:       for (p = 0; p < 2+faceSize+cellSize; ++p) {
5019:         if ((supportRef[p] < eStartNew) || (supportRef[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an interior or hybrid edge [%D, %D)", supportRef[p], eStartNew, eEndNew);
5020:       }
5021: #endif
5022:     }
5023:     PetscFree(supportRef);
5024:     DMPlexRestoreFaces_Internal(dm, 3, cStart, NULL, NULL, &faces);
5025:     break;
5026:   case REFINER_SIMPLEX_TO_HEX_3D:
5027:     DMPlexGetRawFaces_Internal(dm, 3, 4, cellInd, NULL, NULL, &faces);
5028:     /* All cells have 6 faces */
5029:     for (c = cStart; c < cEnd; ++c) {
5030:       const PetscInt  newp = cStartNew + (c - cStart)*4;
5031:       const PetscInt *cone, *ornt;
5032:       PetscInt        coneNew[6];
5033:       PetscInt        orntNew[6];

5035:       DMPlexGetCone(dm, c, &cone);
5036:       DMPlexGetConeOrientation(dm, c, &ornt);
5037:       /* A hex */
5038:       coneNew[0] = fStartNew + (cone[0] - fStart)*3 + GetTriSubface_Static(ornt[0], 0); /* B */
5039:       orntNew[0] = ornt[0] < 0 ? -1 : 1;
5040:       coneNew[1] = fStartNew + (fEnd    - fStart)*3 + (c - cStart)*6 + 3;               /* T */
5041:       orntNew[1] = -4;
5042:       coneNew[2] = fStartNew + (cone[2] - fStart)*3 + GetTriSubface_Static(ornt[2], 0); /* F */
5043:       orntNew[2] = ornt[2] < 0 ? -1 : 1;
5044:       coneNew[3] = fStartNew + (fEnd    - fStart)*3 + (c - cStart)*6 + 0;               /* K */
5045:       orntNew[3] = -1;
5046:       coneNew[4] = fStartNew + (fEnd    - fStart)*3 + (c - cStart)*6 + 2;               /* R */
5047:       orntNew[4] = 0;
5048:       coneNew[5] = fStartNew + (cone[1] - fStart)*3 + GetTriSubface_Static(ornt[1], 0); /* L */
5049:       orntNew[5] = ornt[1] < 0 ? -1 : 1;
5050:       DMPlexSetCone(rdm, newp+0, coneNew);
5051:       DMPlexSetConeOrientation(rdm, newp+0, orntNew);
5052: #if defined(PETSC_USE_DEBUG)
5053:       if ((newp+0 < cStartNew) || (newp+0 >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", newp+0, cStartNew, cEndNew);
5054:       for (p = 0; p < 6; ++p) {
5055:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", coneNew[p], fStartNew, fEndNew);
5056:       }
5057: #endif
5058:       /* B hex */
5059:       coneNew[0] = fStartNew + (cone[0] - fStart)*3 + GetTriSubface_Static(ornt[0], 1); /* B */
5060:       orntNew[0] = ornt[0] < 0 ? -2 : 0;
5061:       coneNew[1] = fStartNew + (fEnd    - fStart)*3 + (c - cStart)*6 + 4;               /* T */
5062:       orntNew[1] = 0;
5063:       coneNew[2] = fStartNew + (fEnd    - fStart)*3 + (c - cStart)*6 + 0;               /* F */
5064:       orntNew[2] = 0;
5065:       coneNew[3] = fStartNew + (cone[3] - fStart)*3 + GetTriSubface_Static(ornt[3], 1); /* K */
5066:       orntNew[3] = ornt[3] < 0 ? -2 : 0;
5067:       coneNew[4] = fStartNew + (fEnd    - fStart)*3 + (c - cStart)*6 + 1;               /* R */
5068:       orntNew[4] = 0;
5069:       coneNew[5] = fStartNew + (cone[1] - fStart)*3 + GetTriSubface_Static(ornt[1], 2); /* L */
5070:       orntNew[5] = ornt[1] < 0 ? -4 : 2;
5071:       DMPlexSetCone(rdm, newp+1, coneNew);
5072:       DMPlexSetConeOrientation(rdm, newp+1, orntNew);
5073: #if defined(PETSC_USE_DEBUG)
5074:       if ((newp+1 < cStartNew) || (newp+1 >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", newp+1, cStartNew, cEndNew);
5075:       for (p = 0; p < 6; ++p) {
5076:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", coneNew[p], fStartNew, fEndNew);
5077:       }
5078: #endif
5079:       /* C hex */
5080:       coneNew[0] = fStartNew + (cone[0] - fStart)*3 + GetTriSubface_Static(ornt[0], 2); /* B */
5081:       orntNew[0] = ornt[0] < 0 ? -4 : 2;
5082:       coneNew[1] = fStartNew + (fEnd    - fStart)*3 + (c - cStart)*6 + 5;               /* T */
5083:       orntNew[1] = -4;
5084:       coneNew[2] = fStartNew + (cone[2] - fStart)*3 + GetTriSubface_Static(ornt[2], 1); /* F */
5085:       orntNew[2] = ornt[2] < 0 ? -2 : 0;
5086:       coneNew[3] = fStartNew + (fEnd    - fStart)*3 + (c - cStart)*6 + 1;               /* K */
5087:       orntNew[3] = -1;
5088:       coneNew[4] = fStartNew + (cone[3] - fStart)*3 + GetTriSubface_Static(ornt[3], 0); /* R */
5089:       orntNew[4] = ornt[3] < 0 ? -1 : 1;
5090:       coneNew[5] = fStartNew + (fEnd    - fStart)*3 + (c - cStart)*6 + 2;               /* L */
5091:       orntNew[5] = -4;
5092:       DMPlexSetCone(rdm, newp+2, coneNew);
5093:       DMPlexSetConeOrientation(rdm, newp+2, orntNew);
5094: #if defined(PETSC_USE_DEBUG)
5095:       if ((newp+2 < cStartNew) || (newp+2 >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", newp+2, cStartNew, cEndNew);
5096:       for (p = 0; p < 6; ++p) {
5097:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", coneNew[p], fStartNew, fEndNew);
5098:       }
5099: #endif
5100:       /* D hex */
5101:       coneNew[0] = fStartNew + (fEnd    - fStart)*3 + (c - cStart)*6 + 3;               /* B */
5102:       orntNew[0] = 0;
5103:       coneNew[1] = fStartNew + (cone[3] - fStart)*3 + GetTriSubface_Static(ornt[3], 2); /* T */
5104:       orntNew[1] = ornt[3] < 0 ? -1 : 1;
5105:       coneNew[2] = fStartNew + (cone[2] - fStart)*3 + GetTriSubface_Static(ornt[2], 2); /* F */
5106:       orntNew[2] = ornt[2] < 0 ? -4 : 2;
5107:       coneNew[3] = fStartNew + (fEnd    - fStart)*3 + (c - cStart)*6 + 4;               /* K */
5108:       orntNew[3] = -1;
5109:       coneNew[4] = fStartNew + (fEnd    - fStart)*3 + (c - cStart)*6 + 5;               /* R */
5110:       orntNew[4] = 0;
5111:       coneNew[5] = fStartNew + (cone[1] - fStart)*3 + GetTriSubface_Static(ornt[1], 1); /* L */
5112:       orntNew[5] = ornt[1] < 0 ? -2 : 0;
5113:       DMPlexSetCone(rdm, newp+3, coneNew);
5114:       DMPlexSetConeOrientation(rdm, newp+3, orntNew);
5115: #if defined(PETSC_USE_DEBUG)
5116:       if ((newp+3 < cStartNew) || (newp+3 >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", newp+3, cStartNew, cEndNew);
5117:       for (p = 0; p < 6; ++p) {
5118:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", coneNew[p], fStartNew, fEndNew);
5119:       }
5120: #endif
5121:     }
5122:     /* Split faces have 4 edges and the same cells as the parent */
5123:     DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);
5124:     PetscMalloc1(2 + maxSupportSize*2, &supportRef);
5125:     for (f = fStart; f < fEnd; ++f) {
5126:       const PetscInt  newp = fStartNew + (f - fStart)*3;
5127:       const PetscInt *cone, *ornt, *support;
5128:       PetscInt        coneNew[4], orntNew[4], coneSize, supportSize, s;

5130:       DMPlexGetCone(dm, f, &cone);
5131:       DMPlexGetConeOrientation(dm, f, &ornt);
5132:       /* A quad */
5133:       coneNew[0] = eStartNew + (cone[2] - eStart)*2 + (ornt[2] < 0 ? 0 : 1);
5134:       orntNew[0] = ornt[2];
5135:       coneNew[1] = eStartNew + (cone[0] - eStart)*2 + (ornt[0] < 0 ? 1 : 0);
5136:       orntNew[1] = ornt[0];
5137:       coneNew[2] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 0;
5138:       orntNew[2] = 0;
5139:       coneNew[3] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 2;
5140:       orntNew[3] = -2;
5141:       DMPlexSetCone(rdm, newp+0, coneNew);
5142:       DMPlexSetConeOrientation(rdm, newp+0, orntNew);
5143: #if defined(PETSC_USE_DEBUG)
5144:       if ((newp+0 < fStartNew) || (newp+0 >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp+0, fStartNew, fEndNew);
5145:       for (p = 0; p < 4; ++p) {
5146:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", coneNew[p], eStartNew, eEndNew);
5147:       }
5148: #endif
5149:       /* B quad */
5150:       coneNew[0] = eStartNew + (cone[0] - eStart)*2 + (ornt[0] < 0 ? 0 : 1);
5151:       orntNew[0] = ornt[0];
5152:       coneNew[1] = eStartNew + (cone[1] - eStart)*2 + (ornt[1] < 0 ? 1 : 0);
5153:       orntNew[1] = ornt[1];
5154:       coneNew[2] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 1;
5155:       orntNew[2] = 0;
5156:       coneNew[3] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 0;
5157:       orntNew[3] = -2;
5158:       DMPlexSetCone(rdm, newp+1, coneNew);
5159:       DMPlexSetConeOrientation(rdm, newp+1, orntNew);
5160: #if defined(PETSC_USE_DEBUG)
5161:       if ((newp+1 < fStartNew) || (newp+1 >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp+1, fStartNew, fEndNew);
5162:       for (p = 0; p < 4; ++p) {
5163:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", coneNew[p], eStartNew, eEndNew);
5164:       }
5165: #endif
5166:       /* C quad */
5167:       coneNew[0] = eStartNew + (cone[1] - eStart)*2 + (ornt[1] < 0 ? 0 : 1);
5168:       orntNew[0] = ornt[1];
5169:       coneNew[1] = eStartNew + (cone[2] - eStart)*2 + (ornt[2] < 0 ? 1 : 0);
5170:       orntNew[1] = ornt[2];
5171:       coneNew[2] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 2;
5172:       orntNew[2] = 0;
5173:       coneNew[3] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 1;
5174:       orntNew[3] = -2;
5175:       DMPlexSetCone(rdm, newp+2, coneNew);
5176:       DMPlexSetConeOrientation(rdm, newp+2, orntNew);
5177: #if defined(PETSC_USE_DEBUG)
5178:       if ((newp+2 < fStartNew) || (newp+2 >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp+2, fStartNew, fEndNew);
5179:       for (p = 0; p < 4; ++p) {
5180:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", coneNew[p], eStartNew, eEndNew);
5181:       }
5182: #endif
5183:       DMPlexGetSupportSize(dm, f, &supportSize);
5184:       DMPlexGetSupport(dm, f, &support);
5185:       for (r = 0; r < 3; ++r) {
5186:         for (s = 0; s < supportSize; ++s) {
5187:           PetscInt subf;
5188:           DMPlexGetConeSize(dm, support[s], &coneSize);
5189:           DMPlexGetCone(dm, support[s], &cone);
5190:           DMPlexGetConeOrientation(dm, support[s], &ornt);
5191:           for (c = 0; c < coneSize; ++c) {
5192:             if (cone[c] == f) break;
5193:           }
5194:           subf = GetTriSubfaceInverse_Static(ornt[c], r);
5195:           supportRef[s] = cStartNew + (support[s] - cStart)*4 + faces[c*3+subf];
5196:         }
5197:         DMPlexSetSupport(rdm, newp+r, supportRef);
5198: #if defined(PETSC_USE_DEBUG)
5199:         if ((newp+r < fStartNew) || (newp+r >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp+r, fStartNew, fEndNew);
5200:         for (p = 0; p < supportSize; ++p) {
5201:           if ((supportRef[p] < cStartNew) || (supportRef[p] >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", supportRef[p], cStartNew, cEndNew);
5202:         }
5203: #endif
5204:       }
5205:     }
5206:     /* Interior faces have 4 edges and 2 cells */
5207:     for (c = cStart; c < cEnd; ++c) {
5208:       PetscInt        newp = fStartNew + (fEnd - fStart)*3 + (c - cStart)*6;
5209:       const PetscInt *cone, *ornt;
5210:       PetscInt        coneNew[4], orntNew[4];
5211:       PetscInt        supportNew[2];

5213:       DMPlexGetCone(dm, c, &cone);
5214:       DMPlexGetConeOrientation(dm, c, &ornt);
5215:       /* Face {a, g, m, h} */
5216:       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*3 + GetTriInteriorEdge_Static(ornt[0],0);
5217:       orntNew[0] = 0;
5218:       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + 0;
5219:       orntNew[1] = 0;
5220:       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + 1;
5221:       orntNew[2] = -2;
5222:       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*3 + GetTriInteriorEdge_Static(ornt[1],2);
5223:       orntNew[3] = -2;
5224:       DMPlexSetCone(rdm, newp, coneNew);
5225:       DMPlexSetConeOrientation(rdm, newp, orntNew);
5226: #if defined(PETSC_USE_DEBUG)
5227:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
5228:       for (p = 0; p < 4; ++p) {
5229:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", coneNew[p], eStartNew, eEndNew);
5230:       }
5231: #endif
5232:       supportNew[0] = (c - cStart)*4 + 0;
5233:       supportNew[1] = (c - cStart)*4 + 1;
5234:       DMPlexSetSupport(rdm, newp, supportNew);
5235: #if defined(PETSC_USE_DEBUG)
5236:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
5237:       for (p = 0; p < 2; ++p) {
5238:         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", supportNew[p], cStartNew, cEndNew);
5239:       }
5240: #endif
5241:       ++newp;
5242:       /* Face {g, b, l , m} */
5243:       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*3 + GetTriInteriorEdge_Static(ornt[0],1);
5244:       orntNew[0] = -2;
5245:       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*3 + GetTriInteriorEdge_Static(ornt[3],0);
5246:       orntNew[1] = 0;
5247:       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + 3;
5248:       orntNew[2] = 0;
5249:       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + 0;
5250:       orntNew[3] = -2;
5251:       DMPlexSetCone(rdm, newp, coneNew);
5252:       DMPlexSetConeOrientation(rdm, newp, orntNew);
5253: #if defined(PETSC_USE_DEBUG)
5254:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
5255:       for (p = 0; p < 4; ++p) {
5256:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", coneNew[p], eStartNew, eEndNew);
5257:       }
5258: #endif
5259:       supportNew[0] = (c - cStart)*4 + 1;
5260:       supportNew[1] = (c - cStart)*4 + 2;
5261:       DMPlexSetSupport(rdm, newp, supportNew);
5262: #if defined(PETSC_USE_DEBUG)
5263:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
5264:       for (p = 0; p < 2; ++p) {
5265:         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", supportNew[p], cStartNew, cEndNew);
5266:       }
5267: #endif
5268:       ++newp;
5269:       /* Face {c, g, m, i} */
5270:       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*3 + GetTriInteriorEdge_Static(ornt[0],2);
5271:       orntNew[0] = 0;
5272:       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + 0;
5273:       orntNew[1] = 0;
5274:       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + 2;
5275:       orntNew[2] = -2;
5276:       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*3 + GetTriInteriorEdge_Static(ornt[2],0);
5277:       orntNew[3] = -2;
5278:       DMPlexSetCone(rdm, newp, coneNew);
5279:       DMPlexSetConeOrientation(rdm, newp, orntNew);
5280: #if defined(PETSC_USE_DEBUG)
5281:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
5282:       for (p = 0; p < 4; ++p) {
5283:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", coneNew[p], eStartNew, eEndNew);
5284:       }
5285: #endif
5286:       supportNew[0] = (c - cStart)*4 + 0;
5287:       supportNew[1] = (c - cStart)*4 + 2;
5288:       DMPlexSetSupport(rdm, newp, supportNew);
5289: #if defined(PETSC_USE_DEBUG)
5290:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
5291:       for (p = 0; p < 2; ++p) {
5292:         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", supportNew[p], cStartNew, cEndNew);
5293:       }
5294: #endif
5295:       ++newp;
5296:       /* Face {d, h, m, i} */
5297:       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*3 + GetTriInteriorEdge_Static(ornt[1],0);
5298:       orntNew[0] = 0;
5299:       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + 1;
5300:       orntNew[1] = 0;
5301:       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + 2;
5302:       orntNew[2] = -2;
5303:       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*3 + GetTriInteriorEdge_Static(ornt[2],2);
5304:       orntNew[3] = -2;
5305:       DMPlexSetCone(rdm, newp, coneNew);
5306:       DMPlexSetConeOrientation(rdm, newp, orntNew);
5307: #if defined(PETSC_USE_DEBUG)
5308:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
5309:       for (p = 0; p < 4; ++p) {
5310:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", coneNew[p], eStartNew, eEndNew);
5311:       }
5312: #endif
5313:       supportNew[0] = (c - cStart)*4 + 0;
5314:       supportNew[1] = (c - cStart)*4 + 3;
5315:       DMPlexSetSupport(rdm, newp, supportNew);
5316: #if defined(PETSC_USE_DEBUG)
5317:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
5318:       for (p = 0; p < 2; ++p) {
5319:         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", supportNew[p], cStartNew, cEndNew);
5320:       }
5321: #endif
5322:       ++newp;
5323:       /* Face {h, m, l, e} */
5324:       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + 1;
5325:       orntNew[0] = 0;
5326:       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + 3;
5327:       orntNew[1] = -2;
5328:       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*3 + GetTriInteriorEdge_Static(ornt[3],1);
5329:       orntNew[2] = -2;
5330:       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*3 + GetTriInteriorEdge_Static(ornt[1],1);
5331:       orntNew[3] = 0;
5332:       DMPlexSetCone(rdm, newp, coneNew);
5333:       DMPlexSetConeOrientation(rdm, newp, orntNew);
5334: #if defined(PETSC_USE_DEBUG)
5335:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
5336:       for (p = 0; p < 4; ++p) {
5337:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", coneNew[p], eStartNew, eEndNew);
5338:       }
5339: #endif
5340:       supportNew[0] = (c - cStart)*4 + 1;
5341:       supportNew[1] = (c - cStart)*4 + 3;
5342:       DMPlexSetSupport(rdm, newp, supportNew);
5343: #if defined(PETSC_USE_DEBUG)
5344:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
5345:       for (p = 0; p < 2; ++p) {
5346:         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", supportNew[p], cStartNew, cEndNew);
5347:       }
5348: #endif
5349:       ++newp;
5350:       /* Face {i, m, l, f} */
5351:       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + 2;
5352:       orntNew[0] = 0;
5353:       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + 3;
5354:       orntNew[1] = -2;
5355:       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*3 + GetTriInteriorEdge_Static(ornt[3],2);
5356:       orntNew[2] = -2;
5357:       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*3 + GetTriInteriorEdge_Static(ornt[2],1);
5358:       orntNew[3] = 0;
5359:       DMPlexSetCone(rdm, newp, coneNew);
5360:       DMPlexSetConeOrientation(rdm, newp, orntNew);
5361: #if defined(PETSC_USE_DEBUG)
5362:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
5363:       for (p = 0; p < 4; ++p) {
5364:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", coneNew[p], eStartNew, eEndNew);
5365:       }
5366: #endif
5367:       supportNew[0] = (c - cStart)*4 + 2;
5368:       supportNew[1] = (c - cStart)*4 + 3;
5369:       DMPlexSetSupport(rdm, newp, supportNew);
5370: #if defined(PETSC_USE_DEBUG)
5371:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
5372:       for (p = 0; p < 2; ++p) {
5373:         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", supportNew[p], cStartNew, cEndNew);
5374:       }
5375: #endif
5376:       ++newp;
5377:     }
5378:     /* Split Edges have 2 vertices and the same faces as the parent */
5379:     for (e = eStart; e < eEnd; ++e) {
5380:       const PetscInt newv = vStartNew + (vEnd - vStart) + (e - eStart);

5382:       for (r = 0; r < 2; ++r) {
5383:         const PetscInt  newp = eStartNew + (e - eStart)*2 + r;
5384:         const PetscInt *cone, *ornt, *support;
5385:         PetscInt        coneNew[2], coneSize, c, supportSize, s;

5387:         DMPlexGetCone(dm, e, &cone);
5388:         coneNew[0]       = vStartNew + (cone[0] - vStart);
5389:         coneNew[1]       = vStartNew + (cone[1] - vStart);
5390:         coneNew[(r+1)%2] = newv;
5391:         DMPlexSetCone(rdm, newp, coneNew);
5392: #if defined(PETSC_USE_DEBUG)
5393:         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eEndNew);
5394:         for (p = 0; p < 2; ++p) {
5395:           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", coneNew[p], vStartNew, vEndNew);
5396:         }
5397: #endif
5398:         DMPlexGetSupportSize(dm, e, &supportSize);
5399:         DMPlexGetSupport(dm, e, &support);
5400:         for (s = 0; s < supportSize; ++s) {
5401:           DMPlexGetConeSize(dm, support[s], &coneSize);
5402:           DMPlexGetCone(dm, support[s], &cone);
5403:           DMPlexGetConeOrientation(dm, support[s], &ornt);
5404:           for (c = 0; c < coneSize; ++c) {
5405:             if (cone[c] == e) break;
5406:           }
5407:           supportRef[s] = fStartNew + (support[s] - fStart)*3 + (c + (ornt[c] < 0 ? 1-r : r))%3;
5408:         }
5409:         DMPlexSetSupport(rdm, newp, supportRef);
5410: #if defined(PETSC_USE_DEBUG)
5411:         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eEndNew);
5412:         for (p = 0; p < supportSize; ++p) {
5413:           if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", supportRef[p], fStartNew, fEndNew);
5414:         }
5415: #endif
5416:       }
5417:     }
5418:     /* Face edges have 2 vertices and 2 + cell faces supports */
5419:     for (f = fStart; f < fEnd; ++f) {
5420:       const PetscInt *cone, *ornt, *support;
5421:       PetscInt        coneSize, supportSize, s;

5423:       DMPlexGetSupportSize(dm, f, &supportSize);
5424:       DMPlexGetSupport(dm, f, &support);
5425:       for (r = 0; r < 3; ++r) {
5426:         const PetscInt  newp = eStartNew + (eEnd - eStart)*2 + (f - fStart)*3 + r;
5427:         PetscInt        coneNew[2];
5428:         PetscInt        fint[4][3] = { {0, 1, 2},
5429:                                        {3, 4, 0},
5430:                                        {2, 5, 3},
5431:                                        {1, 4, 5} };

5433:         DMPlexGetCone(dm, f, &cone);
5434:         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r] - eStart);
5435:         coneNew[1] = vStartNew + (vEnd - vStart) + (eEnd - eStart) + f - fStart;
5436:         DMPlexSetCone(rdm, newp, coneNew);
5437: #if defined(PETSC_USE_DEBUG)
5438:         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eEndNew);
5439:         for (p = 0; p < 2; ++p) {
5440:           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", coneNew[p], vStartNew, vEndNew);
5441:         }
5442: #endif
5443:         supportRef[0] = fStartNew + (f - fStart)*3 + (r+0)%3;
5444:         supportRef[1] = fStartNew + (f - fStart)*3 + (r+1)%3;
5445:         for (s = 0; s < supportSize; ++s) {
5446:           PetscInt er;
5447:           DMPlexGetConeSize(dm, support[s], &coneSize);
5448:           DMPlexGetCone(dm, support[s], &cone);
5449:           DMPlexGetConeOrientation(dm, support[s], &ornt);
5450:           for (c = 0; c < coneSize; ++c) {if (cone[c] == f) break;}
5451:           er = GetTriInteriorEdgeInverse_Static(ornt[c], r);
5452:           supportRef[2+s] = fStartNew + (fEnd - fStart)*3 + (support[s] - cStart)*6 + fint[c][er];
5453:         }
5454:         DMPlexSetSupport(rdm, newp, supportRef);
5455: #if defined(PETSC_USE_DEBUG)
5456:         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eEndNew);
5457:         for (p = 0; p < supportSize + 2; ++p) {
5458:           if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", supportRef[p], fStartNew, fEndNew);
5459:         }
5460: #endif
5461:       }
5462:     }
5463:     /* Interior cell edges have 2 vertices and 3 faces */
5464:     for (c = cStart; c < cEnd; ++c) {
5465:       const PetscInt *cone;
5466:       PetscInt       fint[4][3] = { {0,1,2},
5467:                                     {0,3,4},
5468:                                     {2,3,5},
5469:                                     {1,4,5} } ;

5471:       DMPlexGetCone(dm, c, &cone);
5472:       for (r = 0; r < 4; r++) {
5473:         PetscInt       coneNew[2], supportNew[3];
5474:         const PetscInt newp = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + r;

5476:         coneNew[0] = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (cone[r] - fStart);
5477:         coneNew[1] = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (fEnd -fStart) + c - cStart;
5478:         DMPlexSetCone(rdm, newp, coneNew);
5479: #if defined(PETSC_USE_DEBUG)
5480:         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eEndNew);
5481:         for (p = 0; p < 2; ++p) {
5482:           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", coneNew[p], vStartNew, vEndNew);
5483:         }
5484: #endif
5485:         supportNew[0] = fStartNew + (fEnd - fStart)*3 + (c - cStart)*6 + fint[r][0];
5486:         supportNew[1] = fStartNew + (fEnd - fStart)*3 + (c - cStart)*6 + fint[r][1];
5487:         supportNew[2] = fStartNew + (fEnd - fStart)*3 + (c - cStart)*6 + fint[r][2];
5488:         DMPlexSetSupport(rdm, newp, supportNew);
5489: #if defined(PETSC_USE_DEBUG)
5490:         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eEndNew);
5491:         for (p = 0; p < 3; ++p) {
5492:           if ((supportNew[p] < fStartNew) || (supportNew[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", supportNew[p], fStartNew, fEndNew);
5493:         }
5494: #endif
5495:       }
5496:     }
5497:     /* Old vertices have identical supports */
5498:     for (v = vStart; v < vEnd; ++v) {
5499:       const PetscInt  newp = vStartNew + (v - vStart);
5500:       const PetscInt *support, *cone;
5501:       PetscInt        size, s;

5503:       DMPlexGetSupportSize(dm, v, &size);
5504:       DMPlexGetSupport(dm, v, &support);
5505:       for (s = 0; s < size; ++s) {
5506:         PetscInt r = 0;

5508:         DMPlexGetCone(dm, support[s], &cone);
5509:         if (cone[1] == v) r = 1;
5510:         supportRef[s] = eStartNew + (support[s] - eStart)*2 + r;
5511:       }
5512:       DMPlexSetSupport(rdm, newp, supportRef);
5513: #if defined(PETSC_USE_DEBUG)
5514:       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", newp, vStartNew, vEndNew);
5515:       for (p = 0; p < size; ++p) {
5516:         if ((supportRef[p] < eStartNew) || (supportRef[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", supportRef[p], eStartNew, eEndNew);
5517:       }
5518: #endif
5519:     }
5520:     /* Edge vertices have 2 + faces supports */
5521:     for (e = eStart; e < eEnd; ++e) {
5522:       const PetscInt  newp = vStartNew + (vEnd - vStart) + (e - eStart);
5523:       const PetscInt *cone, *support;
5524:       PetscInt        size, s;

5526:       DMPlexGetSupportSize(dm, e, &size);
5527:       DMPlexGetSupport(dm, e, &support);
5528:       supportRef[0] = eStartNew + (e - eStart)*2 + 0;
5529:       supportRef[1] = eStartNew + (e - eStart)*2 + 1;
5530:       for (s = 0; s < size; ++s) {
5531:         PetscInt r = 0, coneSize;

5533:         DMPlexGetConeSize(dm, support[s], &coneSize);
5534:         DMPlexGetCone(dm, support[s], &cone);
5535:         for (r = 0; r < coneSize; ++r) {if (cone[r] == e) break;}
5536:         supportRef[2+s] = eStartNew + (eEnd - eStart)*2 + (support[s] - fStart)*3 + r;
5537:       }
5538:       DMPlexSetSupport(rdm, newp, supportRef);
5539: #if defined(PETSC_USE_DEBUG)
5540:       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", newp, vStartNew, vEndNew);
5541:       for (p = 0; p < 2+size; ++p) {
5542:         if ((supportRef[p] < eStartNew) || (supportRef[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", supportRef[p], eStartNew, eEndNew);
5543:       }
5544: #endif
5545:     }
5546:     /* Face vertices have 3 + cells supports */
5547:     for (f = fStart; f < fEnd; ++f) {
5548:       const PetscInt  newp = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (f - fStart);
5549:       const PetscInt *cone, *support;
5550:       PetscInt        size, s;

5552:       DMPlexGetSupportSize(dm, f, &size);
5553:       DMPlexGetSupport(dm, f, &support);
5554:       supportRef[0] = eStartNew + (eEnd - eStart)*2 + (f - fStart)*3 + 0;
5555:       supportRef[1] = eStartNew + (eEnd - eStart)*2 + (f - fStart)*3 + 1;
5556:       supportRef[2] = eStartNew + (eEnd - eStart)*2 + (f - fStart)*3 + 2;
5557:       for (s = 0; s < size; ++s) {
5558:         PetscInt r = 0, coneSize;

5560:         DMPlexGetConeSize(dm, support[s], &coneSize);
5561:         DMPlexGetCone(dm, support[s], &cone);
5562:         for (r = 0; r < coneSize; ++r) {if (cone[r] == f) break;}
5563:         supportRef[3+s] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (support[s] - cStart)*4 + r;
5564:       }
5565:       DMPlexSetSupport(rdm, newp, supportRef);
5566: #if defined(PETSC_USE_DEBUG)
5567:       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", newp, vStartNew, vEndNew);
5568:       for (p = 0; p < 3+size; ++p) {
5569:         if ((supportRef[p] < eStartNew) || (supportRef[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", supportRef[p], eStartNew, eEndNew);
5570:       }
5571: #endif
5572:     }
5573:     /* Interior cell vertices have 4 supports */
5574:     for (c = cStart; c < cEnd; ++c) {
5575:       const PetscInt  newp = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (fEnd - fStart) + c - cStart;
5576:       supportRef[0] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + 0;
5577:       supportRef[1] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + 1;
5578:       supportRef[2] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + 2;
5579:       supportRef[3] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + 3;
5580:       DMPlexSetSupport(rdm, newp, supportRef);
5581: #if defined(PETSC_USE_DEBUG)
5582:       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", newp, vStartNew, vEndNew);
5583:       for (p = 0; p < 4; ++p) {
5584:         if ((supportRef[p] < eStartNew) || (supportRef[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", supportRef[p], eStartNew, eEndNew);
5585:       }
5586: #endif
5587:     }
5588:     PetscFree(supportRef);
5589:     DMPlexRestoreFaces_Internal(dm, 3, cStart, NULL, NULL, &faces);
5590:     break;
5591:   case REFINER_HYBRID_SIMPLEX_TO_HEX_3D:
5592:     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
5593:     cMax = PetscMin(cEnd, cMax);
5594:     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
5595:     fMax = PetscMin(fEnd, fMax);
5596:     if (eMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
5597:     eMax = PetscMin(eEnd, eMax);
5598:     DMPlexGetRawFaces_Internal(dm, 3, 4, cellInd, NULL, NULL, &faces);
5599:     /* All cells have 6 faces */
5600:     for (c = cStart; c < cMax; ++c) {
5601:       const PetscInt  newp = cStartNew + (c - cStart)*4;
5602:       const PetscInt *cone, *ornt;
5603:       PetscInt        coneNew[6];
5604:       PetscInt        orntNew[6];

5606:       DMPlexGetCone(dm, c, &cone);
5607: #if defined(PETSC_USE_DEBUG)
5608:       for (p = 0; p < 4; ++p) {
5609:         if (cone[p] >= fMax) SETERRQ4(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected hybrid face %D (fMax %D) in cone position %D for cell %D", cone[p], p, fMax, c);
5610:       }
5611: #endif
5612:       DMPlexGetConeOrientation(dm, c, &ornt);
5613:       /* A hex */
5614:       coneNew[0] = fStartNew + (cone[0] - fStart)*3 + GetTriSubface_Static(ornt[0], 0); /* B */
5615:       orntNew[0] = ornt[0] < 0 ? -1 : 1;
5616:       coneNew[1] = fStartNew + (fMax    - fStart)*3 + (c - cStart)*6 + 3;               /* T */
5617:       orntNew[1] = -4;
5618:       coneNew[2] = fStartNew + (cone[2] - fStart)*3 + GetTriSubface_Static(ornt[2], 0); /* F */
5619:       orntNew[2] = ornt[2] < 0 ? -1 : 1;
5620:       coneNew[3] = fStartNew + (fMax    - fStart)*3 + (c - cStart)*6 + 0;               /* K */
5621:       orntNew[3] = -1;
5622:       coneNew[4] = fStartNew + (fMax    - fStart)*3 + (c - cStart)*6 + 2;               /* R */
5623:       orntNew[4] = 0;
5624:       coneNew[5] = fStartNew + (cone[1] - fStart)*3 + GetTriSubface_Static(ornt[1], 0); /* L */
5625:       orntNew[5] = ornt[1] < 0 ? -1 : 1;
5626:       DMPlexSetCone(rdm, newp+0, coneNew);
5627:       DMPlexSetConeOrientation(rdm, newp+0, orntNew);
5628: #if defined(PETSC_USE_DEBUG)
5629:       if ((newp+0 < cStartNew) || (newp+0 >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", newp+0, cStartNew, cEndNew);
5630:       for (p = 0; p < 6; ++p) {
5631:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", coneNew[p], fStartNew, fEndNew);
5632:       }
5633: #endif
5634:       /* B hex */
5635:       coneNew[0] = fStartNew + (cone[0] - fStart)*3 + GetTriSubface_Static(ornt[0], 1); /* B */
5636:       orntNew[0] = ornt[0] < 0 ? -2 : 0;
5637:       coneNew[1] = fStartNew + (fMax    - fStart)*3 + (c - cStart)*6 + 4;               /* T */
5638:       orntNew[1] = 0;
5639:       coneNew[2] = fStartNew + (fMax    - fStart)*3 + (c - cStart)*6 + 0;               /* F */
5640:       orntNew[2] = 0;
5641:       coneNew[3] = fStartNew + (cone[3] - fStart)*3 + GetTriSubface_Static(ornt[3], 1); /* K */
5642:       orntNew[3] = ornt[3] < 0 ? -2 : 0;
5643:       coneNew[4] = fStartNew + (fMax    - fStart)*3 + (c - cStart)*6 + 1;               /* R */
5644:       orntNew[4] = 0;
5645:       coneNew[5] = fStartNew + (cone[1] - fStart)*3 + GetTriSubface_Static(ornt[1], 2); /* L */
5646:       orntNew[5] = ornt[1] < 0 ? -4 : 2;
5647:       DMPlexSetCone(rdm, newp+1, coneNew);
5648:       DMPlexSetConeOrientation(rdm, newp+1, orntNew);
5649: #if defined(PETSC_USE_DEBUG)
5650:       if ((newp+1 < cStartNew) || (newp+1 >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", newp+1, cStartNew, cEndNew);
5651:       for (p = 0; p < 6; ++p) {
5652:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", coneNew[p], fStartNew, fEndNew);
5653:       }
5654: #endif
5655:       /* C hex */
5656:       coneNew[0] = fStartNew + (cone[0] - fStart)*3 + GetTriSubface_Static(ornt[0], 2); /* B */
5657:       orntNew[0] = ornt[0] < 0 ? -4 : 2;
5658:       coneNew[1] = fStartNew + (fMax    - fStart)*3 + (c - cStart)*6 + 5;               /* T */
5659:       orntNew[1] = -4;
5660:       coneNew[2] = fStartNew + (cone[2] - fStart)*3 + GetTriSubface_Static(ornt[2], 1); /* F */
5661:       orntNew[2] = ornt[2] < 0 ? -2 : 0;
5662:       coneNew[3] = fStartNew + (fMax    - fStart)*3 + (c - cStart)*6 + 1;               /* K */
5663:       orntNew[3] = -1;
5664:       coneNew[4] = fStartNew + (cone[3] - fStart)*3 + GetTriSubface_Static(ornt[3], 0); /* R */
5665:       orntNew[4] = ornt[3] < 0 ? -1 : 1;
5666:       coneNew[5] = fStartNew + (fMax    - fStart)*3 + (c - cStart)*6 + 2;               /* L */
5667:       orntNew[5] = -4;
5668:       DMPlexSetCone(rdm, newp+2, coneNew);
5669:       DMPlexSetConeOrientation(rdm, newp+2, orntNew);
5670: #if defined(PETSC_USE_DEBUG)
5671:       if ((newp+2 < cStartNew) || (newp+2 >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", newp+2, cStartNew, cEndNew);
5672:       for (p = 0; p < 6; ++p) {
5673:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", coneNew[p], fStartNew, fEndNew);
5674:       }
5675: #endif
5676:       /* D hex */
5677:       coneNew[0] = fStartNew + (fMax    - fStart)*3 + (c - cStart)*6 + 3;               /* B */
5678:       orntNew[0] = 0;
5679:       coneNew[1] = fStartNew + (cone[3] - fStart)*3 + GetTriSubface_Static(ornt[3], 2); /* T */
5680:       orntNew[1] = ornt[3] < 0 ? -1 : 1;
5681:       coneNew[2] = fStartNew + (cone[2] - fStart)*3 + GetTriSubface_Static(ornt[2], 2); /* F */
5682:       orntNew[2] = ornt[2] < 0 ? -4 : 2;
5683:       coneNew[3] = fStartNew + (fMax    - fStart)*3 + (c - cStart)*6 + 4;               /* K */
5684:       orntNew[3] = -1;
5685:       coneNew[4] = fStartNew + (fMax    - fStart)*3 + (c - cStart)*6 + 5;               /* R */
5686:       orntNew[4] = 0;
5687:       coneNew[5] = fStartNew + (cone[1] - fStart)*3 + GetTriSubface_Static(ornt[1], 1); /* L */
5688:       orntNew[5] = ornt[1] < 0 ? -2 : 0;
5689:       DMPlexSetCone(rdm, newp+3, coneNew);
5690:       DMPlexSetConeOrientation(rdm, newp+3, orntNew);
5691: #if defined(PETSC_USE_DEBUG)
5692:       if ((newp+3 < cStartNew) || (newp+3 >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", newp+3, cStartNew, cEndNew);
5693:       for (p = 0; p < 6; ++p) {
5694:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", coneNew[p], fStartNew, fEndNew);
5695:       }
5696: #endif
5697:     }
5698:     for (c = cMax; c < cEnd; ++c) {
5699:       const PetscInt  newp = cStartNew + (cMax - cStart)*4 + (c - cMax)*3;
5700:       const PetscInt *cone, *ornt;
5701:       PetscInt        coneNew[6], orntNew[6];
5702:       PetscInt        o, of, cf;

5704:       DMPlexGetCone(dm, c, &cone);
5705: #if defined(PETSC_USE_DEBUG)
5706:       if (cone[0] >= fMax) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected hybrid face %D (fMax %D) in cone position 0 for cell %D", cone[0], fMax, c);
5707:       if (cone[1] >= fMax) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected hybrid face %D (fMax %D) in cone position 1 for cell %D", cone[1], fMax, c);
5708:       if (cone[2] <  fMax) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected face %D (fMax %D) in cone position 2 for cell %D", cone[2], fMax, c);
5709:       if (cone[3] <  fMax) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected face %D (fMax %D) in cone position 3 for cell %D", cone[3], fMax, c);
5710:       if (cone[4] <  fMax) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected face %D (fMax %D) in cone position 4 for cell %D", cone[4], fMax, c);
5711: #endif
5712:       DMPlexGetConeOrientation(dm, c, &ornt);
5713:       o    = ornt[0] < 0 ? -1 : 1;
5714:       o    = 1;
5715:       /* A hex */
5716:       coneNew[0] = fStartNew + (cone[0] - fStart)*3 + GetTriSubface_Static(ornt[0], 0);                            /* B */
5717:       orntNew[0] = ornt[0] < 0 ? -1 :  1;
5718:       coneNew[1] = fStartNew + (cone[1] - fStart)*3 + GetTriSubface_Static(ornt[1], 0);                            /* T */
5719:       orntNew[1] = ornt[1] < 0 ?  1 : -1;
5720:       cf         = 2;
5721:       of         = ornt[2+cf] < 0 ? -1 : 1;
5722:       coneNew[2] = fStartNew + (fMax - fStart)*3 + (cMax - cStart)*6 + (cone[2+cf] - fMax)*2 + (o*of < 0 ? 0 : 1); /* F */
5723:       orntNew[2] = o*of < 0 ? 0 : -1;
5724:       coneNew[3] = fStartNew + (fMax - fStart)*3 + (cMax - cStart)*6 + (fEnd - fMax)*2 + (c - cMax)*3 + 0;         /* K */
5725:       orntNew[3] = -1;
5726:       coneNew[4] = fStartNew + (fMax - fStart)*3 + (cMax - cStart)*6 + (fEnd - fMax)*2 + (c - cMax)*3 + 2;         /* R */
5727:       orntNew[4] = 0;
5728:       cf         = 0;
5729:       of         = ornt[2+cf] < 0 ? -1 : 1;
5730:       coneNew[5] = fStartNew + (fMax - fStart)*3 + (cMax - cStart)*6 + (cone[2+cf] - fMax)*2 + (o*of < 0 ? 1 : 0); /* L */
5731:       orntNew[5] = o*of < 0 ? 1 : -4;
5732:       DMPlexSetCone(rdm, newp+0, coneNew);
5733:       DMPlexSetConeOrientation(rdm, newp+0, orntNew);
5734: #if defined(PETSC_USE_DEBUG)
5735:       if ((newp+0 < cStartNew) || (newp+0 >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", newp+0, cStartNew, cEndNew);
5736:       for (p = 0; p < 6; ++p) {
5737:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", coneNew[p], fStartNew, fEndNew);
5738:       }
5739: #endif
5740:       /* B hex */
5741:       coneNew[0] = fStartNew + (cone[0] - fStart)*3 + GetTriSubface_Static(ornt[0], 1);                            /* B */
5742:       orntNew[0] = ornt[0] < 0 ? -2 :  0;
5743:       coneNew[1] = fStartNew + (cone[1] - fStart)*3 + GetTriSubface_Static(ornt[1], 1);                            /* T */
5744:       orntNew[1] = ornt[1] < 0 ?  2 : -4;
5745:       coneNew[2] = fStartNew + (fMax - fStart)*3 + (cMax - cStart)*6 + (fEnd - fMax)*2 + (c - cMax)*3 + 0;         /* F */
5746:       orntNew[2] = 0;
5747:       cf         = 1;
5748:       of         = ornt[2+cf] < 0 ? -1 : 1;
5749:       coneNew[3] = fStartNew + (fMax - fStart)*3 + (cMax - cStart)*6 + (cone[2+cf] - fMax)*2 + (o*of < 0 ? 1 : 0); /* K */
5750:       orntNew[3] = o*of < 0 ? 0 : -1;
5751:       coneNew[4] = fStartNew + (fMax - fStart)*3 + (cMax - cStart)*6 + (fEnd - fMax)*2 + (c - cMax)*3 + 1;         /* R */
5752:       orntNew[4] = -1;
5753:       cf         = 0;
5754:       of         = ornt[2+cf] < 0 ? -1 : 1;
5755:       coneNew[5] = fStartNew + (fMax - fStart)*3 + (cMax - cStart)*6 + (cone[2+cf] - fMax)*2 + (o*of < 0 ? 0 : 1); /* L */
5756:       orntNew[5] = o*of < 0 ? 1 : -4;
5757:       DMPlexSetCone(rdm, newp+1, coneNew);
5758:       DMPlexSetConeOrientation(rdm, newp+1, orntNew);
5759: #if defined(PETSC_USE_DEBUG)
5760:       if ((newp+1 < cStartNew) || (newp+1 >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", newp+1, cStartNew, cEndNew);
5761:       for (p = 0; p < 6; ++p) {
5762:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", coneNew[p], fStartNew, fEndNew);
5763:       }
5764: #endif
5765:       /* C hex */
5766:       coneNew[0] = fStartNew + (cone[0] - fStart)*3 + GetTriSubface_Static(ornt[0], 2);                            /* B */
5767:       orntNew[0] = ornt[0] < 0 ? -4 : 2;
5768:       coneNew[1] = fStartNew + (cone[1] - fStart)*3 + GetTriSubface_Static(ornt[1], 2);                            /* T */
5769:       orntNew[1] = ornt[1] < 0 ? 0 : -2;
5770:       cf         = 2;
5771:       of         = ornt[2+cf] < 0 ? -1 : 1;
5772:       coneNew[2] = fStartNew + (fMax - fStart)*3 + (cMax - cStart)*6 + (cone[2+cf] - fMax)*2 + (o*of < 0 ? 1 : 0); /* F */
5773:       orntNew[2] = o*of < 0 ? 0 : -1;
5774:       coneNew[3] = fStartNew + (fMax - fStart)*3 + (cMax - cStart)*6 + (fEnd - fMax)*2 + (c - cMax)*3 + 1;         /* K */
5775:       orntNew[3] = 0;
5776:       cf         = 1;
5777:       of         = ornt[2+cf] < 0 ? -1 : 1;
5778:       coneNew[4] = fStartNew + (fMax - fStart)*3 + (cMax - cStart)*6 + (cone[2+cf] - fMax)*2 + (o*of < 0 ? 0 : 1); /* R */
5779:       orntNew[4] = o*of < 0 ? 0 : -1;
5780:       coneNew[5] = fStartNew + (fMax - fStart)*3 + (cMax - cStart)*6 + (fEnd - fMax)*2 + (c - cMax)*3 + 2;         /* L */
5781:       orntNew[5] = -4;
5782:       DMPlexSetCone(rdm, newp+2, coneNew);
5783:       DMPlexSetConeOrientation(rdm, newp+2, orntNew);
5784: #if defined(PETSC_USE_DEBUG)
5785:       if ((newp+2 < cStartNew) || (newp+2 >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", newp+2, cStartNew, cEndNew);
5786:       for (p = 0; p < 6; ++p) {
5787:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", coneNew[p], fStartNew, fEndNew);
5788:       }
5789: #endif
5790:     }

5792:     /* Split faces have 4 edges and the same cells as the parent */
5793:     DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);
5794:     PetscMalloc1(2 + maxSupportSize*2, &supportRef);
5795:     for (f = fStart; f < fMax; ++f) {
5796:       const PetscInt  newp = fStartNew + (f - fStart)*3;
5797:       const PetscInt *cone, *ornt, *support;
5798:       PetscInt        coneNew[4], orntNew[4], coneSize, supportSize, s;

5800:       DMPlexGetCone(dm, f, &cone);
5801: #if defined(PETSC_USE_DEBUG)
5802:       for (p = 0; p < 3; ++p) {
5803:         if (cone[p] >= eMax) SETERRQ4(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected hybrid edge %D (eMax %D) in cone position %D for face %D", cone[p], p, eMax, f);
5804:       }
5805: #endif
5806:       DMPlexGetConeOrientation(dm, f, &ornt);
5807:       /* A quad */
5808:       coneNew[0] = eStartNew + (cone[2] - eStart)*2 + (ornt[2] < 0 ? 0 : 1);
5809:       orntNew[0] = ornt[2];
5810:       coneNew[1] = eStartNew + (cone[0] - eStart)*2 + (ornt[0] < 0 ? 1 : 0);
5811:       orntNew[1] = ornt[0];
5812:       coneNew[2] = eStartNew + (eMax    - eStart)*2 + (f - fStart)*3 + 0;
5813:       orntNew[2] = 0;
5814:       coneNew[3] = eStartNew + (eMax    - eStart)*2 + (f - fStart)*3 + 2;
5815:       orntNew[3] = -2;
5816:       DMPlexSetCone(rdm, newp+0, coneNew);
5817:       DMPlexSetConeOrientation(rdm, newp+0, orntNew);
5818: #if defined(PETSC_USE_DEBUG)
5819:       if ((newp+0 < fStartNew) || (newp+0 >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp+0, fStartNew, fEndNew);
5820:       for (p = 0; p < 4; ++p) {
5821:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", coneNew[p], eStartNew, eEndNew);
5822:       }
5823: #endif
5824:       /* B quad */
5825:       coneNew[0] = eStartNew + (cone[0] - eStart)*2 + (ornt[0] < 0 ? 0 : 1);
5826:       orntNew[0] = ornt[0];
5827:       coneNew[1] = eStartNew + (cone[1] - eStart)*2 + (ornt[1] < 0 ? 1 : 0);
5828:       orntNew[1] = ornt[1];
5829:       coneNew[2] = eStartNew + (eMax    - eStart)*2 + (f - fStart)*3 + 1;
5830:       orntNew[2] = 0;
5831:       coneNew[3] = eStartNew + (eMax    - eStart)*2 + (f - fStart)*3 + 0;
5832:       orntNew[3] = -2;
5833:       DMPlexSetCone(rdm, newp+1, coneNew);
5834:       DMPlexSetConeOrientation(rdm, newp+1, orntNew);
5835: #if defined(PETSC_USE_DEBUG)
5836:       if ((newp+1 < fStartNew) || (newp+1 >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp+1, fStartNew, fEndNew);
5837:       for (p = 0; p < 4; ++p) {
5838:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", coneNew[p], eStartNew, eEndNew);
5839:       }
5840: #endif
5841:       /* C quad */
5842:       coneNew[0] = eStartNew + (cone[1] - eStart)*2 + (ornt[1] < 0 ? 0 : 1);
5843:       orntNew[0] = ornt[1];
5844:       coneNew[1] = eStartNew + (cone[2] - eStart)*2 + (ornt[2] < 0 ? 1 : 0);
5845:       orntNew[1] = ornt[2];
5846:       coneNew[2] = eStartNew + (eMax    - eStart)*2 + (f - fStart)*3 + 2;
5847:       orntNew[2] = 0;
5848:       coneNew[3] = eStartNew + (eMax    - eStart)*2 + (f - fStart)*3 + 1;
5849:       orntNew[3] = -2;
5850:       DMPlexSetCone(rdm, newp+2, coneNew);
5851:       DMPlexSetConeOrientation(rdm, newp+2, orntNew);
5852: #if defined(PETSC_USE_DEBUG)
5853:       if ((newp+2 < fStartNew) || (newp+2 >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp+2, fStartNew, fEndNew);
5854:       for (p = 0; p < 4; ++p) {
5855:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", coneNew[p], eStartNew, eEndNew);
5856:       }
5857: #endif
5858:       DMPlexGetSupportSize(dm, f, &supportSize);
5859:       DMPlexGetSupport(dm, f, &support);
5860:       for (r = 0; r < 3; ++r) {
5861:         for (s = 0; s < supportSize; ++s) {
5862:           PetscInt subf;

5864:           DMPlexGetConeSize(dm, support[s], &coneSize);
5865:           if (coneSize != 5 && support[s] >= cMax) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected conesize %D for cell %D (cMax %D)", coneSize, support[s], cMax);
5866:           if (coneSize != 4 && support[s] <  cMax) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected conesize %D for cell %D (cMax %D)", coneSize, support[s], cMax);
5867:           DMPlexGetCone(dm, support[s], &cone);
5868:           DMPlexGetConeOrientation(dm, support[s], &ornt);
5869:           for (c = 0; c < coneSize; ++c) {
5870:             if (cone[c] == f) break;
5871:           }
5872:           subf = GetTriSubfaceInverse_Static(ornt[c], r);
5873:           if (coneSize == 4) {
5874:             supportRef[s] = cStartNew + (support[s] - cStart)*4 + faces[c*3+subf];
5875:           } else if (coneSize == 5) {
5876:             if (c != 0 && c != 1) SETERRQ4(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected position %D in cone %D of cell %D (cMax %D) for face %D", c, support[s], cMax, f);
5877:             supportRef[s] = cStartNew + (cMax - cStart)*4 + (support[s] - cMax)*3 + subf;
5878:           } else SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected conesize %D for cell %D (cMax %D)", coneSize, support[s], cMax);
5879:         }
5880:         DMPlexSetSupport(rdm, newp+r, supportRef);
5881: #if defined(PETSC_USE_DEBUG)
5882:         if ((newp+r < fStartNew) || (newp+r >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp+r, fStartNew, fEndNew);
5883:         for (p = 0; p < supportSize; ++p) {
5884:           if ((supportRef[p] < cStartNew) || (supportRef[p] >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", supportRef[p], cStartNew, cEndNew);
5885:         }
5886: #endif
5887:       }
5888:     }
5889:     /* Interior faces have 4 edges and 2 cells */
5890:     for (c = cStart; c < cMax; ++c) {
5891:       PetscInt        newp = fStartNew + (fMax - fStart)*3 + (c - cStart)*6;
5892:       const PetscInt *cone, *ornt;
5893:       PetscInt        coneNew[4], orntNew[4];
5894:       PetscInt        supportNew[2];

5896:       DMPlexGetCone(dm, c, &cone);
5897: #if defined(PETSC_USE_DEBUG)
5898:       for (p = 0; p < 4; ++p) {
5899:         if (cone[p] >= fMax) SETERRQ4(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected hybrid face %D (fMax %D) in cone position %D for face %D", cone[p], p, fMax, f);
5900:       }
5901: #endif
5902:       DMPlexGetConeOrientation(dm, c, &ornt);
5903:       /* Face {a, g, m, h} */
5904:       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*3 + GetTriInteriorEdge_Static(ornt[0],0);
5905:       orntNew[0] = 0;
5906:       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart)*4 + 0;
5907:       orntNew[1] = 0;
5908:       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart)*4 + 1;
5909:       orntNew[2] = -2;
5910:       coneNew[3] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*3 + GetTriInteriorEdge_Static(ornt[1],2);
5911:       orntNew[3] = -2;
5912:       DMPlexSetCone(rdm, newp, coneNew);
5913:       DMPlexSetConeOrientation(rdm, newp, orntNew);
5914: #if defined(PETSC_USE_DEBUG)
5915:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
5916:       for (p = 0; p < 4; ++p) {
5917:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", coneNew[p], eStartNew, eEndNew);
5918:       }
5919: #endif
5920:       supportNew[0] = cStartNew + (c - cStart)*4 + 0;
5921:       supportNew[1] = cStartNew + (c - cStart)*4 + 1;
5922:       DMPlexSetSupport(rdm, newp, supportNew);
5923: #if defined(PETSC_USE_DEBUG)
5924:       for (p = 0; p < 2; ++p) {
5925:         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", supportNew[p], cStartNew, cEndNew);
5926:       }
5927: #endif
5928:       ++newp;
5929:       /* Face {g, b, l , m} */
5930:       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*3 + GetTriInteriorEdge_Static(ornt[0],1);
5931:       orntNew[0] = -2;
5932:       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*3 + GetTriInteriorEdge_Static(ornt[3],0);
5933:       orntNew[1] = 0;
5934:       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart)*4 + 3;
5935:       orntNew[2] = 0;
5936:       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart)*4 + 0;
5937:       orntNew[3] = -2;
5938:       DMPlexSetCone(rdm, newp, coneNew);
5939:       DMPlexSetConeOrientation(rdm, newp, orntNew);
5940: #if defined(PETSC_USE_DEBUG)
5941:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
5942:       for (p = 0; p < 4; ++p) {
5943:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", coneNew[p], eStartNew, eEndNew);
5944:       }
5945: #endif
5946:       supportNew[0] = cStartNew + (c - cStart)*4 + 1;
5947:       supportNew[1] = cStartNew + (c - cStart)*4 + 2;
5948:       DMPlexSetSupport(rdm, newp, supportNew);
5949: #if defined(PETSC_USE_DEBUG)
5950:       for (p = 0; p < 2; ++p) {
5951:         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", supportNew[p], cStartNew, cEndNew);
5952:       }
5953: #endif
5954:       ++newp;
5955:       /* Face {c, g, m, i} */
5956:       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*3 + GetTriInteriorEdge_Static(ornt[0],2);
5957:       orntNew[0] = 0;
5958:       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart)*4 + 0;
5959:       orntNew[1] = 0;
5960:       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart)*4 + 2;
5961:       orntNew[2] = -2;
5962:       coneNew[3] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*3 + GetTriInteriorEdge_Static(ornt[2],0);
5963:       orntNew[3] = -2;
5964:       DMPlexSetCone(rdm, newp, coneNew);
5965:       DMPlexSetConeOrientation(rdm, newp, orntNew);
5966: #if defined(PETSC_USE_DEBUG)
5967:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
5968:       for (p = 0; p < 4; ++p) {
5969:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", coneNew[p], eStartNew, eEndNew);
5970:       }
5971: #endif
5972:       supportNew[0] = cStartNew + (c - cStart)*4 + 0;
5973:       supportNew[1] = cStartNew + (c - cStart)*4 + 2;
5974:       DMPlexSetSupport(rdm, newp, supportNew);
5975: #if defined(PETSC_USE_DEBUG)
5976:       for (p = 0; p < 2; ++p) {
5977:         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", supportNew[p], cStartNew, cEndNew);
5978:       }
5979: #endif
5980:       ++newp;
5981:       /* Face {d, h, m, i} */
5982:       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*3 + GetTriInteriorEdge_Static(ornt[1],0);
5983:       orntNew[0] = 0;
5984:       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart)*4 + 1;
5985:       orntNew[1] = 0;
5986:       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart)*4 + 2;
5987:       orntNew[2] = -2;
5988:       coneNew[3] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*3 + GetTriInteriorEdge_Static(ornt[2],2);
5989:       orntNew[3] = -2;
5990:       DMPlexSetCone(rdm, newp, coneNew);
5991:       DMPlexSetConeOrientation(rdm, newp, orntNew);
5992: #if defined(PETSC_USE_DEBUG)
5993:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
5994:       for (p = 0; p < 4; ++p) {
5995:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", coneNew[p], eStartNew, eEndNew);
5996:       }
5997: #endif
5998:       supportNew[0] = cStartNew + (c - cStart)*4 + 0;
5999:       supportNew[1] = cStartNew + (c - cStart)*4 + 3;
6000:       DMPlexSetSupport(rdm, newp, supportNew);
6001: #if defined(PETSC_USE_DEBUG)
6002:       for (p = 0; p < 2; ++p) {
6003:         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", supportNew[p], cStartNew, cEndNew);
6004:       }
6005: #endif
6006:       ++newp;
6007:       /* Face {h, m, l, e} */
6008:       coneNew[0] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart)*4 + 1;
6009:       orntNew[0] = 0;
6010:       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart)*4 + 3;
6011:       orntNew[1] = -2;
6012:       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*3 + GetTriInteriorEdge_Static(ornt[3],1);
6013:       orntNew[2] = -2;
6014:       coneNew[3] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*3 + GetTriInteriorEdge_Static(ornt[1],1);
6015:       orntNew[3] = 0;
6016:       DMPlexSetCone(rdm, newp, coneNew);
6017:       DMPlexSetConeOrientation(rdm, newp, orntNew);
6018: #if defined(PETSC_USE_DEBUG)
6019:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
6020:       for (p = 0; p < 4; ++p) {
6021:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", coneNew[p], eStartNew, eEndNew);
6022:       }
6023: #endif
6024:       supportNew[0] = cStartNew + (c - cStart)*4 + 1;
6025:       supportNew[1] = cStartNew + (c - cStart)*4 + 3;
6026:       DMPlexSetSupport(rdm, newp, supportNew);
6027: #if defined(PETSC_USE_DEBUG)
6028:       for (p = 0; p < 2; ++p) {
6029:         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", supportNew[p], cStartNew, cEndNew);
6030:       }
6031: #endif
6032:       ++newp;
6033:       /* Face {i, m, l, f} */
6034:       coneNew[0] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart)*4 + 2;
6035:       orntNew[0] = 0;
6036:       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart)*4 + 3;
6037:       orntNew[1] = -2;
6038:       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*3 + GetTriInteriorEdge_Static(ornt[3],2);
6039:       orntNew[2] = -2;
6040:       coneNew[3] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*3 + GetTriInteriorEdge_Static(ornt[2],1);
6041:       orntNew[3] = 0;
6042:       DMPlexSetCone(rdm, newp, coneNew);
6043:       DMPlexSetConeOrientation(rdm, newp, orntNew);
6044: #if defined(PETSC_USE_DEBUG)
6045:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
6046:       for (p = 0; p < 4; ++p) {
6047:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", coneNew[p], eStartNew, eEndNew);
6048:       }
6049: #endif
6050:       supportNew[0] = cStartNew + (c - cStart)*4 + 2;
6051:       supportNew[1] = cStartNew + (c - cStart)*4 + 3;
6052:       DMPlexSetSupport(rdm, newp, supportNew);
6053: #if defined(PETSC_USE_DEBUG)
6054:       for (p = 0; p < 2; ++p) {
6055:         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", supportNew[p], cStartNew, cEndNew);
6056:       }
6057: #endif
6058:       ++newp;
6059:     }
6060:     /* Hybrid split faces have 4 edges and same cells */
6061:     for (f = fMax; f < fEnd; ++f) {
6062:       const PetscInt *cone, *ornt, *support;
6063:       PetscInt        coneNew[4], orntNew[4];
6064:       PetscInt        size, s;
6065:       const PetscInt  newp = fStartNew + (fMax - fStart)*3 + (cMax - cStart)*6 + (f - fMax)*2;

6067:       DMPlexGetCone(dm, f, &cone);
6068: #if defined(PETSC_USE_DEBUG)
6069:       if (cone[0] >= eMax) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected hybrid edge %D (eMax %D) in cone position 0 for face %D", cone[0], eMax, f);
6070:       if (cone[1] >= eMax) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected hybrid edge %D (eMax %D) in cone position 1 for face %D", cone[1], eMax, f);
6071:       if (cone[2] <  eMax) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected edge %D (eMax %D) in cone position 2 for face %D", cone[2], eMax, f);
6072:       if (cone[3] <  eMax) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected edge %D (eMax %D) in cone position 3 for face %D", cone[3], eMax, f);
6073: #endif
6074:       DMPlexGetConeOrientation(dm, f, &ornt);
6075:       /* A face */
6076:       coneNew[0] = eStartNew + (cone[0] - eStart)*2 + (ornt[0] < 0 ? 1 : 0);
6077:       orntNew[0] = ornt[0];
6078:       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart)*4 + (eEnd - eMax) + (f - fMax);
6079:       orntNew[1] = 0;
6080:       coneNew[2] = eStartNew + (cone[1] - eStart)*2 + (ornt[1] < 0 ? 1 : 0);
6081:       orntNew[2] = ornt[1] < 0 ? 0 : -2;
6082:       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart)*4 + (cone[2] - eMax);
6083:       orntNew[3] = ornt[2] < 0 ? 0 : -2;
6084:       DMPlexSetCone(rdm, newp, coneNew);
6085:       DMPlexSetConeOrientation(rdm, newp, orntNew);
6086: #if defined(PETSC_USE_DEBUG)
6087:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
6088:       for (p = 0; p < 4; ++p) {
6089:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", coneNew[p], eStartNew, eEndNew);
6090:       }
6091: #endif

6093:       /* B face */
6094:       coneNew[0] = eStartNew + (cone[0] - eStart)*2 + (ornt[0] < 0 ? 0 : 1);
6095:       orntNew[0] = ornt[0];
6096:       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart)*4 + (cone[3] - eMax);
6097:       orntNew[1] = ornt[3];
6098:       coneNew[2] = eStartNew + (cone[1] - eStart)*2 + (ornt[1] < 0 ? 0 : 1);
6099:       orntNew[2] = ornt[1] < 0 ? 0 : -2;
6100:       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart)*4 + (eEnd - eMax) + (f - fMax);
6101:       orntNew[3] = -2;
6102:       DMPlexSetCone(rdm, newp+1, coneNew);
6103:       DMPlexSetConeOrientation(rdm, newp+1, orntNew);
6104: #if defined(PETSC_USE_DEBUG)
6105:       if ((newp+1 < fStartNew) || (newp+1 >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp+1, fStartNew, fEndNew);
6106:       for (p = 0; p < 4; ++p) {
6107:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", coneNew[p], eStartNew, eEndNew);
6108:       }
6109: #endif

6111:       DMPlexGetSupportSize(dm, f, &size);
6112:       DMPlexGetSupport(dm, f, &support);
6113:       for (r = 0; r < 2; ++r) {
6114:         for (s = 0; s < size; ++s) {
6115:           const PetscInt *coneCell, *orntCell;
6116:           PetscInt        coneSize, o, of, c;

6118:           DMPlexGetConeSize(dm, support[s], &coneSize);
6119:           if (coneSize != 5 || support[s] < cMax) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected conesize %D for cell %D (cMax %D)", coneSize, support[s], cMax);
6120:           DMPlexGetCone(dm, support[s], &coneCell);
6121:           DMPlexGetConeOrientation(dm, support[s], &orntCell);
6122:           o = orntCell[0] < 0 ? -1 : 1;
6123:           o = 1;
6124:           for (c = 0; c < coneSize; ++c) if (coneCell[c] == f) break;
6125:           if (c == 0 || c == 1) SETERRQ4(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected position in cone %D of cell %D (cMax %D) for face %D", c, support[s], cMax, f);
6126:           if (c == coneSize) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Could not find face %D in cone of cell %D", f, support[s]);
6127:           of = orntCell[c] < 0 ? -1 : 1;
6128:           supportRef[s] = cStartNew + (cMax - cStart)*4 + (support[s] - cMax)*3 + (c-2 + (o*of < 0 ? 1-r : r))%3;
6129:         }
6130:         DMPlexSetSupport(rdm, newp + r, supportRef);
6131: #if defined(PETSC_USE_DEBUG)
6132:         for (p = 0; p < size; ++p) {
6133:           if ((supportRef[p] < cStartNew) || (supportRef[p] >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", supportRef[p], cStartNew, cEndNew);
6134:         }
6135: #endif
6136:       }
6137:     }
6138:     /* Interior hybrid faces have 4 edges and 2 cells */
6139:     for (c = cMax; c < cEnd; ++c) {
6140:       PetscInt        newp = fStartNew + (fMax - fStart)*3 + (cMax - cStart)*6 + (fEnd - fMax)*2 + (c - cMax)*3;
6141:       const PetscInt *cone, *ornt;
6142:       PetscInt        coneNew[4], orntNew[4];
6143:       PetscInt        supportNew[2];

6145:       DMPlexGetCone(dm, c, &cone);
6146: #if defined(PETSC_USE_DEBUG)
6147:       if (cone[0] >= fMax) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected hybrid face %D (fMax %D) in cone position 0 for cell %D", cone[0], fMax, c);
6148:       if (cone[1] >= fMax) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected hybrid face %D (fMax %D) in cone position 1 for cell %D", cone[1], fMax, c);
6149:       if (cone[2] <  fMax) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected face %D (fMax %D) in cone position 2 for cell %D", cone[2], fMax, c);
6150:       if (cone[3] <  fMax) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected face %D (fMax %D) in cone position 3 for cell %D", cone[3], fMax, c);
6151:       if (cone[4] <  fMax) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected face %D (fMax %D) in cone position 3 for cell %D", cone[3], fMax, c);
6152: #endif
6153:       DMPlexGetConeOrientation(dm, c, &ornt);
6154:       /* Face {a, g, h, d} */
6155:       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*3 + GetTriInteriorEdge_Static(ornt[0],0);
6156:       orntNew[0] = 0;
6157:       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart)*4 + (eEnd - eMax) + (fEnd - fMax) + c - cMax;
6158:       orntNew[1] = 0;
6159:       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*3 + GetTriInteriorEdge_Static(ornt[1],0);
6160:       orntNew[2] = -2;
6161:       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart)*4 + (eEnd - eMax) + (cone[2] - fMax);
6162:       orntNew[3] = -2;
6163:       DMPlexSetCone(rdm, newp, coneNew);
6164:       DMPlexSetConeOrientation(rdm, newp, orntNew);
6165: #if defined(PETSC_USE_DEBUG)
6166:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
6167:       for (p = 0; p < 4; ++p) {
6168:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", coneNew[p], eStartNew, eEndNew);
6169:       }
6170: #endif
6171:       supportNew[0] = cStartNew + (cMax - cStart)*4 + (c - cMax)*3 + 0;
6172:       supportNew[1] = cStartNew + (cMax - cStart)*4 + (c - cMax)*3 + 1;
6173:       DMPlexSetSupport(rdm, newp, supportNew);
6174: #if defined(PETSC_USE_DEBUG)
6175:       for (p = 0; p < 2; ++p) {
6176:         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", supportNew[p], cStartNew, cEndNew);
6177:       }
6178: #endif
6179:       ++newp;
6180:       /* Face {b, g, h, l} */
6181:       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*3 + GetTriInteriorEdge_Static(ornt[0],1);
6182:       orntNew[0] = 0;
6183:       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart)*4 + (eEnd - eMax) + (fEnd - fMax) + c - cMax;
6184:       orntNew[1] = 0;
6185:       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*3 + GetTriInteriorEdge_Static(ornt[1],1);
6186:       orntNew[2] = -2;
6187:       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart)*4 + (eEnd - eMax) + (cone[3] - fMax);
6188:       orntNew[3] = -2;
6189:       DMPlexSetCone(rdm, newp, coneNew);
6190:       DMPlexSetConeOrientation(rdm, newp, orntNew);
6191: #if defined(PETSC_USE_DEBUG)
6192:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
6193:       for (p = 0; p < 4; ++p) {
6194:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", coneNew[p], eStartNew, eEndNew);
6195:       }
6196: #endif
6197:       supportNew[0] = cStartNew + (cMax - cStart)*4 + (c - cMax)*3 + 1;
6198:       supportNew[1] = cStartNew + (cMax - cStart)*4 + (c - cMax)*3 + 2;
6199:       DMPlexSetSupport(rdm, newp, supportNew);
6200: #if defined(PETSC_USE_DEBUG)
6201:       for (p = 0; p < 2; ++p) {
6202:         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", supportNew[p], cStartNew, cEndNew);
6203:       }
6204: #endif
6205:       ++newp;
6206:       /* Face {c, g, h, f} */
6207:       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*3 + GetTriInteriorEdge_Static(ornt[0],2);
6208:       orntNew[0] = 0;
6209:       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart)*4 + (eEnd - eMax) + (fEnd - fMax) + c - cMax;
6210:       orntNew[1] = 0;
6211:       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*3 + GetTriInteriorEdge_Static(ornt[1],2);
6212:       orntNew[2] = -2;
6213:       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart)*4 + (eEnd - eMax) + (cone[4] - fMax);
6214:       orntNew[3] = -2;
6215:       DMPlexSetCone(rdm, newp, coneNew);
6216:       DMPlexSetConeOrientation(rdm, newp, orntNew);
6217: #if defined(PETSC_USE_DEBUG)
6218:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
6219:       for (p = 0; p < 4; ++p) {
6220:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", coneNew[p], eStartNew, eEndNew);
6221:       }
6222: #endif
6223:       supportNew[0] = cStartNew + (cMax - cStart)*4 + (c - cMax)*3 + 2;
6224:       supportNew[1] = cStartNew + (cMax - cStart)*4 + (c - cMax)*3 + 0;
6225:       DMPlexSetSupport(rdm, newp, supportNew);
6226: #if defined(PETSC_USE_DEBUG)
6227:       for (p = 0; p < 2; ++p) {
6228:         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", supportNew[p], cStartNew, cEndNew);
6229:       }
6230: #endif
6231:     }
6232:     /* Face edges have 2 vertices and 2 + cell faces supports */
6233:     for (f = fStart; f < fMax; ++f) {
6234:       const PetscInt *cone, *ornt, *support;
6235:       PetscInt        coneSize, supportSize, s;

6237:       DMPlexGetSupportSize(dm, f, &supportSize);
6238:       DMPlexGetSupport(dm, f, &support);
6239:       for (r = 0; r < 3; ++r) {
6240:         const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (f - fStart)*3 + r;
6241:         PetscInt        coneNew[2];
6242:         PetscInt        fint[4][3] = { {0, 1, 2},
6243:                                        {3, 4, 0},
6244:                                        {2, 5, 3},
6245:                                        {1, 4, 5} };

6247:         DMPlexGetCone(dm, f, &cone);
6248:         if (cone[r] >= eMax) SETERRQ4(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected cone point %D in position %D for face %D (eMax %D)", cone[r], r, f, eMax);
6249:         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r] - eStart);
6250:         coneNew[1] = vStartNew + (vEnd - vStart) + (eMax - eStart) + f - fStart;
6251:         DMPlexSetCone(rdm, newp, coneNew);
6252: #if defined(PETSC_USE_DEBUG)
6253:         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eEndNew);
6254:         for (p = 0; p < 2; ++p) {
6255:           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", coneNew[p], vStartNew, vEndNew);
6256:         }
6257: #endif
6258:         supportRef[0] = fStartNew + (f - fStart)*3 + (r+0)%3;
6259:         supportRef[1] = fStartNew + (f - fStart)*3 + (r+1)%3;
6260:         for (s = 0; s < supportSize; ++s) {
6261:           PetscInt er;

6263:           supportRef[2+s] = -1;
6264:           DMPlexGetConeSize(dm, support[s], &coneSize);
6265:           if (coneSize != 5 && support[s] >= cMax) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected conesize %D for cell %D (cMax %D)", coneSize, support[s], cMax);
6266:           if (coneSize != 4 && support[s] <  cMax) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected conesize %D for cell %D (cMax %D)", coneSize, support[s], cMax);
6267:           DMPlexGetCone(dm, support[s], &cone);
6268:           DMPlexGetConeOrientation(dm, support[s], &ornt);
6269:           for (c = 0; c < coneSize; ++c) {if (cone[c] == f) break;}
6270:           er = GetTriInteriorEdgeInverse_Static(ornt[c], r);
6271:           if (coneSize == 4) {
6272:             supportRef[2+s] = fStartNew + (fMax - fStart)*3 + (support[s] - cStart)*6 + fint[c][er];
6273:           } else if (coneSize == 5) {
6274:             if (c != 0 && c != 1) SETERRQ4(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected position %D in cone %D of cell %D (cMax %D) for face %D", c, support[s], cMax, f);
6275:             supportRef[2+s] = fStartNew + (fMax - fStart)*3 + (cMax - cStart)*6 + (fEnd - fMax)*2 + (support[s] - cMax)*3 + er;
6276:           }
6277:         }
6278:         DMPlexSetSupport(rdm, newp, supportRef);
6279: #if defined(PETSC_USE_DEBUG)
6280:         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eEndNew);
6281:         for (p = 0; p < supportSize + 2; ++p) {
6282:           if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", supportRef[p], fStartNew, fEndNew);
6283:         }
6284: #endif
6285:       }
6286:     }
6287:     /* Interior cell edges have 2 vertices and 3 faces */
6288:     for (c = cStart; c < cMax; ++c) {
6289:       const PetscInt *cone;
6290:       PetscInt       fint[4][3] = { {0,1,2},
6291:                                     {0,3,4},
6292:                                     {2,3,5},
6293:                                     {1,4,5} } ;

6295:       DMPlexGetCone(dm, c, &cone);
6296:       for (r = 0; r < 4; r++) {
6297:         PetscInt       coneNew[2], supportNew[3];
6298:         const PetscInt newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart)*4 + r;

6300:         if (cone[r] >= fMax) SETERRQ4(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected hybrid face %D (fMax %D) in cone position %D for cell %D", cone[r], r, fMax, c);
6301:         coneNew[0] = vStartNew + (vEnd - vStart) + (eMax - eStart) + (cone[r] - fStart);
6302:         coneNew[1] = vStartNew + (vEnd - vStart) + (eMax - eStart) + (fMax     -fStart) + c - cStart;
6303:         DMPlexSetCone(rdm, newp, coneNew);
6304: #if defined(PETSC_USE_DEBUG)
6305:         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eEndNew);
6306:         for (p = 0; p < 2; ++p) {
6307:           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", coneNew[p], vStartNew, vEndNew);
6308:         }
6309: #endif
6310:         supportNew[0] = fStartNew + (fMax - fStart)*3 + (c - cStart)*6 + fint[r][0];
6311:         supportNew[1] = fStartNew + (fMax - fStart)*3 + (c - cStart)*6 + fint[r][1];
6312:         supportNew[2] = fStartNew + (fMax - fStart)*3 + (c - cStart)*6 + fint[r][2];
6313:         DMPlexSetSupport(rdm, newp, supportNew);
6314: #if defined(PETSC_USE_DEBUG)
6315:         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eEndNew);
6316:         for (p = 0; p < 3; ++p) {
6317:           if ((supportNew[p] < fStartNew) || (supportNew[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", supportNew[p], fStartNew, fEndNew);
6318:         }
6319: #endif
6320:       }
6321:     }
6322:     /* Hybrid edges have two vertices and the same faces */
6323:     for (e = eMax; e < eEnd; ++e) {
6324:       const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart)*4 + (e - eMax);
6325:       const PetscInt *cone, *support, *fcone;
6326:       PetscInt        coneNew[2], size, fsize, s;

6328:       DMPlexGetCone(dm, e, &cone);
6329:       DMPlexGetSupportSize(dm, e, &size);
6330:       DMPlexGetSupport(dm, e, &support);
6331:       coneNew[0] = vStartNew + (cone[0] - vStart);
6332:       coneNew[1] = vStartNew + (cone[1] - vStart);
6333:       DMPlexSetCone(rdm, newp, coneNew);
6334: #if defined(PETSC_USE_DEBUG)
6335:       if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is a edge [%D, %D)", newp, eStartNew, eEndNew);
6336:       for (p = 0; p < 2; ++p) {
6337:         if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", coneNew[p], vStartNew, vEndNew);
6338:       }
6339: #endif
6340:       for (s = 0; s < size; ++s) {
6341:         DMPlexGetConeSize(dm, support[s], &fsize);
6342:         DMPlexGetCone(dm, support[s], &fcone);
6343:         for (c = 0; c < fsize; ++c) if (fcone[c] == e) break;
6344:         if ((c < 2) || (c > 3)) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Edge %D not found in cone of face %D", e, support[s]);
6345:         supportRef[s] = fStartNew + (fMax - fStart)*3 + (cMax - cStart)*6 + (support[s] - fMax)*2 + c-2;
6346:       }
6347:       DMPlexSetSupport(rdm, newp, supportRef);
6348: #if defined(PETSC_USE_DEBUG)
6349:       for (p = 0; p < size; ++p) {
6350:         if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", supportRef[p], fStartNew, fEndNew);
6351:       }
6352: #endif
6353:     }
6354:     /* Hybrid face edges have 2 vertices and 2 + cell faces supports */
6355:     for (f = fMax; f < fEnd; ++f) {
6356:       const PetscInt *cone, *ornt, *support;
6357:       PetscInt        coneSize, supportSize;
6358:       const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart)*4 + (eEnd - eMax) + f - fMax;
6359:       PetscInt        coneNew[2], s;

6361:       DMPlexGetCone(dm, f, &cone);
6362: #if defined(PETSC_USE_DEBUG)
6363:       if (cone[0] >= eMax) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected cone point %D in position 0 for face %D (eMax %D)", cone[0], f, eMax);
6364:       if (cone[1] >= eMax) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected cone point %D in position 1 for face %D (eMax %D)", cone[1], f, eMax);
6365: #endif
6366:       coneNew[0] = vStartNew + (vEnd - vStart) + (cone[0] - eStart);
6367:       coneNew[1] = vStartNew + (vEnd - vStart) + (cone[1] - eStart);
6368:       DMPlexSetCone(rdm, newp, coneNew);
6369: #if defined(PETSC_USE_DEBUG)
6370:       if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eEndNew);
6371:       for (p = 0; p < 2; ++p) {
6372:         if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", coneNew[p], vStartNew, vEndNew);
6373:       }
6374: #endif
6375:       supportRef[0] = fStartNew + (fMax - fStart)*3 + (cMax - cStart)*6 + (f- fMax)*2 + 0;
6376:       supportRef[1] = fStartNew + (fMax - fStart)*3 + (cMax - cStart)*6 + (f- fMax)*2 + 1;
6377:       DMPlexGetSupportSize(dm, f, &supportSize);
6378:       DMPlexGetSupport(dm, f, &support);
6379:       for (s = 0; s < supportSize; ++s) {
6380:         DMPlexGetConeSize(dm, support[s], &coneSize);
6381:         if (coneSize != 5 || support[s] < cMax) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected conesize %D for cell %D (cMax %D)", coneSize, support[s], cMax);
6382:         DMPlexGetCone(dm, support[s], &cone);
6383:         DMPlexGetConeOrientation(dm, support[s], &ornt);
6384:         for (c = 0; c < coneSize; ++c) {if (cone[c] == f) break;}
6385:         if (c == 0 || c == 1) SETERRQ4(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected position in cone %D of cell %D (cMax %D) for face %D", c, support[s], cMax, f);
6386:         supportRef[2+s] = fStartNew + (fMax - fStart)*3 + (cMax - cStart)*6 + (fEnd - fMax)*2 + (support[s] - cMax)*3 + c - 2;
6387:       }
6388:       DMPlexSetSupport(rdm, newp, supportRef);
6389: #if defined(PETSC_USE_DEBUG)
6390:       if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eEndNew);
6391:       for (p = 0; p < supportSize + 2; ++p) {
6392:         if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", supportRef[p], fStartNew, fEndNew);
6393:       }
6394: #endif
6395:     }
6396:     /* Hybrid cell edges have 2 vertices and 3 faces */
6397:     for (c = cMax; c < cEnd; ++c) {
6398:       PetscInt       coneNew[2], supportNew[3];
6399:       const PetscInt newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart)*4 + (eEnd - eMax) + (fEnd - fMax) + c - cMax;
6400:       const PetscInt *cone;

6402:       DMPlexGetCone(dm, c, &cone);
6403: #if defined(PETSC_USE_DEBUG)
6404:       if (cone[0] >= fMax) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected hybrid face %D (fMax %D) in cone position 0 for cell %D", cone[0], fMax, c);
6405:       if (cone[1] >= fMax) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected hybrid face %D (fMax %D) in cone position 1 for cell %D", cone[1], fMax, c);
6406: #endif
6407:       coneNew[0] = vStartNew + (vEnd - vStart) + (eMax - eStart) + (cone[0] - fStart);
6408:       coneNew[1] = vStartNew + (vEnd - vStart) + (eMax - eStart) + (cone[1] - fStart);
6409:       DMPlexSetCone(rdm, newp, coneNew);
6410: #if defined(PETSC_USE_DEBUG)
6411:       if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eEndNew);
6412:       for (p = 0; p < 2; ++p) {
6413:         if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", coneNew[p], vStartNew, vEndNew);
6414:       }
6415: #endif
6416:       supportNew[0] = fStartNew + (fMax - fStart)*3 + (cMax - cStart)*6 + (fEnd - fMax)*2 + (c - cMax)*3 + 0;
6417:       supportNew[1] = fStartNew + (fMax - fStart)*3 + (cMax - cStart)*6 + (fEnd - fMax)*2 + (c - cMax)*3 + 1;
6418:       supportNew[2] = fStartNew + (fMax - fStart)*3 + (cMax - cStart)*6 + (fEnd - fMax)*2 + (c - cMax)*3 + 2;
6419:       DMPlexSetSupport(rdm, newp, supportNew);
6420: #if defined(PETSC_USE_DEBUG)
6421:       if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eEndNew);
6422:       for (p = 0; p < 3; ++p) {
6423:         if ((supportNew[p] < fStartNew) || (supportNew[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", supportNew[p], fStartNew, fEndNew);
6424:       }
6425: #endif
6426:     }
6427:     /* Old vertices have identical supports */
6428:     for (v = vStart; v < vEnd; ++v) {
6429:       const PetscInt  newp = vStartNew + (v - vStart);
6430:       const PetscInt *support, *cone;
6431:       PetscInt        size, s;

6433:       DMPlexGetSupportSize(dm, v, &size);
6434:       DMPlexGetSupport(dm, v, &support);
6435:       for (s = 0; s < size; ++s) {
6436:         const PetscInt e = support[s];

6438:         supportRef[s] = -1;
6439:         if (eStart <= e) {
6440:           if (e < eMax) {
6441:             DMPlexGetCone(dm, e, &cone);
6442:             supportRef[s] = eStartNew + (e - eStart)*2 + (cone[1] == v ? 1 : 0);
6443:           } else if (e < eEnd) {
6444:             supportRef[s] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart)*4 + e - eMax;
6445:           } else SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", e, eStart, eEnd);
6446:         } else SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", e, eStart, eEnd);
6447:       }
6448:       DMPlexSetSupport(rdm, newp, supportRef);
6449: #if defined(PETSC_USE_DEBUG)
6450:       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", newp, vStartNew, vEndNew);
6451:       for (p = 0; p < size; ++p) {
6452:         if ((supportRef[p] < eStartNew) || (supportRef[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", supportRef[p], eStartNew, eEndNew);
6453:       }
6454: #endif
6455:     }
6456:     /* Interior edge vertices have 2 + faces supports */
6457:     for (e = eStart; e < eMax; ++e) {
6458:       const PetscInt  newp = vStartNew + (vEnd - vStart) + (e - eStart);
6459:       const PetscInt *cone, *support;
6460:       PetscInt        size, s;

6462:       DMPlexGetSupportSize(dm, e, &size);
6463:       DMPlexGetSupport(dm, e, &support);
6464:       supportRef[0] = eStartNew + (e - eStart)*2 + 0;
6465:       supportRef[1] = eStartNew + (e - eStart)*2 + 1;
6466:       for (s = 0; s < size; ++s) {
6467:         PetscInt r, coneSize;

6469:         supportRef[2+s] = -1;
6470:         DMPlexGetConeSize(dm, support[s], &coneSize);
6471:         if (coneSize != 4 && support[s] >= fMax) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected conesize %D for face %D (fMax %D)", coneSize, support[s], fMax);
6472:         if (coneSize != 3 && support[s] <  fMax) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected conesize %D for face %D (fMax %D)", coneSize, support[s], fMax);
6473:         DMPlexGetCone(dm, support[s], &cone);
6474:         for (r = 0; r < coneSize; ++r) {if (cone[r] == e) break;}
6475:         if (coneSize == 3) supportRef[2+s] = eStartNew + (eMax - eStart)*2 + (support[s] - fStart)*3 + r;
6476:         else if (coneSize == 4) {
6477:           if (r != 0 && r != 1) SETERRQ4(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected position in cone %D of face %D (fMax %D) for edge %D", r, support[s], fMax, e);
6478:           supportRef[2+s] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart)*4 + (eEnd - eMax) + support[s] - fMax;
6479:         } else SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected conesize %D for face %D (fMax %D)", coneSize, support[s], fMax);
6480:       }
6481:       DMPlexSetSupport(rdm, newp, supportRef);
6482: #if defined(PETSC_USE_DEBUG)
6483:       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", newp, vStartNew, vEndNew);
6484:       for (p = 0; p < 2+size; ++p) {
6485:         if ((supportRef[p] < eStartNew) || (supportRef[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", supportRef[p], eStartNew, eEndNew);
6486:       }
6487: #endif
6488:     }
6489:     /* Split Edges have 2 vertices and the same faces as the parent */
6490:     for (e = eStart; e < eMax; ++e) {
6491:       const PetscInt newv = vStartNew + (vEnd - vStart) + (e - eStart);

6493:       for (r = 0; r < 2; ++r) {
6494:         const PetscInt  newp = eStartNew + (e - eStart)*2 + r;
6495:         const PetscInt *cone, *ornt, *support;
6496:         PetscInt        coneNew[2], coneSize, c, supportSize, s;

6498:         DMPlexGetCone(dm, e, &cone);
6499:         coneNew[0]       = vStartNew + (cone[0] - vStart);
6500:         coneNew[1]       = vStartNew + (cone[1] - vStart);
6501:         coneNew[(r+1)%2] = newv;
6502:         DMPlexSetCone(rdm, newp, coneNew);
6503: #if defined(PETSC_USE_DEBUG)
6504:         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eEndNew);
6505:         for (p = 0; p < 2; ++p) {
6506:           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", coneNew[p], vStartNew, vEndNew);
6507:         }
6508: #endif
6509:         DMPlexGetSupportSize(dm, e, &supportSize);
6510:         DMPlexGetSupport(dm, e, &support);
6511:         for (s = 0; s < supportSize; ++s) {
6512:           DMPlexGetConeSize(dm, support[s], &coneSize);
6513:           if (coneSize != 4 && support[s] >= fMax) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected conesize %D for face %D (fMax %D)", coneSize, support[s], fMax);
6514:           if (coneSize != 3 && support[s] <  fMax) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected conesize %D for face %D (fMax %D)", coneSize, support[s], fMax);
6515:           DMPlexGetCone(dm, support[s], &cone);
6516:           DMPlexGetConeOrientation(dm, support[s], &ornt);
6517:           for (c = 0; c < coneSize; ++c) {
6518:             if (cone[c] == e) break;
6519:           }
6520:           if (coneSize == 3) supportRef[s] = fStartNew + (support[s] - fStart)*3 + (c + (ornt[c] < 0 ? 1-r : r))%3;
6521:           else if (coneSize == 4) {
6522:             if (c != 0 && c != 1) SETERRQ4(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected position in cone %D of face %D (fMax %D) for edge %D", c, support[s], fMax, e);
6523:             supportRef[s] = fStartNew + (fMax - fStart)*3 + (cMax - cStart)*6 + (support[s] - fMax)*2 + (ornt[c] < 0 ? 1-r : r);
6524:           } else SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected conesize %D for face %D (fMax %D)", coneSize, support[s], fMax);
6525:         }
6526:         DMPlexSetSupport(rdm, newp, supportRef);
6527: #if defined(PETSC_USE_DEBUG)
6528:         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eEndNew);
6529:         for (p = 0; p < supportSize; ++p) {
6530:           if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", supportRef[p], fStartNew, fEndNew);
6531:         }
6532: #endif
6533:       }
6534:     }
6535:     /* Face vertices have 3 + cells supports */
6536:     for (f = fStart; f < fMax; ++f) {
6537:       const PetscInt  newp = vStartNew + (vEnd - vStart) + (eMax - eStart) + (f - fStart);
6538:       const PetscInt *cone, *support;
6539:       PetscInt        size, s;

6541:       DMPlexGetSupportSize(dm, f, &size);
6542:       DMPlexGetSupport(dm, f, &support);
6543:       supportRef[0] = eStartNew + (eMax - eStart)*2 + (f - fStart)*3 + 0;
6544:       supportRef[1] = eStartNew + (eMax - eStart)*2 + (f - fStart)*3 + 1;
6545:       supportRef[2] = eStartNew + (eMax - eStart)*2 + (f - fStart)*3 + 2;
6546:       for (s = 0; s < size; ++s) {
6547:         PetscInt r, coneSize;

6549:         supportRef[3+s] = -1;
6550:         DMPlexGetConeSize(dm, support[s], &coneSize);
6551:         if (coneSize != 5 && support[s] >= cMax) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected conesize %D for cell %D (cMax %D)", coneSize, support[s], cMax);
6552:         if (coneSize != 4 && support[s] <  cMax) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected conesize %D for cell %D (cMax %D)", coneSize, support[s], cMax);
6553:         DMPlexGetCone(dm, support[s], &cone);
6554:         for (r = 0; r < coneSize; ++r) {if (cone[r] == f) break;}
6555:         if (coneSize == 4) supportRef[3+s] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (support[s] - cStart)*4 + r;
6556:         else if (coneSize == 5) {
6557:           if (r != 0 && r != 1) SETERRQ4(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected position in cone %D of cell %D (cMax %D) for face %D", r, support[s], cMax, f);
6558:           supportRef[3+s] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart)*4 + (eEnd - eMax) + (fEnd - fMax) + support[s] - cMax;
6559:         }
6560:       }
6561:       DMPlexSetSupport(rdm, newp, supportRef);
6562: #if defined(PETSC_USE_DEBUG)
6563:       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", newp, vStartNew, vEndNew);
6564:       for (p = 0; p < 3+size; ++p) {
6565:         if ((supportRef[p] < eStartNew) || (supportRef[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", supportRef[p], eStartNew, eEndNew);
6566:       }
6567: #endif
6568:     }
6569:     /* Interior cell vertices have 4 supports */
6570:     for (c = cStart; c < cMax; ++c) {
6571:       const PetscInt  newp = vStartNew + (vEnd - vStart) + (eMax - eStart) + (fMax - fStart) + c - cStart;

6573:       supportRef[0] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart)*4 + 0;
6574:       supportRef[1] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart)*4 + 1;
6575:       supportRef[2] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart)*4 + 2;
6576:       supportRef[3] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart)*4 + 3;
6577:       DMPlexSetSupport(rdm, newp, supportRef);
6578: #if defined(PETSC_USE_DEBUG)
6579:       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", newp, vStartNew, vEndNew);
6580:       for (p = 0; p < 4; ++p) {
6581:         if ((supportRef[p] < eStartNew) || (supportRef[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", supportRef[p], eStartNew, eEndNew);
6582:       }
6583: #endif
6584:     }
6585:     PetscFree(supportRef);
6586:     DMPlexRestoreFaces_Internal(dm, 3, cStart, NULL, NULL, &faces);
6587:     break;
6588:   case REFINER_HEX_3D:
6589:     /*
6590:      Bottom (viewed from top)    Top
6591:      1---------2---------2       7---------2---------6
6592:      |         |         |       |         |         |
6593:      |    B    2    C    |       |    H    2    G    |
6594:      |         |         |       |         |         |
6595:      3----3----0----1----1       3----3----0----1----1
6596:      |         |         |       |         |         |
6597:      |    A    0    D    |       |    E    0    F    |
6598:      |         |         |       |         |         |
6599:      0---------0---------3       4---------0---------5
6600:      */
6601:     /* All cells have 6 faces: Bottom, Top, Front, Back, Right, Left */
6602:     for (c = cStart; c < cEnd; ++c) {
6603:       const PetscInt  newp = (c - cStart)*8;
6604:       const PetscInt *cone, *ornt;
6605:       PetscInt        coneNew[6], orntNew[6];

6607:       DMPlexGetCone(dm, c, &cone);
6608:       DMPlexGetConeOrientation(dm, c, &ornt);
6609:       /* A hex */
6610:       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], 0);
6611:       orntNew[0] = ornt[0];
6612:       coneNew[1] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  8; /* AE */
6613:       orntNew[1] = 0;
6614:       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetQuadSubface_Static(ornt[2], 0);
6615:       orntNew[2] = ornt[2];
6616:       coneNew[3] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  3; /* AB */
6617:       orntNew[3] = 0;
6618:       coneNew[4] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  0; /* AD */
6619:       orntNew[4] = 0;
6620:       coneNew[5] = fStartNew + (cone[5] - fStart)*4 + GetQuadSubface_Static(ornt[5], 0);
6621:       orntNew[5] = ornt[5];
6622:       DMPlexSetCone(rdm, newp+0, coneNew);
6623:       DMPlexSetConeOrientation(rdm, newp+0, orntNew);
6624: #if defined(PETSC_USE_DEBUG)
6625:       if ((newp+0 < cStartNew) || (newp+0 >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", newp+0, cStartNew, cEndNew);
6626:       for (p = 0; p < 6; ++p) {
6627:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", coneNew[p], fStartNew, fEndNew);
6628:       }
6629: #endif
6630:       /* B hex */
6631:       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], 1);
6632:       orntNew[0] = ornt[0];
6633:       coneNew[1] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 + 11; /* BH */
6634:       orntNew[1] = 0;
6635:       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  3; /* AB */
6636:       orntNew[2] = -1;
6637:       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetQuadSubface_Static(ornt[3], 1);
6638:       orntNew[3] = ornt[3];
6639:       coneNew[4] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  2; /* BC */
6640:       orntNew[4] = 0;
6641:       coneNew[5] = fStartNew + (cone[5] - fStart)*4 + GetQuadSubface_Static(ornt[5], 3);
6642:       orntNew[5] = ornt[5];
6643:       DMPlexSetCone(rdm, newp+1, coneNew);
6644:       DMPlexSetConeOrientation(rdm, newp+1, orntNew);
6645: #if defined(PETSC_USE_DEBUG)
6646:       if ((newp+1 < cStartNew) || (newp+1 >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", newp+1, cStartNew, cEndNew);
6647:       for (p = 0; p < 6; ++p) {
6648:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", coneNew[p], fStartNew, fEndNew);
6649:       }
6650: #endif
6651:       /* C hex */
6652:       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], 2);
6653:       orntNew[0] = ornt[0];
6654:       coneNew[1] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 + 10; /* CG */
6655:       orntNew[1] = 0;
6656:       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  1; /* CD */
6657:       orntNew[2] = -1;
6658:       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetQuadSubface_Static(ornt[3], 0);
6659:       orntNew[3] = ornt[3];
6660:       coneNew[4] = fStartNew + (cone[4] - fStart)*4 + GetQuadSubface_Static(ornt[4], 1);
6661:       orntNew[4] = ornt[4];
6662:       coneNew[5] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  2; /* BC */
6663:       orntNew[5] = -4;
6664:       DMPlexSetCone(rdm, newp+2, coneNew);
6665:       DMPlexSetConeOrientation(rdm, newp+2, orntNew);
6666: #if defined(PETSC_USE_DEBUG)
6667:       if ((newp+2 < cStartNew) || (newp+2 >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", newp+2, cStartNew, cEndNew);
6668:       for (p = 0; p < 6; ++p) {
6669:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", coneNew[p], fStartNew, fEndNew);
6670:       }
6671: #endif
6672:       /* D hex */
6673:       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], 3);
6674:       orntNew[0] = ornt[0];
6675:       coneNew[1] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  9; /* DF */
6676:       orntNew[1] = 0;
6677:       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetQuadSubface_Static(ornt[2], 1);
6678:       orntNew[2] = ornt[2];
6679:       coneNew[3] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  1; /* CD */
6680:       orntNew[3] = 0;
6681:       coneNew[4] = fStartNew + (cone[4] - fStart)*4 + GetQuadSubface_Static(ornt[4], 0);
6682:       orntNew[4] = ornt[4];
6683:       coneNew[5] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  0; /* AD */
6684:       orntNew[5] = -4;
6685:       DMPlexSetCone(rdm, newp+3, coneNew);
6686:       DMPlexSetConeOrientation(rdm, newp+3, orntNew);
6687: #if defined(PETSC_USE_DEBUG)
6688:       if ((newp+3 < cStartNew) || (newp+3 >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", newp+3, cStartNew, cEndNew);
6689:       for (p = 0; p < 6; ++p) {
6690:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", coneNew[p], fStartNew, fEndNew);
6691:       }
6692: #endif
6693:       /* E hex */
6694:       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  8; /* AE */
6695:       orntNew[0] = -4;
6696:       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], 0);
6697:       orntNew[1] = ornt[1];
6698:       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetQuadSubface_Static(ornt[2], 3);
6699:       orntNew[2] = ornt[2];
6700:       coneNew[3] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  7; /* EH */
6701:       orntNew[3] = 0;
6702:       coneNew[4] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  4; /* EF */
6703:       orntNew[4] = -1;
6704:       coneNew[5] = fStartNew + (cone[5] - fStart)*4 + GetQuadSubface_Static(ornt[5], 1);
6705:       orntNew[5] = ornt[5];
6706:       DMPlexSetCone(rdm, newp+4, coneNew);
6707:       DMPlexSetConeOrientation(rdm, newp+4, orntNew);
6708: #if defined(PETSC_USE_DEBUG)
6709:       if ((newp+4 < cStartNew) || (newp+4 >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", newp+4, cStartNew, cEndNew);
6710:       for (p = 0; p < 6; ++p) {
6711:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", coneNew[p], fStartNew, fEndNew);
6712:       }
6713: #endif
6714:       /* F hex */
6715:       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  9; /* DF */
6716:       orntNew[0] = -4;
6717:       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], 1);
6718:       orntNew[1] = ornt[1];
6719:       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetQuadSubface_Static(ornt[2], 2);
6720:       orntNew[2] = ornt[2];
6721:       coneNew[3] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  5; /* FG */
6722:       orntNew[3] = -1;
6723:       coneNew[4] = fStartNew + (cone[4] - fStart)*4 + GetQuadSubface_Static(ornt[4], 3);
6724:       orntNew[4] = ornt[4];
6725:       coneNew[5] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  4; /* EF */
6726:       orntNew[5] = 1;
6727:       DMPlexSetCone(rdm, newp+5, coneNew);
6728:       DMPlexSetConeOrientation(rdm, newp+5, orntNew);
6729: #if defined(PETSC_USE_DEBUG)
6730:       if ((newp+5 < cStartNew) || (newp+5 >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", newp+5, cStartNew, cEndNew);
6731:       for (p = 0; p < 6; ++p) {
6732:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", coneNew[p], fStartNew, fEndNew);
6733:       }
6734: #endif
6735:       /* G hex */
6736:       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 + 10; /* CG */
6737:       orntNew[0] = -4;
6738:       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], 2);
6739:       orntNew[1] = ornt[1];
6740:       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  5; /* FG */
6741:       orntNew[2] = 0;
6742:       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetQuadSubface_Static(ornt[3], 3);
6743:       orntNew[3] = ornt[3];
6744:       coneNew[4] = fStartNew + (cone[4] - fStart)*4 + GetQuadSubface_Static(ornt[4], 2);
6745:       orntNew[4] = ornt[4];
6746:       coneNew[5] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  6; /* GH */
6747:       orntNew[5] = -3;
6748:       DMPlexSetCone(rdm, newp+6, coneNew);
6749:       DMPlexSetConeOrientation(rdm, newp+6, orntNew);
6750: #if defined(PETSC_USE_DEBUG)
6751:       if ((newp+6 < cStartNew) || (newp+6 >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", newp+6, cStartNew, cEndNew);
6752:       for (p = 0; p < 6; ++p) {
6753:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", coneNew[p], fStartNew, fEndNew);
6754:       }
6755: #endif
6756:       /* H hex */
6757:       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 + 11; /* BH */
6758:       orntNew[0] = -4;
6759:       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], 3);
6760:       orntNew[1] = ornt[1];
6761:       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  7; /* EH */
6762:       orntNew[2] = -1;
6763:       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetQuadSubface_Static(ornt[3], 2);
6764:       orntNew[3] = ornt[3];
6765:       coneNew[4] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  6; /* GH */
6766:       orntNew[4] = 3;
6767:       coneNew[5] = fStartNew + (cone[5] - fStart)*4 + GetQuadSubface_Static(ornt[5], 2);
6768:       orntNew[5] = ornt[5];
6769:       DMPlexSetCone(rdm, newp+7, coneNew);
6770:       DMPlexSetConeOrientation(rdm, newp+7, orntNew);
6771: #if defined(PETSC_USE_DEBUG)
6772:       if ((newp+7 < cStartNew) || (newp+7 >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", newp+7, cStartNew, cEndNew);
6773:       for (p = 0; p < 6; ++p) {
6774:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", coneNew[p], fStartNew, fEndNew);
6775:       }
6776: #endif
6777:     }
6778:     /* Split faces have 4 edges and the same cells as the parent */
6779:     DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);
6780:     PetscMalloc1(4 + maxSupportSize*2, &supportRef);
6781:     for (f = fStart; f < fEnd; ++f) {
6782:       for (r = 0; r < 4; ++r) {
6783:         /* TODO: This can come from GetFaces_Internal() */
6784:         const PetscInt  newCells[24] = {0, 1, 2, 3,  4, 5, 6, 7,  0, 3, 5, 4,  2, 1, 7, 6,  3, 2, 6, 5,  0, 4, 7, 1};
6785:         const PetscInt  newp = fStartNew + (f - fStart)*4 + r;
6786:         const PetscInt *cone, *ornt, *support;
6787:         PetscInt        coneNew[4], orntNew[4], coneSize, c, supportSize, s;

6789:         DMPlexGetCone(dm, f, &cone);
6790:         DMPlexGetConeOrientation(dm, f, &ornt);
6791:         coneNew[(r+3)%4] = eStartNew + (cone[(r+3)%4] - eStart)*2 + (ornt[(r+3)%4] < 0 ? 0 : 1);
6792:         orntNew[(r+3)%4] = ornt[(r+3)%4];
6793:         coneNew[(r+0)%4] = eStartNew + (cone[r]       - eStart)*2 + (ornt[r] < 0 ? 1 : 0);
6794:         orntNew[(r+0)%4] = ornt[r];
6795:         coneNew[(r+1)%4] = eStartNew + (eEnd - eStart)*2 + (f - fStart)*4 + r;
6796:         orntNew[(r+1)%4] = 0;
6797:         coneNew[(r+2)%4] = eStartNew + (eEnd - eStart)*2 + (f - fStart)*4 + (r+3)%4;
6798:         orntNew[(r+2)%4] = -2;
6799:         DMPlexSetCone(rdm, newp, coneNew);
6800:         DMPlexSetConeOrientation(rdm, newp, orntNew);
6801: #if defined(PETSC_USE_DEBUG)
6802:         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
6803:         for (p = 0; p < 4; ++p) {
6804:           if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", coneNew[p], eStartNew, eEndNew);
6805:         }
6806: #endif
6807:         DMPlexGetSupportSize(dm, f, &supportSize);
6808:         DMPlexGetSupport(dm, f, &support);
6809:         for (s = 0; s < supportSize; ++s) {
6810:           DMPlexGetConeSize(dm, support[s], &coneSize);
6811:           DMPlexGetCone(dm, support[s], &cone);
6812:           DMPlexGetConeOrientation(dm, support[s], &ornt);
6813:           for (c = 0; c < coneSize; ++c) {
6814:             if (cone[c] == f) break;
6815:           }
6816:           supportRef[s] = cStartNew + (support[s] - cStart)*8 + newCells[c*4+GetQuadSubfaceInverse_Static(ornt[c], r)];
6817:         }
6818:         DMPlexSetSupport(rdm, newp, supportRef);
6819: #if defined(PETSC_USE_DEBUG)
6820:         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
6821:         for (p = 0; p < supportSize; ++p) {
6822:           if ((supportRef[p] < cStartNew) || (supportRef[p] >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", supportRef[p], cStartNew, cEndNew);
6823:         }
6824: #endif
6825:       }
6826:     }
6827:     /* Interior faces have 4 edges and 2 cells */
6828:     for (c = cStart; c < cEnd; ++c) {
6829:       const PetscInt  newCells[24] = {0, 3,  2, 3,  1, 2,  0, 1,  4, 5,  5, 6,  6, 7,  4, 7,  0, 4,  3, 5,  2, 6,  1, 7};
6830:       const PetscInt *cone, *ornt;
6831:       PetscInt        newp, coneNew[4], orntNew[4], supportNew[2];

6833:       DMPlexGetCone(dm, c, &cone);
6834:       DMPlexGetConeOrientation(dm, c, &ornt);
6835:       /* A-D face */
6836:       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 0;
6837:       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*4 + GetQuadEdge_Static(ornt[0], 3);
6838:       orntNew[0] = 0;
6839:       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 0;
6840:       orntNew[1] = 0;
6841:       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 2;
6842:       orntNew[2] = -2;
6843:       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*4 + GetQuadEdge_Static(ornt[2], 0);
6844:       orntNew[3] = -2;
6845:       DMPlexSetCone(rdm, newp, coneNew);
6846:       DMPlexSetConeOrientation(rdm, newp, orntNew);
6847: #if defined(PETSC_USE_DEBUG)
6848:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
6849:       for (p = 0; p < 4; ++p) {
6850:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", coneNew[p], eStartNew, eEndNew);
6851:       }
6852: #endif
6853:       /* C-D face */
6854:       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 1;
6855:       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*4 + GetQuadEdge_Static(ornt[0], 2);
6856:       orntNew[0] = 0;
6857:       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 0;
6858:       orntNew[1] = 0;
6859:       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 4;
6860:       orntNew[2] = -2;
6861:       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (cone[4] - fStart)*4 + GetQuadEdge_Static(ornt[4], 0);
6862:       orntNew[3] = -2;
6863:       DMPlexSetCone(rdm, newp, coneNew);
6864:       DMPlexSetConeOrientation(rdm, newp, orntNew);
6865: #if defined(PETSC_USE_DEBUG)
6866:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
6867:       for (p = 0; p < 4; ++p) {
6868:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", coneNew[p], eStartNew, eEndNew);
6869:       }
6870: #endif
6871:       /* B-C face */
6872:       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 2;
6873:       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*4 + GetQuadEdge_Static(ornt[0], 1);
6874:       orntNew[0] = -2;
6875:       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*4 + GetQuadEdge_Static(ornt[3], 0);
6876:       orntNew[1] = 0;
6877:       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 3;
6878:       orntNew[2] = 0;
6879:       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 0;
6880:       orntNew[3] = -2;
6881:       DMPlexSetCone(rdm, newp, coneNew);
6882:       DMPlexSetConeOrientation(rdm, newp, orntNew);
6883: #if defined(PETSC_USE_DEBUG)
6884:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
6885:       for (p = 0; p < 4; ++p) {
6886:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", coneNew[p], eStartNew, eEndNew);
6887:       }
6888: #endif
6889:       /* A-B face */
6890:       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 3;
6891:       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*4 + GetQuadEdge_Static(ornt[0], 0);
6892:       orntNew[0] = -2;
6893:       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[5] - fStart)*4 + GetQuadEdge_Static(ornt[5], 3);
6894:       orntNew[1] = 0;
6895:       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 5;
6896:       orntNew[2] = 0;
6897:       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 0;
6898:       orntNew[3] = -2;
6899:       DMPlexSetCone(rdm, newp, coneNew);
6900:       DMPlexSetConeOrientation(rdm, newp, orntNew);
6901: #if defined(PETSC_USE_DEBUG)
6902:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
6903:       for (p = 0; p < 4; ++p) {
6904:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", coneNew[p], eStartNew, eEndNew);
6905:       }
6906: #endif
6907:       /* E-F face */
6908:       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 4;
6909:       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 2;
6910:       orntNew[0] = -2;
6911:       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*4 + GetQuadEdge_Static(ornt[2], 2);
6912:       orntNew[1] = -2;
6913:       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*4 + GetQuadEdge_Static(ornt[1], 0);
6914:       orntNew[2] = 0;
6915:       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 1;
6916:       orntNew[3] = 0;
6917:       DMPlexSetCone(rdm, newp, coneNew);
6918:       DMPlexSetConeOrientation(rdm, newp, orntNew);
6919: #if defined(PETSC_USE_DEBUG)
6920:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
6921:       for (p = 0; p < 4; ++p) {
6922:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", coneNew[p], eStartNew, eEndNew);
6923:       }
6924: #endif
6925:       /* F-G face */
6926:       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 5;
6927:       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 4;
6928:       orntNew[0] = -2;
6929:       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[4] - fStart)*4 + GetQuadEdge_Static(ornt[4], 2);
6930:       orntNew[1] = -2;
6931:       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*4 + GetQuadEdge_Static(ornt[1], 1);
6932:       orntNew[2] = 0;
6933:       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 1;
6934:       orntNew[3] = 0;
6935:       DMPlexSetCone(rdm, newp, coneNew);
6936:       DMPlexSetConeOrientation(rdm, newp, orntNew);
6937: #if defined(PETSC_USE_DEBUG)
6938:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
6939:       for (p = 0; p < 4; ++p) {
6940:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", coneNew[p], eStartNew, eEndNew);
6941:       }
6942: #endif
6943:       /* G-H face */
6944:       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 6;
6945:       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*4 + GetQuadEdge_Static(ornt[3], 2);
6946:       orntNew[0] = -2;
6947:       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*4 + GetQuadEdge_Static(ornt[1], 2);
6948:       orntNew[1] = 0;
6949:       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 1;
6950:       orntNew[2] = 0;
6951:       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 3;
6952:       orntNew[3] = -2;
6953:       DMPlexSetCone(rdm, newp, coneNew);
6954:       DMPlexSetConeOrientation(rdm, newp, orntNew);
6955: #if defined(PETSC_USE_DEBUG)
6956:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
6957:       for (p = 0; p < 4; ++p) {
6958:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", coneNew[p], eStartNew, eEndNew);
6959:       }
6960: #endif
6961:       /* E-H face */
6962:       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 7;
6963:       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 5;
6964:       orntNew[0] = -2;
6965:       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[5] - fStart)*4 + GetQuadEdge_Static(ornt[5], 1);
6966:       orntNew[1] = -2;
6967:       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*4 + GetQuadEdge_Static(ornt[1], 3);
6968:       orntNew[2] = 0;
6969:       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 1;
6970:       orntNew[3] = 0;
6971:       DMPlexSetCone(rdm, newp, coneNew);
6972:       DMPlexSetConeOrientation(rdm, newp, orntNew);
6973: #if defined(PETSC_USE_DEBUG)
6974:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
6975:       for (p = 0; p < 4; ++p) {
6976:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", coneNew[p], eStartNew, eEndNew);
6977:       }
6978: #endif
6979:       /* A-E face */
6980:       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 8;
6981:       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*4 + GetQuadEdge_Static(ornt[2], 3);
6982:       orntNew[0] = 0;
6983:       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 2;
6984:       orntNew[1] = 0;
6985:       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 5;
6986:       orntNew[2] = -2;
6987:       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (cone[5] - fStart)*4 + GetQuadEdge_Static(ornt[5], 0);
6988:       orntNew[3] = -2;
6989:       DMPlexSetCone(rdm, newp, coneNew);
6990:       DMPlexSetConeOrientation(rdm, newp, orntNew);
6991: #if defined(PETSC_USE_DEBUG)
6992:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
6993:       for (p = 0; p < 4; ++p) {
6994:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", coneNew[p], eStartNew, eEndNew);
6995:       }
6996: #endif
6997:       /* D-F face */
6998:       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 9;
6999:       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*4 + GetQuadEdge_Static(ornt[2], 1);
7000:       orntNew[0] = -2;
7001:       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[4] - fStart)*4 + GetQuadEdge_Static(ornt[4], 3);
7002:       orntNew[1] = 0;
7003:       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 4;
7004:       orntNew[2] = 0;
7005:       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 2;
7006:       orntNew[3] = -2;
7007:       DMPlexSetCone(rdm, newp, coneNew);
7008:       DMPlexSetConeOrientation(rdm, newp, orntNew);
7009: #if defined(PETSC_USE_DEBUG)
7010:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
7011:       for (p = 0; p < 4; ++p) {
7012:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", coneNew[p], eStartNew, eEndNew);
7013:       }
7014: #endif
7015:       /* C-G face */
7016:       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 10;
7017:       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 4;
7018:       orntNew[0] = -2;
7019:       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[4] - fStart)*4 + GetQuadEdge_Static(ornt[4], 1);
7020:       orntNew[1] = -2;
7021:       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*4 + GetQuadEdge_Static(ornt[3], 3);
7022:       orntNew[2] = 0;
7023:       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 3;
7024:       orntNew[3] = 0;
7025:       DMPlexSetCone(rdm, newp, coneNew);
7026:       DMPlexSetConeOrientation(rdm, newp, orntNew);
7027: #if defined(PETSC_USE_DEBUG)
7028:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
7029:       for (p = 0; p < 4; ++p) {
7030:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", coneNew[p], eStartNew, eEndNew);
7031:       }
7032: #endif
7033:       /* B-H face */
7034:       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 11;
7035:       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 5;
7036:       orntNew[0] = 0;
7037:       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 3;
7038:       orntNew[1] = -2;
7039:       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*4 + GetQuadEdge_Static(ornt[3], 1);
7040:       orntNew[2] = -2;
7041:       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (cone[5] - fStart)*4 + GetQuadEdge_Static(ornt[5], 2);
7042:       orntNew[3] = 0;
7043:       DMPlexSetCone(rdm, newp, coneNew);
7044:       DMPlexSetConeOrientation(rdm, newp, orntNew);
7045: #if defined(PETSC_USE_DEBUG)
7046:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
7047:       for (p = 0; p < 4; ++p) {
7048:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", coneNew[p], eStartNew, eEndNew);
7049:       }
7050: #endif
7051:       for (r = 0; r < 12; ++r) {
7052:         newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + r;
7053:         supportNew[0] = cStartNew + (c - cStart)*8 + newCells[r*2+0];
7054:         supportNew[1] = cStartNew + (c - cStart)*8 + newCells[r*2+1];
7055:         DMPlexSetSupport(rdm, newp, supportNew);
7056: #if defined(PETSC_USE_DEBUG)
7057:         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
7058:         for (p = 0; p < 2; ++p) {
7059:           if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", supportNew[p], cStartNew, cEndNew);
7060:         }
7061: #endif
7062:       }
7063:     }
7064:     /* Split edges have 2 vertices and the same faces as the parent */
7065:     DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);
7066:     for (e = eStart; e < eEnd; ++e) {
7067:       const PetscInt newv = vStartNew + (vEnd - vStart) + (e - eStart);

7069:       for (r = 0; r < 2; ++r) {
7070:         const PetscInt  newp = eStartNew + (e - eStart)*2 + r;
7071:         const PetscInt *cone, *ornt, *support;
7072:         PetscInt        coneNew[2], coneSize, c, supportSize, s;

7074:         DMPlexGetCone(dm, e, &cone);
7075:         coneNew[0]       = vStartNew + (cone[0] - vStart);
7076:         coneNew[1]       = vStartNew + (cone[1] - vStart);
7077:         coneNew[(r+1)%2] = newv;
7078:         DMPlexSetCone(rdm, newp, coneNew);
7079: #if defined(PETSC_USE_DEBUG)
7080:         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eEndNew);
7081:         for (p = 0; p < 2; ++p) {
7082:           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", coneNew[p], vStartNew, vEndNew);
7083:         }
7084: #endif
7085:         DMPlexGetSupportSize(dm, e, &supportSize);
7086:         DMPlexGetSupport(dm, e, &support);
7087:         for (s = 0; s < supportSize; ++s) {
7088:           DMPlexGetConeSize(dm, support[s], &coneSize);
7089:           DMPlexGetCone(dm, support[s], &cone);
7090:           DMPlexGetConeOrientation(dm, support[s], &ornt);
7091:           for (c = 0; c < coneSize; ++c) {
7092:             if (cone[c] == e) break;
7093:           }
7094:           supportRef[s] = fStartNew + (support[s] - fStart)*4 + (ornt[c] < 0 ? (c+1-r)%4 : (c+r)%4);
7095:         }
7096:         DMPlexSetSupport(rdm, newp, supportRef);
7097: #if defined(PETSC_USE_DEBUG)
7098:         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eEndNew);
7099:         for (p = 0; p < supportSize; ++p) {
7100:           if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", supportRef[p], fStartNew, fEndNew);
7101:         }
7102: #endif
7103:       }
7104:     }
7105:     /* Face edges have 2 vertices and 2+cells faces */
7106:     for (f = fStart; f < fEnd; ++f) {
7107:       const PetscInt  newFaces[24] = {3, 2, 1, 0,  4, 5, 6, 7,  0, 9, 4, 8,  2, 11, 6, 10,  1, 10, 5, 9,  8, 7, 11, 3};
7108:       const PetscInt  newv = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (f - fStart);
7109:       const PetscInt *cone, *coneCell, *orntCell, *support;
7110:       PetscInt        coneNew[2], coneSize, c, supportSize, s;

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

7116:         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r] - eStart);
7117:         coneNew[1] = newv;
7118:         DMPlexSetCone(rdm, newp, coneNew);
7119: #if defined(PETSC_USE_DEBUG)
7120:         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eEndNew);
7121:         for (p = 0; p < 2; ++p) {
7122:           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", coneNew[p], vStartNew, vEndNew);
7123:         }
7124: #endif
7125:         DMPlexGetSupportSize(dm, f, &supportSize);
7126:         DMPlexGetSupport(dm, f, &support);
7127:         supportRef[0] = fStartNew + (f - fStart)*4 + r;
7128:         supportRef[1] = fStartNew + (f - fStart)*4 + (r+1)%4;
7129:         for (s = 0; s < supportSize; ++s) {
7130:           DMPlexGetConeSize(dm, support[s], &coneSize);
7131:           DMPlexGetCone(dm, support[s], &coneCell);
7132:           DMPlexGetConeOrientation(dm, support[s], &orntCell);
7133:           for (c = 0; c < coneSize; ++c) if (coneCell[c] == f) break;
7134:           supportRef[2+s] = fStartNew + (fEnd - fStart)*4 + (support[s] - cStart)*12 + newFaces[c*4 + GetQuadEdgeInverse_Static(orntCell[c], r)];
7135:         }
7136:         DMPlexSetSupport(rdm, newp, supportRef);
7137: #if defined(PETSC_USE_DEBUG)
7138:         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eEndNew);
7139:         for (p = 0; p < 2+supportSize; ++p) {
7140:           if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", supportRef[p], fStartNew, fEndNew);
7141:         }
7142: #endif
7143:       }
7144:     }
7145:     /* Cell edges have 2 vertices and 4 faces */
7146:     for (c = cStart; c < cEnd; ++c) {
7147:       const PetscInt  newFaces[24] = {0, 1, 2, 3,  4, 5, 6, 7,  0, 9, 4, 8,  2, 11, 6, 10,  1, 10, 5, 9,  3, 8, 7, 11};
7148:       const PetscInt  newv = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (fEnd - fStart) + (c - cStart);
7149:       const PetscInt *cone;
7150:       PetscInt        coneNew[2], supportNew[4];

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

7156:         coneNew[0] = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (cone[r] - fStart);
7157:         coneNew[1] = newv;
7158:         DMPlexSetCone(rdm, newp, coneNew);
7159: #if defined(PETSC_USE_DEBUG)
7160:         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eEndNew);
7161:         for (p = 0; p < 2; ++p) {
7162:           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", coneNew[p], vStartNew, vEndNew);
7163:         }
7164: #endif
7165:         for (f = 0; f < 4; ++f) supportNew[f] = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + newFaces[r*4+f];
7166:         DMPlexSetSupport(rdm, newp, supportNew);
7167: #if defined(PETSC_USE_DEBUG)
7168:         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eEndNew);
7169:         for (p = 0; p < 4; ++p) {
7170:           if ((supportNew[p] < fStartNew) || (supportNew[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", supportNew[p], fStartNew, fEndNew);
7171:         }
7172: #endif
7173:       }
7174:     }
7175:     /* Old vertices have identical supports */
7176:     for (v = vStart; v < vEnd; ++v) {
7177:       const PetscInt  newp = vStartNew + (v - vStart);
7178:       const PetscInt *support, *cone;
7179:       PetscInt        size, s;

7181:       DMPlexGetSupportSize(dm, v, &size);
7182:       DMPlexGetSupport(dm, v, &support);
7183:       for (s = 0; s < size; ++s) {
7184:         PetscInt r = 0;

7186:         DMPlexGetCone(dm, support[s], &cone);
7187:         if (cone[1] == v) r = 1;
7188:         supportRef[s] = eStartNew + (support[s] - eStart)*2 + r;
7189:       }
7190:       DMPlexSetSupport(rdm, newp, supportRef);
7191: #if defined(PETSC_USE_DEBUG)
7192:       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", newp, vStartNew, vEndNew);
7193:       for (p = 0; p < size; ++p) {
7194:         if ((supportRef[p] < eStartNew) || (supportRef[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", supportRef[p], eStartNew, eEndNew);
7195:       }
7196: #endif
7197:     }
7198:     /* Edge vertices have 2 + faces supports */
7199:     for (e = eStart; e < eEnd; ++e) {
7200:       const PetscInt  newp = vStartNew + (vEnd - vStart) + (e - eStart);
7201:       const PetscInt *cone, *support;
7202:       PetscInt        size, s;

7204:       DMPlexGetSupportSize(dm, e, &size);
7205:       DMPlexGetSupport(dm, e, &support);
7206:       supportRef[0] = eStartNew + (e - eStart)*2 + 0;
7207:       supportRef[1] = eStartNew + (e - eStart)*2 + 1;
7208:       for (s = 0; s < size; ++s) {
7209:         PetscInt r;

7211:         DMPlexGetCone(dm, support[s], &cone);
7212:         for (r = 0; r < 4; ++r) if (cone[r] == e) break;
7213:         supportRef[2+s] = eStartNew + (eEnd - eStart)*2 + (support[s] - fStart)*4 + r;
7214:       }
7215:       DMPlexSetSupport(rdm, newp, supportRef);
7216: #if defined(PETSC_USE_DEBUG)
7217:       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", newp, vStartNew, vEndNew);
7218:       for (p = 0; p < 2+size; ++p) {
7219:         if ((supportRef[p] < eStartNew) || (supportRef[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", supportRef[p], eStartNew, eEndNew);
7220:       }
7221: #endif
7222:     }
7223:     /* Face vertices have 4 + cells supports */
7224:     for (f = fStart; f < fEnd; ++f) {
7225:       const PetscInt  newp = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (f - fStart);
7226:       const PetscInt *cone, *support;
7227:       PetscInt        size, s;

7229:       DMPlexGetSupportSize(dm, f, &size);
7230:       DMPlexGetSupport(dm, f, &support);
7231:       for (r = 0; r < 4; ++r) supportRef[r] = eStartNew + (eEnd - eStart)*2 +  (f - fStart)*4 + r;
7232:       for (s = 0; s < size; ++s) {
7233:         PetscInt r;

7235:         DMPlexGetCone(dm, support[s], &cone);
7236:         for (r = 0; r < 6; ++r) if (cone[r] == f) break;
7237:         supportRef[4+s] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*4 + (support[s] - cStart)*6 + r;
7238:       }
7239:       DMPlexSetSupport(rdm, newp, supportRef);
7240: #if defined(PETSC_USE_DEBUG)
7241:       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", newp, vStartNew, vEndNew);
7242:       for (p = 0; p < 4+size; ++p) {
7243:         if ((supportRef[p] < eStartNew) || (supportRef[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", supportRef[p], eStartNew, eEndNew);
7244:       }
7245: #endif
7246:     }
7247:     /* Cell vertices have 6 supports */
7248:     for (c = cStart; c < cEnd; ++c) {
7249:       const PetscInt newp = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (fEnd - fStart) + (c - cStart);
7250:       PetscInt       supportNew[6];

7252:       for (r = 0; r < 6; ++r) {
7253:         supportNew[r] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*4 + (c - cStart)*6 + r;
7254:       }
7255:       DMPlexSetSupport(rdm, newp, supportNew);
7256:     }
7257:     PetscFree(supportRef);
7258:     break;
7259:   case REFINER_HYBRID_HEX_3D:
7260:     DMPlexGetHybridBounds(rdm, &cMaxNew, &fMaxNew, &eMaxNew, NULL);
7261:     /*
7262:      Bottom (viewed from top)    Top
7263:      1---------2---------2       7---------2---------6
7264:      |         |         |       |         |         |
7265:      |    B    2    C    |       |    H    2    G    |
7266:      |         |         |       |         |         |
7267:      3----3----0----1----1       3----3----0----1----1
7268:      |         |         |       |         |         |
7269:      |    A    0    D    |       |    E    0    F    |
7270:      |         |         |       |         |         |
7271:      0---------0---------3       4---------0---------5
7272:      */
7273:     /* Interior cells have 6 faces: Bottom, Top, Front, Back, Right, Left */
7274:     for (c = cStart; c < cMax; ++c) {
7275:       const PetscInt  newp = (c - cStart)*8;
7276:       const PetscInt *cone, *ornt;
7277:       PetscInt        coneNew[6], orntNew[6];

7279:       DMPlexGetCone(dm, c, &cone);
7280:       DMPlexGetConeOrientation(dm, c, &ornt);
7281:       /* A hex */
7282:       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], 0);
7283:       orntNew[0] = ornt[0];
7284:       coneNew[1] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  8; /* AE */
7285:       orntNew[1] = 0;
7286:       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetQuadSubface_Static(ornt[2], 0);
7287:       orntNew[2] = ornt[2];
7288:       coneNew[3] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  3; /* AB */
7289:       orntNew[3] = 0;
7290:       coneNew[4] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  0; /* AD */
7291:       orntNew[4] = 0;
7292:       coneNew[5] = fStartNew + (cone[5] - fStart)*4 + GetQuadSubface_Static(ornt[5], 0);
7293:       orntNew[5] = ornt[5];
7294:       DMPlexSetCone(rdm, newp+0, coneNew);
7295:       DMPlexSetConeOrientation(rdm, newp+0, orntNew);
7296: #if defined(PETSC_USE_DEBUG)
7297:       if ((newp+0 < cStartNew) || (newp+0 >= cMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", newp+0, cStartNew, cMaxNew);
7298:       for (p = 0; p < 6; ++p) {
7299:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", coneNew[p], fStartNew, fMaxNew);
7300:       }
7301: #endif
7302:       /* B hex */
7303:       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], 1);
7304:       orntNew[0] = ornt[0];
7305:       coneNew[1] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 + 11; /* BH */
7306:       orntNew[1] = 0;
7307:       coneNew[2] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  3; /* AB */
7308:       orntNew[2] = -1;
7309:       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetQuadSubface_Static(ornt[3], 1);
7310:       orntNew[3] = ornt[3];
7311:       coneNew[4] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  2; /* BC */
7312:       orntNew[4] = 0;
7313:       coneNew[5] = fStartNew + (cone[5] - fStart)*4 + GetQuadSubface_Static(ornt[5], 3);
7314:       orntNew[5] = ornt[5];
7315:       DMPlexSetCone(rdm, newp+1, coneNew);
7316:       DMPlexSetConeOrientation(rdm, newp+1, orntNew);
7317: #if defined(PETSC_USE_DEBUG)
7318:       if ((newp+1 < cStartNew) || (newp+1 >= cMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", newp+1, cStartNew, cMaxNew);
7319:       for (p = 0; p < 6; ++p) {
7320:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", coneNew[p], fStartNew, fMaxNew);
7321:       }
7322: #endif
7323:       /* C hex */
7324:       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], 2);
7325:       orntNew[0] = ornt[0];
7326:       coneNew[1] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 + 10; /* CG */
7327:       orntNew[1] = 0;
7328:       coneNew[2] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  1; /* CD */
7329:       orntNew[2] = -1;
7330:       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetQuadSubface_Static(ornt[3], 0);
7331:       orntNew[3] = ornt[3];
7332:       coneNew[4] = fStartNew + (cone[4] - fStart)*4 + GetQuadSubface_Static(ornt[4], 1);
7333:       orntNew[4] = ornt[4];
7334:       coneNew[5] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  2; /* BC */
7335:       orntNew[5] = -4;
7336:       DMPlexSetCone(rdm, newp+2, coneNew);
7337:       DMPlexSetConeOrientation(rdm, newp+2, orntNew);
7338: #if defined(PETSC_USE_DEBUG)
7339:       if ((newp+2 < cStartNew) || (newp+2 >= cMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", newp+2, cStartNew, cMaxNew);
7340:       for (p = 0; p < 6; ++p) {
7341:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", coneNew[p], fStartNew, fMaxNew);
7342:       }
7343: #endif
7344:       /* D hex */
7345:       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], 3);
7346:       orntNew[0] = ornt[0];
7347:       coneNew[1] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  9; /* DF */
7348:       orntNew[1] = 0;
7349:       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetQuadSubface_Static(ornt[2], 1);
7350:       orntNew[2] = ornt[2];
7351:       coneNew[3] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  1; /* CD */
7352:       orntNew[3] = 0;
7353:       coneNew[4] = fStartNew + (cone[4] - fStart)*4 + GetQuadSubface_Static(ornt[4], 0);
7354:       orntNew[4] = ornt[4];
7355:       coneNew[5] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  0; /* AD */
7356:       orntNew[5] = -4;
7357:       DMPlexSetCone(rdm, newp+3, coneNew);
7358:       DMPlexSetConeOrientation(rdm, newp+3, orntNew);
7359: #if defined(PETSC_USE_DEBUG)
7360:       if ((newp+3 < cStartNew) || (newp+3 >= cMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", newp+3, cStartNew, cMaxNew);
7361:       for (p = 0; p < 6; ++p) {
7362:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", coneNew[p], fStartNew, fMaxNew);
7363:       }
7364: #endif
7365:       /* E hex */
7366:       coneNew[0] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  8; /* AE */
7367:       orntNew[0] = -4;
7368:       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], 0);
7369:       orntNew[1] = ornt[1];
7370:       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetQuadSubface_Static(ornt[2], 3);
7371:       orntNew[2] = ornt[2];
7372:       coneNew[3] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  7; /* EH */
7373:       orntNew[3] = 0;
7374:       coneNew[4] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  4; /* EF */
7375:       orntNew[4] = -1;
7376:       coneNew[5] = fStartNew + (cone[5] - fStart)*4 + GetQuadSubface_Static(ornt[5], 1);
7377:       orntNew[5] = ornt[5];
7378:       DMPlexSetCone(rdm, newp+4, coneNew);
7379:       DMPlexSetConeOrientation(rdm, newp+4, orntNew);
7380: #if defined(PETSC_USE_DEBUG)
7381:       if ((newp+4 < cStartNew) || (newp+4 >= cMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", newp+4, cStartNew, cMaxNew);
7382:       for (p = 0; p < 6; ++p) {
7383:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", coneNew[p], fStartNew, fMaxNew);
7384:       }
7385: #endif
7386:       /* F hex */
7387:       coneNew[0] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  9; /* DF */
7388:       orntNew[0] = -4;
7389:       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], 1);
7390:       orntNew[1] = ornt[1];
7391:       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetQuadSubface_Static(ornt[2], 2);
7392:       orntNew[2] = ornt[2];
7393:       coneNew[3] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  5; /* FG */
7394:       orntNew[3] = -1;
7395:       coneNew[4] = fStartNew + (cone[4] - fStart)*4 + GetQuadSubface_Static(ornt[4], 3);
7396:       orntNew[4] = ornt[4];
7397:       coneNew[5] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  4; /* EF */
7398:       orntNew[5] = 1;
7399:       DMPlexSetCone(rdm, newp+5, coneNew);
7400:       DMPlexSetConeOrientation(rdm, newp+5, orntNew);
7401: #if defined(PETSC_USE_DEBUG)
7402:       if ((newp+5 < cStartNew) || (newp+5 >= cMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", newp+5, cStartNew, cMaxNew);
7403:       for (p = 0; p < 6; ++p) {
7404:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", coneNew[p], fStartNew, fMaxNew);
7405:       }
7406: #endif
7407:       /* G hex */
7408:       coneNew[0] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 + 10; /* CG */
7409:       orntNew[0] = -4;
7410:       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], 2);
7411:       orntNew[1] = ornt[1];
7412:       coneNew[2] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  5; /* FG */
7413:       orntNew[2] = 0;
7414:       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetQuadSubface_Static(ornt[3], 3);
7415:       orntNew[3] = ornt[3];
7416:       coneNew[4] = fStartNew + (cone[4] - fStart)*4 + GetQuadSubface_Static(ornt[4], 2);
7417:       orntNew[4] = ornt[4];
7418:       coneNew[5] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  6; /* GH */
7419:       orntNew[5] = -3;
7420:       DMPlexSetCone(rdm, newp+6, coneNew);
7421:       DMPlexSetConeOrientation(rdm, newp+6, orntNew);
7422: #if defined(PETSC_USE_DEBUG)
7423:       if ((newp+6 < cStartNew) || (newp+6 >= cMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", newp+6, cStartNew, cMaxNew);
7424:       for (p = 0; p < 6; ++p) {
7425:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", coneNew[p], fStartNew, fMaxNew);
7426:       }
7427: #endif
7428:       /* H hex */
7429:       coneNew[0] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 + 11; /* BH */
7430:       orntNew[0] = -4;
7431:       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], 3);
7432:       orntNew[1] = ornt[1];
7433:       coneNew[2] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  7; /* EH */
7434:       orntNew[2] = -1;
7435:       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetQuadSubface_Static(ornt[3], 2);
7436:       orntNew[3] = ornt[3];
7437:       coneNew[4] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  6; /* GH */
7438:       orntNew[4] = 3;
7439:       coneNew[5] = fStartNew + (cone[5] - fStart)*4 + GetQuadSubface_Static(ornt[5], 2);
7440:       orntNew[5] = ornt[5];
7441:       DMPlexSetCone(rdm, newp+7, coneNew);
7442:       DMPlexSetConeOrientation(rdm, newp+7, orntNew);
7443: #if defined(PETSC_USE_DEBUG)
7444:       if ((newp+7 < cStartNew) || (newp+7 >= cMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", newp+7, cStartNew, cMaxNew);
7445:       for (p = 0; p < 6; ++p) {
7446:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", coneNew[p], fStartNew, fMaxNew);
7447:       }
7448: #endif
7449:     }
7450:     /* Hybrid cells have 6 faces: Front, Back, Sides */
7451:     /*
7452:      3---------2---------2
7453:      |         |         |
7454:      |    D    2    C    |
7455:      |         |         |
7456:      3----3----0----1----1
7457:      |         |         |
7458:      |    A    0    B    |
7459:      |         |         |
7460:      0---------0---------1
7461:      */
7462:     for (c = cMax; c < cEnd; ++c) {
7463:       const PetscInt  newp = (cMax - cStart)*8 + (c - cMax)*4;
7464:       const PetscInt *cone, *ornt, *fornt;
7465:       PetscInt        coneNew[6], orntNew[6], o, of, i;

7467:       DMPlexGetCone(dm, c, &cone);
7468:       DMPlexGetConeOrientation(dm, c, &ornt);
7469:       DMPlexGetConeOrientation(dm, cone[0], &fornt);
7470:       o = ornt[0] < 0 ? -1 : 1;
7471:       for (r = 0; r < 4; ++r) {
7472:         PetscInt subfA = GetQuadSubface_Static(ornt[0], r);
7473:         PetscInt edgeA = GetQuadEdge_Static(ornt[0], r);
7474:         PetscInt edgeB = GetQuadEdge_Static(ornt[0], (r+3)%4);
7475:         if (ornt[0] != ornt[1]) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Inconsistent ordering for matching ends of hybrid cell %D: %D != %D", c, ornt[0], ornt[1]);
7476:         coneNew[0]         = fStartNew + (cone[0] - fStart)*4 + subfA;
7477:         orntNew[0]         = ornt[0];
7478:         coneNew[1]         = fStartNew + (cone[1] - fStart)*4 + subfA;
7479:         orntNew[1]         = ornt[0];
7480:         of = fornt[edgeA] < 0 ? -1 : 1;
7481:         i  = GetQuadEdgeInverse_Static(ornt[0], r) + 2;
7482:         coneNew[i] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (cone[2+edgeA] - fMax)*2 + (o*of < 0 ? 1 : 0);
7483:         orntNew[i] = ornt[edgeA];
7484:         i  = GetQuadEdgeInverse_Static(ornt[0], (r+1)%4) + 2;
7485:         coneNew[i] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd          - fMax)*2 + (c - cMax)*4 + edgeA;
7486:         orntNew[i] = 0;
7487:         i  = GetQuadEdgeInverse_Static(ornt[0], (r+2)%4) + 2;
7488:         coneNew[i] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd          - fMax)*2 + (c - cMax)*4 + edgeB;
7489:         orntNew[i] = -2;
7490:         of = fornt[edgeB] < 0 ? -1 : 1;
7491:         i  = GetQuadEdgeInverse_Static(ornt[0], (r+3)%4) + 2;
7492:         coneNew[i] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (cone[2+edgeB] - fMax)*2 + (o*of < 0 ? 0 : 1);
7493:         orntNew[i] = ornt[edgeB];
7494:         DMPlexSetCone(rdm, newp+r, coneNew);
7495:         DMPlexSetConeOrientation(rdm, newp+r, orntNew);
7496: #if defined(PETSC_USE_DEBUG)
7497:         if ((newp+r < cMaxNew) || (newp+r >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a hybrid cell [%D, %D)", newp+r, cMaxNew, cEndNew);
7498:         for (p = 0; p < 2; ++p) {
7499:           if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", coneNew[p], fStartNew, fMaxNew);
7500:         }
7501:         for (p = 2; p < 6; ++p) {
7502:           if ((coneNew[p] < fMaxNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a hybrid face [%D, %D)", coneNew[p], fMaxNew, fEndNew);
7503:         }
7504: #endif
7505:       }
7506:     }
7507:     /* Interior split faces have 4 edges and the same cells as the parent */
7508:     DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);
7509:     PetscMalloc1(4 + maxSupportSize*2, &supportRef);
7510:     for (f = fStart; f < fMax; ++f) {
7511:       for (r = 0; r < 4; ++r) {
7512:         /* TODO: This can come from GetFaces_Internal() */
7513:         const PetscInt  newCells[24] = {0, 1, 2, 3,  4, 5, 6, 7,  0, 3, 5, 4,  2, 1, 7, 6,  3, 2, 6, 5,  0, 4, 7, 1};
7514:         const PetscInt  newp = fStartNew + (f - fStart)*4 + r;
7515:         const PetscInt *cone, *ornt, *support;
7516:         PetscInt        coneNew[4], orntNew[4], coneSize, c, supportSize, s;

7518:         DMPlexGetCone(dm, f, &cone);
7519:         DMPlexGetConeOrientation(dm, f, &ornt);
7520:         coneNew[(r+3)%4] = eStartNew + (cone[(r+3)%4] - eStart)*2 + (ornt[(r+3)%4] < 0 ? 0 : 1);
7521:         orntNew[(r+3)%4] = ornt[(r+3)%4];
7522:         coneNew[(r+0)%4] = eStartNew + (cone[r]       - eStart)*2 + (ornt[r] < 0 ? 1 : 0);
7523:         orntNew[(r+0)%4] = ornt[r];
7524:         coneNew[(r+1)%4] = eStartNew + (eMax - eStart)*2 + (f - fStart)*4 + r;
7525:         orntNew[(r+1)%4] = 0;
7526:         coneNew[(r+2)%4] = eStartNew + (eMax - eStart)*2 + (f - fStart)*4 + (r+3)%4;
7527:         orntNew[(r+2)%4] = -2;
7528:         DMPlexSetCone(rdm, newp, coneNew);
7529:         DMPlexSetConeOrientation(rdm, newp, orntNew);
7530: #if defined(PETSC_USE_DEBUG)
7531:         if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fMaxNew);
7532:         for (p = 0; p < 4; ++p) {
7533:           if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", coneNew[p], eStartNew, eMaxNew);
7534:         }
7535: #endif
7536:         DMPlexGetSupportSize(dm, f, &supportSize);
7537:         DMPlexGetSupport(dm, f, &support);
7538:         for (s = 0; s < supportSize; ++s) {
7539:           PetscInt subf;
7540:           DMPlexGetConeSize(dm, support[s], &coneSize);
7541:           DMPlexGetCone(dm, support[s], &cone);
7542:           DMPlexGetConeOrientation(dm, support[s], &ornt);
7543:           for (c = 0; c < coneSize; ++c) {
7544:             if (cone[c] == f) break;
7545:           }
7546:           subf = GetQuadSubfaceInverse_Static(ornt[c], r);
7547:           if (support[s] < cMax) {
7548:             supportRef[s] = cStartNew + (support[s] - cStart)*8 + newCells[c*4+subf];
7549:           } else {
7550:             supportRef[s] = cStartNew + (cMax       - cStart)*8 + (support[s] - cMax)*4 + subf;
7551:           }
7552:         }
7553:         DMPlexSetSupport(rdm, newp, supportRef);
7554: #if defined(PETSC_USE_DEBUG)
7555:         if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fMaxNew);
7556:         for (p = 0; p < supportSize; ++p) {
7557:           if ((supportRef[p] < cStartNew) || (supportRef[p] >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", supportRef[p], cStartNew, cEndNew);
7558:         }
7559: #endif
7560:       }
7561:     }
7562:     /* Interior cell faces have 4 edges and 2 cells */
7563:     for (c = cStart; c < cMax; ++c) {
7564:       const PetscInt  newCells[24] = {0, 3,  2, 3,  1, 2,  0, 1,  4, 5,  5, 6,  6, 7,  4, 7,  0, 4,  3, 5,  2, 6,  1, 7};
7565:       const PetscInt *cone, *ornt;
7566:       PetscInt        newp, coneNew[4], orntNew[4], supportNew[2];

7568:       DMPlexGetCone(dm, c, &cone);
7569:       DMPlexGetConeOrientation(dm, c, &ornt);
7570:       /* A-D face */
7571:       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 0;
7572:       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*4 + GetQuadEdge_Static(ornt[0], 3);
7573:       orntNew[0] = 0;
7574:       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 0;
7575:       orntNew[1] = 0;
7576:       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 2;
7577:       orntNew[2] = -2;
7578:       coneNew[3] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*4 + GetQuadEdge_Static(ornt[2], 0);
7579:       orntNew[3] = -2;
7580:       DMPlexSetCone(rdm, newp, coneNew);
7581:       DMPlexSetConeOrientation(rdm, newp, orntNew);
7582: #if defined(PETSC_USE_DEBUG)
7583:       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fMaxNew);
7584:       for (p = 0; p < 4; ++p) {
7585:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", coneNew[p], eStartNew, eMaxNew);
7586:       }
7587: #endif
7588:       /* C-D face */
7589:       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 1;
7590:       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*4 + GetQuadEdge_Static(ornt[0], 2);
7591:       orntNew[0] = 0;
7592:       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 0;
7593:       orntNew[1] = 0;
7594:       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 4;
7595:       orntNew[2] = -2;
7596:       coneNew[3] = eStartNew + (eMax - eStart)*2 + (cone[4] - fStart)*4 + GetQuadEdge_Static(ornt[4], 0);
7597:       orntNew[3] = -2;
7598:       DMPlexSetCone(rdm, newp, coneNew);
7599:       DMPlexSetConeOrientation(rdm, newp, orntNew);
7600: #if defined(PETSC_USE_DEBUG)
7601:       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fMaxNew);
7602:       for (p = 0; p < 4; ++p) {
7603:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", coneNew[p], eStartNew, eMaxNew);
7604:       }
7605: #endif
7606:       /* B-C face */
7607:       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 2;
7608:       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*4 + GetQuadEdge_Static(ornt[0], 1);
7609:       orntNew[0] = -2;
7610:       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*4 + GetQuadEdge_Static(ornt[3], 0);
7611:       orntNew[1] = 0;
7612:       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 3;
7613:       orntNew[2] = 0;
7614:       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 0;
7615:       orntNew[3] = -2;
7616:       DMPlexSetCone(rdm, newp, coneNew);
7617:       DMPlexSetConeOrientation(rdm, newp, orntNew);
7618: #if defined(PETSC_USE_DEBUG)
7619:       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fMaxNew);
7620:       for (p = 0; p < 4; ++p) {
7621:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", coneNew[p], eStartNew, eMaxNew);
7622:       }
7623: #endif
7624:       /* A-B face */
7625:       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 3;
7626:       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*4 + GetQuadEdge_Static(ornt[0], 0);
7627:       orntNew[0] = -2;
7628:       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[5] - fStart)*4 + GetQuadEdge_Static(ornt[5], 3);
7629:       orntNew[1] = 0;
7630:       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 5;
7631:       orntNew[2] = 0;
7632:       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 0;
7633:       orntNew[3] = -2;
7634:       DMPlexSetCone(rdm, newp, coneNew);
7635:       DMPlexSetConeOrientation(rdm, newp, orntNew);
7636: #if defined(PETSC_USE_DEBUG)
7637:       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fMaxNew);
7638:       for (p = 0; p < 4; ++p) {
7639:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", coneNew[p], eStartNew, eMaxNew);
7640:       }
7641: #endif
7642:       /* E-F face */
7643:       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 4;
7644:       coneNew[0] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 2;
7645:       orntNew[0] = -2;
7646:       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*4 + GetQuadEdge_Static(ornt[2], 2);
7647:       orntNew[1] = -2;
7648:       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*4 + GetQuadEdge_Static(ornt[1], 0);
7649:       orntNew[2] = 0;
7650:       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 1;
7651:       orntNew[3] = 0;
7652:       DMPlexSetCone(rdm, newp, coneNew);
7653:       DMPlexSetConeOrientation(rdm, newp, orntNew);
7654: #if defined(PETSC_USE_DEBUG)
7655:       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fMaxNew);
7656:       for (p = 0; p < 4; ++p) {
7657:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", coneNew[p], eStartNew, eMaxNew);
7658:       }
7659: #endif
7660:       /* F-G face */
7661:       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 5;
7662:       coneNew[0] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 4;
7663:       orntNew[0] = -2;
7664:       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[4] - fStart)*4 + GetQuadEdge_Static(ornt[4], 2);
7665:       orntNew[1] = -2;
7666:       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*4 + GetQuadEdge_Static(ornt[1], 1);
7667:       orntNew[2] = 0;
7668:       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 1;
7669:       orntNew[3] = 0;
7670:       DMPlexSetCone(rdm, newp, coneNew);
7671:       DMPlexSetConeOrientation(rdm, newp, orntNew);
7672: #if defined(PETSC_USE_DEBUG)
7673:       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fMaxNew);
7674:       for (p = 0; p < 4; ++p) {
7675:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", coneNew[p], eStartNew, eMaxNew);
7676:       }
7677: #endif
7678:       /* G-H face */
7679:       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 6;
7680:       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*4 + GetQuadEdge_Static(ornt[3], 2);
7681:       orntNew[0] = -2;
7682:       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*4 + GetQuadEdge_Static(ornt[1], 2);
7683:       orntNew[1] = 0;
7684:       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 1;
7685:       orntNew[2] = 0;
7686:       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 3;
7687:       orntNew[3] = -2;
7688:       DMPlexSetCone(rdm, newp, coneNew);
7689:       DMPlexSetConeOrientation(rdm, newp, orntNew);
7690: #if defined(PETSC_USE_DEBUG)
7691:       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fMaxNew);
7692:       for (p = 0; p < 4; ++p) {
7693:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", coneNew[p], eStartNew, eMaxNew);
7694:       }
7695: #endif
7696:       /* E-H face */
7697:       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 7;
7698:       coneNew[0] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 5;
7699:       orntNew[0] = -2;
7700:       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[5] - fStart)*4 + GetQuadEdge_Static(ornt[5], 1);
7701:       orntNew[1] = -2;
7702:       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*4 + GetQuadEdge_Static(ornt[1], 3);
7703:       orntNew[2] = 0;
7704:       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 1;
7705:       orntNew[3] = 0;
7706:       DMPlexSetCone(rdm, newp, coneNew);
7707:       DMPlexSetConeOrientation(rdm, newp, orntNew);
7708: #if defined(PETSC_USE_DEBUG)
7709:       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fMaxNew);
7710:       for (p = 0; p < 4; ++p) {
7711:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", coneNew[p], eStartNew, eMaxNew);
7712:       }
7713: #endif
7714:       /* A-E face */
7715:       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 8;
7716:       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*4 + GetQuadEdge_Static(ornt[2], 3);
7717:       orntNew[0] = 0;
7718:       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 2;
7719:       orntNew[1] = 0;
7720:       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 5;
7721:       orntNew[2] = -2;
7722:       coneNew[3] = eStartNew + (eMax - eStart)*2 + (cone[5] - fStart)*4 + GetQuadEdge_Static(ornt[5], 0);
7723:       orntNew[3] = -2;
7724:       DMPlexSetCone(rdm, newp, coneNew);
7725:       DMPlexSetConeOrientation(rdm, newp, orntNew);
7726: #if defined(PETSC_USE_DEBUG)
7727:       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fMaxNew);
7728:       for (p = 0; p < 4; ++p) {
7729:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", coneNew[p], eStartNew, eMaxNew);
7730:       }
7731: #endif
7732:       /* D-F face */
7733:       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 9;
7734:       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*4 + GetQuadEdge_Static(ornt[2], 1);
7735:       orntNew[0] = -2;
7736:       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[4] - fStart)*4 + GetQuadEdge_Static(ornt[4], 3);
7737:       orntNew[1] = 0;
7738:       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 4;
7739:       orntNew[2] = 0;
7740:       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 2;
7741:       orntNew[3] = -2;
7742:       DMPlexSetCone(rdm, newp, coneNew);
7743:       DMPlexSetConeOrientation(rdm, newp, orntNew);
7744: #if defined(PETSC_USE_DEBUG)
7745:       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fMaxNew);
7746:       for (p = 0; p < 4; ++p) {
7747:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", coneNew[p], eStartNew, eMaxNew);
7748:       }
7749: #endif
7750:       /* C-G face */
7751:       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 10;
7752:       coneNew[0] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 4;
7753:       orntNew[0] = -2;
7754:       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[4] - fStart)*4 + GetQuadEdge_Static(ornt[4], 1);
7755:       orntNew[1] = -2;
7756:       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*4 + GetQuadEdge_Static(ornt[3], 3);
7757:       orntNew[2] = 0;
7758:       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 3;
7759:       orntNew[3] = 0;
7760:       DMPlexSetCone(rdm, newp, coneNew);
7761:       DMPlexSetConeOrientation(rdm, newp, orntNew);
7762: #if defined(PETSC_USE_DEBUG)
7763:       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fMaxNew);
7764:       for (p = 0; p < 4; ++p) {
7765:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", coneNew[p], eStartNew, eMaxNew);
7766:       }
7767: #endif
7768:       /* B-H face */
7769:       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 11;
7770:       coneNew[0] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 5;
7771:       orntNew[0] = 0;
7772:       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 3;
7773:       orntNew[1] = -2;
7774:       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*4 + GetQuadEdge_Static(ornt[3], 1);
7775:       orntNew[2] = -2;
7776:       coneNew[3] = eStartNew + (eMax - eStart)*2 + (cone[5] - fStart)*4 + GetQuadEdge_Static(ornt[5], 2);
7777:       orntNew[3] = 0;
7778:       DMPlexSetCone(rdm, newp, coneNew);
7779:       DMPlexSetConeOrientation(rdm, newp, orntNew);
7780: #if defined(PETSC_USE_DEBUG)
7781:       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fMaxNew);
7782:       for (p = 0; p < 4; ++p) {
7783:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", coneNew[p], eStartNew, eMaxNew);
7784:       }
7785: #endif
7786:       for (r = 0; r < 12; ++r) {
7787:         newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + r;
7788:         supportNew[0] = cStartNew + (c - cStart)*8 + newCells[r*2+0];
7789:         supportNew[1] = cStartNew + (c - cStart)*8 + newCells[r*2+1];
7790:         DMPlexSetSupport(rdm, newp, supportNew);
7791: #if defined(PETSC_USE_DEBUG)
7792:         if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fMaxNew);
7793:         for (p = 0; p < 2; ++p) {
7794:           if ((supportNew[p] < cStartNew) || (supportNew[p] >= cMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", supportNew[p], cStartNew, cMaxNew);
7795:         }
7796: #endif
7797:       }
7798:     }
7799:     /* Hybrid split faces have 4 edges and same cells */
7800:     for (f = fMax; f < fEnd; ++f) {
7801:       const PetscInt *cone, *ornt, *support;
7802:       PetscInt        coneNew[4], orntNew[4];
7803:       PetscInt        supportNew[2], size, s, c;

7805:       DMPlexGetCone(dm, f, &cone);
7806:       DMPlexGetConeOrientation(dm, f, &ornt);
7807:       DMPlexGetSupportSize(dm, f, &size);
7808:       DMPlexGetSupport(dm, f, &support);
7809:       for (r = 0; r < 2; ++r) {
7810:         const PetscInt newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (f - fMax)*2 + r;

7812:         coneNew[0]   = eStartNew + (cone[0] - eStart)*2 + (ornt[0] < 0 ? 1-r : r);
7813:         orntNew[0]   = ornt[0];
7814:         coneNew[1]   = eStartNew + (cone[1] - eStart)*2 + (ornt[1] < 0 ? 1-r : r);
7815:         orntNew[1]   = ornt[1];
7816:         coneNew[2+r] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (cone[2+r] - eMax);
7817:         orntNew[2+r] = 0;
7818:         coneNew[3-r] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (eEnd      - eMax) + (f - fMax);
7819:         orntNew[3-r] = 0;
7820:         DMPlexSetCone(rdm, newp, coneNew);
7821:         DMPlexSetConeOrientation(rdm, newp, orntNew);
7822: #if defined(PETSC_USE_DEBUG)
7823:         if ((newp < fMaxNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a hybrid face [%D, %D)", newp, fMaxNew, fEndNew);
7824:         for (p = 0; p < 2; ++p) {
7825:           if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", coneNew[p], eStartNew, eMaxNew);
7826:         }
7827:         for (p = 2; p < 4; ++p) {
7828:           if ((coneNew[p] < eMaxNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a hybrid edge [%D, %D)", coneNew[p], eMaxNew, eEndNew);
7829:         }
7830: #endif
7831:         for (s = 0; s < size; ++s) {
7832:           const PetscInt *coneCell, *orntCell, *fornt;
7833:           PetscInt        o, of;

7835:           DMPlexGetCone(dm, support[s], &coneCell);
7836:           DMPlexGetConeOrientation(dm, support[s], &orntCell);
7837:           o = orntCell[0] < 0 ? -1 : 1;
7838:           for (c = 2; c < 6; ++c) if (coneCell[c] == f) break;
7839:           if (c >= 6) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Could not find face %D in cone of cell %D", f, support[s]);
7840:           DMPlexGetConeOrientation(dm, coneCell[0], &fornt);
7841:           of = fornt[c-2] < 0 ? -1 : 1;
7842:           supportNew[s] = cStartNew + (cMax - cStart)*8 + (support[s] - cMax)*4 + (GetQuadEdgeInverse_Static(orntCell[0], c-2) + (o*of < 0 ? 1-r : r))%4;
7843:         }
7844:         DMPlexSetSupport(rdm, newp, supportNew);
7845: #if defined(PETSC_USE_DEBUG)
7846:         if ((newp < fMaxNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a hybrid face [%D, %D)", newp, fMaxNew, fEndNew);
7847:         for (p = 0; p < size; ++p) {
7848:           if ((supportNew[p] < cMaxNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a hybrid cell [%D, %D)", supportNew[p], cMaxNew, cEndNew);
7849:         }
7850: #endif
7851:       }
7852:     }
7853:     /* Hybrid cell faces have 4 edges and 2 cells */
7854:     for (c = cMax; c < cEnd; ++c) {
7855:       PetscInt        newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd - fMax)*2 + (c - cMax)*4;
7856:       const PetscInt *cone, *ornt;
7857:       PetscInt        coneNew[4], orntNew[4];
7858:       PetscInt        supportNew[2];

7860:       DMPlexGetCone(dm, c, &cone);
7861:       DMPlexGetConeOrientation(dm, c, &ornt);
7862:       for (r = 0; r < 4; ++r) {
7863: #if 0
7864:         coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], r);
7865:         orntNew[0] = 0;
7866:         coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], r);
7867:         orntNew[1] = 0;
7868:         coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (eEnd - eMax) + (cone[2+GetQuadEdge_Static(ornt[0], r)] - fMax);
7869:         orntNew[2] = 0;
7870:         coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (eEnd - eMax) + (fEnd                                   - fMax) + (c - cMax);
7871:         orntNew[3] = 0;
7872: #else
7873:         coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*4 + r;
7874:         orntNew[0] = 0;
7875:         coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*4 + r;
7876:         orntNew[1] = 0;
7877:         coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (eEnd - eMax) + (cone[2+r] - fMax);
7878:         orntNew[2] = 0;
7879:         coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (eEnd - eMax) + (fEnd      - fMax) + (c - cMax);
7880:         orntNew[3] = 0;
7881: #endif
7882:         DMPlexSetCone(rdm, newp+r, coneNew);
7883:         DMPlexSetConeOrientation(rdm, newp+r, orntNew);
7884: #if defined(PETSC_USE_DEBUG)
7885:         if ((newp+r < fMaxNew) || (newp+r >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a hybrid face [%D, %D)", newp+r, fMaxNew, fEndNew);
7886:         for (p = 0; p < 2; ++p) {
7887:           if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", coneNew[p], eStartNew, eMaxNew);
7888:         }
7889:         for (p = 2; p < 4; ++p) {
7890:           if ((coneNew[p] < eMaxNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a hybrid edge [%D, %D)", coneNew[p], eMaxNew, eEndNew);
7891:         }
7892: #endif
7893:         supportNew[0] = cStartNew + (cMax - cStart)*8 + (c - cMax)*4 + GetQuadSubface_Static(ornt[0], r);
7894:         supportNew[1] = cStartNew + (cMax - cStart)*8 + (c - cMax)*4 + GetQuadSubface_Static(ornt[0], (r+1)%4);
7895:         DMPlexSetSupport(rdm, newp+r, supportNew);
7896: #if defined(PETSC_USE_DEBUG)
7897:         if ((newp+r < fMaxNew) || (newp+r >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a hybrid face [%D, %D)", newp+r, fMaxNew, fEndNew);
7898:         for (p = 0; p < 2; ++p) {
7899:           if ((supportNew[p] < cMaxNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a hybrid cell [%D, %D)", supportNew[p], cMaxNew, cEndNew);
7900:         }
7901: #endif
7902:       }
7903:     }
7904:     /* Interior split edges have 2 vertices and the same faces as the parent */
7905:     DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);
7906:     for (e = eStart; e < eMax; ++e) {
7907:       const PetscInt newv = vStartNew + (vEnd - vStart) + (e - eStart);

7909:       for (r = 0; r < 2; ++r) {
7910:         const PetscInt  newp = eStartNew + (e - eStart)*2 + r;
7911:         const PetscInt *cone, *ornt, *support;
7912:         PetscInt        coneNew[2], coneSize, c, supportSize, s;

7914:         DMPlexGetCone(dm, e, &cone);
7915:         coneNew[0]       = vStartNew + (cone[0] - vStart);
7916:         coneNew[1]       = vStartNew + (cone[1] - vStart);
7917:         coneNew[(r+1)%2] = newv;
7918:         DMPlexSetCone(rdm, newp, coneNew);
7919: #if defined(PETSC_USE_DEBUG)
7920:         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eMaxNew);
7921:         for (p = 0; p < 2; ++p) {
7922:           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", coneNew[p], vStartNew, vEndNew);
7923:         }
7924: #endif
7925:         DMPlexGetSupportSize(dm, e, &supportSize);
7926:         DMPlexGetSupport(dm, e, &support);
7927:         for (s = 0; s < supportSize; ++s) {
7928:           DMPlexGetConeSize(dm, support[s], &coneSize);
7929:           DMPlexGetCone(dm, support[s], &cone);
7930:           DMPlexGetConeOrientation(dm, support[s], &ornt);
7931:           for (c = 0; c < coneSize; ++c) {
7932:             if (cone[c] == e) break;
7933:           }
7934:           if (support[s] < fMax) {
7935:             supportRef[s] = fStartNew + (support[s] - fStart)*4 + (c + (ornt[c] < 0 ? 1-r : r))%4;
7936:           } else {
7937:             supportRef[s] = fStartNew + (fMax       - fStart)*4 + (cMax - cStart)*12 + (support[s] - fMax)*2 + (ornt[c] < 0 ? 1-r : r);
7938:           }
7939:         }
7940:         DMPlexSetSupport(rdm, newp, supportRef);
7941: #if defined(PETSC_USE_DEBUG)
7942:         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eMaxNew);
7943:         for (p = 0; p < supportSize; ++p) {
7944:           if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", supportRef[p], fStartNew, fEndNew);
7945:         }
7946: #endif
7947:       }
7948:     }
7949:     /* Interior face edges have 2 vertices and 2+cells faces */
7950:     for (f = fStart; f < fMax; ++f) {
7951:       const PetscInt  newFaces[24] = {3, 2, 1, 0,  4, 5, 6, 7,  0, 9, 4, 8,  2, 11, 6, 10,  1, 10, 5, 9,  8, 7, 11, 3};
7952:       const PetscInt  newv = vStartNew + (vEnd - vStart) + (eMax - eStart) + (f - fStart);
7953:       const PetscInt *cone, *coneCell, *orntCell, *support;
7954:       PetscInt        coneNew[2], coneSize, c, supportSize, s;

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

7960:         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r] - eStart);
7961:         coneNew[1] = newv;
7962:         DMPlexSetCone(rdm, newp, coneNew);
7963: #if defined(PETSC_USE_DEBUG)
7964:         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eMaxNew);
7965:         for (p = 0; p < 2; ++p) {
7966:           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", coneNew[p], vStartNew, vEndNew);
7967:         }
7968: #endif
7969:         DMPlexGetSupportSize(dm, f, &supportSize);
7970:         DMPlexGetSupport(dm, f, &support);
7971:         supportRef[0] = fStartNew + (f - fStart)*4 + r;
7972:         supportRef[1] = fStartNew + (f - fStart)*4 + (r+1)%4;
7973:         for (s = 0; s < supportSize; ++s) {
7974:           DMPlexGetConeSize(dm, support[s], &coneSize);
7975:           DMPlexGetCone(dm, support[s], &coneCell);
7976:           DMPlexGetConeOrientation(dm, support[s], &orntCell);
7977:           for (c = 0; c < coneSize; ++c) if (coneCell[c] == f) break;
7978:           if (support[s] < cMax) {
7979:             supportRef[2+s] = fStartNew + (fMax - fStart)*4 + (support[s] - cStart)*12 + newFaces[c*4 + GetQuadEdgeInverse_Static(orntCell[c], r)];
7980:           } else {
7981:             supportRef[2+s] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd - fMax)*2 + (support[s] - cMax)*4 + r;
7982:           }
7983:         }
7984:         DMPlexSetSupport(rdm, newp, supportRef);
7985: #if defined(PETSC_USE_DEBUG)
7986:         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eMaxNew);
7987:         for (p = 0; p < 2+supportSize; ++p) {
7988:           if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", supportRef[p], fStartNew, fEndNew);
7989:         }
7990: #endif
7991:       }
7992:     }
7993:     /* Interior cell edges have 2 vertices and 4 faces */
7994:     for (c = cStart; c < cMax; ++c) {
7995:       const PetscInt  newFaces[24] = {0, 1, 2, 3,  4, 5, 6, 7,  0, 9, 4, 8,  2, 11, 6, 10,  1, 10, 5, 9,  3, 8, 7, 11};
7996:       const PetscInt  newv = vStartNew + (vEnd - vStart) + (eMax - eStart) + (fMax - fStart) + (c - cStart);
7997:       const PetscInt *cone;
7998:       PetscInt        coneNew[2], supportNew[4];

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

8004:         coneNew[0] = vStartNew + (vEnd - vStart) + (eMax - eStart) + (cone[r] - fStart);
8005:         coneNew[1] = newv;
8006:         DMPlexSetCone(rdm, newp, coneNew);
8007: #if defined(PETSC_USE_DEBUG)
8008:         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eMaxNew);
8009:         for (p = 0; p < 2; ++p) {
8010:           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", coneNew[p], vStartNew, vEndNew);
8011:         }
8012: #endif
8013:         for (f = 0; f < 4; ++f) supportNew[f] = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + newFaces[r*4+f];
8014:         DMPlexSetSupport(rdm, newp, supportNew);
8015: #if defined(PETSC_USE_DEBUG)
8016:         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eMaxNew);
8017:         for (p = 0; p < 4; ++p) {
8018:           if ((supportNew[p] < fStartNew) || (supportNew[p] >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", supportNew[p], fStartNew, fMaxNew);
8019:         }
8020: #endif
8021:       }
8022:     }
8023:     /* Hybrid edges have two vertices and the same faces */
8024:     for (e = eMax; e < eEnd; ++e) {
8025:       const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (e - eMax);
8026:       const PetscInt *cone, *support, *fcone;
8027:       PetscInt        coneNew[2], size, fsize, s;

8029:       DMPlexGetCone(dm, e, &cone);
8030:       DMPlexGetSupportSize(dm, e, &size);
8031:       DMPlexGetSupport(dm, e, &support);
8032:       coneNew[0] = vStartNew + (cone[0] - vStart);
8033:       coneNew[1] = vStartNew + (cone[1] - vStart);
8034:       DMPlexSetCone(rdm, newp, coneNew);
8035: #if defined(PETSC_USE_DEBUG)
8036:       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a hybrid edge [%D, %D)", newp, eMaxNew, eEndNew);
8037:       for (p = 0; p < 2; ++p) {
8038:         if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", coneNew[p], vStartNew, vEndNew);
8039:       }
8040: #endif
8041:       for (s = 0; s < size; ++s) {
8042:         DMPlexGetConeSize(dm, support[s], &fsize);
8043:         DMPlexGetCone(dm, support[s], &fcone);
8044:         for (c = 0; c < fsize; ++c) if (fcone[c] == e) break;
8045:         if ((c < 2) || (c > 3)) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Edge %D not found in cone of face %D", e, support[s]);
8046:         supportRef[s] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (support[s] - fMax)*2 + c-2;
8047:       }
8048:       DMPlexSetSupport(rdm, newp, supportRef);
8049: #if defined(PETSC_USE_DEBUG)
8050:       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a hybrid edge [%D, %D)", newp, eMaxNew, eEndNew);
8051:       for (p = 0; p < size; ++p) {
8052:         if ((supportRef[p] < fMaxNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a hybrid face [%D, %D)", supportRef[p], fMaxNew, fEndNew);
8053:       }
8054: #endif
8055:     }
8056:     /* Hybrid face edges have 2 vertices and 2+cells faces */
8057:     for (f = fMax; f < fEnd; ++f) {
8058:       const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (eEnd - eMax) + (f - fMax);
8059:       const PetscInt *cone, *support, *ccone, *cornt;
8060:       PetscInt        coneNew[2], size, csize, s;

8062:       DMPlexGetCone(dm, f, &cone);
8063:       DMPlexGetSupportSize(dm, f, &size);
8064:       DMPlexGetSupport(dm, f, &support);
8065:       coneNew[0] = vStartNew + (vEnd - vStart) + (cone[0] - eStart);
8066:       coneNew[1] = vStartNew + (vEnd - vStart) + (cone[1] - eStart);
8067:       DMPlexSetCone(rdm, newp, coneNew);
8068: #if defined(PETSC_USE_DEBUG)
8069:       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a hybrid edge [%D, %D)", newp, eMaxNew, eEndNew);
8070:       for (p = 0; p < 2; ++p) {
8071:         if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", coneNew[p], vStartNew, vEndNew);
8072:       }
8073: #endif
8074:       supportRef[0] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (f - fMax)*2 + 0;
8075:       supportRef[1] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (f - fMax)*2 + 1;
8076:       for (s = 0; s < size; ++s) {
8077:         DMPlexGetConeSize(dm, support[s], &csize);
8078:         DMPlexGetCone(dm, support[s], &ccone);
8079:         DMPlexGetConeOrientation(dm, support[s], &cornt);
8080:         for (c = 0; c < csize; ++c) if (ccone[c] == f) break;
8081:         if ((c < 2) || (c >= csize)) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Hybrid face %D is not in cone of hybrid cell %D", f, support[s]);
8082:         supportRef[2+s] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd - fMax)*2 + (support[s] - cMax)*4 + c-2;
8083:       }
8084:       DMPlexSetSupport(rdm, newp, supportRef);
8085: #if defined(PETSC_USE_DEBUG)
8086:       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a hybrid edge [%D, %D)", newp, eMaxNew, eEndNew);
8087:       for (p = 0; p < 2+size; ++p) {
8088:         if ((supportRef[p] < fMaxNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a hybrid face [%D, %D)", supportRef[p], fMaxNew, fEndNew);
8089:       }
8090: #endif
8091:     }
8092:     /* Hybrid cell edges have 2 vertices and 4 faces */
8093:     for (c = cMax; c < cEnd; ++c) {
8094:       const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (eEnd - eMax) + (fEnd - fMax) + (c - cMax);
8095:       const PetscInt *cone, *support;
8096:       PetscInt        coneNew[2], size;

8098:       DMPlexGetCone(dm, c, &cone);
8099:       DMPlexGetSupportSize(dm, c, &size);
8100:       DMPlexGetSupport(dm, c, &support);
8101:       coneNew[0] = vStartNew + (vEnd - vStart) + (eMax - eStart) + (cone[0] - fStart);
8102:       coneNew[1] = vStartNew + (vEnd - vStart) + (eMax - eStart) + (cone[1] - fStart);
8103:       DMPlexSetCone(rdm, newp, coneNew);
8104: #if defined(PETSC_USE_DEBUG)
8105:       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a hybrid edge [%D, %D)", newp, eMaxNew, eEndNew);
8106:       for (p = 0; p < 2; ++p) {
8107:         if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", coneNew[p], vStartNew, vEndNew);
8108:       }
8109: #endif
8110:       supportRef[0] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd - fMax)*2 + (c - cMax)*4 + 0;
8111:       supportRef[1] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd - fMax)*2 + (c - cMax)*4 + 1;
8112:       supportRef[2] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd - fMax)*2 + (c - cMax)*4 + 2;
8113:       supportRef[3] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd - fMax)*2 + (c - cMax)*4 + 3;
8114:       DMPlexSetSupport(rdm, newp, supportRef);
8115: #if defined(PETSC_USE_DEBUG)
8116:       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a hybrid edge [%D, %D)", newp, eMaxNew, eEndNew);
8117:       for (p = 0; p < 4; ++p) {
8118:         if ((supportRef[p] < fMaxNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a hybrid face [%D, %D)", supportRef[p], fMaxNew, fEndNew);
8119:       }
8120: #endif
8121:     }
8122:     /* Interior vertices have identical supports */
8123:     for (v = vStart; v < vEnd; ++v) {
8124:       const PetscInt  newp = vStartNew + (v - vStart);
8125:       const PetscInt *support, *cone;
8126:       PetscInt        size, s;

8128:       DMPlexGetSupportSize(dm, v, &size);
8129:       DMPlexGetSupport(dm, v, &support);
8130:       for (s = 0; s < size; ++s) {
8131:         PetscInt r = 0;

8133:         DMPlexGetCone(dm, support[s], &cone);
8134:         if (cone[1] == v) r = 1;
8135:         if (support[s] < eMax) supportRef[s] = eStartNew + (support[s] - eStart)*2 + r;
8136:         else                   supportRef[s] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (support[s] - eMax);
8137:       }
8138:       DMPlexSetSupport(rdm, newp, supportRef);
8139: #if defined(PETSC_USE_DEBUG)
8140:       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", newp, vStartNew, vEndNew);
8141:       for (p = 0; p < size; ++p) {
8142:         if ((supportRef[p] < eStartNew) || (supportRef[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", supportRef[p], eStartNew, eEndNew);
8143:       }
8144: #endif
8145:     }
8146:     /* Interior edge vertices have 2 + faces supports */
8147:     for (e = eStart; e < eMax; ++e) {
8148:       const PetscInt  newp = vStartNew + (vEnd - vStart) + (e - eStart);
8149:       const PetscInt *cone, *support;
8150:       PetscInt        size, s;

8152:       DMPlexGetSupportSize(dm, e, &size);
8153:       DMPlexGetSupport(dm, e, &support);
8154:       supportRef[0] = eStartNew + (e - eStart)*2 + 0;
8155:       supportRef[1] = eStartNew + (e - eStart)*2 + 1;
8156:       for (s = 0; s < size; ++s) {
8157:         PetscInt r;

8159:         DMPlexGetCone(dm, support[s], &cone);
8160:         for (r = 0; r < 4; ++r) if (cone[r] == e) break;
8161:         if (support[s] < fMax) {
8162:           supportRef[2+s] = eStartNew + (eMax - eStart)*2 + (support[s] - fStart)*4 + r;
8163:         } else {
8164:           supportRef[2+s] = eStartNew + (eMax - eStart)*2 + (fMax       - fStart)*4 + (cMax - cStart)*6 + (eEnd - eMax) + (support[s] - fMax);
8165:         }
8166:       }
8167:       DMPlexSetSupport(rdm, newp, supportRef);
8168: #if defined(PETSC_USE_DEBUG)
8169:       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", newp, vStartNew, vEndNew);
8170:       for (p = 0; p < 2+size; ++p) {
8171:         if ((supportRef[p] < eStartNew) || (supportRef[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", supportRef[p], eStartNew, eEndNew);
8172:       }
8173: #endif
8174:     }
8175:     /* Interior face vertices have 4 + cells supports */
8176:     for (f = fStart; f < fMax; ++f) {
8177:       const PetscInt  newp = vStartNew + (vEnd - vStart) + (eMax - eStart) + (f - fStart);
8178:       const PetscInt *cone, *support;
8179:       PetscInt        size, s;

8181:       DMPlexGetSupportSize(dm, f, &size);
8182:       DMPlexGetSupport(dm, f, &support);
8183:       for (r = 0; r < 4; ++r) supportRef[r] = eStartNew + (eMax - eStart)*2 +  (f - fStart)*4 + r;
8184:       for (s = 0; s < size; ++s) {
8185:         PetscInt r;

8187:         DMPlexGetCone(dm, support[s], &cone);
8188:         for (r = 0; r < 6; ++r) if (cone[r] == f) break;
8189:         if (support[s] < cMax) {
8190:           supportRef[4+s] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (support[s] - cStart)*6 + r;
8191:         } else {
8192:           supportRef[4+s] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax       - cStart)*6 + (eEnd - eMax) + (fEnd - fMax) + (support[s] - cMax);
8193:         }
8194:       }
8195:       DMPlexSetSupport(rdm, newp, supportRef);
8196: #if defined(PETSC_USE_DEBUG)
8197:       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", newp, vStartNew, vEndNew);
8198:       for (p = 0; p < 4+size; ++p) {
8199:         if ((supportRef[p] < eStartNew) || (supportRef[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", supportRef[p], eStartNew, eEndNew);
8200:       }
8201: #endif
8202:     }
8203:     /* Cell vertices have 6 supports */
8204:     for (c = cStart; c < cMax; ++c) {
8205:       const PetscInt newp = vStartNew + (vEnd - vStart) + (eMax - eStart) + (fMax - fStart) + (c - cStart);
8206:       PetscInt       supportNew[6];

8208:       for (r = 0; r < 6; ++r) {
8209:         supportNew[r] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (c - cStart)*6 + r;
8210:       }
8211:       DMPlexSetSupport(rdm, newp, supportNew);
8212:     }
8213:     PetscFree(supportRef);
8214:     break;
8215:   default:
8216:     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %s", CellRefiners[refiner]);
8217:   }
8218:   return(0);
8219: }

8221: static PetscErrorCode CellRefinerSetCoordinates(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
8222: {
8223:   PetscSection          coordSection, coordSectionNew;
8224:   Vec                   coordinates, coordinatesNew;
8225:   PetscScalar          *coords, *coordsNew;
8226:   const PetscInt        numVertices = depthSize ? depthSize[0] : 0;
8227:   PetscInt              dim, spaceDim, depth, bs, coordSizeNew, cStart, cEnd, cMax;
8228:   PetscInt              c, vStart, vStartNew, vEnd, v, eStart, eEnd, eMax, e, fStart, fEnd, fMax, f;
8229:   PetscInt              cStartNew, cEndNew, vEndNew, *parentId = NULL;
8230:   VecType               vtype;
8231:   PetscBool             isperiodic, localize = PETSC_FALSE, needcoords = PETSC_FALSE;
8232:   const PetscReal      *maxCell, *L;
8233:   const DMBoundaryType *bd;
8234:   PetscErrorCode        ierr;

8237:   DMGetDimension(dm, &dim);
8238:   DMPlexGetDepth(dm, &depth);
8239:   DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);
8240:   DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);
8241:   DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);
8242:   DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);
8243:   DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, NULL);
8244:   if (cMax < 0) cMax = cEnd;
8245:   if (fMax < 0) fMax = fEnd;
8246:   if (eMax < 0) eMax = eEnd;
8247:   GetDepthStart_Private(depth, depthSize, &cStartNew, NULL, NULL, &vStartNew);
8248:   GetDepthEnd_Private(depth, depthSize, &cEndNew, NULL, NULL, &vEndNew);
8249:   DMGetPeriodicity(dm, &isperiodic, &maxCell, &L, &bd);
8250:   /* Determine if we need to localize coordinates when generating them */
8251:   if (isperiodic && !maxCell) {
8252:     DMGetCoordinatesLocalized(dm, &localize);
8253:     if (!localize) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_USER,"Cannot refine if coordinates have not been localized");
8254:   }
8255:   if (isperiodic) {
8256:     PetscOptionsBegin(PetscObjectComm((PetscObject)dm),((PetscObject)dm)->prefix,"DMPlex coords refinement options","DM");
8257:     PetscOptionsBool("-dm_plex_refine_localize","Automatically localize from parent cells",NULL,localize,&localize,NULL);
8258:     PetscOptionsEnd();
8259:     if (localize) {
8260:       DMLocalizeCoordinates(dm);
8261:     }
8262:   }
8263:   DMSetPeriodicity(rdm, isperiodic,  maxCell,  L,  bd);

8265:   DMGetCoordinateSection(dm, &coordSection);
8266:   PetscSectionGetFieldComponents(coordSection, 0, &spaceDim);
8267:   PetscSectionCreate(PetscObjectComm((PetscObject)dm), &coordSectionNew);
8268:   PetscSectionSetNumFields(coordSectionNew, 1);
8269:   PetscSectionSetFieldComponents(coordSectionNew, 0, spaceDim);

8271:   if (localize) {
8272:     PetscInt p, r, newp, *pi;

8274:     /* New coordinates will be already localized on the cell */
8275:     PetscSectionSetChart(coordSectionNew, 0, vStartNew+numVertices);

8277:     /* We need the parentId to properly localize coordinates */
8278:     PetscMalloc1(cEndNew-cStartNew,&pi);
8279:     switch (refiner) {
8280:     case REFINER_NOOP:
8281:       break;
8282:     case REFINER_SIMPLEX_1D:
8283:       for (p = cStart; p < cEnd; ++p) {
8284:         for (r = 0; r < 2; ++r) {
8285:           newp     = (p - cStart)*2 + r;
8286:           pi[newp] = p;
8287:         }
8288:       }
8289:       break;
8290:     case REFINER_SIMPLEX_2D:
8291:       for (p = cStart; p < cEnd; ++p) {
8292:         for (r = 0; r < 4; ++r) {
8293:           newp     = (p - cStart)*4 + r;
8294:           pi[newp] = p;
8295:         }
8296:       }
8297:       break;
8298:     case REFINER_HEX_2D:
8299:       for (p = cStart; p < cEnd; ++p) {
8300:         for (r = 0; r < 4; ++r) {
8301:           newp     = (p - cStart)*4 + r;
8302:           pi[newp] = p;
8303:         }
8304:       }
8305:       break;
8306:     case REFINER_SIMPLEX_TO_HEX_2D:
8307:       for (p = cStart; p < cEnd; ++p) {
8308:         for (r = 0; r < 3; ++r) {
8309:           newp     = (p - cStart)*3 + r;
8310:           pi[newp] = p;
8311:         }
8312:       }
8313:       break;
8314:     case REFINER_HYBRID_SIMPLEX_TO_HEX_2D:
8315:       for (p = cStart; p < cMax; ++p) {
8316:         for (r = 0; r < 3; ++r) {
8317:           newp     = (p - cStart)*3 + r;
8318:           pi[newp] = p;
8319:         }
8320:       }
8321:       for (p = cMax; p < cEnd; ++p) {
8322:         for (r = 0; r < 4; ++r) {
8323:           newp     = (cMax - cStart)*3 + (p - cMax)*4 + r;
8324:           pi[newp] = p;
8325:         }
8326:       }
8327:       /* The refiner needs midpoint vertices on hybrid edges and hybrid cells */
8328:       cMax = cEnd;
8329:       eMax = eEnd;
8330:       break;
8331:     case REFINER_HYBRID_SIMPLEX_2D:
8332:       for (p = cStart; p < cMax; ++p) {
8333:         for (r = 0; r < 4; ++r) {
8334:           newp     = (p - cStart)*4 + r;
8335:           pi[newp] = p;
8336:         }
8337:       }
8338:       for (p = cMax; p < cEnd; ++p) {
8339:         for (r = 0; r < 2; ++r) {
8340:           newp     = (cMax - cStart)*4 + (p - cMax)*2 + r;
8341:           pi[newp] = p;
8342:         }
8343:       }
8344:       break;
8345:     case REFINER_HYBRID_HEX_2D:
8346:       for (p = cStart; p < cMax; ++p) {
8347:         for (r = 0; r < 4; ++r) {
8348:           newp     = (p - cStart)*4 + r;
8349:           pi[newp] = p;
8350:         }
8351:       }
8352:       for (p = cMax; p < cEnd; ++p) {
8353:         for (r = 0; r < 2; ++r) {
8354:           newp     = (cMax - cStart)*4 + (p - cMax)*2 + r;
8355:           pi[newp] = p;
8356:         }
8357:       }
8358:       break;
8359:     case REFINER_SIMPLEX_3D:
8360:       for (p = cStart; p < cEnd; ++p) {
8361:         for (r = 0; r < 8; ++r) {
8362:           newp     = (p - cStart)*8 + r;
8363:           pi[newp] = p;
8364:         }
8365:       }
8366:       break;
8367:     case REFINER_HYBRID_SIMPLEX_3D:
8368:       for (p = cStart; p < cMax; ++p) {
8369:         for (r = 0; r < 8; ++r) {
8370:           newp     = (p - cStart)*8 + r;
8371:           pi[newp] = p;
8372:         }
8373:       }
8374:       for (p = cMax; p < cEnd; ++p) {
8375:         for (r = 0; r < 4; ++r) {
8376:           newp     = (cMax - cStart)*8 + (p - cMax)*4 + r;
8377:           pi[newp] = p;
8378:         }
8379:       }
8380:       break;
8381:     case REFINER_SIMPLEX_TO_HEX_3D:
8382:       for (p = cStart; p < cEnd; ++p) {
8383:         for (r = 0; r < 4; ++r) {
8384:           newp     = (p - cStart)*4 + r;
8385:           pi[newp] = p;
8386:         }
8387:       }
8388:       break;
8389:     case REFINER_HYBRID_SIMPLEX_TO_HEX_3D:
8390:       for (p = cStart; p < cMax; ++p) {
8391:         for (r = 0; r < 4; ++r) {
8392:           newp     = (p - cStart)*4 + r;
8393:           pi[newp] = p;
8394:         }
8395:       }
8396:       for (p = cMax; p < cEnd; ++p) {
8397:         for (r = 0; r < 3; ++r) {
8398:           newp     = (cMax - cStart)*4 + (p - cMax)*3 + r;
8399:           pi[newp] = p;
8400:         }
8401:       }
8402:       break;
8403:     case REFINER_HEX_3D:
8404:       for (p = cStart; p < cEnd; ++p) {
8405:         for (r = 0; r < 8; ++r) {
8406:           newp = (p - cStart)*8 + r;
8407:           pi[newp] = p;
8408:         }
8409:       }
8410:       break;
8411:     case REFINER_HYBRID_HEX_3D:
8412:       for (p = cStart; p < cMax; ++p) {
8413:         for (r = 0; r < 8; ++r) {
8414:           newp = (p - cStart)*8 + r;
8415:           pi[newp] = p;
8416:         }
8417:       }
8418:       for (p = cMax; p < cEnd; ++p) {
8419:         for (r = 0; r < 4; ++r) {
8420:           newp = (cMax - cStart)*8 + (p - cMax)*4 + r;
8421:           pi[newp] = p;
8422:         }
8423:       }
8424:       break;
8425:     default:
8426:       SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %s", CellRefiners[refiner]);
8427:     }
8428:     parentId = pi;
8429:   } else {
8430:     /* The refiner needs midpoint vertices on hybrid edges and hybrid cells */
8431:     if (REFINER_HYBRID_SIMPLEX_TO_HEX_2D == refiner) { cMax = cEnd; eMax = eEnd; }
8432:     PetscSectionSetChart(coordSectionNew, vStartNew, vStartNew+numVertices);
8433:   }

8435:   /* All vertices have the spaceDim coordinates */
8436:   if (localize) {
8437:     PetscInt c;

8439:     for (c = cStartNew; c < cEndNew; ++c) {
8440:       PetscInt *cone = NULL;
8441:       PetscInt  closureSize, coneSize = 0, p, pdof;

8443:       PetscSectionGetDof(coordSection, parentId[c], &pdof);
8444:       if (pdof) { /* localize on all cells that are refinement of a localized parent cell */
8445:         DMPlexGetTransitiveClosure(rdm, c, PETSC_TRUE, &closureSize, &cone);
8446:         for (p = 0; p < closureSize*2; p += 2) {
8447:           const PetscInt point = cone[p];
8448:           if ((point >= vStartNew) && (point < vEndNew)) coneSize++;
8449:         }
8450:         DMPlexRestoreTransitiveClosure(rdm, c, PETSC_TRUE, &closureSize, &cone);
8451:         PetscSectionSetDof(coordSectionNew, c, coneSize*spaceDim);
8452:         PetscSectionSetFieldDof(coordSectionNew, c, 0, coneSize*spaceDim);
8453:       }
8454:     }
8455:   }
8456:   for (v = vStartNew; v < vStartNew+numVertices; ++v) {
8457:     PetscSectionSetDof(coordSectionNew, v, spaceDim);
8458:     PetscSectionSetFieldDof(coordSectionNew, v, 0, spaceDim);
8459:   }
8460:   PetscSectionSetUp(coordSectionNew);
8461:   DMSetCoordinateSection(rdm, PETSC_DETERMINE, coordSectionNew);
8462:   DMGetCoordinatesLocal(dm, &coordinates);
8463:   PetscSectionGetStorageSize(coordSectionNew, &coordSizeNew);
8464:   VecCreate(PETSC_COMM_SELF, &coordinatesNew);
8465:   PetscObjectSetName((PetscObject) coordinatesNew, "coordinates");
8466:   VecSetSizes(coordinatesNew, coordSizeNew, PETSC_DETERMINE);
8467:   VecGetBlockSize(coordinates, &bs);
8468:   VecSetBlockSize(coordinatesNew, bs);
8469:   VecGetType(coordinates, &vtype);
8470:   VecSetType(coordinatesNew, vtype);
8471:   VecGetArray(coordinates, &coords);
8472:   VecGetArray(coordinatesNew, &coordsNew);

8474:   switch (refiner) {
8475:   case REFINER_NOOP: break;
8476:   case REFINER_HYBRID_SIMPLEX_TO_HEX_3D:
8477:   case REFINER_SIMPLEX_TO_HEX_3D:
8478:   case REFINER_HEX_3D:
8479:   case REFINER_HYBRID_HEX_3D:
8480:     /* Face vertices have the average of corner coordinates */
8481:     for (f = fStart; f < fMax; ++f) {
8482:       const PetscInt newv = vStartNew + (vEnd - vStart) + (eMax - eStart) + (f - fStart);
8483:       PetscInt      *cone = NULL;
8484:       PetscInt       closureSize, coneSize = 0, off[8], offnew, p, d;

8486:       DMPlexGetTransitiveClosure(dm, f, PETSC_TRUE, &closureSize, &cone);
8487:       for (p = 0; p < closureSize*2; p += 2) {
8488:         const PetscInt point = cone[p];
8489:         if ((point >= vStart) && (point < vEnd)) cone[coneSize++] = point;
8490:       }
8491:       if (localize) {
8492:         const PetscInt *support = NULL;
8493:         PetscInt       *rStar = NULL;
8494:         PetscInt        supportSize, rStarSize, coff, s, ccoff[8];
8495:         PetscBool       cellfound = PETSC_FALSE;

8497:         DMPlexGetTransitiveClosure(rdm, newv, PETSC_FALSE, &rStarSize, &rStar);
8498:         DMPlexGetSupportSize(dm,f,&supportSize);
8499:         DMPlexGetSupport(dm,f,&support);
8500:         /* Compute average of coordinates for each cell sharing the face */
8501:         for (s = 0; s < supportSize; ++s) {
8502:           PetscScalar     coordsNewAux[3] = { 0.0, 0.0, 0.0 };
8503:           PetscInt       *cellCone = NULL;
8504:           PetscInt        cellClosureSize, cellConeSize = 0, cdof;
8505:           const PetscInt  cell = support[s];
8506:           PetscBool       copyoff = PETSC_FALSE;

8508:           DMPlexGetTransitiveClosure(dm, cell, PETSC_TRUE, &cellClosureSize, &cellCone);
8509:           for (p = 0; p < cellClosureSize*2; p += 2) {
8510:             const PetscInt point = cellCone[p];
8511:             if ((point >= vStart) && (point < vEnd)) cellCone[cellConeSize++] = point;
8512:           }
8513:           PetscSectionGetDof(coordSection, cell, &cdof);
8514:           if (!cdof) { /* the parent cell does not have localized coordinates */
8515:             cellfound = PETSC_TRUE;
8516:             for (v = 0; v < coneSize; ++v) {
8517:               PetscSectionGetOffset(coordSection, cone[v], &off[v]);
8518:               for (d = 0; d < spaceDim; ++d) coordsNewAux[d] += coords[off[v]+d];
8519:             }
8520:             for (d = 0; d < spaceDim; ++d) coordsNewAux[d] /= coneSize;
8521:           } else {
8522:             PetscSectionGetOffset(coordSection, cell, &coff);
8523:             for (p = 0; p < coneSize; ++p) {
8524:               const PetscInt tv = cone[p];
8525:               PetscInt       cv, voff;
8526:               PetscBool      locv = PETSC_TRUE;

8528:               for (cv = 0; cv < cellConeSize; ++cv) {
8529:                 if (cellCone[cv] == tv) {
8530:                   ccoff[p] = spaceDim*cv + coff;
8531:                   break;
8532:                 }
8533:               }
8534:               if (cv == cellConeSize) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Unable to map vertex %D",tv);

8536:               PetscSectionGetOffset(coordSection, cone[p], &voff);
8537:               for (d = 0; d < spaceDim; ++d) {
8538:                 coordsNewAux[d] += coords[ccoff[p]+d];
8539:                 if (!cellfound && coords[voff+d] != coords[ccoff[p]+d]) locv = PETSC_FALSE;
8540:               }
8541:               if (locv && !cellfound) {
8542:                 cellfound = PETSC_TRUE;
8543:                 copyoff   = PETSC_TRUE;
8544:               }
8545:             }
8546:             for (d = 0; d < spaceDim; ++d) coordsNewAux[d] /= coneSize;

8548:             /* Found a valid face for the "vertex" part of the Section (physical space)
8549:                i.e., a face that has at least one corner in the physical space */
8550:             if (copyoff) for (p = 0; p < coneSize; ++p) off[p] = ccoff[p];
8551:           }

8553:           /* Localize new coordinates on each refined cell */
8554:           for (v = 0; v < rStarSize*2; v += 2) {
8555:             if ((rStar[v] >= cStartNew) && (rStar[v] < cEndNew) && parentId[rStar[v]-cStartNew] == cell) {
8556:               PetscInt       *rcone = NULL, rclosureSize, lid, rcdof, rcoff;
8557:               const PetscInt  rcell = rStar[v];

8559:               PetscSectionGetDof(coordSectionNew, rcell, &rcdof);
8560:               if (!rcdof) continue;
8561:               PetscSectionGetOffset(coordSectionNew, rcell, &rcoff);
8562:               DMPlexGetTransitiveClosure(rdm, rcell, PETSC_TRUE, &rclosureSize, &rcone);
8563:               for (p = 0, lid = 0; p < rclosureSize*2; p += 2) {
8564:                 if (rcone[p] == newv) {
8565:                   for (d = 0; d < spaceDim; d++) coordsNew[rcoff + lid*spaceDim + d] = coordsNewAux[d];
8566:                   break;
8567:                 }
8568:                 if (rcone[p] >= vStartNew && rcone[p] < vEndNew) lid++;
8569:               }
8570:               DMPlexRestoreTransitiveClosure(rdm, rcell, PETSC_TRUE, &rclosureSize, &rcone);
8571:               if (p == closureSize*2) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Unable to map new vertex %D",newv);
8572:             }
8573:           }
8574:           DMPlexRestoreTransitiveClosure(dm, cell, PETSC_TRUE, &cellClosureSize, &cellCone);
8575:         }
8576:         DMPlexRestoreTransitiveClosure(rdm, newv, PETSC_FALSE, &rStarSize, &rStar);
8577:         if (!cellfound) {
8578:           /* Could not find a valid face for the vertex part, we will get this vertex later (final reduction) */
8579:           needcoords = PETSC_TRUE;
8580:           coneSize   = 0;
8581:         }
8582:       } else {
8583:         for (v = 0; v < coneSize; ++v) {
8584:           PetscSectionGetOffset(coordSection, cone[v], &off[v]);
8585:         }
8586:       }
8587:       PetscSectionGetOffset(coordSectionNew, newv, &offnew);
8588:       if (coneSize) {
8589:         for (d = 0; d < spaceDim; ++d) coordsNew[offnew+d] = 0.0;
8590:         for (v = 0; v < coneSize; ++v) {DMLocalizeAddCoordinate_Internal(dm, spaceDim, &coords[off[0]], &coords[off[v]], &coordsNew[offnew]);}
8591:         for (d = 0; d < spaceDim; ++d) coordsNew[offnew+d] /= coneSize;
8592:       } else {
8593:         for (d = 0; d < spaceDim; ++d) coordsNew[offnew+d] = PETSC_MIN_REAL;
8594:       }
8595:       DMPlexRestoreTransitiveClosure(dm, f, PETSC_TRUE, &closureSize, &cone);
8596:     }
8597:   case REFINER_HYBRID_SIMPLEX_TO_HEX_2D:
8598:   case REFINER_SIMPLEX_TO_HEX_2D:
8599:   case REFINER_HEX_2D:
8600:   case REFINER_HYBRID_HEX_2D:
8601:   case REFINER_SIMPLEX_1D:
8602:     /* Cell vertices have the average of corner coordinates */
8603:     for (c = cStart; c < cMax; ++c) {
8604:       const PetscInt newv = vStartNew + (vEnd - vStart) + (dim > 1 ? (eMax - eStart) : 0) + (c - cStart) + (dim > 2 ? (fMax - fStart) : 0);
8605:       PetscInt      *cone = NULL;
8606:       PetscInt       closureSize, coneSize = 0, off[8], offnew, p, d, cdof = 0;

8608:       DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &cone);
8609:       for (p = 0; p < closureSize*2; p += 2) {
8610:         const PetscInt point = cone[p];
8611:         if ((point >= vStart) && (point < vEnd)) cone[coneSize++] = point;
8612:       }
8613:       if (localize) {
8614:         PetscSectionGetDof(coordSection, c, &cdof);
8615:       }
8616:       if (cdof) {
8617:         PetscInt coff;

8619:         PetscSectionGetOffset(coordSection, c, &coff);
8620:         for (v = 0; v < coneSize; ++v) off[v] = spaceDim*v + coff;
8621:       } else {
8622:         for (v = 0; v < coneSize; ++v) {
8623:           PetscSectionGetOffset(coordSection, cone[v], &off[v]);
8624:         }
8625:       }
8626:       PetscSectionGetOffset(coordSectionNew, newv, &offnew);
8627:       for (d = 0; d < spaceDim; ++d) coordsNew[offnew+d] = 0.0;
8628:       for (v = 0; v < coneSize; ++v) {DMLocalizeAddCoordinate_Internal(dm, spaceDim, &coords[off[0]], &coords[off[v]], &coordsNew[offnew]);}
8629:       for (d = 0; d < spaceDim; ++d) coordsNew[offnew+d] /= coneSize;
8630:       DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &cone);

8632:       /* Localize new coordinates on each refined cell */
8633:       if (cdof) {
8634:         PetscInt *rStar = NULL, rStarSize;

8636:         DMPlexGetTransitiveClosure(rdm, newv, PETSC_FALSE, &rStarSize, &rStar);
8637:         for (v = 0; v < rStarSize*2; v += 2) {
8638:           if ((rStar[v] >= cStartNew) && (rStar[v] < cEndNew)) {
8639:             PetscInt *cone = NULL, closureSize, lid, coff, rc, rcdof;

8641:             rc   = rStar[v];
8642:             PetscSectionGetDof(coordSectionNew, rc, &rcdof);
8643:             if (!rcdof) continue;
8644:             PetscSectionGetOffset(coordSectionNew, rc, &coff);
8645:             DMPlexGetTransitiveClosure(rdm, rc, PETSC_TRUE, &closureSize, &cone);
8646:             for (p = 0, lid = 0; p < closureSize*2; p += 2) {
8647:               if (cone[p] == newv) {
8648:                 for (d = 0; d < spaceDim; d++) coordsNew[coff + lid*spaceDim + d] = coordsNew[offnew + d];
8649:                 break;
8650:               }
8651:               if (cone[p] >= vStartNew && cone[p] < vEndNew) lid++;
8652:             }
8653:             if (p == closureSize*2) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Unable to map new vertex %D",newv);
8654:             DMPlexRestoreTransitiveClosure(rdm, rc, PETSC_TRUE, &closureSize, &cone);
8655:           }
8656:         }
8657:         DMPlexRestoreTransitiveClosure(rdm, newv, PETSC_FALSE, &rStarSize, &rStar);
8658:       }
8659:     }
8660:   case REFINER_SIMPLEX_2D:
8661:   case REFINER_HYBRID_SIMPLEX_2D:
8662:   case REFINER_SIMPLEX_3D:
8663:   case REFINER_HYBRID_SIMPLEX_3D:
8664:     /* Edge vertices have the average of endpoint coordinates */
8665:     for (e = eStart; e < eMax; ++e) {
8666:       const PetscInt  newv = vStartNew + (vEnd - vStart) + (e - eStart);
8667:       const PetscInt *cone;
8668:       PetscInt        coneSize, offA, offB, offnew, d;

8670:       DMPlexGetConeSize(dm, e, &coneSize);
8671:       if (coneSize != 2) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Edge %D cone should have two vertices, not %D", e, coneSize);
8672:       DMPlexGetCone(dm, e, &cone);
8673:       if (localize) {
8674:         PetscInt   coff, toffA = -1, toffB = -1, voffA, voffB;
8675:         PetscInt  *eStar = NULL, eStarSize;
8676:         PetscInt  *rStar = NULL, rStarSize;
8677:         PetscBool  cellfound = PETSC_FALSE;

8679:         offA = offB = -1;
8680:         PetscSectionGetOffset(coordSection, cone[0], &voffA);
8681:         PetscSectionGetOffset(coordSection, cone[1], &voffB);
8682:         DMPlexGetTransitiveClosure(dm, e, PETSC_FALSE, &eStarSize, &eStar);
8683:         DMPlexGetTransitiveClosure(rdm, newv, PETSC_FALSE, &rStarSize, &rStar);
8684:         for (v = 0; v < eStarSize*2; v += 2) {
8685:           if ((eStar[v] >= cStart) && (eStar[v] < cEnd)) {
8686:             PetscScalar     coordsNewAux[3] = {0., 0., 0.};
8687:             PetscInt       *cellCone = NULL;
8688:             PetscInt        cellClosureSize, s, cv, cdof;
8689:             PetscBool       locvA = PETSC_TRUE, locvB = PETSC_TRUE;
8690:             const PetscInt  cell = eStar[v];

8692:             PetscSectionGetDof(coordSection, cell, &cdof);
8693:             if (!cdof) {
8694:               /* Found a valid edge for the "vertex" part of the Section */
8695:               offA = voffA;
8696:               offB = voffB;
8697:               cellfound = PETSC_TRUE;
8698:             } else {
8699:               PetscSectionGetOffset(coordSection, cell, &coff);
8700:               DMPlexGetTransitiveClosure(dm, cell, PETSC_TRUE, &cellClosureSize, &cellCone);
8701:               for (s = 0, cv = 0; s < cellClosureSize*2; s += 2) {
8702:                 const PetscInt point = cellCone[s];
8703:                 if ((point >= vStart) && (point < vEnd)) {
8704:                   if (point == cone[0]) toffA = spaceDim*cv + coff;
8705:                   else if (point == cone[1]) toffB = spaceDim*cv + coff;
8706:                   cv++;
8707:                 }
8708:               }
8709:               DMPlexRestoreTransitiveClosure(dm, cell, PETSC_TRUE, &cellClosureSize, &cellCone);
8710:               for (d = 0; d < spaceDim; ++d) {
8711:                 coordsNewAux[d] = 0.5*(coords[toffA+d] + coords[toffB+d]);
8712:                 if (coords[toffA+d] != coords[voffA+d]) locvA = PETSC_FALSE;
8713:                 if (coords[toffB+d] != coords[voffB+d]) locvB = PETSC_FALSE;
8714:               }
8715:               /* Found a valid edge for the "vertex" part of the Section */
8716:               if (!cellfound && (locvA || locvB)) {
8717:                 cellfound = PETSC_TRUE;
8718:                 offA = toffA;
8719:                 offB = toffB;
8720:               }
8721:             }

8723:             /* Localize new coordinates on each refined cell */
8724:             for (s = 0; s < rStarSize*2; s += 2) {
8725:               if ((rStar[s] >= cStartNew) && (rStar[s] < cEndNew) && parentId[rStar[s]-cStartNew] == cell) {
8726:                 PetscInt       *rcone = NULL, rclosureSize, lid, p, rcdof;
8727:                 const PetscInt  rcell = rStar[s];

8729:                 PetscSectionGetDof(coordSectionNew, rcell, &rcdof);
8730:                 if (!rcdof) continue;
8731:                 PetscSectionGetOffset(coordSectionNew, rcell, &coff);
8732:                 DMPlexGetTransitiveClosure(rdm, rcell, PETSC_TRUE, &rclosureSize, &rcone);
8733:                 for (p = 0, lid = 0; p < rclosureSize*2; p += 2) {
8734:                   if (rcone[p] == newv) {
8735:                     for (d = 0; d < spaceDim; d++) coordsNew[coff + lid*spaceDim + d] = coordsNewAux[d];
8736:                     break;
8737:                   }
8738:                   if (rcone[p] >= vStartNew && rcone[p] < vEndNew) lid++;
8739:                 }
8740:                 DMPlexRestoreTransitiveClosure(rdm, rcell, PETSC_TRUE, &rclosureSize, &rcone);
8741:                 if (p == rclosureSize*2) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Unable to map new vertex %D",newv);
8742:               }
8743:             }
8744:           }
8745:         }
8746:         DMPlexRestoreTransitiveClosure(dm, e, PETSC_FALSE, &eStarSize, &eStar);
8747:         DMPlexRestoreTransitiveClosure(rdm, newv, PETSC_FALSE, &rStarSize, &rStar);
8748:         if (!cellfound) {
8749:           /* Could not find a valid edge for the vertex part, we will get this vertex later (final reduction) */
8750:           needcoords = PETSC_TRUE;
8751:         }
8752:       } else {
8753:         PetscSectionGetOffset(coordSection, cone[0], &offA);
8754:         PetscSectionGetOffset(coordSection, cone[1], &offB);
8755:       }
8756:       PetscSectionGetOffset(coordSectionNew, newv, &offnew);
8757:       if (offA != -1 && offB != -1) {
8758:         DMLocalizeCoordinate_Internal(dm, spaceDim, &coords[offA], &coords[offB], &coordsNew[offnew]);
8759:         for (d = 0; d < spaceDim; ++d) {
8760:           coordsNew[offnew+d] = 0.5*(coords[offA+d] + coordsNew[offnew+d]);
8761:         }
8762:       } else {
8763:         for (d = 0; d < spaceDim; ++d) coordsNew[offnew+d] = PETSC_MIN_REAL;
8764:       }
8765:     }
8766:     /* Old vertices have the same coordinates */
8767:     for (v = vStart; v < vEnd; ++v) {
8768:       const PetscInt newv = vStartNew + (v - vStart);
8769:       PetscInt       off, offnew, d;

8771:       PetscSectionGetOffset(coordSection, v, &off);
8772:       PetscSectionGetOffset(coordSectionNew, newv, &offnew);
8773:       for (d = 0; d < spaceDim; ++d) {
8774:         coordsNew[offnew+d] = coords[off+d];
8775:       }

8777:       /* Localize new coordinates on each refined cell */
8778:       if (localize) {
8779:         PetscInt  p;
8780:         PetscInt *rStar = NULL, rStarSize;

8782:         DMPlexGetTransitiveClosure(rdm, newv, PETSC_FALSE, &rStarSize, &rStar);
8783:         for (p = 0; p < rStarSize*2; p += 2) {
8784:           if ((rStar[p] >= cStartNew) && (rStar[p] < cEndNew)) {
8785:             PetscScalar  ocoords[3] = {0,0,0}; /* dummy values for compiler warnings about uninitialized values */
8786:             PetscInt    *cone = NULL, closureSize, lid, coff, s, oc, cdof;

8788:             c    = rStar[p];
8789:             oc   = parentId[c-cStartNew];
8790:             PetscSectionGetDof(coordSectionNew, c, &cdof);
8791:             if (!cdof) continue;
8792:             PetscSectionGetDof(coordSection, oc, &cdof);
8793:             if (!cdof) continue;
8794:             PetscSectionGetOffset(coordSection, oc, &coff);
8795:             DMPlexGetTransitiveClosure(dm, oc, PETSC_TRUE, &closureSize, &cone);
8796:             for (s = 0, lid = 0; s < closureSize*2; s += 2) {
8797:               if (cone[s] == v) {
8798:                 for (d = 0; d < spaceDim; d++) ocoords[d] = coords[coff + lid*spaceDim + d];
8799:                 break;
8800:               }
8801:               if (cone[s] >= vStart && cone[s] < vEnd) lid++;
8802:             }
8803:             if (s == closureSize*2) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Unable to map old vertex %D",v);
8804:             DMPlexRestoreTransitiveClosure(dm, oc, PETSC_TRUE, &closureSize, &cone);

8806:             PetscSectionGetOffset(coordSectionNew, c, &coff);
8807:             DMPlexGetTransitiveClosure(rdm, c, PETSC_TRUE, &closureSize, &cone);
8808:             for (s = 0, lid = 0; s < closureSize*2; s += 2) {
8809:               if (cone[s] == newv) {
8810:                 for (d = 0; d < spaceDim; d++) coordsNew[coff + lid*spaceDim + d] = ocoords[d];
8811:                 break;
8812:               }
8813:               if (cone[s] >= vStartNew && cone[s] < vEndNew) lid++;
8814:             }
8815:             if (s == closureSize*2) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Unable to map new vertex %D",newv);
8816:             DMPlexRestoreTransitiveClosure(rdm, c, PETSC_TRUE, &closureSize, &cone);
8817:           }
8818:         }
8819:         DMPlexRestoreTransitiveClosure(rdm, newv, PETSC_FALSE, &rStarSize, &rStar);
8820:       }
8821:     }
8822:     break;
8823:   default:
8824:     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %s", CellRefiners[refiner]);
8825:   }
8826:   VecRestoreArray(coordinates, &coords);
8827:   VecRestoreArray(coordinatesNew, &coordsNew);
8828:   DMSetCoordinatesLocal(rdm, coordinatesNew);

8830:   /* Final reduction (if needed) if we are localizing */
8831:   if (localize) {
8832:     PetscBool gred;

8834:     MPIU_Allreduce(&needcoords, &gred, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject)rdm));
8835:     if (gred) {
8836:       DM                 cdm;
8837:       Vec                aux;
8838:       PetscSF            sf;
8839:       const PetscScalar *lArray;
8840:       PetscScalar       *gArray;
8841: #if defined(PETSC_USE_COMPLEX)
8842:       PetscInt          i, ln, gn;
8843:       PetscReal         *lrArray;
8844:       PetscReal         *grArray;
8845: #endif

8847:       DMGetCoordinateDM(rdm, &cdm);
8848:       DMCreateGlobalVector(cdm, &aux);
8849:       DMGetSectionSF(cdm, &sf);
8850:       VecGetArrayRead(coordinatesNew, &lArray);
8851:       VecSet(aux, PETSC_MIN_REAL);
8852:       VecGetArray(aux, &gArray);
8853: #if defined(PETSC_USE_COMPLEX)
8854:       VecGetLocalSize(aux, &gn);
8855:       VecGetLocalSize(coordinatesNew, &ln);
8856:       PetscMalloc2(ln,&lrArray,gn,&grArray);
8857:       for (i=0;i<ln;i++) lrArray[i] = PetscRealPart(lArray[i]);
8858:       for (i=0;i<gn;i++) grArray[i] = PetscRealPart(gArray[i]);
8859:       PetscSFReduceBegin(sf, MPIU_REAL, lrArray, grArray, MPIU_MAX);
8860:       PetscSFReduceEnd(sf, MPIU_REAL, lrArray, grArray, MPIU_MAX);
8861:       for (i=0;i<gn;i++) gArray[i] = grArray[i];
8862:       PetscFree2(lrArray,grArray);
8863: #else
8864:       PetscSFReduceBegin(sf, MPIU_SCALAR, lArray, gArray, MPIU_MAX);
8865:       PetscSFReduceEnd(sf, MPIU_SCALAR, lArray, gArray, MPIU_MAX);
8866: #endif
8867:       VecRestoreArrayRead(coordinatesNew, &lArray);
8868:       VecRestoreArray(aux, &gArray);
8869:       DMGlobalToLocalBegin(cdm, aux, INSERT_VALUES, coordinatesNew);
8870:       DMGlobalToLocalEnd(cdm, aux, INSERT_VALUES, coordinatesNew);
8871:       VecDestroy(&aux);
8872:     }
8873:   }
8874:   VecDestroy(&coordinatesNew);
8875:   PetscSectionDestroy(&coordSectionNew);
8876:   PetscFree(parentId);
8877:   return(0);
8878: }

8880: /*@
8881:   DMPlexCreateProcessSF - Create an SF which just has process connectivity

8883:   Collective on dm

8885:   Input Parameters:
8886: + dm      - The DM
8887: - sfPoint - The PetscSF which encodes point connectivity

8889:   Output Parameters:
8890: + processRanks - A list of process neighbors, or NULL
8891: - sfProcess    - An SF encoding the process connectivity, or NULL

8893:   Level: developer

8895: .seealso: PetscSFCreate(), DMPlexCreateTwoSidedProcessSF()
8896: @*/
8897: PetscErrorCode DMPlexCreateProcessSF(DM dm, PetscSF sfPoint, IS *processRanks, PetscSF *sfProcess)
8898: {
8899:   PetscInt           numRoots, numLeaves, l;
8900:   const PetscInt    *localPoints;
8901:   const PetscSFNode *remotePoints;
8902:   PetscInt          *localPointsNew;
8903:   PetscSFNode       *remotePointsNew;
8904:   PetscInt          *ranks, *ranksNew;
8905:   PetscMPIInt        size;
8906:   PetscErrorCode     ierr;

8913:   MPI_Comm_size(PetscObjectComm((PetscObject) dm), &size);
8914:   PetscSFGetGraph(sfPoint, &numRoots, &numLeaves, &localPoints, &remotePoints);
8915:   PetscMalloc1(numLeaves, &ranks);
8916:   for (l = 0; l < numLeaves; ++l) {
8917:     ranks[l] = remotePoints[l].rank;
8918:   }
8919:   PetscSortRemoveDupsInt(&numLeaves, ranks);
8920:   PetscMalloc1(numLeaves, &ranksNew);
8921:   PetscMalloc1(numLeaves, &localPointsNew);
8922:   PetscMalloc1(numLeaves, &remotePointsNew);
8923:   for (l = 0; l < numLeaves; ++l) {
8924:     ranksNew[l]              = ranks[l];
8925:     localPointsNew[l]        = l;
8926:     remotePointsNew[l].index = 0;
8927:     remotePointsNew[l].rank  = ranksNew[l];
8928:   }
8929:   PetscFree(ranks);
8930:   if (processRanks) {ISCreateGeneral(PetscObjectComm((PetscObject)dm), numLeaves, ranksNew, PETSC_OWN_POINTER, processRanks);}
8931:   else              {PetscFree(ranksNew);}
8932:   if (sfProcess) {
8933:     PetscSFCreate(PetscObjectComm((PetscObject)dm), sfProcess);
8934:     PetscObjectSetName((PetscObject) *sfProcess, "Process SF");
8935:     PetscSFSetFromOptions(*sfProcess);
8936:     PetscSFSetGraph(*sfProcess, size, numLeaves, localPointsNew, PETSC_OWN_POINTER, remotePointsNew, PETSC_OWN_POINTER);
8937:   }
8938:   return(0);
8939: }

8941: static PetscErrorCode CellRefinerCreateSF(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
8942: {
8943:   PetscSF            sf, sfNew, sfProcess;
8944:   IS                 processRanks;
8945:   MPI_Datatype       depthType;
8946:   PetscInt           numRoots, numLeaves, numLeavesNew = 0, l, m;
8947:   const PetscInt    *localPoints, *neighbors;
8948:   const PetscSFNode *remotePoints;
8949:   PetscInt          *localPointsNew;
8950:   PetscSFNode       *remotePointsNew;
8951:   PetscInt          *depthSizeOld, *rdepthSize, *rdepthSizeOld, *rdepthMaxOld, *rvStart, *rvStartNew, *reStart, *reStartNew, *rfStart, *rfStartNew, *rcStart, *rcStartNew;
8952:   PetscInt           ldepth, depth, numNeighbors, pStartNew, pEndNew, cStart, cEnd, cMax, vStart, vEnd, vMax, fStart, fEnd, fMax, eStart, eEnd, eMax, r, n;
8953:   PetscInt           cStartNew = 0, vStartNew = 0, fStartNew = 0, eStartNew = 0;
8954:   PetscErrorCode     ierr;

8957:   DMPlexGetChart(rdm, &pStartNew, &pEndNew);
8958:   DMPlexGetDepth(dm, &ldepth);
8959:   MPIU_Allreduce(&ldepth, &depth, 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject) dm));
8960:   if ((ldepth >= 0) && (depth != ldepth)) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Inconsistent Plex depth %D != %D", ldepth, depth);
8961:   DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);
8962:   DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);
8963:   DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);
8964:   DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);
8965:   DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);
8966:   cMax = cMax < 0 ? cEnd : cMax;
8967:   fMax = fMax < 0 ? fEnd : fMax;
8968:   eMax = eMax < 0 ? eEnd : eMax;
8969:   if (refiner) {GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);}
8970:   DMGetPointSF(dm, &sf);
8971:   DMGetPointSF(rdm, &sfNew);
8972:   /* Calculate size of new SF */
8973:   PetscSFGetGraph(sf, &numRoots, &numLeaves, &localPoints, &remotePoints);
8974:   if (numRoots < 0) return(0);
8975:   for (l = 0; l < numLeaves; ++l) {
8976:     const PetscInt p = localPoints[l];

8978:     switch (refiner) {
8979:     case REFINER_SIMPLEX_1D:
8980:       if ((p >= vStart) && (p < vEnd)) {
8981:         /* Interior vertices stay the same */
8982:         ++numLeavesNew;
8983:       } else if ((p >= cStart && p < cMax)) {
8984:         /* Interior cells add new cells and interior vertices */
8985:         numLeavesNew += 2 + 1;
8986:       }
8987:       break;
8988:     case REFINER_SIMPLEX_2D:
8989:     case REFINER_HYBRID_SIMPLEX_2D:
8990:       if ((p >= vStart) && (p < vEnd)) {
8991:         /* Interior vertices stay the same */
8992:         ++numLeavesNew;
8993:       } else if ((p >= fStart) && (p < fMax)) {
8994:         /* Interior faces add new faces and vertex */
8995:         numLeavesNew += 2 + 1;
8996:       } else if ((p >= fMax) && (p < fEnd)) {
8997:         /* Hybrid faces stay the same */
8998:         ++numLeavesNew;
8999:       } else if ((p >= cStart) && (p < cMax)) {
9000:         /* Interior cells add new cells and interior faces */
9001:         numLeavesNew += 4 + 3;
9002:       } else if ((p >= cMax) && (p < cEnd)) {
9003:         /* Hybrid cells add new cells and hybrid face */
9004:         numLeavesNew += 2 + 1;
9005:       }
9006:       break;
9007:     case REFINER_HYBRID_SIMPLEX_TO_HEX_2D:
9008:     case REFINER_SIMPLEX_TO_HEX_2D:
9009:       if ((p >= vStart) && (p < vEnd)) {
9010:         /* Interior vertices stay the same */
9011:         ++numLeavesNew;
9012:       } else if ((p >= fStart) && (p < fEnd)) {
9013:         /* Interior faces add new faces and vertex */
9014:         numLeavesNew += 2 + 1;
9015:       } else if ((p >= cStart) && (p < cMax)) {
9016:         /* Interior cells add new cells, interior faces, and vertex */
9017:         numLeavesNew += 3 + 3 + 1;
9018:       } else if ((p >= cMax) && (p < cEnd)) {
9019:         /* Hybrid cells add new cells, interior faces, and vertex */
9020:         numLeavesNew += 4 + 4 + 1;
9021:       }
9022:       break;
9023:     case REFINER_HEX_2D:
9024:     case REFINER_HYBRID_HEX_2D:
9025:       if ((p >= vStart) && (p < vEnd)) {
9026:         /* Interior vertices stay the same */
9027:         ++numLeavesNew;
9028:       } else if ((p >= fStart) && (p < fMax)) {
9029:         /* Interior faces add new faces and vertex */
9030:         numLeavesNew += 2 + 1;
9031:       } else if ((p >= fMax) && (p < fEnd)) {
9032:         /* Hybrid faces stay the same */
9033:         ++numLeavesNew;
9034:       } else if ((p >= cStart) && (p < cMax)) {
9035:         /* Interior cells add new cells, interior faces, and vertex */
9036:         numLeavesNew += 4 + 4 + 1;
9037:       } else if ((p >= cMax) && (p < cEnd)) {
9038:         /* Hybrid cells add new cells and hybrid face */
9039:         numLeavesNew += 2 + 1;
9040:       }
9041:       break;
9042:     case REFINER_SIMPLEX_3D:
9043:     case REFINER_HYBRID_SIMPLEX_3D:
9044:       if ((p >= vStart) && (p < vEnd)) {
9045:         /* Interior vertices stay the same */
9046:         ++numLeavesNew;
9047:       } else if ((p >= eStart) && (p < eMax)) {
9048:         /* Interior edges add new edges and vertex */
9049:         numLeavesNew += 2 + 1;
9050:       } else if ((p >= eMax) && (p < eEnd)) {
9051:         /* Hybrid edges stay the same */
9052:         ++numLeavesNew;
9053:       } else if ((p >= fStart) && (p < fMax)) {
9054:         /* Interior faces add new faces and edges */
9055:         numLeavesNew += 4 + 3;
9056:       } else if ((p >= fMax) && (p < fEnd)) {
9057:         /* Hybrid faces add new faces and edges */
9058:         numLeavesNew += 2 + 1;
9059:       } else if ((p >= cStart) && (p < cMax)) {
9060:         /* Interior cells add new cells, faces, and edges */
9061:         numLeavesNew += 8 + 8 + 1;
9062:       } else if ((p >= cMax) && (p < cEnd)) {
9063:         /* Hybrid cells add new cells and faces */
9064:         numLeavesNew += 4 + 3;
9065:       }
9066:       break;
9067:     case REFINER_HYBRID_SIMPLEX_TO_HEX_3D:
9068:     case REFINER_SIMPLEX_TO_HEX_3D:
9069:       if ((p >= vStart) && (p < vEnd)) {
9070:         /* Interior vertices stay the same */
9071:         ++numLeavesNew;
9072:       } else if ((p >= eStart) && (p < eMax)) {
9073:         /* Interior edges add new edges and vertex */
9074:         numLeavesNew += 2 + 1;
9075:       } else if ((p >= eMax) && (p < eEnd)) {
9076:         /* Hybrid edges stay the same */
9077:         ++numLeavesNew;
9078:       } else if ((p >= fStart) && (p < fMax)) {
9079:         /* Interior faces add new faces, edges and a vertex */
9080:         numLeavesNew += 3 + 3 + 1;
9081:       } else if ((p >= fMax) && (p < fEnd)) {
9082:         /* Hybrid faces add new faces and an edge */
9083:         numLeavesNew += 2 + 1;
9084:       } else if ((p >= cStart) && (p < cMax)) {
9085:         /* Interior cells add new cells, faces, edges and a vertex */
9086:         numLeavesNew += 4 + 6 + 4 + 1;
9087:       } else if ((p >= cMax) && (p < cEnd)) {
9088:         /* Hybrid cells add new cells, faces and an edge */
9089:         numLeavesNew += 3 + 3 + 1;
9090:       }
9091:       break;
9092:     case REFINER_HEX_3D:
9093:     case REFINER_HYBRID_HEX_3D:
9094:       if ((p >= vStart) && (p < vEnd)) {
9095:         /* Old vertices stay the same */
9096:         ++numLeavesNew;
9097:       } else if ((p >= eStart) && (p < eMax)) {
9098:         /* Interior edges add new edges, and vertex */
9099:         numLeavesNew += 2 + 1;
9100:       } else if ((p >= eMax) && (p < eEnd)) {
9101:         /* Hybrid edges stay the same */
9102:         ++numLeavesNew;
9103:       } else if ((p >= fStart) && (p < fMax)) {
9104:         /* Interior faces add new faces, edges, and vertex */
9105:         numLeavesNew += 4 + 4 + 1;
9106:       } else if ((p >= fMax) && (p < fEnd)) {
9107:         /* Hybrid faces add new faces and edges */
9108:         numLeavesNew += 2 + 1;
9109:       } else if ((p >= cStart) && (p < cMax)) {
9110:         /* Interior cells add new cells, faces, edges, and vertex */
9111:         numLeavesNew += 8 + 12 + 6 + 1;
9112:       } else if ((p >= cStart) && (p < cEnd)) {
9113:         /* Hybrid cells add new cells, faces, and edges */
9114:         numLeavesNew += 4 + 4 + 1;
9115:       }
9116:       break;
9117:     default:
9118:       SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %s", CellRefiners[refiner]);
9119:     }
9120:   }
9121:   /* Communicate depthSizes for each remote rank */
9122:   DMPlexCreateProcessSF(dm, sf, &processRanks, &sfProcess);
9123:   ISGetLocalSize(processRanks, &numNeighbors);
9124:   PetscMalloc5((depth+1)*numNeighbors,&rdepthSize,numNeighbors,&rvStartNew,numNeighbors,&reStartNew,numNeighbors,&rfStartNew,numNeighbors,&rcStartNew);
9125:   PetscMalloc7(depth+1,&depthSizeOld,(depth+1)*numNeighbors,&rdepthSizeOld,(depth+1)*numNeighbors,&rdepthMaxOld,numNeighbors,&rvStart,numNeighbors,&reStart,numNeighbors,&rfStart,numNeighbors,&rcStart);
9126:   MPI_Type_contiguous(depth+1, MPIU_INT, &depthType);
9127:   MPI_Type_commit(&depthType);
9128:   PetscSFBcastBegin(sfProcess, depthType, depthSize, rdepthSize);
9129:   PetscSFBcastEnd(sfProcess, depthType, depthSize, rdepthSize);
9130:   for (n = 0; n < numNeighbors; ++n) {
9131:     GetDepthStart_Private(depth, &rdepthSize[n*(depth+1)], &rcStartNew[n], &rfStartNew[n], &reStartNew[n], &rvStartNew[n]);
9132:   }
9133:   depthSizeOld[depth]   = cMax;
9134:   depthSizeOld[0]       = vMax;
9135:   depthSizeOld[depth-1] = fMax;
9136:   depthSizeOld[1]       = eMax;

9138:   PetscSFBcastBegin(sfProcess, depthType, depthSizeOld, rdepthMaxOld);
9139:   PetscSFBcastEnd(sfProcess, depthType, depthSizeOld, rdepthMaxOld);

9141:   depthSizeOld[depth]   = cEnd - cStart;
9142:   depthSizeOld[0]       = vEnd - vStart;
9143:   depthSizeOld[depth-1] = fEnd - fStart;
9144:   depthSizeOld[1]       = eEnd - eStart;

9146:   PetscSFBcastBegin(sfProcess, depthType, depthSizeOld, rdepthSizeOld);
9147:   PetscSFBcastEnd(sfProcess, depthType, depthSizeOld, rdepthSizeOld);
9148:   for (n = 0; n < numNeighbors; ++n) {
9149:     GetDepthStart_Private(depth, &rdepthSizeOld[n*(depth+1)], &rcStart[n], &rfStart[n], &reStart[n], &rvStart[n]);
9150:     rdepthMaxOld[n*(depth+1)+depth]   = rdepthMaxOld[n*(depth+1)+depth]   < 0 ? rdepthSizeOld[n*(depth+1)+depth]  +rcStart[n]: rdepthMaxOld[n*(depth+1)+depth];
9151:     rdepthMaxOld[n*(depth+1)+depth-1] = rdepthMaxOld[n*(depth+1)+depth-1] < 0 ? rdepthSizeOld[n*(depth+1)+depth-1]+rfStart[n]: rdepthMaxOld[n*(depth+1)+depth-1];
9152:     rdepthMaxOld[n*(depth+1)+1]       = rdepthMaxOld[n*(depth+1)+1]       < 0 ? rdepthSizeOld[n*(depth+1)+1]      +reStart[n]: rdepthMaxOld[n*(depth+1)+1];
9153:   }
9154:   MPI_Type_free(&depthType);
9155:   PetscSFDestroy(&sfProcess);
9156:   /* Calculate new point SF */
9157:   PetscMalloc1(numLeavesNew, &localPointsNew);
9158:   PetscMalloc1(numLeavesNew, &remotePointsNew);
9159:   ISGetIndices(processRanks, &neighbors);
9160:   for (l = 0, m = 0; l < numLeaves; ++l) {
9161:     PetscInt    p     = localPoints[l];
9162:     PetscInt    rp    = remotePoints[l].index, n;
9163:     PetscMPIInt rrank = remotePoints[l].rank;

9165:     PetscFindInt(rrank, numNeighbors, neighbors, &n);
9166:     if (n < 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Could not locate remote rank %D", rrank);
9167:     switch (refiner) {
9168:     case REFINER_SIMPLEX_1D:
9169:       if ((p >= vStart) && (p < vEnd)) {
9170:         /* Old vertices stay the same */
9171:         localPointsNew[m]        = vStartNew     + (p  - vStart);
9172:         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
9173:         remotePointsNew[m].rank  = rrank;
9174:         ++m;
9175:       } else if ((p >= cStart) && (p < cMax)) {
9176:         /* Old interior cells add new cells and vertex */
9177:         for (r = 0; r < 2; ++r, ++m) {
9178:           localPointsNew[m]        = cStartNew     + (p  - cStart)*2     + r;
9179:           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*2 + r;
9180:           remotePointsNew[m].rank  = rrank;
9181:         }
9182:         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - cStart);
9183:         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - rcStart[n]);
9184:         remotePointsNew[m].rank  = rrank;
9185:         ++m;
9186:       }
9187:       break;
9188:     case REFINER_SIMPLEX_2D:
9189:     case REFINER_HYBRID_SIMPLEX_2D:
9190:       if ((p >= vStart) && (p < vEnd)) {
9191:         /* Old vertices stay the same */
9192:         localPointsNew[m]        = vStartNew     + (p  - vStart);
9193:         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
9194:         remotePointsNew[m].rank  = rrank;
9195:         ++m;
9196:       } else if ((p >= fStart) && (p < fMax)) {
9197:         /* Old interior faces add new faces and vertex */
9198:         for (r = 0; r < 2; ++r, ++m) {
9199:           localPointsNew[m]        = fStartNew     + (p  - fStart)*2     + r;
9200:           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*2 + r;
9201:           remotePointsNew[m].rank  = rrank;
9202:         }
9203:         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - fStart);
9204:         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - rfStart[n]);
9205:         remotePointsNew[m].rank  = rrank;
9206:         ++m;
9207:       } else if ((p >= fMax) && (p < fEnd)) {
9208:         /* Old hybrid faces stay the same */
9209:         localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (p  - fMax);
9210:         remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*2 + (rp - rdepthMaxOld[n*(depth+1)+depth-1]);
9211:         remotePointsNew[m].rank  = rrank;
9212:         ++m;
9213:       } else if ((p >= cStart) && (p < cMax)) {
9214:         /* Old interior cells add new cells and interior faces */
9215:         for (r = 0; r < 4; ++r, ++m) {
9216:           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
9217:           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
9218:           remotePointsNew[m].rank  = rrank;
9219:         }
9220:         for (r = 0; r < 3; ++r, ++m) {
9221:           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (p  - cStart)*3     + r;
9222:           remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*2 + (rp - rcStart[n])*3 + r;
9223:           remotePointsNew[m].rank  = rrank;
9224:         }
9225:       } else if ((p >= cMax) && (p < cEnd)) {
9226:         /* Old hybrid cells add new cells and hybrid face */
9227:         for (r = 0; r < 2; ++r, ++m) {
9228:           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
9229:           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
9230:           remotePointsNew[m].rank  = rrank;
9231:         }
9232:         localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (cMax                            - cStart)*3     + (p  - cMax);
9233:         remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*2 + (rdepthMaxOld[n*(depth+1)+depth] - rcStart[n])*3 + (rp - rdepthMaxOld[n*(depth+1)+depth]);
9234:         remotePointsNew[m].rank  = rrank;
9235:         ++m;
9236:       }
9237:       break;
9238:     case REFINER_HYBRID_SIMPLEX_TO_HEX_2D:
9239:     case REFINER_SIMPLEX_TO_HEX_2D:
9240:       if ((p >= vStart) && (p < vEnd)) {
9241:         /* Old vertices stay the same */
9242:         localPointsNew[m]        = vStartNew     + (p  - vStart);
9243:         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
9244:         remotePointsNew[m].rank  = rrank;
9245:         ++m;
9246:       } else if ((p >= fStart) && (p < fEnd)) {
9247:         /* Old interior faces add new faces and vertex */
9248:         for (r = 0; r < 2; ++r, ++m) {
9249:           localPointsNew[m]        = fStartNew     + (p  - fStart)*2     + r;
9250:           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*2 + r;
9251:           remotePointsNew[m].rank  = rrank;
9252:         }
9253:         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - fStart);
9254:         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - rfStart[n]);
9255:         remotePointsNew[m].rank  = rrank;
9256:         ++m;
9257:       } else if ((p >= cStart) && (p < cMax)) {
9258:         /* Old interior cells add new cells, interior faces, and a vertex */
9259:         for (r = 0; r < 3; ++r, ++m) {
9260:           localPointsNew[m]        = cStartNew     + (p  - cStart)*3     + r;
9261:           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*3 + r;
9262:           remotePointsNew[m].rank  = rrank;
9263:         }
9264:         for (r = 0; r < 3; ++r, ++m) {
9265:           localPointsNew[m]        = fStartNew     + (fEnd - fStart)*2                    + (p  - cStart)*3     + r;
9266:           remotePointsNew[m].index = rfStartNew[n] + rdepthSizeOld[n*(depth+1)+depth-1]*2 + (rp - rcStart[n])*3 + r;
9267:           remotePointsNew[m].rank  = rrank;
9268:         }
9269:         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (fEnd - fStart)                    + (p  - cStart);
9270:         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + rdepthSizeOld[n*(depth+1)+depth-1] + (rp - rcStart[n]);
9271:         remotePointsNew[m].rank  = rrank;
9272:         ++m;
9273:       } else if ((p >= cMax) && (p < cEnd)) {
9274:         /* Old interior hybrid cells add new cells, interior faces, and a vertex */
9275:         for (r = 0; r < 4; ++r, ++m) {
9276:           localPointsNew[m]        = cStartNew     + (cMax  - cStart)*3                               + (p  - cMax)*4 + r;
9277:           remotePointsNew[m].index = rcStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth] - rcStart[n])*3 + (rp - rdepthMaxOld[n*(depth+1)+depth])*4 + r;
9278:           remotePointsNew[m].rank  = rrank;
9279:         }
9280:         for (r = 0; r < 4; ++r, ++m) {
9281:           localPointsNew[m]        = fStartNew     + (fEnd - fStart)*2                    + (cMax  - cStart)*3                               + (p - cMax)*4 + r;
9282:           remotePointsNew[m].index = rfStartNew[n] + rdepthSizeOld[n*(depth+1)+depth-1]*2 + (rdepthMaxOld[n*(depth+1)+depth] - rcStart[n])*3 + (rp - rdepthMaxOld[n*(depth+1)+depth])*4 + r;
9283:           remotePointsNew[m].rank  = rrank;
9284:         }
9285:         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (fEnd - fStart)                    + (p  - cStart);
9286:         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + rdepthSizeOld[n*(depth+1)+depth-1] + (rp - rcStart[n]);
9287:         remotePointsNew[m].rank  = rrank;
9288:         ++m;
9289:       }
9290:       break;
9291:     case REFINER_HEX_2D:
9292:     case REFINER_HYBRID_HEX_2D:
9293:       if ((p >= vStart) && (p < vEnd)) {
9294:         /* Old vertices stay the same */
9295:         localPointsNew[m]        = vStartNew     + (p  - vStart);
9296:         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
9297:         remotePointsNew[m].rank  = rrank;
9298:         ++m;
9299:       } else if ((p >= fStart) && (p < fMax)) {
9300:         /* Old interior faces add new faces and vertex */
9301:         for (r = 0; r < 2; ++r, ++m) {
9302:           localPointsNew[m]        = fStartNew     + (p  - fStart)*2     + r;
9303:           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*2 + r;
9304:           remotePointsNew[m].rank  = rrank;
9305:         }
9306:         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - fStart);
9307:         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - rfStart[n]);
9308:         remotePointsNew[m].rank  = rrank;
9309:         ++m;
9310:       } else if ((p >= fMax) && (p < fEnd)) {
9311:         /* Old hybrid faces stay the same */
9312:         localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (p  - fMax);
9313:         remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*2 + (rp - rdepthMaxOld[n*(depth+1)+depth-1]);
9314:         remotePointsNew[m].rank  = rrank;
9315:         ++m;
9316:       } else if ((p >= cStart) && (p < cMax)) {
9317:         /* Old interior cells add new cells, interior faces, and vertex */
9318:         for (r = 0; r < 4; ++r, ++m) {
9319:           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
9320:           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
9321:           remotePointsNew[m].rank  = rrank;
9322:         }
9323:         for (r = 0; r < 4; ++r, ++m) {
9324:           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (p  - cStart)*4     + r;
9325:           remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*2 + (rp - rcStart[n])*4 + r;
9326:           remotePointsNew[m].rank  = rrank;
9327:         }
9328:         localPointsNew[m]        = vStartNew     + (vEnd - vStart)               + (fMax                              - fStart)     + (p  - cStart);
9329:         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0]  + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n]) + (rp - rcStart[n]);
9330:         remotePointsNew[m].rank  = rrank;
9331:         ++m;
9332:       } else if ((p >= cStart) && (p < cMax)) {
9333:         /* Old hybrid cells add new cells and hybrid face */
9334:         for (r = 0; r < 2; ++r, ++m) {
9335:           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r; /* TODO: is this a bug? */
9336:           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r; /* TODO: is this a bug? */
9337:           remotePointsNew[m].rank  = rrank;
9338:         }
9339:         localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (cMax                            - cStart)*4     + (p  - cMax);
9340:         remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*2 + (rdepthMaxOld[n*(depth+1)+depth] - rcStart[n])*4 + (rp - rdepthMaxOld[n*(depth+1)+depth]);
9341:         remotePointsNew[m].rank  = rrank;
9342:         ++m;
9343:       }
9344:       break;
9345:     case REFINER_SIMPLEX_3D:
9346:     case REFINER_HYBRID_SIMPLEX_3D:
9347:       if ((p >= vStart) && (p < vEnd)) {
9348:         /* Interior vertices stay the same */
9349:         localPointsNew[m]        = vStartNew     + (p  - vStart);
9350:         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
9351:         remotePointsNew[m].rank  = rrank;
9352:         ++m;
9353:       } else if ((p >= eStart) && (p < eMax)) {
9354:         /* Interior edges add new edges and vertex */
9355:         for (r = 0; r < 2; ++r, ++m) {
9356:           localPointsNew[m]        = eStartNew     + (p  - eStart)*2     + r;
9357:           remotePointsNew[m].index = reStartNew[n] + (rp - reStart[n])*2 + r;
9358:           remotePointsNew[m].rank  = rrank;
9359:         }
9360:         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - eStart);
9361:         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - reStart[n]);
9362:         remotePointsNew[m].rank  = rrank;
9363:         ++m;
9364:       } else if ((p >= eMax) && (p < eEnd)) {
9365:         /* Hybrid edges stay the same */
9366:         localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (fMax                              - fStart)*3     + (cMax                            - cStart)     + (p  - eMax);
9367:         remotePointsNew[m].index = reStartNew[n] + (rdepthMaxOld[n*(depth+1)+1] - reStart[n])*2 + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*3 + (rdepthMaxOld[n*(depth+1)+depth] - rcStart[n]) + (rp - rdepthMaxOld[n*(depth+1)+1]);
9368:         remotePointsNew[m].rank  = rrank;
9369:         ++m;
9370:       } else if ((p >= fStart) && (p < fMax)) {
9371:         /* Interior faces add new faces and edges */
9372:         for (r = 0; r < 4; ++r, ++m) {
9373:           localPointsNew[m]        = fStartNew     + (p  - fStart)*4     + r;
9374:           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*4 + r;
9375:           remotePointsNew[m].rank  = rrank;
9376:         }
9377:         for (r = 0; r < 3; ++r, ++m) {
9378:           localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (p  - fStart)*3     + r;
9379:           remotePointsNew[m].index = reStartNew[n] + (rdepthMaxOld[n*(depth+1)+1] - reStart[n])*2 + (rp - rfStart[n])*3 + r;
9380:           remotePointsNew[m].rank  = rrank;
9381:         }
9382:       } else if ((p >= fMax) && (p < fEnd)) {
9383:         /* Hybrid faces add new faces and edges */
9384:         for (r = 0; r < 2; ++r, ++m) {
9385:           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*4     + (cMax                            - cStart)*8     + (p  - fMax)*2                              + r;
9386:           remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*4 + (rdepthMaxOld[n*(depth+1)+depth] - rcStart[n])*8 + (rp - rdepthMaxOld[n*(depth+1)+depth-1])*2 + r;
9387:           remotePointsNew[m].rank  = rrank;
9388:         }
9389:         localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (fMax                              - fStart)*3     + (cMax                            - cStart)     + (eEnd                                    - eMax)                        + (p  - fMax);
9390:         remotePointsNew[m].index = reStartNew[n] + (rdepthMaxOld[n*(depth+1)+1] - reStart[n])*2 + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*3 + (rdepthMaxOld[n*(depth+1)+depth] - rcStart[n]) + (rdepthSizeOld[n*(depth+1)+1]+reStart[n] - rdepthMaxOld[n*(depth+1)+1]) + (rp - rdepthMaxOld[n*(depth+1)+depth-1]);
9391:         remotePointsNew[m].rank  = rrank;
9392:         ++m;
9393:       } else if ((p >= cStart) && (p < cMax)) {
9394:         /* Interior cells add new cells, faces, and edges */
9395:         for (r = 0; r < 8; ++r, ++m) {
9396:           localPointsNew[m]        = cStartNew     + (p  - cStart)*8     + r;
9397:           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*8 + r;
9398:           remotePointsNew[m].rank  = rrank;
9399:         }
9400:         for (r = 0; r < 8; ++r, ++m) {
9401:           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*4     + (p  - cStart)*8     + r;
9402:           remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*4 + (rp - rcStart[n])*8 + r;
9403:           remotePointsNew[m].rank  = rrank;
9404:         }
9405:         localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (fMax                              - fStart)*3     + (p  - cStart)*1     + 0;
9406:         remotePointsNew[m].index = reStartNew[n] + (rdepthMaxOld[n*(depth+1)+1] - reStart[n])*2 + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*3 + (rp - rcStart[n])*1 + 0;
9407:         remotePointsNew[m].rank  = rrank;
9408:         ++m;
9409:       } else if ((p >= cMax) && (p < cEnd)) {
9410:         /* Hybrid cells add new cells and faces */
9411:         for (r = 0; r < 4; ++r, ++m) {
9412:           localPointsNew[m]        = cStartNew     + (cMax                            - cStart)*8     + (p  - cMax)*4                            + r;
9413:           remotePointsNew[m].index = rcStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth] - rcStart[n])*8 + (rp - rdepthMaxOld[n*(depth+1)+depth])*4 + r;
9414:           remotePointsNew[m].rank  = rrank;
9415:         }
9416:         for (r = 0; r < 3; ++r, ++m) {
9417:           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*4     + (cMax                            - cStart)*8     + (fEnd                                          - fMax)*2                              + (p  - cMax)*3                            + r;
9418:           remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*4 + (rdepthMaxOld[n*(depth+1)+depth] - rcStart[n])*8 + (rdepthSizeOld[n*(depth+1)+depth-1]+rfStart[n] - rdepthMaxOld[n*(depth+1)+depth-1])*2 + (rp - rdepthMaxOld[n*(depth+1)+depth])*3 + r;
9419:           remotePointsNew[m].rank  = rrank;
9420:         }
9421:       }
9422:       break;
9423:     case REFINER_HYBRID_SIMPLEX_TO_HEX_3D:
9424:     case REFINER_SIMPLEX_TO_HEX_3D:
9425:       if ((p >= vStart) && (p < vEnd)) {
9426:         /* Interior vertices stay the same */
9427:         localPointsNew[m]        = vStartNew     + (p  - vStart);
9428:         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
9429:         remotePointsNew[m].rank  = rrank;
9430:         ++m;
9431:       } else if ((p >= eStart) && (p < eMax)) {
9432:         /* Interior edges add new edges and vertex */
9433:         for (r = 0; r < 2; ++r, ++m) {
9434:           localPointsNew[m]        = eStartNew     + (p  - eStart)*2     + r;
9435:           remotePointsNew[m].index = reStartNew[n] + (rp - reStart[n])*2 + r;
9436:           remotePointsNew[m].rank  = rrank;
9437:         }
9438:         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - eStart);
9439:         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - reStart[n]);
9440:         remotePointsNew[m].rank  = rrank;
9441:         ++m;
9442:       } else if ((p >= eMax) && (p < eEnd)) {
9443:         /* Hybrid edges stay the same */
9444:         localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (fMax                              - fStart)*3     + (cMax                            - cStart)*4     + (p  - eMax);
9445:         remotePointsNew[m].index = reStartNew[n] + (rdepthMaxOld[n*(depth+1)+1] - reStart[n])*2 + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*3 + (rdepthMaxOld[n*(depth+1)+depth] - rcStart[n])*4 + (rp - rdepthMaxOld[n*(depth+1)+1]);
9446:         remotePointsNew[m].rank  = rrank;
9447:         ++m;
9448:       } else if ((p >= fStart) && (p < fMax)) {
9449:         /* Interior faces add new faces, edges and a vertex */
9450:         for (r = 0; r < 3; ++r, ++m) {
9451:           localPointsNew[m]        = fStartNew     + (p  - fStart)*3     + r;
9452:           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*3 + r;
9453:           remotePointsNew[m].rank  = rrank;
9454:         }
9455:         for (r = 0; r < 3; ++r, ++m) {
9456:           localPointsNew[m]        = eStartNew     + (eMax - eStart)*2                            + (p  - fStart)*3     + r;
9457:           remotePointsNew[m].index = reStartNew[n] + (rdepthMaxOld[n*(depth+1)+1] - reStart[n])*2 + (rp - rfStart[n])*3 + r;
9458:           remotePointsNew[m].rank  = rrank;
9459:         }
9460:         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (eMax - eStart)                            + (p - fStart);
9461:         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rdepthMaxOld[n*(depth+1)+1] - reStart[n]) + (rp - rfStart[n]);
9462:         remotePointsNew[m].rank  = rrank;
9463:         ++m;
9464:       } else if ((p >= fMax) && (p < fEnd)) {
9465:         /* Interior hybrid faces add new faces and an edge */
9466:         for (r = 0; r < 2; ++r, ++m) {
9467:           localPointsNew[m]        = fStartNew     + (fMax - fStart)*3                                 + (cMax - cStart)*6                                + (p  - fMax)*2 + r;
9468:           remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1]- rfStart[n])*3 + (rdepthMaxOld[n*(depth+1)+depth] - rcStart[n])*6 + (rp - rdepthMaxOld[n*(depth+1)+depth-1])*2 + r;
9469:           remotePointsNew[m].rank  = rrank;
9470:         }
9471:         localPointsNew[m]        = eStartNew     + (eMax - eStart)*2                            + (fMax - fStart)*3                                 + (cMax - cStart)*4                                + (eEnd - eMax)                                                           + (p  - fMax);
9472:         remotePointsNew[m].index = reStartNew[n] + (rdepthMaxOld[n*(depth+1)+1] - reStart[n])*2 + (rdepthMaxOld[n*(depth+1)+depth-1]- rfStart[n])*3 + (rdepthMaxOld[n*(depth+1)+depth] - rcStart[n])*4 + (rdepthSizeOld[n*(depth+1)+1]+reStart[n] - rdepthMaxOld[n*(depth+1)+1]) + (rp - rdepthMaxOld[n*(depth+1)+depth-1]);
9473:         remotePointsNew[m].rank  = rrank;
9474:         ++m;
9475:       } else if ((p >= cStart) && (p < cMax)) {
9476:         /* Interior cells add new cells, faces, edges, and a vertex */
9477:         for (r = 0; r < 4; ++r, ++m) {
9478:           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
9479:           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
9480:           remotePointsNew[m].rank  = rrank;
9481:         }
9482:         for (r = 0; r < 6; ++r, ++m) {
9483:           localPointsNew[m]        = fStartNew     + (fMax - fStart)*3                                 + (p  - cStart)*6     + r;
9484:           remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1]- rfStart[n])*3 + (rp - rcStart[n])*6 + r;
9485:           remotePointsNew[m].rank  = rrank;
9486:         }
9487:         for (r = 0; r < 4; ++r, ++m) {
9488:           localPointsNew[m]        = eStartNew     + (eMax - eStart)*2                           + (fMax - fStart)*3                                 + (p  - cStart)*4 + r;
9489:           remotePointsNew[m].index = reStartNew[n] + (rdepthMaxOld[n*(depth+1)+1]- reStart[n])*2 + (rdepthMaxOld[n*(depth+1)+depth-1]- rfStart[n])*3 + (rp - rcStart[n])*4 + r;
9490:           remotePointsNew[m].rank  = rrank;
9491:         }
9492:         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (eMax - eStart)                           + (fMax - fStart)                                 + (p  - cStart);
9493:         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rdepthMaxOld[n*(depth+1)+1]- reStart[n]) + (rdepthMaxOld[n*(depth+1)+depth-1]- rfStart[n]) + (rp - rcStart[n]);
9494:         remotePointsNew[m].rank  = rrank;
9495:         ++m;
9496:       } else if ((p >= cMax) && (p < cEnd)) {
9497:         /* Interior hybrid cells add new cells, faces and an edge */
9498:         for (r = 0; r < 3; ++r, ++m) {
9499:           localPointsNew[m]        = cStartNew     + (cMax                            - cStart)*4     + (p  - cMax)*3                            + r;
9500:           remotePointsNew[m].index = rcStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth] - rcStart[n])*4 + (rp - rdepthMaxOld[n*(depth+1)+depth])*3 + r;
9501:           remotePointsNew[m].rank  = rrank;
9502:         }
9503:         for (r = 0; r < 3; ++r, ++m) {
9504:           localPointsNew[m]        = fStartNew     + (fMax - fStart)*3                                 + (cMax - cStart)*6                                + (fEnd  - fMax)*2                                                                      + (p  - cMax)*3 + r;
9505:           remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1]- rfStart[n])*3 + (rdepthMaxOld[n*(depth+1)+depth] - rcStart[n])*6 + (rdepthSizeOld[n*(depth+1)+depth-1]+rfStart[n] - rdepthMaxOld[n*(depth+1)+depth-1])*2 + (rp - rdepthMaxOld[n*(depth+1)+depth])*3 + r;
9506:           remotePointsNew[m].rank  = rrank;
9507:         }
9508:         localPointsNew[m]        = eStartNew     + (eMax - eStart)*2                           + (fMax - fStart)*3                                 + (cMax - cStart)*4                                + (eEnd  - eMax)                                                          + (fEnd  - fMax)                                                                      + (p  - cMax);
9509:         remotePointsNew[m].index = reStartNew[n] + (rdepthMaxOld[n*(depth+1)+1]- reStart[n])*2 + (rdepthMaxOld[n*(depth+1)+depth-1]- rfStart[n])*3 + (rdepthMaxOld[n*(depth+1)+depth] - rcStart[n])*4 + (rdepthSizeOld[n*(depth+1)+1]+reStart[n] - rdepthMaxOld[n*(depth+1)+1]) + (rdepthSizeOld[n*(depth+1)+depth-1]+rfStart[n] - rdepthMaxOld[n*(depth+1)+depth-1]) + (rp - rdepthMaxOld[n*(depth+1)+depth]);
9510:         remotePointsNew[m].rank  = rrank;
9511:         ++m;
9512:       }
9513:       break;
9514:     case REFINER_HEX_3D:
9515:     case REFINER_HYBRID_HEX_3D:
9516:       if ((p >= vStart) && (p < vEnd)) {
9517:         /* Interior vertices stay the same */
9518:         localPointsNew[m]        = vStartNew     + (p  - vStart);
9519:         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
9520:         remotePointsNew[m].rank  = rrank;
9521:         ++m;
9522:       } else if ((p >= eStart) && (p < eMax)) {
9523:         /* Interior edges add new edges and vertex */
9524:         for (r = 0; r < 2; ++r, ++m) {
9525:           localPointsNew[m]        = eStartNew     + (p  - eStart)*2     + r;
9526:           remotePointsNew[m].index = reStartNew[n] + (rp - reStart[n])*2 + r;
9527:           remotePointsNew[m].rank  = rrank;
9528:         }
9529:         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - eStart);
9530:         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - reStart[n]);
9531:         remotePointsNew[m].rank  = rrank;
9532:         ++m;
9533:       } else if ((p >= eMax) && (p < eEnd)) {
9534:         /* Hybrid edges stay the same */
9535:         localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (fMax                              - fStart)*4     + (cMax                            - cStart)*6     + (p  - eMax);
9536:         remotePointsNew[m].index = reStartNew[n] + (rdepthMaxOld[n*(depth+1)+1] - reStart[n])*2 + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*4 + (rdepthMaxOld[n*(depth+1)+depth] - rcStart[n])*6 + (rp - rdepthMaxOld[n*(depth+1)+1]);
9537:         remotePointsNew[m].rank  = rrank;
9538:         ++m;
9539:       } else if ((p >= fStart) && (p < fMax)) {
9540:         /* Interior faces add new faces, edges, and vertex */
9541:         for (r = 0; r < 4; ++r, ++m) {
9542:           localPointsNew[m]        = fStartNew     + (p  - fStart)*4     + r;
9543:           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*4 + r;
9544:           remotePointsNew[m].rank  = rrank;
9545:         }
9546:         for (r = 0; r < 4; ++r, ++m) {
9547:           localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (p  - fStart)*4     + r;
9548:           remotePointsNew[m].index = reStartNew[n] + (rdepthMaxOld[n*(depth+1)+1] - reStart[n])*2 + (rp - rfStart[n])*4 + r;
9549:           remotePointsNew[m].rank  = rrank;
9550:         }
9551:         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (eMax                        - eStart)     + (p  - fStart);
9552:         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rdepthMaxOld[n*(depth+1)+1] - reStart[n]) + (rp - rfStart[n]);
9553:         remotePointsNew[m].rank  = rrank;
9554:         ++m;
9555:       } else if ((p >= fMax) && (p < fEnd)) {
9556:         /* Hybrid faces add new faces and edges */
9557:         for (r = 0; r < 2; ++r, ++m) {
9558:           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*4     + (cMax                            - cStart)*12     + (p  - fMax)*2                              + r;
9559:           remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*4 + (rdepthMaxOld[n*(depth+1)+depth] - rcStart[n])*12 + (rp - rdepthMaxOld[n*(depth+1)+depth-1])*2 + r;
9560:           remotePointsNew[m].rank  = rrank;
9561:         }
9562:         localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (fMax                              - fStart)*4     + (cMax                            - cStart)*6     + (eEnd                                    - eMax)                        + (p  - fMax);
9563:         remotePointsNew[m].index = reStartNew[n] + (rdepthMaxOld[n*(depth+1)+1] - reStart[n])*2 + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*4 + (rdepthMaxOld[n*(depth+1)+depth] - rcStart[n])*6 + (rdepthSizeOld[n*(depth+1)+1]+reStart[n] - rdepthMaxOld[n*(depth+1)+1]) + (rp - rdepthMaxOld[n*(depth+1)+depth-1]);
9564:         remotePointsNew[m].rank  = rrank;
9565:         ++m;
9566:       } else if ((p >= cStart) && (p < cMax)) {
9567:         /* Interior cells add new cells, faces, edges, and vertex */
9568:         for (r = 0; r < 8; ++r, ++m) {
9569:           localPointsNew[m]        = cStartNew     + (p  - cStart)*8     + r;
9570:           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*8 + r;
9571:           remotePointsNew[m].rank  = rrank;
9572:         }
9573:         for (r = 0; r < 12; ++r, ++m) {
9574:           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*4     + (p  - cStart)*12     + r;
9575:           remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*4 + (rp - rcStart[n])*12 + r;
9576:           remotePointsNew[m].rank  = rrank;
9577:         }
9578:         for (r = 0; r < 6; ++r, ++m) {
9579:           localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (fMax                              - fStart)*4     + (p  - cStart)*6     + r;
9580:           remotePointsNew[m].index = reStartNew[n] + (rdepthMaxOld[n*(depth+1)+1] - reStart[n])*2 + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*4 + (rp - rcStart[n])*6 + r;
9581:           remotePointsNew[m].rank  = rrank;
9582:         }
9583:         for (r = 0; r < 1; ++r, ++m) {
9584:           localPointsNew[m]        = vStartNew     + (eMax                        - eStart)     + (fMax                              - fStart)     + (p  - cStart)     + r;
9585:           remotePointsNew[m].index = rvStartNew[n] + (rdepthMaxOld[n*(depth+1)+1] - reStart[n]) + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n]) + (rp - rcStart[n]) + r;
9586:           remotePointsNew[m].rank  = rrank;
9587:         }
9588:       } else if ((p >= cMax) && (p < cEnd)) {
9589:         /* Hybrid cells add new cells, faces, and edges */
9590:         for (r = 0; r < 4; ++r, ++m) {
9591:           localPointsNew[m]        = cStartNew     + (cMax                            - cStart)*8     + (p  - cMax)*4                            + r;
9592:           remotePointsNew[m].index = rcStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth] - rcStart[n])*8 + (rp - rdepthMaxOld[n*(depth+1)+depth])*4 + r;
9593:           remotePointsNew[m].rank  = rrank;
9594:         }
9595:         for (r = 0; r < 4; ++r, ++m) {
9596:           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*4     + (cMax                            - cStart)*12     + (fEnd                                          - fMax)*2                              + (p  - cMax)*4                            + r;
9597:           remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*4 + (rdepthMaxOld[n*(depth+1)+depth] - rcStart[n])*12 + (rdepthSizeOld[n*(depth+1)+depth-1]+rfStart[n] - rdepthMaxOld[n*(depth+1)+depth-1])*2 + (rp - rdepthMaxOld[n*(depth+1)+depth])*4 + r;
9598:           remotePointsNew[m].rank  = rrank;
9599:         }
9600:         localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (fMax                              - fStart)*4     + (cMax                            - cStart)*6     + (eEnd                                    - eMax)                        + (fEnd                                          - fMax)                              + (p  - cMax);
9601:         remotePointsNew[m].index = reStartNew[n] + (rdepthMaxOld[n*(depth+1)+1] - reStart[n])*2 + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*4 + (rdepthMaxOld[n*(depth+1)+depth] - rcStart[n])*6 + (rdepthSizeOld[n*(depth+1)+1]+reStart[n] - rdepthMaxOld[n*(depth+1)+1]) + (rdepthSizeOld[n*(depth+1)+depth-1]+rfStart[n] - rdepthMaxOld[n*(depth+1)+depth-1]) + (rp - rdepthMaxOld[n*(depth+1)+depth]);
9602:         remotePointsNew[m].rank  = rrank;
9603:         ++m;
9604:       }
9605:       break;
9606:     default:
9607:       SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %s", CellRefiners[refiner]);
9608:     }
9609:   }
9610:   if (m != numLeavesNew) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Number of leaf point %D should be %D", m, numLeavesNew);
9611:   ISRestoreIndices(processRanks, &neighbors);
9612:   ISDestroy(&processRanks);
9613:   {
9614:     PetscSFNode *rp, *rtmp;
9615:     PetscInt    *lp, *idx, *ltmp, i;

9617:     /* SF needs sorted leaves to correct calculate Gather */
9618:     PetscMalloc1(numLeavesNew,&idx);
9619:     PetscMalloc1(numLeavesNew, &lp);
9620:     PetscMalloc1(numLeavesNew, &rp);
9621:     for (i = 0; i < numLeavesNew; ++i) {
9622:       if ((localPointsNew[i] < pStartNew) || (localPointsNew[i] >= pEndNew)) SETERRQ4(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Local SF point %D (%D) not in [%D, %D)", localPointsNew[i], i, pStartNew, pEndNew);
9623:       idx[i] = i;
9624:     }
9625:     PetscSortIntWithPermutation(numLeavesNew, localPointsNew, idx);
9626:     for (i = 0; i < numLeavesNew; ++i) {
9627:       lp[i] = localPointsNew[idx[i]];
9628:       rp[i] = remotePointsNew[idx[i]];
9629:     }
9630:     ltmp            = localPointsNew;
9631:     localPointsNew  = lp;
9632:     rtmp            = remotePointsNew;
9633:     remotePointsNew = rp;
9634:     PetscFree(idx);
9635:     PetscFree(ltmp);
9636:     PetscFree(rtmp);
9637:   }
9638:   PetscSFSetGraph(sfNew, pEndNew-pStartNew, numLeavesNew, localPointsNew, PETSC_OWN_POINTER, remotePointsNew, PETSC_OWN_POINTER);
9639:   PetscFree5(rdepthSize,rvStartNew,reStartNew,rfStartNew,rcStartNew);
9640:   PetscFree7(depthSizeOld,rdepthSizeOld,rdepthMaxOld,rvStart,reStart,rfStart,rcStart);
9641:   return(0);
9642: }

9644: static PetscErrorCode CellRefinerCreateLabels(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
9645: {
9646:   PetscInt       numLabels, l;
9647:   PetscInt       depth, newp, cStart, cEnd, cMax, vStart, vEnd, vMax, fStart, fEnd, fMax, eStart, eEnd, eMax, r;
9648:   PetscInt       cStartNew = 0, vStartNew = 0, fStartNew = 0, eStartNew = 0;

9652:   DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);
9653:   DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);
9654:   DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);
9655:   DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);
9656:   DMPlexGetDepth(dm, &depth);
9657:   if (refiner) {GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);}
9658:   DMGetNumLabels(dm, &numLabels);
9659:   DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);
9660:   switch (refiner) {
9661:   case REFINER_NOOP:
9662:   case REFINER_SIMPLEX_1D:
9663:   case REFINER_SIMPLEX_2D:
9664:   case REFINER_SIMPLEX_TO_HEX_2D:
9665:   case REFINER_HEX_2D:
9666:   case REFINER_SIMPLEX_3D:
9667:   case REFINER_HEX_3D:
9668:   case REFINER_SIMPLEX_TO_HEX_3D:
9669:     break;
9670:   case REFINER_HYBRID_SIMPLEX_TO_HEX_3D:
9671:   case REFINER_HYBRID_SIMPLEX_3D:
9672:   case REFINER_HYBRID_HEX_3D:
9673:     if (eMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No edge maximum specified in hybrid mesh");
9674:   case REFINER_HYBRID_SIMPLEX_2D:
9675:   case REFINER_HYBRID_HEX_2D:
9676:     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
9677:   case REFINER_HYBRID_SIMPLEX_TO_HEX_2D:
9678:     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
9679:     break;
9680:   default:
9681:     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %s", CellRefiners[refiner]);
9682:   }
9683:   cMax = cMax < 0 ? cEnd : cMax;
9684:   fMax = fMax < 0 ? fEnd : fMax;
9685:   eMax = eMax < 0 ? eEnd : eMax;
9686:   for (l = 0; l < numLabels; ++l) {
9687:     DMLabel         label, labelNew;
9688:     const char     *lname;
9689:     PetscBool       isDepth;
9690:     IS              valueIS;
9691:     const PetscInt *values;
9692:     PetscInt        defVal;
9693:     PetscInt        numValues, val;

9695:     DMGetLabelName(dm, l, &lname);
9696:     PetscStrcmp(lname, "depth", &isDepth);
9697:     if (isDepth) continue;
9698:     DMCreateLabel(rdm, lname);
9699:     DMGetLabel(dm, lname, &label);
9700:     DMGetLabel(rdm, lname, &labelNew);
9701:     DMLabelGetDefaultValue(label,&defVal);
9702:     DMLabelSetDefaultValue(labelNew,defVal);
9703:     DMLabelGetValueIS(label, &valueIS);
9704:     ISGetLocalSize(valueIS, &numValues);
9705:     ISGetIndices(valueIS, &values);
9706:     for (val = 0; val < numValues; ++val) {
9707:       IS              pointIS;
9708:       const PetscInt *points;
9709:       PetscInt        numPoints, n;

9711:       DMLabelGetStratumIS(label, values[val], &pointIS);
9712:       ISGetLocalSize(pointIS, &numPoints);
9713:       ISGetIndices(pointIS, &points);
9714:       /* Ensure refined label is created with same number of strata as
9715:        * original (even if no entries here). */
9716:       DMLabelAddStratum(labelNew, values[val]);
9717:       for (n = 0; n < numPoints; ++n) {
9718:         const PetscInt p = points[n];
9719:         switch (refiner) {
9720:         case REFINER_SIMPLEX_1D:
9721:           if ((p >= vStart) && (p < vEnd)) {
9722:             /* Old vertices stay the same */
9723:             newp = vStartNew + (p - vStart);
9724:             DMLabelSetValue(labelNew, newp, values[val]);
9725:           } else if ((p >= cStart) && (p < cEnd)) {
9726:             /* Old cells add new cells and vertex */
9727:             newp = vStartNew + (vEnd - vStart) + (p - cStart);
9728:             DMLabelSetValue(labelNew, newp, values[val]);
9729:             for (r = 0; r < 2; ++r) {
9730:               newp = cStartNew + (p - cStart)*2 + r;
9731:               DMLabelSetValue(labelNew, newp, values[val]);
9732:             }
9733:           }
9734:           break;
9735:         case REFINER_SIMPLEX_2D:
9736:           if ((p >= vStart) && (p < vEnd)) {
9737:             /* Old vertices stay the same */
9738:             newp = vStartNew + (p - vStart);
9739:             DMLabelSetValue(labelNew, newp, values[val]);
9740:           } else if ((p >= fStart) && (p < fEnd)) {
9741:             /* Old faces add new faces and vertex */
9742:             newp = vStartNew + (vEnd - vStart) + (p - fStart);
9743:             DMLabelSetValue(labelNew, newp, values[val]);
9744:             for (r = 0; r < 2; ++r) {
9745:               newp = fStartNew + (p - fStart)*2 + r;
9746:               DMLabelSetValue(labelNew, newp, values[val]);
9747:             }
9748:           } else if ((p >= cStart) && (p < cEnd)) {
9749:             /* Old cells add new cells and interior faces */
9750:             for (r = 0; r < 4; ++r) {
9751:               newp = cStartNew + (p - cStart)*4 + r;
9752:               DMLabelSetValue(labelNew, newp, values[val]);
9753:             }
9754:             for (r = 0; r < 3; ++r) {
9755:               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*3 + r;
9756:               DMLabelSetValue(labelNew, newp, values[val]);
9757:             }
9758:           }
9759:           break;
9760:         case REFINER_HYBRID_SIMPLEX_TO_HEX_2D:
9761:         case REFINER_SIMPLEX_TO_HEX_2D:
9762:           if ((p >= vStart) && (p < vEnd)) {
9763:             /* Old vertices stay the same */
9764:             newp = vStartNew + (p - vStart);
9765:             DMLabelSetValue(labelNew, newp, values[val]);
9766:           } else if ((p >= fStart) && (p < fEnd)) {
9767:             /* Old faces add new faces and vertex */
9768:             newp = vStartNew + (vEnd - vStart) + (p - fStart);
9769:             DMLabelSetValue(labelNew, newp, values[val]);
9770:             for (r = 0; r < 2; ++r) {
9771:               newp = fStartNew + (p - fStart)*2 + r;
9772:               DMLabelSetValue(labelNew, newp, values[val]);
9773:             }
9774:           } else if ((p >= cStart) && (p < cMax)) {
9775:             /* Old cells add new cells, interior faces, and a vertex */
9776:             for (r = 0; r < 3; ++r) {
9777:               newp = cStartNew + (p - cStart)*3 + r;
9778:               DMLabelSetValue(labelNew, newp, values[val]);
9779:             }
9780:             for (r = 0; r < 3; ++r) {
9781:               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*3 + r;
9782:               DMLabelSetValue(labelNew, newp, values[val]);
9783:             }
9784:             newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + p;
9785:             DMLabelSetValue(labelNew, newp, values[val]);
9786:           } else if ((p >= cMax) && (p < cEnd)) {
9787:             /* Old hybrid cells add new cells, interior faces, and a vertex */
9788:             for (r = 0; r < 4; ++r) {
9789:               newp = cStartNew + (cMax - cStart)*3 + (p - cMax)*4 + r;
9790:               DMLabelSetValue(labelNew, newp, values[val]);
9791:             }
9792:             for (r = 0; r < 4; ++r) {
9793:               newp = fStartNew + (fEnd - fStart)*2 + (cMax - cStart)*3 + (p - cMax)*4 + r;
9794:               DMLabelSetValue(labelNew, newp, values[val]);
9795:             }
9796:             newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + p;
9797:             DMLabelSetValue(labelNew, newp, values[val]);
9798:           }
9799:           break;
9800:         case REFINER_HEX_2D:
9801:           if ((p >= vStart) && (p < vEnd)) {
9802:             /* Old vertices stay the same */
9803:             newp = vStartNew + (p - vStart);
9804:             DMLabelSetValue(labelNew, newp, values[val]);
9805:           } else if ((p >= fStart) && (p < fEnd)) {
9806:             /* Old faces add new faces and vertex */
9807:             newp = vStartNew + (vEnd - vStart) + (p - fStart);
9808:             DMLabelSetValue(labelNew, newp, values[val]);
9809:             for (r = 0; r < 2; ++r) {
9810:               newp = fStartNew + (p - fStart)*2 + r;
9811:               DMLabelSetValue(labelNew, newp, values[val]);
9812:             }
9813:           } else if ((p >= cStart) && (p < cEnd)) {
9814:             /* Old cells add new cells and interior faces and vertex */
9815:             for (r = 0; r < 4; ++r) {
9816:               newp = cStartNew + (p - cStart)*4 + r;
9817:               DMLabelSetValue(labelNew, newp, values[val]);
9818:             }
9819:             for (r = 0; r < 4; ++r) {
9820:               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*4 + r;
9821:               DMLabelSetValue(labelNew, newp, values[val]);
9822:             }
9823:             newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (p - cStart);
9824:             DMLabelSetValue(labelNew, newp, values[val]);
9825:           }
9826:           break;
9827:         case REFINER_HYBRID_SIMPLEX_2D:
9828:           if ((p >= vStart) && (p < vEnd)) {
9829:             /* Old vertices stay the same */
9830:             newp = vStartNew + (p - vStart);
9831:             DMLabelSetValue(labelNew, newp, values[val]);
9832:           } else if ((p >= fStart) && (p < fMax)) {
9833:             /* Old interior faces add new faces and vertex */
9834:             newp = vStartNew + (vEnd - vStart) + (p - fStart);
9835:             DMLabelSetValue(labelNew, newp, values[val]);
9836:             for (r = 0; r < 2; ++r) {
9837:               newp = fStartNew + (p - fStart)*2 + r;
9838:               DMLabelSetValue(labelNew, newp, values[val]);
9839:             }
9840:           } else if ((p >= fMax) && (p < fEnd)) {
9841:             /* Old hybrid faces stay the same */
9842:             newp = fStartNew + (fMax - fStart)*2 + (p - fMax);
9843:             DMLabelSetValue(labelNew, newp, values[val]);
9844:           } else if ((p >= cStart) && (p < cMax)) {
9845:             /* Old interior cells add new cells and interior faces */
9846:             for (r = 0; r < 4; ++r) {
9847:               newp = cStartNew + (p - cStart)*4 + r;
9848:               DMLabelSetValue(labelNew, newp, values[val]);
9849:             }
9850:             for (r = 0; r < 3; ++r) {
9851:               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*3 + r;
9852:               DMLabelSetValue(labelNew, newp, values[val]);
9853:             }
9854:           } else if ((p >= cMax) && (p < cEnd)) {
9855:             /* Old hybrid cells add new cells and hybrid face */
9856:             for (r = 0; r < 2; ++r) {
9857:               newp = cStartNew + (cMax - cStart)*4 + (p - cMax)*2 + r;
9858:               DMLabelSetValue(labelNew, newp, values[val]);
9859:             }
9860:             newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (p - cMax);
9861:             DMLabelSetValue(labelNew, newp, values[val]);
9862:           }
9863:           break;
9864:         case REFINER_HYBRID_HEX_2D:
9865:           if ((p >= vStart) && (p < vEnd)) {
9866:             /* Old vertices stay the same */
9867:             newp = vStartNew + (p - vStart);
9868:             DMLabelSetValue(labelNew, newp, values[val]);
9869:           } else if ((p >= fStart) && (p < fMax)) {
9870:             /* Old interior faces add new faces and vertex */
9871:             newp = vStartNew + (vEnd - vStart) + (p - fStart);
9872:             DMLabelSetValue(labelNew, newp, values[val]);
9873:             for (r = 0; r < 2; ++r) {
9874:               newp = fStartNew + (p - fStart)*2 + r;
9875:               DMLabelSetValue(labelNew, newp, values[val]);
9876:             }
9877:           } else if ((p >= fMax) && (p < fEnd)) {
9878:             /* Old hybrid faces stay the same */
9879:             newp = fStartNew + (fMax - fStart)*2 + (p - fMax);
9880:             DMLabelSetValue(labelNew, newp, values[val]);
9881:           } else if ((p >= cStart) && (p < cMax)) {
9882:             /* Old interior cells add new cells, interior faces, and vertex */
9883:             for (r = 0; r < 4; ++r) {
9884:               newp = cStartNew + (p - cStart)*4 + r;
9885:               DMLabelSetValue(labelNew, newp, values[val]);
9886:             }
9887:             for (r = 0; r < 4; ++r) {
9888:               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*4 + r;
9889:               DMLabelSetValue(labelNew, newp, values[val]);
9890:             }
9891:             newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (p - cStart);
9892:             DMLabelSetValue(labelNew, newp, values[val]);
9893:           } else if ((p >= cMax) && (p < cEnd)) {
9894:             /* Old hybrid cells add new cells and hybrid face */
9895:             for (r = 0; r < 2; ++r) {
9896:               newp = cStartNew + (cMax - cStart)*4 + (p - cMax)*2 + r;
9897:               DMLabelSetValue(labelNew, newp, values[val]);
9898:             }
9899:             newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*4 + (p - cMax);
9900:             DMLabelSetValue(labelNew, newp, values[val]);
9901:           }
9902:           break;
9903:         case REFINER_SIMPLEX_3D:
9904:           if ((p >= vStart) && (p < vEnd)) {
9905:             /* Old vertices stay the same */
9906:             newp = vStartNew + (p - vStart);
9907:             DMLabelSetValue(labelNew, newp, values[val]);
9908:           } else if ((p >= eStart) && (p < eEnd)) {
9909:             /* Old edges add new edges and vertex */
9910:             for (r = 0; r < 2; ++r) {
9911:               newp = eStartNew + (p - eStart)*2 + r;
9912:               DMLabelSetValue(labelNew, newp, values[val]);
9913:             }
9914:             newp = vStartNew + (vEnd - vStart) + (p - eStart);
9915:             DMLabelSetValue(labelNew, newp, values[val]);
9916:           } else if ((p >= fStart) && (p < fEnd)) {
9917:             /* Old faces add new faces and edges */
9918:             for (r = 0; r < 4; ++r) {
9919:               newp = fStartNew + (p - fStart)*4 + r;
9920:               DMLabelSetValue(labelNew, newp, values[val]);
9921:             }
9922:             for (r = 0; r < 3; ++r) {
9923:               newp = eStartNew + (eEnd - eStart)*2 + (p - fStart)*3 + r;
9924:               DMLabelSetValue(labelNew, newp, values[val]);
9925:             }
9926:           } else if ((p >= cStart) && (p < cEnd)) {
9927:             /* Old cells add new cells and interior faces and edges */
9928:             for (r = 0; r < 8; ++r) {
9929:               newp = cStartNew + (p - cStart)*8 + r;
9930:               DMLabelSetValue(labelNew, newp, values[val]);
9931:             }
9932:             for (r = 0; r < 8; ++r) {
9933:               newp = fStartNew + (fEnd - fStart)*4 + (p - cStart)*8 + r;
9934:               DMLabelSetValue(labelNew, newp, values[val]);
9935:             }
9936:             for (r = 0; r < 1; ++r) {
9937:               newp = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (p - cStart)*1 + r;
9938:               DMLabelSetValue(labelNew, newp, values[val]);
9939:             }
9940:           }
9941:           break;
9942:         case REFINER_HYBRID_SIMPLEX_TO_HEX_3D:
9943:         case REFINER_SIMPLEX_TO_HEX_3D:
9944:           if ((p >= vStart) && (p < vEnd)) {
9945:             /* Old vertices stay the same */
9946:             newp = vStartNew + (p - vStart);
9947:             DMLabelSetValue(labelNew, newp, values[val]);
9948:           } else if ((p >= eStart) && (p < eMax)) {
9949:             /* Interior edges add new edges and vertex */
9950:             for (r = 0; r < 2; ++r) {
9951:               newp = eStartNew + (p - eStart)*2 + r;
9952:               DMLabelSetValue(labelNew, newp, values[val]);
9953:             }
9954:             newp = vStartNew + (vEnd - vStart) + (p - eStart);
9955:             DMLabelSetValue(labelNew, newp, values[val]);
9956:           } else if ((p >= eMax) && (p < eEnd)) {
9957:             /* Hybrid edges stay the same */
9958:             newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart)*4 + p - eMax;
9959:             DMLabelSetValue(labelNew, newp, values[val]);
9960:           } else if ((p >= fStart) && (p < fMax)) {
9961:             /* Old faces add new faces, edges and a vertex */
9962:             for (r = 0; r < 3; ++r) {
9963:               newp = fStartNew + (p - fStart)*3 + r;
9964:               DMLabelSetValue(labelNew, newp, values[val]);
9965:             }
9966:             for (r = 0; r < 3; ++r) {
9967:               newp = eStartNew + (eMax - eStart)*2 + (p - fStart)*3 + r;
9968:               DMLabelSetValue(labelNew, newp, values[val]);
9969:             }
9970:           } else if ((p >= fMax) && (p < fEnd)) {
9971:             /* Old hybrid faces add new faces and an edge */
9972:             for (r = 0; r < 2; ++r) {
9973:               newp = fStartNew + (fMax - fStart)*3 + (cMax - cStart)*6 + (p - fMax)*2 + r;
9974:               DMLabelSetValue(labelNew, newp, values[val]);
9975:             }
9976:             newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart)*4 + (eEnd - eMax) + (p - fMax);
9977:             DMLabelSetValue(labelNew, newp, values[val]);
9978:           } else if ((p >= cStart) && (p < cMax)) {
9979:             /* Old cells add new cells and interior faces and edges and a vertex */
9980:             for (r = 0; r < 4; ++r) {
9981:               newp = cStartNew + (p - cStart)*4 + r;
9982:               DMLabelSetValue(labelNew, newp, values[val]);
9983:             }
9984:             for (r = 0; r < 6; ++r) {
9985:               newp = fStartNew + (fMax - fStart)*3 + (p - cStart)*6 + r;
9986:               DMLabelSetValue(labelNew, newp, values[val]);
9987:             }
9988:             for (r = 0; r < 4; ++r) {
9989:               newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (p - cStart)*4 + r;
9990:               DMLabelSetValue(labelNew, newp, values[val]);
9991:             }
9992:             newp = vStartNew + (vEnd - vStart) + (eMax - eStart) + (fMax - fStart) + p - cStart;
9993:             DMLabelSetValue(labelNew, newp, values[val]);
9994:           } else if ((p >= cMax) && (p < cEnd)) {
9995:             /* Old hybrid cells add new cells and interior faces and an edge */
9996:             for (r = 0; r < 3; ++r) {
9997:               newp = cStartNew + (cMax - cStart)*4 + (p - cMax)*3 + r;
9998:               DMLabelSetValue(labelNew, newp, values[val]);
9999:             }
10000:             for (r = 0; r < 3; ++r) {
10001:               newp = fStartNew + (fMax - fStart)*3 + (cMax - cStart)*6 + (fEnd - fMax)*2 + (p - cMax)*3 + r;
10002:               DMLabelSetValue(labelNew, newp, values[val]);
10003:             }
10004:             newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart)*4 + (eEnd - eMax) + (fEnd - fMax) + p - cMax;
10005:             DMLabelSetValue(labelNew, newp, values[val]);
10006:           }
10007:           break;
10008:         case REFINER_HYBRID_SIMPLEX_3D:
10009:           if ((p >= vStart) && (p < vEnd)) {
10010:             /* Interior vertices stay the same */
10011:             newp = vStartNew + (p - vStart);
10012:             DMLabelSetValue(labelNew, newp, values[val]);
10013:           } else if ((p >= eStart) && (p < eMax)) {
10014:             /* Interior edges add new edges and vertex */
10015:             for (r = 0; r < 2; ++r) {
10016:               newp = eStartNew + (p - eStart)*2 + r;
10017:               DMLabelSetValue(labelNew, newp, values[val]);
10018:             }
10019:             newp = vStartNew + (vEnd - vStart) + (p - eStart);
10020:             DMLabelSetValue(labelNew, newp, values[val]);
10021:           } else if ((p >= eMax) && (p < eEnd)) {
10022:             /* Hybrid edges stay the same */
10023:             newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (p - eMax);
10024:             DMLabelSetValue(labelNew, newp, values[val]);
10025:           } else if ((p >= fStart) && (p < fMax)) {
10026:             /* Interior faces add new faces and edges */
10027:             for (r = 0; r < 4; ++r) {
10028:               newp = fStartNew + (p - fStart)*4 + r;
10029:               DMLabelSetValue(labelNew, newp, values[val]);
10030:             }
10031:             for (r = 0; r < 3; ++r) {
10032:               newp = eStartNew + (eMax - eStart)*2 + (p - fStart)*3 + r;
10033:               DMLabelSetValue(labelNew, newp, values[val]);
10034:             }
10035:           } else if ((p >= fMax) && (p < fEnd)) {
10036:             /* Hybrid faces add new faces and edges */
10037:             for (r = 0; r < 2; ++r) {
10038:               newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (p - fMax)*2 + r;
10039:               DMLabelSetValue(labelNew, newp, values[val]);
10040:             }
10041:             newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (p - fMax);
10042:             DMLabelSetValue(labelNew, newp, values[val]);
10043:           } else if ((p >= cStart) && (p < cMax)) {
10044:             /* Interior cells add new cells, faces, and edges */
10045:             for (r = 0; r < 8; ++r) {
10046:               newp = cStartNew + (p - cStart)*8 + r;
10047:               DMLabelSetValue(labelNew, newp, values[val]);
10048:             }
10049:             for (r = 0; r < 8; ++r) {
10050:               newp = fStartNew + (fMax - fStart)*4 + (p - cStart)*8 + r;
10051:               DMLabelSetValue(labelNew, newp, values[val]);
10052:             }
10053:             newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (p - cStart);
10054:             DMLabelSetValue(labelNew, newp, values[val]);
10055:           } else if ((p >= cMax) && (p < cEnd)) {
10056:             /* Hybrid cells add new cells and faces */
10057:             for (r = 0; r < 4; ++r) {
10058:               newp = cStartNew + (cMax - cStart)*8 + (p - cMax)*4 + r;
10059:               DMLabelSetValue(labelNew, newp, values[val]);
10060:             }
10061:             for (r = 0; r < 3; ++r) {
10062:               newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (p - cMax)*3 + r;
10063:               DMLabelSetValue(labelNew, newp, values[val]);
10064:             }
10065:           }
10066:           break;
10067:         case REFINER_HEX_3D:
10068:           if ((p >= vStart) && (p < vEnd)) {
10069:             /* Old vertices stay the same */
10070:             newp = vStartNew + (p - vStart);
10071:             DMLabelSetValue(labelNew, newp, values[val]);
10072:           } else if ((p >= eStart) && (p < eEnd)) {
10073:             /* Old edges add new edges and vertex */
10074:             for (r = 0; r < 2; ++r) {
10075:               newp = eStartNew + (p - eStart)*2 + r;
10076:               DMLabelSetValue(labelNew, newp, values[val]);
10077:             }
10078:             newp = vStartNew + (vEnd - vStart) + (p - eStart);
10079:             DMLabelSetValue(labelNew, newp, values[val]);
10080:           } else if ((p >= fStart) && (p < fEnd)) {
10081:             /* Old faces add new faces, edges, and vertex */
10082:             for (r = 0; r < 4; ++r) {
10083:               newp = fStartNew + (p - fStart)*4 + r;
10084:               DMLabelSetValue(labelNew, newp, values[val]);
10085:             }
10086:             for (r = 0; r < 4; ++r) {
10087:               newp = eStartNew + (eEnd - eStart)*2 + (p - fStart)*4 + r;
10088:               DMLabelSetValue(labelNew, newp, values[val]);
10089:             }
10090:             newp = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (p - fStart);
10091:             DMLabelSetValue(labelNew, newp, values[val]);
10092:           } else if ((p >= cStart) && (p < cEnd)) {
10093:             /* Old cells add new cells, faces, edges, and vertex */
10094:             for (r = 0; r < 8; ++r) {
10095:               newp = cStartNew + (p - cStart)*8 + r;
10096:               DMLabelSetValue(labelNew, newp, values[val]);
10097:             }
10098:             for (r = 0; r < 12; ++r) {
10099:               newp = fStartNew + (fEnd - fStart)*4 + (p - cStart)*12 + r;
10100:               DMLabelSetValue(labelNew, newp, values[val]);
10101:             }
10102:             for (r = 0; r < 6; ++r) {
10103:               newp = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*4 + (p - cStart)*6 + r;
10104:               DMLabelSetValue(labelNew, newp, values[val]);
10105:             }
10106:             newp = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (fEnd - fStart) + (p - cStart);
10107:             DMLabelSetValue(labelNew, newp, values[val]);
10108:           }
10109:           break;
10110:         case REFINER_HYBRID_HEX_3D:
10111:           if ((p >= vStart) && (p < vEnd)) {
10112:             /* Interior vertices stay the same */
10113:             newp = vStartNew + (p - vStart);
10114:             DMLabelSetValue(labelNew, newp, values[val]);
10115:           } else if ((p >= eStart) && (p < eMax)) {
10116:             /* Interior edges add new edges and vertex */
10117:             for (r = 0; r < 2; ++r) {
10118:               newp = eStartNew + (p - eStart)*2 + r;
10119:               DMLabelSetValue(labelNew, newp, values[val]);
10120:             }
10121:             newp = vStartNew + (vEnd - vStart) + (p - eStart);
10122:             DMLabelSetValue(labelNew, newp, values[val]);
10123:           } else if ((p >= eMax) && (p < eEnd)) {
10124:             /* Hybrid edges stay the same */
10125:             newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (p - eMax);
10126:             DMLabelSetValue(labelNew, newp, values[val]);
10127:           } else if ((p >= fStart) && (p < fMax)) {
10128:             /* Interior faces add new faces, edges, and vertex */
10129:             for (r = 0; r < 4; ++r) {
10130:               newp = fStartNew + (p - fStart)*4 + r;
10131:               DMLabelSetValue(labelNew, newp, values[val]);
10132:             }
10133:             for (r = 0; r < 4; ++r) {
10134:               newp = eStartNew + (eMax - eStart)*2 + (p - fStart)*4 + r;
10135:               DMLabelSetValue(labelNew, newp, values[val]);
10136:             }
10137:             newp = vStartNew + (vEnd - vStart) + (eMax - eStart) + (p - fStart);
10138:             DMLabelSetValue(labelNew, newp, values[val]);
10139:           } else if ((p >= fMax) && (p < fEnd)) {
10140:             /* Hybrid faces add new faces and edges */
10141:             for (r = 0; r < 2; ++r) {
10142:               newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (p - fMax)*2 + r;
10143:               DMLabelSetValue(labelNew, newp, values[val]);
10144:             }
10145:             newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (p - fMax);
10146:             DMLabelSetValue(labelNew, newp, values[val]);
10147:           } else if ((p >= cStart) && (p < cMax)) {
10148:             /* Interior cells add new cells, faces, edges, and vertex */
10149:             for (r = 0; r < 8; ++r) {
10150:               newp = cStartNew + (p - cStart)*8 + r;
10151:               DMLabelSetValue(labelNew, newp, values[val]);
10152:             }
10153:             for (r = 0; r < 12; ++r) {
10154:               newp = fStartNew + (fMax - fStart)*4 + (p - cStart)*12 + r;
10155:               DMLabelSetValue(labelNew, newp, values[val]);
10156:             }
10157:             for (r = 0; r < 6; ++r) {
10158:               newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (p - cStart)*6 + r;
10159:               DMLabelSetValue(labelNew, newp, values[val]);
10160:             }
10161:             newp = vStartNew + (vEnd - vStart) + (eMax - eStart) + (fMax - fStart) + (p - cStart);
10162:             DMLabelSetValue(labelNew, newp, values[val]);
10163:           } else if ((p >= cMax) && (p < cEnd)) {
10164:             /* Hybrid cells add new cells, faces, and edges */
10165:             for (r = 0; r < 4; ++r) {
10166:               newp = cStartNew + (cMax - cStart)*8 + (p - cMax)*4 + r;
10167:               DMLabelSetValue(labelNew, newp, values[val]);
10168:             }
10169:             for (r = 0; r < 4; ++r) {
10170:               newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd - fMax)*2 + (p - cMax)*4 + r;
10171:               DMLabelSetValue(labelNew, newp, values[val]);
10172:             }
10173:             newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (fEnd - fMax) + (p - cMax);
10174:             DMLabelSetValue(labelNew, newp, values[val]);
10175:           }
10176:           break;
10177:         default:
10178:           SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %s", CellRefiners[refiner]);
10179:         }
10180:       }
10181:       ISRestoreIndices(pointIS, &points);
10182:       ISDestroy(&pointIS);
10183:     }
10184:     ISRestoreIndices(valueIS, &values);
10185:     ISDestroy(&valueIS);
10186:   }
10187:   return(0);
10188: }

10190: /* This will only work for interpolated meshes */
10191: PetscErrorCode DMPlexRefineUniform_Internal(DM dm, CellRefiner cellRefiner, DM *dmRefined)
10192: {
10193:   DM             rdm;
10194:   PetscInt      *depthSize;
10195:   PetscInt       dim, embedDim, depth = 0, d, pStart = 0, pEnd = 0;

10199:   DMCreate(PetscObjectComm((PetscObject)dm), &rdm);
10200:   DMSetType(rdm, DMPLEX);
10201:   DMGetDimension(dm, &dim);
10202:   DMSetDimension(rdm, dim);
10203:   DMGetCoordinateDim(dm, &embedDim);
10204:   DMSetCoordinateDim(rdm, embedDim);
10205:   /* Calculate number of new points of each depth */
10206:   DMPlexGetDepth(dm, &depth);
10207:   if (depth >= 0 && dim != depth) SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "Mesh must be interpolated for regular refinement");
10208:   PetscMalloc1(depth+1, &depthSize);
10209:   PetscMemzero(depthSize, (depth+1) * sizeof(PetscInt));
10210:   CellRefinerGetSizes(cellRefiner, dm, depthSize);
10211:   /* Step 1: Set chart */
10212:   for (d = 0; d <= depth; ++d) pEnd += depthSize[d];
10213:   DMPlexSetChart(rdm, pStart, pEnd);
10214:   /* Step 2: Set cone/support sizes (automatically stratifies) */
10215:   CellRefinerSetConeSizes(cellRefiner, dm, depthSize, rdm);
10216:   /* Step 3: Setup refined DM */
10217:   DMSetUp(rdm);
10218:   /* Step 4: Set cones and supports (automatically symmetrizes) */
10219:   CellRefinerSetCones(cellRefiner, dm, depthSize, rdm);
10220:   /* Step 5: Create pointSF */
10221:   CellRefinerCreateSF(cellRefiner, dm, depthSize, rdm);
10222:   /* Step 6: Create labels */
10223:   CellRefinerCreateLabels(cellRefiner, dm, depthSize, rdm);
10224:   /* Step 7: Set coordinates */
10225:   CellRefinerSetCoordinates(cellRefiner, dm, depthSize, rdm);
10226:   PetscFree(depthSize);

10228:   *dmRefined = rdm;
10229:   return(0);
10230: }

10232: /*@
10233:   DMPlexCreateCoarsePointIS - Creates an IS covering the coarse DM chart with the fine points as data

10235:   Input Parameter:
10236: . dm - The coarse DM

10238:   Output Parameter:
10239: . fpointIS - The IS of all the fine points which exist in the original coarse mesh

10241:   Level: developer

10243: .seealso: DMRefine(), DMPlexSetRefinementUniform(), DMPlexCreateSubpointIS()
10244: @*/
10245: PetscErrorCode DMPlexCreateCoarsePointIS(DM dm, IS *fpointIS)
10246: {
10247:   CellRefiner    cellRefiner;
10248:   PetscInt      *depthSize, *fpoints;
10249:   PetscInt       cStartNew = 0, vStartNew = 0, fStartNew = 0, eStartNew = 0;
10250:   PetscInt       depth, pStart, pEnd, p, vStart, vEnd, v;

10254:   DMPlexGetDepth(dm, &depth);
10255:   DMPlexGetChart(dm, &pStart, &pEnd);
10256:   DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);
10257:   DMPlexGetCellRefiner_Internal(dm, &cellRefiner);
10258:   PetscMalloc1(depth+1, &depthSize);
10259:   CellRefinerGetSizes(cellRefiner, dm, depthSize);
10260:   if (cellRefiner) {GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);}
10261:   PetscMalloc1(pEnd-pStart,&fpoints);
10262:   for (p = 0; p < pEnd-pStart; ++p) fpoints[p] = -1;
10263:   switch (cellRefiner) {
10264:   case REFINER_SIMPLEX_1D:
10265:   case REFINER_SIMPLEX_2D:
10266:   case REFINER_HYBRID_SIMPLEX_2D:
10267:   case REFINER_HEX_2D:
10268:   case REFINER_HYBRID_HEX_2D:
10269:   case REFINER_SIMPLEX_3D:
10270:   case REFINER_HYBRID_SIMPLEX_3D:
10271:   case REFINER_HEX_3D:
10272:   case REFINER_HYBRID_HEX_3D:
10273:     for (v = vStart; v < vEnd; ++v) fpoints[v-pStart] = vStartNew + (v - vStart);
10274:     break;
10275:   default:
10276:     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %s", CellRefiners[cellRefiner]);
10277:   }
10278:   ISCreateGeneral(PETSC_COMM_SELF, pEnd-pStart, fpoints, PETSC_OWN_POINTER, fpointIS);
10279:   PetscFree(depthSize);
10280:   return(0);
10281: }

10283: /*@
10284:   DMPlexSetRefinementUniform - Set the flag for uniform refinement

10286:   Input Parameters:
10287: + dm - The DM
10288: - refinementUniform - The flag for uniform refinement

10290:   Level: developer

10292: .seealso: DMRefine(), DMPlexGetRefinementUniform(), DMPlexGetRefinementLimit(), DMPlexSetRefinementLimit()
10293: @*/
10294: PetscErrorCode DMPlexSetRefinementUniform(DM dm, PetscBool refinementUniform)
10295: {
10296:   DM_Plex *mesh = (DM_Plex*) dm->data;

10300:   mesh->refinementUniform = refinementUniform;
10301:   return(0);
10302: }

10304: /*@
10305:   DMPlexGetRefinementUniform - Retrieve the flag for uniform refinement

10307:   Input Parameter:
10308: . dm - The DM

10310:   Output Parameter:
10311: . refinementUniform - The flag for uniform refinement

10313:   Level: developer

10315: .seealso: DMRefine(), DMPlexSetRefinementUniform(), DMPlexGetRefinementLimit(), DMPlexSetRefinementLimit()
10316: @*/
10317: PetscErrorCode DMPlexGetRefinementUniform(DM dm, PetscBool *refinementUniform)
10318: {
10319:   DM_Plex *mesh = (DM_Plex*) dm->data;

10324:   *refinementUniform = mesh->refinementUniform;
10325:   return(0);
10326: }

10328: /*@
10329:   DMPlexSetRefinementLimit - Set the maximum cell volume for refinement

10331:   Input Parameters:
10332: + dm - The DM
10333: - refinementLimit - The maximum cell volume in the refined mesh

10335:   Level: developer

10337: .seealso: DMRefine(), DMPlexGetRefinementLimit(), DMPlexGetRefinementUniform(), DMPlexSetRefinementUniform()
10338: @*/
10339: PetscErrorCode DMPlexSetRefinementLimit(DM dm, PetscReal refinementLimit)
10340: {
10341:   DM_Plex *mesh = (DM_Plex*) dm->data;

10345:   mesh->refinementLimit = refinementLimit;
10346:   return(0);
10347: }

10349: /*@
10350:   DMPlexGetRefinementLimit - Retrieve the maximum cell volume for refinement

10352:   Input Parameter:
10353: . dm - The DM

10355:   Output Parameter:
10356: . refinementLimit - The maximum cell volume in the refined mesh

10358:   Level: developer

10360: .seealso: DMRefine(), DMPlexSetRefinementLimit(), DMPlexGetRefinementUniform(), DMPlexSetRefinementUniform()
10361: @*/
10362: PetscErrorCode DMPlexGetRefinementLimit(DM dm, PetscReal *refinementLimit)
10363: {
10364:   DM_Plex *mesh = (DM_Plex*) dm->data;

10369:   /* if (mesh->refinementLimit < 0) = getMaxVolume()/2.0; */
10370:   *refinementLimit = mesh->refinementLimit;
10371:   return(0);
10372: }

10374: /*@
10375:   DMPlexSetRefinementFunction - Set the function giving the maximum cell volume for refinement

10377:   Input Parameters:
10378: + dm - The DM
10379: - refinementFunc - Function giving the maximum cell volume in the refined mesh

10381:   Note: The calling sequence is refinementFunc(coords, limit)
10382: $ coords - Coordinates of the current point, usually a cell centroid
10383: $ limit  - The maximum cell volume for a cell containing this point

10385:   Level: developer

10387: .seealso: DMRefine(), DMPlexGetRefinementFunction(), DMPlexGetRefinementUniform(), DMPlexSetRefinementUniform(), DMPlexGetRefinementLimit(), DMPlexSetRefinementLimit()
10388: @*/
10389: PetscErrorCode DMPlexSetRefinementFunction(DM dm, PetscErrorCode (*refinementFunc)(const PetscReal [], PetscReal *))
10390: {
10391:   DM_Plex *mesh = (DM_Plex*) dm->data;

10395:   mesh->refinementFunc = refinementFunc;
10396:   return(0);
10397: }

10399: /*@
10400:   DMPlexGetRefinementFunction - Get the function giving the maximum cell volume for refinement

10402:   Input Parameter:
10403: . dm - The DM

10405:   Output Parameter:
10406: . refinementFunc - Function giving the maximum cell volume in the refined mesh

10408:   Note: The calling sequence is refinementFunc(coords, limit)
10409: $ coords - Coordinates of the current point, usually a cell centroid
10410: $ limit  - The maximum cell volume for a cell containing this point

10412:   Level: developer

10414: .seealso: DMRefine(), DMPlexSetRefinementFunction(), DMPlexGetRefinementUniform(), DMPlexSetRefinementUniform(), DMPlexGetRefinementLimit(), DMPlexSetRefinementLimit()
10415: @*/
10416: PetscErrorCode DMPlexGetRefinementFunction(DM dm, PetscErrorCode (**refinementFunc)(const PetscReal [], PetscReal *))
10417: {
10418:   DM_Plex *mesh = (DM_Plex*) dm->data;

10423:   *refinementFunc = mesh->refinementFunc;
10424:   return(0);
10425: }

10427: PetscErrorCode DMPlexGetCellRefiner_Internal(DM dm, CellRefiner *cellRefiner)
10428: {
10429:   PetscInt       dim, cStart, cEnd, coneSize, cMax, fMax;

10433:   DMGetDimension(dm, &dim);
10434:   DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);
10435:   if (cEnd <= cStart) {*cellRefiner = REFINER_NOOP; return(0);}
10436:   DMPlexGetConeSize(dm, cStart, &coneSize);
10437:   DMPlexGetHybridBounds(dm, &cMax, &fMax, NULL, NULL);
10438:   switch (dim) {
10439:   case 1:
10440:     switch (coneSize) {
10441:     case 2:
10442:       *cellRefiner = REFINER_SIMPLEX_1D;
10443:       break;
10444:     default:
10445:       SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown coneSize %D in dimension %D for cell refiner", coneSize, dim);
10446:     }
10447:     break;
10448:   case 2:
10449:     switch (coneSize) {
10450:     case 3:
10451:       if (cMax >= 0) *cellRefiner = REFINER_HYBRID_SIMPLEX_2D;
10452:       else *cellRefiner = REFINER_SIMPLEX_2D;
10453:       break;
10454:     case 4:
10455:       if (cMax >= 0 && fMax >= 0) *cellRefiner = REFINER_HYBRID_HEX_2D;
10456:       else *cellRefiner = REFINER_HEX_2D;
10457:       break;
10458:     default:
10459:       SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown coneSize %D in dimension %D for cell refiner", coneSize, dim);
10460:     }
10461:     break;
10462:   case 3:
10463:     switch (coneSize) {
10464:     case 4:
10465:       if (cMax >= 0) *cellRefiner = REFINER_HYBRID_SIMPLEX_3D;
10466:       else *cellRefiner = REFINER_SIMPLEX_3D;
10467:       break;
10468:     case 5:
10469:       if (cMax == 0) *cellRefiner = REFINER_HYBRID_SIMPLEX_3D;
10470:       else SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown coneSize %D in dimension %D for cell refiner", coneSize, dim);
10471:       break;
10472:     case 6:
10473:       if (cMax >= 0) *cellRefiner = REFINER_HYBRID_HEX_3D;
10474:       else *cellRefiner = REFINER_HEX_3D;
10475:       break;
10476:     default:
10477:       SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown coneSize %D in dimension %D for cell refiner", coneSize, dim);
10478:     }
10479:     break;
10480:   default:
10481:     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown dimension %D for cell refiner", dim);
10482:   }
10483:   return(0);
10484: }

10486: PetscErrorCode DMRefine_Plex(DM dm, MPI_Comm comm, DM *dmRefined)
10487: {
10488:   PetscBool      isUniform;

10492:   DMPlexGetRefinementUniform(dm, &isUniform);
10493:   if (isUniform) {
10494:     CellRefiner cellRefiner;
10495:     PetscBool   localized;

10497:     DMGetCoordinatesLocalized(dm, &localized);
10498:     DMPlexGetCellRefiner_Internal(dm, &cellRefiner);
10499:     DMPlexRefineUniform_Internal(dm, cellRefiner, dmRefined);
10500:     DMPlexSetRegularRefinement(*dmRefined, PETSC_TRUE);
10501:     DMCopyBoundary(dm, *dmRefined);
10502:     if (localized) {DMLocalizeCoordinates(*dmRefined);}
10503:   } else {
10504:     DMPlexRefine_Internal(dm, NULL, dmRefined);
10505:   }
10506:   return(0);
10507: }

10509: PetscErrorCode DMRefineHierarchy_Plex(DM dm, PetscInt nlevels, DM dmRefined[])
10510: {
10511:   DM             cdm = dm;
10512:   PetscInt       r;
10513:   PetscBool      isUniform, localized;

10517:   DMPlexGetRefinementUniform(dm, &isUniform);
10518:   DMGetCoordinatesLocalized(dm, &localized);
10519:   if (isUniform) {
10520:     for (r = 0; r < nlevels; ++r) {
10521:       CellRefiner cellRefiner;

10523:       DMPlexGetCellRefiner_Internal(cdm, &cellRefiner);
10524:       DMPlexRefineUniform_Internal(cdm, cellRefiner, &dmRefined[r]);
10525:       DMSetCoarsenLevel(dmRefined[r], cdm->leveldown);
10526:       DMSetRefineLevel(dmRefined[r], cdm->levelup+1);
10527:       DMCopyBoundary(cdm, dmRefined[r]);
10528:       if (localized) {DMLocalizeCoordinates(dmRefined[r]);}
10529:       DMSetCoarseDM(dmRefined[r], cdm);
10530:       DMPlexSetRegularRefinement(dmRefined[r], PETSC_TRUE);
10531:       cdm  = dmRefined[r];
10532:     }
10533:   } else {
10534:     for (r = 0; r < nlevels; ++r) {
10535:       DMRefine(cdm, PetscObjectComm((PetscObject) dm), &dmRefined[r]);
10536:       DMCopyBoundary(cdm, dmRefined[r]);
10537:       if (localized) {DMLocalizeCoordinates(dmRefined[r]);}
10538:       DMSetCoarseDM(dmRefined[r], cdm);
10539:       cdm  = dmRefined[r];
10540:     }
10541:   }
10542:   return(0);
10543: }