Actual source code: plexrefine.c

petsc-3.11.4 2019-09-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:     PetscObjectStateGet((PetscObject) 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",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",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",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",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",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",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;
8715: #if defined(PETSC_USE_COMPLEX)
8716:       PetscInt          i, ln, gn;
8717:       PetscReal         *lrArray;
8718:       PetscReal         *grArray;
8719: #endif

8721:       DMGetCoordinateDM(rdm, &cdm);
8722:       DMCreateGlobalVector(cdm, &aux);
8723:       DMGetDefaultSF(cdm, &sf);
8724:       VecGetArrayRead(coordinatesNew, &lArray);
8725:       VecSet(aux, PETSC_MIN_REAL);
8726:       VecGetArray(aux, &gArray);
8727: #if defined(PETSC_USE_COMPLEX)
8728:       VecGetLocalSize(aux, &gn);
8729:       VecGetLocalSize(coordinatesNew, &ln);
8730:       PetscMalloc2(ln,&lrArray,gn,&grArray);
8731:       for (i=0;i<ln;i++) lrArray[i] = PetscRealPart(lArray[i]);
8732:       for (i=0;i<gn;i++) grArray[i] = PetscRealPart(gArray[i]);
8733:       PetscSFReduceBegin(sf, MPIU_REAL, lrArray, grArray, MPIU_MAX);
8734:       PetscSFReduceEnd(sf, MPIU_REAL, lrArray, grArray, MPIU_MAX);
8735:       for (i=0;i<gn;i++) gArray[i] = grArray[i];
8736:       PetscFree2(lrArray,grArray);
8737: #else
8738:       PetscSFReduceBegin(sf, MPIU_SCALAR, lArray, gArray, MPIU_MAX);
8739:       PetscSFReduceEnd(sf, MPIU_SCALAR, lArray, gArray, MPIU_MAX);
8740: #endif
8741:       VecRestoreArrayRead(coordinatesNew, &lArray);
8742:       VecRestoreArray(aux, &gArray);
8743:       DMGlobalToLocalBegin(cdm, aux, INSERT_VALUES, coordinatesNew);
8744:       DMGlobalToLocalEnd(cdm, aux, INSERT_VALUES, coordinatesNew);
8745:       VecDestroy(&aux);
8746:     }
8747:   }
8748:   VecDestroy(&coordinatesNew);
8749:   PetscSectionDestroy(&coordSectionNew);
8750:   PetscFree(parentId);
8751:   return(0);
8752: }

8754: /*@
8755:   DMPlexCreateProcessSF - Create an SF which just has process connectivity

8757:   Collective on DM

8759:   Input Parameters:
8760: + dm      - The DM
8761: - sfPoint - The PetscSF which encodes point connectivity

8763:   Output Parameters:
8764: + processRanks - A list of process neighbors, or NULL
8765: - sfProcess    - An SF encoding the process connectivity, or NULL

8767:   Level: developer

8769: .seealso: PetscSFCreate(), DMPlexCreateTwoSidedProcessSF()
8770: @*/
8771: PetscErrorCode DMPlexCreateProcessSF(DM dm, PetscSF sfPoint, IS *processRanks, PetscSF *sfProcess)
8772: {
8773:   PetscInt           numRoots, numLeaves, l;
8774:   const PetscInt    *localPoints;
8775:   const PetscSFNode *remotePoints;
8776:   PetscInt          *localPointsNew;
8777:   PetscSFNode       *remotePointsNew;
8778:   PetscInt          *ranks, *ranksNew;
8779:   PetscMPIInt        size;
8780:   PetscErrorCode     ierr;

8787:   MPI_Comm_size(PetscObjectComm((PetscObject) dm), &size);
8788:   PetscSFGetGraph(sfPoint, &numRoots, &numLeaves, &localPoints, &remotePoints);
8789:   PetscMalloc1(numLeaves, &ranks);
8790:   for (l = 0; l < numLeaves; ++l) {
8791:     ranks[l] = remotePoints[l].rank;
8792:   }
8793:   PetscSortRemoveDupsInt(&numLeaves, ranks);
8794:   PetscMalloc1(numLeaves, &ranksNew);
8795:   PetscMalloc1(numLeaves, &localPointsNew);
8796:   PetscMalloc1(numLeaves, &remotePointsNew);
8797:   for (l = 0; l < numLeaves; ++l) {
8798:     ranksNew[l]              = ranks[l];
8799:     localPointsNew[l]        = l;
8800:     remotePointsNew[l].index = 0;
8801:     remotePointsNew[l].rank  = ranksNew[l];
8802:   }
8803:   PetscFree(ranks);
8804:   if (processRanks) {ISCreateGeneral(PetscObjectComm((PetscObject)dm), numLeaves, ranksNew, PETSC_OWN_POINTER, processRanks);}
8805:   else              {PetscFree(ranksNew);}
8806:   if (sfProcess) {
8807:     PetscSFCreate(PetscObjectComm((PetscObject)dm), sfProcess);
8808:     PetscObjectSetName((PetscObject) *sfProcess, "Process SF");
8809:     PetscSFSetFromOptions(*sfProcess);
8810:     PetscSFSetGraph(*sfProcess, size, numLeaves, localPointsNew, PETSC_OWN_POINTER, remotePointsNew, PETSC_OWN_POINTER);
8811:   }
8812:   return(0);
8813: }

8815: static PetscErrorCode CellRefinerCreateSF(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
8816: {
8817:   PetscSF            sf, sfNew, sfProcess;
8818:   IS                 processRanks;
8819:   MPI_Datatype       depthType;
8820:   PetscInt           numRoots, numLeaves, numLeavesNew = 0, l, m;
8821:   const PetscInt    *localPoints, *neighbors;
8822:   const PetscSFNode *remotePoints;
8823:   PetscInt          *localPointsNew;
8824:   PetscSFNode       *remotePointsNew;
8825:   PetscInt          *depthSizeOld, *rdepthSize, *rdepthSizeOld, *rdepthMaxOld, *rvStart, *rvStartNew, *reStart, *reStartNew, *rfStart, *rfStartNew, *rcStart, *rcStartNew;
8826:   PetscInt           ldepth, depth, numNeighbors, pStartNew, pEndNew, cStart, cEnd, cMax, vStart, vEnd, vMax, fStart, fEnd, fMax, eStart, eEnd, eMax, r, n;
8827:   PetscInt           cStartNew = 0, vStartNew = 0, fStartNew = 0, eStartNew = 0;
8828:   PetscErrorCode     ierr;

8831:   DMPlexGetChart(rdm, &pStartNew, &pEndNew);
8832:   DMPlexGetDepth(dm, &ldepth);
8833:   MPIU_Allreduce(&ldepth, &depth, 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject) dm));
8834:   if ((ldepth >= 0) && (depth != ldepth)) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Inconsistent Plex depth %D != %D", ldepth, depth);
8835:   DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);
8836:   DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);
8837:   DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);
8838:   DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);
8839:   DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);
8840:   cMax = cMax < 0 ? cEnd : cMax;
8841:   fMax = fMax < 0 ? fEnd : fMax;
8842:   eMax = eMax < 0 ? eEnd : eMax;
8843:   if (refiner) {GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);}
8844:   DMGetPointSF(dm, &sf);
8845:   DMGetPointSF(rdm, &sfNew);
8846:   /* Calculate size of new SF */
8847:   PetscSFGetGraph(sf, &numRoots, &numLeaves, &localPoints, &remotePoints);
8848:   if (numRoots < 0) return(0);
8849:   for (l = 0; l < numLeaves; ++l) {
8850:     const PetscInt p = localPoints[l];

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

9012:   PetscSFBcastBegin(sfProcess, depthType, depthSizeOld, rdepthMaxOld);
9013:   PetscSFBcastEnd(sfProcess, depthType, depthSizeOld, rdepthMaxOld);

9015:   depthSizeOld[depth]   = cEnd - cStart;
9016:   depthSizeOld[0]       = vEnd - vStart;
9017:   depthSizeOld[depth-1] = fEnd - fStart;
9018:   depthSizeOld[1]       = eEnd - eStart;

9020:   PetscSFBcastBegin(sfProcess, depthType, depthSizeOld, rdepthSizeOld);
9021:   PetscSFBcastEnd(sfProcess, depthType, depthSizeOld, rdepthSizeOld);
9022:   for (n = 0; n < numNeighbors; ++n) {
9023:     GetDepthStart_Private(depth, &rdepthSizeOld[n*(depth+1)], &rcStart[n], &rfStart[n], &reStart[n], &rvStart[n]);
9024:     rdepthMaxOld[n*(depth+1)+depth]   = rdepthMaxOld[n*(depth+1)+depth]   < 0 ? rdepthSizeOld[n*(depth+1)+depth]  +rcStart[n]: rdepthMaxOld[n*(depth+1)+depth];
9025:     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];
9026:     rdepthMaxOld[n*(depth+1)+1]       = rdepthMaxOld[n*(depth+1)+1]       < 0 ? rdepthSizeOld[n*(depth+1)+1]      +reStart[n]: rdepthMaxOld[n*(depth+1)+1];
9027:   }
9028:   MPI_Type_free(&depthType);
9029:   PetscSFDestroy(&sfProcess);
9030:   /* Calculate new point SF */
9031:   PetscMalloc1(numLeavesNew, &localPointsNew);
9032:   PetscMalloc1(numLeavesNew, &remotePointsNew);
9033:   ISGetIndices(processRanks, &neighbors);
9034:   for (l = 0, m = 0; l < numLeaves; ++l) {
9035:     PetscInt    p     = localPoints[l];
9036:     PetscInt    rp    = remotePoints[l].index, n;
9037:     PetscMPIInt rrank = remotePoints[l].rank;

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

9491:     /* SF needs sorted leaves to correct calculate Gather */
9492:     PetscMalloc1(numLeavesNew,&idx);
9493:     PetscMalloc1(numLeavesNew, &lp);
9494:     PetscMalloc1(numLeavesNew, &rp);
9495:     for (i = 0; i < numLeavesNew; ++i) {
9496:       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);
9497:       idx[i] = i;
9498:     }
9499:     PetscSortIntWithPermutation(numLeavesNew, localPointsNew, idx);
9500:     for (i = 0; i < numLeavesNew; ++i) {
9501:       lp[i] = localPointsNew[idx[i]];
9502:       rp[i] = remotePointsNew[idx[i]];
9503:     }
9504:     ltmp            = localPointsNew;
9505:     localPointsNew  = lp;
9506:     rtmp            = remotePointsNew;
9507:     remotePointsNew = rp;
9508:     PetscFree(idx);
9509:     PetscFree(ltmp);
9510:     PetscFree(rtmp);
9511:   }
9512:   PetscSFSetGraph(sfNew, pEndNew-pStartNew, numLeavesNew, localPointsNew, PETSC_OWN_POINTER, remotePointsNew, PETSC_OWN_POINTER);
9513:   PetscFree5(rdepthSize,rvStartNew,reStartNew,rfStartNew,rcStartNew);
9514:   PetscFree7(depthSizeOld,rdepthSizeOld,rdepthMaxOld,rvStart,reStart,rfStart,rcStart);
9515:   return(0);
9516: }

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

9526:   DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);
9527:   DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);
9528:   DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);
9529:   DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);
9530:   DMPlexGetDepth(dm, &depth);
9531:   if (refiner) {GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);}
9532:   DMGetNumLabels(dm, &numLabels);
9533:   DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);
9534:   switch (refiner) {
9535:   case REFINER_NOOP:
9536:   case REFINER_SIMPLEX_1D:
9537:   case REFINER_SIMPLEX_2D:
9538:   case REFINER_SIMPLEX_TO_HEX_2D:
9539:   case REFINER_HEX_2D:
9540:   case REFINER_SIMPLEX_3D:
9541:   case REFINER_HEX_3D:
9542:   case REFINER_SIMPLEX_TO_HEX_3D:
9543:     break;
9544:   case REFINER_HYBRID_SIMPLEX_TO_HEX_3D:
9545:   case REFINER_HYBRID_SIMPLEX_3D:
9546:   case REFINER_HYBRID_HEX_3D:
9547:     if (eMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No edge maximum specified in hybrid mesh");
9548:   case REFINER_HYBRID_SIMPLEX_2D:
9549:   case REFINER_HYBRID_HEX_2D:
9550:     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
9551:   case REFINER_HYBRID_SIMPLEX_TO_HEX_2D:
9552:     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
9553:     break;
9554:   default:
9555:     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %D", refiner);
9556:   }
9557:   cMax = cMax < 0 ? cEnd : cMax;
9558:   fMax = fMax < 0 ? fEnd : fMax;
9559:   eMax = eMax < 0 ? eEnd : eMax;
9560:   for (l = 0; l < numLabels; ++l) {
9561:     DMLabel         label, labelNew;
9562:     const char     *lname;
9563:     PetscBool       isDepth;
9564:     IS              valueIS;
9565:     const PetscInt *values;
9566:     PetscInt        defVal;
9567:     PetscInt        numValues, val;

9569:     DMGetLabelName(dm, l, &lname);
9570:     PetscStrcmp(lname, "depth", &isDepth);
9571:     if (isDepth) continue;
9572:     DMCreateLabel(rdm, lname);
9573:     DMGetLabel(dm, lname, &label);
9574:     DMGetLabel(rdm, lname, &labelNew);
9575:     DMLabelGetDefaultValue(label,&defVal);
9576:     DMLabelSetDefaultValue(labelNew,defVal);
9577:     DMLabelGetValueIS(label, &valueIS);
9578:     ISGetLocalSize(valueIS, &numValues);
9579:     ISGetIndices(valueIS, &values);
9580:     for (val = 0; val < numValues; ++val) {
9581:       IS              pointIS;
9582:       const PetscInt *points;
9583:       PetscInt        numPoints, n;

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

10067: /* This will only work for interpolated meshes */
10068: PetscErrorCode DMPlexRefineUniform_Internal(DM dm, CellRefiner cellRefiner, DM *dmRefined)
10069: {
10070:   DM             rdm;
10071:   PetscInt      *depthSize;
10072:   PetscInt       dim, embedDim, depth = 0, d, pStart = 0, pEnd = 0;

10076:   DMCreate(PetscObjectComm((PetscObject)dm), &rdm);
10077:   DMSetType(rdm, DMPLEX);
10078:   DMGetDimension(dm, &dim);
10079:   DMSetDimension(rdm, dim);
10080:   DMGetCoordinateDim(dm, &embedDim);
10081:   DMSetCoordinateDim(rdm, embedDim);
10082:   /* Calculate number of new points of each depth */
10083:   DMPlexGetDepth(dm, &depth);
10084:   if (depth >= 0 && dim != depth) SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "Mesh must be interpolated for regular refinement");
10085:   PetscMalloc1(depth+1, &depthSize);
10086:   PetscMemzero(depthSize, (depth+1) * sizeof(PetscInt));
10087:   CellRefinerGetSizes(cellRefiner, dm, depthSize);
10088:   /* Step 1: Set chart */
10089:   for (d = 0; d <= depth; ++d) pEnd += depthSize[d];
10090:   DMPlexSetChart(rdm, pStart, pEnd);
10091:   /* Step 2: Set cone/support sizes (automatically stratifies) */
10092:   CellRefinerSetConeSizes(cellRefiner, dm, depthSize, rdm);
10093:   /* Step 3: Setup refined DM */
10094:   DMSetUp(rdm);
10095:   /* Step 4: Set cones and supports (automatically symmetrizes) */
10096:   CellRefinerSetCones(cellRefiner, dm, depthSize, rdm);
10097:   /* Step 5: Create pointSF */
10098:   CellRefinerCreateSF(cellRefiner, dm, depthSize, rdm);
10099:   /* Step 6: Create labels */
10100:   CellRefinerCreateLabels(cellRefiner, dm, depthSize, rdm);
10101:   /* Step 7: Set coordinates */
10102:   CellRefinerSetCoordinates(cellRefiner, dm, depthSize, rdm);
10103:   PetscFree(depthSize);

10105:   *dmRefined = rdm;
10106:   return(0);
10107: }

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

10112:   Input Parameter:
10113: . dm - The coarse DM

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

10118:   Level: developer

10120: .seealso: DMRefine(), DMPlexSetRefinementUniform(), DMPlexCreateSubpointIS()
10121: @*/
10122: PetscErrorCode DMPlexCreateCoarsePointIS(DM dm, IS *fpointIS)
10123: {
10124:   CellRefiner    cellRefiner;
10125:   PetscInt      *depthSize, *fpoints;
10126:   PetscInt       cStartNew = 0, vStartNew = 0, fStartNew = 0, eStartNew = 0;
10127:   PetscInt       depth, pStart, pEnd, p, vStart, vEnd, v;

10131:   DMPlexGetDepth(dm, &depth);
10132:   DMPlexGetChart(dm, &pStart, &pEnd);
10133:   DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);
10134:   DMPlexGetCellRefiner_Internal(dm, &cellRefiner);
10135:   PetscMalloc1(depth+1, &depthSize);
10136:   CellRefinerGetSizes(cellRefiner, dm, depthSize);
10137:   if (cellRefiner) {GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);}
10138:   PetscMalloc1(pEnd-pStart,&fpoints);
10139:   for (p = 0; p < pEnd-pStart; ++p) fpoints[p] = -1;
10140:   switch (cellRefiner) {
10141:   case REFINER_SIMPLEX_1D:
10142:   case REFINER_SIMPLEX_2D:
10143:   case REFINER_HYBRID_SIMPLEX_2D:
10144:   case REFINER_HEX_2D:
10145:   case REFINER_HYBRID_HEX_2D:
10146:   case REFINER_SIMPLEX_3D:
10147:   case REFINER_HYBRID_SIMPLEX_3D:
10148:   case REFINER_HEX_3D:
10149:   case REFINER_HYBRID_HEX_3D:
10150:     for (v = vStart; v < vEnd; ++v) fpoints[v-pStart] = vStartNew + (v - vStart);
10151:     break;
10152:   default:
10153:     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %D", cellRefiner);
10154:   }
10155:   ISCreateGeneral(PETSC_COMM_SELF, pEnd-pStart, fpoints, PETSC_OWN_POINTER, fpointIS);
10156:   PetscFree(depthSize);
10157:   return(0);
10158: }

10160: /*@
10161:   DMPlexSetRefinementUniform - Set the flag for uniform refinement

10163:   Input Parameters:
10164: + dm - The DM
10165: - refinementUniform - The flag for uniform refinement

10167:   Level: developer

10169: .seealso: DMRefine(), DMPlexGetRefinementUniform(), DMPlexGetRefinementLimit(), DMPlexSetRefinementLimit()
10170: @*/
10171: PetscErrorCode DMPlexSetRefinementUniform(DM dm, PetscBool refinementUniform)
10172: {
10173:   DM_Plex *mesh = (DM_Plex*) dm->data;

10177:   mesh->refinementUniform = refinementUniform;
10178:   return(0);
10179: }

10181: /*@
10182:   DMPlexGetRefinementUniform - Retrieve the flag for uniform refinement

10184:   Input Parameter:
10185: . dm - The DM

10187:   Output Parameter:
10188: . refinementUniform - The flag for uniform refinement

10190:   Level: developer

10192: .seealso: DMRefine(), DMPlexSetRefinementUniform(), DMPlexGetRefinementLimit(), DMPlexSetRefinementLimit()
10193: @*/
10194: PetscErrorCode DMPlexGetRefinementUniform(DM dm, PetscBool *refinementUniform)
10195: {
10196:   DM_Plex *mesh = (DM_Plex*) dm->data;

10201:   *refinementUniform = mesh->refinementUniform;
10202:   return(0);
10203: }

10205: /*@
10206:   DMPlexSetRefinementLimit - Set the maximum cell volume for refinement

10208:   Input Parameters:
10209: + dm - The DM
10210: - refinementLimit - The maximum cell volume in the refined mesh

10212:   Level: developer

10214: .seealso: DMRefine(), DMPlexGetRefinementLimit(), DMPlexGetRefinementUniform(), DMPlexSetRefinementUniform()
10215: @*/
10216: PetscErrorCode DMPlexSetRefinementLimit(DM dm, PetscReal refinementLimit)
10217: {
10218:   DM_Plex *mesh = (DM_Plex*) dm->data;

10222:   mesh->refinementLimit = refinementLimit;
10223:   return(0);
10224: }

10226: /*@
10227:   DMPlexGetRefinementLimit - Retrieve the maximum cell volume for refinement

10229:   Input Parameter:
10230: . dm - The DM

10232:   Output Parameter:
10233: . refinementLimit - The maximum cell volume in the refined mesh

10235:   Level: developer

10237: .seealso: DMRefine(), DMPlexSetRefinementLimit(), DMPlexGetRefinementUniform(), DMPlexSetRefinementUniform()
10238: @*/
10239: PetscErrorCode DMPlexGetRefinementLimit(DM dm, PetscReal *refinementLimit)
10240: {
10241:   DM_Plex *mesh = (DM_Plex*) dm->data;

10246:   /* if (mesh->refinementLimit < 0) = getMaxVolume()/2.0; */
10247:   *refinementLimit = mesh->refinementLimit;
10248:   return(0);
10249: }

10251: /*@
10252:   DMPlexSetRefinementFunction - Set the function giving the maximum cell volume for refinement

10254:   Input Parameters:
10255: + dm - The DM
10256: - refinementFunc - Function giving the maximum cell volume in the refined mesh

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

10262:   Level: developer

10264: .seealso: DMRefine(), DMPlexGetRefinementFunction(), DMPlexGetRefinementUniform(), DMPlexSetRefinementUniform(), DMPlexGetRefinementLimit(), DMPlexSetRefinementLimit()
10265: @*/
10266: PetscErrorCode DMPlexSetRefinementFunction(DM dm, PetscErrorCode (*refinementFunc)(const PetscReal [], PetscReal *))
10267: {
10268:   DM_Plex *mesh = (DM_Plex*) dm->data;

10272:   mesh->refinementFunc = refinementFunc;
10273:   return(0);
10274: }

10276: /*@
10277:   DMPlexGetRefinementFunction - Get the function giving the maximum cell volume for refinement

10279:   Input Parameter:
10280: . dm - The DM

10282:   Output Parameter:
10283: . refinementFunc - Function giving the maximum cell volume in the refined mesh

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

10289:   Level: developer

10291: .seealso: DMRefine(), DMPlexSetRefinementFunction(), DMPlexGetRefinementUniform(), DMPlexSetRefinementUniform(), DMPlexGetRefinementLimit(), DMPlexSetRefinementLimit()
10292: @*/
10293: PetscErrorCode DMPlexGetRefinementFunction(DM dm, PetscErrorCode (**refinementFunc)(const PetscReal [], PetscReal *))
10294: {
10295:   DM_Plex *mesh = (DM_Plex*) dm->data;

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

10304: PetscErrorCode DMPlexGetCellRefiner_Internal(DM dm, CellRefiner *cellRefiner)
10305: {
10306:   PetscInt       dim, cStart, cEnd, coneSize, cMax, fMax;

10310:   DMGetDimension(dm, &dim);
10311:   DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);
10312:   if (cEnd <= cStart) {*cellRefiner = REFINER_NOOP; return(0);}
10313:   DMPlexGetConeSize(dm, cStart, &coneSize);
10314:   DMPlexGetHybridBounds(dm, &cMax, &fMax, NULL, NULL);
10315:   switch (dim) {
10316:   case 1:
10317:     switch (coneSize) {
10318:     case 2:
10319:       *cellRefiner = REFINER_SIMPLEX_1D;
10320:       break;
10321:     default:
10322:       SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown coneSize %D in dimension %D for cell refiner", coneSize, dim);
10323:     }
10324:     break;
10325:   case 2:
10326:     switch (coneSize) {
10327:     case 3:
10328:       if (cMax >= 0) *cellRefiner = REFINER_HYBRID_SIMPLEX_2D;
10329:       else *cellRefiner = REFINER_SIMPLEX_2D;
10330:       break;
10331:     case 4:
10332:       if (cMax >= 0 && fMax >= 0) *cellRefiner = REFINER_HYBRID_HEX_2D;
10333:       else *cellRefiner = REFINER_HEX_2D;
10334:       break;
10335:     default:
10336:       SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown coneSize %D in dimension %D for cell refiner", coneSize, dim);
10337:     }
10338:     break;
10339:   case 3:
10340:     switch (coneSize) {
10341:     case 4:
10342:       if (cMax >= 0) *cellRefiner = REFINER_HYBRID_SIMPLEX_3D;
10343:       else *cellRefiner = REFINER_SIMPLEX_3D;
10344:       break;
10345:     case 5:
10346:       if (cMax == 0) *cellRefiner = REFINER_HYBRID_SIMPLEX_3D;
10347:       else SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown coneSize %D in dimension %D for cell refiner", coneSize, dim);
10348:       break;
10349:     case 6:
10350:       if (cMax >= 0) *cellRefiner = REFINER_HYBRID_HEX_3D;
10351:       else *cellRefiner = REFINER_HEX_3D;
10352:       break;
10353:     default:
10354:       SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown coneSize %D in dimension %D for cell refiner", coneSize, dim);
10355:     }
10356:     break;
10357:   default:
10358:     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown dimension %D for cell refiner", dim);
10359:   }
10360:   return(0);
10361: }

10363: PetscErrorCode DMRefine_Plex(DM dm, MPI_Comm comm, DM *dmRefined)
10364: {
10365:   PetscBool      isUniform;

10369:   DMPlexGetRefinementUniform(dm, &isUniform);
10370:   if (isUniform) {
10371:     CellRefiner cellRefiner;
10372:     PetscBool   localized;

10374:     DMGetCoordinatesLocalized(dm, &localized);
10375:     DMPlexGetCellRefiner_Internal(dm, &cellRefiner);
10376:     DMPlexRefineUniform_Internal(dm, cellRefiner, dmRefined);
10377:     DMPlexSetRegularRefinement(*dmRefined, PETSC_TRUE);
10378:     DMCopyBoundary(dm, *dmRefined);
10379:     if (localized) {DMLocalizeCoordinates(*dmRefined);}
10380:   } else {
10381:     DMPlexRefine_Internal(dm, NULL, dmRefined);
10382:   }
10383:   return(0);
10384: }

10386: PetscErrorCode DMRefineHierarchy_Plex(DM dm, PetscInt nlevels, DM dmRefined[])
10387: {
10388:   DM             cdm = dm;
10389:   PetscInt       r;
10390:   PetscBool      isUniform, localized;

10394:   DMPlexGetRefinementUniform(dm, &isUniform);
10395:   DMGetCoordinatesLocalized(dm, &localized);
10396:   if (isUniform) {
10397:     for (r = 0; r < nlevels; ++r) {
10398:       CellRefiner cellRefiner;

10400:       DMPlexGetCellRefiner_Internal(cdm, &cellRefiner);
10401:       DMPlexRefineUniform_Internal(cdm, cellRefiner, &dmRefined[r]);
10402:       DMSetCoarsenLevel(dmRefined[r], cdm->leveldown);
10403:       DMSetRefineLevel(dmRefined[r], cdm->levelup+1);
10404:       DMCopyBoundary(cdm, dmRefined[r]);
10405:       if (localized) {DMLocalizeCoordinates(dmRefined[r]);}
10406:       DMSetCoarseDM(dmRefined[r], cdm);
10407:       DMPlexSetRegularRefinement(dmRefined[r], PETSC_TRUE);
10408:       cdm  = dmRefined[r];
10409:     }
10410:   } else {
10411:     for (r = 0; r < nlevels; ++r) {
10412:       DMRefine(cdm, PetscObjectComm((PetscObject) dm), &dmRefined[r]);
10413:       DMCopyBoundary(cdm, dmRefined[r]);
10414:       if (localized) {DMLocalizeCoordinates(dmRefined[r]);}
10415:       DMSetCoarseDM(dmRefined[r], cdm);
10416:       cdm  = dmRefined[r];
10417:     }
10418:   }
10419:   return(0);
10420: }