Date: 2015-10-02T22:14:44+00:00

Actual source code: plexrefine.c
petsc-3.6.2 2015-10-02
Report Typos and Errors

      1: #include <petsc/private/dmpleximpl.h>   /*I      "petscdmplex.h"   I*/
      2: #include <petscsf.h>

      6: PETSC_STATIC_INLINE PetscErrorCode GetDepthStart_Private(PetscInt depth, PetscInt depthSize[], PetscInt *cStart, PetscInt *fStart, PetscInt *eStart, PetscInt *vStart)
      7: {
      9:   if (cStart) *cStart = 0;
     10:   if (vStart) *vStart = depth < 0 ? 0 : depthSize[depth];
     11:   if (fStart) *fStart = depth < 0 ? 0 : depthSize[depth] + depthSize[0];
     12:   if (eStart) *eStart = depth < 0 ? 0 : depthSize[depth] + depthSize[0] + depthSize[depth-1];
     13:   return(0);
     14: }

     18: PETSC_STATIC_INLINE PetscErrorCode GetDepthEnd_Private(PetscInt depth, PetscInt depthSize[], PetscInt *cEnd, PetscInt *fEnd, PetscInt *eEnd, PetscInt *vEnd)
     19: {
     21:   if (cEnd) *cEnd = depth < 0 ? 0 : depthSize[depth];
     22:   if (vEnd) *vEnd = depth < 0 ? 0 : depthSize[depth] + depthSize[0];
     23:   if (fEnd) *fEnd = depth < 0 ? 0 : depthSize[depth] + depthSize[0] + depthSize[depth-1];
     24:   if (eEnd) *eEnd = depth < 0 ? 0 : depthSize[depth] + depthSize[0] + depthSize[depth-1] + depthSize[1];
     25:   return(0);
     26: }

     30: /* Gets the affine map from the original cell to each subcell */
     31: PetscErrorCode CellRefinerGetAffineTransforms_Internal(CellRefiner refiner, PetscInt *numSubcells, PetscReal *v0[], PetscReal *jac[], PetscReal *invjac[])
     32: {
     33:   PetscReal     *v = NULL, *j = NULL, *invj = NULL, detJ;
     34:   PetscInt       dim, s;

     38:   switch (refiner) {
     39:   case REFINER_NOOP: break;
     40:   case REFINER_SIMPLEX_2D:
     41:     /*
     42:      2
     43:      |\
     44:      | \
     45:      |  \
     46:      |   \
     47:      | C  \
     48:      |     \
     49:      |      \
     50:      2---1---1
     51:      |\  D  / \
     52:      | 2   0   \
     53:      |A \ /  B  \
     54:      0---0-------1
     55:      */
     56:     dim = 2;
     57:     if (numSubcells) *numSubcells = 4;
     58:     if (v0) {
     59:       PetscMalloc3(4*dim,&v,4*dim*dim,&j,4*dim*dim,&invj);
     60:       /* A */
     61:       v[0+0] = -1.0; v[0+1] = -1.0;
     62:       j[0+0] =  0.5; j[0+1] =  0.0;
     63:       j[0+2] =  0.0; j[0+3] =  0.5;
     64:       /* B */
     65:       v[2+0] =  0.0; v[2+1] = -1.0;
     66:       j[4+0] =  0.5; j[4+1] =  0.0;
     67:       j[4+2] =  0.0; j[4+3] =  0.5;
     68:       /* C */
     69:       v[4+0] = -1.0; v[4+1] =  0.0;
     70:       j[8+0] =  0.5; j[8+1] =  0.0;
     71:       j[8+2] =  0.0; j[8+3] =  0.5;
     72:       /* D */
     73:       v[6+0]  =  0.0; v[6+1]  = -1.0;
     74:       j[12+0] =  0.0; j[12+1] = -0.5;
     75:       j[12+2] =  0.5; j[12+3] =  0.5;
     76:       for (s = 0; s < 4; ++s) {
     77:         DMPlex_Det2D_Internal(&detJ, &j[s*dim*dim]);
     78:         DMPlex_Invert2D_Internal(&invj[s*dim*dim], &j[s*dim*dim], detJ);
     79:       }
     80:     }
     81:     break;
     82:   case REFINER_HEX_2D:
     83:     /*
     84:      3---------2---------2
     85:      |         |         |
     86:      |    D    2    C    |
     87:      |         |         |
     88:      3----3----0----1----1
     89:      |         |         |
     90:      |    A    0    B    |
     91:      |         |         |
     92:      0---------0---------1
     93:      */
     94:     dim = 2;
     95:     if (numSubcells) *numSubcells = 4;
     96:     if (v0) {
     97:       PetscMalloc3(4*dim,&v,4*dim*dim,&j,4*dim*dim,&invj);
     98:       /* A */
     99:       v[0+0] = -1.0; v[0+1] = -1.0;
    100:       j[0+0] =  0.5; j[0+1] =  0.0;
    101:       j[0+2] =  0.0; j[0+3] =  0.5;
    102:       /* B */
    103:       v[2+0] =  0.0; v[2+1] = -1.0;
    104:       j[4+0] =  0.5; j[4+1] =  0.0;
    105:       j[4+2] =  0.0; j[4+3] =  0.5;
    106:       /* C */
    107:       v[4+0] =  0.0; v[4+1] =  0.0;
    108:       j[8+0] =  0.5; j[8+1] =  0.0;
    109:       j[8+2] =  0.0; j[8+3] =  0.5;
    110:       /* D */
    111:       v[6+0]  = -1.0; v[6+1]  =  0.0;
    112:       j[12+0] =  0.5; j[12+1] =  0.0;
    113:       j[12+2] =  0.0; j[12+3] =  0.5;
    114:       for (s = 0; s < 4; ++s) {
    115:         DMPlex_Det2D_Internal(&detJ, &j[s*dim*dim]);
    116:         DMPlex_Invert2D_Internal(&invj[s*dim*dim], &j[s*dim*dim], detJ);
    117:       }
    118:     }
    119:     break;
    120:   default:
    121:     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
    122:   }
    123:   if (v0) {*v0 = v; *jac = j; *invjac = invj;}
    124:   return(0);
    125: }

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

    134:   PetscFree3(*v0,*jac,*invjac);
    135:   return(0);
    136: }

    140: /* Should this be here or in the DualSpace somehow? */
    141: PetscErrorCode CellRefinerInCellTest_Internal(CellRefiner refiner, const PetscReal point[], PetscBool *inside)
    142: {
    143:   PetscReal sum = 0.0;
    144:   PetscInt  d;

    147:   *inside = PETSC_TRUE;
    148:   switch (refiner) {
    149:   case REFINER_NOOP: break;
    150:   case REFINER_SIMPLEX_2D:
    151:     for (d = 0; d < 2; ++d) {
    152:       if (point[d] < -1.0) {*inside = PETSC_FALSE; break;}
    153:       sum += point[d];
    154:     }
    155:     if (sum > 0.0) {*inside = PETSC_FALSE; break;}
    156:     break;
    157:   case REFINER_HEX_2D:
    158:     for (d = 0; d < 2; ++d) if ((point[d] < -1.0) || (point[d] > 1.0)) {*inside = PETSC_FALSE; break;}
    159:     break;
    160:   default:
    161:     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
    162:   }
    163:   return(0);
    164: }

    168: static PetscErrorCode CellRefinerGetSizes(CellRefiner refiner, DM dm, PetscInt depthSize[])
    169: {
    170:   PetscInt       cStart, cEnd, cMax, vStart, vEnd, vMax, fStart, fEnd, fMax, eStart, eEnd, eMax;

    174:   DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);
    175:   DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);
    176:   DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);
    177:   DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);
    178:   DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);
    179:   switch (refiner) {
    180:   case REFINER_NOOP:
    181:     break;
    182:   case REFINER_SIMPLEX_1D:
    183:     depthSize[0] = vEnd - vStart + cEnd - cStart;         /* Add a vertex on every cell. */
    184:     depthSize[1] = 2*(cEnd - cStart);                     /* Split every cell in 2. */
    185:     break;
    186:   case REFINER_SIMPLEX_2D:
    187:     depthSize[0] = vEnd - vStart + fEnd - fStart;         /* Add a vertex on every face */
    188:     depthSize[1] = 2*(fEnd - fStart) + 3*(cEnd - cStart); /* Every face is split into 2 faces and 3 faces are added for each cell */
    189:     depthSize[2] = 4*(cEnd - cStart);                     /* Every cell split into 4 cells */
    190:     break;
    191:   case REFINER_HYBRID_SIMPLEX_2D:
    192:     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
    193:     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
    194:     depthSize[0] = vEnd - vStart + fMax - fStart;                                         /* Add a vertex on every face, but not hybrid faces */
    195:     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 */
    196:     depthSize[2] = 4*(cMax - cStart) + 2*(cEnd - cMax);                                   /* Interior cells split into 4 cells, Hybrid cells split into 2 cells */
    197:     break;
    198:   case REFINER_HEX_2D:
    199:     depthSize[0] = vEnd - vStart + fEnd - fStart + cEnd - cStart; /* Add a vertex on every face and cell */
    200:     depthSize[1] = 2*(fEnd - fStart) + 4*(cEnd - cStart);         /* Every face is split into 2 faces and 4 faces are added for each cell */
    201:     depthSize[2] = 4*(cEnd - cStart);                             /* Every cell split into 4 cells */
    202:     break;
    203:   case REFINER_HYBRID_HEX_2D:
    204:     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
    205:     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
    206:     /* Quadrilateral */
    207:     depthSize[0] = vEnd - vStart + fMax - fStart + cMax - cStart;                 /* Add a vertex on every face and cell */
    208:     depthSize[1] = 2*(fMax - fStart) + 4*(cMax - cStart);                         /* Every face is split into 2 faces, and 4 faces are added for each cell */
    209:     depthSize[2] = 4*(cMax - cStart);                                             /* Every cell split into 4 cells */
    210:     /* Segment Prisms */
    211:     depthSize[0] += 0;                                                            /* No hybrid vertices */
    212:     depthSize[1] +=   (fEnd - fMax)  +   (cEnd - cMax);                           /* Every hybrid face remains and 1 faces is added for each hybrid cell */
    213:     depthSize[2] += 2*(cEnd - cMax);                                              /* Every hybrid cell split into 2 cells */
    214:     break;
    215:   case REFINER_SIMPLEX_3D:
    216:     depthSize[0] =    vEnd - vStart  +    eEnd - eStart;                    /* Add a vertex on every edge */
    217:     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 */
    218:     depthSize[2] = 4*(fEnd - fStart) + 8*(cEnd - cStart);                   /* Every face split into 4 faces and 8 faces are added for each cell */
    219:     depthSize[3] = 8*(cEnd - cStart);                                       /* Every cell split into 8 cells */
    220:     break;
    221:   case REFINER_HYBRID_SIMPLEX_3D:
    222:     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
    223:     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
    224:     if (eMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No edge maximum specified in hybrid mesh");
    225:     /* Tetrahedra */
    226:     depthSize[0]  =    vEnd - vStart  +    eMax - eStart;                    /* Add a vertex on every interior edge */
    227:     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 */
    228:     depthSize[2]  = 4*(fMax - fStart) + 8*(cMax - cStart);                   /* Every interior face split into 4 faces, 8 faces added for each interior cell */
    229:     depthSize[3]  = 8*(cMax - cStart);                                       /* Every interior cell split into 8 cells */
    230:     /* Triangular Prisms */
    231:     depthSize[0] += 0;                                                       /* No hybrid vertices */
    232:     depthSize[1] +=   (eEnd - eMax)   +   (fEnd - fMax);                     /* Every hybrid edge remains, 1 edge for every hybrid face */
    233:     depthSize[2] += 2*(fEnd - fMax)   + 3*(cEnd - cMax);                     /* Every hybrid face split into 2 faces and 3 faces are added for each hybrid cell */
    234:     depthSize[3] += 4*(cEnd - cMax);                                         /* Every hybrid cell split into 4 cells */
    235:     break;
    236:   case REFINER_HEX_3D:
    237:     depthSize[0] = vEnd - vStart + eEnd - eStart + fEnd - fStart + cEnd - cStart; /* Add a vertex on every edge, face and cell */
    238:     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 */
    239:     depthSize[2] = 4*(fEnd - fStart) + 12*(cEnd - cStart);                        /* Every face is split into 4 faces, and 12 faces are added for each cell */
    240:     depthSize[3] = 8*(cEnd - cStart);                                             /* Every cell split into 8 cells */
    241:     break;
    242:   case REFINER_HYBRID_HEX_3D:
    243:     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
    244:     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
    245:     if (eMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No edge maximum specified in hybrid mesh");
    246:     /* Hexahedra */
    247:     depthSize[0] = vEnd - vStart + eMax - eStart + fMax - fStart + cMax - cStart; /* Add a vertex on every edge, face and cell */
    248:     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 */
    249:     depthSize[2] = 4*(fMax - fStart) + 12*(cMax - cStart);                        /* Every face is split into 4 faces, and 12 faces are added for each cell */
    250:     depthSize[3] = 8*(cMax - cStart);                                             /* Every cell split into 8 cells */
    251:     /* Quadrilateral Prisms */
    252:     depthSize[0] += 0;                                                            /* No hybrid vertices */
    253:     depthSize[1] +=   (eEnd - eMax)   +   (fEnd - fMax)   +   (cEnd - cMax);      /* Every hybrid edge remains, 1 edge for every hybrid face and hybrid cell */
    254:     depthSize[2] += 2*(fEnd - fMax)   + 4*(cEnd - cMax);                          /* Every hybrid face split into 2 faces and 4 faces are added for each hybrid cell */
    255:     depthSize[3] += 4*(cEnd - cMax);                                              /* Every hybrid cell split into 4 cells */
    256:     break;
    257:   default:
    258:     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
    259:   }
    260:   return(0);
    261: }

    263: /* Return triangle edge for orientation o, if it is r for o == 0 */
    264: PETSC_STATIC_INLINE PetscInt GetTriEdge_Static(PetscInt o, PetscInt r) {
    265:   return (o < 0 ? 2-(o+r) : o+r)%3;
    266: }
    267: PETSC_STATIC_INLINE PetscInt GetTriEdgeInverse_Static(PetscInt o, PetscInt s) {
    268:   return (o < 0 ? 2-(o+s) : 3+s-o)%3;
    269: }

    271: /* Return triangle subface for orientation o, if it is r for o == 0 */
    272: PETSC_STATIC_INLINE PetscInt GetTriSubface_Static(PetscInt o, PetscInt r) {
    273:   return (o < 0 ? 3-(o+r) : o+r)%3;
    274: }
    275: PETSC_STATIC_INLINE PetscInt GetTriSubfaceInverse_Static(PetscInt o, PetscInt s) {
    276:   return (o < 0 ? 3-(o+s) : 3+s-o)%3;
    277: }

    279: /* I HAVE NO IDEA: Return ??? for orientation o, if it is r for o == 0 */
    280: PETSC_STATIC_INLINE PetscInt GetTetSomething_Static(PetscInt o, PetscInt r) {
    281:   return (o < 0 ? 1-(o+r) : o+r)%3;
    282: }
    283: PETSC_STATIC_INLINE PetscInt GetTetSomethingInverse_Static(PetscInt o, PetscInt s) {
    284:   return (o < 0 ? 1-(o+s) : 3+s-o)%3;
    285: }

    288: /* Return quad edge for orientation o, if it is r for o == 0 */
    289: PETSC_STATIC_INLINE PetscInt GetQuadEdge_Static(PetscInt o, PetscInt r) {
    290:   return (o < 0 ? 3-(o+r) : o+r)%4;
    291: }
    292: PETSC_STATIC_INLINE PetscInt GetQuadEdgeInverse_Static(PetscInt o, PetscInt s) {
    293:   return (o < 0 ? 3-(o+s) : 4+s-o)%4;
    294: }

    296: /* Return quad subface for orientation o, if it is r for o == 0 */
    297: PETSC_STATIC_INLINE PetscInt GetQuadSubface_Static(PetscInt o, PetscInt r) {
    298:   return (o < 0 ? 4-(o+r) : o+r)%4;
    299: }
    300: PETSC_STATIC_INLINE PetscInt GetQuadSubfaceInverse_Static(PetscInt o, PetscInt s) {
    301:   return (o < 0 ? 4-(o+s) : 4+s-o)%4;
    302: }

    306: static PetscErrorCode CellRefinerSetConeSizes(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
    307: {
    308:   PetscInt       depth, cStart, cStartNew, cEnd, cMax, c, vStart, vStartNew, vEnd, vMax, v, fStart, fStartNew, fEnd, fMax, f, eStart, eStartNew, eEnd, eMax, e, r;

    312:   if (!refiner) return(0);
    313:   DMPlexGetDepth(dm, &depth);
    314:   DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);
    315:   DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);
    316:   DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);
    317:   DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);
    318:   DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);
    319:   GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);
    320:   switch (refiner) {
    321:   case REFINER_SIMPLEX_1D:
    322:     /* All cells have 2 vertices */
    323:     for (c = cStart; c < cEnd; ++c) {
    324:       for (r = 0; r < 2; ++r) {
    325:         const PetscInt newp = cStartNew + (c - cStart)*2 + r;

    327:         DMPlexSetConeSize(rdm, newp, 2);
    328:       }
    329:     }
    330:     /* Old vertices have identical supports */
    331:     for (v = vStart; v < vEnd; ++v) {
    332:       const PetscInt newp = vStartNew + (v - vStart);
    333:       PetscInt       size;

    335:       DMPlexGetSupportSize(dm, v, &size);
    336:       DMPlexSetSupportSize(rdm, newp, size);
    337:     }
    338:     /* Cell vertices have support 2 */
    339:     for (c = cStart; c < cEnd; ++c) {
    340:       const PetscInt newp = vStartNew + (vEnd - vStart) + (c - cStart);

    342:       DMPlexSetSupportSize(rdm, newp, 2);
    343:     }
    344:     break;
    345:   case REFINER_SIMPLEX_2D:
    346:     /* All cells have 3 faces */
    347:     for (c = cStart; c < cEnd; ++c) {
    348:       for (r = 0; r < 4; ++r) {
    349:         const PetscInt newp = (c - cStart)*4 + r;

    351:         DMPlexSetConeSize(rdm, newp, 3);
    352:       }
    353:     }
    354:     /* Split faces have 2 vertices and the same cells as the parent */
    355:     for (f = fStart; f < fEnd; ++f) {
    356:       for (r = 0; r < 2; ++r) {
    357:         const PetscInt newp = fStartNew + (f - fStart)*2 + r;
    358:         PetscInt       size;

    360:         DMPlexSetConeSize(rdm, newp, 2);
    361:         DMPlexGetSupportSize(dm, f, &size);
    362:         DMPlexSetSupportSize(rdm, newp, size);
    363:       }
    364:     }
    365:     /* Interior faces have 2 vertices and 2 cells */
    366:     for (c = cStart; c < cEnd; ++c) {
    367:       for (r = 0; r < 3; ++r) {
    368:         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*3 + r;

    370:         DMPlexSetConeSize(rdm, newp, 2);
    371:         DMPlexSetSupportSize(rdm, newp, 2);
    372:       }
    373:     }
    374:     /* Old vertices have identical supports */
    375:     for (v = vStart; v < vEnd; ++v) {
    376:       const PetscInt newp = vStartNew + (v - vStart);
    377:       PetscInt       size;

    379:       DMPlexGetSupportSize(dm, v, &size);
    380:       DMPlexSetSupportSize(rdm, newp, size);
    381:     }
    382:     /* Face vertices have 2 + cells*2 supports */
    383:     for (f = fStart; f < fEnd; ++f) {
    384:       const PetscInt newp = vStartNew + (vEnd - vStart) + (f - fStart);
    385:       PetscInt       size;

    387:       DMPlexGetSupportSize(dm, f, &size);
    388:       DMPlexSetSupportSize(rdm, newp, 2 + size*2);
    389:     }
    390:     break;
    391:   case REFINER_HEX_2D:
    392:     /* All cells have 4 faces */
    393:     for (c = cStart; c < cEnd; ++c) {
    394:       for (r = 0; r < 4; ++r) {
    395:         const PetscInt newp = cStartNew + (c - cStart)*4 + r;

    397:         DMPlexSetConeSize(rdm, newp, 4);
    398:       }
    399:     }
    400:     /* Split faces have 2 vertices and the same cells as the parent */
    401:     for (f = fStart; f < fEnd; ++f) {
    402:       for (r = 0; r < 2; ++r) {
    403:         const PetscInt newp = fStartNew + (f - fStart)*2 + r;
    404:         PetscInt       size;

    406:         DMPlexSetConeSize(rdm, newp, 2);
    407:         DMPlexGetSupportSize(dm, f, &size);
    408:         DMPlexSetSupportSize(rdm, newp, size);
    409:       }
    410:     }
    411:     /* Interior faces have 2 vertices and 2 cells */
    412:     for (c = cStart; c < cEnd; ++c) {
    413:       for (r = 0; r < 4; ++r) {
    414:         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*4 + r;

    416:         DMPlexSetConeSize(rdm, newp, 2);
    417:         DMPlexSetSupportSize(rdm, newp, 2);
    418:       }
    419:     }
    420:     /* Old vertices have identical supports */
    421:     for (v = vStart; v < vEnd; ++v) {
    422:       const PetscInt newp = vStartNew + (v - vStart);
    423:       PetscInt       size;

    425:       DMPlexGetSupportSize(dm, v, &size);
    426:       DMPlexSetSupportSize(rdm, newp, size);
    427:     }
    428:     /* Face vertices have 2 + cells supports */
    429:     for (f = fStart; f < fEnd; ++f) {
    430:       const PetscInt newp = vStartNew + (vEnd - vStart) + (f - fStart);
    431:       PetscInt       size;

    433:       DMPlexGetSupportSize(dm, f, &size);
    434:       DMPlexSetSupportSize(rdm, newp, 2 + size);
    435:     }
    436:     /* Cell vertices have 4 supports */
    437:     for (c = cStart; c < cEnd; ++c) {
    438:       const PetscInt newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (c - cStart);

    440:       DMPlexSetSupportSize(rdm, newp, 4);
    441:     }
    442:     break;
    443:   case REFINER_HYBRID_SIMPLEX_2D:
    444:     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
    445:     cMax = PetscMin(cEnd, cMax);
    446:     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
    447:     fMax = PetscMin(fEnd, fMax);
    448:     DMPlexSetHybridBounds(rdm, cStartNew + (cMax - cStart)*4, fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3, PETSC_DETERMINE, PETSC_DETERMINE);
    449:     /* Interior cells have 3 faces */
    450:     for (c = cStart; c < cMax; ++c) {
    451:       for (r = 0; r < 4; ++r) {
    452:         const PetscInt newp = cStartNew + (c - cStart)*4 + r;

    454:         DMPlexSetConeSize(rdm, newp, 3);
    455:       }
    456:     }
    457:     /* Hybrid cells have 4 faces */
    458:     for (c = cMax; c < cEnd; ++c) {
    459:       for (r = 0; r < 2; ++r) {
    460:         const PetscInt newp = cStartNew + (cMax - cStart)*4 + (c - cMax)*2 + r;

    462:         DMPlexSetConeSize(rdm, newp, 4);
    463:       }
    464:     }
    465:     /* Interior split faces have 2 vertices and the same cells as the parent */
    466:     for (f = fStart; f < fMax; ++f) {
    467:       for (r = 0; r < 2; ++r) {
    468:         const PetscInt newp = fStartNew + (f - fStart)*2 + r;
    469:         PetscInt       size;

    471:         DMPlexSetConeSize(rdm, newp, 2);
    472:         DMPlexGetSupportSize(dm, f, &size);
    473:         DMPlexSetSupportSize(rdm, newp, size);
    474:       }
    475:     }
    476:     /* Interior cell faces have 2 vertices and 2 cells */
    477:     for (c = cStart; c < cMax; ++c) {
    478:       for (r = 0; r < 3; ++r) {
    479:         const PetscInt newp = fStartNew + (fMax - fStart)*2 + (c - cStart)*3 + r;

    481:         DMPlexSetConeSize(rdm, newp, 2);
    482:         DMPlexSetSupportSize(rdm, newp, 2);
    483:       }
    484:     }
    485:     /* Hybrid faces have 2 vertices and the same cells */
    486:     for (f = fMax; f < fEnd; ++f) {
    487:       const PetscInt newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (f - fMax);
    488:       PetscInt       size;

    490:       DMPlexSetConeSize(rdm, newp, 2);
    491:       DMPlexGetSupportSize(dm, f, &size);
    492:       DMPlexSetSupportSize(rdm, newp, size);
    493:     }
    494:     /* Hybrid cell faces have 2 vertices and 2 cells */
    495:     for (c = cMax; c < cEnd; ++c) {
    496:       const PetscInt newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (fEnd - fMax) + (c - cMax);

    498:       DMPlexSetConeSize(rdm, newp, 2);
    499:       DMPlexSetSupportSize(rdm, newp, 2);
    500:     }
    501:     /* Old vertices have identical supports */
    502:     for (v = vStart; v < vEnd; ++v) {
    503:       const PetscInt newp = vStartNew + (v - vStart);
    504:       PetscInt       size;

    506:       DMPlexGetSupportSize(dm, v, &size);
    507:       DMPlexSetSupportSize(rdm, newp, size);
    508:     }
    509:     /* Face vertices have 2 + (2 interior, 1 hybrid) supports */
    510:     for (f = fStart; f < fMax; ++f) {
    511:       const PetscInt newp = vStartNew + (vEnd - vStart) + (f - fStart);
    512:       const PetscInt *support;
    513:       PetscInt       size, newSize = 2, s;

    515:       DMPlexGetSupportSize(dm, f, &size);
    516:       DMPlexGetSupport(dm, f, &support);
    517:       for (s = 0; s < size; ++s) {
    518:         if (support[s] >= cMax) newSize += 1;
    519:         else newSize += 2;
    520:       }
    521:       DMPlexSetSupportSize(rdm, newp, newSize);
    522:     }
    523:     break;
    524:   case REFINER_HYBRID_HEX_2D:
    525:     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
    526:     cMax = PetscMin(cEnd, cMax);
    527:     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
    528:     fMax = PetscMin(fEnd, fMax);
    529:     DMPlexSetHybridBounds(rdm, cStartNew + (cMax - cStart)*4, fStartNew + (fMax - fStart)*2 + (cMax - cStart)*4, PETSC_DETERMINE, PETSC_DETERMINE);
    530:     /* Interior cells have 4 faces */
    531:     for (c = cStart; c < cMax; ++c) {
    532:       for (r = 0; r < 4; ++r) {
    533:         const PetscInt newp = cStartNew + (c - cStart)*4 + r;

    535:         DMPlexSetConeSize(rdm, newp, 4);
    536:       }
    537:     }
    538:     /* Hybrid cells have 4 faces */
    539:     for (c = cMax; c < cEnd; ++c) {
    540:       for (r = 0; r < 2; ++r) {
    541:         const PetscInt newp = cStartNew + (cMax - cStart)*4 + (c - cMax)*2 + r;

    543:         DMPlexSetConeSize(rdm, newp, 4);
    544:       }
    545:     }
    546:     /* Interior split faces have 2 vertices and the same cells as the parent */
    547:     for (f = fStart; f < fMax; ++f) {
    548:       for (r = 0; r < 2; ++r) {
    549:         const PetscInt newp = fStartNew + (f - fStart)*2 + r;
    550:         PetscInt       size;

    552:         DMPlexSetConeSize(rdm, newp, 2);
    553:         DMPlexGetSupportSize(dm, f, &size);
    554:         DMPlexSetSupportSize(rdm, newp, size);
    555:       }
    556:     }
    557:     /* Interior cell faces have 2 vertices and 2 cells */
    558:     for (c = cStart; c < cMax; ++c) {
    559:       for (r = 0; r < 4; ++r) {
    560:         const PetscInt newp = fStartNew + (fMax - fStart)*2 + (c - cStart)*4 + r;

    562:         DMPlexSetConeSize(rdm, newp, 2);
    563:         DMPlexSetSupportSize(rdm, newp, 2);
    564:       }
    565:     }
    566:     /* Hybrid faces have 2 vertices and the same cells */
    567:     for (f = fMax; f < fEnd; ++f) {
    568:       const PetscInt newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*4 + (f - fMax);
    569:       PetscInt       size;

    571:       DMPlexSetConeSize(rdm, newp, 2);
    572:       DMPlexGetSupportSize(dm, f, &size);
    573:       DMPlexSetSupportSize(rdm, newp, size);
    574:     }
    575:     /* Hybrid cell faces have 2 vertices and 2 cells */
    576:     for (c = cMax; c < cEnd; ++c) {
    577:       const PetscInt newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*4 + (fEnd - fMax) + (c - cMax);

    579:       DMPlexSetConeSize(rdm, newp, 2);
    580:       DMPlexSetSupportSize(rdm, newp, 2);
    581:     }
    582:     /* Old vertices have identical supports */
    583:     for (v = vStart; v < vEnd; ++v) {
    584:       const PetscInt newp = vStartNew + (v - vStart);
    585:       PetscInt       size;

    587:       DMPlexGetSupportSize(dm, v, &size);
    588:       DMPlexSetSupportSize(rdm, newp, size);
    589:     }
    590:     /* Face vertices have 2 + cells supports */
    591:     for (f = fStart; f < fMax; ++f) {
    592:       const PetscInt newp = vStartNew + (vEnd - vStart) + (f - fStart);
    593:       PetscInt       size;

    595:       DMPlexGetSupportSize(dm, f, &size);
    596:       DMPlexSetSupportSize(rdm, newp, 2 + size);
    597:     }
    598:     /* Cell vertices have 4 supports */
    599:     for (c = cStart; c < cMax; ++c) {
    600:       const PetscInt newp = vStartNew + (vEnd - vStart) + (fMax - fStart) + (c - cStart);

    602:       DMPlexSetSupportSize(rdm, newp, 4);
    603:     }
    604:     break;
    605:   case REFINER_SIMPLEX_3D:
    606:     /* All cells have 4 faces */
    607:     for (c = cStart; c < cEnd; ++c) {
    608:       for (r = 0; r < 8; ++r) {
    609:         const PetscInt newp = cStartNew + (c - cStart)*8 + r;

    611:         DMPlexSetConeSize(rdm, newp, 4);
    612:       }
    613:     }
    614:     /* Split faces have 3 edges and the same cells as the parent */
    615:     for (f = fStart; f < fEnd; ++f) {
    616:       for (r = 0; r < 4; ++r) {
    617:         const PetscInt newp = fStartNew + (f - fStart)*4 + r;
    618:         PetscInt       size;

    620:         DMPlexSetConeSize(rdm, newp, 3);
    621:         DMPlexGetSupportSize(dm, f, &size);
    622:         DMPlexSetSupportSize(rdm, newp, size);
    623:       }
    624:     }
    625:     /* Interior cell faces have 3 edges and 2 cells */
    626:     for (c = cStart; c < cEnd; ++c) {
    627:       for (r = 0; r < 8; ++r) {
    628:         const PetscInt newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*8 + r;

    630:         DMPlexSetConeSize(rdm, newp, 3);
    631:         DMPlexSetSupportSize(rdm, newp, 2);
    632:       }
    633:     }
    634:     /* Split edges have 2 vertices and the same faces */
    635:     for (e = eStart; e < eEnd; ++e) {
    636:       for (r = 0; r < 2; ++r) {
    637:         const PetscInt newp = eStartNew + (e - eStart)*2 + r;
    638:         PetscInt       size;

    640:         DMPlexSetConeSize(rdm, newp, 2);
    641:         DMPlexGetSupportSize(dm, e, &size);
    642:         DMPlexSetSupportSize(rdm, newp, size);
    643:       }
    644:     }
    645:     /* Face edges have 2 vertices and 2+cells*(1/2) faces */
    646:     for (f = fStart; f < fEnd; ++f) {
    647:       for (r = 0; r < 3; ++r) {
    648:         const PetscInt  newp = eStartNew + (eEnd - eStart)*2 + (f - fStart)*3 + r;
    649:         const PetscInt *cone, *ornt, *support, eint[4] = {1, 0, 2, 0};
    650:         PetscInt        coneSize, c, supportSize, s, er, intFaces = 0;

    652:         DMPlexSetConeSize(rdm, newp, 2);
    653:         DMPlexGetSupportSize(dm, f, &supportSize);
    654:         DMPlexGetSupport(dm, f, &support);
    655:         for (s = 0; s < supportSize; ++s) {
    656:           DMPlexGetConeSize(dm, support[s], &coneSize);
    657:           DMPlexGetCone(dm, support[s], &cone);
    658:           DMPlexGetConeOrientation(dm, support[s], &ornt);
    659:           for (c = 0; c < coneSize; ++c) {if (cone[c] == f) break;}
    660:           /* Here we want to determine whether edge newp contains a vertex which is part of the cross-tet edge */
    661:           er = GetTetSomethingInverse_Static(ornt[c], r);
    662:           if (er == eint[c]) {
    663:             intFaces += 1;
    664:           } else {
    665:             intFaces += 2;
    666:           }
    667:         }
    668:         DMPlexSetSupportSize(rdm, newp, 2+intFaces);
    669:       }
    670:     }
    671:     /* Interior cell edges have 2 vertices and 4 faces */
    672:     for (c = cStart; c < cEnd; ++c) {
    673:       const PetscInt newp = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart);

    675:       DMPlexSetConeSize(rdm, newp, 2);
    676:       DMPlexSetSupportSize(rdm, newp, 4);
    677:     }
    678:     /* Old vertices have identical supports */
    679:     for (v = vStart; v < vEnd; ++v) {
    680:       const PetscInt newp = vStartNew + (v - vStart);
    681:       PetscInt       size;

    683:       DMPlexGetSupportSize(dm, v, &size);
    684:       DMPlexSetSupportSize(rdm, newp, size);
    685:     }
    686:     /* Edge vertices have 2 + faces*2 + cells*0/1 supports */
    687:     for (e = eStart; e < eEnd; ++e) {
    688:       const PetscInt newp = vStartNew + (vEnd - vStart) + (e - eStart);
    689:       PetscInt       size, *star = NULL, starSize, s, cellSize = 0;

    691:       DMPlexGetSupportSize(dm, e, &size);
    692:       DMPlexGetTransitiveClosure(dm, e, PETSC_FALSE, &starSize, &star);
    693:       for (s = 0; s < starSize*2; s += 2) {
    694:         const PetscInt *cone, *ornt;
    695:         PetscInt        e01, e23;

    697:         if ((star[s] >= cStart) && (star[s] < cEnd)) {
    698:           /* Check edge 0-1 */
    699:           DMPlexGetCone(dm, star[s], &cone);
    700:           DMPlexGetConeOrientation(dm, star[s], &ornt);
    701:           DMPlexGetCone(dm, cone[0], &cone);
    702:           e01  = cone[GetTriEdge_Static(ornt[0], 0)];
    703:           /* Check edge 2-3 */
    704:           DMPlexGetCone(dm, star[s], &cone);
    705:           DMPlexGetConeOrientation(dm, star[s], &ornt);
    706:           DMPlexGetCone(dm, cone[2], &cone);
    707:           e23  = cone[GetTriEdge_Static(ornt[2], 1)];
    708:           if ((e01 == e) || (e23 == e)) ++cellSize;
    709:         }
    710:       }
    711:       DMPlexRestoreTransitiveClosure(dm, e, PETSC_FALSE, &starSize, &star);
    712:       DMPlexSetSupportSize(rdm, newp, 2 + size*2 + cellSize);
    713:     }
    714:     break;
    715:   case REFINER_HYBRID_SIMPLEX_3D:
    716:     DMPlexSetHybridBounds(rdm, cStartNew + 8*(cMax-cStart), fStartNew + 4*(fMax - fStart) + 8*(cMax - cStart),
    717:                                  eStartNew + 2*(eMax - eStart) + 3*(fMax - fStart) + (cMax - cStart), PETSC_DETERMINE);
    718:     /* Interior cells have 4 faces */
    719:     for (c = cStart; c < cMax; ++c) {
    720:       for (r = 0; r < 8; ++r) {
    721:         const PetscInt newp = cStartNew + (c - cStart)*8 + r;

    723:         DMPlexSetConeSize(rdm, newp, 4);
    724:       }
    725:     }
    726:     /* Hybrid cells have 5 faces */
    727:     for (c = cMax; c < cEnd; ++c) {
    728:       for (r = 0; r < 4; ++r) {
    729:         const PetscInt newp = cStartNew + (cMax - cStart)*8 + (c - cMax)*4 + r;

    731:         DMPlexSetConeSize(rdm, newp, 5);
    732:       }
    733:     }
    734:     /* Interior split faces have 3 edges and the same cells as the parent */
    735:     for (f = fStart; f < fMax; ++f) {
    736:       for (r = 0; r < 4; ++r) {
    737:         const PetscInt newp = fStartNew + (f - fStart)*4 + r;
    738:         PetscInt       size;

    740:         DMPlexSetConeSize(rdm, newp, 3);
    741:         DMPlexGetSupportSize(dm, f, &size);
    742:         DMPlexSetSupportSize(rdm, newp, size);
    743:       }
    744:     }
    745:     /* Interior cell faces have 3 edges and 2 cells */
    746:     for (c = cStart; c < cMax; ++c) {
    747:       for (r = 0; r < 8; ++r) {
    748:         const PetscInt newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*8 + r;

    750:         DMPlexSetConeSize(rdm, newp, 3);
    751:         DMPlexSetSupportSize(rdm, newp, 2);
    752:       }
    753:     }
    754:     /* Hybrid split faces have 4 edges and the same cells as the parent */
    755:     for (f = fMax; f < fEnd; ++f) {
    756:       for (r = 0; r < 2; ++r) {
    757:         const PetscInt newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (f - fMax)*2 + r;
    758:         PetscInt       size;

    760:         DMPlexSetConeSize(rdm, newp, 4);
    761:         DMPlexGetSupportSize(dm, f, &size);
    762:         DMPlexSetSupportSize(rdm, newp, size);
    763:       }
    764:     }
    765:     /* Hybrid cells faces have 4 edges and 2 cells */
    766:     for (c = cMax; c < cEnd; ++c) {
    767:       for (r = 0; r < 3; ++r) {
    768:         const PetscInt newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (c - cMax)*3 + r;

    770:         DMPlexSetConeSize(rdm, newp, 4);
    771:         DMPlexSetSupportSize(rdm, newp, 2);
    772:       }
    773:     }
    774:     /* Interior split edges have 2 vertices and the same faces */
    775:     for (e = eStart; e < eMax; ++e) {
    776:       for (r = 0; r < 2; ++r) {
    777:         const PetscInt newp = eStartNew + (e - eStart)*2 + r;
    778:         PetscInt       size;

    780:         DMPlexSetConeSize(rdm, newp, 2);
    781:         DMPlexGetSupportSize(dm, e, &size);
    782:         DMPlexSetSupportSize(rdm, newp, size);
    783:       }
    784:     }
    785:     /* Interior face edges have 2 vertices and 2+cells*(1/2) faces */
    786:     for (f = fStart; f < fMax; ++f) {
    787:       for (r = 0; r < 3; ++r) {
    788:         const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (f - fStart)*3 + r;
    789:         const PetscInt *cone, *ornt, *support, eint[4] = {1, 0, 2, 0};
    790:         PetscInt        coneSize, c, supportSize, s, er, intFaces = 0;

    792:         DMPlexSetConeSize(rdm, newp, 2);
    793:         DMPlexGetSupportSize(dm, f, &supportSize);
    794:         DMPlexGetSupport(dm, f, &support);
    795:         for (s = 0; s < supportSize; ++s) {
    796:           DMPlexGetConeSize(dm, support[s], &coneSize);
    797:           DMPlexGetCone(dm, support[s], &cone);
    798:           DMPlexGetConeOrientation(dm, support[s], &ornt);
    799:           for (c = 0; c < coneSize; ++c) {if (cone[c] == f) break;}
    800:           if (support[s] < cMax) {
    801:             /* Here we want to determine whether edge newp contains a vertex which is part of the cross-tet edge */
    802:             er = GetTetSomethingInverse_Static(ornt[c], r);
    803:             if (er == eint[c]) {
    804:               intFaces += 1;
    805:             } else {
    806:               intFaces += 2;
    807:             }
    808:           } else {
    809:             intFaces += 1;
    810:           }
    811:         }
    812:         DMPlexSetSupportSize(rdm, newp, 2+intFaces);
    813:       }
    814:     }
    815:     /* Interior cell edges have 2 vertices and 4 faces */
    816:     for (c = cStart; c < cMax; ++c) {
    817:       const PetscInt newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart);

    819:       DMPlexSetConeSize(rdm, newp, 2);
    820:       DMPlexSetSupportSize(rdm, newp, 4);
    821:     }
    822:     /* Hybrid edges have 2 vertices and the same faces */
    823:     for (e = eMax; e < eEnd; ++e) {
    824:       const PetscInt newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (e - eMax);
    825:       PetscInt       size;

    827:       DMPlexSetConeSize(rdm, newp, 2);
    828:       DMPlexGetSupportSize(dm, e, &size);
    829:       DMPlexSetSupportSize(rdm, newp, size);
    830:     }
    831:     /* Hybrid face edges have 2 vertices and 2+2*cells faces */
    832:     for (f = fMax; f < fEnd; ++f) {
    833:       const PetscInt newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (eEnd - eMax) + (f - fMax);
    834:       PetscInt       size;

    836:       DMPlexSetConeSize(rdm, newp, 2);
    837:       DMPlexGetSupportSize(dm, f, &size);
    838:       DMPlexSetSupportSize(rdm, newp, 2+2*size);
    839:     }
    840:     /* Interior vertices have identical supports */
    841:     for (v = vStart; v < vEnd; ++v) {
    842:       const PetscInt newp = vStartNew + (v - vStart);
    843:       PetscInt       size;

    845:       DMPlexGetSupportSize(dm, v, &size);
    846:       DMPlexSetSupportSize(rdm, newp, size);
    847:     }
    848:     /* Interior edge vertices have 2 + interior face*2 + hybrid face + cells*0/1 supports */
    849:     for (e = eStart; e < eMax; ++e) {
    850:       const PetscInt  newp = vStartNew + (vEnd - vStart) + (e - eStart);
    851:       const PetscInt *support;
    852:       PetscInt        size, *star = NULL, starSize, s, faceSize = 0, cellSize = 0;

    854:       DMPlexGetSupportSize(dm, e, &size);
    855:       DMPlexGetSupport(dm, e, &support);
    856:       for (s = 0; s < size; ++s) {
    857:         if (support[s] < fMax) faceSize += 2;
    858:         else                   faceSize += 1;
    859:       }
    860:       DMPlexGetTransitiveClosure(dm, e, PETSC_FALSE, &starSize, &star);
    861:       for (s = 0; s < starSize*2; s += 2) {
    862:         const PetscInt *cone, *ornt;
    863:         PetscInt        e01, e23;

    865:         if ((star[s] >= cStart) && (star[s] < cMax)) {
    866:           /* Check edge 0-1 */
    867:           DMPlexGetCone(dm, star[s], &cone);
    868:           DMPlexGetConeOrientation(dm, star[s], &ornt);
    869:           DMPlexGetCone(dm, cone[0], &cone);
    870:           e01  = cone[GetTriEdge_Static(ornt[0], 0)];
    871:           /* Check edge 2-3 */
    872:           DMPlexGetCone(dm, star[s], &cone);
    873:           DMPlexGetConeOrientation(dm, star[s], &ornt);
    874:           DMPlexGetCone(dm, cone[2], &cone);
    875:           e23  = cone[GetTriEdge_Static(ornt[2], 1)];
    876:           if ((e01 == e) || (e23 == e)) ++cellSize;
    877:         }
    878:       }
    879:       DMPlexRestoreTransitiveClosure(dm, e, PETSC_FALSE, &starSize, &star);
    880:       DMPlexSetSupportSize(rdm, newp, 2 + faceSize + cellSize);
    881:     }
    882:     break;
    883:   case REFINER_HEX_3D:
    884:     /* All cells have 6 faces */
    885:     for (c = cStart; c < cEnd; ++c) {
    886:       for (r = 0; r < 8; ++r) {
    887:         const PetscInt newp = (c - cStart)*8 + r;

    889:         DMPlexSetConeSize(rdm, newp, 6);
    890:       }
    891:     }
    892:     /* Split faces have 4 edges and the same cells as the parent */
    893:     for (f = fStart; f < fEnd; ++f) {
    894:       for (r = 0; r < 4; ++r) {
    895:         const PetscInt newp = fStartNew + (f - fStart)*4 + r;
    896:         PetscInt       size;

    898:         DMPlexSetConeSize(rdm, newp, 4);
    899:         DMPlexGetSupportSize(dm, f, &size);
    900:         DMPlexSetSupportSize(rdm, newp, size);
    901:       }
    902:     }
    903:     /* Interior faces have 4 edges and 2 cells */
    904:     for (c = cStart; c < cEnd; ++c) {
    905:       for (r = 0; r < 12; ++r) {
    906:         const PetscInt newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + r;

    908:         DMPlexSetConeSize(rdm, newp, 4);
    909:         DMPlexSetSupportSize(rdm, newp, 2);
    910:       }
    911:     }
    912:     /* Split edges have 2 vertices and the same faces as the parent */
    913:     for (e = eStart; e < eEnd; ++e) {
    914:       for (r = 0; r < 2; ++r) {
    915:         const PetscInt newp = eStartNew + (e - eStart)*2 + r;
    916:         PetscInt       size;

    918:         DMPlexSetConeSize(rdm, newp, 2);
    919:         DMPlexGetSupportSize(dm, e, &size);
    920:         DMPlexSetSupportSize(rdm, newp, size);
    921:       }
    922:     }
    923:     /* Face edges have 2 vertices and 2+cells faces */
    924:     for (f = fStart; f < fEnd; ++f) {
    925:       for (r = 0; r < 4; ++r) {
    926:         const PetscInt newp = eStartNew + (eEnd - eStart)*2 + (f - fStart)*4 + r;
    927:         PetscInt       size;

    929:         DMPlexSetConeSize(rdm, newp, 2);
    930:         DMPlexGetSupportSize(dm, f, &size);
    931:         DMPlexSetSupportSize(rdm, newp, 2+size);
    932:       }
    933:     }
    934:     /* Cell edges have 2 vertices and 4 faces */
    935:     for (c = cStart; c < cEnd; ++c) {
    936:       for (r = 0; r < 6; ++r) {
    937:         const PetscInt newp = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*4 + (c - cStart)*6 + r;

    939:         DMPlexSetConeSize(rdm, newp, 2);
    940:         DMPlexSetSupportSize(rdm, newp, 4);
    941:       }
    942:     }
    943:     /* Old vertices have identical supports */
    944:     for (v = vStart; v < vEnd; ++v) {
    945:       const PetscInt newp = vStartNew + (v - vStart);
    946:       PetscInt       size;

    948:       DMPlexGetSupportSize(dm, v, &size);
    949:       DMPlexSetSupportSize(rdm, newp, size);
    950:     }
    951:     /* Edge vertices have 2 + faces supports */
    952:     for (e = eStart; e < eEnd; ++e) {
    953:       const PetscInt newp = vStartNew + (vEnd - vStart) + (e - eStart);
    954:       PetscInt       size;

    956:       DMPlexGetSupportSize(dm, e, &size);
    957:       DMPlexSetSupportSize(rdm, newp, 2 + size);
    958:     }
    959:     /* Face vertices have 4 + cells supports */
    960:     for (f = fStart; f < fEnd; ++f) {
    961:       const PetscInt newp = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (f - fStart);
    962:       PetscInt       size;

    964:       DMPlexGetSupportSize(dm, f, &size);
    965:       DMPlexSetSupportSize(rdm, newp, 4 + size);
    966:     }
    967:     /* Cell vertices have 6 supports */
    968:     for (c = cStart; c < cEnd; ++c) {
    969:       const PetscInt newp = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (fEnd - fStart) + (c - cStart);

    971:       DMPlexSetSupportSize(rdm, newp, 6);
    972:     }
    973:     break;
    974:   case REFINER_HYBRID_HEX_3D:
    975:     DMPlexSetHybridBounds(rdm, cStartNew + 8*(cMax-cStart), fStartNew + 4*(fMax - fStart) + 12*(cMax - cStart),
    976:                                  eStartNew + 2*(eMax - eStart) + 4*(fMax - fStart) + 6*(cMax - cStart), PETSC_DETERMINE);
    977:     /* Interior cells have 6 faces */
    978:     for (c = cStart; c < cMax; ++c) {
    979:       for (r = 0; r < 8; ++r) {
    980:         const PetscInt newp = cStartNew + (c - cStart)*8 + r;

    982:         DMPlexSetConeSize(rdm, newp, 6);
    983:       }
    984:     }
    985:     /* Hybrid cells have 6 faces */
    986:     for (c = cMax; c < cEnd; ++c) {
    987:       for (r = 0; r < 4; ++r) {
    988:         const PetscInt newp = cStartNew + (cMax - cStart)*8 + (c - cMax)*4 + r;

    990:         DMPlexSetConeSize(rdm, newp, 6);
    991:       }
    992:     }
    993:     /* Interior split faces have 4 edges and the same cells as the parent */
    994:     for (f = fStart; f < fMax; ++f) {
    995:       for (r = 0; r < 4; ++r) {
    996:         const PetscInt newp = fStartNew + (f - fStart)*4 + r;
    997:         PetscInt       size;

    999:         DMPlexSetConeSize(rdm, newp, 4);
    1000:         DMPlexGetSupportSize(dm, f, &size);
    1001:         DMPlexSetSupportSize(rdm, newp, size);
    1002:       }
    1003:     }
    1004:     /* Interior cell faces have 4 edges and 2 cells */
    1005:     for (c = cStart; c < cMax; ++c) {
    1006:       for (r = 0; r < 12; ++r) {
    1007:         const PetscInt newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + r;

    1009:         DMPlexSetConeSize(rdm, newp, 4);
    1010:         DMPlexSetSupportSize(rdm, newp, 2);
    1011:       }
    1012:     }
    1013:     /* Hybrid split faces have 4 edges and the same cells as the parent */
    1014:     for (f = fMax; f < fEnd; ++f) {
    1015:       for (r = 0; r < 2; ++r) {
    1016:         const PetscInt newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (f - fMax)*2 + r;
    1017:         PetscInt       size;

    1019:         DMPlexSetConeSize(rdm, newp, 4);
    1020:         DMPlexGetSupportSize(dm, f, &size);
    1021:         DMPlexSetSupportSize(rdm, newp, size);
    1022:       }
    1023:     }
    1024:     /* Hybrid cells faces have 4 edges and 2 cells */
    1025:     for (c = cMax; c < cEnd; ++c) {
    1026:       for (r = 0; r < 4; ++r) {
    1027:         const PetscInt newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd - fMax)*2 + (c - cMax)*4 + r;

    1029:         DMPlexSetConeSize(rdm, newp, 4);
    1030:         DMPlexSetSupportSize(rdm, newp, 2);
    1031:       }
    1032:     }
    1033:     /* Interior split edges have 2 vertices and the same faces as the parent */
    1034:     for (e = eStart; e < eMax; ++e) {
    1035:       for (r = 0; r < 2; ++r) {
    1036:         const PetscInt newp = eStartNew + (e - eStart)*2 + r;
    1037:         PetscInt       size;

    1039:         DMPlexSetConeSize(rdm, newp, 2);
    1040:         DMPlexGetSupportSize(dm, e, &size);
    1041:         DMPlexSetSupportSize(rdm, newp, size);
    1042:       }
    1043:     }
    1044:     /* Interior face edges have 2 vertices and 2+cells faces */
    1045:     for (f = fStart; f < fMax; ++f) {
    1046:       for (r = 0; r < 4; ++r) {
    1047:         const PetscInt newp = eStartNew + (eMax - eStart)*2 + (f - fStart)*4 + r;
    1048:         PetscInt       size;

    1050:         DMPlexSetConeSize(rdm, newp, 2);
    1051:         DMPlexGetSupportSize(dm, f, &size);
    1052:         DMPlexSetSupportSize(rdm, newp, 2+size);
    1053:       }
    1054:     }
    1055:     /* Interior cell edges have 2 vertices and 4 faces */
    1056:     for (c = cStart; c < cMax; ++c) {
    1057:       for (r = 0; r < 6; ++r) {
    1058:         const PetscInt newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (c - cStart)*6 + r;

    1060:         DMPlexSetConeSize(rdm, newp, 2);
    1061:         DMPlexSetSupportSize(rdm, newp, 4);
    1062:       }
    1063:     }
    1064:     /* Hybrid edges have 2 vertices and the same faces */
    1065:     for (e = eMax; e < eEnd; ++e) {
    1066:       const PetscInt newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (e - eMax);
    1067:       PetscInt       size;

    1069:       DMPlexSetConeSize(rdm, newp, 2);
    1070:       DMPlexGetSupportSize(dm, e, &size);
    1071:       DMPlexSetSupportSize(rdm, newp, size);
    1072:     }
    1073:     /* Hybrid face edges have 2 vertices and 2+cells faces */
    1074:     for (f = fMax; f < fEnd; ++f) {
    1075:       const PetscInt newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (eEnd - eMax) + (f - fMax);
    1076:       PetscInt       size;

    1078:       DMPlexSetConeSize(rdm, newp, 2);
    1079:       DMPlexGetSupportSize(dm, f, &size);
    1080:       DMPlexSetSupportSize(rdm, newp, 2+size);
    1081:     }
    1082:     /* Hybrid cell edges have 2 vertices and 4 faces */
    1083:     for (c = cMax; c < cEnd; ++c) {
    1084:       const PetscInt newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (eEnd - eMax) + (fEnd - fMax) + (c - cMax);

    1086:       DMPlexSetConeSize(rdm, newp, 2);
    1087:       DMPlexSetSupportSize(rdm, newp, 4);
    1088:     }
    1089:     /* Interior vertices have identical supports */
    1090:     for (v = vStart; v < vEnd; ++v) {
    1091:       const PetscInt newp = vStartNew + (v - vStart);
    1092:       PetscInt       size;

    1094:       DMPlexGetSupportSize(dm, v, &size);
    1095:       DMPlexSetSupportSize(rdm, newp, size);
    1096:     }
    1097:     /* Interior edge vertices have 2 + faces supports */
    1098:     for (e = eStart; e < eMax; ++e) {
    1099:       const PetscInt newp = vStartNew + (vEnd - vStart) + (e - eStart);
    1100:       PetscInt       size;

    1102:       DMPlexGetSupportSize(dm, e, &size);
    1103:       DMPlexSetSupportSize(rdm, newp, 2 + size);
    1104:     }
    1105:     /* Interior face vertices have 4 + cells supports */
    1106:     for (f = fStart; f < fMax; ++f) {
    1107:       const PetscInt newp = vStartNew + (vEnd - vStart) + (eMax - eStart) + (f - fStart);
    1108:       PetscInt       size;

    1110:       DMPlexGetSupportSize(dm, f, &size);
    1111:       DMPlexSetSupportSize(rdm, newp, 4 + size);
    1112:     }
    1113:     /* Interior cell vertices have 6 supports */
    1114:     for (c = cStart; c < cMax; ++c) {
    1115:       const PetscInt newp = vStartNew + (vEnd - vStart) + (eMax - eStart) + (fMax - fStart) + (c - cStart);

    1117:       DMPlexSetSupportSize(rdm, newp, 6);
    1118:     }
    1119:     break;
    1120:   default:
    1121:     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
    1122:   }
    1123:   return(0);
    1124: }

    1128: static PetscErrorCode CellRefinerSetCones(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
    1129: {
    1130:   const PetscInt *faces, cellInd[4] = {0, 1, 2, 3};
    1131:   PetscInt        cStart,    cEnd,    cMax,    vStart,    vEnd, vMax, fStart,    fEnd,    fMax,    eStart,    eEnd,    eMax;
    1132:   PetscInt        cStartNew, cEndNew, cMaxNew, vStartNew, vEndNew,    fStartNew, fEndNew, fMaxNew, eStartNew, eEndNew, eMaxNew;
    1133:   PetscInt        depth, maxSupportSize, *supportRef, c, f, e, v, r, p;
    1134:   PetscErrorCode  ierr;

    1137:   if (!refiner) return(0);
    1138:   DMPlexGetDepth(dm, &depth);
    1139:   DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);
    1140:   DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);
    1141:   DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);
    1142:   DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);
    1143:   DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);
    1144:   GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);
    1145:   GetDepthEnd_Private(depth, depthSize, &cEndNew, &fEndNew, &eEndNew, &vEndNew);
    1146:   switch (refiner) {
    1147:   case REFINER_SIMPLEX_1D:
    1148:     /* Max support size of refined mesh is 2 */
    1149:     PetscMalloc1(2, &supportRef);
    1150:     /* All cells have 2 vertices */
    1151:     for (c = cStart; c < cEnd; ++c) {
    1152:       const PetscInt  newv = vStartNew + (vEnd - vStart) + (c - cStart);

    1154:       for (r = 0; r < 2; ++r) {
    1155:         const PetscInt newp = cStartNew + (c - cStart)*2 + r;
    1156:         const PetscInt *cone;
    1157:         PetscInt        coneNew[2];

    1159:         DMPlexGetCone(dm, c, &cone);
    1160:         coneNew[0]       = vStartNew + (cone[0] - vStart);
    1161:         coneNew[1]       = vStartNew + (cone[1] - vStart);
    1162:         coneNew[(r+1)%2] = newv;
    1163:         DMPlexSetCone(rdm, newp, coneNew);
    1164: #if 1
    1165:         if ((newp < cStartNew) || (newp >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp, cStartNew, cEndNew);
    1166:         for (p = 0; p < 2; ++p) {
    1167:           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
    1168:         }
    1169: #endif
    1170:       }
    1171:     }
    1172:     /* Old vertices have identical supports */
    1173:     for (v = vStart; v < vEnd; ++v) {
    1174:       const PetscInt  newp = vStartNew + (v - vStart);
    1175:       const PetscInt *support, *cone;
    1176:       PetscInt        size, s;

    1178:       DMPlexGetSupportSize(dm, v, &size);
    1179:       DMPlexGetSupport(dm, v, &support);
    1180:       for (s = 0; s < size; ++s) {
    1181:         PetscInt r = 0;

    1183:         DMPlexGetCone(dm, support[s], &cone);
    1184:         if (cone[1] == v) r = 1;
    1185:         supportRef[s] = cStartNew + (support[s] - cStart)*2 + r;
    1186:       }
    1187:       DMPlexSetSupport(rdm, newp, supportRef);
    1188: #if 1
    1189:       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
    1190:       for (p = 0; p < size; ++p) {
    1191:         if ((supportRef[p] < cStartNew) || (supportRef[p] >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportRef[p], cStartNew, cEndNew);
    1192:       }
    1193: #endif
    1194:     }
    1195:     /* Cell vertices have support of 2 cells */
    1196:     for (c = cStart; c < cEnd; ++c) {
    1197:       const PetscInt  newp = vStartNew + (vEnd - vStart) + (c - cStart);

    1199:       supportRef[0] = cStartNew + (c - cStart)*2 + 0;
    1200:       supportRef[1] = cStartNew + (c - cStart)*2 + 1;
    1201:       DMPlexSetSupport(rdm, newp, supportRef);
    1202: #if 1
    1203:       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
    1204:       for (p = 0; p < 2; ++p) {
    1205:         if ((supportRef[p] < cStartNew) || (supportRef[p] >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportRef[p], cStartNew, cEndNew);
    1206:       }
    1207: #endif
    1208:     }
    1209:     PetscFree(supportRef);
    1210:     break;
    1211:   case REFINER_SIMPLEX_2D:
    1212:     /*
    1213:      2
    1214:      |\
    1215:      | \
    1216:      |  \
    1217:      |   \
    1218:      | C  \
    1219:      |     \
    1220:      |      \
    1221:      2---1---1
    1222:      |\  D  / \
    1223:      | 2   0   \
    1224:      |A \ /  B  \
    1225:      0---0-------1
    1226:      */
    1227:     /* All cells have 3 faces */
    1228:     for (c = cStart; c < cEnd; ++c) {
    1229:       const PetscInt  newp = cStartNew + (c - cStart)*4;
    1230:       const PetscInt *cone, *ornt;
    1231:       PetscInt        coneNew[3], orntNew[3];

    1233:       DMPlexGetCone(dm, c, &cone);
    1234:       DMPlexGetConeOrientation(dm, c, &ornt);
    1235:       /* A triangle */
    1236:       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
    1237:       orntNew[0] = ornt[0];
    1238:       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 2;
    1239:       orntNew[1] = -2;
    1240:       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
    1241:       orntNew[2] = ornt[2];
    1242:       DMPlexSetCone(rdm, newp+0, coneNew);
    1243:       DMPlexSetConeOrientation(rdm, newp+0, orntNew);
    1244: #if 1
    1245:       if ((newp+0 < cStartNew) || (newp+0 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+0, cStartNew, cEndNew);
    1246:       for (p = 0; p < 3; ++p) {
    1247:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
    1248:       }
    1249: #endif
    1250:       /* B triangle */
    1251:       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
    1252:       orntNew[0] = ornt[0];
    1253:       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
    1254:       orntNew[1] = ornt[1];
    1255:       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 0;
    1256:       orntNew[2] = -2;
    1257:       DMPlexSetCone(rdm, newp+1, coneNew);
    1258:       DMPlexSetConeOrientation(rdm, newp+1, orntNew);
    1259: #if 1
    1260:       if ((newp+1 < cStartNew) || (newp+1 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+1, cStartNew, cEndNew);
    1261:       for (p = 0; p < 3; ++p) {
    1262:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
    1263:       }
    1264: #endif
    1265:       /* C triangle */
    1266:       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 1;
    1267:       orntNew[0] = -2;
    1268:       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
    1269:       orntNew[1] = ornt[1];
    1270:       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
    1271:       orntNew[2] = ornt[2];
    1272:       DMPlexSetCone(rdm, newp+2, coneNew);
    1273:       DMPlexSetConeOrientation(rdm, newp+2, orntNew);
    1274: #if 1
    1275:       if ((newp+2 < cStartNew) || (newp+2 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+2, cStartNew, cEndNew);
    1276:       for (p = 0; p < 3; ++p) {
    1277:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
    1278:       }
    1279: #endif
    1280:       /* D triangle */
    1281:       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 0;
    1282:       orntNew[0] = 0;
    1283:       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 1;
    1284:       orntNew[1] = 0;
    1285:       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 2;
    1286:       orntNew[2] = 0;
    1287:       DMPlexSetCone(rdm, newp+3, coneNew);
    1288:       DMPlexSetConeOrientation(rdm, newp+3, orntNew);
    1289: #if 1
    1290:       if ((newp+3 < cStartNew) || (newp+3 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+3, cStartNew, cEndNew);
    1291:       for (p = 0; p < 3; ++p) {
    1292:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
    1293:       }
    1294: #endif
    1295:     }
    1296:     /* Split faces have 2 vertices and the same cells as the parent */
    1297:     DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);
    1298:     PetscMalloc1(2 + maxSupportSize*2, &supportRef);
    1299:     for (f = fStart; f < fEnd; ++f) {
    1300:       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);

    1302:       for (r = 0; r < 2; ++r) {
    1303:         const PetscInt  newp = fStartNew + (f - fStart)*2 + r;
    1304:         const PetscInt *cone, *ornt, *support;
    1305:         PetscInt        coneNew[2], coneSize, c, supportSize, s;

    1307:         DMPlexGetCone(dm, f, &cone);
    1308:         coneNew[0]       = vStartNew + (cone[0] - vStart);
    1309:         coneNew[1]       = vStartNew + (cone[1] - vStart);
    1310:         coneNew[(r+1)%2] = newv;
    1311:         DMPlexSetCone(rdm, newp, coneNew);
    1312: #if 1
    1313:         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
    1314:         for (p = 0; p < 2; ++p) {
    1315:           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
    1316:         }
    1317: #endif
    1318:         DMPlexGetSupportSize(dm, f, &supportSize);
    1319:         DMPlexGetSupport(dm, f, &support);
    1320:         for (s = 0; s < supportSize; ++s) {
    1321:           DMPlexGetConeSize(dm, support[s], &coneSize);
    1322:           DMPlexGetCone(dm, support[s], &cone);
    1323:           DMPlexGetConeOrientation(dm, support[s], &ornt);
    1324:           for (c = 0; c < coneSize; ++c) {
    1325:             if (cone[c] == f) break;
    1326:           }
    1327:           supportRef[s] = cStartNew + (support[s] - cStart)*4 + (ornt[c] < 0 ? (c+1-r)%3 : (c+r)%3);
    1328:         }
    1329:         DMPlexSetSupport(rdm, newp, supportRef);
    1330: #if 1
    1331:         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
    1332:         for (p = 0; p < supportSize; ++p) {
    1333:           if ((supportRef[p] < cStartNew) || (supportRef[p] >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportRef[p], cStartNew, cEndNew);
    1334:         }
    1335: #endif
    1336:       }
    1337:     }
    1338:     /* Interior faces have 2 vertices and 2 cells */
    1339:     for (c = cStart; c < cEnd; ++c) {
    1340:       const PetscInt *cone;

    1342:       DMPlexGetCone(dm, c, &cone);
    1343:       for (r = 0; r < 3; ++r) {
    1344:         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*3 + r;
    1345:         PetscInt       coneNew[2];
    1346:         PetscInt       supportNew[2];

    1348:         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r]       - fStart);
    1349:         coneNew[1] = vStartNew + (vEnd - vStart) + (cone[(r+1)%3] - fStart);
    1350:         DMPlexSetCone(rdm, newp, coneNew);
    1351: #if 1
    1352:         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
    1353:         for (p = 0; p < 2; ++p) {
    1354:           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
    1355:         }
    1356: #endif
    1357:         supportNew[0] = (c - cStart)*4 + (r+1)%3;
    1358:         supportNew[1] = (c - cStart)*4 + 3;
    1359:         DMPlexSetSupport(rdm, newp, supportNew);
    1360: #if 1
    1361:         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
    1362:         for (p = 0; p < 2; ++p) {
    1363:           if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cEndNew);
    1364:         }
    1365: #endif
    1366:       }
    1367:     }
    1368:     /* Old vertices have identical supports */
    1369:     for (v = vStart; v < vEnd; ++v) {
    1370:       const PetscInt  newp = vStartNew + (v - vStart);
    1371:       const PetscInt *support, *cone;
    1372:       PetscInt        size, s;

    1374:       DMPlexGetSupportSize(dm, v, &size);
    1375:       DMPlexGetSupport(dm, v, &support);
    1376:       for (s = 0; s < size; ++s) {
    1377:         PetscInt r = 0;

    1379:         DMPlexGetCone(dm, support[s], &cone);
    1380:         if (cone[1] == v) r = 1;
    1381:         supportRef[s] = fStartNew + (support[s] - fStart)*2 + r;
    1382:       }
    1383:       DMPlexSetSupport(rdm, newp, supportRef);
    1384: #if 1
    1385:       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
    1386:       for (p = 0; p < size; ++p) {
    1387:         if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", supportRef[p], fStartNew, fEndNew);
    1388:       }
    1389: #endif
    1390:     }
    1391:     /* Face vertices have 2 + cells*2 supports */
    1392:     for (f = fStart; f < fEnd; ++f) {
    1393:       const PetscInt  newp = vStartNew + (vEnd - vStart) + (f - fStart);
    1394:       const PetscInt *cone, *support;
    1395:       PetscInt        size, s;

    1397:       DMPlexGetSupportSize(dm, f, &size);
    1398:       DMPlexGetSupport(dm, f, &support);
    1399:       supportRef[0] = fStartNew + (f - fStart)*2 + 0;
    1400:       supportRef[1] = fStartNew + (f - fStart)*2 + 1;
    1401:       for (s = 0; s < size; ++s) {
    1402:         PetscInt r = 0;

    1404:         DMPlexGetCone(dm, support[s], &cone);
    1405:         if      (cone[1] == f) r = 1;
    1406:         else if (cone[2] == f) r = 2;
    1407:         supportRef[2+s*2+0] = fStartNew + (fEnd - fStart)*2 + (support[s] - cStart)*3 + (r+2)%3;
    1408:         supportRef[2+s*2+1] = fStartNew + (fEnd - fStart)*2 + (support[s] - cStart)*3 + r;
    1409:       }
    1410:       DMPlexSetSupport(rdm, newp, supportRef);
    1411: #if 1
    1412:       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
    1413:       for (p = 0; p < 2+size*2; ++p) {
    1414:         if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", supportRef[p], fStartNew, fEndNew);
    1415:       }
    1416: #endif
    1417:     }
    1418:     PetscFree(supportRef);
    1419:     break;
    1420:   case REFINER_HEX_2D:
    1421:     /*
    1422:      3---------2---------2
    1423:      |         |         |
    1424:      |    D    2    C    |
    1425:      |         |         |
    1426:      3----3----0----1----1
    1427:      |         |         |
    1428:      |    A    0    B    |
    1429:      |         |         |
    1430:      0---------0---------1
    1431:      */
    1432:     /* All cells have 4 faces */
    1433:     for (c = cStart; c < cEnd; ++c) {
    1434:       const PetscInt  newp = (c - cStart)*4;
    1435:       const PetscInt *cone, *ornt;
    1436:       PetscInt        coneNew[4], orntNew[4];

    1438:       DMPlexGetCone(dm, c, &cone);
    1439:       DMPlexGetConeOrientation(dm, c, &ornt);
    1440:       /* A quad */
    1441:       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
    1442:       orntNew[0] = ornt[0];
    1443:       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 0;
    1444:       orntNew[1] = 0;
    1445:       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 3;
    1446:       orntNew[2] = -2;
    1447:       coneNew[3] = fStartNew + (cone[3] - fStart)*2 + (ornt[3] < 0 ? 0 : 1);
    1448:       orntNew[3] = ornt[3];
    1449:       DMPlexSetCone(rdm, newp+0, coneNew);
    1450:       DMPlexSetConeOrientation(rdm, newp+0, orntNew);
    1451: #if 1
    1452:       if ((newp+0 < cStartNew) || (newp+0 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+0, cStartNew, cEndNew);
    1453:       for (p = 0; p < 4; ++p) {
    1454:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
    1455:       }
    1456: #endif
    1457:       /* B quad */
    1458:       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
    1459:       orntNew[0] = ornt[0];
    1460:       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
    1461:       orntNew[1] = ornt[1];
    1462:       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 1;
    1463:       orntNew[2] = 0;
    1464:       coneNew[3] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 0;
    1465:       orntNew[3] = -2;
    1466:       DMPlexSetCone(rdm, newp+1, coneNew);
    1467:       DMPlexSetConeOrientation(rdm, newp+1, orntNew);
    1468: #if 1
    1469:       if ((newp+1 < cStartNew) || (newp+1 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+1, cStartNew, cEndNew);
    1470:       for (p = 0; p < 4; ++p) {
    1471:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
    1472:       }
    1473: #endif
    1474:       /* C quad */
    1475:       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 1;
    1476:       orntNew[0] = -2;
    1477:       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
    1478:       orntNew[1] = ornt[1];
    1479:       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
    1480:       orntNew[2] = ornt[2];
    1481:       coneNew[3] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 2;
    1482:       orntNew[3] = 0;
    1483:       DMPlexSetCone(rdm, newp+2, coneNew);
    1484:       DMPlexSetConeOrientation(rdm, newp+2, orntNew);
    1485: #if 1
    1486:       if ((newp+2 < cStartNew) || (newp+2 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+2, cStartNew, cEndNew);
    1487:       for (p = 0; p < 4; ++p) {
    1488:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
    1489:       }
    1490: #endif
    1491:       /* D quad */
    1492:       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 3;
    1493:       orntNew[0] = 0;
    1494:       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 2;
    1495:       orntNew[1] = -2;
    1496:       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
    1497:       orntNew[2] = ornt[2];
    1498:       coneNew[3] = fStartNew + (cone[3] - fStart)*2 + (ornt[3] < 0 ? 1 : 0);
    1499:       orntNew[3] = ornt[3];
    1500:       DMPlexSetCone(rdm, newp+3, coneNew);
    1501:       DMPlexSetConeOrientation(rdm, newp+3, orntNew);
    1502: #if 1
    1503:       if ((newp+3 < cStartNew) || (newp+3 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+3, cStartNew, cEndNew);
    1504:       for (p = 0; p < 4; ++p) {
    1505:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
    1506:       }
    1507: #endif
    1508:     }
    1509:     /* Split faces have 2 vertices and the same cells as the parent */
    1510:     DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);
    1511:     PetscMalloc1(2 + maxSupportSize*2, &supportRef);
    1512:     for (f = fStart; f < fEnd; ++f) {
    1513:       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);

    1515:       for (r = 0; r < 2; ++r) {
    1516:         const PetscInt  newp = fStartNew + (f - fStart)*2 + r;
    1517:         const PetscInt *cone, *ornt, *support;
    1518:         PetscInt        coneNew[2], coneSize, c, supportSize, s;

    1520:         DMPlexGetCone(dm, f, &cone);
    1521:         coneNew[0]       = vStartNew + (cone[0] - vStart);
    1522:         coneNew[1]       = vStartNew + (cone[1] - vStart);
    1523:         coneNew[(r+1)%2] = newv;
    1524:         DMPlexSetCone(rdm, newp, coneNew);
    1525: #if 1
    1526:         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
    1527:         for (p = 0; p < 2; ++p) {
    1528:           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
    1529:         }
    1530: #endif
    1531:         DMPlexGetSupportSize(dm, f, &supportSize);
    1532:         DMPlexGetSupport(dm, f, &support);
    1533:         for (s = 0; s < supportSize; ++s) {
    1534:           DMPlexGetConeSize(dm, support[s], &coneSize);
    1535:           DMPlexGetCone(dm, support[s], &cone);
    1536:           DMPlexGetConeOrientation(dm, support[s], &ornt);
    1537:           for (c = 0; c < coneSize; ++c) {
    1538:             if (cone[c] == f) break;
    1539:           }
    1540:           supportRef[s] = cStartNew + (support[s] - cStart)*4 + (ornt[c] < 0 ? (c+1-r)%4 : (c+r)%4);
    1541:         }
    1542:         DMPlexSetSupport(rdm, newp, supportRef);
    1543: #if 1
    1544:         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
    1545:         for (p = 0; p < supportSize; ++p) {
    1546:           if ((supportRef[p] < cStartNew) || (supportRef[p] >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportRef[p], cStartNew, cEndNew);
    1547:         }
    1548: #endif
    1549:       }
    1550:     }
    1551:     /* Interior faces have 2 vertices and 2 cells */
    1552:     for (c = cStart; c < cEnd; ++c) {
    1553:       const PetscInt *cone;
    1554:       PetscInt        coneNew[2], supportNew[2];

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

    1560:         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r] - fStart);
    1561:         coneNew[1] = vStartNew + (vEnd - vStart) + (fEnd    - fStart) + (c - cStart);
    1562:         DMPlexSetCone(rdm, newp, coneNew);
    1563: #if 1
    1564:         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
    1565:         for (p = 0; p < 2; ++p) {
    1566:           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
    1567:         }
    1568: #endif
    1569:         supportNew[0] = (c - cStart)*4 + r;
    1570:         supportNew[1] = (c - cStart)*4 + (r+1)%4;
    1571:         DMPlexSetSupport(rdm, newp, supportNew);
    1572: #if 1
    1573:         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
    1574:         for (p = 0; p < 2; ++p) {
    1575:           if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cEndNew);
    1576:         }
    1577: #endif
    1578:       }
    1579:     }
    1580:     /* Old vertices have identical supports */
    1581:     for (v = vStart; v < vEnd; ++v) {
    1582:       const PetscInt  newp = vStartNew + (v - vStart);
    1583:       const PetscInt *support, *cone;
    1584:       PetscInt        size, s;

    1586:       DMPlexGetSupportSize(dm, v, &size);
    1587:       DMPlexGetSupport(dm, v, &support);
    1588:       for (s = 0; s < size; ++s) {
    1589:         PetscInt r = 0;

    1591:         DMPlexGetCone(dm, support[s], &cone);
    1592:         if (cone[1] == v) r = 1;
    1593:         supportRef[s] = fStartNew + (support[s] - fStart)*2 + r;
    1594:       }
    1595:       DMPlexSetSupport(rdm, newp, supportRef);
    1596: #if 1
    1597:       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
    1598:       for (p = 0; p < size; ++p) {
    1599:         if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", supportRef[p], fStartNew, fEndNew);
    1600:       }
    1601: #endif
    1602:     }
    1603:     /* Face vertices have 2 + cells supports */
    1604:     for (f = fStart; f < fEnd; ++f) {
    1605:       const PetscInt  newp = vStartNew + (vEnd - vStart) + (f - fStart);
    1606:       const PetscInt *cone, *support;
    1607:       PetscInt        size, s;

    1609:       DMPlexGetSupportSize(dm, f, &size);
    1610:       DMPlexGetSupport(dm, f, &support);
    1611:       supportRef[0] = fStartNew + (f - fStart)*2 + 0;
    1612:       supportRef[1] = fStartNew + (f - fStart)*2 + 1;
    1613:       for (s = 0; s < size; ++s) {
    1614:         PetscInt r = 0;

    1616:         DMPlexGetCone(dm, support[s], &cone);
    1617:         if      (cone[1] == f) r = 1;
    1618:         else if (cone[2] == f) r = 2;
    1619:         else if (cone[3] == f) r = 3;
    1620:         supportRef[2+s] = fStartNew + (fEnd - fStart)*2 + (support[s] - cStart)*4 + r;
    1621:       }
    1622:       DMPlexSetSupport(rdm, newp, supportRef);
    1623: #if 1
    1624:       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
    1625:       for (p = 0; p < 2+size; ++p) {
    1626:         if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", supportRef[p], fStartNew, fEndNew);
    1627:       }
    1628: #endif
    1629:     }
    1630:     /* Cell vertices have 4 supports */
    1631:     for (c = cStart; c < cEnd; ++c) {
    1632:       const PetscInt newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (c - cStart);
    1633:       PetscInt       supportNew[4];

    1635:       for (r = 0; r < 4; ++r) {
    1636:         supportNew[r] = fStartNew + (fEnd - fStart)*2 + (c - cStart)*4 + r;
    1637:       }
    1638:       DMPlexSetSupport(rdm, newp, supportNew);
    1639:     }
    1640:     PetscFree(supportRef);
    1641:     break;
    1642:   case REFINER_HYBRID_SIMPLEX_2D:
    1643:     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
    1644:     cMax = PetscMin(cEnd, cMax);
    1645:     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
    1646:     fMax = PetscMin(fEnd, fMax);
    1647:     DMPlexGetHybridBounds(rdm, &cMaxNew, &fMaxNew, NULL, NULL);
    1648:     /* Interior cells have 3 faces */
    1649:     for (c = cStart; c < cMax; ++c) {
    1650:       const PetscInt  newp = cStartNew + (c - cStart)*4;
    1651:       const PetscInt *cone, *ornt;
    1652:       PetscInt        coneNew[3], orntNew[3];

    1654:       DMPlexGetCone(dm, c, &cone);
    1655:       DMPlexGetConeOrientation(dm, c, &ornt);
    1656:       /* A triangle */
    1657:       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
    1658:       orntNew[0] = ornt[0];
    1659:       coneNew[1] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 2;
    1660:       orntNew[1] = -2;
    1661:       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
    1662:       orntNew[2] = ornt[2];
    1663:       DMPlexSetCone(rdm, newp+0, coneNew);
    1664:       DMPlexSetConeOrientation(rdm, newp+0, orntNew);
    1665: #if 1
    1666:       if ((newp+0 < cStartNew) || (newp+0 >= cMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an interior cell [%d, %d)", newp+0, cStartNew, cMaxNew);
    1667:       for (p = 0; p < 3; ++p) {
    1668:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an interior face [%d, %d)", coneNew[p], fStartNew, fMaxNew);
    1669:       }
    1670: #endif
    1671:       /* B triangle */
    1672:       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
    1673:       orntNew[0] = ornt[0];
    1674:       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
    1675:       orntNew[1] = ornt[1];
    1676:       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 0;
    1677:       orntNew[2] = -2;
    1678:       DMPlexSetCone(rdm, newp+1, coneNew);
    1679:       DMPlexSetConeOrientation(rdm, newp+1, orntNew);
    1680: #if 1
    1681:       if ((newp+1 < cStartNew) || (newp+1 >= cMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an interior cell [%d, %d)", newp+1, cStartNew, cMaxNew);
    1682:       for (p = 0; p < 3; ++p) {
    1683:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an interior face [%d, %d)", coneNew[p], fStartNew, fMaxNew);
    1684:       }
    1685: #endif
    1686:       /* C triangle */
    1687:       coneNew[0] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 1;
    1688:       orntNew[0] = -2;
    1689:       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
    1690:       orntNew[1] = ornt[1];
    1691:       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
    1692:       orntNew[2] = ornt[2];
    1693:       DMPlexSetCone(rdm, newp+2, coneNew);
    1694:       DMPlexSetConeOrientation(rdm, newp+2, orntNew);
    1695: #if 1
    1696:       if ((newp+2 < cStartNew) || (newp+2 >= cMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an interior cell [%d, %d)", newp+2, cStartNew, cMaxNew);
    1697:       for (p = 0; p < 3; ++p) {
    1698:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an interior face [%d, %d)", coneNew[p], fStartNew, fMaxNew);
    1699:       }
    1700: #endif
    1701:       /* D triangle */
    1702:       coneNew[0] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 0;
    1703:       orntNew[0] = 0;
    1704:       coneNew[1] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 1;
    1705:       orntNew[1] = 0;
    1706:       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 2;
    1707:       orntNew[2] = 0;
    1708:       DMPlexSetCone(rdm, newp+3, coneNew);
    1709:       DMPlexSetConeOrientation(rdm, newp+3, orntNew);
    1710: #if 1
    1711:       if ((newp+3 < cStartNew) || (newp+3 >= cMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an interior cell [%d, %d)", newp+3, cStartNew, cMaxNew);
    1712:       for (p = 0; p < 3; ++p) {
    1713:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an interior face [%d, %d)", coneNew[p], fStartNew, fMaxNew);
    1714:       }
    1715: #endif
    1716:     }
    1717:     /*
    1718:      2----3----3
    1719:      |         |
    1720:      |    B    |
    1721:      |         |
    1722:      0----4--- 1
    1723:      |         |
    1724:      |    A    |
    1725:      |         |
    1726:      0----2----1
    1727:      */
    1728:     /* Hybrid cells have 4 faces */
    1729:     for (c = cMax; c < cEnd; ++c) {
    1730:       const PetscInt  newp = cStartNew + (cMax - cStart)*4 + (c - cMax)*2;
    1731:       const PetscInt *cone, *ornt;
    1732:       PetscInt        coneNew[4], orntNew[4], r;

    1734:       DMPlexGetCone(dm, c, &cone);
    1735:       DMPlexGetConeOrientation(dm, c, &ornt);
    1736:       r    = (ornt[0] < 0 ? 1 : 0);
    1737:       /* A quad */
    1738:       coneNew[0]   = fStartNew + (cone[0] - fStart)*2 + r;
    1739:       orntNew[0]   = ornt[0];
    1740:       coneNew[1]   = fStartNew + (cone[1] - fStart)*2 + r;
    1741:       orntNew[1]   = ornt[1];
    1742:       coneNew[2+r] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (cone[2+r] - fMax);
    1743:       orntNew[2+r] = 0;
    1744:       coneNew[3-r] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (fEnd    - fMax) + (c - cMax);
    1745:       orntNew[3-r] = 0;
    1746:       DMPlexSetCone(rdm, newp+0, coneNew);
    1747:       DMPlexSetConeOrientation(rdm, newp+0, orntNew);
    1748: #if 1
    1749:       if ((newp+0 < cStartNew) || (newp+0 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+0, cStartNew, cEndNew);
    1750:       for (p = 0; p < 4; ++p) {
    1751:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
    1752:       }
    1753: #endif
    1754:       /* B quad */
    1755:       coneNew[0]   = fStartNew + (cone[0] - fStart)*2 + 1-r;
    1756:       orntNew[0]   = ornt[0];
    1757:       coneNew[1]   = fStartNew + (cone[1] - fStart)*2 + 1-r;
    1758:       orntNew[1]   = ornt[1];
    1759:       coneNew[2+r] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (fEnd    - fMax) + (c - cMax);
    1760:       orntNew[2+r] = 0;
    1761:       coneNew[3-r] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (cone[3-r] - fMax);
    1762:       orntNew[3-r] = 0;
    1763:       DMPlexSetCone(rdm, newp+1, coneNew);
    1764:       DMPlexSetConeOrientation(rdm, newp+1, orntNew);
    1765: #if 1
    1766:       if ((newp+1 < cStartNew) || (newp+1 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+1, cStartNew, cEndNew);
    1767:       for (p = 0; p < 4; ++p) {
    1768:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
    1769:       }
    1770: #endif
    1771:     }
    1772:     /* Interior split faces have 2 vertices and the same cells as the parent */
    1773:     DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);
    1774:     PetscMalloc1(2 + maxSupportSize*2, &supportRef);
    1775:     for (f = fStart; f < fMax; ++f) {
    1776:       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);

    1778:       for (r = 0; r < 2; ++r) {
    1779:         const PetscInt  newp = fStartNew + (f - fStart)*2 + r;
    1780:         const PetscInt *cone, *ornt, *support;
    1781:         PetscInt        coneNew[2], coneSize, c, supportSize, s;

    1783:         DMPlexGetCone(dm, f, &cone);
    1784:         coneNew[0]       = vStartNew + (cone[0] - vStart);
    1785:         coneNew[1]       = vStartNew + (cone[1] - vStart);
    1786:         coneNew[(r+1)%2] = newv;
    1787:         DMPlexSetCone(rdm, newp, coneNew);
    1788: #if 1
    1789:         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
    1790:         for (p = 0; p < 2; ++p) {
    1791:           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
    1792:         }
    1793: #endif
    1794:         DMPlexGetSupportSize(dm, f, &supportSize);
    1795:         DMPlexGetSupport(dm, f, &support);
    1796:         for (s = 0; s < supportSize; ++s) {
    1797:           DMPlexGetConeSize(dm, support[s], &coneSize);
    1798:           DMPlexGetCone(dm, support[s], &cone);
    1799:           DMPlexGetConeOrientation(dm, support[s], &ornt);
    1800:           for (c = 0; c < coneSize; ++c) if (cone[c] == f) break;
    1801:           if (support[s] >= cMax) {
    1802:             supportRef[s] = cStartNew + (cMax - cStart)*4 + (support[s] - cMax)*2 + (ornt[c] < 0 ? 1-r : r);
    1803:           } else {
    1804:             supportRef[s] = cStartNew + (support[s] - cStart)*4 + (ornt[c] < 0 ? (c+1-r)%3 : (c+r)%3);
    1805:           }
    1806:         }
    1807:         DMPlexSetSupport(rdm, newp, supportRef);
    1808: #if 1
    1809:         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
    1810:         for (p = 0; p < supportSize; ++p) {
    1811:           if ((supportRef[p] < cStartNew) || (supportRef[p] >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportRef[p], cStartNew, cEndNew);
    1812:         }
    1813: #endif
    1814:       }
    1815:     }
    1816:     /* Interior cell faces have 2 vertices and 2 cells */
    1817:     for (c = cStart; c < cMax; ++c) {
    1818:       const PetscInt *cone;

    1820:       DMPlexGetCone(dm, c, &cone);
    1821:       for (r = 0; r < 3; ++r) {
    1822:         const PetscInt newp = fStartNew + (fMax - fStart)*2 + (c - cStart)*3 + r;
    1823:         PetscInt       coneNew[2];
    1824:         PetscInt       supportNew[2];

    1826:         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r]       - fStart);
    1827:         coneNew[1] = vStartNew + (vEnd - vStart) + (cone[(r+1)%3] - fStart);
    1828:         DMPlexSetCone(rdm, newp, coneNew);
    1829: #if 1
    1830:         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
    1831:         for (p = 0; p < 2; ++p) {
    1832:           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
    1833:         }
    1834: #endif
    1835:         supportNew[0] = (c - cStart)*4 + (r+1)%3;
    1836:         supportNew[1] = (c - cStart)*4 + 3;
    1837:         DMPlexSetSupport(rdm, newp, supportNew);
    1838: #if 1
    1839:         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
    1840:         for (p = 0; p < 2; ++p) {
    1841:           if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cEndNew);
    1842:         }
    1843: #endif
    1844:       }
    1845:     }
    1846:     /* Interior hybrid faces have 2 vertices and the same cells */
    1847:     for (f = fMax; f < fEnd; ++f) {
    1848:       const PetscInt  newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (f - fMax);
    1849:       const PetscInt *cone, *ornt;
    1850:       const PetscInt *support;
    1851:       PetscInt        coneNew[2];
    1852:       PetscInt        supportNew[2];
    1853:       PetscInt        size, s, r;

    1855:       DMPlexGetCone(dm, f, &cone);
    1856:       coneNew[0] = vStartNew + (cone[0] - vStart);
    1857:       coneNew[1] = vStartNew + (cone[1] - vStart);
    1858:       DMPlexSetCone(rdm, newp, coneNew);
    1859: #if 1
    1860:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
    1861:       for (p = 0; p < 2; ++p) {
    1862:         if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
    1863:       }
    1864: #endif
    1865:       DMPlexGetSupportSize(dm, f, &size);
    1866:       DMPlexGetSupport(dm, f, &support);
    1867:       for (s = 0; s < size; ++s) {
    1868:         DMPlexGetCone(dm, support[s], &cone);
    1869:         DMPlexGetConeOrientation(dm, support[s], &ornt);
    1870:         for (r = 0; r < 2; ++r) {
    1871:           if (cone[r+2] == f) break;
    1872:         }
    1873:         supportNew[s] = (cMax - cStart)*4 + (support[s] - cMax)*2 + (ornt[0] < 0 ? 1-r : r);
    1874:       }
    1875:       DMPlexSetSupport(rdm, newp, supportNew);
    1876: #if 1
    1877:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
    1878:       for (p = 0; p < size; ++p) {
    1879:         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cEndNew);
    1880:       }
    1881: #endif
    1882:     }
    1883:     /* Cell hybrid faces have 2 vertices and 2 cells */
    1884:     for (c = cMax; c < cEnd; ++c) {
    1885:       const PetscInt  newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (fEnd - fMax) + (c - cMax);
    1886:       const PetscInt *cone;
    1887:       PetscInt        coneNew[2];
    1888:       PetscInt        supportNew[2];

    1890:       DMPlexGetCone(dm, c, &cone);
    1891:       coneNew[0] = vStartNew + (vEnd - vStart) + (cone[0] - fStart);
    1892:       coneNew[1] = vStartNew + (vEnd - vStart) + (cone[1] - fStart);
    1893:       DMPlexSetCone(rdm, newp, coneNew);
    1894: #if 1
    1895:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
    1896:       for (p = 0; p < 2; ++p) {
    1897:         if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
    1898:       }
    1899: #endif
    1900:       supportNew[0] = (cMax - cStart)*4 + (c - cMax)*2 + 0;
    1901:       supportNew[1] = (cMax - cStart)*4 + (c - cMax)*2 + 1;
    1902:       DMPlexSetSupport(rdm, newp, supportNew);
    1903: #if 1
    1904:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
    1905:       for (p = 0; p < 2; ++p) {
    1906:         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cEndNew);
    1907:       }
    1908: #endif
    1909:     }
    1910:     /* Old vertices have identical supports */
    1911:     for (v = vStart; v < vEnd; ++v) {
    1912:       const PetscInt  newp = vStartNew + (v - vStart);
    1913:       const PetscInt *support, *cone;
    1914:       PetscInt        size, s;

    1916:       DMPlexGetSupportSize(dm, v, &size);
    1917:       DMPlexGetSupport(dm, v, &support);
    1918:       for (s = 0; s < size; ++s) {
    1919:         if (support[s] >= fMax) {
    1920:           supportRef[s] = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (support[s] - fMax);
    1921:         } else {
    1922:           PetscInt r = 0;

    1924:           DMPlexGetCone(dm, support[s], &cone);
    1925:           if (cone[1] == v) r = 1;
    1926:           supportRef[s] = fStartNew + (support[s] - fStart)*2 + r;
    1927:         }
    1928:       }
    1929:       DMPlexSetSupport(rdm, newp, supportRef);
    1930: #if 1
    1931:       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
    1932:       for (p = 0; p < size; ++p) {
    1933:         if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", supportRef[p], fStartNew, fEndNew);
    1934:       }
    1935: #endif
    1936:     }
    1937:     /* Face vertices have 2 + (2 interior, 1 hybrid) supports */
    1938:     for (f = fStart; f < fMax; ++f) {
    1939:       const PetscInt  newp = vStartNew + (vEnd - vStart) + (f - fStart);
    1940:       const PetscInt *cone, *support;
    1941:       PetscInt        size, newSize = 2, s;

    1943:       DMPlexGetSupportSize(dm, f, &size);
    1944:       DMPlexGetSupport(dm, f, &support);
    1945:       supportRef[0] = fStartNew + (f - fStart)*2 + 0;
    1946:       supportRef[1] = fStartNew + (f - fStart)*2 + 1;
    1947:       for (s = 0; s < size; ++s) {
    1948:         PetscInt r = 0;

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

    1954:           newSize += 1;
    1955:         } else {
    1956:           if      (cone[1] == f) r = 1;
    1957:           else if (cone[2] == f) r = 2;
    1958:           supportRef[newSize+0] = fStartNew + (fMax - fStart)*2 + (support[s] - cStart)*3 + (r+2)%3;
    1959:           supportRef[newSize+1] = fStartNew + (fMax - fStart)*2 + (support[s] - cStart)*3 + r;

    1961:           newSize += 2;
    1962:         }
    1963:       }
    1964:       DMPlexSetSupport(rdm, newp, supportRef);
    1965: #if 1
    1966:       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
    1967:       for (p = 0; p < newSize; ++p) {
    1968:         if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", supportRef[p], fStartNew, fEndNew);
    1969:       }
    1970: #endif
    1971:     }
    1972:     PetscFree(supportRef);
    1973:     break;
    1974:   case REFINER_HYBRID_HEX_2D:
    1975:     /* Hybrid Hex 2D */
    1976:     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
    1977:     cMax = PetscMin(cEnd, cMax);
    1978:     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
    1979:     fMax = PetscMin(fEnd, fMax);
    1980:     DMPlexGetHybridBounds(rdm, &cMaxNew, &fMaxNew, NULL, NULL);
    1981:     /* Interior cells have 4 faces */
    1982:     for (c = cStart; c < cMax; ++c) {
    1983:       const PetscInt  newp = cStartNew + (c - cStart)*4;
    1984:       const PetscInt *cone, *ornt;
    1985:       PetscInt        coneNew[4], orntNew[4];

    1987:       DMPlexGetCone(dm, c, &cone);
    1988:       DMPlexGetConeOrientation(dm, c, &ornt);
    1989:       /* A quad */
    1990:       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
    1991:       orntNew[0] = ornt[0];
    1992:       coneNew[1] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*4 + 0;
    1993:       orntNew[1] = 0;
    1994:       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*4 + 3;
    1995:       orntNew[2] = -2;
    1996:       coneNew[3] = fStartNew + (cone[3] - fStart)*2 + (ornt[3] < 0 ? 0 : 1);
    1997:       orntNew[3] = ornt[3];
    1998:       DMPlexSetCone(rdm, newp+0, coneNew);
    1999:       DMPlexSetConeOrientation(rdm, newp+0, orntNew);
    2000: #if 1
    2001:       if ((newp+0 < cStartNew) || (newp+0 >= cMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an interior cell [%d, %d)", newp+0, cStartNew, cMaxNew);
    2002:       for (p = 0; p < 4; ++p) {
    2003:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an interior face [%d, %d)", coneNew[p], fStartNew, fMaxNew);
    2004:       }
    2005: #endif
    2006:       /* B quad */
    2007:       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
    2008:       orntNew[0] = ornt[0];
    2009:       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
    2010:       orntNew[1] = ornt[1];
    2011:       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*4 + 1;
    2012:       orntNew[2] = 0;
    2013:       coneNew[3] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*4 + 0;
    2014:       orntNew[3] = -2;
    2015:       DMPlexSetCone(rdm, newp+1, coneNew);
    2016:       DMPlexSetConeOrientation(rdm, newp+1, orntNew);
    2017: #if 1
    2018:       if ((newp+1 < cStartNew) || (newp+1 >= cMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an interior cell [%d, %d)", newp+1, cStartNew, cMaxNew);
    2019:       for (p = 0; p < 4; ++p) {
    2020:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an interior face [%d, %d)", coneNew[p], fStartNew, fMaxNew);
    2021:       }
    2022: #endif
    2023:       /* C quad */
    2024:       coneNew[0] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*4 + 1;
    2025:       orntNew[0] = -2;
    2026:       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
    2027:       orntNew[1] = ornt[1];
    2028:       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
    2029:       orntNew[2] = ornt[2];
    2030:       coneNew[3] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*4 + 2;
    2031:       orntNew[3] = 0;
    2032:       DMPlexSetCone(rdm, newp+2, coneNew);
    2033:       DMPlexSetConeOrientation(rdm, newp+2, orntNew);
    2034: #if 1
    2035:       if ((newp+2 < cStartNew) || (newp+2 >= cMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an interior cell [%d, %d)", newp+2, cStartNew, cMaxNew);
    2036:       for (p = 0; p < 4; ++p) {
    2037:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an interior face [%d, %d)", coneNew[p], fStartNew, fMaxNew);
    2038:       }
    2039: #endif
    2040:       /* D quad */
    2041:       coneNew[0] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*4 + 3;
    2042:       orntNew[0] = 0;
    2043:       coneNew[1] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*4 + 2;
    2044:       orntNew[1] = -2;
    2045:       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
    2046:       orntNew[2] = ornt[2];
    2047:       coneNew[3] = fStartNew + (cone[3] - fStart)*2 + (ornt[3] < 0 ? 1 : 0);
    2048:       orntNew[3] = ornt[3];
    2049:       DMPlexSetCone(rdm, newp+3, coneNew);
    2050:       DMPlexSetConeOrientation(rdm, newp+3, orntNew);
    2051: #if 1
    2052:       if ((newp+3 < cStartNew) || (newp+3 >= cMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an interior cell [%d, %d)", newp+3, cStartNew, cMaxNew);
    2053:       for (p = 0; p < 4; ++p) {
    2054:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an interior face [%d, %d)", coneNew[p], fStartNew, fMaxNew);
    2055:       }
    2056: #endif
    2057:     }
    2058:     /*
    2059:      2----3----3
    2060:      |         |
    2061:      |    B    |
    2062:      |         |
    2063:      0----4--- 1
    2064:      |         |
    2065:      |    A    |
    2066:      |         |
    2067:      0----2----1
    2068:      */
    2069:     /* Hybrid cells have 4 faces */
    2070:     for (c = cMax; c < cEnd; ++c) {
    2071:       const PetscInt  newp = cStartNew + (cMax - cStart)*4 + (c - cMax)*2;
    2072:       const PetscInt *cone, *ornt;
    2073:       PetscInt        coneNew[4], orntNew[4];

    2075:       DMPlexGetCone(dm, c, &cone);
    2076:       DMPlexGetConeOrientation(dm, c, &ornt);
    2077:       /* A quad */
    2078:       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
    2079:       orntNew[0] = ornt[0];
    2080:       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
    2081:       orntNew[1] = ornt[1];
    2082:       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*4 + (cone[2] - fMax);
    2083:       orntNew[2] = 0;
    2084:       coneNew[3] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*4 + (fEnd    - fMax) + (c - cMax);
    2085:       orntNew[3] = 0;
    2086:       DMPlexSetCone(rdm, newp+0, coneNew);
    2087:       DMPlexSetConeOrientation(rdm, newp+0, orntNew);
    2088: #if 1
    2089:       if ((newp+0 < cStartNew) || (newp+0 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+0, cStartNew, cEndNew);
    2090:       for (p = 0; p < 4; ++p) {
    2091:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
    2092:       }
    2093: #endif
    2094:       /* B quad */
    2095:       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
    2096:       orntNew[0] = ornt[0];
    2097:       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
    2098:       orntNew[1] = ornt[1];
    2099:       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*4 + (fEnd    - fMax) + (c - cMax);
    2100:       orntNew[2] = 0;
    2101:       coneNew[3] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*4 + (cone[3] - fMax);
    2102:       orntNew[3] = 0;
    2103:       DMPlexSetCone(rdm, newp+1, coneNew);
    2104:       DMPlexSetConeOrientation(rdm, newp+1, orntNew);
    2105: #if 1
    2106:       if ((newp+1 < cStartNew) || (newp+1 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+1, cStartNew, cEndNew);
    2107:       for (p = 0; p < 4; ++p) {
    2108:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
    2109:       }
    2110: #endif
    2111:     }
    2112:     /* Interior split faces have 2 vertices and the same cells as the parent */
    2113:     DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);
    2114:     PetscMalloc1(2 + maxSupportSize*2, &supportRef);
    2115:     for (f = fStart; f < fMax; ++f) {
    2116:       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);

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

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

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

    2167:         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r] - fStart);
    2168:         coneNew[1] = vStartNew + (vEnd - vStart) + (fMax    - fStart) + (c - cStart);
    2169:         DMPlexSetCone(rdm, newp, coneNew);
    2170: #if 1
    2171:         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
    2172:         for (p = 0; p < 2; ++p) {
    2173:           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
    2174:         }
    2175: #endif
    2176:         supportNew[0] = (c - cStart)*4 + r;
    2177:         supportNew[1] = (c - cStart)*4 + (r+1)%4;
    2178:         DMPlexSetSupport(rdm, newp, supportNew);
    2179: #if 1
    2180:         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
    2181:         for (p = 0; p < 2; ++p) {
    2182:           if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cEndNew);
    2183:         }
    2184: #endif
    2185:       }
    2186:     }
    2187:     /* Hybrid faces have 2 vertices and the same cells */
    2188:     for (f = fMax; f < fEnd; ++f) {
    2189:       const PetscInt  newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*4 + (f - fMax);
    2190:       const PetscInt *cone, *support;
    2191:       PetscInt        coneNew[2], supportNew[2];
    2192:       PetscInt        size, s, r;

    2194:       DMPlexGetCone(dm, f, &cone);
    2195:       coneNew[0] = vStartNew + (cone[0] - vStart);
    2196:       coneNew[1] = vStartNew + (cone[1] - vStart);
    2197:       DMPlexSetCone(rdm, newp, coneNew);
    2198: #if 1
    2199:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
    2200:       for (p = 0; p < 2; ++p) {
    2201:         if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
    2202:       }
    2203: #endif
    2204:       DMPlexGetSupportSize(dm, f, &size);
    2205:       DMPlexGetSupport(dm, f, &support);
    2206:       for (s = 0; s < size; ++s) {
    2207:         DMPlexGetCone(dm, support[s], &cone);
    2208:         for (r = 0; r < 2; ++r) {
    2209:           if (cone[r+2] == f) break;
    2210:         }
    2211:         supportNew[s] = (cMax - cStart)*4 + (support[s] - cMax)*2 + r;
    2212:       }
    2213:       DMPlexSetSupport(rdm, newp, supportNew);
    2214: #if 1
    2215:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
    2216:       for (p = 0; p < size; ++p) {
    2217:         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cEndNew);
    2218:       }
    2219: #endif
    2220:     }
    2221:     /* Cell hybrid faces have 2 vertices and 2 cells */
    2222:     for (c = cMax; c < cEnd; ++c) {
    2223:       const PetscInt  newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*4 + (fEnd - fMax) + (c - cMax);
    2224:       const PetscInt *cone;
    2225:       PetscInt        coneNew[2], supportNew[2];

    2227:       DMPlexGetCone(dm, c, &cone);
    2228:       coneNew[0] = vStartNew + (vEnd - vStart) + (cone[0] - fStart);
    2229:       coneNew[1] = vStartNew + (vEnd - vStart) + (cone[1] - fStart);
    2230:       DMPlexSetCone(rdm, newp, coneNew);
    2231: #if 1
    2232:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
    2233:       for (p = 0; p < 2; ++p) {
    2234:         if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
    2235:       }
    2236: #endif
    2237:       supportNew[0] = (cMax - cStart)*4 + (c - cMax)*2 + 0;
    2238:       supportNew[1] = (cMax - cStart)*4 + (c - cMax)*2 + 1;
    2239:       DMPlexSetSupport(rdm, newp, supportNew);
    2240: #if 1
    2241:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
    2242:       for (p = 0; p < 2; ++p) {
    2243:         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cEndNew);
    2244:       }
    2245: #endif
    2246:     }
    2247:     /* Old vertices have identical supports */
    2248:     for (v = vStart; v < vEnd; ++v) {
    2249:       const PetscInt  newp = vStartNew + (v - vStart);
    2250:       const PetscInt *support, *cone;
    2251:       PetscInt        size, s;

    2253:       DMPlexGetSupportSize(dm, v, &size);
    2254:       DMPlexGetSupport(dm, v, &support);
    2255:       for (s = 0; s < size; ++s) {
    2256:         if (support[s] >= fMax) {
    2257:           supportRef[s] = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*4 + (support[s] - fMax);
    2258:         } else {
    2259:           PetscInt r = 0;

    2261:           DMPlexGetCone(dm, support[s], &cone);
    2262:           if (cone[1] == v) r = 1;
    2263:           supportRef[s] = fStartNew + (support[s] - fStart)*2 + r;
    2264:         }
    2265:       }
    2266:       DMPlexSetSupport(rdm, newp, supportRef);
    2267: #if 1
    2268:       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
    2269:       for (p = 0; p < size; ++p) {
    2270:         if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", supportRef[p], fStartNew, fEndNew);
    2271:       }
    2272: #endif
    2273:     }
    2274:     /* Face vertices have 2 + cells supports */
    2275:     for (f = fStart; f < fMax; ++f) {
    2276:       const PetscInt  newp = vStartNew + (vEnd - vStart) + (f - fStart);
    2277:       const PetscInt *cone, *support;
    2278:       PetscInt        size, s;

    2280:       DMPlexGetSupportSize(dm, f, &size);
    2281:       DMPlexGetSupport(dm, f, &support);
    2282:       supportRef[0] = fStartNew + (f - fStart)*2 + 0;
    2283:       supportRef[1] = fStartNew + (f - fStart)*2 + 1;
    2284:       for (s = 0; s < size; ++s) {
    2285:         PetscInt r = 0;

    2287:         DMPlexGetCone(dm, support[s], &cone);
    2288:         if (support[s] >= cMax) {
    2289:           supportRef[2+s] = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*4 + (fEnd - fMax) + (support[s] - cMax);
    2290:         } else {
    2291:           if      (cone[1] == f) r = 1;
    2292:           else if (cone[2] == f) r = 2;
    2293:           else if (cone[3] == f) r = 3;
    2294:           supportRef[2+s] = fStartNew + (fMax - fStart)*2 + (support[s] - cStart)*4 + r;
    2295:         }
    2296:       }
    2297:       DMPlexSetSupport(rdm, newp, supportRef);
    2298: #if 1
    2299:       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
    2300:       for (p = 0; p < 2+size; ++p) {
    2301:         if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", supportRef[p], fStartNew, fEndNew);
    2302:       }
    2303: #endif
    2304:     }
    2305:     /* Cell vertices have 4 supports */
    2306:     for (c = cStart; c < cMax; ++c) {
    2307:       const PetscInt newp = vStartNew + (vEnd - vStart) + (fMax - fStart) + (c - cStart);
    2308:       PetscInt       supportNew[4];

    2310:       for (r = 0; r < 4; ++r) {
    2311:         supportNew[r] = fStartNew + (fMax - fStart)*2 + (c - cStart)*4 + r;
    2312:       }
    2313:       DMPlexSetSupport(rdm, newp, supportNew);
    2314:     }
    2315:     PetscFree(supportRef);
    2316:     break;
    2317:   case REFINER_SIMPLEX_3D:
    2318:     /* All cells have 4 faces: Tet face order is prescribed in DMPlexGetFaces_Internal() */
    2319:     DMPlexGetRawFaces_Internal(dm, 3, 4, cellInd, NULL, NULL, &faces);
    2320:     for (c = cStart; c < cEnd; ++c) {
    2321:       const PetscInt  newp = cStartNew + (c - cStart)*8;
    2322:       const PetscInt *cone, *ornt;
    2323:       PetscInt        coneNew[4], orntNew[4];

    2325:       DMPlexGetCone(dm, c, &cone);
    2326:       DMPlexGetConeOrientation(dm, c, &ornt);
    2327:       /* A tetrahedron: {0, a, c, d} */
    2328:       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetTriSubface_Static(ornt[0], 0); /* A */
    2329:       orntNew[0] = ornt[0];
    2330:       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetTriSubface_Static(ornt[1], 0); /* A */
    2331:       orntNew[1] = ornt[1];
    2332:       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetTriSubface_Static(ornt[2], 0); /* A */
    2333:       orntNew[2] = ornt[2];
    2334:       coneNew[3] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 0;
    2335:       orntNew[3] = 0;
    2336:       DMPlexSetCone(rdm, newp+0, coneNew);
    2337:       DMPlexSetConeOrientation(rdm, newp+0, orntNew);
    2338: #if 1
    2339:       if ((newp+0 < cStartNew) || (newp+0 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+0, cStartNew, cEndNew);
    2340:       for (p = 0; p < 4; ++p) {
    2341:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
    2342:       }
    2343: #endif
    2344:       /* B tetrahedron: {a, 1, b, e} */
    2345:       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetTriSubface_Static(ornt[0], 1); /* B */
    2346:       orntNew[0] = ornt[0];
    2347:       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetTriSubface_Static(ornt[1], 2); /* C */
    2348:       orntNew[1] = ornt[1];
    2349:       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 1;
    2350:       orntNew[2] = 0;
    2351:       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetTriSubface_Static(ornt[3], 1); /* B */
    2352:       orntNew[3] = ornt[3];
    2353:       DMPlexSetCone(rdm, newp+1, coneNew);
    2354:       DMPlexSetConeOrientation(rdm, newp+1, orntNew);
    2355: #if 1
    2356:       if ((newp+1 < cStartNew) || (newp+1 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+1, cStartNew, cEndNew);
    2357:       for (p = 0; p < 4; ++p) {
    2358:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
    2359:       }
    2360: #endif
    2361:       /* C tetrahedron: {c, b, 2, f} */
    2362:       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetTriSubface_Static(ornt[0], 2); /* C */
    2363:       orntNew[0] = ornt[0];
    2364:       coneNew[1] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 2;
    2365:       orntNew[1] = 0;
    2366:       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetTriSubface_Static(ornt[2], 1); /* B */
    2367:       orntNew[2] = ornt[2];
    2368:       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetTriSubface_Static(ornt[3], 0); /* A */
    2369:       orntNew[3] = ornt[3];
    2370:       DMPlexSetCone(rdm, newp+2, coneNew);
    2371:       DMPlexSetConeOrientation(rdm, newp+2, orntNew);
    2372: #if 1
    2373:       if ((newp+2 < cStartNew) || (newp+2 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+2, cStartNew, cEndNew);
    2374:       for (p = 0; p < 4; ++p) {
    2375:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
    2376:       }
    2377: #endif
    2378:       /* D tetrahedron: {d, e, f, 3} */
    2379:       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 3;
    2380:       orntNew[0] = 0;
    2381:       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetTriSubface_Static(ornt[1], 1); /* B */
    2382:       orntNew[1] = ornt[1];
    2383:       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetTriSubface_Static(ornt[2], 2); /* C */
    2384:       orntNew[2] = ornt[2];
    2385:       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetTriSubface_Static(ornt[3], 2); /* C */
    2386:       orntNew[3] = ornt[3];
    2387:       DMPlexSetCone(rdm, newp+3, coneNew);
    2388:       DMPlexSetConeOrientation(rdm, newp+3, orntNew);
    2389: #if 1
    2390:       if ((newp+3 < cStartNew) || (newp+3 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+3, cStartNew, cEndNew);
    2391:       for (p = 0; p < 4; ++p) {
    2392:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
    2393:       }
    2394: #endif
    2395:       /* A' tetrahedron: {d, a, c, f} */
    2396:       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 0;
    2397:       orntNew[0] = -3;
    2398:       coneNew[1] = fStartNew + (cone[2] - fStart)*4 + 3;
    2399:       orntNew[1] = ornt[2] < 0 ? -(GetTetSomething_Static(ornt[2], 0)+1) : GetTetSomething_Static(ornt[2], 0);
    2400:       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 5;
    2401:       orntNew[2] = 0;
    2402:       coneNew[3] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 4;
    2403:       orntNew[3] = 2;
    2404:       DMPlexSetCone(rdm, newp+4, coneNew);
    2405:       DMPlexSetConeOrientation(rdm, newp+4, orntNew);
    2406: #if 1
    2407:       if ((newp+4 < cStartNew) || (newp+4 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+4, cStartNew, cEndNew);
    2408:       for (p = 0; p < 4; ++p) {
    2409:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
    2410:       }
    2411: #endif
    2412:       /* B' tetrahedron: {e, b, a, f} */
    2413:       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 1;
    2414:       orntNew[0] = -3;
    2415:       coneNew[1] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 6;
    2416:       orntNew[1] = 1;
    2417:       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 7;
    2418:       orntNew[2] = 0;
    2419:       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + 3;
    2420:       orntNew[3] = ornt[3] < 0 ? -(GetTetSomething_Static(ornt[3], 0)+1) : GetTetSomething_Static(ornt[3], 0);
    2421:       DMPlexSetCone(rdm, newp+5, coneNew);
    2422:       DMPlexSetConeOrientation(rdm, newp+5, orntNew);
    2423: #if 1
    2424:       if ((newp+5 < cStartNew) || (newp+5 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+5, cStartNew, cEndNew);
    2425:       for (p = 0; p < 4; ++p) {
    2426:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
    2427:       }
    2428: #endif
    2429:       /* C' tetrahedron: {b, f, c, a} */
    2430:       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 2;
    2431:       orntNew[0] = -3;
    2432:       coneNew[1] = fStartNew + (cone[0] - fStart)*4 + 3;
    2433:       orntNew[1] = ornt[0] < 0 ? -(GetTetSomething_Static(ornt[0], 2)+1) : GetTetSomething_Static(ornt[0], 2);
    2434:       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 5;
    2435:       orntNew[2] = -3;
    2436:       coneNew[3] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 7;
    2437:       orntNew[3] = -2;
    2438:       DMPlexSetCone(rdm, newp+6, coneNew);
    2439:       DMPlexSetConeOrientation(rdm, newp+6, orntNew);
    2440: #if 1
    2441:       if ((newp+6 < cStartNew) || (newp+6 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+6, cStartNew, cEndNew);
    2442:       for (p = 0; p < 4; ++p) {
    2443:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
    2444:       }
    2445: #endif
    2446:       /* D' tetrahedron: {f, e, d, a} */
    2447:       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 3;
    2448:       orntNew[0] = -3;
    2449:       coneNew[1] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 4;
    2450:       orntNew[1] = -3;
    2451:       coneNew[2] = fStartNew + (cone[1] - fStart)*4 + 3;
    2452:       orntNew[2] = ornt[1] < 0 ? -(GetTetSomething_Static(ornt[1], 0)+1) : GetTetSomething_Static(ornt[1], 0);
    2453:       coneNew[3] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 6;
    2454:       orntNew[3] = -3;
    2455:       DMPlexSetCone(rdm, newp+7, coneNew);
    2456:       DMPlexSetConeOrientation(rdm, newp+7, orntNew);
    2457: #if 1
    2458:       if ((newp+7 < cStartNew) || (newp+7 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+7, cStartNew, cEndNew);
    2459:       for (p = 0; p < 4; ++p) {
    2460:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
    2461:       }
    2462: #endif
    2463:     }
    2464:     /* Split faces have 3 edges and the same cells as the parent */
    2465:     DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);
    2466:     PetscMalloc1(2 + maxSupportSize*2, &supportRef);
    2467:     for (f = fStart; f < fEnd; ++f) {
    2468:       const PetscInt  newp = fStartNew + (f - fStart)*4;
    2469:       const PetscInt *cone, *ornt, *support;
    2470:       PetscInt        coneNew[3], orntNew[3], coneSize, supportSize, s;

    2472:       DMPlexGetCone(dm, f, &cone);
    2473:       DMPlexGetConeOrientation(dm, f, &ornt);
    2474:       /* A triangle */
    2475:       coneNew[0] = eStartNew + (cone[0] - eStart)*2 + (ornt[0] < 0 ? 1 : 0);
    2476:       orntNew[0] = ornt[0];
    2477:       coneNew[1] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 2;
    2478:       orntNew[1] = -2;
    2479:       coneNew[2] = eStartNew + (cone[2] - eStart)*2 + (ornt[2] < 0 ? 0 : 1);
    2480:       orntNew[2] = ornt[2];
    2481:       DMPlexSetCone(rdm, newp+0, coneNew);
    2482:       DMPlexSetConeOrientation(rdm, newp+0, orntNew);
    2483: #if 1
    2484:       if ((newp+0 < fStartNew) || (newp+0 >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp+0, fStartNew, fEndNew);
    2485:       for (p = 0; p < 3; ++p) {
    2486:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eEndNew);
    2487:       }
    2488: #endif
    2489:       /* B triangle */
    2490:       coneNew[0] = eStartNew + (cone[0] - eStart)*2 + (ornt[0] < 0 ? 0 : 1);
    2491:       orntNew[0] = ornt[0];
    2492:       coneNew[1] = eStartNew + (cone[1] - eStart)*2 + (ornt[1] < 0 ? 1 : 0);
    2493:       orntNew[1] = ornt[1];
    2494:       coneNew[2] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 0;
    2495:       orntNew[2] = -2;
    2496:       DMPlexSetCone(rdm, newp+1, coneNew);
    2497:       DMPlexSetConeOrientation(rdm, newp+1, orntNew);
    2498: #if 1
    2499:       if ((newp+1 < fStartNew) || (newp+1 >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp+1, fStartNew, fEndNew);
    2500:       for (p = 0; p < 3; ++p) {
    2501:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eEndNew);
    2502:       }
    2503: #endif
    2504:       /* C triangle */
    2505:       coneNew[0] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 1;
    2506:       orntNew[0] = -2;
    2507:       coneNew[1] = eStartNew + (cone[1] - eStart)*2 + (ornt[1] < 0 ? 0 : 1);
    2508:       orntNew[1] = ornt[1];
    2509:       coneNew[2] = eStartNew + (cone[2] - eStart)*2 + (ornt[2] < 0 ? 1 : 0);
    2510:       orntNew[2] = ornt[2];
    2511:       DMPlexSetCone(rdm, newp+2, coneNew);
    2512:       DMPlexSetConeOrientation(rdm, newp+2, orntNew);
    2513: #if 1
    2514:       if ((newp+2 < fStartNew) || (newp+2 >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp+2, fStartNew, fEndNew);
    2515:       for (p = 0; p < 3; ++p) {
    2516:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eEndNew);
    2517:       }
    2518: #endif
    2519:       /* D triangle */
    2520:       coneNew[0] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 0;
    2521:       orntNew[0] = 0;
    2522:       coneNew[1] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 1;
    2523:       orntNew[1] = 0;
    2524:       coneNew[2] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 2;
    2525:       orntNew[2] = 0;
    2526:       DMPlexSetCone(rdm, newp+3, coneNew);
    2527:       DMPlexSetConeOrientation(rdm, newp+3, orntNew);
    2528: #if 1
    2529:       if ((newp+3 < fStartNew) || (newp+3 >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp+3, fStartNew, fEndNew);
    2530:       for (p = 0; p < 3; ++p) {
    2531:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eEndNew);
    2532:       }
    2533: #endif
    2534:       DMPlexGetSupportSize(dm, f, &supportSize);
    2535:       DMPlexGetSupport(dm, f, &support);
    2536:       for (r = 0; r < 4; ++r) {
    2537:         for (s = 0; s < supportSize; ++s) {
    2538:           PetscInt subf;
    2539:           DMPlexGetConeSize(dm, support[s], &coneSize);
    2540:           DMPlexGetCone(dm, support[s], &cone);
    2541:           DMPlexGetConeOrientation(dm, support[s], &ornt);
    2542:           for (c = 0; c < coneSize; ++c) {
    2543:             if (cone[c] == f) break;
    2544:           }
    2545:           subf = GetTriSubfaceInverse_Static(ornt[c], r);
    2546:           supportRef[s] = cStartNew + (support[s] - cStart)*8 + (r==3 ? (c+2)%4 + 4 : faces[c*3+subf]);
    2547:         }
    2548:         DMPlexSetSupport(rdm, newp+r, supportRef);
    2549: #if 1
    2550:         if ((newp+r < fStartNew) || (newp+r >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp+r, fStartNew, fEndNew);
    2551:         for (p = 0; p < supportSize; ++p) {
    2552:           if ((supportRef[p] < cStartNew) || (supportRef[p] >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportRef[p], cStartNew, cEndNew);
    2553:         }
    2554: #endif
    2555:       }
    2556:     }
    2557:     /* Interior faces have 3 edges and 2 cells */
    2558:     for (c = cStart; c < cEnd; ++c) {
    2559:       PetscInt        newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*8;
    2560:       const PetscInt *cone, *ornt;
    2561:       PetscInt        coneNew[3], orntNew[3];
    2562:       PetscInt        supportNew[2];

    2564:       DMPlexGetCone(dm, c, &cone);
    2565:       DMPlexGetConeOrientation(dm, c, &ornt);
    2566:       /* Face A: {c, a, d} */
    2567:       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*3 + GetTetSomething_Static(ornt[0], 2);
    2568:       orntNew[0] = ornt[0] < 0 ? -2 : 0;
    2569:       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*3 + GetTetSomething_Static(ornt[1], 2);
    2570:       orntNew[1] = ornt[1] < 0 ? -2 : 0;
    2571:       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*3 + GetTetSomething_Static(ornt[2], 2);
    2572:       orntNew[2] = ornt[2] < 0 ? -2 : 0;
    2573:       DMPlexSetCone(rdm, newp, coneNew);
    2574:       DMPlexSetConeOrientation(rdm, newp, orntNew);
    2575: #if 1
    2576:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
    2577:       for (p = 0; p < 3; ++p) {
    2578:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eEndNew);
    2579:       }
    2580: #endif
    2581:       supportNew[0] = (c - cStart)*8 + 0;
    2582:       supportNew[1] = (c - cStart)*8 + 0+4;
    2583:       DMPlexSetSupport(rdm, newp, supportNew);
    2584: #if 1
    2585:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
    2586:       for (p = 0; p < 2; ++p) {
    2587:         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cEndNew);
    2588:       }
    2589: #endif
    2590:       ++newp;
    2591:       /* Face B: {a, b, e} */
    2592:       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*3 + GetTetSomething_Static(ornt[0], 0);
    2593:       orntNew[0] = ornt[0] < 0 ? -2 : 0;
    2594:       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*3 + GetTetSomething_Static(ornt[3], 0);
    2595:       orntNew[1] = ornt[3] < 0 ? -2 : 0;
    2596:       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*3 + GetTetSomething_Static(ornt[1], 1);
    2597:       orntNew[2] = ornt[1] < 0 ? -2 : 0;
    2598:       DMPlexSetCone(rdm, newp, coneNew);
    2599:       DMPlexSetConeOrientation(rdm, newp, orntNew);
    2600: #if 1
    2601:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
    2602:       for (p = 0; p < 3; ++p) {
    2603:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eEndNew);
    2604:       }
    2605: #endif
    2606:       supportNew[0] = (c - cStart)*8 + 1;
    2607:       supportNew[1] = (c - cStart)*8 + 1+4;
    2608:       DMPlexSetSupport(rdm, newp, supportNew);
    2609: #if 1
    2610:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
    2611:       for (p = 0; p < 2; ++p) {
    2612:         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cEndNew);
    2613:       }
    2614: #endif
    2615:       ++newp;
    2616:       /* Face C: {c, f, b} */
    2617:       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*3 + GetTetSomething_Static(ornt[2], 0);
    2618:       orntNew[0] = ornt[2] < 0 ? -2 : 0;
    2619:       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*3 + GetTetSomething_Static(ornt[3], 2);
    2620:       orntNew[1] = ornt[3] < 0 ? -2 : 0;
    2621:       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*3 + GetTetSomething_Static(ornt[0], 1);
    2622:       orntNew[2] = ornt[0] < 0 ? -2 : 0;
    2623:       DMPlexSetCone(rdm, newp, coneNew);
    2624:       DMPlexSetConeOrientation(rdm, newp, orntNew);
    2625: #if 1
    2626:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
    2627:       for (p = 0; p < 3; ++p) {
    2628:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eEndNew);
    2629:       }
    2630: #endif
    2631:       supportNew[0] = (c - cStart)*8 + 2;
    2632:       supportNew[1] = (c - cStart)*8 + 2+4;
    2633:       DMPlexSetSupport(rdm, newp, supportNew);
    2634: #if 1
    2635:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
    2636:       for (p = 0; p < 2; ++p) {
    2637:         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cEndNew);
    2638:       }
    2639: #endif
    2640:       ++newp;
    2641:       /* Face D: {d, e, f} */
    2642:       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*3 + GetTetSomething_Static(ornt[1], 0);
    2643:       orntNew[0] = ornt[1] < 0 ? -2 : 0;
    2644:       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*3 + GetTetSomething_Static(ornt[3], 1);
    2645:       orntNew[1] = ornt[3] < 0 ? -2 : 0;
    2646:       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*3 + GetTetSomething_Static(ornt[2], 1);
    2647:       orntNew[2] = ornt[2] < 0 ? -2 : 0;
    2648:       DMPlexSetCone(rdm, newp, coneNew);
    2649:       DMPlexSetConeOrientation(rdm, newp, orntNew);
    2650: #if 1
    2651:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
    2652:       for (p = 0; p < 3; ++p) {
    2653:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eEndNew);
    2654:       }
    2655: #endif
    2656:       supportNew[0] = (c - cStart)*8 + 3;
    2657:       supportNew[1] = (c - cStart)*8 + 3+4;
    2658:       DMPlexSetSupport(rdm, newp, supportNew);
    2659: #if 1
    2660:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
    2661:       for (p = 0; p < 2; ++p) {
    2662:         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cEndNew);
    2663:       }
    2664: #endif
    2665:       ++newp;
    2666:       /* Face E: {d, f, a} */
    2667:       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*3 + GetTetSomething_Static(ornt[2], 1);
    2668:       orntNew[0] = ornt[2] < 0 ? 0 : -2;
    2669:       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart);
    2670:       orntNew[1] = -2;
    2671:       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*3 + GetTetSomething_Static(ornt[1], 2);
    2672:       orntNew[2] = ornt[1] < 0 ? -2 : 0;
    2673:       DMPlexSetCone(rdm, newp, coneNew);
    2674:       DMPlexSetConeOrientation(rdm, newp, orntNew);
    2675: #if 1
    2676:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
    2677:       for (p = 0; p < 3; ++p) {
    2678:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eEndNew);
    2679:       }
    2680: #endif
    2681:       supportNew[0] = (c - cStart)*8 + 0+4;
    2682:       supportNew[1] = (c - cStart)*8 + 3+4;
    2683:       DMPlexSetSupport(rdm, newp, supportNew);
    2684: #if 1
    2685:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
    2686:       for (p = 0; p < 2; ++p) {
    2687:         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cEndNew);
    2688:       }
    2689: #endif
    2690:       ++newp;
    2691:       /* Face F: {c, a, f} */
    2692:       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*3 + GetTetSomething_Static(ornt[0], 2);
    2693:       orntNew[0] = ornt[0] < 0 ? -2 : 0;
    2694:       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart);
    2695:       orntNew[1] = 0;
    2696:       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*3 + GetTetSomething_Static(ornt[2], 0);
    2697:       orntNew[2] = ornt[2] < 0 ? 0 : -2;
    2698:       DMPlexSetCone(rdm, newp, coneNew);
    2699:       DMPlexSetConeOrientation(rdm, newp, orntNew);
    2700: #if 1
    2701:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
    2702:       for (p = 0; p < 3; ++p) {
    2703:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eEndNew);
    2704:       }
    2705: #endif
    2706:       supportNew[0] = (c - cStart)*8 + 0+4;
    2707:       supportNew[1] = (c - cStart)*8 + 2+4;
    2708:       DMPlexSetSupport(rdm, newp, supportNew);
    2709: #if 1
    2710:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
    2711:       for (p = 0; p < 2; ++p) {
    2712:         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cEndNew);
    2713:       }
    2714: #endif
    2715:       ++newp;
    2716:       /* Face G: {e, a, f} */
    2717:       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*3 + GetTetSomething_Static(ornt[1], 1);
    2718:       orntNew[0] = ornt[1] < 0 ? -2 : 0;
    2719:       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart);
    2720:       orntNew[1] = 0;
    2721:       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*3 + GetTetSomething_Static(ornt[3], 1);
    2722:       orntNew[2] = ornt[3] < 0 ? 0 : -2;
    2723:       DMPlexSetCone(rdm, newp, coneNew);
    2724:       DMPlexSetConeOrientation(rdm, newp, orntNew);
    2725: #if 1
    2726:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
    2727:       for (p = 0; p < 3; ++p) {
    2728:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eEndNew);
    2729:       }
    2730: #endif
    2731:       supportNew[0] = (c - cStart)*8 + 1+4;
    2732:       supportNew[1] = (c - cStart)*8 + 3+4;
    2733:       DMPlexSetSupport(rdm, newp, supportNew);
    2734: #if 1
    2735:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
    2736:       for (p = 0; p < 2; ++p) {
    2737:         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cEndNew);
    2738:       }
    2739: #endif
    2740:       ++newp;
    2741:       /* Face H: {a, b, f} */
    2742:       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*3 + GetTetSomething_Static(ornt[0], 0);
    2743:       orntNew[0] = ornt[0] < 0 ? -2 : 0;
    2744:       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*3 + GetTetSomething_Static(ornt[3], 2);
    2745:       orntNew[1] = ornt[3] < 0 ? 0 : -2;
    2746:       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart);
    2747:       orntNew[2] = -2;
    2748:       DMPlexSetCone(rdm, newp, coneNew);
    2749:       DMPlexSetConeOrientation(rdm, newp, orntNew);
    2750: #if 1
    2751:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
    2752:       for (p = 0; p < 3; ++p) {
    2753:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eEndNew);
    2754:       }
    2755: #endif
    2756:       supportNew[0] = (c - cStart)*8 + 1+4;
    2757:       supportNew[1] = (c - cStart)*8 + 2+4;
    2758:       DMPlexSetSupport(rdm, newp, supportNew);
    2759: #if 1
    2760:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
    2761:       for (p = 0; p < 2; ++p) {
    2762:         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cEndNew);
    2763:       }
    2764: #endif
    2765:       ++newp;
    2766:     }
    2767:     /* Split Edges have 2 vertices and the same faces as the parent */
    2768:     for (e = eStart; e < eEnd; ++e) {
    2769:       const PetscInt newv = vStartNew + (vEnd - vStart) + (e - eStart);

    2771:       for (r = 0; r < 2; ++r) {
    2772:         const PetscInt  newp = eStartNew + (e - eStart)*2 + r;
    2773:         const PetscInt *cone, *ornt, *support;
    2774:         PetscInt        coneNew[2], coneSize, c, supportSize, s;

    2776:         DMPlexGetCone(dm, e, &cone);
    2777:         coneNew[0]       = vStartNew + (cone[0] - vStart);
    2778:         coneNew[1]       = vStartNew + (cone[1] - vStart);
    2779:         coneNew[(r+1)%2] = newv;
    2780:         DMPlexSetCone(rdm, newp, coneNew);
    2781: #if 1
    2782:         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
    2783:         for (p = 0; p < 2; ++p) {
    2784:           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
    2785:         }
    2786: #endif
    2787:         DMPlexGetSupportSize(dm, e, &supportSize);
    2788:         DMPlexGetSupport(dm, e, &support);
    2789:         for (s = 0; s < supportSize; ++s) {
    2790:           DMPlexGetConeSize(dm, support[s], &coneSize);
    2791:           DMPlexGetCone(dm, support[s], &cone);
    2792:           DMPlexGetConeOrientation(dm, support[s], &ornt);
    2793:           for (c = 0; c < coneSize; ++c) {
    2794:             if (cone[c] == e) break;
    2795:           }
    2796:           supportRef[s] = fStartNew + (support[s] - fStart)*4 + (c + (ornt[c] < 0 ? 1-r : r))%3;
    2797:         }
    2798:         DMPlexSetSupport(rdm, newp, supportRef);
    2799: #if 1
    2800:         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
    2801:         for (p = 0; p < supportSize; ++p) {
    2802:           if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", supportRef[p], fStartNew, fEndNew);
    2803:         }
    2804: #endif
    2805:       }
    2806:     }
    2807:     /* Face edges have 2 vertices and 2+cells*(1/2) faces */
    2808:     for (f = fStart; f < fEnd; ++f) {
    2809:       const PetscInt *cone, *ornt, *support;
    2810:       PetscInt        coneSize, supportSize, s;

    2812:       DMPlexGetSupportSize(dm, f, &supportSize);
    2813:       DMPlexGetSupport(dm, f, &support);
    2814:       for (r = 0; r < 3; ++r) {
    2815:         const PetscInt  newp = eStartNew + (eEnd - eStart)*2 + (f - fStart)*3 + r;
    2816:         PetscInt        coneNew[2], intFaces = 0, er, eint[4] = {1, 0, 2, 0};
    2817:         PetscInt        fint[24] = { 1,  7, -1, -1,  0,  5,
    2818:                                     -1, -1,  1,  6,  0,  4,
    2819:                                      2,  5,  3,  4, -1, -1,
    2820:                                     -1, -1,  3,  6,  2,  7};

    2822:         DMPlexGetCone(dm, f, &cone);
    2823:         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[(r+0)%3] - eStart);
    2824:         coneNew[1] = vStartNew + (vEnd - vStart) + (cone[(r+1)%3] - eStart);
    2825:         DMPlexSetCone(rdm, newp, coneNew);
    2826: #if 1
    2827:         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
    2828:         for (p = 0; p < 2; ++p) {
    2829:           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
    2830:         }
    2831: #endif
    2832:         supportRef[0] = fStartNew + (f - fStart)*4 + (r+1)%3;
    2833:         supportRef[1] = fStartNew + (f - fStart)*4 + 3;
    2834:         for (s = 0; s < supportSize; ++s) {
    2835:           DMPlexGetConeSize(dm, support[s], &coneSize);
    2836:           DMPlexGetCone(dm, support[s], &cone);
    2837:           DMPlexGetConeOrientation(dm, support[s], &ornt);
    2838:           for (c = 0; c < coneSize; ++c) {if (cone[c] == f) break;}
    2839:           /* Here we want to determine whether edge newp contains a vertex which is part of the cross-tet edge */
    2840:           er = GetTetSomethingInverse_Static(ornt[c], r);
    2841:           if (er == eint[c]) {
    2842:             supportRef[2+intFaces++] = fStartNew + (fEnd - fStart)*4 + (support[s] - cStart)*8 + (c + 2)%4;
    2843:           } else {
    2844:             supportRef[2+intFaces++] = fStartNew + (fEnd - fStart)*4 + (support[s] - cStart)*8 + fint[(c*3 + er)*2 + 0];
    2845:             supportRef[2+intFaces++] = fStartNew + (fEnd - fStart)*4 + (support[s] - cStart)*8 + fint[(c*3 + er)*2 + 1];
    2846:           }
    2847:         }
    2848:         DMPlexSetSupport(rdm, newp, supportRef);
    2849: #if 1
    2850:         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
    2851:         for (p = 0; p < intFaces; ++p) {
    2852:           if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", supportRef[p], fStartNew, fEndNew);
    2853:         }
    2854: #endif
    2855:       }
    2856:     }
    2857:     /* Interior edges have 2 vertices and 4 faces */
    2858:     for (c = cStart; c < cEnd; ++c) {
    2859:       const PetscInt  newp = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart);
    2860:       const PetscInt *cone, *ornt, *fcone;
    2861:       PetscInt        coneNew[2], supportNew[4], find;

    2863:       DMPlexGetCone(dm, c, &cone);
    2864:       DMPlexGetConeOrientation(dm, c, &ornt);
    2865:       DMPlexGetCone(dm, cone[0], &fcone);
    2866:       find = GetTriEdge_Static(ornt[0], 0);
    2867:       coneNew[0] = vStartNew + (vEnd - vStart) + (fcone[find] - eStart);
    2868:       DMPlexGetCone(dm, cone[2], &fcone);
    2869:       find = GetTriEdge_Static(ornt[2], 1);
    2870:       coneNew[1] = vStartNew + (vEnd - vStart) + (fcone[find] - eStart);
    2871:       DMPlexSetCone(rdm, newp, coneNew);
    2872: #if 1
    2873:       if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
    2874:       for (p = 0; p < 2; ++p) {
    2875:         if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
    2876:       }
    2877: #endif
    2878:       supportNew[0] = fStartNew + (fEnd - fStart)*4 + (c - cStart)*8 + 4;
    2879:       supportNew[1] = fStartNew + (fEnd - fStart)*4 + (c - cStart)*8 + 5;
    2880:       supportNew[2] = fStartNew + (fEnd - fStart)*4 + (c - cStart)*8 + 6;
    2881:       supportNew[3] = fStartNew + (fEnd - fStart)*4 + (c - cStart)*8 + 7;
    2882:       DMPlexSetSupport(rdm, newp, supportNew);
    2883: #if 1
    2884:       if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
    2885:       for (p = 0; p < 4; ++p) {
    2886:         if ((supportNew[p] < fStartNew) || (supportNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", supportNew[p], fStartNew, fEndNew);
    2887:       }
    2888: #endif
    2889:     }
    2890:     /* Old vertices have identical supports */
    2891:     for (v = vStart; v < vEnd; ++v) {
    2892:       const PetscInt  newp = vStartNew + (v - vStart);
    2893:       const PetscInt *support, *cone;
    2894:       PetscInt        size, s;

    2896:       DMPlexGetSupportSize(dm, v, &size);
    2897:       DMPlexGetSupport(dm, v, &support);
    2898:       for (s = 0; s < size; ++s) {
    2899:         PetscInt r = 0;

    2901:         DMPlexGetCone(dm, support[s], &cone);
    2902:         if (cone[1] == v) r = 1;
    2903:         supportRef[s] = eStartNew + (support[s] - eStart)*2 + r;
    2904:       }
    2905:       DMPlexSetSupport(rdm, newp, supportRef);
    2906: #if 1
    2907:       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
    2908:       for (p = 0; p < size; ++p) {
    2909:         if ((supportRef[p] < eStartNew) || (supportRef[p] >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", supportRef[p], eStartNew, eEndNew);
    2910:       }
    2911: #endif
    2912:     }
    2913:     /* Edge vertices have 2 + face*2 + 0/1 supports */
    2914:     for (e = eStart; e < eEnd; ++e) {
    2915:       const PetscInt  newp = vStartNew + (vEnd - vStart) + (e - eStart);
    2916:       const PetscInt *cone, *support;
    2917:       PetscInt       *star = NULL, starSize, cellSize = 0, coneSize, size, s;

    2919:       DMPlexGetSupportSize(dm, e, &size);
    2920:       DMPlexGetSupport(dm, e, &support);
    2921:       supportRef[0] = eStartNew + (e - eStart)*2 + 0;
    2922:       supportRef[1] = eStartNew + (e - eStart)*2 + 1;
    2923:       for (s = 0; s < size; ++s) {
    2924:         PetscInt r = 0;

    2926:         DMPlexGetConeSize(dm, support[s], &coneSize);
    2927:         DMPlexGetCone(dm, support[s], &cone);
    2928:         for (r = 0; r < coneSize; ++r) {if (cone[r] == e) break;}
    2929:         supportRef[2+s*2+0] = eStartNew + (eEnd - eStart)*2 + (support[s] - fStart)*3 + (r+0)%3;
    2930:         supportRef[2+s*2+1] = eStartNew + (eEnd - eStart)*2 + (support[s] - fStart)*3 + (r+2)%3;
    2931:       }
    2932:       DMPlexGetTransitiveClosure(dm, e, PETSC_FALSE, &starSize, &star);
    2933:       for (s = 0; s < starSize*2; s += 2) {
    2934:         const PetscInt *cone, *ornt;
    2935:         PetscInt        e01, e23;

    2937:         if ((star[s] >= cStart) && (star[s] < cEnd)) {
    2938:           /* Check edge 0-1 */
    2939:           DMPlexGetCone(dm, star[s], &cone);
    2940:           DMPlexGetConeOrientation(dm, star[s], &ornt);
    2941:           DMPlexGetCone(dm, cone[0], &cone);
    2942:           e01  = cone[GetTriEdge_Static(ornt[0], 0)];
    2943:           /* Check edge 2-3 */
    2944:           DMPlexGetCone(dm, star[s], &cone);
    2945:           DMPlexGetConeOrientation(dm, star[s], &ornt);
    2946:           DMPlexGetCone(dm, cone[2], &cone);
    2947:           e23  = cone[GetTriEdge_Static(ornt[2], 1)];
    2948:           if ((e01 == e) || (e23 == e)) {supportRef[2+size*2+cellSize++] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (star[s] - cStart);}
    2949:         }
    2950:       }
    2951:       DMPlexRestoreTransitiveClosure(dm, e, PETSC_FALSE, &starSize, &star);
    2952:       DMPlexSetSupport(rdm, newp, supportRef);
    2953: #if 1
    2954:       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
    2955:       for (p = 0; p < 2+size*2+cellSize; ++p) {
    2956:         if ((supportRef[p] < eStartNew) || (supportRef[p] >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", supportRef[p], eStartNew, eEndNew);
    2957:       }
    2958: #endif
    2959:     }
    2960:     PetscFree(supportRef);
    2961:     DMPlexRestoreFaces_Internal(dm, 3, cStart, NULL, NULL, &faces);
    2962:     break;
    2963:   case REFINER_HYBRID_SIMPLEX_3D:
    2964:     DMPlexGetHybridBounds(rdm, &cMaxNew, &fMaxNew, &eMaxNew, NULL);
    2965:     /* Interior cells have 4 faces: Tet face order is prescribed in DMPlexGetFaces_Internal() */
    2966:     DMPlexGetRawFaces_Internal(dm, 3, 4, cellInd, NULL, NULL, &faces);
    2967:     for (c = cStart; c < cMax; ++c) {
    2968:       const PetscInt  newp = cStartNew + (c - cStart)*8;
    2969:       const PetscInt *cone, *ornt;
    2970:       PetscInt        coneNew[4], orntNew[4];

    2972:       DMPlexGetCone(dm, c, &cone);
    2973:       DMPlexGetConeOrientation(dm, c, &ornt);
    2974:       /* A tetrahedron: {0, a, c, d} */
    2975:       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetTriSubface_Static(ornt[0], 0); /* A */
    2976:       orntNew[0] = ornt[0];
    2977:       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetTriSubface_Static(ornt[1], 0); /* A */
    2978:       orntNew[1] = ornt[1];
    2979:       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetTriSubface_Static(ornt[2], 0); /* A */
    2980:       orntNew[2] = ornt[2];
    2981:       coneNew[3] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 0;
    2982:       orntNew[3] = 0;
    2983:       DMPlexSetCone(rdm, newp+0, coneNew);
    2984:       DMPlexSetConeOrientation(rdm, newp+0, orntNew);
    2985: #if 1
    2986:       if ((newp+0 < cStartNew) || (newp+0 >= cMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+0, cStartNew, cMaxNew);
    2987:       for (p = 0; p < 4; ++p) {
    2988:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fMaxNew);
    2989:       }
    2990: #endif
    2991:       /* B tetrahedron: {a, 1, b, e} */
    2992:       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetTriSubface_Static(ornt[0], 1); /* B */
    2993:       orntNew[0] = ornt[0];
    2994:       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetTriSubface_Static(ornt[1], 2); /* C */
    2995:       orntNew[1] = ornt[1];
    2996:       coneNew[2] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 1;
    2997:       orntNew[2] = 0;
    2998:       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetTriSubface_Static(ornt[3], 1); /* B */
    2999:       orntNew[3] = ornt[3];
    3000:       DMPlexSetCone(rdm, newp+1, coneNew);
    3001:       DMPlexSetConeOrientation(rdm, newp+1, orntNew);
    3002: #if 1
    3003:       if ((newp+1 < cStartNew) || (newp+1 >= cMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+1, cStartNew, cMaxNew);
    3004:       for (p = 0; p < 4; ++p) {
    3005:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fMaxNew);
    3006:       }
    3007: #endif
    3008:       /* C tetrahedron: {c, b, 2, f} */
    3009:       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetTriSubface_Static(ornt[0], 2); /* C */
    3010:       orntNew[0] = ornt[0];
    3011:       coneNew[1] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 2;
    3012:       orntNew[1] = 0;
    3013:       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetTriSubface_Static(ornt[2], 1); /* B */
    3014:       orntNew[2] = ornt[2];
    3015:       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetTriSubface_Static(ornt[3], 0); /* A */
    3016:       orntNew[3] = ornt[3];
    3017:       DMPlexSetCone(rdm, newp+2, coneNew);
    3018:       DMPlexSetConeOrientation(rdm, newp+2, orntNew);
    3019: #if 1
    3020:       if ((newp+2 < cStartNew) || (newp+2 >= cMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+2, cStartNew, cMaxNew);
    3021:       for (p = 0; p < 4; ++p) {
    3022:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fMaxNew);
    3023:       }
    3024: #endif
    3025:       /* D tetrahedron: {d, e, f, 3} */
    3026:       coneNew[0] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 3;
    3027:       orntNew[0] = 0;
    3028:       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetTriSubface_Static(ornt[1], 1); /* B */
    3029:       orntNew[1] = ornt[1];
    3030:       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetTriSubface_Static(ornt[2], 2); /* C */
    3031:       orntNew[2] = ornt[2];
    3032:       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetTriSubface_Static(ornt[3], 2); /* C */
    3033:       orntNew[3] = ornt[3];
    3034:       DMPlexSetCone(rdm, newp+3, coneNew);
    3035:       DMPlexSetConeOrientation(rdm, newp+3, orntNew);
    3036: #if 1
    3037:       if ((newp+3 < cStartNew) || (newp+3 >= cMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+3, cStartNew, cMaxNew);
    3038:       for (p = 0; p < 4; ++p) {
    3039:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fMaxNew);
    3040:       }
    3041: #endif
    3042:       /* A' tetrahedron: {d, a, c, f} */
    3043:       coneNew[0] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 0;
    3044:       orntNew[0] = -3;
    3045:       coneNew[1] = fStartNew + (cone[2] - fStart)*4 + 3;
    3046:       orntNew[1] = ornt[2] < 0 ? -(GetTetSomething_Static(ornt[2], 0)+1) : GetTetSomething_Static(ornt[2], 0);
    3047:       coneNew[2] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 5;
    3048:       orntNew[2] = 0;
    3049:       coneNew[3] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 4;
    3050:       orntNew[3] = 2;
    3051:       DMPlexSetCone(rdm, newp+4, coneNew);
    3052:       DMPlexSetConeOrientation(rdm, newp+4, orntNew);
    3053: #if 1
    3054:       if ((newp+4 < cStartNew) || (newp+4 >= cMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+4, cStartNew, cMaxNew);
    3055:       for (p = 0; p < 4; ++p) {
    3056:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fMaxNew);
    3057:       }
    3058: #endif
    3059:       /* B' tetrahedron: {e, b, a, f} */
    3060:       coneNew[0] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 1;
    3061:       orntNew[0] = -3;
    3062:       coneNew[1] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 6;
    3063:       orntNew[1] = 1;
    3064:       coneNew[2] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 7;
    3065:       orntNew[2] = 0;
    3066:       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + 3;
    3067:       orntNew[3] = ornt[3] < 0 ? -(GetTetSomething_Static(ornt[3], 0)+1) : GetTetSomething_Static(ornt[3], 0);
    3068:       DMPlexSetCone(rdm, newp+5, coneNew);
    3069:       DMPlexSetConeOrientation(rdm, newp+5, orntNew);
    3070: #if 1
    3071:       if ((newp+5 < cStartNew) || (newp+5 >= cMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+5, cStartNew, cMaxNew);
    3072:       for (p = 0; p < 4; ++p) {
    3073:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fMaxNew);
    3074:       }
    3075: #endif
    3076:       /* C' tetrahedron: {b, f, c, a} */
    3077:       coneNew[0] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 2;
    3078:       orntNew[0] = -3;
    3079:       coneNew[1] = fStartNew + (cone[0] - fStart)*4 + 3;
    3080:       orntNew[1] = ornt[0] < 0 ? -(GetTetSomething_Static(ornt[0], 2)+1) : GetTetSomething_Static(ornt[0], 2);
    3081:       coneNew[2] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 5;
    3082:       orntNew[2] = -3;
    3083:       coneNew[3] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 7;
    3084:       orntNew[3] = -2;
    3085:       DMPlexSetCone(rdm, newp+6, coneNew);
    3086:       DMPlexSetConeOrientation(rdm, newp+6, orntNew);
    3087: #if 1
    3088:       if ((newp+6 < cStartNew) || (newp+6 >= cMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+6, cStartNew, cMaxNew);
    3089:       for (p = 0; p < 4; ++p) {
    3090:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fMaxNew);
    3091:       }
    3092: #endif
    3093:       /* D' tetrahedron: {f, e, d, a} */
    3094:       coneNew[0] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 3;
    3095:       orntNew[0] = -3;
    3096:       coneNew[1] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 4;
    3097:       orntNew[1] = -3;
    3098:       coneNew[2] = fStartNew + (cone[1] - fStart)*4 + 3;
    3099:       orntNew[2] = ornt[1] < 0 ? -(GetTetSomething_Static(ornt[1], 0)+1) : GetTetSomething_Static(ornt[1], 0);
    3100:       coneNew[3] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 6;
    3101:       orntNew[3] = -3;
    3102:       DMPlexSetCone(rdm, newp+7, coneNew);
    3103:       DMPlexSetConeOrientation(rdm, newp+7, orntNew);
    3104: #if 1
    3105:       if ((newp+7 < cStartNew) || (newp+7 >= cMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+7, cStartNew, cMaxNew);
    3106:       for (p = 0; p < 4; ++p) {
    3107:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fMaxNew);
    3108:       }
    3109: #endif
    3110:     }
    3111:     /* Hybrid cells have 5 faces */
    3112:     for (c = cMax; c < cEnd; ++c) {
    3113:       const PetscInt  newp = cStartNew + (cMax - cStart)*8 + (c - cMax)*4;
    3114:       const PetscInt *cone, *ornt, *fornt;
    3115:       PetscInt        coneNew[5], orntNew[5], o, of, i;

    3117:       DMPlexGetCone(dm, c, &cone);
    3118:       DMPlexGetConeOrientation(dm, c, &ornt);
    3119:       DMPlexGetConeOrientation(dm, cone[0], &fornt);
    3120:       o = ornt[0] < 0 ? -1 : 1;
    3121:       for (r = 0; r < 3; ++r) {
    3122:         coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetTriSubface_Static(ornt[0], r);
    3123:         orntNew[0] = ornt[0];
    3124:         coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetTriSubface_Static(ornt[1], r);
    3125:         orntNew[1] = ornt[1];
    3126:         of = fornt[GetTriEdge_Static(ornt[0], r)]       < 0 ? -1 : 1;
    3127:         i  = GetTriEdgeInverse_Static(ornt[0], r)       + 2;
    3128:         coneNew[i] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (cone[2+GetTriEdge_Static(ornt[0], r)]       - fMax)*2 + (o*of < 0 ? 1 : 0);
    3129:         orntNew[i] = 0;
    3130:         i  = GetTriEdgeInverse_Static(ornt[0], (r+1)%3) + 2;
    3131:         coneNew[i] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (c - cMax)*3 + GetTriSubface_Static(ornt[0], r);
    3132:         orntNew[i] = 0;
    3133:         of = fornt[GetTriEdge_Static(ornt[0], (r+2)%3)] < 0 ? -1 : 1;
    3134:         i  = GetTriEdgeInverse_Static(ornt[0], (r+2)%3) + 2;
    3135:         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);
    3136:         orntNew[i] = 0;
    3137:         DMPlexSetCone(rdm, newp+r, coneNew);
    3138:         DMPlexSetConeOrientation(rdm, newp+r, orntNew);
    3139: #if 1
    3140:         if ((newp+r < cMaxNew) || (newp+r >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid cell [%d, %d)", newp+r, cMaxNew, cEndNew);
    3141:         for (p = 0; p < 2; ++p) {
    3142:           if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fMaxNew);
    3143:         }
    3144:         for (p = 2; p < 5; ++p) {
    3145:           if ((coneNew[p] < fMaxNew)   || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid face [%d, %d)", coneNew[p], fMaxNew, fEndNew);
    3146:         }
    3147: #endif
    3148:       }
    3149:       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + 3;
    3150:       orntNew[0] = 0;
    3151:       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + 3;
    3152:       orntNew[1] = 0;
    3153:       coneNew[2] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (c - cMax)*3 + 1;
    3154:       orntNew[2] = 0;
    3155:       coneNew[3] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (c - cMax)*3 + 2;
    3156:       orntNew[3] = 0;
    3157:       coneNew[4] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (c - cMax)*3 + 0;
    3158:       orntNew[4] = 0;
    3159:       DMPlexSetCone(rdm, newp+3, coneNew);
    3160:       DMPlexSetConeOrientation(rdm, newp+3, orntNew);
    3161: #if 1
    3162:       if ((newp+3 < cMaxNew) || (newp+3 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid cell [%d, %d)", newp+3, cMaxNew, cEndNew);
    3163:       for (p = 0; p < 2; ++p) {
    3164:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fMaxNew);
    3165:       }
    3166:       for (p = 2; p < 5; ++p) {
    3167:         if ((coneNew[p] < fMaxNew)   || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid face [%d, %d)", coneNew[p], fMaxNew, fEndNew);
    3168:       }
    3169: #endif
    3170:     }
    3171:     /* Split faces have 3 edges and the same cells as the parent */
    3172:     DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);
    3173:     PetscMalloc1(2 + maxSupportSize*2, &supportRef);
    3174:     for (f = fStart; f < fMax; ++f) {
    3175:       const PetscInt  newp = fStartNew + (f - fStart)*4;
    3176:       const PetscInt *cone, *ornt, *support;
    3177:       PetscInt        coneNew[3], orntNew[3], coneSize, supportSize, s;

    3179:       DMPlexGetCone(dm, f, &cone);
    3180:       DMPlexGetConeOrientation(dm, f, &ornt);
    3181:       /* A triangle */
    3182:       coneNew[0] = eStartNew + (cone[0] - eStart)*2 + (ornt[0] < 0 ? 1 : 0);
    3183:       orntNew[0] = ornt[0];
    3184:       coneNew[1] = eStartNew + (eMax    - eStart)*2 + (f - fStart)*3 + 2;
    3185:       orntNew[1] = -2;
    3186:       coneNew[2] = eStartNew + (cone[2] - eStart)*2 + (ornt[2] < 0 ? 0 : 1);
    3187:       orntNew[2] = ornt[2];
    3188:       DMPlexSetCone(rdm, newp+0, coneNew);
    3189:       DMPlexSetConeOrientation(rdm, newp+0, orntNew);
    3190: #if 1
    3191:       if ((newp+0 < fStartNew) || (newp+0 >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp+0, fStartNew, fMaxNew);
    3192:       for (p = 0; p < 3; ++p) {
    3193:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eMaxNew);
    3194:       }
    3195: #endif
    3196:       /* B triangle */
    3197:       coneNew[0] = eStartNew + (cone[0] - eStart)*2 + (ornt[0] < 0 ? 0 : 1);
    3198:       orntNew[0] = ornt[0];
    3199:       coneNew[1] = eStartNew + (cone[1] - eStart)*2 + (ornt[1] < 0 ? 1 : 0);
    3200:       orntNew[1] = ornt[1];
    3201:       coneNew[2] = eStartNew + (eMax    - eStart)*2 + (f - fStart)*3 + 0;
    3202:       orntNew[2] = -2;
    3203:       DMPlexSetCone(rdm, newp+1, coneNew);
    3204:       DMPlexSetConeOrientation(rdm, newp+1, orntNew);
    3205: #if 1
    3206:       if ((newp+1 < fStartNew) || (newp+1 >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp+1, fStartNew, fMaxNew);
    3207:       for (p = 0; p < 3; ++p) {
    3208:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eMaxNew);
    3209:       }
    3210: #endif
    3211:       /* C triangle */
    3212:       coneNew[0] = eStartNew + (eMax    - eStart)*2 + (f - fStart)*3 + 1;
    3213:       orntNew[0] = -2;
    3214:       coneNew[1] = eStartNew + (cone[1] - eStart)*2 + (ornt[1] < 0 ? 0 : 1);
    3215:       orntNew[1] = ornt[1];
    3216:       coneNew[2] = eStartNew + (cone[2] - eStart)*2 + (ornt[2] < 0 ? 1 : 0);
    3217:       orntNew[2] = ornt[2];
    3218:       DMPlexSetCone(rdm, newp+2, coneNew);
    3219:       DMPlexSetConeOrientation(rdm, newp+2, orntNew);
    3220: #if 1
    3221:       if ((newp+2 < fStartNew) || (newp+2 >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp+2, fStartNew, fMaxNew);
    3222:       for (p = 0; p < 3; ++p) {
    3223:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eMaxNew);
    3224:       }
    3225: #endif
    3226:       /* D triangle */
    3227:       coneNew[0] = eStartNew + (eMax    - eStart)*2 + (f - fStart)*3 + 0;
    3228:       orntNew[0] = 0;
    3229:       coneNew[1] = eStartNew + (eMax    - eStart)*2 + (f - fStart)*3 + 1;
    3230:       orntNew[1] = 0;
    3231:       coneNew[2] = eStartNew + (eMax    - eStart)*2 + (f - fStart)*3 + 2;
    3232:       orntNew[2] = 0;
    3233:       DMPlexSetCone(rdm, newp+3, coneNew);
    3234:       DMPlexSetConeOrientation(rdm, newp+3, orntNew);
    3235: #if 1
    3236:       if ((newp+3 < fStartNew) || (newp+3 >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp+3, fStartNew, fMaxNew);
    3237:       for (p = 0; p < 3; ++p) {
    3238:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eMaxNew);
    3239:       }
    3240: #endif
    3241:       DMPlexGetSupportSize(dm, f, &supportSize);
    3242:       DMPlexGetSupport(dm, f, &support);
    3243:       for (r = 0; r < 4; ++r) {
    3244:         for (s = 0; s < supportSize; ++s) {
    3245:           PetscInt subf;
    3246:           DMPlexGetConeSize(dm, support[s], &coneSize);
    3247:           DMPlexGetCone(dm, support[s], &cone);
    3248:           DMPlexGetConeOrientation(dm, support[s], &ornt);
    3249:           for (c = 0; c < coneSize; ++c) {
    3250:             if (cone[c] == f) break;
    3251:           }
    3252:           subf = GetTriSubfaceInverse_Static(ornt[c], r);
    3253:           if (support[s] < cMax) {
    3254:             supportRef[s] = cStartNew + (support[s] - cStart)*8 + (r==3 ? (c+2)%4 + 4 : faces[c*3+subf]);
    3255:           } else {
    3256:             supportRef[s] = cStartNew + (cMax - cStart)*8 + (support[s] - cMax)*4 + (r==3 ? r : subf);
    3257:           }
    3258:         }
    3259:         DMPlexSetSupport(rdm, newp+r, supportRef);
    3260: #if 1
    3261:         if ((newp+r < fStartNew) || (newp+r >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp+r, fStartNew, fMaxNew);
    3262:         for (p = 0; p < supportSize; ++p) {
    3263:           if ((supportRef[p] < cStartNew) || (supportRef[p] >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an interior or hybrid cell [%d, %d)", supportRef[p], cStartNew, cEndNew);
    3264:         }
    3265: #endif
    3266:       }
    3267:     }
    3268:     /* Interior cell faces have 3 edges and 2 cells */
    3269:     for (c = cStart; c < cMax; ++c) {
    3270:       PetscInt        newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*8;
    3271:       const PetscInt *cone, *ornt;
    3272:       PetscInt        coneNew[3], orntNew[3];
    3273:       PetscInt        supportNew[2];

    3275:       DMPlexGetCone(dm, c, &cone);
    3276:       DMPlexGetConeOrientation(dm, c, &ornt);
    3277:       /* Face A: {c, a, d} */
    3278:       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*3 + GetTetSomething_Static(ornt[0], 2);
    3279:       orntNew[0] = ornt[0] < 0 ? -2 : 0;
    3280:       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*3 + GetTetSomething_Static(ornt[1], 2);
    3281:       orntNew[1] = ornt[1] < 0 ? -2 : 0;
    3282:       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*3 + GetTetSomething_Static(ornt[2], 2);
    3283:       orntNew[2] = ornt[2] < 0 ? -2 : 0;
    3284:       DMPlexSetCone(rdm, newp, coneNew);
    3285:       DMPlexSetConeOrientation(rdm, newp, orntNew);
    3286: #if 1
    3287:       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
    3288:       for (p = 0; p < 3; ++p) {
    3289:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eMaxNew);
    3290:       }
    3291: #endif
    3292:       supportNew[0] = (c - cStart)*8 + 0;
    3293:       supportNew[1] = (c - cStart)*8 + 0+4;
    3294:       DMPlexSetSupport(rdm, newp, supportNew);
    3295: #if 1
    3296:       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
    3297:       for (p = 0; p < 2; ++p) {
    3298:         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cMaxNew);
    3299:       }
    3300: #endif
    3301:       ++newp;
    3302:       /* Face B: {a, b, e} */
    3303:       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*3 + GetTetSomething_Static(ornt[0], 0);
    3304:       orntNew[0] = ornt[0] < 0 ? -2 : 0;
    3305:       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*3 + GetTetSomething_Static(ornt[3], 0);
    3306:       orntNew[1] = ornt[3] < 0 ? -2 : 0;
    3307:       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*3 + GetTetSomething_Static(ornt[1], 1);
    3308:       orntNew[2] = ornt[1] < 0 ? -2 : 0;
    3309:       DMPlexSetCone(rdm, newp, coneNew);
    3310:       DMPlexSetConeOrientation(rdm, newp, orntNew);
    3311: #if 1
    3312:       if ((newp+1 < fStartNew) || (newp+1 >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp+1, fStartNew, fMaxNew);
    3313:       for (p = 0; p < 3; ++p) {
    3314:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eMaxNew);
    3315:       }
    3316: #endif
    3317:       supportNew[0] = (c - cStart)*8 + 1;
    3318:       supportNew[1] = (c - cStart)*8 + 1+4;
    3319:       DMPlexSetSupport(rdm, newp, supportNew);
    3320: #if 1
    3321:       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
    3322:       for (p = 0; p < 2; ++p) {
    3323:         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cMaxNew);
    3324:       }
    3325: #endif
    3326:       ++newp;
    3327:       /* Face C: {c, f, b} */
    3328:       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*3 + GetTetSomething_Static(ornt[2], 0);
    3329:       orntNew[0] = ornt[2] < 0 ? -2 : 0;
    3330:       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*3 + GetTetSomething_Static(ornt[3], 2);
    3331:       orntNew[1] = ornt[3] < 0 ? -2 : 0;
    3332:       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*3 + GetTetSomething_Static(ornt[0], 1);
    3333:       orntNew[2] = ornt[0] < 0 ? -2 : 0;
    3334:       DMPlexSetCone(rdm, newp, coneNew);
    3335:       DMPlexSetConeOrientation(rdm, newp, orntNew);
    3336: #if 1
    3337:       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
    3338:       for (p = 0; p < 3; ++p) {
    3339:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eMaxNew);
    3340:       }
    3341: #endif
    3342:       supportNew[0] = (c - cStart)*8 + 2;
    3343:       supportNew[1] = (c - cStart)*8 + 2+4;
    3344:       DMPlexSetSupport(rdm, newp, supportNew);
    3345: #if 1
    3346:       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
    3347:       for (p = 0; p < 2; ++p) {
    3348:         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cMaxNew);
    3349:       }
    3350: #endif
    3351:       ++newp;
    3352:       /* Face D: {d, e, f} */
    3353:       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*3 + GetTetSomething_Static(ornt[1], 0);
    3354:       orntNew[0] = ornt[1] < 0 ? -2 : 0;
    3355:       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*3 + GetTetSomething_Static(ornt[3], 1);
    3356:       orntNew[1] = ornt[3] < 0 ? -2 : 0;
    3357:       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*3 + GetTetSomething_Static(ornt[2], 1);
    3358:       orntNew[2] = ornt[2] < 0 ? -2 : 0;
    3359:       DMPlexSetCone(rdm, newp, coneNew);
    3360:       DMPlexSetConeOrientation(rdm, newp, orntNew);
    3361: #if 1
    3362:       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
    3363:       for (p = 0; p < 3; ++p) {
    3364:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eMaxNew);
    3365:       }
    3366: #endif
    3367:       supportNew[0] = (c - cStart)*8 + 3;
    3368:       supportNew[1] = (c - cStart)*8 + 3+4;
    3369:       DMPlexSetSupport(rdm, newp, supportNew);
    3370: #if 1
    3371:       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
    3372:       for (p = 0; p < 2; ++p) {
    3373:         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cMaxNew);
    3374:       }
    3375: #endif
    3376:       ++newp;
    3377:       /* Face E: {d, f, a} */
    3378:       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*3 + GetTetSomething_Static(ornt[2], 1);
    3379:       orntNew[0] = ornt[2] < 0 ? 0 : -2;
    3380:       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart);
    3381:       orntNew[1] = -2;
    3382:       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*3 + GetTetSomething_Static(ornt[1], 2);
    3383:       orntNew[2] = ornt[1] < 0 ? -2 : 0;
    3384:       DMPlexSetCone(rdm, newp, coneNew);
    3385:       DMPlexSetConeOrientation(rdm, newp, orntNew);
    3386: #if 1
    3387:       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
    3388:       for (p = 0; p < 3; ++p) {
    3389:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eMaxNew);
    3390:       }
    3391: #endif
    3392:       supportNew[0] = (c - cStart)*8 + 0+4;
    3393:       supportNew[1] = (c - cStart)*8 + 3+4;
    3394:       DMPlexSetSupport(rdm, newp, supportNew);
    3395: #if 1
    3396:       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
    3397:       for (p = 0; p < 2; ++p) {
    3398:         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cMaxNew);
    3399:       }
    3400: #endif
    3401:       ++newp;
    3402:       /* Face F: {c, a, f} */
    3403:       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*3 + GetTetSomething_Static(ornt[0], 2);
    3404:       orntNew[0] = ornt[0] < 0 ? -2 : 0;
    3405:       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart);
    3406:       orntNew[1] = 0;
    3407:       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*3 + GetTetSomething_Static(ornt[2], 0);
    3408:       orntNew[2] = ornt[2] < 0 ? 0 : -2;
    3409:       DMPlexSetCone(rdm, newp, coneNew);
    3410:       DMPlexSetConeOrientation(rdm, newp, orntNew);
    3411: #if 1
    3412:       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
    3413:       for (p = 0; p < 3; ++p) {
    3414:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eMaxNew);
    3415:       }
    3416: #endif
    3417:       supportNew[0] = (c - cStart)*8 + 0+4;
    3418:       supportNew[1] = (c - cStart)*8 + 2+4;
    3419:       DMPlexSetSupport(rdm, newp, supportNew);
    3420: #if 1
    3421:       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
    3422:       for (p = 0; p < 2; ++p) {
    3423:         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cMaxNew);
    3424:       }
    3425: #endif
    3426:       ++newp;
    3427:       /* Face G: {e, a, f} */
    3428:       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*3 + GetTetSomething_Static(ornt[1], 1);
    3429:       orntNew[0] = ornt[1] < 0 ? -2 : 0;
    3430:       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart);
    3431:       orntNew[1] = 0;
    3432:       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*3 + GetTetSomething_Static(ornt[3], 1);
    3433:       orntNew[2] = ornt[3] < 0 ? 0 : -2;
    3434:       DMPlexSetCone(rdm, newp, coneNew);
    3435:       DMPlexSetConeOrientation(rdm, newp, orntNew);
    3436: #if 1
    3437:       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
    3438:       for (p = 0; p < 3; ++p) {
    3439:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eMaxNew);
    3440:       }
    3441: #endif
    3442:       supportNew[0] = (c - cStart)*8 + 1+4;
    3443:       supportNew[1] = (c - cStart)*8 + 3+4;
    3444:       DMPlexSetSupport(rdm, newp, supportNew);
    3445: #if 1
    3446:       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
    3447:       for (p = 0; p < 2; ++p) {
    3448:         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cMaxNew);
    3449:       }
    3450: #endif
    3451:       ++newp;
    3452:       /* Face H: {a, b, f} */
    3453:       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*3 + GetTetSomething_Static(ornt[0], 0);
    3454:       orntNew[0] = ornt[0] < 0 ? -2 : 0;
    3455:       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*3 + GetTetSomething_Static(ornt[3], 2);
    3456:       orntNew[1] = ornt[3] < 0 ? 0 : -2;
    3457:       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart);
    3458:       orntNew[2] = -2;
    3459:       DMPlexSetCone(rdm, newp, coneNew);
    3460:       DMPlexSetConeOrientation(rdm, newp, orntNew);
    3461: #if 1
    3462:       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
    3463:       for (p = 0; p < 3; ++p) {
    3464:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eMaxNew);
    3465:       }
    3466: #endif
    3467:       supportNew[0] = (c - cStart)*8 + 1+4;
    3468:       supportNew[1] = (c - cStart)*8 + 2+4;
    3469:       DMPlexSetSupport(rdm, newp, supportNew);
    3470: #if 1
    3471:       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
    3472:       for (p = 0; p < 2; ++p) {
    3473:         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cMaxNew);
    3474:       }
    3475: #endif
    3476:       ++newp;
    3477:     }
    3478:     /* Hybrid split faces have 4 edges and same cells */
    3479:     for (f = fMax; f < fEnd; ++f) {
    3480:       const PetscInt *cone, *ornt, *support;
    3481:       PetscInt        coneNew[4], orntNew[4];
    3482:       PetscInt        supportNew[2], size, s, c;

    3484:       DMPlexGetCone(dm, f, &cone);
    3485:       DMPlexGetConeOrientation(dm, f, &ornt);
    3486:       DMPlexGetSupportSize(dm, f, &size);
    3487:       DMPlexGetSupport(dm, f, &support);
    3488:       for (r = 0; r < 2; ++r) {
    3489:         const PetscInt newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (f - fMax)*2 + r;

    3491:         coneNew[0]   = eStartNew + (cone[0] - eStart)*2 + (ornt[0] < 0 ? 1-r : r);
    3492:         orntNew[0]   = ornt[0];
    3493:         coneNew[1]   = eStartNew + (cone[1] - eStart)*2 + (ornt[1] < 0 ? 1-r : r);
    3494:         orntNew[1]   = ornt[1];
    3495:         coneNew[2+r] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (cone[2+r] - eMax);
    3496:         orntNew[2+r] = 0;
    3497:         coneNew[3-r] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (eEnd      - eMax) + (f - fMax);
    3498:         orntNew[3-r] = 0;
    3499:         DMPlexSetCone(rdm, newp, coneNew);
    3500:         DMPlexSetConeOrientation(rdm, newp, orntNew);
    3501: #if 1
    3502:         if ((newp < fMaxNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid face [%d, %d)", newp, fMaxNew, fEndNew);
    3503:         for (p = 0; p < 2; ++p) {
    3504:           if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eMaxNew);
    3505:         }
    3506:         for (p = 2; p < 4; ++p) {
    3507:           if ((coneNew[p] < eMaxNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid edge [%d, %d)", coneNew[p], eMaxNew, eEndNew);
    3508:         }
    3509: #endif
    3510:         for (s = 0; s < size; ++s) {
    3511:           const PetscInt *coneCell, *orntCell, *fornt;
    3512:           PetscInt        o, of;

    3514:           DMPlexGetCone(dm, support[s], &coneCell);
    3515:           DMPlexGetConeOrientation(dm, support[s], &orntCell);
    3516:           o = orntCell[0] < 0 ? -1 : 1;
    3517:           for (c = 2; c < 5; ++c) if (coneCell[c] == f) break;
    3518:           if (c >= 5) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Could not find face %d in cone of cell %d", f, support[s]);
    3519:           DMPlexGetConeOrientation(dm, coneCell[0], &fornt);
    3520:           of = fornt[c-2] < 0 ? -1 : 1;
    3521:           supportNew[s] = cStartNew + (cMax - cStart)*8 + (support[s] - cMax)*4 + (GetTriEdgeInverse_Static(orntCell[0], c-2) + (o*of < 0 ? 1-r : r))%3;
    3522:         }
    3523:         DMPlexSetSupport(rdm, newp, supportNew);
    3524: #if 1
    3525:         if ((newp < fMaxNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid face [%d, %d)", newp, fMaxNew, fEndNew);
    3526:         for (p = 0; p < size; ++p) {
    3527:           if ((supportNew[p] < cMaxNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid cell [%d, %d)", supportNew[p], cMaxNew, cEndNew);
    3528:         }
    3529: #endif
    3530:       }
    3531:     }
    3532:     /* Hybrid cell faces have 4 edges and 2 cells */
    3533:     for (c = cMax; c < cEnd; ++c) {
    3534:       PetscInt        newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (c - cMax)*3;
    3535:       const PetscInt *cone, *ornt;
    3536:       PetscInt        coneNew[4], orntNew[4];
    3537:       PetscInt        supportNew[2];

    3539:       DMPlexGetCone(dm, c, &cone);
    3540:       DMPlexGetConeOrientation(dm, c, &ornt);
    3541:       for (r = 0; r < 3; ++r) {
    3542:         coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*3 + (r+2)%3;
    3543:         orntNew[0] = 0;
    3544:         coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*3 + (r+2)%3;
    3545:         orntNew[1] = 0;
    3546:         coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (eEnd - eMax) + (cone[2+(r+2)%3] - fMax);
    3547:         orntNew[2] = 0;
    3548:         coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (eEnd - eMax) + (cone[2+r]       - fMax);
    3549:         orntNew[3] = 0;
    3550:         DMPlexSetCone(rdm, newp+r, coneNew);
    3551:         DMPlexSetConeOrientation(rdm, newp+r, orntNew);
    3552: #if 1
    3553:         if ((newp+r < fMaxNew) || (newp+r >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid face [%d, %d)", newp+r, fMaxNew, fEndNew);
    3554:         for (p = 0; p < 2; ++p) {
    3555:           if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eMaxNew);
    3556:         }
    3557:         for (p = 2; p < 4; ++p) {
    3558:           if ((coneNew[p] < eMaxNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid edge [%d, %d)", coneNew[p], eMaxNew, eEndNew);
    3559:         }
    3560: #endif
    3561:         supportNew[0] = cStartNew + (cMax - cStart)*8 + (c - cMax)*4 + GetTriSubface_Static(ornt[0], r);
    3562:         supportNew[1] = cStartNew + (cMax - cStart)*8 + (c - cMax)*4 + 3;
    3563:         DMPlexSetSupport(rdm, newp+r, supportNew);
    3564: #if 1
    3565:         if ((newp+r < fMaxNew) || (newp+r >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid face [%d, %d)", newp+r, fMaxNew, fEndNew);
    3566:         for (p = 0; p < 2; ++p) {
    3567:           if ((supportNew[p] < cMaxNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid cell [%d, %d)", supportNew[p], cMaxNew, cEndNew);
    3568:         }
    3569: #endif
    3570:       }
    3571:     }
    3572:     /* Interior split edges have 2 vertices and the same faces as the parent */
    3573:     for (e = eStart; e < eMax; ++e) {
    3574:       const PetscInt newv = vStartNew + (vEnd - vStart) + (e - eStart);

    3576:       for (r = 0; r < 2; ++r) {
    3577:         const PetscInt  newp = eStartNew + (e - eStart)*2 + r;
    3578:         const PetscInt *cone, *ornt, *support;
    3579:         PetscInt        coneNew[2], coneSize, c, supportSize, s;

    3581:         DMPlexGetCone(dm, e, &cone);
    3582:         coneNew[0]       = vStartNew + (cone[0] - vStart);
    3583:         coneNew[1]       = vStartNew + (cone[1] - vStart);
    3584:         coneNew[(r+1)%2] = newv;
    3585:         DMPlexSetCone(rdm, newp, coneNew);
    3586: #if 1
    3587:         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
    3588:         for (p = 0; p < 2; ++p) {
    3589:           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
    3590:         }
    3591: #endif
    3592:         DMPlexGetSupportSize(dm, e, &supportSize);
    3593:         DMPlexGetSupport(dm, e, &support);
    3594:         for (s = 0; s < supportSize; ++s) {
    3595:           DMPlexGetConeSize(dm, support[s], &coneSize);
    3596:           DMPlexGetCone(dm, support[s], &cone);
    3597:           DMPlexGetConeOrientation(dm, support[s], &ornt);
    3598:           for (c = 0; c < coneSize; ++c) if (cone[c] == e) break;
    3599:           if (support[s] < fMax) {
    3600:             supportRef[s] = fStartNew + (support[s] - fStart)*4 + (c + (ornt[c] < 0 ? 1-r : r))%3;
    3601:           } else {
    3602:             supportRef[s] = fStartNew + (fMax       - fStart)*4 + (cMax - cStart)*8 + (support[s] - fMax)*2 + (ornt[c] < 0 ? 1-r : r);
    3603:           }
    3604:         }
    3605:         DMPlexSetSupport(rdm, newp, supportRef);
    3606: #if 1
    3607:         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
    3608:         for (p = 0; p < supportSize; ++p) {
    3609:           if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an interior or hybrid face [%d, %d)", supportRef[p], fStartNew, fEndNew);
    3610:         }
    3611: #endif
    3612:       }
    3613:     }
    3614:     /* Interior face edges have 2 vertices and 2+cells*(1/2) faces */
    3615:     for (f = fStart; f < fMax; ++f) {
    3616:       const PetscInt *cone, *ornt, *support;
    3617:       PetscInt        coneSize, supportSize, s;

    3619:       DMPlexGetSupportSize(dm, f, &supportSize);
    3620:       DMPlexGetSupport(dm, f, &support);
    3621:       for (r = 0; r < 3; ++r) {
    3622:         const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (f - fStart)*3 + r;
    3623:         PetscInt        coneNew[2], intFaces = 0, er, eint[4] = {1, 0, 2, 0};
    3624:         PetscInt        fint[24] = { 1,  7, -1, -1,  0,  5,
    3625:                                     -1, -1,  1,  6,  0,  4,
    3626:                                      2,  5,  3,  4, -1, -1,
    3627:                                     -1, -1,  3,  6,  2,  7};

    3629:         DMPlexGetCone(dm, f, &cone);
    3630:         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[(r+0)%3] - eStart);
    3631:         coneNew[1] = vStartNew + (vEnd - vStart) + (cone[(r+1)%3] - eStart);
    3632:         DMPlexSetCone(rdm, newp, coneNew);
    3633: #if 1
    3634:         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
    3635:         for (p = 0; p < 2; ++p) {
    3636:           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
    3637:         }
    3638: #endif
    3639:         supportRef[0] = fStartNew + (f - fStart)*4 + (r+1)%3;
    3640:         supportRef[1] = fStartNew + (f - fStart)*4 + 3;
    3641:         for (s = 0; s < supportSize; ++s) {
    3642:           DMPlexGetConeSize(dm, support[s], &coneSize);
    3643:           DMPlexGetCone(dm, support[s], &cone);
    3644:           DMPlexGetConeOrientation(dm, support[s], &ornt);
    3645:           for (c = 0; c < coneSize; ++c) {if (cone[c] == f) break;}
    3646:           if (support[s] < cMax) {
    3647:             /* Here we want to determine whether edge newp contains a vertex which is part of the cross-tet edge */
    3648:             er = GetTetSomethingInverse_Static(ornt[c], r);
    3649:             if (er == eint[c]) {
    3650:               supportRef[2+intFaces++] = fStartNew + (fMax - fStart)*4 + (support[s] - cStart)*8 + (c + 2)%4;
    3651:             } else {
    3652:               supportRef[2+intFaces++] = fStartNew + (fMax - fStart)*4 + (support[s] - cStart)*8 + fint[(c*3 + er)*2 + 0];
    3653:               supportRef[2+intFaces++] = fStartNew + (fMax - fStart)*4 + (support[s] - cStart)*8 + fint[(c*3 + er)*2 + 1];
    3654:             }
    3655:           } else {
    3656:             supportRef[2+intFaces++] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (support[s] - cMax)*3 + (r + 1)%3;
    3657:           }
    3658:         }
    3659:         DMPlexSetSupport(rdm, newp, supportRef);
    3660: #if 1
    3661:         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
    3662:         for (p = 0; p < intFaces; ++p) {
    3663:           if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an interior or hybrid face [%d, %d)", supportRef[p], fStartNew, fEndNew);
    3664:         }
    3665: #endif
    3666:       }
    3667:     }
    3668:     /* Interior cell edges have 2 vertices and 4 faces */
    3669:     for (c = cStart; c < cMax; ++c) {
    3670:       const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart);
    3671:       const PetscInt *cone, *ornt, *fcone;
    3672:       PetscInt        coneNew[2], supportNew[4], find;

    3674:       DMPlexGetCone(dm, c, &cone);
    3675:       DMPlexGetConeOrientation(dm, c, &ornt);
    3676:       DMPlexGetCone(dm, cone[0], &fcone);
    3677:       find = GetTriEdge_Static(ornt[0], 0);
    3678:       coneNew[0] = vStartNew + (vEnd - vStart) + (fcone[find] - eStart);
    3679:       DMPlexGetCone(dm, cone[2], &fcone);
    3680:       find = GetTriEdge_Static(ornt[2], 1);
    3681:       coneNew[1] = vStartNew + (vEnd - vStart) + (fcone[find] - eStart);
    3682:       DMPlexSetCone(rdm, newp, coneNew);
    3683: #if 1
    3684:       if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
    3685:       for (p = 0; p < 2; ++p) {
    3686:         if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
    3687:       }
    3688: #endif
    3689:       supportNew[0] = fStartNew + (fMax - fStart)*4 + (c - cStart)*8 + 4;
    3690:       supportNew[1] = fStartNew + (fMax - fStart)*4 + (c - cStart)*8 + 5;
    3691:       supportNew[2] = fStartNew + (fMax - fStart)*4 + (c - cStart)*8 + 6;
    3692:       supportNew[3] = fStartNew + (fMax - fStart)*4 + (c - cStart)*8 + 7;
    3693:       DMPlexSetSupport(rdm, newp, supportNew);
    3694: #if 1
    3695:       if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
    3696:       for (p = 0; p < 4; ++p) {
    3697:         if ((supportNew[p] < fStartNew) || (supportNew[p] >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", supportNew[p], fStartNew, fMaxNew);
    3698:       }
    3699: #endif
    3700:     }
    3701:     /* Hybrid edges have two vertices and the same faces */
    3702:     for (e = eMax; e < eEnd; ++e) {
    3703:       const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (e - eMax);
    3704:       const PetscInt *cone, *support, *fcone;
    3705:       PetscInt        coneNew[2], size, fsize, s;

    3707:       DMPlexGetCone(dm, e, &cone);
    3708:       DMPlexGetSupportSize(dm, e, &size);
    3709:       DMPlexGetSupport(dm, e, &support);
    3710:       coneNew[0] = vStartNew + (cone[0] - vStart);
    3711:       coneNew[1] = vStartNew + (cone[1] - vStart);
    3712:       DMPlexSetCone(rdm, newp, coneNew);
    3713: #if 1
    3714:       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid edge [%d, %d)", newp, eMaxNew, eEndNew);
    3715:       for (p = 0; p < 2; ++p) {
    3716:         if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
    3717:       }
    3718: #endif
    3719:       for (s = 0; s < size; ++s) {
    3720:         DMPlexGetConeSize(dm, support[s], &fsize);
    3721:         DMPlexGetCone(dm, support[s], &fcone);
    3722:         for (c = 0; c < fsize; ++c) if (fcone[c] == e) break;
    3723:         if ((c < 2) || (c > 3)) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Edge %d not found in cone of face %d", e, support[s]);
    3724:         supportRef[s] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (support[s] - fMax)*2 + c-2;
    3725:       }
    3726:       DMPlexSetSupport(rdm, newp, supportRef);
    3727: #if 1
    3728:       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid edge [%d, %d)", newp, eMaxNew, eEndNew);
    3729:       for (p = 0; p < size; ++p) {
    3730:         if ((supportRef[p] < fMaxNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid face [%d, %d)", supportRef[p], fMaxNew, fEndNew);
    3731:       }
    3732: #endif
    3733:     }
    3734:     /* Hybrid face edges have 2 vertices and 2+2*cells faces */
    3735:     for (f = fMax; f < fEnd; ++f) {
    3736:       const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (eEnd - eMax) + (f - fMax);
    3737:       const PetscInt *cone, *support, *ccone, *cornt;
    3738:       PetscInt        coneNew[2], size, csize, s;

    3740:       DMPlexGetCone(dm, f, &cone);
    3741:       DMPlexGetSupportSize(dm, f, &size);
    3742:       DMPlexGetSupport(dm, f, &support);
    3743:       coneNew[0] = vStartNew + (vEnd - vStart) + (cone[0] - eStart);
    3744:       coneNew[1] = vStartNew + (vEnd - vStart) + (cone[1] - eStart);
    3745:       DMPlexSetCone(rdm, newp, coneNew);
    3746: #if 1
    3747:       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid edge [%d, %d)", newp, eMaxNew, eEndNew);
    3748:       for (p = 0; p < 2; ++p) {
    3749:         if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
    3750:       }
    3751: #endif
    3752:       supportRef[0] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (f - fMax)*2 + 0;
    3753:       supportRef[1] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (f - fMax)*2 + 1;
    3754:       for (s = 0; s < size; ++s) {
    3755:         DMPlexGetConeSize(dm, support[s], &csize);
    3756:         DMPlexGetCone(dm, support[s], &ccone);
    3757:         DMPlexGetConeOrientation(dm, support[s], &cornt);
    3758:         for (c = 0; c < csize; ++c) if (ccone[c] == f) break;
    3759:         if ((c < 2) || (c >= csize)) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Hybrid face %d is not in cone of hybrid cell %d", f, support[s]);
    3760:         supportRef[2+s*2+0] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (support[s] - cMax)*3 + c-2;
    3761:         supportRef[2+s*2+1] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (support[s] - cMax)*3 + (c-1)%3;
    3762:       }
    3763:       DMPlexSetSupport(rdm, newp, supportRef);
    3764: #if 1
    3765:       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid edge [%d, %d)", newp, eMaxNew, eEndNew);
    3766:       for (p = 0; p < 2+size*2; ++p) {
    3767:         if ((supportRef[p] < fMaxNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid face [%d, %d)", supportRef[p], fMaxNew, fEndNew);
    3768:       }
    3769: #endif
    3770:     }
    3771:     /* Interior vertices have identical supports */
    3772:     for (v = vStart; v < vEnd; ++v) {
    3773:       const PetscInt  newp = vStartNew + (v - vStart);
    3774:       const PetscInt *support, *cone;
    3775:       PetscInt        size, s;

    3777:       DMPlexGetSupportSize(dm, v, &size);
    3778:       DMPlexGetSupport(dm, v, &support);
    3779:       for (s = 0; s < size; ++s) {
    3780:         PetscInt r = 0;

    3782:         DMPlexGetCone(dm, support[s], &cone);
    3783:         if (cone[1] == v) r = 1;
    3784:         if (support[s] < eMax) supportRef[s] = eStartNew + (support[s] - eStart)*2 + r;
    3785:         else                   supportRef[s] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (support[s] - eMax);
    3786:       }
    3787:       DMPlexSetSupport(rdm, newp, supportRef);
    3788: #if 1
    3789:       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
    3790:       for (p = 0; p < size; ++p) {
    3791:         if ((supportRef[p] < eStartNew) || (supportRef[p] >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an interior or hybrid edge [%d, %d)", supportRef[p], eStartNew, eEndNew);
    3792:       }
    3793: #endif
    3794:     }
    3795:     /* Interior edge vertices have 2 + interior face*2 + hybrid face + cells*0/1 supports */
    3796:     for (e = eStart; e < eMax; ++e) {
    3797:       const PetscInt  newp = vStartNew + (vEnd - vStart) + (e - eStart);
    3798:       const PetscInt *cone, *support;
    3799:       PetscInt       *star = NULL, starSize, faceSize = 0, cellSize = 0, coneSize, size, s;

    3801:       DMPlexGetSupportSize(dm, e, &size);
    3802:       DMPlexGetSupport(dm, e, &support);
    3803:       supportRef[0] = eStartNew + (e - eStart)*2 + 0;
    3804:       supportRef[1] = eStartNew + (e - eStart)*2 + 1;
    3805:       for (s = 0; s < size; ++s) {
    3806:         PetscInt r = 0;

    3808:         if (support[s] < fMax) {
    3809:           DMPlexGetConeSize(dm, support[s], &coneSize);
    3810:           DMPlexGetCone(dm, support[s], &cone);
    3811:           for (r = 0; r < coneSize; ++r) {if (cone[r] == e) break;}
    3812:           supportRef[2+faceSize+0] = eStartNew + (eMax - eStart)*2 + (support[s] - fStart)*3 + (r+0)%3;
    3813:           supportRef[2+faceSize+1] = eStartNew + (eMax - eStart)*2 + (support[s] - fStart)*3 + (r+2)%3;
    3814:           faceSize += 2;
    3815:         } else {
    3816:           supportRef[2+faceSize+0] = eStartNew + (eMax - eStart)*2 + (fMax       - fStart)*3 + (cMax - cStart) + (eEnd - eMax) + (support[s] - fMax);
    3817:           ++faceSize;
    3818:         }
    3819:       }
    3820:       DMPlexGetTransitiveClosure(dm, e, PETSC_FALSE, &starSize, &star);
    3821:       for (s = 0; s < starSize*2; s += 2) {
    3822:         const PetscInt *cone, *ornt;
    3823:         PetscInt        e01, e23;

    3825:         if ((star[s] >= cStart) && (star[s] < cMax)) {
    3826:           /* Check edge 0-1 */
    3827:           DMPlexGetCone(dm, star[s], &cone);
    3828:           DMPlexGetConeOrientation(dm, star[s], &ornt);
    3829:           DMPlexGetCone(dm, cone[0], &cone);
    3830:           e01  = cone[GetTriEdge_Static(ornt[0], 0)];
    3831:           /* Check edge 2-3 */
    3832:           DMPlexGetCone(dm, star[s], &cone);
    3833:           DMPlexGetConeOrientation(dm, star[s], &ornt);
    3834:           DMPlexGetCone(dm, cone[2], &cone);
    3835:           e23  = cone[GetTriEdge_Static(ornt[2], 1)];
    3836:           if ((e01 == e) || (e23 == e)) {supportRef[2+faceSize+cellSize++] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (star[s] - cStart);}
    3837:         }
    3838:       }
    3839:       DMPlexRestoreTransitiveClosure(dm, e, PETSC_FALSE, &starSize, &star);
    3840:       DMPlexSetSupport(rdm, newp, supportRef);
    3841: #if 1
    3842:       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
    3843:       for (p = 0; p < 2+faceSize+cellSize; ++p) {
    3844:         if ((supportRef[p] < eStartNew) || (supportRef[p] >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an interior or hybrid edge [%d, %d)", supportRef[p], eStartNew, eEndNew);
    3845:       }
    3846: #endif
    3847:     }
    3848:     PetscFree(supportRef);
    3849:     DMPlexRestoreFaces_Internal(dm, 3, cStart, NULL, NULL, &faces);
    3850:     break;
    3851:   case REFINER_HEX_3D:
    3852:     /*
    3853:      Bottom (viewed from top)    Top
    3854:      1---------2---------2       7---------2---------6
    3855:      |         |         |       |         |         |
    3856:      |    B    2    C    |       |    H    2    G    |
    3857:      |         |         |       |         |         |
    3858:      3----3----0----1----1       3----3----0----1----1
    3859:      |         |         |       |         |         |
    3860:      |    A    0    D    |       |    E    0    F    |
    3861:      |         |         |       |         |         |
    3862:      0---------0---------3       4---------0---------5
    3863:      */
    3864:     /* All cells have 6 faces: Bottom, Top, Front, Back, Right, Left */
    3865:     for (c = cStart; c < cEnd; ++c) {
    3866:       const PetscInt  newp = (c - cStart)*8;
    3867:       const PetscInt *cone, *ornt;
    3868:       PetscInt        coneNew[6], orntNew[6];

    3870:       DMPlexGetCone(dm, c, &cone);
    3871:       DMPlexGetConeOrientation(dm, c, &ornt);
    3872:       /* A hex */
    3873:       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], 0);
    3874:       orntNew[0] = ornt[0];
    3875:       coneNew[1] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  8; /* AE */
    3876:       orntNew[1] = 0;
    3877:       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetQuadSubface_Static(ornt[2], 0);
    3878:       orntNew[2] = ornt[2];
    3879:       coneNew[3] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  3; /* AB */
    3880:       orntNew[3] = 0;
    3881:       coneNew[4] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  0; /* AD */
    3882:       orntNew[4] = 0;
    3883:       coneNew[5] = fStartNew + (cone[5] - fStart)*4 + GetQuadSubface_Static(ornt[5], 0);
    3884:       orntNew[5] = ornt[5];
    3885:       DMPlexSetCone(rdm, newp+0, coneNew);
    3886:       DMPlexSetConeOrientation(rdm, newp+0, orntNew);
    3887: #if 1
    3888:       if ((newp+0 < cStartNew) || (newp+0 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+0, cStartNew, cEndNew);
    3889:       for (p = 0; p < 6; ++p) {
    3890:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
    3891:       }
    3892: #endif
    3893:       /* B hex */
    3894:       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], 1);
    3895:       orntNew[0] = ornt[0];
    3896:       coneNew[1] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 + 11; /* BH */
    3897:       orntNew[1] = 0;
    3898:       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  3; /* AB */
    3899:       orntNew[2] = -1;
    3900:       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetQuadSubface_Static(ornt[3], 1);
    3901:       orntNew[3] = ornt[3];
    3902:       coneNew[4] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  2; /* BC */
    3903:       orntNew[4] = 0;
    3904:       coneNew[5] = fStartNew + (cone[5] - fStart)*4 + GetQuadSubface_Static(ornt[5], 3);
    3905:       orntNew[5] = ornt[5];
    3906:       DMPlexSetCone(rdm, newp+1, coneNew);
    3907:       DMPlexSetConeOrientation(rdm, newp+1, orntNew);
    3908: #if 1
    3909:       if ((newp+1 < cStartNew) || (newp+1 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+1, cStartNew, cEndNew);
    3910:       for (p = 0; p < 6; ++p) {
    3911:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
    3912:       }
    3913: #endif
    3914:       /* C hex */
    3915:       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], 2);
    3916:       orntNew[0] = ornt[0];
    3917:       coneNew[1] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 + 10; /* CG */
    3918:       orntNew[1] = 0;
    3919:       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  1; /* CD */
    3920:       orntNew[2] = -1;
    3921:       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetQuadSubface_Static(ornt[3], 0);
    3922:       orntNew[3] = ornt[3];
    3923:       coneNew[4] = fStartNew + (cone[4] - fStart)*4 + GetQuadSubface_Static(ornt[4], 1);
    3924:       orntNew[4] = ornt[4];
    3925:       coneNew[5] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  2; /* BC */
    3926:       orntNew[5] = -4;
    3927:       DMPlexSetCone(rdm, newp+2, coneNew);
    3928:       DMPlexSetConeOrientation(rdm, newp+2, orntNew);
    3929: #if 1
    3930:       if ((newp+2 < cStartNew) || (newp+2 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+2, cStartNew, cEndNew);
    3931:       for (p = 0; p < 6; ++p) {
    3932:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
    3933:       }
    3934: #endif
    3935:       /* D hex */
    3936:       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], 3);
    3937:       orntNew[0] = ornt[0];
    3938:       coneNew[1] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  9; /* DF */
    3939:       orntNew[1] = 0;
    3940:       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetQuadSubface_Static(ornt[2], 1);
    3941:       orntNew[2] = ornt[2];
    3942:       coneNew[3] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  1; /* CD */
    3943:       orntNew[3] = 0;
    3944:       coneNew[4] = fStartNew + (cone[4] - fStart)*4 + GetQuadSubface_Static(ornt[4], 0);
    3945:       orntNew[4] = ornt[4];
    3946:       coneNew[5] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  0; /* AD */
    3947:       orntNew[5] = -4;
    3948:       DMPlexSetCone(rdm, newp+3, coneNew);
    3949:       DMPlexSetConeOrientation(rdm, newp+3, orntNew);
    3950: #if 1
    3951:       if ((newp+3 < cStartNew) || (newp+3 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+3, cStartNew, cEndNew);
    3952:       for (p = 0; p < 6; ++p) {
    3953:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
    3954:       }
    3955: #endif
    3956:       /* E hex */
    3957:       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  8; /* AE */
    3958:       orntNew[0] = -4;
    3959:       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], 0);
    3960:       orntNew[1] = ornt[1];
    3961:       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetQuadSubface_Static(ornt[2], 3);
    3962:       orntNew[2] = ornt[2];
    3963:       coneNew[3] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  7; /* EH */
    3964:       orntNew[3] = 0;
    3965:       coneNew[4] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  4; /* EF */
    3966:       orntNew[4] = -1;
    3967:       coneNew[5] = fStartNew + (cone[5] - fStart)*4 + GetQuadSubface_Static(ornt[5], 1);
    3968:       orntNew[5] = ornt[5];
    3969:       DMPlexSetCone(rdm, newp+4, coneNew);
    3970:       DMPlexSetConeOrientation(rdm, newp+4, orntNew);
    3971: #if 1
    3972:       if ((newp+4 < cStartNew) || (newp+4 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+4, cStartNew, cEndNew);
    3973:       for (p = 0; p < 6; ++p) {
    3974:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
    3975:       }
    3976: #endif
    3977:       /* F hex */
    3978:       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  9; /* DF */
    3979:       orntNew[0] = -4;
    3980:       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], 1);
    3981:       orntNew[1] = ornt[1];
    3982:       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetQuadSubface_Static(ornt[2], 2);
    3983:       orntNew[2] = ornt[2];
    3984:       coneNew[3] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  5; /* FG */
    3985:       orntNew[3] = -1;
    3986:       coneNew[4] = fStartNew + (cone[4] - fStart)*4 + GetQuadSubface_Static(ornt[4], 3);
    3987:       orntNew[4] = ornt[4];
    3988:       coneNew[5] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  4; /* EF */
    3989:       orntNew[5] = 1;
    3990:       DMPlexSetCone(rdm, newp+5, coneNew);
    3991:       DMPlexSetConeOrientation(rdm, newp+5, orntNew);
    3992: #if 1
    3993:       if ((newp+5 < cStartNew) || (newp+5 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+5, cStartNew, cEndNew);
    3994:       for (p = 0; p < 6; ++p) {
    3995:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
    3996:       }
    3997: #endif
    3998:       /* G hex */
    3999:       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 + 10; /* CG */
    4000:       orntNew[0] = -4;
    4001:       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], 2);
    4002:       orntNew[1] = ornt[1];
    4003:       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  5; /* FG */
    4004:       orntNew[2] = 0;
    4005:       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetQuadSubface_Static(ornt[3], 3);
    4006:       orntNew[3] = ornt[3];
    4007:       coneNew[4] = fStartNew + (cone[4] - fStart)*4 + GetQuadSubface_Static(ornt[4], 2);
    4008:       orntNew[4] = ornt[4];
    4009:       coneNew[5] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  6; /* GH */
    4010:       orntNew[5] = -3;
    4011:       DMPlexSetCone(rdm, newp+6, coneNew);
    4012:       DMPlexSetConeOrientation(rdm, newp+6, orntNew);
    4013: #if 1
    4014:       if ((newp+6 < cStartNew) || (newp+6 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+6, cStartNew, cEndNew);
    4015:       for (p = 0; p < 6; ++p) {
    4016:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
    4017:       }
    4018: #endif
    4019:       /* H hex */
    4020:       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 + 11; /* BH */
    4021:       orntNew[0] = -4;
    4022:       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], 3);
    4023:       orntNew[1] = ornt[1];
    4024:       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  7; /* EH */
    4025:       orntNew[2] = -1;
    4026:       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetQuadSubface_Static(ornt[3], 2);
    4027:       orntNew[3] = ornt[3];
    4028:       coneNew[4] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  6; /* GH */
    4029:       orntNew[4] = 3;
    4030:       coneNew[5] = fStartNew + (cone[5] - fStart)*4 + GetQuadSubface_Static(ornt[5], 2);
    4031:       orntNew[5] = ornt[5];
    4032:       DMPlexSetCone(rdm, newp+7, coneNew);
    4033:       DMPlexSetConeOrientation(rdm, newp+7, orntNew);
    4034: #if 1
    4035:       if ((newp+7 < cStartNew) || (newp+7 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+7, cStartNew, cEndNew);
    4036:       for (p = 0; p < 6; ++p) {
    4037:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
    4038:       }
    4039: #endif
    4040:     }
    4041:     /* Split faces have 4 edges and the same cells as the parent */
    4042:     DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);
    4043:     PetscMalloc1(4 + maxSupportSize*2, &supportRef);
    4044:     for (f = fStart; f < fEnd; ++f) {
    4045:       for (r = 0; r < 4; ++r) {
    4046:         /* TODO: This can come from GetFaces_Internal() */
    4047:         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};
    4048:         const PetscInt  newp = fStartNew + (f - fStart)*4 + r;
    4049:         const PetscInt *cone, *ornt, *support;
    4050:         PetscInt        coneNew[4], orntNew[4], coneSize, c, supportSize, s;

    4052:         DMPlexGetCone(dm, f, &cone);
    4053:         DMPlexGetConeOrientation(dm, f, &ornt);
    4054:         coneNew[(r+3)%4] = eStartNew + (cone[(r+3)%4] - eStart)*2 + (ornt[(r+3)%4] < 0 ? 0 : 1);
    4055:         orntNew[(r+3)%4] = ornt[(r+3)%4];
    4056:         coneNew[(r+0)%4] = eStartNew + (cone[r]       - eStart)*2 + (ornt[r] < 0 ? 1 : 0);
    4057:         orntNew[(r+0)%4] = ornt[r];
    4058:         coneNew[(r+1)%4] = eStartNew + (eEnd - eStart)*2 + (f - fStart)*4 + r;
    4059:         orntNew[(r+1)%4] = 0;
    4060:         coneNew[(r+2)%4] = eStartNew + (eEnd - eStart)*2 + (f - fStart)*4 + (r+3)%4;
    4061:         orntNew[(r+2)%4] = -2;
    4062:         DMPlexSetCone(rdm, newp, coneNew);
    4063:         DMPlexSetConeOrientation(rdm, newp, orntNew);
    4064: #if 1
    4065:         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
    4066:         for (p = 0; p < 4; ++p) {
    4067:           if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eEndNew);
    4068:         }
    4069: #endif
    4070:         DMPlexGetSupportSize(dm, f, &supportSize);
    4071:         DMPlexGetSupport(dm, f, &support);
    4072:         for (s = 0; s < supportSize; ++s) {
    4073:           DMPlexGetConeSize(dm, support[s], &coneSize);
    4074:           DMPlexGetCone(dm, support[s], &cone);
    4075:           DMPlexGetConeOrientation(dm, support[s], &ornt);
    4076:           for (c = 0; c < coneSize; ++c) {
    4077:             if (cone[c] == f) break;
    4078:           }
    4079:           supportRef[s] = cStartNew + (support[s] - cStart)*8 + newCells[c*4+GetQuadSubfaceInverse_Static(ornt[c], r)];
    4080:         }
    4081:         DMPlexSetSupport(rdm, newp, supportRef);
    4082: #if 1
    4083:         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
    4084:         for (p = 0; p < supportSize; ++p) {
    4085:           if ((supportRef[p] < cStartNew) || (supportRef[p] >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportRef[p], cStartNew, cEndNew);
    4086:         }
    4087: #endif
    4088:       }
    4089:     }
    4090:     /* Interior faces have 4 edges and 2 cells */
    4091:     for (c = cStart; c < cEnd; ++c) {
    4092:       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};
    4093:       const PetscInt *cone, *ornt;
    4094:       PetscInt        newp, coneNew[4], orntNew[4], supportNew[2];

    4096:       DMPlexGetCone(dm, c, &cone);
    4097:       DMPlexGetConeOrientation(dm, c, &ornt);
    4098:       /* A-D face */
    4099:       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 0;
    4100:       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*4 + GetQuadEdge_Static(ornt[0], 3);
    4101:       orntNew[0] = 0;
    4102:       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 0;
    4103:       orntNew[1] = 0;
    4104:       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 2;
    4105:       orntNew[2] = -2;
    4106:       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*4 + GetQuadEdge_Static(ornt[2], 0);
    4107:       orntNew[3] = -2;
    4108:       DMPlexSetCone(rdm, newp, coneNew);
    4109:       DMPlexSetConeOrientation(rdm, newp, orntNew);
    4110: #if 1
    4111:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
    4112:       for (p = 0; p < 4; ++p) {
    4113:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eEndNew);
    4114:       }
    4115: #endif
    4116:       /* C-D face */
    4117:       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 1;
    4118:       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*4 + GetQuadEdge_Static(ornt[0], 2);
    4119:       orntNew[0] = 0;
    4120:       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 0;
    4121:       orntNew[1] = 0;
    4122:       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 4;
    4123:       orntNew[2] = -2;
    4124:       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (cone[4] - fStart)*4 + GetQuadEdge_Static(ornt[4], 0);
    4125:       orntNew[3] = -2;
    4126:       DMPlexSetCone(rdm, newp, coneNew);
    4127:       DMPlexSetConeOrientation(rdm, newp, orntNew);
    4128: #if 1
    4129:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
    4130:       for (p = 0; p < 4; ++p) {
    4131:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eEndNew);
    4132:       }
    4133: #endif
    4134:       /* B-C face */
    4135:       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 2;
    4136:       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*4 + GetQuadEdge_Static(ornt[0], 1);
    4137:       orntNew[0] = -2;
    4138:       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*4 + GetQuadEdge_Static(ornt[3], 0);
    4139:       orntNew[1] = 0;
    4140:       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 3;
    4141:       orntNew[2] = 0;
    4142:       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 0;
    4143:       orntNew[3] = -2;
    4144:       DMPlexSetCone(rdm, newp, coneNew);
    4145:       DMPlexSetConeOrientation(rdm, newp, orntNew);
    4146: #if 1
    4147:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
    4148:       for (p = 0; p < 4; ++p) {
    4149:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eEndNew);
    4150:       }
    4151: #endif
    4152:       /* A-B face */
    4153:       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 3;
    4154:       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*4 + GetQuadEdge_Static(ornt[0], 0);
    4155:       orntNew[0] = -2;
    4156:       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[5] - fStart)*4 + GetQuadEdge_Static(ornt[5], 3);
    4157:       orntNew[1] = 0;
    4158:       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 5;
    4159:       orntNew[2] = 0;
    4160:       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 0;
    4161:       orntNew[3] = -2;
    4162:       DMPlexSetCone(rdm, newp, coneNew);
    4163:       DMPlexSetConeOrientation(rdm, newp, orntNew);
    4164: #if 1
    4165:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
    4166:       for (p = 0; p < 4; ++p) {
    4167:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eEndNew);
    4168:       }
    4169: #endif
    4170:       /* E-F face */
    4171:       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 4;
    4172:       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 2;
    4173:       orntNew[0] = -2;
    4174:       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*4 + GetQuadEdge_Static(ornt[2], 2);
    4175:       orntNew[1] = -2;
    4176:       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*4 + GetQuadEdge_Static(ornt[1], 0);
    4177:       orntNew[2] = 0;
    4178:       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 1;
    4179:       orntNew[3] = 0;
    4180:       DMPlexSetCone(rdm, newp, coneNew);
    4181:       DMPlexSetConeOrientation(rdm, newp, orntNew);
    4182: #if 1
    4183:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
    4184:       for (p = 0; p < 4; ++p) {
    4185:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eEndNew);
    4186:       }
    4187: #endif
    4188:       /* F-G face */
    4189:       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 5;
    4190:       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 4;
    4191:       orntNew[0] = -2;
    4192:       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[4] - fStart)*4 + GetQuadEdge_Static(ornt[4], 2);
    4193:       orntNew[1] = -2;
    4194:       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*4 + GetQuadEdge_Static(ornt[1], 1);
    4195:       orntNew[2] = 0;
    4196:       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 1;
    4197:       orntNew[3] = 0;
    4198:       DMPlexSetCone(rdm, newp, coneNew);
    4199:       DMPlexSetConeOrientation(rdm, newp, orntNew);
    4200: #if 1
    4201:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
    4202:       for (p = 0; p < 4; ++p) {
    4203:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eEndNew);
    4204:       }
    4205: #endif
    4206:       /* G-H face */
    4207:       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 6;
    4208:       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*4 + GetQuadEdge_Static(ornt[3], 2);
    4209:       orntNew[0] = -2;
    4210:       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*4 + GetQuadEdge_Static(ornt[1], 2);
    4211:       orntNew[1] = 0;
    4212:       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 1;
    4213:       orntNew[2] = 0;
    4214:       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 3;
    4215:       orntNew[3] = -2;
    4216:       DMPlexSetCone(rdm, newp, coneNew);
    4217:       DMPlexSetConeOrientation(rdm, newp, orntNew);
    4218: #if 1
    4219:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
    4220:       for (p = 0; p < 4; ++p) {
    4221:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eEndNew);
    4222:       }
    4223: #endif
    4224:       /* E-H face */
    4225:       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 7;
    4226:       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 5;
    4227:       orntNew[0] = -2;
    4228:       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[5] - fStart)*4 + GetQuadEdge_Static(ornt[5], 1);
    4229:       orntNew[1] = -2;
    4230:       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*4 + GetQuadEdge_Static(ornt[1], 3);
    4231:       orntNew[2] = 0;
    4232:       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 1;
    4233:       orntNew[3] = 0;
    4234:       DMPlexSetCone(rdm, newp, coneNew);
    4235:       DMPlexSetConeOrientation(rdm, newp, orntNew);
    4236: #if 1
    4237:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
    4238:       for (p = 0; p < 4; ++p) {
    4239:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eEndNew);
    4240:       }
    4241: #endif
    4242:       /* A-E face */
    4243:       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 8;
    4244:       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*4 + GetQuadEdge_Static(ornt[2], 3);
    4245:       orntNew[0] = 0;
    4246:       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 2;
    4247:       orntNew[1] = 0;
    4248:       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 5;
    4249:       orntNew[2] = -2;
    4250:       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (cone[5] - fStart)*4 + GetQuadEdge_Static(ornt[5], 0);
    4251:       orntNew[3] = -2;
    4252:       DMPlexSetCone(rdm, newp, coneNew);
    4253:       DMPlexSetConeOrientation(rdm, newp, orntNew);
    4254: #if 1
    4255:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
    4256:       for (p = 0; p < 4; ++p) {
    4257:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eEndNew);
    4258:       }
    4259: #endif
    4260:       /* D-F face */
    4261:       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 9;
    4262:       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*4 + GetQuadEdge_Static(ornt[2], 1);
    4263:       orntNew[0] = -2;
    4264:       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[4] - fStart)*4 + GetQuadEdge_Static(ornt[4], 3);
    4265:       orntNew[1] = 0;
    4266:       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 4;
    4267:       orntNew[2] = 0;
    4268:       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 2;
    4269:       orntNew[3] = -2;
    4270:       DMPlexSetCone(rdm, newp, coneNew);
    4271:       DMPlexSetConeOrientation(rdm, newp, orntNew);
    4272: #if 1
    4273:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
    4274:       for (p = 0; p < 4; ++p) {
    4275:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eEndNew);
    4276:       }
    4277: #endif
    4278:       /* C-G face */
    4279:       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 10;
    4280:       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 4;
    4281:       orntNew[0] = -2;
    4282:       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[4] - fStart)*4 + GetQuadEdge_Static(ornt[4], 1);
    4283:       orntNew[1] = -2;
    4284:       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*4 + GetQuadEdge_Static(ornt[3], 3);
    4285:       orntNew[2] = 0;
    4286:       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 3;
    4287:       orntNew[3] = 0;
    4288:       DMPlexSetCone(rdm, newp, coneNew);
    4289:       DMPlexSetConeOrientation(rdm, newp, orntNew);
    4290: #if 1
    4291:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
    4292:       for (p = 0; p < 4; ++p) {
    4293:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eEndNew);
    4294:       }
    4295: #endif
    4296:       /* B-H face */
    4297:       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 11;
    4298:       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 5;
    4299:       orntNew[0] = 0;
    4300:       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 3;
    4301:       orntNew[1] = -2;
    4302:       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*4 + GetQuadEdge_Static(ornt[3], 1);
    4303:       orntNew[2] = -2;
    4304:       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (cone[5] - fStart)*4 + GetQuadEdge_Static(ornt[5], 2);
    4305:       orntNew[3] = 0;
    4306:       DMPlexSetCone(rdm, newp, coneNew);
    4307:       DMPlexSetConeOrientation(rdm, newp, orntNew);
    4308: #if 1
    4309:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
    4310:       for (p = 0; p < 4; ++p) {
    4311:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eEndNew);
    4312:       }
    4313: #endif
    4314:       for (r = 0; r < 12; ++r) {
    4315:         newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + r;
    4316:         supportNew[0] = cStartNew + (c - cStart)*8 + newCells[r*2+0];
    4317:         supportNew[1] = cStartNew + (c - cStart)*8 + newCells[r*2+1];
    4318:         DMPlexSetSupport(rdm, newp, supportNew);
    4319: #if 1
    4320:         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
    4321:         for (p = 0; p < 2; ++p) {
    4322:           if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cEndNew);
    4323:         }
    4324: #endif
    4325:       }
    4326:     }
    4327:     /* Split edges have 2 vertices and the same faces as the parent */
    4328:     DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);
    4329:     for (e = eStart; e < eEnd; ++e) {
    4330:       const PetscInt newv = vStartNew + (vEnd - vStart) + (e - eStart);

    4332:       for (r = 0; r < 2; ++r) {
    4333:         const PetscInt  newp = eStartNew + (e - eStart)*2 + r;
    4334:         const PetscInt *cone, *ornt, *support;
    4335:         PetscInt        coneNew[2], coneSize, c, supportSize, s;

    4337:         DMPlexGetCone(dm, e, &cone);
    4338:         coneNew[0]       = vStartNew + (cone[0] - vStart);
    4339:         coneNew[1]       = vStartNew + (cone[1] - vStart);
    4340:         coneNew[(r+1)%2] = newv;
    4341:         DMPlexSetCone(rdm, newp, coneNew);
    4342: #if 1
    4343:         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
    4344:         for (p = 0; p < 2; ++p) {
    4345:           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
    4346:         }
    4347: #endif
    4348:         DMPlexGetSupportSize(dm, e, &supportSize);
    4349:         DMPlexGetSupport(dm, e, &support);
    4350:         for (s = 0; s < supportSize; ++s) {
    4351:           DMPlexGetConeSize(dm, support[s], &coneSize);
    4352:           DMPlexGetCone(dm, support[s], &cone);
    4353:           DMPlexGetConeOrientation(dm, support[s], &ornt);
    4354:           for (c = 0; c < coneSize; ++c) {
    4355:             if (cone[c] == e) break;
    4356:           }
    4357:           supportRef[s] = fStartNew + (support[s] - fStart)*4 + (ornt[c] < 0 ? (c+1-r)%4 : (c+r)%4);
    4358:         }
    4359:         DMPlexSetSupport(rdm, newp, supportRef);
    4360: #if 1
    4361:         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
    4362:         for (p = 0; p < supportSize; ++p) {
    4363:           if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", supportRef[p], fStartNew, fEndNew);
    4364:         }
    4365: #endif
    4366:       }
    4367:     }
    4368:     /* Face edges have 2 vertices and 2+cells faces */
    4369:     for (f = fStart; f < fEnd; ++f) {
    4370:       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};
    4371:       const PetscInt  newv = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (f - fStart);
    4372:       const PetscInt *cone, *coneCell, *orntCell, *support;
    4373:       PetscInt        coneNew[2], coneSize, c, supportSize, s;

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

    4379:         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r] - eStart);
    4380:         coneNew[1] = newv;
    4381:         DMPlexSetCone(rdm, newp, coneNew);
    4382: #if 1
    4383:         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
    4384:         for (p = 0; p < 2; ++p) {
    4385:           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
    4386:         }
    4387: #endif
    4388:         DMPlexGetSupportSize(dm, f, &supportSize);
    4389:         DMPlexGetSupport(dm, f, &support);
    4390:         supportRef[0] = fStartNew + (f - fStart)*4 + r;
    4391:         supportRef[1] = fStartNew + (f - fStart)*4 + (r+1)%4;
    4392:         for (s = 0; s < supportSize; ++s) {
    4393:           DMPlexGetConeSize(dm, support[s], &coneSize);
    4394:           DMPlexGetCone(dm, support[s], &coneCell);
    4395:           DMPlexGetConeOrientation(dm, support[s], &orntCell);
    4396:           for (c = 0; c < coneSize; ++c) if (coneCell[c] == f) break;
    4397:           supportRef[2+s] = fStartNew + (fEnd - fStart)*4 + (support[s] - cStart)*12 + newFaces[c*4 + GetQuadEdgeInverse_Static(orntCell[c], r)];
    4398:         }
    4399:         DMPlexSetSupport(rdm, newp, supportRef);
    4400: #if 1
    4401:         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
    4402:         for (p = 0; p < 2+supportSize; ++p) {
    4403:           if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", supportRef[p], fStartNew, fEndNew);
    4404:         }
    4405: #endif
    4406:       }
    4407:     }
    4408:     /* Cell edges have 2 vertices and 4 faces */
    4409:     for (c = cStart; c < cEnd; ++c) {
    4410:       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};
    4411:       const PetscInt  newv = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (fEnd - fStart) + (c - cStart);
    4412:       const PetscInt *cone;
    4413:       PetscInt        coneNew[2], supportNew[4];

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

    4419:         coneNew[0] = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (cone[r] - fStart);
    4420:         coneNew[1] = newv;
    4421:         DMPlexSetCone(rdm, newp, coneNew);
    4422: #if 1
    4423:         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
    4424:         for (p = 0; p < 2; ++p) {
    4425:           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
    4426:         }
    4427: #endif
    4428:         for (f = 0; f < 4; ++f) supportNew[f] = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + newFaces[r*4+f];
    4429:         DMPlexSetSupport(rdm, newp, supportNew);
    4430: #if 1
    4431:         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
    4432:         for (p = 0; p < 4; ++p) {
    4433:           if ((supportNew[p] < fStartNew) || (supportNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", supportNew[p], fStartNew, fEndNew);
    4434:         }
    4435: #endif
    4436:       }
    4437:     }
    4438:     /* Old vertices have identical supports */
    4439:     for (v = vStart; v < vEnd; ++v) {
    4440:       const PetscInt  newp = vStartNew + (v - vStart);
    4441:       const PetscInt *support, *cone;
    4442:       PetscInt        size, s;

    4444:       DMPlexGetSupportSize(dm, v, &size);
    4445:       DMPlexGetSupport(dm, v, &support);
    4446:       for (s = 0; s < size; ++s) {
    4447:         PetscInt r = 0;

    4449:         DMPlexGetCone(dm, support[s], &cone);
    4450:         if (cone[1] == v) r = 1;
    4451:         supportRef[s] = eStartNew + (support[s] - eStart)*2 + r;
    4452:       }
    4453:       DMPlexSetSupport(rdm, newp, supportRef);
    4454: #if 1
    4455:       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
    4456:       for (p = 0; p < size; ++p) {
    4457:         if ((supportRef[p] < eStartNew) || (supportRef[p] >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", supportRef[p], eStartNew, eEndNew);
    4458:       }
    4459: #endif
    4460:     }
    4461:     /* Edge vertices have 2 + faces supports */
    4462:     for (e = eStart; e < eEnd; ++e) {
    4463:       const PetscInt  newp = vStartNew + (vEnd - vStart) + (e - eStart);
    4464:       const PetscInt *cone, *support;
    4465:       PetscInt        size, s;

    4467:       DMPlexGetSupportSize(dm, e, &size);
    4468:       DMPlexGetSupport(dm, e, &support);
    4469:       supportRef[0] = eStartNew + (e - eStart)*2 + 0;
    4470:       supportRef[1] = eStartNew + (e - eStart)*2 + 1;
    4471:       for (s = 0; s < size; ++s) {
    4472:         PetscInt r;

    4474:         DMPlexGetCone(dm, support[s], &cone);
    4475:         for (r = 0; r < 4; ++r) if (cone[r] == e) break;
    4476:         supportRef[2+s] = eStartNew + (eEnd - eStart)*2 + (support[s] - fStart)*4 + r;
    4477:       }
    4478:       DMPlexSetSupport(rdm, newp, supportRef);
    4479: #if 1
    4480:       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
    4481:       for (p = 0; p < 2+size; ++p) {
    4482:         if ((supportRef[p] < eStartNew) || (supportRef[p] >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", supportRef[p], eStartNew, eEndNew);
    4483:       }
    4484: #endif
    4485:     }
    4486:     /* Face vertices have 4 + cells supports */
    4487:     for (f = fStart; f < fEnd; ++f) {
    4488:       const PetscInt  newp = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (f - fStart);
    4489:       const PetscInt *cone, *support;
    4490:       PetscInt        size, s;

    4492:       DMPlexGetSupportSize(dm, f, &size);
    4493:       DMPlexGetSupport(dm, f, &support);
    4494:       for (r = 0; r < 4; ++r) supportRef[r] = eStartNew + (eEnd - eStart)*2 +  (f - fStart)*4 + r;
    4495:       for (s = 0; s < size; ++s) {
    4496:         PetscInt r;

    4498:         DMPlexGetCone(dm, support[s], &cone);
    4499:         for (r = 0; r < 6; ++r) if (cone[r] == f) break;
    4500:         supportRef[4+s] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*4 + (support[s] - cStart)*6 + r;
    4501:       }
    4502:       DMPlexSetSupport(rdm, newp, supportRef);
    4503: #if 1
    4504:       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
    4505:       for (p = 0; p < 4+size; ++p) {
    4506:         if ((supportRef[p] < eStartNew) || (supportRef[p] >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", supportRef[p], eStartNew, eEndNew);
    4507:       }
    4508: #endif
    4509:     }
    4510:     /* Cell vertices have 6 supports */
    4511:     for (c = cStart; c < cEnd; ++c) {
    4512:       const PetscInt newp = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (fEnd - fStart) + (c - cStart);
    4513:       PetscInt       supportNew[6];

    4515:       for (r = 0; r < 6; ++r) {
    4516:         supportNew[r] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*4 + (c - cStart)*6 + r;
    4517:       }
    4518:       DMPlexSetSupport(rdm, newp, supportNew);
    4519:     }
    4520:     PetscFree(supportRef);
    4521:     break;
    4522:   case REFINER_HYBRID_HEX_3D:
    4523:     DMPlexGetHybridBounds(rdm, &cMaxNew, &fMaxNew, &eMaxNew, NULL);
    4524:     /*
    4525:      Bottom (viewed from top)    Top
    4526:      1---------2---------2       7---------2---------6
    4527:      |         |         |       |         |         |
    4528:      |    B    2    C    |       |    H    2    G    |
    4529:      |         |         |       |         |         |
    4530:      3----3----0----1----1       3----3----0----1----1
    4531:      |         |         |       |         |         |
    4532:      |    A    0    D    |       |    E    0    F    |
    4533:      |         |         |       |         |         |
    4534:      0---------0---------3       4---------0---------5
    4535:      */
    4536:     /* Interior cells have 6 faces: Bottom, Top, Front, Back, Right, Left */
    4537:     for (c = cStart; c < cMax; ++c) {
    4538:       const PetscInt  newp = (c - cStart)*8;
    4539:       const PetscInt *cone, *ornt;
    4540:       PetscInt        coneNew[6], orntNew[6];

    4542:       DMPlexGetCone(dm, c, &cone);
    4543:       DMPlexGetConeOrientation(dm, c, &ornt);
    4544:       /* A hex */
    4545:       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], 0);
    4546:       orntNew[0] = ornt[0];
    4547:       coneNew[1] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  8; /* AE */
    4548:       orntNew[1] = 0;
    4549:       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetQuadSubface_Static(ornt[2], 0);
    4550:       orntNew[2] = ornt[2];
    4551:       coneNew[3] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  3; /* AB */
    4552:       orntNew[3] = 0;
    4553:       coneNew[4] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  0; /* AD */
    4554:       orntNew[4] = 0;
    4555:       coneNew[5] = fStartNew + (cone[5] - fStart)*4 + GetQuadSubface_Static(ornt[5], 0);
    4556:       orntNew[5] = ornt[5];
    4557:       DMPlexSetCone(rdm, newp+0, coneNew);
    4558:       DMPlexSetConeOrientation(rdm, newp+0, orntNew);
    4559: #if 1
    4560:       if ((newp+0 < cStartNew) || (newp+0 >= cMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+0, cStartNew, cMaxNew);
    4561:       for (p = 0; p < 6; ++p) {
    4562:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fMaxNew);
    4563:       }
    4564: #endif
    4565:       /* B hex */
    4566:       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], 1);
    4567:       orntNew[0] = ornt[0];
    4568:       coneNew[1] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 + 11; /* BH */
    4569:       orntNew[1] = 0;
    4570:       coneNew[2] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  3; /* AB */
    4571:       orntNew[2] = -1;
    4572:       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetQuadSubface_Static(ornt[3], 1);
    4573:       orntNew[3] = ornt[3];
    4574:       coneNew[4] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  2; /* BC */
    4575:       orntNew[4] = 0;
    4576:       coneNew[5] = fStartNew + (cone[5] - fStart)*4 + GetQuadSubface_Static(ornt[5], 3);
    4577:       orntNew[5] = ornt[5];
    4578:       DMPlexSetCone(rdm, newp+1, coneNew);
    4579:       DMPlexSetConeOrientation(rdm, newp+1, orntNew);
    4580: #if 1
    4581:       if ((newp+1 < cStartNew) || (newp+1 >= cMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+1, cStartNew, cMaxNew);
    4582:       for (p = 0; p < 6; ++p) {
    4583:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fMaxNew);
    4584:       }
    4585: #endif
    4586:       /* C hex */
    4587:       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], 2);
    4588:       orntNew[0] = ornt[0];
    4589:       coneNew[1] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 + 10; /* CG */
    4590:       orntNew[1] = 0;
    4591:       coneNew[2] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  1; /* CD */
    4592:       orntNew[2] = -1;
    4593:       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetQuadSubface_Static(ornt[3], 0);
    4594:       orntNew[3] = ornt[3];
    4595:       coneNew[4] = fStartNew + (cone[4] - fStart)*4 + GetQuadSubface_Static(ornt[4], 1);
    4596:       orntNew[4] = ornt[4];
    4597:       coneNew[5] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  2; /* BC */
    4598:       orntNew[5] = -4;
    4599:       DMPlexSetCone(rdm, newp+2, coneNew);
    4600:       DMPlexSetConeOrientation(rdm, newp+2, orntNew);
    4601: #if 1
    4602:       if ((newp+2 < cStartNew) || (newp+2 >= cMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+2, cStartNew, cMaxNew);
    4603:       for (p = 0; p < 6; ++p) {
    4604:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fMaxNew);
    4605:       }
    4606: #endif
    4607:       /* D hex */
    4608:       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], 3);
    4609:       orntNew[0] = ornt[0];
    4610:       coneNew[1] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  9; /* DF */
    4611:       orntNew[1] = 0;
    4612:       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetQuadSubface_Static(ornt[2], 1);
    4613:       orntNew[2] = ornt[2];
    4614:       coneNew[3] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  1; /* CD */
    4615:       orntNew[3] = 0;
    4616:       coneNew[4] = fStartNew + (cone[4] - fStart)*4 + GetQuadSubface_Static(ornt[4], 0);
    4617:       orntNew[4] = ornt[4];
    4618:       coneNew[5] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  0; /* AD */
    4619:       orntNew[5] = -4;
    4620:       DMPlexSetCone(rdm, newp+3, coneNew);
    4621:       DMPlexSetConeOrientation(rdm, newp+3, orntNew);
    4622: #if 1
    4623:       if ((newp+3 < cStartNew) || (newp+3 >= cMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+3, cStartNew, cMaxNew);
    4624:       for (p = 0; p < 6; ++p) {
    4625:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fMaxNew);
    4626:       }
    4627: #endif
    4628:       /* E hex */
    4629:       coneNew[0] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  8; /* AE */
    4630:       orntNew[0] = -4;
    4631:       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], 0);
    4632:       orntNew[1] = ornt[1];
    4633:       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetQuadSubface_Static(ornt[2], 3);
    4634:       orntNew[2] = ornt[2];
    4635:       coneNew[3] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  7; /* EH */
    4636:       orntNew[3] = 0;
    4637:       coneNew[4] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  4; /* EF */
    4638:       orntNew[4] = -1;
    4639:       coneNew[5] = fStartNew + (cone[5] - fStart)*4 + GetQuadSubface_Static(ornt[5], 1);
    4640:       orntNew[5] = ornt[5];
    4641:       DMPlexSetCone(rdm, newp+4, coneNew);
    4642:       DMPlexSetConeOrientation(rdm, newp+4, orntNew);
    4643: #if 1
    4644:       if ((newp+4 < cStartNew) || (newp+4 >= cMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+4, cStartNew, cMaxNew);
    4645:       for (p = 0; p < 6; ++p) {
    4646:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fMaxNew);
    4647:       }
    4648: #endif
    4649:       /* F hex */
    4650:       coneNew[0] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  9; /* DF */
    4651:       orntNew[0] = -4;
    4652:       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], 1);
    4653:       orntNew[1] = ornt[1];
    4654:       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetQuadSubface_Static(ornt[2], 2);
    4655:       orntNew[2] = ornt[2];
    4656:       coneNew[3] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  5; /* FG */
    4657:       orntNew[3] = -1;
    4658:       coneNew[4] = fStartNew + (cone[4] - fStart)*4 + GetQuadSubface_Static(ornt[4], 3);
    4659:       orntNew[4] = ornt[4];
    4660:       coneNew[5] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  4; /* EF */
    4661:       orntNew[5] = 1;
    4662:       DMPlexSetCone(rdm, newp+5, coneNew);
    4663:       DMPlexSetConeOrientation(rdm, newp+5, orntNew);
    4664: #if 1
    4665:       if ((newp+5 < cStartNew) || (newp+5 >= cMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+5, cStartNew, cMaxNew);
    4666:       for (p = 0; p < 6; ++p) {
    4667:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fMaxNew);
    4668:       }
    4669: #endif
    4670:       /* G hex */
    4671:       coneNew[0] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 + 10; /* CG */
    4672:       orntNew[0] = -4;
    4673:       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], 2);
    4674:       orntNew[1] = ornt[1];
    4675:       coneNew[2] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  5; /* FG */
    4676:       orntNew[2] = 0;
    4677:       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetQuadSubface_Static(ornt[3], 3);
    4678:       orntNew[3] = ornt[3];
    4679:       coneNew[4] = fStartNew + (cone[4] - fStart)*4 + GetQuadSubface_Static(ornt[4], 2);
    4680:       orntNew[4] = ornt[4];
    4681:       coneNew[5] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  6; /* GH */
    4682:       orntNew[5] = -3;
    4683:       DMPlexSetCone(rdm, newp+6, coneNew);
    4684:       DMPlexSetConeOrientation(rdm, newp+6, orntNew);
    4685: #if 1
    4686:       if ((newp+6 < cStartNew) || (newp+6 >= cMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+6, cStartNew, cMaxNew);
    4687:       for (p = 0; p < 6; ++p) {
    4688:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fMaxNew);
    4689:       }
    4690: #endif
    4691:       /* H hex */
    4692:       coneNew[0] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 + 11; /* BH */
    4693:       orntNew[0] = -4;
    4694:       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], 3);
    4695:       orntNew[1] = ornt[1];
    4696:       coneNew[2] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  7; /* EH */
    4697:       orntNew[2] = -1;
    4698:       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetQuadSubface_Static(ornt[3], 2);
    4699:       orntNew[3] = ornt[3];
    4700:       coneNew[4] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  6; /* GH */
    4701:       orntNew[4] = 3;
    4702:       coneNew[5] = fStartNew + (cone[5] - fStart)*4 + GetQuadSubface_Static(ornt[5], 2);
    4703:       orntNew[5] = ornt[5];
    4704:       DMPlexSetCone(rdm, newp+7, coneNew);
    4705:       DMPlexSetConeOrientation(rdm, newp+7, orntNew);
    4706: #if 1
    4707:       if ((newp+7 < cStartNew) || (newp+7 >= cMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+7, cStartNew, cMaxNew);
    4708:       for (p = 0; p < 6; ++p) {
    4709:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fMaxNew);
    4710:       }
    4711: #endif
    4712:     }
    4713:     /* Hybrid cells have 6 faces: Front, Back, Sides */
    4714:     /*
    4715:      3---------2---------2
    4716:      |         |         |
    4717:      |    D    2    C    |
    4718:      |         |         |
    4719:      3----3----0----1----1
    4720:      |         |         |
    4721:      |    A    0    B    |
    4722:      |         |         |
    4723:      0---------0---------1
    4724:      */
    4725:     for (c = cMax; c < cEnd; ++c) {
    4726:       const PetscInt  newp = (cMax - cStart)*8 + (c - cMax)*4;
    4727:       const PetscInt *cone, *ornt, *fornt;
    4728:       PetscInt        coneNew[6], orntNew[6], o, of, i;

    4730:       DMPlexGetCone(dm, c, &cone);
    4731:       DMPlexGetConeOrientation(dm, c, &ornt);
    4732:       DMPlexGetConeOrientation(dm, cone[0], &fornt);
    4733:       o = ornt[0] < 0 ? -1 : 1;
    4734:       for (r = 0; r < 4; ++r) {
    4735:         PetscInt subfA = GetQuadSubface_Static(ornt[0], r);
    4736:         PetscInt edgeA = GetQuadEdge_Static(ornt[0], r);
    4737:         PetscInt edgeB = GetQuadEdge_Static(ornt[0], (r+3)%4);
    4738:         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]);
    4739:         coneNew[0]         = fStartNew + (cone[0] - fStart)*4 + subfA;
    4740:         orntNew[0]         = ornt[0];
    4741:         coneNew[1]         = fStartNew + (cone[1] - fStart)*4 + subfA;
    4742:         orntNew[1]         = ornt[0];
    4743:         of = fornt[edgeA] < 0 ? -1 : 1;
    4744:         i  = GetQuadEdgeInverse_Static(ornt[0], r) + 2;
    4745:         coneNew[i] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (cone[2+edgeA] - fMax)*2 + (o*of < 0 ? 1 : 0);
    4746:         orntNew[i] = ornt[edgeA];
    4747:         i  = GetQuadEdgeInverse_Static(ornt[0], (r+1)%4) + 2;
    4748:         coneNew[i] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd          - fMax)*2 + (c - cMax)*4 + edgeA;
    4749:         orntNew[i] = 0;
    4750:         i  = GetQuadEdgeInverse_Static(ornt[0], (r+2)%4) + 2;
    4751:         coneNew[i] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd          - fMax)*2 + (c - cMax)*4 + edgeB;
    4752:         orntNew[i] = -2;
    4753:         of = fornt[edgeB] < 0 ? -1 : 1;
    4754:         i  = GetQuadEdgeInverse_Static(ornt[0], (r+3)%4) + 2;
    4755:         coneNew[i] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (cone[2+edgeB] - fMax)*2 + (o*of < 0 ? 0 : 1);
    4756:         orntNew[i] = ornt[edgeB];
    4757:         DMPlexSetCone(rdm, newp+r, coneNew);
    4758:         DMPlexSetConeOrientation(rdm, newp+r, orntNew);
    4759: #if 1
    4760:         if ((newp+r < cMaxNew) || (newp+r >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid cell [%d, %d)", newp+r, cMaxNew, cEndNew);
    4761:         for (p = 0; p < 2; ++p) {
    4762:           if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fMaxNew);
    4763:         }
    4764:         for (p = 2; p < 6; ++p) {
    4765:           if ((coneNew[p] < fMaxNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid face [%d, %d)", coneNew[p], fMaxNew, fEndNew);
    4766:         }
    4767: #endif
    4768:       }
    4769:     }
    4770:     /* Interior split faces have 4 edges and the same cells as the parent */
    4771:     DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);
    4772:     PetscMalloc1(4 + maxSupportSize*2, &supportRef);
    4773:     for (f = fStart; f < fMax; ++f) {
    4774:       for (r = 0; r < 4; ++r) {
    4775:         /* TODO: This can come from GetFaces_Internal() */
    4776:         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};
    4777:         const PetscInt  newp = fStartNew + (f - fStart)*4 + r;
    4778:         const PetscInt *cone, *ornt, *support;
    4779:         PetscInt        coneNew[4], orntNew[4], coneSize, c, supportSize, s;

    4781:         DMPlexGetCone(dm, f, &cone);
    4782:         DMPlexGetConeOrientation(dm, f, &ornt);
    4783:         coneNew[(r+3)%4] = eStartNew + (cone[(r+3)%4] - eStart)*2 + (ornt[(r+3)%4] < 0 ? 0 : 1);
    4784:         orntNew[(r+3)%4] = ornt[(r+3)%4];
    4785:         coneNew[(r+0)%4] = eStartNew + (cone[r]       - eStart)*2 + (ornt[r] < 0 ? 1 : 0);
    4786:         orntNew[(r+0)%4] = ornt[r];
    4787:         coneNew[(r+1)%4] = eStartNew + (eMax - eStart)*2 + (f - fStart)*4 + r;
    4788:         orntNew[(r+1)%4] = 0;
    4789:         coneNew[(r+2)%4] = eStartNew + (eMax - eStart)*2 + (f - fStart)*4 + (r+3)%4;
    4790:         orntNew[(r+2)%4] = -2;
    4791:         DMPlexSetCone(rdm, newp, coneNew);
    4792:         DMPlexSetConeOrientation(rdm, newp, orntNew);
    4793: #if 1
    4794:         if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
    4795:         for (p = 0; p < 4; ++p) {
    4796:           if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eMaxNew);
    4797:         }
    4798: #endif
    4799:         DMPlexGetSupportSize(dm, f, &supportSize);
    4800:         DMPlexGetSupport(dm, f, &support);
    4801:         for (s = 0; s < supportSize; ++s) {
    4802:           PetscInt subf;
    4803:           DMPlexGetConeSize(dm, support[s], &coneSize);
    4804:           DMPlexGetCone(dm, support[s], &cone);
    4805:           DMPlexGetConeOrientation(dm, support[s], &ornt);
    4806:           for (c = 0; c < coneSize; ++c) {
    4807:             if (cone[c] == f) break;
    4808:           }
    4809:           subf = GetQuadSubfaceInverse_Static(ornt[c], r);
    4810:           if (support[s] < cMax) {
    4811:             supportRef[s] = cStartNew + (support[s] - cStart)*8 + newCells[c*4+subf];
    4812:           } else {
    4813:             supportRef[s] = cStartNew + (cMax       - cStart)*8 + (support[s] - cMax)*4 + subf;
    4814:           }
    4815:         }
    4816:         DMPlexSetSupport(rdm, newp, supportRef);
    4817: #if 1
    4818:         if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
    4819:         for (p = 0; p < supportSize; ++p) {
    4820:           if ((supportRef[p] < cStartNew) || (supportRef[p] >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportRef[p], cStartNew, cEndNew);
    4821:         }
    4822: #endif
    4823:       }
    4824:     }
    4825:     /* Interior cell faces have 4 edges and 2 cells */
    4826:     for (c = cStart; c < cMax; ++c) {
    4827:       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};
    4828:       const PetscInt *cone, *ornt;
    4829:       PetscInt        newp, coneNew[4], orntNew[4], supportNew[2];

    4831:       DMPlexGetCone(dm, c, &cone);
    4832:       DMPlexGetConeOrientation(dm, c, &ornt);
    4833:       /* A-D face */
    4834:       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 0;
    4835:       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*4 + GetQuadEdge_Static(ornt[0], 3);
    4836:       orntNew[0] = 0;
    4837:       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 0;
    4838:       orntNew[1] = 0;
    4839:       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 2;
    4840:       orntNew[2] = -2;
    4841:       coneNew[3] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*4 + GetQuadEdge_Static(ornt[2], 0);
    4842:       orntNew[3] = -2;
    4843:       DMPlexSetCone(rdm, newp, coneNew);
    4844:       DMPlexSetConeOrientation(rdm, newp, orntNew);
    4845: #if 1
    4846:       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
    4847:       for (p = 0; p < 4; ++p) {
    4848:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eMaxNew);
    4849:       }
    4850: #endif
    4851:       /* C-D face */
    4852:       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 1;
    4853:       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*4 + GetQuadEdge_Static(ornt[0], 2);
    4854:       orntNew[0] = 0;
    4855:       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 0;
    4856:       orntNew[1] = 0;
    4857:       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 4;
    4858:       orntNew[2] = -2;
    4859:       coneNew[3] = eStartNew + (eMax - eStart)*2 + (cone[4] - fStart)*4 + GetQuadEdge_Static(ornt[4], 0);
    4860:       orntNew[3] = -2;
    4861:       DMPlexSetCone(rdm, newp, coneNew);
    4862:       DMPlexSetConeOrientation(rdm, newp, orntNew);
    4863: #if 1
    4864:       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
    4865:       for (p = 0; p < 4; ++p) {
    4866:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eMaxNew);
    4867:       }
    4868: #endif
    4869:       /* B-C face */
    4870:       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 2;
    4871:       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*4 + GetQuadEdge_Static(ornt[0], 1);
    4872:       orntNew[0] = -2;
    4873:       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*4 + GetQuadEdge_Static(ornt[3], 0);
    4874:       orntNew[1] = 0;
    4875:       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 3;
    4876:       orntNew[2] = 0;
    4877:       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 0;
    4878:       orntNew[3] = -2;
    4879:       DMPlexSetCone(rdm, newp, coneNew);
    4880:       DMPlexSetConeOrientation(rdm, newp, orntNew);
    4881: #if 1
    4882:       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
    4883:       for (p = 0; p < 4; ++p) {
    4884:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eMaxNew);
    4885:       }
    4886: #endif
    4887:       /* A-B face */
    4888:       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 3;
    4889:       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*4 + GetQuadEdge_Static(ornt[0], 0);
    4890:       orntNew[0] = -2;
    4891:       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[5] - fStart)*4 + GetQuadEdge_Static(ornt[5], 3);
    4892:       orntNew[1] = 0;
    4893:       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 5;
    4894:       orntNew[2] = 0;
    4895:       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 0;
    4896:       orntNew[3] = -2;
    4897:       DMPlexSetCone(rdm, newp, coneNew);
    4898:       DMPlexSetConeOrientation(rdm, newp, orntNew);
    4899: #if 1
    4900:       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
    4901:       for (p = 0; p < 4; ++p) {
    4902:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eMaxNew);
    4903:       }
    4904: #endif
    4905:       /* E-F face */
    4906:       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 4;
    4907:       coneNew[0] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 2;
    4908:       orntNew[0] = -2;
    4909:       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*4 + GetQuadEdge_Static(ornt[2], 2);
    4910:       orntNew[1] = -2;
    4911:       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*4 + GetQuadEdge_Static(ornt[1], 0);
    4912:       orntNew[2] = 0;
    4913:       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 1;
    4914:       orntNew[3] = 0;
    4915:       DMPlexSetCone(rdm, newp, coneNew);
    4916:       DMPlexSetConeOrientation(rdm, newp, orntNew);
    4917: #if 1
    4918:       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
    4919:       for (p = 0; p < 4; ++p) {
    4920:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eMaxNew);
    4921:       }
    4922: #endif
    4923:       /* F-G face */
    4924:       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 5;
    4925:       coneNew[0] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 4;
    4926:       orntNew[0] = -2;
    4927:       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[4] - fStart)*4 + GetQuadEdge_Static(ornt[4], 2);
    4928:       orntNew[1] = -2;
    4929:       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*4 + GetQuadEdge_Static(ornt[1], 1);
    4930:       orntNew[2] = 0;
    4931:       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 1;
    4932:       orntNew[3] = 0;
    4933:       DMPlexSetCone(rdm, newp, coneNew);
    4934:       DMPlexSetConeOrientation(rdm, newp, orntNew);
    4935: #if 1
    4936:       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
    4937:       for (p = 0; p < 4; ++p) {
    4938:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eMaxNew);
    4939:       }
    4940: #endif
    4941:       /* G-H face */
    4942:       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 6;
    4943:       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*4 + GetQuadEdge_Static(ornt[3], 2);
    4944:       orntNew[0] = -2;
    4945:       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*4 + GetQuadEdge_Static(ornt[1], 2);
    4946:       orntNew[1] = 0;
    4947:       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 1;
    4948:       orntNew[2] = 0;
    4949:       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 3;
    4950:       orntNew[3] = -2;
    4951:       DMPlexSetCone(rdm, newp, coneNew);
    4952:       DMPlexSetConeOrientation(rdm, newp, orntNew);
    4953: #if 1
    4954:       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
    4955:       for (p = 0; p < 4; ++p) {
    4956:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eMaxNew);
    4957:       }
    4958: #endif
    4959:       /* E-H face */
    4960:       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 7;
    4961:       coneNew[0] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 5;
    4962:       orntNew[0] = -2;
    4963:       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[5] - fStart)*4 + GetQuadEdge_Static(ornt[5], 1);
    4964:       orntNew[1] = -2;
    4965:       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*4 + GetQuadEdge_Static(ornt[1], 3);
    4966:       orntNew[2] = 0;
    4967:       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 1;
    4968:       orntNew[3] = 0;
    4969:       DMPlexSetCone(rdm, newp, coneNew);
    4970:       DMPlexSetConeOrientation(rdm, newp, orntNew);
    4971: #if 1
    4972:       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
    4973:       for (p = 0; p < 4; ++p) {
    4974:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eMaxNew);
    4975:       }
    4976: #endif
    4977:       /* A-E face */
    4978:       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 8;
    4979:       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*4 + GetQuadEdge_Static(ornt[2], 3);
    4980:       orntNew[0] = 0;
    4981:       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 2;
    4982:       orntNew[1] = 0;
    4983:       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 5;
    4984:       orntNew[2] = -2;
    4985:       coneNew[3] = eStartNew + (eMax - eStart)*2 + (cone[5] - fStart)*4 + GetQuadEdge_Static(ornt[5], 0);
    4986:       orntNew[3] = -2;
    4987:       DMPlexSetCone(rdm, newp, coneNew);
    4988:       DMPlexSetConeOrientation(rdm, newp, orntNew);
    4989: #if 1
    4990:       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
    4991:       for (p = 0; p < 4; ++p) {
    4992:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eMaxNew);
    4993:       }
    4994: #endif
    4995:       /* D-F face */
    4996:       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 9;
    4997:       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*4 + GetQuadEdge_Static(ornt[2], 1);
    4998:       orntNew[0] = -2;
    4999:       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[4] - fStart)*4 + GetQuadEdge_Static(ornt[4], 3);
    5000:       orntNew[1] = 0;
    5001:       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 4;
    5002:       orntNew[2] = 0;
    5003:       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 2;
    5004:       orntNew[3] = -2;
    5005:       DMPlexSetCone(rdm, newp, coneNew);
    5006:       DMPlexSetConeOrientation(rdm, newp, orntNew);
    5007: #if 1
    5008:       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
    5009:       for (p = 0; p < 4; ++p) {
    5010:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eMaxNew);
    5011:       }
    5012: #endif
    5013:       /* C-G face */
    5014:       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 10;
    5015:       coneNew[0] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 4;
    5016:       orntNew[0] = -2;
    5017:       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[4] - fStart)*4 + GetQuadEdge_Static(ornt[4], 1);
    5018:       orntNew[1] = -2;
    5019:       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*4 + GetQuadEdge_Static(ornt[3], 3);
    5020:       orntNew[2] = 0;
    5021:       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 3;
    5022:       orntNew[3] = 0;
    5023:       DMPlexSetCone(rdm, newp, coneNew);
    5024:       DMPlexSetConeOrientation(rdm, newp, orntNew);
    5025: #if 1
    5026:       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
    5027:       for (p = 0; p < 4; ++p) {
    5028:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eMaxNew);
    5029:       }
    5030: #endif
    5031:       /* B-H face */
    5032:       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 11;
    5033:       coneNew[0] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 5;
    5034:       orntNew[0] = 0;
    5035:       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 3;
    5036:       orntNew[1] = -2;
    5037:       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*4 + GetQuadEdge_Static(ornt[3], 1);
    5038:       orntNew[2] = -2;
    5039:       coneNew[3] = eStartNew + (eMax - eStart)*2 + (cone[5] - fStart)*4 + GetQuadEdge_Static(ornt[5], 2);
    5040:       orntNew[3] = 0;
    5041:       DMPlexSetCone(rdm, newp, coneNew);
    5042:       DMPlexSetConeOrientation(rdm, newp, orntNew);
    5043: #if 1
    5044:       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
    5045:       for (p = 0; p < 4; ++p) {
    5046:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eMaxNew);
    5047:       }
    5048: #endif
    5049:       for (r = 0; r < 12; ++r) {
    5050:         newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + r;
    5051:         supportNew[0] = cStartNew + (c - cStart)*8 + newCells[r*2+0];
    5052:         supportNew[1] = cStartNew + (c - cStart)*8 + newCells[r*2+1];
    5053:         DMPlexSetSupport(rdm, newp, supportNew);
    5054: #if 1
    5055:         if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
    5056:         for (p = 0; p < 2; ++p) {
    5057:           if ((supportNew[p] < cStartNew) || (supportNew[p] >= cMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cMaxNew);
    5058:         }
    5059: #endif
    5060:       }
    5061:     }
    5062:     /* Hybrid split faces have 4 edges and same cells */
    5063:     for (f = fMax; f < fEnd; ++f) {
    5064:       const PetscInt *cone, *ornt, *support;
    5065:       PetscInt        coneNew[4], orntNew[4];
    5066:       PetscInt        supportNew[2], size, s, c;

    5068:       DMPlexGetCone(dm, f, &cone);
    5069:       DMPlexGetConeOrientation(dm, f, &ornt);
    5070:       DMPlexGetSupportSize(dm, f, &size);
    5071:       DMPlexGetSupport(dm, f, &support);
    5072:       for (r = 0; r < 2; ++r) {
    5073:         const PetscInt newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (f - fMax)*2 + r;

    5075:         coneNew[0]   = eStartNew + (cone[0] - eStart)*2 + (ornt[0] < 0 ? 1-r : r);
    5076:         orntNew[0]   = ornt[0];
    5077:         coneNew[1]   = eStartNew + (cone[1] - eStart)*2 + (ornt[1] < 0 ? 1-r : r);
    5078:         orntNew[1]   = ornt[1];
    5079:         coneNew[2+r] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (cone[2+r] - eMax);
    5080:         orntNew[2+r] = 0;
    5081:         coneNew[3-r] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (eEnd      - eMax) + (f - fMax);
    5082:         orntNew[3-r] = 0;
    5083:         DMPlexSetCone(rdm, newp, coneNew);
    5084:         DMPlexSetConeOrientation(rdm, newp, orntNew);
    5085: #if 1
    5086:         if ((newp < fMaxNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid face [%d, %d)", newp, fMaxNew, fEndNew);
    5087:         for (p = 0; p < 2; ++p) {
    5088:           if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eMaxNew);
    5089:         }
    5090:         for (p = 2; p < 4; ++p) {
    5091:           if ((coneNew[p] < eMaxNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid edge [%d, %d)", coneNew[p], eMaxNew, eEndNew);
    5092:         }
    5093: #endif
    5094:         for (s = 0; s < size; ++s) {
    5095:           const PetscInt *coneCell, *orntCell, *fornt;
    5096:           PetscInt        o, of;

    5098:           DMPlexGetCone(dm, support[s], &coneCell);
    5099:           DMPlexGetConeOrientation(dm, support[s], &orntCell);
    5100:           o = orntCell[0] < 0 ? -1 : 1;
    5101:           for (c = 2; c < 6; ++c) if (coneCell[c] == f) break;
    5102:           if (c >= 6) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Could not find face %d in cone of cell %d", f, support[s]);
    5103:           DMPlexGetConeOrientation(dm, coneCell[0], &fornt);
    5104:           of = fornt[c-2] < 0 ? -1 : 1;
    5105:           supportNew[s] = cStartNew + (cMax - cStart)*8 + (support[s] - cMax)*4 + (GetQuadEdgeInverse_Static(orntCell[0], c-2) + (o*of < 0 ? 1-r : r))%4;
    5106:         }
    5107:         DMPlexSetSupport(rdm, newp, supportNew);
    5108: #if 1
    5109:         if ((newp < fMaxNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid face [%d, %d)", newp, fMaxNew, fEndNew);
    5110:         for (p = 0; p < size; ++p) {
    5111:           if ((supportNew[p] < cMaxNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid cell [%d, %d)", supportNew[p], cMaxNew, cEndNew);
    5112:         }
    5113: #endif
    5114:       }
    5115:     }
    5116:     /* Hybrid cell faces have 4 edges and 2 cells */
    5117:     for (c = cMax; c < cEnd; ++c) {
    5118:       PetscInt        newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd - fMax)*2 + (c - cMax)*4;
    5119:       const PetscInt *cone, *ornt;
    5120:       PetscInt        coneNew[4], orntNew[4];
    5121:       PetscInt        supportNew[2];

    5123:       DMPlexGetCone(dm, c, &cone);
    5124:       DMPlexGetConeOrientation(dm, c, &ornt);
    5125:       for (r = 0; r < 4; ++r) {
    5126: #if 0
    5127:         coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], r);
    5128:         orntNew[0] = 0;
    5129:         coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], r);
    5130:         orntNew[1] = 0;
    5131:         coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (eEnd - eMax) + (cone[2+GetQuadEdge_Static(ornt[0], r)] - fMax);
    5132:         orntNew[2] = 0;
    5133:         coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (eEnd - eMax) + (fEnd                                   - fMax) + (c - cMax);
    5134:         orntNew[3] = 0;
    5135: #else
    5136:         coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*4 + r;
    5137:         orntNew[0] = 0;
    5138:         coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*4 + r;
    5139:         orntNew[1] = 0;
    5140:         coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (eEnd - eMax) + (cone[2+r] - fMax);
    5141:         orntNew[2] = 0;
    5142:         coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (eEnd - eMax) + (fEnd      - fMax) + (c - cMax);
    5143:         orntNew[3] = 0;
    5144: #endif
    5145:         DMPlexSetCone(rdm, newp+r, coneNew);
    5146:         DMPlexSetConeOrientation(rdm, newp+r, orntNew);
    5147: #if 1
    5148:         if ((newp+r < fMaxNew) || (newp+r >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid face [%d, %d)", newp+r, fMaxNew, fEndNew);
    5149:         for (p = 0; p < 2; ++p) {
    5150:           if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eMaxNew);
    5151:         }
    5152:         for (p = 2; p < 4; ++p) {
    5153:           if ((coneNew[p] < eMaxNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid edge [%d, %d)", coneNew[p], eMaxNew, eEndNew);
    5154:         }
    5155: #endif
    5156:         supportNew[0] = cStartNew + (cMax - cStart)*8 + (c - cMax)*4 + GetQuadSubface_Static(ornt[0], r);
    5157:         supportNew[1] = cStartNew + (cMax - cStart)*8 + (c - cMax)*4 + GetQuadSubface_Static(ornt[0], (r+1)%4);
    5158:         DMPlexSetSupport(rdm, newp+r, supportNew);
    5159: #if 1
    5160:         if ((newp+r < fMaxNew) || (newp+r >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid face [%d, %d)", newp+r, fMaxNew, fEndNew);
    5161:         for (p = 0; p < 2; ++p) {
    5162:           if ((supportNew[p] < cMaxNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid cell [%d, %d)", supportNew[p], cMaxNew, cEndNew);
    5163:         }
    5164: #endif
    5165:       }
    5166:     }
    5167:     /* Interior split edges have 2 vertices and the same faces as the parent */
    5168:     DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);
    5169:     for (e = eStart; e < eMax; ++e) {
    5170:       const PetscInt newv = vStartNew + (vEnd - vStart) + (e - eStart);

    5172:       for (r = 0; r < 2; ++r) {
    5173:         const PetscInt  newp = eStartNew + (e - eStart)*2 + r;
    5174:         const PetscInt *cone, *ornt, *support;
    5175:         PetscInt        coneNew[2], coneSize, c, supportSize, s;

    5177:         DMPlexGetCone(dm, e, &cone);
    5178:         coneNew[0]       = vStartNew + (cone[0] - vStart);
    5179:         coneNew[1]       = vStartNew + (cone[1] - vStart);
    5180:         coneNew[(r+1)%2] = newv;
    5181:         DMPlexSetCone(rdm, newp, coneNew);
    5182: #if 1
    5183:         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
    5184:         for (p = 0; p < 2; ++p) {
    5185:           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
    5186:         }
    5187: #endif
    5188:         DMPlexGetSupportSize(dm, e, &supportSize);
    5189:         DMPlexGetSupport(dm, e, &support);
    5190:         for (s = 0; s < supportSize; ++s) {
    5191:           DMPlexGetConeSize(dm, support[s], &coneSize);
    5192:           DMPlexGetCone(dm, support[s], &cone);
    5193:           DMPlexGetConeOrientation(dm, support[s], &ornt);
    5194:           for (c = 0; c < coneSize; ++c) {
    5195:             if (cone[c] == e) break;
    5196:           }
    5197:           if (support[s] < fMax) {
    5198:             supportRef[s] = fStartNew + (support[s] - fStart)*4 + (c + (ornt[c] < 0 ? 1-r : r))%4;
    5199:           } else {
    5200:             supportRef[s] = fStartNew + (fMax       - fStart)*4 + (cMax - cStart)*12 + (support[s] - fMax)*2 + (ornt[c] < 0 ? 1-r : r);
    5201:           }
    5202:         }
    5203:         DMPlexSetSupport(rdm, newp, supportRef);
    5204: #if 1
    5205:         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
    5206:         for (p = 0; p < supportSize; ++p) {
    5207:           if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", supportRef[p], fStartNew, fEndNew);
    5208:         }
    5209: #endif
    5210:       }
    5211:     }
    5212:     /* Interior face edges have 2 vertices and 2+cells faces */
    5213:     for (f = fStart; f < fMax; ++f) {
    5214:       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};
    5215:       const PetscInt  newv = vStartNew + (vEnd - vStart) + (eMax - eStart) + (f - fStart);
    5216:       const PetscInt *cone, *coneCell, *orntCell, *support;
    5217:       PetscInt        coneNew[2], coneSize, c, supportSize, s;

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

    5223:         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r] - eStart);
    5224:         coneNew[1] = newv;
    5225:         DMPlexSetCone(rdm, newp, coneNew);
    5226: #if 1
    5227:         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
    5228:         for (p = 0; p < 2; ++p) {
    5229:           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
    5230:         }
    5231: #endif
    5232:         DMPlexGetSupportSize(dm, f, &supportSize);
    5233:         DMPlexGetSupport(dm, f, &support);
    5234:         supportRef[0] = fStartNew + (f - fStart)*4 + r;
    5235:         supportRef[1] = fStartNew + (f - fStart)*4 + (r+1)%4;
    5236:         for (s = 0; s < supportSize; ++s) {
    5237:           DMPlexGetConeSize(dm, support[s], &coneSize);
    5238:           DMPlexGetCone(dm, support[s], &coneCell);
    5239:           DMPlexGetConeOrientation(dm, support[s], &orntCell);
    5240:           for (c = 0; c < coneSize; ++c) if (coneCell[c] == f) break;
    5241:           if (support[s] < cMax) {
    5242:             supportRef[2+s] = fStartNew + (fMax - fStart)*4 + (support[s] - cStart)*12 + newFaces[c*4 + GetQuadEdgeInverse_Static(orntCell[c], r)];
    5243:           } else {
    5244:             supportRef[2+s] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd - fMax)*2 + (support[s] - cMax)*4 + r;
    5245:           }
    5246:         }
    5247:         DMPlexSetSupport(rdm, newp, supportRef);
    5248: #if 1
    5249:         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
    5250:         for (p = 0; p < 2+supportSize; ++p) {
    5251:           if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", supportRef[p], fStartNew, fEndNew);
    5252:         }
    5253: #endif
    5254:       }
    5255:     }
    5256:     /* Interior cell edges have 2 vertices and 4 faces */
    5257:     for (c = cStart; c < cMax; ++c) {
    5258:       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};
    5259:       const PetscInt  newv = vStartNew + (vEnd - vStart) + (eMax - eStart) + (fMax - fStart) + (c - cStart);
    5260:       const PetscInt *cone;
    5261:       PetscInt        coneNew[2], supportNew[4];

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

    5267:         coneNew[0] = vStartNew + (vEnd - vStart) + (eMax - eStart) + (cone[r] - fStart);
    5268:         coneNew[1] = newv;
    5269:         DMPlexSetCone(rdm, newp, coneNew);
    5270: #if 1
    5271:         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
    5272:         for (p = 0; p < 2; ++p) {
    5273:           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
    5274:         }
    5275: #endif
    5276:         for (f = 0; f < 4; ++f) supportNew[f] = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + newFaces[r*4+f];
    5277:         DMPlexSetSupport(rdm, newp, supportNew);
    5278: #if 1
    5279:         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
    5280:         for (p = 0; p < 4; ++p) {
    5281:           if ((supportNew[p] < fStartNew) || (supportNew[p] >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", supportNew[p], fStartNew, fMaxNew);
    5282:         }
    5283: #endif
    5284:       }
    5285:     }
    5286:     /* Hybrid edges have two vertices and the same faces */
    5287:     for (e = eMax; e < eEnd; ++e) {
    5288:       const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (e - eMax);
    5289:       const PetscInt *cone, *support, *fcone;
    5290:       PetscInt        coneNew[2], size, fsize, s;

    5292:       DMPlexGetCone(dm, e, &cone);
    5293:       DMPlexGetSupportSize(dm, e, &size);
    5294:       DMPlexGetSupport(dm, e, &support);
    5295:       coneNew[0] = vStartNew + (cone[0] - vStart);
    5296:       coneNew[1] = vStartNew + (cone[1] - vStart);
    5297:       DMPlexSetCone(rdm, newp, coneNew);
    5298: #if 1
    5299:       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid edge [%d, %d)", newp, eMaxNew, eEndNew);
    5300:       for (p = 0; p < 2; ++p) {
    5301:         if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
    5302:       }
    5303: #endif
    5304:       for (s = 0; s < size; ++s) {
    5305:         DMPlexGetConeSize(dm, support[s], &fsize);
    5306:         DMPlexGetCone(dm, support[s], &fcone);
    5307:         for (c = 0; c < fsize; ++c) if (fcone[c] == e) break;
    5308:         if ((c < 2) || (c > 3)) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Edge %d not found in cone of face %d", e, support[s]);
    5309:         supportRef[s] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (support[s] - fMax)*2 + c-2;
    5310:       }
    5311:       DMPlexSetSupport(rdm, newp, supportRef);
    5312: #if 1
    5313:       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid edge [%d, %d)", newp, eMaxNew, eEndNew);
    5314:       for (p = 0; p < size; ++p) {
    5315:         if ((supportRef[p] < fMaxNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid face [%d, %d)", supportRef[p], fMaxNew, fEndNew);
    5316:       }
    5317: #endif
    5318:     }
    5319:     /* Hybrid face edges have 2 vertices and 2+cells faces */
    5320:     for (f = fMax; f < fEnd; ++f) {
    5321:       const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (eEnd - eMax) + (f - fMax);
    5322:       const PetscInt *cone, *support, *ccone, *cornt;
    5323:       PetscInt        coneNew[2], size, csize, s;

    5325:       DMPlexGetCone(dm, f, &cone);
    5326:       DMPlexGetSupportSize(dm, f, &size);
    5327:       DMPlexGetSupport(dm, f, &support);
    5328:       coneNew[0] = vStartNew + (vEnd - vStart) + (cone[0] - eStart);
    5329:       coneNew[1] = vStartNew + (vEnd - vStart) + (cone[1] - eStart);
    5330:       DMPlexSetCone(rdm, newp, coneNew);
    5331: #if 1
    5332:       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid edge [%d, %d)", newp, eMaxNew, eEndNew);
    5333:       for (p = 0; p < 2; ++p) {
    5334:         if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
    5335:       }
    5336: #endif
    5337:       supportRef[0] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (f - fMax)*2 + 0;
    5338:       supportRef[1] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (f - fMax)*2 + 1;
    5339:       for (s = 0; s < size; ++s) {
    5340:         DMPlexGetConeSize(dm, support[s], &csize);
    5341:         DMPlexGetCone(dm, support[s], &ccone);
    5342:         DMPlexGetConeOrientation(dm, support[s], &cornt);
    5343:         for (c = 0; c < csize; ++c) if (ccone[c] == f) break;
    5344:         if ((c < 2) || (c >= csize)) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Hybrid face %d is not in cone of hybrid cell %d", f, support[s]);
    5345:         supportRef[2+s] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd - fMax)*2 + (support[s] - cMax)*4 + c-2;
    5346:       }
    5347:       DMPlexSetSupport(rdm, newp, supportRef);
    5348: #if 1
    5349:       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid edge [%d, %d)", newp, eMaxNew, eEndNew);
    5350:       for (p = 0; p < 2+size; ++p) {
    5351:         if ((supportRef[p] < fMaxNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid face [%d, %d)", supportRef[p], fMaxNew, fEndNew);
    5352:       }
    5353: #endif
    5354:     }
    5355:     /* Hybrid cell edges have 2 vertices and 4 faces */
    5356:     for (c = cMax; c < cEnd; ++c) {
    5357:       const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (eEnd - eMax) + (fEnd - fMax) + (c - cMax);
    5358:       const PetscInt *cone, *support;
    5359:       PetscInt        coneNew[2], size;

    5361:       DMPlexGetCone(dm, c, &cone);
    5362:       DMPlexGetSupportSize(dm, c, &size);
    5363:       DMPlexGetSupport(dm, c, &support);
    5364:       coneNew[0] = vStartNew + (vEnd - vStart) + (eMax - eStart) + (cone[0] - fStart);
    5365:       coneNew[1] = vStartNew + (vEnd - vStart) + (eMax - eStart) + (cone[1] - fStart);
    5366:       DMPlexSetCone(rdm, newp, coneNew);
    5367: #if 1
    5368:       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid edge [%d, %d)", newp, eMaxNew, eEndNew);
    5369:       for (p = 0; p < 2; ++p) {
    5370:         if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
    5371:       }
    5372: #endif
    5373:       supportRef[0] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd - fMax)*2 + (c - cMax)*4 + 0;
    5374:       supportRef[1] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd - fMax)*2 + (c - cMax)*4 + 1;
    5375:       supportRef[2] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd - fMax)*2 + (c - cMax)*4 + 2;
    5376:       supportRef[3] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd - fMax)*2 + (c - cMax)*4 + 3;
    5377:       DMPlexSetSupport(rdm, newp, supportRef);
    5378: #if 1
    5379:       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid edge [%d, %d)", newp, eMaxNew, eEndNew);
    5380:       for (p = 0; p < 4; ++p) {
    5381:         if ((supportRef[p] < fMaxNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid face [%d, %d)", supportRef[p], fMaxNew, fEndNew);
    5382:       }
    5383: #endif
    5384:     }
    5385:     /* Interior vertices have identical supports */
    5386:     for (v = vStart; v < vEnd; ++v) {
    5387:       const PetscInt  newp = vStartNew + (v - vStart);
    5388:       const PetscInt *support, *cone;
    5389:       PetscInt        size, s;

    5391:       DMPlexGetSupportSize(dm, v, &size);
    5392:       DMPlexGetSupport(dm, v, &support);
    5393:       for (s = 0; s < size; ++s) {
    5394:         PetscInt r = 0;

    5396:         DMPlexGetCone(dm, support[s], &cone);
    5397:         if (cone[1] == v) r = 1;
    5398:         if (support[s] < eMax) supportRef[s] = eStartNew + (support[s] - eStart)*2 + r;
    5399:         else                   supportRef[s] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (support[s] - eMax);
    5400:       }
    5401:       DMPlexSetSupport(rdm, newp, supportRef);
    5402: #if 1
    5403:       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
    5404:       for (p = 0; p < size; ++p) {
    5405:         if ((supportRef[p] < eStartNew) || (supportRef[p] >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", supportRef[p], eStartNew, eEndNew);
    5406:       }
    5407: #endif
    5408:     }
    5409:     /* Interior edge vertices have 2 + faces supports */
    5410:     for (e = eStart; e < eMax; ++e) {
    5411:       const PetscInt  newp = vStartNew + (vEnd - vStart) + (e - eStart);
    5412:       const PetscInt *cone, *support;
    5413:       PetscInt        size, s;

    5415:       DMPlexGetSupportSize(dm, e, &size);
    5416:       DMPlexGetSupport(dm, e, &support);
    5417:       supportRef[0] = eStartNew + (e - eStart)*2 + 0;
    5418:       supportRef[1] = eStartNew + (e - eStart)*2 + 1;
    5419:       for (s = 0; s < size; ++s) {
    5420:         PetscInt r;

    5422:         DMPlexGetCone(dm, support[s], &cone);
    5423:         for (r = 0; r < 4; ++r) if (cone[r] == e) break;
    5424:         if (support[s] < fMax) {
    5425:           supportRef[2+s] = eStartNew + (eMax - eStart)*2 + (support[s] - fStart)*4 + r;
    5426:         } else {
    5427:           supportRef[2+s] = eStartNew + (eMax - eStart)*2 + (fMax       - fStart)*4 + (cMax - cStart)*6 + (eEnd - eMax) + (support[s] - fMax);
    5428:         }
    5429:       }
    5430:       DMPlexSetSupport(rdm, newp, supportRef);
    5431: #if 1
    5432:       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
    5433:       for (p = 0; p < 2+size; ++p) {
    5434:         if ((supportRef[p] < eStartNew) || (supportRef[p] >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", supportRef[p], eStartNew, eEndNew);
    5435:       }
    5436: #endif
    5437:     }
    5438:     /* Interior face vertices have 4 + cells supports */
    5439:     for (f = fStart; f < fMax; ++f) {
    5440:       const PetscInt  newp = vStartNew + (vEnd - vStart) + (eMax - eStart) + (f - fStart);
    5441:       const PetscInt *cone, *support;
    5442:       PetscInt        size, s;

    5444:       DMPlexGetSupportSize(dm, f, &size);
    5445:       DMPlexGetSupport(dm, f, &support);
    5446:       for (r = 0; r < 4; ++r) supportRef[r] = eStartNew + (eMax - eStart)*2 +  (f - fStart)*4 + r;
    5447:       for (s = 0; s < size; ++s) {
    5448:         PetscInt r;

    5450:         DMPlexGetCone(dm, support[s], &cone);
    5451:         for (r = 0; r < 6; ++r) if (cone[r] == f) break;
    5452:         if (support[s] < cMax) {
    5453:           supportRef[4+s] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (support[s] - cStart)*6 + r;
    5454:         } else {
    5455:           supportRef[4+s] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax       - cStart)*6 + (eEnd - eMax) + (fEnd - fMax) + (support[s] - cMax);
    5456:         }
    5457:       }
    5458:       DMPlexSetSupport(rdm, newp, supportRef);
    5459: #if 1
    5460:       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
    5461:       for (p = 0; p < 4+size; ++p) {
    5462:         if ((supportRef[p] < eStartNew) || (supportRef[p] >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", supportRef[p], eStartNew, eEndNew);
    5463:       }
    5464: #endif
    5465:     }
    5466:     /* Cell vertices have 6 supports */
    5467:     for (c = cStart; c < cMax; ++c) {
    5468:       const PetscInt newp = vStartNew + (vEnd - vStart) + (eMax - eStart) + (fMax - fStart) + (c - cStart);
    5469:       PetscInt       supportNew[6];

    5471:       for (r = 0; r < 6; ++r) {
    5472:         supportNew[r] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (c - cStart)*6 + r;
    5473:       }
    5474:       DMPlexSetSupport(rdm, newp, supportNew);
    5475:     }
    5476:     PetscFree(supportRef);
    5477:     break;
    5478:   default:
    5479:     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
    5480:   }
    5481:   return(0);
    5482: }

    5486: static PetscErrorCode CellRefinerSetCoordinates(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
    5487: {
    5488:   PetscSection   coordSection, coordSectionNew;
    5489:   Vec            coordinates, coordinatesNew;
    5490:   PetscScalar   *coords, *coordsNew;
    5491:   const PetscInt numVertices = depthSize ? depthSize[0] : 0;
    5492:   PetscInt       dim, spaceDim, depth, bs, coordSizeNew, cStart, cEnd, cMax, c, vStart, vStartNew, vEnd, v, eStart, eEnd, eMax, e, fStart, fEnd, fMax, f;

    5496:   DMGetDimension(dm, &dim);
    5497:   DMPlexGetDepth(dm, &depth);
    5498:   DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);
    5499:   DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);
    5500:   DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);
    5501:   DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);
    5502:   DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, NULL);
    5503:   if (refiner) {GetDepthStart_Private(depth, depthSize, NULL, NULL, NULL, &vStartNew);}
    5504:   GetDepthStart_Private(depth, depthSize, NULL, NULL, NULL, &vStartNew);
    5505:   DMGetCoordinateSection(dm, &coordSection);
    5506:   PetscSectionGetFieldComponents(coordSection, 0, &spaceDim);
    5507:   PetscSectionCreate(PetscObjectComm((PetscObject)dm), &coordSectionNew);
    5508:   PetscSectionSetNumFields(coordSectionNew, 1);
    5509:   PetscSectionSetFieldComponents(coordSectionNew, 0, spaceDim);
    5510:   PetscSectionSetChart(coordSectionNew, vStartNew, vStartNew+numVertices);
    5511:   if (cMax < 0) cMax = cEnd;
    5512:   if (fMax < 0) fMax = fEnd;
    5513:   if (eMax < 0) eMax = eEnd;
    5514:   /* All vertices have the spaceDim coordinates */
    5515:   for (v = vStartNew; v < vStartNew+numVertices; ++v) {
    5516:     PetscSectionSetDof(coordSectionNew, v, spaceDim);
    5517:     PetscSectionSetFieldDof(coordSectionNew, v, 0, spaceDim);
    5518:   }
    5519:   PetscSectionSetUp(coordSectionNew);
    5520:   DMSetCoordinateSection(rdm, PETSC_DETERMINE, coordSectionNew);
    5521:   DMGetCoordinatesLocal(dm, &coordinates);
    5522:   PetscSectionGetStorageSize(coordSectionNew, &coordSizeNew);
    5523:   VecCreate(PetscObjectComm((PetscObject)dm), &coordinatesNew);
    5524:   PetscObjectSetName((PetscObject) coordinatesNew, "coordinates");
    5525:   VecSetSizes(coordinatesNew, coordSizeNew, PETSC_DETERMINE);
    5526:   VecGetBlockSize(coordinates, &bs);
    5527:   VecSetBlockSize(coordinatesNew, bs);
    5528:   VecSetFromOptions(coordinatesNew);
    5529:   VecGetArray(coordinates, &coords);
    5530:   VecGetArray(coordinatesNew, &coordsNew);
    5531:   switch (refiner) {
    5532:   case REFINER_NOOP: break;
    5533:   case REFINER_HEX_3D:
    5534:   case REFINER_HYBRID_HEX_3D:
    5535:     /* Face vertices have the average of corner coordinates */
    5536:     for (f = fStart; f < fMax; ++f) {
    5537:       const PetscInt newv = vStartNew + (vEnd - vStart) + (eMax - eStart) + (f - fStart);
    5538:       PetscInt      *cone = NULL;
    5539:       PetscInt       closureSize, coneSize = 0, off[8], offnew, p, d;

    5541:       DMPlexGetTransitiveClosure(dm, f, PETSC_TRUE, &closureSize, &cone);
    5542:       for (p = 0; p < closureSize*2; p += 2) {
    5543:         const PetscInt point = cone[p];
    5544:         if ((point >= vStart) && (point < vEnd)) cone[coneSize++] = point;
    5545:       }
    5546:       for (v = 0; v < coneSize; ++v) {
    5547:         PetscSectionGetOffset(coordSection, cone[v], &off[v]);
    5548:       }
    5549:       PetscSectionGetOffset(coordSectionNew, newv, &offnew);
    5550:       for (d = 0; d < spaceDim; ++d) coordsNew[offnew+d] = 0.0;
    5551:       for (v = 0; v < coneSize; ++v) {DMPlexLocalizeAddCoordinate_Internal(dm, spaceDim, &coords[off[0]], &coords[off[v]], &coordsNew[offnew]);}
    5552:       for (d = 0; d < spaceDim; ++d) coordsNew[offnew+d] /= coneSize;
    5553:       DMPlexRestoreTransitiveClosure(dm, f, PETSC_TRUE, &closureSize, &cone);
    5554:     }
    5555:   case REFINER_HEX_2D:
    5556:   case REFINER_HYBRID_HEX_2D:
    5557:   case REFINER_SIMPLEX_1D:
    5558:     /* Cell vertices have the average of corner coordinates */
    5559:     for (c = cStart; c < cMax; ++c) {
    5560:       const PetscInt newv = vStartNew + (vEnd - vStart) + (dim > 1 ? (eMax - eStart) : 0) + (c - cStart) + (dim > 2 ? (fMax - fStart) : 0);
    5561:       PetscInt      *cone = NULL;
    5562:       PetscInt       closureSize, coneSize = 0, off[8], offnew, p, d;

    5564:       DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &cone);
    5565:       for (p = 0; p < closureSize*2; p += 2) {
    5566:         const PetscInt point = cone[p];
    5567:         if ((point >= vStart) && (point < vEnd)) cone[coneSize++] = point;
    5568:       }
    5569:       for (v = 0; v < coneSize; ++v) {
    5570:         PetscSectionGetOffset(coordSection, cone[v], &off[v]);
    5571:       }
    5572:       PetscSectionGetOffset(coordSectionNew, newv, &offnew);
    5573:       for (d = 0; d < spaceDim; ++d) coordsNew[offnew+d] = 0.0;
    5574:       for (v = 0; v < coneSize; ++v) {DMPlexLocalizeAddCoordinate_Internal(dm, spaceDim, &coords[off[0]], &coords[off[v]], &coordsNew[offnew]);}
    5575:       for (d = 0; d < spaceDim; ++d) coordsNew[offnew+d] /= coneSize;
    5576:       DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &cone);
    5577:     }
    5578:   case REFINER_SIMPLEX_2D:
    5579:   case REFINER_HYBRID_SIMPLEX_2D:
    5580:   case REFINER_SIMPLEX_3D:
    5581:   case REFINER_HYBRID_SIMPLEX_3D:
    5582:     /* Edge vertices have the average of endpoint coordinates */
    5583:     for (e = eStart; e < eMax; ++e) {
    5584:       const PetscInt  newv = vStartNew + (vEnd - vStart) + (e - eStart);
    5585:       const PetscInt *cone;
    5586:       PetscInt        coneSize, offA, offB, offnew, d;

    5588:       DMPlexGetConeSize(dm, e, &coneSize);
    5589:       if (coneSize != 2) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Edge %d cone should have two vertices, not %d", e, coneSize);
    5590:       DMPlexGetCone(dm, e, &cone);
    5591:       PetscSectionGetOffset(coordSection, cone[0], &offA);
    5592:       PetscSectionGetOffset(coordSection, cone[1], &offB);
    5593:       PetscSectionGetOffset(coordSectionNew, newv, &offnew);
    5594:       DMPlexLocalizeCoordinate_Internal(dm, spaceDim, &coords[offA], &coords[offB], &coordsNew[offnew]);
    5595:       for (d = 0; d < spaceDim; ++d) {
    5596:         coordsNew[offnew+d] = 0.5*(coords[offA+d] + coordsNew[offnew+d]);
    5597:       }
    5598:     }
    5599:     /* Old vertices have the same coordinates */
    5600:     for (v = vStart; v < vEnd; ++v) {
    5601:       const PetscInt newv = vStartNew + (v - vStart);
    5602:       PetscInt       off, offnew, d;

    5604:       PetscSectionGetOffset(coordSection, v, &off);
    5605:       PetscSectionGetOffset(coordSectionNew, newv, &offnew);
    5606:       for (d = 0; d < spaceDim; ++d) {
    5607:         coordsNew[offnew+d] = coords[off+d];
    5608:       }
    5609:     }
    5610:     break;
    5611:   default:
    5612:     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
    5613:   }
    5614:   VecRestoreArray(coordinates, &coords);
    5615:   VecRestoreArray(coordinatesNew, &coordsNew);
    5616:   DMSetCoordinatesLocal(rdm, coordinatesNew);
    5617:   VecDestroy(&coordinatesNew);
    5618:   PetscSectionDestroy(&coordSectionNew);
    5619:   if (dm->maxCell) {
    5620:     const PetscReal *maxCell, *L;
    5621:     const DMBoundaryType *bd;
    5622:     DMGetPeriodicity(dm,  &maxCell, &L, &bd);
    5623:     DMSetPeriodicity(rdm,  maxCell,  L,  bd);
    5624:   }
    5625:   return(0);
    5626: }

    5630: /*@
    5631:   DMPlexCreateProcessSF - Create an SF which just has process connectivity

    5633:   Collective on DM

    5635:   Input Parameters:
    5636: + dm      - The DM
    5637: - sfPoint - The PetscSF which encodes point connectivity

    5639:   Output Parameters:
    5640: + processRanks - A list of process neighbors, or NULL
    5641: - sfProcess    - An SF encoding the process connectivity, or NULL

    5643:   Level: developer

    5645: .seealso: PetscSFCreate(), DMPlexCreateTwoSidedProcessSF()
    5646: @*/
    5647: PetscErrorCode DMPlexCreateProcessSF(DM dm, PetscSF sfPoint, IS *processRanks, PetscSF *sfProcess)
    5648: {
    5649:   PetscInt           numRoots, numLeaves, l;
    5650:   const PetscInt    *localPoints;
    5651:   const PetscSFNode *remotePoints;
    5652:   PetscInt          *localPointsNew;
    5653:   PetscSFNode       *remotePointsNew;
    5654:   PetscInt          *ranks, *ranksNew;
    5655:   PetscMPIInt        numProcs;
    5656:   PetscErrorCode     ierr;

    5663:   MPI_Comm_size(PetscObjectComm((PetscObject) dm), &numProcs);
    5664:   PetscSFGetGraph(sfPoint, &numRoots, &numLeaves, &localPoints, &remotePoints);
    5665:   PetscMalloc1(numLeaves, &ranks);
    5666:   for (l = 0; l < numLeaves; ++l) {
    5667:     ranks[l] = remotePoints[l].rank;
    5668:   }
    5669:   PetscSortRemoveDupsInt(&numLeaves, ranks);
    5670:   PetscMalloc1(numLeaves, &ranksNew);
    5671:   PetscMalloc1(numLeaves, &localPointsNew);
    5672:   PetscMalloc1(numLeaves, &remotePointsNew);
    5673:   for (l = 0; l < numLeaves; ++l) {
    5674:     ranksNew[l]              = ranks[l];
    5675:     localPointsNew[l]        = l;
    5676:     remotePointsNew[l].index = 0;
    5677:     remotePointsNew[l].rank  = ranksNew[l];
    5678:   }
    5679:   PetscFree(ranks);
    5680:   if (processRanks) {ISCreateGeneral(PetscObjectComm((PetscObject)dm), numLeaves, ranksNew, PETSC_OWN_POINTER, processRanks);}
    5681:   else              {PetscFree(ranksNew);}
    5682:   if (sfProcess) {
    5683:     PetscSFCreate(PetscObjectComm((PetscObject)dm), sfProcess);
    5684:     PetscObjectSetName((PetscObject) *sfProcess, "Process SF");
    5685:     PetscSFSetFromOptions(*sfProcess);
    5686:     PetscSFSetGraph(*sfProcess, numProcs, numLeaves, localPointsNew, PETSC_OWN_POINTER, remotePointsNew, PETSC_OWN_POINTER);
    5687:   }
    5688:   return(0);
    5689: }

    5693: static PetscErrorCode CellRefinerCreateSF(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
    5694: {
    5695:   PetscSF            sf, sfNew, sfProcess;
    5696:   IS                 processRanks;
    5697:   MPI_Datatype       depthType;
    5698:   PetscInt           numRoots, numLeaves, numLeavesNew = 0, l, m;
    5699:   const PetscInt    *localPoints, *neighbors;
    5700:   const PetscSFNode *remotePoints;
    5701:   PetscInt          *localPointsNew;
    5702:   PetscSFNode       *remotePointsNew;
    5703:   PetscInt          *depthSizeOld, *rdepthSize, *rdepthSizeOld, *rdepthMaxOld, *rvStart, *rvStartNew, *reStart, *reStartNew, *rfStart, *rfStartNew, *rcStart, *rcStartNew;
    5704:   PetscInt           depth, numNeighbors, pStartNew, pEndNew, cStart, cEnd, cMax, vStart, vEnd, vMax, fStart, fEnd, fMax, eStart, eEnd, eMax, r, n;
    5705:   PetscInt           cStartNew = 0, vStartNew = 0, fStartNew = 0, eStartNew = 0;
    5706:   PetscErrorCode     ierr;

    5709:   DMPlexGetChart(rdm, &pStartNew, &pEndNew);
    5710:   DMPlexGetDepth(dm, &depth);
    5711:   DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);
    5712:   DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);
    5713:   DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);
    5714:   DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);
    5715:   DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);
    5716:   cMax = cMax < 0 ? cEnd : cMax;
    5717:   fMax = fMax < 0 ? fEnd : fMax;
    5718:   eMax = eMax < 0 ? eEnd : eMax;
    5719:   if (refiner) {GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);}
    5720:   DMGetPointSF(dm, &sf);
    5721:   DMGetPointSF(rdm, &sfNew);
    5722:   /* Calculate size of new SF */
    5723:   PetscSFGetGraph(sf, &numRoots, &numLeaves, &localPoints, &remotePoints);
    5724:   if (numRoots < 0) return(0);
    5725:   for (l = 0; l < numLeaves; ++l) {
    5726:     const PetscInt p = localPoints[l];

    5728:     switch (refiner) {
    5729:     case REFINER_SIMPLEX_1D:
    5730:       if ((p >= vStart) && (p < vEnd)) {
    5731:         /* Interior vertices stay the same */
    5732:         ++numLeavesNew;
    5733:       } else if ((p >= cStart && p < cMax)) {
    5734:         /* Interior cells add new cells and interior vertices */
    5735:         numLeavesNew += 2 + 1;
    5736:       }
    5737:       break;
    5738:     case REFINER_SIMPLEX_2D:
    5739:     case REFINER_HYBRID_SIMPLEX_2D:
    5740:       if ((p >= vStart) && (p < vEnd)) {
    5741:         /* Interior vertices stay the same */
    5742:         ++numLeavesNew;
    5743:       } else if ((p >= fStart) && (p < fMax)) {
    5744:         /* Interior faces add new faces and vertex */
    5745:         numLeavesNew += 2 + 1;
    5746:       } else if ((p >= fMax) && (p < fEnd)) {
    5747:         /* Hybrid faces stay the same */
    5748:         ++numLeavesNew;
    5749:       } else if ((p >= cStart) && (p < cMax)) {
    5750:         /* Interior cells add new cells and interior faces */
    5751:         numLeavesNew += 4 + 3;
    5752:       } else if ((p >= cMax) && (p < cEnd)) {
    5753:         /* Hybrid cells add new cells and hybrid face */
    5754:         numLeavesNew += 2 + 1;
    5755:       }
    5756:       break;
    5757:     case REFINER_HEX_2D:
    5758:     case REFINER_HYBRID_HEX_2D:
    5759:       if ((p >= vStart) && (p < vEnd)) {
    5760:         /* Interior vertices stay the same */
    5761:         ++numLeavesNew;
    5762:       } else if ((p >= fStart) && (p < fMax)) {
    5763:         /* Interior faces add new faces and vertex */
    5764:         numLeavesNew += 2 + 1;
    5765:       } else if ((p >= fMax) && (p < fEnd)) {
    5766:         /* Hybrid faces stay the same */
    5767:         ++numLeavesNew;
    5768:       } else if ((p >= cStart) && (p < cMax)) {
    5769:         /* Interior cells add new cells, interior faces, and vertex */
    5770:         numLeavesNew += 4 + 4 + 1;
    5771:       } else if ((p >= cMax) && (p < cEnd)) {
    5772:         /* Hybrid cells add new cells and hybrid face */
    5773:         numLeavesNew += 2 + 1;
    5774:       }
    5775:       break;
    5776:     case REFINER_SIMPLEX_3D:
    5777:     case REFINER_HYBRID_SIMPLEX_3D:
    5778:       if ((p >= vStart) && (p < vEnd)) {
    5779:         /* Interior vertices stay the same */
    5780:         ++numLeavesNew;
    5781:       } else if ((p >= eStart) && (p < eMax)) {
    5782:         /* Interior edges add new edges and vertex */
    5783:         numLeavesNew += 2 + 1;
    5784:       } else if ((p >= eMax) && (p < eEnd)) {
    5785:         /* Hybrid edges stay the same */
    5786:         ++numLeavesNew;
    5787:       } else if ((p >= fStart) && (p < fMax)) {
    5788:         /* Interior faces add new faces and edges */
    5789:         numLeavesNew += 4 + 3;
    5790:       } else if ((p >= fMax) && (p < fEnd)) {
    5791:         /* Hybrid faces add new faces and edges */
    5792:         numLeavesNew += 2 + 1;
    5793:       } else if ((p >= cStart) && (p < cMax)) {
    5794:         /* Interior cells add new cells, faces, and edges */
    5795:         numLeavesNew += 8 + 8 + 1;
    5796:       } else if ((p >= cMax) && (p < cEnd)) {
    5797:         /* Hybrid cells add new cells and faces */
    5798:         numLeavesNew += 4 + 3;
    5799:       }
    5800:       break;
    5801:     case REFINER_HEX_3D:
    5802:     case REFINER_HYBRID_HEX_3D:
    5803:       if ((p >= vStart) && (p < vEnd)) {
    5804:         /* Old vertices stay the same */
    5805:         ++numLeavesNew;
    5806:       } else if ((p >= eStart) && (p < eMax)) {
    5807:         /* Interior edges add new edges, and vertex */
    5808:         numLeavesNew += 2 + 1;
    5809:       } else if ((p >= eMax) && (p < eEnd)) {
    5810:         /* Hybrid edges stay the same */
    5811:         ++numLeavesNew;
    5812:       } else if ((p >= fStart) && (p < fMax)) {
    5813:         /* Interior faces add new faces, edges, and vertex */
    5814:         numLeavesNew += 4 + 4 + 1;
    5815:       } else if ((p >= fMax) && (p < fEnd)) {
    5816:         /* Hybrid faces add new faces and edges */
    5817:         numLeavesNew += 2 + 1;
    5818:       } else if ((p >= cStart) && (p < cMax)) {
    5819:         /* Interior cells add new cells, faces, edges, and vertex */
    5820:         numLeavesNew += 8 + 12 + 6 + 1;
    5821:       } else if ((p >= cStart) && (p < cEnd)) {
    5822:         /* Hybrid cells add new cells, faces, and edges */
    5823:         numLeavesNew += 4 + 4 + 1;
    5824:       }
    5825:       break;
    5826:     default:
    5827:       SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
    5828:     }
    5829:   }
    5830:   /* Communicate depthSizes for each remote rank */
    5831:   DMPlexCreateProcessSF(dm, sf, &processRanks, &sfProcess);
    5832:   ISGetLocalSize(processRanks, &numNeighbors);
    5833:   PetscMalloc5((depth+1)*numNeighbors,&rdepthSize,numNeighbors,&rvStartNew,numNeighbors,&reStartNew,numNeighbors,&rfStartNew,numNeighbors,&rcStartNew);
    5834:   PetscMalloc7(depth+1,&depthSizeOld,(depth+1)*numNeighbors,&rdepthSizeOld,(depth+1)*numNeighbors,&rdepthMaxOld,numNeighbors,&rvStart,numNeighbors,&reStart,numNeighbors,&rfStart,numNeighbors,&rcStart);
    5835:   MPI_Type_contiguous(depth+1, MPIU_INT, &depthType);
    5836:   MPI_Type_commit(&depthType);
    5837:   PetscSFBcastBegin(sfProcess, depthType, depthSize, rdepthSize);
    5838:   PetscSFBcastEnd(sfProcess, depthType, depthSize, rdepthSize);
    5839:   for (n = 0; n < numNeighbors; ++n) {
    5840:     GetDepthStart_Private(depth, &rdepthSize[n*(depth+1)], &rcStartNew[n], &rfStartNew[n], &reStartNew[n], &rvStartNew[n]);
    5841:   }
    5842:   depthSizeOld[depth]   = cMax;
    5843:   depthSizeOld[0]       = vMax;
    5844:   depthSizeOld[depth-1] = fMax;
    5845:   depthSizeOld[1]       = eMax;

    5847:   PetscSFBcastBegin(sfProcess, depthType, depthSizeOld, rdepthMaxOld);
    5848:   PetscSFBcastEnd(sfProcess, depthType, depthSizeOld, rdepthMaxOld);

    5850:   depthSizeOld[depth]   = cEnd - cStart;
    5851:   depthSizeOld[0]       = vEnd - vStart;
    5852:   depthSizeOld[depth-1] = fEnd - fStart;
    5853:   depthSizeOld[1]       = eEnd - eStart;

    5855:   PetscSFBcastBegin(sfProcess, depthType, depthSizeOld, rdepthSizeOld);
    5856:   PetscSFBcastEnd(sfProcess, depthType, depthSizeOld, rdepthSizeOld);
    5857:   for (n = 0; n < numNeighbors; ++n) {
    5858:     GetDepthStart_Private(depth, &rdepthSizeOld[n*(depth+1)], &rcStart[n], &rfStart[n], &reStart[n], &rvStart[n]);
    5859:     rdepthMaxOld[n*(depth+1)+depth]   = rdepthMaxOld[n*(depth+1)+depth]   < 0 ? rdepthSizeOld[n*(depth+1)+depth]  +rcStart[n]: rdepthMaxOld[n*(depth+1)+depth];
    5860:     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];
    5861:     rdepthMaxOld[n*(depth+1)+1]       = rdepthMaxOld[n*(depth+1)+1]       < 0 ? rdepthSizeOld[n*(depth+1)+1]      +reStart[n]: rdepthMaxOld[n*(depth+1)+1];
    5862:   }
    5863:   MPI_Type_free(&depthType);
    5864:   PetscSFDestroy(&sfProcess);
    5865:   /* Calculate new point SF */
    5866:   PetscMalloc1(numLeavesNew, &localPointsNew);
    5867:   PetscMalloc1(numLeavesNew, &remotePointsNew);
    5868:   ISGetIndices(processRanks, &neighbors);
    5869:   for (l = 0, m = 0; l < numLeaves; ++l) {
    5870:     PetscInt    p     = localPoints[l];
    5871:     PetscInt    rp    = remotePoints[l].index, n;
    5872:     PetscMPIInt rrank = remotePoints[l].rank;

    5874:     PetscFindInt(rrank, numNeighbors, neighbors, &n);
    5875:     if (n < 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Could not locate remote rank %d", rrank);
    5876:     switch (refiner) {
    5877:     case REFINER_SIMPLEX_1D:
    5878:       if ((p >= vStart) && (p < vEnd)) {
    5879:         /* Old vertices stay the same */
    5880:         localPointsNew[m]        = vStartNew     + (p  - vStart);
    5881:         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
    5882:         remotePointsNew[m].rank  = rrank;
    5883:         ++m;
    5884:       } else if ((p >= cStart) && (p < cMax)) {
    5885:         /* Old interior cells add new cells and vertex */
    5886:         for (r = 0; r < 2; ++r, ++m) {
    5887:           localPointsNew[m]        = cStartNew     + (p  - cStart)*2     + r;
    5888:           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*2 + r;
    5889:           remotePointsNew[m].rank  = rrank;
    5890:         }
    5891:         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - cStart);
    5892:         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - rcStart[n]);
    5893:         remotePointsNew[m].rank  = rrank;
    5894:         ++m;
    5895:       }
    5896:       break;
    5897:     case REFINER_SIMPLEX_2D:
    5898:     case REFINER_HYBRID_SIMPLEX_2D:
    5899:       if ((p >= vStart) && (p < vEnd)) {
    5900:         /* Old vertices stay the same */
    5901:         localPointsNew[m]        = vStartNew     + (p  - vStart);
    5902:         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
    5903:         remotePointsNew[m].rank  = rrank;
    5904:         ++m;
    5905:       } else if ((p >= fStart) && (p < fMax)) {
    5906:         /* Old interior faces add new faces and vertex */
    5907:         for (r = 0; r < 2; ++r, ++m) {
    5908:           localPointsNew[m]        = fStartNew     + (p  - fStart)*2     + r;
    5909:           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*2 + r;
    5910:           remotePointsNew[m].rank  = rrank;
    5911:         }
    5912:         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - fStart);
    5913:         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - rfStart[n]);
    5914:         remotePointsNew[m].rank  = rrank;
    5915:         ++m;
    5916:       } else if ((p >= fMax) && (p < fEnd)) {
    5917:         /* Old hybrid faces stay the same */
    5918:         localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (p  - fMax);
    5919:         remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*2 + (rp - rdepthMaxOld[n*(depth+1)+depth-1]);
    5920:         remotePointsNew[m].rank  = rrank;
    5921:         ++m;
    5922:       } else if ((p >= cStart) && (p < cMax)) {
    5923:         /* Old interior cells add new cells and interior faces */
    5924:         for (r = 0; r < 4; ++r, ++m) {
    5925:           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
    5926:           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
    5927:           remotePointsNew[m].rank  = rrank;
    5928:         }
    5929:         for (r = 0; r < 3; ++r, ++m) {
    5930:           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (p  - cStart)*3     + r;
    5931:           remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*2 + (rp - rcStart[n])*3 + r;
    5932:           remotePointsNew[m].rank  = rrank;
    5933:         }
    5934:       } else if ((p >= cMax) && (p < cEnd)) {
    5935:         /* Old hybrid cells add new cells and hybrid face */
    5936:         for (r = 0; r < 2; ++r, ++m) {
    5937:           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
    5938:           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
    5939:           remotePointsNew[m].rank  = rrank;
    5940:         }
    5941:         localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (cMax                            - cStart)*3     + (p  - cMax);
    5942:         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]);
    5943:         remotePointsNew[m].rank  = rrank;
    5944:         ++m;
    5945:       }
    5946:       break;
    5947:     case REFINER_HEX_2D:
    5948:     case REFINER_HYBRID_HEX_2D:
    5949:       if ((p >= vStart) && (p < vEnd)) {
    5950:         /* Old vertices stay the same */
    5951:         localPointsNew[m]        = vStartNew     + (p  - vStart);
    5952:         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
    5953:         remotePointsNew[m].rank  = rrank;
    5954:         ++m;
    5955:       } else if ((p >= fStart) && (p < fMax)) {
    5956:         /* Old interior faces add new faces and vertex */
    5957:         for (r = 0; r < 2; ++r, ++m) {
    5958:           localPointsNew[m]        = fStartNew     + (p  - fStart)*2     + r;
    5959:           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*2 + r;
    5960:           remotePointsNew[m].rank  = rrank;
    5961:         }
    5962:         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - fStart);
    5963:         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - rfStart[n]);
    5964:         remotePointsNew[m].rank  = rrank;
    5965:         ++m;
    5966:       } else if ((p >= fMax) && (p < fEnd)) {
    5967:         /* Old hybrid faces stay the same */
    5968:         localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (p  - fMax);
    5969:         remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*2 + (rp - rdepthMaxOld[n*(depth+1)+depth-1]);
    5970:         remotePointsNew[m].rank  = rrank;
    5971:         ++m;
    5972:       } else if ((p >= cStart) && (p < cMax)) {
    5973:         /* Old interior cells add new cells, interior faces, and vertex */
    5974:         for (r = 0; r < 4; ++r, ++m) {
    5975:           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
    5976:           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
    5977:           remotePointsNew[m].rank  = rrank;
    5978:         }
    5979:         for (r = 0; r < 4; ++r, ++m) {
    5980:           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (p  - cStart)*4     + r;
    5981:           remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*2 + (rp - rcStart[n])*4 + r;
    5982:           remotePointsNew[m].rank  = rrank;
    5983:         }
    5984:         localPointsNew[m]        = vStartNew     + (vEnd - vStart)               + (fMax                              - fStart)     + (p  - cStart);
    5985:         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0]  + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n]) + (rp - rcStart[n]);
    5986:         remotePointsNew[m].rank  = rrank;
    5987:         ++m;
    5988:       } else if ((p >= cStart) && (p < cMax)) {
    5989:         /* Old hybrid cells add new cells and hybrid face */
    5990:         for (r = 0; r < 2; ++r, ++m) {
    5991:           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
    5992:           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
    5993:           remotePointsNew[m].rank  = rrank;
    5994:         }
    5995:         localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (cMax                            - cStart)*4     + (p  - cMax);
    5996:         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]);
    5997:         remotePointsNew[m].rank  = rrank;
    5998:         ++m;
    5999:       }
    6000:       break;
    6001:     case REFINER_SIMPLEX_3D:
    6002:     case REFINER_HYBRID_SIMPLEX_3D:
    6003:       if ((p >= vStart) && (p < vEnd)) {
    6004:         /* Interior vertices stay the same */
    6005:         localPointsNew[m]        = vStartNew     + (p  - vStart);
    6006:         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
    6007:         remotePointsNew[m].rank  = rrank;
    6008:         ++m;
    6009:       } else if ((p >= eStart) && (p < eMax)) {
    6010:         /* Interior edges add new edges and vertex */
    6011:         for (r = 0; r < 2; ++r, ++m) {
    6012:           localPointsNew[m]        = eStartNew     + (p  - eStart)*2     + r;
    6013:           remotePointsNew[m].index = reStartNew[n] + (rp - reStart[n])*2 + r;
    6014:           remotePointsNew[m].rank  = rrank;
    6015:         }
    6016:         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - eStart);
    6017:         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - reStart[n]);
    6018:         remotePointsNew[m].rank  = rrank;
    6019:         ++m;
    6020:       } else if ((p >= eMax) && (p < eEnd)) {
    6021:         /* Hybrid edges stay the same */
    6022:         localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (fMax                              - fStart)*3     + (cMax                            - cStart)     + (p  - eMax);
    6023:         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]);
    6024:         remotePointsNew[m].rank  = rrank;
    6025:         ++m;
    6026:       } else if ((p >= fStart) && (p < fMax)) {
    6027:         /* Interior faces add new faces and edges */
    6028:         for (r = 0; r < 4; ++r, ++m) {
    6029:           localPointsNew[m]        = fStartNew     + (p  - fStart)*4     + r;
    6030:           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*4 + r;
    6031:           remotePointsNew[m].rank  = rrank;
    6032:         }
    6033:         for (r = 0; r < 3; ++r, ++m) {
    6034:           localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (p  - fStart)*3     + r;
    6035:           remotePointsNew[m].index = reStartNew[n] + (rdepthMaxOld[n*(depth+1)+1] - reStart[n])*2 + (rp - rfStart[n])*3 + r;
    6036:           remotePointsNew[m].rank  = rrank;
    6037:         }
    6038:       } else if ((p >= fMax) && (p < fEnd)) {
    6039:         /* Hybrid faces add new faces and edges */
    6040:         for (r = 0; r < 2; ++r, ++m) {
    6041:           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*4     + (cMax                            - cStart)*8     + (p  - fMax)*2                              + r;
    6042:           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;
    6043:           remotePointsNew[m].rank  = rrank;
    6044:         }
    6045:         localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (fMax                              - fStart)*3     + (cMax                            - cStart)     + (eEnd                                    - eMax)                        + (p  - fMax);
    6046:         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]);
    6047:         remotePointsNew[m].rank  = rrank;
    6048:         ++m;
    6049:       } else if ((p >= cStart) && (p < cMax)) {
    6050:         /* Interior cells add new cells, faces, and edges */
    6051:         for (r = 0; r < 8; ++r, ++m) {
    6052:           localPointsNew[m]        = cStartNew     + (p  - cStart)*8     + r;
    6053:           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*8 + r;
    6054:           remotePointsNew[m].rank  = rrank;
    6055:         }
    6056:         for (r = 0; r < 8; ++r, ++m) {
    6057:           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*4     + (p  - cStart)*8     + r;
    6058:           remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*4 + (rp - rcStart[n])*8 + r;
    6059:           remotePointsNew[m].rank  = rrank;
    6060:         }
    6061:         localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (fMax                              - fStart)*3     + (p  - cStart)*1     + 0;
    6062:         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;
    6063:         remotePointsNew[m].rank  = rrank;
    6064:         ++m;
    6065:       } else if ((p >= cMax) && (p < cEnd)) {
    6066:         /* Hybrid cells add new cells and faces */
    6067:         for (r = 0; r < 4; ++r, ++m) {
    6068:           localPointsNew[m]        = cStartNew     + (cMax                            - cStart)*8     + (p  - cMax)*4                            + r;
    6069:           remotePointsNew[m].index = rcStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth] - rcStart[n])*8 + (rp - rdepthMaxOld[n*(depth+1)+depth])*4 + r;
    6070:           remotePointsNew[m].rank  = rrank;
    6071:         }
    6072:         for (r = 0; r < 3; ++r, ++m) {
    6073:           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*4     + (cMax                            - cStart)*8     + (fEnd                                          - fMax)*2                              + (p  - cMax)*3                            + r;
    6074:           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;
    6075:           remotePointsNew[m].rank  = rrank;
    6076:         }
    6077:       }
    6078:       break;
    6079:     case REFINER_HEX_3D:
    6080:     case REFINER_HYBRID_HEX_3D:
    6081:       if ((p >= vStart) && (p < vEnd)) {
    6082:         /* Interior vertices stay the same */
    6083:         localPointsNew[m]        = vStartNew     + (p  - vStart);
    6084:         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
    6085:         remotePointsNew[m].rank  = rrank;
    6086:         ++m;
    6087:       } else if ((p >= eStart) && (p < eMax)) {
    6088:         /* Interior edges add new edges and vertex */
    6089:         for (r = 0; r < 2; ++r, ++m) {
    6090:           localPointsNew[m]        = eStartNew     + (p  - eStart)*2     + r;
    6091:           remotePointsNew[m].index = reStartNew[n] + (rp - reStart[n])*2 + r;
    6092:           remotePointsNew[m].rank  = rrank;
    6093:         }
    6094:         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - eStart);
    6095:         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - reStart[n]);
    6096:         remotePointsNew[m].rank  = rrank;
    6097:         ++m;
    6098:       } else if ((p >= eMax) && (p < eEnd)) {
    6099:         /* Hybrid edges stay the same */
    6100:         localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (fMax                              - fStart)*4     + (cMax                            - cStart)*6     + (p  - eMax);
    6101:         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]);
    6102:         remotePointsNew[m].rank  = rrank;
    6103:         ++m;
    6104:       } else if ((p >= fStart) && (p < fMax)) {
    6105:         /* Interior faces add new faces, edges, and vertex */
    6106:         for (r = 0; r < 4; ++r, ++m) {
    6107:           localPointsNew[m]        = fStartNew     + (p  - fStart)*4     + r;
    6108:           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*4 + r;
    6109:           remotePointsNew[m].rank  = rrank;
    6110:         }
    6111:         for (r = 0; r < 4; ++r, ++m) {
    6112:           localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (p  - fStart)*4     + r;
    6113:           remotePointsNew[m].index = reStartNew[n] + (rdepthMaxOld[n*(depth+1)+1] - reStart[n])*2 + (rp - rfStart[n])*4 + r;
    6114:           remotePointsNew[m].rank  = rrank;
    6115:         }
    6116:         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (eMax                        - eStart)     + (p  - fStart);
    6117:         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rdepthMaxOld[n*(depth+1)+1] - reStart[n]) + (rp - rfStart[n]);
    6118:         remotePointsNew[m].rank  = rrank;
    6119:         ++m;
    6120:       } else if ((p >= fMax) && (p < fEnd)) {
    6121:         /* Hybrid faces add new faces and edges */
    6122:         for (r = 0; r < 2; ++r, ++m) {
    6123:           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*4     + (cMax                            - cStart)*12     + (p  - fMax)*2                              + r;
    6124:           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;
    6125:           remotePointsNew[m].rank  = rrank;
    6126:         }
    6127:         localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (fMax                              - fStart)*4     + (cMax                            - cStart)*6     + (eEnd                                    - eMax)                        + (p  - fMax);
    6128:         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]);
    6129:         remotePointsNew[m].rank  = rrank;
    6130:         ++m;
    6131:       } else if ((p >= cStart) && (p < cMax)) {
    6132:         /* Interior cells add new cells, faces, edges, and vertex */
    6133:         for (r = 0; r < 8; ++r, ++m) {
    6134:           localPointsNew[m]        = cStartNew     + (p  - cStart)*8     + r;
    6135:           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*8 + r;
    6136:           remotePointsNew[m].rank  = rrank;
    6137:         }
    6138:         for (r = 0; r < 12; ++r, ++m) {
    6139:           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*4     + (p  - cStart)*12     + r;
    6140:           remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*4 + (rp - rcStart[n])*12 + r;
    6141:           remotePointsNew[m].rank  = rrank;
    6142:         }
    6143:         for (r = 0; r < 6; ++r, ++m) {
    6144:           localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (fMax                              - fStart)*4     + (p  - cStart)*6     + r;
    6145:           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;
    6146:           remotePointsNew[m].rank  = rrank;
    6147:         }
    6148:         for (r = 0; r < 1; ++r, ++m) {
    6149:           localPointsNew[m]        = vStartNew     + (eMax                        - eStart)     + (fMax                              - fStart)     + (p  - cStart)     + r;
    6150:           remotePointsNew[m].index = rvStartNew[n] + (rdepthMaxOld[n*(depth+1)+1] - reStart[n]) + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n]) + (rp - rcStart[n]) + r;
    6151:           remotePointsNew[m].rank  = rrank;
    6152:         }
    6153:       } else if ((p >= cMax) && (p < cEnd)) {
    6154:         /* Hybrid cells add new cells, faces, and edges */
    6155:         for (r = 0; r < 4; ++r, ++m) {
    6156:           localPointsNew[m]        = cStartNew     + (cMax                            - cStart)*8     + (p  - cMax)*4                            + r;
    6157:           remotePointsNew[m].index = rcStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth] - rcStart[n])*8 + (rp - rdepthMaxOld[n*(depth+1)+depth])*4 + r;
    6158:           remotePointsNew[m].rank  = rrank;
    6159:         }
    6160:         for (r = 0; r < 4; ++r, ++m) {
    6161:           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*4     + (cMax                            - cStart)*12     + (fEnd                                          - fMax)*2                              + (p  - cMax)*4                            + r;
    6162:           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;
    6163:           remotePointsNew[m].rank  = rrank;
    6164:         }
    6165:         localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (fMax                              - fStart)*4     + (cMax                            - cStart)*6     + (eEnd                                    - eMax)                        + (fEnd                                          - fMax)                              + (p  - cMax);
    6166:         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]);
    6167:         remotePointsNew[m].rank  = rrank;
    6168:         ++m;
    6169:       }
    6170:       break;
    6171:     default:
    6172:       SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
    6173:     }
    6174:   }
    6175:   if (m != numLeavesNew) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Number of leaf point %d should be %d", m, numLeavesNew);
    6176:   ISRestoreIndices(processRanks, &neighbors);
    6177:   ISDestroy(&processRanks);
    6178:   {
    6179:     PetscSFNode *rp, *rtmp;
    6180:     PetscInt    *lp, *idx, *ltmp, i;

    6182:     /* SF needs sorted leaves to correct calculate Gather */
    6183:     PetscMalloc1(numLeavesNew,&idx);
    6184:     PetscMalloc1(numLeavesNew, &lp);
    6185:     PetscMalloc1(numLeavesNew, &rp);
    6186:     for (i = 0; i < numLeavesNew; ++i) {
    6187:       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);
    6188:       idx[i] = i;
    6189:     }
    6190:     PetscSortIntWithPermutation(numLeavesNew, localPointsNew, idx);
    6191:     for (i = 0; i < numLeavesNew; ++i) {
    6192:       lp[i] = localPointsNew[idx[i]];
    6193:       rp[i] = remotePointsNew[idx[i]];
    6194:     }
    6195:     ltmp            = localPointsNew;
    6196:     localPointsNew  = lp;
    6197:     rtmp            = remotePointsNew;
    6198:     remotePointsNew = rp;
    6199:     PetscFree(idx);
    6200:     PetscFree(ltmp);
    6201:     PetscFree(rtmp);
    6202:   }
    6203:   PetscSFSetGraph(sfNew, pEndNew-pStartNew, numLeavesNew, localPointsNew, PETSC_OWN_POINTER, remotePointsNew, PETSC_OWN_POINTER);
    6204:   PetscFree5(rdepthSize,rvStartNew,reStartNew,rfStartNew,rcStartNew);
    6205:   PetscFree7(depthSizeOld,rdepthSizeOld,rdepthMaxOld,rvStart,reStart,rfStart,rcStart);
    6206:   return(0);
    6207: }

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

    6219:   DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);
    6220:   DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);
    6221:   DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);
    6222:   DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);
    6223:   DMPlexGetDepth(dm, &depth);
    6224:   if (refiner) {GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);}
    6225:   DMPlexGetNumLabels(dm, &numLabels);
    6226:   DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);
    6227:   switch (refiner) {
    6228:   case REFINER_NOOP:
    6229:   case REFINER_SIMPLEX_1D:
    6230:   case REFINER_SIMPLEX_2D:
    6231:   case REFINER_HEX_2D:
    6232:   case REFINER_SIMPLEX_3D:
    6233:   case REFINER_HEX_3D:
    6234:     break;
    6235:   case REFINER_HYBRID_SIMPLEX_3D:
    6236:   case REFINER_HYBRID_HEX_3D:
    6237:     if (eMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No edge maximum specified in hybrid mesh");
    6238:   case REFINER_HYBRID_SIMPLEX_2D:
    6239:   case REFINER_HYBRID_HEX_2D:
    6240:     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
    6241:     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
    6242:     break;
    6243:   default:
    6244:     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
    6245:   }
    6246:   for (l = 0; l < numLabels; ++l) {
    6247:     DMLabel         label, labelNew;
    6248:     const char     *lname;
    6249:     PetscBool       isDepth;
    6250:     IS              valueIS;
    6251:     const PetscInt *values;
    6252:     PetscInt        numValues, val;

    6254:     DMPlexGetLabelName(dm, l, &lname);
    6255:     PetscStrcmp(lname, "depth", &isDepth);
    6256:     if (isDepth) continue;
    6257:     DMPlexCreateLabel(rdm, lname);
    6258:     DMPlexGetLabel(dm, lname, &label);
    6259:     DMPlexGetLabel(rdm, lname, &labelNew);
    6260:     DMLabelGetValueIS(label, &valueIS);
    6261:     ISGetLocalSize(valueIS, &numValues);
    6262:     ISGetIndices(valueIS, &values);
    6263:     for (val = 0; val < numValues; ++val) {
    6264:       IS              pointIS;
    6265:       const PetscInt *points;
    6266:       PetscInt        numPoints, n;

    6268:       DMLabelGetStratumIS(label, values[val], &pointIS);
    6269:       ISGetLocalSize(pointIS, &numPoints);
    6270:       ISGetIndices(pointIS, &points);
    6271:       /* Ensure refined label is created with same number of strata as
    6272:        * original (even if no entries here). */
    6273:       if (!numPoints) {
    6274:         DMLabelSetValue(labelNew, 0, values[val]);
    6275:         DMLabelClearValue(labelNew, 0, values[val]);
    6276:       }
    6277:       for (n = 0; n < numPoints; ++n) {
    6278:         const PetscInt p = points[n];
    6279:         switch (refiner) {
    6280:         case REFINER_SIMPLEX_1D:
    6281:           if ((p >= vStart) && (p < vEnd)) {
    6282:             /* Old vertices stay the same */
    6283:             newp = vStartNew + (p - vStart);
    6284:             DMLabelSetValue(labelNew, newp, values[val]);
    6285:           } else if ((p >= cStart) && (p < cEnd)) {
    6286:             /* Old cells add new cells and vertex */
    6287:             newp = vStartNew + (vEnd - vStart) + (p - cStart);
    6288:             DMLabelSetValue(labelNew, newp, values[val]);
    6289:             for (r = 0; r < 2; ++r) {
    6290:               newp = cStartNew + (p - cStart)*2 + r;
    6291:               DMLabelSetValue(labelNew, newp, values[val]);
    6292:             }
    6293:           }
    6294:           break;
    6295:         case REFINER_SIMPLEX_2D:
    6296:           if ((p >= vStart) && (p < vEnd)) {
    6297:             /* Old vertices stay the same */
    6298:             newp = vStartNew + (p - vStart);
    6299:             DMLabelSetValue(labelNew, newp, values[val]);
    6300:           } else if ((p >= fStart) && (p < fEnd)) {
    6301:             /* Old faces add new faces and vertex */
    6302:             newp = vStartNew + (vEnd - vStart) + (p - fStart);
    6303:             DMLabelSetValue(labelNew, newp, values[val]);
    6304:             for (r = 0; r < 2; ++r) {
    6305:               newp = fStartNew + (p - fStart)*2 + r;
    6306:               DMLabelSetValue(labelNew, newp, values[val]);
    6307:             }
    6308:           } else if ((p >= cStart) && (p < cEnd)) {
    6309:             /* Old cells add new cells and interior faces */
    6310:             for (r = 0; r < 4; ++r) {
    6311:               newp = cStartNew + (p - cStart)*4 + r;
    6312:               DMLabelSetValue(labelNew, newp, values[val]);
    6313:             }
    6314:             for (r = 0; r < 3; ++r) {
    6315:               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*3 + r;
    6316:               DMLabelSetValue(labelNew, newp, values[val]);
    6317:             }
    6318:           }
    6319:           break;
    6320:         case REFINER_HEX_2D:
    6321:           if ((p >= vStart) && (p < vEnd)) {
    6322:             /* Old vertices stay the same */
    6323:             newp = vStartNew + (p - vStart);
    6324:             DMLabelSetValue(labelNew, newp, values[val]);
    6325:           } else if ((p >= fStart) && (p < fEnd)) {
    6326:             /* Old faces add new faces and vertex */
    6327:             newp = vStartNew + (vEnd - vStart) + (p - fStart);
    6328:             DMLabelSetValue(labelNew, newp, values[val]);
    6329:             for (r = 0; r < 2; ++r) {
    6330:               newp = fStartNew + (p - fStart)*2 + r;
    6331:               DMLabelSetValue(labelNew, newp, values[val]);
    6332:             }
    6333:           } else if ((p >= cStart) && (p < cEnd)) {
    6334:             /* Old cells add new cells and interior faces and vertex */
    6335:             for (r = 0; r < 4; ++r) {
    6336:               newp = cStartNew + (p - cStart)*4 + r;
    6337:               DMLabelSetValue(labelNew, newp, values[val]);
    6338:             }
    6339:             for (r = 0; r < 4; ++r) {
    6340:               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*4 + r;
    6341:               DMLabelSetValue(labelNew, newp, values[val]);
    6342:             }
    6343:             newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (p - cStart);
    6344:             DMLabelSetValue(labelNew, newp, values[val]);
    6345:           }
    6346:           break;
    6347:         case REFINER_HYBRID_SIMPLEX_2D:
    6348:           if ((p >= vStart) && (p < vEnd)) {
    6349:             /* Old vertices stay the same */
    6350:             newp = vStartNew + (p - vStart);
    6351:             DMLabelSetValue(labelNew, newp, values[val]);
    6352:           } else if ((p >= fStart) && (p < fMax)) {
    6353:             /* Old interior faces add new faces and vertex */
    6354:             newp = vStartNew + (vEnd - vStart) + (p - fStart);
    6355:             DMLabelSetValue(labelNew, newp, values[val]);
    6356:             for (r = 0; r < 2; ++r) {
    6357:               newp = fStartNew + (p - fStart)*2 + r;
    6358:               DMLabelSetValue(labelNew, newp, values[val]);
    6359:             }
    6360:           } else if ((p >= fMax) && (p < fEnd)) {
    6361:             /* Old hybrid faces stay the same */
    6362:             newp = fStartNew + (fMax - fStart)*2 + (p - fMax);
    6363:             DMLabelSetValue(labelNew, newp, values[val]);
    6364:           } else if ((p >= cStart) && (p < cMax)) {
    6365:             /* Old interior cells add new cells and interior faces */
    6366:             for (r = 0; r < 4; ++r) {
    6367:               newp = cStartNew + (p - cStart)*4 + r;
    6368:               DMLabelSetValue(labelNew, newp, values[val]);
    6369:             }
    6370:             for (r = 0; r < 3; ++r) {
    6371:               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*3 + r;
    6372:               DMLabelSetValue(labelNew, newp, values[val]);
    6373:             }
    6374:           } else if ((p >= cMax) && (p < cEnd)) {
    6375:             /* Old hybrid cells add new cells and hybrid face */
    6376:             for (r = 0; r < 2; ++r) {
    6377:               newp = cStartNew + (cMax - cStart)*4 + (p - cMax)*2 + r;
    6378:               DMLabelSetValue(labelNew, newp, values[val]);
    6379:             }
    6380:             newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (p - cMax);
    6381:             DMLabelSetValue(labelNew, newp, values[val]);
    6382:           }
    6383:           break;
    6384:         case REFINER_HYBRID_HEX_2D:
    6385:           if ((p >= vStart) && (p < vEnd)) {
    6386:             /* Old vertices stay the same */
    6387:             newp = vStartNew + (p - vStart);
    6388:             DMLabelSetValue(labelNew, newp, values[val]);
    6389:           } else if ((p >= fStart) && (p < fMax)) {
    6390:             /* Old interior faces add new faces and vertex */
    6391:             newp = vStartNew + (vEnd - vStart) + (p - fStart);
    6392:             DMLabelSetValue(labelNew, newp, values[val]);
    6393:             for (r = 0; r < 2; ++r) {
    6394:               newp = fStartNew + (p - fStart)*2 + r;
    6395:               DMLabelSetValue(labelNew, newp, values[val]);
    6396:             }
    6397:           } else if ((p >= fMax) && (p < fEnd)) {
    6398:             /* Old hybrid faces stay the same */
    6399:             newp = fStartNew + (fMax - fStart)*2 + (p - fMax);
    6400:             DMLabelSetValue(labelNew, newp, values[val]);
    6401:           } else if ((p >= cStart) && (p < cMax)) {
    6402:             /* Old interior cells add new cells, interior faces, and vertex */
    6403:             for (r = 0; r < 4; ++r) {
    6404:               newp = cStartNew + (p - cStart)*4 + r;
    6405:               DMLabelSetValue(labelNew, newp, values[val]);
    6406:             }
    6407:             for (r = 0; r < 4; ++r) {
    6408:               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*4 + r;
    6409:               DMLabelSetValue(labelNew, newp, values[val]);
    6410:             }
    6411:             newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (p - cStart);
    6412:             DMLabelSetValue(labelNew, newp, values[val]);
    6413:           } else if ((p >= cMax) && (p < cEnd)) {
    6414:             /* Old hybrid cells add new cells and hybrid face */
    6415:             for (r = 0; r < 2; ++r) {
    6416:               newp = cStartNew + (cMax - cStart)*4 + (p - cMax)*2 + r;
    6417:               DMLabelSetValue(labelNew, newp, values[val]);
    6418:             }
    6419:             newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*4 + (p - cMax);
    6420:             DMLabelSetValue(labelNew, newp, values[val]);
    6421:           }
    6422:           break;
    6423:         case REFINER_SIMPLEX_3D:
    6424:           if ((p >= vStart) && (p < vEnd)) {
    6425:             /* Old vertices stay the same */
    6426:             newp = vStartNew + (p - vStart);
    6427:             DMLabelSetValue(labelNew, newp, values[val]);
    6428:           } else if ((p >= eStart) && (p < eEnd)) {
    6429:             /* Old edges add new edges and vertex */
    6430:             for (r = 0; r < 2; ++r) {
    6431:               newp = eStartNew + (p - eStart)*2 + r;
    6432:               DMLabelSetValue(labelNew, newp, values[val]);
    6433:             }
    6434:             newp = vStartNew + (vEnd - vStart) + (p - eStart);
    6435:             DMLabelSetValue(labelNew, newp, values[val]);
    6436:           } else if ((p >= fStart) && (p < fEnd)) {
    6437:             /* Old faces add new faces and edges */
    6438:             for (r = 0; r < 4; ++r) {
    6439:               newp = fStartNew + (p - fStart)*4 + r;
    6440:               DMLabelSetValue(labelNew, newp, values[val]);
    6441:             }
    6442:             for (r = 0; r < 3; ++r) {
    6443:               newp = eStartNew + (eEnd - eStart)*2 + (p - fStart)*3 + r;
    6444:               DMLabelSetValue(labelNew, newp, values[val]);
    6445:             }
    6446:           } else if ((p >= cStart) && (p < cEnd)) {
    6447:             /* Old cells add new cells and interior faces and edges */
    6448:             for (r = 0; r < 8; ++r) {
    6449:               newp = cStartNew + (p - cStart)*8 + r;
    6450:               DMLabelSetValue(labelNew, newp, values[val]);
    6451:             }
    6452:             for (r = 0; r < 8; ++r) {
    6453:               newp = fStartNew + (fEnd - fStart)*4 + (p - cStart)*8 + r;
    6454:               DMLabelSetValue(labelNew, newp, values[val]);
    6455:             }
    6456:             for (r = 0; r < 1; ++r) {
    6457:               newp = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (p - cStart)*1 + r;
    6458:               DMLabelSetValue(labelNew, newp, values[val]);
    6459:             }
    6460:           }
    6461:           break;
    6462:         case REFINER_HYBRID_SIMPLEX_3D:
    6463:           if ((p >= vStart) && (p < vEnd)) {
    6464:             /* Interior vertices stay the same */
    6465:             newp = vStartNew + (p - vStart);
    6466:             DMLabelSetValue(labelNew, newp, values[val]);
    6467:           } else if ((p >= eStart) && (p < eMax)) {
    6468:             /* Interior edges add new edges and vertex */
    6469:             for (r = 0; r < 2; ++r) {
    6470:               newp = eStartNew + (p - eStart)*2 + r;
    6471:               DMLabelSetValue(labelNew, newp, values[val]);
    6472:             }
    6473:             newp = vStartNew + (vEnd - vStart) + (p - eStart);
    6474:             DMLabelSetValue(labelNew, newp, values[val]);
    6475:           } else if ((p >= eMax) && (p < eEnd)) {
    6476:             /* Hybrid edges stay the same */
    6477:             newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (p - eMax);
    6478:             DMLabelSetValue(labelNew, newp, values[val]);
    6479:           } else if ((p >= fStart) && (p < fMax)) {
    6480:             /* Interior faces add new faces and edges */
    6481:             for (r = 0; r < 4; ++r) {
    6482:               newp = fStartNew + (p - fStart)*4 + r;
    6483:               DMLabelSetValue(labelNew, newp, values[val]);
    6484:             }
    6485:             for (r = 0; r < 3; ++r) {
    6486:               newp = eStartNew + (eMax - eStart)*2 + (p - fStart)*3 + r;
    6487:               DMLabelSetValue(labelNew, newp, values[val]);
    6488:             }
    6489:           } else if ((p >= fMax) && (p < fEnd)) {
    6490:             /* Hybrid faces add new faces and edges */
    6491:             for (r = 0; r < 2; ++r) {
    6492:               newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (p - fMax)*2 + r;
    6493:               DMLabelSetValue(labelNew, newp, values[val]);
    6494:             }
    6495:             newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (p - fMax);
    6496:             DMLabelSetValue(labelNew, newp, values[val]);
    6497:           } else if ((p >= cStart) && (p < cMax)) {
    6498:             /* Interior cells add new cells, faces, and edges */
    6499:             for (r = 0; r < 8; ++r) {
    6500:               newp = cStartNew + (p - cStart)*8 + r;
    6501:               DMLabelSetValue(labelNew, newp, values[val]);
    6502:             }
    6503:             for (r = 0; r < 8; ++r) {
    6504:               newp = fStartNew + (fMax - fStart)*4 + (p - cStart)*8 + r;
    6505:               DMLabelSetValue(labelNew, newp, values[val]);
    6506:             }
    6507:             newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (p - cStart);
    6508:             DMLabelSetValue(labelNew, newp, values[val]);
    6509:           } else if ((p >= cMax) && (p < cEnd)) {
    6510:             /* Hybrid cells add new cells and faces */
    6511:             for (r = 0; r < 4; ++r) {
    6512:               newp = cStartNew + (cMax - cStart)*8 + (p - cMax)*4 + r;
    6513:               DMLabelSetValue(labelNew, newp, values[val]);
    6514:             }
    6515:             for (r = 0; r < 3; ++r) {
    6516:               newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (p - cMax)*3 + r;
    6517:               DMLabelSetValue(labelNew, newp, values[val]);
    6518:             }
    6519:           }
    6520:           break;
    6521:         case REFINER_HEX_3D:
    6522:           if ((p >= vStart) && (p < vEnd)) {
    6523:             /* Old vertices stay the same */
    6524:             newp = vStartNew + (p - vStart);
    6525:             DMLabelSetValue(labelNew, newp, values[val]);
    6526:           } else if ((p >= eStart) && (p < eEnd)) {
    6527:             /* Old edges add new edges and vertex */
    6528:             for (r = 0; r < 2; ++r) {
    6529:               newp = eStartNew + (p - eStart)*2 + r;
    6530:               DMLabelSetValue(labelNew, newp, values[val]);
    6531:             }
    6532:             newp = vStartNew + (vEnd - vStart) + (p - eStart);
    6533:             DMLabelSetValue(labelNew, newp, values[val]);
    6534:           } else if ((p >= fStart) && (p < fEnd)) {
    6535:             /* Old faces add new faces, edges, and vertex */
    6536:             for (r = 0; r < 4; ++r) {
    6537:               newp = fStartNew + (p - fStart)*4 + r;
    6538:               DMLabelSetValue(labelNew, newp, values[val]);
    6539:             }
    6540:             for (r = 0; r < 4; ++r) {
    6541:               newp = eStartNew + (eEnd - eStart)*2 + (p - fStart)*4 + r;
    6542:               DMLabelSetValue(labelNew, newp, values[val]);
    6543:             }
    6544:             newp = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (p - fStart);
    6545:             DMLabelSetValue(labelNew, newp, values[val]);
    6546:           } else if ((p >= cStart) && (p < cEnd)) {
    6547:             /* Old cells add new cells, faces, edges, and vertex */
    6548:             for (r = 0; r < 8; ++r) {
    6549:               newp = cStartNew + (p - cStart)*8 + r;
    6550:               DMLabelSetValue(labelNew, newp, values[val]);
    6551:             }
    6552:             for (r = 0; r < 12; ++r) {
    6553:               newp = fStartNew + (fEnd - fStart)*4 + (p - cStart)*12 + r;
    6554:               DMLabelSetValue(labelNew, newp, values[val]);
    6555:             }
    6556:             for (r = 0; r < 6; ++r) {
    6557:               newp = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*4 + (p - cStart)*6 + r;
    6558:               DMLabelSetValue(labelNew, newp, values[val]);
    6559:             }
    6560:             newp = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (fEnd - fStart) + (p - cStart);
    6561:             DMLabelSetValue(labelNew, newp, values[val]);
    6562:           }
    6563:           break;
    6564:         case REFINER_HYBRID_HEX_3D:
    6565:           if ((p >= vStart) && (p < vEnd)) {
    6566:             /* Interior vertices stay the same */
    6567:             newp = vStartNew + (p - vStart);
    6568:             DMLabelSetValue(labelNew, newp, values[val]);
    6569:           } else if ((p >= eStart) && (p < eMax)) {
    6570:             /* Interior edges add new edges and vertex */
    6571:             for (r = 0; r < 2; ++r) {
    6572:               newp = eStartNew + (p - eStart)*2 + r;
    6573:               DMLabelSetValue(labelNew, newp, values[val]);
    6574:             }
    6575:             newp = vStartNew + (vEnd - vStart) + (p - eStart);
    6576:             DMLabelSetValue(labelNew, newp, values[val]);
    6577:           } else if ((p >= eMax) && (p < eEnd)) {
    6578:             /* Hybrid edges stay the same */
    6579:             newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (p - eMax);
    6580:             DMLabelSetValue(labelNew, newp, values[val]);
    6581:           } else if ((p >= fStart) && (p < fMax)) {
    6582:             /* Interior faces add new faces, edges, and vertex */
    6583:             for (r = 0; r < 4; ++r) {
    6584:               newp = fStartNew + (p - fStart)*4 + r;
    6585:               DMLabelSetValue(labelNew, newp, values[val]);
    6586:             }
    6587:             for (r = 0; r < 4; ++r) {
    6588:               newp = eStartNew + (eMax - eStart)*2 + (p - fStart)*4 + r;
    6589:               DMLabelSetValue(labelNew, newp, values[val]);
    6590:             }
    6591:             newp = vStartNew + (vEnd - vStart) + (eMax - eStart) + (p - fStart);
    6592:             DMLabelSetValue(labelNew, newp, values[val]);
    6593:           } else if ((p >= fMax) && (p < fEnd)) {
    6594:             /* Hybrid faces add new faces and edges */
    6595:             for (r = 0; r < 2; ++r) {
    6596:               newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (p - fMax)*2 + r;
    6597:               DMLabelSetValue(labelNew, newp, values[val]);
    6598:             }
    6599:             newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (p - fMax);
    6600:             DMLabelSetValue(labelNew, newp, values[val]);
    6601:           } else if ((p >= cStart) && (p < cMax)) {
    6602:             /* Interior cells add new cells, faces, edges, and vertex */
    6603:             for (r = 0; r < 8; ++r) {
    6604:               newp = cStartNew + (p - cStart)*8 + r;
    6605:               DMLabelSetValue(labelNew, newp, values[val]);
    6606:             }
    6607:             for (r = 0; r < 12; ++r) {
    6608:               newp = fStartNew + (fMax - fStart)*4 + (p - cStart)*12 + r;
    6609:               DMLabelSetValue(labelNew, newp, values[val]);
    6610:             }
    6611:             for (r = 0; r < 6; ++r) {
    6612:               newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (p - cStart)*6 + r;
    6613:               DMLabelSetValue(labelNew, newp, values[val]);
    6614:             }
    6615:             newp = vStartNew + (vEnd - vStart) + (eMax - eStart) + (fMax - fStart) + (p - cStart);
    6616:             DMLabelSetValue(labelNew, newp, values[val]);
    6617:           } else if ((p >= cMax) && (p < cEnd)) {
    6618:             /* Hybrid cells add new cells, faces, and edges */
    6619:             for (r = 0; r < 4; ++r) {
    6620:               newp = cStartNew + (cMax - cStart)*8 + (p - cMax)*4 + r;
    6621:               DMLabelSetValue(labelNew, newp, values[val]);
    6622:             }
    6623:             for (r = 0; r < 4; ++r) {
    6624:               newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd - fMax)*2 + (p - cMax)*4 + r;
    6625:               DMLabelSetValue(labelNew, newp, values[val]);
    6626:             }
    6627:             newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (fEnd - fMax) + (p - cMax);
    6628:             DMLabelSetValue(labelNew, newp, values[val]);
    6629:           }
    6630:           break;
    6631:         default:
    6632:           SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
    6633:         }
    6634:       }
    6635:       ISRestoreIndices(pointIS, &points);
    6636:       ISDestroy(&pointIS);
    6637:     }
    6638:     ISRestoreIndices(valueIS, &values);
    6639:     ISDestroy(&valueIS);
    6640:     if (0) {
    6641:       PetscViewerASCIISynchronizedAllow(PETSC_VIEWER_STDOUT_WORLD, PETSC_TRUE);
    6642:       DMLabelView(labelNew, PETSC_VIEWER_STDOUT_WORLD);
    6643:       PetscViewerFlush(PETSC_VIEWER_STDOUT_WORLD);
    6644:     }
    6645:   }
    6646:   return(0);
    6647: }

    6651: /* This will only work for interpolated meshes */
    6652: PetscErrorCode DMPlexRefineUniform_Internal(DM dm, CellRefiner cellRefiner, DM *dmRefined)
    6653: {
    6654:   DM             rdm;
    6655:   PetscInt      *depthSize;
    6656:   PetscInt       dim, depth = 0, d, pStart = 0, pEnd = 0;

    6660:   DMCreate(PetscObjectComm((PetscObject)dm), &rdm);
    6661:   DMSetType(rdm, DMPLEX);
    6662:   DMGetDimension(dm, &dim);
    6663:   DMSetDimension(rdm, dim);
    6664:   /* Calculate number of new points of each depth */
    6665:   DMPlexGetDepth(dm, &depth);
    6666:   if (depth >= 0 && dim != depth) SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "Mesh must be interpolated for regular refinement");
    6667:   PetscMalloc1(depth+1, &depthSize);
    6668:   PetscMemzero(depthSize, (depth+1) * sizeof(PetscInt));
    6669:   CellRefinerGetSizes(cellRefiner, dm, depthSize);
    6670:   /* Step 1: Set chart */
    6671:   for (d = 0; d <= depth; ++d) pEnd += depthSize[d];
    6672:   DMPlexSetChart(rdm, pStart, pEnd);
    6673:   /* Step 2: Set cone/support sizes */
    6674:   CellRefinerSetConeSizes(cellRefiner, dm, depthSize, rdm);
    6675:   /* Step 3: Setup refined DM */
    6676:   DMSetUp(rdm);
    6677:   /* Step 4: Set cones and supports */
    6678:   CellRefinerSetCones(cellRefiner, dm, depthSize, rdm);
    6679:   /* Step 5: Stratify */
    6680:   DMPlexStratify(rdm);
    6681:   /* Step 6: Create pointSF */
    6682:   CellRefinerCreateSF(cellRefiner, dm, depthSize, rdm);
    6683:   /* Step 7: Set coordinates for vertices */
    6684:   CellRefinerSetCoordinates(cellRefiner, dm, depthSize, rdm);
    6685:   /* Step 8: Create labels */
    6686:   CellRefinerCreateLabels(cellRefiner, dm, depthSize, rdm);
    6687:   PetscFree(depthSize);

    6689:   *dmRefined = rdm;
    6690:   return(0);
    6691: }

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

    6698:   Input Parameter:
    6699: . dm - The coarse DM

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

    6704:   Level: developer

    6706: .seealso: DMRefine(), DMPlexSetRefinementUniform(), DMPlexCreateSubpointIS()
    6707: @*/
    6708: PetscErrorCode DMPlexCreateCoarsePointIS(DM dm, IS *fpointIS)
    6709: {
    6710:   CellRefiner    cellRefiner;
    6711:   PetscInt      *depthSize, *fpoints;
    6712:   PetscInt       cStartNew = 0, vStartNew = 0, fStartNew = 0, eStartNew = 0;
    6713:   PetscInt       depth, pStart, pEnd, p, vStart, vEnd, v;

    6717:   DMPlexGetDepth(dm, &depth);
    6718:   DMPlexGetChart(dm, &pStart, &pEnd);
    6719:   DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);
    6720:   DMPlexGetCellRefiner_Internal(dm, &cellRefiner);
    6721:   PetscMalloc1(depth+1, &depthSize);
    6722:   CellRefinerGetSizes(cellRefiner, dm, depthSize);
    6723:   if (cellRefiner) {GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);}
    6724:   PetscMalloc1(pEnd-pStart,&fpoints);
    6725:   for (p = 0; p < pEnd-pStart; ++p) fpoints[p] = -1;
    6726:   switch (cellRefiner) {
    6727:   case REFINER_SIMPLEX_1D:
    6728:   case REFINER_SIMPLEX_2D:
    6729:   case REFINER_HYBRID_SIMPLEX_2D:
    6730:   case REFINER_HEX_2D:
    6731:   case REFINER_HYBRID_HEX_2D:
    6732:   case REFINER_SIMPLEX_3D:
    6733:   case REFINER_HYBRID_SIMPLEX_3D:
    6734:   case REFINER_HEX_3D:
    6735:   case REFINER_HYBRID_HEX_3D:
    6736:     for (v = vStart; v < vEnd; ++v) fpoints[v-pStart] = vStartNew + (v - vStart);
    6737:     break;
    6738:   default:
    6739:     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", cellRefiner);
    6740:   }
    6741:   ISCreateGeneral(PETSC_COMM_SELF, pEnd-pStart, fpoints, PETSC_OWN_POINTER, fpointIS);
    6742:   PetscFree(depthSize);
    6743:   return(0);
    6744: }

    6748: /*@
    6749:   DMPlexSetRefinementUniform - Set the flag for uniform refinement

    6751:   Input Parameters:
    6752: + dm - The DM
    6753: - refinementUniform - The flag for uniform refinement

    6755:   Level: developer

    6757: .seealso: DMRefine(), DMPlexGetRefinementUniform(), DMPlexGetRefinementLimit(), DMPlexSetRefinementLimit()
    6758: @*/
    6759: PetscErrorCode DMPlexSetRefinementUniform(DM dm, PetscBool refinementUniform)
    6760: {
    6761:   DM_Plex *mesh = (DM_Plex*) dm->data;

    6765:   mesh->refinementUniform = refinementUniform;
    6766:   return(0);
    6767: }

    6771: /*@
    6772:   DMPlexGetRefinementUniform - Retrieve the flag for uniform refinement

    6774:   Input Parameter:
    6775: . dm - The DM

    6777:   Output Parameter:
    6778: . refinementUniform - The flag for uniform refinement

    6780:   Level: developer

    6782: .seealso: DMRefine(), DMPlexSetRefinementUniform(), DMPlexGetRefinementLimit(), DMPlexSetRefinementLimit()
    6783: @*/
    6784: PetscErrorCode DMPlexGetRefinementUniform(DM dm, PetscBool *refinementUniform)
    6785: {
    6786:   DM_Plex *mesh = (DM_Plex*) dm->data;

    6791:   *refinementUniform = mesh->refinementUniform;
    6792:   return(0);
    6793: }

    6797: /*@
    6798:   DMPlexSetRefinementLimit - Set the maximum cell volume for refinement

    6800:   Input Parameters:
    6801: + dm - The DM
    6802: - refinementLimit - The maximum cell volume in the refined mesh

    6804:   Level: developer

    6806: .seealso: DMRefine(), DMPlexGetRefinementLimit(), DMPlexGetRefinementUniform(), DMPlexSetRefinementUniform()
    6807: @*/
    6808: PetscErrorCode DMPlexSetRefinementLimit(DM dm, PetscReal refinementLimit)
    6809: {
    6810:   DM_Plex *mesh = (DM_Plex*) dm->data;

    6814:   mesh->refinementLimit = refinementLimit;
    6815:   return(0);
    6816: }

    6820: /*@
    6821:   DMPlexGetRefinementLimit - Retrieve the maximum cell volume for refinement

    6823:   Input Parameter:
    6824: . dm - The DM

    6826:   Output Parameter:
    6827: . refinementLimit - The maximum cell volume in the refined mesh

    6829:   Level: developer

    6831: .seealso: DMRefine(), DMPlexSetRefinementLimit(), DMPlexGetRefinementUniform(), DMPlexSetRefinementUniform()
    6832: @*/
    6833: PetscErrorCode DMPlexGetRefinementLimit(DM dm, PetscReal *refinementLimit)
    6834: {
    6835:   DM_Plex *mesh = (DM_Plex*) dm->data;

    6840:   /* if (mesh->refinementLimit < 0) = getMaxVolume()/2.0; */
    6841:   *refinementLimit = mesh->refinementLimit;
    6842:   return(0);
    6843: }

    6847: PetscErrorCode DMPlexGetCellRefiner_Internal(DM dm, CellRefiner *cellRefiner)
    6848: {
    6849:   PetscInt       dim, cStart, cEnd, coneSize, cMax, fMax;

    6853:   DMGetDimension(dm, &dim);
    6854:   DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);
    6855:   if (cEnd <= cStart) {*cellRefiner = REFINER_NOOP; return(0);}
    6856:   DMPlexGetConeSize(dm, cStart, &coneSize);
    6857:   DMPlexGetHybridBounds(dm, &cMax, &fMax, NULL, NULL);
    6858:   switch (dim) {
    6859:   case 1:
    6860:     switch (coneSize) {
    6861:     case 2:
    6862:       *cellRefiner = REFINER_SIMPLEX_1D;
    6863:       break;
    6864:     default:
    6865:       SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown coneSize %d in dimension %d for cell refiner", coneSize, dim);
    6866:     }
    6867:     break;
    6868:   case 2:
    6869:     switch (coneSize) {
    6870:     case 3:
    6871:       if (cMax >= 0) *cellRefiner = REFINER_HYBRID_SIMPLEX_2D;
    6872:       else *cellRefiner = REFINER_SIMPLEX_2D;
    6873:       break;
    6874:     case 4:
    6875:       if (cMax >= 0 && fMax >= 0) *cellRefiner = REFINER_HYBRID_HEX_2D;
    6876:       else *cellRefiner = REFINER_HEX_2D;
    6877:       break;
    6878:     default:
    6879:       SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown coneSize %d in dimension %d for cell refiner", coneSize, dim);
    6880:     }
    6881:     break;
    6882:   case 3:
    6883:     switch (coneSize) {
    6884:     case 4:
    6885:       if (cMax >= 0) *cellRefiner = REFINER_HYBRID_SIMPLEX_3D;
    6886:       else *cellRefiner = REFINER_SIMPLEX_3D;
    6887:       break;
    6888:     case 6:
    6889:       if (cMax >= 0) *cellRefiner = REFINER_HYBRID_HEX_3D;
    6890:       else *cellRefiner = REFINER_HEX_3D;
    6891:       break;
    6892:     default:
    6893:       SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown coneSize %d in dimension %d for cell refiner", coneSize, dim);
    6894:     }
    6895:     break;
    6896:   default:
    6897:     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown dimension %d for cell refiner", dim);
    6898:   }
    6899:   return(0);
    6900: }