Actual source code: plexrefine.c
petsc-3.10.5 2019-03-28
Report Typos and Errors

      1:  #include <petsc/private/dmpleximpl.h>
      2:  #include <petscsf.h>

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

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

     24: /* Gets the affine map from the original cell to each subcell */
     25: PetscErrorCode CellRefinerGetAffineTransforms_Internal(CellRefiner refiner, PetscInt *numSubcells, PetscReal *v0[], PetscReal *jac[], PetscReal *invjac[])
     26: {
     27:   PetscReal     *v = NULL, *j = NULL, *invj = NULL, detJ;
     28:   PetscInt       dim, s;

     32:   switch (refiner) {
     33:   case REFINER_NOOP: break;
     34:   case REFINER_SIMPLEX_2D:
     35:     /*
     36:      2
     37:      |\
     38:      | \
     39:      |  \
     40:      |   \
     41:      | C  \
     42:      |     \
     43:      |      \
     44:      2---1---1
     45:      |\  D  / \
     46:      | 2   0   \
     47:      |A \ /  B  \
     48:      0---0-------1
     49:      */
     50:     dim = 2;
     51:     if (numSubcells) *numSubcells = 4;
     52:     if (v0) {
     53:       PetscMalloc3(4*dim,&v,4*dim*dim,&j,4*dim*dim,&invj);
     54:       /* A */
     55:       v[0+0] = -1.0; v[0+1] = -1.0;
     56:       j[0+0] =  0.5; j[0+1] =  0.0;
     57:       j[0+2] =  0.0; j[0+3] =  0.5;
     58:       /* B */
     59:       v[2+0] =  0.0; v[2+1] = -1.0;
     60:       j[4+0] =  0.5; j[4+1] =  0.0;
     61:       j[4+2] =  0.0; j[4+3] =  0.5;
     62:       /* C */
     63:       v[4+0] = -1.0; v[4+1] =  0.0;
     64:       j[8+0] =  0.5; j[8+1] =  0.0;
     65:       j[8+2] =  0.0; j[8+3] =  0.5;
     66:       /* D */
     67:       v[6+0]  =  0.0; v[6+1]  = -1.0;
     68:       j[12+0] =  0.0; j[12+1] = -0.5;
     69:       j[12+2] =  0.5; j[12+3] =  0.5;
     70:       for (s = 0; s < 4; ++s) {
     71:         DMPlex_Det2D_Internal(&detJ, &j[s*dim*dim]);
     72:         DMPlex_Invert2D_Internal(&invj[s*dim*dim], &j[s*dim*dim], detJ);
     73:       }
     74:     }
     75:     break;
     76:   case REFINER_HEX_2D:
     77:     /*
     78:      3---------2---------2
     79:      |         |         |
     80:      |    D    2    C    |
     81:      |         |         |
     82:      3----3----0----1----1
     83:      |         |         |
     84:      |    A    0    B    |
     85:      |         |         |
     86:      0---------0---------1
     87:      */
     88:     dim = 2;
     89:     if (numSubcells) *numSubcells = 4;
     90:     if (v0) {
     91:       PetscMalloc3(4*dim,&v,4*dim*dim,&j,4*dim*dim,&invj);
     92:       /* A */
     93:       v[0+0] = -1.0; v[0+1] = -1.0;
     94:       j[0+0] =  0.5; j[0+1] =  0.0;
     95:       j[0+2] =  0.0; j[0+3] =  0.5;
     96:       /* B */
     97:       v[2+0] =  0.0; v[2+1] = -1.0;
     98:       j[4+0] =  0.5; j[4+1] =  0.0;
     99:       j[4+2] =  0.0; j[4+3] =  0.5;
    100:       /* C */
    101:       v[4+0] =  0.0; v[4+1] =  0.0;
    102:       j[8+0] =  0.5; j[8+1] =  0.0;
    103:       j[8+2] =  0.0; j[8+3] =  0.5;
    104:       /* D */
    105:       v[6+0]  = -1.0; v[6+1]  =  0.0;
    106:       j[12+0] =  0.5; j[12+1] =  0.0;
    107:       j[12+2] =  0.0; j[12+3] =  0.5;
    108:       for (s = 0; s < 4; ++s) {
    109:         DMPlex_Det2D_Internal(&detJ, &j[s*dim*dim]);
    110:         DMPlex_Invert2D_Internal(&invj[s*dim*dim], &j[s*dim*dim], detJ);
    111:       }
    112:     }
    113:     break;
    114:   case REFINER_HEX_3D:
    115:     /*
    116:      Bottom (viewed from top)    Top
    117:      1---------2---------2       7---------2---------6
    118:      |         |         |       |         |         |
    119:      |    B    2    C    |       |    H    2    G    |
    120:      |         |         |       |         |         |
    121:      3----3----0----1----1       3----3----0----1----1
    122:      |         |         |       |         |         |
    123:      |    A    0    D    |       |    E    0    F    |
    124:      |         |         |       |         |         |
    125:      0---------0---------3       4---------0---------5
    126:      */
    127:     break;
    128:     dim = 3;
    129:     if (numSubcells) *numSubcells = 8;
    130:     if (v0) {
    131:       PetscMalloc3(4*dim,&v,4*dim*dim,&j,4*dim*dim,&invj);
    132:       /* A */
    133:       v[0+0] = -1.0; v[0+1] = -1.0; v[0+2] = -1.0;
    134:       j[0+0] =  0.5; j[0+1] =  0.0; j[0+2] =  0.0;
    135:       j[0+3] =  0.0; j[0+4] =  0.5; j[0+5] =  0.0;
    136:       j[0+6] =  0.0; j[0+7] =  0.0; j[0+8] =  0.5;
    137:       /* B */
    138:       v[3+0] = -1.0; v[3+1] =  0.0; v[3+2] = -1.0;
    139:       j[9+0] =  0.5; j[9+1] =  0.0; j[9+2] =  0.0;
    140:       j[9+3] =  0.0; j[9+4] =  0.5; j[9+5] =  0.0;
    141:       j[9+6] =  0.0; j[9+7] =  0.0; j[9+8] =  0.5;
    142:       /* C */
    143:       v[6+0] =  0.0; v[6+1] =  0.0; v[6+2] = -1.0;
    144:       j[18+0] = 0.5; j[18+1] = 0.0; j[18+2] = 0.0;
    145:       j[18+3] = 0.0; j[18+4] = 0.5; j[18+5] = 0.0;
    146:       j[18+6] = 0.0; j[18+7] = 0.0; j[18+8] = 0.5;
    147:       /* D */
    148:       v[9+0] =  0.0; v[9+1] = -1.0; v[9+2] = -1.0;
    149:       j[27+0] = 0.5; j[27+1] = 0.0; j[27+2] = 0.0;
    150:       j[27+3] = 0.0; j[27+4] = 0.5; j[27+5] = 0.0;
    151:       j[27+6] = 0.0; j[27+7] = 0.0; j[27+8] = 0.5;
    152:       /* E */
    153:       v[12+0] = -1.0; v[12+1] = -1.0; v[12+2] =  0.0;
    154:       j[36+0] =  0.5; j[36+1] =  0.0; j[36+2] =  0.0;
    155:       j[36+3] =  0.0; j[36+4] =  0.5; j[36+5] =  0.0;
    156:       j[36+6] =  0.0; j[36+7] =  0.0; j[36+8] =  0.5;
    157:       /* F */
    158:       v[15+0] =  0.0; v[15+1] = -1.0; v[15+2] =  0.0;
    159:       j[45+0] =  0.5; j[45+1] =  0.0; j[45+2] =  0.0;
    160:       j[45+3] =  0.0; j[45+4] =  0.5; j[45+5] =  0.0;
    161:       j[45+6] =  0.0; j[45+7] =  0.0; j[45+8] =  0.5;
    162:       /* G */
    163:       v[18+0] =  0.0; v[18+1] =  0.0; v[18+2] =  0.0;
    164:       j[54+0] =  0.5; j[54+1] =  0.0; j[54+2] =  0.0;
    165:       j[54+3] =  0.0; j[54+4] =  0.5; j[54+5] =  0.0;
    166:       j[54+6] =  0.0; j[54+7] =  0.0; j[54+8] =  0.5;
    167:       /* H */
    168:       v[21+0] = -1.0; v[21+1] =  0.0; v[21+2] =  0.0;
    169:       j[63+0] =  0.5; j[63+1] =  0.0; j[63+2] =  0.0;
    170:       j[63+3] =  0.0; j[63+4] =  0.5; j[63+5] =  0.0;
    171:       j[63+6] =  0.0; j[63+7] =  0.0; j[63+8] =  0.5;
    172:       for (s = 0; s < 8; ++s) {
    173:         DMPlex_Det3D_Internal(&detJ, &j[s*dim*dim]);
    174:         DMPlex_Invert3D_Internal(&invj[s*dim*dim], &j[s*dim*dim], detJ);
    175:       }
    176:     }
    177:   default:
    178:     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %D", refiner);
    179:   }
    180:   if (v0) {*v0 = v; *jac = j; *invjac = invj;}
    181:   return(0);
    182: }

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

    189:   PetscFree3(*v0,*jac,*invjac);
    190:   return(0);
    191: }

    193: /* Should this be here or in the DualSpace somehow? */
    194: PetscErrorCode CellRefinerInCellTest_Internal(CellRefiner refiner, const PetscReal point[], PetscBool *inside)
    195: {
    196:   PetscReal sum = 0.0;
    197:   PetscInt  d;

    200:   *inside = PETSC_TRUE;
    201:   switch (refiner) {
    202:   case REFINER_NOOP: break;
    203:   case REFINER_SIMPLEX_2D:
    204:     for (d = 0; d < 2; ++d) {
    205:       if (point[d] < -1.0) {*inside = PETSC_FALSE; break;}
    206:       sum += point[d];
    207:     }
    208:     if (sum > 1.0e-10) {*inside = PETSC_FALSE; break;}
    209:     break;
    210:   case REFINER_HEX_2D:
    211:     for (d = 0; d < 2; ++d) if ((point[d] < -1.00000000001) || (point[d] > 1.000000000001)) {*inside = PETSC_FALSE; break;}
    212:     break;
    213:   default:
    214:     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %D", refiner);
    215:   }
    216:   return(0);
    217: }

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

    225:   DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);
    226:   DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);
    227:   DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);
    228:   DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);
    229:   DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);
    230:   switch (refiner) {
    231:   case REFINER_NOOP:
    232:     break;
    233:   case REFINER_SIMPLEX_1D:
    234:     depthSize[0] = vEnd - vStart + cEnd - cStart;         /* Add a vertex on every cell. */
    235:     depthSize[1] = 2*(cEnd - cStart);                     /* Split every cell in 2. */
    236:     break;
    237:   case REFINER_SIMPLEX_2D:
    238:     depthSize[0] = vEnd - vStart + fEnd - fStart;         /* Add a vertex on every face */
    239:     depthSize[1] = 2*(fEnd - fStart) + 3*(cEnd - cStart); /* Every face is split into 2 faces and 3 faces are added for each cell */
    240:     depthSize[2] = 4*(cEnd - cStart);                     /* Every cell split into 4 cells */
    241:     break;
    242:   case REFINER_HYBRID_SIMPLEX_2D:
    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:     depthSize[0] = vEnd - vStart + fMax - fStart;                                         /* Add a vertex on every face, but not hybrid faces */
    246:     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 */
    247:     depthSize[2] = 4*(cMax - cStart) + 2*(cEnd - cMax);                                   /* Interior cells split into 4 cells, hybrid cells split into 2 cells */
    248:     break;
    249:   case REFINER_SIMPLEX_TO_HEX_2D:
    250:     depthSize[0] = vEnd - vStart + fEnd - fStart + cEnd - cStart; /* Add a vertex on every face and cell */
    251:     depthSize[1] = 2*(fEnd - fStart) + 3*(cEnd - cStart);         /* Every face is split into 2 faces and 3 faces are added for each cell */
    252:     depthSize[2] = 3*(cEnd - cStart);                             /* Every cell split into 3 cells */
    253:     break;
    254:   case REFINER_HYBRID_SIMPLEX_TO_HEX_2D:
    255:     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
    256:     depthSize[0] = vEnd - vStart + fEnd - fStart + cEnd - cStart;           /* Add a vertex on every face and cell */
    257:     depthSize[1] = 2*(fEnd - fStart) + 3*(cMax - cStart) + 4*(cEnd - cMax); /* Every face is split into 2 faces and 3 faces are added for each cell. 4 for each hybrid cell */
    258:     depthSize[2] = 3*(cMax - cStart) + 4*(cEnd - cMax);                     /* Every cell split into 3 cells, hybrid cells split in 4 */
    259:     break;
    260:   case REFINER_HEX_2D:
    261:     depthSize[0] = vEnd - vStart + fEnd - fStart + cEnd - cStart; /* Add a vertex on every face and cell */
    262:     depthSize[1] = 2*(fEnd - fStart) + 4*(cEnd - cStart);         /* Every face is split into 2 faces and 4 faces are added for each cell */
    263:     depthSize[2] = 4*(cEnd - cStart);                             /* Every cell split into 4 cells */
    264:     break;
    265:   case REFINER_HYBRID_HEX_2D:
    266:     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
    267:     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
    268:     /* Quadrilateral */
    269:     depthSize[0] = vEnd - vStart + fMax - fStart + cMax - cStart;                 /* Add a vertex on every face and cell */
    270:     depthSize[1] = 2*(fMax - fStart) + 4*(cMax - cStart);                         /* Every face is split into 2 faces, and 4 faces are added for each cell */
    271:     depthSize[2] = 4*(cMax - cStart);                                             /* Every cell split into 4 cells */
    272:     /* Segment Prisms */
    273:     depthSize[0] += 0;                                                            /* No hybrid vertices */
    274:     depthSize[1] +=   (fEnd - fMax)  +   (cEnd - cMax);                           /* Every hybrid face remains and 1 faces is added for each hybrid cell */
    275:     depthSize[2] += 2*(cEnd - cMax);                                              /* Every hybrid cell split into 2 cells */
    276:     break;
    277:   case REFINER_SIMPLEX_3D:
    278:     depthSize[0] =    vEnd - vStart  +    eEnd - eStart;                    /* Add a vertex on every edge */
    279:     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 */
    280:     depthSize[2] = 4*(fEnd - fStart) + 8*(cEnd - cStart);                   /* Every face split into 4 faces and 8 faces are added for each cell */
    281:     depthSize[3] = 8*(cEnd - cStart);                                       /* Every cell split into 8 cells */
    282:     break;
    283:   case REFINER_HYBRID_SIMPLEX_3D:
    284:     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
    285:     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
    286:     if (eMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No edge maximum specified in hybrid mesh");
    287:     /* Tetrahedra */
    288:     depthSize[0]  =    vEnd - vStart  +    eMax - eStart;                    /* Add a vertex on every interior edge */
    289:     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 */
    290:     depthSize[2]  = 4*(fMax - fStart) + 8*(cMax - cStart);                   /* Every interior face split into 4 faces, 8 faces added for each interior cell */
    291:     depthSize[3]  = 8*(cMax - cStart);                                       /* Every interior cell split into 8 cells */
    292:     /* Triangular Prisms */
    293:     depthSize[0] += 0;                                                       /* No hybrid vertices */
    294:     depthSize[1] +=   (eEnd - eMax)   +   (fEnd - fMax);                     /* Every hybrid edge remains, 1 edge for every hybrid face */
    295:     depthSize[2] += 2*(fEnd - fMax)   + 3*(cEnd - cMax);                     /* Every hybrid face split into 2 faces and 3 faces are added for each hybrid cell */
    296:     depthSize[3] += 4*(cEnd - cMax);                                         /* Every hybrid cell split into 4 cells */
    297:     break;
    298:   case REFINER_SIMPLEX_TO_HEX_3D:
    299:     depthSize[0] = vEnd - vStart + fEnd - fStart + eEnd - eStart + cEnd - cStart; /* Add a vertex on every face, edge and cell */
    300:     depthSize[1] = 2*(eEnd - eStart) + 3*(fEnd - fStart) + 4*(cEnd - cStart);     /* Every edge is split into 2 edges, 3 edges are added for each face, and 4 for each cell */
    301:     depthSize[2] = 3*(fEnd - fStart) + 6*(cEnd - cStart);                         /* Every face is split into 3 faces and 6 faces are added for each cell */
    302:     depthSize[3] = 4*(cEnd - cStart);                                             /* Every cell split into 4 cells */
    303:     break;
    304:   case REFINER_HYBRID_SIMPLEX_TO_HEX_3D:
    305:     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
    306:     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
    307:     if (eMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No edge maximum specified in hybrid mesh");
    308:     /* Tetrahedra */
    309:     depthSize[0]  =    vEnd - vStart  +    eMax - eStart  + fMax - fStart + cMax - cStart; /* Add a vertex on every interior edge, face and cell */
    310:     depthSize[1]  = 2*(eMax - eStart) + 3*(fMax - fStart) + 4*(cMax - cStart);             /* Every interior edge split into 2 edges, 3 edges added for each interior face, 4 edges for each interior cell */
    311:     depthSize[2]  = 3*(fMax - fStart) + 6*(cMax - cStart);                                 /* Every interior face split into 3 faces, 6 faces added for each interior cell */
    312:     depthSize[3]  = 4*(cMax - cStart);                                                     /* Every interior cell split into 8 cells */
    313:     /* Triangular Prisms */
    314:     depthSize[0] += 0;                                                 /* No hybrid vertices */
    315:     depthSize[1] +=   (eEnd - eMax) +   (fEnd - fMax) + (cEnd - cMax); /* Every hybrid edge remains, 1 edge for every hybrid face and cell */
    316:     depthSize[2] += 2*(fEnd - fMax) + 3*(cEnd - cMax);                 /* Every hybrid face split into 2 faces and 3 faces are added for each hybrid cell */
    317:     depthSize[3] += 3*(cEnd - cMax);                                   /* Every hybrid cell split into 3 cells */
    318:     break;
    319:   case REFINER_HEX_3D:
    320:     depthSize[0] = vEnd - vStart + eEnd - eStart + fEnd - fStart + cEnd - cStart; /* Add a vertex on every edge, face and cell */
    321:     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 */
    322:     depthSize[2] = 4*(fEnd - fStart) + 12*(cEnd - cStart);                        /* Every face is split into 4 faces, and 12 faces are added for each cell */
    323:     depthSize[3] = 8*(cEnd - cStart);                                             /* Every cell split into 8 cells */
    324:     break;
    325:   case REFINER_HYBRID_HEX_3D:
    326:     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
    327:     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
    328:     if (eMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No edge maximum specified in hybrid mesh");
    329:     /* Hexahedra */
    330:     depthSize[0] = vEnd - vStart + eMax - eStart + fMax - fStart + cMax - cStart; /* Add a vertex on every edge, face and cell */
    331:     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 */
    332:     depthSize[2] = 4*(fMax - fStart) + 12*(cMax - cStart);                        /* Every face is split into 4 faces, and 12 faces are added for each cell */
    333:     depthSize[3] = 8*(cMax - cStart);                                             /* Every cell split into 8 cells */
    334:     /* Quadrilateral Prisms */
    335:     depthSize[0] += 0;                                                            /* No hybrid vertices */
    336:     depthSize[1] +=   (eEnd - eMax)   +   (fEnd - fMax)   +   (cEnd - cMax);      /* Every hybrid edge remains, 1 edge for every hybrid face and hybrid cell */
    337:     depthSize[2] += 2*(fEnd - fMax)   + 4*(cEnd - cMax);                          /* Every hybrid face split into 2 faces and 4 faces are added for each hybrid cell */
    338:     depthSize[3] += 4*(cEnd - cMax);                                              /* Every hybrid cell split into 4 cells */
    339:     break;
    340:   default:
    341:     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %D", refiner);
    342:   }
    343:   return(0);
    344: }

    346: /* Return triangle edge for orientation o, if it is r for o == 0 */
    347: PETSC_STATIC_INLINE PetscInt GetTriEdge_Static(PetscInt o, PetscInt r) {
    348:   return (o < 0 ? 2-(o+r) : o+r)%3;
    349: }
    350: PETSC_STATIC_INLINE PetscInt GetTriEdgeInverse_Static(PetscInt o, PetscInt s) {
    351:   return (o < 0 ? 2-(o+s) : 3+s-o)%3;
    352: }

    354: /* Return triangle subface for orientation o, if it is r for o == 0 */
    355: PETSC_STATIC_INLINE PetscInt GetTriSubface_Static(PetscInt o, PetscInt r) {
    356:   return (o < 0 ? 3-(o+r) : o+r)%3;
    357: }
    358: PETSC_STATIC_INLINE PetscInt GetTriSubfaceInverse_Static(PetscInt o, PetscInt s) {
    359:   return (o < 0 ? 3-(o+s) : 3+s-o)%3;
    360: }

    362: /* Return the interior edge number connecting the midpoints of the triangle edges r
    363:    and r+1 in the transitive closure for triangle orientation o */
    364: PETSC_STATIC_INLINE PetscInt GetTriMidEdge_Static(PetscInt o, PetscInt r) {
    365:   return (o < 0 ? 1-(o+r) : o+r)%3;
    366: }
    367: PETSC_STATIC_INLINE PetscInt GetTriMidEdgeInverse_Static(PetscInt o, PetscInt s) {
    368:   return (o < 0 ? 1-(o+s) : 3+s-o)%3;
    369: }

    371: /* Return the interior edge number connecting the midpoint of the triangle edge r
    372:    (in the transitive closure) and the vertex in the interior of the face for triangle orientation o */
    373: PETSC_STATIC_INLINE PetscInt GetTriInteriorEdge_Static(PetscInt o, PetscInt r) {
    374:   return (o < 0 ? 2-(o+r) : o+r)%3;
    375: }
    376: PETSC_STATIC_INLINE PetscInt GetTriInteriorEdgeInverse_Static(PetscInt o, PetscInt s) {
    377:   return (o < 0 ? 2-(o+s) : 3+s-o)%3;
    378: }

    380: /* Return quad edge for orientation o, if it is r for o == 0 */
    381: PETSC_STATIC_INLINE PetscInt GetQuadEdge_Static(PetscInt o, PetscInt r) {
    382:   return (o < 0 ? 3-(o+r) : o+r)%4;
    383: }
    384: PETSC_STATIC_INLINE PetscInt GetQuadEdgeInverse_Static(PetscInt o, PetscInt s) {
    385:   return (o < 0 ? 3-(o+s) : 4+s-o)%4;
    386: }

    388: /* Return quad subface for orientation o, if it is r for o == 0 */
    389: PETSC_STATIC_INLINE PetscInt GetQuadSubface_Static(PetscInt o, PetscInt r) {
    390:   return (o < 0 ? 4-(o+r) : o+r)%4;
    391: }
    392: PETSC_STATIC_INLINE PetscInt GetQuadSubfaceInverse_Static(PetscInt o, PetscInt s) {
    393:   return (o < 0 ? 4-(o+s) : 4+s-o)%4;
    394: }

    396: static PetscErrorCode DMLabelSetStratumBounds(DMLabel label, PetscInt value, PetscInt cStart, PetscInt cEnd)
    397: {
    398:   IS             cIS;

    402:   ISCreateStride(PETSC_COMM_SELF, cEnd - cStart, cStart, 1, &cIS);
    403:   DMLabelSetStratumIS(label, value, cIS);
    404:   ISDestroy(&cIS);
    405:   return(0);
    406: }

    408: static PetscErrorCode CellRefinerSetConeSizes(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
    409: {
    410:   PetscInt       depth, cStart, cStartNew, cEnd, cEndNew, cMax, c, vStart, vStartNew, vEnd, vEndNew, vMax, v, fStart, fStartNew, fEnd, fEndNew, fMax, f, eStart, eStartNew, eEnd, eEndNew, eMax, e, r;
    411:   DMLabel        depthLabel;

    415:   DMPlexGetDepth(dm, &depth);
    416:   DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);
    417:   DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);
    418:   DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);
    419:   DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);
    420:   DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);
    421:   GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);
    422:   GetDepthEnd_Private(depth, depthSize, &cEndNew, &fEndNew, &eEndNew, &vEndNew);
    423:   DMCreateLabel(rdm,"depth");
    424:   DMPlexGetDepthLabel(rdm,&depthLabel);
    425:   DMLabelSetStratumBounds(depthLabel, 0, vStartNew, vEndNew);
    426:   if (depth > 2) DMLabelSetStratumBounds(depthLabel, 1, eStartNew, eEndNew);
    427:   if (depth > 1) DMLabelSetStratumBounds(depthLabel, depth - 1, fStartNew, fEndNew);
    428:   if (depth > 0) DMLabelSetStratumBounds(depthLabel, depth, cStartNew, cEndNew);
    429:   {
    430:     DM_Plex *plex = (DM_Plex *) rdm->data;
    431:     DMLabelGetState(depthLabel, &plex->depthState);
    432:   }
    433:   if (!refiner) return(0);
    434:   switch (refiner) {
    435:   case REFINER_SIMPLEX_1D:
    436:     /* All cells have 2 vertices */
    437:     for (c = cStart; c < cEnd; ++c) {
    438:       for (r = 0; r < 2; ++r) {
    439:         const PetscInt newp = cStartNew + (c - cStart)*2 + r;

    441:         DMPlexSetConeSize(rdm, newp, 2);
    442:       }
    443:     }
    444:     /* Old vertices have identical supports */
    445:     for (v = vStart; v < vEnd; ++v) {
    446:       const PetscInt newp = vStartNew + (v - vStart);
    447:       PetscInt       size;

    449:       DMPlexGetSupportSize(dm, v, &size);
    450:       DMPlexSetSupportSize(rdm, newp, size);
    451:     }
    452:     /* Cell vertices have support 2 */
    453:     for (c = cStart; c < cEnd; ++c) {
    454:       const PetscInt newp = vStartNew + (vEnd - vStart) + (c - cStart);

    456:       DMPlexSetSupportSize(rdm, newp, 2);
    457:     }
    458:     break;
    459:   case REFINER_SIMPLEX_2D:
    460:     /* All cells have 3 faces */
    461:     for (c = cStart; c < cEnd; ++c) {
    462:       for (r = 0; r < 4; ++r) {
    463:         const PetscInt newp = (c - cStart)*4 + r;

    465:         DMPlexSetConeSize(rdm, newp, 3);
    466:       }
    467:     }
    468:     /* Split faces have 2 vertices and the same cells as the parent */
    469:     for (f = fStart; f < fEnd; ++f) {
    470:       for (r = 0; r < 2; ++r) {
    471:         const PetscInt newp = fStartNew + (f - fStart)*2 + r;
    472:         PetscInt       size;

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

    484:         DMPlexSetConeSize(rdm, newp, 2);
    485:         DMPlexSetSupportSize(rdm, newp, 2);
    486:       }
    487:     }
    488:     /* Old vertices have identical supports */
    489:     for (v = vStart; v < vEnd; ++v) {
    490:       const PetscInt newp = vStartNew + (v - vStart);
    491:       PetscInt       size;

    493:       DMPlexGetSupportSize(dm, v, &size);
    494:       DMPlexSetSupportSize(rdm, newp, size);
    495:     }
    496:     /* Face vertices have 2 + cells*2 supports */
    497:     for (f = fStart; f < fEnd; ++f) {
    498:       const PetscInt newp = vStartNew + (vEnd - vStart) + (f - fStart);
    499:       PetscInt       size;

    501:       DMPlexGetSupportSize(dm, f, &size);
    502:       DMPlexSetSupportSize(rdm, newp, 2 + size*2);
    503:     }
    504:     break;
    505:   case REFINER_SIMPLEX_TO_HEX_2D:
    506:     /* All cells have 4 faces */
    507:     for (c = cStart; c < cEnd; ++c) {
    508:       for (r = 0; r < 3; ++r) {
    509:         const PetscInt newp = (c - cStart)*3 + r;

    511:         DMPlexSetConeSize(rdm, newp, 4);
    512:       }
    513:     }
    514:     /* Split faces have 2 vertices and the same cells as the parent */
    515:     for (f = fStart; f < fEnd; ++f) {
    516:       for (r = 0; r < 2; ++r) {
    517:         const PetscInt newp = fStartNew + (f - fStart)*2 + r;
    518:         PetscInt       size;

    520:         DMPlexSetConeSize(rdm, newp, 2);
    521:         DMPlexGetSupportSize(dm, f, &size);
    522:         DMPlexSetSupportSize(rdm, newp, size);
    523:       }
    524:     }
    525:     /* Interior faces have 2 vertices and 2 cells */
    526:     for (c = cStart; c < cEnd; ++c) {
    527:       for (r = 0; r < 3; ++r) {
    528:         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*3 + r;

    530:         DMPlexSetConeSize(rdm, newp, 2);
    531:         DMPlexSetSupportSize(rdm, newp, 2);
    532:       }
    533:     }
    534:     /* Old vertices have identical supports */
    535:     for (v = vStart; v < vEnd; ++v) {
    536:       const PetscInt newp = vStartNew + (v - vStart);
    537:       PetscInt       size;

    539:       DMPlexGetSupportSize(dm, v, &size);
    540:       DMPlexSetSupportSize(rdm, newp, size);
    541:     }
    542:     /* Split-face vertices have cells + 2 supports */
    543:     for (f = fStart; f < fEnd; ++f) {
    544:       const PetscInt newp = vStartNew + (vEnd - vStart) + (f - fStart);
    545:       PetscInt       size;

    547:       DMPlexGetSupportSize(dm, f, &size);
    548:       DMPlexSetSupportSize(rdm, newp, size + 2);
    549:     }
    550:     /* Interior vertices have 3 supports */
    551:     for (c = cStart; c < cEnd; ++c) {
    552:       const PetscInt newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + c - cStart;

    554:       DMPlexSetSupportSize(rdm, newp, 3);
    555:     }
    556:     break;
    557:   case REFINER_HYBRID_SIMPLEX_TO_HEX_2D:
    558:     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
    559:     /* the mesh is no longer hybrid */
    560:     cMax = PetscMin(cEnd, cMax);
    561:     /* All cells have 4 faces */
    562:     for (c = cStart; c < cMax; ++c) {
    563:       for (r = 0; r < 3; ++r) {
    564:         const PetscInt newp = (c - cStart)*3 + r;

    566:         DMPlexSetConeSize(rdm, newp, 4);
    567:       }
    568:     }
    569:     for (c = cMax; c < cEnd; ++c) {
    570:       for (r = 0; r < 4; ++r) {
    571:         const PetscInt newp = (cMax - cStart)*3 + (c - cMax)*4 + r;

    573:         DMPlexSetConeSize(rdm, newp, 4);
    574:       }
    575:     }
    576:     /* Split faces have 2 vertices and the same cells as the parent */
    577:     for (f = fStart; f < fEnd; ++f) {
    578:       for (r = 0; r < 2; ++r) {
    579:         const PetscInt newp = fStartNew + (f - fStart)*2 + r;
    580:         PetscInt       size;

    582:         DMPlexSetConeSize(rdm, newp, 2);
    583:         DMPlexGetSupportSize(dm, f, &size);
    584:         DMPlexSetSupportSize(rdm, newp, size);
    585:       }
    586:     }
    587:     /* Interior faces have 2 vertices and 2 cells */
    588:     for (c = cStart; c < cMax; ++c) {
    589:       for (r = 0; r < 3; ++r) {
    590:         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*3 + r;

    592:         DMPlexSetConeSize(rdm, newp, 2);
    593:         DMPlexSetSupportSize(rdm, newp, 2);
    594:       }
    595:     }
    596:     /* Hybrid interior faces have 2 vertices and 2 cells */
    597:     for (c = cMax; c < cEnd; ++c) {
    598:       for (r = 0; r < 4; ++r) {
    599:         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (cMax - cStart)*3 + (c - cMax)*4 + r;

    601:         DMPlexSetConeSize(rdm, newp, 2);
    602:         DMPlexSetSupportSize(rdm, newp, 2);
    603:       }
    604:     }
    605:     /* Old vertices have identical supports */
    606:     for (v = vStart; v < vEnd; ++v) {
    607:       const PetscInt newp = vStartNew + (v - vStart);
    608:       PetscInt       size;

    610:       DMPlexGetSupportSize(dm, v, &size);
    611:       DMPlexSetSupportSize(rdm, newp, size);
    612:     }
    613:     /* Split-face vertices have cells + 2 supports */
    614:     for (f = fStart; f < fEnd; ++f) {
    615:       const PetscInt newp = vStartNew + (vEnd - vStart) + (f - fStart);
    616:       PetscInt       size;

    618:       DMPlexGetSupportSize(dm, f, &size);
    619:       DMPlexSetSupportSize(rdm, newp, size + 2);
    620:     }
    621:     /* Interior vertices have 3 supports */
    622:     for (c = cStart; c < cMax; ++c) {
    623:       const PetscInt newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + c - cStart;

    625:       DMPlexSetSupportSize(rdm, newp, 3);
    626:     }
    627:     /* Hybrid interior vertices have 4 supports */
    628:     for (c = cMax; c < cEnd; ++c) {
    629:       const PetscInt newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + c - cStart;

    631:       DMPlexSetSupportSize(rdm, newp, 4);
    632:     }
    633:     break;
    634:   case REFINER_HEX_2D:
    635:     /* All cells have 4 faces */
    636:     for (c = cStart; c < cEnd; ++c) {
    637:       for (r = 0; r < 4; ++r) {
    638:         const PetscInt newp = cStartNew + (c - cStart)*4 + r;

    640:         DMPlexSetConeSize(rdm, newp, 4);
    641:       }
    642:     }
    643:     /* Split faces have 2 vertices and the same cells as the parent */
    644:     for (f = fStart; f < fEnd; ++f) {
    645:       for (r = 0; r < 2; ++r) {
    646:         const PetscInt newp = fStartNew + (f - fStart)*2 + r;
    647:         PetscInt       size;

    649:         DMPlexSetConeSize(rdm, newp, 2);
    650:         DMPlexGetSupportSize(dm, f, &size);
    651:         DMPlexSetSupportSize(rdm, newp, size);
    652:       }
    653:     }
    654:     /* Interior faces have 2 vertices and 2 cells */
    655:     for (c = cStart; c < cEnd; ++c) {
    656:       for (r = 0; r < 4; ++r) {
    657:         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*4 + r;

    659:         DMPlexSetConeSize(rdm, newp, 2);
    660:         DMPlexSetSupportSize(rdm, newp, 2);
    661:       }
    662:     }
    663:     /* Old vertices have identical supports */
    664:     for (v = vStart; v < vEnd; ++v) {
    665:       const PetscInt newp = vStartNew + (v - vStart);
    666:       PetscInt       size;

    668:       DMPlexGetSupportSize(dm, v, &size);
    669:       DMPlexSetSupportSize(rdm, newp, size);
    670:     }
    671:     /* Face vertices have 2 + cells supports */
    672:     for (f = fStart; f < fEnd; ++f) {
    673:       const PetscInt newp = vStartNew + (vEnd - vStart) + (f - fStart);
    674:       PetscInt       size;

    676:       DMPlexGetSupportSize(dm, f, &size);
    677:       DMPlexSetSupportSize(rdm, newp, 2 + size);
    678:     }
    679:     /* Cell vertices have 4 supports */
    680:     for (c = cStart; c < cEnd; ++c) {
    681:       const PetscInt newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (c - cStart);

    683:       DMPlexSetSupportSize(rdm, newp, 4);
    684:     }
    685:     break;
    686:   case REFINER_HYBRID_SIMPLEX_2D:
    687:     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
    688:     cMax = PetscMin(cEnd, cMax);
    689:     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
    690:     fMax = PetscMin(fEnd, fMax);
    691:     DMPlexSetHybridBounds(rdm, cStartNew + (cMax - cStart)*4, fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3, PETSC_DETERMINE, PETSC_DETERMINE);
    692:     /* Interior cells have 3 faces */
    693:     for (c = cStart; c < cMax; ++c) {
    694:       for (r = 0; r < 4; ++r) {
    695:         const PetscInt newp = cStartNew + (c - cStart)*4 + r;

    697:         DMPlexSetConeSize(rdm, newp, 3);
    698:       }
    699:     }
    700:     /* Hybrid cells have 4 faces */
    701:     for (c = cMax; c < cEnd; ++c) {
    702:       for (r = 0; r < 2; ++r) {
    703:         const PetscInt newp = cStartNew + (cMax - cStart)*4 + (c - cMax)*2 + r;

    705:         DMPlexSetConeSize(rdm, newp, 4);
    706:       }
    707:     }
    708:     /* Interior split faces have 2 vertices and the same cells as the parent */
    709:     for (f = fStart; f < fMax; ++f) {
    710:       for (r = 0; r < 2; ++r) {
    711:         const PetscInt newp = fStartNew + (f - fStart)*2 + r;
    712:         PetscInt       size;

    714:         DMPlexSetConeSize(rdm, newp, 2);
    715:         DMPlexGetSupportSize(dm, f, &size);
    716:         DMPlexSetSupportSize(rdm, newp, size);
    717:       }
    718:     }
    719:     /* Interior cell faces have 2 vertices and 2 cells */
    720:     for (c = cStart; c < cMax; ++c) {
    721:       for (r = 0; r < 3; ++r) {
    722:         const PetscInt newp = fStartNew + (fMax - fStart)*2 + (c - cStart)*3 + r;

    724:         DMPlexSetConeSize(rdm, newp, 2);
    725:         DMPlexSetSupportSize(rdm, newp, 2);
    726:       }
    727:     }
    728:     /* Hybrid faces have 2 vertices and the same cells */
    729:     for (f = fMax; f < fEnd; ++f) {
    730:       const PetscInt newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (f - fMax);
    731:       PetscInt       size;

    733:       DMPlexSetConeSize(rdm, newp, 2);
    734:       DMPlexGetSupportSize(dm, f, &size);
    735:       DMPlexSetSupportSize(rdm, newp, size);
    736:     }
    737:     /* Hybrid cell faces have 2 vertices and 2 cells */
    738:     for (c = cMax; c < cEnd; ++c) {
    739:       const PetscInt newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (fEnd - fMax) + (c - cMax);

    741:       DMPlexSetConeSize(rdm, newp, 2);
    742:       DMPlexSetSupportSize(rdm, newp, 2);
    743:     }
    744:     /* Old vertices have identical supports */
    745:     for (v = vStart; v < vEnd; ++v) {
    746:       const PetscInt newp = vStartNew + (v - vStart);
    747:       PetscInt       size;

    749:       DMPlexGetSupportSize(dm, v, &size);
    750:       DMPlexSetSupportSize(rdm, newp, size);
    751:     }
    752:     /* Face vertices have 2 + (2 interior, 1 hybrid) supports */
    753:     for (f = fStart; f < fMax; ++f) {
    754:       const PetscInt newp = vStartNew + (vEnd - vStart) + (f - fStart);
    755:       const PetscInt *support;
    756:       PetscInt       size, newSize = 2, s;

    758:       DMPlexGetSupportSize(dm, f, &size);
    759:       DMPlexGetSupport(dm, f, &support);
    760:       for (s = 0; s < size; ++s) {
    761:         if (support[s] >= cMax) newSize += 1;
    762:         else newSize += 2;
    763:       }
    764:       DMPlexSetSupportSize(rdm, newp, newSize);
    765:     }
    766:     break;
    767:   case REFINER_HYBRID_HEX_2D:
    768:     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
    769:     cMax = PetscMin(cEnd, cMax);
    770:     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
    771:     fMax = PetscMin(fEnd, fMax);
    772:     DMPlexSetHybridBounds(rdm, cStartNew + (cMax - cStart)*4, fStartNew + (fMax - fStart)*2 + (cMax - cStart)*4, PETSC_DETERMINE, PETSC_DETERMINE);
    773:     /* Interior cells have 4 faces */
    774:     for (c = cStart; c < cMax; ++c) {
    775:       for (r = 0; r < 4; ++r) {
    776:         const PetscInt newp = cStartNew + (c - cStart)*4 + r;

    778:         DMPlexSetConeSize(rdm, newp, 4);
    779:       }
    780:     }
    781:     /* Hybrid cells have 4 faces */
    782:     for (c = cMax; c < cEnd; ++c) {
    783:       for (r = 0; r < 2; ++r) {
    784:         const PetscInt newp = cStartNew + (cMax - cStart)*4 + (c - cMax)*2 + r;

    786:         DMPlexSetConeSize(rdm, newp, 4);
    787:       }
    788:     }
    789:     /* Interior split faces have 2 vertices and the same cells as the parent */
    790:     for (f = fStart; f < fMax; ++f) {
    791:       for (r = 0; r < 2; ++r) {
    792:         const PetscInt newp = fStartNew + (f - fStart)*2 + r;
    793:         PetscInt       size;

    795:         DMPlexSetConeSize(rdm, newp, 2);
    796:         DMPlexGetSupportSize(dm, f, &size);
    797:         DMPlexSetSupportSize(rdm, newp, size);
    798:       }
    799:     }
    800:     /* Interior cell faces have 2 vertices and 2 cells */
    801:     for (c = cStart; c < cMax; ++c) {
    802:       for (r = 0; r < 4; ++r) {
    803:         const PetscInt newp = fStartNew + (fMax - fStart)*2 + (c - cStart)*4 + r;

    805:         DMPlexSetConeSize(rdm, newp, 2);
    806:         DMPlexSetSupportSize(rdm, newp, 2);
    807:       }
    808:     }
    809:     /* Hybrid faces have 2 vertices and the same cells */
    810:     for (f = fMax; f < fEnd; ++f) {
    811:       const PetscInt newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*4 + (f - fMax);
    812:       PetscInt       size;

    814:       DMPlexSetConeSize(rdm, newp, 2);
    815:       DMPlexGetSupportSize(dm, f, &size);
    816:       DMPlexSetSupportSize(rdm, newp, size);
    817:     }
    818:     /* Hybrid cell faces have 2 vertices and 2 cells */
    819:     for (c = cMax; c < cEnd; ++c) {
    820:       const PetscInt newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*4 + (fEnd - fMax) + (c - cMax);

    822:       DMPlexSetConeSize(rdm, newp, 2);
    823:       DMPlexSetSupportSize(rdm, newp, 2);
    824:     }
    825:     /* Old vertices have identical supports */
    826:     for (v = vStart; v < vEnd; ++v) {
    827:       const PetscInt newp = vStartNew + (v - vStart);
    828:       PetscInt       size;

    830:       DMPlexGetSupportSize(dm, v, &size);
    831:       DMPlexSetSupportSize(rdm, newp, size);
    832:     }
    833:     /* Face vertices have 2 + cells supports */
    834:     for (f = fStart; f < fMax; ++f) {
    835:       const PetscInt newp = vStartNew + (vEnd - vStart) + (f - fStart);
    836:       PetscInt       size;

    838:       DMPlexGetSupportSize(dm, f, &size);
    839:       DMPlexSetSupportSize(rdm, newp, 2 + size);
    840:     }
    841:     /* Cell vertices have 4 supports */
    842:     for (c = cStart; c < cMax; ++c) {
    843:       const PetscInt newp = vStartNew + (vEnd - vStart) + (fMax - fStart) + (c - cStart);

    845:       DMPlexSetSupportSize(rdm, newp, 4);
    846:     }
    847:     break;
    848:   case REFINER_SIMPLEX_3D:
    849:     /* All cells have 4 faces */
    850:     for (c = cStart; c < cEnd; ++c) {
    851:       for (r = 0; r < 8; ++r) {
    852:         const PetscInt newp = cStartNew + (c - cStart)*8 + r;

    854:         DMPlexSetConeSize(rdm, newp, 4);
    855:       }
    856:     }
    857:     /* Split faces have 3 edges and the same cells as the parent */
    858:     for (f = fStart; f < fEnd; ++f) {
    859:       for (r = 0; r < 4; ++r) {
    860:         const PetscInt newp = fStartNew + (f - fStart)*4 + r;
    861:         PetscInt       size;

    863:         DMPlexSetConeSize(rdm, newp, 3);
    864:         DMPlexGetSupportSize(dm, f, &size);
    865:         DMPlexSetSupportSize(rdm, newp, size);
    866:       }
    867:     }
    868:     /* Interior cell faces have 3 edges and 2 cells */
    869:     for (c = cStart; c < cEnd; ++c) {
    870:       for (r = 0; r < 8; ++r) {
    871:         const PetscInt newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*8 + r;

    873:         DMPlexSetConeSize(rdm, newp, 3);
    874:         DMPlexSetSupportSize(rdm, newp, 2);
    875:       }
    876:     }
    877:     /* Split edges have 2 vertices and the same faces */
    878:     for (e = eStart; e < eEnd; ++e) {
    879:       for (r = 0; r < 2; ++r) {
    880:         const PetscInt newp = eStartNew + (e - eStart)*2 + r;
    881:         PetscInt       size;

    883:         DMPlexSetConeSize(rdm, newp, 2);
    884:         DMPlexGetSupportSize(dm, e, &size);
    885:         DMPlexSetSupportSize(rdm, newp, size);
    886:       }
    887:     }
    888:     /* Face edges have 2 vertices and 2+cells*(1/2) faces */
    889:     for (f = fStart; f < fEnd; ++f) {
    890:       for (r = 0; r < 3; ++r) {
    891:         const PetscInt  newp = eStartNew + (eEnd - eStart)*2 + (f - fStart)*3 + r;
    892:         const PetscInt *cone, *ornt, *support, eint[4] = {1, 0, 2, 0};
    893:         PetscInt        coneSize, c, supportSize, s, er, intFaces = 0;

    895:         DMPlexSetConeSize(rdm, newp, 2);
    896:         DMPlexGetSupportSize(dm, f, &supportSize);
    897:         DMPlexGetSupport(dm, f, &support);
    898:         for (s = 0; s < supportSize; ++s) {
    899:           DMPlexGetConeSize(dm, support[s], &coneSize);
    900:           DMPlexGetCone(dm, support[s], &cone);
    901:           DMPlexGetConeOrientation(dm, support[s], &ornt);
    902:           for (c = 0; c < coneSize; ++c) {if (cone[c] == f) break;}
    903:           /* Here we want to determine whether edge newp contains a vertex which is part of the cross-tet edge */
    904:           er = GetTriMidEdgeInverse_Static(ornt[c], r);
    905:           if (er == eint[c]) {
    906:             intFaces += 1;
    907:           } else {
    908:             intFaces += 2;
    909:           }
    910:         }
    911:         DMPlexSetSupportSize(rdm, newp, 2+intFaces);
    912:       }
    913:     }
    914:     /* Interior cell edges have 2 vertices and 4 faces */
    915:     for (c = cStart; c < cEnd; ++c) {
    916:       const PetscInt newp = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart);

    918:       DMPlexSetConeSize(rdm, newp, 2);
    919:       DMPlexSetSupportSize(rdm, newp, 4);
    920:     }
    921:     /* Old vertices have identical supports */
    922:     for (v = vStart; v < vEnd; ++v) {
    923:       const PetscInt newp = vStartNew + (v - vStart);
    924:       PetscInt       size;

    926:       DMPlexGetSupportSize(dm, v, &size);
    927:       DMPlexSetSupportSize(rdm, newp, size);
    928:     }
    929:     /* Edge vertices have 2 + faces*2 + cells*0/1 supports */
    930:     for (e = eStart; e < eEnd; ++e) {
    931:       const PetscInt newp = vStartNew + (vEnd - vStart) + (e - eStart);
    932:       PetscInt       size, *star = NULL, starSize, s, cellSize = 0;

    934:       DMPlexGetSupportSize(dm, e, &size);
    935:       DMPlexGetTransitiveClosure(dm, e, PETSC_FALSE, &starSize, &star);
    936:       for (s = 0; s < starSize*2; s += 2) {
    937:         const PetscInt *cone, *ornt;
    938:         PetscInt        e01, e23;

    940:         if ((star[s] >= cStart) && (star[s] < cEnd)) {
    941:           /* Check edge 0-1 */
    942:           DMPlexGetCone(dm, star[s], &cone);
    943:           DMPlexGetConeOrientation(dm, star[s], &ornt);
    944:           DMPlexGetCone(dm, cone[0], &cone);
    945:           e01  = cone[GetTriEdge_Static(ornt[0], 0)];
    946:           /* Check edge 2-3 */
    947:           DMPlexGetCone(dm, star[s], &cone);
    948:           DMPlexGetConeOrientation(dm, star[s], &ornt);
    949:           DMPlexGetCone(dm, cone[2], &cone);
    950:           e23  = cone[GetTriEdge_Static(ornt[2], 1)];
    951:           if ((e01 == e) || (e23 == e)) ++cellSize;
    952:         }
    953:       }
    954:       DMPlexRestoreTransitiveClosure(dm, e, PETSC_FALSE, &starSize, &star);
    955:       DMPlexSetSupportSize(rdm, newp, 2 + size*2 + cellSize);
    956:     }
    957:     break;
    958:   case REFINER_HYBRID_SIMPLEX_3D:
    959:     DMPlexSetHybridBounds(rdm, cStartNew + 8*(cMax-cStart), fStartNew + 4*(fMax - fStart) + 8*(cMax - cStart),
    960:                                  eStartNew + 2*(eMax - eStart) + 3*(fMax - fStart) + (cMax - cStart), PETSC_DETERMINE);
    961:     /* Interior cells have 4 faces */
    962:     for (c = cStart; c < cMax; ++c) {
    963:       for (r = 0; r < 8; ++r) {
    964:         const PetscInt newp = cStartNew + (c - cStart)*8 + r;

    966:         DMPlexSetConeSize(rdm, newp, 4);
    967:       }
    968:     }
    969:     /* Hybrid cells have 5 faces */
    970:     for (c = cMax; c < cEnd; ++c) {
    971:       for (r = 0; r < 4; ++r) {
    972:         const PetscInt newp = cStartNew + (cMax - cStart)*8 + (c - cMax)*4 + r;

    974:         DMPlexSetConeSize(rdm, newp, 5);
    975:       }
    976:     }
    977:     /* Interior split faces have 3 edges and the same cells as the parent */
    978:     for (f = fStart; f < fMax; ++f) {
    979:       for (r = 0; r < 4; ++r) {
    980:         const PetscInt newp = fStartNew + (f - fStart)*4 + r;
    981:         PetscInt       size;

    983:         DMPlexSetConeSize(rdm, newp, 3);
    984:         DMPlexGetSupportSize(dm, f, &size);
    985:         DMPlexSetSupportSize(rdm, newp, size);
    986:       }
    987:     }
    988:     /* Interior cell faces have 3 edges and 2 cells */
    989:     for (c = cStart; c < cMax; ++c) {
    990:       for (r = 0; r < 8; ++r) {
    991:         const PetscInt newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*8 + r;

    993:         DMPlexSetConeSize(rdm, newp, 3);
    994:         DMPlexSetSupportSize(rdm, newp, 2);
    995:       }
    996:     }
    997:     /* Hybrid split faces have 4 edges and the same cells as the parent */
    998:     for (f = fMax; f < fEnd; ++f) {
    999:       for (r = 0; r < 2; ++r) {
    1000:         const PetscInt newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (f - fMax)*2 + r;
    1001:         PetscInt       size;

    1003:         DMPlexSetConeSize(rdm, newp, 4);
    1004:         DMPlexGetSupportSize(dm, f, &size);
    1005:         DMPlexSetSupportSize(rdm, newp, size);
    1006:       }
    1007:     }
    1008:     /* Hybrid cells faces have 4 edges and 2 cells */
    1009:     for (c = cMax; c < cEnd; ++c) {
    1010:       for (r = 0; r < 3; ++r) {
    1011:         const PetscInt newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (c - cMax)*3 + r;

    1013:         DMPlexSetConeSize(rdm, newp, 4);
    1014:         DMPlexSetSupportSize(rdm, newp, 2);
    1015:       }
    1016:     }
    1017:     /* Interior split edges have 2 vertices and the same faces */
    1018:     for (e = eStart; e < eMax; ++e) {
    1019:       for (r = 0; r < 2; ++r) {
    1020:         const PetscInt newp = eStartNew + (e - eStart)*2 + r;
    1021:         PetscInt       size;

    1023:         DMPlexSetConeSize(rdm, newp, 2);
    1024:         DMPlexGetSupportSize(dm, e, &size);
    1025:         DMPlexSetSupportSize(rdm, newp, size);
    1026:       }
    1027:     }
    1028:     /* Interior face edges have 2 vertices and 2+cells*(1/2) faces */
    1029:     for (f = fStart; f < fMax; ++f) {
    1030:       for (r = 0; r < 3; ++r) {
    1031:         const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (f - fStart)*3 + r;
    1032:         const PetscInt *cone, *ornt, *support, eint[4] = {1, 0, 2, 0};
    1033:         PetscInt        coneSize, c, supportSize, s, er, intFaces = 0;

    1035:         DMPlexSetConeSize(rdm, newp, 2);
    1036:         DMPlexGetSupportSize(dm, f, &supportSize);
    1037:         DMPlexGetSupport(dm, f, &support);
    1038:         for (s = 0; s < supportSize; ++s) {
    1039:           DMPlexGetConeSize(dm, support[s], &coneSize);
    1040:           DMPlexGetCone(dm, support[s], &cone);
    1041:           DMPlexGetConeOrientation(dm, support[s], &ornt);
    1042:           for (c = 0; c < coneSize; ++c) {if (cone[c] == f) break;}
    1043:           if (support[s] < cMax) {
    1044:             /* Here we want to determine whether edge newp contains a vertex which is part of the cross-tet edge */
    1045:             er = GetTriMidEdgeInverse_Static(ornt[c], r);
    1046:             if (er == eint[c]) {
    1047:               intFaces += 1;
    1048:             } else {
    1049:               intFaces += 2;
    1050:             }
    1051:           } else {
    1052:             intFaces += 1;
    1053:           }
    1054:         }
    1055:         DMPlexSetSupportSize(rdm, newp, 2+intFaces);
    1056:       }
    1057:     }
    1058:     /* Interior cell edges have 2 vertices and 4 faces */
    1059:     for (c = cStart; c < cMax; ++c) {
    1060:       const PetscInt newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart);

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

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

    1079:       DMPlexSetConeSize(rdm, newp, 2);
    1080:       DMPlexGetSupportSize(dm, f, &size);
    1081:       DMPlexSetSupportSize(rdm, newp, 2+2*size);
    1082:     }
    1083:     /* Interior vertices have identical supports */
    1084:     for (v = vStart; v < vEnd; ++v) {
    1085:       const PetscInt newp = vStartNew + (v - vStart);
    1086:       PetscInt       size;

    1088:       DMPlexGetSupportSize(dm, v, &size);
    1089:       DMPlexSetSupportSize(rdm, newp, size);
    1090:     }
    1091:     /* Interior edge vertices have 2 + interior face*2 + hybrid face + cells*0/1 supports */
    1092:     for (e = eStart; e < eMax; ++e) {
    1093:       const PetscInt  newp = vStartNew + (vEnd - vStart) + (e - eStart);
    1094:       const PetscInt *support;
    1095:       PetscInt        size, *star = NULL, starSize, s, faceSize = 0, cellSize = 0;

    1097:       DMPlexGetSupportSize(dm, e, &size);
    1098:       DMPlexGetSupport(dm, e, &support);
    1099:       for (s = 0; s < size; ++s) {
    1100:         if (support[s] < fMax) faceSize += 2;
    1101:         else                   faceSize += 1;
    1102:       }
    1103:       DMPlexGetTransitiveClosure(dm, e, PETSC_FALSE, &starSize, &star);
    1104:       for (s = 0; s < starSize*2; s += 2) {
    1105:         const PetscInt *cone, *ornt;
    1106:         PetscInt        e01, e23;

    1108:         if ((star[s] >= cStart) && (star[s] < cMax)) {
    1109:           /* Check edge 0-1 */
    1110:           DMPlexGetCone(dm, star[s], &cone);
    1111:           DMPlexGetConeOrientation(dm, star[s], &ornt);
    1112:           DMPlexGetCone(dm, cone[0], &cone);
    1113:           e01  = cone[GetTriEdge_Static(ornt[0], 0)];
    1114:           /* Check edge 2-3 */
    1115:           DMPlexGetCone(dm, star[s], &cone);
    1116:           DMPlexGetConeOrientation(dm, star[s], &ornt);
    1117:           DMPlexGetCone(dm, cone[2], &cone);
    1118:           e23  = cone[GetTriEdge_Static(ornt[2], 1)];
    1119:           if ((e01 == e) || (e23 == e)) ++cellSize;
    1120:         }
    1121:       }
    1122:       DMPlexRestoreTransitiveClosure(dm, e, PETSC_FALSE, &starSize, &star);
    1123:       DMPlexSetSupportSize(rdm, newp, 2 + faceSize + cellSize);
    1124:     }
    1125:     break;
    1126:   case REFINER_SIMPLEX_TO_HEX_3D:
    1127:     /* All cells have 6 faces */
    1128:     for (c = cStart; c < cEnd; ++c) {
    1129:       for (r = 0; r < 4; ++r) {
    1130:         const PetscInt newp = cStartNew + (c - cStart)*4 + r;

    1132:         DMPlexSetConeSize(rdm, newp, 6);
    1133:       }
    1134:     }
    1135:     /* Split faces have 4 edges and the same cells as the parent */
    1136:     for (f = fStart; f < fEnd; ++f) {
    1137:       for (r = 0; r < 3; ++r) {
    1138:         const PetscInt newp = fStartNew + (f - fStart)*3 + r;
    1139:         PetscInt       size;

    1141:         DMPlexSetConeSize(rdm, newp, 4);
    1142:         DMPlexGetSupportSize(dm, f, &size);
    1143:         DMPlexSetSupportSize(rdm, newp, size);
    1144:       }
    1145:     }
    1146:     /* Interior cell faces have 4 edges and 2 cells */
    1147:     for (c = cStart; c < cEnd; ++c) {
    1148:       for (r = 0; r < 6; ++r) {
    1149:         const PetscInt newp = fStartNew + (fEnd - fStart)*3 + (c - cStart)*6 + r;

    1151:         DMPlexSetConeSize(rdm, newp, 4);
    1152:         DMPlexSetSupportSize(rdm, newp, 2);
    1153:       }
    1154:     }
    1155:     /* Split edges have 2 vertices and the same faces */
    1156:     for (e = eStart; e < eEnd; ++e) {
    1157:       for (r = 0; r < 2; ++r) {
    1158:         const PetscInt newp = eStartNew + (e - eStart)*2 + r;
    1159:         PetscInt       size;

    1161:         DMPlexSetConeSize(rdm, newp, 2);
    1162:         DMPlexGetSupportSize(dm, e, &size);
    1163:         DMPlexSetSupportSize(rdm, newp, size);
    1164:       }
    1165:     }
    1166:     /* Face edges have 2 vertices and 2 + cell faces supports */
    1167:     for (f = fStart; f < fEnd; ++f) {
    1168:       for (r = 0; r < 3; ++r) {
    1169:         const PetscInt  newp = eStartNew + (eEnd - eStart)*2 + (f - fStart)*3 + r;
    1170:         PetscInt        size;

    1172:         DMPlexSetConeSize(rdm, newp, 2);
    1173:         DMPlexGetSupportSize(dm, f, &size);
    1174:         DMPlexSetSupportSize(rdm, newp, 2+size);
    1175:       }
    1176:     }
    1177:     /* Interior cell edges have 2 vertices and 3 faces */
    1178:     for (c = cStart; c < cEnd; ++c) {
    1179:       for (r = 0; r < 4; ++r) {
    1180:         const PetscInt newp = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + r;

    1182:         DMPlexSetConeSize(rdm, newp, 2);
    1183:         DMPlexSetSupportSize(rdm, newp, 3);
    1184:       }
    1185:     }
    1186:     /* Old vertices have identical supports */
    1187:     for (v = vStart; v < vEnd; ++v) {
    1188:       const PetscInt newp = vStartNew + (v - vStart);
    1189:       PetscInt       size;

    1191:       DMPlexGetSupportSize(dm, v, &size);
    1192:       DMPlexSetSupportSize(rdm, newp, size);
    1193:     }
    1194:     /* Edge vertices have 2 + faces supports */
    1195:     for (e = eStart; e < eEnd; ++e) {
    1196:       const PetscInt newp = vStartNew + (vEnd - vStart) + (e - eStart);
    1197:       PetscInt       size;

    1199:       DMPlexGetSupportSize(dm, e, &size);
    1200:       DMPlexSetSupportSize(rdm, newp, 2 + size);
    1201:     }
    1202:     /* Face vertices have 3 + cells supports */
    1203:     for (f = fStart; f < fEnd; ++f) {
    1204:       const PetscInt newp = vStartNew + (vEnd - vStart) + (eEnd - eStart) + f - fStart;
    1205:       PetscInt       size;

    1207:       DMPlexGetSupportSize(dm, f, &size);
    1208:       DMPlexSetSupportSize(rdm, newp, 3 + size);
    1209:     }
    1210:     /* Interior cell vertices have 4 supports */
    1211:     for (c = cStart; c < cEnd; ++c) {
    1212:       const PetscInt newp = vStartNew + (vEnd - vStart) + (eEnd - eStart) + fEnd - fStart + c - cStart;

    1214:       DMPlexSetSupportSize(rdm, newp, 4);
    1215:     }
    1216:     break;
    1217:   case REFINER_HYBRID_SIMPLEX_TO_HEX_3D:
    1218:     /* the mesh is no longer hybrid */
    1219:     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
    1220:     cMax = PetscMin(cEnd, cMax);
    1221:     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
    1222:     fMax = PetscMin(fEnd, fMax);
    1223:     if (eMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No edge maximum specified in hybrid mesh");
    1224:     eMax = PetscMin(eEnd, eMax);
    1225:     /* All cells have 6 faces */
    1226:     for (c = cStart; c < cMax; ++c) {
    1227:       for (r = 0; r < 4; ++r) {
    1228:         const PetscInt newp = cStartNew + (c - cStart)*4 + r;

    1230:         DMPlexSetConeSize(rdm, newp, 6);
    1231:       }
    1232:     }
    1233:     for (c = cMax; c < cEnd; ++c) {
    1234:       for (r = 0; r < 3; ++r) {
    1235:         const PetscInt newp = cStartNew + (cMax - cStart)*4 + (c - cMax)*3 + r;

    1237:         DMPlexSetConeSize(rdm, newp, 6);
    1238:       }
    1239:     }
    1240:     /* Interior split faces have 4 edges and the same cells as the parent */
    1241:     for (f = fStart; f < fMax; ++f) {
    1242:       for (r = 0; r < 3; ++r) {
    1243:         const PetscInt newp = fStartNew + (f - fStart)*3 + r;
    1244:         PetscInt       size;

    1246:         DMPlexSetConeSize(rdm, newp, 4);
    1247:         DMPlexGetSupportSize(dm, f, &size);
    1248:         DMPlexSetSupportSize(rdm, newp, size);
    1249:       }
    1250:     }
    1251:     /* Interior cell faces have 4 edges and 2 cells */
    1252:     for (c = cStart; c < cMax; ++c) {
    1253:       for (r = 0; r < 6; ++r) {
    1254:         const PetscInt newp = fStartNew + (fMax - fStart)*3 + (c - cStart)*6 + r;

    1256:         DMPlexSetConeSize(rdm, newp, 4);
    1257:         DMPlexSetSupportSize(rdm, newp, 2);
    1258:       }
    1259:     }
    1260:     /* Hybrid split faces have 4 edges and the same cells as the parent */
    1261:     for (f = fMax; f < fEnd; ++f) {
    1262:       for (r = 0; r < 2; ++r) {
    1263:         const PetscInt newp = fStartNew + (fMax - fStart)*3 + (cMax - cStart)*6 + (f - fMax)*2 + r;
    1264:         PetscInt       size;

    1266:         DMPlexSetConeSize(rdm, newp, 4);
    1267:         DMPlexGetSupportSize(dm, f, &size);
    1268:         DMPlexSetSupportSize(rdm, newp, size);
    1269:       }
    1270:     }
    1271:     /* Hybrid cell faces have 4 edges and 2 cells */
    1272:     for (c = cMax; c < cEnd; ++c) {
    1273:       for (r = 0; r < 3; ++r) {
    1274:         const PetscInt newp = fStartNew + (fMax - fStart)*3 + (cMax - cStart)*6 + (fEnd - fMax)*2 + (c - cMax)*3 + r;

    1276:         DMPlexSetConeSize(rdm, newp, 4);
    1277:         DMPlexSetSupportSize(rdm, newp, 2);
    1278:       }
    1279:     }
    1280:     /* Interior split edges have 2 vertices and the same faces */
    1281:     for (e = eStart; e < eMax; ++e) {
    1282:       for (r = 0; r < 2; ++r) {
    1283:         const PetscInt newp = eStartNew + (e - eStart)*2 + r;
    1284:         PetscInt       size;

    1286:         DMPlexSetConeSize(rdm, newp, 2);
    1287:         DMPlexGetSupportSize(dm, e, &size);
    1288:         DMPlexSetSupportSize(rdm, newp, size);
    1289:       }
    1290:     }
    1291:     /* Interior face edges have 2 vertices and 2 + cell faces supports */
    1292:     for (f = fStart; f < fMax; ++f) {
    1293:       for (r = 0; r < 3; ++r) {
    1294:         const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (f - fStart)*3 + r;
    1295:         PetscInt        size;

    1297:         DMPlexSetConeSize(rdm, newp, 2);
    1298:         DMPlexGetSupportSize(dm, f, &size);
    1299:         DMPlexSetSupportSize(rdm, newp, 2+size);
    1300:       }
    1301:     }
    1302:     /* Interior cell edges have 2 vertices and 3 faces */
    1303:     for (c = cStart; c < cMax; ++c) {
    1304:       for (r = 0; r < 4; ++r) {
    1305:         const PetscInt newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart)*4 + r;

    1307:         DMPlexSetConeSize(rdm, newp, 2);
    1308:         DMPlexSetSupportSize(rdm, newp, 3);
    1309:       }
    1310:     }
    1311:     /* Hybrid edges have 2 vertices and the same faces */
    1312:     for (e = eMax; e < eEnd; ++e) {
    1313:       const PetscInt newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart)*4 + (e - eMax);
    1314:       PetscInt       size;

    1316:       DMPlexSetConeSize(rdm, newp, 2);
    1317:       DMPlexGetSupportSize(dm, e, &size);
    1318:       DMPlexSetSupportSize(rdm, newp, size);
    1319:     }
    1320:     /* Hybrid face edges have 2 vertices and 2+cells faces */
    1321:     for (f = fMax; f < fEnd; ++f) {
    1322:       const PetscInt newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart)*4 + (eEnd - eMax) + (f - fMax);
    1323:       PetscInt        size;

    1325:       DMPlexSetConeSize(rdm, newp, 2);
    1326:       DMPlexGetSupportSize(dm, f, &size);
    1327:       DMPlexSetSupportSize(rdm, newp, 2+size);
    1328:     }
    1329:     /* Hybrid cell edges have 2 vertices and 3 faces */
    1330:     for (c = cMax; c < cEnd; ++c) {
    1331:       const PetscInt newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart)*4 + (eEnd - eMax) + (fEnd - fMax) + (c - cMax);

    1333:       DMPlexSetConeSize(rdm, newp, 2);
    1334:       DMPlexSetSupportSize(rdm, newp, 3);
    1335:     }
    1336:     /* Old vertices have identical supports */
    1337:     for (v = vStart; v < vEnd; ++v) {
    1338:       const PetscInt newp = vStartNew + (v - vStart);
    1339:       PetscInt       size;

    1341:       DMPlexGetSupportSize(dm, v, &size);
    1342:       DMPlexSetSupportSize(rdm, newp, size);
    1343:     }
    1344:     /* Interior edge vertices have 2 + faces supports */
    1345:     for (e = eStart; e < eMax; ++e) {
    1346:       const PetscInt newp = vStartNew + (vEnd - vStart) + (e - eStart);
    1347:       PetscInt       size;

    1349:       DMPlexGetSupportSize(dm, e, &size);
    1350:       DMPlexSetSupportSize(rdm, newp, 2 + size);
    1351:     }
    1352:     /* Interior face vertices have 3 + cells supports */
    1353:     for (f = fStart; f < fMax; ++f) {
    1354:       const PetscInt newp = vStartNew + (vEnd - vStart) + (eMax - eStart) + f - fStart;
    1355:       PetscInt       size;

    1357:       DMPlexGetSupportSize(dm, f, &size);
    1358:       DMPlexSetSupportSize(rdm, newp, 3 + size);
    1359:     }
    1360:     /* Interior cell vertices have 4 supports */
    1361:     for (c = cStart; c < cMax; ++c) {
    1362:       const PetscInt newp = vStartNew + (vEnd - vStart) + (eMax - eStart) + (fMax - fStart) + c - cStart;

    1364:       DMPlexSetSupportSize(rdm, newp, 4);
    1365:     }
    1366:     break;
    1367:   case REFINER_HEX_3D:
    1368:     /* All cells have 6 faces */
    1369:     for (c = cStart; c < cEnd; ++c) {
    1370:       for (r = 0; r < 8; ++r) {
    1371:         const PetscInt newp = (c - cStart)*8 + r;

    1373:         DMPlexSetConeSize(rdm, newp, 6);
    1374:       }
    1375:     }
    1376:     /* Split faces have 4 edges and the same cells as the parent */
    1377:     for (f = fStart; f < fEnd; ++f) {
    1378:       for (r = 0; r < 4; ++r) {
    1379:         const PetscInt newp = fStartNew + (f - fStart)*4 + r;
    1380:         PetscInt       size;

    1382:         DMPlexSetConeSize(rdm, newp, 4);
    1383:         DMPlexGetSupportSize(dm, f, &size);
    1384:         DMPlexSetSupportSize(rdm, newp, size);
    1385:       }
    1386:     }
    1387:     /* Interior faces have 4 edges and 2 cells */
    1388:     for (c = cStart; c < cEnd; ++c) {
    1389:       for (r = 0; r < 12; ++r) {
    1390:         const PetscInt newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + r;

    1392:         DMPlexSetConeSize(rdm, newp, 4);
    1393:         DMPlexSetSupportSize(rdm, newp, 2);
    1394:       }
    1395:     }
    1396:     /* Split edges have 2 vertices and the same faces as the parent */
    1397:     for (e = eStart; e < eEnd; ++e) {
    1398:       for (r = 0; r < 2; ++r) {
    1399:         const PetscInt newp = eStartNew + (e - eStart)*2 + r;
    1400:         PetscInt       size;

    1402:         DMPlexSetConeSize(rdm, newp, 2);
    1403:         DMPlexGetSupportSize(dm, e, &size);
    1404:         DMPlexSetSupportSize(rdm, newp, size);
    1405:       }
    1406:     }
    1407:     /* Face edges have 2 vertices and 2+cells faces */
    1408:     for (f = fStart; f < fEnd; ++f) {
    1409:       for (r = 0; r < 4; ++r) {
    1410:         const PetscInt newp = eStartNew + (eEnd - eStart)*2 + (f - fStart)*4 + r;
    1411:         PetscInt       size;

    1413:         DMPlexSetConeSize(rdm, newp, 2);
    1414:         DMPlexGetSupportSize(dm, f, &size);
    1415:         DMPlexSetSupportSize(rdm, newp, 2+size);
    1416:       }
    1417:     }
    1418:     /* Cell edges have 2 vertices and 4 faces */
    1419:     for (c = cStart; c < cEnd; ++c) {
    1420:       for (r = 0; r < 6; ++r) {
    1421:         const PetscInt newp = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*4 + (c - cStart)*6 + r;

    1423:         DMPlexSetConeSize(rdm, newp, 2);
    1424:         DMPlexSetSupportSize(rdm, newp, 4);
    1425:       }
    1426:     }
    1427:     /* Old vertices have identical supports */
    1428:     for (v = vStart; v < vEnd; ++v) {
    1429:       const PetscInt newp = vStartNew + (v - vStart);
    1430:       PetscInt       size;

    1432:       DMPlexGetSupportSize(dm, v, &size);
    1433:       DMPlexSetSupportSize(rdm, newp, size);
    1434:     }
    1435:     /* Edge vertices have 2 + faces supports */
    1436:     for (e = eStart; e < eEnd; ++e) {
    1437:       const PetscInt newp = vStartNew + (vEnd - vStart) + (e - eStart);
    1438:       PetscInt       size;

    1440:       DMPlexGetSupportSize(dm, e, &size);
    1441:       DMPlexSetSupportSize(rdm, newp, 2 + size);
    1442:     }
    1443:     /* Face vertices have 4 + cells supports */
    1444:     for (f = fStart; f < fEnd; ++f) {
    1445:       const PetscInt newp = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (f - fStart);
    1446:       PetscInt       size;

    1448:       DMPlexGetSupportSize(dm, f, &size);
    1449:       DMPlexSetSupportSize(rdm, newp, 4 + size);
    1450:     }
    1451:     /* Cell vertices have 6 supports */
    1452:     for (c = cStart; c < cEnd; ++c) {
    1453:       const PetscInt newp = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (fEnd - fStart) + (c - cStart);

    1455:       DMPlexSetSupportSize(rdm, newp, 6);
    1456:     }
    1457:     break;
    1458:   case REFINER_HYBRID_HEX_3D:
    1459:     DMPlexSetHybridBounds(rdm, cStartNew + 8*(cMax-cStart), fStartNew + 4*(fMax - fStart) + 12*(cMax - cStart),
    1460:                                  eStartNew + 2*(eMax - eStart) + 4*(fMax - fStart) + 6*(cMax - cStart), PETSC_DETERMINE);
    1461:     /* Interior cells have 6 faces */
    1462:     for (c = cStart; c < cMax; ++c) {
    1463:       for (r = 0; r < 8; ++r) {
    1464:         const PetscInt newp = cStartNew + (c - cStart)*8 + r;

    1466:         DMPlexSetConeSize(rdm, newp, 6);
    1467:       }
    1468:     }
    1469:     /* Hybrid cells have 6 faces */
    1470:     for (c = cMax; c < cEnd; ++c) {
    1471:       for (r = 0; r < 4; ++r) {
    1472:         const PetscInt newp = cStartNew + (cMax - cStart)*8 + (c - cMax)*4 + r;

    1474:         DMPlexSetConeSize(rdm, newp, 6);
    1475:       }
    1476:     }
    1477:     /* Interior split faces have 4 edges and the same cells as the parent */
    1478:     for (f = fStart; f < fMax; ++f) {
    1479:       for (r = 0; r < 4; ++r) {
    1480:         const PetscInt newp = fStartNew + (f - fStart)*4 + r;
    1481:         PetscInt       size;

    1483:         DMPlexSetConeSize(rdm, newp, 4);
    1484:         DMPlexGetSupportSize(dm, f, &size);
    1485:         DMPlexSetSupportSize(rdm, newp, size);
    1486:       }
    1487:     }
    1488:     /* Interior cell faces have 4 edges and 2 cells */
    1489:     for (c = cStart; c < cMax; ++c) {
    1490:       for (r = 0; r < 12; ++r) {
    1491:         const PetscInt newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + r;

    1493:         DMPlexSetConeSize(rdm, newp, 4);
    1494:         DMPlexSetSupportSize(rdm, newp, 2);
    1495:       }
    1496:     }
    1497:     /* Hybrid split faces have 4 edges and the same cells as the parent */
    1498:     for (f = fMax; f < fEnd; ++f) {
    1499:       for (r = 0; r < 2; ++r) {
    1500:         const PetscInt newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (f - fMax)*2 + r;
    1501:         PetscInt       size;

    1503:         DMPlexSetConeSize(rdm, newp, 4);
    1504:         DMPlexGetSupportSize(dm, f, &size);
    1505:         DMPlexSetSupportSize(rdm, newp, size);
    1506:       }
    1507:     }
    1508:     /* Hybrid cells faces have 4 edges and 2 cells */
    1509:     for (c = cMax; c < cEnd; ++c) {
    1510:       for (r = 0; r < 4; ++r) {
    1511:         const PetscInt newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd - fMax)*2 + (c - cMax)*4 + r;

    1513:         DMPlexSetConeSize(rdm, newp, 4);
    1514:         DMPlexSetSupportSize(rdm, newp, 2);
    1515:       }
    1516:     }
    1517:     /* Interior split edges have 2 vertices and the same faces as the parent */
    1518:     for (e = eStart; e < eMax; ++e) {
    1519:       for (r = 0; r < 2; ++r) {
    1520:         const PetscInt newp = eStartNew + (e - eStart)*2 + r;
    1521:         PetscInt       size;

    1523:         DMPlexSetConeSize(rdm, newp, 2);
    1524:         DMPlexGetSupportSize(dm, e, &size);
    1525:         DMPlexSetSupportSize(rdm, newp, size);
    1526:       }
    1527:     }
    1528:     /* Interior face edges have 2 vertices and 2+cells faces */
    1529:     for (f = fStart; f < fMax; ++f) {
    1530:       for (r = 0; r < 4; ++r) {
    1531:         const PetscInt newp = eStartNew + (eMax - eStart)*2 + (f - fStart)*4 + r;
    1532:         PetscInt       size;

    1534:         DMPlexSetConeSize(rdm, newp, 2);
    1535:         DMPlexGetSupportSize(dm, f, &size);
    1536:         DMPlexSetSupportSize(rdm, newp, 2+size);
    1537:       }
    1538:     }
    1539:     /* Interior cell edges have 2 vertices and 4 faces */
    1540:     for (c = cStart; c < cMax; ++c) {
    1541:       for (r = 0; r < 6; ++r) {
    1542:         const PetscInt newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (c - cStart)*6 + r;

    1544:         DMPlexSetConeSize(rdm, newp, 2);
    1545:         DMPlexSetSupportSize(rdm, newp, 4);
    1546:       }
    1547:     }
    1548:     /* Hybrid edges have 2 vertices and the same faces */
    1549:     for (e = eMax; e < eEnd; ++e) {
    1550:       const PetscInt newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (e - eMax);
    1551:       PetscInt       size;

    1553:       DMPlexSetConeSize(rdm, newp, 2);
    1554:       DMPlexGetSupportSize(dm, e, &size);
    1555:       DMPlexSetSupportSize(rdm, newp, size);
    1556:     }
    1557:     /* Hybrid face edges have 2 vertices and 2+cells faces */
    1558:     for (f = fMax; f < fEnd; ++f) {
    1559:       const PetscInt newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (eEnd - eMax) + (f - fMax);
    1560:       PetscInt       size;

    1562:       DMPlexSetConeSize(rdm, newp, 2);
    1563:       DMPlexGetSupportSize(dm, f, &size);
    1564:       DMPlexSetSupportSize(rdm, newp, 2+size);
    1565:     }
    1566:     /* Hybrid cell edges have 2 vertices and 4 faces */
    1567:     for (c = cMax; c < cEnd; ++c) {
    1568:       const PetscInt newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (eEnd - eMax) + (fEnd - fMax) + (c - cMax);

    1570:       DMPlexSetConeSize(rdm, newp, 2);
    1571:       DMPlexSetSupportSize(rdm, newp, 4);
    1572:     }
    1573:     /* Interior vertices have identical supports */
    1574:     for (v = vStart; v < vEnd; ++v) {
    1575:       const PetscInt newp = vStartNew + (v - vStart);
    1576:       PetscInt       size;

    1578:       DMPlexGetSupportSize(dm, v, &size);
    1579:       DMPlexSetSupportSize(rdm, newp, size);
    1580:     }
    1581:     /* Interior edge vertices have 2 + faces supports */
    1582:     for (e = eStart; e < eMax; ++e) {
    1583:       const PetscInt newp = vStartNew + (vEnd - vStart) + (e - eStart);
    1584:       PetscInt       size;

    1586:       DMPlexGetSupportSize(dm, e, &size);
    1587:       DMPlexSetSupportSize(rdm, newp, 2 + size);
    1588:     }
    1589:     /* Interior face vertices have 4 + cells supports */
    1590:     for (f = fStart; f < fMax; ++f) {
    1591:       const PetscInt newp = vStartNew + (vEnd - vStart) + (eMax - eStart) + (f - fStart);
    1592:       PetscInt       size;

    1594:       DMPlexGetSupportSize(dm, f, &size);
    1595:       DMPlexSetSupportSize(rdm, newp, 4 + size);
    1596:     }
    1597:     /* Interior cell vertices have 6 supports */
    1598:     for (c = cStart; c < cMax; ++c) {
    1599:       const PetscInt newp = vStartNew + (vEnd - vStart) + (eMax - eStart) + (fMax - fStart) + (c - cStart);

    1601:       DMPlexSetSupportSize(rdm, newp, 6);
    1602:     }
    1603:     break;
    1604:   default:
    1605:     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %D", refiner);
    1606:   }
    1607:   return(0);
    1608: }

    1610: static PetscErrorCode CellRefinerSetCones(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
    1611: {
    1612:   const PetscInt *faces, cellInd[4] = {0, 1, 2, 3};
    1613:   PetscInt        cStart,    cEnd,    cMax,    vStart,    vEnd, vMax, fStart,    fEnd,    fMax,    eStart,    eEnd,    eMax;
    1614:   PetscInt        cStartNew, cEndNew, cMaxNew, vStartNew, vEndNew,    fStartNew, fEndNew, fMaxNew, eStartNew, eEndNew, eMaxNew;
    1615:   PetscInt        depth, maxSupportSize, *supportRef, c, f, e, v, r;
    1616: #if defined(PETSC_USE_DEBUG)
    1617:   PetscInt        p;
    1618: #endif
    1619:   PetscErrorCode  ierr;

    1622:   if (!refiner) return(0);
    1623:   DMPlexGetDepth(dm, &depth);
    1624:   DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);
    1625:   DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);
    1626:   DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);
    1627:   DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);
    1628:   DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);
    1629:   GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);
    1630:   GetDepthEnd_Private(depth, depthSize, &cEndNew, &fEndNew, &eEndNew, &vEndNew);
    1631:   switch (refiner) {
    1632:   case REFINER_SIMPLEX_1D:
    1633:     /* Max support size of refined mesh is 2 */
    1634:     PetscMalloc1(2, &supportRef);
    1635:     /* All cells have 2 vertices */
    1636:     for (c = cStart; c < cEnd; ++c) {
    1637:       const PetscInt  newv = vStartNew + (vEnd - vStart) + (c - cStart);

    1639:       for (r = 0; r < 2; ++r) {
    1640:         const PetscInt newp = cStartNew + (c - cStart)*2 + r;
    1641:         const PetscInt *cone;
    1642:         PetscInt        coneNew[2];

    1644:         DMPlexGetCone(dm, c, &cone);
    1645:         coneNew[0]       = vStartNew + (cone[0] - vStart);
    1646:         coneNew[1]       = vStartNew + (cone[1] - vStart);
    1647:         coneNew[(r+1)%2] = newv;
    1648:         DMPlexSetCone(rdm, newp, coneNew);
    1649: #if defined(PETSC_USE_DEBUG)
    1650:         if ((newp < cStartNew) || (newp >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", newp, cStartNew, cEndNew);
    1651:         for (p = 0; p < 2; ++p) {
    1652:           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", coneNew[p], vStartNew, vEndNew);
    1653:         }
    1654: #endif
    1655:       }
    1656:     }
    1657:     /* Old vertices have identical supports */
    1658:     for (v = vStart; v < vEnd; ++v) {
    1659:       const PetscInt  newp = vStartNew + (v - vStart);
    1660:       const PetscInt *support, *cone;
    1661:       PetscInt        size, s;

    1663:       DMPlexGetSupportSize(dm, v, &size);
    1664:       DMPlexGetSupport(dm, v, &support);
    1665:       for (s = 0; s < size; ++s) {
    1666:         PetscInt r = 0;

    1668:         DMPlexGetCone(dm, support[s], &cone);
    1669:         if (cone[1] == v) r = 1;
    1670:         supportRef[s] = cStartNew + (support[s] - cStart)*2 + r;
    1671:       }
    1672:       DMPlexSetSupport(rdm, newp, supportRef);
    1673: #if defined(PETSC_USE_DEBUG)
    1674:       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", newp, vStartNew, vEndNew);
    1675:       for (p = 0; p < size; ++p) {
    1676:         if ((supportRef[p] < cStartNew) || (supportRef[p] >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", supportRef[p], cStartNew, cEndNew);
    1677:       }
    1678: #endif
    1679:     }
    1680:     /* Cell vertices have support of 2 cells */
    1681:     for (c = cStart; c < cEnd; ++c) {
    1682:       const PetscInt  newp = vStartNew + (vEnd - vStart) + (c - cStart);

    1684:       supportRef[0] = cStartNew + (c - cStart)*2 + 0;
    1685:       supportRef[1] = cStartNew + (c - cStart)*2 + 1;
    1686:       DMPlexSetSupport(rdm, newp, supportRef);
    1687: #if defined(PETSC_USE_DEBUG)
    1688:       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", newp, vStartNew, vEndNew);
    1689:       for (p = 0; p < 2; ++p) {
    1690:         if ((supportRef[p] < cStartNew) || (supportRef[p] >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", supportRef[p], cStartNew, cEndNew);
    1691:       }
    1692: #endif
    1693:     }
    1694:     PetscFree(supportRef);
    1695:     break;
    1696:   case REFINER_SIMPLEX_2D:
    1697:     /*
    1698:      2
    1699:      |\
    1700:      | \
    1701:      |  \
    1702:      |   \
    1703:      | C  \
    1704:      |     \
    1705:      |      \
    1706:      2---1---1
    1707:      |\  D  / \
    1708:      | 2   0   \
    1709:      |A \ /  B  \
    1710:      0---0-------1
    1711:      */
    1712:     /* All cells have 3 faces */
    1713:     for (c = cStart; c < cEnd; ++c) {
    1714:       const PetscInt  newp = cStartNew + (c - cStart)*4;
    1715:       const PetscInt *cone, *ornt;
    1716:       PetscInt        coneNew[3], orntNew[3];

    1718:       DMPlexGetCone(dm, c, &cone);
    1719:       DMPlexGetConeOrientation(dm, c, &ornt);
    1720:       /* A triangle */
    1721:       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
    1722:       orntNew[0] = ornt[0];
    1723:       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 2;
    1724:       orntNew[1] = -2;
    1725:       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
    1726:       orntNew[2] = ornt[2];
    1727:       DMPlexSetCone(rdm, newp+0, coneNew);
    1728:       DMPlexSetConeOrientation(rdm, newp+0, orntNew);
    1729: #if defined(PETSC_USE_DEBUG)
    1730:       if ((newp+0 < cStartNew) || (newp+0 >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", newp+0, cStartNew, cEndNew);
    1731:       for (p = 0; p < 3; ++p) {
    1732:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", coneNew[p], fStartNew, fEndNew);
    1733:       }
    1734: #endif
    1735:       /* B triangle */
    1736:       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
    1737:       orntNew[0] = ornt[0];
    1738:       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
    1739:       orntNew[1] = ornt[1];
    1740:       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 0;
    1741:       orntNew[2] = -2;
    1742:       DMPlexSetCone(rdm, newp+1, coneNew);
    1743:       DMPlexSetConeOrientation(rdm, newp+1, orntNew);
    1744: #if defined(PETSC_USE_DEBUG)
    1745:       if ((newp+1 < cStartNew) || (newp+1 >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", newp+1, cStartNew, cEndNew);
    1746:       for (p = 0; p < 3; ++p) {
    1747:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", coneNew[p], fStartNew, fEndNew);
    1748:       }
    1749: #endif
    1750:       /* C triangle */
    1751:       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 1;
    1752:       orntNew[0] = -2;
    1753:       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
    1754:       orntNew[1] = ornt[1];
    1755:       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
    1756:       orntNew[2] = ornt[2];
    1757:       DMPlexSetCone(rdm, newp+2, coneNew);
    1758:       DMPlexSetConeOrientation(rdm, newp+2, orntNew);
    1759: #if defined(PETSC_USE_DEBUG)
    1760:       if ((newp+2 < cStartNew) || (newp+2 >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", newp+2, cStartNew, cEndNew);
    1761:       for (p = 0; p < 3; ++p) {
    1762:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", coneNew[p], fStartNew, fEndNew);
    1763:       }
    1764: #endif
    1765:       /* D triangle */
    1766:       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 0;
    1767:       orntNew[0] = 0;
    1768:       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 1;
    1769:       orntNew[1] = 0;
    1770:       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 2;
    1771:       orntNew[2] = 0;
    1772:       DMPlexSetCone(rdm, newp+3, coneNew);
    1773:       DMPlexSetConeOrientation(rdm, newp+3, orntNew);
    1774: #if defined(PETSC_USE_DEBUG)
    1775:       if ((newp+3 < cStartNew) || (newp+3 >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", newp+3, cStartNew, cEndNew);
    1776:       for (p = 0; p < 3; ++p) {
    1777:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", coneNew[p], fStartNew, fEndNew);
    1778:       }
    1779: #endif
    1780:     }
    1781:     /* Split faces have 2 vertices and the same cells as the parent */
    1782:     DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);
    1783:     PetscMalloc1(2 + maxSupportSize*2, &supportRef);
    1784:     for (f = fStart; f < fEnd; ++f) {
    1785:       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);

    1787:       for (r = 0; r < 2; ++r) {
    1788:         const PetscInt  newp = fStartNew + (f - fStart)*2 + r;
    1789:         const PetscInt *cone, *ornt, *support;
    1790:         PetscInt        coneNew[2], coneSize, c, supportSize, s;

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

    1827:       DMPlexGetCone(dm, c, &cone);
    1828:       for (r = 0; r < 3; ++r) {
    1829:         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*3 + r;
    1830:         PetscInt       coneNew[2];
    1831:         PetscInt       supportNew[2];

    1833:         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r]       - fStart);
    1834:         coneNew[1] = vStartNew + (vEnd - vStart) + (cone[(r+1)%3] - fStart);
    1835:         DMPlexSetCone(rdm, newp, coneNew);
    1836: #if defined(PETSC_USE_DEBUG)
    1837:         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
    1838:         for (p = 0; p < 2; ++p) {
    1839:           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", coneNew[p], vStartNew, vEndNew);
    1840:         }
    1841: #endif
    1842:         supportNew[0] = (c - cStart)*4 + (r+1)%3;
    1843:         supportNew[1] = (c - cStart)*4 + 3;
    1844:         DMPlexSetSupport(rdm, newp, supportNew);
    1845: #if defined(PETSC_USE_DEBUG)
    1846:         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
    1847:         for (p = 0; p < 2; ++p) {
    1848:           if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", supportNew[p], cStartNew, cEndNew);
    1849:         }
    1850: #endif
    1851:       }
    1852:     }
    1853:     /* Old vertices have identical supports */
    1854:     for (v = vStart; v < vEnd; ++v) {
    1855:       const PetscInt  newp = vStartNew + (v - vStart);
    1856:       const PetscInt *support, *cone;
    1857:       PetscInt        size, s;

    1859:       DMPlexGetSupportSize(dm, v, &size);
    1860:       DMPlexGetSupport(dm, v, &support);
    1861:       for (s = 0; s < size; ++s) {
    1862:         PetscInt r = 0;

    1864:         DMPlexGetCone(dm, support[s], &cone);
    1865:         if (cone[1] == v) r = 1;
    1866:         supportRef[s] = fStartNew + (support[s] - fStart)*2 + r;
    1867:       }
    1868:       DMPlexSetSupport(rdm, newp, supportRef);
    1869: #if defined(PETSC_USE_DEBUG)
    1870:       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", newp, vStartNew, vEndNew);
    1871:       for (p = 0; p < size; ++p) {
    1872:         if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", supportRef[p], fStartNew, fEndNew);
    1873:       }
    1874: #endif
    1875:     }
    1876:     /* Face vertices have 2 + cells*2 supports */
    1877:     for (f = fStart; f < fEnd; ++f) {
    1878:       const PetscInt  newp = vStartNew + (vEnd - vStart) + (f - fStart);
    1879:       const PetscInt *cone, *support;
    1880:       PetscInt        size, s;

    1882:       DMPlexGetSupportSize(dm, f, &size);
    1883:       DMPlexGetSupport(dm, f, &support);
    1884:       supportRef[0] = fStartNew + (f - fStart)*2 + 0;
    1885:       supportRef[1] = fStartNew + (f - fStart)*2 + 1;
    1886:       for (s = 0; s < size; ++s) {
    1887:         PetscInt r = 0;

    1889:         DMPlexGetCone(dm, support[s], &cone);
    1890:         if      (cone[1] == f) r = 1;
    1891:         else if (cone[2] == f) r = 2;
    1892:         supportRef[2+s*2+0] = fStartNew + (fEnd - fStart)*2 + (support[s] - cStart)*3 + (r+2)%3;
    1893:         supportRef[2+s*2+1] = fStartNew + (fEnd - fStart)*2 + (support[s] - cStart)*3 + r;
    1894:       }
    1895:       DMPlexSetSupport(rdm, newp, supportRef);
    1896: #if defined(PETSC_USE_DEBUG)
    1897:       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", newp, vStartNew, vEndNew);
    1898:       for (p = 0; p < 2+size*2; ++p) {
    1899:         if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", supportRef[p], fStartNew, fEndNew);
    1900:       }
    1901: #endif
    1902:     }
    1903:     PetscFree(supportRef);
    1904:     break;
    1905:   case REFINER_SIMPLEX_TO_HEX_2D:
    1906:     /*
    1907:      2
    1908:      |\
    1909:      | \
    1910:      |  \
    1911:      |   \
    1912:      | C  \
    1913:      |     \
    1914:      2      1
    1915:      |\    / \
    1916:      | 2  1   \
    1917:      |  \/     \
    1918:      |   |      \
    1919:      |A  |   B   \
    1920:      |   0        \
    1921:      |   |         \
    1922:      0---0----------1
    1923:      */
    1924:     /* All cells have 4 faces */
    1925:     for (c = cStart; c < cEnd; ++c) {
    1926:       const PetscInt  newp = cStartNew + (c - cStart)*3;
    1927:       const PetscInt *cone, *ornt;
    1928:       PetscInt        coneNew[4], orntNew[4];

    1930:       DMPlexGetCone(dm, c, &cone);
    1931:       DMPlexGetConeOrientation(dm, c, &ornt);
    1932:       /* A quad */
    1933:       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
    1934:       orntNew[0] = ornt[0];
    1935:       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 0;
    1936:       orntNew[1] = 0;
    1937:       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 2;
    1938:       orntNew[2] = -2;
    1939:       coneNew[3] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
    1940:       orntNew[3] = ornt[2];
    1941:       DMPlexSetCone(rdm, newp+0, coneNew);
    1942:       DMPlexSetConeOrientation(rdm, newp+0, orntNew);
    1943: #if defined(PETSC_USE_DEBUG)
    1944:       if ((newp+0 < cStartNew) || (newp+0 >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", newp+0, cStartNew, cEndNew);
    1945:       for (p = 0; p < 4; ++p) {
    1946:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", coneNew[p], fStartNew, fEndNew);
    1947:       }
    1948: #endif
    1949:       /* B quad */
    1950:       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
    1951:       orntNew[0] = ornt[0];
    1952:       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
    1953:       orntNew[1] = ornt[1];
    1954:       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 1;
    1955:       orntNew[2] = 0;
    1956:       coneNew[3] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 0;
    1957:       orntNew[3] = -2;
    1958:       DMPlexSetCone(rdm, newp+1, coneNew);
    1959:       DMPlexSetConeOrientation(rdm, newp+1, orntNew);
    1960: #if defined(PETSC_USE_DEBUG)
    1961:       if ((newp+1 < cStartNew) || (newp+1 >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", newp+1, cStartNew, cEndNew);
    1962:       for (p = 0; p < 4; ++p) {
    1963:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", coneNew[p], fStartNew, fEndNew);
    1964:       }
    1965: #endif
    1966:       /* C quad */
    1967:       coneNew[0] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
    1968:       orntNew[0] = ornt[1];
    1969:       coneNew[1] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
    1970:       orntNew[1] = ornt[2];
    1971:       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 2;
    1972:       orntNew[2] = 0;
    1973:       coneNew[3] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 1;
    1974:       orntNew[3] = -2;
    1975:       DMPlexSetCone(rdm, newp+2, coneNew);
    1976:       DMPlexSetConeOrientation(rdm, newp+2, orntNew);
    1977: #if defined(PETSC_USE_DEBUG)
    1978:       if ((newp+2 < cStartNew) || (newp+2 >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", newp+2, cStartNew, cEndNew);
    1979:       for (p = 0; p < 4; ++p) {
    1980:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", coneNew[p], fStartNew, fEndNew);
    1981:       }
    1982: #endif
    1983:     }
    1984:     /* Split faces have 2 vertices and the same cells as the parent */
    1985:     DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);
    1986:     PetscMalloc1(2 + maxSupportSize*2, &supportRef);
    1987:     for (f = fStart; f < fEnd; ++f) {
    1988:       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);

    1990:       for (r = 0; r < 2; ++r) {
    1991:         const PetscInt  newp = fStartNew + (f - fStart)*2 + r;
    1992:         const PetscInt *cone, *ornt, *support;
    1993:         PetscInt        coneNew[2], coneSize, c, supportSize, s;

    1995:         DMPlexGetCone(dm, f, &cone);
    1996:         coneNew[0]       = vStartNew + (cone[0] - vStart);
    1997:         coneNew[1]       = vStartNew + (cone[1] - vStart);
    1998:         coneNew[(r+1)%2] = newv;
    1999:         DMPlexSetCone(rdm, newp, coneNew);
    2000: #if defined(PETSC_USE_DEBUG)
    2001:         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
    2002:         for (p = 0; p < 2; ++p) {
    2003:           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", coneNew[p], vStartNew, vEndNew);
    2004:         }
    2005: #endif
    2006:         DMPlexGetSupportSize(dm, f, &supportSize);
    2007:         DMPlexGetSupport(dm, f, &support);
    2008:         for (s = 0; s < supportSize; ++s) {
    2009:           DMPlexGetConeSize(dm, support[s], &coneSize);
    2010:           DMPlexGetCone(dm, support[s], &cone);
    2011:           DMPlexGetConeOrientation(dm, support[s], &ornt);
    2012:           for (c = 0; c < coneSize; ++c) {
    2013:             if (cone[c] == f) break;
    2014:           }
    2015:           supportRef[s] = cStartNew + (support[s] - cStart)*3 + (ornt[c] < 0 ? (c+1-r)%3 : (c+r)%3);
    2016:         }
    2017:         DMPlexSetSupport(rdm, newp, supportRef);
    2018: #if defined(PETSC_USE_DEBUG)
    2019:         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
    2020:         for (p = 0; p < supportSize; ++p) {
    2021:           if ((supportRef[p] < cStartNew) || (supportRef[p] >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", supportRef[p], cStartNew, cEndNew);
    2022:         }
    2023: #endif
    2024:       }
    2025:     }
    2026:     /* Interior faces have 2 vertices and 2 cells */
    2027:     for (c = cStart; c < cEnd; ++c) {
    2028:       const PetscInt *cone;

    2030:       DMPlexGetCone(dm, c, &cone);
    2031:       for (r = 0; r < 3; ++r) {
    2032:         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*3 + r;
    2033:         PetscInt       coneNew[2];
    2034:         PetscInt       supportNew[2];

    2036:         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r] - fStart);
    2037:         coneNew[1] = vStartNew + (vEnd - vStart) + (fEnd    - fStart) + (c - cStart);
    2038:         DMPlexSetCone(rdm, newp, coneNew);
    2039: #if defined(PETSC_USE_DEBUG)
    2040:         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
    2041:         for (p = 0; p < 2; ++p) {
    2042:           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", coneNew[p], vStartNew, vEndNew);
    2043:         }
    2044: #endif
    2045:         supportNew[0] = (c - cStart)*3 + r%3;
    2046:         supportNew[1] = (c - cStart)*3 + (r+1)%3;
    2047:         DMPlexSetSupport(rdm, newp, supportNew);
    2048: #if defined(PETSC_USE_DEBUG)
    2049:         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
    2050:         for (p = 0; p < 2; ++p) {
    2051:           if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", supportNew[p], cStartNew, cEndNew);
    2052:         }
    2053: #endif
    2054:       }
    2055:     }
    2056:     /* Old vertices have identical supports */
    2057:     for (v = vStart; v < vEnd; ++v) {
    2058:       const PetscInt  newp = vStartNew + (v - vStart);
    2059:       const PetscInt *support, *cone;
    2060:       PetscInt        size, s;

    2062:       DMPlexGetSupportSize(dm, v, &size);
    2063:       DMPlexGetSupport(dm, v, &support);
    2064:       for (s = 0; s < size; ++s) {
    2065:         PetscInt r = 0;

    2067:         DMPlexGetCone(dm, support[s], &cone);
    2068:         if (cone[1] == v) r = 1;
    2069:         supportRef[s] = fStartNew + (support[s] - fStart)*2 + r;
    2070:       }
    2071:       DMPlexSetSupport(rdm, newp, supportRef);
    2072: #if defined(PETSC_USE_DEBUG)
    2073:       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", newp, vStartNew, vEndNew);
    2074:       for (p = 0; p < size; ++p) {
    2075:         if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", supportRef[p], fStartNew, fEndNew);
    2076:       }
    2077: #endif
    2078:     }
    2079:     /* Split-face vertices have cells + 2 supports */
    2080:     for (f = fStart; f < fEnd; ++f) {
    2081:       const PetscInt  newp = vStartNew + (vEnd - vStart) + (f - fStart);
    2082:       const PetscInt *cone, *support;
    2083:       PetscInt        size, s;

    2085:       DMPlexGetSupportSize(dm, f, &size);
    2086:       DMPlexGetSupport(dm, f, &support);
    2087:       supportRef[0] = fStartNew + (f - fStart)*2 + 0;
    2088:       supportRef[1] = fStartNew + (f - fStart)*2 + 1;
    2089:       for (s = 0; s < size; ++s) {
    2090:         PetscInt r = 0;

    2092:         DMPlexGetCone(dm, support[s], &cone);
    2093:         if      (cone[1] == f) r = 1;
    2094:         else if (cone[2] == f) r = 2;
    2095:         supportRef[2+s+0] = fStartNew + (fEnd - fStart)*2 + (support[s] - cStart)*3 + r;
    2096:       }
    2097:       DMPlexSetSupport(rdm, newp, supportRef);
    2098: #if defined(PETSC_USE_DEBUG)
    2099:       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", newp, vStartNew, vEndNew);
    2100:       for (p = 0; p < 2+size; ++p) {
    2101:         if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", supportRef[p], fStartNew, fEndNew);
    2102:       }
    2103: #endif
    2104:     }
    2105:     /* Interior vertices have 3 supports */
    2106:     for (c = cStart; c < cEnd; ++c) {
    2107:       const PetscInt newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + c - cStart;

    2109:       supportRef[0] = fStartNew + (fEnd - fStart)*2 + (c - cStart)*3 + 0;
    2110:       supportRef[1] = fStartNew + (fEnd - fStart)*2 + (c - cStart)*3 + 1;
    2111:       supportRef[2] = fStartNew + (fEnd - fStart)*2 + (c - cStart)*3 + 2;
    2112:       DMPlexSetSupport(rdm, newp, supportRef);
    2113:     }
    2114:     PetscFree(supportRef);
    2115:     break;
    2116:   case REFINER_HYBRID_SIMPLEX_TO_HEX_2D:
    2117:     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
    2118:     cMax = PetscMin(cEnd, cMax);
    2119:     for (c = cStart; c < cMax; ++c) {
    2120:       const PetscInt  newp = cStartNew + (c - cStart)*3;
    2121:       const PetscInt *cone, *ornt;
    2122:       PetscInt        coneNew[4], orntNew[4];

    2124:       DMPlexGetCone(dm, c, &cone);
    2125:       DMPlexGetConeOrientation(dm, c, &ornt);
    2126:       /* A quad */
    2127:       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
    2128:       orntNew[0] = ornt[0];
    2129:       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 0;
    2130:       orntNew[1] = 0;
    2131:       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 2;
    2132:       orntNew[2] = -2;
    2133:       coneNew[3] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
    2134:       orntNew[3] = ornt[2];
    2135:       DMPlexSetCone(rdm, newp+0, coneNew);
    2136:       DMPlexSetConeOrientation(rdm, newp+0, orntNew);
    2137: #if defined(PETSC_USE_DEBUG)
    2138:       if ((newp+0 < cStartNew) || (newp+0 >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", newp+0, cStartNew, cEndNew);
    2139:       for (p = 0; p < 4; ++p) {
    2140:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", coneNew[p], fStartNew, fEndNew);
    2141:       }
    2142: #endif
    2143:       /* B quad */
    2144:       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
    2145:       orntNew[0] = ornt[0];
    2146:       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
    2147:       orntNew[1] = ornt[1];
    2148:       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 1;
    2149:       orntNew[2] = 0;
    2150:       coneNew[3] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 0;
    2151:       orntNew[3] = -2;
    2152:       DMPlexSetCone(rdm, newp+1, coneNew);
    2153:       DMPlexSetConeOrientation(rdm, newp+1, orntNew);
    2154: #if defined(PETSC_USE_DEBUG)
    2155:       if ((newp+1 < cStartNew) || (newp+1 >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", newp+1, cStartNew, cEndNew);
    2156:       for (p = 0; p < 4; ++p) {
    2157:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", coneNew[p], fStartNew, fEndNew);
    2158:       }
    2159: #endif
    2160:       /* C quad */
    2161:       coneNew[0] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
    2162:       orntNew[0] = ornt[1];
    2163:       coneNew[1] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
    2164:       orntNew[1] = ornt[2];
    2165:       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 2;
    2166:       orntNew[2] = 0;
    2167:       coneNew[3] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 1;
    2168:       orntNew[3] = -2;
    2169:       DMPlexSetCone(rdm, newp+2, coneNew);
    2170:       DMPlexSetConeOrientation(rdm, newp+2, orntNew);
    2171: #if defined(PETSC_USE_DEBUG)
    2172:       if ((newp+2 < cStartNew) || (newp+2 >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", newp+2, cStartNew, cEndNew);
    2173:       for (p = 0; p < 4; ++p) {
    2174:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", coneNew[p], fStartNew, fEndNew);
    2175:       }
    2176: #endif
    2177:     }
    2178:     /*
    2179:      2---------1---------3
    2180:      |         |         |
    2181:      |    D    1    C    |
    2182:      |         |         |
    2183:      2----2----0----3----3
    2184:      |         |         |
    2185:      |    A    0    B    |
    2186:      |         |         |
    2187:      0---------0---------1
    2188:      */
    2189:     /* Parent cells are input as prisms but children are quads, since the mesh is no longer hybrid */
    2190:     for (c = cMax; c < cEnd; ++c) {
    2191:       const PetscInt  newp  = cStartNew + (cMax - cStart)*3 + (c - cMax)*4;
    2192:       const PetscInt  newpt = (cMax - cStart)*3 + (c - cMax)*4;
    2193:       const PetscInt *cone, *ornt;
    2194:       PetscInt        coneNew[4], orntNew[4];

    2196:       DMPlexGetCone(dm, c, &cone);
    2197:       DMPlexGetConeOrientation(dm, c, &ornt);
    2198:       /* A quad */
    2199:       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
    2200:       orntNew[0] = ornt[0];
    2201:       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + newpt + 0;
    2202:       orntNew[1] = 0;
    2203:       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + newpt + 2;
    2204:       orntNew[2] = -2;
    2205:       coneNew[3] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
    2206:       orntNew[3] = ornt[2] < 0 ? 0 : -2;
    2207:       DMPlexSetCone(rdm, newp+0, coneNew);
    2208:       DMPlexSetConeOrientation(rdm, newp+0, orntNew);
    2209: #if defined(PETSC_USE_DEBUG)
    2210:       if ((newp+0 < cStartNew) || (newp+0 >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", newp+0, cStartNew, cEndNew);
    2211:       for (p = 0; p < 4; ++p) {
    2212:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", coneNew[p], fStartNew, fEndNew);
    2213:       }
    2214: #endif
    2215:       /* B quad */
    2216:       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
    2217:       orntNew[0] = ornt[0];
    2218:       coneNew[1] = fStartNew + (cone[3] - fStart)*2 + (ornt[3] < 0 ? 1 : 0);
    2219:       orntNew[1] = ornt[3];
    2220:       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + newpt + 3;
    2221:       orntNew[2] = 0;
    2222:       coneNew[3] = fStartNew + (fEnd    - fStart)*2 + newpt + 0;
    2223:       orntNew[3] = -2;
    2224:       DMPlexSetCone(rdm, newp+1, coneNew);
    2225:       DMPlexSetConeOrientation(rdm, newp+1, orntNew);
    2226: #if defined(PETSC_USE_DEBUG)
    2227:       if ((newp+1 < cStartNew) || (newp+1 >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", newp+1, cStartNew, cEndNew);
    2228:       for (p = 0; p < 4; ++p) {
    2229:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", coneNew[p], fStartNew, fEndNew);
    2230:       }
    2231: #endif
    2232:       /* C quad */
    2233:       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + newpt + 3;
    2234:       orntNew[0] = -2;
    2235:       coneNew[1] = fStartNew + (cone[3] - fStart)*2 + (ornt[3] < 0 ? 0 : 1);
    2236:       orntNew[1] = ornt[3];
    2237:       coneNew[2] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
    2238:       orntNew[2] = ornt[1] < 0 ? 0 : -2;
    2239:       coneNew[3] = fStartNew + (fEnd    - fStart)*2 + newpt + 1;
    2240:       orntNew[3] = 0;
    2241:       DMPlexSetCone(rdm, newp+2, coneNew);
    2242:       DMPlexSetConeOrientation(rdm, newp+2, orntNew);
    2243: #if defined(PETSC_USE_DEBUG)
    2244:       if ((newp+2 < cStartNew) || (newp+2 >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", newp+2, cStartNew, cEndNew);
    2245:       for (p = 0; p < 4; ++p) {
    2246:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", coneNew[p], fStartNew, fEndNew);
    2247:       }
    2248: #endif
    2249:       /* D quad */
    2250:       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + newpt + 2;
    2251:       orntNew[0] = 0;
    2252:       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + newpt + 1;
    2253:       orntNew[1] = -2;
    2254:       coneNew[2] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
    2255:       orntNew[2] = ornt[1] < 0 ? 0 : -2;
    2256:       coneNew[3] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
    2257:       orntNew[3] = ornt[2] < 0 ? 0 : -2;
    2258:       DMPlexSetCone(rdm, newp+3, coneNew);
    2259:       DMPlexSetConeOrientation(rdm, newp+3, orntNew);
    2260: #if defined(PETSC_USE_DEBUG)
    2261:       if ((newp+3 < cStartNew) || (newp+3 >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", newp+3, cStartNew, cEndNew);
    2262:       for (p = 0; p < 4; ++p) {
    2263:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", coneNew[p], fStartNew, fEndNew);
    2264:       }
    2265: #endif
    2266:     }
    2267:     /* Split faces have 2 vertices and the same cells as the parent */
    2268:     DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);
    2269:     PetscMalloc1(2 + maxSupportSize*2, &supportRef);
    2270:     for (f = fStart; f < fEnd; ++f) {
    2271:       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);

    2273:       for (r = 0; r < 2; ++r) {
    2274:         const PetscInt  newp = fStartNew + (f - fStart)*2 + r;
    2275:         const PetscInt *cone, *ornt, *support;
    2276:         PetscInt        coneNew[2], coneSize, c, supportSize, s;

    2278:         DMPlexGetCone(dm, f, &cone);
    2279:         coneNew[0]       = vStartNew + (cone[0] - vStart);
    2280:         coneNew[1]       = vStartNew + (cone[1] - vStart);
    2281:         coneNew[(r+1)%2] = newv;
    2282:         DMPlexSetCone(rdm, newp, coneNew);
    2283: #if defined(PETSC_USE_DEBUG)
    2284:         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
    2285:         for (p = 0; p < 2; ++p) {
    2286:           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", coneNew[p], vStartNew, vEndNew);
    2287:         }
    2288: #endif
    2289:         DMPlexGetSupportSize(dm, f, &supportSize);
    2290:         DMPlexGetSupport(dm, f, &support);
    2291:         for (s = 0; s < supportSize; ++s) {
    2292:           const PetscInt p2q[4][2] = { {0, 1},
    2293:                                        {3, 2},
    2294:                                        {0, 3},
    2295:                                        {1, 2} };

    2297:           DMPlexGetConeSize(dm, support[s], &coneSize);
    2298:           DMPlexGetCone(dm, support[s], &cone);
    2299:           DMPlexGetConeOrientation(dm, support[s], &ornt);
    2300:           for (c = 0; c < coneSize; ++c) {
    2301:             if (cone[c] == f) break;
    2302:           }
    2303:           if (coneSize == 3)      supportRef[s] = cStartNew + (support[s] - cStart)*3 + (ornt[c] < 0 ? (c+1-r)%3 : (c+r)%3);
    2304:           else if (coneSize == 4) supportRef[s] = cStartNew + (cMax - cStart)*3 + (support[s] - cMax)*4 + (ornt[c] < 0 ? p2q[c][(r+1)%2] : p2q[c][r]);
    2305:           else SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected cone size %D", coneSize);
    2306:         }
    2307:         DMPlexSetSupport(rdm, newp, supportRef);
    2308: #if defined(PETSC_USE_DEBUG)
    2309:         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
    2310:         for (p = 0; p < supportSize; ++p) {
    2311:           if ((supportRef[p] < cStartNew) || (supportRef[p] >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", supportRef[p], cStartNew, cEndNew);
    2312:         }
    2313: #endif
    2314:       }
    2315:     }
    2316:     /* Interior faces have 2 vertices and 2 cells */
    2317:     for (c = cStart; c < cMax; ++c) {
    2318:       const PetscInt *cone;

    2320:       DMPlexGetCone(dm, c, &cone);
    2321:       for (r = 0; r < 3; ++r) {
    2322:         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*3 + r;
    2323:         PetscInt       coneNew[2];
    2324:         PetscInt       supportNew[2];

    2326:         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r] - fStart);
    2327:         coneNew[1] = vStartNew + (vEnd - vStart) + (fEnd    - fStart) + (c - cStart);
    2328:         DMPlexSetCone(rdm, newp, coneNew);
    2329: #if defined(PETSC_USE_DEBUG)
    2330:         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
    2331:         for (p = 0; p < 2; ++p) {
    2332:           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", coneNew[p], vStartNew, vEndNew);
    2333:         }
    2334: #endif
    2335:         supportNew[0] = (c - cStart)*3 + r%3;
    2336:         supportNew[1] = (c - cStart)*3 + (r+1)%3;
    2337:         DMPlexSetSupport(rdm, newp, supportNew);
    2338: #if defined(PETSC_USE_DEBUG)
    2339:         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
    2340:         for (p = 0; p < 2; ++p) {
    2341:           if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", supportNew[p], cStartNew, cEndNew);
    2342:         }
    2343: #endif
    2344:       }
    2345:     }
    2346:     /* Hybrid interior faces have 2 vertices and 2 cells */
    2347:     for (c = cMax; c < cEnd; ++c) {
    2348:       const PetscInt *cone;
    2349:       PetscInt        coneNew[2], supportNew[2];

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

    2355:         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r] - fStart);
    2356:         coneNew[1] = vStartNew + (vEnd - vStart) + (fEnd    - fStart) + (cMax - cStart) + (c - cMax);
    2357:         DMPlexSetCone(rdm, newp, coneNew);
    2358: #if defined(PETSC_USE_DEBUG)
    2359:         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
    2360:         for (p = 0; p < 2; ++p) {
    2361:           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", coneNew[p], vStartNew, vEndNew);
    2362:         }
    2363: #endif
    2364:         if (r==0) {
    2365:           supportNew[0] = (cMax - cStart)*3 + (c - cMax)*4 + 0;
    2366:           supportNew[1] = (cMax - cStart)*3 + (c - cMax)*4 + 1;
    2367:         } else if (r==1) {
    2368:           supportNew[0] = (cMax - cStart)*3 + (c - cMax)*4 + 2;
    2369:           supportNew[1] = (cMax - cStart)*3 + (c - cMax)*4 + 3;
    2370:         } else if (r==2) {
    2371:           supportNew[0] = (cMax - cStart)*3 + (c - cMax)*4 + 0;
    2372:           supportNew[1] = (cMax - cStart)*3 + (c - cMax)*4 + 3;
    2373:         } else {
    2374:           supportNew[0] = (cMax - cStart)*3 + (c - cMax)*4 + 1;
    2375:           supportNew[1] = (cMax - cStart)*3 + (c - cMax)*4 + 2;
    2376:         }
    2377:         DMPlexSetSupport(rdm, newp, supportNew);
    2378: #if defined(PETSC_USE_DEBUG)
    2379:         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
    2380:         for (p = 0; p < 2; ++p) {
    2381:           if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", supportNew[p], cStartNew, cEndNew);
    2382:         }
    2383: #endif
    2384:       }
    2385:     }
    2386:     /* Old vertices have identical supports */
    2387:     for (v = vStart; v < vEnd; ++v) {
    2388:       const PetscInt  newp = vStartNew + (v - vStart);
    2389:       const PetscInt *support, *cone;
    2390:       PetscInt        size, s;

    2392:       DMPlexGetSupportSize(dm, v, &size);
    2393:       DMPlexGetSupport(dm, v, &support);
    2394:       for (s = 0; s < size; ++s) {
    2395:         PetscInt r = 0;

    2397:         DMPlexGetCone(dm, support[s], &cone);
    2398:         if (cone[1] == v) r = 1;
    2399:         supportRef[s] = fStartNew + (support[s] - fStart)*2 + r;
    2400:       }
    2401:       DMPlexSetSupport(rdm, newp, supportRef);
    2402: #if defined(PETSC_USE_DEBUG)
    2403:       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", newp, vStartNew, vEndNew);
    2404:       for (p = 0; p < size; ++p) {
    2405:         if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", supportRef[p], fStartNew, fEndNew);
    2406:       }
    2407: #endif
    2408:     }
    2409:     /* Split-face vertices have cells + 2 supports */
    2410:     for (f = fStart; f < fEnd; ++f) {
    2411:       const PetscInt  newp = vStartNew + (vEnd - vStart) + (f - fStart);
    2412:       const PetscInt *cone, *support;
    2413:       PetscInt        size, s;

    2415:       DMPlexGetSupportSize(dm, f, &size);
    2416:       DMPlexGetSupport(dm, f, &support);
    2417:       supportRef[0] = fStartNew + (f - fStart)*2 + 0;
    2418:       supportRef[1] = fStartNew + (f - fStart)*2 + 1;
    2419:       for (s = 0; s < size; ++s) {
    2420:         PetscInt r = 0, coneSize;

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

    2447:       supportRef[0] = fStartNew + (fEnd - fStart)*2 + (c - cStart)*3 + 0;
    2448:       supportRef[1] = fStartNew + (fEnd - fStart)*2 + (c - cStart)*3 + 1;
    2449:       supportRef[2] = fStartNew + (fEnd - fStart)*2 + (c - cStart)*3 + 2;
    2450:       DMPlexSetSupport(rdm, newp, supportRef);
    2451:     }
    2452:     /* Hybrid interior vertices have 4 supports */
    2453:     for (c = cMax; c < cEnd; ++c) {
    2454:       const PetscInt newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + c - cStart;

    2456:       supportRef[0] = fStartNew + (fEnd - fStart)*2 + (cMax - cStart)*3 + (c - cMax)*4 + 0;
    2457:       supportRef[1] = fStartNew + (fEnd - fStart)*2 + (cMax - cStart)*3 + (c - cMax)*4 + 1;
    2458:       supportRef[2] = fStartNew + (fEnd - fStart)*2 + (cMax - cStart)*3 + (c - cMax)*4 + 2;
    2459:       supportRef[3] = fStartNew + (fEnd - fStart)*2 + (cMax - cStart)*3 + (c - cMax)*4 + 3;
    2460:       DMPlexSetSupport(rdm, newp, supportRef);
    2461:     }
    2462:     PetscFree(supportRef);
    2463:     break;
    2464:   case REFINER_HEX_2D:
    2465:     /*
    2466:      3---------2---------2
    2467:      |         |         |
    2468:      |    D    2    C    |
    2469:      |         |         |
    2470:      3----3----0----1----1
    2471:      |         |         |
    2472:      |    A    0    B    |
    2473:      |         |         |
    2474:      0---------0---------1
    2475:      */
    2476:     /* All cells have 4 faces */
    2477:     for (c = cStart; c < cEnd; ++c) {
    2478:       const PetscInt  newp = (c - cStart)*4;
    2479:       const PetscInt *cone, *ornt;
    2480:       PetscInt        coneNew[4], orntNew[4];

    2482:       DMPlexGetCone(dm, c, &cone);
    2483:       DMPlexGetConeOrientation(dm, c, &ornt);
    2484:       /* A quad */
    2485:       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
    2486:       orntNew[0] = ornt[0];
    2487:       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 0;
    2488:       orntNew[1] = 0;
    2489:       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 3;
    2490:       orntNew[2] = -2;
    2491:       coneNew[3] = fStartNew + (cone[3] - fStart)*2 + (ornt[3] < 0 ? 0 : 1);
    2492:       orntNew[3] = ornt[3];
    2493:       DMPlexSetCone(rdm, newp+0, coneNew);
    2494:       DMPlexSetConeOrientation(rdm, newp+0, orntNew);
    2495: #if defined(PETSC_USE_DEBUG)
    2496:       if ((newp+0 < cStartNew) || (newp+0 >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", newp+0, cStartNew, cEndNew);
    2497:       for (p = 0; p < 4; ++p) {
    2498:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", coneNew[p], fStartNew, fEndNew);
    2499:       }
    2500: #endif
    2501:       /* B quad */
    2502:       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
    2503:       orntNew[0] = ornt[0];
    2504:       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
    2505:       orntNew[1] = ornt[1];
    2506:       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 1;
    2507:       orntNew[2] = -2;
    2508:       coneNew[3] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 0;
    2509:       orntNew[3] = -2;
    2510:       DMPlexSetCone(rdm, newp+1, coneNew);
    2511:       DMPlexSetConeOrientation(rdm, newp+1, orntNew);
    2512: #if defined(PETSC_USE_DEBUG)
    2513:       if ((newp+1 < cStartNew) || (newp+1 >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", newp+1, cStartNew, cEndNew);
    2514:       for (p = 0; p < 4; ++p) {
    2515:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", coneNew[p], fStartNew, fEndNew);
    2516:       }
    2517: #endif
    2518:       /* C quad */
    2519:       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 1;
    2520:       orntNew[0] = 0;
    2521:       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
    2522:       orntNew[1] = ornt[1];
    2523:       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
    2524:       orntNew[2] = ornt[2];
    2525:       coneNew[3] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 2;
    2526:       orntNew[3] = -2;
    2527:       DMPlexSetCone(rdm, newp+2, coneNew);
    2528:       DMPlexSetConeOrientation(rdm, newp+2, orntNew);
    2529: #if defined(PETSC_USE_DEBUG)
    2530:       if ((newp+2 < cStartNew) || (newp+2 >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", newp+2, cStartNew, cEndNew);
    2531:       for (p = 0; p < 4; ++p) {
    2532:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", coneNew[p], fStartNew, fEndNew);
    2533:       }
    2534: #endif
    2535:       /* D quad */
    2536:       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 3;
    2537:       orntNew[0] = 0;
    2538:       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 2;
    2539:       orntNew[1] = 0;
    2540:       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
    2541:       orntNew[2] = ornt[2];
    2542:       coneNew[3] = fStartNew + (cone[3] - fStart)*2 + (ornt[3] < 0 ? 1 : 0);
    2543:       orntNew[3] = ornt[3];
    2544:       DMPlexSetCone(rdm, newp+3, coneNew);
    2545:       DMPlexSetConeOrientation(rdm, newp+3, orntNew);
    2546: #if defined(PETSC_USE_DEBUG)
    2547:       if ((newp+3 < cStartNew) || (newp+3 >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", newp+3, cStartNew, cEndNew);
    2548:       for (p = 0; p < 4; ++p) {
    2549:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", coneNew[p], fStartNew, fEndNew);
    2550:       }
    2551: #endif
    2552:     }
    2553:     /* Split faces have 2 vertices and the same cells as the parent */
    2554:     DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);
    2555:     PetscMalloc1(2 + maxSupportSize*2, &supportRef);
    2556:     for (f = fStart; f < fEnd; ++f) {
    2557:       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);

    2559:       for (r = 0; r < 2; ++r) {
    2560:         const PetscInt  newp = fStartNew + (f - fStart)*2 + r;
    2561:         const PetscInt *cone, *ornt, *support;
    2562:         PetscInt        coneNew[2], coneSize, c, supportSize, s;

    2564:         DMPlexGetCone(dm, f, &cone);
    2565:         coneNew[0]       = vStartNew + (cone[0] - vStart);
    2566:         coneNew[1]       = vStartNew + (cone[1] - vStart);
    2567:         coneNew[(r+1)%2] = newv;
    2568:         DMPlexSetCone(rdm, newp, coneNew);
    2569: #if defined(PETSC_USE_DEBUG)
    2570:         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
    2571:         for (p = 0; p < 2; ++p) {
    2572:           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", coneNew[p], vStartNew, vEndNew);
    2573:         }
    2574: #endif
    2575:         DMPlexGetSupportSize(dm, f, &supportSize);
    2576:         DMPlexGetSupport(dm, f, &support);
    2577:         for (s = 0; s < supportSize; ++s) {
    2578:           DMPlexGetConeSize(dm, support[s], &coneSize);
    2579:           DMPlexGetCone(dm, support[s], &cone);
    2580:           DMPlexGetConeOrientation(dm, support[s], &ornt);
    2581:           for (c = 0; c < coneSize; ++c) {
    2582:             if (cone[c] == f) break;
    2583:           }
    2584:           supportRef[s] = cStartNew + (support[s] - cStart)*4 + (ornt[c] < 0 ? (c+1-r)%4 : (c+r)%4);
    2585:         }
    2586:         DMPlexSetSupport(rdm, newp, supportRef);
    2587: #if defined(PETSC_USE_DEBUG)
    2588:         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
    2589:         for (p = 0; p < supportSize; ++p) {
    2590:           if ((supportRef[p] < cStartNew) || (supportRef[p] >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", supportRef[p], cStartNew, cEndNew);
    2591:         }
    2592: #endif
    2593:       }
    2594:     }
    2595:     /* Interior faces have 2 vertices and 2 cells */
    2596:     for (c = cStart; c < cEnd; ++c) {
    2597:       const PetscInt *cone;
    2598:       PetscInt        coneNew[2], supportNew[2];

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

    2604:         if (r==1 || r==2) {
    2605:           coneNew[0] = vStartNew + (vEnd - vStart) + (fEnd    - fStart) + (c - cStart);
    2606:           coneNew[1] = vStartNew + (vEnd - vStart) + (cone[r] - fStart);
    2607:         } else {
    2608:           coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r] - fStart);
    2609:           coneNew[1] = vStartNew + (vEnd - vStart) + (fEnd    - fStart) + (c - cStart);
    2610:         }
    2611:         DMPlexSetCone(rdm, newp, coneNew);
    2612: #if defined(PETSC_USE_DEBUG)
    2613:         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
    2614:         for (p = 0; p < 2; ++p) {
    2615:           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", coneNew[p], vStartNew, vEndNew);
    2616:         }
    2617: #endif
    2618:         supportNew[0] = (c - cStart)*4 + r;
    2619:         supportNew[1] = (c - cStart)*4 + (r+1)%4;
    2620:         DMPlexSetSupport(rdm, newp, supportNew);
    2621: #if defined(PETSC_USE_DEBUG)
    2622:         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
    2623:         for (p = 0; p < 2; ++p) {
    2624:           if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", supportNew[p], cStartNew, cEndNew);
    2625:         }
    2626: #endif
    2627:       }
    2628:     }
    2629:     /* Old vertices have identical supports */
    2630:     for (v = vStart; v < vEnd; ++v) {
    2631:       const PetscInt  newp = vStartNew + (v - vStart);
    2632:       const PetscInt *support, *cone;
    2633:       PetscInt        size, s;

    2635:       DMPlexGetSupportSize(dm, v, &size);
    2636:       DMPlexGetSupport(dm, v, &support);
    2637:       for (s = 0; s < size; ++s) {
    2638:         PetscInt r = 0;

    2640:         DMPlexGetCone(dm, support[s], &cone);
    2641:         if (cone[1] == v) r = 1;
    2642:         supportRef[s] = fStartNew + (support[s] - fStart)*2 + r;
    2643:       }
    2644:       DMPlexSetSupport(rdm, newp, supportRef);
    2645: #if defined(PETSC_USE_DEBUG)
    2646:       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", newp, vStartNew, vEndNew);
    2647:       for (p = 0; p < size; ++p) {
    2648:         if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", supportRef[p], fStartNew, fEndNew);
    2649:       }
    2650: #endif
    2651:     }
    2652:     /* Face vertices have 2 + cells supports */
    2653:     for (f = fStart; f < fEnd; ++f) {
    2654:       const PetscInt  newp = vStartNew + (vEnd - vStart) + (f - fStart);
    2655:       const PetscInt *cone, *support;
    2656:       PetscInt        size, s;

    2658:       DMPlexGetSupportSize(dm, f, &size);
    2659:       DMPlexGetSupport(dm, f, &support);
    2660:       supportRef[0] = fStartNew + (f - fStart)*2 + 0;
    2661:       supportRef[1] = fStartNew + (f - fStart)*2 + 1;
    2662:       for (s = 0; s < size; ++s) {
    2663:         PetscInt r = 0;

    2665:         DMPlexGetCone(dm, support[s], &cone);
    2666:         if      (cone[1] == f) r = 1;
    2667:         else if (cone[2] == f) r = 2;
    2668:         else if (cone[3] == f) r = 3;
    2669:         supportRef[2+s] = fStartNew + (fEnd - fStart)*2 + (support[s] - cStart)*4 + r;
    2670:       }
    2671:       DMPlexSetSupport(rdm, newp, supportRef);
    2672: #if defined(PETSC_USE_DEBUG)
    2673:       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", newp, vStartNew, vEndNew);
    2674:       for (p = 0; p < 2+size; ++p) {
    2675:         if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", supportRef[p], fStartNew, fEndNew);
    2676:       }
    2677: #endif
    2678:     }
    2679:     /* Cell vertices have 4 supports */
    2680:     for (c = cStart; c < cEnd; ++c) {
    2681:       const PetscInt newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (c - cStart);
    2682:       PetscInt       supportNew[4];

    2684:       for (r = 0; r < 4; ++r) {
    2685:         supportNew[r] = fStartNew + (fEnd - fStart)*2 + (c - cStart)*4 + r;
    2686:       }
    2687:       DMPlexSetSupport(rdm, newp, supportNew);
    2688:     }
    2689:     PetscFree(supportRef);
    2690:     break;
    2691:   case REFINER_HYBRID_SIMPLEX_2D:
    2692:     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
    2693:     cMax = PetscMin(cEnd, cMax);
    2694:     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
    2695:     fMax = PetscMin(fEnd, fMax);
    2696:     DMPlexGetHybridBounds(rdm, &cMaxNew, &fMaxNew, NULL, NULL);
    2697:     /* Interior cells have 3 faces */
    2698:     for (c = cStart; c < cMax; ++c) {
    2699:       const PetscInt  newp = cStartNew + (c - cStart)*4;
    2700:       const PetscInt *cone, *ornt;
    2701:       PetscInt        coneNew[3], orntNew[3];

    2703:       DMPlexGetCone(dm, c, &cone);
    2704:       DMPlexGetConeOrientation(dm, c, &ornt);
    2705:       /* A triangle */
    2706:       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
    2707:       orntNew[0] = ornt[0];
    2708:       coneNew[1] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 2;
    2709:       orntNew[1] = -2;
    2710:       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
    2711:       orntNew[2] = ornt[2];
    2712:       DMPlexSetCone(rdm, newp+0, coneNew);
    2713:       DMPlexSetConeOrientation(rdm, newp+0, orntNew);
    2714: #if defined(PETSC_USE_DEBUG)
    2715:       if ((newp+0 < cStartNew) || (newp+0 >= cMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an interior cell [%D, %D)", newp+0, cStartNew, cMaxNew);
    2716:       for (p = 0; p < 3; ++p) {
    2717:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an interior face [%D, %D)", coneNew[p], fStartNew, fMaxNew);
    2718:       }
    2719: #endif
    2720:       /* B triangle */
    2721:       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
    2722:       orntNew[0] = ornt[0];
    2723:       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
    2724:       orntNew[1] = ornt[1];
    2725:       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 0;
    2726:       orntNew[2] = -2;
    2727:       DMPlexSetCone(rdm, newp+1, coneNew);
    2728:       DMPlexSetConeOrientation(rdm, newp+1, orntNew);
    2729: #if defined(PETSC_USE_DEBUG)
    2730:       if ((newp+1 < cStartNew) || (newp+1 >= cMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an interior cell [%D, %D)", newp+1, cStartNew, cMaxNew);
    2731:       for (p = 0; p < 3; ++p) {
    2732:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an interior face [%D, %D)", coneNew[p], fStartNew, fMaxNew);
    2733:       }
    2734: #endif
    2735:       /* C triangle */
    2736:       coneNew[0] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 1;
    2737:       orntNew[0] = -2;
    2738:       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
    2739:       orntNew[1] = ornt[1];
    2740:       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
    2741:       orntNew[2] = ornt[2];
    2742:       DMPlexSetCone(rdm, newp+2, coneNew);
    2743:       DMPlexSetConeOrientation(rdm, newp+2, orntNew);
    2744: #if defined(PETSC_USE_DEBUG)
    2745:       if ((newp+2 < cStartNew) || (newp+2 >= cMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an interior cell [%D, %D)", newp+2, cStartNew, cMaxNew);
    2746:       for (p = 0; p < 3; ++p) {
    2747:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an interior face [%D, %D)", coneNew[p], fStartNew, fMaxNew);
    2748:       }
    2749: #endif
    2750:       /* D triangle */
    2751:       coneNew[0] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 0;
    2752:       orntNew[0] = 0;
    2753:       coneNew[1] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 1;
    2754:       orntNew[1] = 0;
    2755:       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 2;
    2756:       orntNew[2] = 0;
    2757:       DMPlexSetCone(rdm, newp+3, coneNew);
    2758:       DMPlexSetConeOrientation(rdm, newp+3, orntNew);
    2759: #if defined(PETSC_USE_DEBUG)
    2760:       if ((newp+3 < cStartNew) || (newp+3 >= cMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an interior cell [%D, %D)", newp+3, cStartNew, cMaxNew);
    2761:       for (p = 0; p < 3; ++p) {
    2762:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an interior face [%D, %D)", coneNew[p], fStartNew, fMaxNew);
    2763:       }
    2764: #endif
    2765:     }
    2766:     /*
    2767:      2----3----3
    2768:      |         |
    2769:      |    B    |
    2770:      |         |
    2771:      0----4--- 1
    2772:      |         |
    2773:      |    A    |
    2774:      |         |
    2775:      0----2----1
    2776:      */
    2777:     /* Hybrid cells have 4 faces */
    2778:     for (c = cMax; c < cEnd; ++c) {
    2779:       const PetscInt  newp = cStartNew + (cMax - cStart)*4 + (c - cMax)*2;
    2780:       const PetscInt *cone, *ornt;
    2781:       PetscInt        coneNew[4], orntNew[4], r;

    2783:       DMPlexGetCone(dm, c, &cone);
    2784:       DMPlexGetConeOrientation(dm, c, &ornt);
    2785:       r    = (ornt[0] < 0 ? 1 : 0);
    2786:       /* A quad */
    2787:       coneNew[0]   = fStartNew + (cone[0] - fStart)*2 + r;
    2788:       orntNew[0]   = ornt[0];
    2789:       coneNew[1]   = fStartNew + (cone[1] - fStart)*2 + r;
    2790:       orntNew[1]   = ornt[1];
    2791:       coneNew[2+r] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (cone[2+r] - fMax);
    2792:       orntNew[2+r] = 0;
    2793:       coneNew[3-r] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (fEnd    - fMax) + (c - cMax);
    2794:       orntNew[3-r] = 0;
    2795:       DMPlexSetCone(rdm, newp+0, coneNew);
    2796:       DMPlexSetConeOrientation(rdm, newp+0, orntNew);
    2797: #if defined(PETSC_USE_DEBUG)
    2798:       if ((newp+0 < cStartNew) || (newp+0 >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", newp+0, cStartNew, cEndNew);
    2799:       for (p = 0; p < 4; ++p) {
    2800:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", coneNew[p], fStartNew, fEndNew);
    2801:       }
    2802: #endif
    2803:       /* B quad */
    2804:       coneNew[0]   = fStartNew + (cone[0] - fStart)*2 + 1-r;
    2805:       orntNew[0]   = ornt[0];
    2806:       coneNew[1]   = fStartNew + (cone[1] - fStart)*2 + 1-r;
    2807:       orntNew[1]   = ornt[1];
    2808:       coneNew[2+r] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (fEnd    - fMax) + (c - cMax);
    2809:       orntNew[2+r] = 0;
    2810:       coneNew[3-r] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (cone[3-r] - fMax);
    2811:       orntNew[3-r] = 0;
    2812:       DMPlexSetCone(rdm, newp+1, coneNew);
    2813:       DMPlexSetConeOrientation(rdm, newp+1, orntNew);
    2814: #if defined(PETSC_USE_DEBUG)
    2815:       if ((newp+1 < cStartNew) || (newp+1 >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", newp+1, cStartNew, cEndNew);
    2816:       for (p = 0; p < 4; ++p) {
    2817:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", coneNew[p], fStartNew, fEndNew);
    2818:       }
    2819: #endif
    2820:     }
    2821:     /* Interior split faces have 2 vertices and the same cells as the parent */
    2822:     DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);
    2823:     PetscMalloc1(2 + maxSupportSize*2, &supportRef);
    2824:     for (f = fStart; f < fMax; ++f) {
    2825:       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);

    2827:       for (r = 0; r < 2; ++r) {
    2828:         const PetscInt  newp = fStartNew + (f - fStart)*2 + r;
    2829:         const PetscInt *cone, *ornt, *support;
    2830:         PetscInt        coneNew[2], coneSize, c, supportSize, s;

    2832:         DMPlexGetCone(dm, f, &cone);
    2833:         coneNew[0]       = vStartNew + (cone[0] - vStart);
    2834:         coneNew[1]       = vStartNew + (cone[1] - vStart);
    2835:         coneNew[(r+1)%2] = newv;
    2836:         DMPlexSetCone(rdm, newp, coneNew);
    2837: #if defined(PETSC_USE_DEBUG)
    2838:         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
    2839:         for (p = 0; p < 2; ++p) {
    2840:           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", coneNew[p], vStartNew, vEndNew);
    2841:         }
    2842: #endif
    2843:         DMPlexGetSupportSize(dm, f, &supportSize);
    2844:         DMPlexGetSupport(dm, f, &support);
    2845:         for (s = 0; s < supportSize; ++s) {
    2846:           DMPlexGetConeSize(dm, support[s], &coneSize);
    2847:           DMPlexGetCone(dm, support[s], &cone);
    2848:           DMPlexGetConeOrientation(dm, support[s], &ornt);
    2849:           for (c = 0; c < coneSize; ++c) if (cone[c] == f) break;
    2850:           if (support[s] >= cMax) {
    2851:             supportRef[s] = cStartNew + (cMax - cStart)*4 + (support[s] - cMax)*2 + (ornt[c] < 0 ? 1-r : r);
    2852:           } else {
    2853:             supportRef[s] = cStartNew + (support[s] - cStart)*4 + (ornt[c] < 0 ? (c+1-r)%3 : (c+r)%3);
    2854:           }
    2855:         }
    2856:         DMPlexSetSupport(rdm, newp, supportRef);
    2857: #if defined(PETSC_USE_DEBUG)
    2858:         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
    2859:         for (p = 0; p < supportSize; ++p) {
    2860:           if ((supportRef[p] < cStartNew) || (supportRef[p] >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", supportRef[p], cStartNew, cEndNew);
    2861:         }
    2862: #endif
    2863:       }
    2864:     }
    2865:     /* Interior cell faces have 2 vertices and 2 cells */
    2866:     for (c = cStart; c < cMax; ++c) {
    2867:       const PetscInt *cone;

    2869:       DMPlexGetCone(dm, c, &cone);
    2870:       for (r = 0; r < 3; ++r) {
    2871:         const PetscInt newp = fStartNew + (fMax - fStart)*2 + (c - cStart)*3 + r;
    2872:         PetscInt       coneNew[2];
    2873:         PetscInt       supportNew[2];

    2875:         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r]       - fStart);
    2876:         coneNew[1] = vStartNew + (vEnd - vStart) + (cone[(r+1)%3] - fStart);
    2877:         DMPlexSetCone(rdm, newp, coneNew);
    2878: #if defined(PETSC_USE_DEBUG)
    2879:         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
    2880:         for (p = 0; p < 2; ++p) {
    2881:           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", coneNew[p], vStartNew, vEndNew);
    2882:         }
    2883: #endif
    2884:         supportNew[0] = (c - cStart)*4 + (r+1)%3;
    2885:         supportNew[1] = (c - cStart)*4 + 3;
    2886:         DMPlexSetSupport(rdm, newp, supportNew);
    2887: #if defined(PETSC_USE_DEBUG)
    2888:         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
    2889:         for (p = 0; p < 2; ++p) {
    2890:           if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", supportNew[p], cStartNew, cEndNew);
    2891:         }
    2892: #endif
    2893:       }
    2894:     }
    2895:     /* Interior hybrid faces have 2 vertices and the same cells */
    2896:     for (f = fMax; f < fEnd; ++f) {
    2897:       const PetscInt  newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (f - fMax);
    2898:       const PetscInt *cone, *ornt;
    2899:       const PetscInt *support;
    2900:       PetscInt        coneNew[2];
    2901:       PetscInt        supportNew[2];
    2902:       PetscInt        size, s, r;

    2904:       DMPlexGetCone(dm, f, &cone);
    2905:       coneNew[0] = vStartNew + (cone[0] - vStart);
    2906:       coneNew[1] = vStartNew + (cone[1] - vStart);
    2907:       DMPlexSetCone(rdm, newp, coneNew);
    2908: #if defined(PETSC_USE_DEBUG)
    2909:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
    2910:       for (p = 0; p < 2; ++p) {
    2911:         if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", coneNew[p], vStartNew, vEndNew);
    2912:       }
    2913: #endif
    2914:       DMPlexGetSupportSize(dm, f, &size);
    2915:       DMPlexGetSupport(dm, f, &support);
    2916:       for (s = 0; s < size; ++s) {
    2917:         DMPlexGetCone(dm, support[s], &cone);
    2918:         DMPlexGetConeOrientation(dm, support[s], &ornt);
    2919:         for (r = 0; r < 2; ++r) {
    2920:           if (cone[r+2] == f) break;
    2921:         }
    2922:         supportNew[s] = (cMax - cStart)*4 + (support[s] - cMax)*2 + (ornt[0] < 0 ? 1-r : r);
    2923:       }
    2924:       DMPlexSetSupport(rdm, newp, supportNew);
    2925: #if defined(PETSC_USE_DEBUG)
    2926:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
    2927:       for (p = 0; p < size; ++p) {
    2928:         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", supportNew[p], cStartNew, cEndNew);
    2929:       }
    2930: #endif
    2931:     }
    2932:     /* Cell hybrid faces have 2 vertices and 2 cells */
    2933:     for (c = cMax; c < cEnd; ++c) {
    2934:       const PetscInt  newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (fEnd - fMax) + (c - cMax);
    2935:       const PetscInt *cone;
    2936:       PetscInt        coneNew[2];
    2937:       PetscInt        supportNew[2];

    2939:       DMPlexGetCone(dm, c, &cone);
    2940:       coneNew[0] = vStartNew + (vEnd - vStart) + (cone[0] - fStart);
    2941:       coneNew[1] = vStartNew + (vEnd - vStart) + (cone[1] - fStart);
    2942:       DMPlexSetCone(rdm, newp, coneNew);
    2943: #if defined(PETSC_USE_DEBUG)
    2944:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
    2945:       for (p = 0; p < 2; ++p) {
    2946:         if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", coneNew[p], vStartNew, vEndNew);
    2947:       }
    2948: #endif
    2949:       supportNew[0] = (cMax - cStart)*4 + (c - cMax)*2 + 0;
    2950:       supportNew[1] = (cMax - cStart)*4 + (c - cMax)*2 + 1;
    2951:       DMPlexSetSupport(rdm, newp, supportNew);
    2952: #if defined(PETSC_USE_DEBUG)
    2953:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
    2954:       for (p = 0; p < 2; ++p) {
    2955:         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", supportNew[p], cStartNew, cEndNew);
    2956:       }
    2957: #endif
    2958:     }
    2959:     /* Old vertices have identical supports */
    2960:     for (v = vStart; v < vEnd; ++v) {
    2961:       const PetscInt  newp = vStartNew + (v - vStart);
    2962:       const PetscInt *support, *cone;
    2963:       PetscInt        size, s;

    2965:       DMPlexGetSupportSize(dm, v, &size);
    2966:       DMPlexGetSupport(dm, v, &support);
    2967:       for (s = 0; s < size; ++s) {
    2968:         if (support[s] >= fMax) {
    2969:           supportRef[s] = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (support[s] - fMax);
    2970:         } else {
    2971:           PetscInt r = 0;

    2973:           DMPlexGetCone(dm, support[s], &cone);
    2974:           if (cone[1] == v) r = 1;
    2975:           supportRef[s] = fStartNew + (support[s] - fStart)*2 + r;
    2976:         }
    2977:       }
    2978:       DMPlexSetSupport(rdm, newp, supportRef);
    2979: #if defined(PETSC_USE_DEBUG)
    2980:       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", newp, vStartNew, vEndNew);
    2981:       for (p = 0; p < size; ++p) {
    2982:         if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", supportRef[p], fStartNew, fEndNew);
    2983:       }
    2984: #endif
    2985:     }
    2986:     /* Face vertices have 2 + (2 interior, 1 hybrid) supports */
    2987:     for (f = fStart; f < fMax; ++f) {
    2988:       const PetscInt  newp = vStartNew + (vEnd - vStart) + (f - fStart);
    2989:       const PetscInt *cone, *support;
    2990:       PetscInt        size, newSize = 2, s;

    2992:       DMPlexGetSupportSize(dm, f, &size);
    2993:       DMPlexGetSupport(dm, f, &support);
    2994:       supportRef[0] = fStartNew + (f - fStart)*2 + 0;
    2995:       supportRef[1] = fStartNew + (f - fStart)*2 + 1;
    2996:       for (s = 0; s < size; ++s) {
    2997:         PetscInt r = 0;

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

    3003:           newSize += 1;
    3004:         } else {
    3005:           if      (cone[1] == f) r = 1;
    3006:           else if (cone[2] == f) r = 2;
    3007:           supportRef[newSize+0] = fStartNew + (fMax - fStart)*2 + (support[s] - cStart)*3 + (r+2)%3;
    3008:           supportRef[newSize+1] = fStartNew + (fMax - fStart)*2 + (support[s] - cStart)*3 + r;

    3010:           newSize += 2;
    3011:         }
    3012:       }
    3013:       DMPlexSetSupport(rdm, newp, supportRef);
    3014: #if defined(PETSC_USE_DEBUG)
    3015:       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", newp, vStartNew, vEndNew);
    3016:       for (p = 0; p < newSize; ++p) {
    3017:         if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", supportRef[p], fStartNew, fEndNew);
    3018:       }
    3019: #endif
    3020:     }
    3021:     PetscFree(supportRef);
    3022:     break;
    3023:   case REFINER_HYBRID_HEX_2D:
    3024:     /* Hybrid Hex 2D */
    3025:     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
    3026:     cMax = PetscMin(cEnd, cMax);
    3027:     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
    3028:     fMax = PetscMin(fEnd, fMax);
    3029:     DMPlexGetHybridBounds(rdm, &cMaxNew, &fMaxNew, NULL, NULL);
    3030:     /* Interior cells have 4 faces */
    3031:     for (c = cStart; c < cMax; ++c) {
    3032:       const PetscInt  newp = cStartNew + (c - cStart)*4;
    3033:       const PetscInt *cone, *ornt;
    3034:       PetscInt        coneNew[4], orntNew[4];

    3036:       DMPlexGetCone(dm, c, &cone);
    3037:       DMPlexGetConeOrientation(dm, c, &ornt);
    3038:       /* A quad */
    3039:       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
    3040:       orntNew[0] = ornt[0];
    3041:       coneNew[1] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*4 + 0;
    3042:       orntNew[1] = 0;
    3043:       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*4 + 3;
    3044:       orntNew[2] = -2;
    3045:       coneNew[3] = fStartNew + (cone[3] - fStart)*2 + (ornt[3] < 0 ? 0 : 1);
    3046:       orntNew[3] = ornt[3];
    3047:       DMPlexSetCone(rdm, newp+0, coneNew);
    3048:       DMPlexSetConeOrientation(rdm, newp+0, orntNew);
    3049: #if defined(PETSC_USE_DEBUG)
    3050:       if ((newp+0 < cStartNew) || (newp+0 >= cMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an interior cell [%D, %D)", newp+0, cStartNew, cMaxNew);
    3051:       for (p = 0; p < 4; ++p) {
    3052:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an interior face [%D, %D)", coneNew[p], fStartNew, fMaxNew);
    3053:       }
    3054: #endif
    3055:       /* B quad */
    3056:       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
    3057:       orntNew[0] = ornt[0];
    3058:       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
    3059:       orntNew[1] = ornt[1];
    3060:       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*4 + 1;
    3061:       orntNew[2] = 0;
    3062:       coneNew[3] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*4 + 0;
    3063:       orntNew[3] = -2;
    3064:       DMPlexSetCone(rdm, newp+1, coneNew);
    3065:       DMPlexSetConeOrientation(rdm, newp+1, orntNew);
    3066: #if defined(PETSC_USE_DEBUG)
    3067:       if ((newp+1 < cStartNew) || (newp+1 >= cMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an interior cell [%D, %D)", newp+1, cStartNew, cMaxNew);
    3068:       for (p = 0; p < 4; ++p) {
    3069:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an interior face [%D, %D)", coneNew[p], fStartNew, fMaxNew);
    3070:       }
    3071: #endif
    3072:       /* C quad */
    3073:       coneNew[0] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*4 + 1;
    3074:       orntNew[0] = -2;
    3075:       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
    3076:       orntNew[1] = ornt[1];
    3077:       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
    3078:       orntNew[2] = ornt[2];
    3079:       coneNew[3] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*4 + 2;
    3080:       orntNew[3] = 0;
    3081:       DMPlexSetCone(rdm, newp+2, coneNew);
    3082:       DMPlexSetConeOrientation(rdm, newp+2, orntNew);
    3083: #if defined(PETSC_USE_DEBUG)
    3084:       if ((newp+2 < cStartNew) || (newp+2 >= cMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an interior cell [%D, %D)", newp+2, cStartNew, cMaxNew);
    3085:       for (p = 0; p < 4; ++p) {
    3086:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an interior face [%D, %D)", coneNew[p], fStartNew, fMaxNew);
    3087:       }
    3088: #endif
    3089:       /* D quad */
    3090:       coneNew[0] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*4 + 3;
    3091:       orntNew[0] = 0;
    3092:       coneNew[1] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*4 + 2;
    3093:       orntNew[1] = -2;
    3094:       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
    3095:       orntNew[2] = ornt[2];
    3096:       coneNew[3] = fStartNew + (cone[3] - fStart)*2 + (ornt[3] < 0 ? 1 : 0);
    3097:       orntNew[3] = ornt[3];
    3098:       DMPlexSetCone(rdm, newp+3, coneNew);
    3099:       DMPlexSetConeOrientation(rdm, newp+3, orntNew);
    3100: #if defined(PETSC_USE_DEBUG)
    3101:       if ((newp+3 < cStartNew) || (newp+3 >= cMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an interior cell [%D, %D)", newp+3, cStartNew, cMaxNew);
    3102:       for (p = 0; p < 4; ++p) {
    3103:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an interior face [%D, %D)", coneNew[p], fStartNew, fMaxNew);
    3104:       }
    3105: #endif
    3106:     }
    3107:     /*
    3108:      2----3----3
    3109:      |         |
    3110:      |    B    |
    3111:      |         |
    3112:      0----4--- 1
    3113:      |         |
    3114:      |    A    |
    3115:      |         |
    3116:      0----2----1
    3117:      */
    3118:     /* Hybrid cells have 4 faces */
    3119:     for (c = cMax; c < cEnd; ++c) {
    3120:       const PetscInt  newp = cStartNew + (cMax - cStart)*4 + (c - cMax)*2;
    3121:       const PetscInt *cone, *ornt;
    3122:       PetscInt        coneNew[4], orntNew[4];

    3124:       DMPlexGetCone(dm, c, &cone);
    3125:       DMPlexGetConeOrientation(dm, c, &ornt);
    3126:       /* A quad */
    3127:       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
    3128:       orntNew[0] = ornt[0];
    3129:       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
    3130:       orntNew[1] = ornt[1];
    3131:       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*4 + (cone[2] - fMax);
    3132:       orntNew[2] = 0;
    3133:       coneNew[3] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*4 + (fEnd    - fMax) + (c - cMax);
    3134:       orntNew[3] = 0;
    3135:       DMPlexSetCone(rdm, newp+0, coneNew);
    3136:       DMPlexSetConeOrientation(rdm, newp+0, orntNew);
    3137: #if defined(PETSC_USE_DEBUG)
    3138:       if ((newp+0 < cStartNew) || (newp+0 >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", newp+0, cStartNew, cEndNew);
    3139:       for (p = 0; p < 4; ++p) {
    3140:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", coneNew[p], fStartNew, fEndNew);
    3141:       }
    3142: #endif
    3143:       /* B quad */
    3144:       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
    3145:       orntNew[0] = ornt[0];
    3146:       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
    3147:       orntNew[1] = ornt[1];
    3148:       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*4 + (fEnd    - fMax) + (c - cMax);
    3149:       orntNew[2] = 0;
    3150:       coneNew[3] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*4 + (cone[3] - fMax);
    3151:       orntNew[3] = 0;
    3152:       DMPlexSetCone(rdm, newp+1, coneNew);
    3153:       DMPlexSetConeOrientation(rdm, newp+1, orntNew);
    3154: #if defined(PETSC_USE_DEBUG)
    3155:       if ((newp+1 < cStartNew) || (newp+1 >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", newp+1, cStartNew, cEndNew);
    3156:       for (p = 0; p < 4; ++p) {
    3157:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", coneNew[p], fStartNew, fEndNew);
    3158:       }
    3159: #endif
    3160:     }
    3161:     /* Interior split faces have 2 vertices and the same cells as the parent */
    3162:     DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);
    3163:     PetscMalloc1(2 + maxSupportSize*2, &supportRef);
    3164:     for (f = fStart; f < fMax; ++f) {
    3165:       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);

    3167:       for (r = 0; r < 2; ++r) {
    3168:         const PetscInt  newp = fStartNew + (f - fStart)*2 + r;
    3169:         const PetscInt *cone, *ornt, *support;
    3170:         PetscInt        coneNew[2], coneSize, c, supportSize, s;

    3172:         DMPlexGetCone(dm, f, &cone);
    3173:         coneNew[0]       = vStartNew + (cone[0] - vStart);
    3174:         coneNew[1]       = vStartNew + (cone[1] - vStart);
    3175:         coneNew[(r+1)%2] = newv;
    3176:         DMPlexSetCone(rdm, newp, coneNew);
    3177: #if defined(PETSC_USE_DEBUG)
    3178:         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
    3179:         for (p = 0; p < 2; ++p) {
    3180:           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", coneNew[p], vStartNew, vEndNew);
    3181:         }
    3182: #endif
    3183:         DMPlexGetSupportSize(dm, f, &supportSize);
    3184:         DMPlexGetSupport(dm, f, &support);
    3185:         for (s = 0; s < supportSize; ++s) {
    3186:           if (support[s] >= cMax) {
    3187:             supportRef[s] = cStartNew + (cMax - cStart)*4 + (support[s] - cMax)*2 + r;
    3188:           } else {
    3189:             DMPlexGetConeSize(dm, support[s], &coneSize);
    3190:             DMPlexGetCone(dm, support[s], &cone);
    3191:             DMPlexGetConeOrientation(dm, support[s], &ornt);
    3192:             for (c = 0; c < coneSize; ++c) {
    3193:               if (cone[c] == f) break;
    3194:             }
    3195:             supportRef[s] = cStartNew + (support[s] - cStart)*4 + (ornt[c] < 0 ? (c+1-r)%4 : (c+r)%4);
    3196:           }
    3197:         }
    3198:         DMPlexSetSupport(rdm, newp, supportRef);
    3199: #if defined(PETSC_USE_DEBUG)
    3200:         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
    3201:         for (p = 0; p < supportSize; ++p) {
    3202:           if ((supportRef[p] < cStartNew) || (supportRef[p] >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", supportRef[p], cStartNew, cEndNew);
    3203:         }
    3204: #endif
    3205:       }
    3206:     }
    3207:     /* Interior cell faces have 2 vertices and 2 cells */
    3208:     for (c = cStart; c < cMax; ++c) {
    3209:       const PetscInt *cone;

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

    3216:         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r] - fStart);
    3217:         coneNew[1] = vStartNew + (vEnd - vStart) + (fMax    - fStart) + (c - cStart);
    3218:         DMPlexSetCone(rdm, newp, coneNew);
    3219: #if defined(PETSC_USE_DEBUG)
    3220:         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
    3221:         for (p = 0; p < 2; ++p) {
    3222:           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", coneNew[p], vStartNew, vEndNew);
    3223:         }
    3224: #endif
    3225:         supportNew[0] = (c - cStart)*4 + r;
    3226:         supportNew[1] = (c - cStart)*4 + (r+1)%4;
    3227:         DMPlexSetSupport(rdm, newp, supportNew);
    3228: #if defined(PETSC_USE_DEBUG)
    3229:         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
    3230:         for (p = 0; p < 2; ++p) {
    3231:           if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", supportNew[p], cStartNew, cEndNew);
    3232:         }
    3233: #endif
    3234:       }
    3235:     }
    3236:     /* Hybrid faces have 2 vertices and the same cells */
    3237:     for (f = fMax; f < fEnd; ++f) {
    3238:       const PetscInt  newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*4 + (f - fMax);
    3239:       const PetscInt *cone, *support;
    3240:       PetscInt        coneNew[2], supportNew[2];
    3241:       PetscInt        size, s, r;

    3243:       DMPlexGetCone(dm, f, &cone);
    3244:       coneNew[0] = vStartNew + (cone[0] - vStart);
    3245:       coneNew[1] = vStartNew + (cone[1] - vStart);
    3246:       DMPlexSetCone(rdm, newp, coneNew);
    3247: #if defined(PETSC_USE_DEBUG)
    3248:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
    3249:       for (p = 0; p < 2; ++p) {
    3250:         if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", coneNew[p], vStartNew, vEndNew);
    3251:       }
    3252: #endif
    3253:       DMPlexGetSupportSize(dm, f, &size);
    3254:       DMPlexGetSupport(dm, f, &support);
    3255:       for (s = 0; s < size; ++s) {
    3256:         DMPlexGetCone(dm, support[s], &cone);
    3257:         for (r = 0; r < 2; ++r) {
    3258:           if (cone[r+2] == f) break;
    3259:         }
    3260:         supportNew[s] = (cMax - cStart)*4 + (support[s] - cMax)*2 + r;
    3261:       }
    3262:       DMPlexSetSupport(rdm, newp, supportNew);
    3263: #if defined(PETSC_USE_DEBUG)
    3264:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
    3265:       for (p = 0; p < size; ++p) {
    3266:         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", supportNew[p], cStartNew, cEndNew);
    3267:       }
    3268: #endif
    3269:     }
    3270:     /* Cell hybrid faces have 2 vertices and 2 cells */
    3271:     for (c = cMax; c < cEnd; ++c) {
    3272:       const PetscInt  newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*4 + (fEnd - fMax) + (c - cMax);
    3273:       const PetscInt *cone;
    3274:       PetscInt        coneNew[2], supportNew[2];

    3276:       DMPlexGetCone(dm, c, &cone);
    3277:       coneNew[0] = vStartNew + (vEnd - vStart) + (cone[0] - fStart);
    3278:       coneNew[1] = vStartNew + (vEnd - vStart) + (cone[1] - fStart);
    3279:       DMPlexSetCone(rdm, newp, coneNew);
    3280: #if defined(PETSC_USE_DEBUG)
    3281:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
    3282:       for (p = 0; p < 2; ++p) {
    3283:         if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", coneNew[p], vStartNew, vEndNew);
    3284:       }
    3285: #endif
    3286:       supportNew[0] = (cMax - cStart)*4 + (c - cMax)*2 + 0;
    3287:       supportNew[1] = (cMax - cStart)*4 + (c - cMax)*2 + 1;
    3288:       DMPlexSetSupport(rdm, newp, supportNew);
    3289: #if defined(PETSC_USE_DEBUG)
    3290:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
    3291:       for (p = 0; p < 2; ++p) {
    3292:         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", supportNew[p], cStartNew, cEndNew);
    3293:       }
    3294: #endif
    3295:     }
    3296:     /* Old vertices have identical supports */
    3297:     for (v = vStart; v < vEnd; ++v) {
    3298:       const PetscInt  newp = vStartNew + (v - vStart);
    3299:       const PetscInt *support, *cone;
    3300:       PetscInt        size, s;

    3302:       DMPlexGetSupportSize(dm, v, &size);
    3303:       DMPlexGetSupport(dm, v, &support);
    3304:       for (s = 0; s < size; ++s) {
    3305:         if (support[s] >= fMax) {
    3306:           supportRef[s] = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*4 + (support[s] - fMax);
    3307:         } else {
    3308:           PetscInt r = 0;

    3310:           DMPlexGetCone(dm, support[s], &cone);
    3311:           if (cone[1] == v) r = 1;
    3312:           supportRef[s] = fStartNew + (support[s] - fStart)*2 + r;
    3313:         }
    3314:       }
    3315:       DMPlexSetSupport(rdm, newp, supportRef);
    3316: #if defined(PETSC_USE_DEBUG)
    3317:       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", newp, vStartNew, vEndNew);
    3318:       for (p = 0; p < size; ++p) {
    3319:         if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", supportRef[p], fStartNew, fEndNew);
    3320:       }
    3321: #endif
    3322:     }
    3323:     /* Face vertices have 2 + cells supports */
    3324:     for (f = fStart; f < fMax; ++f) {
    3325:       const PetscInt  newp = vStartNew + (vEnd - vStart) + (f - fStart);
    3326:       const PetscInt *cone, *support;
    3327:       PetscInt        size, s;

    3329:       DMPlexGetSupportSize(dm, f, &size);
    3330:       DMPlexGetSupport(dm, f, &support);
    3331:       supportRef[0] = fStartNew + (f - fStart)*2 + 0;
    3332:       supportRef[1] = fStartNew + (f - fStart)*2 + 1;
    3333:       for (s = 0; s < size; ++s) {
    3334:         PetscInt r = 0;

    3336:         DMPlexGetCone(dm, support[s], &cone);
    3337:         if (support[s] >= cMax) {
    3338:           supportRef[2+s] = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*4 + (fEnd - fMax) + (support[s] - cMax);
    3339:         } else {
    3340:           if      (cone[1] == f) r = 1;
    3341:           else if (cone[2] == f) r = 2;
    3342:           else if (cone[3] == f) r = 3;
    3343:           supportRef[2+s] = fStartNew + (fMax - fStart)*2 + (support[s] - cStart)*4 + r;
    3344:         }
    3345:       }
    3346:       DMPlexSetSupport(rdm, newp, supportRef);
    3347: #if defined(PETSC_USE_DEBUG)
    3348:       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", newp, vStartNew, vEndNew);
    3349:       for (p = 0; p < 2+size; ++p) {
    3350:         if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", supportRef[p], fStartNew, fEndNew);
    3351:       }
    3352: #endif
    3353:     }
    3354:     /* Cell vertices have 4 supports */
    3355:     for (c = cStart; c < cMax; ++c) {
    3356:       const PetscInt newp = vStartNew + (vEnd - vStart) + (fMax - fStart) + (c - cStart);
    3357:       PetscInt       supportNew[4];

    3359:       for (r = 0; r < 4; ++r) {
    3360:         supportNew[r] = fStartNew + (fMax - fStart)*2 + (c - cStart)*4 + r;
    3361:       }
    3362:       DMPlexSetSupport(rdm, newp, supportNew);
    3363:     }
    3364:     PetscFree(supportRef);
    3365:     break;
    3366:   case REFINER_SIMPLEX_3D:
    3367:     /* All cells have 4 faces: Tet face order is prescribed in DMPlexGetFaces_Internal() */
    3368:     DMPlexGetRawFaces_Internal(dm, 3, 4, cellInd, NULL, NULL, &faces);
    3369:     for (c = cStart; c < cEnd; ++c) {
    3370:       const PetscInt  newp = cStartNew + (c - cStart)*8;
    3371:       const PetscInt *cone, *ornt;
    3372:       PetscInt        coneNew[4], orntNew[4];

    3374:       DMPlexGetCone(dm, c, &cone);
    3375:       DMPlexGetConeOrientation(dm, c, &ornt);
    3376:       /* A tetrahedron: {0, a, c, d} */
    3377:       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetTriSubface_Static(ornt[0], 0); /* A */
    3378:       orntNew[0] = ornt[0];
    3379:       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetTriSubface_Static(ornt[1], 0); /* A */
    3380:       orntNew[1] = ornt[1];
    3381:       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetTriSubface_Static(ornt[2], 0); /* A */
    3382:       orntNew[2] = ornt[2];
    3383:       coneNew[3] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 0;
    3384:       orntNew[3] = 0;
    3385:       DMPlexSetCone(rdm, newp+0, coneNew);
    3386:       DMPlexSetConeOrientation(rdm, newp+0, orntNew);
    3387: #if defined(PETSC_USE_DEBUG)
    3388:       if ((newp+0 < cStartNew) || (newp+0 >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", newp+0, cStartNew, cEndNew);
    3389:       for (p = 0; p < 4; ++p) {
    3390:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", coneNew[p], fStartNew, fEndNew);
    3391:       }
    3392: #endif
    3393:       /* B tetrahedron: {a, 1, b, e} */
    3394:       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetTriSubface_Static(ornt[0], 1); /* B */
    3395:       orntNew[0] = ornt[0];
    3396:       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetTriSubface_Static(ornt[1], 2); /* C */
    3397:       orntNew[1] = ornt[1];
    3398:       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 1;
    3399:       orntNew[2] = 0;
    3400:       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetTriSubface_Static(ornt[3], 1); /* B */
    3401:       orntNew[3] = ornt[3];
    3402:       DMPlexSetCone(rdm, newp+1, coneNew);
    3403:       DMPlexSetConeOrientation(rdm, newp+1, orntNew);
    3404: #if defined(PETSC_USE_DEBUG)
    3405:       if ((newp+1 < cStartNew) || (newp+1 >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", newp+1, cStartNew, cEndNew);
    3406:       for (p = 0; p < 4; ++p) {
    3407:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", coneNew[p], fStartNew, fEndNew);
    3408:       }
    3409: #endif
    3410:       /* C tetrahedron: {c, b, 2, f} */
    3411:       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetTriSubface_Static(ornt[0], 2); /* C */
    3412:       orntNew[0] = ornt[0];
    3413:       coneNew[1] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 2;
    3414:       orntNew[1] = 0;
    3415:       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetTriSubface_Static(ornt[2], 1); /* B */
    3416:       orntNew[2] = ornt[2];
    3417:       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetTriSubface_Static(ornt[3], 0); /* A */
    3418:       orntNew[3] = ornt[3];
    3419:       DMPlexSetCone(rdm, newp+2, coneNew);
    3420:       DMPlexSetConeOrientation(rdm, newp+2, orntNew);
    3421: #if defined(PETSC_USE_DEBUG)
    3422:       if ((newp+2 < cStartNew) || (newp+2 >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", newp+2, cStartNew, cEndNew);
    3423:       for (p = 0; p < 4; ++p) {
    3424:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", coneNew[p], fStartNew, fEndNew);
    3425:       }
    3426: #endif
    3427:       /* D tetrahedron: {d, e, f, 3} */
    3428:       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 3;
    3429:       orntNew[0] = 0;
    3430:       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetTriSubface_Static(ornt[1], 1); /* B */
    3431:       orntNew[1] = ornt[1];
    3432:       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetTriSubface_Static(ornt[2], 2); /* C */
    3433:       orntNew[2] = ornt[2];
    3434:       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetTriSubface_Static(ornt[3], 2); /* C */
    3435:       orntNew[3] = ornt[3];
    3436:       DMPlexSetCone(rdm, newp+3, coneNew);
    3437:       DMPlexSetConeOrientation(rdm, newp+3, orntNew);
    3438: #if defined(PETSC_USE_DEBUG)
    3439:       if ((newp+3 < cStartNew) || (newp+3 >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", newp+3, cStartNew, cEndNew);
    3440:       for (p = 0; p < 4; ++p) {
    3441:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", coneNew[p], fStartNew, fEndNew);
    3442:       }
    3443: #endif
    3444:       /* A' tetrahedron: {c, d, a, f} */
    3445:       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 0;
    3446:       orntNew[0] = -3;
    3447:       coneNew[1] = fStartNew + (cone[2] - fStart)*4 + 3;
    3448:       orntNew[1] = ornt[2] < 0 ? -(GetTriMidEdge_Static(ornt[2], 0)+1) : GetTriMidEdge_Static(ornt[2], 0);
    3449:       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 5;
    3450:       orntNew[2] = 0;
    3451:       coneNew[3] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 4;
    3452:       orntNew[3] = 2;
    3453:       DMPlexSetCone(rdm, newp+4, coneNew);
    3454:       DMPlexSetConeOrientation(rdm, newp+4, orntNew);
    3455: #if defined(PETSC_USE_DEBUG)
    3456:       if ((newp+4 < cStartNew) || (newp+4 >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", newp+4, cStartNew, cEndNew);
    3457:       for (p = 0; p < 4; ++p) {
    3458:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", coneNew[p], fStartNew, fEndNew);
    3459:       }
    3460: #endif
    3461:       /* B' tetrahedron: {e, b, a, f} */
    3462:       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 1;
    3463:       orntNew[0] = -2;
    3464:       coneNew[1] = fStartNew + (cone[3] - fStart)*4 + 3;
    3465:       orntNew[1] = ornt[3] < 0 ? -(GetTriMidEdge_Static(ornt[3], 1)+1) : GetTriMidEdge_Static(ornt[3], 1);
    3466:       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 6;
    3467:       orntNew[2] = 0;
    3468:       coneNew[3] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 7;
    3469:       orntNew[3] = 0;
    3470:       DMPlexSetCone(rdm, newp+5, coneNew);
    3471:       DMPlexSetConeOrientation(rdm, newp+5, orntNew);
    3472: #if defined(PETSC_USE_DEBUG)
    3473:       if ((newp+5 < cStartNew) || (newp+5 >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", newp+5, cStartNew, cEndNew);
    3474:       for (p = 0; p < 4; ++p) {
    3475:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", coneNew[p], fStartNew, fEndNew);
    3476:       }
    3477: #endif
    3478:       /* C' tetrahedron: {f, a, c, b} */
    3479:       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 5;
    3480:       orntNew[0] = -2;
    3481:       coneNew[1] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 7;
    3482:       orntNew[1] = -2;
    3483:       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 2;
    3484:       orntNew[2] = -1;
    3485:       coneNew[3] = fStartNew + (cone[0] - fStart)*4 + 3;
    3486:       orntNew[3] = ornt[0] < 0 ? -(GetTriMidEdge_Static(ornt[0], 2)+1) : GetTriMidEdge_Static(ornt[0], 2);
    3487:       DMPlexSetCone(rdm, newp+6, coneNew);
    3488:       DMPlexSetConeOrientation(rdm, newp+6, orntNew);
    3489: #if defined(PETSC_USE_DEBUG)
    3490:       if ((newp+6 < cStartNew) || (newp+6 >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", newp+6, cStartNew, cEndNew);
    3491:       for (p = 0; p < 4; ++p) {
    3492:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", coneNew[p], fStartNew, fEndNew);
    3493:       }
    3494: #endif
    3495:       /* D' tetrahedron: {f, a, e, d} */
    3496:       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 6;
    3497:       orntNew[0] = -2;
    3498:       coneNew[1] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 4;
    3499:       orntNew[1] = -1;
    3500:       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 3;
    3501:       orntNew[2] = -2;
    3502:       coneNew[3] = fStartNew + (cone[1] - fStart)*4 + 3;
    3503:       orntNew[3] = ornt[1] < 0 ? -(GetTriMidEdge_Static(ornt[1], 1)+1) : GetTriMidEdge_Static(ornt[1], 1);
    3504:       DMPlexSetCone(rdm, newp+7, coneNew);
    3505:       DMPlexSetConeOrientation(rdm, newp+7, orntNew);
    3506: #if defined(PETSC_USE_DEBUG)
    3507:       if ((newp+7 < cStartNew) || (newp+7 >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", newp+7, cStartNew, cEndNew);
    3508:       for (p = 0; p < 4; ++p) {
    3509:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", coneNew[p], fStartNew, fEndNew);
    3510:       }
    3511: #endif
    3512:     }
    3513:     /* Split faces have 3 edges and the same cells as the parent */
    3514:     DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);
    3515:     PetscMalloc1(2 + maxSupportSize*3, &supportRef);
    3516:     for (f = fStart; f < fEnd; ++f) {
    3517:       const PetscInt  newp = fStartNew + (f - fStart)*4;
    3518:       const PetscInt *cone, *ornt, *support;
    3519:       PetscInt        coneNew[3], orntNew[3], coneSize, supportSize, s;

    3521:       DMPlexGetCone(dm, f, &cone);
    3522:       DMPlexGetConeOrientation(dm, f, &ornt);
    3523:       /* A triangle */
    3524:       coneNew[0] = eStartNew + (cone[0] - eStart)*2 + (ornt[0] < 0 ? 1 : 0);
    3525:       orntNew[0] = ornt[0];
    3526:       coneNew[1] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 2;
    3527:       orntNew[1] = -2;
    3528:       coneNew[2] = eStartNew + (cone[2] - eStart)*2 + (ornt[2] < 0 ? 0 : 1);
    3529:       orntNew[2] = ornt[2];
    3530:       DMPlexSetCone(rdm, newp+0, coneNew);
    3531:       DMPlexSetConeOrientation(rdm, newp+0, orntNew);
    3532: #if defined(PETSC_USE_DEBUG)
    3533:       if ((newp+0 < fStartNew) || (newp+0 >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp+0, fStartNew, fEndNew);
    3534:       for (p = 0; p < 3; ++p) {
    3535:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", coneNew[p], eStartNew, eEndNew);
    3536:       }
    3537: #endif
    3538:       /* B triangle */
    3539:       coneNew[0] = eStartNew + (cone[0] - eStart)*2 + (ornt[0] < 0 ? 0 : 1);
    3540:       orntNew[0] = ornt[0];
    3541:       coneNew[1] = eStartNew + (cone[1] - eStart)*2 + (ornt[1] < 0 ? 1 : 0);
    3542:       orntNew[1] = ornt[1];
    3543:       coneNew[2] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 0;
    3544:       orntNew[2] = -2;
    3545:       DMPlexSetCone(rdm, newp+1, coneNew);
    3546:       DMPlexSetConeOrientation(rdm, newp+1, orntNew);
    3547: #if defined(PETSC_USE_DEBUG)
    3548:       if ((newp+1 < fStartNew) || (newp+1 >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp+1, fStartNew, fEndNew);
    3549:       for (p = 0; p < 3; ++p) {
    3550:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", coneNew[p], eStartNew, eEndNew);
    3551:       }
    3552: #endif
    3553:       /* C triangle */
    3554:       coneNew[0] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 1;
    3555:       orntNew[0] = -2;
    3556:       coneNew[1] = eStartNew + (cone[1] - eStart)*2 + (ornt[1] < 0 ? 0 : 1);
    3557:       orntNew[1] = ornt[1];
    3558:       coneNew[2] = eStartNew + (cone[2] - eStart)*2 + (ornt[2] < 0 ? 1 : 0);
    3559:       orntNew[2] = ornt[2];
    3560:       DMPlexSetCone(rdm, newp+2, coneNew);
    3561:       DMPlexSetConeOrientation(rdm, newp+2, orntNew);
    3562: #if defined(PETSC_USE_DEBUG)
    3563:       if ((newp+2 < fStartNew) || (newp+2 >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp+2, fStartNew, fEndNew);
    3564:       for (p = 0; p < 3; ++p) {
    3565:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", coneNew[p], eStartNew, eEndNew);
    3566:       }
    3567: #endif
    3568:       /* D triangle */
    3569:       coneNew[0] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 0;
    3570:       orntNew[0] = 0;
    3571:       coneNew[1] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 1;
    3572:       orntNew[1] = 0;
    3573:       coneNew[2] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 2;
    3574:       orntNew[2] = 0;
    3575:       DMPlexSetCone(rdm, newp+3, coneNew);
    3576:       DMPlexSetConeOrientation(rdm, newp+3, orntNew);
    3577: #if defined(PETSC_USE_DEBUG)
    3578:       if ((newp+3 < fStartNew) || (newp+3 >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp+3, fStartNew, fEndNew);
    3579:       for (p = 0; p < 3; ++p) {
    3580:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", coneNew[p], eStartNew, eEndNew);
    3581:       }
    3582: #endif
    3583:       DMPlexGetSupportSize(dm, f, &supportSize);
    3584:       DMPlexGetSupport(dm, f, &support);
    3585:       for (r = 0; r < 4; ++r) {
    3586:         for (s = 0; s < supportSize; ++s) {
    3587:           PetscInt subf;
    3588:           DMPlexGetConeSize(dm, support[s], &coneSize);
    3589:           DMPlexGetCone(dm, support[s], &cone);
    3590:           DMPlexGetConeOrientation(dm, support[s], &ornt);
    3591:           for (c = 0; c < coneSize; ++c) {
    3592:             if (cone[c] == f) break;
    3593:           }
    3594:           subf = GetTriSubfaceInverse_Static(ornt[c], r);
    3595:           supportRef[s] = cStartNew + (support[s] - cStart)*8 + (r==3 ? (c+2)%4 + 4 : faces[c*3+subf]);
    3596:         }
    3597:         DMPlexSetSupport(rdm, newp+r, supportRef);
    3598: #if defined(PETSC_USE_DEBUG)
    3599:         if ((newp+r < fStartNew) || (newp+r >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp+r, fStartNew, fEndNew);
    3600:         for (p = 0; p < supportSize; ++p) {
    3601:           if ((supportRef[p] < cStartNew) || (supportRef[p] >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", supportRef[p], cStartNew, cEndNew);
    3602:         }
    3603: #endif
    3604:       }
    3605:     }
    3606:     /* Interior faces have 3 edges and 2 cells */
    3607:     for (c = cStart; c < cEnd; ++c) {
    3608:       PetscInt        newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*8;
    3609:       const PetscInt *cone, *ornt;
    3610:       PetscInt        coneNew[3], orntNew[3];
    3611:       PetscInt        supportNew[2];

    3613:       DMPlexGetCone(dm, c, &cone);
    3614:       DMPlexGetConeOrientation(dm, c, &ornt);
    3615:       /* Face A: {c, a, d} */
    3616:       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*3 + GetTriMidEdge_Static(ornt[0], 2);
    3617:       orntNew[0] = ornt[0] < 0 ? -2 : 0;
    3618:       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*3 + GetTriMidEdge_Static(ornt[1], 2);
    3619:       orntNew[1] = ornt[1] < 0 ? -2 : 0;
    3620:       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*3 + GetTriMidEdge_Static(ornt[2], 2);
    3621:       orntNew[2] = ornt[2] < 0 ? -2 : 0;
    3622:       DMPlexSetCone(rdm, newp, coneNew);
    3623:       DMPlexSetConeOrientation(rdm, newp, orntNew);
    3624: #if defined(PETSC_USE_DEBUG)
    3625:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
    3626:       for (p = 0; p < 3; ++p) {
    3627:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", coneNew[p], eStartNew, eEndNew);
    3628:       }
    3629: #endif
    3630:       supportNew[0] = (c - cStart)*8 + 0;
    3631:       supportNew[1] = (c - cStart)*8 + 0+4;
    3632:       DMPlexSetSupport(rdm, newp, supportNew);
    3633: #if defined(PETSC_USE_DEBUG)
    3634:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
    3635:       for (p = 0; p < 2; ++p) {
    3636:         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", supportNew[p], cStartNew, cEndNew);
    3637:       }
    3638: #endif
    3639:       ++newp;
    3640:       /* Face B: {a, b, e} */
    3641:       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*3 + GetTriMidEdge_Static(ornt[0], 0);
    3642:       orntNew[0] = ornt[0] < 0 ? -2 : 0;
    3643:       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*3 + GetTriMidEdge_Static(ornt[3], 0);
    3644:       orntNew[1] = ornt[3] < 0 ? -2 : 0;
    3645:       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*3 + GetTriMidEdge_Static(ornt[1], 1);
    3646:       orntNew[2] = ornt[1] < 0 ? -2 : 0;
    3647:       DMPlexSetCone(rdm, newp, coneNew);
    3648:       DMPlexSetConeOrientation(rdm, newp, orntNew);
    3649: #if defined(PETSC_USE_DEBUG)
    3650:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
    3651:       for (p = 0; p < 3; ++p) {
    3652:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", coneNew[p], eStartNew, eEndNew);
    3653:       }
    3654: #endif
    3655:       supportNew[0] = (c - cStart)*8 + 1;
    3656:       supportNew[1] = (c - cStart)*8 + 1+4;
    3657:       DMPlexSetSupport(rdm, newp, supportNew);
    3658: #if defined(PETSC_USE_DEBUG)
    3659:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
    3660:       for (p = 0; p < 2; ++p) {
    3661:         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", supportNew[p], cStartNew, cEndNew);
    3662:       }
    3663: #endif
    3664:       ++newp;
    3665:       /* Face C: {c, f, b} */
    3666:       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*3 + GetTriMidEdge_Static(ornt[2], 0);
    3667:       orntNew[0] = ornt[2] < 0 ? -2 : 0;
    3668:       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*3 + GetTriMidEdge_Static(ornt[3], 2);
    3669:       orntNew[1] = ornt[3] < 0 ? -2 : 0;
    3670:       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*3 + GetTriMidEdge_Static(ornt[0], 1);
    3671:       orntNew[2] = ornt[0] < 0 ? -2 : 0;
    3672:       DMPlexSetCone(rdm, newp, coneNew);
    3673:       DMPlexSetConeOrientation(rdm, newp, orntNew);
    3674: #if defined(PETSC_USE_DEBUG)
    3675:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
    3676:       for (p = 0; p < 3; ++p) {
    3677:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", coneNew[p], eStartNew, eEndNew);
    3678:       }
    3679: #endif
    3680:       supportNew[0] = (c - cStart)*8 + 2;
    3681:       supportNew[1] = (c - cStart)*8 + 2+4;
    3682:       DMPlexSetSupport(rdm, newp, supportNew);
    3683: #if defined(PETSC_USE_DEBUG)
    3684:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
    3685:       for (p = 0; p < 2; ++p) {
    3686:         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", supportNew[p], cStartNew, cEndNew);
    3687:       }
    3688: #endif
    3689:       ++newp;
    3690:       /* Face D: {d, e, f} */
    3691:       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*3 + GetTriMidEdge_Static(ornt[1], 0);
    3692:       orntNew[0] = ornt[1] < 0 ? -2 : 0;
    3693:       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*3 + GetTriMidEdge_Static(ornt[3], 1);
    3694:       orntNew[1] = ornt[3] < 0 ? -2 : 0;
    3695:       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*3 + GetTriMidEdge_Static(ornt[2], 1);
    3696:       orntNew[2] = ornt[2] < 0 ? -2 : 0;
    3697:       DMPlexSetCone(rdm, newp, coneNew);
    3698:       DMPlexSetConeOrientation(rdm, newp, orntNew);
    3699: #if defined(PETSC_USE_DEBUG)
    3700:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
    3701:       for (p = 0; p < 3; ++p) {
    3702:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", coneNew[p], eStartNew, eEndNew);
    3703:       }
    3704: #endif
    3705:       supportNew[0] = (c - cStart)*8 + 3;
    3706:       supportNew[1] = (c - cStart)*8 + 3+4;
    3707:       DMPlexSetSupport(rdm, newp, supportNew);
    3708: #if defined(PETSC_USE_DEBUG)
    3709:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
    3710:       for (p = 0; p < 2; ++p) {
    3711:         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", supportNew[p], cStartNew, cEndNew);
    3712:       }
    3713: #endif
    3714:       ++newp;
    3715:       /* Face E: {d, f, a} */
    3716:       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*3 + GetTriMidEdge_Static(ornt[2], 1);
    3717:       orntNew[0] = ornt[2] < 0 ? 0 : -2;
    3718:       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart);
    3719:       orntNew[1] = -2;
    3720:       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*3 + GetTriMidEdge_Static(ornt[1], 2);
    3721:       orntNew[2] = ornt[1] < 0 ? -2 : 0;
    3722:       DMPlexSetCone(rdm, newp, coneNew);
    3723:       DMPlexSetConeOrientation(rdm, newp, orntNew);
    3724: #if defined(PETSC_USE_DEBUG)
    3725:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
    3726:       for (p = 0; p < 3; ++p) {
    3727:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", coneNew[p], eStartNew, eEndNew);
    3728:       }
    3729: #endif
    3730:       supportNew[0] = (c - cStart)*8 + 0+4;
    3731:       supportNew[1] = (c - cStart)*8 + 3+4;
    3732:       DMPlexSetSupport(rdm, newp, supportNew);
    3733: #if defined(PETSC_USE_DEBUG)
    3734:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
    3735:       for (p = 0; p < 2; ++p) {
    3736:         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", supportNew[p], cStartNew, cEndNew);
    3737:       }
    3738: #endif
    3739:       ++newp;
    3740:       /* Face F: {c, a, f} */
    3741:       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*3 + GetTriMidEdge_Static(ornt[0], 2);
    3742:       orntNew[0] = ornt[0] < 0 ? -2 : 0;
    3743:       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart);
    3744:       orntNew[1] = 0;
    3745:       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*3 + GetTriMidEdge_Static(ornt[2], 0);
    3746:       orntNew[2] = ornt[2] < 0 ? 0 : -2;
    3747:       DMPlexSetCone(rdm, newp, coneNew);
    3748:       DMPlexSetConeOrientation(rdm, newp, orntNew);
    3749: #if defined(PETSC_USE_DEBUG)
    3750:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
    3751:       for (p = 0; p < 3; ++p) {
    3752:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", coneNew[p], eStartNew, eEndNew);
    3753:       }
    3754: #endif
    3755:       supportNew[0] = (c - cStart)*8 + 0+4;
    3756:       supportNew[1] = (c - cStart)*8 + 2+4;
    3757:       DMPlexSetSupport(rdm, newp, supportNew);
    3758: #if defined(PETSC_USE_DEBUG)
    3759:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
    3760:       for (p = 0; p < 2; ++p) {
    3761:         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", supportNew[p], cStartNew, cEndNew);
    3762:       }
    3763: #endif
    3764:       ++newp;
    3765:       /* Face G: {e, a, f} */
    3766:       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*3 + GetTriMidEdge_Static(ornt[1], 1);
    3767:       orntNew[0] = ornt[1] < 0 ? -2 : 0;
    3768:       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart);
    3769:       orntNew[1] = 0;
    3770:       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*3 + GetTriMidEdge_Static(ornt[3], 1);
    3771:       orntNew[2] = ornt[3] < 0 ? 0 : -2;
    3772:       DMPlexSetCone(rdm, newp, coneNew);
    3773:       DMPlexSetConeOrientation(rdm, newp, orntNew);
    3774: #if defined(PETSC_USE_DEBUG)
    3775:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
    3776:       for (p = 0; p < 3; ++p) {
    3777:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", coneNew[p], eStartNew, eEndNew);
    3778:       }
    3779: #endif
    3780:       supportNew[0] = (c - cStart)*8 + 1+4;
    3781:       supportNew[1] = (c - cStart)*8 + 3+4;
    3782:       DMPlexSetSupport(rdm, newp, supportNew);
    3783: #if defined(PETSC_USE_DEBUG)
    3784:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
    3785:       for (p = 0; p < 2; ++p) {
    3786:         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", supportNew[p], cStartNew, cEndNew);
    3787:       }
    3788: #endif
    3789:       ++newp;
    3790:       /* Face H: {a, b, f} */
    3791:       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*3 + GetTriMidEdge_Static(ornt[0], 0);
    3792:       orntNew[0] = ornt[0] < 0 ? -2 : 0;
    3793:       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*3 + GetTriMidEdge_Static(ornt[3], 2);
    3794:       orntNew[1] = ornt[3] < 0 ? 0 : -2;
    3795:       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart);
    3796:       orntNew[2] = -2;
    3797:       DMPlexSetCone(rdm, newp, coneNew);
    3798:       DMPlexSetConeOrientation(rdm, newp, orntNew);
    3799: #if defined(PETSC_USE_DEBUG)
    3800:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
    3801:       for (p = 0; p < 3; ++p) {
    3802:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", coneNew[p], eStartNew, eEndNew);
    3803:       }
    3804: #endif
    3805:       supportNew[0] = (c - cStart)*8 + 1+4;
    3806:       supportNew[1] = (c - cStart)*8 + 2+4;
    3807:       DMPlexSetSupport(rdm, newp, supportNew);
    3808: #if defined(PETSC_USE_DEBUG)
    3809:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
    3810:       for (p = 0; p < 2; ++p) {
    3811:         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", supportNew[p], cStartNew, cEndNew);
    3812:       }
    3813: #endif
    3814:       ++newp;
    3815:     }
    3816:     /* Split Edges have 2 vertices and the same faces as the parent */
    3817:     for (e = eStart; e < eEnd; ++e) {
    3818:       const PetscInt newv = vStartNew + (vEnd - vStart) + (e - eStart);

    3820:       for (r = 0; r < 2; ++r) {
    3821:         const PetscInt  newp = eStartNew + (e - eStart)*2 + r;
    3822:         const PetscInt *cone, *ornt, *support;
    3823:         PetscInt        coneNew[2], coneSize, c, supportSize, s;

    3825:         DMPlexGetCone(dm, e, &cone);
    3826:         coneNew[0]       = vStartNew + (cone[0] - vStart);
    3827:         coneNew[1]       = vStartNew + (cone[1] - vStart);
    3828:         coneNew[(r+1)%2] = newv;
    3829:         DMPlexSetCone(rdm, newp, coneNew);
    3830: #if defined(PETSC_USE_DEBUG)
    3831:         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eEndNew);
    3832:         for (p = 0; p < 2; ++p) {
    3833:           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", coneNew[p], vStartNew, vEndNew);
    3834:         }
    3835: #endif
    3836:         DMPlexGetSupportSize(dm, e, &supportSize);
    3837:         DMPlexGetSupport(dm, e, &support);
    3838:         for (s = 0; s < supportSize; ++s) {
    3839:           DMPlexGetConeSize(dm, support[s], &coneSize);
    3840:           DMPlexGetCone(dm, support[s], &cone);
    3841:           DMPlexGetConeOrientation(dm, support[s], &ornt);
    3842:           for (c = 0; c < coneSize; ++c) {
    3843:             if (cone[c] == e) break;
    3844:           }
    3845:           supportRef[s] = fStartNew + (support[s] - fStart)*4 + (c + (ornt[c] < 0 ? 1-r : r))%3;
    3846:         }
    3847:         DMPlexSetSupport(rdm, newp, supportRef);
    3848: #if defined(PETSC_USE_DEBUG)
    3849:         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eEndNew);
    3850:         for (p = 0; p < supportSize; ++p) {
    3851:           if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", supportRef[p], fStartNew, fEndNew);
    3852:         }
    3853: #endif
    3854:       }
    3855:     }
    3856:     /* Face edges have 2 vertices and 2+cells*(1/2) faces */
    3857:     for (f = fStart; f < fEnd; ++f) {
    3858:       const PetscInt *cone, *ornt, *support;
    3859:       PetscInt        coneSize, supportSize, s;

    3861:       DMPlexGetSupportSize(dm, f, &supportSize);
    3862:       DMPlexGetSupport(dm, f, &support);
    3863:       for (r = 0; r < 3; ++r) {
    3864:         const PetscInt  newp = eStartNew + (eEnd - eStart)*2 + (f - fStart)*3 + r;
    3865:         PetscInt        coneNew[2], intFaces = 0, er, eint[4] = {1, 0, 2, 0};
    3866:         PetscInt        fint[24] = { 1,  7, -1, -1,  0,  5,
    3867:                                     -1, -1,  1,  6,  0,  4,
    3868:                                      2,  5,  3,  4, -1, -1,
    3869:                                     -1, -1,  3,  6,  2,  7};

    3871:         DMPlexGetCone(dm, f, &cone);
    3872:         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[(r+0)%3] - eStart);
    3873:         coneNew[1] = vStartNew + (vEnd - vStart) + (cone[(r+1)%3] - eStart);
    3874:         DMPlexSetCone(rdm, newp, coneNew);
    3875: #if defined(PETSC_USE_DEBUG)
    3876:         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eEndNew);
    3877:         for (p = 0; p < 2; ++p) {
    3878:           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", coneNew[p], vStartNew, vEndNew);
    3879:         }
    3880: #endif
    3881:         supportRef[0] = fStartNew + (f - fStart)*4 + (r+1)%3;
    3882:         supportRef[1] = fStartNew + (f - fStart)*4 + 3;
    3883:         for (s = 0; s < supportSize; ++s) {
    3884:           DMPlexGetConeSize(dm, support[s], &coneSize);
    3885:           DMPlexGetCone(dm, support[s], &cone);
    3886:           DMPlexGetConeOrientation(dm, support[s], &ornt);
    3887:           for (c = 0; c < coneSize; ++c) {if (cone[c] == f) break;}
    3888:           /* Here we want to determine whether edge newp contains a vertex which is part of the cross-tet edge */
    3889:           er = GetTriMidEdgeInverse_Static(ornt[c], r);
    3890:           if (er == eint[c]) {
    3891:             supportRef[2+intFaces++] = fStartNew + (fEnd - fStart)*4 + (support[s] - cStart)*8 + (c + 2)%4;
    3892:           } else {
    3893:             supportRef[2+intFaces++] = fStartNew + (fEnd - fStart)*4 + (support[s] - cStart)*8 + fint[(c*3 + er)*2 + 0];
    3894:             supportRef[2+intFaces++] = fStartNew + (fEnd - fStart)*4 + (support[s] - cStart)*8 + fint[(c*3 + er)*2 + 1];
    3895:           }
    3896:         }
    3897:         DMPlexSetSupport(rdm, newp, supportRef);
    3898: #if defined(PETSC_USE_DEBUG)
    3899:         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eEndNew);
    3900:         for (p = 0; p < intFaces; ++p) {
    3901:           if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", supportRef[p], fStartNew, fEndNew);
    3902:         }
    3903: #endif
    3904:       }
    3905:     }
    3906:     /* Interior edges have 2 vertices and 4 faces */
    3907:     for (c = cStart; c < cEnd; ++c) {
    3908:       const PetscInt  newp = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart);
    3909:       const PetscInt *cone, *ornt, *fcone;
    3910:       PetscInt        coneNew[2], supportNew[4], find;

    3912:       DMPlexGetCone(dm, c, &cone);
    3913:       DMPlexGetConeOrientation(dm, c, &ornt);
    3914:       DMPlexGetCone(dm, cone[0], &fcone);
    3915:       find = GetTriEdge_Static(ornt[0], 0);
    3916:       coneNew[0] = vStartNew + (vEnd - vStart) + (fcone[find] - eStart);
    3917:       DMPlexGetCone(dm, cone[2], &fcone);
    3918:       find = GetTriEdge_Static(ornt[2], 1);
    3919:       coneNew[1] = vStartNew + (vEnd - vStart) + (fcone[find] - eStart);
    3920:       DMPlexSetCone(rdm, newp, coneNew);
    3921: #if defined(PETSC_USE_DEBUG)
    3922:       if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eEndNew);
    3923:       for (p = 0; p < 2; ++p) {
    3924:         if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", coneNew[p], vStartNew, vEndNew);
    3925:       }
    3926: #endif
    3927:       supportNew[0] = fStartNew + (fEnd - fStart)*4 + (c - cStart)*8 + 4;
    3928:       supportNew[1] = fStartNew + (fEnd - fStart)*4 + (c - cStart)*8 + 5;
    3929:       supportNew[2] = fStartNew + (fEnd - fStart)*4 + (c - cStart)*8 + 6;
    3930:       supportNew[3] = fStartNew + (fEnd - fStart)*4 + (c - cStart)*8 + 7;
    3931:       DMPlexSetSupport(rdm, newp, supportNew);
    3932: #if defined(PETSC_USE_DEBUG)
    3933:       if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eEndNew);
    3934:       for (p = 0; p < 4; ++p) {
    3935:         if ((supportNew[p] < fStartNew) || (supportNew[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", supportNew[p], fStartNew, fEndNew);
    3936:       }
    3937: #endif
    3938:     }
    3939:     /* Old vertices have identical supports */
    3940:     for (v = vStart; v < vEnd; ++v) {
    3941:       const PetscInt  newp = vStartNew + (v - vStart);
    3942:       const PetscInt *support, *cone;
    3943:       PetscInt        size, s;

    3945:       DMPlexGetSupportSize(dm, v, &size);
    3946:       DMPlexGetSupport(dm, v, &support);
    3947:       for (s = 0; s < size; ++s) {
    3948:         PetscInt r = 0;

    3950:         DMPlexGetCone(dm, support[s], &cone);
    3951:         if (cone[1] == v) r = 1;
    3952:         supportRef[s] = eStartNew + (support[s] - eStart)*2 + r;
    3953:       }
    3954:       DMPlexSetSupport(rdm, newp, supportRef);
    3955: #if defined(PETSC_USE_DEBUG)
    3956:       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", newp, vStartNew, vEndNew);
    3957:       for (p = 0; p < size; ++p) {
    3958:         if ((supportRef[p] < eStartNew) || (supportRef[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", supportRef[p], eStartNew, eEndNew);
    3959:       }
    3960: #endif
    3961:     }
    3962:     /* Edge vertices have 2 + face*2 + 0/1 supports */
    3963:     for (e = eStart; e < eEnd; ++e) {
    3964:       const PetscInt  newp = vStartNew + (vEnd - vStart) + (e - eStart);
    3965:       const PetscInt *cone, *support;
    3966:       PetscInt       *star = NULL, starSize, cellSize = 0, coneSize, size, s;

    3968:       DMPlexGetSupportSize(dm, e, &size);
    3969:       DMPlexGetSupport(dm, e, &support);
    3970:       supportRef[0] = eStartNew + (e - eStart)*2 + 0;
    3971:       supportRef[1] = eStartNew + (e - eStart)*2 + 1;
    3972:       for (s = 0; s < size; ++s) {
    3973:         PetscInt r = 0;

    3975:         DMPlexGetConeSize(dm, support[s], &coneSize);
    3976:         DMPlexGetCone(dm, support[s], &cone);
    3977:         for (r = 0; r < coneSize; ++r) {if (cone[r] == e) break;}
    3978:         supportRef[2+s*2+0] = eStartNew + (eEnd - eStart)*2 + (support[s] - fStart)*3 + (r+0)%3;
    3979:         supportRef[2+s*2+1] = eStartNew + (eEnd - eStart)*2 + (support[s] - fStart)*3 + (r+2)%3;
    3980:       }
    3981:       DMPlexGetTransitiveClosure(dm, e, PETSC_FALSE, &starSize, &star);
    3982:       for (s = 0; s < starSize*2; s += 2) {
    3983:         const PetscInt *cone, *ornt;
    3984:         PetscInt        e01, e23;

    3986:         if ((star[s] >= cStart) && (star[s] < cEnd)) {
    3987:           /* Check edge 0-1 */
    3988:           DMPlexGetCone(dm, star[s], &cone);
    3989:           DMPlexGetConeOrientation(dm, star[s], &ornt);
    3990:           DMPlexGetCone(dm, cone[0], &cone);
    3991:           e01  = cone[GetTriEdge_Static(ornt[0], 0)];
    3992:           /* Check edge 2-3 */
    3993:           DMPlexGetCone(dm, star[s], &cone);
    3994:           DMPlexGetConeOrientation(dm, star[s], &ornt);
    3995:           DMPlexGetCone(dm, cone[2], &cone);
    3996:           e23  = cone[GetTriEdge_Static(ornt[2], 1)];
    3997:           if ((e01 == e) || (e23 == e)) {supportRef[2+size*2+cellSize++] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (star[s] - cStart);}
    3998:         }
    3999:       }
    4000:       DMPlexRestoreTransitiveClosure(dm, e, PETSC_FALSE, &starSize, &star);
    4001:       DMPlexSetSupport(rdm, newp, supportRef);
    4002: #if defined(PETSC_USE_DEBUG)
    4003:       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", newp, vStartNew, vEndNew);
    4004:       for (p = 0; p < 2+size*2+cellSize; ++p) {
    4005:         if ((supportRef[p] < eStartNew) || (supportRef[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", supportRef[p], eStartNew, eEndNew);
    4006:       }
    4007: #endif
    4008:     }
    4009:     PetscFree(supportRef);
    4010:     DMPlexRestoreFaces_Internal(dm, 3, cStart, NULL, NULL, &faces);
    4011:     break;
    4012:   case REFINER_HYBRID_SIMPLEX_3D:
    4013:     DMPlexGetHybridBounds(rdm, &cMaxNew, &fMaxNew, &eMaxNew, NULL);
    4014:     /* Interior cells have 4 faces: Tet face order is prescribed in DMPlexGetFaces_Internal() */
    4015:     DMPlexGetRawFaces_Internal(dm, 3, 4, cellInd, NULL, NULL, &faces);
    4016:     for (c = cStart; c < cMax; ++c) {
    4017:       const PetscInt  newp = cStartNew + (c - cStart)*8;
    4018:       const PetscInt *cone, *ornt;
    4019:       PetscInt        coneNew[4], orntNew[4];

    4021:       DMPlexGetCone(dm, c, &cone);
    4022:       DMPlexGetConeOrientation(dm, c, &ornt);
    4023:       /* A tetrahedron: {0, a, c, d} */
    4024:       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetTriSubface_Static(ornt[0], 0); /* A */
    4025:       orntNew[0] = ornt[0];
    4026:       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetTriSubface_Static(ornt[1], 0); /* A */
    4027:       orntNew[1] = ornt[1];
    4028:       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetTriSubface_Static(ornt[2], 0); /* A */
    4029:       orntNew[2] = ornt[2];
    4030:       coneNew[3] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 0;
    4031:       orntNew[3] = 0;
    4032:       DMPlexSetCone(rdm, newp+0, coneNew);
    4033:       DMPlexSetConeOrientation(rdm, newp+0, orntNew);
    4034: #if defined(PETSC_USE_DEBUG)
    4035:       if ((newp+0 < cStartNew) || (newp+0 >= cMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", newp+0, cStartNew, cMaxNew);
    4036:       for (p = 0; p < 4; ++p) {
    4037:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", coneNew[p], fStartNew, fMaxNew);
    4038:       }
    4039: #endif
    4040:       /* B tetrahedron: {a, 1, b, e} */
    4041:       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetTriSubface_Static(ornt[0], 1); /* B */
    4042:       orntNew[0] = ornt[0];
    4043:       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetTriSubface_Static(ornt[1], 2); /* C */
    4044:       orntNew[1] = ornt[1];
    4045:       coneNew[2] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 1;
    4046:       orntNew[2] = 0;
    4047:       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetTriSubface_Static(ornt[3], 1); /* B */
    4048:       orntNew[3] = ornt[3];
    4049:       DMPlexSetCone(rdm, newp+1, coneNew);
    4050:       DMPlexSetConeOrientation(rdm, newp+1, orntNew);
    4051: #if defined(PETSC_USE_DEBUG)
    4052:       if ((newp+1 < cStartNew) || (newp+1 >= cMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", newp+1, cStartNew, cMaxNew);
    4053:       for (p = 0; p < 4; ++p) {
    4054:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", coneNew[p], fStartNew, fMaxNew);
    4055:       }
    4056: #endif
    4057:       /* C tetrahedron: {c, b, 2, f} */
    4058:       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetTriSubface_Static(ornt[0], 2); /* C */
    4059:       orntNew[0] = ornt[0];
    4060:       coneNew[1] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 2;
    4061:       orntNew[1] = 0;
    4062:       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetTriSubface_Static(ornt[2], 1); /* B */
    4063:       orntNew[2] = ornt[2];
    4064:       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetTriSubface_Static(ornt[3], 0); /* A */
    4065:       orntNew[3] = ornt[3];
    4066:       DMPlexSetCone(rdm, newp+2, coneNew);
    4067:       DMPlexSetConeOrientation(rdm, newp+2, orntNew);
    4068: #if defined(PETSC_USE_DEBUG)
    4069:       if ((newp+2 < cStartNew) || (newp+2 >= cMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", newp+2, cStartNew, cMaxNew);
    4070:       for (p = 0; p < 4; ++p) {
    4071:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", coneNew[p], fStartNew, fMaxNew);
    4072:       }
    4073: #endif
    4074:       /* D tetrahedron: {d, e, f, 3} */
    4075:       coneNew[0] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 3;
    4076:       orntNew[0] = 0;
    4077:       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetTriSubface_Static(ornt[1], 1); /* B */
    4078:       orntNew[1] = ornt[1];
    4079:       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetTriSubface_Static(ornt[2], 2); /* C */
    4080:       orntNew[2] = ornt[2];
    4081:       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetTriSubface_Static(ornt[3], 2); /* C */
    4082:       orntNew[3] = ornt[3];
    4083:       DMPlexSetCone(rdm, newp+3, coneNew);
    4084:       DMPlexSetConeOrientation(rdm, newp+3, orntNew);
    4085: #if defined(PETSC_USE_DEBUG)
    4086:       if ((newp+3 < cStartNew) || (newp+3 >= cMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", newp+3, cStartNew, cMaxNew);
    4087:       for (p = 0; p < 4; ++p) {
    4088:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", coneNew[p], fStartNew, fMaxNew);
    4089:       }
    4090: #endif
    4091:       /* A' tetrahedron: {d, a, c, f} */
    4092:       coneNew[0] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 0;
    4093:       orntNew[0] = -3;
    4094:       coneNew[1] = fStartNew + (cone[2] - fStart)*4 + 3;
    4095:       orntNew[1] = ornt[2] < 0 ? -(GetTriMidEdge_Static(ornt[2], 0)+1) : GetTriMidEdge_Static(ornt[2], 0);
    4096:       coneNew[2] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 5;
    4097:       orntNew[2] = 0;
    4098:       coneNew[3] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 4;
    4099:       orntNew[3] = 2;
    4100:       DMPlexSetCone(rdm, newp+4, coneNew);
    4101:       DMPlexSetConeOrientation(rdm, newp+4, orntNew);
    4102: #if defined(PETSC_USE_DEBUG)
    4103:       if ((newp+4 < cStartNew) || (newp+4 >= cMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", newp+4, cStartNew, cMaxNew);
    4104:       for (p = 0; p < 4; ++p) {
    4105:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", coneNew[p], fStartNew, fMaxNew);
    4106:       }
    4107: #endif
    4108:       /* B' tetrahedron: {e, b, a, f} */
    4109:       coneNew[0] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 1;
    4110:       orntNew[0] = -3;
    4111:       coneNew[1] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 6;
    4112:       orntNew[1] = 1;
    4113:       coneNew[2] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 7;
    4114:       orntNew[2] = 0;
    4115:       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + 3;
    4116:       orntNew[3] = ornt[3] < 0 ? -(GetTriMidEdge_Static(ornt[3], 0)+1) : GetTriMidEdge_Static(ornt[3], 0);
    4117:       DMPlexSetCone(rdm, newp+5, coneNew);
    4118:       DMPlexSetConeOrientation(rdm, newp+5, orntNew);
    4119: #if defined(PETSC_USE_DEBUG)
    4120:       if ((newp+5 < cStartNew) || (newp+5 >= cMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", newp+5, cStartNew, cMaxNew);
    4121:       for (p = 0; p < 4; ++p) {
    4122:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", coneNew[p], fStartNew, fMaxNew);
    4123:       }
    4124: #endif
    4125:       /* C' tetrahedron: {b, f, c, a} */
    4126:       coneNew[0] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 2;
    4127:       orntNew[0] = -3;
    4128:       coneNew[1] = fStartNew + (cone[0] - fStart)*4 + 3;
    4129:       orntNew[1] = ornt[0] < 0 ? -(GetTriMidEdge_Static(ornt[0], 2)+1) : GetTriMidEdge_Static(ornt[0], 2);
    4130:       coneNew[2] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 5;
    4131:       orntNew[2] = -3;
    4132:       coneNew[3] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 7;
    4133:       orntNew[3] = -2;
    4134:       DMPlexSetCone(rdm, newp+6, coneNew);
    4135:       DMPlexSetConeOrientation(rdm, newp+6, orntNew);
    4136: #if defined(PETSC_USE_DEBUG)
    4137:       if ((newp+6 < cStartNew) || (newp+6 >= cMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", newp+6, cStartNew, cMaxNew);
    4138:       for (p = 0; p < 4; ++p) {
    4139:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", coneNew[p], fStartNew, fMaxNew);
    4140:       }
    4141: #endif
    4142:       /* D' tetrahedron: {f, e, d, a} */
    4143:       coneNew[0] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 3;
    4144:       orntNew[0] = -3;
    4145:       coneNew[1] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 4;
    4146:       orntNew[1] = -3;
    4147:       coneNew[2] = fStartNew + (cone[1] - fStart)*4 + 3;
    4148:       orntNew[2] = ornt[1] < 0 ? -(GetTriMidEdge_Static(ornt[1], 0)+1) : GetTriMidEdge_Static(ornt[1], 0);
    4149:       coneNew[3] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 6;
    4150:       orntNew[3] = -3;
    4151:       DMPlexSetCone(rdm, newp+7, coneNew);
    4152:       DMPlexSetConeOrientation(rdm, newp+7, orntNew);
    4153: #if defined(PETSC_USE_DEBUG)
    4154:       if ((newp+7 < cStartNew) || (newp+7 >= cMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", newp+7, cStartNew, cMaxNew);
    4155:       for (p = 0; p < 4; ++p) {
    4156:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", coneNew[p], fStartNew, fMaxNew);
    4157:       }
    4158: #endif
    4159:     }
    4160:     /* Hybrid cells have 5 faces */
    4161:     for (c = cMax; c < cEnd; ++c) {
    4162:       const PetscInt  newp = cStartNew + (cMax - cStart)*8 + (c - cMax)*4;
    4163:       const PetscInt *cone, *ornt, *fornt;
    4164:       PetscInt        coneNew[5], orntNew[5], o, of, i;

    4166:       DMPlexGetCone(dm, c, &cone);
    4167:       DMPlexGetConeOrientation(dm, c, &ornt);
    4168:       DMPlexGetConeOrientation(dm, cone[0], &fornt);
    4169:       o = ornt[0] < 0 ? -1 : 1;
    4170:       for (r = 0; r < 3; ++r) {
    4171:         coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetTriSubface_Static(ornt[0], r);
    4172:         orntNew[0] = ornt[0];
    4173:         coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetTriSubface_Static(ornt[1], r);
    4174:         orntNew[1] = ornt[1];
    4175:         of = fornt[GetTriEdge_Static(ornt[0], r)]       < 0 ? -1 : 1;
    4176:         i  = GetTriEdgeInverse_Static(ornt[0], r)       + 2;
    4177:         coneNew[i] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (cone[2+GetTriEdge_Static(ornt[0], r)]       - fMax)*2 + (o*of < 0 ? 1 : 0);
    4178:         orntNew[i] = 0;
    4179:         i  = GetTriEdgeInverse_Static(ornt[0], (r+1)%3) + 2;
    4180:         coneNew[i] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (c - cMax)*3 + GetTriSubface_Static(ornt[0], r);
    4181:         orntNew[i] = 0;
    4182:         of = fornt[GetTriEdge_Static(ornt[0], (r+2)%3)] < 0 ? -1 : 1;
    4183:         i  = GetTriEdgeInverse_Static(ornt[0], (r+2)%3) + 2;
    4184:         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);
    4185:         orntNew[i] = 0;
    4186:         DMPlexSetCone(rdm, newp+r, coneNew);
    4187:         DMPlexSetConeOrientation(rdm, newp+r, orntNew);
    4188: #if defined(PETSC_USE_DEBUG)
    4189:         if ((newp+r < cMaxNew) || (newp+r >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a hybrid cell [%D, %D)", newp+r, cMaxNew, cEndNew);
    4190:         for (p = 0; p < 2; ++p) {
    4191:           if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", coneNew[p], fStartNew, fMaxNew);
    4192:         }
    4193:         for (p = 2; p < 5; ++p) {
    4194:           if ((coneNew[p] < fMaxNew)   || (coneNew[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a hybrid face [%D, %D)", coneNew[p], fMaxNew, fEndNew);
    4195:         }
    4196: #endif
    4197:       }
    4198:       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + 3;
    4199:       orntNew[0] = 0;
    4200:       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + 3;
    4201:       orntNew[1] = 0;
    4202:       coneNew[2] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (c - cMax)*3 + 1;
    4203:       orntNew[2] = 0;
    4204:       coneNew[3] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (c - cMax)*3 + 2;
    4205:       orntNew[3] = 0;
    4206:       coneNew[4] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (c - cMax)*3 + 0;
    4207:       orntNew[4] = 0;
    4208:       DMPlexSetCone(rdm, newp+3, coneNew);
    4209:       DMPlexSetConeOrientation(rdm, newp+3, orntNew);
    4210: #if defined(PETSC_USE_DEBUG)
    4211:       if ((newp+3 < cMaxNew) || (newp+3 >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a hybrid cell [%D, %D)", newp+3, cMaxNew, cEndNew);
    4212:       for (p = 0; p < 2; ++p) {
    4213:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", coneNew[p], fStartNew, fMaxNew);
    4214:       }
    4215:       for (p = 2; p < 5; ++p) {
    4216:         if ((coneNew[p] < fMaxNew)   || (coneNew[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a hybrid face [%D, %D)", coneNew[p], fMaxNew, fEndNew);
    4217:       }
    4218: #endif
    4219:     }
    4220:     /* Split faces have 3 edges and the same cells as the parent */
    4221:     DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);
    4222:     PetscMalloc1(2 + maxSupportSize*2, &supportRef);
    4223:     for (f = fStart; f < fMax; ++f) {
    4224:       const PetscInt  newp = fStartNew + (f - fStart)*4;
    4225:       const PetscInt *cone, *ornt, *support;
    4226:       PetscInt        coneNew[3], orntNew[3], coneSize, supportSize, s;

    4228:       DMPlexGetCone(dm, f, &cone);
    4229:       DMPlexGetConeOrientation(dm, f, &ornt);
    4230:       /* A triangle */
    4231:       coneNew[0] = eStartNew + (cone[0] - eStart)*2 + (ornt[0] < 0 ? 1 : 0);
    4232:       orntNew[0] = ornt[0];
    4233:       coneNew[1] = eStartNew + (eMax    - eStart)*2 + (f - fStart)*3 + 2;
    4234:       orntNew[1] = -2;
    4235:       coneNew[2] = eStartNew + (cone[2] - eStart)*2 + (ornt[2] < 0 ? 0 : 1);
    4236:       orntNew[2] = ornt[2];
    4237:       DMPlexSetCone(rdm, newp+0, coneNew);
    4238:       DMPlexSetConeOrientation(rdm, newp+0, orntNew);
    4239: #if defined(PETSC_USE_DEBUG)
    4240:       if ((newp+0 < fStartNew) || (newp+0 >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp+0, fStartNew, fMaxNew);
    4241:       for (p = 0; p < 3; ++p) {
    4242:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", coneNew[p], eStartNew, eMaxNew);
    4243:       }
    4244: #endif
    4245:       /* B triangle */
    4246:       coneNew[0] = eStartNew + (cone[0] - eStart)*2 + (ornt[0] < 0 ? 0 : 1);
    4247:       orntNew[0] = ornt[0];
    4248:       coneNew[1] = eStartNew + (cone[1] - eStart)*2 + (ornt[1] < 0 ? 1 : 0);
    4249:       orntNew[1] = ornt[1];
    4250:       coneNew[2] = eStartNew + (eMax    - eStart)*2 + (f - fStart)*3 + 0;
    4251:       orntNew[2] = -2;
    4252:       DMPlexSetCone(rdm, newp+1, coneNew);
    4253:       DMPlexSetConeOrientation(rdm, newp+1, orntNew);
    4254: #if defined(PETSC_USE_DEBUG)
    4255:       if ((newp+1 < fStartNew) || (newp+1 >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp+1, fStartNew, fMaxNew);
    4256:       for (p = 0; p < 3; ++p) {
    4257:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", coneNew[p], eStartNew, eMaxNew);
    4258:       }
    4259: #endif
    4260:       /* C triangle */
    4261:       coneNew[0] = eStartNew + (eMax    - eStart)*2 + (f - fStart)*3 + 1;
    4262:       orntNew[0] = -2;
    4263:       coneNew[1] = eStartNew + (cone[1] - eStart)*2 + (ornt[1] < 0 ? 0 : 1);
    4264:       orntNew[1] = ornt[1];
    4265:       coneNew[2] = eStartNew + (cone[2] - eStart)*2 + (ornt[2] < 0 ? 1 : 0);
    4266:       orntNew[2] = ornt[2];
    4267:       DMPlexSetCone(rdm, newp+2, coneNew);
    4268:       DMPlexSetConeOrientation(rdm, newp+2, orntNew);
    4269: #if defined(PETSC_USE_DEBUG)
    4270:       if ((newp+2 < fStartNew) || (newp+2 >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp+2, fStartNew, fMaxNew);
    4271:       for (p = 0; p < 3; ++p) {
    4272:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", coneNew[p], eStartNew, eMaxNew);
    4273:       }
    4274: #endif
    4275:       /* D triangle */
    4276:       coneNew[0] = eStartNew + (eMax    - eStart)*2 + (f - fStart)*3 + 0;
    4277:       orntNew[0] = 0;
    4278:       coneNew[1] = eStartNew + (eMax    - eStart)*2 + (f - fStart)*3 + 1;
    4279:       orntNew[1] = 0;
    4280:       coneNew[2] = eStartNew + (eMax    - eStart)*2 + (f - fStart)*3 + 2;
    4281:       orntNew[2] = 0;
    4282:       DMPlexSetCone(rdm, newp+3, coneNew);
    4283:       DMPlexSetConeOrientation(rdm, newp+3, orntNew);
    4284: #if defined(PETSC_USE_DEBUG)
    4285:       if ((newp+3 < fStartNew) || (newp+3 >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp+3, fStartNew, fMaxNew);
    4286:       for (p = 0; p < 3; ++p) {
    4287:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", coneNew[p], eStartNew, eMaxNew);
    4288:       }
    4289: #endif
    4290:       DMPlexGetSupportSize(dm, f, &supportSize);
    4291:       DMPlexGetSupport(dm, f, &support);
    4292:       for (r = 0; r < 4; ++r) {
    4293:         for (s = 0; s < supportSize; ++s) {
    4294:           PetscInt subf;
    4295:           DMPlexGetConeSize(dm, support[s], &coneSize);
    4296:           DMPlexGetCone(dm, support[s], &cone);
    4297:           DMPlexGetConeOrientation(dm, support[s], &ornt);
    4298:           for (c = 0; c < coneSize; ++c) {
    4299:             if (cone[c] == f) break;
    4300:           }
    4301:           subf = GetTriSubfaceInverse_Static(ornt[c], r);
    4302:           if (support[s] < cMax) {
    4303:             supportRef[s] = cStartNew + (support[s] - cStart)*8 + (r==3 ? (c+2)%4 + 4 : faces[c*3+subf]);
    4304:           } else {
    4305:             supportRef[s] = cStartNew + (cMax - cStart)*8 + (support[s] - cMax)*4 + (r==3 ? r : subf);
    4306:           }
    4307:         }
    4308:         DMPlexSetSupport(rdm, newp+r, supportRef);
    4309: #if defined(PETSC_USE_DEBUG)
    4310:         if ((newp+r < fStartNew) || (newp+r >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp+r, fStartNew, fMaxNew);
    4311:         for (p = 0; p < supportSize; ++p) {
    4312:           if ((supportRef[p] < cStartNew) || (supportRef[p] >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an interior or hybrid cell [%D, %D)", supportRef[p], cStartNew, cEndNew);
    4313:         }
    4314: #endif
    4315:       }
    4316:     }
    4317:     /* Interior cell faces have 3 edges and 2 cells */
    4318:     for (c = cStart; c < cMax; ++c) {
    4319:       PetscInt        newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*8;
    4320:       const PetscInt *cone, *ornt;
    4321:       PetscInt        coneNew[3], orntNew[3];
    4322:       PetscInt        supportNew[2];

    4324:       DMPlexGetCone(dm, c, &cone);
    4325:       DMPlexGetConeOrientation(dm, c, &ornt);
    4326:       /* Face A: {c, a, d} */
    4327:       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*3 + GetTriMidEdge_Static(ornt[0], 2);
    4328:       orntNew[0] = ornt[0] < 0 ? -2 : 0;
    4329:       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*3 + GetTriMidEdge_Static(ornt[1], 2);
    4330:       orntNew[1] = ornt[1] < 0 ? -2 : 0;
    4331:       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*3 + GetTriMidEdge_Static(ornt[2], 2);
    4332:       orntNew[2] = ornt[2] < 0 ? -2 : 0;
    4333:       DMPlexSetCone(rdm, newp, coneNew);
    4334:       DMPlexSetConeOrientation(rdm, newp, orntNew);
    4335: #if defined(PETSC_USE_DEBUG)
    4336:       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fMaxNew);
    4337:       for (p = 0; p < 3; ++p) {
    4338:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", coneNew[p], eStartNew, eMaxNew);
    4339:       }
    4340: #endif
    4341:       supportNew[0] = (c - cStart)*8 + 0;
    4342:       supportNew[1] = (c - cStart)*8 + 0+4;
    4343:       DMPlexSetSupport(rdm, newp, supportNew);
    4344: #if defined(PETSC_USE_DEBUG)
    4345:       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fMaxNew);
    4346:       for (p = 0; p < 2; ++p) {
    4347:         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", supportNew[p], cStartNew, cMaxNew);
    4348:       }
    4349: #endif
    4350:       ++newp;
    4351:       /* Face B: {a, b, e} */
    4352:       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*3 + GetTriMidEdge_Static(ornt[0], 0);
    4353:       orntNew[0] = ornt[0] < 0 ? -2 : 0;
    4354:       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*3 + GetTriMidEdge_Static(ornt[3], 0);
    4355:       orntNew[1] = ornt[3] < 0 ? -2 : 0;
    4356:       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*3 + GetTriMidEdge_Static(ornt[1], 1);
    4357:       orntNew[2] = ornt[1] < 0 ? -2 : 0;
    4358:       DMPlexSetCone(rdm, newp, coneNew);
    4359:       DMPlexSetConeOrientation(rdm, newp, orntNew);
    4360: #if defined(PETSC_USE_DEBUG)
    4361:       if ((newp+1 < fStartNew) || (newp+1 >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp+1, fStartNew, fMaxNew);
    4362:       for (p = 0; p < 3; ++p) {
    4363:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", coneNew[p], eStartNew, eMaxNew);
    4364:       }
    4365: #endif
    4366:       supportNew[0] = (c - cStart)*8 + 1;
    4367:       supportNew[1] = (c - cStart)*8 + 1+4;
    4368:       DMPlexSetSupport(rdm, newp, supportNew);
    4369: #if defined(PETSC_USE_DEBUG)
    4370:       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fMaxNew);
    4371:       for (p = 0; p < 2; ++p) {
    4372:         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", supportNew[p], cStartNew, cMaxNew);
    4373:       }
    4374: #endif
    4375:       ++newp;
    4376:       /* Face C: {c, f, b} */
    4377:       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*3 + GetTriMidEdge_Static(ornt[2], 0);
    4378:       orntNew[0] = ornt[2] < 0 ? -2 : 0;
    4379:       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*3 + GetTriMidEdge_Static(ornt[3], 2);
    4380:       orntNew[1] = ornt[3] < 0 ? -2 : 0;
    4381:       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*3 + GetTriMidEdge_Static(ornt[0], 1);
    4382:       orntNew[2] = ornt[0] < 0 ? -2 : 0;
    4383:       DMPlexSetCone(rdm, newp, coneNew);
    4384:       DMPlexSetConeOrientation(rdm, newp, orntNew);
    4385: #if defined(PETSC_USE_DEBUG)
    4386:       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fMaxNew);
    4387:       for (p = 0; p < 3; ++p) {
    4388:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", coneNew[p], eStartNew, eMaxNew);
    4389:       }
    4390: #endif
    4391:       supportNew[0] = (c - cStart)*8 + 2;
    4392:       supportNew[1] = (c - cStart)*8 + 2+4;
    4393:       DMPlexSetSupport(rdm, newp, supportNew);
    4394: #if defined(PETSC_USE_DEBUG)
    4395:       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fMaxNew);
    4396:       for (p = 0; p < 2; ++p) {
    4397:         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", supportNew[p], cStartNew, cMaxNew);
    4398:       }
    4399: #endif
    4400:       ++newp;
    4401:       /* Face D: {d, e, f} */
    4402:       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*3 + GetTriMidEdge_Static(ornt[1], 0);
    4403:       orntNew[0] = ornt[1] < 0 ? -2 : 0;
    4404:       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*3 + GetTriMidEdge_Static(ornt[3], 1);
    4405:       orntNew[1] = ornt[3] < 0 ? -2 : 0;
    4406:       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*3 + GetTriMidEdge_Static(ornt[2], 1);
    4407:       orntNew[2] = ornt[2] < 0 ? -2 : 0;
    4408:       DMPlexSetCone(rdm, newp, coneNew);
    4409:       DMPlexSetConeOrientation(rdm, newp, orntNew);
    4410: #if defined(PETSC_USE_DEBUG)
    4411:       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fMaxNew);
    4412:       for (p = 0; p < 3; ++p) {
    4413:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", coneNew[p], eStartNew, eMaxNew);
    4414:       }
    4415: #endif
    4416:       supportNew[0] = (c - cStart)*8 + 3;
    4417:       supportNew[1] = (c - cStart)*8 + 3+4;
    4418:       DMPlexSetSupport(rdm, newp, supportNew);
    4419: #if defined(PETSC_USE_DEBUG)
    4420:       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fMaxNew);
    4421:       for (p = 0; p < 2; ++p) {
    4422:         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", supportNew[p], cStartNew, cMaxNew);
    4423:       }
    4424: #endif
    4425:       ++newp;
    4426:       /* Face E: {d, f, a} */
    4427:       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*3 + GetTriMidEdge_Static(ornt[2], 1);
    4428:       orntNew[0] = ornt[2] < 0 ? 0 : -2;
    4429:       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart);
    4430:       orntNew[1] = -2;
    4431:       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*3 + GetTriMidEdge_Static(ornt[1], 2);
    4432:       orntNew[2] = ornt[1] < 0 ? -2 : 0;
    4433:       DMPlexSetCone(rdm, newp, coneNew);
    4434:       DMPlexSetConeOrientation(rdm, newp, orntNew);
    4435: #if defined(PETSC_USE_DEBUG)
    4436:       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fMaxNew);
    4437:       for (p = 0; p < 3; ++p) {
    4438:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", coneNew[p], eStartNew, eMaxNew);
    4439:       }
    4440: #endif
    4441:       supportNew[0] = (c - cStart)*8 + 0+4;
    4442:       supportNew[1] = (c - cStart)*8 + 3+4;
    4443:       DMPlexSetSupport(rdm, newp, supportNew);
    4444: #if defined(PETSC_USE_DEBUG)
    4445:       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fMaxNew);
    4446:       for (p = 0; p < 2; ++p) {
    4447:         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", supportNew[p], cStartNew, cMaxNew);
    4448:       }
    4449: #endif
    4450:       ++newp;
    4451:       /* Face F: {c, a, f} */
    4452:       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*3 + GetTriMidEdge_Static(ornt[0], 2);
    4453:       orntNew[0] = ornt[0] < 0 ? -2 : 0;
    4454:       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart);
    4455:       orntNew[1] = 0;
    4456:       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*3 + GetTriMidEdge_Static(ornt[2], 0);
    4457:       orntNew[2] = ornt[2] < 0 ? 0 : -2;
    4458:       DMPlexSetCone(rdm, newp, coneNew);
    4459:       DMPlexSetConeOrientation(rdm, newp, orntNew);
    4460: #if defined(PETSC_USE_DEBUG)
    4461:       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fMaxNew);
    4462:       for (p = 0; p < 3; ++p) {
    4463:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", coneNew[p], eStartNew, eMaxNew);
    4464:       }
    4465: #endif
    4466:       supportNew[0] = (c - cStart)*8 + 0+4;
    4467:       supportNew[1] = (c - cStart)*8 + 2+4;
    4468:       DMPlexSetSupport(rdm, newp, supportNew);
    4469: #if defined(PETSC_USE_DEBUG)
    4470:       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fMaxNew);
    4471:       for (p = 0; p < 2; ++p) {
    4472:         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", supportNew[p], cStartNew, cMaxNew);
    4473:       }
    4474: #endif
    4475:       ++newp;
    4476:       /* Face G: {e, a, f} */
    4477:       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*3 + GetTriMidEdge_Static(ornt[1], 1);
    4478:       orntNew[0] = ornt[1] < 0 ? -2 : 0;
    4479:       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart);
    4480:       orntNew[1] = 0;
    4481:       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*3 + GetTriMidEdge_Static(ornt[3], 1);
    4482:       orntNew[2] = ornt[3] < 0 ? 0 : -2;
    4483:       DMPlexSetCone(rdm, newp, coneNew);
    4484:       DMPlexSetConeOrientation(rdm, newp, orntNew);
    4485: #if defined(PETSC_USE_DEBUG)
    4486:       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fMaxNew);
    4487:       for (p = 0; p < 3; ++p) {
    4488:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", coneNew[p], eStartNew, eMaxNew);
    4489:       }
    4490: #endif
    4491:       supportNew[0] = (c - cStart)*8 + 1+4;
    4492:       supportNew[1] = (c - cStart)*8 + 3+4;
    4493:       DMPlexSetSupport(rdm, newp, supportNew);
    4494: #if defined(PETSC_USE_DEBUG)
    4495:       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fMaxNew);
    4496:       for (p = 0; p < 2; ++p) {
    4497:         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", supportNew[p], cStartNew, cMaxNew);
    4498:       }
    4499: #endif
    4500:       ++newp;
    4501:       /* Face H: {a, b, f} */
    4502:       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*3 + GetTriMidEdge_Static(ornt[0], 0);
    4503:       orntNew[0] = ornt[0] < 0 ? -2 : 0;
    4504:       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*3 + GetTriMidEdge_Static(ornt[3], 2);
    4505:       orntNew[1] = ornt[3] < 0 ? 0 : -2;
    4506:       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart);
    4507:       orntNew[2] = -2;
    4508:       DMPlexSetCone(rdm, newp, coneNew);
    4509:       DMPlexSetConeOrientation(rdm, newp, orntNew);
    4510: #if defined(PETSC_USE_DEBUG)
    4511:       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fMaxNew);
    4512:       for (p = 0; p < 3; ++p) {
    4513:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", coneNew[p], eStartNew, eMaxNew);
    4514:       }
    4515: #endif
    4516:       supportNew[0] = (c - cStart)*8 + 1+4;
    4517:       supportNew[1] = (c - cStart)*8 + 2+4;
    4518:       DMPlexSetSupport(rdm, newp, supportNew);
    4519: #if defined(PETSC_USE_DEBUG)
    4520:       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fMaxNew);
    4521:       for (p = 0; p < 2; ++p) {
    4522:         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", supportNew[p], cStartNew, cMaxNew);
    4523:       }
    4524: #endif
    4525:       ++newp;
    4526:     }
    4527:     /* Hybrid split faces have 4 edges and same cells */
    4528:     for (f = fMax; f < fEnd; ++f) {
    4529:       const PetscInt *cone, *ornt, *support;
    4530:       PetscInt        coneNew[4], orntNew[4];
    4531:       PetscInt        supportNew[2], size, s, c;

    4533:       DMPlexGetCone(dm, f, &cone);
    4534:       DMPlexGetConeOrientation(dm, f, &ornt);
    4535:       DMPlexGetSupportSize(dm, f, &size);
    4536:       DMPlexGetSupport(dm, f, &support);
    4537:       for (r = 0; r < 2; ++r) {
    4538:         const PetscInt newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (f - fMax)*2 + r;

    4540:         coneNew[0]   = eStartNew + (cone[0] - eStart)*2 + (ornt[0] < 0 ? 1-r : r);
    4541:         orntNew[0]   = ornt[0];
    4542:         coneNew[1]   = eStartNew + (cone[1] - eStart)*2 + (ornt[1] < 0 ? 1-r : r);
    4543:         orntNew[1]   = ornt[1];
    4544:         coneNew[2+r] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (cone[2+r] - eMax);
    4545:         orntNew[2+r] = 0;
    4546:         coneNew[3-r] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (eEnd      - eMax) + (f - fMax);
    4547:         orntNew[3-r] = 0;
    4548:         DMPlexSetCone(rdm, newp, coneNew);
    4549:         DMPlexSetConeOrientation(rdm, newp, orntNew);
    4550: #if defined(PETSC_USE_DEBUG)
    4551:         if ((newp < fMaxNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a hybrid face [%D, %D)", newp, fMaxNew, fEndNew);
    4552:         for (p = 0; p < 2; ++p) {
    4553:           if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", coneNew[p], eStartNew, eMaxNew);
    4554:         }
    4555:         for (p = 2; p < 4; ++p) {
    4556:           if ((coneNew[p] < eMaxNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a hybrid edge [%D, %D)", coneNew[p], eMaxNew, eEndNew);
    4557:         }
    4558: #endif
    4559:         for (s = 0; s < size; ++s) {
    4560:           const PetscInt *coneCell, *orntCell, *fornt;
    4561:           PetscInt        o, of;

    4563:           DMPlexGetCone(dm, support[s], &coneCell);
    4564:           DMPlexGetConeOrientation(dm, support[s], &orntCell);
    4565:           o = orntCell[0] < 0 ? -1 : 1;
    4566:           for (c = 2; c < 5; ++c) if (coneCell[c] == f) break;
    4567:           if (c >= 5) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Could not find face %D in cone of cell %D", f, support[s]);
    4568:           DMPlexGetConeOrientation(dm, coneCell[0], &fornt);
    4569:           of = fornt[c-2] < 0 ? -1 : 1;
    4570:           supportNew[s] = cStartNew + (cMax - cStart)*8 + (support[s] - cMax)*4 + (GetTriEdgeInverse_Static(orntCell[0], c-2) + (o*of < 0 ? 1-r : r))%3;
    4571:         }
    4572:         DMPlexSetSupport(rdm, newp, supportNew);
    4573: #if defined(PETSC_USE_DEBUG)
    4574:         if ((newp < fMaxNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a hybrid face [%D, %D)", newp, fMaxNew, fEndNew);
    4575:         for (p = 0; p < size; ++p) {
    4576:           if ((supportNew[p] < cMaxNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a hybrid cell [%D, %D)", supportNew[p], cMaxNew, cEndNew);
    4577:         }
    4578: #endif
    4579:       }
    4580:     }
    4581:     /* Hybrid cell faces have 4 edges and 2 cells */
    4582:     for (c = cMax; c < cEnd; ++c) {
    4583:       PetscInt        newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (c - cMax)*3;
    4584:       const PetscInt *cone, *ornt;
    4585:       PetscInt        coneNew[4], orntNew[4];
    4586:       PetscInt        supportNew[2];

    4588:       DMPlexGetCone(dm, c, &cone);
    4589:       DMPlexGetConeOrientation(dm, c, &ornt);
    4590:       for (r = 0; r < 3; ++r) {
    4591:         coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*3 + (r+2)%3;
    4592:         orntNew[0] = 0;
    4593:         coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*3 + (r+2)%3;
    4594:         orntNew[1] = 0;
    4595:         coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (eEnd - eMax) + (cone[2+(r+2)%3] - fMax);
    4596:         orntNew[2] = 0;
    4597:         coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (eEnd - eMax) + (cone[2+r]       - fMax);
    4598:         orntNew[3] = 0;
    4599:         DMPlexSetCone(rdm, newp+r, coneNew);
    4600:         DMPlexSetConeOrientation(rdm, newp+r, orntNew);
    4601: #if defined(PETSC_USE_DEBUG)
    4602:         if ((newp+r < fMaxNew) || (newp+r >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a hybrid face [%D, %D)", newp+r, fMaxNew, fEndNew);
    4603:         for (p = 0; p < 2; ++p) {
    4604:           if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", coneNew[p], eStartNew, eMaxNew);
    4605:         }
    4606:         for (p = 2; p < 4; ++p) {
    4607:           if ((coneNew[p] < eMaxNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a hybrid edge [%D, %D)", coneNew[p], eMaxNew, eEndNew);
    4608:         }
    4609: #endif
    4610:         supportNew[0] = cStartNew + (cMax - cStart)*8 + (c - cMax)*4 + GetTriSubface_Static(ornt[0], r);
    4611:         supportNew[1] = cStartNew + (cMax - cStart)*8 + (c - cMax)*4 + 3;
    4612:         DMPlexSetSupport(rdm, newp+r, supportNew);
    4613: #if defined(PETSC_USE_DEBUG)
    4614:         if ((newp+r < fMaxNew) || (newp+r >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a hybrid face [%D, %D)", newp+r, fMaxNew, fEndNew);
    4615:         for (p = 0; p < 2; ++p) {
    4616:           if ((supportNew[p] < cMaxNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a hybrid cell [%D, %D)", supportNew[p], cMaxNew, cEndNew);
    4617:         }
    4618: #endif
    4619:       }
    4620:     }
    4621:     /* Interior split edges have 2 vertices and the same faces as the parent */
    4622:     for (e = eStart; e < eMax; ++e) {
    4623:       const PetscInt newv = vStartNew + (vEnd - vStart) + (e - eStart);

    4625:       for (r = 0; r < 2; ++r) {
    4626:         const PetscInt  newp = eStartNew + (e - eStart)*2 + r;
    4627:         const PetscInt *cone, *ornt, *support;
    4628:         PetscInt        coneNew[2], coneSize, c, supportSize, s;

    4630:         DMPlexGetCone(dm, e, &cone);
    4631:         coneNew[0]       = vStartNew + (cone[0] - vStart);
    4632:         coneNew[1]       = vStartNew + (cone[1] - vStart);
    4633:         coneNew[(r+1)%2] = newv;
    4634:         DMPlexSetCone(rdm, newp, coneNew);
    4635: #if defined(PETSC_USE_DEBUG)
    4636:         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eMaxNew);
    4637:         for (p = 0; p < 2; ++p) {
    4638:           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", coneNew[p], vStartNew, vEndNew);
    4639:         }
    4640: #endif
    4641:         DMPlexGetSupportSize(dm, e, &supportSize);
    4642:         DMPlexGetSupport(dm, e, &support);
    4643:         for (s = 0; s < supportSize; ++s) {
    4644:           DMPlexGetConeSize(dm, support[s], &coneSize);
    4645:           DMPlexGetCone(dm, support[s], &cone);
    4646:           DMPlexGetConeOrientation(dm, support[s], &ornt);
    4647:           for (c = 0; c < coneSize; ++c) if (cone[c] == e) break;
    4648:           if (support[s] < fMax) {
    4649:             supportRef[s] = fStartNew + (support[s] - fStart)*4 + (c + (ornt[c] < 0 ? 1-r : r))%3;
    4650:           } else {
    4651:             supportRef[s] = fStartNew + (fMax       - fStart)*4 + (cMax - cStart)*8 + (support[s] - fMax)*2 + (ornt[c] < 0 ? 1-r : r);
    4652:           }
    4653:         }
    4654:         DMPlexSetSupport(rdm, newp, supportRef);
    4655: #if defined(PETSC_USE_DEBUG)
    4656:         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eMaxNew);
    4657:         for (p = 0; p < supportSize; ++p) {
    4658:           if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an interior or hybrid face [%D, %D)", supportRef[p], fStartNew, fEndNew);
    4659:         }
    4660: #endif
    4661:       }
    4662:     }
    4663:     /* Interior face edges have 2 vertices and 2+cells*(1/2) faces */
    4664:     for (f = fStart; f < fMax; ++f) {
    4665:       const PetscInt *cone, *ornt, *support;
    4666:       PetscInt        coneSize, supportSize, s;

    4668:       DMPlexGetSupportSize(dm, f, &supportSize);
    4669:       DMPlexGetSupport(dm, f, &support);
    4670:       for (r = 0; r < 3; ++r) {
    4671:         const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (f - fStart)*3 + r;
    4672:         PetscInt        coneNew[2], intFaces = 0, er, eint[4] = {1, 0, 2, 0};
    4673:         PetscInt        fint[24] = { 1,  7, -1, -1,  0,  5,
    4674:                                     -1, -1,  1,  6,  0,  4,
    4675:                                      2,  5,  3,  4, -1, -1,
    4676:                                     -1, -1,  3,  6,  2,  7};

    4678:         DMPlexGetCone(dm, f, &cone);
    4679:         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[(r+0)%3] - eStart);
    4680:         coneNew[1] = vStartNew + (vEnd - vStart) + (cone[(r+1)%3] - eStart);
    4681:         DMPlexSetCone(rdm, newp, coneNew);
    4682: #if defined(PETSC_USE_DEBUG)
    4683:         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eMaxNew);
    4684:         for (p = 0; p < 2; ++p) {
    4685:           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", coneNew[p], vStartNew, vEndNew);
    4686:         }
    4687: #endif
    4688:         supportRef[0] = fStartNew + (f - fStart)*4 + (r+1)%3;
    4689:         supportRef[1] = fStartNew + (f - fStart)*4 + 3;
    4690:         for (s = 0; s < supportSize; ++s) {
    4691:           DMPlexGetConeSize(dm, support[s], &coneSize);
    4692:           DMPlexGetCone(dm, support[s], &cone);
    4693:           DMPlexGetConeOrientation(dm, support[s], &ornt);
    4694:           for (c = 0; c < coneSize; ++c) {if (cone[c] == f) break;}
    4695:           if (support[s] < cMax) {
    4696:             /* Here we want to determine whether edge newp contains a vertex which is part of the cross-tet edge */
    4697:             er = GetTriMidEdgeInverse_Static(ornt[c], r);
    4698:             if (er == eint[c]) {
    4699:               supportRef[2+intFaces++] = fStartNew + (fMax - fStart)*4 + (support[s] - cStart)*8 + (c + 2)%4;
    4700:             } else {
    4701:               supportRef[2+intFaces++] = fStartNew + (fMax - fStart)*4 + (support[s] - cStart)*8 + fint[(c*3 + er)*2 + 0];
    4702:               supportRef[2+intFaces++] = fStartNew + (fMax - fStart)*4 + (support[s] - cStart)*8 + fint[(c*3 + er)*2 + 1];
    4703:             }
    4704:           } else {
    4705:             supportRef[2+intFaces++] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (support[s] - cMax)*3 + (r + 1)%3;
    4706:           }
    4707:         }
    4708:         DMPlexSetSupport(rdm, newp, supportRef);
    4709: #if defined(PETSC_USE_DEBUG)
    4710:         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eMaxNew);
    4711:         for (p = 0; p < intFaces; ++p) {
    4712:           if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an interior or hybrid face [%D, %D)", supportRef[p], fStartNew, fEndNew);
    4713:         }
    4714: #endif
    4715:       }
    4716:     }
    4717:     /* Interior cell edges have 2 vertices and 4 faces */
    4718:     for (c = cStart; c < cMax; ++c) {
    4719:       const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart);
    4720:       const PetscInt *cone, *ornt, *fcone;
    4721:       PetscInt        coneNew[2], supportNew[4], find;

    4723:       DMPlexGetCone(dm, c, &cone);
    4724:       DMPlexGetConeOrientation(dm, c, &ornt);
    4725:       DMPlexGetCone(dm, cone[0], &fcone);
    4726:       find = GetTriEdge_Static(ornt[0], 0);
    4727:       coneNew[0] = vStartNew + (vEnd - vStart) + (fcone[find] - eStart);
    4728:       DMPlexGetCone(dm, cone[2], &fcone);
    4729:       find = GetTriEdge_Static(ornt[2], 1);
    4730:       coneNew[1] = vStartNew + (vEnd - vStart) + (fcone[find] - eStart);
    4731:       DMPlexSetCone(rdm, newp, coneNew);
    4732: #if defined(PETSC_USE_DEBUG)
    4733:       if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eMaxNew);
    4734:       for (p = 0; p < 2; ++p) {
    4735:         if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", coneNew[p], vStartNew, vEndNew);
    4736:       }
    4737: #endif
    4738:       supportNew[0] = fStartNew + (fMax - fStart)*4 + (c - cStart)*8 + 4;
    4739:       supportNew[1] = fStartNew + (fMax - fStart)*4 + (c - cStart)*8 + 5;
    4740:       supportNew[2] = fStartNew + (fMax - fStart)*4 + (c - cStart)*8 + 6;
    4741:       supportNew[3] = fStartNew + (fMax - fStart)*4 + (c - cStart)*8 + 7;
    4742:       DMPlexSetSupport(rdm, newp, supportNew);
    4743: #if defined(PETSC_USE_DEBUG)
    4744:       if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eMaxNew);
    4745:       for (p = 0; p < 4; ++p) {
    4746:         if ((supportNew[p] < fStartNew) || (supportNew[p] >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", supportNew[p], fStartNew, fMaxNew);
    4747:       }
    4748: #endif
    4749:     }
    4750:     /* Hybrid edges have two vertices and the same faces */
    4751:     for (e = eMax; e < eEnd; ++e) {
    4752:       const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (e - eMax);
    4753:       const PetscInt *cone, *support, *fcone;
    4754:       PetscInt        coneNew[2], size, fsize, s;

    4756:       DMPlexGetCone(dm, e, &cone);
    4757:       DMPlexGetSupportSize(dm, e, &size);
    4758:       DMPlexGetSupport(dm, e, &support);
    4759:       coneNew[0] = vStartNew + (cone[0] - vStart);
    4760:       coneNew[1] = vStartNew + (cone[1] - vStart);
    4761:       DMPlexSetCone(rdm, newp, coneNew);
    4762: #if defined(PETSC_USE_DEBUG)
    4763:       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a hybrid edge [%D, %D)", newp, eMaxNew, eEndNew);
    4764:       for (p = 0; p < 2; ++p) {
    4765:         if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", coneNew[p], vStartNew, vEndNew);
    4766:       }
    4767: #endif
    4768:       for (s = 0; s < size; ++s) {
    4769:         DMPlexGetConeSize(dm, support[s], &fsize);
    4770:         DMPlexGetCone(dm, support[s], &fcone);
    4771:         for (c = 0; c < fsize; ++c) if (fcone[c] == e) break;
    4772:         if ((c < 2) || (c > 3)) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Edge %D not found in cone of face %D", e, support[s]);
    4773:         supportRef[s] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (support[s] - fMax)*2 + c-2;
    4774:       }
    4775:       DMPlexSetSupport(rdm, newp, supportRef);
    4776: #if defined(PETSC_USE_DEBUG)
    4777:       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a hybrid edge [%D, %D)", newp, eMaxNew, eEndNew);
    4778:       for (p = 0; p < size; ++p) {
    4779:         if ((supportRef[p] < fMaxNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a hybrid face [%D, %D)", supportRef[p], fMaxNew, fEndNew);
    4780:       }
    4781: #endif
    4782:     }
    4783:     /* Hybrid face edges have 2 vertices and 2+2*cells faces */
    4784:     for (f = fMax; f < fEnd; ++f) {
    4785:       const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (eEnd - eMax) + (f - fMax);
    4786:       const PetscInt *cone, *support, *ccone, *cornt;
    4787:       PetscInt        coneNew[2], size, csize, s;

    4789:       DMPlexGetCone(dm, f, &cone);
    4790:       DMPlexGetSupportSize(dm, f, &size);
    4791:       DMPlexGetSupport(dm, f, &support);
    4792:       coneNew[0] = vStartNew + (vEnd - vStart) + (cone[0] - eStart);
    4793:       coneNew[1] = vStartNew + (vEnd - vStart) + (cone[1] - eStart);
    4794:       DMPlexSetCone(rdm, newp, coneNew);
    4795: #if defined(PETSC_USE_DEBUG)
    4796:       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a hybrid edge [%D, %D)", newp, eMaxNew, eEndNew);
    4797:       for (p = 0; p < 2; ++p) {
    4798:         if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", coneNew[p], vStartNew, vEndNew);
    4799:       }
    4800: #endif
    4801:       supportRef[0] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (f - fMax)*2 + 0;
    4802:       supportRef[1] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (f - fMax)*2 + 1;
    4803:       for (s = 0; s < size; ++s) {
    4804:         DMPlexGetConeSize(dm, support[s], &csize);
    4805:         DMPlexGetCone(dm, support[s], &ccone);
    4806:         DMPlexGetConeOrientation(dm, support[s], &cornt);
    4807:         for (c = 0; c < csize; ++c) if (ccone[c] == f) break;
    4808:         if ((c < 2) || (c >= csize)) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Hybrid face %D is not in cone of hybrid cell %D", f, support[s]);
    4809:         supportRef[2+s*2+0] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (support[s] - cMax)*3 + c-2;
    4810:         supportRef[2+s*2+1] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (support[s] - cMax)*3 + (c-1)%3;
    4811:       }
    4812:       DMPlexSetSupport(rdm, newp, supportRef);
    4813: #if defined(PETSC_USE_DEBUG)
    4814:       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a hybrid edge [%D, %D)", newp, eMaxNew, eEndNew);
    4815:       for (p = 0; p < 2+size*2; ++p) {
    4816:         if ((supportRef[p] < fMaxNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a hybrid face [%D, %D)", supportRef[p], fMaxNew, fEndNew);
    4817:       }
    4818: #endif
    4819:     }
    4820:     /* Interior vertices have identical supports */
    4821:     for (v = vStart; v < vEnd; ++v) {
    4822:       const PetscInt  newp = vStartNew + (v - vStart);
    4823:       const PetscInt *support, *cone;
    4824:       PetscInt        size, s;

    4826:       DMPlexGetSupportSize(dm, v, &size);
    4827:       DMPlexGetSupport(dm, v, &support);
    4828:       for (s = 0; s < size; ++s) {
    4829:         PetscInt r = 0;

    4831:         DMPlexGetCone(dm, support[s], &cone);
    4832:         if (cone[1] == v) r = 1;
    4833:         if (support[s] < eMax) supportRef[s] = eStartNew + (support[s] - eStart)*2 + r;
    4834:         else                   supportRef[s] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (support[s] - eMax);
    4835:       }
    4836:       DMPlexSetSupport(rdm, newp, supportRef);
    4837: #if defined(PETSC_USE_DEBUG)
    4838:       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", newp, vStartNew, vEndNew);
    4839:       for (p = 0; p < size; ++p) {
    4840:         if ((supportRef[p] < eStartNew) || (supportRef[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an interior or hybrid edge [%D, %D)", supportRef[p], eStartNew, eEndNew);
    4841:       }
    4842: #endif
    4843:     }
    4844:     /* Interior edge vertices have 2 + interior face*2 + hybrid face + cells*0/1 supports */
    4845:     for (e = eStart; e < eMax; ++e) {
    4846:       const PetscInt  newp = vStartNew + (vEnd - vStart) + (e - eStart);
    4847:       const PetscInt *cone, *support;
    4848:       PetscInt       *star = NULL, starSize, faceSize = 0, cellSize = 0, coneSize, size, s;

    4850:       DMPlexGetSupportSize(dm, e, &size);
    4851:       DMPlexGetSupport(dm, e, &support);
    4852:       supportRef[0] = eStartNew + (e - eStart)*2 + 0;
    4853:       supportRef[1] = eStartNew + (e - eStart)*2 + 1;
    4854:       for (s = 0; s < size; ++s) {
    4855:         PetscInt r = 0;

    4857:         if (support[s] < fMax) {
    4858:           DMPlexGetConeSize(dm, support[s], &coneSize);
    4859:           DMPlexGetCone(dm, support[s], &cone);
    4860:           for (r = 0; r < coneSize; ++r) {if (cone[r] == e) break;}
    4861:           supportRef[2+faceSize+0] = eStartNew + (eMax - eStart)*2 + (support[s] - fStart)*3 + (r+0)%3;
    4862:           supportRef[2+faceSize+1] = eStartNew + (eMax - eStart)*2 + (support[s] - fStart)*3 + (r+2)%3;
    4863:           faceSize += 2;
    4864:         } else {
    4865:           supportRef[2+faceSize+0] = eStartNew + (eMax - eStart)*2 + (fMax       - fStart)*3 + (cMax - cStart) + (eEnd - eMax) + (support[s] - fMax);
    4866:           ++faceSize;
    4867:         }
    4868:       }
    4869:       DMPlexGetTransitiveClosure(dm, e, PETSC_FALSE, &starSize, &star);
    4870:       for (s = 0; s < starSize*2; s += 2) {
    4871:         const PetscInt *cone, *ornt;
    4872:         PetscInt        e01, e23;

    4874:         if ((star[s] >= cStart) && (star[s] < cMax)) {
    4875:           /* Check edge 0-1 */
    4876:           DMPlexGetCone(dm, star[s], &cone);
    4877:           DMPlexGetConeOrientation(dm, star[s], &ornt);
    4878:           DMPlexGetCone(dm, cone[0], &cone);
    4879:           e01  = cone[GetTriEdge_Static(ornt[0], 0)];
    4880:           /* Check edge 2-3 */
    4881:           DMPlexGetCone(dm, star[s], &cone);
    4882:           DMPlexGetConeOrientation(dm, star[s], &ornt);
    4883:           DMPlexGetCone(dm, cone[2], &cone);
    4884:           e23  = cone[GetTriEdge_Static(ornt[2], 1)];
    4885:           if ((e01 == e) || (e23 == e)) {supportRef[2+faceSize+cellSize++] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (star[s] - cStart);}
    4886:         }
    4887:       }
    4888:       DMPlexRestoreTransitiveClosure(dm, e, PETSC_FALSE, &starSize, &star);
    4889:       DMPlexSetSupport(rdm, newp, supportRef);
    4890: #if defined(PETSC_USE_DEBUG)
    4891:       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", newp, vStartNew, vEndNew);
    4892:       for (p = 0; p < 2+faceSize+cellSize; ++p) {
    4893:         if ((supportRef[p] < eStartNew) || (supportRef[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an interior or hybrid edge [%D, %D)", supportRef[p], eStartNew, eEndNew);
    4894:       }
    4895: #endif
    4896:     }
    4897:     PetscFree(supportRef);
    4898:     DMPlexRestoreFaces_Internal(dm, 3, cStart, NULL, NULL, &faces);
    4899:     break;
    4900:   case REFINER_SIMPLEX_TO_HEX_3D:
    4901:     DMPlexGetRawFaces_Internal(dm, 3, 4, cellInd, NULL, NULL, &faces);
    4902:     /* All cells have 6 faces */
    4903:     for (c = cStart; c < cEnd; ++c) {
    4904:       const PetscInt  newp = cStartNew + (c - cStart)*4;
    4905:       const PetscInt *cone, *ornt;
    4906:       PetscInt        coneNew[6];
    4907:       PetscInt        orntNew[6];

    4909:       DMPlexGetCone(dm, c, &cone);
    4910:       DMPlexGetConeOrientation(dm, c, &ornt);
    4911:       /* A hex */
    4912:       coneNew[0] = fStartNew + (cone[0] - fStart)*3 + GetTriSubface_Static(ornt[0], 0); /* B */
    4913:       orntNew[0] = ornt[0] < 0 ? -1 : 1;
    4914:       coneNew[1] = fStartNew + (fEnd    - fStart)*3 + (c - cStart)*6 + 3;               /* T */
    4915:       orntNew[1] = -4;
    4916:       coneNew[2] = fStartNew + (cone[2] - fStart)*3 + GetTriSubface_Static(ornt[2], 0); /* F */
    4917:       orntNew[2] = ornt[2] < 0 ? -1 : 1;
    4918:       coneNew[3] = fStartNew + (fEnd    - fStart)*3 + (c - cStart)*6 + 0;               /* K */
    4919:       orntNew[3] = -1;
    4920:       coneNew[4] = fStartNew + (fEnd    - fStart)*3 + (c - cStart)*6 + 2;               /* R */
    4921:       orntNew[4] = 0;
    4922:       coneNew[5] = fStartNew + (cone[1] - fStart)*3 + GetTriSubface_Static(ornt[1], 0); /* L */
    4923:       orntNew[5] = ornt[1] < 0 ? -1 : 1;
    4924:       DMPlexSetCone(rdm, newp+0, coneNew);
    4925:       DMPlexSetConeOrientation(rdm, newp+0, orntNew);
    4926: #if defined(PETSC_USE_DEBUG)
    4927:       if ((newp+0 < cStartNew) || (newp+0 >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", newp+0, cStartNew, cEndNew);
    4928:       for (p = 0; p < 6; ++p) {
    4929:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", coneNew[p], fStartNew, fEndNew);
    4930:       }
    4931: #endif
    4932:       /* B hex */
    4933:       coneNew[0] = fStartNew + (cone[0] - fStart)*3 + GetTriSubface_Static(ornt[0], 1); /* B */
    4934:       orntNew[0] = ornt[0] < 0 ? -2 : 0;
    4935:       coneNew[1] = fStartNew + (fEnd    - fStart)*3 + (c - cStart)*6 + 4;               /* T */
    4936:       orntNew[1] = 0;
    4937:       coneNew[2] = fStartNew + (fEnd    - fStart)*3 + (c - cStart)*6 + 0;               /* F */
    4938:       orntNew[2] = 0;
    4939:       coneNew[3] = fStartNew + (cone[3] - fStart)*3 + GetTriSubface_Static(ornt[3], 1); /* K */
    4940:       orntNew[3] = ornt[3] < 0 ? -2 : 0;
    4941:       coneNew[4] = fStartNew + (fEnd    - fStart)*3 + (c - cStart)*6 + 1;               /* R */
    4942:       orntNew[4] = 0;
    4943:       coneNew[5] = fStartNew + (cone[1] - fStart)*3 + GetTriSubface_Static(ornt[1], 2); /* L */
    4944:       orntNew[5] = ornt[1] < 0 ? -4 : 2;
    4945:       DMPlexSetCone(rdm, newp+1, coneNew);
    4946:       DMPlexSetConeOrientation(rdm, newp+1, orntNew);
    4947: #if defined(PETSC_USE_DEBUG)
    4948:       if ((newp+1 < cStartNew) || (newp+1 >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", newp+1, cStartNew, cEndNew);
    4949:       for (p = 0; p < 6; ++p) {
    4950:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", coneNew[p], fStartNew, fEndNew);
    4951:       }
    4952: #endif
    4953:       /* C hex */
    4954:       coneNew[0] = fStartNew + (cone[0] - fStart)*3 + GetTriSubface_Static(ornt[0], 2); /* B */
    4955:       orntNew[0] = ornt[0] < 0 ? -4 : 2;
    4956:       coneNew[1] = fStartNew + (fEnd    - fStart)*3 + (c - cStart)*6 + 5;               /* T */
    4957:       orntNew[1] = -4;
    4958:       coneNew[2] = fStartNew + (cone[2] - fStart)*3 + GetTriSubface_Static(ornt[2], 1); /* F */
    4959:       orntNew[2] = ornt[2] < 0 ? -2 : 0;
    4960:       coneNew[3] = fStartNew + (fEnd    - fStart)*3 + (c - cStart)*6 + 1;               /* K */
    4961:       orntNew[3] = -1;
    4962:       coneNew[4] = fStartNew + (cone[3] - fStart)*3 + GetTriSubface_Static(ornt[3], 0); /* R */
    4963:       orntNew[4] = ornt[3] < 0 ? -1 : 1;
    4964:       coneNew[5] = fStartNew + (fEnd    - fStart)*3 + (c - cStart)*6 + 2;               /* L */
    4965:       orntNew[5] = -4;
    4966:       DMPlexSetCone(rdm, newp+2, coneNew);
    4967:       DMPlexSetConeOrientation(rdm, newp+2, orntNew);
    4968: #if defined(PETSC_USE_DEBUG)
    4969:       if ((newp+2 < cStartNew) || (newp+2 >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", newp+2, cStartNew, cEndNew);
    4970:       for (p = 0; p < 6; ++p) {
    4971:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", coneNew[p], fStartNew, fEndNew);
    4972:       }
    4973: #endif
    4974:       /* D hex */
    4975:       coneNew[0] = fStartNew + (fEnd    - fStart)*3 + (c - cStart)*6 + 3;               /* B */
    4976:       orntNew[0] = 0;
    4977:       coneNew[1] = fStartNew + (cone[3] - fStart)*3 + GetTriSubface_Static(ornt[3], 2); /* T */
    4978:       orntNew[1] = ornt[3] < 0 ? -1 : 1;
    4979:       coneNew[2] = fStartNew + (cone[2] - fStart)*3 + GetTriSubface_Static(ornt[2], 2); /* F */
    4980:       orntNew[2] = ornt[2] < 0 ? -4 : 2;
    4981:       coneNew[3] = fStartNew + (fEnd    - fStart)*3 + (c - cStart)*6 + 4;               /* K */
    4982:       orntNew[3] = -1;
    4983:       coneNew[4] = fStartNew + (fEnd    - fStart)*3 + (c - cStart)*6 + 5;               /* R */
    4984:       orntNew[4] = 0;
    4985:       coneNew[5] = fStartNew + (cone[1] - fStart)*3 + GetTriSubface_Static(ornt[1], 1); /* L */
    4986:       orntNew[5] = ornt[1] < 0 ? -2 : 0;
    4987:       DMPlexSetCone(rdm, newp+3, coneNew);
    4988:       DMPlexSetConeOrientation(rdm, newp+3, orntNew);
    4989: #if defined(PETSC_USE_DEBUG)
    4990:       if ((newp+3 < cStartNew) || (newp+3 >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", newp+3, cStartNew, cEndNew);
    4991:       for (p = 0; p < 6; ++p) {
    4992:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", coneNew[p], fStartNew, fEndNew);
    4993:       }
    4994: #endif
    4995:     }
    4996:     /* Split faces have 4 edges and the same cells as the parent */
    4997:     DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);
    4998:     PetscMalloc1(2 + maxSupportSize*2, &supportRef);
    4999:     for (f = fStart; f < fEnd; ++f) {
    5000:       const PetscInt  newp = fStartNew + (f - fStart)*3;
    5001:       const PetscInt *cone, *ornt, *support;
    5002:       PetscInt        coneNew[4], orntNew[4], coneSize, supportSize, s;

    5004:       DMPlexGetCone(dm, f, &cone);
    5005:       DMPlexGetConeOrientation(dm, f, &ornt);
    5006:       /* A quad */
    5007:       coneNew[0] = eStartNew + (cone[2] - eStart)*2 + (ornt[2] < 0 ? 0 : 1);
    5008:       orntNew[0] = ornt[2];
    5009:       coneNew[1] = eStartNew + (cone[0] - eStart)*2 + (ornt[0] < 0 ? 1 : 0);
    5010:       orntNew[1] = ornt[0];
    5011:       coneNew[2] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 0;
    5012:       orntNew[2] = 0;
    5013:       coneNew[3] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 2;
    5014:       orntNew[3] = -2;
    5015:       DMPlexSetCone(rdm, newp+0, coneNew);
    5016:       DMPlexSetConeOrientation(rdm, newp+0, orntNew);
    5017: #if defined(PETSC_USE_DEBUG)
    5018:       if ((newp+0 < fStartNew) || (newp+0 >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp+0, fStartNew, fEndNew);
    5019:       for (p = 0; p < 4; ++p) {
    5020:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", coneNew[p], eStartNew, eEndNew);
    5021:       }
    5022: #endif
    5023:       /* B quad */
    5024:       coneNew[0] = eStartNew + (cone[0] - eStart)*2 + (ornt[0] < 0 ? 0 : 1);
    5025:       orntNew[0] = ornt[0];
    5026:       coneNew[1] = eStartNew + (cone[1] - eStart)*2 + (ornt[1] < 0 ? 1 : 0);
    5027:       orntNew[1] = ornt[1];
    5028:       coneNew[2] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 1;
    5029:       orntNew[2] = 0;
    5030:       coneNew[3] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 0;
    5031:       orntNew[3] = -2;
    5032:       DMPlexSetCone(rdm, newp+1, coneNew);
    5033:       DMPlexSetConeOrientation(rdm, newp+1, orntNew);
    5034: #if defined(PETSC_USE_DEBUG)
    5035:       if ((newp+1 < fStartNew) || (newp+1 >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp+1, fStartNew, fEndNew);
    5036:       for (p = 0; p < 4; ++p) {
    5037:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", coneNew[p], eStartNew, eEndNew);
    5038:       }
    5039: #endif
    5040:       /* C quad */
    5041:       coneNew[0] = eStartNew + (cone[1] - eStart)*2 + (ornt[1] < 0 ? 0 : 1);
    5042:       orntNew[0] = ornt[1];
    5043:       coneNew[1] = eStartNew + (cone[2] - eStart)*2 + (ornt[2] < 0 ? 1 : 0);
    5044:       orntNew[1] = ornt[2];
    5045:       coneNew[2] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 2;
    5046:       orntNew[2] = 0;
    5047:       coneNew[3] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 1;
    5048:       orntNew[3] = -2;
    5049:       DMPlexSetCone(rdm, newp+2, coneNew);
    5050:       DMPlexSetConeOrientation(rdm, newp+2, orntNew);
    5051: #if defined(PETSC_USE_DEBUG)
    5052:       if ((newp+2 < fStartNew) || (newp+2 >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp+2, fStartNew, fEndNew);
    5053:       for (p = 0; p < 4; ++p) {
    5054:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", coneNew[p], eStartNew, eEndNew);
    5055:       }
    5056: #endif
    5057:       DMPlexGetSupportSize(dm, f, &supportSize);
    5058:       DMPlexGetSupport(dm, f, &support);
    5059:       for (r = 0; r < 3; ++r) {
    5060:         for (s = 0; s < supportSize; ++s) {
    5061:           PetscInt subf;
    5062:           DMPlexGetConeSize(dm, support[s], &coneSize);
    5063:           DMPlexGetCone(dm, support[s], &cone);
    5064:           DMPlexGetConeOrientation(dm, support[s], &ornt);
    5065:           for (c = 0; c < coneSize; ++c) {
    5066:             if (cone[c] == f) break;
    5067:           }
    5068:           subf = GetTriSubfaceInverse_Static(ornt[c], r);
    5069:           supportRef[s] = cStartNew + (support[s] - cStart)*4 + faces[c*3+subf];
    5070:         }
    5071:         DMPlexSetSupport(rdm, newp+r, supportRef);
    5072: #if defined(PETSC_USE_DEBUG)
    5073:         if ((newp+r < fStartNew) || (newp+r >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp+r, fStartNew, fEndNew);
    5074:         for (p = 0; p < supportSize; ++p) {
    5075:           if ((supportRef[p] < cStartNew) || (supportRef[p] >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", supportRef[p], cStartNew, cEndNew);
    5076:         }
    5077: #endif
    5078:       }
    5079:     }
    5080:     /* Interior faces have 4 edges and 2 cells */
    5081:     for (c = cStart; c < cEnd; ++c) {
    5082:       PetscInt        newp = fStartNew + (fEnd - fStart)*3 + (c - cStart)*6;
    5083:       const PetscInt *cone, *ornt;
    5084:       PetscInt        coneNew[4], orntNew[4];
    5085:       PetscInt        supportNew[2];

    5087:       DMPlexGetCone(dm, c, &cone);
    5088:       DMPlexGetConeOrientation(dm, c, &ornt);
    5089:       /* Face {a, g, m, h} */
    5090:       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*3 + GetTriInteriorEdge_Static(ornt[0],0);
    5091:       orntNew[0] = 0;
    5092:       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + 0;
    5093:       orntNew[1] = 0;
    5094:       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + 1;
    5095:       orntNew[2] = -2;
    5096:       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*3 + GetTriInteriorEdge_Static(ornt[1],2);
    5097:       orntNew[3] = -2;
    5098:       DMPlexSetCone(rdm, newp, coneNew);
    5099:       DMPlexSetConeOrientation(rdm, newp, orntNew);
    5100: #if defined(PETSC_USE_DEBUG)
    5101:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
    5102:       for (p = 0; p < 4; ++p) {
    5103:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", coneNew[p], eStartNew, eEndNew);
    5104:       }
    5105: #endif
    5106:       supportNew[0] = (c - cStart)*4 + 0;
    5107:       supportNew[1] = (c - cStart)*4 + 1;
    5108:       DMPlexSetSupport(rdm, newp, supportNew);
    5109: #if defined(PETSC_USE_DEBUG)
    5110:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
    5111:       for (p = 0; p < 2; ++p) {
    5112:         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", supportNew[p], cStartNew, cEndNew);
    5113:       }
    5114: #endif
    5115:       ++newp;
    5116:       /* Face {g, b, l , m} */
    5117:       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*3 + GetTriInteriorEdge_Static(ornt[0],1);
    5118:       orntNew[0] = -2;
    5119:       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*3 + GetTriInteriorEdge_Static(ornt[3],0);
    5120:       orntNew[1] = 0;
    5121:       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + 3;
    5122:       orntNew[2] = 0;
    5123:       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + 0;
    5124:       orntNew[3] = -2;
    5125:       DMPlexSetCone(rdm, newp, coneNew);
    5126:       DMPlexSetConeOrientation(rdm, newp, orntNew);
    5127: #if defined(PETSC_USE_DEBUG)
    5128:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
    5129:       for (p = 0; p < 4; ++p) {
    5130:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", coneNew[p], eStartNew, eEndNew);
    5131:       }
    5132: #endif
    5133:       supportNew[0] = (c - cStart)*4 + 1;
    5134:       supportNew[1] = (c - cStart)*4 + 2;
    5135:       DMPlexSetSupport(rdm, newp, supportNew);
    5136: #if defined(PETSC_USE_DEBUG)
    5137:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
    5138:       for (p = 0; p < 2; ++p) {
    5139:         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", supportNew[p], cStartNew, cEndNew);
    5140:       }
    5141: #endif
    5142:       ++newp;
    5143:       /* Face {c, g, m, i} */
    5144:       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*3 + GetTriInteriorEdge_Static(ornt[0],2);
    5145:       orntNew[0] = 0;
    5146:       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + 0;
    5147:       orntNew[1] = 0;
    5148:       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + 2;
    5149:       orntNew[2] = -2;
    5150:       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*3 + GetTriInteriorEdge_Static(ornt[2],0);
    5151:       orntNew[3] = -2;
    5152:       DMPlexSetCone(rdm, newp, coneNew);
    5153:       DMPlexSetConeOrientation(rdm, newp, orntNew);
    5154: #if defined(PETSC_USE_DEBUG)
    5155:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
    5156:       for (p = 0; p < 4; ++p) {
    5157:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", coneNew[p], eStartNew, eEndNew);
    5158:       }
    5159: #endif
    5160:       supportNew[0] = (c - cStart)*4 + 0;
    5161:       supportNew[1] = (c - cStart)*4 + 2;
    5162:       DMPlexSetSupport(rdm, newp, supportNew);
    5163: #if defined(PETSC_USE_DEBUG)
    5164:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
    5165:       for (p = 0; p < 2; ++p) {
    5166:         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", supportNew[p], cStartNew, cEndNew);
    5167:       }
    5168: #endif
    5169:       ++newp;
    5170:       /* Face {d, h, m, i} */
    5171:       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*3 + GetTriInteriorEdge_Static(ornt[1],0);
    5172:       orntNew[0] = 0;
    5173:       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + 1;
    5174:       orntNew[1] = 0;
    5175:       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + 2;
    5176:       orntNew[2] = -2;
    5177:       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*3 + GetTriInteriorEdge_Static(ornt[2],2);
    5178:       orntNew[3] = -2;
    5179:       DMPlexSetCone(rdm, newp, coneNew);
    5180:       DMPlexSetConeOrientation(rdm, newp, orntNew);
    5181: #if defined(PETSC_USE_DEBUG)
    5182:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
    5183:       for (p = 0; p < 4; ++p) {
    5184:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", coneNew[p], eStartNew, eEndNew);
    5185:       }
    5186: #endif
    5187:       supportNew[0] = (c - cStart)*4 + 0;
    5188:       supportNew[1] = (c - cStart)*4 + 3;
    5189:       DMPlexSetSupport(rdm, newp, supportNew);
    5190: #if defined(PETSC_USE_DEBUG)
    5191:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
    5192:       for (p = 0; p < 2; ++p) {
    5193:         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", supportNew[p], cStartNew, cEndNew);
    5194:       }
    5195: #endif
    5196:       ++newp;
    5197:       /* Face {h, m, l, e} */
    5198:       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + 1;
    5199:       orntNew[0] = 0;
    5200:       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + 3;
    5201:       orntNew[1] = -2;
    5202:       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*3 + GetTriInteriorEdge_Static(ornt[3],1);
    5203:       orntNew[2] = -2;
    5204:       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*3 + GetTriInteriorEdge_Static(ornt[1],1);
    5205:       orntNew[3] = 0;
    5206:       DMPlexSetCone(rdm, newp, coneNew);
    5207:       DMPlexSetConeOrientation(rdm, newp, orntNew);
    5208: #if defined(PETSC_USE_DEBUG)
    5209:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
    5210:       for (p = 0; p < 4; ++p) {
    5211:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", coneNew[p], eStartNew, eEndNew);
    5212:       }
    5213: #endif
    5214:       supportNew[0] = (c - cStart)*4 + 1;
    5215:       supportNew[1] = (c - cStart)*4 + 3;
    5216:       DMPlexSetSupport(rdm, newp, supportNew);
    5217: #if defined(PETSC_USE_DEBUG)
    5218:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
    5219:       for (p = 0; p < 2; ++p) {
    5220:         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", supportNew[p], cStartNew, cEndNew);
    5221:       }
    5222: #endif
    5223:       ++newp;
    5224:       /* Face {i, m, l, f} */
    5225:       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + 2;
    5226:       orntNew[0] = 0;
    5227:       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + 3;
    5228:       orntNew[1] = -2;
    5229:       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*3 + GetTriInteriorEdge_Static(ornt[3],2);
    5230:       orntNew[2] = -2;
    5231:       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*3 + GetTriInteriorEdge_Static(ornt[2],1);
    5232:       orntNew[3] = 0;
    5233:       DMPlexSetCone(rdm, newp, coneNew);
    5234:       DMPlexSetConeOrientation(rdm, newp, orntNew);
    5235: #if defined(PETSC_USE_DEBUG)
    5236:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
    5237:       for (p = 0; p < 4; ++p) {
    5238:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", coneNew[p], eStartNew, eEndNew);
    5239:       }
    5240: #endif
    5241:       supportNew[0] = (c - cStart)*4 + 2;
    5242:       supportNew[1] = (c - cStart)*4 + 3;
    5243:       DMPlexSetSupport(rdm, newp, supportNew);
    5244: #if defined(PETSC_USE_DEBUG)
    5245:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
    5246:       for (p = 0; p < 2; ++p) {
    5247:         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", supportNew[p], cStartNew, cEndNew);
    5248:       }
    5249: #endif
    5250:       ++newp;
    5251:     }
    5252:     /* Split Edges have 2 vertices and the same faces as the parent */
    5253:     for (e = eStart; e < eEnd; ++e) {
    5254:       const PetscInt newv = vStartNew + (vEnd - vStart) + (e - eStart);

    5256:       for (r = 0; r < 2; ++r) {
    5257:         const PetscInt  newp = eStartNew + (e - eStart)*2 + r;
    5258:         const PetscInt *cone, *ornt, *support;
    5259:         PetscInt        coneNew[2], coneSize, c, supportSize, s;

    5261:         DMPlexGetCone(dm, e, &cone);
    5262:         coneNew[0]       = vStartNew + (cone[0] - vStart);
    5263:         coneNew[1]       = vStartNew + (cone[1] - vStart);
    5264:         coneNew[(r+1)%2] = newv;
    5265:         DMPlexSetCone(rdm, newp, coneNew);
    5266: #if defined(PETSC_USE_DEBUG)
    5267:         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eEndNew);
    5268:         for (p = 0; p < 2; ++p) {
    5269:           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", coneNew[p], vStartNew, vEndNew);
    5270:         }
    5271: #endif
    5272:         DMPlexGetSupportSize(dm, e, &supportSize);
    5273:         DMPlexGetSupport(dm, e, &support);
    5274:         for (s = 0; s < supportSize; ++s) {
    5275:           DMPlexGetConeSize(dm, support[s], &coneSize);
    5276:           DMPlexGetCone(dm, support[s], &cone);
    5277:           DMPlexGetConeOrientation(dm, support[s], &ornt);
    5278:           for (c = 0; c < coneSize; ++c) {
    5279:             if (cone[c] == e) break;
    5280:           }
    5281:           supportRef[s] = fStartNew + (support[s] - fStart)*3 + (c + (ornt[c] < 0 ? 1-r : r))%3;
    5282:         }
    5283:         DMPlexSetSupport(rdm, newp, supportRef);
    5284: #if defined(PETSC_USE_DEBUG)
    5285:         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eEndNew);
    5286:         for (p = 0; p < supportSize; ++p) {
    5287:           if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", supportRef[p], fStartNew, fEndNew);
    5288:         }
    5289: #endif
    5290:       }
    5291:     }
    5292:     /* Face edges have 2 vertices and 2 + cell faces supports */
    5293:     for (f = fStart; f < fEnd; ++f) {
    5294:       const PetscInt *cone, *ornt, *support;
    5295:       PetscInt        coneSize, supportSize, s;

    5297:       DMPlexGetSupportSize(dm, f, &supportSize);
    5298:       DMPlexGetSupport(dm, f, &support);
    5299:       for (r = 0; r < 3; ++r) {
    5300:         const PetscInt  newp = eStartNew + (eEnd - eStart)*2 + (f - fStart)*3 + r;
    5301:         PetscInt        coneNew[2];
    5302:         PetscInt        fint[4][3] = { {0, 1, 2},
    5303:                                        {3, 4, 0},
    5304:                                        {2, 5, 3},
    5305:                                        {1, 4, 5} };

    5307:         DMPlexGetCone(dm, f, &cone);
    5308:         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r] - eStart);
    5309:         coneNew[1] = vStartNew + (vEnd - vStart) + (eEnd - eStart) + f - fStart;
    5310:         DMPlexSetCone(rdm, newp, coneNew);
    5311: #if defined(PETSC_USE_DEBUG)
    5312:         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eEndNew);
    5313:         for (p = 0; p < 2; ++p) {
    5314:           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", coneNew[p], vStartNew, vEndNew);
    5315:         }
    5316: #endif
    5317:         supportRef[0] = fStartNew + (f - fStart)*3 + (r+0)%3;
    5318:         supportRef[1] = fStartNew + (f - fStart)*3 + (r+1)%3;
    5319:         for (s = 0; s < supportSize; ++s) {
    5320:           PetscInt er;
    5321:           DMPlexGetConeSize(dm, support[s], &coneSize);
    5322:           DMPlexGetCone(dm, support[s], &cone);
    5323:           DMPlexGetConeOrientation(dm, support[s], &ornt);
    5324:           for (c = 0; c < coneSize; ++c) {if (cone[c] == f) break;}
    5325:           er = GetTriInteriorEdgeInverse_Static(ornt[c], r);
    5326:           supportRef[2+s] = fStartNew + (fEnd - fStart)*3 + (support[s] - cStart)*6 + fint[c][er];
    5327:         }
    5328:         DMPlexSetSupport(rdm, newp, supportRef);
    5329: #if defined(PETSC_USE_DEBUG)
    5330:         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eEndNew);
    5331:         for (p = 0; p < supportSize + 2; ++p) {
    5332:           if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", supportRef[p], fStartNew, fEndNew);
    5333:         }
    5334: #endif
    5335:       }
    5336:     }
    5337:     /* Interior cell edges have 2 vertices and 3 faces */
    5338:     for (c = cStart; c < cEnd; ++c) {
    5339:       const PetscInt *cone;
    5340:       PetscInt       fint[4][3] = { {0,1,2},
    5341:                                     {0,3,4},
    5342:                                     {2,3,5},
    5343:                                     {1,4,5} } ;

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

    5350:         coneNew[0] = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (cone[r] - fStart);
    5351:         coneNew[1] = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (fEnd -fStart) + c - cStart;
    5352:         DMPlexSetCone(rdm, newp, coneNew);
    5353: #if defined(PETSC_USE_DEBUG)
    5354:         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eEndNew);
    5355:         for (p = 0; p < 2; ++p) {
    5356:           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", coneNew[p], vStartNew, vEndNew);
    5357:         }
    5358: #endif
    5359:         supportNew[0] = fStartNew + (fEnd - fStart)*3 + (c - cStart)*6 + fint[r][0];
    5360:         supportNew[1] = fStartNew + (fEnd - fStart)*3 + (c - cStart)*6 + fint[r][1];
    5361:         supportNew[2] = fStartNew + (fEnd - fStart)*3 + (c - cStart)*6 + fint[r][2];
    5362:         DMPlexSetSupport(rdm, newp, supportNew);
    5363: #if defined(PETSC_USE_DEBUG)
    5364:         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eEndNew);
    5365:         for (p = 0; p < 3; ++p) {
    5366:           if ((supportNew[p] < fStartNew) || (supportNew[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", supportNew[p], fStartNew, fEndNew);
    5367:         }
    5368: #endif
    5369:       }
    5370:     }
    5371:     /* Old vertices have identical supports */
    5372:     for (v = vStart; v < vEnd; ++v) {
    5373:       const PetscInt  newp = vStartNew + (v - vStart);
    5374:       const PetscInt *support, *cone;
    5375:       PetscInt        size, s;

    5377:       DMPlexGetSupportSize(dm, v, &size);
    5378:       DMPlexGetSupport(dm, v, &support);
    5379:       for (s = 0; s < size; ++s) {
    5380:         PetscInt r = 0;

    5382:         DMPlexGetCone(dm, support[s], &cone);
    5383:         if (cone[1] == v) r = 1;
    5384:         supportRef[s] = eStartNew + (support[s] - eStart)*2 + r;
    5385:       }
    5386:       DMPlexSetSupport(rdm, newp, supportRef);
    5387: #if defined(PETSC_USE_DEBUG)
    5388:       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", newp, vStartNew, vEndNew);
    5389:       for (p = 0; p < size; ++p) {
    5390:         if ((supportRef[p] < eStartNew) || (supportRef[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", supportRef[p], eStartNew, eEndNew);
    5391:       }
    5392: #endif
    5393:     }
    5394:     /* Edge vertices have 2 + faces supports */
    5395:     for (e = eStart; e < eEnd; ++e) {
    5396:       const PetscInt  newp = vStartNew + (vEnd - vStart) + (e - eStart);
    5397:       const PetscInt *cone, *support;
    5398:       PetscInt        size, s;

    5400:       DMPlexGetSupportSize(dm, e, &size);
    5401:       DMPlexGetSupport(dm, e, &support);
    5402:       supportRef[0] = eStartNew + (e - eStart)*2 + 0;
    5403:       supportRef[1] = eStartNew + (e - eStart)*2 + 1;
    5404:       for (s = 0; s < size; ++s) {
    5405:         PetscInt r = 0, coneSize;

    5407:         DMPlexGetConeSize(dm, support[s], &coneSize);
    5408:         DMPlexGetCone(dm, support[s], &cone);
    5409:         for (r = 0; r < coneSize; ++r) {if (cone[r] == e) break;}
    5410:         supportRef[2+s] = eStartNew + (eEnd - eStart)*2 + (support[s] - fStart)*3 + r;
    5411:       }
    5412:       DMPlexSetSupport(rdm, newp, supportRef);
    5413: #if defined(PETSC_USE_DEBUG)
    5414:       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", newp, vStartNew, vEndNew);
    5415:       for (p = 0; p < 2+size; ++p) {
    5416:         if ((supportRef[p] < eStartNew) || (supportRef[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", supportRef[p], eStartNew, eEndNew);
    5417:       }
    5418: #endif
    5419:     }
    5420:     /* Face vertices have 3 + cells supports */
    5421:     for (f = fStart; f < fEnd; ++f) {
    5422:       const PetscInt  newp = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (f - fStart);
    5423:       const PetscInt *cone, *support;
    5424:       PetscInt        size, s;

    5426:       DMPlexGetSupportSize(dm, f, &size);
    5427:       DMPlexGetSupport(dm, f, &support);
    5428:       supportRef[0] = eStartNew + (eEnd - eStart)*2 + (f - fStart)*3 + 0;
    5429:       supportRef[1] = eStartNew + (eEnd - eStart)*2 + (f - fStart)*3 + 1;
    5430:       supportRef[2] = eStartNew + (eEnd - eStart)*2 + (f - fStart)*3 + 2;
    5431:       for (s = 0; s < size; ++s) {
    5432:         PetscInt r = 0, coneSize;

    5434:         DMPlexGetConeSize(dm, support[s], &coneSize);
    5435:         DMPlexGetCone(dm, support[s], &cone);
    5436:         for (r = 0; r < coneSize; ++r) {if (cone[r] == f) break;}
    5437:         supportRef[3+s] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (support[s] - cStart)*4 + r;
    5438:       }
    5439:       DMPlexSetSupport(rdm, newp, supportRef);
    5440: #if defined(PETSC_USE_DEBUG)
    5441:       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", newp, vStartNew, vEndNew);
    5442:       for (p = 0; p < 3+size; ++p) {
    5443:         if ((supportRef[p] < eStartNew) || (supportRef[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", supportRef[p], eStartNew, eEndNew);
    5444:       }
    5445: #endif
    5446:     }
    5447:     /* Interior cell vertices have 4 supports */
    5448:     for (c = cStart; c < cEnd; ++c) {
    5449:       const PetscInt  newp = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (fEnd - fStart) + c - cStart;
    5450:       supportRef[0] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + 0;
    5451:       supportRef[1] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + 1;
    5452:       supportRef[2] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + 2;
    5453:       supportRef[3] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + 3;
    5454:       DMPlexSetSupport(rdm, newp, supportRef);
    5455: #if defined(PETSC_USE_DEBUG)
    5456:       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", newp, vStartNew, vEndNew);
    5457:       for (p = 0; p < 4; ++p) {
    5458:         if ((supportRef[p] < eStartNew) || (supportRef[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", supportRef[p], eStartNew, eEndNew);
    5459:       }
    5460: #endif
    5461:     }
    5462:     PetscFree(supportRef);
    5463:     DMPlexRestoreFaces_Internal(dm, 3, cStart, NULL, NULL, &faces);
    5464:     break;
    5465:   case REFINER_HYBRID_SIMPLEX_TO_HEX_3D:
    5466:     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
    5467:     cMax = PetscMin(cEnd, cMax);
    5468:     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
    5469:     fMax = PetscMin(fEnd, fMax);
    5470:     if (eMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
    5471:     eMax = PetscMin(eEnd, eMax);
    5472:     DMPlexGetRawFaces_Internal(dm, 3, 4, cellInd, NULL, NULL, &faces);
    5473:     /* All cells have 6 faces */
    5474:     for (c = cStart; c < cMax; ++c) {
    5475:       const PetscInt  newp = cStartNew + (c - cStart)*4;
    5476:       const PetscInt *cone, *ornt;
    5477:       PetscInt        coneNew[6];
    5478:       PetscInt        orntNew[6];

    5480:       DMPlexGetCone(dm, c, &cone);
    5481: #if defined(PETSC_USE_DEBUG)
    5482:       for (p = 0; p < 4; ++p) {
    5483:         if (cone[p] >= fMax) SETERRQ4(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected hybrid face %D (fMax %D) in cone position %D for cell %D", cone[p], p, fMax, c);
    5484:       }
    5485: #endif
    5486:       DMPlexGetConeOrientation(dm, c, &ornt);
    5487:       /* A hex */
    5488:       coneNew[0] = fStartNew + (cone[0] - fStart)*3 + GetTriSubface_Static(ornt[0], 0); /* B */
    5489:       orntNew[0] = ornt[0] < 0 ? -1 : 1;
    5490:       coneNew[1] = fStartNew + (fMax    - fStart)*3 + (c - cStart)*6 + 3;               /* T */
    5491:       orntNew[1] = -4;
    5492:       coneNew[2] = fStartNew + (cone[2] - fStart)*3 + GetTriSubface_Static(ornt[2], 0); /* F */
    5493:       orntNew[2] = ornt[2] < 0 ? -1 : 1;
    5494:       coneNew[3] = fStartNew + (fMax    - fStart)*3 + (c - cStart)*6 + 0;               /* K */
    5495:       orntNew[3] = -1;
    5496:       coneNew[4] = fStartNew + (fMax    - fStart)*3 + (c - cStart)*6 + 2;               /* R */
    5497:       orntNew[4] = 0;
    5498:       coneNew[5] = fStartNew + (cone[1] - fStart)*3 + GetTriSubface_Static(ornt[1], 0); /* L */
    5499:       orntNew[5] = ornt[1] < 0 ? -1 : 1;
    5500:       DMPlexSetCone(rdm, newp+0, coneNew);
    5501:       DMPlexSetConeOrientation(rdm, newp+0, orntNew);
    5502: #if defined(PETSC_USE_DEBUG)
    5503:       if ((newp+0 < cStartNew) || (newp+0 >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", newp+0, cStartNew, cEndNew);
    5504:       for (p = 0; p < 6; ++p) {
    5505:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", coneNew[p], fStartNew, fEndNew);
    5506:       }
    5507: #endif
    5508:       /* B hex */
    5509:       coneNew[0] = fStartNew + (cone[0] - fStart)*3 + GetTriSubface_Static(ornt[0], 1); /* B */
    5510:       orntNew[0] = ornt[0] < 0 ? -2 : 0;
    5511:       coneNew[1] = fStartNew + (fMax    - fStart)*3 + (c - cStart)*6 + 4;               /* T */
    5512:       orntNew[1] = 0;
    5513:       coneNew[2] = fStartNew + (fMax    - fStart)*3 + (c - cStart)*6 + 0;               /* F */
    5514:       orntNew[2] = 0;
    5515:       coneNew[3] = fStartNew + (cone[3] - fStart)*3 + GetTriSubface_Static(ornt[3], 1); /* K */
    5516:       orntNew[3] = ornt[3] < 0 ? -2 : 0;
    5517:       coneNew[4] = fStartNew + (fMax    - fStart)*3 + (c - cStart)*6 + 1;               /* R */
    5518:       orntNew[4] = 0;
    5519:       coneNew[5] = fStartNew + (cone[1] - fStart)*3 + GetTriSubface_Static(ornt[1], 2); /* L */
    5520:       orntNew[5] = ornt[1] < 0 ? -4 : 2;
    5521:       DMPlexSetCone(rdm, newp+1, coneNew);
    5522:       DMPlexSetConeOrientation(rdm, newp+1, orntNew);
    5523: #if defined(PETSC_USE_DEBUG)
    5524:       if ((newp+1 < cStartNew) || (newp+1 >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", newp+1, cStartNew, cEndNew);
    5525:       for (p = 0; p < 6; ++p) {
    5526:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", coneNew[p], fStartNew, fEndNew);
    5527:       }
    5528: #endif
    5529:       /* C hex */
    5530:       coneNew[0] = fStartNew + (cone[0] - fStart)*3 + GetTriSubface_Static(ornt[0], 2); /* B */
    5531:       orntNew[0] = ornt[0] < 0 ? -4 : 2;
    5532:       coneNew[1] = fStartNew + (fMax    - fStart)*3 + (c - cStart)*6 + 5;               /* T */
    5533:       orntNew[1] = -4;
    5534:       coneNew[2] = fStartNew + (cone[2] - fStart)*3 + GetTriSubface_Static(ornt[2], 1); /* F */
    5535:       orntNew[2] = ornt[2] < 0 ? -2 : 0;
    5536:       coneNew[3] = fStartNew + (fMax    - fStart)*3 + (c - cStart)*6 + 1;               /* K */
    5537:       orntNew[3] = -1;
    5538:       coneNew[4] = fStartNew + (cone[3] - fStart)*3 + GetTriSubface_Static(ornt[3], 0); /* R */
    5539:       orntNew[4] = ornt[3] < 0 ? -1 : 1;
    5540:       coneNew[5] = fStartNew + (fMax    - fStart)*3 + (c - cStart)*6 + 2;               /* L */
    5541:       orntNew[5] = -4;
    5542:       DMPlexSetCone(rdm, newp+2, coneNew);
    5543:       DMPlexSetConeOrientation(rdm, newp+2, orntNew);
    5544: #if defined(PETSC_USE_DEBUG)
    5545:       if ((newp+2 < cStartNew) || (newp+2 >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", newp+2, cStartNew, cEndNew);
    5546:       for (p = 0; p < 6; ++p) {
    5547:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", coneNew[p], fStartNew, fEndNew);
    5548:       }
    5549: #endif
    5550:       /* D hex */
    5551:       coneNew[0] = fStartNew + (fMax    - fStart)*3 + (c - cStart)*6 + 3;               /* B */
    5552:       orntNew[0] = 0;
    5553:       coneNew[1] = fStartNew + (cone[3] - fStart)*3 + GetTriSubface_Static(ornt[3], 2); /* T */
    5554:       orntNew[1] = ornt[3] < 0 ? -1 : 1;
    5555:       coneNew[2] = fStartNew + (cone[2] - fStart)*3 + GetTriSubface_Static(ornt[2], 2); /* F */
    5556:       orntNew[2] = ornt[2] < 0 ? -4 : 2;
    5557:       coneNew[3] = fStartNew + (fMax    - fStart)*3 + (c - cStart)*6 + 4;               /* K */
    5558:       orntNew[3] = -1;
    5559:       coneNew[4] = fStartNew + (fMax    - fStart)*3 + (c - cStart)*6 + 5;               /* R */
    5560:       orntNew[4] = 0;
    5561:       coneNew[5] = fStartNew + (cone[1] - fStart)*3 + GetTriSubface_Static(ornt[1], 1); /* L */
    5562:       orntNew[5] = ornt[1] < 0 ? -2 : 0;
    5563:       DMPlexSetCone(rdm, newp+3, coneNew);
    5564:       DMPlexSetConeOrientation(rdm, newp+3, orntNew);
    5565: #if defined(PETSC_USE_DEBUG)
    5566:       if ((newp+3 < cStartNew) || (newp+3 >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", newp+3, cStartNew, cEndNew);
    5567:       for (p = 0; p < 6; ++p) {
    5568:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", coneNew[p], fStartNew, fEndNew);
    5569:       }
    5570: #endif
    5571:     }
    5572:     for (c = cMax; c < cEnd; ++c) {
    5573:       const PetscInt  newp = cStartNew + (cMax - cStart)*4 + (c - cMax)*3;
    5574:       const PetscInt *cone, *ornt, *fornt;
    5575:       PetscInt        coneNew[6], orntNew[6];
    5576:       PetscInt        o, of, cf;

    5578:       DMPlexGetCone(dm, c, &cone);
    5579: #if defined(PETSC_USE_DEBUG)
    5580:       if (cone[0] >= fMax) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected hybrid face %D (fMax %D) in cone position 0 for cell %D", cone[0], fMax, c);
    5581:       if (cone[1] >= fMax) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected hybrid face %D (fMax %D) in cone position 1 for cell %D", cone[1], fMax, c);
    5582:       if (cone[2] <  fMax) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected face %D (fMax %D) in cone position 2 for cell %D", cone[2], fMax, c);
    5583:       if (cone[3] <  fMax) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected face %D (fMax %D) in cone position 3 for cell %D", cone[3], fMax, c);
    5584:       if (cone[4] <  fMax) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected face %D (fMax %D) in cone position 4 for cell %D", cone[4], fMax, c);
    5585: #endif
    5586:       DMPlexGetConeOrientation(dm, c, &ornt);
    5587:       DMPlexGetConeOrientation(dm, cone[0], &fornt);
    5588:       o    = ornt[0] < 0 ? -1 : 1;
    5589:       /* A hex */
    5590:       coneNew[0] = fStartNew + (cone[0] - fStart)*3 + GetTriSubface_Static(ornt[0], 0);                            /* B */
    5591:       orntNew[0] = ornt[0] < 0 ? -1 :  1;
    5592:       coneNew[1] = fStartNew + (cone[1] - fStart)*3 + GetTriSubface_Static(ornt[1], 0);                            /* T */
    5593:       orntNew[1] = ornt[1] < 0 ?  1 : -1;
    5594:       cf         = GetTriEdge_Static(ornt[0], 2);
    5595:       of         = fornt[cf] < 0 ? -1 : 1;
    5596:       coneNew[2] = fStartNew + (fMax - fStart)*3 + (cMax - cStart)*6 + (cone[2+cf] - fMax)*2 + (o*of < 0 ? 0 : 1); /* F */
    5597:       orntNew[2] = o*of < 0 ? 0 : -1;
    5598:       coneNew[3] = fStartNew + (fMax - fStart)*3 + (cMax - cStart)*6 + (fEnd - fMax)*2 + (c - cMax)*3 + 0;         /* K */
    5599:       orntNew[3] = -1;
    5600:       coneNew[4] = fStartNew + (fMax - fStart)*3 + (cMax - cStart)*6 + (fEnd - fMax)*2 + (c - cMax)*3 + 2;         /* R */
    5601:       orntNew[4] = 0;
    5602:       cf         = GetTriEdge_Static(ornt[0], 0);
    5603:       of         = fornt[cf] < 0 ? -1 : 1;
    5604:       coneNew[5] = fStartNew + (fMax - fStart)*3 + (cMax - cStart)*6 + (cone[2+cf] - fMax)*2 + (o*of < 0 ? 1 : 0); /* L */
    5605:       orntNew[5] = o*of < 0 ? 1 : -4;
    5606:       DMPlexSetCone(rdm, newp+0, coneNew);
    5607:       DMPlexSetConeOrientation(rdm, newp+0, orntNew);
    5608: #if defined(PETSC_USE_DEBUG)
    5609:       if ((newp+0 < cStartNew) || (newp+0 >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", newp+0, cStartNew, cEndNew);
    5610:       for (p = 0; p < 6; ++p) {
    5611:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", coneNew[p], fStartNew, fEndNew);
    5612:       }
    5613: #endif
    5614:       /* B hex */
    5615:       coneNew[0] = fStartNew + (cone[0] - fStart)*3 + GetTriSubface_Static(ornt[0], 1);                            /* B */
    5616:       orntNew[0] = ornt[0] < 0 ? -2 :  0;
    5617:       coneNew[1] = fStartNew + (cone[1] - fStart)*3 + GetTriSubface_Static(ornt[1], 1);                            /* T */
    5618:       orntNew[1] = ornt[1] < 0 ?  2 : -4;
    5619:       coneNew[2] = fStartNew + (fMax - fStart)*3 + (cMax - cStart)*6 + (fEnd - fMax)*2 + (c - cMax)*3 + 0;         /* F */
    5620:       orntNew[2] = 0;
    5621:       cf         = GetTriEdge_Static(ornt[0], 1);
    5622:       of         = fornt[cf] < 0 ? -1 : 1;
    5623:       coneNew[3] = fStartNew + (fMax - fStart)*3 + (cMax - cStart)*6 + (cone[2+cf] - fMax)*2 + (o*of < 0 ? 1 : 0); /* K */
    5624:       orntNew[3] = o*of < 0 ? 0 : -1;
    5625:       coneNew[4] = fStartNew + (fMax - fStart)*3 + (cMax - cStart)*6 + (fEnd - fMax)*2 + (c - cMax)*3 + 1;         /* R */
    5626:       orntNew[4] = -1;
    5627:       cf         = GetTriEdge_Static(ornt[0], 0);
    5628:       of         = fornt[cf] < 0 ? -1 : 1;
    5629:       coneNew[5] = fStartNew + (fMax - fStart)*3 + (cMax - cStart)*6 + (cone[2+cf] - fMax)*2 + (o*of < 0 ? 0 : 1); /* L */
    5630:       orntNew[5] = o*of < 0 ? 1 : -4;
    5631:       DMPlexSetCone(rdm, newp+1, coneNew);
    5632:       DMPlexSetConeOrientation(rdm, newp+1, orntNew);
    5633: #if defined(PETSC_USE_DEBUG)
    5634:       if ((newp+1 < cStartNew) || (newp+1 >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", newp+1, cStartNew, cEndNew);
    5635:       for (p = 0; p < 6; ++p) {
    5636:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", coneNew[p], fStartNew, fEndNew);
    5637:       }
    5638: #endif
    5639:       /* C hex */
    5640:       coneNew[0] = fStartNew + (cone[0] - fStart)*3 + GetTriSubface_Static(ornt[0], 2);                            /* B */
    5641:       orntNew[0] = ornt[0] < 0 ? -4 : 2;
    5642:       coneNew[1] = fStartNew + (cone[1] - fStart)*3 + GetTriSubface_Static(ornt[1], 2);                            /* T */
    5643:       orntNew[1] = ornt[1] < 0 ? 0 : -2;
    5644:       cf         = GetTriEdge_Static(ornt[0], 2);
    5645:       of         = fornt[cf] < 0 ? -1 : 1;
    5646:       coneNew[2] = fStartNew + (fMax - fStart)*3 + (cMax - cStart)*6 + (cone[2+cf] - fMax)*2 + (o*of < 0 ? 1 : 0); /* F */
    5647:       orntNew[2] = o*of < 0 ? 0 : -1;
    5648:       coneNew[3] = fStartNew + (fMax - fStart)*3 + (cMax - cStart)*6 + (fEnd - fMax)*2 + (c - cMax)*3 + 1;         /* K */
    5649:       orntNew[3] = 0;
    5650:       cf         = GetTriEdge_Static(ornt[0], 1);
    5651:       of         = fornt[cf] < 0 ? -1 : 1;
    5652:       coneNew[4] = fStartNew + (fMax - fStart)*3 + (cMax - cStart)*6 + (cone[2+cf] - fMax)*2 + (o*of < 0 ? 0 : 1); /* R */
    5653:       orntNew[4] = o*of < 0 ? 0 : -1;
    5654:       coneNew[5] = fStartNew + (fMax - fStart)*3 + (cMax - cStart)*6 + (fEnd - fMax)*2 + (c - cMax)*3 + 2;         /* L */
    5655:       orntNew[5] = -4;
    5656:       DMPlexSetCone(rdm, newp+2, coneNew);
    5657:       DMPlexSetConeOrientation(rdm, newp+2, orntNew);
    5658: #if defined(PETSC_USE_DEBUG)
    5659:       if ((newp+2 < cStartNew) || (newp+2 >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", newp+2, cStartNew, cEndNew);
    5660:       for (p = 0; p < 6; ++p) {
    5661:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", coneNew[p], fStartNew, fEndNew);
    5662:       }
    5663: #endif
    5664:     }

    5666:     /* Split faces have 4 edges and the same cells as the parent */
    5667:     DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);
    5668:     PetscMalloc1(2 + maxSupportSize*2, &supportRef);
    5669:     for (f = fStart; f < fMax; ++f) {
    5670:       const PetscInt  newp = fStartNew + (f - fStart)*3;
    5671:       const PetscInt *cone, *ornt, *support;
    5672:       PetscInt        coneNew[4], orntNew[4], coneSize, supportSize, s;

    5674:       DMPlexGetCone(dm, f, &cone);
    5675: #if defined(PETSC_USE_DEBUG)
    5676:       for (p = 0; p < 3; ++p) {
    5677:         if (cone[p] >= eMax) SETERRQ4(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected hybrid edge %D (eMax %D) in cone position %D for face %D", cone[p], p, eMax, f);
    5678:       }
    5679: #endif
    5680:       DMPlexGetConeOrientation(dm, f, &ornt);
    5681:       /* A quad */
    5682:       coneNew[0] = eStartNew + (cone[2] - eStart)*2 + (ornt[2] < 0 ? 0 : 1);
    5683:       orntNew[0] = ornt[2];
    5684:       coneNew[1] = eStartNew + (cone[0] - eStart)*2 + (ornt[0] < 0 ? 1 : 0);
    5685:       orntNew[1] = ornt[0];
    5686:       coneNew[2] = eStartNew + (eMax    - eStart)*2 + (f - fStart)*3 + 0;
    5687:       orntNew[2] = 0;
    5688:       coneNew[3] = eStartNew + (eMax    - eStart)*2 + (f - fStart)*3 + 2;
    5689:       orntNew[3] = -2;
    5690:       DMPlexSetCone(rdm, newp+0, coneNew);
    5691:       DMPlexSetConeOrientation(rdm, newp+0, orntNew);
    5692: #if defined(PETSC_USE_DEBUG)
    5693:       if ((newp+0 < fStartNew) || (newp+0 >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp+0, fStartNew, fEndNew);
    5694:       for (p = 0; p < 4; ++p) {
    5695:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", coneNew[p], eStartNew, eEndNew);
    5696:       }
    5697: #endif
    5698:       /* B quad */
    5699:       coneNew[0] = eStartNew + (cone[0] - eStart)*2 + (ornt[0] < 0 ? 0 : 1);
    5700:       orntNew[0] = ornt[0];
    5701:       coneNew[1] = eStartNew + (cone[1] - eStart)*2 + (ornt[1] < 0 ? 1 : 0);
    5702:       orntNew[1] = ornt[1];
    5703:       coneNew[2] = eStartNew + (eMax    - eStart)*2 + (f - fStart)*3 + 1;
    5704:       orntNew[2] = 0;
    5705:       coneNew[3] = eStartNew + (eMax    - eStart)*2 + (f - fStart)*3 + 0;
    5706:       orntNew[3] = -2;
    5707:       DMPlexSetCone(rdm, newp+1, coneNew);
    5708:       DMPlexSetConeOrientation(rdm, newp+1, orntNew);
    5709: #if defined(PETSC_USE_DEBUG)
    5710:       if ((newp+1 < fStartNew) || (newp+1 >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp+1, fStartNew, fEndNew);
    5711:       for (p = 0; p < 4; ++p) {
    5712:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", coneNew[p], eStartNew, eEndNew);
    5713:       }
    5714: #endif
    5715:       /* C quad */
    5716:       coneNew[0] = eStartNew + (cone[1] - eStart)*2 + (ornt[1] < 0 ? 0 : 1);
    5717:       orntNew[0] = ornt[1];
    5718:       coneNew[1] = eStartNew + (cone[2] - eStart)*2 + (ornt[2] < 0 ? 1 : 0);
    5719:       orntNew[1] = ornt[2];
    5720:       coneNew[2] = eStartNew + (eMax    - eStart)*2 + (f - fStart)*3 + 2;
    5721:       orntNew[2] = 0;
    5722:       coneNew[3] = eStartNew + (eMax    - eStart)*2 + (f - fStart)*3 + 1;
    5723:       orntNew[3] = -2;
    5724:       DMPlexSetCone(rdm, newp+2, coneNew);
    5725:       DMPlexSetConeOrientation(rdm, newp+2, orntNew);
    5726: #if defined(PETSC_USE_DEBUG)
    5727:       if ((newp+2 < fStartNew) || (newp+2 >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp+2, fStartNew, fEndNew);
    5728:       for (p = 0; p < 4; ++p) {
    5729:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", coneNew[p], eStartNew, eEndNew);
    5730:       }
    5731: #endif
    5732:       DMPlexGetSupportSize(dm, f, &supportSize);
    5733:       DMPlexGetSupport(dm, f, &support);
    5734:       for (r = 0; r < 3; ++r) {
    5735:         for (s = 0; s < supportSize; ++s) {
    5736:           PetscInt subf;

    5738:           DMPlexGetConeSize(dm, support[s], &coneSize);
    5739:           if (coneSize != 5 && support[s] >= cMax) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected conesize %D for cell %D (cMax %D)", coneSize, support[s], cMax);
    5740:           if (coneSize != 4 && support[s] <  cMax) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected conesize %D for cell %D (cMax %D)", coneSize, support[s], cMax);
    5741:           DMPlexGetCone(dm, support[s], &cone);
    5742:           DMPlexGetConeOrientation(dm, support[s], &ornt);
    5743:           for (c = 0; c < coneSize; ++c) {
    5744:             if (cone[c] == f) break;
    5745:           }
    5746:           subf = GetTriSubfaceInverse_Static(ornt[c], r);
    5747:           if (coneSize == 4) {
    5748:             supportRef[s] = cStartNew + (support[s] - cStart)*4 + faces[c*3+subf];
    5749:           } else if (coneSize == 5) {
    5750:             if (c != 0 && c != 1) SETERRQ4(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected position %D in cone %D of cell %D (cMax %D) for face %D", c, support[s], cMax, f);
    5751:             supportRef[s] = cStartNew + (cMax - cStart)*4 + (support[s] - cMax)*3 + subf;
    5752:           } else SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected conesize %D for cell %D (cMax %D)", coneSize, support[s], cMax);
    5753:         }
    5754:         DMPlexSetSupport(rdm, newp+r, supportRef);
    5755: #if defined(PETSC_USE_DEBUG)
    5756:         if ((newp+r < fStartNew) || (newp+r >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp+r, fStartNew, fEndNew);
    5757:         for (p = 0; p < supportSize; ++p) {
    5758:           if ((supportRef[p] < cStartNew) || (supportRef[p] >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", supportRef[p], cStartNew, cEndNew);
    5759:         }
    5760: #endif
    5761:       }
    5762:     }
    5763:     /* Interior faces have 4 edges and 2 cells */
    5764:     for (c = cStart; c < cMax; ++c) {
    5765:       PetscInt        newp = fStartNew + (fMax - fStart)*3 + (c - cStart)*6;
    5766:       const PetscInt *cone, *ornt;
    5767:       PetscInt        coneNew[4], orntNew[4];
    5768:       PetscInt        supportNew[2];

    5770:       DMPlexGetCone(dm, c, &cone);
    5771: #if defined(PETSC_USE_DEBUG)
    5772:       for (p = 0; p < 4; ++p) {
    5773:         if (cone[p] >= fMax) SETERRQ4(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected hybrid face %D (fMax %D) in cone position %D for face %D", cone[p], p, fMax, f);
    5774:       }
    5775: #endif
    5776:       DMPlexGetConeOrientation(dm, c, &ornt);
    5777:       /* Face {a, g, m, h} */
    5778:       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*3 + GetTriInteriorEdge_Static(ornt[0],0);
    5779:       orntNew[0] = 0;
    5780:       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart)*4 + 0;
    5781:       orntNew[1] = 0;
    5782:       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart)*4 + 1;
    5783:       orntNew[2] = -2;
    5784:       coneNew[3] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*3 + GetTriInteriorEdge_Static(ornt[1],2);
    5785:       orntNew[3] = -2;
    5786:       DMPlexSetCone(rdm, newp, coneNew);
    5787:       DMPlexSetConeOrientation(rdm, newp, orntNew);
    5788: #if defined(PETSC_USE_DEBUG)
    5789:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
    5790:       for (p = 0; p < 4; ++p) {
    5791:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", coneNew[p], eStartNew, eEndNew);
    5792:       }
    5793: #endif
    5794:       supportNew[0] = cStartNew + (c - cStart)*4 + 0;
    5795:       supportNew[1] = cStartNew + (c - cStart)*4 + 1;
    5796:       DMPlexSetSupport(rdm, newp, supportNew);
    5797: #if defined(PETSC_USE_DEBUG)
    5798:       for (p = 0; p < 2; ++p) {
    5799:         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", supportNew[p], cStartNew, cEndNew);
    5800:       }
    5801: #endif
    5802:       ++newp;
    5803:       /* Face {g, b, l , m} */
    5804:       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*3 + GetTriInteriorEdge_Static(ornt[0],1);
    5805:       orntNew[0] = -2;
    5806:       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*3 + GetTriInteriorEdge_Static(ornt[3],0);
    5807:       orntNew[1] = 0;
    5808:       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart)*4 + 3;
    5809:       orntNew[2] = 0;
    5810:       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart)*4 + 0;
    5811:       orntNew[3] = -2;
    5812:       DMPlexSetCone(rdm, newp, coneNew);
    5813:       DMPlexSetConeOrientation(rdm, newp, orntNew);
    5814: #if defined(PETSC_USE_DEBUG)
    5815:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
    5816:       for (p = 0; p < 4; ++p) {
    5817:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", coneNew[p], eStartNew, eEndNew);
    5818:       }
    5819: #endif
    5820:       supportNew[0] = cStartNew + (c - cStart)*4 + 1;
    5821:       supportNew[1] = cStartNew + (c - cStart)*4 + 2;
    5822:       DMPlexSetSupport(rdm, newp, supportNew);
    5823: #if defined(PETSC_USE_DEBUG)
    5824:       for (p = 0; p < 2; ++p) {
    5825:         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", supportNew[p], cStartNew, cEndNew);
    5826:       }
    5827: #endif
    5828:       ++newp;
    5829:       /* Face {c, g, m, i} */
    5830:       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*3 + GetTriInteriorEdge_Static(ornt[0],2);
    5831:       orntNew[0] = 0;
    5832:       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart)*4 + 0;
    5833:       orntNew[1] = 0;
    5834:       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart)*4 + 2;
    5835:       orntNew[2] = -2;
    5836:       coneNew[3] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*3 + GetTriInteriorEdge_Static(ornt[2],0);
    5837:       orntNew[3] = -2;
    5838:       DMPlexSetCone(rdm, newp, coneNew);
    5839:       DMPlexSetConeOrientation(rdm, newp, orntNew);
    5840: #if defined(PETSC_USE_DEBUG)
    5841:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
    5842:       for (p = 0; p < 4; ++p) {
    5843:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", coneNew[p], eStartNew, eEndNew);
    5844:       }
    5845: #endif
    5846:       supportNew[0] = cStartNew + (c - cStart)*4 + 0;
    5847:       supportNew[1] = cStartNew + (c - cStart)*4 + 2;
    5848:       DMPlexSetSupport(rdm, newp, supportNew);
    5849: #if defined(PETSC_USE_DEBUG)
    5850:       for (p = 0; p < 2; ++p) {
    5851:         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", supportNew[p], cStartNew, cEndNew);
    5852:       }
    5853: #endif
    5854:       ++newp;
    5855:       /* Face {d, h, m, i} */
    5856:       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*3 + GetTriInteriorEdge_Static(ornt[1],0);
    5857:       orntNew[0] = 0;
    5858:       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart)*4 + 1;
    5859:       orntNew[1] = 0;
    5860:       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart)*4 + 2;
    5861:       orntNew[2] = -2;
    5862:       coneNew[3] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*3 + GetTriInteriorEdge_Static(ornt[2],2);
    5863:       orntNew[3] = -2;
    5864:       DMPlexSetCone(rdm, newp, coneNew);
    5865:       DMPlexSetConeOrientation(rdm, newp, orntNew);
    5866: #if defined(PETSC_USE_DEBUG)
    5867:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
    5868:       for (p = 0; p < 4; ++p) {
    5869:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", coneNew[p], eStartNew, eEndNew);
    5870:       }
    5871: #endif
    5872:       supportNew[0] = cStartNew + (c - cStart)*4 + 0;
    5873:       supportNew[1] = cStartNew + (c - cStart)*4 + 3;
    5874:       DMPlexSetSupport(rdm, newp, supportNew);
    5875: #if defined(PETSC_USE_DEBUG)
    5876:       for (p = 0; p < 2; ++p) {
    5877:         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", supportNew[p], cStartNew, cEndNew);
    5878:       }
    5879: #endif
    5880:       ++newp;
    5881:       /* Face {h, m, l, e} */
    5882:       coneNew[0] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart)*4 + 1;
    5883:       orntNew[0] = 0;
    5884:       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart)*4 + 3;
    5885:       orntNew[1] = -2;
    5886:       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*3 + GetTriInteriorEdge_Static(ornt[3],1);
    5887:       orntNew[2] = -2;
    5888:       coneNew[3] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*3 + GetTriInteriorEdge_Static(ornt[1],1);
    5889:       orntNew[3] = 0;
    5890:       DMPlexSetCone(rdm, newp, coneNew);
    5891:       DMPlexSetConeOrientation(rdm, newp, orntNew);
    5892: #if defined(PETSC_USE_DEBUG)
    5893:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
    5894:       for (p = 0; p < 4; ++p) {
    5895:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", coneNew[p], eStartNew, eEndNew);
    5896:       }
    5897: #endif
    5898:       supportNew[0] = cStartNew + (c - cStart)*4 + 1;
    5899:       supportNew[1] = cStartNew + (c - cStart)*4 + 3;
    5900:       DMPlexSetSupport(rdm, newp, supportNew);
    5901: #if defined(PETSC_USE_DEBUG)
    5902:       for (p = 0; p < 2; ++p) {
    5903:         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", supportNew[p], cStartNew, cEndNew);
    5904:       }
    5905: #endif
    5906:       ++newp;
    5907:       /* Face {i, m, l, f} */
    5908:       coneNew[0] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart)*4 + 2;
    5909:       orntNew[0] = 0;
    5910:       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart)*4 + 3;
    5911:       orntNew[1] = -2;
    5912:       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*3 + GetTriInteriorEdge_Static(ornt[3],2);
    5913:       orntNew[2] = -2;
    5914:       coneNew[3] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*3 + GetTriInteriorEdge_Static(ornt[2],1);
    5915:       orntNew[3] = 0;
    5916:       DMPlexSetCone(rdm, newp, coneNew);
    5917:       DMPlexSetConeOrientation(rdm, newp, orntNew);
    5918: #if defined(PETSC_USE_DEBUG)
    5919:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
    5920:       for (p = 0; p < 4; ++p) {
    5921:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", coneNew[p], eStartNew, eEndNew);
    5922:       }
    5923: #endif
    5924:       supportNew[0] = cStartNew + (c - cStart)*4 + 2;
    5925:       supportNew[1] = cStartNew + (c - cStart)*4 + 3;
    5926:       DMPlexSetSupport(rdm, newp, supportNew);
    5927: #if defined(PETSC_USE_DEBUG)
    5928:       for (p = 0; p < 2; ++p) {
    5929:         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", supportNew[p], cStartNew, cEndNew);
    5930:       }
    5931: #endif
    5932:       ++newp;
    5933:     }
    5934:     /* Hybrid split faces have 4 edges and same cells */
    5935:     for (f = fMax; f < fEnd; ++f) {
    5936:       const PetscInt *cone, *ornt, *support;
    5937:       PetscInt        coneNew[4], orntNew[4];
    5938:       PetscInt        size, s;
    5939:       const PetscInt  newp = fStartNew + (fMax - fStart)*3 + (cMax - cStart)*6 + (f - fMax)*2;

    5941:       DMPlexGetCone(dm, f, &cone);
    5942: #if defined(PETSC_USE_DEBUG)
    5943:       if (cone[0] >= eMax) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected hybrid edge %D (eMax %D) in cone position 0 for face %D", cone[0], eMax, f);
    5944:       if (cone[1] >= eMax) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected hybrid edge %D (eMax %D) in cone position 1 for face %D", cone[1], eMax, f);
    5945:       if (cone[2] <  eMax) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected edge %D (eMax %D) in cone position 2 for face %D", cone[2], eMax, f);
    5946:       if (cone[3] <  eMax) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected edge %D (eMax %D) in cone position 3 for face %D", cone[3], eMax, f);
    5947: #endif
    5948:       DMPlexGetConeOrientation(dm, f, &ornt);
    5949:       /* A face */
    5950:       coneNew[0] = eStartNew + (cone[0] - eStart)*2 + (ornt[0] < 0 ? 1 : 0);
    5951:       orntNew[0] = ornt[0];
    5952:       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart)*4 + (eEnd - eMax) + (f - fMax);
    5953:       orntNew[1] = 0;
    5954:       coneNew[2] = eStartNew + (cone[1] - eStart)*2 + (ornt[1] < 0 ? 1 : 0);
    5955:       orntNew[2] = ornt[1] < 0 ? 0 : -2;
    5956:       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart)*4 + (cone[2] - eMax);
    5957:       orntNew[3] = ornt[2] < 0 ? 0 : -2;
    5958:       DMPlexSetCone(rdm, newp, coneNew);
    5959:       DMPlexSetConeOrientation(rdm, newp, orntNew);
    5960: #if defined(PETSC_USE_DEBUG)
    5961:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
    5962:       for (p = 0; p < 4; ++p) {
    5963:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", coneNew[p], eStartNew, eEndNew);
    5964:       }
    5965: #endif

    5967:       /* B face */
    5968:       coneNew[0] = eStartNew + (cone[0] - eStart)*2 + (ornt[0] < 0 ? 0 : 1);
    5969:       orntNew[0] = ornt[0];
    5970:       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart)*4 + (cone[3] - eMax);
    5971:       orntNew[1] = ornt[3];
    5972:       coneNew[2] = eStartNew + (cone[1] - eStart)*2 + (ornt[1] < 0 ? 0 : 1);
    5973:       orntNew[2] = ornt[1] < 0 ? 0 : -2;
    5974:       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart)*4 + (eEnd - eMax) + (f - fMax);
    5975:       orntNew[3] = -2;
    5976:       DMPlexSetCone(rdm, newp+1, coneNew);
    5977:       DMPlexSetConeOrientation(rdm, newp+1, orntNew);
    5978: #if defined(PETSC_USE_DEBUG)
    5979:       if ((newp+1 < fStartNew) || (newp+1 >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp+1, fStartNew, fEndNew);
    5980:       for (p = 0; p < 4; ++p) {
    5981:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", coneNew[p], eStartNew, eEndNew);
    5982:       }
    5983: #endif

    5985:       DMPlexGetSupportSize(dm, f, &size);
    5986:       DMPlexGetSupport(dm, f, &support);
    5987:       for (r = 0; r < 2; ++r) {
    5988:         for (s = 0; s < size; ++s) {
    5989:           const PetscInt *coneCell, *orntCell, *fornt;
    5990:           PetscInt        coneSize, o, of, c;

    5992:           DMPlexGetConeSize(dm, support[s], &coneSize);
    5993:           if (coneSize != 5 || support[s] < cMax) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected conesize %D for cell %D (cMax %D)", coneSize, support[s], cMax);
    5994:           DMPlexGetCone(dm, support[s], &coneCell);
    5995:           DMPlexGetConeOrientation(dm, support[s], &orntCell);
    5996:           o = orntCell[0] < 0 ? -1 : 1;
    5997:           for (c = 0; c < coneSize; ++c) if (coneCell[c] == f) break;
    5998:           if (c == 0 || c == 1) SETERRQ4(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected position in cone %D of cell %D (cMax %D) for face %D", c, support[s], cMax, f);
    5999:           if (c == coneSize) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Could not find face %D in cone of cell %D", f, support[s]);
    6000:           DMPlexGetConeOrientation(dm, coneCell[0], &fornt);
    6001:           of = fornt[c-2] < 0 ? -1 : 1;
    6002:           supportRef[s] = cStartNew + (cMax - cStart)*4 + (support[s] - cMax)*3 + (GetTriEdgeInverse_Static(orntCell[0], c-2) + (o*of < 0 ? 1-r : r))%3;
    6003:         }
    6004:         DMPlexSetSupport(rdm, newp + r, supportRef);
    6005: #if defined(PETSC_USE_DEBUG)
    6006:         for (p = 0; p < size; ++p) {
    6007:           if ((supportRef[p] < cStartNew) || (supportRef[p] >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", supportRef[p], cStartNew, cEndNew);
    6008:         }
    6009: #endif
    6010:       }
    6011:     }
    6012:     /* Interior hybrid faces have 4 edges and 2 cells */
    6013:     for (c = cMax; c < cEnd; ++c) {
    6014:       PetscInt        newp = fStartNew + (fMax - fStart)*3 + (cMax - cStart)*6 + (fEnd - fMax)*2 + (c - cMax)*3;
    6015:       const PetscInt *cone, *ornt;
    6016:       PetscInt        coneNew[4], orntNew[4];
    6017:       PetscInt        supportNew[2];

    6019:       DMPlexGetCone(dm, c, &cone);
    6020: #if defined(PETSC_USE_DEBUG)
    6021:       if (cone[0] >= fMax) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected hybrid face %D (fMax %D) in cone position 0 for cell %D", cone[0], fMax, c);
    6022:       if (cone[1] >= fMax) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected hybrid face %D (fMax %D) in cone position 1 for cell %D", cone[1], fMax, c);
    6023:       if (cone[2] <  fMax) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected face %D (fMax %D) in cone position 2 for cell %D", cone[2], fMax, c);
    6024:       if (cone[3] <  fMax) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected face %D (fMax %D) in cone position 3 for cell %D", cone[3], fMax, c);
    6025:       if (cone[4] <  fMax) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected face %D (fMax %D) in cone position 3 for cell %D", cone[3], fMax, c);
    6026: #endif
    6027:       DMPlexGetConeOrientation(dm, c, &ornt);
    6028:       /* Face {a, g, h, d} */
    6029:       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*3 + GetTriInteriorEdge_Static(ornt[0],0);
    6030:       orntNew[0] = 0;
    6031:       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart)*4 + (eEnd - eMax) + (fEnd - fMax) + c - cMax;
    6032:       orntNew[1] = 0;
    6033:       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*3 + GetTriInteriorEdge_Static(ornt[1],0);
    6034:       orntNew[2] = -2;
    6035:       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart)*4 + (eEnd - eMax) + (cone[2] - fMax);
    6036:       orntNew[3] = -2;
    6037:       DMPlexSetCone(rdm, newp, coneNew);
    6038:       DMPlexSetConeOrientation(rdm, newp, orntNew);
    6039: #if defined(PETSC_USE_DEBUG)
    6040:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
    6041:       for (p = 0; p < 4; ++p) {
    6042:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", coneNew[p], eStartNew, eEndNew);
    6043:       }
    6044: #endif
    6045:       supportNew[0] = cStartNew + (cMax - cStart)*4 + (c - cMax)*3 + 0;
    6046:       supportNew[1] = cStartNew + (cMax - cStart)*4 + (c - cMax)*3 + 1;
    6047:       DMPlexSetSupport(rdm, newp, supportNew);
    6048: #if defined(PETSC_USE_DEBUG)
    6049:       for (p = 0; p < 2; ++p) {
    6050:         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", supportNew[p], cStartNew, cEndNew);
    6051:       }
    6052: #endif
    6053:       ++newp;
    6054:       /* Face {b, g, h, l} */
    6055:       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*3 + GetTriInteriorEdge_Static(ornt[0],1);
    6056:       orntNew[0] = 0;
    6057:       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart)*4 + (eEnd - eMax) + (fEnd - fMax) + c - cMax;
    6058:       orntNew[1] = 0;
    6059:       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*3 + GetTriInteriorEdge_Static(ornt[1],1);
    6060:       orntNew[2] = -2;
    6061:       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart)*4 + (eEnd - eMax) + (cone[3] - fMax);
    6062:       orntNew[3] = -2;
    6063:       DMPlexSetCone(rdm, newp, coneNew);
    6064:       DMPlexSetConeOrientation(rdm, newp, orntNew);
    6065: #if defined(PETSC_USE_DEBUG)
    6066:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
    6067:       for (p = 0; p < 4; ++p) {
    6068:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", coneNew[p], eStartNew, eEndNew);
    6069:       }
    6070: #endif
    6071:       supportNew[0] = cStartNew + (cMax - cStart)*4 + (c - cMax)*3 + 1;
    6072:       supportNew[1] = cStartNew + (cMax - cStart)*4 + (c - cMax)*3 + 2;
    6073:       DMPlexSetSupport(rdm, newp, supportNew);
    6074: #if defined(PETSC_USE_DEBUG)
    6075:       for (p = 0; p < 2; ++p) {
    6076:         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", supportNew[p], cStartNew, cEndNew);
    6077:       }
    6078: #endif
    6079:       ++newp;
    6080:       /* Face {c, g, h, f} */
    6081:       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*3 + GetTriInteriorEdge_Static(ornt[0],2);
    6082:       orntNew[0] = 0;
    6083:       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart)*4 + (eEnd - eMax) + (fEnd - fMax) + c - cMax;
    6084:       orntNew[1] = 0;
    6085:       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*3 + GetTriInteriorEdge_Static(ornt[1],2);
    6086:       orntNew[2] = -2;
    6087:       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart)*4 + (eEnd - eMax) + (cone[4] - fMax);
    6088:       orntNew[3] = -2;
    6089:       DMPlexSetCone(rdm, newp, coneNew);
    6090:       DMPlexSetConeOrientation(rdm, newp, orntNew);
    6091: #if defined(PETSC_USE_DEBUG)
    6092:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
    6093:       for (p = 0; p < 4; ++p) {
    6094:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", coneNew[p], eStartNew, eEndNew);
    6095:       }
    6096: #endif
    6097:       supportNew[0] = cStartNew + (cMax - cStart)*4 + (c - cMax)*3 + 2;
    6098:       supportNew[1] = cStartNew + (cMax - cStart)*4 + (c - cMax)*3 + 0;
    6099:       DMPlexSetSupport(rdm, newp, supportNew);
    6100: #if defined(PETSC_USE_DEBUG)
    6101:       for (p = 0; p < 2; ++p) {
    6102:         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", supportNew[p], cStartNew, cEndNew);
    6103:       }
    6104: #endif
    6105:     }
    6106:     /* Face edges have 2 vertices and 2 + cell faces supports */
    6107:     for (f = fStart; f < fMax; ++f) {
    6108:       const PetscInt *cone, *ornt, *support;
    6109:       PetscInt        coneSize, supportSize, s;

    6111:       DMPlexGetSupportSize(dm, f, &supportSize);
    6112:       DMPlexGetSupport(dm, f, &support);
    6113:       for (r = 0; r < 3; ++r) {
    6114:         const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (f - fStart)*3 + r;
    6115:         PetscInt        coneNew[2];
    6116:         PetscInt        fint[4][3] = { {0, 1, 2},
    6117:                                        {3, 4, 0},
    6118:                                        {2, 5, 3},
    6119:                                        {1, 4, 5} };

    6121:         DMPlexGetCone(dm, f, &cone);
    6122:         if (cone[r] >= eMax) SETERRQ4(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected cone point %D in position %D for face %D (eMax %D)", cone[r], r, f, eMax);
    6123:         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r] - eStart);
    6124:         coneNew[1] = vStartNew + (vEnd - vStart) + (eMax - eStart) + f - fStart;
    6125:         DMPlexSetCone(rdm, newp, coneNew);
    6126: #if defined(PETSC_USE_DEBUG)
    6127:         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eEndNew);
    6128:         for (p = 0; p < 2; ++p) {
    6129:           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", coneNew[p], vStartNew, vEndNew);
    6130:         }
    6131: #endif
    6132:         supportRef[0] = fStartNew + (f - fStart)*3 + (r+0)%3;
    6133:         supportRef[1] = fStartNew + (f - fStart)*3 + (r+1)%3;
    6134:         for (s = 0; s < supportSize; ++s) {
    6135:           PetscInt er;

    6137:           supportRef[2+s] = -1;
    6138:           DMPlexGetConeSize(dm, support[s], &coneSize);
    6139:           if (coneSize != 5 && support[s] >= cMax) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected conesize %D for cell %D (cMax %D)", coneSize, support[s], cMax);
    6140:           if (coneSize != 4 && support[s] <  cMax) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected conesize %D for cell %D (cMax %D)", coneSize, support[s], cMax);
    6141:           DMPlexGetCone(dm, support[s], &cone);
    6142:           DMPlexGetConeOrientation(dm, support[s], &ornt);
    6143:           for (c = 0; c < coneSize; ++c) {if (cone[c] == f) break;}
    6144:           er = GetTriInteriorEdgeInverse_Static(ornt[c], r);
    6145:           if (coneSize == 4) {
    6146:             supportRef[2+s] = fStartNew + (fMax - fStart)*3 + (support[s] - cStart)*6 + fint[c][er];
    6147:           } else if (coneSize == 5) {
    6148:             if (c != 0 && c != 1) SETERRQ4(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected position %D in cone %D of cell %D (cMax %D) for face %D", c, support[s], cMax, f);
    6149:             supportRef[2+s] = fStartNew + (fMax - fStart)*3 + (cMax - cStart)*6 + (fEnd - fMax)*2 + (support[s] - cMax)*3 + er;
    6150:           }
    6151:         }
    6152:         DMPlexSetSupport(rdm, newp, supportRef);
    6153: #if defined(PETSC_USE_DEBUG)
    6154:         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eEndNew);
    6155:         for (p = 0; p < supportSize + 2; ++p) {
    6156:           if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", supportRef[p], fStartNew, fEndNew);
    6157:         }
    6158: #endif
    6159:       }
    6160:     }
    6161:     /* Interior cell edges have 2 vertices and 3 faces */
    6162:     for (c = cStart; c < cMax; ++c) {
    6163:       const PetscInt *cone;
    6164:       PetscInt       fint[4][3] = { {0,1,2},
    6165:                                     {0,3,4},
    6166:                                     {2,3,5},
    6167:                                     {1,4,5} } ;

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

    6174:         if (cone[r] >= fMax) SETERRQ4(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected hybrid face %D (fMax %D) in cone position %D for cell %D", cone[r], r, fMax, c);
    6175:         coneNew[0] = vStartNew + (vEnd - vStart) + (eMax - eStart) + (cone[r] - fStart);
    6176:         coneNew[1] = vStartNew + (vEnd - vStart) + (eMax - eStart) + (fMax     -fStart) + c - cStart;
    6177:         DMPlexSetCone(rdm, newp, coneNew);
    6178: #if defined(PETSC_USE_DEBUG)
    6179:         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eEndNew);
    6180:         for (p = 0; p < 2; ++p) {
    6181:           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", coneNew[p], vStartNew, vEndNew);
    6182:         }
    6183: #endif
    6184:         supportNew[0] = fStartNew + (fMax - fStart)*3 + (c - cStart)*6 + fint[r][0];
    6185:         supportNew[1] = fStartNew + (fMax - fStart)*3 + (c - cStart)*6 + fint[r][1];
    6186:         supportNew[2] = fStartNew + (fMax - fStart)*3 + (c - cStart)*6 + fint[r][2];
    6187:         DMPlexSetSupport(rdm, newp, supportNew);
    6188: #if defined(PETSC_USE_DEBUG)
    6189:         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eEndNew);
    6190:         for (p = 0; p < 3; ++p) {
    6191:           if ((supportNew[p] < fStartNew) || (supportNew[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", supportNew[p], fStartNew, fEndNew);
    6192:         }
    6193: #endif
    6194:       }
    6195:     }
    6196:     /* Hybrid edges have two vertices and the same faces */
    6197:     for (e = eMax; e < eEnd; ++e) {
    6198:       const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart)*4 + (e - eMax);
    6199:       const PetscInt *cone, *support, *fcone;
    6200:       PetscInt        coneNew[2], size, fsize, s;

    6202:       DMPlexGetCone(dm, e, &cone);
    6203:       DMPlexGetSupportSize(dm, e, &size);
    6204:       DMPlexGetSupport(dm, e, &support);
    6205:       coneNew[0] = vStartNew + (cone[0] - vStart);
    6206:       coneNew[1] = vStartNew + (cone[1] - vStart);
    6207:       DMPlexSetCone(rdm, newp, coneNew);
    6208: #if defined(PETSC_USE_DEBUG)
    6209:       if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is a edge [%D, %D)", newp, eStartNew, eEndNew);
    6210:       for (p = 0; p < 2; ++p) {
    6211:         if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", coneNew[p], vStartNew, vEndNew);
    6212:       }
    6213: #endif
    6214:       for (s = 0; s < size; ++s) {
    6215:         DMPlexGetConeSize(dm, support[s], &fsize);
    6216:         DMPlexGetCone(dm, support[s], &fcone);
    6217:         for (c = 0; c < fsize; ++c) if (fcone[c] == e) break;
    6218:         if ((c < 2) || (c > 3)) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Edge %D not found in cone of face %D", e, support[s]);
    6219:         supportRef[s] = fStartNew + (fMax - fStart)*3 + (cMax - cStart)*6 + (support[s] - fMax)*2 + c-2;
    6220:       }
    6221:       DMPlexSetSupport(rdm, newp, supportRef);
    6222: #if defined(PETSC_USE_DEBUG)
    6223:       for (p = 0; p < size; ++p) {
    6224:         if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", supportRef[p], fStartNew, fEndNew);
    6225:       }
    6226: #endif
    6227:     }
    6228:     /* Hybrid face edges have 2 vertices and 2 + cell faces supports */
    6229:     for (f = fMax; f < fEnd; ++f) {
    6230:       const PetscInt *cone, *ornt, *support;
    6231:       PetscInt        coneSize, supportSize;
    6232:       const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart)*4 + (eEnd - eMax) + f - fMax;
    6233:       PetscInt        coneNew[2], s;

    6235:       DMPlexGetCone(dm, f, &cone);
    6236: #if defined(PETSC_USE_DEBUG)
    6237:       if (cone[0] >= eMax) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected cone point %D in position 0 for face %D (eMax %D)", cone[0], f, eMax);
    6238:       if (cone[1] >= eMax) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected cone point %D in position 1 for face %D (eMax %D)", cone[1], f, eMax);
    6239: #endif
    6240:       coneNew[0] = vStartNew + (vEnd - vStart) + (cone[0] - eStart);
    6241:       coneNew[1] = vStartNew + (vEnd - vStart) + (cone[1] - eStart);
    6242:       DMPlexSetCone(rdm, newp, coneNew);
    6243: #if defined(PETSC_USE_DEBUG)
    6244:       if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eEndNew);
    6245:       for (p = 0; p < 2; ++p) {
    6246:         if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", coneNew[p], vStartNew, vEndNew);
    6247:       }
    6248: #endif
    6249:       supportRef[0] = fStartNew + (fMax - fStart)*3 + (cMax - cStart)*6 + (f- fMax)*2 + 0;
    6250:       supportRef[1] = fStartNew + (fMax - fStart)*3 + (cMax - cStart)*6 + (f- fMax)*2 + 1;
    6251:       DMPlexGetSupportSize(dm, f, &supportSize);
    6252:       DMPlexGetSupport(dm, f, &support);
    6253:       for (s = 0; s < supportSize; ++s) {
    6254:         DMPlexGetConeSize(dm, support[s], &coneSize);
    6255:         if (coneSize != 5 || support[s] < cMax) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected conesize %D for cell %D (cMax %D)", coneSize, support[s], cMax);
    6256:         DMPlexGetCone(dm, support[s], &cone);
    6257:         DMPlexGetConeOrientation(dm, support[s], &ornt);
    6258:         for (c = 0; c < coneSize; ++c) {if (cone[c] == f) break;}
    6259:         if (c == 0 || c == 1) SETERRQ4(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected position in cone %D of cell %D (cMax %D) for face %D", c, support[s], cMax, f);
    6260:         supportRef[2+s] = fStartNew + (fMax - fStart)*3 + (cMax - cStart)*6 + (fEnd - fMax)*2 + (support[s] - cMax)*3 + c - 2;
    6261:       }
    6262:       DMPlexSetSupport(rdm, newp, supportRef);
    6263: #if defined(PETSC_USE_DEBUG)
    6264:       if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eEndNew);
    6265:       for (p = 0; p < supportSize + 2; ++p) {
    6266:         if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", supportRef[p], fStartNew, fEndNew);
    6267:       }
    6268: #endif
    6269:     }
    6270:     /* Hybrid cell edges have 2 vertices and 3 faces */
    6271:     for (c = cMax; c < cEnd; ++c) {
    6272:       PetscInt       coneNew[2], supportNew[3];
    6273:       const PetscInt newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart)*4 + (eEnd - eMax) + (fEnd - fMax) + c - cMax;
    6274:       const PetscInt *cone;

    6276:       DMPlexGetCone(dm, c, &cone);
    6277: #if defined(PETSC_USE_DEBUG)
    6278:       if (cone[0] >= fMax) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected hybrid face %D (fMax %D) in cone position 0 for cell %D", cone[0], fMax, c);
    6279:       if (cone[1] >= fMax) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected hybrid face %D (fMax %D) in cone position 1 for cell %D", cone[1], fMax, c);
    6280: #endif
    6281:       coneNew[0] = vStartNew + (vEnd - vStart) + (eMax - eStart) + (cone[0] - fStart);
    6282:       coneNew[1] = vStartNew + (vEnd - vStart) + (eMax - eStart) + (cone[1] - fStart);
    6283:       DMPlexSetCone(rdm, newp, coneNew);
    6284: #if defined(PETSC_USE_DEBUG)
    6285:       if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eEndNew);
    6286:       for (p = 0; p < 2; ++p) {
    6287:         if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", coneNew[p], vStartNew, vEndNew);
    6288:       }
    6289: #endif
    6290:       supportNew[0] = fStartNew + (fMax - fStart)*3 + (cMax - cStart)*6 + (fEnd - fMax)*2 + (c - cMax)*3 + 0;
    6291:       supportNew[1] = fStartNew + (fMax - fStart)*3 + (cMax - cStart)*6 + (fEnd - fMax)*2 + (c - cMax)*3 + 1;
    6292:       supportNew[2] = fStartNew + (fMax - fStart)*3 + (cMax - cStart)*6 + (fEnd - fMax)*2 + (c - cMax)*3 + 2;
    6293:       DMPlexSetSupport(rdm, newp, supportNew);
    6294: #if defined(PETSC_USE_DEBUG)
    6295:       if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eEndNew);
    6296:       for (p = 0; p < 3; ++p) {
    6297:         if ((supportNew[p] < fStartNew) || (supportNew[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", supportNew[p], fStartNew, fEndNew);
    6298:       }
    6299: #endif
    6300:     }
    6301:     /* Old vertices have identical supports */
    6302:     for (v = vStart; v < vEnd; ++v) {
    6303:       const PetscInt  newp = vStartNew + (v - vStart);
    6304:       const PetscInt *support, *cone;
    6305:       PetscInt        size, s;

    6307:       DMPlexGetSupportSize(dm, v, &size);
    6308:       DMPlexGetSupport(dm, v, &support);
    6309:       for (s = 0; s < size; ++s) {
    6310:         const PetscInt e = support[s];

    6312:         supportRef[s] = -1;
    6313:         if (eStart <= e) {
    6314:           if (e < eMax) {
    6315:             DMPlexGetCone(dm, e, &cone);
    6316:             supportRef[s] = eStartNew + (e - eStart)*2 + (cone[1] == v ? 1 : 0);
    6317:           } else if (e < eEnd) {
    6318:             supportRef[s] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart)*4 + e - eMax;
    6319:           } else SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", e, eStart, eEnd);
    6320:         } else SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", e, eStart, eEnd);
    6321:       }
    6322:       DMPlexSetSupport(rdm, newp, supportRef);
    6323: #if defined(PETSC_USE_DEBUG)
    6324:       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", newp, vStartNew, vEndNew);
    6325:       for (p = 0; p < size; ++p) {
    6326:         if ((supportRef[p] < eStartNew) || (supportRef[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", supportRef[p], eStartNew, eEndNew);
    6327:       }
    6328: #endif
    6329:     }
    6330:     /* Interior edge vertices have 2 + faces supports */
    6331:     for (e = eStart; e < eMax; ++e) {
    6332:       const PetscInt  newp = vStartNew + (vEnd - vStart) + (e - eStart);
    6333:       const PetscInt *cone, *support;
    6334:       PetscInt        size, s;

    6336:       DMPlexGetSupportSize(dm, e, &size);
    6337:       DMPlexGetSupport(dm, e, &support);
    6338:       supportRef[0] = eStartNew + (e - eStart)*2 + 0;
    6339:       supportRef[1] = eStartNew + (e - eStart)*2 + 1;
    6340:       for (s = 0; s < size; ++s) {
    6341:         PetscInt r, coneSize;

    6343:         supportRef[2+s] = -1;
    6344:         DMPlexGetConeSize(dm, support[s], &coneSize);
    6345:         if (coneSize != 4 && support[s] >= fMax) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected conesize %D for face %D (fMax %D)", coneSize, support[s], fMax);
    6346:         if (coneSize != 3 && support[s] <  fMax) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected conesize %D for face %D (fMax %D)", coneSize, support[s], fMax);
    6347:         DMPlexGetCone(dm, support[s], &cone);
    6348:         for (r = 0; r < coneSize; ++r) {if (cone[r] == e) break;}
    6349:         if (coneSize == 3) supportRef[2+s] = eStartNew + (eMax - eStart)*2 + (support[s] - fStart)*3 + r;
    6350:         else if (coneSize == 4) {
    6351:           if (r != 0 && r != 1) SETERRQ4(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected position in cone %D of face %D (fMax %D) for edge %D", r, support[s], fMax, e);
    6352:           supportRef[2+s] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart)*4 + (eEnd - eMax) + support[s] - fMax;
    6353:         } else SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected conesize %D for face %D (fMax %D)", coneSize, support[s], fMax);
    6354:       }
    6355:       DMPlexSetSupport(rdm, newp, supportRef);
    6356: #if defined(PETSC_USE_DEBUG)
    6357:       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", newp, vStartNew, vEndNew);
    6358:       for (p = 0; p < 2+size; ++p) {
    6359:         if ((supportRef[p] < eStartNew) || (supportRef[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", supportRef[p], eStartNew, eEndNew);
    6360:       }
    6361: #endif
    6362:     }
    6363:     /* Split Edges have 2 vertices and the same faces as the parent */
    6364:     for (e = eStart; e < eMax; ++e) {
    6365:       const PetscInt newv = vStartNew + (vEnd - vStart) + (e - eStart);

    6367:       for (r = 0; r < 2; ++r) {
    6368:         const PetscInt  newp = eStartNew + (e - eStart)*2 + r;
    6369:         const PetscInt *cone, *ornt, *support;
    6370:         PetscInt        coneNew[2], coneSize, c, supportSize, s;

    6372:         DMPlexGetCone(dm, e, &cone);
    6373:         coneNew[0]       = vStartNew + (cone[0] - vStart);
    6374:         coneNew[1]       = vStartNew + (cone[1] - vStart);
    6375:         coneNew[(r+1)%2] = newv;
    6376:         DMPlexSetCone(rdm, newp, coneNew);
    6377: #if defined(PETSC_USE_DEBUG)
    6378:         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eEndNew);
    6379:         for (p = 0; p < 2; ++p) {
    6380:           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", coneNew[p], vStartNew, vEndNew);
    6381:         }
    6382: #endif
    6383:         DMPlexGetSupportSize(dm, e, &supportSize);
    6384:         DMPlexGetSupport(dm, e, &support);
    6385:         for (s = 0; s < supportSize; ++s) {
    6386:           DMPlexGetConeSize(dm, support[s], &coneSize);
    6387:           if (coneSize != 4 && support[s] >= fMax) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected conesize %D for face %D (fMax %D)", coneSize, support[s], fMax);
    6388:           if (coneSize != 3 && support[s] <  fMax) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected conesize %D for face %D (fMax %D)", coneSize, support[s], fMax);
    6389:           DMPlexGetCone(dm, support[s], &cone);
    6390:           DMPlexGetConeOrientation(dm, support[s], &ornt);
    6391:           for (c = 0; c < coneSize; ++c) {
    6392:             if (cone[c] == e) break;
    6393:           }
    6394:           if (coneSize == 3) supportRef[s] = fStartNew + (support[s] - fStart)*3 + (c + (ornt[c] < 0 ? 1-r : r))%3;
    6395:           else if (coneSize == 4) {
    6396:             if (c != 0 && c != 1) SETERRQ4(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected position in cone %D of face %D (fMax %D) for edge %D", c, support[s], fMax, e);
    6397:             supportRef[s] = fStartNew + (fMax - fStart)*3 + (cMax - cStart)*6 + (support[s] - fMax)*2 + (ornt[c] < 0 ? 1-r : r);
    6398:           } else SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected conesize %D for face %D (fMax %D)", coneSize, support[s], fMax);
    6399:         }
    6400:         DMPlexSetSupport(rdm, newp, supportRef);
    6401: #if defined(PETSC_USE_DEBUG)
    6402:         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eEndNew);
    6403:         for (p = 0; p < supportSize; ++p) {
    6404:           if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", supportRef[p], fStartNew, fEndNew);
    6405:         }
    6406: #endif
    6407:       }
    6408:     }
    6409:     /* Face vertices have 3 + cells supports */
    6410:     for (f = fStart; f < fMax; ++f) {
    6411:       const PetscInt  newp = vStartNew + (vEnd - vStart) + (eMax - eStart) + (f - fStart);
    6412:       const PetscInt *cone, *support;
    6413:       PetscInt        size, s;

    6415:       DMPlexGetSupportSize(dm, f, &size);
    6416:       DMPlexGetSupport(dm, f, &support);
    6417:       supportRef[0] = eStartNew + (eMax - eStart)*2 + (f - fStart)*3 + 0;
    6418:       supportRef[1] = eStartNew + (eMax - eStart)*2 + (f - fStart)*3 + 1;
    6419:       supportRef[2] = eStartNew + (eMax - eStart)*2 + (f - fStart)*3 + 2;
    6420:       for (s = 0; s < size; ++s) {
    6421:         PetscInt r, coneSize;

    6423:         supportRef[3+s] = -1;
    6424:         DMPlexGetConeSize(dm, support[s], &coneSize);
    6425:         if (coneSize != 5 && support[s] >= cMax) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected conesize %D for cell %D (cMax %D)", coneSize, support[s], cMax);
    6426:         if (coneSize != 4 && support[s] <  cMax) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected conesize %D for cell %D (cMax %D)", coneSize, support[s], cMax);
    6427:         DMPlexGetCone(dm, support[s], &cone);
    6428:         for (r = 0; r < coneSize; ++r) {if (cone[r] == f) break;}
    6429:         if (coneSize == 4) supportRef[3+s] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (support[s] - cStart)*4 + r;
    6430:         else if (coneSize == 5) {
    6431:           if (r != 0 && r != 1) SETERRQ4(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected position in cone %D of cell %D (cMax %D) for face %D", r, support[s], cMax, f);
    6432:           supportRef[3+s] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart)*4 + (eEnd - eMax) + (fEnd - fMax) + support[s] - cMax;
    6433:         }
    6434:       }
    6435:       DMPlexSetSupport(rdm, newp, supportRef);
    6436: #if defined(PETSC_USE_DEBUG)
    6437:       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", newp, vStartNew, vEndNew);
    6438:       for (p = 0; p < 3+size; ++p) {
    6439:         if ((supportRef[p] < eStartNew) || (supportRef[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", supportRef[p], eStartNew, eEndNew);
    6440:       }
    6441: #endif
    6442:     }
    6443:     /* Interior cell vertices have 4 supports */
    6444:     for (c = cStart; c < cMax; ++c) {
    6445:       const PetscInt  newp = vStartNew + (vEnd - vStart) + (eMax - eStart) + (fMax - fStart) + c - cStart;

    6447:       supportRef[0] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart)*4 + 0;
    6448:       supportRef[1] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart)*4 + 1;
    6449:       supportRef[2] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart)*4 + 2;
    6450:       supportRef[3] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart)*4 + 3;
    6451:       DMPlexSetSupport(rdm, newp, supportRef);
    6452: #if defined(PETSC_USE_DEBUG)
    6453:       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", newp, vStartNew, vEndNew);
    6454:       for (p = 0; p < 4; ++p) {
    6455:         if ((supportRef[p] < eStartNew) || (supportRef[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", supportRef[p], eStartNew, eEndNew);
    6456:       }
    6457: #endif
    6458:     }
    6459:     PetscFree(supportRef);
    6460:     DMPlexRestoreFaces_Internal(dm, 3, cStart, NULL, NULL, &faces);
    6461:     break;
    6462:   case REFINER_HEX_3D:
    6463:     /*
    6464:      Bottom (viewed from top)    Top
    6465:      1---------2---------2       7---------2---------6
    6466:      |         |         |       |         |         |
    6467:      |    B    2    C    |       |    H    2    G    |
    6468:      |         |         |       |         |         |
    6469:      3----3----0----1----1       3----3----0----1----1
    6470:      |         |         |       |         |         |
    6471:      |    A    0    D    |       |    E    0    F    |
    6472:      |         |         |       |         |         |
    6473:      0---------0---------3       4---------0---------5
    6474:      */
    6475:     /* All cells have 6 faces: Bottom, Top, Front, Back, Right, Left */
    6476:     for (c = cStart; c < cEnd; ++c) {
    6477:       const PetscInt  newp = (c - cStart)*8;
    6478:       const PetscInt *cone, *ornt;
    6479:       PetscInt        coneNew[6], orntNew[6];

    6481:       DMPlexGetCone(dm, c, &cone);
    6482:       DMPlexGetConeOrientation(dm, c, &ornt);
    6483:       /* A hex */
    6484:       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], 0);
    6485:       orntNew[0] = ornt[0];
    6486:       coneNew[1] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  8; /* AE */
    6487:       orntNew[1] = 0;
    6488:       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetQuadSubface_Static(ornt[2], 0);
    6489:       orntNew[2] = ornt[2];
    6490:       coneNew[3] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  3; /* AB */
    6491:       orntNew[3] = 0;
    6492:       coneNew[4] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  0; /* AD */
    6493:       orntNew[4] = 0;
    6494:       coneNew[5] = fStartNew + (cone[5] - fStart)*4 + GetQuadSubface_Static(ornt[5], 0);
    6495:       orntNew[5] = ornt[5];
    6496:       DMPlexSetCone(rdm, newp+0, coneNew);
    6497:       DMPlexSetConeOrientation(rdm, newp+0, orntNew);
    6498: #if defined(PETSC_USE_DEBUG)
    6499:       if ((newp+0 < cStartNew) || (newp+0 >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", newp+0, cStartNew, cEndNew);
    6500:       for (p = 0; p < 6; ++p) {
    6501:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", coneNew[p], fStartNew, fEndNew);
    6502:       }
    6503: #endif
    6504:       /* B hex */
    6505:       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], 1);
    6506:       orntNew[0] = ornt[0];
    6507:       coneNew[1] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 + 11; /* BH */
    6508:       orntNew[1] = 0;
    6509:       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  3; /* AB */
    6510:       orntNew[2] = -1;
    6511:       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetQuadSubface_Static(ornt[3], 1);
    6512:       orntNew[3] = ornt[3];
    6513:       coneNew[4] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  2; /* BC */
    6514:       orntNew[4] = 0;
    6515:       coneNew[5] = fStartNew + (cone[5] - fStart)*4 + GetQuadSubface_Static(ornt[5], 3);
    6516:       orntNew[5] = ornt[5];
    6517:       DMPlexSetCone(rdm, newp+1, coneNew);
    6518:       DMPlexSetConeOrientation(rdm, newp+1, orntNew);
    6519: #if defined(PETSC_USE_DEBUG)
    6520:       if ((newp+1 < cStartNew) || (newp+1 >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", newp+1, cStartNew, cEndNew);
    6521:       for (p = 0; p < 6; ++p) {
    6522:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", coneNew[p], fStartNew, fEndNew);
    6523:       }
    6524: #endif
    6525:       /* C hex */
    6526:       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], 2);
    6527:       orntNew[0] = ornt[0];
    6528:       coneNew[1] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 + 10; /* CG */
    6529:       orntNew[1] = 0;
    6530:       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  1; /* CD */
    6531:       orntNew[2] = -1;
    6532:       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetQuadSubface_Static(ornt[3], 0);
    6533:       orntNew[3] = ornt[3];
    6534:       coneNew[4] = fStartNew + (cone[4] - fStart)*4 + GetQuadSubface_Static(ornt[4], 1);
    6535:       orntNew[4] = ornt[4];
    6536:       coneNew[5] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  2; /* BC */
    6537:       orntNew[5] = -4;
    6538:       DMPlexSetCone(rdm, newp+2, coneNew);
    6539:       DMPlexSetConeOrientation(rdm, newp+2, orntNew);
    6540: #if defined(PETSC_USE_DEBUG)
    6541:       if ((newp+2 < cStartNew) || (newp+2 >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", newp+2, cStartNew, cEndNew);
    6542:       for (p = 0; p < 6; ++p) {
    6543:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", coneNew[p], fStartNew, fEndNew);
    6544:       }
    6545: #endif
    6546:       /* D hex */
    6547:       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], 3);
    6548:       orntNew[0] = ornt[0];
    6549:       coneNew[1] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  9; /* DF */
    6550:       orntNew[1] = 0;
    6551:       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetQuadSubface_Static(ornt[2], 1);
    6552:       orntNew[2] = ornt[2];
    6553:       coneNew[3] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  1; /* CD */
    6554:       orntNew[3] = 0;
    6555:       coneNew[4] = fStartNew + (cone[4] - fStart)*4 + GetQuadSubface_Static(ornt[4], 0);
    6556:       orntNew[4] = ornt[4];
    6557:       coneNew[5] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  0; /* AD */
    6558:       orntNew[5] = -4;
    6559:       DMPlexSetCone(rdm, newp+3, coneNew);
    6560:       DMPlexSetConeOrientation(rdm, newp+3, orntNew);
    6561: #if defined(PETSC_USE_DEBUG)
    6562:       if ((newp+3 < cStartNew) || (newp+3 >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", newp+3, cStartNew, cEndNew);
    6563:       for (p = 0; p < 6; ++p) {
    6564:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", coneNew[p], fStartNew, fEndNew);
    6565:       }
    6566: #endif
    6567:       /* E hex */
    6568:       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  8; /* AE */
    6569:       orntNew[0] = -4;
    6570:       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], 0);
    6571:       orntNew[1] = ornt[1];
    6572:       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetQuadSubface_Static(ornt[2], 3);
    6573:       orntNew[2] = ornt[2];
    6574:       coneNew[3] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  7; /* EH */
    6575:       orntNew[3] = 0;
    6576:       coneNew[4] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  4; /* EF */
    6577:       orntNew[4] = -1;
    6578:       coneNew[5] = fStartNew + (cone[5] - fStart)*4 + GetQuadSubface_Static(ornt[5], 1);
    6579:       orntNew[5] = ornt[5];
    6580:       DMPlexSetCone(rdm, newp+4, coneNew);
    6581:       DMPlexSetConeOrientation(rdm, newp+4, orntNew);
    6582: #if defined(PETSC_USE_DEBUG)
    6583:       if ((newp+4 < cStartNew) || (newp+4 >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", newp+4, cStartNew, cEndNew);
    6584:       for (p = 0; p < 6; ++p) {
    6585:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", coneNew[p], fStartNew, fEndNew);
    6586:       }
    6587: #endif
    6588:       /* F hex */
    6589:       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  9; /* DF */
    6590:       orntNew[0] = -4;
    6591:       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], 1);
    6592:       orntNew[1] = ornt[1];
    6593:       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetQuadSubface_Static(ornt[2], 2);
    6594:       orntNew[2] = ornt[2];
    6595:       coneNew[3] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  5; /* FG */
    6596:       orntNew[3] = -1;
    6597:       coneNew[4] = fStartNew + (cone[4] - fStart)*4 + GetQuadSubface_Static(ornt[4], 3);
    6598:       orntNew[4] = ornt[4];
    6599:       coneNew[5] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  4; /* EF */
    6600:       orntNew[5] = 1;
    6601:       DMPlexSetCone(rdm, newp+5, coneNew);
    6602:       DMPlexSetConeOrientation(rdm, newp+5, orntNew);
    6603: #if defined(PETSC_USE_DEBUG)
    6604:       if ((newp+5 < cStartNew) || (newp+5 >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", newp+5, cStartNew, cEndNew);
    6605:       for (p = 0; p < 6; ++p) {
    6606:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", coneNew[p], fStartNew, fEndNew);
    6607:       }
    6608: #endif
    6609:       /* G hex */
    6610:       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 + 10; /* CG */
    6611:       orntNew[0] = -4;
    6612:       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], 2);
    6613:       orntNew[1] = ornt[1];
    6614:       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  5; /* FG */
    6615:       orntNew[2] = 0;
    6616:       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetQuadSubface_Static(ornt[3], 3);
    6617:       orntNew[3] = ornt[3];
    6618:       coneNew[4] = fStartNew + (cone[4] - fStart)*4 + GetQuadSubface_Static(ornt[4], 2);
    6619:       orntNew[4] = ornt[4];
    6620:       coneNew[5] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  6; /* GH */
    6621:       orntNew[5] = -3;
    6622:       DMPlexSetCone(rdm, newp+6, coneNew);
    6623:       DMPlexSetConeOrientation(rdm, newp+6, orntNew);
    6624: #if defined(PETSC_USE_DEBUG)
    6625:       if ((newp+6 < cStartNew) || (newp+6 >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", newp+6, cStartNew, cEndNew);
    6626:       for (p = 0; p < 6; ++p) {
    6627:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", coneNew[p], fStartNew, fEndNew);
    6628:       }
    6629: #endif
    6630:       /* H hex */
    6631:       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 + 11; /* BH */
    6632:       orntNew[0] = -4;
    6633:       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], 3);
    6634:       orntNew[1] = ornt[1];
    6635:       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  7; /* EH */
    6636:       orntNew[2] = -1;
    6637:       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetQuadSubface_Static(ornt[3], 2);
    6638:       orntNew[3] = ornt[3];
    6639:       coneNew[4] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  6; /* GH */
    6640:       orntNew[4] = 3;
    6641:       coneNew[5] = fStartNew + (cone[5] - fStart)*4 + GetQuadSubface_Static(ornt[5], 2);
    6642:       orntNew[5] = ornt[5];
    6643:       DMPlexSetCone(rdm, newp+7, coneNew);
    6644:       DMPlexSetConeOrientation(rdm, newp+7, orntNew);
    6645: #if defined(PETSC_USE_DEBUG)
    6646:       if ((newp+7 < cStartNew) || (newp+7 >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", newp+7, cStartNew, cEndNew);
    6647:       for (p = 0; p < 6; ++p) {
    6648:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", coneNew[p], fStartNew, fEndNew);
    6649:       }
    6650: #endif
    6651:     }
    6652:     /* Split faces have 4 edges and the same cells as the parent */
    6653:     DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);
    6654:     PetscMalloc1(4 + maxSupportSize*2, &supportRef);
    6655:     for (f = fStart; f < fEnd; ++f) {
    6656:       for (r = 0; r < 4; ++r) {
    6657:         /* TODO: This can come from GetFaces_Internal() */
    6658:         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};
    6659:         const PetscInt  newp = fStartNew + (f - fStart)*4 + r;
    6660:         const PetscInt *cone, *ornt, *support;
    6661:         PetscInt        coneNew[4], orntNew[4], coneSize, c, supportSize, s;

    6663:         DMPlexGetCone(dm, f, &cone);
    6664:         DMPlexGetConeOrientation(dm, f, &ornt);
    6665:         coneNew[(r+3)%4] = eStartNew + (cone[(r+3)%4] - eStart)*2 + (ornt[(r+3)%4] < 0 ? 0 : 1);
    6666:         orntNew[(r+3)%4] = ornt[(r+3)%4];
    6667:         coneNew[(r+0)%4] = eStartNew + (cone[r]       - eStart)*2 + (ornt[r] < 0 ? 1 : 0);
    6668:         orntNew[(r+0)%4] = ornt[r];
    6669:         coneNew[(r+1)%4] = eStartNew + (eEnd - eStart)*2 + (f - fStart)*4 + r;
    6670:         orntNew[(r+1)%4] = 0;
    6671:         coneNew[(r+2)%4] = eStartNew + (eEnd - eStart)*2 + (f - fStart)*4 + (r+3)%4;
    6672:         orntNew[(r+2)%4] = -2;
    6673:         DMPlexSetCone(rdm, newp, coneNew);
    6674:         DMPlexSetConeOrientation(rdm, newp, orntNew);
    6675: #if defined(PETSC_USE_DEBUG)
    6676:         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
    6677:         for (p = 0; p < 4; ++p) {
    6678:           if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", coneNew[p], eStartNew, eEndNew);
    6679:         }
    6680: #endif
    6681:         DMPlexGetSupportSize(dm, f, &supportSize);
    6682:         DMPlexGetSupport(dm, f, &support);
    6683:         for (s = 0; s < supportSize; ++s) {
    6684:           DMPlexGetConeSize(dm, support[s], &coneSize);
    6685:           DMPlexGetCone(dm, support[s], &cone);
    6686:           DMPlexGetConeOrientation(dm, support[s], &ornt);
    6687:           for (c = 0; c < coneSize; ++c) {
    6688:             if (cone[c] == f) break;
    6689:           }
    6690:           supportRef[s] = cStartNew + (support[s] - cStart)*8 + newCells[c*4+GetQuadSubfaceInverse_Static(ornt[c], r)];
    6691:         }
    6692:         DMPlexSetSupport(rdm, newp, supportRef);
    6693: #if defined(PETSC_USE_DEBUG)
    6694:         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
    6695:         for (p = 0; p < supportSize; ++p) {
    6696:           if ((supportRef[p] < cStartNew) || (supportRef[p] >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", supportRef[p], cStartNew, cEndNew);
    6697:         }
    6698: #endif
    6699:       }
    6700:     }
    6701:     /* Interior faces have 4 edges and 2 cells */
    6702:     for (c = cStart; c < cEnd; ++c) {
    6703:       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};
    6704:       const PetscInt *cone, *ornt;
    6705:       PetscInt        newp, coneNew[4], orntNew[4], supportNew[2];

    6707:       DMPlexGetCone(dm, c, &cone);
    6708:       DMPlexGetConeOrientation(dm, c, &ornt);
    6709:       /* A-D face */
    6710:       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 0;
    6711:       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*4 + GetQuadEdge_Static(ornt[0], 3);
    6712:       orntNew[0] = 0;
    6713:       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 0;
    6714:       orntNew[1] = 0;
    6715:       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 2;
    6716:       orntNew[2] = -2;
    6717:       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*4 + GetQuadEdge_Static(ornt[2], 0);
    6718:       orntNew[3] = -2;
    6719:       DMPlexSetCone(rdm, newp, coneNew);
    6720:       DMPlexSetConeOrientation(rdm, newp, orntNew);
    6721: #if defined(PETSC_USE_DEBUG)
    6722:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
    6723:       for (p = 0; p < 4; ++p) {
    6724:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", coneNew[p], eStartNew, eEndNew);
    6725:       }
    6726: #endif
    6727:       /* C-D face */
    6728:       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 1;
    6729:       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*4 + GetQuadEdge_Static(ornt[0], 2);
    6730:       orntNew[0] = 0;
    6731:       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 0;
    6732:       orntNew[1] = 0;
    6733:       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 4;
    6734:       orntNew[2] = -2;
    6735:       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (cone[4] - fStart)*4 + GetQuadEdge_Static(ornt[4], 0);
    6736:       orntNew[3] = -2;
    6737:       DMPlexSetCone(rdm, newp, coneNew);
    6738:       DMPlexSetConeOrientation(rdm, newp, orntNew);
    6739: #if defined(PETSC_USE_DEBUG)
    6740:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
    6741:       for (p = 0; p < 4; ++p) {
    6742:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", coneNew[p], eStartNew, eEndNew);
    6743:       }
    6744: #endif
    6745:       /* B-C face */
    6746:       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 2;
    6747:       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*4 + GetQuadEdge_Static(ornt[0], 1);
    6748:       orntNew[0] = -2;
    6749:       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*4 + GetQuadEdge_Static(ornt[3], 0);
    6750:       orntNew[1] = 0;
    6751:       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 3;
    6752:       orntNew[2] = 0;
    6753:       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 0;
    6754:       orntNew[3] = -2;
    6755:       DMPlexSetCone(rdm, newp, coneNew);
    6756:       DMPlexSetConeOrientation(rdm, newp, orntNew);
    6757: #if defined(PETSC_USE_DEBUG)
    6758:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
    6759:       for (p = 0; p < 4; ++p) {
    6760:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", coneNew[p], eStartNew, eEndNew);
    6761:       }
    6762: #endif
    6763:       /* A-B face */
    6764:       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 3;
    6765:       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*4 + GetQuadEdge_Static(ornt[0], 0);
    6766:       orntNew[0] = -2;
    6767:       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[5] - fStart)*4 + GetQuadEdge_Static(ornt[5], 3);
    6768:       orntNew[1] = 0;
    6769:       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 5;
    6770:       orntNew[2] = 0;
    6771:       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 0;
    6772:       orntNew[3] = -2;
    6773:       DMPlexSetCone(rdm, newp, coneNew);
    6774:       DMPlexSetConeOrientation(rdm, newp, orntNew);
    6775: #if defined(PETSC_USE_DEBUG)
    6776:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
    6777:       for (p = 0; p < 4; ++p) {
    6778:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", coneNew[p], eStartNew, eEndNew);
    6779:       }
    6780: #endif
    6781:       /* E-F face */
    6782:       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 4;
    6783:       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 2;
    6784:       orntNew[0] = -2;
    6785:       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*4 + GetQuadEdge_Static(ornt[2], 2);
    6786:       orntNew[1] = -2;
    6787:       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*4 + GetQuadEdge_Static(ornt[1], 0);
    6788:       orntNew[2] = 0;
    6789:       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 1;
    6790:       orntNew[3] = 0;
    6791:       DMPlexSetCone(rdm, newp, coneNew);
    6792:       DMPlexSetConeOrientation(rdm, newp, orntNew);
    6793: #if defined(PETSC_USE_DEBUG)
    6794:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
    6795:       for (p = 0; p < 4; ++p) {
    6796:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", coneNew[p], eStartNew, eEndNew);
    6797:       }
    6798: #endif
    6799:       /* F-G face */
    6800:       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 5;
    6801:       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 4;
    6802:       orntNew[0] = -2;
    6803:       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[4] - fStart)*4 + GetQuadEdge_Static(ornt[4], 2);
    6804:       orntNew[1] = -2;
    6805:       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*4 + GetQuadEdge_Static(ornt[1], 1);
    6806:       orntNew[2] = 0;
    6807:       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 1;
    6808:       orntNew[3] = 0;
    6809:       DMPlexSetCone(rdm, newp, coneNew);
    6810:       DMPlexSetConeOrientation(rdm, newp, orntNew);
    6811: #if defined(PETSC_USE_DEBUG)
    6812:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
    6813:       for (p = 0; p < 4; ++p) {
    6814:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", coneNew[p], eStartNew, eEndNew);
    6815:       }
    6816: #endif
    6817:       /* G-H face */
    6818:       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 6;
    6819:       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*4 + GetQuadEdge_Static(ornt[3], 2);
    6820:       orntNew[0] = -2;
    6821:       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*4 + GetQuadEdge_Static(ornt[1], 2);
    6822:       orntNew[1] = 0;
    6823:       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 1;
    6824:       orntNew[2] = 0;
    6825:       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 3;
    6826:       orntNew[3] = -2;
    6827:       DMPlexSetCone(rdm, newp, coneNew);
    6828:       DMPlexSetConeOrientation(rdm, newp, orntNew);
    6829: #if defined(PETSC_USE_DEBUG)
    6830:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
    6831:       for (p = 0; p < 4; ++p) {
    6832:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", coneNew[p], eStartNew, eEndNew);
    6833:       }
    6834: #endif
    6835:       /* E-H face */
    6836:       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 7;
    6837:       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 5;
    6838:       orntNew[0] = -2;
    6839:       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[5] - fStart)*4 + GetQuadEdge_Static(ornt[5], 1);
    6840:       orntNew[1] = -2;
    6841:       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*4 + GetQuadEdge_Static(ornt[1], 3);
    6842:       orntNew[2] = 0;
    6843:       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 1;
    6844:       orntNew[3] = 0;
    6845:       DMPlexSetCone(rdm, newp, coneNew);
    6846:       DMPlexSetConeOrientation(rdm, newp, orntNew);
    6847: #if defined(PETSC_USE_DEBUG)
    6848:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
    6849:       for (p = 0; p < 4; ++p) {
    6850:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", coneNew[p], eStartNew, eEndNew);
    6851:       }
    6852: #endif
    6853:       /* A-E face */
    6854:       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 8;
    6855:       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*4 + GetQuadEdge_Static(ornt[2], 3);
    6856:       orntNew[0] = 0;
    6857:       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 2;
    6858:       orntNew[1] = 0;
    6859:       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 5;
    6860:       orntNew[2] = -2;
    6861:       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (cone[5] - fStart)*4 + GetQuadEdge_Static(ornt[5], 0);
    6862:       orntNew[3] = -2;
    6863:       DMPlexSetCone(rdm, newp, coneNew);
    6864:       DMPlexSetConeOrientation(rdm, newp, orntNew);
    6865: #if defined(PETSC_USE_DEBUG)
    6866:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
    6867:       for (p = 0; p < 4; ++p) {
    6868:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", coneNew[p], eStartNew, eEndNew);
    6869:       }
    6870: #endif
    6871:       /* D-F face */
    6872:       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 9;
    6873:       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*4 + GetQuadEdge_Static(ornt[2], 1);
    6874:       orntNew[0] = -2;
    6875:       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[4] - fStart)*4 + GetQuadEdge_Static(ornt[4], 3);
    6876:       orntNew[1] = 0;
    6877:       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 4;
    6878:       orntNew[2] = 0;
    6879:       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 2;
    6880:       orntNew[3] = -2;
    6881:       DMPlexSetCone(rdm, newp, coneNew);
    6882:       DMPlexSetConeOrientation(rdm, newp, orntNew);
    6883: #if defined(PETSC_USE_DEBUG)
    6884:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
    6885:       for (p = 0; p < 4; ++p) {
    6886:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", coneNew[p], eStartNew, eEndNew);
    6887:       }
    6888: #endif
    6889:       /* C-G face */
    6890:       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 10;
    6891:       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 4;
    6892:       orntNew[0] = -2;
    6893:       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[4] - fStart)*4 + GetQuadEdge_Static(ornt[4], 1);
    6894:       orntNew[1] = -2;
    6895:       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*4 + GetQuadEdge_Static(ornt[3], 3);
    6896:       orntNew[2] = 0;
    6897:       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 3;
    6898:       orntNew[3] = 0;
    6899:       DMPlexSetCone(rdm, newp, coneNew);
    6900:       DMPlexSetConeOrientation(rdm, newp, orntNew);
    6901: #if defined(PETSC_USE_DEBUG)
    6902:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
    6903:       for (p = 0; p < 4; ++p) {
    6904:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", coneNew[p], eStartNew, eEndNew);
    6905:       }
    6906: #endif
    6907:       /* B-H face */
    6908:       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 11;
    6909:       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 5;
    6910:       orntNew[0] = 0;
    6911:       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 3;
    6912:       orntNew[1] = -2;
    6913:       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*4 + GetQuadEdge_Static(ornt[3], 1);
    6914:       orntNew[2] = -2;
    6915:       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (cone[5] - fStart)*4 + GetQuadEdge_Static(ornt[5], 2);
    6916:       orntNew[3] = 0;
    6917:       DMPlexSetCone(rdm, newp, coneNew);
    6918:       DMPlexSetConeOrientation(rdm, newp, orntNew);
    6919: #if defined(PETSC_USE_DEBUG)
    6920:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
    6921:       for (p = 0; p < 4; ++p) {
    6922:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", coneNew[p], eStartNew, eEndNew);
    6923:       }
    6924: #endif
    6925:       for (r = 0; r < 12; ++r) {
    6926:         newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + r;
    6927:         supportNew[0] = cStartNew + (c - cStart)*8 + newCells[r*2+0];
    6928:         supportNew[1] = cStartNew + (c - cStart)*8 + newCells[r*2+1];
    6929:         DMPlexSetSupport(rdm, newp, supportNew);
    6930: #if defined(PETSC_USE_DEBUG)
    6931:         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
    6932:         for (p = 0; p < 2; ++p) {
    6933:           if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", supportNew[p], cStartNew, cEndNew);
    6934:         }
    6935: #endif
    6936:       }
    6937:     }
    6938:     /* Split edges have 2 vertices and the same faces as the parent */
    6939:     DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);
    6940:     for (e = eStart; e < eEnd; ++e) {
    6941:       const PetscInt newv = vStartNew + (vEnd - vStart) + (e - eStart);

    6943:       for (r = 0; r < 2; ++r) {
    6944:         const PetscInt  newp = eStartNew + (e - eStart)*2 + r;
    6945:         const PetscInt *cone, *ornt, *support;
    6946:         PetscInt        coneNew[2], coneSize, c, supportSize, s;

    6948:         DMPlexGetCone(dm, e, &cone);
    6949:         coneNew[0]       = vStartNew + (cone[0] - vStart);
    6950:         coneNew[1]       = vStartNew + (cone[1] - vStart);
    6951:         coneNew[(r+1)%2] = newv;
    6952:         DMPlexSetCone(rdm, newp, coneNew);
    6953: #if defined(PETSC_USE_DEBUG)
    6954:         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eEndNew);
    6955:         for (p = 0; p < 2; ++p) {
    6956:           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", coneNew[p], vStartNew, vEndNew);
    6957:         }
    6958: #endif
    6959:         DMPlexGetSupportSize(dm, e, &supportSize);
    6960:         DMPlexGetSupport(dm, e, &support);
    6961:         for (s = 0; s < supportSize; ++s) {
    6962:           DMPlexGetConeSize(dm, support[s], &coneSize);
    6963:           DMPlexGetCone(dm, support[s], &cone);
    6964:           DMPlexGetConeOrientation(dm, support[s], &ornt);
    6965:           for (c = 0; c < coneSize; ++c) {
    6966:             if (cone[c] == e) break;
    6967:           }
    6968:           supportRef[s] = fStartNew + (support[s] - fStart)*4 + (ornt[c] < 0 ? (c+1-r)%4 : (c+r)%4);
    6969:         }
    6970:         DMPlexSetSupport(rdm, newp, supportRef);
    6971: #if defined(PETSC_USE_DEBUG)
    6972:         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eEndNew);
    6973:         for (p = 0; p < supportSize; ++p) {
    6974:           if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", supportRef[p], fStartNew, fEndNew);
    6975:         }
    6976: #endif
    6977:       }
    6978:     }
    6979:     /* Face edges have 2 vertices and 2+cells faces */
    6980:     for (f = fStart; f < fEnd; ++f) {
    6981:       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};
    6982:       const PetscInt  newv = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (f - fStart);
    6983:       const PetscInt *cone, *coneCell, *orntCell, *support;
    6984:       PetscInt        coneNew[2], coneSize, c, supportSize, s;

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

    6990:         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r] - eStart);
    6991:         coneNew[1] = newv;
    6992:         DMPlexSetCone(rdm, newp, coneNew);
    6993: #if defined(PETSC_USE_DEBUG)
    6994:         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eEndNew);
    6995:         for (p = 0; p < 2; ++p) {
    6996:           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", coneNew[p], vStartNew, vEndNew);
    6997:         }
    6998: #endif
    6999:         DMPlexGetSupportSize(dm, f, &supportSize);
    7000:         DMPlexGetSupport(dm, f, &support);
    7001:         supportRef[0] = fStartNew + (f - fStart)*4 + r;
    7002:         supportRef[1] = fStartNew + (f - fStart)*4 + (r+1)%4;
    7003:         for (s = 0; s < supportSize; ++s) {
    7004:           DMPlexGetConeSize(dm, support[s], &coneSize);
    7005:           DMPlexGetCone(dm, support[s], &coneCell);
    7006:           DMPlexGetConeOrientation(dm, support[s], &orntCell);
    7007:           for (c = 0; c < coneSize; ++c) if (coneCell[c] == f) break;
    7008:           supportRef[2+s] = fStartNew + (fEnd - fStart)*4 + (support[s] - cStart)*12 + newFaces[c*4 + GetQuadEdgeInverse_Static(orntCell[c], r)];
    7009:         }
    7010:         DMPlexSetSupport(rdm, newp, supportRef);
    7011: #if defined(PETSC_USE_DEBUG)
    7012:         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eEndNew);
    7013:         for (p = 0; p < 2+supportSize; ++p) {
    7014:           if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", supportRef[p], fStartNew, fEndNew);
    7015:         }
    7016: #endif
    7017:       }
    7018:     }
    7019:     /* Cell edges have 2 vertices and 4 faces */
    7020:     for (c = cStart; c < cEnd; ++c) {
    7021:       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};
    7022:       const PetscInt  newv = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (fEnd - fStart) + (c - cStart);
    7023:       const PetscInt *cone;
    7024:       PetscInt        coneNew[2], supportNew[4];

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

    7030:         coneNew[0] = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (cone[r] - fStart);
    7031:         coneNew[1] = newv;
    7032:         DMPlexSetCone(rdm, newp, coneNew);
    7033: #if defined(PETSC_USE_DEBUG)
    7034:         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eEndNew);
    7035:         for (p = 0; p < 2; ++p) {
    7036:           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", coneNew[p], vStartNew, vEndNew);
    7037:         }
    7038: #endif
    7039:         for (f = 0; f < 4; ++f) supportNew[f] = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + newFaces[r*4+f];
    7040:         DMPlexSetSupport(rdm, newp, supportNew);
    7041: #if defined(PETSC_USE_DEBUG)
    7042:         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eEndNew);
    7043:         for (p = 0; p < 4; ++p) {
    7044:           if ((supportNew[p] < fStartNew) || (supportNew[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", supportNew[p], fStartNew, fEndNew);
    7045:         }
    7046: #endif
    7047:       }
    7048:     }
    7049:     /* Old vertices have identical supports */
    7050:     for (v = vStart; v < vEnd; ++v) {
    7051:       const PetscInt  newp = vStartNew + (v - vStart);
    7052:       const PetscInt *support, *cone;
    7053:       PetscInt        size, s;

    7055:       DMPlexGetSupportSize(dm, v, &size);
    7056:       DMPlexGetSupport(dm, v, &support);
    7057:       for (s = 0; s < size; ++s) {
    7058:         PetscInt r = 0;

    7060:         DMPlexGetCone(dm, support[s], &cone);
    7061:         if (cone[1] == v) r = 1;
    7062:         supportRef[s] = eStartNew + (support[s] - eStart)*2 + r;
    7063:       }
    7064:       DMPlexSetSupport(rdm, newp, supportRef);
    7065: #if defined(PETSC_USE_DEBUG)
    7066:       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", newp, vStartNew, vEndNew);
    7067:       for (p = 0; p < size; ++p) {
    7068:         if ((supportRef[p] < eStartNew) || (supportRef[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", supportRef[p], eStartNew, eEndNew);
    7069:       }
    7070: #endif
    7071:     }
    7072:     /* Edge vertices have 2 + faces supports */
    7073:     for (e = eStart; e < eEnd; ++e) {
    7074:       const PetscInt  newp = vStartNew + (vEnd - vStart) + (e - eStart);
    7075:       const PetscInt *cone, *support;
    7076:       PetscInt        size, s;

    7078:       DMPlexGetSupportSize(dm, e, &size);
    7079:       DMPlexGetSupport(dm, e, &support);
    7080:       supportRef[0] = eStartNew + (e - eStart)*2 + 0;
    7081:       supportRef[1] = eStartNew + (e - eStart)*2 + 1;
    7082:       for (s = 0; s < size; ++s) {
    7083:         PetscInt r;

    7085:         DMPlexGetCone(dm, support[s], &cone);
    7086:         for (r = 0; r < 4; ++r) if (cone[r] == e) break;
    7087:         supportRef[2+s] = eStartNew + (eEnd - eStart)*2 + (support[s] - fStart)*4 + r;
    7088:       }
    7089:       DMPlexSetSupport(rdm, newp, supportRef);
    7090: #if defined(PETSC_USE_DEBUG)
    7091:       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", newp, vStartNew, vEndNew);
    7092:       for (p = 0; p < 2+size; ++p) {
    7093:         if ((supportRef[p] < eStartNew) || (supportRef[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", supportRef[p], eStartNew, eEndNew);
    7094:       }
    7095: #endif
    7096:     }
    7097:     /* Face vertices have 4 + cells supports */
    7098:     for (f = fStart; f < fEnd; ++f) {
    7099:       const PetscInt  newp = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (f - fStart);
    7100:       const PetscInt *cone, *support;
    7101:       PetscInt        size, s;

    7103:       DMPlexGetSupportSize(dm, f, &size);
    7104:       DMPlexGetSupport(dm, f, &support);
    7105:       for (r = 0; r < 4; ++r) supportRef[r] = eStartNew + (eEnd - eStart)*2 +  (f - fStart)*4 + r;
    7106:       for (s = 0; s < size; ++s) {
    7107:         PetscInt r;

    7109:         DMPlexGetCone(dm, support[s], &cone);
    7110:         for (r = 0; r < 6; ++r) if (cone[r] == f) break;
    7111:         supportRef[4+s] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*4 + (support[s] - cStart)*6 + r;
    7112:       }
    7113:       DMPlexSetSupport(rdm, newp, supportRef);
    7114: #if defined(PETSC_USE_DEBUG)
    7115:       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", newp, vStartNew, vEndNew);
    7116:       for (p = 0; p < 4+size; ++p) {
    7117:         if ((supportRef[p] < eStartNew) || (supportRef[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", supportRef[p], eStartNew, eEndNew);
    7118:       }
    7119: #endif
    7120:     }
    7121:     /* Cell vertices have 6 supports */
    7122:     for (c = cStart; c < cEnd; ++c) {
    7123:       const PetscInt newp = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (fEnd - fStart) + (c - cStart);
    7124:       PetscInt       supportNew[6];

    7126:       for (r = 0; r < 6; ++r) {
    7127:         supportNew[r] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*4 + (c - cStart)*6 + r;
    7128:       }
    7129:       DMPlexSetSupport(rdm, newp, supportNew);
    7130:     }
    7131:     PetscFree(supportRef);
    7132:     break;
    7133:   case REFINER_HYBRID_HEX_3D:
    7134:     DMPlexGetHybridBounds(rdm, &cMaxNew, &fMaxNew, &eMaxNew, NULL);
    7135:     /*
    7136:      Bottom (viewed from top)    Top
    7137:      1---------2---------2       7---------2---------6
    7138:      |         |         |       |         |         |
    7139:      |    B    2    C    |       |    H    2    G    |
    7140:      |         |         |       |         |         |
    7141:      3----3----0----1----1       3----3----0----1----1
    7142:      |         |         |       |         |         |
    7143:      |    A    0    D    |       |    E    0    F    |
    7144:      |         |         |       |         |         |
    7145:      0---------0---------3       4---------0---------5
    7146:      */
    7147:     /* Interior cells have 6 faces: Bottom, Top, Front, Back, Right, Left */
    7148:     for (c = cStart; c < cMax; ++c) {
    7149:       const PetscInt  newp = (c - cStart)*8;
    7150:       const PetscInt *cone, *ornt;
    7151:       PetscInt        coneNew[6], orntNew[6];

    7153:       DMPlexGetCone(dm, c, &cone);
    7154:       DMPlexGetConeOrientation(dm, c, &ornt);
    7155:       /* A hex */
    7156:       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], 0);
    7157:       orntNew[0] = ornt[0];
    7158:       coneNew[1] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  8; /* AE */
    7159:       orntNew[1] = 0;
    7160:       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetQuadSubface_Static(ornt[2], 0);
    7161:       orntNew[2] = ornt[2];
    7162:       coneNew[3] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  3; /* AB */
    7163:       orntNew[3] = 0;
    7164:       coneNew[4] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  0; /* AD */
    7165:       orntNew[4] = 0;
    7166:       coneNew[5] = fStartNew + (cone[5] - fStart)*4 + GetQuadSubface_Static(ornt[5], 0);
    7167:       orntNew[5] = ornt[5];
    7168:       DMPlexSetCone(rdm, newp+0, coneNew);
    7169:       DMPlexSetConeOrientation(rdm, newp+0, orntNew);
    7170: #if defined(PETSC_USE_DEBUG)
    7171:       if ((newp+0 < cStartNew) || (newp+0 >= cMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", newp+0, cStartNew, cMaxNew);
    7172:       for (p = 0; p < 6; ++p) {
    7173:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", coneNew[p], fStartNew, fMaxNew);
    7174:       }
    7175: #endif
    7176:       /* B hex */
    7177:       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], 1);
    7178:       orntNew[0] = ornt[0];
    7179:       coneNew[1] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 + 11; /* BH */
    7180:       orntNew[1] = 0;
    7181:       coneNew[2] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  3; /* AB */
    7182:       orntNew[2] = -1;
    7183:       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetQuadSubface_Static(ornt[3], 1);
    7184:       orntNew[3] = ornt[3];
    7185:       coneNew[4] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  2; /* BC */
    7186:       orntNew[4] = 0;
    7187:       coneNew[5] = fStartNew + (cone[5] - fStart)*4 + GetQuadSubface_Static(ornt[5], 3);
    7188:       orntNew[5] = ornt[5];
    7189:       DMPlexSetCone(rdm, newp+1, coneNew);
    7190:       DMPlexSetConeOrientation(rdm, newp+1, orntNew);
    7191: #if defined(PETSC_USE_DEBUG)
    7192:       if ((newp+1 < cStartNew) || (newp+1 >= cMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", newp+1, cStartNew, cMaxNew);
    7193:       for (p = 0; p < 6; ++p) {
    7194:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", coneNew[p], fStartNew, fMaxNew);
    7195:       }
    7196: #endif
    7197:       /* C hex */
    7198:       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], 2);
    7199:       orntNew[0] = ornt[0];
    7200:       coneNew[1] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 + 10; /* CG */
    7201:       orntNew[1] = 0;
    7202:       coneNew[2] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  1; /* CD */
    7203:       orntNew[2] = -1;
    7204:       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetQuadSubface_Static(ornt[3], 0);
    7205:       orntNew[3] = ornt[3];
    7206:       coneNew[4] = fStartNew + (cone[4] - fStart)*4 + GetQuadSubface_Static(ornt[4], 1);
    7207:       orntNew[4] = ornt[4];
    7208:       coneNew[5] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  2; /* BC */
    7209:       orntNew[5] = -4;
    7210:       DMPlexSetCone(rdm, newp+2, coneNew);
    7211:       DMPlexSetConeOrientation(rdm, newp+2, orntNew);
    7212: #if defined(PETSC_USE_DEBUG)
    7213:       if ((newp+2 < cStartNew) || (newp+2 >= cMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", newp+2, cStartNew, cMaxNew);
    7214:       for (p = 0; p < 6; ++p) {
    7215:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", coneNew[p], fStartNew, fMaxNew);
    7216:       }
    7217: #endif
    7218:       /* D hex */
    7219:       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], 3);
    7220:       orntNew[0] = ornt[0];
    7221:       coneNew[1] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  9; /* DF */
    7222:       orntNew[1] = 0;
    7223:       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetQuadSubface_Static(ornt[2], 1);
    7224:       orntNew[2] = ornt[2];
    7225:       coneNew[3] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  1; /* CD */
    7226:       orntNew[3] = 0;
    7227:       coneNew[4] = fStartNew + (cone[4] - fStart)*4 + GetQuadSubface_Static(ornt[4], 0);
    7228:       orntNew[4] = ornt[4];
    7229:       coneNew[5] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  0; /* AD */
    7230:       orntNew[5] = -4;
    7231:       DMPlexSetCone(rdm, newp+3, coneNew);
    7232:       DMPlexSetConeOrientation(rdm, newp+3, orntNew);
    7233: #if defined(PETSC_USE_DEBUG)
    7234:       if ((newp+3 < cStartNew) || (newp+3 >= cMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", newp+3, cStartNew, cMaxNew);
    7235:       for (p = 0; p < 6; ++p) {
    7236:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", coneNew[p], fStartNew, fMaxNew);
    7237:       }
    7238: #endif
    7239:       /* E hex */
    7240:       coneNew[0] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  8; /* AE */
    7241:       orntNew[0] = -4;
    7242:       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], 0);
    7243:       orntNew[1] = ornt[1];
    7244:       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetQuadSubface_Static(ornt[2], 3);
    7245:       orntNew[2] = ornt[2];
    7246:       coneNew[3] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  7; /* EH */
    7247:       orntNew[3] = 0;
    7248:       coneNew[4] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  4; /* EF */
    7249:       orntNew[4] = -1;
    7250:       coneNew[5] = fStartNew + (cone[5] - fStart)*4 + GetQuadSubface_Static(ornt[5], 1);
    7251:       orntNew[5] = ornt[5];
    7252:       DMPlexSetCone(rdm, newp+4, coneNew);
    7253:       DMPlexSetConeOrientation(rdm, newp+4, orntNew);
    7254: #if defined(PETSC_USE_DEBUG)
    7255:       if ((newp+4 < cStartNew) || (newp+4 >= cMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", newp+4, cStartNew, cMaxNew);
    7256:       for (p = 0; p < 6; ++p) {
    7257:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", coneNew[p], fStartNew, fMaxNew);
    7258:       }
    7259: #endif
    7260:       /* F hex */
    7261:       coneNew[0] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  9; /* DF */
    7262:       orntNew[0] = -4;
    7263:       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], 1);
    7264:       orntNew[1] = ornt[1];
    7265:       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetQuadSubface_Static(ornt[2], 2);
    7266:       orntNew[2] = ornt[2];
    7267:       coneNew[3] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  5; /* FG */
    7268:       orntNew[3] = -1;
    7269:       coneNew[4] = fStartNew + (cone[4] - fStart)*4 + GetQuadSubface_Static(ornt[4], 3);
    7270:       orntNew[4] = ornt[4];
    7271:       coneNew[5] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  4; /* EF */
    7272:       orntNew[5] = 1;
    7273:       DMPlexSetCone(rdm, newp+5, coneNew);
    7274:       DMPlexSetConeOrientation(rdm, newp+5, orntNew);
    7275: #if defined(PETSC_USE_DEBUG)
    7276:       if ((newp+5 < cStartNew) || (newp+5 >= cMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", newp+5, cStartNew, cMaxNew);
    7277:       for (p = 0; p < 6; ++p) {
    7278:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", coneNew[p], fStartNew, fMaxNew);
    7279:       }
    7280: #endif
    7281:       /* G hex */
    7282:       coneNew[0] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 + 10; /* CG */
    7283:       orntNew[0] = -4;
    7284:       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], 2);
    7285:       orntNew[1] = ornt[1];
    7286:       coneNew[2] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  5; /* FG */
    7287:       orntNew[2] = 0;
    7288:       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetQuadSubface_Static(ornt[3], 3);
    7289:       orntNew[3] = ornt[3];
    7290:       coneNew[4] = fStartNew + (cone[4] - fStart)*4 + GetQuadSubface_Static(ornt[4], 2);
    7291:       orntNew[4] = ornt[4];
    7292:       coneNew[5] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  6; /* GH */
    7293:       orntNew[5] = -3;
    7294:       DMPlexSetCone(rdm, newp+6, coneNew);
    7295:       DMPlexSetConeOrientation(rdm, newp+6, orntNew);
    7296: #if defined(PETSC_USE_DEBUG)
    7297:       if ((newp+6 < cStartNew) || (newp+6 >= cMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", newp+6, cStartNew, cMaxNew);
    7298:       for (p = 0; p < 6; ++p) {
    7299:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", coneNew[p], fStartNew, fMaxNew);
    7300:       }
    7301: #endif
    7302:       /* H hex */
    7303:       coneNew[0] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 + 11; /* BH */
    7304:       orntNew[0] = -4;
    7305:       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], 3);
    7306:       orntNew[1] = ornt[1];
    7307:       coneNew[2] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  7; /* EH */
    7308:       orntNew[2] = -1;
    7309:       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetQuadSubface_Static(ornt[3], 2);
    7310:       orntNew[3] = ornt[3];
    7311:       coneNew[4] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  6; /* GH */
    7312:       orntNew[4] = 3;
    7313:       coneNew[5] = fStartNew + (cone[5] - fStart)*4 + GetQuadSubface_Static(ornt[5], 2);
    7314:       orntNew[5] = ornt[5];
    7315:       DMPlexSetCone(rdm, newp+7, coneNew);
    7316:       DMPlexSetConeOrientation(rdm, newp+7, orntNew);
    7317: #if defined(PETSC_USE_DEBUG)
    7318:       if ((newp+7 < cStartNew) || (newp+7 >= cMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", newp+7, cStartNew, cMaxNew);
    7319:       for (p = 0; p < 6; ++p) {
    7320:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", coneNew[p], fStartNew, fMaxNew);
    7321:       }
    7322: #endif
    7323:     }
    7324:     /* Hybrid cells have 6 faces: Front, Back, Sides */
    7325:     /*
    7326:      3---------2---------2
    7327:      |         |         |
    7328:      |    D    2    C    |
    7329:      |         |         |
    7330:      3----3----0----1----1
    7331:      |         |         |
    7332:      |    A    0    B    |
    7333:      |         |         |
    7334:      0---------0---------1
    7335:      */
    7336:     for (c = cMax; c < cEnd; ++c) {
    7337:       const PetscInt  newp = (cMax - cStart)*8 + (c - cMax)*4;
    7338:       const PetscInt *cone, *ornt, *fornt;
    7339:       PetscInt        coneNew[6], orntNew[6], o, of, i;

    7341:       DMPlexGetCone(dm, c, &cone);
    7342:       DMPlexGetConeOrientation(dm, c, &ornt);
    7343:       DMPlexGetConeOrientation(dm, cone[0], &fornt);
    7344:       o = ornt[0] < 0 ? -1 : 1;
    7345:       for (r = 0; r < 4; ++r) {
    7346:         PetscInt subfA = GetQuadSubface_Static(ornt[0], r);
    7347:         PetscInt edgeA = GetQuadEdge_Static(ornt[0], r);
    7348:         PetscInt edgeB = GetQuadEdge_Static(ornt[0], (r+3)%4);
    7349:         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]);
    7350:         coneNew[0]         = fStartNew + (cone[0] - fStart)*4 + subfA;
    7351:         orntNew[0]         = ornt[0];
    7352:         coneNew[1]         = fStartNew + (cone[1] - fStart)*4 + subfA;
    7353:         orntNew[1]         = ornt[0];
    7354:         of = fornt[edgeA] < 0 ? -1 : 1;
    7355:         i  = GetQuadEdgeInverse_Static(ornt[0], r) + 2;
    7356:         coneNew[i] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (cone[2+edgeA] - fMax)*2 + (o*of < 0 ? 1 : 0);
    7357:         orntNew[i] = ornt[edgeA];
    7358:         i  = GetQuadEdgeInverse_Static(ornt[0], (r+1)%4) + 2;
    7359:         coneNew[i] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd          - fMax)*2 + (c - cMax)*4 + edgeA;
    7360:         orntNew[i] = 0;
    7361:         i  = GetQuadEdgeInverse_Static(ornt[0], (r+2)%4) + 2;
    7362:         coneNew[i] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd          - fMax)*2 + (c - cMax)*4 + edgeB;
    7363:         orntNew[i] = -2;
    7364:         of = fornt[edgeB] < 0 ? -1 : 1;
    7365:         i  = GetQuadEdgeInverse_Static(ornt[0], (r+3)%4) + 2;
    7366:         coneNew[i] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (cone[2+edgeB] - fMax)*2 + (o*of < 0 ? 0 : 1);
    7367:         orntNew[i] = ornt[edgeB];
    7368:         DMPlexSetCone(rdm, newp+r, coneNew);
    7369:         DMPlexSetConeOrientation(rdm, newp+r, orntNew);
    7370: #if defined(PETSC_USE_DEBUG)
    7371:         if ((newp+r < cMaxNew) || (newp+r >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a hybrid cell [%D, %D)", newp+r, cMaxNew, cEndNew);
    7372:         for (p = 0; p < 2; ++p) {
    7373:           if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", coneNew[p], fStartNew, fMaxNew);
    7374:         }
    7375:         for (p = 2; p < 6; ++p) {
    7376:           if ((coneNew[p] < fMaxNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a hybrid face [%D, %D)", coneNew[p], fMaxNew, fEndNew);
    7377:         }
    7378: #endif
    7379:       }
    7380:     }
    7381:     /* Interior split faces have 4 edges and the same cells as the parent */
    7382:     DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);
    7383:     PetscMalloc1(4 + maxSupportSize*2, &supportRef);
    7384:     for (f = fStart; f < fMax; ++f) {
    7385:       for (r = 0; r < 4; ++r) {
    7386:         /* TODO: This can come from GetFaces_Internal() */
    7387:         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};
    7388:         const PetscInt  newp = fStartNew + (f - fStart)*4 + r;
    7389:         const PetscInt *cone, *ornt, *support;
    7390:         PetscInt        coneNew[4], orntNew[4], coneSize, c, supportSize, s;

    7392:         DMPlexGetCone(dm, f, &cone);
    7393:         DMPlexGetConeOrientation(dm, f, &ornt);
    7394:         coneNew[(r+3)%4] = eStartNew + (cone[(r+3)%4] - eStart)*2 + (ornt[(r+3)%4] < 0 ? 0 : 1);
    7395:         orntNew[(r+3)%4] = ornt[(r+3)%4];
    7396:         coneNew[(r+0)%4] = eStartNew + (cone[r]       - eStart)*2 + (ornt[r] < 0 ? 1 : 0);
    7397:         orntNew[(r+0)%4] = ornt[r];
    7398:         coneNew[(r+1)%4] = eStartNew + (eMax - eStart)*2 + (f - fStart)*4 + r;
    7399:         orntNew[(r+1)%4] = 0;
    7400:         coneNew[(r+2)%4] = eStartNew + (eMax - eStart)*2 + (f - fStart)*4 + (r+3)%4;
    7401:         orntNew[(r+2)%4] = -2;
    7402:         DMPlexSetCone(rdm, newp, coneNew);
    7403:         DMPlexSetConeOrientation(rdm, newp, orntNew);
    7404: #if defined(PETSC_USE_DEBUG)
    7405:         if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fMaxNew);
    7406:         for (p = 0; p < 4; ++p) {
    7407:           if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", coneNew[p], eStartNew, eMaxNew);
    7408:         }
    7409: #endif
    7410:         DMPlexGetSupportSize(dm, f, &supportSize);
    7411:         DMPlexGetSupport(dm, f, &support);
    7412:         for (s = 0; s < supportSize; ++s) {
    7413:           PetscInt subf;
    7414:           DMPlexGetConeSize(dm, support[s], &coneSize);
    7415:           DMPlexGetCone(dm, support[s], &cone);
    7416:           DMPlexGetConeOrientation(dm, support[s], &ornt);
    7417:           for (c = 0; c < coneSize; ++c) {
    7418:             if (cone[c] == f) break;
    7419:           }
    7420:           subf = GetQuadSubfaceInverse_Static(ornt[c], r);
    7421:           if (support[s] < cMax) {
    7422:             supportRef[s] = cStartNew + (support[s] - cStart)*8 + newCells[c*4+subf];
    7423:           } else {
    7424:             supportRef[s] = cStartNew + (cMax       - cStart)*8 + (support[s] - cMax)*4 + subf;
    7425:           }
    7426:         }
    7427:         DMPlexSetSupport(rdm, newp, supportRef);
    7428: #if defined(PETSC_USE_DEBUG)
    7429:         if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fMaxNew);
    7430:         for (p = 0; p < supportSize; ++p) {
    7431:           if ((supportRef[p] < cStartNew) || (supportRef[p] >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", supportRef[p], cStartNew, cEndNew);
    7432:         }
    7433: #endif
    7434:       }
    7435:     }
    7436:     /* Interior cell faces have 4 edges and 2 cells */
    7437:     for (c = cStart; c < cMax; ++c) {
    7438:       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};
    7439:       const PetscInt *cone, *ornt;
    7440:       PetscInt        newp, coneNew[4], orntNew[4], supportNew[2];

    7442:       DMPlexGetCone(dm, c, &cone);
    7443:       DMPlexGetConeOrientation(dm, c, &ornt);
    7444:       /* A-D face */
    7445:       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 0;
    7446:       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*4 + GetQuadEdge_Static(ornt[0], 3);
    7447:       orntNew[0] = 0;
    7448:       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 0;
    7449:       orntNew[1] = 0;
    7450:       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 2;
    7451:       orntNew[2] = -2;
    7452:       coneNew[3] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*4 + GetQuadEdge_Static(ornt[2], 0);
    7453:       orntNew[3] = -2;
    7454:       DMPlexSetCone(rdm, newp, coneNew);
    7455:       DMPlexSetConeOrientation(rdm, newp, orntNew);
    7456: #if defined(PETSC_USE_DEBUG)
    7457:       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fMaxNew);
    7458:       for (p = 0; p < 4; ++p) {
    7459:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", coneNew[p], eStartNew, eMaxNew);
    7460:       }
    7461: #endif
    7462:       /* C-D face */
    7463:       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 1;
    7464:       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*4 + GetQuadEdge_Static(ornt[0], 2);
    7465:       orntNew[0] = 0;
    7466:       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 0;
    7467:       orntNew[1] = 0;
    7468:       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 4;
    7469:       orntNew[2] = -2;
    7470:       coneNew[3] = eStartNew + (eMax - eStart)*2 + (cone[4] - fStart)*4 + GetQuadEdge_Static(ornt[4], 0);
    7471:       orntNew[3] = -2;
    7472:       DMPlexSetCone(rdm, newp, coneNew);
    7473:       DMPlexSetConeOrientation(rdm, newp, orntNew);
    7474: #if defined(PETSC_USE_DEBUG)
    7475:       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fMaxNew);
    7476:       for (p = 0; p < 4; ++p) {
    7477:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", coneNew[p], eStartNew, eMaxNew);
    7478:       }
    7479: #endif
    7480:       /* B-C face */
    7481:       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 2;
    7482:       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*4 + GetQuadEdge_Static(ornt[0], 1);
    7483:       orntNew[0] = -2;
    7484:       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*4 + GetQuadEdge_Static(ornt[3], 0);
    7485:       orntNew[1] = 0;
    7486:       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 3;
    7487:       orntNew[2] = 0;
    7488:       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 0;
    7489:       orntNew[3] = -2;
    7490:       DMPlexSetCone(rdm, newp, coneNew);
    7491:       DMPlexSetConeOrientation(rdm, newp, orntNew);
    7492: #if defined(PETSC_USE_DEBUG)
    7493:       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fMaxNew);
    7494:       for (p = 0; p < 4; ++p) {
    7495:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", coneNew[p], eStartNew, eMaxNew);
    7496:       }
    7497: #endif
    7498:       /* A-B face */
    7499:       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 3;
    7500:       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*4 + GetQuadEdge_Static(ornt[0], 0);
    7501:       orntNew[0] = -2;
    7502:       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[5] - fStart)*4 + GetQuadEdge_Static(ornt[5], 3);
    7503:       orntNew[1] = 0;
    7504:       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 5;
    7505:       orntNew[2] = 0;
    7506:       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 0;
    7507:       orntNew[3] = -2;
    7508:       DMPlexSetCone(rdm, newp, coneNew);
    7509:       DMPlexSetConeOrientation(rdm, newp, orntNew);
    7510: #if defined(PETSC_USE_DEBUG)
    7511:       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fMaxNew);
    7512:       for (p = 0; p < 4; ++p) {
    7513:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", coneNew[p], eStartNew, eMaxNew);
    7514:       }
    7515: #endif
    7516:       /* E-F face */
    7517:       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 4;
    7518:       coneNew[0] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 2;
    7519:       orntNew[0] = -2;
    7520:       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*4 + GetQuadEdge_Static(ornt[2], 2);
    7521:       orntNew[1] = -2;
    7522:       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*4 + GetQuadEdge_Static(ornt[1], 0);
    7523:       orntNew[2] = 0;
    7524:       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 1;
    7525:       orntNew[3] = 0;
    7526:       DMPlexSetCone(rdm, newp, coneNew);
    7527:       DMPlexSetConeOrientation(rdm, newp, orntNew);
    7528: #if defined(PETSC_USE_DEBUG)
    7529:       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fMaxNew);
    7530:       for (p = 0; p < 4; ++p) {
    7531:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", coneNew[p], eStartNew, eMaxNew);
    7532:       }
    7533: #endif
    7534:       /* F-G face */
    7535:       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 5;
    7536:       coneNew[0] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 4;
    7537:       orntNew[0] = -2;
    7538:       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[4] - fStart)*4 + GetQuadEdge_Static(ornt[4], 2);
    7539:       orntNew[1] = -2;
    7540:       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*4 + GetQuadEdge_Static(ornt[1], 1);
    7541:       orntNew[2] = 0;
    7542:       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 1;
    7543:       orntNew[3] = 0;
    7544:       DMPlexSetCone(rdm, newp, coneNew);
    7545:       DMPlexSetConeOrientation(rdm, newp, orntNew);
    7546: #if defined(PETSC_USE_DEBUG)
    7547:       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fMaxNew);
    7548:       for (p = 0; p < 4; ++p) {
    7549:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", coneNew[p], eStartNew, eMaxNew);
    7550:       }
    7551: #endif
    7552:       /* G-H face */
    7553:       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 6;
    7554:       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*4 + GetQuadEdge_Static(ornt[3], 2);
    7555:       orntNew[0] = -2;
    7556:       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*4 + GetQuadEdge_Static(ornt[1], 2);
    7557:       orntNew[1] = 0;
    7558:       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 1;
    7559:       orntNew[2] = 0;
    7560:       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 3;
    7561:       orntNew[3] = -2;
    7562:       DMPlexSetCone(rdm, newp, coneNew);
    7563:       DMPlexSetConeOrientation(rdm, newp, orntNew);
    7564: #if defined(PETSC_USE_DEBUG)
    7565:       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fMaxNew);
    7566:       for (p = 0; p < 4; ++p) {
    7567:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", coneNew[p], eStartNew, eMaxNew);
    7568:       }
    7569: #endif
    7570:       /* E-H face */
    7571:       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 7;
    7572:       coneNew[0] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 5;
    7573:       orntNew[0] = -2;
    7574:       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[5] - fStart)*4 + GetQuadEdge_Static(ornt[5], 1);
    7575:       orntNew[1] = -2;
    7576:       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*4 + GetQuadEdge_Static(ornt[1], 3);
    7577:       orntNew[2] = 0;
    7578:       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 1;
    7579:       orntNew[3] = 0;
    7580:       DMPlexSetCone(rdm, newp, coneNew);
    7581:       DMPlexSetConeOrientation(rdm, newp, orntNew);
    7582: #if defined(PETSC_USE_DEBUG)
    7583:       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fMaxNew);
    7584:       for (p = 0; p < 4; ++p) {
    7585:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", coneNew[p], eStartNew, eMaxNew);
    7586:       }
    7587: #endif
    7588:       /* A-E face */
    7589:       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 8;
    7590:       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*4 + GetQuadEdge_Static(ornt[2], 3);
    7591:       orntNew[0] = 0;
    7592:       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 2;
    7593:       orntNew[1] = 0;
    7594:       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 5;
    7595:       orntNew[2] = -2;
    7596:       coneNew[3] = eStartNew + (eMax - eStart)*2 + (cone[5] - fStart)*4 + GetQuadEdge_Static(ornt[5], 0);
    7597:       orntNew[3] = -2;
    7598:       DMPlexSetCone(rdm, newp, coneNew);
    7599:       DMPlexSetConeOrientation(rdm, newp, orntNew);
    7600: #if defined(PETSC_USE_DEBUG)
    7601:       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fMaxNew);
    7602:       for (p = 0; p < 4; ++p) {
    7603:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", coneNew[p], eStartNew, eMaxNew);
    7604:       }
    7605: #endif
    7606:       /* D-F face */
    7607:       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 9;
    7608:       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*4 + GetQuadEdge_Static(ornt[2], 1);
    7609:       orntNew[0] = -2;
    7610:       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[4] - fStart)*4 + GetQuadEdge_Static(ornt[4], 3);
    7611:       orntNew[1] = 0;
    7612:       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 4;
    7613:       orntNew[2] = 0;
    7614:       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 2;
    7615:       orntNew[3] = -2;
    7616:       DMPlexSetCone(rdm, newp, coneNew);
    7617:       DMPlexSetConeOrientation(rdm, newp, orntNew);
    7618: #if defined(PETSC_USE_DEBUG)
    7619:       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fMaxNew);
    7620:       for (p = 0; p < 4; ++p) {
    7621:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", coneNew[p], eStartNew, eMaxNew);
    7622:       }
    7623: #endif
    7624:       /* C-G face */
    7625:       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 10;
    7626:       coneNew[0] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 4;
    7627:       orntNew[0] = -2;
    7628:       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[4] - fStart)*4 + GetQuadEdge_Static(ornt[4], 1);
    7629:       orntNew[1] = -2;
    7630:       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*4 + GetQuadEdge_Static(ornt[3], 3);
    7631:       orntNew[2] = 0;
    7632:       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 3;
    7633:       orntNew[3] = 0;
    7634:       DMPlexSetCone(rdm, newp, coneNew);
    7635:       DMPlexSetConeOrientation(rdm, newp, orntNew);
    7636: #if defined(PETSC_USE_DEBUG)
    7637:       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fMaxNew);
    7638:       for (p = 0; p < 4; ++p) {
    7639:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", coneNew[p], eStartNew, eMaxNew);
    7640:       }
    7641: #endif
    7642:       /* B-H face */
    7643:       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 11;
    7644:       coneNew[0] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 5;
    7645:       orntNew[0] = 0;
    7646:       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 3;
    7647:       orntNew[1] = -2;
    7648:       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*4 + GetQuadEdge_Static(ornt[3], 1);
    7649:       orntNew[2] = -2;
    7650:       coneNew[3] = eStartNew + (eMax - eStart)*2 + (cone[5] - fStart)*4 + GetQuadEdge_Static(ornt[5], 2);
    7651:       orntNew[3] = 0;
    7652:       DMPlexSetCone(rdm, newp, coneNew);
    7653:       DMPlexSetConeOrientation(rdm, newp, orntNew);
    7654: #if defined(PETSC_USE_DEBUG)
    7655:       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fMaxNew);
    7656:       for (p = 0; p < 4; ++p) {
    7657:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", coneNew[p], eStartNew, eMaxNew);
    7658:       }
    7659: #endif
    7660:       for (r = 0; r < 12; ++r) {
    7661:         newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + r;
    7662:         supportNew[0] = cStartNew + (c - cStart)*8 + newCells[r*2+0];
    7663:         supportNew[1] = cStartNew + (c - cStart)*8 + newCells[r*2+1];
    7664:         DMPlexSetSupport(rdm, newp, supportNew);
    7665: #if defined(PETSC_USE_DEBUG)
    7666:         if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fMaxNew);
    7667:         for (p = 0; p < 2; ++p) {
    7668:           if ((supportNew[p] < cStartNew) || (supportNew[p] >= cMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", supportNew[p], cStartNew, cMaxNew);
    7669:         }
    7670: #endif
    7671:       }
    7672:     }
    7673:     /* Hybrid split faces have 4 edges and same cells */
    7674:     for (f = fMax; f < fEnd; ++f) {
    7675:       const PetscInt *cone, *ornt, *support;
    7676:       PetscInt        coneNew[4], orntNew[4];
    7677:       PetscInt        supportNew[2], size, s, c;

    7679:       DMPlexGetCone(dm, f, &cone);
    7680:       DMPlexGetConeOrientation(dm, f, &ornt);
    7681:       DMPlexGetSupportSize(dm, f, &size);
    7682:       DMPlexGetSupport(dm, f, &support);
    7683:       for (r = 0; r < 2; ++r) {
    7684:         const PetscInt newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (f - fMax)*2 + r;

    7686:         coneNew[0]   = eStartNew + (cone[0] - eStart)*2 + (ornt[0] < 0 ? 1-r : r);
    7687:         orntNew[0]   = ornt[0];
    7688:         coneNew[1]   = eStartNew + (cone[1] - eStart)*2 + (ornt[1] < 0 ? 1-r : r);
    7689:         orntNew[1]   = ornt[1];
    7690:         coneNew[2+r] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (cone[2+r] - eMax);
    7691:         orntNew[2+r] = 0;
    7692:         coneNew[3-r] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (eEnd      - eMax) + (f - fMax);
    7693:         orntNew[3-r] = 0;
    7694:         DMPlexSetCone(rdm, newp, coneNew);
    7695:         DMPlexSetConeOrientation(rdm, newp, orntNew);
    7696: #if defined(PETSC_USE_DEBUG)
    7697:         if ((newp < fMaxNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a hybrid face [%D, %D)", newp, fMaxNew, fEndNew);
    7698:         for (p = 0; p < 2; ++p) {
    7699:           if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", coneNew[p], eStartNew, eMaxNew);
    7700:         }
    7701:         for (p = 2; p < 4; ++p) {
    7702:           if ((coneNew[p] < eMaxNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a hybrid edge [%D, %D)", coneNew[p], eMaxNew, eEndNew);
    7703:         }
    7704: #endif
    7705:         for (s = 0; s < size; ++s) {
    7706:           const PetscInt *coneCell, *orntCell, *fornt;
    7707:           PetscInt        o, of;

    7709:           DMPlexGetCone(dm, support[s], &coneCell);
    7710:           DMPlexGetConeOrientation(dm, support[s], &orntCell);
    7711:           o = orntCell[0] < 0 ? -1 : 1;
    7712:           for (c = 2; c < 6; ++c) if (coneCell[c] == f) break;
    7713:           if (c >= 6) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Could not find face %D in cone of cell %D", f, support[s]);
    7714:           DMPlexGetConeOrientation(dm, coneCell[0], &fornt);
    7715:           of = fornt[c-2] < 0 ? -1 : 1;
    7716:           supportNew[s] = cStartNew + (cMax - cStart)*8 + (support[s] - cMax)*4 + (GetQuadEdgeInverse_Static(orntCell[0], c-2) + (o*of < 0 ? 1-r : r))%4;
    7717:         }
    7718:         DMPlexSetSupport(rdm, newp, supportNew);
    7719: #if defined(PETSC_USE_DEBUG)
    7720:         if ((newp < fMaxNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a hybrid face [%D, %D)", newp, fMaxNew, fEndNew);
    7721:         for (p = 0; p < size; ++p) {
    7722:           if ((supportNew[p] < cMaxNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a hybrid cell [%D, %D)", supportNew[p], cMaxNew, cEndNew);
    7723:         }
    7724: #endif
    7725:       }
    7726:     }
    7727:     /* Hybrid cell faces have 4 edges and 2 cells */
    7728:     for (c = cMax; c < cEnd; ++c) {
    7729:       PetscInt        newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd - fMax)*2 + (c - cMax)*4;
    7730:       const PetscInt *cone, *ornt;
    7731:       PetscInt        coneNew[4], orntNew[4];
    7732:       PetscInt        supportNew[2];

    7734:       DMPlexGetCone(dm, c, &cone);
    7735:       DMPlexGetConeOrientation(dm, c, &ornt);
    7736:       for (r = 0; r < 4; ++r) {
    7737: #if 0
    7738:         coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], r);
    7739:         orntNew[0] = 0;
    7740:         coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], r);
    7741:         orntNew[1] = 0;
    7742:         coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (eEnd - eMax) + (cone[2+GetQuadEdge_Static(ornt[0], r)] - fMax);
    7743:         orntNew[2] = 0;
    7744:         coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (eEnd - eMax) + (fEnd                                   - fMax) + (c - cMax);
    7745:         orntNew[3] = 0;
    7746: #else
    7747:         coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*4 + r;
    7748:         orntNew[0] = 0;
    7749:         coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*4 + r;
    7750:         orntNew[1] = 0;
    7751:         coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (eEnd - eMax) + (cone[2+r] - fMax);
    7752:         orntNew[2] = 0;
    7753:         coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (eEnd - eMax) + (fEnd      - fMax) + (c - cMax);
    7754:         orntNew[3] = 0;
    7755: #endif
    7756:         DMPlexSetCone(rdm, newp+r, coneNew);
    7757:         DMPlexSetConeOrientation(rdm, newp+r, orntNew);
    7758: #if defined(PETSC_USE_DEBUG)
    7759:         if ((newp+r < fMaxNew) || (newp+r >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a hybrid face [%D, %D)", newp+r, fMaxNew, fEndNew);
    7760:         for (p = 0; p < 2; ++p) {
    7761:           if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", coneNew[p], eStartNew, eMaxNew);
    7762:         }
    7763:         for (p = 2; p < 4; ++p) {
    7764:           if ((coneNew[p] < eMaxNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a hybrid edge [%D, %D)", coneNew[p], eMaxNew, eEndNew);
    7765:         }
    7766: #endif
    7767:         supportNew[0] = cStartNew + (cMax - cStart)*8 + (c - cMax)*4 + GetQuadSubface_Static(ornt[0], r);
    7768:         supportNew[1] = cStartNew + (cMax - cStart)*8 + (c - cMax)*4 + GetQuadSubface_Static(ornt[0], (r+1)%4);
    7769:         DMPlexSetSupport(rdm, newp+r, supportNew);
    7770: #if defined(PETSC_USE_DEBUG)
    7771:         if ((newp+r < fMaxNew) || (newp+r >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a hybrid face [%D, %D)", newp+r, fMaxNew, fEndNew);
    7772:         for (p = 0; p < 2; ++p) {
    7773:           if ((supportNew[p] < cMaxNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a hybrid cell [%D, %D)", supportNew[p], cMaxNew, cEndNew);
    7774:         }
    7775: #endif
    7776:       }
    7777:     }
    7778:     /* Interior split edges have 2 vertices and the same faces as the parent */
    7779:     DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);
    7780:     for (e = eStart; e < eMax; ++e) {
    7781:       const PetscInt newv = vStartNew + (vEnd - vStart) + (e - eStart);

    7783:       for (r = 0; r < 2; ++r) {
    7784:         const PetscInt  newp = eStartNew + (e - eStart)*2 + r;
    7785:         const PetscInt *cone, *ornt, *support;
    7786:         PetscInt        coneNew[2], coneSize, c, supportSize, s;

    7788:         DMPlexGetCone(dm, e, &cone);
    7789:         coneNew[0]       = vStartNew + (cone[0] - vStart);
    7790:         coneNew[1]       = vStartNew + (cone[1] - vStart);
    7791:         coneNew[(r+1)%2] = newv;
    7792:         DMPlexSetCone(rdm, newp, coneNew);
    7793: #if defined(PETSC_USE_DEBUG)
    7794:         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eMaxNew);
    7795:         for (p = 0; p < 2; ++p) {
    7796:           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", coneNew[p], vStartNew, vEndNew);
    7797:         }
    7798: #endif
    7799:         DMPlexGetSupportSize(dm, e, &supportSize);
    7800:         DMPlexGetSupport(dm, e, &support);
    7801:         for (s = 0; s < supportSize; ++s) {
    7802:           DMPlexGetConeSize(dm, support[s], &coneSize);
    7803:           DMPlexGetCone(dm, support[s], &cone);
    7804:           DMPlexGetConeOrientation(dm, support[s], &ornt);
    7805:           for (c = 0; c < coneSize; ++c) {
    7806:             if (cone[c] == e) break;
    7807:           }
    7808:           if (support[s] < fMax) {
    7809:             supportRef[s] = fStartNew + (support[s] - fStart)*4 + (c + (ornt[c] < 0 ? 1-r : r))%4;
    7810:           } else {
    7811:             supportRef[s] = fStartNew + (fMax       - fStart)*4 + (cMax - cStart)*12 + (support[s] - fMax)*2 + (ornt[c] < 0 ? 1-r : r);
    7812:           }
    7813:         }
    7814:         DMPlexSetSupport(rdm, newp, supportRef);
    7815: #if defined(PETSC_USE_DEBUG)
    7816:         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eMaxNew);
    7817:         for (p = 0; p < supportSize; ++p) {
    7818:           if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", supportRef[p], fStartNew, fEndNew);
    7819:         }
    7820: #endif
    7821:       }
    7822:     }
    7823:     /* Interior face edges have 2 vertices and 2+cells faces */
    7824:     for (f = fStart; f < fMax; ++f) {
    7825:       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};
    7826:       const PetscInt  newv = vStartNew + (vEnd - vStart) + (eMax - eStart) + (f - fStart);
    7827:       const PetscInt *cone, *coneCell, *orntCell, *support;
    7828:       PetscInt        coneNew[2], coneSize, c, supportSize, s;

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

    7834:         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r] - eStart);
    7835:         coneNew[1] = newv;
    7836:         DMPlexSetCone(rdm, newp, coneNew);
    7837: #if defined(PETSC_USE_DEBUG)
    7838:         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eMaxNew);
    7839:         for (p = 0; p < 2; ++p) {
    7840:           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", coneNew[p], vStartNew, vEndNew);
    7841:         }
    7842: #endif
    7843:         DMPlexGetSupportSize(dm, f, &supportSize);
    7844:         DMPlexGetSupport(dm, f, &support);
    7845:         supportRef[0] = fStartNew + (f - fStart)*4 + r;
    7846:         supportRef[1] = fStartNew + (f - fStart)*4 + (r+1)%4;
    7847:         for (s = 0; s < supportSize; ++s) {
    7848:           DMPlexGetConeSize(dm, support[s], &coneSize);
    7849:           DMPlexGetCone(dm, support[s], &coneCell);
    7850:           DMPlexGetConeOrientation(dm, support[s], &orntCell);
    7851:           for (c = 0; c < coneSize; ++c) if (coneCell[c] == f) break;
    7852:           if (support[s] < cMax) {
    7853:             supportRef[2+s] = fStartNew + (fMax - fStart)*4 + (support[s] - cStart)*12 + newFaces[c*4 + GetQuadEdgeInverse_Static(orntCell[c], r)];
    7854:           } else {
    7855:             supportRef[2+s] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd - fMax)*2 + (support[s] - cMax)*4 + r;
    7856:           }
    7857:         }
    7858:         DMPlexSetSupport(rdm, newp, supportRef);
    7859: #if defined(PETSC_USE_DEBUG)
    7860:         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eMaxNew);
    7861:         for (p = 0; p < 2+supportSize; ++p) {
    7862:           if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", supportRef[p], fStartNew, fEndNew);
    7863:         }
    7864: #endif
    7865:       }
    7866:     }
    7867:     /* Interior cell edges have 2 vertices and 4 faces */
    7868:     for (c = cStart; c < cMax; ++c) {
    7869:       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};
    7870:       const PetscInt  newv = vStartNew + (vEnd - vStart) + (eMax - eStart) + (fMax - fStart) + (c - cStart);
    7871:       const PetscInt *cone;
    7872:       PetscInt        coneNew[2], supportNew[4];

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

    7878:         coneNew[0] = vStartNew + (vEnd - vStart) + (eMax - eStart) + (cone[r] - fStart);
    7879:         coneNew[1] = newv;
    7880:         DMPlexSetCone(rdm, newp, coneNew);
    7881: #if defined(PETSC_USE_DEBUG)
    7882:         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eMaxNew);
    7883:         for (p = 0; p < 2; ++p) {
    7884:           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", coneNew[p], vStartNew, vEndNew);
    7885:         }
    7886: #endif
    7887:         for (f = 0; f < 4; ++f) supportNew[f] = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + newFaces[r*4+f];
    7888:         DMPlexSetSupport(rdm, newp, supportNew);
    7889: #if defined(PETSC_USE_DEBUG)
    7890:         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eMaxNew);
    7891:         for (p = 0; p < 4; ++p) {
    7892:           if ((supportNew[p] < fStartNew) || (supportNew[p] >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", supportNew[p], fStartNew, fMaxNew);
    7893:         }
    7894: #endif
    7895:       }
    7896:     }
    7897:     /* Hybrid edges have two vertices and the same faces */
    7898:     for (e = eMax; e < eEnd; ++e) {
    7899:       const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (e - eMax);
    7900:       const PetscInt *cone, *support, *fcone;
    7901:       PetscInt        coneNew[2], size, fsize, s;

    7903:       DMPlexGetCone(dm, e, &cone);
    7904:       DMPlexGetSupportSize(dm, e, &size);
    7905:       DMPlexGetSupport(dm, e, &support);
    7906:       coneNew[0] = vStartNew + (cone[0] - vStart);
    7907:       coneNew[1] = vStartNew + (cone[1] - vStart);
    7908:       DMPlexSetCone(rdm, newp, coneNew);
    7909: #if defined(PETSC_USE_DEBUG)
    7910:       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a hybrid edge [%D, %D)", newp, eMaxNew, eEndNew);
    7911:       for (p = 0; p < 2; ++p) {
    7912:         if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", coneNew[p], vStartNew, vEndNew);
    7913:       }
    7914: #endif
    7915:       for (s = 0; s < size; ++s) {
    7916:         DMPlexGetConeSize(dm, support[s], &fsize);
    7917:         DMPlexGetCone(dm, support[s], &fcone);
    7918:         for (c = 0; c < fsize; ++c) if (fcone[c] == e) break;
    7919:         if ((c < 2) || (c > 3)) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Edge %D not found in cone of face %D", e, support[s]);
    7920:         supportRef[s] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (support[s] - fMax)*2 + c-2;
    7921:       }
    7922:       DMPlexSetSupport(rdm, newp, supportRef);
    7923: #if defined(PETSC_USE_DEBUG)
    7924:       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a hybrid edge [%D, %D)", newp, eMaxNew, eEndNew);
    7925:       for (p = 0; p < size; ++p) {
    7926:         if ((supportRef[p] < fMaxNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a hybrid face [%D, %D)", supportRef[p], fMaxNew, fEndNew);
    7927:       }
    7928: #endif
    7929:     }
    7930:     /* Hybrid face edges have 2 vertices and 2+cells faces */
    7931:     for (f = fMax; f < fEnd; ++f) {
    7932:       const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (eEnd - eMax) + (f - fMax);
    7933:       const PetscInt *cone, *support, *ccone, *cornt;
    7934:       PetscInt        coneNew[2], size, csize, s;

    7936:       DMPlexGetCone(dm, f, &cone);
    7937:       DMPlexGetSupportSize(dm, f, &size);
    7938:       DMPlexGetSupport(dm, f, &support);
    7939:       coneNew[0] = vStartNew + (vEnd - vStart) + (cone[0] - eStart);
    7940:       coneNew[1] = vStartNew + (vEnd - vStart) + (cone[1] - eStart);
    7941:       DMPlexSetCone(rdm, newp, coneNew);
    7942: #if defined(PETSC_USE_DEBUG)
    7943:       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a hybrid edge [%D, %D)", newp, eMaxNew, eEndNew);
    7944:       for (p = 0; p < 2; ++p) {
    7945:         if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", coneNew[p], vStartNew, vEndNew);
    7946:       }
    7947: #endif
    7948:       supportRef[0] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (f - fMax)*2 + 0;
    7949:       supportRef[1] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (f - fMax)*2 + 1;
    7950:       for (s = 0; s < size; ++s) {
    7951:         DMPlexGetConeSize(dm, support[s], &csize);
    7952:         DMPlexGetCone(dm, support[s], &ccone);
    7953:         DMPlexGetConeOrientation(dm, support[s], &cornt);
    7954:         for (c = 0; c < csize; ++c) if (ccone[c] == f) break;
    7955:         if ((c < 2) || (c >= csize)) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Hybrid face %D is not in cone of hybrid cell %D", f, support[s]);
    7956:         supportRef[2+s] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd - fMax)*2 + (support[s] - cMax)*4 + c-2;
    7957:       }
    7958:       DMPlexSetSupport(rdm, newp, supportRef);
    7959: #if defined(PETSC_USE_DEBUG)
    7960:       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a hybrid edge [%D, %D)", newp, eMaxNew, eEndNew);
    7961:       for (p = 0; p < 2+size; ++p) {
    7962:         if ((supportRef[p] < fMaxNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a hybrid face [%D, %D)", supportRef[p], fMaxNew, fEndNew);
    7963:       }
    7964: #endif
    7965:     }
    7966:     /* Hybrid cell edges have 2 vertices and 4 faces */
    7967:     for (c = cMax; c < cEnd; ++c) {
    7968:       const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (eEnd - eMax) + (fEnd - fMax) + (c - cMax);
    7969:       const PetscInt *cone, *support;
    7970:       PetscInt        coneNew[2], size;

    7972:       DMPlexGetCone(dm, c, &cone);
    7973:       DMPlexGetSupportSize(dm, c, &size);
    7974:       DMPlexGetSupport(dm, c, &support);
    7975:       coneNew[0] = vStartNew + (vEnd - vStart) + (eMax - eStart) + (cone[0] - fStart);
    7976:       coneNew[1] = vStartNew + (vEnd - vStart) + (eMax - eStart) + (cone[1] - fStart);
    7977:       DMPlexSetCone(rdm, newp, coneNew);
    7978: #if defined(PETSC_USE_DEBUG)
    7979:       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a hybrid edge [%D, %D)", newp, eMaxNew, eEndNew);
    7980:       for (p = 0; p < 2; ++p) {
    7981:         if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", coneNew[p], vStartNew, vEndNew);
    7982:       }
    7983: #endif
    7984:       supportRef[0] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd - fMax)*2 + (c - cMax)*4 + 0;
    7985:       supportRef[1] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd - fMax)*2 + (c - cMax)*4 + 1;
    7986:       supportRef[2] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd - fMax)*2 + (c - cMax)*4 + 2;
    7987:       supportRef[3] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd - fMax)*2 + (c - cMax)*4 + 3;
    7988:       DMPlexSetSupport(rdm, newp, supportRef);
    7989: #if defined(PETSC_USE_DEBUG)
    7990:       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a hybrid edge [%D, %D)", newp, eMaxNew, eEndNew);
    7991:       for (p = 0; p < 4; ++p) {
    7992:         if ((supportRef[p] < fMaxNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a hybrid face [%D, %D)", supportRef[p], fMaxNew, fEndNew);
    7993:       }
    7994: #endif
    7995:     }
    7996:     /* Interior vertices have identical supports */
    7997:     for (v = vStart; v < vEnd; ++v) {
    7998:       const PetscInt  newp = vStartNew + (v - vStart);
    7999:       const PetscInt *support, *cone;
    8000:       PetscInt        size, s;

    8002:       DMPlexGetSupportSize(dm, v, &size);
    8003:       DMPlexGetSupport(dm, v, &support);
    8004:       for (s = 0; s < size; ++s) {
    8005:         PetscInt r = 0;

    8007:         DMPlexGetCone(dm, support[s], &cone);
    8008:         if (cone[1] == v) r = 1;
    8009:         if (support[s] < eMax) supportRef[s] = eStartNew + (support[s] - eStart)*2 + r;
    8010:         else                   supportRef[s] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (support[s] - eMax);
    8011:       }
    8012:       DMPlexSetSupport(rdm, newp, supportRef);
    8013: #if defined(PETSC_USE_DEBUG)
    8014:       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", newp, vStartNew, vEndNew);
    8015:       for (p = 0; p < size; ++p) {
    8016:         if ((supportRef[p] < eStartNew) || (supportRef[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", supportRef[p], eStartNew, eEndNew);
    8017:       }
    8018: #endif
    8019:     }
    8020:     /* Interior edge vertices have 2 + faces supports */
    8021:     for (e = eStart; e < eMax; ++e) {
    8022:       const PetscInt  newp = vStartNew + (vEnd - vStart) + (e - eStart);
    8023:       const PetscInt *cone, *support;
    8024:       PetscInt        size, s;

    8026:       DMPlexGetSupportSize(dm, e, &size);
    8027:       DMPlexGetSupport(dm, e, &support);
    8028:       supportRef[0] = eStartNew + (e - eStart)*2 + 0;
    8029:       supportRef[1] = eStartNew + (e - eStart)*2 + 1;
    8030:       for (s = 0; s < size; ++s) {
    8031:         PetscInt r;

    8033:         DMPlexGetCone(dm, support[s], &cone);
    8034:         for (r = 0; r < 4; ++r) if (cone[r] == e) break;
    8035:         if (support[s] < fMax) {
    8036:           supportRef[2+s] = eStartNew + (eMax - eStart)*2 + (support[s] - fStart)*4 + r;
    8037:         } else {
    8038:           supportRef[2+s] = eStartNew + (eMax - eStart)*2 + (fMax       - fStart)*4 + (cMax - cStart)*6 + (eEnd - eMax) + (support[s] - fMax);
    8039:         }
    8040:       }
    8041:       DMPlexSetSupport(rdm, newp, supportRef);
    8042: #if defined(PETSC_USE_DEBUG)
    8043:       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", newp, vStartNew, vEndNew);
    8044:       for (p = 0; p < 2+size; ++p) {
    8045:         if ((supportRef[p] < eStartNew) || (supportRef[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", supportRef[p], eStartNew, eEndNew);
    8046:       }
    8047: #endif
    8048:     }
    8049:     /* Interior face vertices have 4 + cells supports */
    8050:     for (f = fStart; f < fMax; ++f) {
    8051:       const PetscInt  newp = vStartNew + (vEnd - vStart) + (eMax - eStart) + (f - fStart);
    8052:       const PetscInt *cone, *support;
    8053:       PetscInt        size, s;

    8055:       DMPlexGetSupportSize(dm, f, &size);
    8056:       DMPlexGetSupport(dm, f, &support);
    8057:       for (r = 0; r < 4; ++r) supportRef[r] = eStartNew + (eMax - eStart)*2 +  (f - fStart)*4 + r;
    8058:       for (s = 0; s < size; ++s) {
    8059:         PetscInt r;

    8061:         DMPlexGetCone(dm, support[s], &cone);
    8062:         for (r = 0; r < 6; ++r) if (cone[r] == f) break;
    8063:         if (support[s] < cMax) {
    8064:           supportRef[4+s] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (support[s] - cStart)*6 + r;
    8065:         } else {
    8066:           supportRef[4+s] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax       - cStart)*6 + (eEnd - eMax) + (fEnd - fMax) + (support[s] - cMax);
    8067:         }
    8068:       }
    8069:       DMPlexSetSupport(rdm, newp, supportRef);
    8070: #if defined(PETSC_USE_DEBUG)
    8071:       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", newp, vStartNew, vEndNew);
    8072:       for (p = 0; p < 4+size; ++p) {
    8073:         if ((supportRef[p] < eStartNew) || (supportRef[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", supportRef[p], eStartNew, eEndNew);
    8074:       }
    8075: #endif
    8076:     }
    8077:     /* Cell vertices have 6 supports */
    8078:     for (c = cStart; c < cMax; ++c) {
    8079:       const PetscInt newp = vStartNew + (vEnd - vStart) + (eMax - eStart) + (fMax - fStart) + (c - cStart);
    8080:       PetscInt       supportNew[6];

    8082:       for (r = 0; r < 6; ++r) {
    8083:         supportNew[r] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (c - cStart)*6 + r;
    8084:       }
    8085:       DMPlexSetSupport(rdm, newp, supportNew);
    8086:     }
    8087:     PetscFree(supportRef);
    8088:     break;
    8089:   default:
    8090:     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %D", refiner);
    8091:   }
    8092:   return(0);
    8093: }

    8095: static PetscErrorCode CellRefinerSetCoordinates(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
    8096: {
    8097:   PetscSection          coordSection, coordSectionNew;
    8098:   Vec                   coordinates, coordinatesNew;
    8099:   PetscScalar          *coords, *coordsNew;
    8100:   const PetscInt        numVertices = depthSize ? depthSize[0] : 0;
    8101:   PetscInt              dim, spaceDim, depth, bs, coordSizeNew, cStart, cEnd, cMax;
    8102:   PetscInt              c, vStart, vStartNew, vEnd, v, eStart, eEnd, eMax, e, fStart, fEnd, fMax, f;
    8103:   PetscInt              cStartNew, cEndNew, vEndNew, *parentId = NULL;
    8104:   VecType               vtype;
    8105:   PetscBool             isperiodic, localize = PETSC_FALSE, needcoords = PETSC_FALSE;
    8106:   const PetscReal      *maxCell, *L;
    8107:   const DMBoundaryType *bd;
    8108:   PetscErrorCode        ierr;

    8111:   DMGetDimension(dm, &dim);
    8112:   DMPlexGetDepth(dm, &depth);
    8113:   DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);
    8114:   DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);
    8115:   DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);
    8116:   DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);
    8117:   DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, NULL);
    8118:   if (cMax < 0) cMax = cEnd;
    8119:   if (fMax < 0) fMax = fEnd;
    8120:   if (eMax < 0) eMax = eEnd;
    8121:   GetDepthStart_Private(depth, depthSize, &cStartNew, NULL, NULL, &vStartNew);
    8122:   GetDepthEnd_Private(depth, depthSize, &cEndNew, NULL, NULL, &vEndNew);
    8123:   DMGetPeriodicity(dm, &isperiodic, &maxCell, &L, &bd);
    8124:   /* Determine if we need to localize coordinates when generating them */
    8125:   if (isperiodic && !maxCell) {
    8126:     DMGetCoordinatesLocalized(dm, &localize);
    8127:     if (!localize) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_USER,"Cannot refine if coordinates have not been localized");
    8128:   }
    8129:   if (isperiodic) {
    8130:     PetscOptionsBegin(PetscObjectComm((PetscObject)dm),((PetscObject)dm)->prefix,"DMPlex coords refinement options","DM");
    8131:     PetscOptionsBool("-dm_plex_refine_localize","Automatically localize from parent cells",NULL,localize,&localize,NULL);
    8132:     PetscOptionsEnd();
    8133:     if (localize) {
    8134:       DMLocalizeCoordinates(dm);
    8135:     }
    8136:   }
    8137:   DMSetPeriodicity(rdm, isperiodic,  maxCell,  L,  bd);

    8139:   DMGetCoordinateSection(dm, &coordSection);
    8140:   PetscSectionGetFieldComponents(coordSection, 0, &spaceDim);
    8141:   PetscSectionCreate(PetscObjectComm((PetscObject)dm), &coordSectionNew);
    8142:   PetscSectionSetNumFields(coordSectionNew, 1);
    8143:   PetscSectionSetFieldComponents(coordSectionNew, 0, spaceDim);

    8145:   if (localize) {
    8146:     PetscInt p, r, newp, *pi;

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

    8151:     /* We need the parentId to properly localize coordinates */
    8152:     PetscMalloc1(cEndNew-cStartNew,&pi);
    8153:     switch (refiner) {
    8154:     case REFINER_NOOP:
    8155:       break;
    8156:     case REFINER_SIMPLEX_1D:
    8157:       for (p = cStart; p < cEnd; ++p) {
    8158:         for (r = 0; r < 2; ++r) {
    8159:           newp     = (p - cStart)*2 + r;
    8160:           pi[newp] = p;
    8161:         }
    8162:       }
    8163:       break;
    8164:     case REFINER_SIMPLEX_2D:
    8165:       for (p = cStart; p < cEnd; ++p) {
    8166:         for (r = 0; r < 4; ++r) {
    8167:           newp     = (p - cStart)*4 + r;
    8168:           pi[newp] = p;
    8169:         }
    8170:       }
    8171:       break;
    8172:     case REFINER_HEX_2D:
    8173:       for (p = cStart; p < cEnd; ++p) {
    8174:         for (r = 0; r < 4; ++r) {
    8175:           newp     = (p - cStart)*4 + r;
    8176:           pi[newp] = p;
    8177:         }
    8178:       }
    8179:       break;
    8180:     case REFINER_SIMPLEX_TO_HEX_2D:
    8181:       for (p = cStart; p < cEnd; ++p) {
    8182:         for (r = 0; r < 3; ++r) {
    8183:           newp     = (p - cStart)*3 + r;
    8184:           pi[newp] = p;
    8185:         }
    8186:       }
    8187:       break;
    8188:     case REFINER_HYBRID_SIMPLEX_TO_HEX_2D:
    8189:       for (p = cStart; p < cMax; ++p) {
    8190:         for (r = 0; r < 3; ++r) {
    8191:           newp     = (p - cStart)*3 + r;
    8192:           pi[newp] = p;
    8193:         }
    8194:       }
    8195:       for (p = cMax; p < cEnd; ++p) {
    8196:         for (r = 0; r < 4; ++r) {
    8197:           newp     = (cMax - cStart)*3 + (p - cMax)*4 + r;
    8198:           pi[newp] = p;
    8199:         }
    8200:       }
    8201:       /* The refiner needs midpoint vertices on hybrid edges and hybrid cells */
    8202:       cMax = cEnd;
    8203:       eMax = eEnd;
    8204:       break;
    8205:     case REFINER_HYBRID_SIMPLEX_2D:
    8206:       for (p = cStart; p < cMax; ++p) {
    8207:         for (r = 0; r < 4; ++r) {
    8208:           newp     = (p - cStart)*4 + r;
    8209:           pi[newp] = p;
    8210:         }
    8211:       }
    8212:       for (p = cMax; p < cEnd; ++p) {
    8213:         for (r = 0; r < 2; ++r) {
    8214:           newp     = (cMax - cStart)*4 + (p - cMax)*2 + r;
    8215:           pi[newp] = p;
    8216:         }
    8217:       }
    8218:       break;
    8219:     case REFINER_HYBRID_HEX_2D:
    8220:       for (p = cStart; p < cMax; ++p) {
    8221:         for (r = 0; r < 4; ++r) {
    8222:           newp     = (p - cStart)*4 + r;
    8223:           pi[newp] = p;
    8224:         }
    8225:       }
    8226:       for (p = cMax; p < cEnd; ++p) {
    8227:         for (r = 0; r < 2; ++r) {
    8228:           newp     = (cMax - cStart)*4 + (p - cMax)*2 + r;
    8229:           pi[newp] = p;
    8230:         }
    8231:       }
    8232:       break;
    8233:     case REFINER_SIMPLEX_3D:
    8234:       for (p = cStart; p < cEnd; ++p) {
    8235:         for (r = 0; r < 8; ++r) {
    8236:           newp     = (p - cStart)*8 + r;
    8237:           pi[newp] = p;
    8238:         }
    8239:       }
    8240:       break;
    8241:     case REFINER_HYBRID_SIMPLEX_3D:
    8242:       for (p = cStart; p < cMax; ++p) {
    8243:         for (r = 0; r < 8; ++r) {
    8244:           newp     = (p - cStart)*8 + r;
    8245:           pi[newp] = p;
    8246:         }
    8247:       }
    8248:       for (p = cMax; p < cEnd; ++p) {
    8249:         for (r = 0; r < 4; ++r) {
    8250:           newp     = (cMax - cStart)*8 + (p - cMax)*4 + r;
    8251:           pi[newp] = p;
    8252:         }
    8253:       }
    8254:       break;
    8255:     case REFINER_SIMPLEX_TO_HEX_3D:
    8256:       for (p = cStart; p < cEnd; ++p) {
    8257:         for (r = 0; r < 4; ++r) {
    8258:           newp     = (p - cStart)*4 + r;
    8259:           pi[newp] = p;
    8260:         }
    8261:       }
    8262:       break;
    8263:     case REFINER_HYBRID_SIMPLEX_TO_HEX_3D:
    8264:       for (p = cStart; p < cMax; ++p) {
    8265:         for (r = 0; r < 4; ++r) {
    8266:           newp     = (p - cStart)*4 + r;
    8267:           pi[newp] = p;
    8268:         }
    8269:       }
    8270:       for (p = cMax; p < cEnd; ++p) {
    8271:         for (r = 0; r < 3; ++r) {
    8272:           newp     = (cMax - cStart)*4 + (p - cMax)*3 + r;
    8273:           pi[newp] = p;
    8274:         }
    8275:       }
    8276:       break;
    8277:     case REFINER_HEX_3D:
    8278:       for (p = cStart; p < cEnd; ++p) {
    8279:         for (r = 0; r < 8; ++r) {
    8280:           newp = (p - cStart)*8 + r;
    8281:           pi[newp] = p;
    8282:         }
    8283:       }
    8284:       break;
    8285:     case REFINER_HYBRID_HEX_3D:
    8286:       for (p = cStart; p < cMax; ++p) {
    8287:         for (r = 0; r < 8; ++r) {
    8288:           newp = (p - cStart)*8 + r;
    8289:           pi[newp] = p;
    8290:         }
    8291:       }
    8292:       for (p = cMax; p < cEnd; ++p) {
    8293:         for (r = 0; r < 4; ++r) {
    8294:           newp = (cMax - cStart)*8 + (p - cMax)*4 + r;
    8295:           pi[newp] = p;
    8296:         }
    8297:       }
    8298:       break;
    8299:     default:
    8300:       SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %D", refiner);
    8301:     }
    8302:     parentId = pi;
    8303:   } else {
    8304:     /* The refiner needs midpoint vertices on hybrid edges and hybrid cells */
    8305:     if (REFINER_HYBRID_SIMPLEX_TO_HEX_2D == refiner) { cMax = cEnd; eMax = eEnd; }
    8306:     PetscSectionSetChart(coordSectionNew, vStartNew, vStartNew+numVertices);
    8307:   }

    8309:   /* All vertices have the spaceDim coordinates */
    8310:   if (localize) {
    8311:     PetscInt c;

    8313:     for (c = cStartNew; c < cEndNew; ++c) {
    8314:       PetscInt *cone = NULL;
    8315:       PetscInt  closureSize, coneSize = 0, p, pdof;

    8317:       PetscSectionGetDof(coordSection, parentId[c], &pdof);
    8318:       if (pdof) { /* localize on all cells that are refinement of a localized parent cell */
    8319:         DMPlexGetTransitiveClosure(rdm, c, PETSC_TRUE, &closureSize, &cone);
    8320:         for (p = 0; p < closureSize*2; p += 2) {
    8321:           const PetscInt point = cone[p];
    8322:           if ((point >= vStartNew) && (point < vEndNew)) coneSize++;
    8323:         }
    8324:         DMPlexRestoreTransitiveClosure(rdm, c, PETSC_TRUE, &closureSize, &cone);
    8325:         PetscSectionSetDof(coordSectionNew, c, coneSize*spaceDim);
    8326:         PetscSectionSetFieldDof(coordSectionNew, c, 0, coneSize*spaceDim);
    8327:       }
    8328:     }
    8329:   }
    8330:   for (v = vStartNew; v < vStartNew+numVertices; ++v) {
    8331:     PetscSectionSetDof(coordSectionNew, v, spaceDim);
    8332:     PetscSectionSetFieldDof(coordSectionNew, v, 0, spaceDim);
    8333:   }
    8334:   PetscSectionSetUp(coordSectionNew);
    8335:   DMSetCoordinateSection(rdm, PETSC_DETERMINE, coordSectionNew);
    8336:   DMGetCoordinatesLocal(dm, &coordinates);
    8337:   PetscSectionGetStorageSize(coordSectionNew, &coordSizeNew);
    8338:   VecCreate(PETSC_COMM_SELF, &coordinatesNew);
    8339:   PetscObjectSetName((PetscObject) coordinatesNew, "coordinates");
    8340:   VecSetSizes(coordinatesNew, coordSizeNew, PETSC_DETERMINE);
    8341:   VecGetBlockSize(coordinates, &bs);
    8342:   VecSetBlockSize(coordinatesNew, bs);
    8343:   VecGetType(coordinates, &vtype);
    8344:   VecSetType(coordinatesNew, vtype);
    8345:   VecGetArray(coordinates, &coords);
    8346:   VecGetArray(coordinatesNew, &coordsNew);

    8348:   switch (refiner) {
    8349:   case REFINER_NOOP: break;
    8350:   case REFINER_HYBRID_SIMPLEX_TO_HEX_3D:
    8351:   case REFINER_SIMPLEX_TO_HEX_3D:
    8352:   case REFINER_HEX_3D:
    8353:   case REFINER_HYBRID_HEX_3D:
    8354:     /* Face vertices have the average of corner coordinates */
    8355:     for (f = fStart; f < fMax; ++f) {
    8356:       const PetscInt newv = vStartNew + (vEnd - vStart) + (eMax - eStart) + (f - fStart);
    8357:       PetscInt      *cone = NULL;
    8358:       PetscInt       closureSize, coneSize = 0, off[8], offnew, p, d;

    8360:       DMPlexGetTransitiveClosure(dm, f, PETSC_TRUE, &closureSize, &cone);
    8361:       for (p = 0; p < closureSize*2; p += 2) {
    8362:         const PetscInt point = cone[p];
    8363:         if ((point >= vStart) && (point < vEnd)) cone[coneSize++] = point;
    8364:       }
    8365:       if (localize) {
    8366:         const PetscInt *support = NULL;
    8367:         PetscInt       *rStar = NULL;
    8368:         PetscInt        supportSize, rStarSize, coff, s, ccoff[8];
    8369:         PetscBool       cellfound = PETSC_FALSE;

    8371:         DMPlexGetTransitiveClosure(rdm, newv, PETSC_FALSE, &rStarSize, &rStar);
    8372:         DMPlexGetSupportSize(dm,f,&supportSize);
    8373:         DMPlexGetSupport(dm,f,&support);
    8374:         /* Compute average of coordinates for each cell sharing the face */
    8375:         for (s = 0; s < supportSize; ++s) {
    8376:           PetscScalar     coordsNewAux[3] = { 0.0, 0.0, 0.0 };
    8377:           PetscInt       *cellCone = NULL;
    8378:           PetscInt        cellClosureSize, cellConeSize = 0, cdof;
    8379:           const PetscInt  cell = support[s];
    8380:           PetscBool       copyoff = PETSC_FALSE;

    8382:           DMPlexGetTransitiveClosure(dm, cell, PETSC_TRUE, &cellClosureSize, &cellCone);
    8383:           for (p = 0; p < cellClosureSize*2; p += 2) {
    8384:             const PetscInt point = cellCone[p];
    8385:             if ((point >= vStart) && (point < vEnd)) cellCone[cellConeSize++] = point;
    8386:           }
    8387:           PetscSectionGetDof(coordSection, cell, &cdof);
    8388:           if (!cdof) { /* the parent cell does not have localized coordinates */
    8389:             cellfound = PETSC_TRUE;
    8390:             for (v = 0; v < coneSize; ++v) {
    8391:               PetscSectionGetOffset(coordSection, cone[v], &off[v]);
    8392:               for (d = 0; d < spaceDim; ++d) coordsNewAux[d] += coords[off[v]+d];
    8393:             }
    8394:             for (d = 0; d < spaceDim; ++d) coordsNewAux[d] /= coneSize;
    8395:           } else {
    8396:             PetscSectionGetOffset(coordSection, cell, &coff);
    8397:             for (p = 0; p < coneSize; ++p) {
    8398:               const PetscInt tv = cone[p];
    8399:               PetscInt       cv, voff;
    8400:               PetscBool      locv = PETSC_TRUE;

    8402:               for (cv = 0; cv < cellConeSize; ++cv) {
    8403:                 if (cellCone[cv] == tv) {
    8404:                   ccoff[p] = spaceDim*cv + coff;
    8405:                   break;
    8406:                 }
    8407:               }
    8408:               if (cv == cellConeSize) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Unable to map vertex %D\n",tv);

    8410:               PetscSectionGetOffset(coordSection, cone[p], &voff);
    8411:               for (d = 0; d < spaceDim; ++d) {
    8412:                 coordsNewAux[d] += coords[ccoff[p]+d];
    8413:                 if (!cellfound && coords[voff+d] != coords[ccoff[p]+d]) locv = PETSC_FALSE;
    8414:               }
    8415:               if (locv && !cellfound) {
    8416:                 cellfound = PETSC_TRUE;
    8417:                 copyoff   = PETSC_TRUE;
    8418:               }
    8419:             }
    8420:             for (d = 0; d < spaceDim; ++d) coordsNewAux[d] /= coneSize;

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

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

    8433:               PetscSectionGetDof(coordSectionNew, rcell, &rcdof);
    8434:               if (!rcdof) continue;
    8435:               PetscSectionGetOffset(coordSectionNew, rcell, &rcoff);
    8436:               DMPlexGetTransitiveClosure(rdm, rcell, PETSC_TRUE, &rclosureSize, &rcone);
    8437:               for (p = 0, lid = 0; p < rclosureSize*2; p += 2) {
    8438:                 if (rcone[p] == newv) {
    8439:                   for (d = 0; d < spaceDim; d++) coordsNew[rcoff + lid*spaceDim + d] = coordsNewAux[d];
    8440:                   break;
    8441:                 }
    8442:                 if (rcone[p] >= vStartNew && rcone[p] < vEndNew) lid++;
    8443:               }
    8444:               DMPlexRestoreTransitiveClosure(rdm, rcell, PETSC_TRUE, &rclosureSize, &rcone);
    8445:               if (p == closureSize*2) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Unable to map new vertex %D\n",newv);
    8446:             }
    8447:           }
    8448:           DMPlexRestoreTransitiveClosure(dm, cell, PETSC_TRUE, &cellClosureSize, &cellCone);
    8449:         }
    8450:         DMPlexRestoreTransitiveClosure(rdm, newv, PETSC_FALSE, &rStarSize, &rStar);
    8451:         if (!cellfound) {
    8452:           /* Could not find a valid face for the vertex part, we will get this vertex later (final reduction) */
    8453:           needcoords = PETSC_TRUE;
    8454:           coneSize   = 0;
    8455:         }
    8456:       } else {
    8457:         for (v = 0; v < coneSize; ++v) {
    8458:           PetscSectionGetOffset(coordSection, cone[v], &off[v]);
    8459:         }
    8460:       }
    8461:       PetscSectionGetOffset(coordSectionNew, newv, &offnew);
    8462:       if (coneSize) {
    8463:         for (d = 0; d < spaceDim; ++d) coordsNew[offnew+d] = 0.0;
    8464:         for (v = 0; v < coneSize; ++v) {DMLocalizeAddCoordinate_Internal(dm, spaceDim, &coords[off[0]], &coords[off[v]], &coordsNew[offnew]);}
    8465:         for (d = 0; d < spaceDim; ++d) coordsNew[offnew+d] /= coneSize;
    8466:       } else {
    8467:         for (d = 0; d < spaceDim; ++d) coordsNew[offnew+d] = PETSC_MIN_REAL;
    8468:       }
    8469:       DMPlexRestoreTransitiveClosure(dm, f, PETSC_TRUE, &closureSize, &cone);
    8470:     }
    8471:   case REFINER_HYBRID_SIMPLEX_TO_HEX_2D:
    8472:   case REFINER_SIMPLEX_TO_HEX_2D:
    8473:   case REFINER_HEX_2D:
    8474:   case REFINER_HYBRID_HEX_2D:
    8475:   case REFINER_SIMPLEX_1D:
    8476:     /* Cell vertices have the average of corner coordinates */
    8477:     for (c = cStart; c < cMax; ++c) {
    8478:       const PetscInt newv = vStartNew + (vEnd - vStart) + (dim > 1 ? (eMax - eStart) : 0) + (c - cStart) + (dim > 2 ? (fMax - fStart) : 0);
    8479:       PetscInt      *cone = NULL;
    8480:       PetscInt       closureSize, coneSize = 0, off[8], offnew, p, d, cdof = 0;

    8482:       DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &cone);
    8483:       for (p = 0; p < closureSize*2; p += 2) {
    8484:         const PetscInt point = cone[p];
    8485:         if ((point >= vStart) && (point < vEnd)) cone[coneSize++] = point;
    8486:       }
    8487:       if (localize) {
    8488:         PetscSectionGetDof(coordSection, c, &cdof);
    8489:       }
    8490:       if (cdof) {
    8491:         PetscInt coff;

    8493:         PetscSectionGetOffset(coordSection, c, &coff);
    8494:         for (v = 0; v < coneSize; ++v) off[v] = spaceDim*v + coff;
    8495:       } else {
    8496:         for (v = 0; v < coneSize; ++v) {
    8497:           PetscSectionGetOffset(coordSection, cone[v], &off[v]);
    8498:         }
    8499:       }
    8500:       PetscSectionGetOffset(coordSectionNew, newv, &offnew);
    8501:       for (d = 0; d < spaceDim; ++d) coordsNew[offnew+d] = 0.0;
    8502:       for (v = 0; v < coneSize; ++v) {DMLocalizeAddCoordinate_Internal(dm, spaceDim, &coords[off[0]], &coords[off[v]], &coordsNew[offnew]);}
    8503:       for (d = 0; d < spaceDim; ++d) coordsNew[offnew+d] /= coneSize;
    8504:       DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &cone);

    8506:       /* Localize new coordinates on each refined cell */
    8507:       if (cdof) {
    8508:         PetscInt *rStar = NULL, rStarSize;

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

    8515:             rc   = rStar[v];
    8516:             PetscSectionGetDof(coordSectionNew, rc, &rcdof);
    8517:             if (!rcdof) continue;
    8518:             PetscSectionGetOffset(coordSectionNew, rc, &coff);
    8519:             DMPlexGetTransitiveClosure(rdm, rc, PETSC_TRUE, &closureSize, &cone);
    8520:             for (p = 0, lid = 0; p < closureSize*2; p += 2) {
    8521:               if (cone[p] == newv) {
    8522:                 for (d = 0; d < spaceDim; d++) coordsNew[coff + lid*spaceDim + d] = coordsNew[offnew + d];
    8523:                 break;
    8524:               }
    8525:               if (cone[p] >= vStartNew && cone[p] < vEndNew) lid++;
    8526:             }
    8527:             if (p == closureSize*2) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Unable to map new vertex %D\n",newv);
    8528:             DMPlexRestoreTransitiveClosure(rdm, rc, PETSC_TRUE, &closureSize, &cone);
    8529:           }
    8530:         }
    8531:         DMPlexRestoreTransitiveClosure(rdm, newv, PETSC_FALSE, &rStarSize, &rStar);
    8532:       }
    8533:     }
    8534:   case REFINER_SIMPLEX_2D:
    8535:   case REFINER_HYBRID_SIMPLEX_2D:
    8536:   case REFINER_SIMPLEX_3D:
    8537:   case REFINER_HYBRID_SIMPLEX_3D:
    8538:     /* Edge vertices have the average of endpoint coordinates */
    8539:     for (e = eStart; e < eMax; ++e) {
    8540:       const PetscInt  newv = vStartNew + (vEnd - vStart) + (e - eStart);
    8541:       const PetscInt *cone;
    8542:       PetscInt        coneSize, offA, offB, offnew, d;

    8544:       DMPlexGetConeSize(dm, e, &coneSize);
    8545:       if (coneSize != 2) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Edge %D cone should have two vertices, not %D", e, coneSize);
    8546:       DMPlexGetCone(dm, e, &cone);
    8547:       if (localize) {
    8548:         PetscInt   coff, toffA = -1, toffB = -1, voffA, voffB;
    8549:         PetscInt  *eStar = NULL, eStarSize;
    8550:         PetscInt  *rStar = NULL, rStarSize;
    8551:         PetscBool  cellfound = PETSC_FALSE;

    8553:         offA = offB = -1;
    8554:         PetscSectionGetOffset(coordSection, cone[0], &voffA);
    8555:         PetscSectionGetOffset(coordSection, cone[1], &voffB);
    8556:         DMPlexGetTransitiveClosure(dm, e, PETSC_FALSE, &eStarSize, &eStar);
    8557:         DMPlexGetTransitiveClosure(rdm, newv, PETSC_FALSE, &rStarSize, &rStar);
    8558:         for (v = 0; v < eStarSize*2; v += 2) {
    8559:           if ((eStar[v] >= cStart) && (eStar[v] < cEnd)) {
    8560:             PetscScalar     coordsNewAux[3];
    8561:             PetscInt       *cellCone = NULL;
    8562:             PetscInt        cellClosureSize, s, cv, cdof;
    8563:             PetscBool       locvA = PETSC_TRUE, locvB = PETSC_TRUE;
    8564:             const PetscInt  cell = eStar[v];

    8566:             PetscSectionGetDof(coordSection, cell, &cdof);
    8567:             if (!cdof) {
    8568:               /* Found a valid edge for the "vertex" part of the Section */
    8569:               offA = voffA;
    8570:               offB = voffB;
    8571:               cellfound = PETSC_TRUE;
    8572:             } else {
    8573:               PetscSectionGetOffset(coordSection, cell, &coff);
    8574:               DMPlexGetTransitiveClosure(dm, cell, PETSC_TRUE, &cellClosureSize, &cellCone);
    8575:               for (s = 0, cv = 0; s < cellClosureSize*2; s += 2) {
    8576:                 const PetscInt point = cellCone[s];
    8577:                 if ((point >= vStart) && (point < vEnd)) {
    8578:                   if (point == cone[0]) toffA = spaceDim*cv + coff;
    8579:                   else if (point == cone[1]) toffB = spaceDim*cv + coff;
    8580:                   cv++;
    8581:                 }
    8582:               }
    8583:               DMPlexRestoreTransitiveClosure(dm, cell, PETSC_TRUE, &cellClosureSize, &cellCone);
    8584:               for (d = 0; d < spaceDim; ++d) {
    8585:                 coordsNewAux[d] = 0.5*(coords[toffA+d] + coords[toffB+d]);
    8586:                 if (coords[toffA+d] != coords[voffA+d]) locvA = PETSC_FALSE;
    8587:                 if (coords[toffB+d] != coords[voffB+d]) locvB = PETSC_FALSE;
    8588:               }
    8589:               /* Found a valid edge for the "vertex" part of the Section */
    8590:               if (!cellfound && (locvA || locvB)) {
    8591:                 cellfound = PETSC_TRUE;
    8592:                 offA = toffA;
    8593:                 offB = toffB;
    8594:               }
    8595:             }

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

    8603:                 PetscSectionGetDof(coordSectionNew, rcell, &rcdof);
    8604:                 if (!rcdof) continue;
    8605:                 PetscSectionGetOffset(coordSectionNew, rcell, &coff);
    8606:                 DMPlexGetTransitiveClosure(rdm, rcell, PETSC_TRUE, &rclosureSize, &rcone);
    8607:                 for (p = 0, lid = 0; p < rclosureSize*2; p += 2) {
    8608:                   if (rcone[p] == newv) {
    8609:                     for (d = 0; d < spaceDim; d++) coordsNew[coff + lid*spaceDim + d] = coordsNewAux[d];
    8610:                     break;
    8611:                   }
    8612:                   if (rcone[p] >= vStartNew && rcone[p] < vEndNew) lid++;
    8613:                 }
    8614:                 DMPlexRestoreTransitiveClosure(rdm, rcell, PETSC_TRUE, &rclosureSize, &rcone);
    8615:                 if (p == rclosureSize*2) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Unable to map new vertex %D\n",newv);
    8616:               }
    8617:             }
    8618:           }
    8619:         }
    8620:         DMPlexRestoreTransitiveClosure(dm, e, PETSC_FALSE, &eStarSize, &eStar);
    8621:         DMPlexRestoreTransitiveClosure(rdm, newv, PETSC_FALSE, &rStarSize, &rStar);
    8622:         if (!cellfound) {
    8623:           /* Could not find a valid edge for the vertex part, we will get this vertex later (final reduction) */
    8624:           needcoords = PETSC_TRUE;
    8625:         }
    8626:       } else {
    8627:         PetscSectionGetOffset(coordSection, cone[0], &offA);
    8628:         PetscSectionGetOffset(coordSection, cone[1], &offB);
    8629:       }
    8630:       PetscSectionGetOffset(coordSectionNew, newv, &offnew);
    8631:       if (offA != -1 && offB != -1) {
    8632:         DMLocalizeCoordinate_Internal(dm, spaceDim, &coords[offA], &coords[offB], &coordsNew[offnew]);
    8633:         for (d = 0; d < spaceDim; ++d) {
    8634:           coordsNew[offnew+d] = 0.5*(coords[offA+d] + coordsNew[offnew+d]);
    8635:         }
    8636:       } else {
    8637:         for (d = 0; d < spaceDim; ++d) coordsNew[offnew+d] = PETSC_MIN_REAL;
    8638:       }
    8639:     }
    8640:     /* Old vertices have the same coordinates */
    8641:     for (v = vStart; v < vEnd; ++v) {
    8642:       const PetscInt newv = vStartNew + (v - vStart);
    8643:       PetscInt       off, offnew, d;

    8645:       PetscSectionGetOffset(coordSection, v, &off);
    8646:       PetscSectionGetOffset(coordSectionNew, newv, &offnew);
    8647:       for (d = 0; d < spaceDim; ++d) {
    8648:         coordsNew[offnew+d] = coords[off+d];
    8649:       }

    8651:       /* Localize new coordinates on each refined cell */
    8652:       if (localize) {
    8653:         PetscInt  p;
    8654:         PetscInt *rStar = NULL, rStarSize;

    8656:         DMPlexGetTransitiveClosure(rdm, newv, PETSC_FALSE, &rStarSize, &rStar);
    8657:         for (p = 0; p < rStarSize*2; p += 2) {
    8658:           if ((rStar[p] >= cStartNew) && (rStar[p] < cEndNew)) {
    8659:             PetscScalar  ocoords[3];
    8660:             PetscInt    *cone = NULL, closureSize, lid, coff, s, oc, cdof;

    8662:             c    = rStar[p];
    8663:             oc   = parentId[c-cStartNew];
    8664:             PetscSectionGetDof(coordSectionNew, c, &cdof);
    8665:             if (!cdof) continue;
    8666:             PetscSectionGetDof(coordSection, oc, &cdof);
    8667:             if (!cdof) continue;
    8668:             PetscSectionGetOffset(coordSection, oc, &coff);
    8669:             DMPlexGetTransitiveClosure(dm, oc, PETSC_TRUE, &closureSize, &cone);
    8670:             for (s = 0, lid = 0; s < closureSize*2; s += 2) {
    8671:               if (cone[s] == v) {
    8672:                 for (d = 0; d < spaceDim; d++) ocoords[d] = coords[coff + lid*spaceDim + d];
    8673:                 break;
    8674:               }
    8675:               if (cone[s] >= vStart && cone[s] < vEnd) lid++;
    8676:             }
    8677:             if (s == closureSize*2) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Unable to map old vertex %D\n",v);
    8678:             DMPlexRestoreTransitiveClosure(dm, oc, PETSC_TRUE, &closureSize, &cone);

    8680:             PetscSectionGetOffset(coordSectionNew, c, &coff);
    8681:             DMPlexGetTransitiveClosure(rdm, c, PETSC_TRUE, &closureSize, &cone);
    8682:             for (s = 0, lid = 0; s < closureSize*2; s += 2) {
    8683:               if (cone[s] == newv) {
    8684:                 for (d = 0; d < spaceDim; d++) coordsNew[coff + lid*spaceDim + d] = ocoords[d];
    8685:                 break;
    8686:               }
    8687:               if (cone[s] >= vStartNew && cone[s] < vEndNew) lid++;
    8688:             }
    8689:             if (s == closureSize*2) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Unable to map new vertex %D\n",newv);
    8690:             DMPlexRestoreTransitiveClosure(rdm, c, PETSC_TRUE, &closureSize, &cone);
    8691:           }
    8692:         }
    8693:         DMPlexRestoreTransitiveClosure(rdm, newv, PETSC_FALSE, &rStarSize, &rStar);
    8694:       }
    8695:     }
    8696:     break;
    8697:   default:
    8698:     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %D", refiner);
    8699:   }
    8700:   VecRestoreArray(coordinates, &coords);
    8701:   VecRestoreArray(coordinatesNew, &coordsNew);
    8702:   DMSetCoordinatesLocal(rdm, coordinatesNew);

    8704:   /* Final reduction (if needed) if we are localizing */
    8705:   if (localize) {
    8706:     PetscBool gred;

    8708:     MPIU_Allreduce(&needcoords, &gred, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject)rdm));
    8709:     if (gred) {
    8710:       DM                 cdm;
    8711:       Vec                aux;
    8712:       PetscSF            sf;
    8713:       const PetscScalar *lArray;
    8714:       PetscScalar       *gArray;

    8716:       DMGetCoordinateDM(rdm, &cdm);
    8717:       DMCreateGlobalVector(cdm, &aux);
    8718:       DMGetDefaultSF(cdm, &sf);
    8719:       VecGetArrayRead(coordinatesNew, &lArray);
    8720:       VecSet(aux, PETSC_MIN_REAL);
    8721:       VecGetArray(aux, &gArray);
    8722:       PetscSFReduceBegin(sf, MPIU_SCALAR, lArray, gArray, MPIU_MAX);
    8723:       PetscSFReduceEnd(sf, MPIU_SCALAR, lArray, gArray, MPIU_MAX);
    8724:       VecRestoreArrayRead(coordinatesNew, &lArray);
    8725:       VecRestoreArray(aux, &gArray);
    8726:       DMGlobalToLocalBegin(cdm, aux, INSERT_VALUES, coordinatesNew);
    8727:       DMGlobalToLocalEnd(cdm, aux, INSERT_VALUES, coordinatesNew);
    8728:       VecDestroy(&aux);
    8729:     }
    8730:   }
    8731:   VecDestroy(&coordinatesNew);
    8732:   PetscSectionDestroy(&coordSectionNew);
    8733:   PetscFree(parentId);
    8734:   return(0);
    8735: }

    8737: /*@
    8738:   DMPlexCreateProcessSF - Create an SF which just has process connectivity

    8740:   Collective on DM

    8742:   Input Parameters:
    8743: + dm      - The DM
    8744: - sfPoint - The PetscSF which encodes point connectivity

    8746:   Output Parameters:
    8747: + processRanks - A list of process neighbors, or NULL
    8748: - sfProcess    - An SF encoding the process connectivity, or NULL

    8750:   Level: developer

    8752: .seealso: PetscSFCreate(), DMPlexCreateTwoSidedProcessSF()
    8753: @*/
    8754: PetscErrorCode DMPlexCreateProcessSF(DM dm, PetscSF sfPoint, IS *processRanks, PetscSF *sfProcess)
    8755: {
    8756:   PetscInt           numRoots, numLeaves, l;
    8757:   const PetscInt    *localPoints;
    8758:   const PetscSFNode *remotePoints;
    8759:   PetscInt          *localPointsNew;
    8760:   PetscSFNode       *remotePointsNew;
    8761:   PetscInt          *ranks, *ranksNew;
    8762:   PetscMPIInt        size;
    8763:   PetscErrorCode     ierr;

    8770:   MPI_Comm_size(PetscObjectComm((PetscObject) dm), &size);
    8771:   PetscSFGetGraph(sfPoint, &numRoots, &numLeaves, &localPoints, &remotePoints);
    8772:   PetscMalloc1(numLeaves, &ranks);
    8773:   for (l = 0; l < numLeaves; ++l) {
    8774:     ranks[l] = remotePoints[l].rank;
    8775:   }
    8776:   PetscSortRemoveDupsInt(&numLeaves, ranks);
    8777:   PetscMalloc1(numLeaves, &ranksNew);
    8778:   PetscMalloc1(numLeaves, &localPointsNew);
    8779:   PetscMalloc1(numLeaves, &remotePointsNew);
    8780:   for (l = 0; l < numLeaves; ++l) {
    8781:     ranksNew[l]              = ranks[l];
    8782:     localPointsNew[l]        = l;
    8783:     remotePointsNew[l].index = 0;
    8784:     remotePointsNew[l].rank  = ranksNew[l];
    8785:   }
    8786:   PetscFree(ranks);
    8787:   if (processRanks) {ISCreateGeneral(PetscObjectComm((PetscObject)dm), numLeaves, ranksNew, PETSC_OWN_POINTER, processRanks);}
    8788:   else              {PetscFree(ranksNew);}
    8789:   if (sfProcess) {
    8790:     PetscSFCreate(PetscObjectComm((PetscObject)dm), sfProcess);
    8791:     PetscObjectSetName((PetscObject) *sfProcess, "Process SF");
    8792:     PetscSFSetFromOptions(*sfProcess);
    8793:     PetscSFSetGraph(*sfProcess, size, numLeaves, localPointsNew, PETSC_OWN_POINTER, remotePointsNew, PETSC_OWN_POINTER);
    8794:   }
    8795:   return(0);
    8796: }

    8798: static PetscErrorCode CellRefinerCreateSF(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
    8799: {
    8800:   PetscSF            sf, sfNew, sfProcess;
    8801:   IS                 processRanks;
    8802:   MPI_Datatype       depthType;
    8803:   PetscInt           numRoots, numLeaves, numLeavesNew = 0, l, m;
    8804:   const PetscInt    *localPoints, *neighbors;
    8805:   const PetscSFNode *remotePoints;
    8806:   PetscInt          *localPointsNew;
    8807:   PetscSFNode       *remotePointsNew;
    8808:   PetscInt          *depthSizeOld, *rdepthSize, *rdepthSizeOld, *rdepthMaxOld, *rvStart, *rvStartNew, *reStart, *reStartNew, *rfStart, *rfStartNew, *rcStart, *rcStartNew;
    8809:   PetscInt           ldepth, depth, numNeighbors, pStartNew, pEndNew, cStart, cEnd, cMax, vStart, vEnd, vMax, fStart, fEnd, fMax, eStart, eEnd, eMax, r, n;
    8810:   PetscInt           cStartNew = 0, vStartNew = 0, fStartNew = 0, eStartNew = 0;
    8811:   PetscErrorCode     ierr;

    8814:   DMPlexGetChart(rdm, &pStartNew, &pEndNew);
    8815:   DMPlexGetDepth(dm, &ldepth);
    8816:   MPIU_Allreduce(&ldepth, &depth, 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject) dm));
    8817:   if ((ldepth >= 0) && (depth != ldepth)) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Inconsistent Plex depth %D != %D", ldepth, depth);
    8818:   DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);
    8819:   DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);
    8820:   DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);
    8821:   DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);
    8822:   DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);
    8823:   cMax = cMax < 0 ? cEnd : cMax;
    8824:   fMax = fMax < 0 ? fEnd : fMax;
    8825:   eMax = eMax < 0 ? eEnd : eMax;
    8826:   if (refiner) {GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);}
    8827:   DMGetPointSF(dm, &sf);
    8828:   DMGetPointSF(rdm, &sfNew);
    8829:   /* Calculate size of new SF */
    8830:   PetscSFGetGraph(sf, &numRoots, &numLeaves, &localPoints, &remotePoints);
    8831:   if (numRoots < 0) return(0);
    8832:   for (l = 0; l < numLeaves; ++l) {
    8833:     const PetscInt p = localPoints[l];

    8835:     switch (refiner) {
    8836:     case REFINER_SIMPLEX_1D:
    8837:       if ((p >= vStart) && (p < vEnd)) {
    8838:         /* Interior vertices stay the same */
    8839:         ++numLeavesNew;
    8840:       } else if ((p >= cStart && p < cMax)) {
    8841:         /* Interior cells add new cells and interior vertices */
    8842:         numLeavesNew += 2 + 1;
    8843:       }
    8844:       break;
    8845:     case REFINER_SIMPLEX_2D:
    8846:     case REFINER_HYBRID_SIMPLEX_2D:
    8847:       if ((p >= vStart) && (p < vEnd)) {
    8848:         /* Interior vertices stay the same */
    8849:         ++numLeavesNew;
    8850:       } else if ((p >= fStart) && (p < fMax)) {
    8851:         /* Interior faces add new faces and vertex */
    8852:         numLeavesNew += 2 + 1;
    8853:       } else if ((p >= fMax) && (p < fEnd)) {
    8854:         /* Hybrid faces stay the same */
    8855:         ++numLeavesNew;
    8856:       } else if ((p >= cStart) && (p < cMax)) {
    8857:         /* Interior cells add new cells and interior faces */
    8858:         numLeavesNew += 4 + 3;
    8859:       } else if ((p >= cMax) && (p < cEnd)) {
    8860:         /* Hybrid cells add new cells and hybrid face */
    8861:         numLeavesNew += 2 + 1;
    8862:       }
    8863:       break;
    8864:     case REFINER_HYBRID_SIMPLEX_TO_HEX_2D:
    8865:     case REFINER_SIMPLEX_TO_HEX_2D:
    8866:       if ((p >= vStart) && (p < vEnd)) {
    8867:         /* Interior vertices stay the same */
    8868:         ++numLeavesNew;
    8869:       } else if ((p >= fStart) && (p < fEnd)) {
    8870:         /* Interior faces add new faces and vertex */
    8871:         numLeavesNew += 2 + 1;
    8872:       } else if ((p >= cStart) && (p < cMax)) {
    8873:         /* Interior cells add new cells, interior faces, and vertex */
    8874:         numLeavesNew += 3 + 3 + 1;
    8875:       } else if ((p >= cMax) && (p < cEnd)) {
    8876:         /* Hybrid cells add new cells, interior faces, and vertex */
    8877:         numLeavesNew += 4 + 4 + 1;
    8878:       }
    8879:       break;
    8880:     case REFINER_HEX_2D:
    8881:     case REFINER_HYBRID_HEX_2D:
    8882:       if ((p >= vStart) && (p < vEnd)) {
    8883:         /* Interior vertices stay the same */
    8884:         ++numLeavesNew;
    8885:       } else if ((p >= fStart) && (p < fMax)) {
    8886:         /* Interior faces add new faces and vertex */
    8887:         numLeavesNew += 2 + 1;
    8888:       } else if ((p >= fMax) && (p < fEnd)) {
    8889:         /* Hybrid faces stay the same */
    8890:         ++numLeavesNew;
    8891:       } else if ((p >= cStart) && (p < cMax)) {
    8892:         /* Interior cells add new cells, interior faces, and vertex */
    8893:         numLeavesNew += 4 + 4 + 1;
    8894:       } else if ((p >= cMax) && (p < cEnd)) {
    8895:         /* Hybrid cells add new cells and hybrid face */
    8896:         numLeavesNew += 2 + 1;
    8897:       }
    8898:       break;
    8899:     case REFINER_SIMPLEX_3D:
    8900:     case REFINER_HYBRID_SIMPLEX_3D:
    8901:       if ((p >= vStart) && (p < vEnd)) {
    8902:         /* Interior vertices stay the same */
    8903:         ++numLeavesNew;
    8904:       } else if ((p >= eStart) && (p < eMax)) {
    8905:         /* Interior edges add new edges and vertex */
    8906:         numLeavesNew += 2 + 1;
    8907:       } else if ((p >= eMax) && (p < eEnd)) {
    8908:         /* Hybrid edges stay the same */
    8909:         ++numLeavesNew;
    8910:       } else if ((p >= fStart) && (p < fMax)) {
    8911:         /* Interior faces add new faces and edges */
    8912:         numLeavesNew += 4 + 3;
    8913:       } else if ((p >= fMax) && (p < fEnd)) {
    8914:         /* Hybrid faces add new faces and edges */
    8915:         numLeavesNew += 2 + 1;
    8916:       } else if ((p >= cStart) && (p < cMax)) {
    8917:         /* Interior cells add new cells, faces, and edges */
    8918:         numLeavesNew += 8 + 8 + 1;
    8919:       } else if ((p >= cMax) && (p < cEnd)) {
    8920:         /* Hybrid cells add new cells and faces */
    8921:         numLeavesNew += 4 + 3;
    8922:       }
    8923:       break;
    8924:     case REFINER_HYBRID_SIMPLEX_TO_HEX_3D:
    8925:     case REFINER_SIMPLEX_TO_HEX_3D:
    8926:       if ((p >= vStart) && (p < vEnd)) {
    8927:         /* Interior vertices stay the same */
    8928:         ++numLeavesNew;
    8929:       } else if ((p >= eStart) && (p < eMax)) {
    8930:         /* Interior edges add new edges and vertex */
    8931:         numLeavesNew += 2 + 1;
    8932:       } else if ((p >= eMax) && (p < eEnd)) {
    8933:         /* Hybrid edges stay the same */
    8934:         ++numLeavesNew;
    8935:       } else if ((p >= fStart) && (p < fMax)) {
    8936:         /* Interior faces add new faces, edges and a vertex */
    8937:         numLeavesNew += 3 + 3 + 1;
    8938:       } else if ((p >= fMax) && (p < fEnd)) {
    8939:         /* Hybrid faces add new faces and an edge */
    8940:         numLeavesNew += 2 + 1;
    8941:       } else if ((p >= cStart) && (p < cMax)) {
    8942:         /* Interior cells add new cells, faces, edges and a vertex */
    8943:         numLeavesNew += 4 + 6 + 4 + 1;
    8944:       } else if ((p >= cMax) && (p < cEnd)) {
    8945:         /* Hybrid cells add new cells, faces and an edge */
    8946:         numLeavesNew += 3 + 3 + 1;
    8947:       }
    8948:       break;
    8949:     case REFINER_HEX_3D:
    8950:     case REFINER_HYBRID_HEX_3D:
    8951:       if ((p >= vStart) && (p < vEnd)) {
    8952:         /* Old vertices stay the same */
    8953:         ++numLeavesNew;
    8954:       } else if ((p >= eStart) && (p < eMax)) {
    8955:         /* Interior edges add new edges, and vertex */
    8956:         numLeavesNew += 2 + 1;
    8957:       } else if ((p >= eMax) && (p < eEnd)) {
    8958:         /* Hybrid edges stay the same */
    8959:         ++numLeavesNew;
    8960:       } else if ((p >= fStart) && (p < fMax)) {
    8961:         /* Interior faces add new faces, edges, and vertex */
    8962:         numLeavesNew += 4 + 4 + 1;
    8963:       } else if ((p >= fMax) && (p < fEnd)) {
    8964:         /* Hybrid faces add new faces and edges */
    8965:         numLeavesNew += 2 + 1;
    8966:       } else if ((p >= cStart) && (p < cMax)) {
    8967:         /* Interior cells add new cells, faces, edges, and vertex */
    8968:         numLeavesNew += 8 + 12 + 6 + 1;
    8969:       } else if ((p >= cStart) && (p < cEnd)) {
    8970:         /* Hybrid cells add new cells, faces, and edges */
    8971:         numLeavesNew += 4 + 4 + 1;
    8972:       }
    8973:       break;
    8974:     default:
    8975:       SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %D", refiner);
    8976:     }
    8977:   }
    8978:   /* Communicate depthSizes for each remote rank */
    8979:   DMPlexCreateProcessSF(dm, sf, &processRanks, &sfProcess);
    8980:   ISGetLocalSize(processRanks, &numNeighbors);
    8981:   PetscMalloc5((depth+1)*numNeighbors,&rdepthSize,numNeighbors,&rvStartNew,numNeighbors,&reStartNew,numNeighbors,&rfStartNew,numNeighbors,&rcStartNew);
    8982:   PetscMalloc7(depth+1,&depthSizeOld,(depth+1)*numNeighbors,&rdepthSizeOld,(depth+1)*numNeighbors,&rdepthMaxOld,numNeighbors,&rvStart,numNeighbors,&reStart,numNeighbors,&rfStart,numNeighbors,&rcStart);
    8983:   MPI_Type_contiguous(depth+1, MPIU_INT, &depthType);
    8984:   MPI_Type_commit(&depthType);
    8985:   PetscSFBcastBegin(sfProcess, depthType, depthSize, rdepthSize);
    8986:   PetscSFBcastEnd(sfProcess, depthType, depthSize, rdepthSize);
    8987:   for (n = 0; n < numNeighbors; ++n) {
    8988:     GetDepthStart_Private(depth, &rdepthSize[n*(depth+1)], &rcStartNew[n], &rfStartNew[n], &reStartNew[n], &rvStartNew[n]);
    8989:   }
    8990:   depthSizeOld[depth]   = cMax;
    8991:   depthSizeOld[0]       = vMax;
    8992:   depthSizeOld[depth-1] = fMax;
    8993:   depthSizeOld[1]       = eMax;

    8995:   PetscSFBcastBegin(sfProcess, depthType, depthSizeOld, rdepthMaxOld);
    8996:   PetscSFBcastEnd(sfProcess, depthType, depthSizeOld, rdepthMaxOld);

    8998:   depthSizeOld[depth]   = cEnd - cStart;
    8999:   depthSizeOld[0]       = vEnd - vStart;
    9000:   depthSizeOld[depth-1] = fEnd - fStart;
    9001:   depthSizeOld[1]       = eEnd - eStart;

    9003:   PetscSFBcastBegin(sfProcess, depthType, depthSizeOld, rdepthSizeOld);
    9004:   PetscSFBcastEnd(sfProcess, depthType, depthSizeOld, rdepthSizeOld);
    9005:   for (n = 0; n < numNeighbors; ++n) {
    9006:     GetDepthStart_Private(depth, &rdepthSizeOld[n*(depth+1)], &rcStart[n], &rfStart[n], &reStart[n], &rvStart[n]);
    9007:     rdepthMaxOld[n*(depth+1)+depth]   = rdepthMaxOld[n*(depth+1)+depth]   < 0 ? rdepthSizeOld[n*(depth+1)+depth]  +rcStart[n]: rdepthMaxOld[n*(depth+1)+depth];
    9008:     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];
    9009:     rdepthMaxOld[n*(depth+1)+1]       = rdepthMaxOld[n*(depth+1)+1]       < 0 ? rdepthSizeOld[n*(depth+1)+1]      +reStart[n]: rdepthMaxOld[n*(depth+1)+1];
    9010:   }
    9011:   MPI_Type_free(&depthType);
    9012:   PetscSFDestroy(&sfProcess);
    9013:   /* Calculate new point SF */
    9014:   PetscMalloc1(numLeavesNew, &localPointsNew);
    9015:   PetscMalloc1(numLeavesNew, &remotePointsNew);
    9016:   ISGetIndices(processRanks, &neighbors);
    9017:   for (l = 0, m = 0; l < numLeaves; ++l) {
    9018:     PetscInt    p     = localPoints[l];
    9019:     PetscInt    rp    = remotePoints[l].index, n;
    9020:     PetscMPIInt rrank = remotePoints[l].rank;

    9022:     PetscFindInt(rrank, numNeighbors, neighbors, &n);
    9023:     if (n < 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Could not locate remote rank %D", rrank);
    9024:     switch (refiner) {
    9025:     case REFINER_SIMPLEX_1D:
    9026:       if ((p >= vStart) && (p < vEnd)) {
    9027:         /* Old vertices stay the same */
    9028:         localPointsNew[m]        = vStartNew     + (p  - vStart);
    9029:         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
    9030:         remotePointsNew[m].rank  = rrank;
    9031:         ++m;
    9032:       } else if ((p >= cStart) && (p < cMax)) {
    9033:         /* Old interior cells add new cells and vertex */
    9034:         for (r = 0; r < 2; ++r, ++m) {
    9035:           localPointsNew[m]        = cStartNew     + (p  - cStart)*2     + r;
    9036:           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*2 + r;
    9037:           remotePointsNew[m].rank  = rrank;
    9038:         }
    9039:         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - cStart);
    9040:         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - rcStart[n]);
    9041:         remotePointsNew[m].rank  = rrank;
    9042:         ++m;
    9043:       }
    9044:       break;
    9045:     case REFINER_SIMPLEX_2D:
    9046:     case REFINER_HYBRID_SIMPLEX_2D:
    9047:       if ((p >= vStart) && (p < vEnd)) {
    9048:         /* Old vertices stay the same */
    9049:         localPointsNew[m]        = vStartNew     + (p  - vStart);
    9050:         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
    9051:         remotePointsNew[m].rank  = rrank;
    9052:         ++m;
    9053:       } else if ((p >= fStart) && (p < fMax)) {
    9054:         /* Old interior faces add new faces and vertex */
    9055:         for (r = 0; r < 2; ++r, ++m) {
    9056:           localPointsNew[m]        = fStartNew     + (p  - fStart)*2     + r;
    9057:           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*2 + r;
    9058:           remotePointsNew[m].rank  = rrank;
    9059:         }
    9060:         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - fStart);
    9061:         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - rfStart[n]);
    9062:         remotePointsNew[m].rank  = rrank;
    9063:         ++m;
    9064:       } else if ((p >= fMax) && (p < fEnd)) {
    9065:         /* Old hybrid faces stay the same */
    9066:         localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (p  - fMax);
    9067:         remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*2 + (rp - rdepthMaxOld[n*(depth+1)+depth-1]);
    9068:         remotePointsNew[m].rank  = rrank;
    9069:         ++m;
    9070:       } else if ((p >= cStart) && (p < cMax)) {
    9071:         /* Old interior cells add new cells and interior faces */
    9072:         for (r = 0; r < 4; ++r, ++m) {
    9073:           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
    9074:           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
    9075:           remotePointsNew[m].rank  = rrank;
    9076:         }
    9077:         for (r = 0; r < 3; ++r, ++m) {
    9078:           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (p  - cStart)*3     + r;
    9079:           remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*2 + (rp - rcStart[n])*3 + r;
    9080:           remotePointsNew[m].rank  = rrank;
    9081:         }
    9082:       } else if ((p >= cMax) && (p < cEnd)) {
    9083:         /* Old hybrid cells add new cells and hybrid face */
    9084:         for (r = 0; r < 2; ++r, ++m) {
    9085:           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
    9086:           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
    9087:           remotePointsNew[m].rank  = rrank;
    9088:         }
    9089:         localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (cMax                            - cStart)*3     + (p  - cMax);
    9090:         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]);
    9091:         remotePointsNew[m].rank  = rrank;
    9092:         ++m;
    9093:       }
    9094:       break;
    9095:     case REFINER_HYBRID_SIMPLEX_TO_HEX_2D:
    9096:     case REFINER_SIMPLEX_TO_HEX_2D:
    9097:       if ((p >= vStart) && (p < vEnd)) {
    9098:         /* Old vertices stay the same */
    9099:         localPointsNew[m]        = vStartNew     + (p  - vStart);
    9100:         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
    9101:         remotePointsNew[m].rank  = rrank;
    9102:         ++m;
    9103:       } else if ((p >= fStart) && (p < fEnd)) {
    9104:         /* Old interior faces add new faces and vertex */
    9105:         for (r = 0; r < 2; ++r, ++m) {
    9106:           localPointsNew[m]        = fStartNew     + (p  - fStart)*2     + r;
    9107:           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*2 + r;
    9108:           remotePointsNew[m].rank  = rrank;
    9109:         }
    9110:         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - fStart);
    9111:         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - rfStart[n]);
    9112:         remotePointsNew[m].rank  = rrank;
    9113:         ++m;
    9114:       } else if ((p >= cStart) && (p < cMax)) {
    9115:         /* Old interior cells add new cells, interior faces, and a vertex */
    9116:         for (r = 0; r < 3; ++r, ++m) {
    9117:           localPointsNew[m]        = cStartNew     + (p  - cStart)*3     + r;
    9118:           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*3 + r;
    9119:           remotePointsNew[m].rank  = rrank;
    9120:         }
    9121:         for (r = 0; r < 3; ++r, ++m) {
    9122:           localPointsNew[m]        = fStartNew     + (fEnd - fStart)*2                    + (p  - cStart)*3     + r;
    9123:           remotePointsNew[m].index = rfStartNew[n] + rdepthSizeOld[n*(depth+1)+depth-1]*2 + (rp - rcStart[n])*3 + r;
    9124:           remotePointsNew[m].rank  = rrank;
    9125:         }
    9126:         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (fEnd - fStart)                    + (p  - cStart);
    9127:         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + rdepthSizeOld[n*(depth+1)+depth-1] + (rp - rcStart[n]);
    9128:         remotePointsNew[m].rank  = rrank;
    9129:         ++m;
    9130:       } else if ((p >= cMax) && (p < cEnd)) {
    9131:         /* Old interior hybrid cells add new cells, interior faces, and a vertex */
    9132:         for (r = 0; r < 4; ++r, ++m) {
    9133:           localPointsNew[m]        = cStartNew     + (cMax  - cStart)*3                               + (p  - cMax)*4 + r;
    9134:           remotePointsNew[m].index = rcStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth] - rcStart[n])*3 + (rp - rdepthMaxOld[n*(depth+1)+depth])*4 + r;
    9135:           remotePointsNew[m].rank  = rrank;
    9136:         }
    9137:         for (r = 0; r < 4; ++r, ++m) {
    9138:           localPointsNew[m]        = fStartNew     + (fEnd - fStart)*2                    + (cMax  - cStart)*3                               + (p - cMax)*4 + r;
    9139:           remotePointsNew[m].index = rfStartNew[n] + rdepthSizeOld[n*(depth+1)+depth-1]*2 + (rdepthMaxOld[n*(depth+1)+depth] - rcStart[n])*3 + (rp - rdepthMaxOld[n*(depth+1)+depth])*4 + r;
    9140:           remotePointsNew[m].rank  = rrank;
    9141:         }
    9142:         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (fEnd - fStart)                    + (p  - cStart);
    9143:         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + rdepthSizeOld[n*(depth+1)+depth-1] + (rp - rcStart[n]);
    9144:         remotePointsNew[m].rank  = rrank;
    9145:         ++m;
    9146:       }
    9147:       break;
    9148:     case REFINER_HEX_2D:
    9149:     case REFINER_HYBRID_HEX_2D:
    9150:       if ((p >= vStart) && (p < vEnd)) {
    9151:         /* Old vertices stay the same */
    9152:         localPointsNew[m]        = vStartNew     + (p  - vStart);
    9153:         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
    9154:         remotePointsNew[m].rank  = rrank;
    9155:         ++m;
    9156:       } else if ((p >= fStart) && (p < fMax)) {
    9157:         /* Old interior faces add new faces and vertex */
    9158:         for (r = 0; r < 2; ++r, ++m) {
    9159:           localPointsNew[m]        = fStartNew     + (p  - fStart)*2     + r;
    9160:           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*2 + r;
    9161:           remotePointsNew[m].rank  = rrank;
    9162:         }
    9163:         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - fStart);
    9164:         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - rfStart[n]);
    9165:         remotePointsNew[m].rank  = rrank;
    9166:         ++m;
    9167:       } else if ((p >= fMax) && (p < fEnd)) {
    9168:         /* Old hybrid faces stay the same */
    9169:         localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (p  - fMax);
    9170:         remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*2 + (rp - rdepthMaxOld[n*(depth+1)+depth-1]);
    9171:         remotePointsNew[m].rank  = rrank;
    9172:         ++m;
    9173:       } else if ((p >= cStart) && (p < cMax)) {
    9174:         /* Old interior cells add new cells, interior faces, and vertex */
    9175:         for (r = 0; r < 4; ++r, ++m) {
    9176:           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
    9177:           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
    9178:           remotePointsNew[m].rank  = rrank;
    9179:         }
    9180:         for (r = 0; r < 4; ++r, ++m) {
    9181:           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (p  - cStart)*4     + r;
    9182:           remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*2 + (rp - rcStart[n])*4 + r;
    9183:           remotePointsNew[m].rank  = rrank;
    9184:         }
    9185:         localPointsNew[m]        = vStartNew     + (vEnd - vStart)               + (fMax                              - fStart)     + (p  - cStart);
    9186:         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0]  + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n]) + (rp - rcStart[n]);
    9187:         remotePointsNew[m].rank  = rrank;
    9188:         ++m;
    9189:       } else if ((p >= cStart) && (p < cMax)) {
    9190:         /* Old hybrid cells add new cells and hybrid face */
    9191:         for (r = 0; r < 2; ++r, ++m) {
    9192:           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r; /* TODO: is this a bug? */
    9193:           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r; /* TODO: is this a bug? */
    9194:           remotePointsNew[m].rank  = rrank;
    9195:         }
    9196:         localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (cMax                            - cStart)*4     + (p  - cMax);
    9197:         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]);
    9198:         remotePointsNew[m].rank  = rrank;
    9199:         ++m;
    9200:       }
    9201:       break;
    9202:     case REFINER_SIMPLEX_3D:
    9203:     case REFINER_HYBRID_SIMPLEX_3D:
    9204:       if ((p >= vStart) && (p < vEnd)) {
    9205:         /* Interior vertices stay the same */
    9206:         localPointsNew[m]        = vStartNew     + (p  - vStart);
    9207:         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
    9208:         remotePointsNew[m].rank  = rrank;
    9209:         ++m;
    9210:       } else if ((p >= eStart) && (p < eMax)) {
    9211:         /* Interior edges add new edges and vertex */
    9212:         for (r = 0; r < 2; ++r, ++m) {
    9213:           localPointsNew[m]        = eStartNew     + (p  - eStart)*2     + r;
    9214:           remotePointsNew[m].index = reStartNew[n] + (rp - reStart[n])*2 + r;
    9215:           remotePointsNew[m].rank  = rrank;
    9216:         }
    9217:         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - eStart);
    9218:         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - reStart[n]);
    9219:         remotePointsNew[m].rank  = rrank;
    9220:         ++m;
    9221:       } else if ((p >= eMax) && (p < eEnd)) {
    9222:         /* Hybrid edges stay the same */
    9223:         localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (fMax                              - fStart)*3     + (cMax                            - cStart)     + (p  - eMax);
    9224:         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]);
    9225:         remotePointsNew[m].rank  = rrank;
    9226:         ++m;
    9227:       } else if ((p >= fStart) && (p < fMax)) {
    9228:         /* Interior faces add new faces and edges */
    9229:         for (r = 0; r < 4; ++r, ++m) {
    9230:           localPointsNew[m]        = fStartNew     + (p  - fStart)*4     + r;
    9231:           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*4 + r;
    9232:           remotePointsNew[m].rank  = rrank;
    9233:         }
    9234:         for (r = 0; r < 3; ++r, ++m) {
    9235:           localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (p  - fStart)*3     + r;
    9236:           remotePointsNew[m].index = reStartNew[n] + (rdepthMaxOld[n*(depth+1)+1] - reStart[n])*2 + (rp - rfStart[n])*3 + r;
    9237:           remotePointsNew[m].rank  = rrank;
    9238:         }
    9239:       } else if ((p >= fMax) && (p < fEnd)) {
    9240:         /* Hybrid faces add new faces and edges */
    9241:         for (r = 0; r < 2; ++r, ++m) {
    9242:           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*4     + (cMax                            - cStart)*8     + (p  - fMax)*2                              + r;
    9243:           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;
    9244:           remotePointsNew[m].rank  = rrank;
    9245:         }
    9246:         localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (fMax                              - fStart)*3     + (cMax                            - cStart)     + (eEnd                                    - eMax)                        + (p  - fMax);
    9247:         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]);
    9248:         remotePointsNew[m].rank  = rrank;
    9249:         ++m;
    9250:       } else if ((p >= cStart) && (p < cMax)) {
    9251:         /* Interior cells add new cells, faces, and edges */
    9252:         for (r = 0; r < 8; ++r, ++m) {
    9253:           localPointsNew[m]        = cStartNew     + (p  - cStart)*8     + r;
    9254:           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*8 + r;
    9255:           remotePointsNew[m].rank  = rrank;
    9256:         }
    9257:         for (r = 0; r < 8; ++r, ++m) {
    9258:           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*4     + (p  - cStart)*8     + r;
    9259:           remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*4 + (rp - rcStart[n])*8 + r;
    9260:           remotePointsNew[m].rank  = rrank;
    9261:         }
    9262:         localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (fMax                              - fStart)*3     + (p  - cStart)*1     + 0;
    9263:         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;
    9264:         remotePointsNew[m].rank  = rrank;
    9265:         ++m;
    9266:       } else if ((p >= cMax) && (p < cEnd)) {
    9267:         /* Hybrid cells add new cells and faces */
    9268:         for (r = 0; r < 4; ++r, ++m) {
    9269:           localPointsNew[m]        = cStartNew     + (cMax                            - cStart)*8     + (p  - cMax)*4                            + r;
    9270:           remotePointsNew[m].index = rcStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth] - rcStart[n])*8 + (rp - rdepthMaxOld[n*(depth+1)+depth])*4 + r;
    9271:           remotePointsNew[m].rank  = rrank;
    9272:         }
    9273:         for (r = 0; r < 3; ++r, ++m) {
    9274:           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*4     + (cMax                            - cStart)*8     + (fEnd                                          - fMax)*2                              + (p  - cMax)*3                            + r;
    9275:           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;
    9276:           remotePointsNew[m].rank  = rrank;
    9277:         }
    9278:       }
    9279:       break;
    9280:     case REFINER_HYBRID_SIMPLEX_TO_HEX_3D:
    9281:     case REFINER_SIMPLEX_TO_HEX_3D:
    9282:       if ((p >= vStart) && (p < vEnd)) {
    9283:         /* Interior vertices stay the same */
    9284:         localPointsNew[m]        = vStartNew     + (p  - vStart);
    9285:         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
    9286:         remotePointsNew[m].rank  = rrank;
    9287:         ++m;
    9288:       } else if ((p >= eStart) && (p < eMax)) {
    9289:         /* Interior edges add new edges and vertex */
    9290:         for (r = 0; r < 2; ++r, ++m) {
    9291:           localPointsNew[m]        = eStartNew     + (p  - eStart)*2     + r;
    9292:           remotePointsNew[m].index = reStartNew[n] + (rp - reStart[n])*2 + r;
    9293:           remotePointsNew[m].rank  = rrank;
    9294:         }
    9295:         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - eStart);
    9296:         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - reStart[n]);
    9297:         remotePointsNew[m].rank  = rrank;
    9298:         ++m;
    9299:       } else if ((p >= eMax) && (p < eEnd)) {
    9300:         /* Hybrid edges stay the same */
    9301:         localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (fMax                              - fStart)*3     + (cMax                            - cStart)*4     + (p  - eMax);
    9302:         remotePointsNew[m].index = reStartNew[n] + (rdepthMaxOld[n*(depth+1)+1] - reStart[n])*2 + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*3 + (rdepthMaxOld[n*(depth+1)+depth] - rcStart[n])*4 + (rp - rdepthMaxOld[n*(depth+1)+1]);
    9303:         remotePointsNew[m].rank  = rrank;
    9304:         ++m;
    9305:       } else if ((p >= fStart) && (p < fMax)) {
    9306:         /* Interior faces add new faces, edges and a vertex */
    9307:         for (r = 0; r < 3; ++r, ++m) {
    9308:           localPointsNew[m]        = fStartNew     + (p  - fStart)*3     + r;
    9309:           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*3 + r;
    9310:           remotePointsNew[m].rank  = rrank;
    9311:         }
    9312:         for (r = 0; r < 3; ++r, ++m) {
    9313:           localPointsNew[m]        = eStartNew     + (eMax - eStart)*2                            + (p  - fStart)*3     + r;
    9314:           remotePointsNew[m].index = reStartNew[n] + (rdepthMaxOld[n*(depth+1)+1] - reStart[n])*2 + (rp - rfStart[n])*3 + r;
    9315:           remotePointsNew[m].rank  = rrank;
    9316:         }
    9317:         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (eMax - eStart)                            + (p - fStart);
    9318:         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rdepthMaxOld[n*(depth+1)+1] - reStart[n]) + (rp - rfStart[n]);
    9319:         remotePointsNew[m].rank  = rrank;
    9320:         ++m;
    9321:       } else if ((p >= fMax) && (p < fEnd)) {
    9322:         /* Interior hybrid faces add new faces and an edge */
    9323:         for (r = 0; r < 2; ++r, ++m) {
    9324:           localPointsNew[m]        = fStartNew     + (fMax - fStart)*3                                 + (cMax - cStart)*6                                + (p  - fMax)*2 + r;
    9325:           remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1]- rfStart[n])*3 + (rdepthMaxOld[n*(depth+1)+depth] - rcStart[n])*6 + (rp - rdepthMaxOld[n*(depth+1)+depth-1])*2 + r;
    9326:           remotePointsNew[m].rank  = rrank;
    9327:         }
    9328:         localPointsNew[m]        = eStartNew     + (eMax - eStart)*2                            + (fMax - fStart)*3                                 + (cMax - cStart)*4                                + (eEnd - eMax)                                                           + (p  - fMax);
    9329:         remotePointsNew[m].index = reStartNew[n] + (rdepthMaxOld[n*(depth+1)+1] - reStart[n])*2 + (rdepthMaxOld[n*(depth+1)+depth-1]- rfStart[n])*3 + (rdepthMaxOld[n*(depth+1)+depth] - rcStart[n])*4 + (rdepthSizeOld[n*(depth+1)+1]+reStart[n] - rdepthMaxOld[n*(depth+1)+1]) + (rp - rdepthMaxOld[n*(depth+1)+depth-1]);
    9330:         remotePointsNew[m].rank  = rrank;
    9331:         ++m;
    9332:       } else if ((p >= cStart) && (p < cMax)) {
    9333:         /* Interior cells add new cells, faces, edges, and a vertex */
    9334:         for (r = 0; r < 4; ++r, ++m) {
    9335:           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
    9336:           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
    9337:           remotePointsNew[m].rank  = rrank;
    9338:         }
    9339:         for (r = 0; r < 6; ++r, ++m) {
    9340:           localPointsNew[m]        = fStartNew     + (fMax - fStart)*3                                 + (p  - cStart)*6     + r;
    9341:           remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1]- rfStart[n])*3 + (rp - rcStart[n])*6 + r;
    9342:           remotePointsNew[m].rank  = rrank;
    9343:         }
    9344:         for (r = 0; r < 4; ++r, ++m) {
    9345:           localPointsNew[m]        = eStartNew     + (eMax - eStart)*2                           + (fMax - fStart)*3                                 + (p  - cStart)*4 + r;
    9346:           remotePointsNew[m].index = reStartNew[n] + (rdepthMaxOld[n*(depth+1)+1]- reStart[n])*2 + (rdepthMaxOld[n*(depth+1)+depth-1]- rfStart[n])*3 + (rp - rcStart[n])*4 + r;
    9347:           remotePointsNew[m].rank  = rrank;
    9348:         }
    9349:         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (eMax - eStart)                           + (fMax - fStart)                                 + (p  - cStart);
    9350:         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rdepthMaxOld[n*(depth+1)+1]- reStart[n]) + (rdepthMaxOld[n*(depth+1)+depth-1]- rfStart[n]) + (rp - rcStart[n]);
    9351:         remotePointsNew[m].rank  = rrank;
    9352:         ++m;
    9353:       } else if ((p >= cMax) && (p < cEnd)) {
    9354:         /* Interior hybrid cells add new cells, faces and an edge */
    9355:         for (r = 0; r < 3; ++r, ++m) {
    9356:           localPointsNew[m]        = cStartNew     + (cMax                            - cStart)*4     + (p  - cMax)*3                            + r;
    9357:           remotePointsNew[m].index = rcStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth] - rcStart[n])*4 + (rp - rdepthMaxOld[n*(depth+1)+depth])*3 + r;
    9358:           remotePointsNew[m].rank  = rrank;
    9359:         }
    9360:         for (r = 0; r < 3; ++r, ++m) {
    9361:           localPointsNew[m]        = fStartNew     + (fMax - fStart)*3                                 + (cMax - cStart)*6                                + (fEnd  - fMax)*2                                                                      + (p  - cMax)*3 + r;
    9362:           remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1]- rfStart[n])*3 + (rdepthMaxOld[n*(depth+1)+depth] - rcStart[n])*6 + (rdepthSizeOld[n*(depth+1)+depth-1]+rfStart[n] - rdepthMaxOld[n*(depth+1)+depth-1])*2 + (rp - rdepthMaxOld[n*(depth+1)+depth])*3 + r;
    9363:           remotePointsNew[m].rank  = rrank;
    9364:         }
    9365:         localPointsNew[m]        = eStartNew     + (eMax - eStart)*2                           + (fMax - fStart)*3                                 + (cMax - cStart)*4                                + (eEnd  - eMax)                                                          + (fEnd  - fMax)                                                                      + (p  - cMax);
    9366:         remotePointsNew[m].index = reStartNew[n] + (rdepthMaxOld[n*(depth+1)+1]- reStart[n])*2 + (rdepthMaxOld[n*(depth+1)+depth-1]- rfStart[n])*3 + (rdepthMaxOld[n*(depth+1)+depth] - rcStart[n])*4 + (rdepthSizeOld[n*(depth+1)+1]+reStart[n] - rdepthMaxOld[n*(depth+1)+1]) + (rdepthSizeOld[n*(depth+1)+depth-1]+rfStart[n] - rdepthMaxOld[n*(depth+1)+depth-1]) + (rp - rdepthMaxOld[n*(depth+1)+depth]);
    9367:         remotePointsNew[m].rank  = rrank;
    9368:         ++m;
    9369:       }
    9370:       break;
    9371:     case REFINER_HEX_3D:
    9372:     case REFINER_HYBRID_HEX_3D:
    9373:       if ((p >= vStart) && (p < vEnd)) {
    9374:         /* Interior vertices stay the same */
    9375:         localPointsNew[m]        = vStartNew     + (p  - vStart);
    9376:         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
    9377:         remotePointsNew[m].rank  = rrank;
    9378:         ++m;
    9379:       } else if ((p >= eStart) && (p < eMax)) {
    9380:         /* Interior edges add new edges and vertex */
    9381:         for (r = 0; r < 2; ++r, ++m) {
    9382:           localPointsNew[m]        = eStartNew     + (p  - eStart)*2     + r;
    9383:           remotePointsNew[m].index = reStartNew[n] + (rp - reStart[n])*2 + r;
    9384:           remotePointsNew[m].rank  = rrank;
    9385:         }
    9386:         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - eStart);
    9387:         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - reStart[n]);
    9388:         remotePointsNew[m].rank  = rrank;
    9389:         ++m;
    9390:       } else if ((p >= eMax) && (p < eEnd)) {
    9391:         /* Hybrid edges stay the same */
    9392:         localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (fMax                              - fStart)*4     + (cMax                            - cStart)*6     + (p  - eMax);
    9393:         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]);
    9394:         remotePointsNew[m].rank  = rrank;
    9395:         ++m;
    9396:       } else if ((p >= fStart) && (p < fMax)) {
    9397:         /* Interior faces add new faces, edges, and vertex */
    9398:         for (r = 0; r < 4; ++r, ++m) {
    9399:           localPointsNew[m]        = fStartNew     + (p  - fStart)*4     + r;
    9400:           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*4 + r;
    9401:           remotePointsNew[m].rank  = rrank;
    9402:         }
    9403:         for (r = 0; r < 4; ++r, ++m) {
    9404:           localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (p  - fStart)*4     + r;
    9405:           remotePointsNew[m].index = reStartNew[n] + (rdepthMaxOld[n*(depth+1)+1] - reStart[n])*2 + (rp - rfStart[n])*4 + r;
    9406:           remotePointsNew[m].rank  = rrank;
    9407:         }
    9408:         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (eMax                        - eStart)     + (p  - fStart);
    9409:         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rdepthMaxOld[n*(depth+1)+1] - reStart[n]) + (rp - rfStart[n]);
    9410:         remotePointsNew[m].rank  = rrank;
    9411:         ++m;
    9412:       } else if ((p >= fMax) && (p < fEnd)) {
    9413:         /* Hybrid faces add new faces and edges */
    9414:         for (r = 0; r < 2; ++r, ++m) {
    9415:           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*4     + (cMax                            - cStart)*12     + (p  - fMax)*2                              + r;
    9416:           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;
    9417:           remotePointsNew[m].rank  = rrank;
    9418:         }
    9419:         localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (fMax                              - fStart)*4     + (cMax                            - cStart)*6     + (eEnd                                    - eMax)                        + (p  - fMax);
    9420:         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]);
    9421:         remotePointsNew[m].rank  = rrank;
    9422:         ++m;
    9423:       } else if ((p >= cStart) && (p < cMax)) {
    9424:         /* Interior cells add new cells, faces, edges, and vertex */
    9425:         for (r = 0; r < 8; ++r, ++m) {
    9426:           localPointsNew[m]        = cStartNew     + (p  - cStart)*8     + r;
    9427:           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*8 + r;
    9428:           remotePointsNew[m].rank  = rrank;
    9429:         }
    9430:         for (r = 0; r < 12; ++r, ++m) {
    9431:           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*4     + (p  - cStart)*12     + r;
    9432:           remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*4 + (rp - rcStart[n])*12 + r;
    9433:           remotePointsNew[m].rank  = rrank;
    9434:         }
    9435:         for (r = 0; r < 6; ++r, ++m) {
    9436:           localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (fMax                              - fStart)*4     + (p  - cStart)*6     + r;
    9437:           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;
    9438:           remotePointsNew[m].rank  = rrank;
    9439:         }
    9440:         for (r = 0; r < 1; ++r, ++m) {
    9441:           localPointsNew[m]        = vStartNew     + (eMax                        - eStart)     + (fMax                              - fStart)     + (p  - cStart)     + r;
    9442:           remotePointsNew[m].index = rvStartNew[n] + (rdepthMaxOld[n*(depth+1)+1] - reStart[n]) + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n]) + (rp - rcStart[n]) + r;
    9443:           remotePointsNew[m].rank  = rrank;
    9444:         }
    9445:       } else if ((p >= cMax) && (p < cEnd)) {
    9446:         /* Hybrid cells add new cells, faces, and edges */
    9447:         for (r = 0; r < 4; ++r, ++m) {
    9448:           localPointsNew[m]        = cStartNew     + (cMax                            - cStart)*8     + (p  - cMax)*4                            + r;
    9449:           remotePointsNew[m].index = rcStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth] - rcStart[n])*8 + (rp - rdepthMaxOld[n*(depth+1)+depth])*4 + r;
    9450:           remotePointsNew[m].rank  = rrank;
    9451:         }
    9452:         for (r = 0; r < 4; ++r, ++m) {
    9453:           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*4     + (cMax                            - cStart)*12     + (fEnd                                          - fMax)*2                              + (p  - cMax)*4                            + r;
    9454:           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;
    9455:           remotePointsNew[m].rank  = rrank;
    9456:         }
    9457:         localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (fMax                              - fStart)*4     + (cMax                            - cStart)*6     + (eEnd                                    - eMax)                        + (fEnd                                          - fMax)                              + (p  - cMax);
    9458:         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]);
    9459:         remotePointsNew[m].rank  = rrank;
    9460:         ++m;
    9461:       }
    9462:       break;
    9463:     default:
    9464:       SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %D", refiner);
    9465:     }
    9466:   }
    9467:   if (m != numLeavesNew) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Number of leaf point %D should be %D", m, numLeavesNew);
    9468:   ISRestoreIndices(processRanks, &neighbors);
    9469:   ISDestroy(&processRanks);
    9470:   {
    9471:     PetscSFNode *rp, *rtmp;
    9472:     PetscInt    *lp, *idx, *ltmp, i;

    9474:     /* SF needs sorted leaves to correct calculate Gather */
    9475:     PetscMalloc1(numLeavesNew,&idx);
    9476:     PetscMalloc1(numLeavesNew, &lp);
    9477:     PetscMalloc1(numLeavesNew, &rp);
    9478:     for (i = 0; i < numLeavesNew; ++i) {
    9479:       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);
    9480:       idx[i] = i;
    9481:     }
    9482:     PetscSortIntWithPermutation(numLeavesNew, localPointsNew, idx);
    9483:     for (i = 0; i < numLeavesNew; ++i) {
    9484:       lp[i] = localPointsNew[idx[i]];
    9485:       rp[i] = remotePointsNew[idx[i]];
    9486:     }
    9487:     ltmp            = localPointsNew;
    9488:     localPointsNew  = lp;
    9489:     rtmp            = remotePointsNew;
    9490:     remotePointsNew = rp;
    9491:     PetscFree(idx);
    9492:     PetscFree(ltmp);
    9493:     PetscFree(rtmp);
    9494:   }
    9495:   PetscSFSetGraph(sfNew, pEndNew-pStartNew, numLeavesNew, localPointsNew, PETSC_OWN_POINTER, remotePointsNew, PETSC_OWN_POINTER);
    9496:   PetscFree5(rdepthSize,rvStartNew,reStartNew,rfStartNew,rcStartNew);
    9497:   PetscFree7(depthSizeOld,rdepthSizeOld,rdepthMaxOld,rvStart,reStart,rfStart,rcStart);
    9498:   return(0);
    9499: }

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

    9509:   DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);
    9510:   DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);
    9511:   DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);
    9512:   DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);
    9513:   DMPlexGetDepth(dm, &depth);
    9514:   if (refiner) {GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);}
    9515:   DMGetNumLabels(dm, &numLabels);
    9516:   DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);
    9517:   switch (refiner) {
    9518:   case REFINER_NOOP:
    9519:   case REFINER_SIMPLEX_1D:
    9520:   case REFINER_SIMPLEX_2D:
    9521:   case REFINER_SIMPLEX_TO_HEX_2D:
    9522:   case REFINER_HEX_2D:
    9523:   case REFINER_SIMPLEX_3D:
    9524:   case REFINER_HEX_3D:
    9525:   case REFINER_SIMPLEX_TO_HEX_3D:
    9526:     break;
    9527:   case REFINER_HYBRID_SIMPLEX_TO_HEX_3D:
    9528:   case REFINER_HYBRID_SIMPLEX_3D:
    9529:   case REFINER_HYBRID_HEX_3D:
    9530:     if (eMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No edge maximum specified in hybrid mesh");
    9531:   case REFINER_HYBRID_SIMPLEX_2D:
    9532:   case REFINER_HYBRID_HEX_2D:
    9533:     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
    9534:   case REFINER_HYBRID_SIMPLEX_TO_HEX_2D:
    9535:     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
    9536:     break;
    9537:   default:
    9538:     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %D", refiner);
    9539:   }
    9540:   cMax = cMax < 0 ? cEnd : cMax;
    9541:   fMax = fMax < 0 ? fEnd : fMax;
    9542:   eMax = eMax < 0 ? eEnd : eMax;
    9543:   for (l = 0; l < numLabels; ++l) {
    9544:     DMLabel         label, labelNew;
    9545:     const char     *lname;
    9546:     PetscBool       isDepth;
    9547:     IS              valueIS;
    9548:     const PetscInt *values;
    9549:     PetscInt        defVal;
    9550:     PetscInt        numValues, val;

    9552:     DMGetLabelName(dm, l, &lname);
    9553:     PetscStrcmp(lname, "depth", &isDepth);
    9554:     if (isDepth) continue;
    9555:     DMCreateLabel(rdm, lname);
    9556:     DMGetLabel(dm, lname, &label);
    9557:     DMGetLabel(rdm, lname, &labelNew);
    9558:     DMLabelGetDefaultValue(label,&defVal);
    9559:     DMLabelSetDefaultValue(labelNew,defVal);
    9560:     DMLabelGetValueIS(label, &valueIS);
    9561:     ISGetLocalSize(valueIS, &numValues);
    9562:     ISGetIndices(valueIS, &values);
    9563:     for (val = 0; val < numValues; ++val) {
    9564:       IS              pointIS;
    9565:       const PetscInt *points;
    9566:       PetscInt        numPoints, n;

    9568:       DMLabelGetStratumIS(label, values[val], &pointIS);
    9569:       ISGetLocalSize(pointIS, &numPoints);
    9570:       ISGetIndices(pointIS, &points);
    9571:       /* Ensure refined label is created with same number of strata as
    9572:        * original (even if no entries here). */
    9573:       DMLabelAddStratum(labelNew, values[val]);
    9574:       for (n = 0; n < numPoints; ++n) {
    9575:         const PetscInt p = points[n];
    9576:         switch (refiner) {
    9577:         case REFINER_SIMPLEX_1D:
    9578:           if ((p >= vStart) && (p < vEnd)) {
    9579:             /* Old vertices stay the same */
    9580:             newp = vStartNew + (p - vStart);
    9581:             DMLabelSetValue(labelNew, newp, values[val]);
    9582:           } else if ((p >= cStart) && (p < cEnd)) {
    9583:             /* Old cells add new cells and vertex */
    9584:             newp = vStartNew + (vEnd - vStart) + (p - cStart);
    9585:             DMLabelSetValue(labelNew, newp, values[val]);
    9586:             for (r = 0; r < 2; ++r) {
    9587:               newp = cStartNew + (p - cStart)*2 + r;
    9588:               DMLabelSetValue(labelNew, newp, values[val]);
    9589:             }
    9590:           }
    9591:           break;
    9592:         case REFINER_SIMPLEX_2D:
    9593:           if ((p >= vStart) && (p < vEnd)) {
    9594:             /* Old vertices stay the same */
    9595:             newp = vStartNew + (p - vStart);
    9596:             DMLabelSetValue(labelNew, newp, values[val]);
    9597:           } else if ((p >= fStart) && (p < fEnd)) {
    9598:             /* Old faces add new faces and vertex */
    9599:             newp = vStartNew + (vEnd - vStart) + (p - fStart);
    9600:             DMLabelSetValue(labelNew, newp, values[val]);
    9601:             for (r = 0; r < 2; ++r) {
    9602:               newp = fStartNew + (p - fStart)*2 + r;
    9603:               DMLabelSetValue(labelNew, newp, values[val]);
    9604:             }
    9605:           } else if ((p >= cStart) && (p < cEnd)) {
    9606:             /* Old cells add new cells and interior faces */
    9607:             for (r = 0; r < 4; ++r) {
    9608:               newp = cStartNew + (p - cStart)*4 + r;
    9609:               DMLabelSetValue(labelNew, newp, values[val]);
    9610:             }
    9611:             for (r = 0; r < 3; ++r) {
    9612:               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*3 + r;
    9613:               DMLabelSetValue(labelNew, newp, values[val]);
    9614:             }
    9615:           }
    9616:           break;
    9617:         case REFINER_HYBRID_SIMPLEX_TO_HEX_2D:
    9618:         case REFINER_SIMPLEX_TO_HEX_2D:
    9619:           if ((p >= vStart) && (p < vEnd)) {
    9620:             /* Old vertices stay the same */
    9621:             newp = vStartNew + (p - vStart);
    9622:             DMLabelSetValue(labelNew, newp, values[val]);
    9623:           } else if ((p >= fStart) && (p < fEnd)) {
    9624:             /* Old faces add new faces and vertex */
    9625:             newp = vStartNew + (vEnd - vStart) + (p - fStart);
    9626:             DMLabelSetValue(labelNew, newp, values[val]);
    9627:             for (r = 0; r < 2; ++r) {
    9628:               newp = fStartNew + (p - fStart)*2 + r;
    9629:               DMLabelSetValue(labelNew, newp, values[val]);
    9630:             }
    9631:           } else if ((p >= cStart) && (p < cMax)) {
    9632:             /* Old cells add new cells, interior faces, and a vertex */
    9633:             for (r = 0; r < 3; ++r) {
    9634:               newp = cStartNew + (p - cStart)*3 + r;
    9635:               DMLabelSetValue(labelNew, newp, values[val]);
    9636:             }
    9637:             for (r = 0; r < 3; ++r) {
    9638:               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*3 + r;
    9639:               DMLabelSetValue(labelNew, newp, values[val]);
    9640:             }
    9641:             newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + p;
    9642:             DMLabelSetValue(labelNew, newp, values[val]);
    9643:           } else if ((p >= cMax) && (p < cEnd)) {
    9644:             /* Old hybrid cells add new cells, interior faces, and a vertex */
    9645:             for (r = 0; r < 4; ++r) {
    9646:               newp = cStartNew + (cMax - cStart)*3 + (p - cMax)*4 + r;
    9647:               DMLabelSetValue(labelNew, newp, values[val]);
    9648:             }
    9649:             for (r = 0; r < 4; ++r) {
    9650:               newp = fStartNew + (fEnd - fStart)*2 + (cMax - cStart)*3 + (p - cMax)*4 + r;
    9651:               DMLabelSetValue(labelNew, newp, values[val]);
    9652:             }
    9653:             newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + p;
    9654:             DMLabelSetValue(labelNew, newp, values[val]);
    9655:           }
    9656:           break;
    9657:         case REFINER_HEX_2D:
    9658:           if ((p >= vStart) && (p < vEnd)) {
    9659:             /* Old vertices stay the same */
    9660:             newp = vStartNew + (p - vStart);
    9661:             DMLabelSetValue(labelNew, newp, values[val]);
    9662:           } else if ((p >= fStart) && (p < fEnd)) {
    9663:             /* Old faces add new faces and vertex */
    9664:             newp = vStartNew + (vEnd - vStart) + (p - fStart);
    9665:             DMLabelSetValue(labelNew, newp, values[val]);
    9666:             for (r = 0; r < 2; ++r) {
    9667:               newp = fStartNew + (p - fStart)*2 + r;
    9668:               DMLabelSetValue(labelNew, newp, values[val]);
    9669:             }
    9670:           } else if ((p >= cStart) && (p < cEnd)) {
    9671:             /* Old cells add new cells and interior faces and vertex */
    9672:             for (r = 0; r < 4; ++r) {
    9673:               newp = cStartNew + (p - cStart)*4 + r;
    9674:               DMLabelSetValue(labelNew, newp, values[val]);
    9675:             }
    9676:             for (r = 0; r < 4; ++r) {
    9677:               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*4 + r;
    9678:               DMLabelSetValue(labelNew, newp, values[val]);
    9679:             }
    9680:             newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (p - cStart);
    9681:             DMLabelSetValue(labelNew, newp, values[val]);
    9682:           }
    9683:           break;
    9684:         case REFINER_HYBRID_SIMPLEX_2D:
    9685:           if ((p >= vStart) && (p < vEnd)) {
    9686:             /* Old vertices stay the same */
    9687:             newp = vStartNew + (p - vStart);
    9688:             DMLabelSetValue(labelNew, newp, values[val]);
    9689:           } else if ((p >= fStart) && (p < fMax)) {
    9690:             /* Old interior faces add new faces and vertex */
    9691:             newp = vStartNew + (vEnd - vStart) + (p - fStart);
    9692:             DMLabelSetValue(labelNew, newp, values[val]);
    9693:             for (r = 0; r < 2; ++r) {
    9694:               newp = fStartNew + (p - fStart)*2 + r;
    9695:               DMLabelSetValue(labelNew, newp, values[val]);
    9696:             }
    9697:           } else if ((p >= fMax) && (p < fEnd)) {
    9698:             /* Old hybrid faces stay the same */
    9699:             newp = fStartNew + (fMax - fStart)*2 + (p - fMax);
    9700:             DMLabelSetValue(labelNew, newp, values[val]);
    9701:           } else if ((p >= cStart) && (p < cMax)) {
    9702:             /* Old interior cells add new cells and interior faces */
    9703:             for (r = 0; r < 4; ++r) {
    9704:               newp = cStartNew + (p - cStart)*4 + r;
    9705:               DMLabelSetValue(labelNew, newp, values[val]);
    9706:             }
    9707:             for (r = 0; r < 3; ++r) {
    9708:               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*3 + r;
    9709:               DMLabelSetValue(labelNew, newp, values[val]);
    9710:             }
    9711:           } else if ((p >= cMax) && (p < cEnd)) {
    9712:             /* Old hybrid cells add new cells and hybrid face */
    9713:             for (r = 0; r < 2; ++r) {
    9714:               newp = cStartNew + (cMax - cStart)*4 + (p - cMax)*2 + r;
    9715:               DMLabelSetValue(labelNew, newp, values[val]);
    9716:             }
    9717:             newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (p - cMax);
    9718:             DMLabelSetValue(labelNew, newp, values[val]);
    9719:           }
    9720:           break;
    9721:         case REFINER_HYBRID_HEX_2D:
    9722:           if ((p >= vStart) && (p < vEnd)) {
    9723:             /* Old vertices stay the same */
    9724:             newp = vStartNew + (p - vStart);
    9725:             DMLabelSetValue(labelNew, newp, values[val]);
    9726:           } else if ((p >= fStart) && (p < fMax)) {
    9727:             /* Old interior faces add new faces and vertex */
    9728:             newp = vStartNew + (vEnd - vStart) + (p - fStart);
    9729:             DMLabelSetValue(labelNew, newp, values[val]);
    9730:             for (r = 0; r < 2; ++r) {
    9731:               newp = fStartNew + (p - fStart)*2 + r;
    9732:               DMLabelSetValue(labelNew, newp, values[val]);
    9733:             }
    9734:           } else if ((p >= fMax) && (p < fEnd)) {
    9735:             /* Old hybrid faces stay the same */
    9736:             newp = fStartNew + (fMax - fStart)*2 + (p - fMax);
    9737:             DMLabelSetValue(labelNew, newp, values[val]);
    9738:           } else if ((p >= cStart) && (p < cMax)) {
    9739:             /* Old interior cells add new cells, interior faces, and vertex */
    9740:             for (r = 0; r < 4; ++r) {
    9741:               newp = cStartNew + (p - cStart)*4 + r;
    9742:               DMLabelSetValue(labelNew, newp, values[val]);
    9743:             }
    9744:             for (r = 0; r < 4; ++r) {
    9745:               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*4 + r;
    9746:               DMLabelSetValue(labelNew, newp, values[val]);
    9747:             }
    9748:             newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (p - cStart);
    9749:             DMLabelSetValue(labelNew, newp, values[val]);
    9750:           } else if ((p >= cMax) && (p < cEnd)) {
    9751:             /* Old hybrid cells add new cells and hybrid face */
    9752:             for (r = 0; r < 2; ++r) {
    9753:               newp = cStartNew + (cMax - cStart)*4 + (p - cMax)*2 + r;
    9754:               DMLabelSetValue(labelNew, newp, values[val]);
    9755:             }
    9756:             newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*4 + (p - cMax);
    9757:             DMLabelSetValue(labelNew, newp, values[val]);
    9758:           }
    9759:           break;
    9760:         case REFINER_SIMPLEX_3D:
    9761:           if ((p >= vStart) && (p < vEnd)) {
    9762:             /* Old vertices stay the same */
    9763:             newp = vStartNew + (p - vStart);
    9764:             DMLabelSetValue(labelNew, newp, values[val]);
    9765:           } else if ((p >= eStart) && (p < eEnd)) {
    9766:             /* Old edges add new edges and vertex */
    9767:             for (r = 0; r < 2; ++r) {
    9768:               newp = eStartNew + (p - eStart)*2 + r;
    9769:               DMLabelSetValue(labelNew, newp, values[val]);
    9770:             }
    9771:             newp = vStartNew + (vEnd - vStart) + (p - eStart);
    9772:             DMLabelSetValue(labelNew, newp, values[val]);
    9773:           } else if ((p >= fStart) && (p < fEnd)) {
    9774:             /* Old faces add new faces and edges */
    9775:             for (r = 0; r < 4; ++r) {
    9776:               newp = fStartNew + (p - fStart)*4 + r;
    9777:               DMLabelSetValue(labelNew, newp, values[val]);
    9778:             }
    9779:             for (r = 0; r < 3; ++r) {
    9780:               newp = eStartNew + (eEnd - eStart)*2 + (p - fStart)*3 + r;
    9781:               DMLabelSetValue(labelNew, newp, values[val]);
    9782:             }
    9783:           } else if ((p >= cStart) && (p < cEnd)) {
    9784:             /* Old cells add new cells and interior faces and edges */
    9785:             for (r = 0; r < 8; ++r) {
    9786:               newp = cStartNew + (p - cStart)*8 + r;
    9787:               DMLabelSetValue(labelNew, newp, values[val]);
    9788:             }
    9789:             for (r = 0; r < 8; ++r) {
    9790:               newp = fStartNew + (fEnd - fStart)*4 + (p - cStart)*8 + r;
    9791:               DMLabelSetValue(labelNew, newp, values[val]);
    9792:             }
    9793:             for (r = 0; r < 1; ++r) {
    9794:               newp = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (p - cStart)*1 + r;
    9795:               DMLabelSetValue(labelNew, newp, values[val]);
    9796:             }
    9797:           }
    9798:           break;
    9799:         case REFINER_HYBRID_SIMPLEX_TO_HEX_3D:
    9800:         case REFINER_SIMPLEX_TO_HEX_3D:
    9801:           if ((p >= vStart) && (p < vEnd)) {
    9802:             /* Old vertices stay the same */
    9803:             newp = vStartNew + (p - vStart);
    9804:             DMLabelSetValue(labelNew, newp, values[val]);
    9805:           } else if ((p >= eStart) && (p < eMax)) {
    9806:             /* Interior edges add new edges and vertex */
    9807:             for (r = 0; r < 2; ++r) {
    9808:               newp = eStartNew + (p - eStart)*2 + r;
    9809:               DMLabelSetValue(labelNew, newp, values[val]);
    9810:             }
    9811:             newp = vStartNew + (vEnd - vStart) + (p - eStart);
    9812:             DMLabelSetValue(labelNew, newp, values[val]);
    9813:           } else if ((p >= eMax) && (p < eEnd)) {
    9814:             /* Hybrid edges stay the same */
    9815:             newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart)*4 + p - eMax;
    9816:             DMLabelSetValue(labelNew, newp, values[val]);
    9817:           } else if ((p >= fStart) && (p < fMax)) {
    9818:             /* Old faces add new faces, edges and a vertex */
    9819:             for (r = 0; r < 3; ++r) {
    9820:               newp = fStartNew + (p - fStart)*3 + r;
    9821:               DMLabelSetValue(labelNew, newp, values[val]);
    9822:             }
    9823:             for (r = 0; r < 3; ++r) {
    9824:               newp = eStartNew + (eMax - eStart)*2 + (p - fStart)*3 + r;
    9825:               DMLabelSetValue(labelNew, newp, values[val]);
    9826:             }
    9827:           } else if ((p >= fMax) && (p < fEnd)) {
    9828:             /* Old hybrid faces add new faces and an edge */
    9829:             for (r = 0; r < 2; ++r) {
    9830:               newp = fStartNew + (fMax - fStart)*3 + (cMax - cStart)*6 + (p - fMax)*2 + r;
    9831:               DMLabelSetValue(labelNew, newp, values[val]);
    9832:             }
    9833:             newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart)*4 + (eEnd - eMax) + (p - fMax);
    9834:             DMLabelSetValue(labelNew, newp, values[val]);
    9835:           } else if ((p >= cStart) && (p < cMax)) {
    9836:             /* Old cells add new cells and interior faces and edges and a vertex */
    9837:             for (r = 0; r < 4; ++r) {
    9838:               newp = cStartNew + (p - cStart)*4 + r;
    9839:               DMLabelSetValue(labelNew, newp, values[val]);
    9840:             }
    9841:             for (r = 0; r < 6; ++r) {
    9842:               newp = fStartNew + (fMax - fStart)*3 + (p - cStart)*6 + r;
    9843:               DMLabelSetValue(labelNew, newp, values[val]);
    9844:             }
    9845:             for (r = 0; r < 4; ++r) {
    9846:               newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (p - cStart)*4 + r;
    9847:               DMLabelSetValue(labelNew, newp, values[val]);
    9848:             }
    9849:             newp = vStartNew + (vEnd - vStart) + (eMax - eStart) + (fMax - fStart) + p - cStart;
    9850:             DMLabelSetValue(labelNew, newp, values[val]);
    9851:           } else if ((p >= cMax) && (p < cEnd)) {
    9852:             /* Old hybrid cells add new cells and interior faces and an edge */
    9853:             for (r = 0; r < 3; ++r) {
    9854:               newp = cStartNew + (cMax - cStart)*4 + (p - cMax)*3 + r;
    9855:               DMLabelSetValue(labelNew, newp, values[val]);
    9856:             }
    9857:             for (r = 0; r < 3; ++r) {
    9858:               newp = fStartNew + (fMax - fStart)*3 + (cMax - cStart)*6 + (fEnd - fMax)*2 + (p - cMax)*3 + r;
    9859:               DMLabelSetValue(labelNew, newp, values[val]);
    9860:             }
    9861:             newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart)*4 + (eEnd - eMax) + (fEnd - fMax) + p - cMax;
    9862:             DMLabelSetValue(labelNew, newp, values[val]);
    9863:           }
    9864:           break;
    9865:         case REFINER_HYBRID_SIMPLEX_3D:
    9866:           if ((p >= vStart) && (p < vEnd)) {
    9867:             /* Interior vertices stay the same */
    9868:             newp = vStartNew + (p - vStart);
    9869:             DMLabelSetValue(labelNew, newp, values[val]);
    9870:           } else if ((p >= eStart) && (p < eMax)) {
    9871:             /* Interior edges add new edges and vertex */
    9872:             for (r = 0; r < 2; ++r) {
    9873:               newp = eStartNew + (p - eStart)*2 + r;
    9874:               DMLabelSetValue(labelNew, newp, values[val]);
    9875:             }
    9876:             newp = vStartNew + (vEnd - vStart) + (p - eStart);
    9877:             DMLabelSetValue(labelNew, newp, values[val]);
    9878:           } else if ((p >= eMax) && (p < eEnd)) {
    9879:             /* Hybrid edges stay the same */
    9880:             newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (p - eMax);
    9881:             DMLabelSetValue(labelNew, newp, values[val]);
    9882:           } else if ((p >= fStart) && (p < fMax)) {
    9883:             /* Interior faces add new faces and edges */
    9884:             for (r = 0; r < 4; ++r) {
    9885:               newp = fStartNew + (p - fStart)*4 + r;
    9886:               DMLabelSetValue(labelNew, newp, values[val]);
    9887:             }
    9888:             for (r = 0; r < 3; ++r) {
    9889:               newp = eStartNew + (eMax - eStart)*2 + (p - fStart)*3 + r;
    9890:               DMLabelSetValue(labelNew, newp, values[val]);
    9891:             }
    9892:           } else if ((p >= fMax) && (p < fEnd)) {
    9893:             /* Hybrid faces add new faces and edges */
    9894:             for (r = 0; r < 2; ++r) {
    9895:               newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (p - fMax)*2 + r;
    9896:               DMLabelSetValue(labelNew, newp, values[val]);
    9897:             }
    9898:             newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (p - fMax);
    9899:             DMLabelSetValue(labelNew, newp, values[val]);
    9900:           } else if ((p >= cStart) && (p < cMax)) {
    9901:             /* Interior cells add new cells, faces, and edges */
    9902:             for (r = 0; r < 8; ++r) {
    9903:               newp = cStartNew + (p - cStart)*8 + r;
    9904:               DMLabelSetValue(labelNew, newp, values[val]);
    9905:             }
    9906:             for (r = 0; r < 8; ++r) {
    9907:               newp = fStartNew + (fMax - fStart)*4 + (p - cStart)*8 + r;
    9908:               DMLabelSetValue(labelNew, newp, values[val]);
    9909:             }
    9910:             newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (p - cStart);
    9911:             DMLabelSetValue(labelNew, newp, values[val]);
    9912:           } else if ((p >= cMax) && (p < cEnd)) {
    9913:             /* Hybrid cells add new cells and faces */
    9914:             for (r = 0; r < 4; ++r) {
    9915:               newp = cStartNew + (cMax - cStart)*8 + (p - cMax)*4 + r;
    9916:               DMLabelSetValue(labelNew, newp, values[val]);
    9917:             }
    9918:             for (r = 0; r < 3; ++r) {
    9919:               newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (p - cMax)*3 + r;
    9920:               DMLabelSetValue(labelNew, newp, values[val]);
    9921:             }
    9922:           }
    9923:           break;
    9924:         case REFINER_HEX_3D:
    9925:           if ((p >= vStart) && (p < vEnd)) {
    9926:             /* Old vertices stay the same */
    9927:             newp = vStartNew + (p - vStart);
    9928:             DMLabelSetValue(labelNew, newp, values[val]);
    9929:           } else if ((p >= eStart) && (p < eEnd)) {
    9930:             /* Old edges add new edges and vertex */
    9931:             for (r = 0; r < 2; ++r) {
    9932:               newp = eStartNew + (p - eStart)*2 + r;
    9933:               DMLabelSetValue(labelNew, newp, values[val]);
    9934:             }
    9935:             newp = vStartNew + (vEnd - vStart) + (p - eStart);
    9936:             DMLabelSetValue(labelNew, newp, values[val]);
    9937:           } else if ((p >= fStart) && (p < fEnd)) {
    9938:             /* Old faces add new faces, edges, and vertex */
    9939:             for (r = 0; r < 4; ++r) {
    9940:               newp = fStartNew + (p - fStart)*4 + r;
    9941:               DMLabelSetValue(labelNew, newp, values[val]);
    9942:             }
    9943:             for (r = 0; r < 4; ++r) {
    9944:               newp = eStartNew + (eEnd - eStart)*2 + (p - fStart)*4 + r;
    9945:               DMLabelSetValue(labelNew, newp, values[val]);
    9946:             }
    9947:             newp = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (p - fStart);
    9948:             DMLabelSetValue(labelNew, newp, values[val]);
    9949:           } else if ((p >= cStart) && (p < cEnd)) {
    9950:             /* Old cells add new cells, faces, edges, and vertex */
    9951:             for (r = 0; r < 8; ++r) {
    9952:               newp = cStartNew + (p - cStart)*8 + r;
    9953:               DMLabelSetValue(labelNew, newp, values[val]);
    9954:             }
    9955:             for (r = 0; r < 12; ++r) {
    9956:               newp = fStartNew + (fEnd - fStart)*4 + (p - cStart)*12 + r;
    9957:               DMLabelSetValue(labelNew, newp, values[val]);
    9958:             }
    9959:             for (r = 0; r < 6; ++r) {
    9960:               newp = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*4 + (p - cStart)*6 + r;
    9961:               DMLabelSetValue(labelNew, newp, values[val]);
    9962:             }
    9963:             newp = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (fEnd - fStart) + (p - cStart);
    9964:             DMLabelSetValue(labelNew, newp, values[val]);
    9965:           }
    9966:           break;
    9967:         case REFINER_HYBRID_HEX_3D:
    9968:           if ((p >= vStart) && (p < vEnd)) {
    9969:             /* Interior vertices stay the same */
    9970:             newp = vStartNew + (p - vStart);
    9971:             DMLabelSetValue(labelNew, newp, values[val]);
    9972:           } else if ((p >= eStart) && (p < eMax)) {
    9973:             /* Interior edges add new edges and vertex */
    9974:             for (r = 0; r < 2; ++r) {
    9975:               newp = eStartNew + (p - eStart)*2 + r;
    9976:               DMLabelSetValue(labelNew, newp, values[val]);
    9977:             }
    9978:             newp = vStartNew + (vEnd - vStart) + (p - eStart);
    9979:             DMLabelSetValue(labelNew, newp, values[val]);
    9980:           } else if ((p >= eMax) && (p < eEnd)) {
    9981:             /* Hybrid edges stay the same */
    9982:             newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (p - eMax);
    9983:             DMLabelSetValue(labelNew, newp, values[val]);
    9984:           } else if ((p >= fStart) && (p < fMax)) {
    9985:             /* Interior faces add new faces, edges, and vertex */
    9986:             for (r = 0; r < 4; ++r) {
    9987:               newp = fStartNew + (p - fStart)*4 + r;
    9988:               DMLabelSetValue(labelNew, newp, values[val]);
    9989:             }
    9990:             for (r = 0; r < 4; ++r) {
    9991:               newp = eStartNew + (eMax - eStart)*2 + (p - fStart)*4 + r;
    9992:               DMLabelSetValue(labelNew, newp, values[val]);
    9993:             }
    9994:             newp = vStartNew + (vEnd - vStart) + (eMax - eStart) + (p - fStart);
    9995:             DMLabelSetValue(labelNew, newp, values[val]);
    9996:           } else if ((p >= fMax) && (p < fEnd)) {
    9997:             /* Hybrid faces add new faces and edges */
    9998:             for (r = 0; r < 2; ++r) {
    9999:               newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (p - fMax)*2 + r;
    10000:               DMLabelSetValue(labelNew, newp, values[val]);
    10001:             }
    10002:             newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (p - fMax);
    10003:             DMLabelSetValue(labelNew, newp, values[val]);
    10004:           } else if ((p >= cStart) && (p < cMax)) {
    10005:             /* Interior cells add new cells, faces, edges, and vertex */
    10006:             for (r = 0; r < 8; ++r) {
    10007:               newp = cStartNew + (p - cStart)*8 + r;
    10008:               DMLabelSetValue(labelNew, newp, values[val]);
    10009:             }
    10010:             for (r = 0; r < 12; ++r) {
    10011:               newp = fStartNew + (fMax - fStart)*4 + (p - cStart)*12 + r;
    10012:               DMLabelSetValue(labelNew, newp, values[val]);
    10013:             }
    10014:             for (r = 0; r < 6; ++r) {
    10015:               newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (p - cStart)*6 + r;
    10016:               DMLabelSetValue(labelNew, newp, values[val]);
    10017:             }
    10018:             newp = vStartNew + (vEnd - vStart) + (eMax - eStart) + (fMax - fStart) + (p - cStart);
    10019:             DMLabelSetValue(labelNew, newp, values[val]);
    10020:           } else if ((p >= cMax) && (p < cEnd)) {
    10021:             /* Hybrid cells add new cells, faces, and edges */
    10022:             for (r = 0; r < 4; ++r) {
    10023:               newp = cStartNew + (cMax - cStart)*8 + (p - cMax)*4 + r;
    10024:               DMLabelSetValue(labelNew, newp, values[val]);
    10025:             }
    10026:             for (r = 0; r < 4; ++r) {
    10027:               newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd - fMax)*2 + (p - cMax)*4 + r;
    10028:               DMLabelSetValue(labelNew, newp, values[val]);
    10029:             }
    10030:             newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (fEnd - fMax) + (p - cMax);
    10031:             DMLabelSetValue(labelNew, newp, values[val]);
    10032:           }
    10033:           break;
    10034:         default:
    10035:           SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %D", refiner);
    10036:         }
    10037:       }
    10038:       ISRestoreIndices(pointIS, &points);
    10039:       ISDestroy(&pointIS);
    10040:     }
    10041:     ISRestoreIndices(valueIS, &values);
    10042:     ISDestroy(&valueIS);
    10043:     if (0) {
    10044:       DMLabelView(labelNew, PETSC_VIEWER_STDOUT_WORLD);
    10045:     }
    10046:   }
    10047:   return(0);
    10048: }

    10050: /* This will only work for interpolated meshes */
    10051: PetscErrorCode DMPlexRefineUniform_Internal(DM dm, CellRefiner cellRefiner, DM *dmRefined)
    10052: {
    10053:   DM             rdm;
    10054:   PetscInt      *depthSize;
    10055:   PetscInt       dim, depth = 0, d, pStart = 0, pEnd = 0;

    10059:   DMCreate(PetscObjectComm((PetscObject)dm), &rdm);
    10060:   DMSetType(rdm, DMPLEX);
    10061:   DMGetDimension(dm, &dim);
    10062:   DMSetDimension(rdm, dim);
    10063:   /* Calculate number of new points of each depth */
    10064:   DMPlexGetDepth(dm, &depth);
    10065:   if (depth >= 0 && dim != depth) SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "Mesh must be interpolated for regular refinement");
    10066:   PetscMalloc1(depth+1, &depthSize);
    10067:   PetscMemzero(depthSize, (depth+1) * sizeof(PetscInt));
    10068:   CellRefinerGetSizes(cellRefiner, dm, depthSize);
    10069:   /* Step 1: Set chart */
    10070:   for (d = 0; d <= depth; ++d) pEnd += depthSize[d];
    10071:   DMPlexSetChart(rdm, pStart, pEnd);
    10072:   /* Step 2: Set cone/support sizes (automatically stratifies) */
    10073:   CellRefinerSetConeSizes(cellRefiner, dm, depthSize, rdm);
    10074:   /* Step 3: Setup refined DM */
    10075:   DMSetUp(rdm);
    10076:   /* Step 4: Set cones and supports (automatically symmetrizes) */
    10077:   CellRefinerSetCones(cellRefiner, dm, depthSize, rdm);
    10078:   /* Step 5: Create pointSF */
    10079:   CellRefinerCreateSF(cellRefiner, dm, depthSize, rdm);
    10080:   /* Step 6: Create labels */
    10081:   CellRefinerCreateLabels(cellRefiner, dm, depthSize, rdm);
    10082:   /* Step 7: Set coordinates */
    10083:   CellRefinerSetCoordinates(cellRefiner, dm, depthSize, rdm);
    10084:   PetscFree(depthSize);

    10086:   *dmRefined = rdm;
    10087:   return(0);
    10088: }

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

    10093:   Input Parameter:
    10094: . dm - The coarse DM

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

    10099:   Level: developer

    10101: .seealso: DMRefine(), DMPlexSetRefinementUniform(), DMPlexCreateSubpointIS()
    10102: @*/
    10103: PetscErrorCode DMPlexCreateCoarsePointIS(DM dm, IS *fpointIS)
    10104: {
    10105:   CellRefiner    cellRefiner;
    10106:   PetscInt      *depthSize, *fpoints;
    10107:   PetscInt       cStartNew = 0, vStartNew = 0, fStartNew = 0, eStartNew = 0;
    10108:   PetscInt       depth, pStart, pEnd, p, vStart, vEnd, v;

    10112:   DMPlexGetDepth(dm, &depth);
    10113:   DMPlexGetChart(dm, &pStart, &pEnd);
    10114:   DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);
    10115:   DMPlexGetCellRefiner_Internal(dm, &cellRefiner);
    10116:   PetscMalloc1(depth+1, &depthSize);
    10117:   CellRefinerGetSizes(cellRefiner, dm, depthSize);
    10118:   if (cellRefiner) {GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);}
    10119:   PetscMalloc1(pEnd-pStart,&fpoints);
    10120:   for (p = 0; p < pEnd-pStart; ++p) fpoints[p] = -1;
    10121:   switch (cellRefiner) {
    10122:   case REFINER_SIMPLEX_1D:
    10123:   case REFINER_SIMPLEX_2D:
    10124:   case REFINER_HYBRID_SIMPLEX_2D:
    10125:   case REFINER_HEX_2D:
    10126:   case REFINER_HYBRID_HEX_2D:
    10127:   case REFINER_SIMPLEX_3D:
    10128:   case REFINER_HYBRID_SIMPLEX_3D:
    10129:   case REFINER_HEX_3D:
    10130:   case REFINER_HYBRID_HEX_3D:
    10131:     for (v = vStart; v < vEnd; ++v) fpoints[v-pStart] = vStartNew + (v - vStart);
    10132:     break;
    10133:   default:
    10134:     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %D", cellRefiner);
    10135:   }
    10136:   ISCreateGeneral(PETSC_COMM_SELF, pEnd-pStart, fpoints, PETSC_OWN_POINTER, fpointIS);
    10137:   PetscFree(depthSize);
    10138:   return(0);
    10139: }

    10141: /*@
    10142:   DMPlexSetRefinementUniform - Set the flag for uniform refinement

    10144:   Input Parameters:
    10145: + dm - The DM
    10146: - refinementUniform - The flag for uniform refinement

    10148:   Level: developer

    10150: .seealso: DMRefine(), DMPlexGetRefinementUniform(), DMPlexGetRefinementLimit(), DMPlexSetRefinementLimit()
    10151: @*/
    10152: PetscErrorCode DMPlexSetRefinementUniform(DM dm, PetscBool refinementUniform)
    10153: {
    10154:   DM_Plex *mesh = (DM_Plex*) dm->data;

    10158:   mesh->refinementUniform = refinementUniform;
    10159:   return(0);
    10160: }

    10162: /*@
    10163:   DMPlexGetRefinementUniform - Retrieve the flag for uniform refinement

    10165:   Input Parameter:
    10166: . dm - The DM

    10168:   Output Parameter:
    10169: . refinementUniform - The flag for uniform refinement

    10171:   Level: developer

    10173: .seealso: DMRefine(), DMPlexSetRefinementUniform(), DMPlexGetRefinementLimit(), DMPlexSetRefinementLimit()
    10174: @*/
    10175: PetscErrorCode DMPlexGetRefinementUniform(DM dm, PetscBool *refinementUniform)
    10176: {
    10177:   DM_Plex *mesh = (DM_Plex*) dm->data;

    10182:   *refinementUniform = mesh->refinementUniform;
    10183:   return(0);
    10184: }

    10186: /*@
    10187:   DMPlexSetRefinementLimit - Set the maximum cell volume for refinement

    10189:   Input Parameters:
    10190: + dm - The DM
    10191: - refinementLimit - The maximum cell volume in the refined mesh

    10193:   Level: developer

    10195: .seealso: DMRefine(), DMPlexGetRefinementLimit(), DMPlexGetRefinementUniform(), DMPlexSetRefinementUniform()
    10196: @*/
    10197: PetscErrorCode DMPlexSetRefinementLimit(DM dm, PetscReal refinementLimit)
    10198: {
    10199:   DM_Plex *mesh = (DM_Plex*) dm->data;

    10203:   mesh->refinementLimit = refinementLimit;
    10204:   return(0);
    10205: }

    10207: /*@
    10208:   DMPlexGetRefinementLimit - Retrieve the maximum cell volume for refinement

    10210:   Input Parameter:
    10211: . dm - The DM

    10213:   Output Parameter:
    10214: . refinementLimit - The maximum cell volume in the refined mesh

    10216:   Level: developer

    10218: .seealso: DMRefine(), DMPlexSetRefinementLimit(), DMPlexGetRefinementUniform(), DMPlexSetRefinementUniform()
    10219: @*/
    10220: PetscErrorCode DMPlexGetRefinementLimit(DM dm, PetscReal *refinementLimit)
    10221: {
    10222:   DM_Plex *mesh = (DM_Plex*) dm->data;

    10227:   /* if (mesh->refinementLimit < 0) = getMaxVolume()/2.0; */
    10228:   *refinementLimit = mesh->refinementLimit;
    10229:   return(0);
    10230: }

    10232: /*@
    10233:   DMPlexSetRefinementFunction - Set the function giving the maximum cell volume for refinement

    10235:   Input Parameters:
    10236: + dm - The DM
    10237: - refinementFunc - Function giving the maximum cell volume in the refined mesh

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

    10243:   Level: developer

    10245: .seealso: DMRefine(), DMPlexGetRefinementFunction(), DMPlexGetRefinementUniform(), DMPlexSetRefinementUniform(), DMPlexGetRefinementLimit(), DMPlexSetRefinementLimit()
    10246: @*/
    10247: PetscErrorCode DMPlexSetRefinementFunction(DM dm, PetscErrorCode (*refinementFunc)(const PetscReal [], PetscReal *))
    10248: {
    10249:   DM_Plex *mesh = (DM_Plex*) dm->data;

    10253:   mesh->refinementFunc = refinementFunc;
    10254:   return(0);
    10255: }

    10257: /*@
    10258:   DMPlexGetRefinementFunction - Get the function giving the maximum cell volume for refinement

    10260:   Input Parameter:
    10261: . dm - The DM

    10263:   Output Parameter:
    10264: . refinementFunc - Function giving the maximum cell volume in the refined mesh

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

    10270:   Level: developer

    10272: .seealso: DMRefine(), DMPlexSetRefinementFunction(), DMPlexGetRefinementUniform(), DMPlexSetRefinementUniform(), DMPlexGetRefinementLimit(), DMPlexSetRefinementLimit()
    10273: @*/
    10274: PetscErrorCode DMPlexGetRefinementFunction(DM dm, PetscErrorCode (**refinementFunc)(const PetscReal [], PetscReal *))
    10275: {
    10276:   DM_Plex *mesh = (DM_Plex*) dm->data;

    10281:   *refinementFunc = mesh->refinementFunc;
    10282:   return(0);
    10283: }

    10285: PetscErrorCode DMPlexGetCellRefiner_Internal(DM dm, CellRefiner *cellRefiner)
    10286: {
    10287:   PetscInt       dim, cStart, cEnd, coneSize, cMax, fMax;

    10291:   DMGetDimension(dm, &dim);
    10292:   DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);
    10293:   if (cEnd <= cStart) {*cellRefiner = REFINER_NOOP; return(0);}
    10294:   DMPlexGetConeSize(dm, cStart, &coneSize);
    10295:   DMPlexGetHybridBounds(dm, &cMax, &fMax, NULL, NULL);
    10296:   switch (dim) {
    10297:   case 1:
    10298:     switch (coneSize) {
    10299:     case 2:
    10300:       *cellRefiner = REFINER_SIMPLEX_1D;
    10301:       break;
    10302:     default:
    10303:       SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown coneSize %D in dimension %D for cell refiner", coneSize, dim);
    10304:     }
    10305:     break;
    10306:   case 2:
    10307:     switch (coneSize) {
    10308:     case 3:
    10309:       if (cMax >= 0) *cellRefiner = REFINER_HYBRID_SIMPLEX_2D;
    10310:       else *cellRefiner = REFINER_SIMPLEX_2D;
    10311:       break;
    10312:     case 4:
    10313:       if (cMax >= 0 && fMax >= 0) *cellRefiner = REFINER_HYBRID_HEX_2D;
    10314:       else *cellRefiner = REFINER_HEX_2D;
    10315:       break;
    10316:     default:
    10317:       SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown coneSize %D in dimension %D for cell refiner", coneSize, dim);
    10318:     }
    10319:     break;
    10320:   case 3:
    10321:     switch (coneSize) {
    10322:     case 4:
    10323:       if (cMax >= 0) *cellRefiner = REFINER_HYBRID_SIMPLEX_3D;
    10324:       else *cellRefiner = REFINER_SIMPLEX_3D;
    10325:       break;
    10326:     case 5:
    10327:       if (cMax == 0) *cellRefiner = REFINER_HYBRID_SIMPLEX_3D;
    10328:       else SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown coneSize %D in dimension %D for cell refiner", coneSize, dim);
    10329:       break;
    10330:     case 6:
    10331:       if (cMax >= 0) *cellRefiner = REFINER_HYBRID_HEX_3D;
    10332:       else *cellRefiner = REFINER_HEX_3D;
    10333:       break;
    10334:     default:
    10335:       SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown coneSize %D in dimension %D for cell refiner", coneSize, dim);
    10336:     }
    10337:     break;
    10338:   default:
    10339:     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown dimension %D for cell refiner", dim);
    10340:   }
    10341:   return(0);
    10342: }

    10344: PetscErrorCode DMRefine_Plex(DM dm, MPI_Comm comm, DM *dmRefined)
    10345: {
    10346:   PetscBool      isUniform;

    10350:   DMPlexGetRefinementUniform(dm, &isUniform);
    10351:   if (isUniform) {
    10352:     CellRefiner cellRefiner;
    10353:     PetscBool   localized;

    10355:     DMGetCoordinatesLocalized(dm, &localized);
    10356:     DMPlexGetCellRefiner_Internal(dm, &cellRefiner);
    10357:     DMPlexRefineUniform_Internal(dm, cellRefiner, dmRefined);
    10358:     DMCopyBoundary(dm, *dmRefined);
    10359:     if (localized) {DMLocalizeCoordinates(*dmRefined);}
    10360:   } else {
    10361:     DMPlexRefine_Internal(dm, NULL, dmRefined);
    10362:   }
    10363:   return(0);
    10364: }

    10366: PetscErrorCode DMRefineHierarchy_Plex(DM dm, PetscInt nlevels, DM dmRefined[])
    10367: {
    10368:   DM             cdm = dm;
    10369:   PetscInt       r;
    10370:   PetscBool      isUniform, localized;

    10374:   DMPlexGetRefinementUniform(dm, &isUniform);
    10375:   DMGetCoordinatesLocalized(dm, &localized);
    10376:   if (isUniform) {
    10377:     for (r = 0; r < nlevels; ++r) {
    10378:       CellRefiner cellRefiner;

    10380:       DMPlexGetCellRefiner_Internal(cdm, &cellRefiner);
    10381:       DMPlexRefineUniform_Internal(cdm, cellRefiner, &dmRefined[r]);
    10382:       DMCopyBoundary(cdm, dmRefined[r]);
    10383:       if (localized) {DMLocalizeCoordinates(dmRefined[r]);}
    10384:       DMSetCoarseDM(dmRefined[r], cdm);
    10385:       DMPlexSetRegularRefinement(dmRefined[r], PETSC_TRUE);
    10386:       cdm  = dmRefined[r];
    10387:     }
    10388:   } else {
    10389:     for (r = 0; r < nlevels; ++r) {
    10390:       DMRefine(cdm, PetscObjectComm((PetscObject) dm), &dmRefined[r]);
    10391:       DMCopyBoundary(cdm, dmRefined[r]);
    10392:       if (localized) {DMLocalizeCoordinates(dmRefined[r]);}
    10393:       DMSetCoarseDM(dmRefined[r], cdm);
    10394:       cdm  = dmRefined[r];
    10395:     }
    10396:   }
    10397:   return(0);
    10398: }