Actual source code: plexrefine.c

petsc-3.9.4 2018-09-11
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_HEX_2D:
255:     depthSize[0] = vEnd - vStart + fEnd - fStart + cEnd - cStart; /* Add a vertex on every face and cell */
256:     depthSize[1] = 2*(fEnd - fStart) + 4*(cEnd - cStart);         /* Every face is split into 2 faces and 4 faces are added for each cell */
257:     depthSize[2] = 4*(cEnd - cStart);                             /* Every cell split into 4 cells */
258:     break;
259:   case REFINER_HYBRID_HEX_2D:
260:     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
261:     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
262:     /* Quadrilateral */
263:     depthSize[0] = vEnd - vStart + fMax - fStart + cMax - cStart;                 /* Add a vertex on every face and cell */
264:     depthSize[1] = 2*(fMax - fStart) + 4*(cMax - cStart);                         /* Every face is split into 2 faces, and 4 faces are added for each cell */
265:     depthSize[2] = 4*(cMax - cStart);                                             /* Every cell split into 4 cells */
266:     /* Segment Prisms */
267:     depthSize[0] += 0;                                                            /* No hybrid vertices */
268:     depthSize[1] +=   (fEnd - fMax)  +   (cEnd - cMax);                           /* Every hybrid face remains and 1 faces is added for each hybrid cell */
269:     depthSize[2] += 2*(cEnd - cMax);                                              /* Every hybrid cell split into 2 cells */
270:     break;
271:   case REFINER_SIMPLEX_3D:
272:     depthSize[0] =    vEnd - vStart  +    eEnd - eStart;                    /* Add a vertex on every edge */
273:     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 */
274:     depthSize[2] = 4*(fEnd - fStart) + 8*(cEnd - cStart);                   /* Every face split into 4 faces and 8 faces are added for each cell */
275:     depthSize[3] = 8*(cEnd - cStart);                                       /* Every cell split into 8 cells */
276:     break;
277:   case REFINER_HYBRID_SIMPLEX_3D:
278:     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
279:     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
280:     if (eMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No edge maximum specified in hybrid mesh");
281:     /* Tetrahedra */
282:     depthSize[0]  =    vEnd - vStart  +    eMax - eStart;                    /* Add a vertex on every interior edge */
283:     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 */
284:     depthSize[2]  = 4*(fMax - fStart) + 8*(cMax - cStart);                   /* Every interior face split into 4 faces, 8 faces added for each interior cell */
285:     depthSize[3]  = 8*(cMax - cStart);                                       /* Every interior cell split into 8 cells */
286:     /* Triangular Prisms */
287:     depthSize[0] += 0;                                                       /* No hybrid vertices */
288:     depthSize[1] +=   (eEnd - eMax)   +   (fEnd - fMax);                     /* Every hybrid edge remains, 1 edge for every hybrid face */
289:     depthSize[2] += 2*(fEnd - fMax)   + 3*(cEnd - cMax);                     /* Every hybrid face split into 2 faces and 3 faces are added for each hybrid cell */
290:     depthSize[3] += 4*(cEnd - cMax);                                         /* Every hybrid cell split into 4 cells */
291:     break;
292:   case REFINER_SIMPLEX_TO_HEX_3D:
293:     depthSize[0] = vEnd - vStart + fEnd - fStart + eEnd - eStart + cEnd - cStart; /* Add a vertex on every face, edge and cell */
294:     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 */
295:     depthSize[2] = 3*(fEnd - fStart) + 6*(cEnd - cStart);                         /* Every face is split into 3 faces and 6 faces are added for each cell */
296:     depthSize[3] = 4*(cEnd - cStart);                                             /* Every cell split into 4 cells */
297:     break;
298:   case REFINER_HEX_3D:
299:     depthSize[0] = vEnd - vStart + eEnd - eStart + fEnd - fStart + cEnd - cStart; /* Add a vertex on every edge, face and cell */
300:     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 */
301:     depthSize[2] = 4*(fEnd - fStart) + 12*(cEnd - cStart);                        /* Every face is split into 4 faces, and 12 faces are added for each cell */
302:     depthSize[3] = 8*(cEnd - cStart);                                             /* Every cell split into 8 cells */
303:     break;
304:   case REFINER_HYBRID_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:     /* Hexahedra */
309:     depthSize[0] = vEnd - vStart + eMax - eStart + fMax - fStart + cMax - cStart; /* Add a vertex on every edge, face and cell */
310:     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 */
311:     depthSize[2] = 4*(fMax - fStart) + 12*(cMax - cStart);                        /* Every face is split into 4 faces, and 12 faces are added for each cell */
312:     depthSize[3] = 8*(cMax - cStart);                                             /* Every cell split into 8 cells */
313:     /* Quadrilateral 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 hybrid cell */
316:     depthSize[2] += 2*(fEnd - fMax)   + 4*(cEnd - cMax);                          /* Every hybrid face split into 2 faces and 4 faces are added for each hybrid cell */
317:     depthSize[3] += 4*(cEnd - cMax);                                              /* Every hybrid cell split into 4 cells */
318:     break;
319:   default:
320:     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
321:   }
322:   return(0);
323: }

325: /* Return triangle edge for orientation o, if it is r for o == 0 */
326: PETSC_STATIC_INLINE PetscInt GetTriEdge_Static(PetscInt o, PetscInt r) {
327:   return (o < 0 ? 2-(o+r) : o+r)%3;
328: }
329: PETSC_STATIC_INLINE PetscInt GetTriEdgeInverse_Static(PetscInt o, PetscInt s) {
330:   return (o < 0 ? 2-(o+s) : 3+s-o)%3;
331: }

333: /* Return triangle subface for orientation o, if it is r for o == 0 */
334: PETSC_STATIC_INLINE PetscInt GetTriSubface_Static(PetscInt o, PetscInt r) {
335:   return (o < 0 ? 3-(o+r) : o+r)%3;
336: }
337: PETSC_STATIC_INLINE PetscInt GetTriSubfaceInverse_Static(PetscInt o, PetscInt s) {
338:   return (o < 0 ? 3-(o+s) : 3+s-o)%3;
339: }

341: /* Return the interior edge number connecting the midpoints of the triangle edges r
342:    and r+1 in the transitive closure for triangle orientation o */
343: PETSC_STATIC_INLINE PetscInt GetTriMidEdge_Static(PetscInt o, PetscInt r) {
344:   return (o < 0 ? 1-(o+r) : o+r)%3;
345: }
346: PETSC_STATIC_INLINE PetscInt GetTriMidEdgeInverse_Static(PetscInt o, PetscInt s) {
347:   return (o < 0 ? 1-(o+s) : 3+s-o)%3;
348: }

350: /* Return the interior edge number connecting the midpoint of the triangle edge r
351:    (in the transitive closure) and the vertex in the interior of the face for triangle orientation o */
352: PETSC_STATIC_INLINE PetscInt GetTriInteriorEdge_Static(PetscInt o, PetscInt r) {
353:   return (o < 0 ? 2-(o+r) : o+r)%3;
354: }
355: PETSC_STATIC_INLINE PetscInt GetTriInteriorEdgeInverse_Static(PetscInt o, PetscInt s) {
356:   return (o < 0 ? 2-(o+s) : 3+s-o)%3;
357: }

359: /* Return quad edge for orientation o, if it is r for o == 0 */
360: PETSC_STATIC_INLINE PetscInt GetQuadEdge_Static(PetscInt o, PetscInt r) {
361:   return (o < 0 ? 3-(o+r) : o+r)%4;
362: }
363: PETSC_STATIC_INLINE PetscInt GetQuadEdgeInverse_Static(PetscInt o, PetscInt s) {
364:   return (o < 0 ? 3-(o+s) : 4+s-o)%4;
365: }

367: /* Return quad subface for orientation o, if it is r for o == 0 */
368: PETSC_STATIC_INLINE PetscInt GetQuadSubface_Static(PetscInt o, PetscInt r) {
369:   return (o < 0 ? 4-(o+r) : o+r)%4;
370: }
371: PETSC_STATIC_INLINE PetscInt GetQuadSubfaceInverse_Static(PetscInt o, PetscInt s) {
372:   return (o < 0 ? 4-(o+s) : 4+s-o)%4;
373: }

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

381:   if (!refiner) return(0);
382:   DMPlexGetDepth(dm, &depth);
383:   DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);
384:   DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);
385:   DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);
386:   DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);
387:   DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);
388:   GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);
389:   switch (refiner) {
390:   case REFINER_SIMPLEX_1D:
391:     /* All cells have 2 vertices */
392:     for (c = cStart; c < cEnd; ++c) {
393:       for (r = 0; r < 2; ++r) {
394:         const PetscInt newp = cStartNew + (c - cStart)*2 + r;

396:         DMPlexSetConeSize(rdm, newp, 2);
397:       }
398:     }
399:     /* Old vertices have identical supports */
400:     for (v = vStart; v < vEnd; ++v) {
401:       const PetscInt newp = vStartNew + (v - vStart);
402:       PetscInt       size;

404:       DMPlexGetSupportSize(dm, v, &size);
405:       DMPlexSetSupportSize(rdm, newp, size);
406:     }
407:     /* Cell vertices have support 2 */
408:     for (c = cStart; c < cEnd; ++c) {
409:       const PetscInt newp = vStartNew + (vEnd - vStart) + (c - cStart);

411:       DMPlexSetSupportSize(rdm, newp, 2);
412:     }
413:     break;
414:   case REFINER_SIMPLEX_2D:
415:     /* All cells have 3 faces */
416:     for (c = cStart; c < cEnd; ++c) {
417:       for (r = 0; r < 4; ++r) {
418:         const PetscInt newp = (c - cStart)*4 + r;

420:         DMPlexSetConeSize(rdm, newp, 3);
421:       }
422:     }
423:     /* Split faces have 2 vertices and the same cells as the parent */
424:     for (f = fStart; f < fEnd; ++f) {
425:       for (r = 0; r < 2; ++r) {
426:         const PetscInt newp = fStartNew + (f - fStart)*2 + r;
427:         PetscInt       size;

429:         DMPlexSetConeSize(rdm, newp, 2);
430:         DMPlexGetSupportSize(dm, f, &size);
431:         DMPlexSetSupportSize(rdm, newp, size);
432:       }
433:     }
434:     /* Interior faces have 2 vertices and 2 cells */
435:     for (c = cStart; c < cEnd; ++c) {
436:       for (r = 0; r < 3; ++r) {
437:         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*3 + r;

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

448:       DMPlexGetSupportSize(dm, v, &size);
449:       DMPlexSetSupportSize(rdm, newp, size);
450:     }
451:     /* Face vertices have 2 + cells*2 supports */
452:     for (f = fStart; f < fEnd; ++f) {
453:       const PetscInt newp = vStartNew + (vEnd - vStart) + (f - fStart);
454:       PetscInt       size;

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

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

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

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

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

502:       DMPlexGetSupportSize(dm, f, &size);
503:       DMPlexSetSupportSize(rdm, newp, size + 2);
504:     }
505:     /* Interior vertices have 3 supports */
506:     for (c = cStart; c < cEnd; ++c) {
507:       const PetscInt newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + c - cStart;

509:       DMPlexSetSupportSize(rdm, newp, 3);
510:     }
511:     break;
512:   case REFINER_HEX_2D:
513:     /* All cells have 4 faces */
514:     for (c = cStart; c < cEnd; ++c) {
515:       for (r = 0; r < 4; ++r) {
516:         const PetscInt newp = cStartNew + (c - cStart)*4 + r;

518:         DMPlexSetConeSize(rdm, newp, 4);
519:       }
520:     }
521:     /* Split faces have 2 vertices and the same cells as the parent */
522:     for (f = fStart; f < fEnd; ++f) {
523:       for (r = 0; r < 2; ++r) {
524:         const PetscInt newp = fStartNew + (f - fStart)*2 + r;
525:         PetscInt       size;

527:         DMPlexSetConeSize(rdm, newp, 2);
528:         DMPlexGetSupportSize(dm, f, &size);
529:         DMPlexSetSupportSize(rdm, newp, size);
530:       }
531:     }
532:     /* Interior faces have 2 vertices and 2 cells */
533:     for (c = cStart; c < cEnd; ++c) {
534:       for (r = 0; r < 4; ++r) {
535:         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*4 + r;

537:         DMPlexSetConeSize(rdm, newp, 2);
538:         DMPlexSetSupportSize(rdm, newp, 2);
539:       }
540:     }
541:     /* Old vertices have identical supports */
542:     for (v = vStart; v < vEnd; ++v) {
543:       const PetscInt newp = vStartNew + (v - vStart);
544:       PetscInt       size;

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

554:       DMPlexGetSupportSize(dm, f, &size);
555:       DMPlexSetSupportSize(rdm, newp, 2 + size);
556:     }
557:     /* Cell vertices have 4 supports */
558:     for (c = cStart; c < cEnd; ++c) {
559:       const PetscInt newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (c - cStart);

561:       DMPlexSetSupportSize(rdm, newp, 4);
562:     }
563:     break;
564:   case REFINER_HYBRID_SIMPLEX_2D:
565:     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
566:     cMax = PetscMin(cEnd, cMax);
567:     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
568:     fMax = PetscMin(fEnd, fMax);
569:     DMPlexSetHybridBounds(rdm, cStartNew + (cMax - cStart)*4, fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3, PETSC_DETERMINE, PETSC_DETERMINE);
570:     /* Interior cells have 3 faces */
571:     for (c = cStart; c < cMax; ++c) {
572:       for (r = 0; r < 4; ++r) {
573:         const PetscInt newp = cStartNew + (c - cStart)*4 + r;

575:         DMPlexSetConeSize(rdm, newp, 3);
576:       }
577:     }
578:     /* Hybrid cells have 4 faces */
579:     for (c = cMax; c < cEnd; ++c) {
580:       for (r = 0; r < 2; ++r) {
581:         const PetscInt newp = cStartNew + (cMax - cStart)*4 + (c - cMax)*2 + r;

583:         DMPlexSetConeSize(rdm, newp, 4);
584:       }
585:     }
586:     /* Interior split faces have 2 vertices and the same cells as the parent */
587:     for (f = fStart; f < fMax; ++f) {
588:       for (r = 0; r < 2; ++r) {
589:         const PetscInt newp = fStartNew + (f - fStart)*2 + r;
590:         PetscInt       size;

592:         DMPlexSetConeSize(rdm, newp, 2);
593:         DMPlexGetSupportSize(dm, f, &size);
594:         DMPlexSetSupportSize(rdm, newp, size);
595:       }
596:     }
597:     /* Interior cell faces have 2 vertices and 2 cells */
598:     for (c = cStart; c < cMax; ++c) {
599:       for (r = 0; r < 3; ++r) {
600:         const PetscInt newp = fStartNew + (fMax - fStart)*2 + (c - cStart)*3 + r;

602:         DMPlexSetConeSize(rdm, newp, 2);
603:         DMPlexSetSupportSize(rdm, newp, 2);
604:       }
605:     }
606:     /* Hybrid faces have 2 vertices and the same cells */
607:     for (f = fMax; f < fEnd; ++f) {
608:       const PetscInt newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (f - fMax);
609:       PetscInt       size;

611:       DMPlexSetConeSize(rdm, newp, 2);
612:       DMPlexGetSupportSize(dm, f, &size);
613:       DMPlexSetSupportSize(rdm, newp, size);
614:     }
615:     /* Hybrid cell faces have 2 vertices and 2 cells */
616:     for (c = cMax; c < cEnd; ++c) {
617:       const PetscInt newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (fEnd - fMax) + (c - cMax);

619:       DMPlexSetConeSize(rdm, newp, 2);
620:       DMPlexSetSupportSize(rdm, newp, 2);
621:     }
622:     /* Old vertices have identical supports */
623:     for (v = vStart; v < vEnd; ++v) {
624:       const PetscInt newp = vStartNew + (v - vStart);
625:       PetscInt       size;

627:       DMPlexGetSupportSize(dm, v, &size);
628:       DMPlexSetSupportSize(rdm, newp, size);
629:     }
630:     /* Face vertices have 2 + (2 interior, 1 hybrid) supports */
631:     for (f = fStart; f < fMax; ++f) {
632:       const PetscInt newp = vStartNew + (vEnd - vStart) + (f - fStart);
633:       const PetscInt *support;
634:       PetscInt       size, newSize = 2, s;

636:       DMPlexGetSupportSize(dm, f, &size);
637:       DMPlexGetSupport(dm, f, &support);
638:       for (s = 0; s < size; ++s) {
639:         if (support[s] >= cMax) newSize += 1;
640:         else newSize += 2;
641:       }
642:       DMPlexSetSupportSize(rdm, newp, newSize);
643:     }
644:     break;
645:   case REFINER_HYBRID_HEX_2D:
646:     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
647:     cMax = PetscMin(cEnd, cMax);
648:     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
649:     fMax = PetscMin(fEnd, fMax);
650:     DMPlexSetHybridBounds(rdm, cStartNew + (cMax - cStart)*4, fStartNew + (fMax - fStart)*2 + (cMax - cStart)*4, PETSC_DETERMINE, PETSC_DETERMINE);
651:     /* Interior cells have 4 faces */
652:     for (c = cStart; c < cMax; ++c) {
653:       for (r = 0; r < 4; ++r) {
654:         const PetscInt newp = cStartNew + (c - cStart)*4 + r;

656:         DMPlexSetConeSize(rdm, newp, 4);
657:       }
658:     }
659:     /* Hybrid cells have 4 faces */
660:     for (c = cMax; c < cEnd; ++c) {
661:       for (r = 0; r < 2; ++r) {
662:         const PetscInt newp = cStartNew + (cMax - cStart)*4 + (c - cMax)*2 + r;

664:         DMPlexSetConeSize(rdm, newp, 4);
665:       }
666:     }
667:     /* Interior split faces have 2 vertices and the same cells as the parent */
668:     for (f = fStart; f < fMax; ++f) {
669:       for (r = 0; r < 2; ++r) {
670:         const PetscInt newp = fStartNew + (f - fStart)*2 + r;
671:         PetscInt       size;

673:         DMPlexSetConeSize(rdm, newp, 2);
674:         DMPlexGetSupportSize(dm, f, &size);
675:         DMPlexSetSupportSize(rdm, newp, size);
676:       }
677:     }
678:     /* Interior cell faces have 2 vertices and 2 cells */
679:     for (c = cStart; c < cMax; ++c) {
680:       for (r = 0; r < 4; ++r) {
681:         const PetscInt newp = fStartNew + (fMax - fStart)*2 + (c - cStart)*4 + r;

683:         DMPlexSetConeSize(rdm, newp, 2);
684:         DMPlexSetSupportSize(rdm, newp, 2);
685:       }
686:     }
687:     /* Hybrid faces have 2 vertices and the same cells */
688:     for (f = fMax; f < fEnd; ++f) {
689:       const PetscInt newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*4 + (f - fMax);
690:       PetscInt       size;

692:       DMPlexSetConeSize(rdm, newp, 2);
693:       DMPlexGetSupportSize(dm, f, &size);
694:       DMPlexSetSupportSize(rdm, newp, size);
695:     }
696:     /* Hybrid cell faces have 2 vertices and 2 cells */
697:     for (c = cMax; c < cEnd; ++c) {
698:       const PetscInt newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*4 + (fEnd - fMax) + (c - cMax);

700:       DMPlexSetConeSize(rdm, newp, 2);
701:       DMPlexSetSupportSize(rdm, newp, 2);
702:     }
703:     /* Old vertices have identical supports */
704:     for (v = vStart; v < vEnd; ++v) {
705:       const PetscInt newp = vStartNew + (v - vStart);
706:       PetscInt       size;

708:       DMPlexGetSupportSize(dm, v, &size);
709:       DMPlexSetSupportSize(rdm, newp, size);
710:     }
711:     /* Face vertices have 2 + cells supports */
712:     for (f = fStart; f < fMax; ++f) {
713:       const PetscInt newp = vStartNew + (vEnd - vStart) + (f - fStart);
714:       PetscInt       size;

716:       DMPlexGetSupportSize(dm, f, &size);
717:       DMPlexSetSupportSize(rdm, newp, 2 + size);
718:     }
719:     /* Cell vertices have 4 supports */
720:     for (c = cStart; c < cMax; ++c) {
721:       const PetscInt newp = vStartNew + (vEnd - vStart) + (fMax - fStart) + (c - cStart);

723:       DMPlexSetSupportSize(rdm, newp, 4);
724:     }
725:     break;
726:   case REFINER_SIMPLEX_3D:
727:     /* All cells have 4 faces */
728:     for (c = cStart; c < cEnd; ++c) {
729:       for (r = 0; r < 8; ++r) {
730:         const PetscInt newp = cStartNew + (c - cStart)*8 + r;

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

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

751:         DMPlexSetConeSize(rdm, newp, 3);
752:         DMPlexSetSupportSize(rdm, newp, 2);
753:       }
754:     }
755:     /* Split edges have 2 vertices and the same faces */
756:     for (e = eStart; e < eEnd; ++e) {
757:       for (r = 0; r < 2; ++r) {
758:         const PetscInt newp = eStartNew + (e - eStart)*2 + r;
759:         PetscInt       size;

761:         DMPlexSetConeSize(rdm, newp, 2);
762:         DMPlexGetSupportSize(dm, e, &size);
763:         DMPlexSetSupportSize(rdm, newp, size);
764:       }
765:     }
766:     /* Face edges have 2 vertices and 2+cells*(1/2) faces */
767:     for (f = fStart; f < fEnd; ++f) {
768:       for (r = 0; r < 3; ++r) {
769:         const PetscInt  newp = eStartNew + (eEnd - eStart)*2 + (f - fStart)*3 + r;
770:         const PetscInt *cone, *ornt, *support, eint[4] = {1, 0, 2, 0};
771:         PetscInt        coneSize, c, supportSize, s, er, intFaces = 0;

773:         DMPlexSetConeSize(rdm, newp, 2);
774:         DMPlexGetSupportSize(dm, f, &supportSize);
775:         DMPlexGetSupport(dm, f, &support);
776:         for (s = 0; s < supportSize; ++s) {
777:           DMPlexGetConeSize(dm, support[s], &coneSize);
778:           DMPlexGetCone(dm, support[s], &cone);
779:           DMPlexGetConeOrientation(dm, support[s], &ornt);
780:           for (c = 0; c < coneSize; ++c) {if (cone[c] == f) break;}
781:           /* Here we want to determine whether edge newp contains a vertex which is part of the cross-tet edge */
782:           er = GetTriMidEdgeInverse_Static(ornt[c], r);
783:           if (er == eint[c]) {
784:             intFaces += 1;
785:           } else {
786:             intFaces += 2;
787:           }
788:         }
789:         DMPlexSetSupportSize(rdm, newp, 2+intFaces);
790:       }
791:     }
792:     /* Interior cell edges have 2 vertices and 4 faces */
793:     for (c = cStart; c < cEnd; ++c) {
794:       const PetscInt newp = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart);

796:       DMPlexSetConeSize(rdm, newp, 2);
797:       DMPlexSetSupportSize(rdm, newp, 4);
798:     }
799:     /* Old vertices have identical supports */
800:     for (v = vStart; v < vEnd; ++v) {
801:       const PetscInt newp = vStartNew + (v - vStart);
802:       PetscInt       size;

804:       DMPlexGetSupportSize(dm, v, &size);
805:       DMPlexSetSupportSize(rdm, newp, size);
806:     }
807:     /* Edge vertices have 2 + faces*2 + cells*0/1 supports */
808:     for (e = eStart; e < eEnd; ++e) {
809:       const PetscInt newp = vStartNew + (vEnd - vStart) + (e - eStart);
810:       PetscInt       size, *star = NULL, starSize, s, cellSize = 0;

812:       DMPlexGetSupportSize(dm, e, &size);
813:       DMPlexGetTransitiveClosure(dm, e, PETSC_FALSE, &starSize, &star);
814:       for (s = 0; s < starSize*2; s += 2) {
815:         const PetscInt *cone, *ornt;
816:         PetscInt        e01, e23;

818:         if ((star[s] >= cStart) && (star[s] < cEnd)) {
819:           /* Check edge 0-1 */
820:           DMPlexGetCone(dm, star[s], &cone);
821:           DMPlexGetConeOrientation(dm, star[s], &ornt);
822:           DMPlexGetCone(dm, cone[0], &cone);
823:           e01  = cone[GetTriEdge_Static(ornt[0], 0)];
824:           /* Check edge 2-3 */
825:           DMPlexGetCone(dm, star[s], &cone);
826:           DMPlexGetConeOrientation(dm, star[s], &ornt);
827:           DMPlexGetCone(dm, cone[2], &cone);
828:           e23  = cone[GetTriEdge_Static(ornt[2], 1)];
829:           if ((e01 == e) || (e23 == e)) ++cellSize;
830:         }
831:       }
832:       DMPlexRestoreTransitiveClosure(dm, e, PETSC_FALSE, &starSize, &star);
833:       DMPlexSetSupportSize(rdm, newp, 2 + size*2 + cellSize);
834:     }
835:     break;
836:   case REFINER_HYBRID_SIMPLEX_3D:
837:     DMPlexSetHybridBounds(rdm, cStartNew + 8*(cMax-cStart), fStartNew + 4*(fMax - fStart) + 8*(cMax - cStart),
838:                                  eStartNew + 2*(eMax - eStart) + 3*(fMax - fStart) + (cMax - cStart), PETSC_DETERMINE);
839:     /* Interior cells have 4 faces */
840:     for (c = cStart; c < cMax; ++c) {
841:       for (r = 0; r < 8; ++r) {
842:         const PetscInt newp = cStartNew + (c - cStart)*8 + r;

844:         DMPlexSetConeSize(rdm, newp, 4);
845:       }
846:     }
847:     /* Hybrid cells have 5 faces */
848:     for (c = cMax; c < cEnd; ++c) {
849:       for (r = 0; r < 4; ++r) {
850:         const PetscInt newp = cStartNew + (cMax - cStart)*8 + (c - cMax)*4 + r;

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

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

871:         DMPlexSetConeSize(rdm, newp, 3);
872:         DMPlexSetSupportSize(rdm, newp, 2);
873:       }
874:     }
875:     /* Hybrid split faces have 4 edges and the same cells as the parent */
876:     for (f = fMax; f < fEnd; ++f) {
877:       for (r = 0; r < 2; ++r) {
878:         const PetscInt newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (f - fMax)*2 + r;
879:         PetscInt       size;

881:         DMPlexSetConeSize(rdm, newp, 4);
882:         DMPlexGetSupportSize(dm, f, &size);
883:         DMPlexSetSupportSize(rdm, newp, size);
884:       }
885:     }
886:     /* Hybrid cells faces have 4 edges and 2 cells */
887:     for (c = cMax; c < cEnd; ++c) {
888:       for (r = 0; r < 3; ++r) {
889:         const PetscInt newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (c - cMax)*3 + r;

891:         DMPlexSetConeSize(rdm, newp, 4);
892:         DMPlexSetSupportSize(rdm, newp, 2);
893:       }
894:     }
895:     /* Interior split edges have 2 vertices and the same faces */
896:     for (e = eStart; e < eMax; ++e) {
897:       for (r = 0; r < 2; ++r) {
898:         const PetscInt newp = eStartNew + (e - eStart)*2 + r;
899:         PetscInt       size;

901:         DMPlexSetConeSize(rdm, newp, 2);
902:         DMPlexGetSupportSize(dm, e, &size);
903:         DMPlexSetSupportSize(rdm, newp, size);
904:       }
905:     }
906:     /* Interior face edges have 2 vertices and 2+cells*(1/2) faces */
907:     for (f = fStart; f < fMax; ++f) {
908:       for (r = 0; r < 3; ++r) {
909:         const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (f - fStart)*3 + r;
910:         const PetscInt *cone, *ornt, *support, eint[4] = {1, 0, 2, 0};
911:         PetscInt        coneSize, c, supportSize, s, er, intFaces = 0;

913:         DMPlexSetConeSize(rdm, newp, 2);
914:         DMPlexGetSupportSize(dm, f, &supportSize);
915:         DMPlexGetSupport(dm, f, &support);
916:         for (s = 0; s < supportSize; ++s) {
917:           DMPlexGetConeSize(dm, support[s], &coneSize);
918:           DMPlexGetCone(dm, support[s], &cone);
919:           DMPlexGetConeOrientation(dm, support[s], &ornt);
920:           for (c = 0; c < coneSize; ++c) {if (cone[c] == f) break;}
921:           if (support[s] < cMax) {
922:             /* Here we want to determine whether edge newp contains a vertex which is part of the cross-tet edge */
923:             er = GetTriMidEdgeInverse_Static(ornt[c], r);
924:             if (er == eint[c]) {
925:               intFaces += 1;
926:             } else {
927:               intFaces += 2;
928:             }
929:           } else {
930:             intFaces += 1;
931:           }
932:         }
933:         DMPlexSetSupportSize(rdm, newp, 2+intFaces);
934:       }
935:     }
936:     /* Interior cell edges have 2 vertices and 4 faces */
937:     for (c = cStart; c < cMax; ++c) {
938:       const PetscInt newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart);

940:       DMPlexSetConeSize(rdm, newp, 2);
941:       DMPlexSetSupportSize(rdm, newp, 4);
942:     }
943:     /* Hybrid edges have 2 vertices and the same faces */
944:     for (e = eMax; e < eEnd; ++e) {
945:       const PetscInt newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (e - eMax);
946:       PetscInt       size;

948:       DMPlexSetConeSize(rdm, newp, 2);
949:       DMPlexGetSupportSize(dm, e, &size);
950:       DMPlexSetSupportSize(rdm, newp, size);
951:     }
952:     /* Hybrid face edges have 2 vertices and 2+2*cells faces */
953:     for (f = fMax; f < fEnd; ++f) {
954:       const PetscInt newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (eEnd - eMax) + (f - fMax);
955:       PetscInt       size;

957:       DMPlexSetConeSize(rdm, newp, 2);
958:       DMPlexGetSupportSize(dm, f, &size);
959:       DMPlexSetSupportSize(rdm, newp, 2+2*size);
960:     }
961:     /* Interior vertices have identical supports */
962:     for (v = vStart; v < vEnd; ++v) {
963:       const PetscInt newp = vStartNew + (v - vStart);
964:       PetscInt       size;

966:       DMPlexGetSupportSize(dm, v, &size);
967:       DMPlexSetSupportSize(rdm, newp, size);
968:     }
969:     /* Interior edge vertices have 2 + interior face*2 + hybrid face + cells*0/1 supports */
970:     for (e = eStart; e < eMax; ++e) {
971:       const PetscInt  newp = vStartNew + (vEnd - vStart) + (e - eStart);
972:       const PetscInt *support;
973:       PetscInt        size, *star = NULL, starSize, s, faceSize = 0, cellSize = 0;

975:       DMPlexGetSupportSize(dm, e, &size);
976:       DMPlexGetSupport(dm, e, &support);
977:       for (s = 0; s < size; ++s) {
978:         if (support[s] < fMax) faceSize += 2;
979:         else                   faceSize += 1;
980:       }
981:       DMPlexGetTransitiveClosure(dm, e, PETSC_FALSE, &starSize, &star);
982:       for (s = 0; s < starSize*2; s += 2) {
983:         const PetscInt *cone, *ornt;
984:         PetscInt        e01, e23;

986:         if ((star[s] >= cStart) && (star[s] < cMax)) {
987:           /* Check edge 0-1 */
988:           DMPlexGetCone(dm, star[s], &cone);
989:           DMPlexGetConeOrientation(dm, star[s], &ornt);
990:           DMPlexGetCone(dm, cone[0], &cone);
991:           e01  = cone[GetTriEdge_Static(ornt[0], 0)];
992:           /* Check edge 2-3 */
993:           DMPlexGetCone(dm, star[s], &cone);
994:           DMPlexGetConeOrientation(dm, star[s], &ornt);
995:           DMPlexGetCone(dm, cone[2], &cone);
996:           e23  = cone[GetTriEdge_Static(ornt[2], 1)];
997:           if ((e01 == e) || (e23 == e)) ++cellSize;
998:         }
999:       }
1000:       DMPlexRestoreTransitiveClosure(dm, e, PETSC_FALSE, &starSize, &star);
1001:       DMPlexSetSupportSize(rdm, newp, 2 + faceSize + cellSize);
1002:     }
1003:     break;
1004:   case REFINER_SIMPLEX_TO_HEX_3D:
1005:     /* All cells have 6 faces */
1006:     for (c = cStart; c < cEnd; ++c) {
1007:       for (r = 0; r < 4; ++r) {
1008:         const PetscInt newp = cStartNew + (c - cStart)*4 + r;

1010:         DMPlexSetConeSize(rdm, newp, 6);
1011:       }
1012:     }
1013:     /* Split faces have 4 edges and the same cells as the parent */
1014:     for (f = fStart; f < fEnd; ++f) {
1015:       for (r = 0; r < 3; ++r) {
1016:         const PetscInt newp = fStartNew + (f - fStart)*3 + r;
1017:         PetscInt       size;

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

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

1039:         DMPlexSetConeSize(rdm, newp, 2);
1040:         DMPlexGetSupportSize(dm, e, &size);
1041:         DMPlexSetSupportSize(rdm, newp, size);
1042:       }
1043:     }
1044:     /* Face edges have 2 vertices and 2 + cell faces supports */
1045:     for (f = fStart; f < fEnd; ++f) {
1046:       for (r = 0; r < 3; ++r) {
1047:         const PetscInt  newp = eStartNew + (eEnd - eStart)*2 + (f - fStart)*3 + r;
1048:         PetscInt        size;

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

1060:         DMPlexSetConeSize(rdm, newp, 2);
1061:         DMPlexSetSupportSize(rdm, newp, 3);
1062:       }
1063:     }
1064:     /* Old vertices have identical supports */
1065:     for (v = vStart; v < vEnd; ++v) {
1066:       const PetscInt newp = vStartNew + (v - vStart);
1067:       PetscInt       size;

1069:       DMPlexGetSupportSize(dm, v, &size);
1070:       DMPlexSetSupportSize(rdm, newp, size);
1071:     }
1072:     /* Edge vertices have 2 + faces supports */
1073:     for (e = eStart; e < eEnd; ++e) {
1074:       const PetscInt newp = vStartNew + (vEnd - vStart) + (e - eStart);
1075:       PetscInt       size;

1077:       DMPlexGetSupportSize(dm, e, &size);
1078:       DMPlexSetSupportSize(rdm, newp, 2 + size);
1079:     }
1080:     /* Face vertices have 3 + cells supports */
1081:     for (f = fStart; f < fEnd; ++f) {
1082:       const PetscInt newp = vStartNew + (vEnd - vStart) + (eEnd - eStart) + f - fStart;
1083:       PetscInt       size;

1085:       DMPlexGetSupportSize(dm, f, &size);
1086:       DMPlexSetSupportSize(rdm, newp, 3 + size);
1087:     }
1088:     /* Interior cell vertices have 4 supports */
1089:     for (c = cStart; c < cEnd; ++c) {
1090:       const PetscInt newp = vStartNew + (vEnd - vStart) + (eEnd - eStart) + fEnd - fStart + c - cStart;

1092:       DMPlexSetSupportSize(rdm, newp, 4);
1093:     }
1094:     break;
1095:   case REFINER_HEX_3D:
1096:     /* All cells have 6 faces */
1097:     for (c = cStart; c < cEnd; ++c) {
1098:       for (r = 0; r < 8; ++r) {
1099:         const PetscInt newp = (c - cStart)*8 + r;

1101:         DMPlexSetConeSize(rdm, newp, 6);
1102:       }
1103:     }
1104:     /* Split faces have 4 edges and the same cells as the parent */
1105:     for (f = fStart; f < fEnd; ++f) {
1106:       for (r = 0; r < 4; ++r) {
1107:         const PetscInt newp = fStartNew + (f - fStart)*4 + r;
1108:         PetscInt       size;

1110:         DMPlexSetConeSize(rdm, newp, 4);
1111:         DMPlexGetSupportSize(dm, f, &size);
1112:         DMPlexSetSupportSize(rdm, newp, size);
1113:       }
1114:     }
1115:     /* Interior faces have 4 edges and 2 cells */
1116:     for (c = cStart; c < cEnd; ++c) {
1117:       for (r = 0; r < 12; ++r) {
1118:         const PetscInt newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + r;

1120:         DMPlexSetConeSize(rdm, newp, 4);
1121:         DMPlexSetSupportSize(rdm, newp, 2);
1122:       }
1123:     }
1124:     /* Split edges have 2 vertices and the same faces as the parent */
1125:     for (e = eStart; e < eEnd; ++e) {
1126:       for (r = 0; r < 2; ++r) {
1127:         const PetscInt newp = eStartNew + (e - eStart)*2 + r;
1128:         PetscInt       size;

1130:         DMPlexSetConeSize(rdm, newp, 2);
1131:         DMPlexGetSupportSize(dm, e, &size);
1132:         DMPlexSetSupportSize(rdm, newp, size);
1133:       }
1134:     }
1135:     /* Face edges have 2 vertices and 2+cells faces */
1136:     for (f = fStart; f < fEnd; ++f) {
1137:       for (r = 0; r < 4; ++r) {
1138:         const PetscInt newp = eStartNew + (eEnd - eStart)*2 + (f - fStart)*4 + r;
1139:         PetscInt       size;

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

1151:         DMPlexSetConeSize(rdm, newp, 2);
1152:         DMPlexSetSupportSize(rdm, newp, 4);
1153:       }
1154:     }
1155:     /* Old vertices have identical supports */
1156:     for (v = vStart; v < vEnd; ++v) {
1157:       const PetscInt newp = vStartNew + (v - vStart);
1158:       PetscInt       size;

1160:       DMPlexGetSupportSize(dm, v, &size);
1161:       DMPlexSetSupportSize(rdm, newp, size);
1162:     }
1163:     /* Edge vertices have 2 + faces supports */
1164:     for (e = eStart; e < eEnd; ++e) {
1165:       const PetscInt newp = vStartNew + (vEnd - vStart) + (e - eStart);
1166:       PetscInt       size;

1168:       DMPlexGetSupportSize(dm, e, &size);
1169:       DMPlexSetSupportSize(rdm, newp, 2 + size);
1170:     }
1171:     /* Face vertices have 4 + cells supports */
1172:     for (f = fStart; f < fEnd; ++f) {
1173:       const PetscInt newp = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (f - fStart);
1174:       PetscInt       size;

1176:       DMPlexGetSupportSize(dm, f, &size);
1177:       DMPlexSetSupportSize(rdm, newp, 4 + size);
1178:     }
1179:     /* Cell vertices have 6 supports */
1180:     for (c = cStart; c < cEnd; ++c) {
1181:       const PetscInt newp = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (fEnd - fStart) + (c - cStart);

1183:       DMPlexSetSupportSize(rdm, newp, 6);
1184:     }
1185:     break;
1186:   case REFINER_HYBRID_HEX_3D:
1187:     DMPlexSetHybridBounds(rdm, cStartNew + 8*(cMax-cStart), fStartNew + 4*(fMax - fStart) + 12*(cMax - cStart),
1188:                                  eStartNew + 2*(eMax - eStart) + 4*(fMax - fStart) + 6*(cMax - cStart), PETSC_DETERMINE);
1189:     /* Interior cells have 6 faces */
1190:     for (c = cStart; c < cMax; ++c) {
1191:       for (r = 0; r < 8; ++r) {
1192:         const PetscInt newp = cStartNew + (c - cStart)*8 + r;

1194:         DMPlexSetConeSize(rdm, newp, 6);
1195:       }
1196:     }
1197:     /* Hybrid cells have 6 faces */
1198:     for (c = cMax; c < cEnd; ++c) {
1199:       for (r = 0; r < 4; ++r) {
1200:         const PetscInt newp = cStartNew + (cMax - cStart)*8 + (c - cMax)*4 + r;

1202:         DMPlexSetConeSize(rdm, newp, 6);
1203:       }
1204:     }
1205:     /* Interior split faces have 4 edges and the same cells as the parent */
1206:     for (f = fStart; f < fMax; ++f) {
1207:       for (r = 0; r < 4; ++r) {
1208:         const PetscInt newp = fStartNew + (f - fStart)*4 + r;
1209:         PetscInt       size;

1211:         DMPlexSetConeSize(rdm, newp, 4);
1212:         DMPlexGetSupportSize(dm, f, &size);
1213:         DMPlexSetSupportSize(rdm, newp, size);
1214:       }
1215:     }
1216:     /* Interior cell faces have 4 edges and 2 cells */
1217:     for (c = cStart; c < cMax; ++c) {
1218:       for (r = 0; r < 12; ++r) {
1219:         const PetscInt newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + r;

1221:         DMPlexSetConeSize(rdm, newp, 4);
1222:         DMPlexSetSupportSize(rdm, newp, 2);
1223:       }
1224:     }
1225:     /* Hybrid split faces have 4 edges and the same cells as the parent */
1226:     for (f = fMax; f < fEnd; ++f) {
1227:       for (r = 0; r < 2; ++r) {
1228:         const PetscInt newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (f - fMax)*2 + r;
1229:         PetscInt       size;

1231:         DMPlexSetConeSize(rdm, newp, 4);
1232:         DMPlexGetSupportSize(dm, f, &size);
1233:         DMPlexSetSupportSize(rdm, newp, size);
1234:       }
1235:     }
1236:     /* Hybrid cells faces have 4 edges and 2 cells */
1237:     for (c = cMax; c < cEnd; ++c) {
1238:       for (r = 0; r < 4; ++r) {
1239:         const PetscInt newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd - fMax)*2 + (c - cMax)*4 + r;

1241:         DMPlexSetConeSize(rdm, newp, 4);
1242:         DMPlexSetSupportSize(rdm, newp, 2);
1243:       }
1244:     }
1245:     /* Interior split edges have 2 vertices and the same faces as the parent */
1246:     for (e = eStart; e < eMax; ++e) {
1247:       for (r = 0; r < 2; ++r) {
1248:         const PetscInt newp = eStartNew + (e - eStart)*2 + r;
1249:         PetscInt       size;

1251:         DMPlexSetConeSize(rdm, newp, 2);
1252:         DMPlexGetSupportSize(dm, e, &size);
1253:         DMPlexSetSupportSize(rdm, newp, size);
1254:       }
1255:     }
1256:     /* Interior face edges have 2 vertices and 2+cells faces */
1257:     for (f = fStart; f < fMax; ++f) {
1258:       for (r = 0; r < 4; ++r) {
1259:         const PetscInt newp = eStartNew + (eMax - eStart)*2 + (f - fStart)*4 + r;
1260:         PetscInt       size;

1262:         DMPlexSetConeSize(rdm, newp, 2);
1263:         DMPlexGetSupportSize(dm, f, &size);
1264:         DMPlexSetSupportSize(rdm, newp, 2+size);
1265:       }
1266:     }
1267:     /* Interior cell edges have 2 vertices and 4 faces */
1268:     for (c = cStart; c < cMax; ++c) {
1269:       for (r = 0; r < 6; ++r) {
1270:         const PetscInt newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (c - cStart)*6 + r;

1272:         DMPlexSetConeSize(rdm, newp, 2);
1273:         DMPlexSetSupportSize(rdm, newp, 4);
1274:       }
1275:     }
1276:     /* Hybrid edges have 2 vertices and the same faces */
1277:     for (e = eMax; e < eEnd; ++e) {
1278:       const PetscInt newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (e - eMax);
1279:       PetscInt       size;

1281:       DMPlexSetConeSize(rdm, newp, 2);
1282:       DMPlexGetSupportSize(dm, e, &size);
1283:       DMPlexSetSupportSize(rdm, newp, size);
1284:     }
1285:     /* Hybrid face edges have 2 vertices and 2+cells faces */
1286:     for (f = fMax; f < fEnd; ++f) {
1287:       const PetscInt newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (eEnd - eMax) + (f - fMax);
1288:       PetscInt       size;

1290:       DMPlexSetConeSize(rdm, newp, 2);
1291:       DMPlexGetSupportSize(dm, f, &size);
1292:       DMPlexSetSupportSize(rdm, newp, 2+size);
1293:     }
1294:     /* Hybrid cell edges have 2 vertices and 4 faces */
1295:     for (c = cMax; c < cEnd; ++c) {
1296:       const PetscInt newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (eEnd - eMax) + (fEnd - fMax) + (c - cMax);

1298:       DMPlexSetConeSize(rdm, newp, 2);
1299:       DMPlexSetSupportSize(rdm, newp, 4);
1300:     }
1301:     /* Interior vertices have identical supports */
1302:     for (v = vStart; v < vEnd; ++v) {
1303:       const PetscInt newp = vStartNew + (v - vStart);
1304:       PetscInt       size;

1306:       DMPlexGetSupportSize(dm, v, &size);
1307:       DMPlexSetSupportSize(rdm, newp, size);
1308:     }
1309:     /* Interior edge vertices have 2 + faces supports */
1310:     for (e = eStart; e < eMax; ++e) {
1311:       const PetscInt newp = vStartNew + (vEnd - vStart) + (e - eStart);
1312:       PetscInt       size;

1314:       DMPlexGetSupportSize(dm, e, &size);
1315:       DMPlexSetSupportSize(rdm, newp, 2 + size);
1316:     }
1317:     /* Interior face vertices have 4 + cells supports */
1318:     for (f = fStart; f < fMax; ++f) {
1319:       const PetscInt newp = vStartNew + (vEnd - vStart) + (eMax - eStart) + (f - fStart);
1320:       PetscInt       size;

1322:       DMPlexGetSupportSize(dm, f, &size);
1323:       DMPlexSetSupportSize(rdm, newp, 4 + size);
1324:     }
1325:     /* Interior cell vertices have 6 supports */
1326:     for (c = cStart; c < cMax; ++c) {
1327:       const PetscInt newp = vStartNew + (vEnd - vStart) + (eMax - eStart) + (fMax - fStart) + (c - cStart);

1329:       DMPlexSetSupportSize(rdm, newp, 6);
1330:     }
1331:     break;
1332:   default:
1333:     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
1334:   }
1335:   return(0);
1336: }

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

1347:   if (!refiner) return(0);
1348:   DMPlexGetDepth(dm, &depth);
1349:   DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);
1350:   DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);
1351:   DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);
1352:   DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);
1353:   DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);
1354:   GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);
1355:   GetDepthEnd_Private(depth, depthSize, &cEndNew, &fEndNew, &eEndNew, &vEndNew);
1356:   switch (refiner) {
1357:   case REFINER_SIMPLEX_1D:
1358:     /* Max support size of refined mesh is 2 */
1359:     PetscMalloc1(2, &supportRef);
1360:     /* All cells have 2 vertices */
1361:     for (c = cStart; c < cEnd; ++c) {
1362:       const PetscInt  newv = vStartNew + (vEnd - vStart) + (c - cStart);

1364:       for (r = 0; r < 2; ++r) {
1365:         const PetscInt newp = cStartNew + (c - cStart)*2 + r;
1366:         const PetscInt *cone;
1367:         PetscInt        coneNew[2];

1369:         DMPlexGetCone(dm, c, &cone);
1370:         coneNew[0]       = vStartNew + (cone[0] - vStart);
1371:         coneNew[1]       = vStartNew + (cone[1] - vStart);
1372:         coneNew[(r+1)%2] = newv;
1373:         DMPlexSetCone(rdm, newp, coneNew);
1374: #if 1
1375:         if ((newp < cStartNew) || (newp >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp, cStartNew, cEndNew);
1376:         for (p = 0; p < 2; ++p) {
1377:           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
1378:         }
1379: #endif
1380:       }
1381:     }
1382:     /* Old vertices have identical supports */
1383:     for (v = vStart; v < vEnd; ++v) {
1384:       const PetscInt  newp = vStartNew + (v - vStart);
1385:       const PetscInt *support, *cone;
1386:       PetscInt        size, s;

1388:       DMPlexGetSupportSize(dm, v, &size);
1389:       DMPlexGetSupport(dm, v, &support);
1390:       for (s = 0; s < size; ++s) {
1391:         PetscInt r = 0;

1393:         DMPlexGetCone(dm, support[s], &cone);
1394:         if (cone[1] == v) r = 1;
1395:         supportRef[s] = cStartNew + (support[s] - cStart)*2 + r;
1396:       }
1397:       DMPlexSetSupport(rdm, newp, supportRef);
1398: #if 1
1399:       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
1400:       for (p = 0; p < size; ++p) {
1401:         if ((supportRef[p] < cStartNew) || (supportRef[p] >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportRef[p], cStartNew, cEndNew);
1402:       }
1403: #endif
1404:     }
1405:     /* Cell vertices have support of 2 cells */
1406:     for (c = cStart; c < cEnd; ++c) {
1407:       const PetscInt  newp = vStartNew + (vEnd - vStart) + (c - cStart);

1409:       supportRef[0] = cStartNew + (c - cStart)*2 + 0;
1410:       supportRef[1] = cStartNew + (c - cStart)*2 + 1;
1411:       DMPlexSetSupport(rdm, newp, supportRef);
1412: #if 1
1413:       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
1414:       for (p = 0; p < 2; ++p) {
1415:         if ((supportRef[p] < cStartNew) || (supportRef[p] >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportRef[p], cStartNew, cEndNew);
1416:       }
1417: #endif
1418:     }
1419:     PetscFree(supportRef);
1420:     break;
1421:   case REFINER_SIMPLEX_2D:
1422:     /*
1423:      2
1424:      |\
1425:      | \
1426:      |  \
1427:      |   \
1428:      | C  \
1429:      |     \
1430:      |      \
1431:      2---1---1
1432:      |\  D  / \
1433:      | 2   0   \
1434:      |A \ /  B  \
1435:      0---0-------1
1436:      */
1437:     /* All cells have 3 faces */
1438:     for (c = cStart; c < cEnd; ++c) {
1439:       const PetscInt  newp = cStartNew + (c - cStart)*4;
1440:       const PetscInt *cone, *ornt;
1441:       PetscInt        coneNew[3], orntNew[3];

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

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

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

1552:       DMPlexGetCone(dm, c, &cone);
1553:       for (r = 0; r < 3; ++r) {
1554:         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*3 + r;
1555:         PetscInt       coneNew[2];
1556:         PetscInt       supportNew[2];

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

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

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

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

1614:         DMPlexGetCone(dm, support[s], &cone);
1615:         if      (cone[1] == f) r = 1;
1616:         else if (cone[2] == f) r = 2;
1617:         supportRef[2+s*2+0] = fStartNew + (fEnd - fStart)*2 + (support[s] - cStart)*3 + (r+2)%3;
1618:         supportRef[2+s*2+1] = fStartNew + (fEnd - fStart)*2 + (support[s] - cStart)*3 + r;
1619:       }
1620:       DMPlexSetSupport(rdm, newp, supportRef);
1621: #if 1
1622:       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
1623:       for (p = 0; p < 2+size*2; ++p) {
1624:         if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", supportRef[p], fStartNew, fEndNew);
1625:       }
1626: #endif
1627:     }
1628:     PetscFree(supportRef);
1629:     break;
1630:   case REFINER_SIMPLEX_TO_HEX_2D:
1631:     /*
1632:      2
1633:      |\
1634:      | \
1635:      |  \
1636:      |   \
1637:      | C  \
1638:      |     \
1639:      2      1
1640:      |\    / \
1641:      | 2  1   \
1642:      |  \/     \
1643:      |   |      \
1644:      |A  |   B   \
1645:      |   0        \
1646:      |   |         \
1647:      0---0----------1
1648:      */
1649:     /* All cells have 4 faces */
1650:     for (c = cStart; c < cEnd; ++c) {
1651:       const PetscInt  newp = cStartNew + (c - cStart)*3;
1652:       const PetscInt *cone, *ornt;
1653:       PetscInt        coneNew[4], orntNew[4];

1655:       DMPlexGetCone(dm, c, &cone);
1656:       DMPlexGetConeOrientation(dm, c, &ornt);
1657:       /* A quad */
1658:       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
1659:       orntNew[0] = ornt[0];
1660:       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 0;
1661:       orntNew[1] = 0;
1662:       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 2;
1663:       orntNew[2] = -2;
1664:       coneNew[3] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
1665:       orntNew[3] = ornt[2];
1666:       DMPlexSetCone(rdm, newp+0, coneNew);
1667:       DMPlexSetConeOrientation(rdm, newp+0, orntNew);
1668: #if 1
1669:       if ((newp+0 < cStartNew) || (newp+0 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+0, cStartNew, cEndNew);
1670:       for (p = 0; p < 4; ++p) {
1671:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
1672:       }
1673: #endif
1674:       /* B quad */
1675:       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
1676:       orntNew[0] = ornt[0];
1677:       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
1678:       orntNew[1] = ornt[1];
1679:       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 1;
1680:       orntNew[2] = 0;
1681:       coneNew[3] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 0;
1682:       orntNew[3] = -2;
1683:       DMPlexSetCone(rdm, newp+1, coneNew);
1684:       DMPlexSetConeOrientation(rdm, newp+1, orntNew);
1685: #if 1
1686:       if ((newp+1 < cStartNew) || (newp+1 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+1, cStartNew, cEndNew);
1687:       for (p = 0; p < 4; ++p) {
1688:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
1689:       }
1690: #endif
1691:       /* C quad */
1692:       coneNew[0] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
1693:       orntNew[0] = ornt[1];
1694:       coneNew[1] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
1695:       orntNew[1] = ornt[2];
1696:       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 2;
1697:       orntNew[2] = 0;
1698:       coneNew[3] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 1;
1699:       orntNew[3] = -2;
1700:       DMPlexSetCone(rdm, newp+2, coneNew);
1701:       DMPlexSetConeOrientation(rdm, newp+2, orntNew);
1702: #if 1
1703:       if ((newp+2 < cStartNew) || (newp+2 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+2, cStartNew, cEndNew);
1704:       for (p = 0; p < 4; ++p) {
1705:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
1706:       }
1707: #endif
1708:     }
1709:     /* Split faces have 2 vertices and the same cells as the parent */
1710:     DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);
1711:     PetscMalloc1(2 + maxSupportSize*2, &supportRef);
1712:     for (f = fStart; f < fEnd; ++f) {
1713:       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);

1715:       for (r = 0; r < 2; ++r) {
1716:         const PetscInt  newp = fStartNew + (f - fStart)*2 + r;
1717:         const PetscInt *cone, *ornt, *support;
1718:         PetscInt        coneNew[2], coneSize, c, supportSize, s;

1720:         DMPlexGetCone(dm, f, &cone);
1721:         coneNew[0]       = vStartNew + (cone[0] - vStart);
1722:         coneNew[1]       = vStartNew + (cone[1] - vStart);
1723:         coneNew[(r+1)%2] = newv;
1724:         DMPlexSetCone(rdm, newp, coneNew);
1725: #if 1
1726:         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1727:         for (p = 0; p < 2; ++p) {
1728:           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
1729:         }
1730: #endif
1731:         DMPlexGetSupportSize(dm, f, &supportSize);
1732:         DMPlexGetSupport(dm, f, &support);
1733:         for (s = 0; s < supportSize; ++s) {
1734:           DMPlexGetConeSize(dm, support[s], &coneSize);
1735:           DMPlexGetCone(dm, support[s], &cone);
1736:           DMPlexGetConeOrientation(dm, support[s], &ornt);
1737:           for (c = 0; c < coneSize; ++c) {
1738:             if (cone[c] == f) break;
1739:           }
1740:           supportRef[s] = cStartNew + (support[s] - cStart)*3 + (ornt[c] < 0 ? (c+1-r)%3 : (c+r)%3);
1741:         }
1742:         DMPlexSetSupport(rdm, newp, supportRef);
1743: #if 1
1744:         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1745:         for (p = 0; p < supportSize; ++p) {
1746:           if ((supportRef[p] < cStartNew) || (supportRef[p] >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportRef[p], cStartNew, cEndNew);
1747:         }
1748: #endif
1749:       }
1750:     }
1751:     /* Interior faces have 2 vertices and 2 cells */
1752:     for (c = cStart; c < cEnd; ++c) {
1753:       const PetscInt *cone;

1755:       DMPlexGetCone(dm, c, &cone);
1756:       for (r = 0; r < 3; ++r) {
1757:         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*3 + r;
1758:         PetscInt       coneNew[2];
1759:         PetscInt       supportNew[2];

1761:         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r] - fStart);
1762:         coneNew[1] = vStartNew + (vEnd - vStart) + (fEnd    - fStart) + (c - cStart);
1763:         DMPlexSetCone(rdm, newp, coneNew);
1764: #if 1
1765:         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1766:         for (p = 0; p < 2; ++p) {
1767:           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
1768:         }
1769: #endif
1770:         supportNew[0] = (c - cStart)*3 + r%3;
1771:         supportNew[1] = (c - cStart)*3 + (r+1)%3;
1772:         DMPlexSetSupport(rdm, newp, supportNew);
1773: #if 1
1774:         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1775:         for (p = 0; p < 2; ++p) {
1776:           if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cEndNew);
1777:         }
1778: #endif
1779:       }
1780:     }
1781:     /* Old vertices have identical supports */
1782:     for (v = vStart; v < vEnd; ++v) {
1783:       const PetscInt  newp = vStartNew + (v - vStart);
1784:       const PetscInt *support, *cone;
1785:       PetscInt        size, s;

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

1792:         DMPlexGetCone(dm, support[s], &cone);
1793:         if (cone[1] == v) r = 1;
1794:         supportRef[s] = fStartNew + (support[s] - fStart)*2 + r;
1795:       }
1796:       DMPlexSetSupport(rdm, newp, supportRef);
1797: #if 1
1798:       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
1799:       for (p = 0; p < size; ++p) {
1800:         if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", supportRef[p], fStartNew, fEndNew);
1801:       }
1802: #endif
1803:     }
1804:     /* Split-face vertices have cells + 2 supports */
1805:     for (f = fStart; f < fEnd; ++f) {
1806:       const PetscInt  newp = vStartNew + (vEnd - vStart) + (f - fStart);
1807:       const PetscInt *cone, *support;
1808:       PetscInt        size, s;

1810:       DMPlexGetSupportSize(dm, f, &size);
1811:       DMPlexGetSupport(dm, f, &support);
1812:       supportRef[0] = fStartNew + (f - fStart)*2 + 0;
1813:       supportRef[1] = fStartNew + (f - fStart)*2 + 1;
1814:       for (s = 0; s < size; ++s) {
1815:         PetscInt r = 0;

1817:         DMPlexGetCone(dm, support[s], &cone);
1818:         if      (cone[1] == f) r = 1;
1819:         else if (cone[2] == f) r = 2;
1820:         supportRef[2+s+0] = fStartNew + (fEnd - fStart)*2 + (support[s] - cStart)*3 + r;
1821:       }
1822:       DMPlexSetSupport(rdm, newp, supportRef);
1823: #if 1
1824:       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
1825:       for (p = 0; p < 2+size; ++p) {
1826:         if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", supportRef[p], fStartNew, fEndNew);
1827:       }
1828: #endif
1829:     }
1830:     /* Interior vertices vertices have 3 supports */
1831:     for (c = cStart; c < cEnd; ++c) {
1832:       const PetscInt newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + c - cStart;

1834:       supportRef[0] = fStartNew + (fEnd - fStart)*2 + (c - cStart)*3 + 0;
1835:       supportRef[1] = fStartNew + (fEnd - fStart)*2 + (c - cStart)*3 + 1;
1836:       supportRef[2] = fStartNew + (fEnd - fStart)*2 + (c - cStart)*3 + 2;
1837:       DMPlexSetSupport(rdm, newp, supportRef);
1838:     }
1839:     PetscFree(supportRef);
1840:     break;
1841:   case REFINER_HEX_2D:
1842:     /*
1843:      3---------2---------2
1844:      |         |         |
1845:      |    D    2    C    |
1846:      |         |         |
1847:      3----3----0----1----1
1848:      |         |         |
1849:      |    A    0    B    |
1850:      |         |         |
1851:      0---------0---------1
1852:      */
1853:     /* All cells have 4 faces */
1854:     for (c = cStart; c < cEnd; ++c) {
1855:       const PetscInt  newp = (c - cStart)*4;
1856:       const PetscInt *cone, *ornt;
1857:       PetscInt        coneNew[4], orntNew[4];

1859:       DMPlexGetCone(dm, c, &cone);
1860:       DMPlexGetConeOrientation(dm, c, &ornt);
1861:       /* A quad */
1862:       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
1863:       orntNew[0] = ornt[0];
1864:       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 0;
1865:       orntNew[1] = 0;
1866:       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 3;
1867:       orntNew[2] = -2;
1868:       coneNew[3] = fStartNew + (cone[3] - fStart)*2 + (ornt[3] < 0 ? 0 : 1);
1869:       orntNew[3] = ornt[3];
1870:       DMPlexSetCone(rdm, newp+0, coneNew);
1871:       DMPlexSetConeOrientation(rdm, newp+0, orntNew);
1872: #if 1
1873:       if ((newp+0 < cStartNew) || (newp+0 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+0, cStartNew, cEndNew);
1874:       for (p = 0; p < 4; ++p) {
1875:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
1876:       }
1877: #endif
1878:       /* B quad */
1879:       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
1880:       orntNew[0] = ornt[0];
1881:       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
1882:       orntNew[1] = ornt[1];
1883:       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 1;
1884:       orntNew[2] = -2;
1885:       coneNew[3] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 0;
1886:       orntNew[3] = -2;
1887:       DMPlexSetCone(rdm, newp+1, coneNew);
1888:       DMPlexSetConeOrientation(rdm, newp+1, orntNew);
1889: #if 1
1890:       if ((newp+1 < cStartNew) || (newp+1 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+1, cStartNew, cEndNew);
1891:       for (p = 0; p < 4; ++p) {
1892:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
1893:       }
1894: #endif
1895:       /* C quad */
1896:       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 1;
1897:       orntNew[0] = 0;
1898:       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
1899:       orntNew[1] = ornt[1];
1900:       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
1901:       orntNew[2] = ornt[2];
1902:       coneNew[3] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 2;
1903:       orntNew[3] = -2;
1904:       DMPlexSetCone(rdm, newp+2, coneNew);
1905:       DMPlexSetConeOrientation(rdm, newp+2, orntNew);
1906: #if 1
1907:       if ((newp+2 < cStartNew) || (newp+2 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+2, cStartNew, cEndNew);
1908:       for (p = 0; p < 4; ++p) {
1909:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
1910:       }
1911: #endif
1912:       /* D quad */
1913:       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 3;
1914:       orntNew[0] = 0;
1915:       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 2;
1916:       orntNew[1] = 0;
1917:       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
1918:       orntNew[2] = ornt[2];
1919:       coneNew[3] = fStartNew + (cone[3] - fStart)*2 + (ornt[3] < 0 ? 1 : 0);
1920:       orntNew[3] = ornt[3];
1921:       DMPlexSetCone(rdm, newp+3, coneNew);
1922:       DMPlexSetConeOrientation(rdm, newp+3, orntNew);
1923: #if 1
1924:       if ((newp+3 < cStartNew) || (newp+3 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+3, cStartNew, cEndNew);
1925:       for (p = 0; p < 4; ++p) {
1926:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
1927:       }
1928: #endif
1929:     }
1930:     /* Split faces have 2 vertices and the same cells as the parent */
1931:     DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);
1932:     PetscMalloc1(2 + maxSupportSize*2, &supportRef);
1933:     for (f = fStart; f < fEnd; ++f) {
1934:       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);

1936:       for (r = 0; r < 2; ++r) {
1937:         const PetscInt  newp = fStartNew + (f - fStart)*2 + r;
1938:         const PetscInt *cone, *ornt, *support;
1939:         PetscInt        coneNew[2], coneSize, c, supportSize, s;

1941:         DMPlexGetCone(dm, f, &cone);
1942:         coneNew[0]       = vStartNew + (cone[0] - vStart);
1943:         coneNew[1]       = vStartNew + (cone[1] - vStart);
1944:         coneNew[(r+1)%2] = newv;
1945:         DMPlexSetCone(rdm, newp, coneNew);
1946: #if 1
1947:         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1948:         for (p = 0; p < 2; ++p) {
1949:           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
1950:         }
1951: #endif
1952:         DMPlexGetSupportSize(dm, f, &supportSize);
1953:         DMPlexGetSupport(dm, f, &support);
1954:         for (s = 0; s < supportSize; ++s) {
1955:           DMPlexGetConeSize(dm, support[s], &coneSize);
1956:           DMPlexGetCone(dm, support[s], &cone);
1957:           DMPlexGetConeOrientation(dm, support[s], &ornt);
1958:           for (c = 0; c < coneSize; ++c) {
1959:             if (cone[c] == f) break;
1960:           }
1961:           supportRef[s] = cStartNew + (support[s] - cStart)*4 + (ornt[c] < 0 ? (c+1-r)%4 : (c+r)%4);
1962:         }
1963:         DMPlexSetSupport(rdm, newp, supportRef);
1964: #if 1
1965:         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1966:         for (p = 0; p < supportSize; ++p) {
1967:           if ((supportRef[p] < cStartNew) || (supportRef[p] >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportRef[p], cStartNew, cEndNew);
1968:         }
1969: #endif
1970:       }
1971:     }
1972:     /* Interior faces have 2 vertices and 2 cells */
1973:     for (c = cStart; c < cEnd; ++c) {
1974:       const PetscInt *cone;
1975:       PetscInt        coneNew[2], supportNew[2];

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

1981:         if (r==1 || r==2) {
1982:           coneNew[0] = vStartNew + (vEnd - vStart) + (fEnd    - fStart) + (c - cStart);
1983:           coneNew[1] = vStartNew + (vEnd - vStart) + (cone[r] - fStart);
1984:         } else {
1985:           coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r] - fStart);
1986:           coneNew[1] = vStartNew + (vEnd - vStart) + (fEnd    - fStart) + (c - cStart);
1987:         }
1988:         DMPlexSetCone(rdm, newp, coneNew);
1989: #if 1
1990:         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1991:         for (p = 0; p < 2; ++p) {
1992:           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
1993:         }
1994: #endif
1995:         supportNew[0] = (c - cStart)*4 + r;
1996:         supportNew[1] = (c - cStart)*4 + (r+1)%4;
1997:         DMPlexSetSupport(rdm, newp, supportNew);
1998: #if 1
1999:         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2000:         for (p = 0; p < 2; ++p) {
2001:           if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cEndNew);
2002:         }
2003: #endif
2004:       }
2005:     }
2006:     /* Old vertices have identical supports */
2007:     for (v = vStart; v < vEnd; ++v) {
2008:       const PetscInt  newp = vStartNew + (v - vStart);
2009:       const PetscInt *support, *cone;
2010:       PetscInt        size, s;

2012:       DMPlexGetSupportSize(dm, v, &size);
2013:       DMPlexGetSupport(dm, v, &support);
2014:       for (s = 0; s < size; ++s) {
2015:         PetscInt r = 0;

2017:         DMPlexGetCone(dm, support[s], &cone);
2018:         if (cone[1] == v) r = 1;
2019:         supportRef[s] = fStartNew + (support[s] - fStart)*2 + r;
2020:       }
2021:       DMPlexSetSupport(rdm, newp, supportRef);
2022: #if 1
2023:       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
2024:       for (p = 0; p < size; ++p) {
2025:         if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", supportRef[p], fStartNew, fEndNew);
2026:       }
2027: #endif
2028:     }
2029:     /* Face vertices have 2 + cells supports */
2030:     for (f = fStart; f < fEnd; ++f) {
2031:       const PetscInt  newp = vStartNew + (vEnd - vStart) + (f - fStart);
2032:       const PetscInt *cone, *support;
2033:       PetscInt        size, s;

2035:       DMPlexGetSupportSize(dm, f, &size);
2036:       DMPlexGetSupport(dm, f, &support);
2037:       supportRef[0] = fStartNew + (f - fStart)*2 + 0;
2038:       supportRef[1] = fStartNew + (f - fStart)*2 + 1;
2039:       for (s = 0; s < size; ++s) {
2040:         PetscInt r = 0;

2042:         DMPlexGetCone(dm, support[s], &cone);
2043:         if      (cone[1] == f) r = 1;
2044:         else if (cone[2] == f) r = 2;
2045:         else if (cone[3] == f) r = 3;
2046:         supportRef[2+s] = fStartNew + (fEnd - fStart)*2 + (support[s] - cStart)*4 + r;
2047:       }
2048:       DMPlexSetSupport(rdm, newp, supportRef);
2049: #if 1
2050:       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
2051:       for (p = 0; p < 2+size; ++p) {
2052:         if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", supportRef[p], fStartNew, fEndNew);
2053:       }
2054: #endif
2055:     }
2056:     /* Cell vertices have 4 supports */
2057:     for (c = cStart; c < cEnd; ++c) {
2058:       const PetscInt newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (c - cStart);
2059:       PetscInt       supportNew[4];

2061:       for (r = 0; r < 4; ++r) {
2062:         supportNew[r] = fStartNew + (fEnd - fStart)*2 + (c - cStart)*4 + r;
2063:       }
2064:       DMPlexSetSupport(rdm, newp, supportNew);
2065:     }
2066:     PetscFree(supportRef);
2067:     break;
2068:   case REFINER_HYBRID_SIMPLEX_2D:
2069:     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
2070:     cMax = PetscMin(cEnd, cMax);
2071:     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
2072:     fMax = PetscMin(fEnd, fMax);
2073:     DMPlexGetHybridBounds(rdm, &cMaxNew, &fMaxNew, NULL, NULL);
2074:     /* Interior cells have 3 faces */
2075:     for (c = cStart; c < cMax; ++c) {
2076:       const PetscInt  newp = cStartNew + (c - cStart)*4;
2077:       const PetscInt *cone, *ornt;
2078:       PetscInt        coneNew[3], orntNew[3];

2080:       DMPlexGetCone(dm, c, &cone);
2081:       DMPlexGetConeOrientation(dm, c, &ornt);
2082:       /* A triangle */
2083:       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
2084:       orntNew[0] = ornt[0];
2085:       coneNew[1] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 2;
2086:       orntNew[1] = -2;
2087:       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
2088:       orntNew[2] = ornt[2];
2089:       DMPlexSetCone(rdm, newp+0, coneNew);
2090:       DMPlexSetConeOrientation(rdm, newp+0, orntNew);
2091: #if 1
2092:       if ((newp+0 < cStartNew) || (newp+0 >= cMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an interior cell [%d, %d)", newp+0, cStartNew, cMaxNew);
2093:       for (p = 0; p < 3; ++p) {
2094:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an interior face [%d, %d)", coneNew[p], fStartNew, fMaxNew);
2095:       }
2096: #endif
2097:       /* B triangle */
2098:       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
2099:       orntNew[0] = ornt[0];
2100:       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
2101:       orntNew[1] = ornt[1];
2102:       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 0;
2103:       orntNew[2] = -2;
2104:       DMPlexSetCone(rdm, newp+1, coneNew);
2105:       DMPlexSetConeOrientation(rdm, newp+1, orntNew);
2106: #if 1
2107:       if ((newp+1 < cStartNew) || (newp+1 >= cMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an interior cell [%d, %d)", newp+1, cStartNew, cMaxNew);
2108:       for (p = 0; p < 3; ++p) {
2109:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an interior face [%d, %d)", coneNew[p], fStartNew, fMaxNew);
2110:       }
2111: #endif
2112:       /* C triangle */
2113:       coneNew[0] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 1;
2114:       orntNew[0] = -2;
2115:       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
2116:       orntNew[1] = ornt[1];
2117:       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
2118:       orntNew[2] = ornt[2];
2119:       DMPlexSetCone(rdm, newp+2, coneNew);
2120:       DMPlexSetConeOrientation(rdm, newp+2, orntNew);
2121: #if 1
2122:       if ((newp+2 < cStartNew) || (newp+2 >= cMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an interior cell [%d, %d)", newp+2, cStartNew, cMaxNew);
2123:       for (p = 0; p < 3; ++p) {
2124:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an interior face [%d, %d)", coneNew[p], fStartNew, fMaxNew);
2125:       }
2126: #endif
2127:       /* D triangle */
2128:       coneNew[0] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 0;
2129:       orntNew[0] = 0;
2130:       coneNew[1] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 1;
2131:       orntNew[1] = 0;
2132:       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 2;
2133:       orntNew[2] = 0;
2134:       DMPlexSetCone(rdm, newp+3, coneNew);
2135:       DMPlexSetConeOrientation(rdm, newp+3, orntNew);
2136: #if 1
2137:       if ((newp+3 < cStartNew) || (newp+3 >= cMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an interior cell [%d, %d)", newp+3, cStartNew, cMaxNew);
2138:       for (p = 0; p < 3; ++p) {
2139:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an interior face [%d, %d)", coneNew[p], fStartNew, fMaxNew);
2140:       }
2141: #endif
2142:     }
2143:     /*
2144:      2----3----3
2145:      |         |
2146:      |    B    |
2147:      |         |
2148:      0----4--- 1
2149:      |         |
2150:      |    A    |
2151:      |         |
2152:      0----2----1
2153:      */
2154:     /* Hybrid cells have 4 faces */
2155:     for (c = cMax; c < cEnd; ++c) {
2156:       const PetscInt  newp = cStartNew + (cMax - cStart)*4 + (c - cMax)*2;
2157:       const PetscInt *cone, *ornt;
2158:       PetscInt        coneNew[4], orntNew[4], r;

2160:       DMPlexGetCone(dm, c, &cone);
2161:       DMPlexGetConeOrientation(dm, c, &ornt);
2162:       r    = (ornt[0] < 0 ? 1 : 0);
2163:       /* A quad */
2164:       coneNew[0]   = fStartNew + (cone[0] - fStart)*2 + r;
2165:       orntNew[0]   = ornt[0];
2166:       coneNew[1]   = fStartNew + (cone[1] - fStart)*2 + r;
2167:       orntNew[1]   = ornt[1];
2168:       coneNew[2+r] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (cone[2+r] - fMax);
2169:       orntNew[2+r] = 0;
2170:       coneNew[3-r] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (fEnd    - fMax) + (c - cMax);
2171:       orntNew[3-r] = 0;
2172:       DMPlexSetCone(rdm, newp+0, coneNew);
2173:       DMPlexSetConeOrientation(rdm, newp+0, orntNew);
2174: #if 1
2175:       if ((newp+0 < cStartNew) || (newp+0 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+0, cStartNew, cEndNew);
2176:       for (p = 0; p < 4; ++p) {
2177:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
2178:       }
2179: #endif
2180:       /* B quad */
2181:       coneNew[0]   = fStartNew + (cone[0] - fStart)*2 + 1-r;
2182:       orntNew[0]   = ornt[0];
2183:       coneNew[1]   = fStartNew + (cone[1] - fStart)*2 + 1-r;
2184:       orntNew[1]   = ornt[1];
2185:       coneNew[2+r] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (fEnd    - fMax) + (c - cMax);
2186:       orntNew[2+r] = 0;
2187:       coneNew[3-r] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (cone[3-r] - fMax);
2188:       orntNew[3-r] = 0;
2189:       DMPlexSetCone(rdm, newp+1, coneNew);
2190:       DMPlexSetConeOrientation(rdm, newp+1, orntNew);
2191: #if 1
2192:       if ((newp+1 < cStartNew) || (newp+1 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+1, cStartNew, cEndNew);
2193:       for (p = 0; p < 4; ++p) {
2194:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
2195:       }
2196: #endif
2197:     }
2198:     /* Interior split faces have 2 vertices and the same cells as the parent */
2199:     DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);
2200:     PetscMalloc1(2 + maxSupportSize*2, &supportRef);
2201:     for (f = fStart; f < fMax; ++f) {
2202:       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);

2204:       for (r = 0; r < 2; ++r) {
2205:         const PetscInt  newp = fStartNew + (f - fStart)*2 + r;
2206:         const PetscInt *cone, *ornt, *support;
2207:         PetscInt        coneNew[2], coneSize, c, supportSize, s;

2209:         DMPlexGetCone(dm, f, &cone);
2210:         coneNew[0]       = vStartNew + (cone[0] - vStart);
2211:         coneNew[1]       = vStartNew + (cone[1] - vStart);
2212:         coneNew[(r+1)%2] = newv;
2213:         DMPlexSetCone(rdm, newp, coneNew);
2214: #if 1
2215:         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2216:         for (p = 0; p < 2; ++p) {
2217:           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
2218:         }
2219: #endif
2220:         DMPlexGetSupportSize(dm, f, &supportSize);
2221:         DMPlexGetSupport(dm, f, &support);
2222:         for (s = 0; s < supportSize; ++s) {
2223:           DMPlexGetConeSize(dm, support[s], &coneSize);
2224:           DMPlexGetCone(dm, support[s], &cone);
2225:           DMPlexGetConeOrientation(dm, support[s], &ornt);
2226:           for (c = 0; c < coneSize; ++c) if (cone[c] == f) break;
2227:           if (support[s] >= cMax) {
2228:             supportRef[s] = cStartNew + (cMax - cStart)*4 + (support[s] - cMax)*2 + (ornt[c] < 0 ? 1-r : r);
2229:           } else {
2230:             supportRef[s] = cStartNew + (support[s] - cStart)*4 + (ornt[c] < 0 ? (c+1-r)%3 : (c+r)%3);
2231:           }
2232:         }
2233:         DMPlexSetSupport(rdm, newp, supportRef);
2234: #if 1
2235:         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2236:         for (p = 0; p < supportSize; ++p) {
2237:           if ((supportRef[p] < cStartNew) || (supportRef[p] >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportRef[p], cStartNew, cEndNew);
2238:         }
2239: #endif
2240:       }
2241:     }
2242:     /* Interior cell faces have 2 vertices and 2 cells */
2243:     for (c = cStart; c < cMax; ++c) {
2244:       const PetscInt *cone;

2246:       DMPlexGetCone(dm, c, &cone);
2247:       for (r = 0; r < 3; ++r) {
2248:         const PetscInt newp = fStartNew + (fMax - fStart)*2 + (c - cStart)*3 + r;
2249:         PetscInt       coneNew[2];
2250:         PetscInt       supportNew[2];

2252:         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r]       - fStart);
2253:         coneNew[1] = vStartNew + (vEnd - vStart) + (cone[(r+1)%3] - fStart);
2254:         DMPlexSetCone(rdm, newp, coneNew);
2255: #if 1
2256:         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2257:         for (p = 0; p < 2; ++p) {
2258:           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
2259:         }
2260: #endif
2261:         supportNew[0] = (c - cStart)*4 + (r+1)%3;
2262:         supportNew[1] = (c - cStart)*4 + 3;
2263:         DMPlexSetSupport(rdm, newp, supportNew);
2264: #if 1
2265:         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2266:         for (p = 0; p < 2; ++p) {
2267:           if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cEndNew);
2268:         }
2269: #endif
2270:       }
2271:     }
2272:     /* Interior hybrid faces have 2 vertices and the same cells */
2273:     for (f = fMax; f < fEnd; ++f) {
2274:       const PetscInt  newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (f - fMax);
2275:       const PetscInt *cone, *ornt;
2276:       const PetscInt *support;
2277:       PetscInt        coneNew[2];
2278:       PetscInt        supportNew[2];
2279:       PetscInt        size, s, r;

2281:       DMPlexGetCone(dm, f, &cone);
2282:       coneNew[0] = vStartNew + (cone[0] - vStart);
2283:       coneNew[1] = vStartNew + (cone[1] - vStart);
2284:       DMPlexSetCone(rdm, newp, coneNew);
2285: #if 1
2286:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2287:       for (p = 0; p < 2; ++p) {
2288:         if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
2289:       }
2290: #endif
2291:       DMPlexGetSupportSize(dm, f, &size);
2292:       DMPlexGetSupport(dm, f, &support);
2293:       for (s = 0; s < size; ++s) {
2294:         DMPlexGetCone(dm, support[s], &cone);
2295:         DMPlexGetConeOrientation(dm, support[s], &ornt);
2296:         for (r = 0; r < 2; ++r) {
2297:           if (cone[r+2] == f) break;
2298:         }
2299:         supportNew[s] = (cMax - cStart)*4 + (support[s] - cMax)*2 + (ornt[0] < 0 ? 1-r : r);
2300:       }
2301:       DMPlexSetSupport(rdm, newp, supportNew);
2302: #if 1
2303:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2304:       for (p = 0; p < size; ++p) {
2305:         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cEndNew);
2306:       }
2307: #endif
2308:     }
2309:     /* Cell hybrid faces have 2 vertices and 2 cells */
2310:     for (c = cMax; c < cEnd; ++c) {
2311:       const PetscInt  newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (fEnd - fMax) + (c - cMax);
2312:       const PetscInt *cone;
2313:       PetscInt        coneNew[2];
2314:       PetscInt        supportNew[2];

2316:       DMPlexGetCone(dm, c, &cone);
2317:       coneNew[0] = vStartNew + (vEnd - vStart) + (cone[0] - fStart);
2318:       coneNew[1] = vStartNew + (vEnd - vStart) + (cone[1] - fStart);
2319:       DMPlexSetCone(rdm, newp, coneNew);
2320: #if 1
2321:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2322:       for (p = 0; p < 2; ++p) {
2323:         if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
2324:       }
2325: #endif
2326:       supportNew[0] = (cMax - cStart)*4 + (c - cMax)*2 + 0;
2327:       supportNew[1] = (cMax - cStart)*4 + (c - cMax)*2 + 1;
2328:       DMPlexSetSupport(rdm, newp, supportNew);
2329: #if 1
2330:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2331:       for (p = 0; p < 2; ++p) {
2332:         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cEndNew);
2333:       }
2334: #endif
2335:     }
2336:     /* Old vertices have identical supports */
2337:     for (v = vStart; v < vEnd; ++v) {
2338:       const PetscInt  newp = vStartNew + (v - vStart);
2339:       const PetscInt *support, *cone;
2340:       PetscInt        size, s;

2342:       DMPlexGetSupportSize(dm, v, &size);
2343:       DMPlexGetSupport(dm, v, &support);
2344:       for (s = 0; s < size; ++s) {
2345:         if (support[s] >= fMax) {
2346:           supportRef[s] = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (support[s] - fMax);
2347:         } else {
2348:           PetscInt r = 0;

2350:           DMPlexGetCone(dm, support[s], &cone);
2351:           if (cone[1] == v) r = 1;
2352:           supportRef[s] = fStartNew + (support[s] - fStart)*2 + r;
2353:         }
2354:       }
2355:       DMPlexSetSupport(rdm, newp, supportRef);
2356: #if 1
2357:       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
2358:       for (p = 0; p < size; ++p) {
2359:         if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", supportRef[p], fStartNew, fEndNew);
2360:       }
2361: #endif
2362:     }
2363:     /* Face vertices have 2 + (2 interior, 1 hybrid) supports */
2364:     for (f = fStart; f < fMax; ++f) {
2365:       const PetscInt  newp = vStartNew + (vEnd - vStart) + (f - fStart);
2366:       const PetscInt *cone, *support;
2367:       PetscInt        size, newSize = 2, s;

2369:       DMPlexGetSupportSize(dm, f, &size);
2370:       DMPlexGetSupport(dm, f, &support);
2371:       supportRef[0] = fStartNew + (f - fStart)*2 + 0;
2372:       supportRef[1] = fStartNew + (f - fStart)*2 + 1;
2373:       for (s = 0; s < size; ++s) {
2374:         PetscInt r = 0;

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

2380:           newSize += 1;
2381:         } else {
2382:           if      (cone[1] == f) r = 1;
2383:           else if (cone[2] == f) r = 2;
2384:           supportRef[newSize+0] = fStartNew + (fMax - fStart)*2 + (support[s] - cStart)*3 + (r+2)%3;
2385:           supportRef[newSize+1] = fStartNew + (fMax - fStart)*2 + (support[s] - cStart)*3 + r;

2387:           newSize += 2;
2388:         }
2389:       }
2390:       DMPlexSetSupport(rdm, newp, supportRef);
2391: #if 1
2392:       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
2393:       for (p = 0; p < newSize; ++p) {
2394:         if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", supportRef[p], fStartNew, fEndNew);
2395:       }
2396: #endif
2397:     }
2398:     PetscFree(supportRef);
2399:     break;
2400:   case REFINER_HYBRID_HEX_2D:
2401:     /* Hybrid Hex 2D */
2402:     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
2403:     cMax = PetscMin(cEnd, cMax);
2404:     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
2405:     fMax = PetscMin(fEnd, fMax);
2406:     DMPlexGetHybridBounds(rdm, &cMaxNew, &fMaxNew, NULL, NULL);
2407:     /* Interior cells have 4 faces */
2408:     for (c = cStart; c < cMax; ++c) {
2409:       const PetscInt  newp = cStartNew + (c - cStart)*4;
2410:       const PetscInt *cone, *ornt;
2411:       PetscInt        coneNew[4], orntNew[4];

2413:       DMPlexGetCone(dm, c, &cone);
2414:       DMPlexGetConeOrientation(dm, c, &ornt);
2415:       /* A quad */
2416:       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
2417:       orntNew[0] = ornt[0];
2418:       coneNew[1] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*4 + 0;
2419:       orntNew[1] = 0;
2420:       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*4 + 3;
2421:       orntNew[2] = -2;
2422:       coneNew[3] = fStartNew + (cone[3] - fStart)*2 + (ornt[3] < 0 ? 0 : 1);
2423:       orntNew[3] = ornt[3];
2424:       DMPlexSetCone(rdm, newp+0, coneNew);
2425:       DMPlexSetConeOrientation(rdm, newp+0, orntNew);
2426: #if 1
2427:       if ((newp+0 < cStartNew) || (newp+0 >= cMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an interior cell [%d, %d)", newp+0, cStartNew, cMaxNew);
2428:       for (p = 0; p < 4; ++p) {
2429:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an interior face [%d, %d)", coneNew[p], fStartNew, fMaxNew);
2430:       }
2431: #endif
2432:       /* B quad */
2433:       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
2434:       orntNew[0] = ornt[0];
2435:       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
2436:       orntNew[1] = ornt[1];
2437:       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*4 + 1;
2438:       orntNew[2] = 0;
2439:       coneNew[3] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*4 + 0;
2440:       orntNew[3] = -2;
2441:       DMPlexSetCone(rdm, newp+1, coneNew);
2442:       DMPlexSetConeOrientation(rdm, newp+1, orntNew);
2443: #if 1
2444:       if ((newp+1 < cStartNew) || (newp+1 >= cMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an interior cell [%d, %d)", newp+1, cStartNew, cMaxNew);
2445:       for (p = 0; p < 4; ++p) {
2446:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an interior face [%d, %d)", coneNew[p], fStartNew, fMaxNew);
2447:       }
2448: #endif
2449:       /* C quad */
2450:       coneNew[0] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*4 + 1;
2451:       orntNew[0] = -2;
2452:       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
2453:       orntNew[1] = ornt[1];
2454:       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
2455:       orntNew[2] = ornt[2];
2456:       coneNew[3] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*4 + 2;
2457:       orntNew[3] = 0;
2458:       DMPlexSetCone(rdm, newp+2, coneNew);
2459:       DMPlexSetConeOrientation(rdm, newp+2, orntNew);
2460: #if 1
2461:       if ((newp+2 < cStartNew) || (newp+2 >= cMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an interior cell [%d, %d)", newp+2, cStartNew, cMaxNew);
2462:       for (p = 0; p < 4; ++p) {
2463:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an interior face [%d, %d)", coneNew[p], fStartNew, fMaxNew);
2464:       }
2465: #endif
2466:       /* D quad */
2467:       coneNew[0] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*4 + 3;
2468:       orntNew[0] = 0;
2469:       coneNew[1] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*4 + 2;
2470:       orntNew[1] = -2;
2471:       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
2472:       orntNew[2] = ornt[2];
2473:       coneNew[3] = fStartNew + (cone[3] - fStart)*2 + (ornt[3] < 0 ? 1 : 0);
2474:       orntNew[3] = ornt[3];
2475:       DMPlexSetCone(rdm, newp+3, coneNew);
2476:       DMPlexSetConeOrientation(rdm, newp+3, orntNew);
2477: #if 1
2478:       if ((newp+3 < cStartNew) || (newp+3 >= cMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an interior cell [%d, %d)", newp+3, cStartNew, cMaxNew);
2479:       for (p = 0; p < 4; ++p) {
2480:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an interior face [%d, %d)", coneNew[p], fStartNew, fMaxNew);
2481:       }
2482: #endif
2483:     }
2484:     /*
2485:      2----3----3
2486:      |         |
2487:      |    B    |
2488:      |         |
2489:      0----4--- 1
2490:      |         |
2491:      |    A    |
2492:      |         |
2493:      0----2----1
2494:      */
2495:     /* Hybrid cells have 4 faces */
2496:     for (c = cMax; c < cEnd; ++c) {
2497:       const PetscInt  newp = cStartNew + (cMax - cStart)*4 + (c - cMax)*2;
2498:       const PetscInt *cone, *ornt;
2499:       PetscInt        coneNew[4], orntNew[4];

2501:       DMPlexGetCone(dm, c, &cone);
2502:       DMPlexGetConeOrientation(dm, c, &ornt);
2503:       /* A quad */
2504:       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
2505:       orntNew[0] = ornt[0];
2506:       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
2507:       orntNew[1] = ornt[1];
2508:       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*4 + (cone[2] - fMax);
2509:       orntNew[2] = 0;
2510:       coneNew[3] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*4 + (fEnd    - fMax) + (c - cMax);
2511:       orntNew[3] = 0;
2512:       DMPlexSetCone(rdm, newp+0, coneNew);
2513:       DMPlexSetConeOrientation(rdm, newp+0, orntNew);
2514: #if 1
2515:       if ((newp+0 < cStartNew) || (newp+0 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+0, cStartNew, cEndNew);
2516:       for (p = 0; p < 4; ++p) {
2517:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
2518:       }
2519: #endif
2520:       /* B quad */
2521:       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
2522:       orntNew[0] = ornt[0];
2523:       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
2524:       orntNew[1] = ornt[1];
2525:       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*4 + (fEnd    - fMax) + (c - cMax);
2526:       orntNew[2] = 0;
2527:       coneNew[3] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*4 + (cone[3] - fMax);
2528:       orntNew[3] = 0;
2529:       DMPlexSetCone(rdm, newp+1, coneNew);
2530:       DMPlexSetConeOrientation(rdm, newp+1, orntNew);
2531: #if 1
2532:       if ((newp+1 < cStartNew) || (newp+1 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+1, cStartNew, cEndNew);
2533:       for (p = 0; p < 4; ++p) {
2534:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
2535:       }
2536: #endif
2537:     }
2538:     /* Interior split faces have 2 vertices and the same cells as the parent */
2539:     DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);
2540:     PetscMalloc1(2 + maxSupportSize*2, &supportRef);
2541:     for (f = fStart; f < fMax; ++f) {
2542:       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);

2544:       for (r = 0; r < 2; ++r) {
2545:         const PetscInt  newp = fStartNew + (f - fStart)*2 + r;
2546:         const PetscInt *cone, *ornt, *support;
2547:         PetscInt        coneNew[2], coneSize, c, supportSize, s;

2549:         DMPlexGetCone(dm, f, &cone);
2550:         coneNew[0]       = vStartNew + (cone[0] - vStart);
2551:         coneNew[1]       = vStartNew + (cone[1] - vStart);
2552:         coneNew[(r+1)%2] = newv;
2553:         DMPlexSetCone(rdm, newp, coneNew);
2554: #if 1
2555:         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2556:         for (p = 0; p < 2; ++p) {
2557:           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
2558:         }
2559: #endif
2560:         DMPlexGetSupportSize(dm, f, &supportSize);
2561:         DMPlexGetSupport(dm, f, &support);
2562:         for (s = 0; s < supportSize; ++s) {
2563:           if (support[s] >= cMax) {
2564:             supportRef[s] = cStartNew + (cMax - cStart)*4 + (support[s] - cMax)*2 + r;
2565:           } else {
2566:             DMPlexGetConeSize(dm, support[s], &coneSize);
2567:             DMPlexGetCone(dm, support[s], &cone);
2568:             DMPlexGetConeOrientation(dm, support[s], &ornt);
2569:             for (c = 0; c < coneSize; ++c) {
2570:               if (cone[c] == f) break;
2571:             }
2572:             supportRef[s] = cStartNew + (support[s] - cStart)*4 + (ornt[c] < 0 ? (c+1-r)%4 : (c+r)%4);
2573:           }
2574:         }
2575:         DMPlexSetSupport(rdm, newp, supportRef);
2576: #if 1
2577:         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2578:         for (p = 0; p < supportSize; ++p) {
2579:           if ((supportRef[p] < cStartNew) || (supportRef[p] >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportRef[p], cStartNew, cEndNew);
2580:         }
2581: #endif
2582:       }
2583:     }
2584:     /* Interior cell faces have 2 vertices and 2 cells */
2585:     for (c = cStart; c < cMax; ++c) {
2586:       const PetscInt *cone;

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

2593:         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r] - fStart);
2594:         coneNew[1] = vStartNew + (vEnd - vStart) + (fMax    - fStart) + (c - cStart);
2595:         DMPlexSetCone(rdm, newp, coneNew);
2596: #if 1
2597:         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2598:         for (p = 0; p < 2; ++p) {
2599:           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
2600:         }
2601: #endif
2602:         supportNew[0] = (c - cStart)*4 + r;
2603:         supportNew[1] = (c - cStart)*4 + (r+1)%4;
2604:         DMPlexSetSupport(rdm, newp, supportNew);
2605: #if 1
2606:         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2607:         for (p = 0; p < 2; ++p) {
2608:           if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cEndNew);
2609:         }
2610: #endif
2611:       }
2612:     }
2613:     /* Hybrid faces have 2 vertices and the same cells */
2614:     for (f = fMax; f < fEnd; ++f) {
2615:       const PetscInt  newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*4 + (f - fMax);
2616:       const PetscInt *cone, *support;
2617:       PetscInt        coneNew[2], supportNew[2];
2618:       PetscInt        size, s, r;

2620:       DMPlexGetCone(dm, f, &cone);
2621:       coneNew[0] = vStartNew + (cone[0] - vStart);
2622:       coneNew[1] = vStartNew + (cone[1] - vStart);
2623:       DMPlexSetCone(rdm, newp, coneNew);
2624: #if 1
2625:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2626:       for (p = 0; p < 2; ++p) {
2627:         if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
2628:       }
2629: #endif
2630:       DMPlexGetSupportSize(dm, f, &size);
2631:       DMPlexGetSupport(dm, f, &support);
2632:       for (s = 0; s < size; ++s) {
2633:         DMPlexGetCone(dm, support[s], &cone);
2634:         for (r = 0; r < 2; ++r) {
2635:           if (cone[r+2] == f) break;
2636:         }
2637:         supportNew[s] = (cMax - cStart)*4 + (support[s] - cMax)*2 + r;
2638:       }
2639:       DMPlexSetSupport(rdm, newp, supportNew);
2640: #if 1
2641:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2642:       for (p = 0; p < size; ++p) {
2643:         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cEndNew);
2644:       }
2645: #endif
2646:     }
2647:     /* Cell hybrid faces have 2 vertices and 2 cells */
2648:     for (c = cMax; c < cEnd; ++c) {
2649:       const PetscInt  newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*4 + (fEnd - fMax) + (c - cMax);
2650:       const PetscInt *cone;
2651:       PetscInt        coneNew[2], supportNew[2];

2653:       DMPlexGetCone(dm, c, &cone);
2654:       coneNew[0] = vStartNew + (vEnd - vStart) + (cone[0] - fStart);
2655:       coneNew[1] = vStartNew + (vEnd - vStart) + (cone[1] - fStart);
2656:       DMPlexSetCone(rdm, newp, coneNew);
2657: #if 1
2658:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2659:       for (p = 0; p < 2; ++p) {
2660:         if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
2661:       }
2662: #endif
2663:       supportNew[0] = (cMax - cStart)*4 + (c - cMax)*2 + 0;
2664:       supportNew[1] = (cMax - cStart)*4 + (c - cMax)*2 + 1;
2665:       DMPlexSetSupport(rdm, newp, supportNew);
2666: #if 1
2667:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2668:       for (p = 0; p < 2; ++p) {
2669:         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cEndNew);
2670:       }
2671: #endif
2672:     }
2673:     /* Old vertices have identical supports */
2674:     for (v = vStart; v < vEnd; ++v) {
2675:       const PetscInt  newp = vStartNew + (v - vStart);
2676:       const PetscInt *support, *cone;
2677:       PetscInt        size, s;

2679:       DMPlexGetSupportSize(dm, v, &size);
2680:       DMPlexGetSupport(dm, v, &support);
2681:       for (s = 0; s < size; ++s) {
2682:         if (support[s] >= fMax) {
2683:           supportRef[s] = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*4 + (support[s] - fMax);
2684:         } else {
2685:           PetscInt r = 0;

2687:           DMPlexGetCone(dm, support[s], &cone);
2688:           if (cone[1] == v) r = 1;
2689:           supportRef[s] = fStartNew + (support[s] - fStart)*2 + r;
2690:         }
2691:       }
2692:       DMPlexSetSupport(rdm, newp, supportRef);
2693: #if 1
2694:       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
2695:       for (p = 0; p < size; ++p) {
2696:         if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", supportRef[p], fStartNew, fEndNew);
2697:       }
2698: #endif
2699:     }
2700:     /* Face vertices have 2 + cells supports */
2701:     for (f = fStart; f < fMax; ++f) {
2702:       const PetscInt  newp = vStartNew + (vEnd - vStart) + (f - fStart);
2703:       const PetscInt *cone, *support;
2704:       PetscInt        size, s;

2706:       DMPlexGetSupportSize(dm, f, &size);
2707:       DMPlexGetSupport(dm, f, &support);
2708:       supportRef[0] = fStartNew + (f - fStart)*2 + 0;
2709:       supportRef[1] = fStartNew + (f - fStart)*2 + 1;
2710:       for (s = 0; s < size; ++s) {
2711:         PetscInt r = 0;

2713:         DMPlexGetCone(dm, support[s], &cone);
2714:         if (support[s] >= cMax) {
2715:           supportRef[2+s] = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*4 + (fEnd - fMax) + (support[s] - cMax);
2716:         } else {
2717:           if      (cone[1] == f) r = 1;
2718:           else if (cone[2] == f) r = 2;
2719:           else if (cone[3] == f) r = 3;
2720:           supportRef[2+s] = fStartNew + (fMax - fStart)*2 + (support[s] - cStart)*4 + r;
2721:         }
2722:       }
2723:       DMPlexSetSupport(rdm, newp, supportRef);
2724: #if 1
2725:       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
2726:       for (p = 0; p < 2+size; ++p) {
2727:         if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", supportRef[p], fStartNew, fEndNew);
2728:       }
2729: #endif
2730:     }
2731:     /* Cell vertices have 4 supports */
2732:     for (c = cStart; c < cMax; ++c) {
2733:       const PetscInt newp = vStartNew + (vEnd - vStart) + (fMax - fStart) + (c - cStart);
2734:       PetscInt       supportNew[4];

2736:       for (r = 0; r < 4; ++r) {
2737:         supportNew[r] = fStartNew + (fMax - fStart)*2 + (c - cStart)*4 + r;
2738:       }
2739:       DMPlexSetSupport(rdm, newp, supportNew);
2740:     }
2741:     PetscFree(supportRef);
2742:     break;
2743:   case REFINER_SIMPLEX_3D:
2744:     /* All cells have 4 faces: Tet face order is prescribed in DMPlexGetFaces_Internal() */
2745:     DMPlexGetRawFaces_Internal(dm, 3, 4, cellInd, NULL, NULL, &faces);
2746:     for (c = cStart; c < cEnd; ++c) {
2747:       const PetscInt  newp = cStartNew + (c - cStart)*8;
2748:       const PetscInt *cone, *ornt;
2749:       PetscInt        coneNew[4], orntNew[4];

2751:       DMPlexGetCone(dm, c, &cone);
2752:       DMPlexGetConeOrientation(dm, c, &ornt);
2753:       /* A tetrahedron: {0, a, c, d} */
2754:       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetTriSubface_Static(ornt[0], 0); /* A */
2755:       orntNew[0] = ornt[0];
2756:       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetTriSubface_Static(ornt[1], 0); /* A */
2757:       orntNew[1] = ornt[1];
2758:       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetTriSubface_Static(ornt[2], 0); /* A */
2759:       orntNew[2] = ornt[2];
2760:       coneNew[3] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 0;
2761:       orntNew[3] = 0;
2762:       DMPlexSetCone(rdm, newp+0, coneNew);
2763:       DMPlexSetConeOrientation(rdm, newp+0, orntNew);
2764: #if 1
2765:       if ((newp+0 < cStartNew) || (newp+0 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+0, cStartNew, cEndNew);
2766:       for (p = 0; p < 4; ++p) {
2767:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
2768:       }
2769: #endif
2770:       /* B tetrahedron: {a, 1, b, e} */
2771:       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetTriSubface_Static(ornt[0], 1); /* B */
2772:       orntNew[0] = ornt[0];
2773:       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetTriSubface_Static(ornt[1], 2); /* C */
2774:       orntNew[1] = ornt[1];
2775:       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 1;
2776:       orntNew[2] = 0;
2777:       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetTriSubface_Static(ornt[3], 1); /* B */
2778:       orntNew[3] = ornt[3];
2779:       DMPlexSetCone(rdm, newp+1, coneNew);
2780:       DMPlexSetConeOrientation(rdm, newp+1, orntNew);
2781: #if 1
2782:       if ((newp+1 < cStartNew) || (newp+1 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+1, cStartNew, cEndNew);
2783:       for (p = 0; p < 4; ++p) {
2784:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
2785:       }
2786: #endif
2787:       /* C tetrahedron: {c, b, 2, f} */
2788:       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetTriSubface_Static(ornt[0], 2); /* C */
2789:       orntNew[0] = ornt[0];
2790:       coneNew[1] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 2;
2791:       orntNew[1] = 0;
2792:       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetTriSubface_Static(ornt[2], 1); /* B */
2793:       orntNew[2] = ornt[2];
2794:       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetTriSubface_Static(ornt[3], 0); /* A */
2795:       orntNew[3] = ornt[3];
2796:       DMPlexSetCone(rdm, newp+2, coneNew);
2797:       DMPlexSetConeOrientation(rdm, newp+2, orntNew);
2798: #if 1
2799:       if ((newp+2 < cStartNew) || (newp+2 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+2, cStartNew, cEndNew);
2800:       for (p = 0; p < 4; ++p) {
2801:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
2802:       }
2803: #endif
2804:       /* D tetrahedron: {d, e, f, 3} */
2805:       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 3;
2806:       orntNew[0] = 0;
2807:       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetTriSubface_Static(ornt[1], 1); /* B */
2808:       orntNew[1] = ornt[1];
2809:       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetTriSubface_Static(ornt[2], 2); /* C */
2810:       orntNew[2] = ornt[2];
2811:       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetTriSubface_Static(ornt[3], 2); /* C */
2812:       orntNew[3] = ornt[3];
2813:       DMPlexSetCone(rdm, newp+3, coneNew);
2814:       DMPlexSetConeOrientation(rdm, newp+3, orntNew);
2815: #if 1
2816:       if ((newp+3 < cStartNew) || (newp+3 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+3, cStartNew, cEndNew);
2817:       for (p = 0; p < 4; ++p) {
2818:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
2819:       }
2820: #endif
2821:       /* A' tetrahedron: {c, d, a, f} */
2822:       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 0;
2823:       orntNew[0] = -3;
2824:       coneNew[1] = fStartNew + (cone[2] - fStart)*4 + 3;
2825:       orntNew[1] = ornt[2] < 0 ? -(GetTriMidEdge_Static(ornt[2], 0)+1) : GetTriMidEdge_Static(ornt[2], 0);
2826:       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 5;
2827:       orntNew[2] = 0;
2828:       coneNew[3] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 4;
2829:       orntNew[3] = 2;
2830:       DMPlexSetCone(rdm, newp+4, coneNew);
2831:       DMPlexSetConeOrientation(rdm, newp+4, orntNew);
2832: #if 1
2833:       if ((newp+4 < cStartNew) || (newp+4 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+4, cStartNew, cEndNew);
2834:       for (p = 0; p < 4; ++p) {
2835:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
2836:       }
2837: #endif
2838:       /* B' tetrahedron: {e, b, a, f} */
2839:       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 1;
2840:       orntNew[0] = -2;
2841:       coneNew[1] = fStartNew + (cone[3] - fStart)*4 + 3;
2842:       orntNew[1] = ornt[3] < 0 ? -(GetTriMidEdge_Static(ornt[3], 1)+1) : GetTriMidEdge_Static(ornt[3], 1);
2843:       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 6;
2844:       orntNew[2] = 0;
2845:       coneNew[3] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 7;
2846:       orntNew[3] = 0;
2847:       DMPlexSetCone(rdm, newp+5, coneNew);
2848:       DMPlexSetConeOrientation(rdm, newp+5, orntNew);
2849: #if 1
2850:       if ((newp+5 < cStartNew) || (newp+5 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+5, cStartNew, cEndNew);
2851:       for (p = 0; p < 4; ++p) {
2852:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
2853:       }
2854: #endif
2855:       /* C' tetrahedron: {f, a, c, b} */
2856:       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 5;
2857:       orntNew[0] = -2;
2858:       coneNew[1] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 7;
2859:       orntNew[1] = -2;
2860:       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 2;
2861:       orntNew[2] = -1;
2862:       coneNew[3] = fStartNew + (cone[0] - fStart)*4 + 3;
2863:       orntNew[3] = ornt[0] < 0 ? -(GetTriMidEdge_Static(ornt[0], 2)+1) : GetTriMidEdge_Static(ornt[0], 2);
2864:       DMPlexSetCone(rdm, newp+6, coneNew);
2865:       DMPlexSetConeOrientation(rdm, newp+6, orntNew);
2866: #if 1
2867:       if ((newp+6 < cStartNew) || (newp+6 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+6, cStartNew, cEndNew);
2868:       for (p = 0; p < 4; ++p) {
2869:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
2870:       }
2871: #endif
2872:       /* D' tetrahedron: {f, a, e, d} */
2873:       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 6;
2874:       orntNew[0] = -2;
2875:       coneNew[1] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 4;
2876:       orntNew[1] = -1;
2877:       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 3;
2878:       orntNew[2] = -2;
2879:       coneNew[3] = fStartNew + (cone[1] - fStart)*4 + 3;
2880:       orntNew[3] = ornt[1] < 0 ? -(GetTriMidEdge_Static(ornt[1], 1)+1) : GetTriMidEdge_Static(ornt[1], 1);
2881:       DMPlexSetCone(rdm, newp+7, coneNew);
2882:       DMPlexSetConeOrientation(rdm, newp+7, orntNew);
2883: #if 1
2884:       if ((newp+7 < cStartNew) || (newp+7 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+7, cStartNew, cEndNew);
2885:       for (p = 0; p < 4; ++p) {
2886:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
2887:       }
2888: #endif
2889:     }
2890:     /* Split faces have 3 edges and the same cells as the parent */
2891:     DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);
2892:     PetscMalloc1(2 + maxSupportSize*2, &supportRef);
2893:     for (f = fStart; f < fEnd; ++f) {
2894:       const PetscInt  newp = fStartNew + (f - fStart)*4;
2895:       const PetscInt *cone, *ornt, *support;
2896:       PetscInt        coneNew[3], orntNew[3], coneSize, supportSize, s;

2898:       DMPlexGetCone(dm, f, &cone);
2899:       DMPlexGetConeOrientation(dm, f, &ornt);
2900:       /* A triangle */
2901:       coneNew[0] = eStartNew + (cone[0] - eStart)*2 + (ornt[0] < 0 ? 1 : 0);
2902:       orntNew[0] = ornt[0];
2903:       coneNew[1] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 2;
2904:       orntNew[1] = -2;
2905:       coneNew[2] = eStartNew + (cone[2] - eStart)*2 + (ornt[2] < 0 ? 0 : 1);
2906:       orntNew[2] = ornt[2];
2907:       DMPlexSetCone(rdm, newp+0, coneNew);
2908:       DMPlexSetConeOrientation(rdm, newp+0, orntNew);
2909: #if 1
2910:       if ((newp+0 < fStartNew) || (newp+0 >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp+0, fStartNew, fEndNew);
2911:       for (p = 0; p < 3; ++p) {
2912:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eEndNew);
2913:       }
2914: #endif
2915:       /* B triangle */
2916:       coneNew[0] = eStartNew + (cone[0] - eStart)*2 + (ornt[0] < 0 ? 0 : 1);
2917:       orntNew[0] = ornt[0];
2918:       coneNew[1] = eStartNew + (cone[1] - eStart)*2 + (ornt[1] < 0 ? 1 : 0);
2919:       orntNew[1] = ornt[1];
2920:       coneNew[2] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 0;
2921:       orntNew[2] = -2;
2922:       DMPlexSetCone(rdm, newp+1, coneNew);
2923:       DMPlexSetConeOrientation(rdm, newp+1, orntNew);
2924: #if 1
2925:       if ((newp+1 < fStartNew) || (newp+1 >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp+1, fStartNew, fEndNew);
2926:       for (p = 0; p < 3; ++p) {
2927:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eEndNew);
2928:       }
2929: #endif
2930:       /* C triangle */
2931:       coneNew[0] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 1;
2932:       orntNew[0] = -2;
2933:       coneNew[1] = eStartNew + (cone[1] - eStart)*2 + (ornt[1] < 0 ? 0 : 1);
2934:       orntNew[1] = ornt[1];
2935:       coneNew[2] = eStartNew + (cone[2] - eStart)*2 + (ornt[2] < 0 ? 1 : 0);
2936:       orntNew[2] = ornt[2];
2937:       DMPlexSetCone(rdm, newp+2, coneNew);
2938:       DMPlexSetConeOrientation(rdm, newp+2, orntNew);
2939: #if 1
2940:       if ((newp+2 < fStartNew) || (newp+2 >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp+2, fStartNew, fEndNew);
2941:       for (p = 0; p < 3; ++p) {
2942:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eEndNew);
2943:       }
2944: #endif
2945:       /* D triangle */
2946:       coneNew[0] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 0;
2947:       orntNew[0] = 0;
2948:       coneNew[1] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 1;
2949:       orntNew[1] = 0;
2950:       coneNew[2] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 2;
2951:       orntNew[2] = 0;
2952:       DMPlexSetCone(rdm, newp+3, coneNew);
2953:       DMPlexSetConeOrientation(rdm, newp+3, orntNew);
2954: #if 1
2955:       if ((newp+3 < fStartNew) || (newp+3 >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp+3, fStartNew, fEndNew);
2956:       for (p = 0; p < 3; ++p) {
2957:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eEndNew);
2958:       }
2959: #endif
2960:       DMPlexGetSupportSize(dm, f, &supportSize);
2961:       DMPlexGetSupport(dm, f, &support);
2962:       for (r = 0; r < 4; ++r) {
2963:         for (s = 0; s < supportSize; ++s) {
2964:           PetscInt subf;
2965:           DMPlexGetConeSize(dm, support[s], &coneSize);
2966:           DMPlexGetCone(dm, support[s], &cone);
2967:           DMPlexGetConeOrientation(dm, support[s], &ornt);
2968:           for (c = 0; c < coneSize; ++c) {
2969:             if (cone[c] == f) break;
2970:           }
2971:           subf = GetTriSubfaceInverse_Static(ornt[c], r);
2972:           supportRef[s] = cStartNew + (support[s] - cStart)*8 + (r==3 ? (c+2)%4 + 4 : faces[c*3+subf]);
2973:         }
2974:         DMPlexSetSupport(rdm, newp+r, supportRef);
2975: #if 1
2976:         if ((newp+r < fStartNew) || (newp+r >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp+r, fStartNew, fEndNew);
2977:         for (p = 0; p < supportSize; ++p) {
2978:           if ((supportRef[p] < cStartNew) || (supportRef[p] >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportRef[p], cStartNew, cEndNew);
2979:         }
2980: #endif
2981:       }
2982:     }
2983:     /* Interior faces have 3 edges and 2 cells */
2984:     for (c = cStart; c < cEnd; ++c) {
2985:       PetscInt        newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*8;
2986:       const PetscInt *cone, *ornt;
2987:       PetscInt        coneNew[3], orntNew[3];
2988:       PetscInt        supportNew[2];

2990:       DMPlexGetCone(dm, c, &cone);
2991:       DMPlexGetConeOrientation(dm, c, &ornt);
2992:       /* Face A: {c, a, d} */
2993:       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*3 + GetTriMidEdge_Static(ornt[0], 2);
2994:       orntNew[0] = ornt[0] < 0 ? -2 : 0;
2995:       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*3 + GetTriMidEdge_Static(ornt[1], 2);
2996:       orntNew[1] = ornt[1] < 0 ? -2 : 0;
2997:       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*3 + GetTriMidEdge_Static(ornt[2], 2);
2998:       orntNew[2] = ornt[2] < 0 ? -2 : 0;
2999:       DMPlexSetCone(rdm, newp, coneNew);
3000:       DMPlexSetConeOrientation(rdm, newp, orntNew);
3001: #if 1
3002:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
3003:       for (p = 0; p < 3; ++p) {
3004:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eEndNew);
3005:       }
3006: #endif
3007:       supportNew[0] = (c - cStart)*8 + 0;
3008:       supportNew[1] = (c - cStart)*8 + 0+4;
3009:       DMPlexSetSupport(rdm, newp, supportNew);
3010: #if 1
3011:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
3012:       for (p = 0; p < 2; ++p) {
3013:         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cEndNew);
3014:       }
3015: #endif
3016:       ++newp;
3017:       /* Face B: {a, b, e} */
3018:       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*3 + GetTriMidEdge_Static(ornt[0], 0);
3019:       orntNew[0] = ornt[0] < 0 ? -2 : 0;
3020:       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*3 + GetTriMidEdge_Static(ornt[3], 0);
3021:       orntNew[1] = ornt[3] < 0 ? -2 : 0;
3022:       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*3 + GetTriMidEdge_Static(ornt[1], 1);
3023:       orntNew[2] = ornt[1] < 0 ? -2 : 0;
3024:       DMPlexSetCone(rdm, newp, coneNew);
3025:       DMPlexSetConeOrientation(rdm, newp, orntNew);
3026: #if 1
3027:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
3028:       for (p = 0; p < 3; ++p) {
3029:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eEndNew);
3030:       }
3031: #endif
3032:       supportNew[0] = (c - cStart)*8 + 1;
3033:       supportNew[1] = (c - cStart)*8 + 1+4;
3034:       DMPlexSetSupport(rdm, newp, supportNew);
3035: #if 1
3036:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
3037:       for (p = 0; p < 2; ++p) {
3038:         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cEndNew);
3039:       }
3040: #endif
3041:       ++newp;
3042:       /* Face C: {c, f, b} */
3043:       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*3 + GetTriMidEdge_Static(ornt[2], 0);
3044:       orntNew[0] = ornt[2] < 0 ? -2 : 0;
3045:       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*3 + GetTriMidEdge_Static(ornt[3], 2);
3046:       orntNew[1] = ornt[3] < 0 ? -2 : 0;
3047:       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*3 + GetTriMidEdge_Static(ornt[0], 1);
3048:       orntNew[2] = ornt[0] < 0 ? -2 : 0;
3049:       DMPlexSetCone(rdm, newp, coneNew);
3050:       DMPlexSetConeOrientation(rdm, newp, orntNew);
3051: #if 1
3052:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
3053:       for (p = 0; p < 3; ++p) {
3054:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eEndNew);
3055:       }
3056: #endif
3057:       supportNew[0] = (c - cStart)*8 + 2;
3058:       supportNew[1] = (c - cStart)*8 + 2+4;
3059:       DMPlexSetSupport(rdm, newp, supportNew);
3060: #if 1
3061:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
3062:       for (p = 0; p < 2; ++p) {
3063:         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cEndNew);
3064:       }
3065: #endif
3066:       ++newp;
3067:       /* Face D: {d, e, f} */
3068:       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*3 + GetTriMidEdge_Static(ornt[1], 0);
3069:       orntNew[0] = ornt[1] < 0 ? -2 : 0;
3070:       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*3 + GetTriMidEdge_Static(ornt[3], 1);
3071:       orntNew[1] = ornt[3] < 0 ? -2 : 0;
3072:       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*3 + GetTriMidEdge_Static(ornt[2], 1);
3073:       orntNew[2] = ornt[2] < 0 ? -2 : 0;
3074:       DMPlexSetCone(rdm, newp, coneNew);
3075:       DMPlexSetConeOrientation(rdm, newp, orntNew);
3076: #if 1
3077:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
3078:       for (p = 0; p < 3; ++p) {
3079:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eEndNew);
3080:       }
3081: #endif
3082:       supportNew[0] = (c - cStart)*8 + 3;
3083:       supportNew[1] = (c - cStart)*8 + 3+4;
3084:       DMPlexSetSupport(rdm, newp, supportNew);
3085: #if 1
3086:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
3087:       for (p = 0; p < 2; ++p) {
3088:         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cEndNew);
3089:       }
3090: #endif
3091:       ++newp;
3092:       /* Face E: {d, f, a} */
3093:       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*3 + GetTriMidEdge_Static(ornt[2], 1);
3094:       orntNew[0] = ornt[2] < 0 ? 0 : -2;
3095:       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart);
3096:       orntNew[1] = -2;
3097:       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*3 + GetTriMidEdge_Static(ornt[1], 2);
3098:       orntNew[2] = ornt[1] < 0 ? -2 : 0;
3099:       DMPlexSetCone(rdm, newp, coneNew);
3100:       DMPlexSetConeOrientation(rdm, newp, orntNew);
3101: #if 1
3102:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
3103:       for (p = 0; p < 3; ++p) {
3104:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eEndNew);
3105:       }
3106: #endif
3107:       supportNew[0] = (c - cStart)*8 + 0+4;
3108:       supportNew[1] = (c - cStart)*8 + 3+4;
3109:       DMPlexSetSupport(rdm, newp, supportNew);
3110: #if 1
3111:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
3112:       for (p = 0; p < 2; ++p) {
3113:         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cEndNew);
3114:       }
3115: #endif
3116:       ++newp;
3117:       /* Face F: {c, a, f} */
3118:       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*3 + GetTriMidEdge_Static(ornt[0], 2);
3119:       orntNew[0] = ornt[0] < 0 ? -2 : 0;
3120:       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart);
3121:       orntNew[1] = 0;
3122:       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*3 + GetTriMidEdge_Static(ornt[2], 0);
3123:       orntNew[2] = ornt[2] < 0 ? 0 : -2;
3124:       DMPlexSetCone(rdm, newp, coneNew);
3125:       DMPlexSetConeOrientation(rdm, newp, orntNew);
3126: #if 1
3127:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
3128:       for (p = 0; p < 3; ++p) {
3129:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eEndNew);
3130:       }
3131: #endif
3132:       supportNew[0] = (c - cStart)*8 + 0+4;
3133:       supportNew[1] = (c - cStart)*8 + 2+4;
3134:       DMPlexSetSupport(rdm, newp, supportNew);
3135: #if 1
3136:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
3137:       for (p = 0; p < 2; ++p) {
3138:         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cEndNew);
3139:       }
3140: #endif
3141:       ++newp;
3142:       /* Face G: {e, a, f} */
3143:       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*3 + GetTriMidEdge_Static(ornt[1], 1);
3144:       orntNew[0] = ornt[1] < 0 ? -2 : 0;
3145:       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart);
3146:       orntNew[1] = 0;
3147:       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*3 + GetTriMidEdge_Static(ornt[3], 1);
3148:       orntNew[2] = ornt[3] < 0 ? 0 : -2;
3149:       DMPlexSetCone(rdm, newp, coneNew);
3150:       DMPlexSetConeOrientation(rdm, newp, orntNew);
3151: #if 1
3152:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
3153:       for (p = 0; p < 3; ++p) {
3154:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eEndNew);
3155:       }
3156: #endif
3157:       supportNew[0] = (c - cStart)*8 + 1+4;
3158:       supportNew[1] = (c - cStart)*8 + 3+4;
3159:       DMPlexSetSupport(rdm, newp, supportNew);
3160: #if 1
3161:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
3162:       for (p = 0; p < 2; ++p) {
3163:         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cEndNew);
3164:       }
3165: #endif
3166:       ++newp;
3167:       /* Face H: {a, b, f} */
3168:       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*3 + GetTriMidEdge_Static(ornt[0], 0);
3169:       orntNew[0] = ornt[0] < 0 ? -2 : 0;
3170:       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*3 + GetTriMidEdge_Static(ornt[3], 2);
3171:       orntNew[1] = ornt[3] < 0 ? 0 : -2;
3172:       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart);
3173:       orntNew[2] = -2;
3174:       DMPlexSetCone(rdm, newp, coneNew);
3175:       DMPlexSetConeOrientation(rdm, newp, orntNew);
3176: #if 1
3177:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
3178:       for (p = 0; p < 3; ++p) {
3179:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eEndNew);
3180:       }
3181: #endif
3182:       supportNew[0] = (c - cStart)*8 + 1+4;
3183:       supportNew[1] = (c - cStart)*8 + 2+4;
3184:       DMPlexSetSupport(rdm, newp, supportNew);
3185: #if 1
3186:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
3187:       for (p = 0; p < 2; ++p) {
3188:         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cEndNew);
3189:       }
3190: #endif
3191:       ++newp;
3192:     }
3193:     /* Split Edges have 2 vertices and the same faces as the parent */
3194:     for (e = eStart; e < eEnd; ++e) {
3195:       const PetscInt newv = vStartNew + (vEnd - vStart) + (e - eStart);

3197:       for (r = 0; r < 2; ++r) {
3198:         const PetscInt  newp = eStartNew + (e - eStart)*2 + r;
3199:         const PetscInt *cone, *ornt, *support;
3200:         PetscInt        coneNew[2], coneSize, c, supportSize, s;

3202:         DMPlexGetCone(dm, e, &cone);
3203:         coneNew[0]       = vStartNew + (cone[0] - vStart);
3204:         coneNew[1]       = vStartNew + (cone[1] - vStart);
3205:         coneNew[(r+1)%2] = newv;
3206:         DMPlexSetCone(rdm, newp, coneNew);
3207: #if 1
3208:         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
3209:         for (p = 0; p < 2; ++p) {
3210:           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
3211:         }
3212: #endif
3213:         DMPlexGetSupportSize(dm, e, &supportSize);
3214:         DMPlexGetSupport(dm, e, &support);
3215:         for (s = 0; s < supportSize; ++s) {
3216:           DMPlexGetConeSize(dm, support[s], &coneSize);
3217:           DMPlexGetCone(dm, support[s], &cone);
3218:           DMPlexGetConeOrientation(dm, support[s], &ornt);
3219:           for (c = 0; c < coneSize; ++c) {
3220:             if (cone[c] == e) break;
3221:           }
3222:           supportRef[s] = fStartNew + (support[s] - fStart)*4 + (c + (ornt[c] < 0 ? 1-r : r))%3;
3223:         }
3224:         DMPlexSetSupport(rdm, newp, supportRef);
3225: #if 1
3226:         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
3227:         for (p = 0; p < supportSize; ++p) {
3228:           if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", supportRef[p], fStartNew, fEndNew);
3229:         }
3230: #endif
3231:       }
3232:     }
3233:     /* Face edges have 2 vertices and 2+cells*(1/2) faces */
3234:     for (f = fStart; f < fEnd; ++f) {
3235:       const PetscInt *cone, *ornt, *support;
3236:       PetscInt        coneSize, supportSize, s;

3238:       DMPlexGetSupportSize(dm, f, &supportSize);
3239:       DMPlexGetSupport(dm, f, &support);
3240:       for (r = 0; r < 3; ++r) {
3241:         const PetscInt  newp = eStartNew + (eEnd - eStart)*2 + (f - fStart)*3 + r;
3242:         PetscInt        coneNew[2], intFaces = 0, er, eint[4] = {1, 0, 2, 0};
3243:         PetscInt        fint[24] = { 1,  7, -1, -1,  0,  5,
3244:                                     -1, -1,  1,  6,  0,  4,
3245:                                      2,  5,  3,  4, -1, -1,
3246:                                     -1, -1,  3,  6,  2,  7};

3248:         DMPlexGetCone(dm, f, &cone);
3249:         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[(r+0)%3] - eStart);
3250:         coneNew[1] = vStartNew + (vEnd - vStart) + (cone[(r+1)%3] - eStart);
3251:         DMPlexSetCone(rdm, newp, coneNew);
3252: #if 1
3253:         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
3254:         for (p = 0; p < 2; ++p) {
3255:           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
3256:         }
3257: #endif
3258:         supportRef[0] = fStartNew + (f - fStart)*4 + (r+1)%3;
3259:         supportRef[1] = fStartNew + (f - fStart)*4 + 3;
3260:         for (s = 0; s < supportSize; ++s) {
3261:           DMPlexGetConeSize(dm, support[s], &coneSize);
3262:           DMPlexGetCone(dm, support[s], &cone);
3263:           DMPlexGetConeOrientation(dm, support[s], &ornt);
3264:           for (c = 0; c < coneSize; ++c) {if (cone[c] == f) break;}
3265:           /* Here we want to determine whether edge newp contains a vertex which is part of the cross-tet edge */
3266:           er = GetTriMidEdgeInverse_Static(ornt[c], r);
3267:           if (er == eint[c]) {
3268:             supportRef[2+intFaces++] = fStartNew + (fEnd - fStart)*4 + (support[s] - cStart)*8 + (c + 2)%4;
3269:           } else {
3270:             supportRef[2+intFaces++] = fStartNew + (fEnd - fStart)*4 + (support[s] - cStart)*8 + fint[(c*3 + er)*2 + 0];
3271:             supportRef[2+intFaces++] = fStartNew + (fEnd - fStart)*4 + (support[s] - cStart)*8 + fint[(c*3 + er)*2 + 1];
3272:           }
3273:         }
3274:         DMPlexSetSupport(rdm, newp, supportRef);
3275: #if 1
3276:         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
3277:         for (p = 0; p < intFaces; ++p) {
3278:           if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", supportRef[p], fStartNew, fEndNew);
3279:         }
3280: #endif
3281:       }
3282:     }
3283:     /* Interior edges have 2 vertices and 4 faces */
3284:     for (c = cStart; c < cEnd; ++c) {
3285:       const PetscInt  newp = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart);
3286:       const PetscInt *cone, *ornt, *fcone;
3287:       PetscInt        coneNew[2], supportNew[4], find;

3289:       DMPlexGetCone(dm, c, &cone);
3290:       DMPlexGetConeOrientation(dm, c, &ornt);
3291:       DMPlexGetCone(dm, cone[0], &fcone);
3292:       find = GetTriEdge_Static(ornt[0], 0);
3293:       coneNew[0] = vStartNew + (vEnd - vStart) + (fcone[find] - eStart);
3294:       DMPlexGetCone(dm, cone[2], &fcone);
3295:       find = GetTriEdge_Static(ornt[2], 1);
3296:       coneNew[1] = vStartNew + (vEnd - vStart) + (fcone[find] - eStart);
3297:       DMPlexSetCone(rdm, newp, coneNew);
3298: #if 1
3299:       if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
3300:       for (p = 0; p < 2; ++p) {
3301:         if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
3302:       }
3303: #endif
3304:       supportNew[0] = fStartNew + (fEnd - fStart)*4 + (c - cStart)*8 + 4;
3305:       supportNew[1] = fStartNew + (fEnd - fStart)*4 + (c - cStart)*8 + 5;
3306:       supportNew[2] = fStartNew + (fEnd - fStart)*4 + (c - cStart)*8 + 6;
3307:       supportNew[3] = fStartNew + (fEnd - fStart)*4 + (c - cStart)*8 + 7;
3308:       DMPlexSetSupport(rdm, newp, supportNew);
3309: #if 1
3310:       if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
3311:       for (p = 0; p < 4; ++p) {
3312:         if ((supportNew[p] < fStartNew) || (supportNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", supportNew[p], fStartNew, fEndNew);
3313:       }
3314: #endif
3315:     }
3316:     /* Old vertices have identical supports */
3317:     for (v = vStart; v < vEnd; ++v) {
3318:       const PetscInt  newp = vStartNew + (v - vStart);
3319:       const PetscInt *support, *cone;
3320:       PetscInt        size, s;

3322:       DMPlexGetSupportSize(dm, v, &size);
3323:       DMPlexGetSupport(dm, v, &support);
3324:       for (s = 0; s < size; ++s) {
3325:         PetscInt r = 0;

3327:         DMPlexGetCone(dm, support[s], &cone);
3328:         if (cone[1] == v) r = 1;
3329:         supportRef[s] = eStartNew + (support[s] - eStart)*2 + r;
3330:       }
3331:       DMPlexSetSupport(rdm, newp, supportRef);
3332: #if 1
3333:       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
3334:       for (p = 0; p < size; ++p) {
3335:         if ((supportRef[p] < eStartNew) || (supportRef[p] >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", supportRef[p], eStartNew, eEndNew);
3336:       }
3337: #endif
3338:     }
3339:     /* Edge vertices have 2 + face*2 + 0/1 supports */
3340:     for (e = eStart; e < eEnd; ++e) {
3341:       const PetscInt  newp = vStartNew + (vEnd - vStart) + (e - eStart);
3342:       const PetscInt *cone, *support;
3343:       PetscInt       *star = NULL, starSize, cellSize = 0, coneSize, size, s;

3345:       DMPlexGetSupportSize(dm, e, &size);
3346:       DMPlexGetSupport(dm, e, &support);
3347:       supportRef[0] = eStartNew + (e - eStart)*2 + 0;
3348:       supportRef[1] = eStartNew + (e - eStart)*2 + 1;
3349:       for (s = 0; s < size; ++s) {
3350:         PetscInt r = 0;

3352:         DMPlexGetConeSize(dm, support[s], &coneSize);
3353:         DMPlexGetCone(dm, support[s], &cone);
3354:         for (r = 0; r < coneSize; ++r) {if (cone[r] == e) break;}
3355:         supportRef[2+s*2+0] = eStartNew + (eEnd - eStart)*2 + (support[s] - fStart)*3 + (r+0)%3;
3356:         supportRef[2+s*2+1] = eStartNew + (eEnd - eStart)*2 + (support[s] - fStart)*3 + (r+2)%3;
3357:       }
3358:       DMPlexGetTransitiveClosure(dm, e, PETSC_FALSE, &starSize, &star);
3359:       for (s = 0; s < starSize*2; s += 2) {
3360:         const PetscInt *cone, *ornt;
3361:         PetscInt        e01, e23;

3363:         if ((star[s] >= cStart) && (star[s] < cEnd)) {
3364:           /* Check edge 0-1 */
3365:           DMPlexGetCone(dm, star[s], &cone);
3366:           DMPlexGetConeOrientation(dm, star[s], &ornt);
3367:           DMPlexGetCone(dm, cone[0], &cone);
3368:           e01  = cone[GetTriEdge_Static(ornt[0], 0)];
3369:           /* Check edge 2-3 */
3370:           DMPlexGetCone(dm, star[s], &cone);
3371:           DMPlexGetConeOrientation(dm, star[s], &ornt);
3372:           DMPlexGetCone(dm, cone[2], &cone);
3373:           e23  = cone[GetTriEdge_Static(ornt[2], 1)];
3374:           if ((e01 == e) || (e23 == e)) {supportRef[2+size*2+cellSize++] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (star[s] - cStart);}
3375:         }
3376:       }
3377:       DMPlexRestoreTransitiveClosure(dm, e, PETSC_FALSE, &starSize, &star);
3378:       DMPlexSetSupport(rdm, newp, supportRef);
3379: #if 1
3380:       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
3381:       for (p = 0; p < 2+size*2+cellSize; ++p) {
3382:         if ((supportRef[p] < eStartNew) || (supportRef[p] >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", supportRef[p], eStartNew, eEndNew);
3383:       }
3384: #endif
3385:     }
3386:     PetscFree(supportRef);
3387:     DMPlexRestoreFaces_Internal(dm, 3, cStart, NULL, NULL, &faces);
3388:     break;
3389:   case REFINER_HYBRID_SIMPLEX_3D:
3390:     DMPlexGetHybridBounds(rdm, &cMaxNew, &fMaxNew, &eMaxNew, NULL);
3391:     /* Interior cells have 4 faces: Tet face order is prescribed in DMPlexGetFaces_Internal() */
3392:     DMPlexGetRawFaces_Internal(dm, 3, 4, cellInd, NULL, NULL, &faces);
3393:     for (c = cStart; c < cMax; ++c) {
3394:       const PetscInt  newp = cStartNew + (c - cStart)*8;
3395:       const PetscInt *cone, *ornt;
3396:       PetscInt        coneNew[4], orntNew[4];

3398:       DMPlexGetCone(dm, c, &cone);
3399:       DMPlexGetConeOrientation(dm, c, &ornt);
3400:       /* A tetrahedron: {0, a, c, d} */
3401:       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetTriSubface_Static(ornt[0], 0); /* A */
3402:       orntNew[0] = ornt[0];
3403:       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetTriSubface_Static(ornt[1], 0); /* A */
3404:       orntNew[1] = ornt[1];
3405:       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetTriSubface_Static(ornt[2], 0); /* A */
3406:       orntNew[2] = ornt[2];
3407:       coneNew[3] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 0;
3408:       orntNew[3] = 0;
3409:       DMPlexSetCone(rdm, newp+0, coneNew);
3410:       DMPlexSetConeOrientation(rdm, newp+0, orntNew);
3411: #if 1
3412:       if ((newp+0 < cStartNew) || (newp+0 >= cMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+0, cStartNew, cMaxNew);
3413:       for (p = 0; p < 4; ++p) {
3414:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fMaxNew);
3415:       }
3416: #endif
3417:       /* B tetrahedron: {a, 1, b, e} */
3418:       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetTriSubface_Static(ornt[0], 1); /* B */
3419:       orntNew[0] = ornt[0];
3420:       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetTriSubface_Static(ornt[1], 2); /* C */
3421:       orntNew[1] = ornt[1];
3422:       coneNew[2] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 1;
3423:       orntNew[2] = 0;
3424:       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetTriSubface_Static(ornt[3], 1); /* B */
3425:       orntNew[3] = ornt[3];
3426:       DMPlexSetCone(rdm, newp+1, coneNew);
3427:       DMPlexSetConeOrientation(rdm, newp+1, orntNew);
3428: #if 1
3429:       if ((newp+1 < cStartNew) || (newp+1 >= cMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+1, cStartNew, cMaxNew);
3430:       for (p = 0; p < 4; ++p) {
3431:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fMaxNew);
3432:       }
3433: #endif
3434:       /* C tetrahedron: {c, b, 2, f} */
3435:       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetTriSubface_Static(ornt[0], 2); /* C */
3436:       orntNew[0] = ornt[0];
3437:       coneNew[1] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 2;
3438:       orntNew[1] = 0;
3439:       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetTriSubface_Static(ornt[2], 1); /* B */
3440:       orntNew[2] = ornt[2];
3441:       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetTriSubface_Static(ornt[3], 0); /* A */
3442:       orntNew[3] = ornt[3];
3443:       DMPlexSetCone(rdm, newp+2, coneNew);
3444:       DMPlexSetConeOrientation(rdm, newp+2, orntNew);
3445: #if 1
3446:       if ((newp+2 < cStartNew) || (newp+2 >= cMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+2, cStartNew, cMaxNew);
3447:       for (p = 0; p < 4; ++p) {
3448:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fMaxNew);
3449:       }
3450: #endif
3451:       /* D tetrahedron: {d, e, f, 3} */
3452:       coneNew[0] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 3;
3453:       orntNew[0] = 0;
3454:       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetTriSubface_Static(ornt[1], 1); /* B */
3455:       orntNew[1] = ornt[1];
3456:       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetTriSubface_Static(ornt[2], 2); /* C */
3457:       orntNew[2] = ornt[2];
3458:       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetTriSubface_Static(ornt[3], 2); /* C */
3459:       orntNew[3] = ornt[3];
3460:       DMPlexSetCone(rdm, newp+3, coneNew);
3461:       DMPlexSetConeOrientation(rdm, newp+3, orntNew);
3462: #if 1
3463:       if ((newp+3 < cStartNew) || (newp+3 >= cMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+3, cStartNew, cMaxNew);
3464:       for (p = 0; p < 4; ++p) {
3465:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fMaxNew);
3466:       }
3467: #endif
3468:       /* A' tetrahedron: {d, a, c, f} */
3469:       coneNew[0] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 0;
3470:       orntNew[0] = -3;
3471:       coneNew[1] = fStartNew + (cone[2] - fStart)*4 + 3;
3472:       orntNew[1] = ornt[2] < 0 ? -(GetTriMidEdge_Static(ornt[2], 0)+1) : GetTriMidEdge_Static(ornt[2], 0);
3473:       coneNew[2] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 5;
3474:       orntNew[2] = 0;
3475:       coneNew[3] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 4;
3476:       orntNew[3] = 2;
3477:       DMPlexSetCone(rdm, newp+4, coneNew);
3478:       DMPlexSetConeOrientation(rdm, newp+4, orntNew);
3479: #if 1
3480:       if ((newp+4 < cStartNew) || (newp+4 >= cMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+4, cStartNew, cMaxNew);
3481:       for (p = 0; p < 4; ++p) {
3482:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fMaxNew);
3483:       }
3484: #endif
3485:       /* B' tetrahedron: {e, b, a, f} */
3486:       coneNew[0] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 1;
3487:       orntNew[0] = -3;
3488:       coneNew[1] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 6;
3489:       orntNew[1] = 1;
3490:       coneNew[2] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 7;
3491:       orntNew[2] = 0;
3492:       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + 3;
3493:       orntNew[3] = ornt[3] < 0 ? -(GetTriMidEdge_Static(ornt[3], 0)+1) : GetTriMidEdge_Static(ornt[3], 0);
3494:       DMPlexSetCone(rdm, newp+5, coneNew);
3495:       DMPlexSetConeOrientation(rdm, newp+5, orntNew);
3496: #if 1
3497:       if ((newp+5 < cStartNew) || (newp+5 >= cMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+5, cStartNew, cMaxNew);
3498:       for (p = 0; p < 4; ++p) {
3499:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fMaxNew);
3500:       }
3501: #endif
3502:       /* C' tetrahedron: {b, f, c, a} */
3503:       coneNew[0] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 2;
3504:       orntNew[0] = -3;
3505:       coneNew[1] = fStartNew + (cone[0] - fStart)*4 + 3;
3506:       orntNew[1] = ornt[0] < 0 ? -(GetTriMidEdge_Static(ornt[0], 2)+1) : GetTriMidEdge_Static(ornt[0], 2);
3507:       coneNew[2] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 5;
3508:       orntNew[2] = -3;
3509:       coneNew[3] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 7;
3510:       orntNew[3] = -2;
3511:       DMPlexSetCone(rdm, newp+6, coneNew);
3512:       DMPlexSetConeOrientation(rdm, newp+6, orntNew);
3513: #if 1
3514:       if ((newp+6 < cStartNew) || (newp+6 >= cMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+6, cStartNew, cMaxNew);
3515:       for (p = 0; p < 4; ++p) {
3516:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fMaxNew);
3517:       }
3518: #endif
3519:       /* D' tetrahedron: {f, e, d, a} */
3520:       coneNew[0] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 3;
3521:       orntNew[0] = -3;
3522:       coneNew[1] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 4;
3523:       orntNew[1] = -3;
3524:       coneNew[2] = fStartNew + (cone[1] - fStart)*4 + 3;
3525:       orntNew[2] = ornt[1] < 0 ? -(GetTriMidEdge_Static(ornt[1], 0)+1) : GetTriMidEdge_Static(ornt[1], 0);
3526:       coneNew[3] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 6;
3527:       orntNew[3] = -3;
3528:       DMPlexSetCone(rdm, newp+7, coneNew);
3529:       DMPlexSetConeOrientation(rdm, newp+7, orntNew);
3530: #if 1
3531:       if ((newp+7 < cStartNew) || (newp+7 >= cMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+7, cStartNew, cMaxNew);
3532:       for (p = 0; p < 4; ++p) {
3533:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fMaxNew);
3534:       }
3535: #endif
3536:     }
3537:     /* Hybrid cells have 5 faces */
3538:     for (c = cMax; c < cEnd; ++c) {
3539:       const PetscInt  newp = cStartNew + (cMax - cStart)*8 + (c - cMax)*4;
3540:       const PetscInt *cone, *ornt, *fornt;
3541:       PetscInt        coneNew[5], orntNew[5], o, of, i;

3543:       DMPlexGetCone(dm, c, &cone);
3544:       DMPlexGetConeOrientation(dm, c, &ornt);
3545:       DMPlexGetConeOrientation(dm, cone[0], &fornt);
3546:       o = ornt[0] < 0 ? -1 : 1;
3547:       for (r = 0; r < 3; ++r) {
3548:         coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetTriSubface_Static(ornt[0], r);
3549:         orntNew[0] = ornt[0];
3550:         coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetTriSubface_Static(ornt[1], r);
3551:         orntNew[1] = ornt[1];
3552:         of = fornt[GetTriEdge_Static(ornt[0], r)]       < 0 ? -1 : 1;
3553:         i  = GetTriEdgeInverse_Static(ornt[0], r)       + 2;
3554:         coneNew[i] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (cone[2+GetTriEdge_Static(ornt[0], r)]       - fMax)*2 + (o*of < 0 ? 1 : 0);
3555:         orntNew[i] = 0;
3556:         i  = GetTriEdgeInverse_Static(ornt[0], (r+1)%3) + 2;
3557:         coneNew[i] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (c - cMax)*3 + GetTriSubface_Static(ornt[0], r);
3558:         orntNew[i] = 0;
3559:         of = fornt[GetTriEdge_Static(ornt[0], (r+2)%3)] < 0 ? -1 : 1;
3560:         i  = GetTriEdgeInverse_Static(ornt[0], (r+2)%3) + 2;
3561:         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);
3562:         orntNew[i] = 0;
3563:         DMPlexSetCone(rdm, newp+r, coneNew);
3564:         DMPlexSetConeOrientation(rdm, newp+r, orntNew);
3565: #if 1
3566:         if ((newp+r < cMaxNew) || (newp+r >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid cell [%d, %d)", newp+r, cMaxNew, cEndNew);
3567:         for (p = 0; p < 2; ++p) {
3568:           if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fMaxNew);
3569:         }
3570:         for (p = 2; p < 5; ++p) {
3571:           if ((coneNew[p] < fMaxNew)   || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid face [%d, %d)", coneNew[p], fMaxNew, fEndNew);
3572:         }
3573: #endif
3574:       }
3575:       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + 3;
3576:       orntNew[0] = 0;
3577:       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + 3;
3578:       orntNew[1] = 0;
3579:       coneNew[2] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (c - cMax)*3 + 1;
3580:       orntNew[2] = 0;
3581:       coneNew[3] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (c - cMax)*3 + 2;
3582:       orntNew[3] = 0;
3583:       coneNew[4] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (c - cMax)*3 + 0;
3584:       orntNew[4] = 0;
3585:       DMPlexSetCone(rdm, newp+3, coneNew);
3586:       DMPlexSetConeOrientation(rdm, newp+3, orntNew);
3587: #if 1
3588:       if ((newp+3 < cMaxNew) || (newp+3 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid cell [%d, %d)", newp+3, cMaxNew, cEndNew);
3589:       for (p = 0; p < 2; ++p) {
3590:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fMaxNew);
3591:       }
3592:       for (p = 2; p < 5; ++p) {
3593:         if ((coneNew[p] < fMaxNew)   || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid face [%d, %d)", coneNew[p], fMaxNew, fEndNew);
3594:       }
3595: #endif
3596:     }
3597:     /* Split faces have 3 edges and the same cells as the parent */
3598:     DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);
3599:     PetscMalloc1(2 + maxSupportSize*2, &supportRef);
3600:     for (f = fStart; f < fMax; ++f) {
3601:       const PetscInt  newp = fStartNew + (f - fStart)*4;
3602:       const PetscInt *cone, *ornt, *support;
3603:       PetscInt        coneNew[3], orntNew[3], coneSize, supportSize, s;

3605:       DMPlexGetCone(dm, f, &cone);
3606:       DMPlexGetConeOrientation(dm, f, &ornt);
3607:       /* A triangle */
3608:       coneNew[0] = eStartNew + (cone[0] - eStart)*2 + (ornt[0] < 0 ? 1 : 0);
3609:       orntNew[0] = ornt[0];
3610:       coneNew[1] = eStartNew + (eMax    - eStart)*2 + (f - fStart)*3 + 2;
3611:       orntNew[1] = -2;
3612:       coneNew[2] = eStartNew + (cone[2] - eStart)*2 + (ornt[2] < 0 ? 0 : 1);
3613:       orntNew[2] = ornt[2];
3614:       DMPlexSetCone(rdm, newp+0, coneNew);
3615:       DMPlexSetConeOrientation(rdm, newp+0, orntNew);
3616: #if 1
3617:       if ((newp+0 < fStartNew) || (newp+0 >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp+0, fStartNew, fMaxNew);
3618:       for (p = 0; p < 3; ++p) {
3619:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eMaxNew);
3620:       }
3621: #endif
3622:       /* B triangle */
3623:       coneNew[0] = eStartNew + (cone[0] - eStart)*2 + (ornt[0] < 0 ? 0 : 1);
3624:       orntNew[0] = ornt[0];
3625:       coneNew[1] = eStartNew + (cone[1] - eStart)*2 + (ornt[1] < 0 ? 1 : 0);
3626:       orntNew[1] = ornt[1];
3627:       coneNew[2] = eStartNew + (eMax    - eStart)*2 + (f - fStart)*3 + 0;
3628:       orntNew[2] = -2;
3629:       DMPlexSetCone(rdm, newp+1, coneNew);
3630:       DMPlexSetConeOrientation(rdm, newp+1, orntNew);
3631: #if 1
3632:       if ((newp+1 < fStartNew) || (newp+1 >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp+1, fStartNew, fMaxNew);
3633:       for (p = 0; p < 3; ++p) {
3634:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eMaxNew);
3635:       }
3636: #endif
3637:       /* C triangle */
3638:       coneNew[0] = eStartNew + (eMax    - eStart)*2 + (f - fStart)*3 + 1;
3639:       orntNew[0] = -2;
3640:       coneNew[1] = eStartNew + (cone[1] - eStart)*2 + (ornt[1] < 0 ? 0 : 1);
3641:       orntNew[1] = ornt[1];
3642:       coneNew[2] = eStartNew + (cone[2] - eStart)*2 + (ornt[2] < 0 ? 1 : 0);
3643:       orntNew[2] = ornt[2];
3644:       DMPlexSetCone(rdm, newp+2, coneNew);
3645:       DMPlexSetConeOrientation(rdm, newp+2, orntNew);
3646: #if 1
3647:       if ((newp+2 < fStartNew) || (newp+2 >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp+2, fStartNew, fMaxNew);
3648:       for (p = 0; p < 3; ++p) {
3649:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eMaxNew);
3650:       }
3651: #endif
3652:       /* D triangle */
3653:       coneNew[0] = eStartNew + (eMax    - eStart)*2 + (f - fStart)*3 + 0;
3654:       orntNew[0] = 0;
3655:       coneNew[1] = eStartNew + (eMax    - eStart)*2 + (f - fStart)*3 + 1;
3656:       orntNew[1] = 0;
3657:       coneNew[2] = eStartNew + (eMax    - eStart)*2 + (f - fStart)*3 + 2;
3658:       orntNew[2] = 0;
3659:       DMPlexSetCone(rdm, newp+3, coneNew);
3660:       DMPlexSetConeOrientation(rdm, newp+3, orntNew);
3661: #if 1
3662:       if ((newp+3 < fStartNew) || (newp+3 >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp+3, fStartNew, fMaxNew);
3663:       for (p = 0; p < 3; ++p) {
3664:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eMaxNew);
3665:       }
3666: #endif
3667:       DMPlexGetSupportSize(dm, f, &supportSize);
3668:       DMPlexGetSupport(dm, f, &support);
3669:       for (r = 0; r < 4; ++r) {
3670:         for (s = 0; s < supportSize; ++s) {
3671:           PetscInt subf;
3672:           DMPlexGetConeSize(dm, support[s], &coneSize);
3673:           DMPlexGetCone(dm, support[s], &cone);
3674:           DMPlexGetConeOrientation(dm, support[s], &ornt);
3675:           for (c = 0; c < coneSize; ++c) {
3676:             if (cone[c] == f) break;
3677:           }
3678:           subf = GetTriSubfaceInverse_Static(ornt[c], r);
3679:           if (support[s] < cMax) {
3680:             supportRef[s] = cStartNew + (support[s] - cStart)*8 + (r==3 ? (c+2)%4 + 4 : faces[c*3+subf]);
3681:           } else {
3682:             supportRef[s] = cStartNew + (cMax - cStart)*8 + (support[s] - cMax)*4 + (r==3 ? r : subf);
3683:           }
3684:         }
3685:         DMPlexSetSupport(rdm, newp+r, supportRef);
3686: #if 1
3687:         if ((newp+r < fStartNew) || (newp+r >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp+r, fStartNew, fMaxNew);
3688:         for (p = 0; p < supportSize; ++p) {
3689:           if ((supportRef[p] < cStartNew) || (supportRef[p] >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an interior or hybrid cell [%d, %d)", supportRef[p], cStartNew, cEndNew);
3690:         }
3691: #endif
3692:       }
3693:     }
3694:     /* Interior cell faces have 3 edges and 2 cells */
3695:     for (c = cStart; c < cMax; ++c) {
3696:       PetscInt        newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*8;
3697:       const PetscInt *cone, *ornt;
3698:       PetscInt        coneNew[3], orntNew[3];
3699:       PetscInt        supportNew[2];

3701:       DMPlexGetCone(dm, c, &cone);
3702:       DMPlexGetConeOrientation(dm, c, &ornt);
3703:       /* Face A: {c, a, d} */
3704:       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*3 + GetTriMidEdge_Static(ornt[0], 2);
3705:       orntNew[0] = ornt[0] < 0 ? -2 : 0;
3706:       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*3 + GetTriMidEdge_Static(ornt[1], 2);
3707:       orntNew[1] = ornt[1] < 0 ? -2 : 0;
3708:       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*3 + GetTriMidEdge_Static(ornt[2], 2);
3709:       orntNew[2] = ornt[2] < 0 ? -2 : 0;
3710:       DMPlexSetCone(rdm, newp, coneNew);
3711:       DMPlexSetConeOrientation(rdm, newp, orntNew);
3712: #if 1
3713:       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
3714:       for (p = 0; p < 3; ++p) {
3715:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eMaxNew);
3716:       }
3717: #endif
3718:       supportNew[0] = (c - cStart)*8 + 0;
3719:       supportNew[1] = (c - cStart)*8 + 0+4;
3720:       DMPlexSetSupport(rdm, newp, supportNew);
3721: #if 1
3722:       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
3723:       for (p = 0; p < 2; ++p) {
3724:         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cMaxNew);
3725:       }
3726: #endif
3727:       ++newp;
3728:       /* Face B: {a, b, e} */
3729:       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*3 + GetTriMidEdge_Static(ornt[0], 0);
3730:       orntNew[0] = ornt[0] < 0 ? -2 : 0;
3731:       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*3 + GetTriMidEdge_Static(ornt[3], 0);
3732:       orntNew[1] = ornt[3] < 0 ? -2 : 0;
3733:       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*3 + GetTriMidEdge_Static(ornt[1], 1);
3734:       orntNew[2] = ornt[1] < 0 ? -2 : 0;
3735:       DMPlexSetCone(rdm, newp, coneNew);
3736:       DMPlexSetConeOrientation(rdm, newp, orntNew);
3737: #if 1
3738:       if ((newp+1 < fStartNew) || (newp+1 >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp+1, fStartNew, fMaxNew);
3739:       for (p = 0; p < 3; ++p) {
3740:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eMaxNew);
3741:       }
3742: #endif
3743:       supportNew[0] = (c - cStart)*8 + 1;
3744:       supportNew[1] = (c - cStart)*8 + 1+4;
3745:       DMPlexSetSupport(rdm, newp, supportNew);
3746: #if 1
3747:       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
3748:       for (p = 0; p < 2; ++p) {
3749:         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cMaxNew);
3750:       }
3751: #endif
3752:       ++newp;
3753:       /* Face C: {c, f, b} */
3754:       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*3 + GetTriMidEdge_Static(ornt[2], 0);
3755:       orntNew[0] = ornt[2] < 0 ? -2 : 0;
3756:       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*3 + GetTriMidEdge_Static(ornt[3], 2);
3757:       orntNew[1] = ornt[3] < 0 ? -2 : 0;
3758:       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*3 + GetTriMidEdge_Static(ornt[0], 1);
3759:       orntNew[2] = ornt[0] < 0 ? -2 : 0;
3760:       DMPlexSetCone(rdm, newp, coneNew);
3761:       DMPlexSetConeOrientation(rdm, newp, orntNew);
3762: #if 1
3763:       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
3764:       for (p = 0; p < 3; ++p) {
3765:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eMaxNew);
3766:       }
3767: #endif
3768:       supportNew[0] = (c - cStart)*8 + 2;
3769:       supportNew[1] = (c - cStart)*8 + 2+4;
3770:       DMPlexSetSupport(rdm, newp, supportNew);
3771: #if 1
3772:       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
3773:       for (p = 0; p < 2; ++p) {
3774:         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cMaxNew);
3775:       }
3776: #endif
3777:       ++newp;
3778:       /* Face D: {d, e, f} */
3779:       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*3 + GetTriMidEdge_Static(ornt[1], 0);
3780:       orntNew[0] = ornt[1] < 0 ? -2 : 0;
3781:       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*3 + GetTriMidEdge_Static(ornt[3], 1);
3782:       orntNew[1] = ornt[3] < 0 ? -2 : 0;
3783:       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*3 + GetTriMidEdge_Static(ornt[2], 1);
3784:       orntNew[2] = ornt[2] < 0 ? -2 : 0;
3785:       DMPlexSetCone(rdm, newp, coneNew);
3786:       DMPlexSetConeOrientation(rdm, newp, orntNew);
3787: #if 1
3788:       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
3789:       for (p = 0; p < 3; ++p) {
3790:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eMaxNew);
3791:       }
3792: #endif
3793:       supportNew[0] = (c - cStart)*8 + 3;
3794:       supportNew[1] = (c - cStart)*8 + 3+4;
3795:       DMPlexSetSupport(rdm, newp, supportNew);
3796: #if 1
3797:       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
3798:       for (p = 0; p < 2; ++p) {
3799:         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cMaxNew);
3800:       }
3801: #endif
3802:       ++newp;
3803:       /* Face E: {d, f, a} */
3804:       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*3 + GetTriMidEdge_Static(ornt[2], 1);
3805:       orntNew[0] = ornt[2] < 0 ? 0 : -2;
3806:       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart);
3807:       orntNew[1] = -2;
3808:       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*3 + GetTriMidEdge_Static(ornt[1], 2);
3809:       orntNew[2] = ornt[1] < 0 ? -2 : 0;
3810:       DMPlexSetCone(rdm, newp, coneNew);
3811:       DMPlexSetConeOrientation(rdm, newp, orntNew);
3812: #if 1
3813:       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
3814:       for (p = 0; p < 3; ++p) {
3815:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eMaxNew);
3816:       }
3817: #endif
3818:       supportNew[0] = (c - cStart)*8 + 0+4;
3819:       supportNew[1] = (c - cStart)*8 + 3+4;
3820:       DMPlexSetSupport(rdm, newp, supportNew);
3821: #if 1
3822:       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
3823:       for (p = 0; p < 2; ++p) {
3824:         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cMaxNew);
3825:       }
3826: #endif
3827:       ++newp;
3828:       /* Face F: {c, a, f} */
3829:       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*3 + GetTriMidEdge_Static(ornt[0], 2);
3830:       orntNew[0] = ornt[0] < 0 ? -2 : 0;
3831:       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart);
3832:       orntNew[1] = 0;
3833:       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*3 + GetTriMidEdge_Static(ornt[2], 0);
3834:       orntNew[2] = ornt[2] < 0 ? 0 : -2;
3835:       DMPlexSetCone(rdm, newp, coneNew);
3836:       DMPlexSetConeOrientation(rdm, newp, orntNew);
3837: #if 1
3838:       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
3839:       for (p = 0; p < 3; ++p) {
3840:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eMaxNew);
3841:       }
3842: #endif
3843:       supportNew[0] = (c - cStart)*8 + 0+4;
3844:       supportNew[1] = (c - cStart)*8 + 2+4;
3845:       DMPlexSetSupport(rdm, newp, supportNew);
3846: #if 1
3847:       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
3848:       for (p = 0; p < 2; ++p) {
3849:         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cMaxNew);
3850:       }
3851: #endif
3852:       ++newp;
3853:       /* Face G: {e, a, f} */
3854:       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*3 + GetTriMidEdge_Static(ornt[1], 1);
3855:       orntNew[0] = ornt[1] < 0 ? -2 : 0;
3856:       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart);
3857:       orntNew[1] = 0;
3858:       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*3 + GetTriMidEdge_Static(ornt[3], 1);
3859:       orntNew[2] = ornt[3] < 0 ? 0 : -2;
3860:       DMPlexSetCone(rdm, newp, coneNew);
3861:       DMPlexSetConeOrientation(rdm, newp, orntNew);
3862: #if 1
3863:       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
3864:       for (p = 0; p < 3; ++p) {
3865:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eMaxNew);
3866:       }
3867: #endif
3868:       supportNew[0] = (c - cStart)*8 + 1+4;
3869:       supportNew[1] = (c - cStart)*8 + 3+4;
3870:       DMPlexSetSupport(rdm, newp, supportNew);
3871: #if 1
3872:       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
3873:       for (p = 0; p < 2; ++p) {
3874:         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cMaxNew);
3875:       }
3876: #endif
3877:       ++newp;
3878:       /* Face H: {a, b, f} */
3879:       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*3 + GetTriMidEdge_Static(ornt[0], 0);
3880:       orntNew[0] = ornt[0] < 0 ? -2 : 0;
3881:       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*3 + GetTriMidEdge_Static(ornt[3], 2);
3882:       orntNew[1] = ornt[3] < 0 ? 0 : -2;
3883:       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart);
3884:       orntNew[2] = -2;
3885:       DMPlexSetCone(rdm, newp, coneNew);
3886:       DMPlexSetConeOrientation(rdm, newp, orntNew);
3887: #if 1
3888:       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
3889:       for (p = 0; p < 3; ++p) {
3890:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eMaxNew);
3891:       }
3892: #endif
3893:       supportNew[0] = (c - cStart)*8 + 1+4;
3894:       supportNew[1] = (c - cStart)*8 + 2+4;
3895:       DMPlexSetSupport(rdm, newp, supportNew);
3896: #if 1
3897:       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
3898:       for (p = 0; p < 2; ++p) {
3899:         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cMaxNew);
3900:       }
3901: #endif
3902:       ++newp;
3903:     }
3904:     /* Hybrid split faces have 4 edges and same cells */
3905:     for (f = fMax; f < fEnd; ++f) {
3906:       const PetscInt *cone, *ornt, *support;
3907:       PetscInt        coneNew[4], orntNew[4];
3908:       PetscInt        supportNew[2], size, s, c;

3910:       DMPlexGetCone(dm, f, &cone);
3911:       DMPlexGetConeOrientation(dm, f, &ornt);
3912:       DMPlexGetSupportSize(dm, f, &size);
3913:       DMPlexGetSupport(dm, f, &support);
3914:       for (r = 0; r < 2; ++r) {
3915:         const PetscInt newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (f - fMax)*2 + r;

3917:         coneNew[0]   = eStartNew + (cone[0] - eStart)*2 + (ornt[0] < 0 ? 1-r : r);
3918:         orntNew[0]   = ornt[0];
3919:         coneNew[1]   = eStartNew + (cone[1] - eStart)*2 + (ornt[1] < 0 ? 1-r : r);
3920:         orntNew[1]   = ornt[1];
3921:         coneNew[2+r] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (cone[2+r] - eMax);
3922:         orntNew[2+r] = 0;
3923:         coneNew[3-r] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (eEnd      - eMax) + (f - fMax);
3924:         orntNew[3-r] = 0;
3925:         DMPlexSetCone(rdm, newp, coneNew);
3926:         DMPlexSetConeOrientation(rdm, newp, orntNew);
3927: #if 1
3928:         if ((newp < fMaxNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid face [%d, %d)", newp, fMaxNew, fEndNew);
3929:         for (p = 0; p < 2; ++p) {
3930:           if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eMaxNew);
3931:         }
3932:         for (p = 2; p < 4; ++p) {
3933:           if ((coneNew[p] < eMaxNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid edge [%d, %d)", coneNew[p], eMaxNew, eEndNew);
3934:         }
3935: #endif
3936:         for (s = 0; s < size; ++s) {
3937:           const PetscInt *coneCell, *orntCell, *fornt;
3938:           PetscInt        o, of;

3940:           DMPlexGetCone(dm, support[s], &coneCell);
3941:           DMPlexGetConeOrientation(dm, support[s], &orntCell);
3942:           o = orntCell[0] < 0 ? -1 : 1;
3943:           for (c = 2; c < 5; ++c) if (coneCell[c] == f) break;
3944:           if (c >= 5) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Could not find face %d in cone of cell %d", f, support[s]);
3945:           DMPlexGetConeOrientation(dm, coneCell[0], &fornt);
3946:           of = fornt[c-2] < 0 ? -1 : 1;
3947:           supportNew[s] = cStartNew + (cMax - cStart)*8 + (support[s] - cMax)*4 + (GetTriEdgeInverse_Static(orntCell[0], c-2) + (o*of < 0 ? 1-r : r))%3;
3948:         }
3949:         DMPlexSetSupport(rdm, newp, supportNew);
3950: #if 1
3951:         if ((newp < fMaxNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid face [%d, %d)", newp, fMaxNew, fEndNew);
3952:         for (p = 0; p < size; ++p) {
3953:           if ((supportNew[p] < cMaxNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid cell [%d, %d)", supportNew[p], cMaxNew, cEndNew);
3954:         }
3955: #endif
3956:       }
3957:     }
3958:     /* Hybrid cell faces have 4 edges and 2 cells */
3959:     for (c = cMax; c < cEnd; ++c) {
3960:       PetscInt        newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (c - cMax)*3;
3961:       const PetscInt *cone, *ornt;
3962:       PetscInt        coneNew[4], orntNew[4];
3963:       PetscInt        supportNew[2];

3965:       DMPlexGetCone(dm, c, &cone);
3966:       DMPlexGetConeOrientation(dm, c, &ornt);
3967:       for (r = 0; r < 3; ++r) {
3968:         coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*3 + (r+2)%3;
3969:         orntNew[0] = 0;
3970:         coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*3 + (r+2)%3;
3971:         orntNew[1] = 0;
3972:         coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (eEnd - eMax) + (cone[2+(r+2)%3] - fMax);
3973:         orntNew[2] = 0;
3974:         coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (eEnd - eMax) + (cone[2+r]       - fMax);
3975:         orntNew[3] = 0;
3976:         DMPlexSetCone(rdm, newp+r, coneNew);
3977:         DMPlexSetConeOrientation(rdm, newp+r, orntNew);
3978: #if 1
3979:         if ((newp+r < fMaxNew) || (newp+r >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid face [%d, %d)", newp+r, fMaxNew, fEndNew);
3980:         for (p = 0; p < 2; ++p) {
3981:           if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eMaxNew);
3982:         }
3983:         for (p = 2; p < 4; ++p) {
3984:           if ((coneNew[p] < eMaxNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid edge [%d, %d)", coneNew[p], eMaxNew, eEndNew);
3985:         }
3986: #endif
3987:         supportNew[0] = cStartNew + (cMax - cStart)*8 + (c - cMax)*4 + GetTriSubface_Static(ornt[0], r);
3988:         supportNew[1] = cStartNew + (cMax - cStart)*8 + (c - cMax)*4 + 3;
3989:         DMPlexSetSupport(rdm, newp+r, supportNew);
3990: #if 1
3991:         if ((newp+r < fMaxNew) || (newp+r >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid face [%d, %d)", newp+r, fMaxNew, fEndNew);
3992:         for (p = 0; p < 2; ++p) {
3993:           if ((supportNew[p] < cMaxNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid cell [%d, %d)", supportNew[p], cMaxNew, cEndNew);
3994:         }
3995: #endif
3996:       }
3997:     }
3998:     /* Interior split edges have 2 vertices and the same faces as the parent */
3999:     for (e = eStart; e < eMax; ++e) {
4000:       const PetscInt newv = vStartNew + (vEnd - vStart) + (e - eStart);

4002:       for (r = 0; r < 2; ++r) {
4003:         const PetscInt  newp = eStartNew + (e - eStart)*2 + r;
4004:         const PetscInt *cone, *ornt, *support;
4005:         PetscInt        coneNew[2], coneSize, c, supportSize, s;

4007:         DMPlexGetCone(dm, e, &cone);
4008:         coneNew[0]       = vStartNew + (cone[0] - vStart);
4009:         coneNew[1]       = vStartNew + (cone[1] - vStart);
4010:         coneNew[(r+1)%2] = newv;
4011:         DMPlexSetCone(rdm, newp, coneNew);
4012: #if 1
4013:         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
4014:         for (p = 0; p < 2; ++p) {
4015:           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
4016:         }
4017: #endif
4018:         DMPlexGetSupportSize(dm, e, &supportSize);
4019:         DMPlexGetSupport(dm, e, &support);
4020:         for (s = 0; s < supportSize; ++s) {
4021:           DMPlexGetConeSize(dm, support[s], &coneSize);
4022:           DMPlexGetCone(dm, support[s], &cone);
4023:           DMPlexGetConeOrientation(dm, support[s], &ornt);
4024:           for (c = 0; c < coneSize; ++c) if (cone[c] == e) break;
4025:           if (support[s] < fMax) {
4026:             supportRef[s] = fStartNew + (support[s] - fStart)*4 + (c + (ornt[c] < 0 ? 1-r : r))%3;
4027:           } else {
4028:             supportRef[s] = fStartNew + (fMax       - fStart)*4 + (cMax - cStart)*8 + (support[s] - fMax)*2 + (ornt[c] < 0 ? 1-r : r);
4029:           }
4030:         }
4031:         DMPlexSetSupport(rdm, newp, supportRef);
4032: #if 1
4033:         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
4034:         for (p = 0; p < supportSize; ++p) {
4035:           if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an interior or hybrid face [%d, %d)", supportRef[p], fStartNew, fEndNew);
4036:         }
4037: #endif
4038:       }
4039:     }
4040:     /* Interior face edges have 2 vertices and 2+cells*(1/2) faces */
4041:     for (f = fStart; f < fMax; ++f) {
4042:       const PetscInt *cone, *ornt, *support;
4043:       PetscInt        coneSize, supportSize, s;

4045:       DMPlexGetSupportSize(dm, f, &supportSize);
4046:       DMPlexGetSupport(dm, f, &support);
4047:       for (r = 0; r < 3; ++r) {
4048:         const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (f - fStart)*3 + r;
4049:         PetscInt        coneNew[2], intFaces = 0, er, eint[4] = {1, 0, 2, 0};
4050:         PetscInt        fint[24] = { 1,  7, -1, -1,  0,  5,
4051:                                     -1, -1,  1,  6,  0,  4,
4052:                                      2,  5,  3,  4, -1, -1,
4053:                                     -1, -1,  3,  6,  2,  7};

4055:         DMPlexGetCone(dm, f, &cone);
4056:         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[(r+0)%3] - eStart);
4057:         coneNew[1] = vStartNew + (vEnd - vStart) + (cone[(r+1)%3] - eStart);
4058:         DMPlexSetCone(rdm, newp, coneNew);
4059: #if 1
4060:         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
4061:         for (p = 0; p < 2; ++p) {
4062:           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
4063:         }
4064: #endif
4065:         supportRef[0] = fStartNew + (f - fStart)*4 + (r+1)%3;
4066:         supportRef[1] = fStartNew + (f - fStart)*4 + 3;
4067:         for (s = 0; s < supportSize; ++s) {
4068:           DMPlexGetConeSize(dm, support[s], &coneSize);
4069:           DMPlexGetCone(dm, support[s], &cone);
4070:           DMPlexGetConeOrientation(dm, support[s], &ornt);
4071:           for (c = 0; c < coneSize; ++c) {if (cone[c] == f) break;}
4072:           if (support[s] < cMax) {
4073:             /* Here we want to determine whether edge newp contains a vertex which is part of the cross-tet edge */
4074:             er = GetTriMidEdgeInverse_Static(ornt[c], r);
4075:             if (er == eint[c]) {
4076:               supportRef[2+intFaces++] = fStartNew + (fMax - fStart)*4 + (support[s] - cStart)*8 + (c + 2)%4;
4077:             } else {
4078:               supportRef[2+intFaces++] = fStartNew + (fMax - fStart)*4 + (support[s] - cStart)*8 + fint[(c*3 + er)*2 + 0];
4079:               supportRef[2+intFaces++] = fStartNew + (fMax - fStart)*4 + (support[s] - cStart)*8 + fint[(c*3 + er)*2 + 1];
4080:             }
4081:           } else {
4082:             supportRef[2+intFaces++] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (support[s] - cMax)*3 + (r + 1)%3;
4083:           }
4084:         }
4085:         DMPlexSetSupport(rdm, newp, supportRef);
4086: #if 1
4087:         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
4088:         for (p = 0; p < intFaces; ++p) {
4089:           if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an interior or hybrid face [%d, %d)", supportRef[p], fStartNew, fEndNew);
4090:         }
4091: #endif
4092:       }
4093:     }
4094:     /* Interior cell edges have 2 vertices and 4 faces */
4095:     for (c = cStart; c < cMax; ++c) {
4096:       const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart);
4097:       const PetscInt *cone, *ornt, *fcone;
4098:       PetscInt        coneNew[2], supportNew[4], find;

4100:       DMPlexGetCone(dm, c, &cone);
4101:       DMPlexGetConeOrientation(dm, c, &ornt);
4102:       DMPlexGetCone(dm, cone[0], &fcone);
4103:       find = GetTriEdge_Static(ornt[0], 0);
4104:       coneNew[0] = vStartNew + (vEnd - vStart) + (fcone[find] - eStart);
4105:       DMPlexGetCone(dm, cone[2], &fcone);
4106:       find = GetTriEdge_Static(ornt[2], 1);
4107:       coneNew[1] = vStartNew + (vEnd - vStart) + (fcone[find] - eStart);
4108:       DMPlexSetCone(rdm, newp, coneNew);
4109: #if 1
4110:       if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
4111:       for (p = 0; p < 2; ++p) {
4112:         if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
4113:       }
4114: #endif
4115:       supportNew[0] = fStartNew + (fMax - fStart)*4 + (c - cStart)*8 + 4;
4116:       supportNew[1] = fStartNew + (fMax - fStart)*4 + (c - cStart)*8 + 5;
4117:       supportNew[2] = fStartNew + (fMax - fStart)*4 + (c - cStart)*8 + 6;
4118:       supportNew[3] = fStartNew + (fMax - fStart)*4 + (c - cStart)*8 + 7;
4119:       DMPlexSetSupport(rdm, newp, supportNew);
4120: #if 1
4121:       if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
4122:       for (p = 0; p < 4; ++p) {
4123:         if ((supportNew[p] < fStartNew) || (supportNew[p] >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", supportNew[p], fStartNew, fMaxNew);
4124:       }
4125: #endif
4126:     }
4127:     /* Hybrid edges have two vertices and the same faces */
4128:     for (e = eMax; e < eEnd; ++e) {
4129:       const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (e - eMax);
4130:       const PetscInt *cone, *support, *fcone;
4131:       PetscInt        coneNew[2], size, fsize, s;

4133:       DMPlexGetCone(dm, e, &cone);
4134:       DMPlexGetSupportSize(dm, e, &size);
4135:       DMPlexGetSupport(dm, e, &support);
4136:       coneNew[0] = vStartNew + (cone[0] - vStart);
4137:       coneNew[1] = vStartNew + (cone[1] - vStart);
4138:       DMPlexSetCone(rdm, newp, coneNew);
4139: #if 1
4140:       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid edge [%d, %d)", newp, eMaxNew, eEndNew);
4141:       for (p = 0; p < 2; ++p) {
4142:         if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
4143:       }
4144: #endif
4145:       for (s = 0; s < size; ++s) {
4146:         DMPlexGetConeSize(dm, support[s], &fsize);
4147:         DMPlexGetCone(dm, support[s], &fcone);
4148:         for (c = 0; c < fsize; ++c) if (fcone[c] == e) break;
4149:         if ((c < 2) || (c > 3)) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Edge %d not found in cone of face %d", e, support[s]);
4150:         supportRef[s] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (support[s] - fMax)*2 + c-2;
4151:       }
4152:       DMPlexSetSupport(rdm, newp, supportRef);
4153: #if 1
4154:       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid edge [%d, %d)", newp, eMaxNew, eEndNew);
4155:       for (p = 0; p < size; ++p) {
4156:         if ((supportRef[p] < fMaxNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid face [%d, %d)", supportRef[p], fMaxNew, fEndNew);
4157:       }
4158: #endif
4159:     }
4160:     /* Hybrid face edges have 2 vertices and 2+2*cells faces */
4161:     for (f = fMax; f < fEnd; ++f) {
4162:       const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (eEnd - eMax) + (f - fMax);
4163:       const PetscInt *cone, *support, *ccone, *cornt;
4164:       PetscInt        coneNew[2], size, csize, s;

4166:       DMPlexGetCone(dm, f, &cone);
4167:       DMPlexGetSupportSize(dm, f, &size);
4168:       DMPlexGetSupport(dm, f, &support);
4169:       coneNew[0] = vStartNew + (vEnd - vStart) + (cone[0] - eStart);
4170:       coneNew[1] = vStartNew + (vEnd - vStart) + (cone[1] - eStart);
4171:       DMPlexSetCone(rdm, newp, coneNew);
4172: #if 1
4173:       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid edge [%d, %d)", newp, eMaxNew, eEndNew);
4174:       for (p = 0; p < 2; ++p) {
4175:         if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
4176:       }
4177: #endif
4178:       supportRef[0] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (f - fMax)*2 + 0;
4179:       supportRef[1] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (f - fMax)*2 + 1;
4180:       for (s = 0; s < size; ++s) {
4181:         DMPlexGetConeSize(dm, support[s], &csize);
4182:         DMPlexGetCone(dm, support[s], &ccone);
4183:         DMPlexGetConeOrientation(dm, support[s], &cornt);
4184:         for (c = 0; c < csize; ++c) if (ccone[c] == f) break;
4185:         if ((c < 2) || (c >= csize)) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Hybrid face %d is not in cone of hybrid cell %d", f, support[s]);
4186:         supportRef[2+s*2+0] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (support[s] - cMax)*3 + c-2;
4187:         supportRef[2+s*2+1] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (support[s] - cMax)*3 + (c-1)%3;
4188:       }
4189:       DMPlexSetSupport(rdm, newp, supportRef);
4190: #if 1
4191:       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid edge [%d, %d)", newp, eMaxNew, eEndNew);
4192:       for (p = 0; p < 2+size*2; ++p) {
4193:         if ((supportRef[p] < fMaxNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid face [%d, %d)", supportRef[p], fMaxNew, fEndNew);
4194:       }
4195: #endif
4196:     }
4197:     /* Interior vertices have identical supports */
4198:     for (v = vStart; v < vEnd; ++v) {
4199:       const PetscInt  newp = vStartNew + (v - vStart);
4200:       const PetscInt *support, *cone;
4201:       PetscInt        size, s;

4203:       DMPlexGetSupportSize(dm, v, &size);
4204:       DMPlexGetSupport(dm, v, &support);
4205:       for (s = 0; s < size; ++s) {
4206:         PetscInt r = 0;

4208:         DMPlexGetCone(dm, support[s], &cone);
4209:         if (cone[1] == v) r = 1;
4210:         if (support[s] < eMax) supportRef[s] = eStartNew + (support[s] - eStart)*2 + r;
4211:         else                   supportRef[s] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (support[s] - eMax);
4212:       }
4213:       DMPlexSetSupport(rdm, newp, supportRef);
4214: #if 1
4215:       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
4216:       for (p = 0; p < size; ++p) {
4217:         if ((supportRef[p] < eStartNew) || (supportRef[p] >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an interior or hybrid edge [%d, %d)", supportRef[p], eStartNew, eEndNew);
4218:       }
4219: #endif
4220:     }
4221:     /* Interior edge vertices have 2 + interior face*2 + hybrid face + cells*0/1 supports */
4222:     for (e = eStart; e < eMax; ++e) {
4223:       const PetscInt  newp = vStartNew + (vEnd - vStart) + (e - eStart);
4224:       const PetscInt *cone, *support;
4225:       PetscInt       *star = NULL, starSize, faceSize = 0, cellSize = 0, coneSize, size, s;

4227:       DMPlexGetSupportSize(dm, e, &size);
4228:       DMPlexGetSupport(dm, e, &support);
4229:       supportRef[0] = eStartNew + (e - eStart)*2 + 0;
4230:       supportRef[1] = eStartNew + (e - eStart)*2 + 1;
4231:       for (s = 0; s < size; ++s) {
4232:         PetscInt r = 0;

4234:         if (support[s] < fMax) {
4235:           DMPlexGetConeSize(dm, support[s], &coneSize);
4236:           DMPlexGetCone(dm, support[s], &cone);
4237:           for (r = 0; r < coneSize; ++r) {if (cone[r] == e) break;}
4238:           supportRef[2+faceSize+0] = eStartNew + (eMax - eStart)*2 + (support[s] - fStart)*3 + (r+0)%3;
4239:           supportRef[2+faceSize+1] = eStartNew + (eMax - eStart)*2 + (support[s] - fStart)*3 + (r+2)%3;
4240:           faceSize += 2;
4241:         } else {
4242:           supportRef[2+faceSize+0] = eStartNew + (eMax - eStart)*2 + (fMax       - fStart)*3 + (cMax - cStart) + (eEnd - eMax) + (support[s] - fMax);
4243:           ++faceSize;
4244:         }
4245:       }
4246:       DMPlexGetTransitiveClosure(dm, e, PETSC_FALSE, &starSize, &star);
4247:       for (s = 0; s < starSize*2; s += 2) {
4248:         const PetscInt *cone, *ornt;
4249:         PetscInt        e01, e23;

4251:         if ((star[s] >= cStart) && (star[s] < cMax)) {
4252:           /* Check edge 0-1 */
4253:           DMPlexGetCone(dm, star[s], &cone);
4254:           DMPlexGetConeOrientation(dm, star[s], &ornt);
4255:           DMPlexGetCone(dm, cone[0], &cone);
4256:           e01  = cone[GetTriEdge_Static(ornt[0], 0)];
4257:           /* Check edge 2-3 */
4258:           DMPlexGetCone(dm, star[s], &cone);
4259:           DMPlexGetConeOrientation(dm, star[s], &ornt);
4260:           DMPlexGetCone(dm, cone[2], &cone);
4261:           e23  = cone[GetTriEdge_Static(ornt[2], 1)];
4262:           if ((e01 == e) || (e23 == e)) {supportRef[2+faceSize+cellSize++] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (star[s] - cStart);}
4263:         }
4264:       }
4265:       DMPlexRestoreTransitiveClosure(dm, e, PETSC_FALSE, &starSize, &star);
4266:       DMPlexSetSupport(rdm, newp, supportRef);
4267: #if 1
4268:       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
4269:       for (p = 0; p < 2+faceSize+cellSize; ++p) {
4270:         if ((supportRef[p] < eStartNew) || (supportRef[p] >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an interior or hybrid edge [%d, %d)", supportRef[p], eStartNew, eEndNew);
4271:       }
4272: #endif
4273:     }
4274:     PetscFree(supportRef);
4275:     DMPlexRestoreFaces_Internal(dm, 3, cStart, NULL, NULL, &faces);
4276:     break;
4277:   case REFINER_SIMPLEX_TO_HEX_3D:
4278:     DMPlexGetRawFaces_Internal(dm, 3, 4, cellInd, NULL, NULL, &faces);
4279:     /* All cells have 6 faces */
4280:     for (c = cStart; c < cEnd; ++c) {
4281:       const PetscInt  newp = cStartNew + (c - cStart)*4;
4282:       const PetscInt *cone, *ornt;
4283:       PetscInt        coneNew[6];
4284:       PetscInt        orntNew[6];

4286:       DMPlexGetCone(dm, c, &cone);
4287:       DMPlexGetConeOrientation(dm, c, &ornt);
4288:       /* A hex */
4289:       coneNew[0] = fStartNew + (cone[0] - fStart)*3 + GetTriSubface_Static(ornt[0], 0); /* B */
4290:       orntNew[0] = ornt[0] < 0 ? -1 : 1;
4291:       coneNew[1] = fStartNew + (fEnd    - fStart)*3 + (c - cStart)*6 + 3;               /* T */
4292:       orntNew[1] = -4;
4293:       coneNew[2] = fStartNew + (cone[2] - fStart)*3 + GetTriSubface_Static(ornt[2], 0); /* F */
4294:       orntNew[2] = ornt[2] < 0 ? -1 : 1;
4295:       coneNew[3] = fStartNew + (fEnd    - fStart)*3 + (c - cStart)*6 + 0;               /* K */
4296:       orntNew[3] = -1;
4297:       coneNew[4] = fStartNew + (fEnd    - fStart)*3 + (c - cStart)*6 + 2;               /* R */
4298:       orntNew[4] = 0;
4299:       coneNew[5] = fStartNew + (cone[1] - fStart)*3 + GetTriSubface_Static(ornt[1], 0); /* L */
4300:       orntNew[5] = ornt[1] < 0 ? -1 : 1;
4301:       DMPlexSetCone(rdm, newp+0, coneNew);
4302:       DMPlexSetConeOrientation(rdm, newp+0, orntNew);
4303: #if 1
4304:       if ((newp+0 < cStartNew) || (newp+0 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+0, cStartNew, cEndNew);
4305:       for (p = 0; p < 6; ++p) {
4306:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
4307:       }
4308: #endif
4309:       /* B hex */
4310:       coneNew[0] = fStartNew + (cone[0] - fStart)*3 + GetTriSubface_Static(ornt[0], 1); /* B */
4311:       orntNew[0] = ornt[0] < 0 ? -2 : 0;
4312:       coneNew[1] = fStartNew + (fEnd    - fStart)*3 + (c - cStart)*6 + 4;               /* T */
4313:       orntNew[1] = 0;
4314:       coneNew[2] = fStartNew + (fEnd    - fStart)*3 + (c - cStart)*6 + 0;               /* F */
4315:       orntNew[2] = 0;
4316:       coneNew[3] = fStartNew + (cone[3] - fStart)*3 + GetTriSubface_Static(ornt[3], 1); /* K */
4317:       orntNew[3] = ornt[3] < 0 ? -2 : 0;
4318:       coneNew[4] = fStartNew + (fEnd    - fStart)*3 + (c - cStart)*6 + 1;               /* R */
4319:       orntNew[4] = 0;
4320:       coneNew[5] = fStartNew + (cone[1] - fStart)*3 + GetTriSubface_Static(ornt[1], 2); /* L */
4321:       orntNew[5] = ornt[1] < 0 ? -4 : 2;
4322:       DMPlexSetCone(rdm, newp+1, coneNew);
4323:       DMPlexSetConeOrientation(rdm, newp+1, orntNew);
4324: #if 1
4325:       if ((newp+1 < cStartNew) || (newp+1 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+1, cStartNew, cEndNew);
4326:       for (p = 0; p < 6; ++p) {
4327:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
4328:       }
4329: #endif
4330:       /* C hex */
4331:       coneNew[0] = fStartNew + (cone[0] - fStart)*3 + GetTriSubface_Static(ornt[0], 2); /* B */
4332:       orntNew[0] = ornt[0] < 0 ? -4 : 2;
4333:       coneNew[1] = fStartNew + (fEnd    - fStart)*3 + (c - cStart)*6 + 5;               /* T */
4334:       orntNew[1] = -4;
4335:       coneNew[2] = fStartNew + (cone[2] - fStart)*3 + GetTriSubface_Static(ornt[2], 1); /* F */
4336:       orntNew[2] = ornt[2] < 0 ? -2 : 0;
4337:       coneNew[3] = fStartNew + (fEnd    - fStart)*3 + (c - cStart)*6 + 1;               /* K */
4338:       orntNew[3] = -1;
4339:       coneNew[4] = fStartNew + (cone[3] - fStart)*3 + GetTriSubface_Static(ornt[3], 0); /* R */
4340:       orntNew[4] = ornt[3] < 0 ? -1 : 1;
4341:       coneNew[5] = fStartNew + (fEnd    - fStart)*3 + (c - cStart)*6 + 2;               /* L */
4342:       orntNew[5] = -4;
4343:       DMPlexSetCone(rdm, newp+2, coneNew);
4344:       DMPlexSetConeOrientation(rdm, newp+2, orntNew);
4345: #if 1
4346:       if ((newp+2 < cStartNew) || (newp+2 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+2, cStartNew, cEndNew);
4347:       for (p = 0; p < 6; ++p) {
4348:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
4349:       }
4350: #endif
4351:       /* D hex */
4352:       coneNew[0] = fStartNew + (fEnd    - fStart)*3 + (c - cStart)*6 + 3;               /* B */
4353:       orntNew[0] = 0;
4354:       coneNew[1] = fStartNew + (cone[3] - fStart)*3 + GetTriSubface_Static(ornt[3], 2); /* T */
4355:       orntNew[1] = ornt[3] < 0 ? -1 : 1;
4356:       coneNew[2] = fStartNew + (cone[2] - fStart)*3 + GetTriSubface_Static(ornt[2], 2); /* F */
4357:       orntNew[2] = ornt[2] < 0 ? -4 : 2;
4358:       coneNew[3] = fStartNew + (fEnd    - fStart)*3 + (c - cStart)*6 + 4;               /* K */
4359:       orntNew[3] = -1;
4360:       coneNew[4] = fStartNew + (fEnd    - fStart)*3 + (c - cStart)*6 + 5;               /* R */
4361:       orntNew[4] = 0;
4362:       coneNew[5] = fStartNew + (cone[1] - fStart)*3 + GetTriSubface_Static(ornt[1], 1); /* L */
4363:       orntNew[5] = ornt[1] < 0 ? -2 : 0;
4364:       DMPlexSetCone(rdm, newp+3, coneNew);
4365:       DMPlexSetConeOrientation(rdm, newp+3, orntNew);
4366: #if 1
4367:       if ((newp+3 < cStartNew) || (newp+3 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+3, cStartNew, cEndNew);
4368:       for (p = 0; p < 6; ++p) {
4369:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
4370:       }
4371: #endif
4372:     }
4373:     /* Split faces have 4 edges and the same cells as the parent */
4374:     DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);
4375:     PetscMalloc1(2 + maxSupportSize*2, &supportRef);
4376:     for (f = fStart; f < fEnd; ++f) {
4377:       const PetscInt  newp = fStartNew + (f - fStart)*3;
4378:       const PetscInt *cone, *ornt, *support;
4379:       PetscInt        coneNew[4], orntNew[4], coneSize, supportSize, s;

4381:       DMPlexGetCone(dm, f, &cone);
4382:       DMPlexGetConeOrientation(dm, f, &ornt);
4383:       /* A quad */
4384:       coneNew[0] = eStartNew + (cone[2] - eStart)*2 + (ornt[2] < 0 ? 0 : 1);
4385:       orntNew[0] = ornt[2];
4386:       coneNew[1] = eStartNew + (cone[0] - eStart)*2 + (ornt[0] < 0 ? 1 : 0);
4387:       orntNew[1] = ornt[0];
4388:       coneNew[2] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 0;
4389:       orntNew[2] = 0;
4390:       coneNew[3] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 2;
4391:       orntNew[3] = -2;
4392:       DMPlexSetCone(rdm, newp+0, coneNew);
4393:       DMPlexSetConeOrientation(rdm, newp+0, orntNew);
4394: #if 1
4395:       if ((newp+0 < fStartNew) || (newp+0 >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp+0, fStartNew, fEndNew);
4396:       for (p = 0; p < 4; ++p) {
4397:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eEndNew);
4398:       }
4399: #endif
4400:       /* B quad */
4401:       coneNew[0] = eStartNew + (cone[0] - eStart)*2 + (ornt[0] < 0 ? 0 : 1);
4402:       orntNew[0] = ornt[0];
4403:       coneNew[1] = eStartNew + (cone[1] - eStart)*2 + (ornt[1] < 0 ? 1 : 0);
4404:       orntNew[1] = ornt[1];
4405:       coneNew[2] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 1;
4406:       orntNew[2] = 0;
4407:       coneNew[3] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 0;
4408:       orntNew[3] = -2;
4409:       DMPlexSetCone(rdm, newp+1, coneNew);
4410:       DMPlexSetConeOrientation(rdm, newp+1, orntNew);
4411: #if 1
4412:       if ((newp+1 < fStartNew) || (newp+1 >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp+1, fStartNew, fEndNew);
4413:       for (p = 0; p < 4; ++p) {
4414:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eEndNew);
4415:       }
4416: #endif
4417:       /* C quad */
4418:       coneNew[0] = eStartNew + (cone[1] - eStart)*2 + (ornt[1] < 0 ? 0 : 1);
4419:       orntNew[0] = ornt[1];
4420:       coneNew[1] = eStartNew + (cone[2] - eStart)*2 + (ornt[2] < 0 ? 1 : 0);
4421:       orntNew[1] = ornt[2];
4422:       coneNew[2] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 2;
4423:       orntNew[2] = 0;
4424:       coneNew[3] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 1;
4425:       orntNew[3] = -2;
4426:       DMPlexSetCone(rdm, newp+2, coneNew);
4427:       DMPlexSetConeOrientation(rdm, newp+2, orntNew);
4428: #if 1
4429:       if ((newp+2 < fStartNew) || (newp+2 >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp+2, fStartNew, fEndNew);
4430:       for (p = 0; p < 4; ++p) {
4431:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eEndNew);
4432:       }
4433: #endif
4434:       DMPlexGetSupportSize(dm, f, &supportSize);
4435:       DMPlexGetSupport(dm, f, &support);
4436:       for (r = 0; r < 3; ++r) {
4437:         for (s = 0; s < supportSize; ++s) {
4438:           PetscInt subf;
4439:           DMPlexGetConeSize(dm, support[s], &coneSize);
4440:           DMPlexGetCone(dm, support[s], &cone);
4441:           DMPlexGetConeOrientation(dm, support[s], &ornt);
4442:           for (c = 0; c < coneSize; ++c) {
4443:             if (cone[c] == f) break;
4444:           }
4445:           subf = GetTriSubfaceInverse_Static(ornt[c], r);
4446:           supportRef[s] = cStartNew + (support[s] - cStart)*4 + faces[c*3+subf];
4447:         }
4448:         DMPlexSetSupport(rdm, newp+r, supportRef);
4449: #if 1
4450:         if ((newp+r < fStartNew) || (newp+r >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp+r, fStartNew, fEndNew);
4451:         for (p = 0; p < supportSize; ++p) {
4452:           if ((supportRef[p] < cStartNew) || (supportRef[p] >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportRef[p], cStartNew, cEndNew);
4453:         }
4454: #endif
4455:       }
4456:     }
4457:     /* Interior faces have 4 edges and 2 cells */
4458:     for (c = cStart; c < cEnd; ++c) {
4459:       PetscInt        newp = fStartNew + (fEnd - fStart)*3 + (c - cStart)*6;
4460:       const PetscInt *cone, *ornt;
4461:       PetscInt        coneNew[4], orntNew[4];
4462:       PetscInt        supportNew[2];

4464:       DMPlexGetCone(dm, c, &cone);
4465:       DMPlexGetConeOrientation(dm, c, &ornt);
4466:       /* Face {a, g, m, h} */
4467:       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*3 + GetTriInteriorEdge_Static(ornt[0],0);
4468:       orntNew[0] = 0;
4469:       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + 0;
4470:       orntNew[1] = 0;
4471:       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + 1;
4472:       orntNew[2] = -2;
4473:       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*3 + GetTriInteriorEdge_Static(ornt[1],2);
4474:       orntNew[3] = -2;
4475:       DMPlexSetCone(rdm, newp, coneNew);
4476:       DMPlexSetConeOrientation(rdm, newp, orntNew);
4477: #if 1
4478:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4479:       for (p = 0; p < 4; ++p) {
4480:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eEndNew);
4481:       }
4482: #endif
4483:       supportNew[0] = (c - cStart)*4 + 0;
4484:       supportNew[1] = (c - cStart)*4 + 1;
4485:       DMPlexSetSupport(rdm, newp, supportNew);
4486: #if 1
4487:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4488:       for (p = 0; p < 2; ++p) {
4489:         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cEndNew);
4490:       }
4491: #endif
4492:       ++newp;
4493:       /* Face {g, b, l , m} */
4494:       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*3 + GetTriInteriorEdge_Static(ornt[0],1);
4495:       orntNew[0] = -2;
4496:       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*3 + GetTriInteriorEdge_Static(ornt[3],0);
4497:       orntNew[1] = 0;
4498:       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + 3;
4499:       orntNew[2] = 0;
4500:       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + 0;
4501:       orntNew[3] = -2;
4502:       DMPlexSetCone(rdm, newp, coneNew);
4503:       DMPlexSetConeOrientation(rdm, newp, orntNew);
4504: #if 1
4505:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4506:       for (p = 0; p < 4; ++p) {
4507:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eEndNew);
4508:       }
4509: #endif
4510:       supportNew[0] = (c - cStart)*4 + 1;
4511:       supportNew[1] = (c - cStart)*4 + 2;
4512:       DMPlexSetSupport(rdm, newp, supportNew);
4513: #if 1
4514:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4515:       for (p = 0; p < 2; ++p) {
4516:         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cEndNew);
4517:       }
4518: #endif
4519:       ++newp;
4520:       /* Face {c, g, m, i} */
4521:       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*3 + GetTriInteriorEdge_Static(ornt[0],2);
4522:       orntNew[0] = 0;
4523:       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + 0;
4524:       orntNew[1] = 0;
4525:       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + 2;
4526:       orntNew[2] = -2;
4527:       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*3 + GetTriInteriorEdge_Static(ornt[2],0);
4528:       orntNew[3] = -2;
4529:       DMPlexSetCone(rdm, newp, coneNew);
4530:       DMPlexSetConeOrientation(rdm, newp, orntNew);
4531: #if 1
4532:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4533:       for (p = 0; p < 4; ++p) {
4534:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eEndNew);
4535:       }
4536: #endif
4537:       supportNew[0] = (c - cStart)*4 + 0;
4538:       supportNew[1] = (c - cStart)*4 + 2;
4539:       DMPlexSetSupport(rdm, newp, supportNew);
4540: #if 1
4541:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4542:       for (p = 0; p < 2; ++p) {
4543:         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cEndNew);
4544:       }
4545: #endif
4546:       ++newp;
4547:       /* Face {d, h, m, i} */
4548:       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*3 + GetTriInteriorEdge_Static(ornt[1],0);
4549:       orntNew[0] = 0;
4550:       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + 1;
4551:       orntNew[1] = 0;
4552:       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + 2;
4553:       orntNew[2] = -2;
4554:       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*3 + GetTriInteriorEdge_Static(ornt[2],2);
4555:       orntNew[3] = -2;
4556:       DMPlexSetCone(rdm, newp, coneNew);
4557:       DMPlexSetConeOrientation(rdm, newp, orntNew);
4558: #if 1
4559:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4560:       for (p = 0; p < 4; ++p) {
4561:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eEndNew);
4562:       }
4563: #endif
4564:       supportNew[0] = (c - cStart)*4 + 0;
4565:       supportNew[1] = (c - cStart)*4 + 3;
4566:       DMPlexSetSupport(rdm, newp, supportNew);
4567: #if 1
4568:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4569:       for (p = 0; p < 2; ++p) {
4570:         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cEndNew);
4571:       }
4572: #endif
4573:       ++newp;
4574:       /* Face {h, m, l, e} */
4575:       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + 1;
4576:       orntNew[0] = 0;
4577:       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + 3;
4578:       orntNew[1] = -2;
4579:       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*3 + GetTriInteriorEdge_Static(ornt[3],1);
4580:       orntNew[2] = -2;
4581:       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*3 + GetTriInteriorEdge_Static(ornt[1],1);
4582:       orntNew[3] = 0;
4583:       DMPlexSetCone(rdm, newp, coneNew);
4584:       DMPlexSetConeOrientation(rdm, newp, orntNew);
4585: #if 1
4586:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4587:       for (p = 0; p < 4; ++p) {
4588:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eEndNew);
4589:       }
4590: #endif
4591:       supportNew[0] = (c - cStart)*4 + 1;
4592:       supportNew[1] = (c - cStart)*4 + 3;
4593:       DMPlexSetSupport(rdm, newp, supportNew);
4594: #if 1
4595:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4596:       for (p = 0; p < 2; ++p) {
4597:         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cEndNew);
4598:       }
4599: #endif
4600:       ++newp;
4601:       /* Face {i, m, l, f} */
4602:       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + 2;
4603:       orntNew[0] = 0;
4604:       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + 3;
4605:       orntNew[1] = -2;
4606:       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*3 + GetTriInteriorEdge_Static(ornt[3],2);
4607:       orntNew[2] = -2;
4608:       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*3 + GetTriInteriorEdge_Static(ornt[2],1);
4609:       orntNew[3] = 0;
4610:       DMPlexSetCone(rdm, newp, coneNew);
4611:       DMPlexSetConeOrientation(rdm, newp, orntNew);
4612: #if 1
4613:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4614:       for (p = 0; p < 4; ++p) {
4615:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eEndNew);
4616:       }
4617: #endif
4618:       supportNew[0] = (c - cStart)*4 + 2;
4619:       supportNew[1] = (c - cStart)*4 + 3;
4620:       DMPlexSetSupport(rdm, newp, supportNew);
4621: #if 1
4622:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4623:       for (p = 0; p < 2; ++p) {
4624:         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cEndNew);
4625:       }
4626: #endif
4627:       ++newp;
4628:     }
4629:     /* Split Edges have 2 vertices and the same faces as the parent */
4630:     for (e = eStart; e < eEnd; ++e) {
4631:       const PetscInt newv = vStartNew + (vEnd - vStart) + (e - eStart);

4633:       for (r = 0; r < 2; ++r) {
4634:         const PetscInt  newp = eStartNew + (e - eStart)*2 + r;
4635:         const PetscInt *cone, *ornt, *support;
4636:         PetscInt        coneNew[2], coneSize, c, supportSize, s;

4638:         DMPlexGetCone(dm, e, &cone);
4639:         coneNew[0]       = vStartNew + (cone[0] - vStart);
4640:         coneNew[1]       = vStartNew + (cone[1] - vStart);
4641:         coneNew[(r+1)%2] = newv;
4642:         DMPlexSetCone(rdm, newp, coneNew);
4643: #if 1
4644:         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
4645:         for (p = 0; p < 2; ++p) {
4646:           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
4647:         }
4648: #endif
4649:         DMPlexGetSupportSize(dm, e, &supportSize);
4650:         DMPlexGetSupport(dm, e, &support);
4651:         for (s = 0; s < supportSize; ++s) {
4652:           DMPlexGetConeSize(dm, support[s], &coneSize);
4653:           DMPlexGetCone(dm, support[s], &cone);
4654:           DMPlexGetConeOrientation(dm, support[s], &ornt);
4655:           for (c = 0; c < coneSize; ++c) {
4656:             if (cone[c] == e) break;
4657:           }
4658:           supportRef[s] = fStartNew + (support[s] - fStart)*3 + (c + (ornt[c] < 0 ? 1-r : r))%3;
4659:         }
4660:         DMPlexSetSupport(rdm, newp, supportRef);
4661: #if 1
4662:         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
4663:         for (p = 0; p < supportSize; ++p) {
4664:           if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", supportRef[p], fStartNew, fEndNew);
4665:         }
4666: #endif
4667:       }
4668:     }
4669:     /* Face edges have 2 vertices and 2 + cell faces supports */
4670:     for (f = fStart; f < fEnd; ++f) {
4671:       const PetscInt *cone, *ornt, *support;
4672:       PetscInt        coneSize, supportSize, s;

4674:       DMPlexGetSupportSize(dm, f, &supportSize);
4675:       DMPlexGetSupport(dm, f, &support);
4676:       for (r = 0; r < 3; ++r) {
4677:         const PetscInt  newp = eStartNew + (eEnd - eStart)*2 + (f - fStart)*3 + r;
4678:         PetscInt        coneNew[2];
4679:         PetscInt        fint[4][3] = { {0, 1, 2},
4680:                                        {3, 4, 0},
4681:                                        {2, 5, 3},
4682:                                        {1, 4, 5} };

4684:         DMPlexGetCone(dm, f, &cone);
4685:         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r] - eStart);
4686:         coneNew[1] = vStartNew + (vEnd - vStart) + (eEnd - eStart) + f - fStart;
4687:         DMPlexSetCone(rdm, newp, coneNew);
4688: #if 1
4689:         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
4690:         for (p = 0; p < 2; ++p) {
4691:           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
4692:         }
4693: #endif
4694:         supportRef[0] = fStartNew + (f - fStart)*3 + (r+0)%3;
4695:         supportRef[1] = fStartNew + (f - fStart)*3 + (r+1)%3;
4696:         for (s = 0; s < supportSize; ++s) {
4697:           PetscInt er;
4698:           DMPlexGetConeSize(dm, support[s], &coneSize);
4699:           DMPlexGetCone(dm, support[s], &cone);
4700:           DMPlexGetConeOrientation(dm, support[s], &ornt);
4701:           for (c = 0; c < coneSize; ++c) {if (cone[c] == f) break;}
4702:           er = GetTriInteriorEdgeInverse_Static(ornt[c], r);
4703:           supportRef[2+s] = fStartNew + (fEnd - fStart)*3 + (support[s] - cStart)*6 + fint[c][er];
4704:         }
4705:         DMPlexSetSupport(rdm, newp, supportRef);
4706: #if 1
4707:         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
4708:         for (p = 0; p < supportSize + 2; ++p) {
4709:           if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", supportRef[p], fStartNew, fEndNew);
4710:         }
4711: #endif
4712:       }
4713:     }
4714:     /* Interior cell edges have 2 vertices and 3 faces */
4715:     for (c = cStart; c < cEnd; ++c) {
4716:       const PetscInt *cone;
4717:       PetscInt       fint[4][3] = { {0,1,2},
4718:                                     {0,3,4},
4719:                                     {2,3,5},
4720:                                     {1,4,5} } ;

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

4727:         coneNew[0] = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (cone[r] - fStart);
4728:         coneNew[1] = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (fEnd -fStart) + c - cStart;
4729:         DMPlexSetCone(rdm, newp, coneNew);
4730: #if 1
4731:         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
4732:         for (p = 0; p < 2; ++p) {
4733:           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
4734:         }
4735: #endif
4736:         supportNew[0] = fStartNew + (fEnd - fStart)*3 + (c - cStart)*6 + fint[r][0];
4737:         supportNew[1] = fStartNew + (fEnd - fStart)*3 + (c - cStart)*6 + fint[r][1];
4738:         supportNew[2] = fStartNew + (fEnd - fStart)*3 + (c - cStart)*6 + fint[r][2];
4739:         DMPlexSetSupport(rdm, newp, supportNew);
4740: #if 1
4741:         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
4742:         for (p = 0; p < 3; ++p) {
4743:           if ((supportNew[p] < fStartNew) || (supportNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", supportNew[p], fStartNew, fEndNew);
4744:         }
4745: #endif
4746:       }
4747:     }
4748:     /* Old vertices have identical supports */
4749:     for (v = vStart; v < vEnd; ++v) {
4750:       const PetscInt  newp = vStartNew + (v - vStart);
4751:       const PetscInt *support, *cone;
4752:       PetscInt        size, s;

4754:       DMPlexGetSupportSize(dm, v, &size);
4755:       DMPlexGetSupport(dm, v, &support);
4756:       for (s = 0; s < size; ++s) {
4757:         PetscInt r = 0;

4759:         DMPlexGetCone(dm, support[s], &cone);
4760:         if (cone[1] == v) r = 1;
4761:         supportRef[s] = eStartNew + (support[s] - eStart)*2 + r;
4762:       }
4763:       DMPlexSetSupport(rdm, newp, supportRef);
4764: #if 1
4765:       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
4766:       for (p = 0; p < size; ++p) {
4767:         if ((supportRef[p] < eStartNew) || (supportRef[p] >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", supportRef[p], eStartNew, eEndNew);
4768:       }
4769: #endif
4770:     }
4771:     /* Edge vertices have 2 + faces supports */
4772:     for (e = eStart; e < eEnd; ++e) {
4773:       const PetscInt  newp = vStartNew + (vEnd - vStart) + (e - eStart);
4774:       const PetscInt *cone, *support;
4775:       PetscInt        size, s;

4777:       DMPlexGetSupportSize(dm, e, &size);
4778:       DMPlexGetSupport(dm, e, &support);
4779:       supportRef[0] = eStartNew + (e - eStart)*2 + 0;
4780:       supportRef[1] = eStartNew + (e - eStart)*2 + 1;
4781:       for (s = 0; s < size; ++s) {
4782:         PetscInt r = 0, coneSize;

4784:         DMPlexGetConeSize(dm, support[s], &coneSize);
4785:         DMPlexGetCone(dm, support[s], &cone);
4786:         for (r = 0; r < coneSize; ++r) {if (cone[r] == e) break;}
4787:         supportRef[2+s] = eStartNew + (eEnd - eStart)*2 + (support[s] - fStart)*3 + r;
4788:       }
4789:       DMPlexSetSupport(rdm, newp, supportRef);
4790: #if 1
4791:       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
4792:       for (p = 0; p < 2+size; ++p) {
4793:         if ((supportRef[p] < eStartNew) || (supportRef[p] >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", supportRef[p], eStartNew, eEndNew);
4794:       }
4795: #endif
4796:     }
4797:     /* Face vertices have 3 + cells supports */
4798:     for (f = fStart; f < fEnd; ++f) {
4799:       const PetscInt  newp = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (f - fStart);
4800:       const PetscInt *cone, *support;
4801:       PetscInt        size, s;

4803:       DMPlexGetSupportSize(dm, f, &size);
4804:       DMPlexGetSupport(dm, f, &support);
4805:       supportRef[0] = eStartNew + (eEnd - eStart)*2 + (f - fStart)*3 + 0;
4806:       supportRef[1] = eStartNew + (eEnd - eStart)*2 + (f - fStart)*3 + 1;
4807:       supportRef[2] = eStartNew + (eEnd - eStart)*2 + (f - fStart)*3 + 2;
4808:       for (s = 0; s < size; ++s) {
4809:         PetscInt r = 0, coneSize;

4811:         DMPlexGetConeSize(dm, support[s], &coneSize);
4812:         DMPlexGetCone(dm, support[s], &cone);
4813:         for (r = 0; r < coneSize; ++r) {if (cone[r] == f) break;}
4814:         supportRef[3+s] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (support[s] - cStart)*4 + r;
4815:       }
4816:       DMPlexSetSupport(rdm, newp, supportRef);
4817: #if 1
4818:       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
4819:       for (p = 0; p < 3+size; ++p) {
4820:         if ((supportRef[p] < eStartNew) || (supportRef[p] >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", supportRef[p], eStartNew, eEndNew);
4821:       }
4822: #endif
4823:     }
4824:     /* Interior cell vertices have 4 supports */
4825:     for (c = cStart; c < cEnd; ++c) {
4826:       const PetscInt  newp = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (fEnd - fStart) + c - cStart;
4827:       supportRef[0] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + 0;
4828:       supportRef[1] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + 1;
4829:       supportRef[2] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + 2;
4830:       supportRef[3] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + 3;
4831:       DMPlexSetSupport(rdm, newp, supportRef);
4832: #if 1
4833:       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
4834:       for (p = 0; p < 4; ++p) {
4835:         if ((supportRef[p] < eStartNew) || (supportRef[p] >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", supportRef[p], eStartNew, eEndNew);
4836:       }
4837: #endif
4838:     }
4839:     PetscFree(supportRef);
4840:     DMPlexRestoreFaces_Internal(dm, 3, cStart, NULL, NULL, &faces);
4841:     break;
4842:   case REFINER_HEX_3D:
4843:     /*
4844:      Bottom (viewed from top)    Top
4845:      1---------2---------2       7---------2---------6
4846:      |         |         |       |         |         |
4847:      |    B    2    C    |       |    H    2    G    |
4848:      |         |         |       |         |         |
4849:      3----3----0----1----1       3----3----0----1----1
4850:      |         |         |       |         |         |
4851:      |    A    0    D    |       |    E    0    F    |
4852:      |         |         |       |         |         |
4853:      0---------0---------3       4---------0---------5
4854:      */
4855:     /* All cells have 6 faces: Bottom, Top, Front, Back, Right, Left */
4856:     for (c = cStart; c < cEnd; ++c) {
4857:       const PetscInt  newp = (c - cStart)*8;
4858:       const PetscInt *cone, *ornt;
4859:       PetscInt        coneNew[6], orntNew[6];

4861:       DMPlexGetCone(dm, c, &cone);
4862:       DMPlexGetConeOrientation(dm, c, &ornt);
4863:       /* A hex */
4864:       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], 0);
4865:       orntNew[0] = ornt[0];
4866:       coneNew[1] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  8; /* AE */
4867:       orntNew[1] = 0;
4868:       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetQuadSubface_Static(ornt[2], 0);
4869:       orntNew[2] = ornt[2];
4870:       coneNew[3] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  3; /* AB */
4871:       orntNew[3] = 0;
4872:       coneNew[4] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  0; /* AD */
4873:       orntNew[4] = 0;
4874:       coneNew[5] = fStartNew + (cone[5] - fStart)*4 + GetQuadSubface_Static(ornt[5], 0);
4875:       orntNew[5] = ornt[5];
4876:       DMPlexSetCone(rdm, newp+0, coneNew);
4877:       DMPlexSetConeOrientation(rdm, newp+0, orntNew);
4878: #if 1
4879:       if ((newp+0 < cStartNew) || (newp+0 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+0, cStartNew, cEndNew);
4880:       for (p = 0; p < 6; ++p) {
4881:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
4882:       }
4883: #endif
4884:       /* B hex */
4885:       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], 1);
4886:       orntNew[0] = ornt[0];
4887:       coneNew[1] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 + 11; /* BH */
4888:       orntNew[1] = 0;
4889:       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  3; /* AB */
4890:       orntNew[2] = -1;
4891:       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetQuadSubface_Static(ornt[3], 1);
4892:       orntNew[3] = ornt[3];
4893:       coneNew[4] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  2; /* BC */
4894:       orntNew[4] = 0;
4895:       coneNew[5] = fStartNew + (cone[5] - fStart)*4 + GetQuadSubface_Static(ornt[5], 3);
4896:       orntNew[5] = ornt[5];
4897:       DMPlexSetCone(rdm, newp+1, coneNew);
4898:       DMPlexSetConeOrientation(rdm, newp+1, orntNew);
4899: #if 1
4900:       if ((newp+1 < cStartNew) || (newp+1 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+1, cStartNew, cEndNew);
4901:       for (p = 0; p < 6; ++p) {
4902:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
4903:       }
4904: #endif
4905:       /* C hex */
4906:       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], 2);
4907:       orntNew[0] = ornt[0];
4908:       coneNew[1] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 + 10; /* CG */
4909:       orntNew[1] = 0;
4910:       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  1; /* CD */
4911:       orntNew[2] = -1;
4912:       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetQuadSubface_Static(ornt[3], 0);
4913:       orntNew[3] = ornt[3];
4914:       coneNew[4] = fStartNew + (cone[4] - fStart)*4 + GetQuadSubface_Static(ornt[4], 1);
4915:       orntNew[4] = ornt[4];
4916:       coneNew[5] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  2; /* BC */
4917:       orntNew[5] = -4;
4918:       DMPlexSetCone(rdm, newp+2, coneNew);
4919:       DMPlexSetConeOrientation(rdm, newp+2, orntNew);
4920: #if 1
4921:       if ((newp+2 < cStartNew) || (newp+2 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+2, cStartNew, cEndNew);
4922:       for (p = 0; p < 6; ++p) {
4923:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
4924:       }
4925: #endif
4926:       /* D hex */
4927:       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], 3);
4928:       orntNew[0] = ornt[0];
4929:       coneNew[1] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  9; /* DF */
4930:       orntNew[1] = 0;
4931:       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetQuadSubface_Static(ornt[2], 1);
4932:       orntNew[2] = ornt[2];
4933:       coneNew[3] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  1; /* CD */
4934:       orntNew[3] = 0;
4935:       coneNew[4] = fStartNew + (cone[4] - fStart)*4 + GetQuadSubface_Static(ornt[4], 0);
4936:       orntNew[4] = ornt[4];
4937:       coneNew[5] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  0; /* AD */
4938:       orntNew[5] = -4;
4939:       DMPlexSetCone(rdm, newp+3, coneNew);
4940:       DMPlexSetConeOrientation(rdm, newp+3, orntNew);
4941: #if 1
4942:       if ((newp+3 < cStartNew) || (newp+3 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+3, cStartNew, cEndNew);
4943:       for (p = 0; p < 6; ++p) {
4944:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
4945:       }
4946: #endif
4947:       /* E hex */
4948:       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  8; /* AE */
4949:       orntNew[0] = -4;
4950:       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], 0);
4951:       orntNew[1] = ornt[1];
4952:       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetQuadSubface_Static(ornt[2], 3);
4953:       orntNew[2] = ornt[2];
4954:       coneNew[3] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  7; /* EH */
4955:       orntNew[3] = 0;
4956:       coneNew[4] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  4; /* EF */
4957:       orntNew[4] = -1;
4958:       coneNew[5] = fStartNew + (cone[5] - fStart)*4 + GetQuadSubface_Static(ornt[5], 1);
4959:       orntNew[5] = ornt[5];
4960:       DMPlexSetCone(rdm, newp+4, coneNew);
4961:       DMPlexSetConeOrientation(rdm, newp+4, orntNew);
4962: #if 1
4963:       if ((newp+4 < cStartNew) || (newp+4 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+4, cStartNew, cEndNew);
4964:       for (p = 0; p < 6; ++p) {
4965:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
4966:       }
4967: #endif
4968:       /* F hex */
4969:       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  9; /* DF */
4970:       orntNew[0] = -4;
4971:       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], 1);
4972:       orntNew[1] = ornt[1];
4973:       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetQuadSubface_Static(ornt[2], 2);
4974:       orntNew[2] = ornt[2];
4975:       coneNew[3] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  5; /* FG */
4976:       orntNew[3] = -1;
4977:       coneNew[4] = fStartNew + (cone[4] - fStart)*4 + GetQuadSubface_Static(ornt[4], 3);
4978:       orntNew[4] = ornt[4];
4979:       coneNew[5] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  4; /* EF */
4980:       orntNew[5] = 1;
4981:       DMPlexSetCone(rdm, newp+5, coneNew);
4982:       DMPlexSetConeOrientation(rdm, newp+5, orntNew);
4983: #if 1
4984:       if ((newp+5 < cStartNew) || (newp+5 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+5, cStartNew, cEndNew);
4985:       for (p = 0; p < 6; ++p) {
4986:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
4987:       }
4988: #endif
4989:       /* G hex */
4990:       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 + 10; /* CG */
4991:       orntNew[0] = -4;
4992:       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], 2);
4993:       orntNew[1] = ornt[1];
4994:       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  5; /* FG */
4995:       orntNew[2] = 0;
4996:       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetQuadSubface_Static(ornt[3], 3);
4997:       orntNew[3] = ornt[3];
4998:       coneNew[4] = fStartNew + (cone[4] - fStart)*4 + GetQuadSubface_Static(ornt[4], 2);
4999:       orntNew[4] = ornt[4];
5000:       coneNew[5] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  6; /* GH */
5001:       orntNew[5] = -3;
5002:       DMPlexSetCone(rdm, newp+6, coneNew);
5003:       DMPlexSetConeOrientation(rdm, newp+6, orntNew);
5004: #if 1
5005:       if ((newp+6 < cStartNew) || (newp+6 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+6, cStartNew, cEndNew);
5006:       for (p = 0; p < 6; ++p) {
5007:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
5008:       }
5009: #endif
5010:       /* H hex */
5011:       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 + 11; /* BH */
5012:       orntNew[0] = -4;
5013:       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], 3);
5014:       orntNew[1] = ornt[1];
5015:       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  7; /* EH */
5016:       orntNew[2] = -1;
5017:       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetQuadSubface_Static(ornt[3], 2);
5018:       orntNew[3] = ornt[3];
5019:       coneNew[4] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  6; /* GH */
5020:       orntNew[4] = 3;
5021:       coneNew[5] = fStartNew + (cone[5] - fStart)*4 + GetQuadSubface_Static(ornt[5], 2);
5022:       orntNew[5] = ornt[5];
5023:       DMPlexSetCone(rdm, newp+7, coneNew);
5024:       DMPlexSetConeOrientation(rdm, newp+7, orntNew);
5025: #if 1
5026:       if ((newp+7 < cStartNew) || (newp+7 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+7, cStartNew, cEndNew);
5027:       for (p = 0; p < 6; ++p) {
5028:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
5029:       }
5030: #endif
5031:     }
5032:     /* Split faces have 4 edges and the same cells as the parent */
5033:     DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);
5034:     PetscMalloc1(4 + maxSupportSize*2, &supportRef);
5035:     for (f = fStart; f < fEnd; ++f) {
5036:       for (r = 0; r < 4; ++r) {
5037:         /* TODO: This can come from GetFaces_Internal() */
5038:         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};
5039:         const PetscInt  newp = fStartNew + (f - fStart)*4 + r;
5040:         const PetscInt *cone, *ornt, *support;
5041:         PetscInt        coneNew[4], orntNew[4], coneSize, c, supportSize, s;

5043:         DMPlexGetCone(dm, f, &cone);
5044:         DMPlexGetConeOrientation(dm, f, &ornt);
5045:         coneNew[(r+3)%4] = eStartNew + (cone[(r+3)%4] - eStart)*2 + (ornt[(r+3)%4] < 0 ? 0 : 1);
5046:         orntNew[(r+3)%4] = ornt[(r+3)%4];
5047:         coneNew[(r+0)%4] = eStartNew + (cone[r]       - eStart)*2 + (ornt[r] < 0 ? 1 : 0);
5048:         orntNew[(r+0)%4] = ornt[r];
5049:         coneNew[(r+1)%4] = eStartNew + (eEnd - eStart)*2 + (f - fStart)*4 + r;
5050:         orntNew[(r+1)%4] = 0;
5051:         coneNew[(r+2)%4] = eStartNew + (eEnd - eStart)*2 + (f - fStart)*4 + (r+3)%4;
5052:         orntNew[(r+2)%4] = -2;
5053:         DMPlexSetCone(rdm, newp, coneNew);
5054:         DMPlexSetConeOrientation(rdm, newp, orntNew);
5055: #if 1
5056:         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5057:         for (p = 0; p < 4; ++p) {
5058:           if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eEndNew);
5059:         }
5060: #endif
5061:         DMPlexGetSupportSize(dm, f, &supportSize);
5062:         DMPlexGetSupport(dm, f, &support);
5063:         for (s = 0; s < supportSize; ++s) {
5064:           DMPlexGetConeSize(dm, support[s], &coneSize);
5065:           DMPlexGetCone(dm, support[s], &cone);
5066:           DMPlexGetConeOrientation(dm, support[s], &ornt);
5067:           for (c = 0; c < coneSize; ++c) {
5068:             if (cone[c] == f) break;
5069:           }
5070:           supportRef[s] = cStartNew + (support[s] - cStart)*8 + newCells[c*4+GetQuadSubfaceInverse_Static(ornt[c], r)];
5071:         }
5072:         DMPlexSetSupport(rdm, newp, supportRef);
5073: #if 1
5074:         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5075:         for (p = 0; p < supportSize; ++p) {
5076:           if ((supportRef[p] < cStartNew) || (supportRef[p] >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportRef[p], cStartNew, cEndNew);
5077:         }
5078: #endif
5079:       }
5080:     }
5081:     /* Interior faces have 4 edges and 2 cells */
5082:     for (c = cStart; c < cEnd; ++c) {
5083:       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};
5084:       const PetscInt *cone, *ornt;
5085:       PetscInt        newp, coneNew[4], orntNew[4], supportNew[2];

5087:       DMPlexGetCone(dm, c, &cone);
5088:       DMPlexGetConeOrientation(dm, c, &ornt);
5089:       /* A-D face */
5090:       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 0;
5091:       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*4 + GetQuadEdge_Static(ornt[0], 3);
5092:       orntNew[0] = 0;
5093:       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 0;
5094:       orntNew[1] = 0;
5095:       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 2;
5096:       orntNew[2] = -2;
5097:       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*4 + GetQuadEdge_Static(ornt[2], 0);
5098:       orntNew[3] = -2;
5099:       DMPlexSetCone(rdm, newp, coneNew);
5100:       DMPlexSetConeOrientation(rdm, newp, orntNew);
5101: #if 1
5102:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5103:       for (p = 0; p < 4; ++p) {
5104:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eEndNew);
5105:       }
5106: #endif
5107:       /* C-D face */
5108:       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 1;
5109:       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*4 + GetQuadEdge_Static(ornt[0], 2);
5110:       orntNew[0] = 0;
5111:       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 0;
5112:       orntNew[1] = 0;
5113:       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 4;
5114:       orntNew[2] = -2;
5115:       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (cone[4] - fStart)*4 + GetQuadEdge_Static(ornt[4], 0);
5116:       orntNew[3] = -2;
5117:       DMPlexSetCone(rdm, newp, coneNew);
5118:       DMPlexSetConeOrientation(rdm, newp, orntNew);
5119: #if 1
5120:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5121:       for (p = 0; p < 4; ++p) {
5122:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eEndNew);
5123:       }
5124: #endif
5125:       /* B-C face */
5126:       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 2;
5127:       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*4 + GetQuadEdge_Static(ornt[0], 1);
5128:       orntNew[0] = -2;
5129:       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*4 + GetQuadEdge_Static(ornt[3], 0);
5130:       orntNew[1] = 0;
5131:       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 3;
5132:       orntNew[2] = 0;
5133:       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 0;
5134:       orntNew[3] = -2;
5135:       DMPlexSetCone(rdm, newp, coneNew);
5136:       DMPlexSetConeOrientation(rdm, newp, orntNew);
5137: #if 1
5138:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5139:       for (p = 0; p < 4; ++p) {
5140:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eEndNew);
5141:       }
5142: #endif
5143:       /* A-B face */
5144:       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 3;
5145:       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*4 + GetQuadEdge_Static(ornt[0], 0);
5146:       orntNew[0] = -2;
5147:       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[5] - fStart)*4 + GetQuadEdge_Static(ornt[5], 3);
5148:       orntNew[1] = 0;
5149:       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 5;
5150:       orntNew[2] = 0;
5151:       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 0;
5152:       orntNew[3] = -2;
5153:       DMPlexSetCone(rdm, newp, coneNew);
5154:       DMPlexSetConeOrientation(rdm, newp, orntNew);
5155: #if 1
5156:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5157:       for (p = 0; p < 4; ++p) {
5158:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eEndNew);
5159:       }
5160: #endif
5161:       /* E-F face */
5162:       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 4;
5163:       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 2;
5164:       orntNew[0] = -2;
5165:       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*4 + GetQuadEdge_Static(ornt[2], 2);
5166:       orntNew[1] = -2;
5167:       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*4 + GetQuadEdge_Static(ornt[1], 0);
5168:       orntNew[2] = 0;
5169:       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 1;
5170:       orntNew[3] = 0;
5171:       DMPlexSetCone(rdm, newp, coneNew);
5172:       DMPlexSetConeOrientation(rdm, newp, orntNew);
5173: #if 1
5174:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5175:       for (p = 0; p < 4; ++p) {
5176:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eEndNew);
5177:       }
5178: #endif
5179:       /* F-G face */
5180:       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 5;
5181:       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 4;
5182:       orntNew[0] = -2;
5183:       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[4] - fStart)*4 + GetQuadEdge_Static(ornt[4], 2);
5184:       orntNew[1] = -2;
5185:       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*4 + GetQuadEdge_Static(ornt[1], 1);
5186:       orntNew[2] = 0;
5187:       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 1;
5188:       orntNew[3] = 0;
5189:       DMPlexSetCone(rdm, newp, coneNew);
5190:       DMPlexSetConeOrientation(rdm, newp, orntNew);
5191: #if 1
5192:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5193:       for (p = 0; p < 4; ++p) {
5194:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eEndNew);
5195:       }
5196: #endif
5197:       /* G-H face */
5198:       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 6;
5199:       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*4 + GetQuadEdge_Static(ornt[3], 2);
5200:       orntNew[0] = -2;
5201:       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*4 + GetQuadEdge_Static(ornt[1], 2);
5202:       orntNew[1] = 0;
5203:       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 1;
5204:       orntNew[2] = 0;
5205:       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 3;
5206:       orntNew[3] = -2;
5207:       DMPlexSetCone(rdm, newp, coneNew);
5208:       DMPlexSetConeOrientation(rdm, newp, orntNew);
5209: #if 1
5210:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5211:       for (p = 0; p < 4; ++p) {
5212:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eEndNew);
5213:       }
5214: #endif
5215:       /* E-H face */
5216:       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 7;
5217:       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 5;
5218:       orntNew[0] = -2;
5219:       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[5] - fStart)*4 + GetQuadEdge_Static(ornt[5], 1);
5220:       orntNew[1] = -2;
5221:       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*4 + GetQuadEdge_Static(ornt[1], 3);
5222:       orntNew[2] = 0;
5223:       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 1;
5224:       orntNew[3] = 0;
5225:       DMPlexSetCone(rdm, newp, coneNew);
5226:       DMPlexSetConeOrientation(rdm, newp, orntNew);
5227: #if 1
5228:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5229:       for (p = 0; p < 4; ++p) {
5230:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eEndNew);
5231:       }
5232: #endif
5233:       /* A-E face */
5234:       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 8;
5235:       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*4 + GetQuadEdge_Static(ornt[2], 3);
5236:       orntNew[0] = 0;
5237:       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 2;
5238:       orntNew[1] = 0;
5239:       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 5;
5240:       orntNew[2] = -2;
5241:       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (cone[5] - fStart)*4 + GetQuadEdge_Static(ornt[5], 0);
5242:       orntNew[3] = -2;
5243:       DMPlexSetCone(rdm, newp, coneNew);
5244:       DMPlexSetConeOrientation(rdm, newp, orntNew);
5245: #if 1
5246:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5247:       for (p = 0; p < 4; ++p) {
5248:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eEndNew);
5249:       }
5250: #endif
5251:       /* D-F face */
5252:       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 9;
5253:       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*4 + GetQuadEdge_Static(ornt[2], 1);
5254:       orntNew[0] = -2;
5255:       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[4] - fStart)*4 + GetQuadEdge_Static(ornt[4], 3);
5256:       orntNew[1] = 0;
5257:       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 4;
5258:       orntNew[2] = 0;
5259:       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 2;
5260:       orntNew[3] = -2;
5261:       DMPlexSetCone(rdm, newp, coneNew);
5262:       DMPlexSetConeOrientation(rdm, newp, orntNew);
5263: #if 1
5264:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5265:       for (p = 0; p < 4; ++p) {
5266:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eEndNew);
5267:       }
5268: #endif
5269:       /* C-G face */
5270:       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 10;
5271:       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 4;
5272:       orntNew[0] = -2;
5273:       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[4] - fStart)*4 + GetQuadEdge_Static(ornt[4], 1);
5274:       orntNew[1] = -2;
5275:       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*4 + GetQuadEdge_Static(ornt[3], 3);
5276:       orntNew[2] = 0;
5277:       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 3;
5278:       orntNew[3] = 0;
5279:       DMPlexSetCone(rdm, newp, coneNew);
5280:       DMPlexSetConeOrientation(rdm, newp, orntNew);
5281: #if 1
5282:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5283:       for (p = 0; p < 4; ++p) {
5284:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eEndNew);
5285:       }
5286: #endif
5287:       /* B-H face */
5288:       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 11;
5289:       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 5;
5290:       orntNew[0] = 0;
5291:       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 3;
5292:       orntNew[1] = -2;
5293:       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*4 + GetQuadEdge_Static(ornt[3], 1);
5294:       orntNew[2] = -2;
5295:       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (cone[5] - fStart)*4 + GetQuadEdge_Static(ornt[5], 2);
5296:       orntNew[3] = 0;
5297:       DMPlexSetCone(rdm, newp, coneNew);
5298:       DMPlexSetConeOrientation(rdm, newp, orntNew);
5299: #if 1
5300:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5301:       for (p = 0; p < 4; ++p) {
5302:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eEndNew);
5303:       }
5304: #endif
5305:       for (r = 0; r < 12; ++r) {
5306:         newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + r;
5307:         supportNew[0] = cStartNew + (c - cStart)*8 + newCells[r*2+0];
5308:         supportNew[1] = cStartNew + (c - cStart)*8 + newCells[r*2+1];
5309:         DMPlexSetSupport(rdm, newp, supportNew);
5310: #if 1
5311:         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5312:         for (p = 0; p < 2; ++p) {
5313:           if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cEndNew);
5314:         }
5315: #endif
5316:       }
5317:     }
5318:     /* Split edges have 2 vertices and the same faces as the parent */
5319:     DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);
5320:     for (e = eStart; e < eEnd; ++e) {
5321:       const PetscInt newv = vStartNew + (vEnd - vStart) + (e - eStart);

5323:       for (r = 0; r < 2; ++r) {
5324:         const PetscInt  newp = eStartNew + (e - eStart)*2 + r;
5325:         const PetscInt *cone, *ornt, *support;
5326:         PetscInt        coneNew[2], coneSize, c, supportSize, s;

5328:         DMPlexGetCone(dm, e, &cone);
5329:         coneNew[0]       = vStartNew + (cone[0] - vStart);
5330:         coneNew[1]       = vStartNew + (cone[1] - vStart);
5331:         coneNew[(r+1)%2] = newv;
5332:         DMPlexSetCone(rdm, newp, coneNew);
5333: #if 1
5334:         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
5335:         for (p = 0; p < 2; ++p) {
5336:           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
5337:         }
5338: #endif
5339:         DMPlexGetSupportSize(dm, e, &supportSize);
5340:         DMPlexGetSupport(dm, e, &support);
5341:         for (s = 0; s < supportSize; ++s) {
5342:           DMPlexGetConeSize(dm, support[s], &coneSize);
5343:           DMPlexGetCone(dm, support[s], &cone);
5344:           DMPlexGetConeOrientation(dm, support[s], &ornt);
5345:           for (c = 0; c < coneSize; ++c) {
5346:             if (cone[c] == e) break;
5347:           }
5348:           supportRef[s] = fStartNew + (support[s] - fStart)*4 + (ornt[c] < 0 ? (c+1-r)%4 : (c+r)%4);
5349:         }
5350:         DMPlexSetSupport(rdm, newp, supportRef);
5351: #if 1
5352:         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
5353:         for (p = 0; p < supportSize; ++p) {
5354:           if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", supportRef[p], fStartNew, fEndNew);
5355:         }
5356: #endif
5357:       }
5358:     }
5359:     /* Face edges have 2 vertices and 2+cells faces */
5360:     for (f = fStart; f < fEnd; ++f) {
5361:       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};
5362:       const PetscInt  newv = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (f - fStart);
5363:       const PetscInt *cone, *coneCell, *orntCell, *support;
5364:       PetscInt        coneNew[2], coneSize, c, supportSize, s;

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

5370:         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r] - eStart);
5371:         coneNew[1] = newv;
5372:         DMPlexSetCone(rdm, newp, coneNew);
5373: #if 1
5374:         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
5375:         for (p = 0; p < 2; ++p) {
5376:           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
5377:         }
5378: #endif
5379:         DMPlexGetSupportSize(dm, f, &supportSize);
5380:         DMPlexGetSupport(dm, f, &support);
5381:         supportRef[0] = fStartNew + (f - fStart)*4 + r;
5382:         supportRef[1] = fStartNew + (f - fStart)*4 + (r+1)%4;
5383:         for (s = 0; s < supportSize; ++s) {
5384:           DMPlexGetConeSize(dm, support[s], &coneSize);
5385:           DMPlexGetCone(dm, support[s], &coneCell);
5386:           DMPlexGetConeOrientation(dm, support[s], &orntCell);
5387:           for (c = 0; c < coneSize; ++c) if (coneCell[c] == f) break;
5388:           supportRef[2+s] = fStartNew + (fEnd - fStart)*4 + (support[s] - cStart)*12 + newFaces[c*4 + GetQuadEdgeInverse_Static(orntCell[c], r)];
5389:         }
5390:         DMPlexSetSupport(rdm, newp, supportRef);
5391: #if 1
5392:         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
5393:         for (p = 0; p < 2+supportSize; ++p) {
5394:           if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", supportRef[p], fStartNew, fEndNew);
5395:         }
5396: #endif
5397:       }
5398:     }
5399:     /* Cell edges have 2 vertices and 4 faces */
5400:     for (c = cStart; c < cEnd; ++c) {
5401:       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};
5402:       const PetscInt  newv = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (fEnd - fStart) + (c - cStart);
5403:       const PetscInt *cone;
5404:       PetscInt        coneNew[2], supportNew[4];

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

5410:         coneNew[0] = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (cone[r] - fStart);
5411:         coneNew[1] = newv;
5412:         DMPlexSetCone(rdm, newp, coneNew);
5413: #if 1
5414:         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
5415:         for (p = 0; p < 2; ++p) {
5416:           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
5417:         }
5418: #endif
5419:         for (f = 0; f < 4; ++f) supportNew[f] = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + newFaces[r*4+f];
5420:         DMPlexSetSupport(rdm, newp, supportNew);
5421: #if 1
5422:         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
5423:         for (p = 0; p < 4; ++p) {
5424:           if ((supportNew[p] < fStartNew) || (supportNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", supportNew[p], fStartNew, fEndNew);
5425:         }
5426: #endif
5427:       }
5428:     }
5429:     /* Old vertices have identical supports */
5430:     for (v = vStart; v < vEnd; ++v) {
5431:       const PetscInt  newp = vStartNew + (v - vStart);
5432:       const PetscInt *support, *cone;
5433:       PetscInt        size, s;

5435:       DMPlexGetSupportSize(dm, v, &size);
5436:       DMPlexGetSupport(dm, v, &support);
5437:       for (s = 0; s < size; ++s) {
5438:         PetscInt r = 0;

5440:         DMPlexGetCone(dm, support[s], &cone);
5441:         if (cone[1] == v) r = 1;
5442:         supportRef[s] = eStartNew + (support[s] - eStart)*2 + r;
5443:       }
5444:       DMPlexSetSupport(rdm, newp, supportRef);
5445: #if 1
5446:       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
5447:       for (p = 0; p < size; ++p) {
5448:         if ((supportRef[p] < eStartNew) || (supportRef[p] >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", supportRef[p], eStartNew, eEndNew);
5449:       }
5450: #endif
5451:     }
5452:     /* Edge vertices have 2 + faces supports */
5453:     for (e = eStart; e < eEnd; ++e) {
5454:       const PetscInt  newp = vStartNew + (vEnd - vStart) + (e - eStart);
5455:       const PetscInt *cone, *support;
5456:       PetscInt        size, s;

5458:       DMPlexGetSupportSize(dm, e, &size);
5459:       DMPlexGetSupport(dm, e, &support);
5460:       supportRef[0] = eStartNew + (e - eStart)*2 + 0;
5461:       supportRef[1] = eStartNew + (e - eStart)*2 + 1;
5462:       for (s = 0; s < size; ++s) {
5463:         PetscInt r;

5465:         DMPlexGetCone(dm, support[s], &cone);
5466:         for (r = 0; r < 4; ++r) if (cone[r] == e) break;
5467:         supportRef[2+s] = eStartNew + (eEnd - eStart)*2 + (support[s] - fStart)*4 + r;
5468:       }
5469:       DMPlexSetSupport(rdm, newp, supportRef);
5470: #if 1
5471:       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
5472:       for (p = 0; p < 2+size; ++p) {
5473:         if ((supportRef[p] < eStartNew) || (supportRef[p] >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", supportRef[p], eStartNew, eEndNew);
5474:       }
5475: #endif
5476:     }
5477:     /* Face vertices have 4 + cells supports */
5478:     for (f = fStart; f < fEnd; ++f) {
5479:       const PetscInt  newp = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (f - fStart);
5480:       const PetscInt *cone, *support;
5481:       PetscInt        size, s;

5483:       DMPlexGetSupportSize(dm, f, &size);
5484:       DMPlexGetSupport(dm, f, &support);
5485:       for (r = 0; r < 4; ++r) supportRef[r] = eStartNew + (eEnd - eStart)*2 +  (f - fStart)*4 + r;
5486:       for (s = 0; s < size; ++s) {
5487:         PetscInt r;

5489:         DMPlexGetCone(dm, support[s], &cone);
5490:         for (r = 0; r < 6; ++r) if (cone[r] == f) break;
5491:         supportRef[4+s] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*4 + (support[s] - cStart)*6 + r;
5492:       }
5493:       DMPlexSetSupport(rdm, newp, supportRef);
5494: #if 1
5495:       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
5496:       for (p = 0; p < 4+size; ++p) {
5497:         if ((supportRef[p] < eStartNew) || (supportRef[p] >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", supportRef[p], eStartNew, eEndNew);
5498:       }
5499: #endif
5500:     }
5501:     /* Cell vertices have 6 supports */
5502:     for (c = cStart; c < cEnd; ++c) {
5503:       const PetscInt newp = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (fEnd - fStart) + (c - cStart);
5504:       PetscInt       supportNew[6];

5506:       for (r = 0; r < 6; ++r) {
5507:         supportNew[r] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*4 + (c - cStart)*6 + r;
5508:       }
5509:       DMPlexSetSupport(rdm, newp, supportNew);
5510:     }
5511:     PetscFree(supportRef);
5512:     break;
5513:   case REFINER_HYBRID_HEX_3D:
5514:     DMPlexGetHybridBounds(rdm, &cMaxNew, &fMaxNew, &eMaxNew, NULL);
5515:     /*
5516:      Bottom (viewed from top)    Top
5517:      1---------2---------2       7---------2---------6
5518:      |         |         |       |         |         |
5519:      |    B    2    C    |       |    H    2    G    |
5520:      |         |         |       |         |         |
5521:      3----3----0----1----1       3----3----0----1----1
5522:      |         |         |       |         |         |
5523:      |    A    0    D    |       |    E    0    F    |
5524:      |         |         |       |         |         |
5525:      0---------0---------3       4---------0---------5
5526:      */
5527:     /* Interior cells have 6 faces: Bottom, Top, Front, Back, Right, Left */
5528:     for (c = cStart; c < cMax; ++c) {
5529:       const PetscInt  newp = (c - cStart)*8;
5530:       const PetscInt *cone, *ornt;
5531:       PetscInt        coneNew[6], orntNew[6];

5533:       DMPlexGetCone(dm, c, &cone);
5534:       DMPlexGetConeOrientation(dm, c, &ornt);
5535:       /* A hex */
5536:       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], 0);
5537:       orntNew[0] = ornt[0];
5538:       coneNew[1] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  8; /* AE */
5539:       orntNew[1] = 0;
5540:       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetQuadSubface_Static(ornt[2], 0);
5541:       orntNew[2] = ornt[2];
5542:       coneNew[3] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  3; /* AB */
5543:       orntNew[3] = 0;
5544:       coneNew[4] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  0; /* AD */
5545:       orntNew[4] = 0;
5546:       coneNew[5] = fStartNew + (cone[5] - fStart)*4 + GetQuadSubface_Static(ornt[5], 0);
5547:       orntNew[5] = ornt[5];
5548:       DMPlexSetCone(rdm, newp+0, coneNew);
5549:       DMPlexSetConeOrientation(rdm, newp+0, orntNew);
5550: #if 1
5551:       if ((newp+0 < cStartNew) || (newp+0 >= cMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+0, cStartNew, cMaxNew);
5552:       for (p = 0; p < 6; ++p) {
5553:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fMaxNew);
5554:       }
5555: #endif
5556:       /* B hex */
5557:       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], 1);
5558:       orntNew[0] = ornt[0];
5559:       coneNew[1] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 + 11; /* BH */
5560:       orntNew[1] = 0;
5561:       coneNew[2] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  3; /* AB */
5562:       orntNew[2] = -1;
5563:       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetQuadSubface_Static(ornt[3], 1);
5564:       orntNew[3] = ornt[3];
5565:       coneNew[4] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  2; /* BC */
5566:       orntNew[4] = 0;
5567:       coneNew[5] = fStartNew + (cone[5] - fStart)*4 + GetQuadSubface_Static(ornt[5], 3);
5568:       orntNew[5] = ornt[5];
5569:       DMPlexSetCone(rdm, newp+1, coneNew);
5570:       DMPlexSetConeOrientation(rdm, newp+1, orntNew);
5571: #if 1
5572:       if ((newp+1 < cStartNew) || (newp+1 >= cMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+1, cStartNew, cMaxNew);
5573:       for (p = 0; p < 6; ++p) {
5574:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fMaxNew);
5575:       }
5576: #endif
5577:       /* C hex */
5578:       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], 2);
5579:       orntNew[0] = ornt[0];
5580:       coneNew[1] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 + 10; /* CG */
5581:       orntNew[1] = 0;
5582:       coneNew[2] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  1; /* CD */
5583:       orntNew[2] = -1;
5584:       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetQuadSubface_Static(ornt[3], 0);
5585:       orntNew[3] = ornt[3];
5586:       coneNew[4] = fStartNew + (cone[4] - fStart)*4 + GetQuadSubface_Static(ornt[4], 1);
5587:       orntNew[4] = ornt[4];
5588:       coneNew[5] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  2; /* BC */
5589:       orntNew[5] = -4;
5590:       DMPlexSetCone(rdm, newp+2, coneNew);
5591:       DMPlexSetConeOrientation(rdm, newp+2, orntNew);
5592: #if 1
5593:       if ((newp+2 < cStartNew) || (newp+2 >= cMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+2, cStartNew, cMaxNew);
5594:       for (p = 0; p < 6; ++p) {
5595:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fMaxNew);
5596:       }
5597: #endif
5598:       /* D hex */
5599:       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], 3);
5600:       orntNew[0] = ornt[0];
5601:       coneNew[1] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  9; /* DF */
5602:       orntNew[1] = 0;
5603:       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetQuadSubface_Static(ornt[2], 1);
5604:       orntNew[2] = ornt[2];
5605:       coneNew[3] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  1; /* CD */
5606:       orntNew[3] = 0;
5607:       coneNew[4] = fStartNew + (cone[4] - fStart)*4 + GetQuadSubface_Static(ornt[4], 0);
5608:       orntNew[4] = ornt[4];
5609:       coneNew[5] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  0; /* AD */
5610:       orntNew[5] = -4;
5611:       DMPlexSetCone(rdm, newp+3, coneNew);
5612:       DMPlexSetConeOrientation(rdm, newp+3, orntNew);
5613: #if 1
5614:       if ((newp+3 < cStartNew) || (newp+3 >= cMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+3, cStartNew, cMaxNew);
5615:       for (p = 0; p < 6; ++p) {
5616:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fMaxNew);
5617:       }
5618: #endif
5619:       /* E hex */
5620:       coneNew[0] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  8; /* AE */
5621:       orntNew[0] = -4;
5622:       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], 0);
5623:       orntNew[1] = ornt[1];
5624:       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetQuadSubface_Static(ornt[2], 3);
5625:       orntNew[2] = ornt[2];
5626:       coneNew[3] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  7; /* EH */
5627:       orntNew[3] = 0;
5628:       coneNew[4] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  4; /* EF */
5629:       orntNew[4] = -1;
5630:       coneNew[5] = fStartNew + (cone[5] - fStart)*4 + GetQuadSubface_Static(ornt[5], 1);
5631:       orntNew[5] = ornt[5];
5632:       DMPlexSetCone(rdm, newp+4, coneNew);
5633:       DMPlexSetConeOrientation(rdm, newp+4, orntNew);
5634: #if 1
5635:       if ((newp+4 < cStartNew) || (newp+4 >= cMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+4, cStartNew, cMaxNew);
5636:       for (p = 0; p < 6; ++p) {
5637:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fMaxNew);
5638:       }
5639: #endif
5640:       /* F hex */
5641:       coneNew[0] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  9; /* DF */
5642:       orntNew[0] = -4;
5643:       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], 1);
5644:       orntNew[1] = ornt[1];
5645:       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetQuadSubface_Static(ornt[2], 2);
5646:       orntNew[2] = ornt[2];
5647:       coneNew[3] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  5; /* FG */
5648:       orntNew[3] = -1;
5649:       coneNew[4] = fStartNew + (cone[4] - fStart)*4 + GetQuadSubface_Static(ornt[4], 3);
5650:       orntNew[4] = ornt[4];
5651:       coneNew[5] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  4; /* EF */
5652:       orntNew[5] = 1;
5653:       DMPlexSetCone(rdm, newp+5, coneNew);
5654:       DMPlexSetConeOrientation(rdm, newp+5, orntNew);
5655: #if 1
5656:       if ((newp+5 < cStartNew) || (newp+5 >= cMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+5, cStartNew, cMaxNew);
5657:       for (p = 0; p < 6; ++p) {
5658:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fMaxNew);
5659:       }
5660: #endif
5661:       /* G hex */
5662:       coneNew[0] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 + 10; /* CG */
5663:       orntNew[0] = -4;
5664:       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], 2);
5665:       orntNew[1] = ornt[1];
5666:       coneNew[2] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  5; /* FG */
5667:       orntNew[2] = 0;
5668:       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetQuadSubface_Static(ornt[3], 3);
5669:       orntNew[3] = ornt[3];
5670:       coneNew[4] = fStartNew + (cone[4] - fStart)*4 + GetQuadSubface_Static(ornt[4], 2);
5671:       orntNew[4] = ornt[4];
5672:       coneNew[5] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  6; /* GH */
5673:       orntNew[5] = -3;
5674:       DMPlexSetCone(rdm, newp+6, coneNew);
5675:       DMPlexSetConeOrientation(rdm, newp+6, orntNew);
5676: #if 1
5677:       if ((newp+6 < cStartNew) || (newp+6 >= cMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+6, cStartNew, cMaxNew);
5678:       for (p = 0; p < 6; ++p) {
5679:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fMaxNew);
5680:       }
5681: #endif
5682:       /* H hex */
5683:       coneNew[0] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 + 11; /* BH */
5684:       orntNew[0] = -4;
5685:       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], 3);
5686:       orntNew[1] = ornt[1];
5687:       coneNew[2] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  7; /* EH */
5688:       orntNew[2] = -1;
5689:       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetQuadSubface_Static(ornt[3], 2);
5690:       orntNew[3] = ornt[3];
5691:       coneNew[4] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  6; /* GH */
5692:       orntNew[4] = 3;
5693:       coneNew[5] = fStartNew + (cone[5] - fStart)*4 + GetQuadSubface_Static(ornt[5], 2);
5694:       orntNew[5] = ornt[5];
5695:       DMPlexSetCone(rdm, newp+7, coneNew);
5696:       DMPlexSetConeOrientation(rdm, newp+7, orntNew);
5697: #if 1
5698:       if ((newp+7 < cStartNew) || (newp+7 >= cMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+7, cStartNew, cMaxNew);
5699:       for (p = 0; p < 6; ++p) {
5700:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fMaxNew);
5701:       }
5702: #endif
5703:     }
5704:     /* Hybrid cells have 6 faces: Front, Back, Sides */
5705:     /*
5706:      3---------2---------2
5707:      |         |         |
5708:      |    D    2    C    |
5709:      |         |         |
5710:      3----3----0----1----1
5711:      |         |         |
5712:      |    A    0    B    |
5713:      |         |         |
5714:      0---------0---------1
5715:      */
5716:     for (c = cMax; c < cEnd; ++c) {
5717:       const PetscInt  newp = (cMax - cStart)*8 + (c - cMax)*4;
5718:       const PetscInt *cone, *ornt, *fornt;
5719:       PetscInt        coneNew[6], orntNew[6], o, of, i;

5721:       DMPlexGetCone(dm, c, &cone);
5722:       DMPlexGetConeOrientation(dm, c, &ornt);
5723:       DMPlexGetConeOrientation(dm, cone[0], &fornt);
5724:       o = ornt[0] < 0 ? -1 : 1;
5725:       for (r = 0; r < 4; ++r) {
5726:         PetscInt subfA = GetQuadSubface_Static(ornt[0], r);
5727:         PetscInt edgeA = GetQuadEdge_Static(ornt[0], r);
5728:         PetscInt edgeB = GetQuadEdge_Static(ornt[0], (r+3)%4);
5729:         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]);
5730:         coneNew[0]         = fStartNew + (cone[0] - fStart)*4 + subfA;
5731:         orntNew[0]         = ornt[0];
5732:         coneNew[1]         = fStartNew + (cone[1] - fStart)*4 + subfA;
5733:         orntNew[1]         = ornt[0];
5734:         of = fornt[edgeA] < 0 ? -1 : 1;
5735:         i  = GetQuadEdgeInverse_Static(ornt[0], r) + 2;
5736:         coneNew[i] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (cone[2+edgeA] - fMax)*2 + (o*of < 0 ? 1 : 0);
5737:         orntNew[i] = ornt[edgeA];
5738:         i  = GetQuadEdgeInverse_Static(ornt[0], (r+1)%4) + 2;
5739:         coneNew[i] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd          - fMax)*2 + (c - cMax)*4 + edgeA;
5740:         orntNew[i] = 0;
5741:         i  = GetQuadEdgeInverse_Static(ornt[0], (r+2)%4) + 2;
5742:         coneNew[i] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd          - fMax)*2 + (c - cMax)*4 + edgeB;
5743:         orntNew[i] = -2;
5744:         of = fornt[edgeB] < 0 ? -1 : 1;
5745:         i  = GetQuadEdgeInverse_Static(ornt[0], (r+3)%4) + 2;
5746:         coneNew[i] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (cone[2+edgeB] - fMax)*2 + (o*of < 0 ? 0 : 1);
5747:         orntNew[i] = ornt[edgeB];
5748:         DMPlexSetCone(rdm, newp+r, coneNew);
5749:         DMPlexSetConeOrientation(rdm, newp+r, orntNew);
5750: #if 1
5751:         if ((newp+r < cMaxNew) || (newp+r >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid cell [%d, %d)", newp+r, cMaxNew, cEndNew);
5752:         for (p = 0; p < 2; ++p) {
5753:           if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fMaxNew);
5754:         }
5755:         for (p = 2; p < 6; ++p) {
5756:           if ((coneNew[p] < fMaxNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid face [%d, %d)", coneNew[p], fMaxNew, fEndNew);
5757:         }
5758: #endif
5759:       }
5760:     }
5761:     /* Interior split faces have 4 edges and the same cells as the parent */
5762:     DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);
5763:     PetscMalloc1(4 + maxSupportSize*2, &supportRef);
5764:     for (f = fStart; f < fMax; ++f) {
5765:       for (r = 0; r < 4; ++r) {
5766:         /* TODO: This can come from GetFaces_Internal() */
5767:         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};
5768:         const PetscInt  newp = fStartNew + (f - fStart)*4 + r;
5769:         const PetscInt *cone, *ornt, *support;
5770:         PetscInt        coneNew[4], orntNew[4], coneSize, c, supportSize, s;

5772:         DMPlexGetCone(dm, f, &cone);
5773:         DMPlexGetConeOrientation(dm, f, &ornt);
5774:         coneNew[(r+3)%4] = eStartNew + (cone[(r+3)%4] - eStart)*2 + (ornt[(r+3)%4] < 0 ? 0 : 1);
5775:         orntNew[(r+3)%4] = ornt[(r+3)%4];
5776:         coneNew[(r+0)%4] = eStartNew + (cone[r]       - eStart)*2 + (ornt[r] < 0 ? 1 : 0);
5777:         orntNew[(r+0)%4] = ornt[r];
5778:         coneNew[(r+1)%4] = eStartNew + (eMax - eStart)*2 + (f - fStart)*4 + r;
5779:         orntNew[(r+1)%4] = 0;
5780:         coneNew[(r+2)%4] = eStartNew + (eMax - eStart)*2 + (f - fStart)*4 + (r+3)%4;
5781:         orntNew[(r+2)%4] = -2;
5782:         DMPlexSetCone(rdm, newp, coneNew);
5783:         DMPlexSetConeOrientation(rdm, newp, orntNew);
5784: #if 1
5785:         if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
5786:         for (p = 0; p < 4; ++p) {
5787:           if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eMaxNew);
5788:         }
5789: #endif
5790:         DMPlexGetSupportSize(dm, f, &supportSize);
5791:         DMPlexGetSupport(dm, f, &support);
5792:         for (s = 0; s < supportSize; ++s) {
5793:           PetscInt subf;
5794:           DMPlexGetConeSize(dm, support[s], &coneSize);
5795:           DMPlexGetCone(dm, support[s], &cone);
5796:           DMPlexGetConeOrientation(dm, support[s], &ornt);
5797:           for (c = 0; c < coneSize; ++c) {
5798:             if (cone[c] == f) break;
5799:           }
5800:           subf = GetQuadSubfaceInverse_Static(ornt[c], r);
5801:           if (support[s] < cMax) {
5802:             supportRef[s] = cStartNew + (support[s] - cStart)*8 + newCells[c*4+subf];
5803:           } else {
5804:             supportRef[s] = cStartNew + (cMax       - cStart)*8 + (support[s] - cMax)*4 + subf;
5805:           }
5806:         }
5807:         DMPlexSetSupport(rdm, newp, supportRef);
5808: #if 1
5809:         if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
5810:         for (p = 0; p < supportSize; ++p) {
5811:           if ((supportRef[p] < cStartNew) || (supportRef[p] >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportRef[p], cStartNew, cEndNew);
5812:         }
5813: #endif
5814:       }
5815:     }
5816:     /* Interior cell faces have 4 edges and 2 cells */
5817:     for (c = cStart; c < cMax; ++c) {
5818:       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};
5819:       const PetscInt *cone, *ornt;
5820:       PetscInt        newp, coneNew[4], orntNew[4], supportNew[2];

5822:       DMPlexGetCone(dm, c, &cone);
5823:       DMPlexGetConeOrientation(dm, c, &ornt);
5824:       /* A-D face */
5825:       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 0;
5826:       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*4 + GetQuadEdge_Static(ornt[0], 3);
5827:       orntNew[0] = 0;
5828:       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 0;
5829:       orntNew[1] = 0;
5830:       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 2;
5831:       orntNew[2] = -2;
5832:       coneNew[3] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*4 + GetQuadEdge_Static(ornt[2], 0);
5833:       orntNew[3] = -2;
5834:       DMPlexSetCone(rdm, newp, coneNew);
5835:       DMPlexSetConeOrientation(rdm, newp, orntNew);
5836: #if 1
5837:       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
5838:       for (p = 0; p < 4; ++p) {
5839:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eMaxNew);
5840:       }
5841: #endif
5842:       /* C-D face */
5843:       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 1;
5844:       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*4 + GetQuadEdge_Static(ornt[0], 2);
5845:       orntNew[0] = 0;
5846:       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 0;
5847:       orntNew[1] = 0;
5848:       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 4;
5849:       orntNew[2] = -2;
5850:       coneNew[3] = eStartNew + (eMax - eStart)*2 + (cone[4] - fStart)*4 + GetQuadEdge_Static(ornt[4], 0);
5851:       orntNew[3] = -2;
5852:       DMPlexSetCone(rdm, newp, coneNew);
5853:       DMPlexSetConeOrientation(rdm, newp, orntNew);
5854: #if 1
5855:       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
5856:       for (p = 0; p < 4; ++p) {
5857:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eMaxNew);
5858:       }
5859: #endif
5860:       /* B-C face */
5861:       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 2;
5862:       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*4 + GetQuadEdge_Static(ornt[0], 1);
5863:       orntNew[0] = -2;
5864:       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*4 + GetQuadEdge_Static(ornt[3], 0);
5865:       orntNew[1] = 0;
5866:       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 3;
5867:       orntNew[2] = 0;
5868:       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 0;
5869:       orntNew[3] = -2;
5870:       DMPlexSetCone(rdm, newp, coneNew);
5871:       DMPlexSetConeOrientation(rdm, newp, orntNew);
5872: #if 1
5873:       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
5874:       for (p = 0; p < 4; ++p) {
5875:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eMaxNew);
5876:       }
5877: #endif
5878:       /* A-B face */
5879:       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 3;
5880:       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*4 + GetQuadEdge_Static(ornt[0], 0);
5881:       orntNew[0] = -2;
5882:       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[5] - fStart)*4 + GetQuadEdge_Static(ornt[5], 3);
5883:       orntNew[1] = 0;
5884:       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 5;
5885:       orntNew[2] = 0;
5886:       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 0;
5887:       orntNew[3] = -2;
5888:       DMPlexSetCone(rdm, newp, coneNew);
5889:       DMPlexSetConeOrientation(rdm, newp, orntNew);
5890: #if 1
5891:       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
5892:       for (p = 0; p < 4; ++p) {
5893:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eMaxNew);
5894:       }
5895: #endif
5896:       /* E-F face */
5897:       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 4;
5898:       coneNew[0] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 2;
5899:       orntNew[0] = -2;
5900:       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*4 + GetQuadEdge_Static(ornt[2], 2);
5901:       orntNew[1] = -2;
5902:       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*4 + GetQuadEdge_Static(ornt[1], 0);
5903:       orntNew[2] = 0;
5904:       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 1;
5905:       orntNew[3] = 0;
5906:       DMPlexSetCone(rdm, newp, coneNew);
5907:       DMPlexSetConeOrientation(rdm, newp, orntNew);
5908: #if 1
5909:       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
5910:       for (p = 0; p < 4; ++p) {
5911:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eMaxNew);
5912:       }
5913: #endif
5914:       /* F-G face */
5915:       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 5;
5916:       coneNew[0] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 4;
5917:       orntNew[0] = -2;
5918:       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[4] - fStart)*4 + GetQuadEdge_Static(ornt[4], 2);
5919:       orntNew[1] = -2;
5920:       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*4 + GetQuadEdge_Static(ornt[1], 1);
5921:       orntNew[2] = 0;
5922:       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 1;
5923:       orntNew[3] = 0;
5924:       DMPlexSetCone(rdm, newp, coneNew);
5925:       DMPlexSetConeOrientation(rdm, newp, orntNew);
5926: #if 1
5927:       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
5928:       for (p = 0; p < 4; ++p) {
5929:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eMaxNew);
5930:       }
5931: #endif
5932:       /* G-H face */
5933:       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 6;
5934:       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*4 + GetQuadEdge_Static(ornt[3], 2);
5935:       orntNew[0] = -2;
5936:       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*4 + GetQuadEdge_Static(ornt[1], 2);
5937:       orntNew[1] = 0;
5938:       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 1;
5939:       orntNew[2] = 0;
5940:       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 3;
5941:       orntNew[3] = -2;
5942:       DMPlexSetCone(rdm, newp, coneNew);
5943:       DMPlexSetConeOrientation(rdm, newp, orntNew);
5944: #if 1
5945:       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
5946:       for (p = 0; p < 4; ++p) {
5947:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eMaxNew);
5948:       }
5949: #endif
5950:       /* E-H face */
5951:       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 7;
5952:       coneNew[0] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 5;
5953:       orntNew[0] = -2;
5954:       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[5] - fStart)*4 + GetQuadEdge_Static(ornt[5], 1);
5955:       orntNew[1] = -2;
5956:       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*4 + GetQuadEdge_Static(ornt[1], 3);
5957:       orntNew[2] = 0;
5958:       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 1;
5959:       orntNew[3] = 0;
5960:       DMPlexSetCone(rdm, newp, coneNew);
5961:       DMPlexSetConeOrientation(rdm, newp, orntNew);
5962: #if 1
5963:       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
5964:       for (p = 0; p < 4; ++p) {
5965:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eMaxNew);
5966:       }
5967: #endif
5968:       /* A-E face */
5969:       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 8;
5970:       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*4 + GetQuadEdge_Static(ornt[2], 3);
5971:       orntNew[0] = 0;
5972:       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 2;
5973:       orntNew[1] = 0;
5974:       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 5;
5975:       orntNew[2] = -2;
5976:       coneNew[3] = eStartNew + (eMax - eStart)*2 + (cone[5] - fStart)*4 + GetQuadEdge_Static(ornt[5], 0);
5977:       orntNew[3] = -2;
5978:       DMPlexSetCone(rdm, newp, coneNew);
5979:       DMPlexSetConeOrientation(rdm, newp, orntNew);
5980: #if 1
5981:       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
5982:       for (p = 0; p < 4; ++p) {
5983:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eMaxNew);
5984:       }
5985: #endif
5986:       /* D-F face */
5987:       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 9;
5988:       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*4 + GetQuadEdge_Static(ornt[2], 1);
5989:       orntNew[0] = -2;
5990:       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[4] - fStart)*4 + GetQuadEdge_Static(ornt[4], 3);
5991:       orntNew[1] = 0;
5992:       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 4;
5993:       orntNew[2] = 0;
5994:       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 2;
5995:       orntNew[3] = -2;
5996:       DMPlexSetCone(rdm, newp, coneNew);
5997:       DMPlexSetConeOrientation(rdm, newp, orntNew);
5998: #if 1
5999:       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
6000:       for (p = 0; p < 4; ++p) {
6001:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eMaxNew);
6002:       }
6003: #endif
6004:       /* C-G face */
6005:       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 10;
6006:       coneNew[0] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 4;
6007:       orntNew[0] = -2;
6008:       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[4] - fStart)*4 + GetQuadEdge_Static(ornt[4], 1);
6009:       orntNew[1] = -2;
6010:       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*4 + GetQuadEdge_Static(ornt[3], 3);
6011:       orntNew[2] = 0;
6012:       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 3;
6013:       orntNew[3] = 0;
6014:       DMPlexSetCone(rdm, newp, coneNew);
6015:       DMPlexSetConeOrientation(rdm, newp, orntNew);
6016: #if 1
6017:       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
6018:       for (p = 0; p < 4; ++p) {
6019:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eMaxNew);
6020:       }
6021: #endif
6022:       /* B-H face */
6023:       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 11;
6024:       coneNew[0] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 5;
6025:       orntNew[0] = 0;
6026:       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 3;
6027:       orntNew[1] = -2;
6028:       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*4 + GetQuadEdge_Static(ornt[3], 1);
6029:       orntNew[2] = -2;
6030:       coneNew[3] = eStartNew + (eMax - eStart)*2 + (cone[5] - fStart)*4 + GetQuadEdge_Static(ornt[5], 2);
6031:       orntNew[3] = 0;
6032:       DMPlexSetCone(rdm, newp, coneNew);
6033:       DMPlexSetConeOrientation(rdm, newp, orntNew);
6034: #if 1
6035:       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
6036:       for (p = 0; p < 4; ++p) {
6037:         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eMaxNew);
6038:       }
6039: #endif
6040:       for (r = 0; r < 12; ++r) {
6041:         newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + r;
6042:         supportNew[0] = cStartNew + (c - cStart)*8 + newCells[r*2+0];
6043:         supportNew[1] = cStartNew + (c - cStart)*8 + newCells[r*2+1];
6044:         DMPlexSetSupport(rdm, newp, supportNew);
6045: #if 1
6046:         if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
6047:         for (p = 0; p < 2; ++p) {
6048:           if ((supportNew[p] < cStartNew) || (supportNew[p] >= cMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cMaxNew);
6049:         }
6050: #endif
6051:       }
6052:     }
6053:     /* Hybrid split faces have 4 edges and same cells */
6054:     for (f = fMax; f < fEnd; ++f) {
6055:       const PetscInt *cone, *ornt, *support;
6056:       PetscInt        coneNew[4], orntNew[4];
6057:       PetscInt        supportNew[2], size, s, c;

6059:       DMPlexGetCone(dm, f, &cone);
6060:       DMPlexGetConeOrientation(dm, f, &ornt);
6061:       DMPlexGetSupportSize(dm, f, &size);
6062:       DMPlexGetSupport(dm, f, &support);
6063:       for (r = 0; r < 2; ++r) {
6064:         const PetscInt newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (f - fMax)*2 + r;

6066:         coneNew[0]   = eStartNew + (cone[0] - eStart)*2 + (ornt[0] < 0 ? 1-r : r);
6067:         orntNew[0]   = ornt[0];
6068:         coneNew[1]   = eStartNew + (cone[1] - eStart)*2 + (ornt[1] < 0 ? 1-r : r);
6069:         orntNew[1]   = ornt[1];
6070:         coneNew[2+r] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (cone[2+r] - eMax);
6071:         orntNew[2+r] = 0;
6072:         coneNew[3-r] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (eEnd      - eMax) + (f - fMax);
6073:         orntNew[3-r] = 0;
6074:         DMPlexSetCone(rdm, newp, coneNew);
6075:         DMPlexSetConeOrientation(rdm, newp, orntNew);
6076: #if 1
6077:         if ((newp < fMaxNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid face [%d, %d)", newp, fMaxNew, fEndNew);
6078:         for (p = 0; p < 2; ++p) {
6079:           if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eMaxNew);
6080:         }
6081:         for (p = 2; p < 4; ++p) {
6082:           if ((coneNew[p] < eMaxNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid edge [%d, %d)", coneNew[p], eMaxNew, eEndNew);
6083:         }
6084: #endif
6085:         for (s = 0; s < size; ++s) {
6086:           const PetscInt *coneCell, *orntCell, *fornt;
6087:           PetscInt        o, of;

6089:           DMPlexGetCone(dm, support[s], &coneCell);
6090:           DMPlexGetConeOrientation(dm, support[s], &orntCell);
6091:           o = orntCell[0] < 0 ? -1 : 1;
6092:           for (c = 2; c < 6; ++c) if (coneCell[c] == f) break;
6093:           if (c >= 6) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Could not find face %d in cone of cell %d", f, support[s]);
6094:           DMPlexGetConeOrientation(dm, coneCell[0], &fornt);
6095:           of = fornt[c-2] < 0 ? -1 : 1;
6096:           supportNew[s] = cStartNew + (cMax - cStart)*8 + (support[s] - cMax)*4 + (GetQuadEdgeInverse_Static(orntCell[0], c-2) + (o*of < 0 ? 1-r : r))%4;
6097:         }
6098:         DMPlexSetSupport(rdm, newp, supportNew);
6099: #if 1
6100:         if ((newp < fMaxNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid face [%d, %d)", newp, fMaxNew, fEndNew);
6101:         for (p = 0; p < size; ++p) {
6102:           if ((supportNew[p] < cMaxNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid cell [%d, %d)", supportNew[p], cMaxNew, cEndNew);
6103:         }
6104: #endif
6105:       }
6106:     }
6107:     /* Hybrid cell faces have 4 edges and 2 cells */
6108:     for (c = cMax; c < cEnd; ++c) {
6109:       PetscInt        newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd - fMax)*2 + (c - cMax)*4;
6110:       const PetscInt *cone, *ornt;
6111:       PetscInt        coneNew[4], orntNew[4];
6112:       PetscInt        supportNew[2];

6114:       DMPlexGetCone(dm, c, &cone);
6115:       DMPlexGetConeOrientation(dm, c, &ornt);
6116:       for (r = 0; r < 4; ++r) {
6117: #if 0
6118:         coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], r);
6119:         orntNew[0] = 0;
6120:         coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], r);
6121:         orntNew[1] = 0;
6122:         coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (eEnd - eMax) + (cone[2+GetQuadEdge_Static(ornt[0], r)] - fMax);
6123:         orntNew[2] = 0;
6124:         coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (eEnd - eMax) + (fEnd                                   - fMax) + (c - cMax);
6125:         orntNew[3] = 0;
6126: #else
6127:         coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*4 + r;
6128:         orntNew[0] = 0;
6129:         coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*4 + r;
6130:         orntNew[1] = 0;
6131:         coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (eEnd - eMax) + (cone[2+r] - fMax);
6132:         orntNew[2] = 0;
6133:         coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (eEnd - eMax) + (fEnd      - fMax) + (c - cMax);
6134:         orntNew[3] = 0;
6135: #endif
6136:         DMPlexSetCone(rdm, newp+r, coneNew);
6137:         DMPlexSetConeOrientation(rdm, newp+r, orntNew);
6138: #if 1
6139:         if ((newp+r < fMaxNew) || (newp+r >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid face [%d, %d)", newp+r, fMaxNew, fEndNew);
6140:         for (p = 0; p < 2; ++p) {
6141:           if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eMaxNew);
6142:         }
6143:         for (p = 2; p < 4; ++p) {
6144:           if ((coneNew[p] < eMaxNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid edge [%d, %d)", coneNew[p], eMaxNew, eEndNew);
6145:         }
6146: #endif
6147:         supportNew[0] = cStartNew + (cMax - cStart)*8 + (c - cMax)*4 + GetQuadSubface_Static(ornt[0], r);
6148:         supportNew[1] = cStartNew + (cMax - cStart)*8 + (c - cMax)*4 + GetQuadSubface_Static(ornt[0], (r+1)%4);
6149:         DMPlexSetSupport(rdm, newp+r, supportNew);
6150: #if 1
6151:         if ((newp+r < fMaxNew) || (newp+r >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid face [%d, %d)", newp+r, fMaxNew, fEndNew);
6152:         for (p = 0; p < 2; ++p) {
6153:           if ((supportNew[p] < cMaxNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid cell [%d, %d)", supportNew[p], cMaxNew, cEndNew);
6154:         }
6155: #endif
6156:       }
6157:     }
6158:     /* Interior split edges have 2 vertices and the same faces as the parent */
6159:     DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);
6160:     for (e = eStart; e < eMax; ++e) {
6161:       const PetscInt newv = vStartNew + (vEnd - vStart) + (e - eStart);

6163:       for (r = 0; r < 2; ++r) {
6164:         const PetscInt  newp = eStartNew + (e - eStart)*2 + r;
6165:         const PetscInt *cone, *ornt, *support;
6166:         PetscInt        coneNew[2], coneSize, c, supportSize, s;

6168:         DMPlexGetCone(dm, e, &cone);
6169:         coneNew[0]       = vStartNew + (cone[0] - vStart);
6170:         coneNew[1]       = vStartNew + (cone[1] - vStart);
6171:         coneNew[(r+1)%2] = newv;
6172:         DMPlexSetCone(rdm, newp, coneNew);
6173: #if 1
6174:         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
6175:         for (p = 0; p < 2; ++p) {
6176:           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
6177:         }
6178: #endif
6179:         DMPlexGetSupportSize(dm, e, &supportSize);
6180:         DMPlexGetSupport(dm, e, &support);
6181:         for (s = 0; s < supportSize; ++s) {
6182:           DMPlexGetConeSize(dm, support[s], &coneSize);
6183:           DMPlexGetCone(dm, support[s], &cone);
6184:           DMPlexGetConeOrientation(dm, support[s], &ornt);
6185:           for (c = 0; c < coneSize; ++c) {
6186:             if (cone[c] == e) break;
6187:           }
6188:           if (support[s] < fMax) {
6189:             supportRef[s] = fStartNew + (support[s] - fStart)*4 + (c + (ornt[c] < 0 ? 1-r : r))%4;
6190:           } else {
6191:             supportRef[s] = fStartNew + (fMax       - fStart)*4 + (cMax - cStart)*12 + (support[s] - fMax)*2 + (ornt[c] < 0 ? 1-r : r);
6192:           }
6193:         }
6194:         DMPlexSetSupport(rdm, newp, supportRef);
6195: #if 1
6196:         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
6197:         for (p = 0; p < supportSize; ++p) {
6198:           if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", supportRef[p], fStartNew, fEndNew);
6199:         }
6200: #endif
6201:       }
6202:     }
6203:     /* Interior face edges have 2 vertices and 2+cells faces */
6204:     for (f = fStart; f < fMax; ++f) {
6205:       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};
6206:       const PetscInt  newv = vStartNew + (vEnd - vStart) + (eMax - eStart) + (f - fStart);
6207:       const PetscInt *cone, *coneCell, *orntCell, *support;
6208:       PetscInt        coneNew[2], coneSize, c, supportSize, s;

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

6214:         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r] - eStart);
6215:         coneNew[1] = newv;
6216:         DMPlexSetCone(rdm, newp, coneNew);
6217: #if 1
6218:         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
6219:         for (p = 0; p < 2; ++p) {
6220:           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
6221:         }
6222: #endif
6223:         DMPlexGetSupportSize(dm, f, &supportSize);
6224:         DMPlexGetSupport(dm, f, &support);
6225:         supportRef[0] = fStartNew + (f - fStart)*4 + r;
6226:         supportRef[1] = fStartNew + (f - fStart)*4 + (r+1)%4;
6227:         for (s = 0; s < supportSize; ++s) {
6228:           DMPlexGetConeSize(dm, support[s], &coneSize);
6229:           DMPlexGetCone(dm, support[s], &coneCell);
6230:           DMPlexGetConeOrientation(dm, support[s], &orntCell);
6231:           for (c = 0; c < coneSize; ++c) if (coneCell[c] == f) break;
6232:           if (support[s] < cMax) {
6233:             supportRef[2+s] = fStartNew + (fMax - fStart)*4 + (support[s] - cStart)*12 + newFaces[c*4 + GetQuadEdgeInverse_Static(orntCell[c], r)];
6234:           } else {
6235:             supportRef[2+s] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd - fMax)*2 + (support[s] - cMax)*4 + r;
6236:           }
6237:         }
6238:         DMPlexSetSupport(rdm, newp, supportRef);
6239: #if 1
6240:         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
6241:         for (p = 0; p < 2+supportSize; ++p) {
6242:           if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", supportRef[p], fStartNew, fEndNew);
6243:         }
6244: #endif
6245:       }
6246:     }
6247:     /* Interior cell edges have 2 vertices and 4 faces */
6248:     for (c = cStart; c < cMax; ++c) {
6249:       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};
6250:       const PetscInt  newv = vStartNew + (vEnd - vStart) + (eMax - eStart) + (fMax - fStart) + (c - cStart);
6251:       const PetscInt *cone;
6252:       PetscInt        coneNew[2], supportNew[4];

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

6258:         coneNew[0] = vStartNew + (vEnd - vStart) + (eMax - eStart) + (cone[r] - fStart);
6259:         coneNew[1] = newv;
6260:         DMPlexSetCone(rdm, newp, coneNew);
6261: #if 1
6262:         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
6263:         for (p = 0; p < 2; ++p) {
6264:           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
6265:         }
6266: #endif
6267:         for (f = 0; f < 4; ++f) supportNew[f] = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + newFaces[r*4+f];
6268:         DMPlexSetSupport(rdm, newp, supportNew);
6269: #if 1
6270:         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
6271:         for (p = 0; p < 4; ++p) {
6272:           if ((supportNew[p] < fStartNew) || (supportNew[p] >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", supportNew[p], fStartNew, fMaxNew);
6273:         }
6274: #endif
6275:       }
6276:     }
6277:     /* Hybrid edges have two vertices and the same faces */
6278:     for (e = eMax; e < eEnd; ++e) {
6279:       const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (e - eMax);
6280:       const PetscInt *cone, *support, *fcone;
6281:       PetscInt        coneNew[2], size, fsize, s;

6283:       DMPlexGetCone(dm, e, &cone);
6284:       DMPlexGetSupportSize(dm, e, &size);
6285:       DMPlexGetSupport(dm, e, &support);
6286:       coneNew[0] = vStartNew + (cone[0] - vStart);
6287:       coneNew[1] = vStartNew + (cone[1] - vStart);
6288:       DMPlexSetCone(rdm, newp, coneNew);
6289: #if 1
6290:       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid edge [%d, %d)", newp, eMaxNew, eEndNew);
6291:       for (p = 0; p < 2; ++p) {
6292:         if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
6293:       }
6294: #endif
6295:       for (s = 0; s < size; ++s) {
6296:         DMPlexGetConeSize(dm, support[s], &fsize);
6297:         DMPlexGetCone(dm, support[s], &fcone);
6298:         for (c = 0; c < fsize; ++c) if (fcone[c] == e) break;
6299:         if ((c < 2) || (c > 3)) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Edge %d not found in cone of face %d", e, support[s]);
6300:         supportRef[s] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (support[s] - fMax)*2 + c-2;
6301:       }
6302:       DMPlexSetSupport(rdm, newp, supportRef);
6303: #if 1
6304:       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid edge [%d, %d)", newp, eMaxNew, eEndNew);
6305:       for (p = 0; p < size; ++p) {
6306:         if ((supportRef[p] < fMaxNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid face [%d, %d)", supportRef[p], fMaxNew, fEndNew);
6307:       }
6308: #endif
6309:     }
6310:     /* Hybrid face edges have 2 vertices and 2+cells faces */
6311:     for (f = fMax; f < fEnd; ++f) {
6312:       const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (eEnd - eMax) + (f - fMax);
6313:       const PetscInt *cone, *support, *ccone, *cornt;
6314:       PetscInt        coneNew[2], size, csize, s;

6316:       DMPlexGetCone(dm, f, &cone);
6317:       DMPlexGetSupportSize(dm, f, &size);
6318:       DMPlexGetSupport(dm, f, &support);
6319:       coneNew[0] = vStartNew + (vEnd - vStart) + (cone[0] - eStart);
6320:       coneNew[1] = vStartNew + (vEnd - vStart) + (cone[1] - eStart);
6321:       DMPlexSetCone(rdm, newp, coneNew);
6322: #if 1
6323:       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid edge [%d, %d)", newp, eMaxNew, eEndNew);
6324:       for (p = 0; p < 2; ++p) {
6325:         if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
6326:       }
6327: #endif
6328:       supportRef[0] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (f - fMax)*2 + 0;
6329:       supportRef[1] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (f - fMax)*2 + 1;
6330:       for (s = 0; s < size; ++s) {
6331:         DMPlexGetConeSize(dm, support[s], &csize);
6332:         DMPlexGetCone(dm, support[s], &ccone);
6333:         DMPlexGetConeOrientation(dm, support[s], &cornt);
6334:         for (c = 0; c < csize; ++c) if (ccone[c] == f) break;
6335:         if ((c < 2) || (c >= csize)) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Hybrid face %d is not in cone of hybrid cell %d", f, support[s]);
6336:         supportRef[2+s] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd - fMax)*2 + (support[s] - cMax)*4 + c-2;
6337:       }
6338:       DMPlexSetSupport(rdm, newp, supportRef);
6339: #if 1
6340:       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid edge [%d, %d)", newp, eMaxNew, eEndNew);
6341:       for (p = 0; p < 2+size; ++p) {
6342:         if ((supportRef[p] < fMaxNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid face [%d, %d)", supportRef[p], fMaxNew, fEndNew);
6343:       }
6344: #endif
6345:     }
6346:     /* Hybrid cell edges have 2 vertices and 4 faces */
6347:     for (c = cMax; c < cEnd; ++c) {
6348:       const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (eEnd - eMax) + (fEnd - fMax) + (c - cMax);
6349:       const PetscInt *cone, *support;
6350:       PetscInt        coneNew[2], size;

6352:       DMPlexGetCone(dm, c, &cone);
6353:       DMPlexGetSupportSize(dm, c, &size);
6354:       DMPlexGetSupport(dm, c, &support);
6355:       coneNew[0] = vStartNew + (vEnd - vStart) + (eMax - eStart) + (cone[0] - fStart);
6356:       coneNew[1] = vStartNew + (vEnd - vStart) + (eMax - eStart) + (cone[1] - fStart);
6357:       DMPlexSetCone(rdm, newp, coneNew);
6358: #if 1
6359:       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid edge [%d, %d)", newp, eMaxNew, eEndNew);
6360:       for (p = 0; p < 2; ++p) {
6361:         if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
6362:       }
6363: #endif
6364:       supportRef[0] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd - fMax)*2 + (c - cMax)*4 + 0;
6365:       supportRef[1] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd - fMax)*2 + (c - cMax)*4 + 1;
6366:       supportRef[2] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd - fMax)*2 + (c - cMax)*4 + 2;
6367:       supportRef[3] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd - fMax)*2 + (c - cMax)*4 + 3;
6368:       DMPlexSetSupport(rdm, newp, supportRef);
6369: #if 1
6370:       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid edge [%d, %d)", newp, eMaxNew, eEndNew);
6371:       for (p = 0; p < 4; ++p) {
6372:         if ((supportRef[p] < fMaxNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid face [%d, %d)", supportRef[p], fMaxNew, fEndNew);
6373:       }
6374: #endif
6375:     }
6376:     /* Interior vertices have identical supports */
6377:     for (v = vStart; v < vEnd; ++v) {
6378:       const PetscInt  newp = vStartNew + (v - vStart);
6379:       const PetscInt *support, *cone;
6380:       PetscInt        size, s;

6382:       DMPlexGetSupportSize(dm, v, &size);
6383:       DMPlexGetSupport(dm, v, &support);
6384:       for (s = 0; s < size; ++s) {
6385:         PetscInt r = 0;

6387:         DMPlexGetCone(dm, support[s], &cone);
6388:         if (cone[1] == v) r = 1;
6389:         if (support[s] < eMax) supportRef[s] = eStartNew + (support[s] - eStart)*2 + r;
6390:         else                   supportRef[s] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (support[s] - eMax);
6391:       }
6392:       DMPlexSetSupport(rdm, newp, supportRef);
6393: #if 1
6394:       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
6395:       for (p = 0; p < size; ++p) {
6396:         if ((supportRef[p] < eStartNew) || (supportRef[p] >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", supportRef[p], eStartNew, eEndNew);
6397:       }
6398: #endif
6399:     }
6400:     /* Interior edge vertices have 2 + faces supports */
6401:     for (e = eStart; e < eMax; ++e) {
6402:       const PetscInt  newp = vStartNew + (vEnd - vStart) + (e - eStart);
6403:       const PetscInt *cone, *support;
6404:       PetscInt        size, s;

6406:       DMPlexGetSupportSize(dm, e, &size);
6407:       DMPlexGetSupport(dm, e, &support);
6408:       supportRef[0] = eStartNew + (e - eStart)*2 + 0;
6409:       supportRef[1] = eStartNew + (e - eStart)*2 + 1;
6410:       for (s = 0; s < size; ++s) {
6411:         PetscInt r;

6413:         DMPlexGetCone(dm, support[s], &cone);
6414:         for (r = 0; r < 4; ++r) if (cone[r] == e) break;
6415:         if (support[s] < fMax) {
6416:           supportRef[2+s] = eStartNew + (eMax - eStart)*2 + (support[s] - fStart)*4 + r;
6417:         } else {
6418:           supportRef[2+s] = eStartNew + (eMax - eStart)*2 + (fMax       - fStart)*4 + (cMax - cStart)*6 + (eEnd - eMax) + (support[s] - fMax);
6419:         }
6420:       }
6421:       DMPlexSetSupport(rdm, newp, supportRef);
6422: #if 1
6423:       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
6424:       for (p = 0; p < 2+size; ++p) {
6425:         if ((supportRef[p] < eStartNew) || (supportRef[p] >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", supportRef[p], eStartNew, eEndNew);
6426:       }
6427: #endif
6428:     }
6429:     /* Interior face vertices have 4 + cells supports */
6430:     for (f = fStart; f < fMax; ++f) {
6431:       const PetscInt  newp = vStartNew + (vEnd - vStart) + (eMax - eStart) + (f - fStart);
6432:       const PetscInt *cone, *support;
6433:       PetscInt        size, s;

6435:       DMPlexGetSupportSize(dm, f, &size);
6436:       DMPlexGetSupport(dm, f, &support);
6437:       for (r = 0; r < 4; ++r) supportRef[r] = eStartNew + (eMax - eStart)*2 +  (f - fStart)*4 + r;
6438:       for (s = 0; s < size; ++s) {
6439:         PetscInt r;

6441:         DMPlexGetCone(dm, support[s], &cone);
6442:         for (r = 0; r < 6; ++r) if (cone[r] == f) break;
6443:         if (support[s] < cMax) {
6444:           supportRef[4+s] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (support[s] - cStart)*6 + r;
6445:         } else {
6446:           supportRef[4+s] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax       - cStart)*6 + (eEnd - eMax) + (fEnd - fMax) + (support[s] - cMax);
6447:         }
6448:       }
6449:       DMPlexSetSupport(rdm, newp, supportRef);
6450: #if 1
6451:       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
6452:       for (p = 0; p < 4+size; ++p) {
6453:         if ((supportRef[p] < eStartNew) || (supportRef[p] >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", supportRef[p], eStartNew, eEndNew);
6454:       }
6455: #endif
6456:     }
6457:     /* Cell vertices have 6 supports */
6458:     for (c = cStart; c < cMax; ++c) {
6459:       const PetscInt newp = vStartNew + (vEnd - vStart) + (eMax - eStart) + (fMax - fStart) + (c - cStart);
6460:       PetscInt       supportNew[6];

6462:       for (r = 0; r < 6; ++r) {
6463:         supportNew[r] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (c - cStart)*6 + r;
6464:       }
6465:       DMPlexSetSupport(rdm, newp, supportNew);
6466:     }
6467:     PetscFree(supportRef);
6468:     break;
6469:   default:
6470:     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
6471:   }
6472:   return(0);
6473: }

6475: static PetscErrorCode CellRefinerSetCoordinates(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
6476: {
6477:   PetscSection          coordSection, coordSectionNew;
6478:   Vec                   coordinates, coordinatesNew;
6479:   PetscScalar          *coords, *coordsNew;
6480:   const PetscInt        numVertices = depthSize ? depthSize[0] : 0;
6481:   PetscInt              dim, spaceDim, depth, bs, coordSizeNew, cStart, cEnd, cMax;
6482:   PetscInt              c, vStart, vStartNew, vEnd, v, eStart, eEnd, eMax, e, fStart, fEnd, fMax, f;
6483:   PetscInt              cStartNew, cEndNew, vEndNew, *parentId = NULL;
6484:   VecType               vtype;
6485:   PetscBool             isperiodic, localize = PETSC_FALSE, needcoords = PETSC_FALSE;
6486:   const PetscReal      *maxCell, *L;
6487:   const DMBoundaryType *bd;
6488:   PetscErrorCode        ierr;

6491:   DMGetDimension(dm, &dim);
6492:   DMPlexGetDepth(dm, &depth);
6493:   DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);
6494:   DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);
6495:   DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);
6496:   DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);
6497:   DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, NULL);
6498:   GetDepthStart_Private(depth, depthSize, &cStartNew, NULL, NULL, &vStartNew);
6499:   GetDepthEnd_Private(depth, depthSize, &cEndNew, NULL, NULL, &vEndNew);
6500:   DMGetPeriodicity(dm, &isperiodic, &maxCell, &L, &bd);
6501:   /* Determine if we need to localize coordinates when generating them */
6502:   if (isperiodic && !maxCell) {
6503:     DMGetCoordinatesLocalized(dm, &localize);
6504:     if (!localize) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_USER,"Cannot refine if coordinates have not been localized");
6505:   }
6506:   if (isperiodic) {
6507:     PetscOptionsBegin(PetscObjectComm((PetscObject)dm),((PetscObject)dm)->prefix,"DMPlex coords refinement options","DM");
6508:     PetscOptionsBool("-dm_plex_refine_localize","Automatically localize from parent cells",NULL,localize,&localize,NULL);
6509:     PetscOptionsEnd();
6510:     if (localize) {
6511:       DMLocalizeCoordinates(dm);
6512:     }
6513:   }
6514:   DMSetPeriodicity(rdm, isperiodic,  maxCell,  L,  bd);

6516:   DMGetCoordinateSection(dm, &coordSection);
6517:   PetscSectionGetFieldComponents(coordSection, 0, &spaceDim);
6518:   PetscSectionCreate(PetscObjectComm((PetscObject)dm), &coordSectionNew);
6519:   PetscSectionSetNumFields(coordSectionNew, 1);
6520:   PetscSectionSetFieldComponents(coordSectionNew, 0, spaceDim);

6522:   if (localize) {
6523:     PetscInt p, r, newp, *pi;

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

6528:     /* We need the parentId to properly localize coordinates */
6529:     PetscMalloc1(cEndNew-cStartNew,&pi);
6530:     switch (refiner) {
6531:     case REFINER_NOOP:
6532:       break;
6533:     case REFINER_SIMPLEX_1D:
6534:       for (p = cStart; p < cEnd; ++p) {
6535:         for (r = 0; r < 2; ++r) {
6536:           newp     = (p - cStart)*2 + r;
6537:           pi[newp] = p;
6538:         }
6539:       }
6540:       break;
6541:     case REFINER_SIMPLEX_2D:
6542:       for (p = cStart; p < cEnd; ++p) {
6543:         for (r = 0; r < 4; ++r) {
6544:           newp     = (p - cStart)*4 + r;
6545:           pi[newp] = p;
6546:         }
6547:       }
6548:       break;
6549:     case REFINER_HEX_2D:
6550:       for (p = cStart; p < cEnd; ++p) {
6551:         for (r = 0; r < 4; ++r) {
6552:           newp     = (p - cStart)*4 + r;
6553:           pi[newp] = p;
6554:         }
6555:       }
6556:       break;
6557:     case REFINER_SIMPLEX_TO_HEX_2D:
6558:       for (p = cStart; p < cEnd; ++p) {
6559:         for (r = 0; r < 3; ++r) {
6560:           newp     = (p - cStart)*3 + r;
6561:           pi[newp] = p;
6562:         }
6563:       }
6564:       break;
6565:     case REFINER_HYBRID_SIMPLEX_2D:
6566:       for (p = cStart; p < cMax; ++p) {
6567:         for (r = 0; r < 4; ++r) {
6568:           newp     = (p - cStart)*4 + r;
6569:           pi[newp] = p;
6570:         }
6571:       }
6572:       for (p = cMax; p < cEnd; ++p) {
6573:         for (r = 0; r < 2; ++r) {
6574:           newp     = (cMax - cStart)*4 + (p - cMax)*2 + r;
6575:           pi[newp] = p;
6576:         }
6577:       }
6578:       break;
6579:     case REFINER_HYBRID_HEX_2D:
6580:       for (p = cStart; p < cMax; ++p) {
6581:         for (r = 0; r < 4; ++r) {
6582:           newp     = (p - cStart)*4 + r;
6583:           pi[newp] = p;
6584:         }
6585:       }
6586:       for (p = cMax; p < cEnd; ++p) {
6587:         for (r = 0; r < 2; ++r) {
6588:           newp     = (cMax - cStart)*4 + (p - cMax)*2 + r;
6589:           pi[newp] = p;
6590:         }
6591:       }
6592:       break;
6593:     case REFINER_SIMPLEX_3D:
6594:       for (p = cStart; p < cEnd; ++p) {
6595:         for (r = 0; r < 8; ++r) {
6596:           newp     = (p - cStart)*8 + r;
6597:           pi[newp] = p;
6598:         }
6599:       }
6600:       break;
6601:     case REFINER_HYBRID_SIMPLEX_3D:
6602:       for (p = cStart; p < cMax; ++p) {
6603:         for (r = 0; r < 8; ++r) {
6604:           newp     = (p - cStart)*8 + r;
6605:           pi[newp] = p;
6606:         }
6607:       }
6608:       for (p = cMax; p < cEnd; ++p) {
6609:         for (r = 0; r < 4; ++r) {
6610:           newp     = (cMax - cStart)*8 + (p - cMax)*4 + r;
6611:           pi[newp] = p;
6612:         }
6613:       }
6614:       break;
6615:     case REFINER_SIMPLEX_TO_HEX_3D:
6616:       for (p = cStart; p < cEnd; ++p) {
6617:         for (r = 0; r < 4; ++r) {
6618:           newp     = (p - cStart)*4 + r;
6619:           pi[newp] = p;
6620:         }
6621:       }
6622:       break;
6623:     case REFINER_HEX_3D:
6624:       for (p = cStart; p < cEnd; ++p) {
6625:         for (r = 0; r < 8; ++r) {
6626:           newp = (p - cStart)*8 + r;
6627:           pi[newp] = p;
6628:         }
6629:       }
6630:       break;
6631:     case REFINER_HYBRID_HEX_3D:
6632:       for (p = cStart; p < cMax; ++p) {
6633:         for (r = 0; r < 8; ++r) {
6634:           newp = (p - cStart)*8 + r;
6635:           pi[newp] = p;
6636:         }
6637:       }
6638:       for (p = cMax; p < cEnd; ++p) {
6639:         for (r = 0; r < 4; ++r) {
6640:           newp = (cMax - cStart)*8 + (p - cMax)*4 + r;
6641:           pi[newp] = p;
6642:         }
6643:       }
6644:       break;
6645:     default:
6646:       SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
6647:     }
6648:     parentId = pi;
6649:   } else {
6650:     PetscSectionSetChart(coordSectionNew, vStartNew, vStartNew+numVertices);
6651:   }
6652:   if (cMax < 0) cMax = cEnd;
6653:   if (fMax < 0) fMax = fEnd;
6654:   if (eMax < 0) eMax = eEnd;

6656:   /* All vertices have the spaceDim coordinates */
6657:   if (localize) {
6658:     PetscInt c;

6660:     for (c = cStartNew; c < cEndNew; ++c) {
6661:       PetscInt *cone = NULL;
6662:       PetscInt  closureSize, coneSize = 0, p, pdof;

6664:       PetscSectionGetDof(coordSection, parentId[c], &pdof);
6665:       if (pdof) { /* localize on all cells that are refinement of a localized parent cell */
6666:         DMPlexGetTransitiveClosure(rdm, c, PETSC_TRUE, &closureSize, &cone);
6667:         for (p = 0; p < closureSize*2; p += 2) {
6668:           const PetscInt point = cone[p];
6669:           if ((point >= vStartNew) && (point < vEndNew)) coneSize++;
6670:         }
6671:         DMPlexRestoreTransitiveClosure(rdm, c, PETSC_TRUE, &closureSize, &cone);
6672:         PetscSectionSetDof(coordSectionNew, c, coneSize*spaceDim);
6673:         PetscSectionSetFieldDof(coordSectionNew, c, 0, coneSize*spaceDim);
6674:       }
6675:     }
6676:   }
6677:   for (v = vStartNew; v < vStartNew+numVertices; ++v) {
6678:     PetscSectionSetDof(coordSectionNew, v, spaceDim);
6679:     PetscSectionSetFieldDof(coordSectionNew, v, 0, spaceDim);
6680:   }
6681:   PetscSectionSetUp(coordSectionNew);
6682:   DMSetCoordinateSection(rdm, PETSC_DETERMINE, coordSectionNew);
6683:   DMGetCoordinatesLocal(dm, &coordinates);
6684:   PetscSectionGetStorageSize(coordSectionNew, &coordSizeNew);
6685:   VecCreate(PETSC_COMM_SELF, &coordinatesNew);
6686:   PetscObjectSetName((PetscObject) coordinatesNew, "coordinates");
6687:   VecSetSizes(coordinatesNew, coordSizeNew, PETSC_DETERMINE);
6688:   VecGetBlockSize(coordinates, &bs);
6689:   VecSetBlockSize(coordinatesNew, bs);
6690:   VecGetType(coordinates, &vtype);
6691:   VecSetType(coordinatesNew, vtype);
6692:   VecGetArray(coordinates, &coords);
6693:   VecGetArray(coordinatesNew, &coordsNew);

6695:   switch (refiner) {
6696:   case REFINER_NOOP: break;
6697:   case REFINER_SIMPLEX_TO_HEX_3D:
6698:   case REFINER_HEX_3D:
6699:   case REFINER_HYBRID_HEX_3D:
6700:     /* Face vertices have the average of corner coordinates */
6701:     for (f = fStart; f < fMax; ++f) {
6702:       const PetscInt newv = vStartNew + (vEnd - vStart) + (eMax - eStart) + (f - fStart);
6703:       PetscInt      *cone = NULL;
6704:       PetscInt       closureSize, coneSize = 0, off[8], offnew, p, d;

6706:       DMPlexGetTransitiveClosure(dm, f, PETSC_TRUE, &closureSize, &cone);
6707:       for (p = 0; p < closureSize*2; p += 2) {
6708:         const PetscInt point = cone[p];
6709:         if ((point >= vStart) && (point < vEnd)) cone[coneSize++] = point;
6710:       }
6711:       if (localize) {
6712:         const PetscInt *support = NULL;
6713:         PetscInt       *rStar = NULL;
6714:         PetscInt        supportSize, rStarSize, coff, s, ccoff[8];
6715:         PetscBool       cellfound = PETSC_FALSE;

6717:         DMPlexGetTransitiveClosure(rdm, newv, PETSC_FALSE, &rStarSize, &rStar);
6718:         DMPlexGetSupportSize(dm,f,&supportSize);
6719:         DMPlexGetSupport(dm,f,&support);
6720:         /* Compute average of coordinates for each cell sharing the face */
6721:         for (s = 0; s < supportSize; ++s) {
6722:           PetscScalar     coordsNewAux[3] = { 0.0, 0.0, 0.0 };
6723:           PetscInt       *cellCone = NULL;
6724:           PetscInt        cellClosureSize, cellConeSize = 0, cdof;
6725:           const PetscInt  cell = support[s];
6726:           PetscBool       copyoff = PETSC_FALSE;

6728:           DMPlexGetTransitiveClosure(dm, cell, PETSC_TRUE, &cellClosureSize, &cellCone);
6729:           for (p = 0; p < cellClosureSize*2; p += 2) {
6730:             const PetscInt point = cellCone[p];
6731:             if ((point >= vStart) && (point < vEnd)) cellCone[cellConeSize++] = point;
6732:           }
6733:           PetscSectionGetDof(coordSection, cell, &cdof);
6734:           if (!cdof) { /* the parent cell does not have localized coordinates */
6735:             cellfound = PETSC_TRUE;
6736:             for (v = 0; v < coneSize; ++v) {
6737:               PetscSectionGetOffset(coordSection, cone[v], &off[v]);
6738:               for (d = 0; d < spaceDim; ++d) coordsNewAux[d] += coords[off[v]+d];
6739:             }
6740:             for (d = 0; d < spaceDim; ++d) coordsNewAux[d] /= coneSize;
6741:           } else {
6742:             PetscSectionGetOffset(coordSection, cell, &coff);
6743:             for (p = 0; p < coneSize; ++p) {
6744:               const PetscInt tv = cone[p];
6745:               PetscInt       cv, voff;
6746:               PetscBool      locv = PETSC_TRUE;

6748:               for (cv = 0; cv < cellConeSize; ++cv) {
6749:                 if (cellCone[cv] == tv) {
6750:                   ccoff[p] = spaceDim*cv + coff;
6751:                   break;
6752:                 }
6753:               }
6754:               if (cv == cellConeSize) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Unable to map vertex %D\n",tv);

6756:               PetscSectionGetOffset(coordSection, cone[p], &voff);
6757:               for (d = 0; d < spaceDim; ++d) {
6758:                 coordsNewAux[d] += coords[ccoff[p]+d];
6759:                 if (!cellfound && coords[voff+d] != coords[ccoff[p]+d]) locv = PETSC_FALSE;
6760:               }
6761:               if (locv && !cellfound) {
6762:                 cellfound = PETSC_TRUE;
6763:                 copyoff   = PETSC_TRUE;
6764:               }
6765:             }
6766:             for (d = 0; d < spaceDim; ++d) coordsNewAux[d] /= coneSize;

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

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

6779:               PetscSectionGetDof(coordSectionNew, rcell, &rcdof);
6780:               if (!rcdof) continue;
6781:               PetscSectionGetOffset(coordSectionNew, rcell, &rcoff);
6782:               DMPlexGetTransitiveClosure(rdm, rcell, PETSC_TRUE, &rclosureSize, &rcone);
6783:               for (p = 0, lid = 0; p < rclosureSize*2; p += 2) {
6784:                 if (rcone[p] == newv) {
6785:                   for (d = 0; d < spaceDim; d++) coordsNew[rcoff + lid*spaceDim + d] = coordsNewAux[d];
6786:                   break;
6787:                 }
6788:                 if (rcone[p] >= vStartNew && rcone[p] < vEndNew) lid++;
6789:               }
6790:               DMPlexRestoreTransitiveClosure(rdm, rcell, PETSC_TRUE, &rclosureSize, &rcone);
6791:               if (p == closureSize*2) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Unable to map new vertex %D\n",newv);
6792:             }
6793:           }
6794:           DMPlexRestoreTransitiveClosure(dm, cell, PETSC_TRUE, &cellClosureSize, &cellCone);
6795:         }
6796:         DMPlexRestoreTransitiveClosure(rdm, newv, PETSC_FALSE, &rStarSize, &rStar);
6797:         if (!cellfound) {
6798:           /* Could not find a valid face for the vertex part, we will get this vertex later (final reduction) */
6799:           needcoords = PETSC_TRUE;
6800:           coneSize   = 0;
6801:         }
6802:       } else {
6803:         for (v = 0; v < coneSize; ++v) {
6804:           PetscSectionGetOffset(coordSection, cone[v], &off[v]);
6805:         }
6806:       }
6807:       PetscSectionGetOffset(coordSectionNew, newv, &offnew);
6808:       if (coneSize) {
6809:         for (d = 0; d < spaceDim; ++d) coordsNew[offnew+d] = 0.0;
6810:         for (v = 0; v < coneSize; ++v) {DMLocalizeAddCoordinate_Internal(dm, spaceDim, &coords[off[0]], &coords[off[v]], &coordsNew[offnew]);}
6811:         for (d = 0; d < spaceDim; ++d) coordsNew[offnew+d] /= coneSize;
6812:       } else {
6813:         for (d = 0; d < spaceDim; ++d) coordsNew[offnew+d] = PETSC_MIN_REAL;
6814:       }
6815:       DMPlexRestoreTransitiveClosure(dm, f, PETSC_TRUE, &closureSize, &cone);
6816:     }
6817:   case REFINER_SIMPLEX_TO_HEX_2D:
6818:   case REFINER_HEX_2D:
6819:   case REFINER_HYBRID_HEX_2D:
6820:   case REFINER_SIMPLEX_1D:
6821:     /* Cell vertices have the average of corner coordinates */
6822:     for (c = cStart; c < cMax; ++c) {
6823:       const PetscInt newv = vStartNew + (vEnd - vStart) + (dim > 1 ? (eMax - eStart) : 0) + (c - cStart) + (dim > 2 ? (fMax - fStart) : 0);
6824:       PetscInt      *cone = NULL;
6825:       PetscInt       closureSize, coneSize = 0, off[8], offnew, p, d, cdof = 0;

6827:       DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &cone);
6828:       for (p = 0; p < closureSize*2; p += 2) {
6829:         const PetscInt point = cone[p];
6830:         if ((point >= vStart) && (point < vEnd)) cone[coneSize++] = point;
6831:       }
6832:       if (localize) {
6833:         PetscSectionGetDof(coordSection, c, &cdof);
6834:       }
6835:       if (cdof) {
6836:         PetscInt coff;

6838:         PetscSectionGetOffset(coordSection, c, &coff);
6839:         for (v = 0; v < coneSize; ++v) off[v] = spaceDim*v + coff;
6840:       } else {
6841:         for (v = 0; v < coneSize; ++v) {
6842:           PetscSectionGetOffset(coordSection, cone[v], &off[v]);
6843:         }
6844:       }
6845:       PetscSectionGetOffset(coordSectionNew, newv, &offnew);
6846:       for (d = 0; d < spaceDim; ++d) coordsNew[offnew+d] = 0.0;
6847:       for (v = 0; v < coneSize; ++v) {DMLocalizeAddCoordinate_Internal(dm, spaceDim, &coords[off[0]], &coords[off[v]], &coordsNew[offnew]);}
6848:       for (d = 0; d < spaceDim; ++d) coordsNew[offnew+d] /= coneSize;
6849:       DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &cone);

6851:       /* Localize new coordinates on each refined cell */
6852:       if (cdof) {
6853:         PetscInt *rStar = NULL, rStarSize;

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

6860:             rc   = rStar[v];
6861:             PetscSectionGetDof(coordSectionNew, rc, &rcdof);
6862:             if (!rcdof) continue;
6863:             PetscSectionGetOffset(coordSectionNew, rc, &coff);
6864:             DMPlexGetTransitiveClosure(rdm, rc, PETSC_TRUE, &closureSize, &cone);
6865:             for (p = 0, lid = 0; p < closureSize*2; p += 2) {
6866:               if (cone[p] == newv) {
6867:                 for (d = 0; d < spaceDim; d++) coordsNew[coff + lid*spaceDim + d] = coordsNew[offnew + d];
6868:                 break;
6869:               }
6870:               if (cone[p] >= vStartNew && cone[p] < vEndNew) lid++;
6871:             }
6872:             if (p == closureSize*2) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Unable to map new vertex %D\n",newv);
6873:             DMPlexRestoreTransitiveClosure(rdm, rc, PETSC_TRUE, &closureSize, &cone);
6874:           }
6875:         }
6876:         DMPlexRestoreTransitiveClosure(rdm, newv, PETSC_FALSE, &rStarSize, &rStar);
6877:       }
6878:     }
6879:   case REFINER_SIMPLEX_2D:
6880:   case REFINER_HYBRID_SIMPLEX_2D:
6881:   case REFINER_SIMPLEX_3D:
6882:   case REFINER_HYBRID_SIMPLEX_3D:
6883:     /* Edge vertices have the average of endpoint coordinates */
6884:     for (e = eStart; e < eMax; ++e) {
6885:       const PetscInt  newv = vStartNew + (vEnd - vStart) + (e - eStart);
6886:       const PetscInt *cone;
6887:       PetscInt        coneSize, offA, offB, offnew, d;

6889:       DMPlexGetConeSize(dm, e, &coneSize);
6890:       if (coneSize != 2) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Edge %d cone should have two vertices, not %d", e, coneSize);
6891:       DMPlexGetCone(dm, e, &cone);
6892:       if (localize) {
6893:         PetscInt   coff, toffA = -1, toffB = -1, voffA, voffB;
6894:         PetscInt  *eStar = NULL, eStarSize;
6895:         PetscInt  *rStar = NULL, rStarSize;
6896:         PetscBool  cellfound = PETSC_FALSE;

6898:         offA = offB = -1;
6899:         PetscSectionGetOffset(coordSection, cone[0], &voffA);
6900:         PetscSectionGetOffset(coordSection, cone[1], &voffB);
6901:         DMPlexGetTransitiveClosure(dm, e, PETSC_FALSE, &eStarSize, &eStar);
6902:         DMPlexGetTransitiveClosure(rdm, newv, PETSC_FALSE, &rStarSize, &rStar);
6903:         for (v = 0; v < eStarSize*2; v += 2) {
6904:           if ((eStar[v] >= cStart) && (eStar[v] < cEnd)) {
6905:             PetscScalar     coordsNewAux[3];
6906:             PetscInt       *cellCone = NULL;
6907:             PetscInt        cellClosureSize, s, cv, cdof;
6908:             PetscBool       locvA = PETSC_TRUE, locvB = PETSC_TRUE;
6909:             const PetscInt  cell = eStar[v];

6911:             PetscSectionGetDof(coordSection, cell, &cdof);
6912:             if (!cdof) {
6913:               /* Found a valid edge for the "vertex" part of the Section */
6914:               offA = voffA;
6915:               offB = voffB;
6916:               cellfound = PETSC_TRUE;
6917:             } else {
6918:               PetscSectionGetOffset(coordSection, cell, &coff);
6919:               DMPlexGetTransitiveClosure(dm, cell, PETSC_TRUE, &cellClosureSize, &cellCone);
6920:               for (s = 0, cv = 0; s < cellClosureSize*2; s += 2) {
6921:                 const PetscInt point = cellCone[s];
6922:                 if ((point >= vStart) && (point < vEnd)) {
6923:                   if (point == cone[0]) toffA = spaceDim*cv + coff;
6924:                   else if (point == cone[1]) toffB = spaceDim*cv + coff;
6925:                   cv++;
6926:                 }
6927:               }
6928:               DMPlexRestoreTransitiveClosure(dm, cell, PETSC_TRUE, &cellClosureSize, &cellCone);
6929:               for (d = 0; d < spaceDim; ++d) {
6930:                 coordsNewAux[d] = 0.5*(coords[toffA+d] + coords[toffB+d]);
6931:                 if (coords[toffA+d] != coords[voffA+d]) locvA = PETSC_FALSE;
6932:                 if (coords[toffB+d] != coords[voffB+d]) locvB = PETSC_FALSE;
6933:               }
6934:               /* Found a valid edge for the "vertex" part of the Section */
6935:               if (!cellfound && (locvA || locvB)) {
6936:                 cellfound = PETSC_TRUE;
6937:                 offA = toffA;
6938:                 offB = toffB;
6939:               }
6940:             }

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

6948:                 PetscSectionGetDof(coordSectionNew, rcell, &rcdof);
6949:                 if (!rcdof) continue;
6950:                 PetscSectionGetOffset(coordSectionNew, rcell, &coff);
6951:                 DMPlexGetTransitiveClosure(rdm, rcell, PETSC_TRUE, &rclosureSize, &rcone);
6952:                 for (p = 0, lid = 0; p < rclosureSize*2; p += 2) {
6953:                   if (rcone[p] == newv) {
6954:                     for (d = 0; d < spaceDim; d++) coordsNew[coff + lid*spaceDim + d] = coordsNewAux[d];
6955:                     break;
6956:                   }
6957:                   if (rcone[p] >= vStartNew && rcone[p] < vEndNew) lid++;
6958:                 }
6959:                 DMPlexRestoreTransitiveClosure(rdm, rcell, PETSC_TRUE, &rclosureSize, &rcone);
6960:                 if (p == rclosureSize*2) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Unable to map new vertex %D\n",newv);
6961:               }
6962:             }
6963:           }
6964:         }
6965:         DMPlexRestoreTransitiveClosure(dm, e, PETSC_FALSE, &eStarSize, &eStar);
6966:         DMPlexRestoreTransitiveClosure(rdm, newv, PETSC_FALSE, &rStarSize, &rStar);
6967:         if (!cellfound) {
6968:           /* Could not find a valid edge for the vertex part, we will get this vertex later (final reduction) */
6969:           needcoords = PETSC_TRUE;
6970:         }
6971:       } else {
6972:         PetscSectionGetOffset(coordSection, cone[0], &offA);
6973:         PetscSectionGetOffset(coordSection, cone[1], &offB);
6974:       }
6975:       PetscSectionGetOffset(coordSectionNew, newv, &offnew);
6976:       if (offA != -1 && offB != -1) {
6977:         DMLocalizeCoordinate_Internal(dm, spaceDim, &coords[offA], &coords[offB], &coordsNew[offnew]);
6978:         for (d = 0; d < spaceDim; ++d) {
6979:           coordsNew[offnew+d] = 0.5*(coords[offA+d] + coordsNew[offnew+d]);
6980:         }
6981:       } else {
6982:         for (d = 0; d < spaceDim; ++d) coordsNew[offnew+d] = PETSC_MIN_REAL;
6983:       }
6984:     }
6985:     /* Old vertices have the same coordinates */
6986:     for (v = vStart; v < vEnd; ++v) {
6987:       const PetscInt newv = vStartNew + (v - vStart);
6988:       PetscInt       off, offnew, d;

6990:       PetscSectionGetOffset(coordSection, v, &off);
6991:       PetscSectionGetOffset(coordSectionNew, newv, &offnew);
6992:       for (d = 0; d < spaceDim; ++d) {
6993:         coordsNew[offnew+d] = coords[off+d];
6994:       }

6996:       /* Localize new coordinates on each refined cell */
6997:       if (localize) {
6998:         PetscInt  p;
6999:         PetscInt *rStar = NULL, rStarSize;

7001:         DMPlexGetTransitiveClosure(rdm, newv, PETSC_FALSE, &rStarSize, &rStar);
7002:         for (p = 0; p < rStarSize*2; p += 2) {
7003:           if ((rStar[p] >= cStartNew) && (rStar[p] < cEndNew)) {
7004:             PetscScalar  ocoords[3];
7005:             PetscInt    *cone = NULL, closureSize, lid, coff, s, oc, cdof;

7007:             c    = rStar[p];
7008:             oc   = parentId[c-cStartNew];
7009:             PetscSectionGetDof(coordSectionNew, c, &cdof);
7010:             if (!cdof) continue;
7011:             PetscSectionGetDof(coordSection, oc, &cdof);
7012:             if (!cdof) continue;
7013:             PetscSectionGetOffset(coordSection, oc, &coff);
7014:             DMPlexGetTransitiveClosure(dm, oc, PETSC_TRUE, &closureSize, &cone);
7015:             for (s = 0, lid = 0; s < closureSize*2; s += 2) {
7016:               if (cone[s] == v) {
7017:                 for (d = 0; d < spaceDim; d++) ocoords[d] = coords[coff + lid*spaceDim + d];
7018:                 break;
7019:               }
7020:               if (cone[s] >= vStart && cone[s] < vEnd) lid++;
7021:             }
7022:             if (s == closureSize*2) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Unable to map old vertex %D\n",v);
7023:             DMPlexRestoreTransitiveClosure(dm, oc, PETSC_TRUE, &closureSize, &cone);

7025:             PetscSectionGetOffset(coordSectionNew, c, &coff);
7026:             DMPlexGetTransitiveClosure(rdm, c, PETSC_TRUE, &closureSize, &cone);
7027:             for (s = 0, lid = 0; s < closureSize*2; s += 2) {
7028:               if (cone[s] == newv) {
7029:                 for (d = 0; d < spaceDim; d++) coordsNew[coff + lid*spaceDim + d] = ocoords[d];
7030:                 break;
7031:               }
7032:               if (cone[s] >= vStartNew && cone[s] < vEndNew) lid++;
7033:             }
7034:             if (s == closureSize*2) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Unable to map new vertex %D\n",newv);
7035:             DMPlexRestoreTransitiveClosure(rdm, c, PETSC_TRUE, &closureSize, &cone);
7036:           }
7037:         }
7038:         DMPlexRestoreTransitiveClosure(rdm, newv, PETSC_FALSE, &rStarSize, &rStar);
7039:       }
7040:     }
7041:     break;
7042:   default:
7043:     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
7044:   }
7045:   VecRestoreArray(coordinates, &coords);
7046:   VecRestoreArray(coordinatesNew, &coordsNew);
7047:   DMSetCoordinatesLocal(rdm, coordinatesNew);

7049:   /* Final reduction (if needed) if we are localizing */
7050:   if (localize) {
7051:     PetscBool gred;

7053:     MPIU_Allreduce(&needcoords, &gred, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject)rdm));
7054:     if (gred) {
7055:       DM                 cdm;
7056:       Vec                aux;
7057:       PetscSF            sf;
7058:       const PetscScalar *lArray;
7059:       PetscScalar       *gArray;

7061:       DMGetCoordinateDM(rdm, &cdm);
7062:       DMCreateGlobalVector(cdm, &aux);
7063:       DMGetDefaultSF(cdm, &sf);
7064:       VecGetArrayRead(coordinatesNew, &lArray);
7065:       VecSet(aux, PETSC_MIN_REAL);
7066:       VecGetArray(aux, &gArray);
7067:       PetscSFReduceBegin(sf, MPIU_SCALAR, lArray, gArray, MPIU_MAX);
7068:       PetscSFReduceEnd(sf, MPIU_SCALAR, lArray, gArray, MPIU_MAX);
7069:       VecRestoreArrayRead(coordinatesNew, &lArray);
7070:       VecRestoreArray(aux, &gArray);
7071:       DMGlobalToLocalBegin(cdm, aux, INSERT_VALUES, coordinatesNew);
7072:       DMGlobalToLocalEnd(cdm, aux, INSERT_VALUES, coordinatesNew);
7073:       VecDestroy(&aux);
7074:     }
7075:   }
7076:   VecDestroy(&coordinatesNew);
7077:   PetscSectionDestroy(&coordSectionNew);
7078:   PetscFree(parentId);
7079:   return(0);
7080: }

7082: /*@
7083:   DMPlexCreateProcessSF - Create an SF which just has process connectivity

7085:   Collective on DM

7087:   Input Parameters:
7088: + dm      - The DM
7089: - sfPoint - The PetscSF which encodes point connectivity

7091:   Output Parameters:
7092: + processRanks - A list of process neighbors, or NULL
7093: - sfProcess    - An SF encoding the process connectivity, or NULL

7095:   Level: developer

7097: .seealso: PetscSFCreate(), DMPlexCreateTwoSidedProcessSF()
7098: @*/
7099: PetscErrorCode DMPlexCreateProcessSF(DM dm, PetscSF sfPoint, IS *processRanks, PetscSF *sfProcess)
7100: {
7101:   PetscInt           numRoots, numLeaves, l;
7102:   const PetscInt    *localPoints;
7103:   const PetscSFNode *remotePoints;
7104:   PetscInt          *localPointsNew;
7105:   PetscSFNode       *remotePointsNew;
7106:   PetscInt          *ranks, *ranksNew;
7107:   PetscMPIInt        size;
7108:   PetscErrorCode     ierr;

7115:   MPI_Comm_size(PetscObjectComm((PetscObject) dm), &size);
7116:   PetscSFGetGraph(sfPoint, &numRoots, &numLeaves, &localPoints, &remotePoints);
7117:   PetscMalloc1(numLeaves, &ranks);
7118:   for (l = 0; l < numLeaves; ++l) {
7119:     ranks[l] = remotePoints[l].rank;
7120:   }
7121:   PetscSortRemoveDupsInt(&numLeaves, ranks);
7122:   PetscMalloc1(numLeaves, &ranksNew);
7123:   PetscMalloc1(numLeaves, &localPointsNew);
7124:   PetscMalloc1(numLeaves, &remotePointsNew);
7125:   for (l = 0; l < numLeaves; ++l) {
7126:     ranksNew[l]              = ranks[l];
7127:     localPointsNew[l]        = l;
7128:     remotePointsNew[l].index = 0;
7129:     remotePointsNew[l].rank  = ranksNew[l];
7130:   }
7131:   PetscFree(ranks);
7132:   if (processRanks) {ISCreateGeneral(PetscObjectComm((PetscObject)dm), numLeaves, ranksNew, PETSC_OWN_POINTER, processRanks);}
7133:   else              {PetscFree(ranksNew);}
7134:   if (sfProcess) {
7135:     PetscSFCreate(PetscObjectComm((PetscObject)dm), sfProcess);
7136:     PetscObjectSetName((PetscObject) *sfProcess, "Process SF");
7137:     PetscSFSetFromOptions(*sfProcess);
7138:     PetscSFSetGraph(*sfProcess, size, numLeaves, localPointsNew, PETSC_OWN_POINTER, remotePointsNew, PETSC_OWN_POINTER);
7139:   }
7140:   return(0);
7141: }

7143: static PetscErrorCode CellRefinerCreateSF(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
7144: {
7145:   PetscSF            sf, sfNew, sfProcess;
7146:   IS                 processRanks;
7147:   MPI_Datatype       depthType;
7148:   PetscInt           numRoots, numLeaves, numLeavesNew = 0, l, m;
7149:   const PetscInt    *localPoints, *neighbors;
7150:   const PetscSFNode *remotePoints;
7151:   PetscInt          *localPointsNew;
7152:   PetscSFNode       *remotePointsNew;
7153:   PetscInt          *depthSizeOld, *rdepthSize, *rdepthSizeOld, *rdepthMaxOld, *rvStart, *rvStartNew, *reStart, *reStartNew, *rfStart, *rfStartNew, *rcStart, *rcStartNew;
7154:   PetscInt           ldepth, depth, numNeighbors, pStartNew, pEndNew, cStart, cEnd, cMax, vStart, vEnd, vMax, fStart, fEnd, fMax, eStart, eEnd, eMax, r, n;
7155:   PetscInt           cStartNew = 0, vStartNew = 0, fStartNew = 0, eStartNew = 0;
7156:   PetscErrorCode     ierr;

7159:   DMPlexGetChart(rdm, &pStartNew, &pEndNew);
7160:   DMPlexGetDepth(dm, &ldepth);
7161:   MPIU_Allreduce(&ldepth, &depth, 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject) dm));
7162:   if ((ldepth >= 0) && (depth != ldepth)) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Inconsistent Plex depth %d != %d", ldepth, depth);
7163:   DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);
7164:   DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);
7165:   DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);
7166:   DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);
7167:   DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);
7168:   cMax = cMax < 0 ? cEnd : cMax;
7169:   fMax = fMax < 0 ? fEnd : fMax;
7170:   eMax = eMax < 0 ? eEnd : eMax;
7171:   if (refiner) {GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);}
7172:   DMGetPointSF(dm, &sf);
7173:   DMGetPointSF(rdm, &sfNew);
7174:   /* Calculate size of new SF */
7175:   PetscSFGetGraph(sf, &numRoots, &numLeaves, &localPoints, &remotePoints);
7176:   if (numRoots < 0) return(0);
7177:   for (l = 0; l < numLeaves; ++l) {
7178:     const PetscInt p = localPoints[l];

7180:     switch (refiner) {
7181:     case REFINER_SIMPLEX_1D:
7182:       if ((p >= vStart) && (p < vEnd)) {
7183:         /* Interior vertices stay the same */
7184:         ++numLeavesNew;
7185:       } else if ((p >= cStart && p < cMax)) {
7186:         /* Interior cells add new cells and interior vertices */
7187:         numLeavesNew += 2 + 1;
7188:       }
7189:       break;
7190:     case REFINER_SIMPLEX_2D:
7191:     case REFINER_HYBRID_SIMPLEX_2D:
7192:       if ((p >= vStart) && (p < vEnd)) {
7193:         /* Interior vertices stay the same */
7194:         ++numLeavesNew;
7195:       } else if ((p >= fStart) && (p < fMax)) {
7196:         /* Interior faces add new faces and vertex */
7197:         numLeavesNew += 2 + 1;
7198:       } else if ((p >= fMax) && (p < fEnd)) {
7199:         /* Hybrid faces stay the same */
7200:         ++numLeavesNew;
7201:       } else if ((p >= cStart) && (p < cMax)) {
7202:         /* Interior cells add new cells and interior faces */
7203:         numLeavesNew += 4 + 3;
7204:       } else if ((p >= cMax) && (p < cEnd)) {
7205:         /* Hybrid cells add new cells and hybrid face */
7206:         numLeavesNew += 2 + 1;
7207:       }
7208:       break;
7209:     case REFINER_SIMPLEX_TO_HEX_2D:
7210:       if ((p >= vStart) && (p < vEnd)) {
7211:         /* Interior vertices stay the same */
7212:         ++numLeavesNew;
7213:       } else if ((p >= fStart) && (p < fEnd)) {
7214:         /* Interior faces add new faces and vertex */
7215:         numLeavesNew += 2 + 1;
7216:       } else if ((p >= cStart) && (p < cEnd)) {
7217:         /* Interior cells add new cells, interior faces, and vertex */
7218:         numLeavesNew += 3 + 3 + 1;
7219:       }
7220:       break;
7221:     case REFINER_HEX_2D:
7222:     case REFINER_HYBRID_HEX_2D:
7223:       if ((p >= vStart) && (p < vEnd)) {
7224:         /* Interior vertices stay the same */
7225:         ++numLeavesNew;
7226:       } else if ((p >= fStart) && (p < fMax)) {
7227:         /* Interior faces add new faces and vertex */
7228:         numLeavesNew += 2 + 1;
7229:       } else if ((p >= fMax) && (p < fEnd)) {
7230:         /* Hybrid faces stay the same */
7231:         ++numLeavesNew;
7232:       } else if ((p >= cStart) && (p < cMax)) {
7233:         /* Interior cells add new cells, interior faces, and vertex */
7234:         numLeavesNew += 4 + 4 + 1;
7235:       } else if ((p >= cMax) && (p < cEnd)) {
7236:         /* Hybrid cells add new cells and hybrid face */
7237:         numLeavesNew += 2 + 1;
7238:       }
7239:       break;
7240:     case REFINER_SIMPLEX_3D:
7241:     case REFINER_HYBRID_SIMPLEX_3D:
7242:       if ((p >= vStart) && (p < vEnd)) {
7243:         /* Interior vertices stay the same */
7244:         ++numLeavesNew;
7245:       } else if ((p >= eStart) && (p < eMax)) {
7246:         /* Interior edges add new edges and vertex */
7247:         numLeavesNew += 2 + 1;
7248:       } else if ((p >= eMax) && (p < eEnd)) {
7249:         /* Hybrid edges stay the same */
7250:         ++numLeavesNew;
7251:       } else if ((p >= fStart) && (p < fMax)) {
7252:         /* Interior faces add new faces and edges */
7253:         numLeavesNew += 4 + 3;
7254:       } else if ((p >= fMax) && (p < fEnd)) {
7255:         /* Hybrid faces add new faces and edges */
7256:         numLeavesNew += 2 + 1;
7257:       } else if ((p >= cStart) && (p < cMax)) {
7258:         /* Interior cells add new cells, faces, and edges */
7259:         numLeavesNew += 8 + 8 + 1;
7260:       } else if ((p >= cMax) && (p < cEnd)) {
7261:         /* Hybrid cells add new cells and faces */
7262:         numLeavesNew += 4 + 3;
7263:       }
7264:       break;
7265:     case REFINER_SIMPLEX_TO_HEX_3D:
7266:       if ((p >= vStart) && (p < vEnd)) {
7267:         /* Interior vertices stay the same */
7268:         ++numLeavesNew;
7269:       } else if ((p >= eStart) && (p < eEnd)) {
7270:         /* Interior edges add new edges and vertex */
7271:         numLeavesNew += 2 + 1;
7272:       } else if ((p >= fStart) && (p < fEnd)) {
7273:         /* Interior faces add new faces, edges and a vertex */
7274:         numLeavesNew += 3 + 3 + 1;
7275:       } else if ((p >= cStart) && (p < cEnd)) {
7276:         /* Interior cells add new cells, faces, edges and a vertex */
7277:         numLeavesNew += 4 + 6 + 4 + 1;
7278:       }
7279:       break;
7280:     case REFINER_HEX_3D:
7281:     case REFINER_HYBRID_HEX_3D:
7282:       if ((p >= vStart) && (p < vEnd)) {
7283:         /* Old vertices stay the same */
7284:         ++numLeavesNew;
7285:       } else if ((p >= eStart) && (p < eMax)) {
7286:         /* Interior edges add new edges, and vertex */
7287:         numLeavesNew += 2 + 1;
7288:       } else if ((p >= eMax) && (p < eEnd)) {
7289:         /* Hybrid edges stay the same */
7290:         ++numLeavesNew;
7291:       } else if ((p >= fStart) && (p < fMax)) {
7292:         /* Interior faces add new faces, edges, and vertex */
7293:         numLeavesNew += 4 + 4 + 1;
7294:       } else if ((p >= fMax) && (p < fEnd)) {
7295:         /* Hybrid faces add new faces and edges */
7296:         numLeavesNew += 2 + 1;
7297:       } else if ((p >= cStart) && (p < cMax)) {
7298:         /* Interior cells add new cells, faces, edges, and vertex */
7299:         numLeavesNew += 8 + 12 + 6 + 1;
7300:       } else if ((p >= cStart) && (p < cEnd)) {
7301:         /* Hybrid cells add new cells, faces, and edges */
7302:         numLeavesNew += 4 + 4 + 1;
7303:       }
7304:       break;
7305:     default:
7306:       SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
7307:     }
7308:   }
7309:   /* Communicate depthSizes for each remote rank */
7310:   DMPlexCreateProcessSF(dm, sf, &processRanks, &sfProcess);
7311:   ISGetLocalSize(processRanks, &numNeighbors);
7312:   PetscMalloc5((depth+1)*numNeighbors,&rdepthSize,numNeighbors,&rvStartNew,numNeighbors,&reStartNew,numNeighbors,&rfStartNew,numNeighbors,&rcStartNew);
7313:   PetscMalloc7(depth+1,&depthSizeOld,(depth+1)*numNeighbors,&rdepthSizeOld,(depth+1)*numNeighbors,&rdepthMaxOld,numNeighbors,&rvStart,numNeighbors,&reStart,numNeighbors,&rfStart,numNeighbors,&rcStart);
7314:   MPI_Type_contiguous(depth+1, MPIU_INT, &depthType);
7315:   MPI_Type_commit(&depthType);
7316:   PetscSFBcastBegin(sfProcess, depthType, depthSize, rdepthSize);
7317:   PetscSFBcastEnd(sfProcess, depthType, depthSize, rdepthSize);
7318:   for (n = 0; n < numNeighbors; ++n) {
7319:     GetDepthStart_Private(depth, &rdepthSize[n*(depth+1)], &rcStartNew[n], &rfStartNew[n], &reStartNew[n], &rvStartNew[n]);
7320:   }
7321:   depthSizeOld[depth]   = cMax;
7322:   depthSizeOld[0]       = vMax;
7323:   depthSizeOld[depth-1] = fMax;
7324:   depthSizeOld[1]       = eMax;

7326:   PetscSFBcastBegin(sfProcess, depthType, depthSizeOld, rdepthMaxOld);
7327:   PetscSFBcastEnd(sfProcess, depthType, depthSizeOld, rdepthMaxOld);

7329:   depthSizeOld[depth]   = cEnd - cStart;
7330:   depthSizeOld[0]       = vEnd - vStart;
7331:   depthSizeOld[depth-1] = fEnd - fStart;
7332:   depthSizeOld[1]       = eEnd - eStart;

7334:   PetscSFBcastBegin(sfProcess, depthType, depthSizeOld, rdepthSizeOld);
7335:   PetscSFBcastEnd(sfProcess, depthType, depthSizeOld, rdepthSizeOld);
7336:   for (n = 0; n < numNeighbors; ++n) {
7337:     GetDepthStart_Private(depth, &rdepthSizeOld[n*(depth+1)], &rcStart[n], &rfStart[n], &reStart[n], &rvStart[n]);
7338:     rdepthMaxOld[n*(depth+1)+depth]   = rdepthMaxOld[n*(depth+1)+depth]   < 0 ? rdepthSizeOld[n*(depth+1)+depth]  +rcStart[n]: rdepthMaxOld[n*(depth+1)+depth];
7339:     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];
7340:     rdepthMaxOld[n*(depth+1)+1]       = rdepthMaxOld[n*(depth+1)+1]       < 0 ? rdepthSizeOld[n*(depth+1)+1]      +reStart[n]: rdepthMaxOld[n*(depth+1)+1];
7341:   }
7342:   MPI_Type_free(&depthType);
7343:   PetscSFDestroy(&sfProcess);
7344:   /* Calculate new point SF */
7345:   PetscMalloc1(numLeavesNew, &localPointsNew);
7346:   PetscMalloc1(numLeavesNew, &remotePointsNew);
7347:   ISGetIndices(processRanks, &neighbors);
7348:   for (l = 0, m = 0; l < numLeaves; ++l) {
7349:     PetscInt    p     = localPoints[l];
7350:     PetscInt    rp    = remotePoints[l].index, n;
7351:     PetscMPIInt rrank = remotePoints[l].rank;

7353:     PetscFindInt(rrank, numNeighbors, neighbors, &n);
7354:     if (n < 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Could not locate remote rank %d", rrank);
7355:     switch (refiner) {
7356:     case REFINER_SIMPLEX_1D:
7357:       if ((p >= vStart) && (p < vEnd)) {
7358:         /* Old vertices stay the same */
7359:         localPointsNew[m]        = vStartNew     + (p  - vStart);
7360:         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
7361:         remotePointsNew[m].rank  = rrank;
7362:         ++m;
7363:       } else if ((p >= cStart) && (p < cMax)) {
7364:         /* Old interior cells add new cells and vertex */
7365:         for (r = 0; r < 2; ++r, ++m) {
7366:           localPointsNew[m]        = cStartNew     + (p  - cStart)*2     + r;
7367:           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*2 + r;
7368:           remotePointsNew[m].rank  = rrank;
7369:         }
7370:         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - cStart);
7371:         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - rcStart[n]);
7372:         remotePointsNew[m].rank  = rrank;
7373:         ++m;
7374:       }
7375:       break;
7376:     case REFINER_SIMPLEX_2D:
7377:     case REFINER_HYBRID_SIMPLEX_2D:
7378:       if ((p >= vStart) && (p < vEnd)) {
7379:         /* Old vertices stay the same */
7380:         localPointsNew[m]        = vStartNew     + (p  - vStart);
7381:         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
7382:         remotePointsNew[m].rank  = rrank;
7383:         ++m;
7384:       } else if ((p >= fStart) && (p < fMax)) {
7385:         /* Old interior faces add new faces and vertex */
7386:         for (r = 0; r < 2; ++r, ++m) {
7387:           localPointsNew[m]        = fStartNew     + (p  - fStart)*2     + r;
7388:           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*2 + r;
7389:           remotePointsNew[m].rank  = rrank;
7390:         }
7391:         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - fStart);
7392:         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - rfStart[n]);
7393:         remotePointsNew[m].rank  = rrank;
7394:         ++m;
7395:       } else if ((p >= fMax) && (p < fEnd)) {
7396:         /* Old hybrid faces stay the same */
7397:         localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (p  - fMax);
7398:         remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*2 + (rp - rdepthMaxOld[n*(depth+1)+depth-1]);
7399:         remotePointsNew[m].rank  = rrank;
7400:         ++m;
7401:       } else if ((p >= cStart) && (p < cMax)) {
7402:         /* Old interior cells add new cells and interior faces */
7403:         for (r = 0; r < 4; ++r, ++m) {
7404:           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
7405:           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
7406:           remotePointsNew[m].rank  = rrank;
7407:         }
7408:         for (r = 0; r < 3; ++r, ++m) {
7409:           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (p  - cStart)*3     + r;
7410:           remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*2 + (rp - rcStart[n])*3 + r;
7411:           remotePointsNew[m].rank  = rrank;
7412:         }
7413:       } else if ((p >= cMax) && (p < cEnd)) {
7414:         /* Old hybrid cells add new cells and hybrid face */
7415:         for (r = 0; r < 2; ++r, ++m) {
7416:           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
7417:           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
7418:           remotePointsNew[m].rank  = rrank;
7419:         }
7420:         localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (cMax                            - cStart)*3     + (p  - cMax);
7421:         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]);
7422:         remotePointsNew[m].rank  = rrank;
7423:         ++m;
7424:       }
7425:       break;
7426:     case REFINER_SIMPLEX_TO_HEX_2D:
7427:       if ((p >= vStart) && (p < vEnd)) {
7428:         /* Old vertices stay the same */
7429:         localPointsNew[m]        = vStartNew     + (p  - vStart);
7430:         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
7431:         remotePointsNew[m].rank  = rrank;
7432:         ++m;
7433:       } else if ((p >= fStart) && (p < fEnd)) {
7434:         /* Old interior faces add new faces and vertex */
7435:         for (r = 0; r < 2; ++r, ++m) {
7436:           localPointsNew[m]        = fStartNew     + (p  - fStart)*2     + r;
7437:           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*2 + r;
7438:           remotePointsNew[m].rank  = rrank;
7439:         }
7440:         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - fStart);
7441:         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - rfStart[n]);
7442:         remotePointsNew[m].rank  = rrank;
7443:         ++m;
7444:       } else if ((p >= cStart) && (p < cEnd)) {
7445:         /* Old interior cells add new cells, interior faces, and a vertex */
7446:         for (r = 0; r < 3; ++r, ++m) {
7447:           localPointsNew[m]        = cStartNew     + (p  - cStart)*3     + r;
7448:           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*3 + r;
7449:           remotePointsNew[m].rank  = rrank;
7450:         }
7451:         for (r = 0; r < 3; ++r, ++m) {
7452:           localPointsNew[m]        = fStartNew     + (fEnd - fStart)*2                    + (p  - cStart)*3     + r;
7453:           remotePointsNew[m].index = rfStartNew[n] + rdepthSizeOld[n*(depth+1)+depth-1]*2 + (rp - rcStart[n])*3 + r;
7454:           remotePointsNew[m].rank  = rrank;
7455:         }
7456:         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (fEnd - fStart)                    + (p  - cStart);
7457:         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + rdepthSizeOld[n*(depth+1)+depth-1] + (rp - rcStart[n]);
7458:         remotePointsNew[m].rank  = rrank;
7459:         ++m;
7460:       }
7461:       break;
7462:     case REFINER_HEX_2D:
7463:     case REFINER_HYBRID_HEX_2D:
7464:       if ((p >= vStart) && (p < vEnd)) {
7465:         /* Old vertices stay the same */
7466:         localPointsNew[m]        = vStartNew     + (p  - vStart);
7467:         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
7468:         remotePointsNew[m].rank  = rrank;
7469:         ++m;
7470:       } else if ((p >= fStart) && (p < fMax)) {
7471:         /* Old interior faces add new faces and vertex */
7472:         for (r = 0; r < 2; ++r, ++m) {
7473:           localPointsNew[m]        = fStartNew     + (p  - fStart)*2     + r;
7474:           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*2 + r;
7475:           remotePointsNew[m].rank  = rrank;
7476:         }
7477:         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - fStart);
7478:         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - rfStart[n]);
7479:         remotePointsNew[m].rank  = rrank;
7480:         ++m;
7481:       } else if ((p >= fMax) && (p < fEnd)) {
7482:         /* Old hybrid faces stay the same */
7483:         localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (p  - fMax);
7484:         remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*2 + (rp - rdepthMaxOld[n*(depth+1)+depth-1]);
7485:         remotePointsNew[m].rank  = rrank;
7486:         ++m;
7487:       } else if ((p >= cStart) && (p < cMax)) {
7488:         /* Old interior cells add new cells, interior faces, and vertex */
7489:         for (r = 0; r < 4; ++r, ++m) {
7490:           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
7491:           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
7492:           remotePointsNew[m].rank  = rrank;
7493:         }
7494:         for (r = 0; r < 4; ++r, ++m) {
7495:           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (p  - cStart)*4     + r;
7496:           remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*2 + (rp - rcStart[n])*4 + r;
7497:           remotePointsNew[m].rank  = rrank;
7498:         }
7499:         localPointsNew[m]        = vStartNew     + (vEnd - vStart)               + (fMax                              - fStart)     + (p  - cStart);
7500:         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0]  + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n]) + (rp - rcStart[n]);
7501:         remotePointsNew[m].rank  = rrank;
7502:         ++m;
7503:       } else if ((p >= cStart) && (p < cMax)) {
7504:         /* Old hybrid cells add new cells and hybrid face */
7505:         for (r = 0; r < 2; ++r, ++m) {
7506:           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
7507:           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
7508:           remotePointsNew[m].rank  = rrank;
7509:         }
7510:         localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (cMax                            - cStart)*4     + (p  - cMax);
7511:         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]);
7512:         remotePointsNew[m].rank  = rrank;
7513:         ++m;
7514:       }
7515:       break;
7516:     case REFINER_SIMPLEX_3D:
7517:     case REFINER_HYBRID_SIMPLEX_3D:
7518:       if ((p >= vStart) && (p < vEnd)) {
7519:         /* Interior vertices stay the same */
7520:         localPointsNew[m]        = vStartNew     + (p  - vStart);
7521:         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
7522:         remotePointsNew[m].rank  = rrank;
7523:         ++m;
7524:       } else if ((p >= eStart) && (p < eMax)) {
7525:         /* Interior edges add new edges and vertex */
7526:         for (r = 0; r < 2; ++r, ++m) {
7527:           localPointsNew[m]        = eStartNew     + (p  - eStart)*2     + r;
7528:           remotePointsNew[m].index = reStartNew[n] + (rp - reStart[n])*2 + r;
7529:           remotePointsNew[m].rank  = rrank;
7530:         }
7531:         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - eStart);
7532:         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - reStart[n]);
7533:         remotePointsNew[m].rank  = rrank;
7534:         ++m;
7535:       } else if ((p >= eMax) && (p < eEnd)) {
7536:         /* Hybrid edges stay the same */
7537:         localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (fMax                              - fStart)*3     + (cMax                            - cStart)     + (p  - eMax);
7538:         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]);
7539:         remotePointsNew[m].rank  = rrank;
7540:         ++m;
7541:       } else if ((p >= fStart) && (p < fMax)) {
7542:         /* Interior faces add new faces and edges */
7543:         for (r = 0; r < 4; ++r, ++m) {
7544:           localPointsNew[m]        = fStartNew     + (p  - fStart)*4     + r;
7545:           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*4 + r;
7546:           remotePointsNew[m].rank  = rrank;
7547:         }
7548:         for (r = 0; r < 3; ++r, ++m) {
7549:           localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (p  - fStart)*3     + r;
7550:           remotePointsNew[m].index = reStartNew[n] + (rdepthMaxOld[n*(depth+1)+1] - reStart[n])*2 + (rp - rfStart[n])*3 + r;
7551:           remotePointsNew[m].rank  = rrank;
7552:         }
7553:       } else if ((p >= fMax) && (p < fEnd)) {
7554:         /* Hybrid faces add new faces and edges */
7555:         for (r = 0; r < 2; ++r, ++m) {
7556:           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*4     + (cMax                            - cStart)*8     + (p  - fMax)*2                              + r;
7557:           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;
7558:           remotePointsNew[m].rank  = rrank;
7559:         }
7560:         localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (fMax                              - fStart)*3     + (cMax                            - cStart)     + (eEnd                                    - eMax)                        + (p  - fMax);
7561:         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]);
7562:         remotePointsNew[m].rank  = rrank;
7563:         ++m;
7564:       } else if ((p >= cStart) && (p < cMax)) {
7565:         /* Interior cells add new cells, faces, and edges */
7566:         for (r = 0; r < 8; ++r, ++m) {
7567:           localPointsNew[m]        = cStartNew     + (p  - cStart)*8     + r;
7568:           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*8 + r;
7569:           remotePointsNew[m].rank  = rrank;
7570:         }
7571:         for (r = 0; r < 8; ++r, ++m) {
7572:           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*4     + (p  - cStart)*8     + r;
7573:           remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*4 + (rp - rcStart[n])*8 + r;
7574:           remotePointsNew[m].rank  = rrank;
7575:         }
7576:         localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (fMax                              - fStart)*3     + (p  - cStart)*1     + 0;
7577:         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;
7578:         remotePointsNew[m].rank  = rrank;
7579:         ++m;
7580:       } else if ((p >= cMax) && (p < cEnd)) {
7581:         /* Hybrid cells add new cells and faces */
7582:         for (r = 0; r < 4; ++r, ++m) {
7583:           localPointsNew[m]        = cStartNew     + (cMax                            - cStart)*8     + (p  - cMax)*4                            + r;
7584:           remotePointsNew[m].index = rcStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth] - rcStart[n])*8 + (rp - rdepthMaxOld[n*(depth+1)+depth])*4 + r;
7585:           remotePointsNew[m].rank  = rrank;
7586:         }
7587:         for (r = 0; r < 3; ++r, ++m) {
7588:           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*4     + (cMax                            - cStart)*8     + (fEnd                                          - fMax)*2                              + (p  - cMax)*3                            + r;
7589:           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;
7590:           remotePointsNew[m].rank  = rrank;
7591:         }
7592:       }
7593:       break;
7594:     case REFINER_SIMPLEX_TO_HEX_3D:
7595:       if ((p >= vStart) && (p < vEnd)) {
7596:         /* Interior vertices stay the same */
7597:         localPointsNew[m]        = vStartNew     + (p  - vStart);
7598:         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
7599:         remotePointsNew[m].rank  = rrank;
7600:         ++m;
7601:       } else if ((p >= eStart) && (p < eEnd)) {
7602:         /* Interior edges add new edges and vertex */
7603:         for (r = 0; r < 2; ++r, ++m) {
7604:           localPointsNew[m]        = eStartNew     + (p  - eStart)*2     + r;
7605:           remotePointsNew[m].index = reStartNew[n] + (rp - reStart[n])*2 + r;
7606:           remotePointsNew[m].rank  = rrank;
7607:         }
7608:         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - eStart);
7609:         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - reStart[n]);
7610:         remotePointsNew[m].rank  = rrank;
7611:         ++m;
7612:       } else if ((p >= fStart) && (p < fEnd)) {
7613:         /* Interior faces add new faces, edges and a vertex */
7614:         for (r = 0; r < 3; ++r, ++m) {
7615:           localPointsNew[m]        = fStartNew     + (p  - fStart)*3     + r;
7616:           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*3 + r;
7617:           remotePointsNew[m].rank  = rrank;
7618:         }
7619:         for (r = 0; r < 3; ++r, ++m) {
7620:           localPointsNew[m]        = eStartNew     + (eEnd - eStart)*2                + (p  - fStart)*3     + r;
7621:           remotePointsNew[m].index = reStartNew[n] + (rdepthSizeOld[n*(depth+1)+1])*2 + (rp - rfStart[n])*3 + r;
7622:           remotePointsNew[m].rank  = rrank;
7623:         }
7624:         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (eEnd - eStart)              + (p - fStart);
7625:         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + rdepthSizeOld[n*(depth+1)+1] + (rp - rfStart[n]);
7626:         remotePointsNew[m].rank  = rrank;
7627:         ++m;
7628:       } else if ((p >= cStart) && (p < cEnd)) {
7629:         /* Interior cells add new cells, faces, edges, and a vertex */
7630:         for (r = 0; r < 4; ++r, ++m) {
7631:           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
7632:           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
7633:           remotePointsNew[m].rank  = rrank;
7634:         }
7635:         for (r = 0; r < 6; ++r, ++m) {
7636:           localPointsNew[m]        = fStartNew     + (fEnd - fStart)*3                    + (p  - cStart)*6     + r;
7637:           remotePointsNew[m].index = rfStartNew[n] + rdepthSizeOld[n*(depth+1)+depth-1]*3 + (rp - rcStart[n])*6 + r;
7638:           remotePointsNew[m].rank  = rrank;
7639:         }
7640:         for (r = 0; r < 4; ++r, ++m) {
7641:           localPointsNew[m]        = eStartNew     + (eEnd - eStart)*2              + (fEnd - fStart)*3                    + (p  - cStart)*4 + r;
7642:           remotePointsNew[m].index = reStartNew[n] + rdepthSizeOld[n*(depth+1)+1]*2 + rdepthSizeOld[n*(depth+1)+depth-1]*3 + (rp - rcStart[n])*4 + r;
7643:           remotePointsNew[m].rank  = rrank;
7644:         }
7645:         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (eEnd - eStart)              + (fEnd - fStart)                    + (p - cStart);
7646:         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + rdepthSizeOld[n*(depth+1)+1] + rdepthSizeOld[n*(depth+1)+depth-1] + (rp - rcStart[n]);
7647:         remotePointsNew[m].rank  = rrank;
7648:         ++m;
7649:       }
7650:       break;
7651:     case REFINER_HEX_3D:
7652:     case REFINER_HYBRID_HEX_3D:
7653:       if ((p >= vStart) && (p < vEnd)) {
7654:         /* Interior vertices stay the same */
7655:         localPointsNew[m]        = vStartNew     + (p  - vStart);
7656:         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
7657:         remotePointsNew[m].rank  = rrank;
7658:         ++m;
7659:       } else if ((p >= eStart) && (p < eMax)) {
7660:         /* Interior edges add new edges and vertex */
7661:         for (r = 0; r < 2; ++r, ++m) {
7662:           localPointsNew[m]        = eStartNew     + (p  - eStart)*2     + r;
7663:           remotePointsNew[m].index = reStartNew[n] + (rp - reStart[n])*2 + r;
7664:           remotePointsNew[m].rank  = rrank;
7665:         }
7666:         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - eStart);
7667:         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - reStart[n]);
7668:         remotePointsNew[m].rank  = rrank;
7669:         ++m;
7670:       } else if ((p >= eMax) && (p < eEnd)) {
7671:         /* Hybrid edges stay the same */
7672:         localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (fMax                              - fStart)*4     + (cMax                            - cStart)*6     + (p  - eMax);
7673:         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]);
7674:         remotePointsNew[m].rank  = rrank;
7675:         ++m;
7676:       } else if ((p >= fStart) && (p < fMax)) {
7677:         /* Interior faces add new faces, edges, and vertex */
7678:         for (r = 0; r < 4; ++r, ++m) {
7679:           localPointsNew[m]        = fStartNew     + (p  - fStart)*4     + r;
7680:           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*4 + r;
7681:           remotePointsNew[m].rank  = rrank;
7682:         }
7683:         for (r = 0; r < 4; ++r, ++m) {
7684:           localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (p  - fStart)*4     + r;
7685:           remotePointsNew[m].index = reStartNew[n] + (rdepthMaxOld[n*(depth+1)+1] - reStart[n])*2 + (rp - rfStart[n])*4 + r;
7686:           remotePointsNew[m].rank  = rrank;
7687:         }
7688:         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (eMax                        - eStart)     + (p  - fStart);
7689:         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rdepthMaxOld[n*(depth+1)+1] - reStart[n]) + (rp - rfStart[n]);
7690:         remotePointsNew[m].rank  = rrank;
7691:         ++m;
7692:       } else if ((p >= fMax) && (p < fEnd)) {
7693:         /* Hybrid faces add new faces and edges */
7694:         for (r = 0; r < 2; ++r, ++m) {
7695:           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*4     + (cMax                            - cStart)*12     + (p  - fMax)*2                              + r;
7696:           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;
7697:           remotePointsNew[m].rank  = rrank;
7698:         }
7699:         localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (fMax                              - fStart)*4     + (cMax                            - cStart)*6     + (eEnd                                    - eMax)                        + (p  - fMax);
7700:         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]);
7701:         remotePointsNew[m].rank  = rrank;
7702:         ++m;
7703:       } else if ((p >= cStart) && (p < cMax)) {
7704:         /* Interior cells add new cells, faces, edges, and vertex */
7705:         for (r = 0; r < 8; ++r, ++m) {
7706:           localPointsNew[m]        = cStartNew     + (p  - cStart)*8     + r;
7707:           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*8 + r;
7708:           remotePointsNew[m].rank  = rrank;
7709:         }
7710:         for (r = 0; r < 12; ++r, ++m) {
7711:           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*4     + (p  - cStart)*12     + r;
7712:           remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*4 + (rp - rcStart[n])*12 + r;
7713:           remotePointsNew[m].rank  = rrank;
7714:         }
7715:         for (r = 0; r < 6; ++r, ++m) {
7716:           localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (fMax                              - fStart)*4     + (p  - cStart)*6     + r;
7717:           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;
7718:           remotePointsNew[m].rank  = rrank;
7719:         }
7720:         for (r = 0; r < 1; ++r, ++m) {
7721:           localPointsNew[m]        = vStartNew     + (eMax                        - eStart)     + (fMax                              - fStart)     + (p  - cStart)     + r;
7722:           remotePointsNew[m].index = rvStartNew[n] + (rdepthMaxOld[n*(depth+1)+1] - reStart[n]) + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n]) + (rp - rcStart[n]) + r;
7723:           remotePointsNew[m].rank  = rrank;
7724:         }
7725:       } else if ((p >= cMax) && (p < cEnd)) {
7726:         /* Hybrid cells add new cells, faces, and edges */
7727:         for (r = 0; r < 4; ++r, ++m) {
7728:           localPointsNew[m]        = cStartNew     + (cMax                            - cStart)*8     + (p  - cMax)*4                            + r;
7729:           remotePointsNew[m].index = rcStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth] - rcStart[n])*8 + (rp - rdepthMaxOld[n*(depth+1)+depth])*4 + r;
7730:           remotePointsNew[m].rank  = rrank;
7731:         }
7732:         for (r = 0; r < 4; ++r, ++m) {
7733:           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*4     + (cMax                            - cStart)*12     + (fEnd                                          - fMax)*2                              + (p  - cMax)*4                            + r;
7734:           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;
7735:           remotePointsNew[m].rank  = rrank;
7736:         }
7737:         localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (fMax                              - fStart)*4     + (cMax                            - cStart)*6     + (eEnd                                    - eMax)                        + (fEnd                                          - fMax)                              + (p  - cMax);
7738:         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]);
7739:         remotePointsNew[m].rank  = rrank;
7740:         ++m;
7741:       }
7742:       break;
7743:     default:
7744:       SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
7745:     }
7746:   }
7747:   if (m != numLeavesNew) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Number of leaf point %d should be %d", m, numLeavesNew);
7748:   ISRestoreIndices(processRanks, &neighbors);
7749:   ISDestroy(&processRanks);
7750:   {
7751:     PetscSFNode *rp, *rtmp;
7752:     PetscInt    *lp, *idx, *ltmp, i;

7754:     /* SF needs sorted leaves to correct calculate Gather */
7755:     PetscMalloc1(numLeavesNew,&idx);
7756:     PetscMalloc1(numLeavesNew, &lp);
7757:     PetscMalloc1(numLeavesNew, &rp);
7758:     for (i = 0; i < numLeavesNew; ++i) {
7759:       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);
7760:       idx[i] = i;
7761:     }
7762:     PetscSortIntWithPermutation(numLeavesNew, localPointsNew, idx);
7763:     for (i = 0; i < numLeavesNew; ++i) {
7764:       lp[i] = localPointsNew[idx[i]];
7765:       rp[i] = remotePointsNew[idx[i]];
7766:     }
7767:     ltmp            = localPointsNew;
7768:     localPointsNew  = lp;
7769:     rtmp            = remotePointsNew;
7770:     remotePointsNew = rp;
7771:     PetscFree(idx);
7772:     PetscFree(ltmp);
7773:     PetscFree(rtmp);
7774:   }
7775:   PetscSFSetGraph(sfNew, pEndNew-pStartNew, numLeavesNew, localPointsNew, PETSC_OWN_POINTER, remotePointsNew, PETSC_OWN_POINTER);
7776:   PetscFree5(rdepthSize,rvStartNew,reStartNew,rfStartNew,rcStartNew);
7777:   PetscFree7(depthSizeOld,rdepthSizeOld,rdepthMaxOld,rvStart,reStart,rfStart,rcStart);
7778:   return(0);
7779: }

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

7789:   DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);
7790:   DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);
7791:   DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);
7792:   DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);
7793:   DMPlexGetDepth(dm, &depth);
7794:   if (refiner) {GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);}
7795:   DMGetNumLabels(dm, &numLabels);
7796:   DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);
7797:   switch (refiner) {
7798:   case REFINER_NOOP:
7799:   case REFINER_SIMPLEX_1D:
7800:   case REFINER_SIMPLEX_2D:
7801:   case REFINER_SIMPLEX_TO_HEX_2D:
7802:   case REFINER_HEX_2D:
7803:   case REFINER_SIMPLEX_3D:
7804:   case REFINER_HEX_3D:
7805:   case REFINER_SIMPLEX_TO_HEX_3D:
7806:     break;
7807:   case REFINER_HYBRID_SIMPLEX_3D:
7808:   case REFINER_HYBRID_HEX_3D:
7809:     if (eMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No edge maximum specified in hybrid mesh");
7810:   case REFINER_HYBRID_SIMPLEX_2D:
7811:   case REFINER_HYBRID_HEX_2D:
7812:     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
7813:     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
7814:     break;
7815:   default:
7816:     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
7817:   }
7818:   for (l = 0; l < numLabels; ++l) {
7819:     DMLabel         label, labelNew;
7820:     const char     *lname;
7821:     PetscBool       isDepth;
7822:     IS              valueIS;
7823:     const PetscInt *values;
7824:     PetscInt        defVal;
7825:     PetscInt        numValues, val;

7827:     DMGetLabelName(dm, l, &lname);
7828:     PetscStrcmp(lname, "depth", &isDepth);
7829:     if (isDepth) continue;
7830:     DMCreateLabel(rdm, lname);
7831:     DMGetLabel(dm, lname, &label);
7832:     DMGetLabel(rdm, lname, &labelNew);
7833:     DMLabelGetDefaultValue(label,&defVal);
7834:     DMLabelSetDefaultValue(labelNew,defVal);
7835:     DMLabelGetValueIS(label, &valueIS);
7836:     ISGetLocalSize(valueIS, &numValues);
7837:     ISGetIndices(valueIS, &values);
7838:     for (val = 0; val < numValues; ++val) {
7839:       IS              pointIS;
7840:       const PetscInt *points;
7841:       PetscInt        numPoints, n;

7843:       DMLabelGetStratumIS(label, values[val], &pointIS);
7844:       ISGetLocalSize(pointIS, &numPoints);
7845:       ISGetIndices(pointIS, &points);
7846:       /* Ensure refined label is created with same number of strata as
7847:        * original (even if no entries here). */
7848:       DMLabelAddStratum(labelNew, values[val]);
7849:       for (n = 0; n < numPoints; ++n) {
7850:         const PetscInt p = points[n];
7851:         switch (refiner) {
7852:         case REFINER_SIMPLEX_1D:
7853:           if ((p >= vStart) && (p < vEnd)) {
7854:             /* Old vertices stay the same */
7855:             newp = vStartNew + (p - vStart);
7856:             DMLabelSetValue(labelNew, newp, values[val]);
7857:           } else if ((p >= cStart) && (p < cEnd)) {
7858:             /* Old cells add new cells and vertex */
7859:             newp = vStartNew + (vEnd - vStart) + (p - cStart);
7860:             DMLabelSetValue(labelNew, newp, values[val]);
7861:             for (r = 0; r < 2; ++r) {
7862:               newp = cStartNew + (p - cStart)*2 + r;
7863:               DMLabelSetValue(labelNew, newp, values[val]);
7864:             }
7865:           }
7866:           break;
7867:         case REFINER_SIMPLEX_2D:
7868:           if ((p >= vStart) && (p < vEnd)) {
7869:             /* Old vertices stay the same */
7870:             newp = vStartNew + (p - vStart);
7871:             DMLabelSetValue(labelNew, newp, values[val]);
7872:           } else if ((p >= fStart) && (p < fEnd)) {
7873:             /* Old faces add new faces and vertex */
7874:             newp = vStartNew + (vEnd - vStart) + (p - fStart);
7875:             DMLabelSetValue(labelNew, newp, values[val]);
7876:             for (r = 0; r < 2; ++r) {
7877:               newp = fStartNew + (p - fStart)*2 + r;
7878:               DMLabelSetValue(labelNew, newp, values[val]);
7879:             }
7880:           } else if ((p >= cStart) && (p < cEnd)) {
7881:             /* Old cells add new cells and interior faces */
7882:             for (r = 0; r < 4; ++r) {
7883:               newp = cStartNew + (p - cStart)*4 + r;
7884:               DMLabelSetValue(labelNew, newp, values[val]);
7885:             }
7886:             for (r = 0; r < 3; ++r) {
7887:               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*3 + r;
7888:               DMLabelSetValue(labelNew, newp, values[val]);
7889:             }
7890:           }
7891:           break;
7892:         case REFINER_SIMPLEX_TO_HEX_2D:
7893:           if ((p >= vStart) && (p < vEnd)) {
7894:             /* Old vertices stay the same */
7895:             newp = vStartNew + (p - vStart);
7896:             DMLabelSetValue(labelNew, newp, values[val]);
7897:           } else if ((p >= fStart) && (p < fEnd)) {
7898:             /* Old faces add new faces and vertex */
7899:             newp = vStartNew + (vEnd - vStart) + (p - fStart);
7900:             DMLabelSetValue(labelNew, newp, values[val]);
7901:             for (r = 0; r < 2; ++r) {
7902:               newp = fStartNew + (p - fStart)*2 + r;
7903:               DMLabelSetValue(labelNew, newp, values[val]);
7904:             }
7905:           } else if ((p >= cStart) && (p < cEnd)) {
7906:             /* Old cells add new cells, interior faces, and a vertex */
7907:             for (r = 0; r < 3; ++r) {
7908:               newp = cStartNew + (p - cStart)*3 + r;
7909:               DMLabelSetValue(labelNew, newp, values[val]);
7910:             }
7911:             for (r = 0; r < 3; ++r) {
7912:               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*3 + r;
7913:               DMLabelSetValue(labelNew, newp, values[val]);
7914:             }
7915:             newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + p;
7916:             DMLabelSetValue(labelNew, newp, values[val]);
7917:           }
7918:           break;
7919:         case REFINER_HEX_2D:
7920:           if ((p >= vStart) && (p < vEnd)) {
7921:             /* Old vertices stay the same */
7922:             newp = vStartNew + (p - vStart);
7923:             DMLabelSetValue(labelNew, newp, values[val]);
7924:           } else if ((p >= fStart) && (p < fEnd)) {
7925:             /* Old faces add new faces and vertex */
7926:             newp = vStartNew + (vEnd - vStart) + (p - fStart);
7927:             DMLabelSetValue(labelNew, newp, values[val]);
7928:             for (r = 0; r < 2; ++r) {
7929:               newp = fStartNew + (p - fStart)*2 + r;
7930:               DMLabelSetValue(labelNew, newp, values[val]);
7931:             }
7932:           } else if ((p >= cStart) && (p < cEnd)) {
7933:             /* Old cells add new cells and interior faces and vertex */
7934:             for (r = 0; r < 4; ++r) {
7935:               newp = cStartNew + (p - cStart)*4 + r;
7936:               DMLabelSetValue(labelNew, newp, values[val]);
7937:             }
7938:             for (r = 0; r < 4; ++r) {
7939:               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*4 + r;
7940:               DMLabelSetValue(labelNew, newp, values[val]);
7941:             }
7942:             newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (p - cStart);
7943:             DMLabelSetValue(labelNew, newp, values[val]);
7944:           }
7945:           break;
7946:         case REFINER_HYBRID_SIMPLEX_2D:
7947:           if ((p >= vStart) && (p < vEnd)) {
7948:             /* Old vertices stay the same */
7949:             newp = vStartNew + (p - vStart);
7950:             DMLabelSetValue(labelNew, newp, values[val]);
7951:           } else if ((p >= fStart) && (p < fMax)) {
7952:             /* Old interior faces add new faces and vertex */
7953:             newp = vStartNew + (vEnd - vStart) + (p - fStart);
7954:             DMLabelSetValue(labelNew, newp, values[val]);
7955:             for (r = 0; r < 2; ++r) {
7956:               newp = fStartNew + (p - fStart)*2 + r;
7957:               DMLabelSetValue(labelNew, newp, values[val]);
7958:             }
7959:           } else if ((p >= fMax) && (p < fEnd)) {
7960:             /* Old hybrid faces stay the same */
7961:             newp = fStartNew + (fMax - fStart)*2 + (p - fMax);
7962:             DMLabelSetValue(labelNew, newp, values[val]);
7963:           } else if ((p >= cStart) && (p < cMax)) {
7964:             /* Old interior cells add new cells and interior faces */
7965:             for (r = 0; r < 4; ++r) {
7966:               newp = cStartNew + (p - cStart)*4 + r;
7967:               DMLabelSetValue(labelNew, newp, values[val]);
7968:             }
7969:             for (r = 0; r < 3; ++r) {
7970:               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*3 + r;
7971:               DMLabelSetValue(labelNew, newp, values[val]);
7972:             }
7973:           } else if ((p >= cMax) && (p < cEnd)) {
7974:             /* Old hybrid cells add new cells and hybrid face */
7975:             for (r = 0; r < 2; ++r) {
7976:               newp = cStartNew + (cMax - cStart)*4 + (p - cMax)*2 + r;
7977:               DMLabelSetValue(labelNew, newp, values[val]);
7978:             }
7979:             newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (p - cMax);
7980:             DMLabelSetValue(labelNew, newp, values[val]);
7981:           }
7982:           break;
7983:         case REFINER_HYBRID_HEX_2D:
7984:           if ((p >= vStart) && (p < vEnd)) {
7985:             /* Old vertices stay the same */
7986:             newp = vStartNew + (p - vStart);
7987:             DMLabelSetValue(labelNew, newp, values[val]);
7988:           } else if ((p >= fStart) && (p < fMax)) {
7989:             /* Old interior faces add new faces and vertex */
7990:             newp = vStartNew + (vEnd - vStart) + (p - fStart);
7991:             DMLabelSetValue(labelNew, newp, values[val]);
7992:             for (r = 0; r < 2; ++r) {
7993:               newp = fStartNew + (p - fStart)*2 + r;
7994:               DMLabelSetValue(labelNew, newp, values[val]);
7995:             }
7996:           } else if ((p >= fMax) && (p < fEnd)) {
7997:             /* Old hybrid faces stay the same */
7998:             newp = fStartNew + (fMax - fStart)*2 + (p - fMax);
7999:             DMLabelSetValue(labelNew, newp, values[val]);
8000:           } else if ((p >= cStart) && (p < cMax)) {
8001:             /* Old interior cells add new cells, interior faces, and vertex */
8002:             for (r = 0; r < 4; ++r) {
8003:               newp = cStartNew + (p - cStart)*4 + r;
8004:               DMLabelSetValue(labelNew, newp, values[val]);
8005:             }
8006:             for (r = 0; r < 4; ++r) {
8007:               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*4 + r;
8008:               DMLabelSetValue(labelNew, newp, values[val]);
8009:             }
8010:             newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (p - cStart);
8011:             DMLabelSetValue(labelNew, newp, values[val]);
8012:           } else if ((p >= cMax) && (p < cEnd)) {
8013:             /* Old hybrid cells add new cells and hybrid face */
8014:             for (r = 0; r < 2; ++r) {
8015:               newp = cStartNew + (cMax - cStart)*4 + (p - cMax)*2 + r;
8016:               DMLabelSetValue(labelNew, newp, values[val]);
8017:             }
8018:             newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*4 + (p - cMax);
8019:             DMLabelSetValue(labelNew, newp, values[val]);
8020:           }
8021:           break;
8022:         case REFINER_SIMPLEX_3D:
8023:           if ((p >= vStart) && (p < vEnd)) {
8024:             /* Old vertices stay the same */
8025:             newp = vStartNew + (p - vStart);
8026:             DMLabelSetValue(labelNew, newp, values[val]);
8027:           } else if ((p >= eStart) && (p < eEnd)) {
8028:             /* Old edges add new edges and vertex */
8029:             for (r = 0; r < 2; ++r) {
8030:               newp = eStartNew + (p - eStart)*2 + r;
8031:               DMLabelSetValue(labelNew, newp, values[val]);
8032:             }
8033:             newp = vStartNew + (vEnd - vStart) + (p - eStart);
8034:             DMLabelSetValue(labelNew, newp, values[val]);
8035:           } else if ((p >= fStart) && (p < fEnd)) {
8036:             /* Old faces add new faces and edges */
8037:             for (r = 0; r < 4; ++r) {
8038:               newp = fStartNew + (p - fStart)*4 + r;
8039:               DMLabelSetValue(labelNew, newp, values[val]);
8040:             }
8041:             for (r = 0; r < 3; ++r) {
8042:               newp = eStartNew + (eEnd - eStart)*2 + (p - fStart)*3 + r;
8043:               DMLabelSetValue(labelNew, newp, values[val]);
8044:             }
8045:           } else if ((p >= cStart) && (p < cEnd)) {
8046:             /* Old cells add new cells and interior faces and edges */
8047:             for (r = 0; r < 8; ++r) {
8048:               newp = cStartNew + (p - cStart)*8 + r;
8049:               DMLabelSetValue(labelNew, newp, values[val]);
8050:             }
8051:             for (r = 0; r < 8; ++r) {
8052:               newp = fStartNew + (fEnd - fStart)*4 + (p - cStart)*8 + r;
8053:               DMLabelSetValue(labelNew, newp, values[val]);
8054:             }
8055:             for (r = 0; r < 1; ++r) {
8056:               newp = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (p - cStart)*1 + r;
8057:               DMLabelSetValue(labelNew, newp, values[val]);
8058:             }
8059:           }
8060:           break;
8061:         case REFINER_SIMPLEX_TO_HEX_3D:
8062:           if ((p >= vStart) && (p < vEnd)) {
8063:             /* Old vertices stay the same */
8064:             newp = vStartNew + (p - vStart);
8065:             DMLabelSetValue(labelNew, newp, values[val]);
8066:           } else if ((p >= eStart) && (p < eEnd)) {
8067:             /* Old edges add new edges and vertex */
8068:             for (r = 0; r < 2; ++r) {
8069:               newp = eStartNew + (p - eStart)*2 + r;
8070:               DMLabelSetValue(labelNew, newp, values[val]);
8071:             }
8072:             newp = vStartNew + (vEnd - vStart) + (p - eStart);
8073:             DMLabelSetValue(labelNew, newp, values[val]);
8074:           } else if ((p >= fStart) && (p < fEnd)) {
8075:             /* Old faces add new faces, edges and a vertex */
8076:             for (r = 0; r < 3; ++r) {
8077:               newp = fStartNew + (p - fStart)*3 + r;
8078:               DMLabelSetValue(labelNew, newp, values[val]);
8079:             }
8080:             for (r = 0; r < 3; ++r) {
8081:               newp = eStartNew + (eEnd - eStart)*2 + (p - fStart)*3 + r;
8082:               DMLabelSetValue(labelNew, newp, values[val]);
8083:             }
8084:           } else if ((p >= cStart) && (p < cEnd)) {
8085:             /* Old cells add new cells and interior faces and edges and a vertex */
8086:             for (r = 0; r < 4; ++r) {
8087:               newp = cStartNew + (p - cStart)*4 + r;
8088:               DMLabelSetValue(labelNew, newp, values[val]);
8089:             }
8090:             for (r = 0; r < 6; ++r) {
8091:               newp = fStartNew + (fEnd - fStart)*3 + (p - cStart)*6 + r;
8092:               DMLabelSetValue(labelNew, newp, values[val]);
8093:             }
8094:             for (r = 0; r < 4; ++r) {
8095:               newp = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (p - cStart)*4 + r;
8096:               DMLabelSetValue(labelNew, newp, values[val]);
8097:             }
8098:             newp = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (fEnd - fStart) + p - cStart;
8099:             DMLabelSetValue(labelNew, newp, values[val]);
8100:           }
8101:           break;
8102:         case REFINER_HYBRID_SIMPLEX_3D:
8103:           if ((p >= vStart) && (p < vEnd)) {
8104:             /* Interior vertices stay the same */
8105:             newp = vStartNew + (p - vStart);
8106:             DMLabelSetValue(labelNew, newp, values[val]);
8107:           } else if ((p >= eStart) && (p < eMax)) {
8108:             /* Interior edges add new edges and vertex */
8109:             for (r = 0; r < 2; ++r) {
8110:               newp = eStartNew + (p - eStart)*2 + r;
8111:               DMLabelSetValue(labelNew, newp, values[val]);
8112:             }
8113:             newp = vStartNew + (vEnd - vStart) + (p - eStart);
8114:             DMLabelSetValue(labelNew, newp, values[val]);
8115:           } else if ((p >= eMax) && (p < eEnd)) {
8116:             /* Hybrid edges stay the same */
8117:             newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (p - eMax);
8118:             DMLabelSetValue(labelNew, newp, values[val]);
8119:           } else if ((p >= fStart) && (p < fMax)) {
8120:             /* Interior faces add new faces and edges */
8121:             for (r = 0; r < 4; ++r) {
8122:               newp = fStartNew + (p - fStart)*4 + r;
8123:               DMLabelSetValue(labelNew, newp, values[val]);
8124:             }
8125:             for (r = 0; r < 3; ++r) {
8126:               newp = eStartNew + (eMax - eStart)*2 + (p - fStart)*3 + r;
8127:               DMLabelSetValue(labelNew, newp, values[val]);
8128:             }
8129:           } else if ((p >= fMax) && (p < fEnd)) {
8130:             /* Hybrid faces add new faces and edges */
8131:             for (r = 0; r < 2; ++r) {
8132:               newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (p - fMax)*2 + r;
8133:               DMLabelSetValue(labelNew, newp, values[val]);
8134:             }
8135:             newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (p - fMax);
8136:             DMLabelSetValue(labelNew, newp, values[val]);
8137:           } else if ((p >= cStart) && (p < cMax)) {
8138:             /* Interior cells add new cells, faces, and edges */
8139:             for (r = 0; r < 8; ++r) {
8140:               newp = cStartNew + (p - cStart)*8 + r;
8141:               DMLabelSetValue(labelNew, newp, values[val]);
8142:             }
8143:             for (r = 0; r < 8; ++r) {
8144:               newp = fStartNew + (fMax - fStart)*4 + (p - cStart)*8 + r;
8145:               DMLabelSetValue(labelNew, newp, values[val]);
8146:             }
8147:             newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (p - cStart);
8148:             DMLabelSetValue(labelNew, newp, values[val]);
8149:           } else if ((p >= cMax) && (p < cEnd)) {
8150:             /* Hybrid cells add new cells and faces */
8151:             for (r = 0; r < 4; ++r) {
8152:               newp = cStartNew + (cMax - cStart)*8 + (p - cMax)*4 + r;
8153:               DMLabelSetValue(labelNew, newp, values[val]);
8154:             }
8155:             for (r = 0; r < 3; ++r) {
8156:               newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (p - cMax)*3 + r;
8157:               DMLabelSetValue(labelNew, newp, values[val]);
8158:             }
8159:           }
8160:           break;
8161:         case REFINER_HEX_3D:
8162:           if ((p >= vStart) && (p < vEnd)) {
8163:             /* Old vertices stay the same */
8164:             newp = vStartNew + (p - vStart);
8165:             DMLabelSetValue(labelNew, newp, values[val]);
8166:           } else if ((p >= eStart) && (p < eEnd)) {
8167:             /* Old edges add new edges and vertex */
8168:             for (r = 0; r < 2; ++r) {
8169:               newp = eStartNew + (p - eStart)*2 + r;
8170:               DMLabelSetValue(labelNew, newp, values[val]);
8171:             }
8172:             newp = vStartNew + (vEnd - vStart) + (p - eStart);
8173:             DMLabelSetValue(labelNew, newp, values[val]);
8174:           } else if ((p >= fStart) && (p < fEnd)) {
8175:             /* Old faces add new faces, edges, and vertex */
8176:             for (r = 0; r < 4; ++r) {
8177:               newp = fStartNew + (p - fStart)*4 + r;
8178:               DMLabelSetValue(labelNew, newp, values[val]);
8179:             }
8180:             for (r = 0; r < 4; ++r) {
8181:               newp = eStartNew + (eEnd - eStart)*2 + (p - fStart)*4 + r;
8182:               DMLabelSetValue(labelNew, newp, values[val]);
8183:             }
8184:             newp = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (p - fStart);
8185:             DMLabelSetValue(labelNew, newp, values[val]);
8186:           } else if ((p >= cStart) && (p < cEnd)) {
8187:             /* Old cells add new cells, faces, edges, and vertex */
8188:             for (r = 0; r < 8; ++r) {
8189:               newp = cStartNew + (p - cStart)*8 + r;
8190:               DMLabelSetValue(labelNew, newp, values[val]);
8191:             }
8192:             for (r = 0; r < 12; ++r) {
8193:               newp = fStartNew + (fEnd - fStart)*4 + (p - cStart)*12 + r;
8194:               DMLabelSetValue(labelNew, newp, values[val]);
8195:             }
8196:             for (r = 0; r < 6; ++r) {
8197:               newp = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*4 + (p - cStart)*6 + r;
8198:               DMLabelSetValue(labelNew, newp, values[val]);
8199:             }
8200:             newp = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (fEnd - fStart) + (p - cStart);
8201:             DMLabelSetValue(labelNew, newp, values[val]);
8202:           }
8203:           break;
8204:         case REFINER_HYBRID_HEX_3D:
8205:           if ((p >= vStart) && (p < vEnd)) {
8206:             /* Interior vertices stay the same */
8207:             newp = vStartNew + (p - vStart);
8208:             DMLabelSetValue(labelNew, newp, values[val]);
8209:           } else if ((p >= eStart) && (p < eMax)) {
8210:             /* Interior edges add new edges and vertex */
8211:             for (r = 0; r < 2; ++r) {
8212:               newp = eStartNew + (p - eStart)*2 + r;
8213:               DMLabelSetValue(labelNew, newp, values[val]);
8214:             }
8215:             newp = vStartNew + (vEnd - vStart) + (p - eStart);
8216:             DMLabelSetValue(labelNew, newp, values[val]);
8217:           } else if ((p >= eMax) && (p < eEnd)) {
8218:             /* Hybrid edges stay the same */
8219:             newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (p - eMax);
8220:             DMLabelSetValue(labelNew, newp, values[val]);
8221:           } else if ((p >= fStart) && (p < fMax)) {
8222:             /* Interior faces add new faces, edges, and vertex */
8223:             for (r = 0; r < 4; ++r) {
8224:               newp = fStartNew + (p - fStart)*4 + r;
8225:               DMLabelSetValue(labelNew, newp, values[val]);
8226:             }
8227:             for (r = 0; r < 4; ++r) {
8228:               newp = eStartNew + (eMax - eStart)*2 + (p - fStart)*4 + r;
8229:               DMLabelSetValue(labelNew, newp, values[val]);
8230:             }
8231:             newp = vStartNew + (vEnd - vStart) + (eMax - eStart) + (p - fStart);
8232:             DMLabelSetValue(labelNew, newp, values[val]);
8233:           } else if ((p >= fMax) && (p < fEnd)) {
8234:             /* Hybrid faces add new faces and edges */
8235:             for (r = 0; r < 2; ++r) {
8236:               newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (p - fMax)*2 + r;
8237:               DMLabelSetValue(labelNew, newp, values[val]);
8238:             }
8239:             newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (p - fMax);
8240:             DMLabelSetValue(labelNew, newp, values[val]);
8241:           } else if ((p >= cStart) && (p < cMax)) {
8242:             /* Interior cells add new cells, faces, edges, and vertex */
8243:             for (r = 0; r < 8; ++r) {
8244:               newp = cStartNew + (p - cStart)*8 + r;
8245:               DMLabelSetValue(labelNew, newp, values[val]);
8246:             }
8247:             for (r = 0; r < 12; ++r) {
8248:               newp = fStartNew + (fMax - fStart)*4 + (p - cStart)*12 + r;
8249:               DMLabelSetValue(labelNew, newp, values[val]);
8250:             }
8251:             for (r = 0; r < 6; ++r) {
8252:               newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (p - cStart)*6 + r;
8253:               DMLabelSetValue(labelNew, newp, values[val]);
8254:             }
8255:             newp = vStartNew + (vEnd - vStart) + (eMax - eStart) + (fMax - fStart) + (p - cStart);
8256:             DMLabelSetValue(labelNew, newp, values[val]);
8257:           } else if ((p >= cMax) && (p < cEnd)) {
8258:             /* Hybrid cells add new cells, faces, and edges */
8259:             for (r = 0; r < 4; ++r) {
8260:               newp = cStartNew + (cMax - cStart)*8 + (p - cMax)*4 + r;
8261:               DMLabelSetValue(labelNew, newp, values[val]);
8262:             }
8263:             for (r = 0; r < 4; ++r) {
8264:               newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd - fMax)*2 + (p - cMax)*4 + r;
8265:               DMLabelSetValue(labelNew, newp, values[val]);
8266:             }
8267:             newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (fEnd - fMax) + (p - cMax);
8268:             DMLabelSetValue(labelNew, newp, values[val]);
8269:           }
8270:           break;
8271:         default:
8272:           SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
8273:         }
8274:       }
8275:       ISRestoreIndices(pointIS, &points);
8276:       ISDestroy(&pointIS);
8277:     }
8278:     ISRestoreIndices(valueIS, &values);
8279:     ISDestroy(&valueIS);
8280:     if (0) {
8281:       DMLabelView(labelNew, PETSC_VIEWER_STDOUT_WORLD);
8282:     }
8283:   }
8284:   return(0);
8285: }

8287: /* This will only work for interpolated meshes */
8288: PetscErrorCode DMPlexRefineUniform_Internal(DM dm, CellRefiner cellRefiner, DM *dmRefined)
8289: {
8290:   DM             rdm;
8291:   PetscInt      *depthSize;
8292:   PetscInt       dim, depth = 0, d, pStart = 0, pEnd = 0;

8296:   DMCreate(PetscObjectComm((PetscObject)dm), &rdm);
8297:   DMSetType(rdm, DMPLEX);
8298:   DMGetDimension(dm, &dim);
8299:   DMSetDimension(rdm, dim);
8300:   /* Calculate number of new points of each depth */
8301:   DMPlexGetDepth(dm, &depth);
8302:   if (depth >= 0 && dim != depth) SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "Mesh must be interpolated for regular refinement");
8303:   PetscMalloc1(depth+1, &depthSize);
8304:   PetscMemzero(depthSize, (depth+1) * sizeof(PetscInt));
8305:   CellRefinerGetSizes(cellRefiner, dm, depthSize);
8306:   /* Step 1: Set chart */
8307:   for (d = 0; d <= depth; ++d) pEnd += depthSize[d];
8308:   DMPlexSetChart(rdm, pStart, pEnd);
8309:   /* Step 2: Set cone/support sizes */
8310:   CellRefinerSetConeSizes(cellRefiner, dm, depthSize, rdm);
8311:   /* Step 3: Setup refined DM */
8312:   DMSetUp(rdm);
8313:   /* Step 4: Set cones and supports */
8314:   CellRefinerSetCones(cellRefiner, dm, depthSize, rdm);
8315:   /* Step 5: Stratify */
8316:   DMPlexStratify(rdm);
8317:   /* Step 6: Create pointSF */
8318:   CellRefinerCreateSF(cellRefiner, dm, depthSize, rdm);
8319:   /* Step 7: Create labels */
8320:   CellRefinerCreateLabels(cellRefiner, dm, depthSize, rdm);
8321:   /* Step 8: Set coordinates */
8322:   CellRefinerSetCoordinates(cellRefiner, dm, depthSize, rdm);
8323:   PetscFree(depthSize);

8325:   *dmRefined = rdm;
8326:   return(0);
8327: }

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

8332:   Input Parameter:
8333: . dm - The coarse DM

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

8338:   Level: developer

8340: .seealso: DMRefine(), DMPlexSetRefinementUniform(), DMPlexCreateSubpointIS()
8341: @*/
8342: PetscErrorCode DMPlexCreateCoarsePointIS(DM dm, IS *fpointIS)
8343: {
8344:   CellRefiner    cellRefiner;
8345:   PetscInt      *depthSize, *fpoints;
8346:   PetscInt       cStartNew = 0, vStartNew = 0, fStartNew = 0, eStartNew = 0;
8347:   PetscInt       depth, pStart, pEnd, p, vStart, vEnd, v;

8351:   DMPlexGetDepth(dm, &depth);
8352:   DMPlexGetChart(dm, &pStart, &pEnd);
8353:   DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);
8354:   DMPlexGetCellRefiner_Internal(dm, &cellRefiner);
8355:   PetscMalloc1(depth+1, &depthSize);
8356:   CellRefinerGetSizes(cellRefiner, dm, depthSize);
8357:   if (cellRefiner) {GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);}
8358:   PetscMalloc1(pEnd-pStart,&fpoints);
8359:   for (p = 0; p < pEnd-pStart; ++p) fpoints[p] = -1;
8360:   switch (cellRefiner) {
8361:   case REFINER_SIMPLEX_1D:
8362:   case REFINER_SIMPLEX_2D:
8363:   case REFINER_HYBRID_SIMPLEX_2D:
8364:   case REFINER_HEX_2D:
8365:   case REFINER_HYBRID_HEX_2D:
8366:   case REFINER_SIMPLEX_3D:
8367:   case REFINER_HYBRID_SIMPLEX_3D:
8368:   case REFINER_HEX_3D:
8369:   case REFINER_HYBRID_HEX_3D:
8370:     for (v = vStart; v < vEnd; ++v) fpoints[v-pStart] = vStartNew + (v - vStart);
8371:     break;
8372:   default:
8373:     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", cellRefiner);
8374:   }
8375:   ISCreateGeneral(PETSC_COMM_SELF, pEnd-pStart, fpoints, PETSC_OWN_POINTER, fpointIS);
8376:   PetscFree(depthSize);
8377:   return(0);
8378: }

8380: /*@
8381:   DMPlexSetRefinementUniform - Set the flag for uniform refinement

8383:   Input Parameters:
8384: + dm - The DM
8385: - refinementUniform - The flag for uniform refinement

8387:   Level: developer

8389: .seealso: DMRefine(), DMPlexGetRefinementUniform(), DMPlexGetRefinementLimit(), DMPlexSetRefinementLimit()
8390: @*/
8391: PetscErrorCode DMPlexSetRefinementUniform(DM dm, PetscBool refinementUniform)
8392: {
8393:   DM_Plex *mesh = (DM_Plex*) dm->data;

8397:   mesh->refinementUniform = refinementUniform;
8398:   return(0);
8399: }

8401: /*@
8402:   DMPlexGetRefinementUniform - Retrieve the flag for uniform refinement

8404:   Input Parameter:
8405: . dm - The DM

8407:   Output Parameter:
8408: . refinementUniform - The flag for uniform refinement

8410:   Level: developer

8412: .seealso: DMRefine(), DMPlexSetRefinementUniform(), DMPlexGetRefinementLimit(), DMPlexSetRefinementLimit()
8413: @*/
8414: PetscErrorCode DMPlexGetRefinementUniform(DM dm, PetscBool *refinementUniform)
8415: {
8416:   DM_Plex *mesh = (DM_Plex*) dm->data;

8421:   *refinementUniform = mesh->refinementUniform;
8422:   return(0);
8423: }

8425: /*@
8426:   DMPlexSetRefinementLimit - Set the maximum cell volume for refinement

8428:   Input Parameters:
8429: + dm - The DM
8430: - refinementLimit - The maximum cell volume in the refined mesh

8432:   Level: developer

8434: .seealso: DMRefine(), DMPlexGetRefinementLimit(), DMPlexGetRefinementUniform(), DMPlexSetRefinementUniform()
8435: @*/
8436: PetscErrorCode DMPlexSetRefinementLimit(DM dm, PetscReal refinementLimit)
8437: {
8438:   DM_Plex *mesh = (DM_Plex*) dm->data;

8442:   mesh->refinementLimit = refinementLimit;
8443:   return(0);
8444: }

8446: /*@
8447:   DMPlexGetRefinementLimit - Retrieve the maximum cell volume for refinement

8449:   Input Parameter:
8450: . dm - The DM

8452:   Output Parameter:
8453: . refinementLimit - The maximum cell volume in the refined mesh

8455:   Level: developer

8457: .seealso: DMRefine(), DMPlexSetRefinementLimit(), DMPlexGetRefinementUniform(), DMPlexSetRefinementUniform()
8458: @*/
8459: PetscErrorCode DMPlexGetRefinementLimit(DM dm, PetscReal *refinementLimit)
8460: {
8461:   DM_Plex *mesh = (DM_Plex*) dm->data;

8466:   /* if (mesh->refinementLimit < 0) = getMaxVolume()/2.0; */
8467:   *refinementLimit = mesh->refinementLimit;
8468:   return(0);
8469: }

8471: /*@
8472:   DMPlexSetRefinementFunction - Set the function giving the maximum cell volume for refinement

8474:   Input Parameters:
8475: + dm - The DM
8476: - refinementFunc - Function giving the maximum cell volume in the refined mesh

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

8482:   Level: developer

8484: .seealso: DMRefine(), DMPlexGetRefinementFunction(), DMPlexGetRefinementUniform(), DMPlexSetRefinementUniform(), DMPlexGetRefinementLimit(), DMPlexSetRefinementLimit()
8485: @*/
8486: PetscErrorCode DMPlexSetRefinementFunction(DM dm, PetscErrorCode (*refinementFunc)(const PetscReal [], PetscReal *))
8487: {
8488:   DM_Plex *mesh = (DM_Plex*) dm->data;

8492:   mesh->refinementFunc = refinementFunc;
8493:   return(0);
8494: }

8496: /*@
8497:   DMPlexGetRefinementFunction - Get the function giving the maximum cell volume for refinement

8499:   Input Parameter:
8500: . dm - The DM

8502:   Output Parameter:
8503: . refinementFunc - Function giving the maximum cell volume in the refined mesh

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

8509:   Level: developer

8511: .seealso: DMRefine(), DMPlexSetRefinementFunction(), DMPlexGetRefinementUniform(), DMPlexSetRefinementUniform(), DMPlexGetRefinementLimit(), DMPlexSetRefinementLimit()
8512: @*/
8513: PetscErrorCode DMPlexGetRefinementFunction(DM dm, PetscErrorCode (**refinementFunc)(const PetscReal [], PetscReal *))
8514: {
8515:   DM_Plex *mesh = (DM_Plex*) dm->data;

8520:   *refinementFunc = mesh->refinementFunc;
8521:   return(0);
8522: }

8524: PetscErrorCode DMPlexGetCellRefiner_Internal(DM dm, CellRefiner *cellRefiner)
8525: {
8526:   PetscInt       dim, cStart, cEnd, coneSize, cMax, fMax;

8530:   DMGetDimension(dm, &dim);
8531:   DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);
8532:   if (cEnd <= cStart) {*cellRefiner = REFINER_NOOP; return(0);}
8533:   DMPlexGetConeSize(dm, cStart, &coneSize);
8534:   DMPlexGetHybridBounds(dm, &cMax, &fMax, NULL, NULL);
8535:   switch (dim) {
8536:   case 1:
8537:     switch (coneSize) {
8538:     case 2:
8539:       *cellRefiner = REFINER_SIMPLEX_1D;
8540:       break;
8541:     default:
8542:       SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown coneSize %d in dimension %d for cell refiner", coneSize, dim);
8543:     }
8544:     break;
8545:   case 2:
8546:     switch (coneSize) {
8547:     case 3:
8548:       if (cMax >= 0) *cellRefiner = REFINER_HYBRID_SIMPLEX_2D;
8549:       else *cellRefiner = REFINER_SIMPLEX_2D;
8550:       break;
8551:     case 4:
8552:       if (cMax >= 0 && fMax >= 0) *cellRefiner = REFINER_HYBRID_HEX_2D;
8553:       else *cellRefiner = REFINER_HEX_2D;
8554:       break;
8555:     default:
8556:       SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown coneSize %d in dimension %d for cell refiner", coneSize, dim);
8557:     }
8558:     break;
8559:   case 3:
8560:     switch (coneSize) {
8561:     case 4:
8562:       if (cMax >= 0) *cellRefiner = REFINER_HYBRID_SIMPLEX_3D;
8563:       else *cellRefiner = REFINER_SIMPLEX_3D;
8564:       break;
8565:     case 6:
8566:       if (cMax >= 0) *cellRefiner = REFINER_HYBRID_HEX_3D;
8567:       else *cellRefiner = REFINER_HEX_3D;
8568:       break;
8569:     default:
8570:       SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown coneSize %d in dimension %d for cell refiner", coneSize, dim);
8571:     }
8572:     break;
8573:   default:
8574:     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown dimension %d for cell refiner", dim);
8575:   }
8576:   return(0);
8577: }

8579: PetscErrorCode DMRefine_Plex(DM dm, MPI_Comm comm, DM *dmRefined)
8580: {
8581:   PetscBool      isUniform;

8585:   DMPlexGetRefinementUniform(dm, &isUniform);
8586:   if (isUniform) {
8587:     CellRefiner cellRefiner;
8588:     PetscBool   localized;

8590:     DMGetCoordinatesLocalized(dm, &localized);
8591:     DMPlexGetCellRefiner_Internal(dm, &cellRefiner);
8592:     DMPlexRefineUniform_Internal(dm, cellRefiner, dmRefined);
8593:     DMCopyBoundary(dm, *dmRefined);
8594:     if (localized) {DMLocalizeCoordinates(*dmRefined);}
8595:   } else {
8596:     DMPlexRefine_Internal(dm, NULL, dmRefined);
8597:   }
8598:   return(0);
8599: }

8601: PetscErrorCode DMRefineHierarchy_Plex(DM dm, PetscInt nlevels, DM dmRefined[])
8602: {
8603:   DM             cdm = dm;
8604:   PetscInt       r;
8605:   PetscBool      isUniform, localized;

8609:   DMPlexGetRefinementUniform(dm, &isUniform);
8610:   DMGetCoordinatesLocalized(dm, &localized);
8611:   if (isUniform) {
8612:     for (r = 0; r < nlevels; ++r) {
8613:       CellRefiner cellRefiner;

8615:       DMPlexGetCellRefiner_Internal(cdm, &cellRefiner);
8616:       DMPlexRefineUniform_Internal(cdm, cellRefiner, &dmRefined[r]);
8617:       DMCopyBoundary(cdm, dmRefined[r]);
8618:       if (localized) {DMLocalizeCoordinates(dmRefined[r]);}
8619:       DMSetCoarseDM(dmRefined[r], cdm);
8620:       DMPlexSetRegularRefinement(dmRefined[r], PETSC_TRUE);
8621:       cdm  = dmRefined[r];
8622:     }
8623:   } else {
8624:     for (r = 0; r < nlevels; ++r) {
8625:       DMRefine(cdm, PetscObjectComm((PetscObject) dm), &dmRefined[r]);
8626:       DMCopyBoundary(cdm, dmRefined[r]);
8627:       if (localized) {DMLocalizeCoordinates(dmRefined[r]);}
8628:       DMSetCoarseDM(dmRefined[r], cdm);
8629:       cdm  = dmRefined[r];
8630:     }
8631:   }
8632:   return(0);
8633: }