Actual source code: plexrefine.c

petsc-3.8.4 2018-03-24
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:   default:
115:     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
116:   }
117:   if (v0) {*v0 = v; *jac = j; *invjac = invj;}
118:   return(0);
119: }

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

126:   PetscFree3(*v0,*jac,*invjac);
127:   return(0);
128: }

130: /* Should this be here or in the DualSpace somehow? */
131: PetscErrorCode CellRefinerInCellTest_Internal(CellRefiner refiner, const PetscReal point[], PetscBool *inside)
132: {
133:   PetscReal sum = 0.0;
134:   PetscInt  d;

137:   *inside = PETSC_TRUE;
138:   switch (refiner) {
139:   case REFINER_NOOP: break;
140:   case REFINER_SIMPLEX_2D:
141:     for (d = 0; d < 2; ++d) {
142:       if (point[d] < -1.0) {*inside = PETSC_FALSE; break;}
143:       sum += point[d];
144:     }
145:     if (sum > 1.0e-10) {*inside = PETSC_FALSE; break;}
146:     break;
147:   case REFINER_HEX_2D:
148:     for (d = 0; d < 2; ++d) if ((point[d] < -1.00000000001) || (point[d] > 1.000000000001)) {*inside = PETSC_FALSE; break;}
149:     break;
150:   default:
151:     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
152:   }
153:   return(0);
154: }

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

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

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

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

278: /* Return the interior edge number connecting the midpoints of the triangle edges r
279:    and r+1 in the transitive closure for triangle orientation o */
280: PETSC_STATIC_INLINE PetscInt GetTriMidEdge_Static(PetscInt o, PetscInt r) {
281:   return (o < 0 ? 1-(o+r) : o+r)%3;
282: }
283: PETSC_STATIC_INLINE PetscInt GetTriMidEdgeInverse_Static(PetscInt o, PetscInt s) {
284:   return (o < 0 ? 1-(o+s) : 3+s-o)%3;
285: }

287: /* Return the interior edge number connecting the midpoint of the triangle edge r
288:    (in the transitive closure) and the vertex in the interior of the face for triangle orientation o */
289: PETSC_STATIC_INLINE PetscInt GetTriInteriorEdge_Static(PetscInt o, PetscInt r) {
290:   return (o < 0 ? 2-(o+r) : o+r)%3;
291: }
292: PETSC_STATIC_INLINE PetscInt GetTriInteriorEdgeInverse_Static(PetscInt o, PetscInt s) {
293:   return (o < 0 ? 2-(o+s) : 3+s-o)%3;
294: }

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

304: /* Return quad subface for orientation o, if it is r for o == 0 */
305: PETSC_STATIC_INLINE PetscInt GetQuadSubface_Static(PetscInt o, PetscInt r) {
306:   return (o < 0 ? 4-(o+r) : o+r)%4;
307: }
308: PETSC_STATIC_INLINE PetscInt GetQuadSubfaceInverse_Static(PetscInt o, PetscInt s) {
309:   return (o < 0 ? 4-(o+s) : 4+s-o)%4;
310: }

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

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

333:         DMPlexSetConeSize(rdm, newp, 2);
334:       }
335:     }
336:     /* Old vertices have identical supports */
337:     for (v = vStart; v < vEnd; ++v) {
338:       const PetscInt newp = vStartNew + (v - vStart);
339:       PetscInt       size;

341:       DMPlexGetSupportSize(dm, v, &size);
342:       DMPlexSetSupportSize(rdm, newp, size);
343:     }
344:     /* Cell vertices have support 2 */
345:     for (c = cStart; c < cEnd; ++c) {
346:       const PetscInt newp = vStartNew + (vEnd - vStart) + (c - cStart);

348:       DMPlexSetSupportSize(rdm, newp, 2);
349:     }
350:     break;
351:   case REFINER_SIMPLEX_2D:
352:     /* All cells have 3 faces */
353:     for (c = cStart; c < cEnd; ++c) {
354:       for (r = 0; r < 4; ++r) {
355:         const PetscInt newp = (c - cStart)*4 + r;

357:         DMPlexSetConeSize(rdm, newp, 3);
358:       }
359:     }
360:     /* Split faces have 2 vertices and the same cells as the parent */
361:     for (f = fStart; f < fEnd; ++f) {
362:       for (r = 0; r < 2; ++r) {
363:         const PetscInt newp = fStartNew + (f - fStart)*2 + r;
364:         PetscInt       size;

366:         DMPlexSetConeSize(rdm, newp, 2);
367:         DMPlexGetSupportSize(dm, f, &size);
368:         DMPlexSetSupportSize(rdm, newp, size);
369:       }
370:     }
371:     /* Interior faces have 2 vertices and 2 cells */
372:     for (c = cStart; c < cEnd; ++c) {
373:       for (r = 0; r < 3; ++r) {
374:         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*3 + r;

376:         DMPlexSetConeSize(rdm, newp, 2);
377:         DMPlexSetSupportSize(rdm, newp, 2);
378:       }
379:     }
380:     /* Old vertices have identical supports */
381:     for (v = vStart; v < vEnd; ++v) {
382:       const PetscInt newp = vStartNew + (v - vStart);
383:       PetscInt       size;

385:       DMPlexGetSupportSize(dm, v, &size);
386:       DMPlexSetSupportSize(rdm, newp, size);
387:     }
388:     /* Face vertices have 2 + cells*2 supports */
389:     for (f = fStart; f < fEnd; ++f) {
390:       const PetscInt newp = vStartNew + (vEnd - vStart) + (f - fStart);
391:       PetscInt       size;

393:       DMPlexGetSupportSize(dm, f, &size);
394:       DMPlexSetSupportSize(rdm, newp, 2 + size*2);
395:     }
396:     break;
397:   case REFINER_SIMPLEX_TO_HEX_2D:
398:     /* All cells have 4 faces */
399:     for (c = cStart; c < cEnd; ++c) {
400:       for (r = 0; r < 3; ++r) {
401:         const PetscInt newp = (c - cStart)*3 + r;

403:         DMPlexSetConeSize(rdm, newp, 4);
404:       }
405:     }
406:     /* Split faces have 2 vertices and the same cells as the parent */
407:     for (f = fStart; f < fEnd; ++f) {
408:       for (r = 0; r < 2; ++r) {
409:         const PetscInt newp = fStartNew + (f - fStart)*2 + r;
410:         PetscInt       size;

412:         DMPlexSetConeSize(rdm, newp, 2);
413:         DMPlexGetSupportSize(dm, f, &size);
414:         DMPlexSetSupportSize(rdm, newp, size);
415:       }
416:     }
417:     /* Interior faces have 2 vertices and 2 cells */
418:     for (c = cStart; c < cEnd; ++c) {
419:       for (r = 0; r < 3; ++r) {
420:         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*3 + r;

422:         DMPlexSetConeSize(rdm, newp, 2);
423:         DMPlexSetSupportSize(rdm, newp, 2);
424:       }
425:     }
426:     /* Old vertices have identical supports */
427:     for (v = vStart; v < vEnd; ++v) {
428:       const PetscInt newp = vStartNew + (v - vStart);
429:       PetscInt       size;

431:       DMPlexGetSupportSize(dm, v, &size);
432:       DMPlexSetSupportSize(rdm, newp, size);
433:     }
434:     /* Split-face vertices have cells + 2 supports */
435:     for (f = fStart; f < fEnd; ++f) {
436:       const PetscInt newp = vStartNew + (vEnd - vStart) + (f - fStart);
437:       PetscInt       size;

439:       DMPlexGetSupportSize(dm, f, &size);
440:       DMPlexSetSupportSize(rdm, newp, size + 2);
441:     }
442:     /* Interior vertices have 3 supports */
443:     for (c = cStart; c < cEnd; ++c) {
444:       const PetscInt newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + c - cStart;

446:       DMPlexSetSupportSize(rdm, newp, 3);
447:     }
448:     break;
449:   case REFINER_HEX_2D:
450:     /* All cells have 4 faces */
451:     for (c = cStart; c < cEnd; ++c) {
452:       for (r = 0; r < 4; ++r) {
453:         const PetscInt newp = cStartNew + (c - cStart)*4 + r;

455:         DMPlexSetConeSize(rdm, newp, 4);
456:       }
457:     }
458:     /* Split faces have 2 vertices and the same cells as the parent */
459:     for (f = fStart; f < fEnd; ++f) {
460:       for (r = 0; r < 2; ++r) {
461:         const PetscInt newp = fStartNew + (f - fStart)*2 + r;
462:         PetscInt       size;

464:         DMPlexSetConeSize(rdm, newp, 2);
465:         DMPlexGetSupportSize(dm, f, &size);
466:         DMPlexSetSupportSize(rdm, newp, size);
467:       }
468:     }
469:     /* Interior faces have 2 vertices and 2 cells */
470:     for (c = cStart; c < cEnd; ++c) {
471:       for (r = 0; r < 4; ++r) {
472:         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*4 + r;

474:         DMPlexSetConeSize(rdm, newp, 2);
475:         DMPlexSetSupportSize(rdm, newp, 2);
476:       }
477:     }
478:     /* Old vertices have identical supports */
479:     for (v = vStart; v < vEnd; ++v) {
480:       const PetscInt newp = vStartNew + (v - vStart);
481:       PetscInt       size;

483:       DMPlexGetSupportSize(dm, v, &size);
484:       DMPlexSetSupportSize(rdm, newp, size);
485:     }
486:     /* Face vertices have 2 + cells supports */
487:     for (f = fStart; f < fEnd; ++f) {
488:       const PetscInt newp = vStartNew + (vEnd - vStart) + (f - fStart);
489:       PetscInt       size;

491:       DMPlexGetSupportSize(dm, f, &size);
492:       DMPlexSetSupportSize(rdm, newp, 2 + size);
493:     }
494:     /* Cell vertices have 4 supports */
495:     for (c = cStart; c < cEnd; ++c) {
496:       const PetscInt newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (c - cStart);

498:       DMPlexSetSupportSize(rdm, newp, 4);
499:     }
500:     break;
501:   case REFINER_HYBRID_SIMPLEX_2D:
502:     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
503:     cMax = PetscMin(cEnd, cMax);
504:     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
505:     fMax = PetscMin(fEnd, fMax);
506:     DMPlexSetHybridBounds(rdm, cStartNew + (cMax - cStart)*4, fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3, PETSC_DETERMINE, PETSC_DETERMINE);
507:     /* Interior cells have 3 faces */
508:     for (c = cStart; c < cMax; ++c) {
509:       for (r = 0; r < 4; ++r) {
510:         const PetscInt newp = cStartNew + (c - cStart)*4 + r;

512:         DMPlexSetConeSize(rdm, newp, 3);
513:       }
514:     }
515:     /* Hybrid cells have 4 faces */
516:     for (c = cMax; c < cEnd; ++c) {
517:       for (r = 0; r < 2; ++r) {
518:         const PetscInt newp = cStartNew + (cMax - cStart)*4 + (c - cMax)*2 + r;

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

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

539:         DMPlexSetConeSize(rdm, newp, 2);
540:         DMPlexSetSupportSize(rdm, newp, 2);
541:       }
542:     }
543:     /* Hybrid faces have 2 vertices and the same cells */
544:     for (f = fMax; f < fEnd; ++f) {
545:       const PetscInt newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (f - fMax);
546:       PetscInt       size;

548:       DMPlexSetConeSize(rdm, newp, 2);
549:       DMPlexGetSupportSize(dm, f, &size);
550:       DMPlexSetSupportSize(rdm, newp, size);
551:     }
552:     /* Hybrid cell faces have 2 vertices and 2 cells */
553:     for (c = cMax; c < cEnd; ++c) {
554:       const PetscInt newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (fEnd - fMax) + (c - cMax);

556:       DMPlexSetConeSize(rdm, newp, 2);
557:       DMPlexSetSupportSize(rdm, newp, 2);
558:     }
559:     /* Old vertices have identical supports */
560:     for (v = vStart; v < vEnd; ++v) {
561:       const PetscInt newp = vStartNew + (v - vStart);
562:       PetscInt       size;

564:       DMPlexGetSupportSize(dm, v, &size);
565:       DMPlexSetSupportSize(rdm, newp, size);
566:     }
567:     /* Face vertices have 2 + (2 interior, 1 hybrid) supports */
568:     for (f = fStart; f < fMax; ++f) {
569:       const PetscInt newp = vStartNew + (vEnd - vStart) + (f - fStart);
570:       const PetscInt *support;
571:       PetscInt       size, newSize = 2, s;

573:       DMPlexGetSupportSize(dm, f, &size);
574:       DMPlexGetSupport(dm, f, &support);
575:       for (s = 0; s < size; ++s) {
576:         if (support[s] >= cMax) newSize += 1;
577:         else newSize += 2;
578:       }
579:       DMPlexSetSupportSize(rdm, newp, newSize);
580:     }
581:     break;
582:   case REFINER_HYBRID_HEX_2D:
583:     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
584:     cMax = PetscMin(cEnd, cMax);
585:     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
586:     fMax = PetscMin(fEnd, fMax);
587:     DMPlexSetHybridBounds(rdm, cStartNew + (cMax - cStart)*4, fStartNew + (fMax - fStart)*2 + (cMax - cStart)*4, PETSC_DETERMINE, PETSC_DETERMINE);
588:     /* Interior cells have 4 faces */
589:     for (c = cStart; c < cMax; ++c) {
590:       for (r = 0; r < 4; ++r) {
591:         const PetscInt newp = cStartNew + (c - cStart)*4 + r;

593:         DMPlexSetConeSize(rdm, newp, 4);
594:       }
595:     }
596:     /* Hybrid cells have 4 faces */
597:     for (c = cMax; c < cEnd; ++c) {
598:       for (r = 0; r < 2; ++r) {
599:         const PetscInt newp = cStartNew + (cMax - cStart)*4 + (c - cMax)*2 + r;

601:         DMPlexSetConeSize(rdm, newp, 4);
602:       }
603:     }
604:     /* Interior split faces have 2 vertices and the same cells as the parent */
605:     for (f = fStart; f < fMax; ++f) {
606:       for (r = 0; r < 2; ++r) {
607:         const PetscInt newp = fStartNew + (f - fStart)*2 + r;
608:         PetscInt       size;

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

620:         DMPlexSetConeSize(rdm, newp, 2);
621:         DMPlexSetSupportSize(rdm, newp, 2);
622:       }
623:     }
624:     /* Hybrid faces have 2 vertices and the same cells */
625:     for (f = fMax; f < fEnd; ++f) {
626:       const PetscInt newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*4 + (f - fMax);
627:       PetscInt       size;

629:       DMPlexSetConeSize(rdm, newp, 2);
630:       DMPlexGetSupportSize(dm, f, &size);
631:       DMPlexSetSupportSize(rdm, newp, size);
632:     }
633:     /* Hybrid cell faces have 2 vertices and 2 cells */
634:     for (c = cMax; c < cEnd; ++c) {
635:       const PetscInt newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*4 + (fEnd - fMax) + (c - cMax);

637:       DMPlexSetConeSize(rdm, newp, 2);
638:       DMPlexSetSupportSize(rdm, newp, 2);
639:     }
640:     /* Old vertices have identical supports */
641:     for (v = vStart; v < vEnd; ++v) {
642:       const PetscInt newp = vStartNew + (v - vStart);
643:       PetscInt       size;

645:       DMPlexGetSupportSize(dm, v, &size);
646:       DMPlexSetSupportSize(rdm, newp, size);
647:     }
648:     /* Face vertices have 2 + cells supports */
649:     for (f = fStart; f < fMax; ++f) {
650:       const PetscInt newp = vStartNew + (vEnd - vStart) + (f - fStart);
651:       PetscInt       size;

653:       DMPlexGetSupportSize(dm, f, &size);
654:       DMPlexSetSupportSize(rdm, newp, 2 + size);
655:     }
656:     /* Cell vertices have 4 supports */
657:     for (c = cStart; c < cMax; ++c) {
658:       const PetscInt newp = vStartNew + (vEnd - vStart) + (fMax - fStart) + (c - cStart);

660:       DMPlexSetSupportSize(rdm, newp, 4);
661:     }
662:     break;
663:   case REFINER_SIMPLEX_3D:
664:     /* All cells have 4 faces */
665:     for (c = cStart; c < cEnd; ++c) {
666:       for (r = 0; r < 8; ++r) {
667:         const PetscInt newp = cStartNew + (c - cStart)*8 + r;

669:         DMPlexSetConeSize(rdm, newp, 4);
670:       }
671:     }
672:     /* Split faces have 3 edges and the same cells as the parent */
673:     for (f = fStart; f < fEnd; ++f) {
674:       for (r = 0; r < 4; ++r) {
675:         const PetscInt newp = fStartNew + (f - fStart)*4 + r;
676:         PetscInt       size;

678:         DMPlexSetConeSize(rdm, newp, 3);
679:         DMPlexGetSupportSize(dm, f, &size);
680:         DMPlexSetSupportSize(rdm, newp, size);
681:       }
682:     }
683:     /* Interior cell faces have 3 edges and 2 cells */
684:     for (c = cStart; c < cEnd; ++c) {
685:       for (r = 0; r < 8; ++r) {
686:         const PetscInt newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*8 + r;

688:         DMPlexSetConeSize(rdm, newp, 3);
689:         DMPlexSetSupportSize(rdm, newp, 2);
690:       }
691:     }
692:     /* Split edges have 2 vertices and the same faces */
693:     for (e = eStart; e < eEnd; ++e) {
694:       for (r = 0; r < 2; ++r) {
695:         const PetscInt newp = eStartNew + (e - eStart)*2 + r;
696:         PetscInt       size;

698:         DMPlexSetConeSize(rdm, newp, 2);
699:         DMPlexGetSupportSize(dm, e, &size);
700:         DMPlexSetSupportSize(rdm, newp, size);
701:       }
702:     }
703:     /* Face edges have 2 vertices and 2+cells*(1/2) faces */
704:     for (f = fStart; f < fEnd; ++f) {
705:       for (r = 0; r < 3; ++r) {
706:         const PetscInt  newp = eStartNew + (eEnd - eStart)*2 + (f - fStart)*3 + r;
707:         const PetscInt *cone, *ornt, *support, eint[4] = {1, 0, 2, 0};
708:         PetscInt        coneSize, c, supportSize, s, er, intFaces = 0;

710:         DMPlexSetConeSize(rdm, newp, 2);
711:         DMPlexGetSupportSize(dm, f, &supportSize);
712:         DMPlexGetSupport(dm, f, &support);
713:         for (s = 0; s < supportSize; ++s) {
714:           DMPlexGetConeSize(dm, support[s], &coneSize);
715:           DMPlexGetCone(dm, support[s], &cone);
716:           DMPlexGetConeOrientation(dm, support[s], &ornt);
717:           for (c = 0; c < coneSize; ++c) {if (cone[c] == f) break;}
718:           /* Here we want to determine whether edge newp contains a vertex which is part of the cross-tet edge */
719:           er = GetTriMidEdgeInverse_Static(ornt[c], r);
720:           if (er == eint[c]) {
721:             intFaces += 1;
722:           } else {
723:             intFaces += 2;
724:           }
725:         }
726:         DMPlexSetSupportSize(rdm, newp, 2+intFaces);
727:       }
728:     }
729:     /* Interior cell edges have 2 vertices and 4 faces */
730:     for (c = cStart; c < cEnd; ++c) {
731:       const PetscInt newp = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart);

733:       DMPlexSetConeSize(rdm, newp, 2);
734:       DMPlexSetSupportSize(rdm, newp, 4);
735:     }
736:     /* Old vertices have identical supports */
737:     for (v = vStart; v < vEnd; ++v) {
738:       const PetscInt newp = vStartNew + (v - vStart);
739:       PetscInt       size;

741:       DMPlexGetSupportSize(dm, v, &size);
742:       DMPlexSetSupportSize(rdm, newp, size);
743:     }
744:     /* Edge vertices have 2 + faces*2 + cells*0/1 supports */
745:     for (e = eStart; e < eEnd; ++e) {
746:       const PetscInt newp = vStartNew + (vEnd - vStart) + (e - eStart);
747:       PetscInt       size, *star = NULL, starSize, s, cellSize = 0;

749:       DMPlexGetSupportSize(dm, e, &size);
750:       DMPlexGetTransitiveClosure(dm, e, PETSC_FALSE, &starSize, &star);
751:       for (s = 0; s < starSize*2; s += 2) {
752:         const PetscInt *cone, *ornt;
753:         PetscInt        e01, e23;

755:         if ((star[s] >= cStart) && (star[s] < cEnd)) {
756:           /* Check edge 0-1 */
757:           DMPlexGetCone(dm, star[s], &cone);
758:           DMPlexGetConeOrientation(dm, star[s], &ornt);
759:           DMPlexGetCone(dm, cone[0], &cone);
760:           e01  = cone[GetTriEdge_Static(ornt[0], 0)];
761:           /* Check edge 2-3 */
762:           DMPlexGetCone(dm, star[s], &cone);
763:           DMPlexGetConeOrientation(dm, star[s], &ornt);
764:           DMPlexGetCone(dm, cone[2], &cone);
765:           e23  = cone[GetTriEdge_Static(ornt[2], 1)];
766:           if ((e01 == e) || (e23 == e)) ++cellSize;
767:         }
768:       }
769:       DMPlexRestoreTransitiveClosure(dm, e, PETSC_FALSE, &starSize, &star);
770:       DMPlexSetSupportSize(rdm, newp, 2 + size*2 + cellSize);
771:     }
772:     break;
773:   case REFINER_HYBRID_SIMPLEX_3D:
774:     DMPlexSetHybridBounds(rdm, cStartNew + 8*(cMax-cStart), fStartNew + 4*(fMax - fStart) + 8*(cMax - cStart),
775:                                  eStartNew + 2*(eMax - eStart) + 3*(fMax - fStart) + (cMax - cStart), PETSC_DETERMINE);
776:     /* Interior cells have 4 faces */
777:     for (c = cStart; c < cMax; ++c) {
778:       for (r = 0; r < 8; ++r) {
779:         const PetscInt newp = cStartNew + (c - cStart)*8 + r;

781:         DMPlexSetConeSize(rdm, newp, 4);
782:       }
783:     }
784:     /* Hybrid cells have 5 faces */
785:     for (c = cMax; c < cEnd; ++c) {
786:       for (r = 0; r < 4; ++r) {
787:         const PetscInt newp = cStartNew + (cMax - cStart)*8 + (c - cMax)*4 + r;

789:         DMPlexSetConeSize(rdm, newp, 5);
790:       }
791:     }
792:     /* Interior split faces have 3 edges and the same cells as the parent */
793:     for (f = fStart; f < fMax; ++f) {
794:       for (r = 0; r < 4; ++r) {
795:         const PetscInt newp = fStartNew + (f - fStart)*4 + r;
796:         PetscInt       size;

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

808:         DMPlexSetConeSize(rdm, newp, 3);
809:         DMPlexSetSupportSize(rdm, newp, 2);
810:       }
811:     }
812:     /* Hybrid split faces have 4 edges and the same cells as the parent */
813:     for (f = fMax; f < fEnd; ++f) {
814:       for (r = 0; r < 2; ++r) {
815:         const PetscInt newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (f - fMax)*2 + r;
816:         PetscInt       size;

818:         DMPlexSetConeSize(rdm, newp, 4);
819:         DMPlexGetSupportSize(dm, f, &size);
820:         DMPlexSetSupportSize(rdm, newp, size);
821:       }
822:     }
823:     /* Hybrid cells faces have 4 edges and 2 cells */
824:     for (c = cMax; c < cEnd; ++c) {
825:       for (r = 0; r < 3; ++r) {
826:         const PetscInt newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (c - cMax)*3 + r;

828:         DMPlexSetConeSize(rdm, newp, 4);
829:         DMPlexSetSupportSize(rdm, newp, 2);
830:       }
831:     }
832:     /* Interior split edges have 2 vertices and the same faces */
833:     for (e = eStart; e < eMax; ++e) {
834:       for (r = 0; r < 2; ++r) {
835:         const PetscInt newp = eStartNew + (e - eStart)*2 + r;
836:         PetscInt       size;

838:         DMPlexSetConeSize(rdm, newp, 2);
839:         DMPlexGetSupportSize(dm, e, &size);
840:         DMPlexSetSupportSize(rdm, newp, size);
841:       }
842:     }
843:     /* Interior face edges have 2 vertices and 2+cells*(1/2) faces */
844:     for (f = fStart; f < fMax; ++f) {
845:       for (r = 0; r < 3; ++r) {
846:         const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (f - fStart)*3 + r;
847:         const PetscInt *cone, *ornt, *support, eint[4] = {1, 0, 2, 0};
848:         PetscInt        coneSize, c, supportSize, s, er, intFaces = 0;

850:         DMPlexSetConeSize(rdm, newp, 2);
851:         DMPlexGetSupportSize(dm, f, &supportSize);
852:         DMPlexGetSupport(dm, f, &support);
853:         for (s = 0; s < supportSize; ++s) {
854:           DMPlexGetConeSize(dm, support[s], &coneSize);
855:           DMPlexGetCone(dm, support[s], &cone);
856:           DMPlexGetConeOrientation(dm, support[s], &ornt);
857:           for (c = 0; c < coneSize; ++c) {if (cone[c] == f) break;}
858:           if (support[s] < cMax) {
859:             /* Here we want to determine whether edge newp contains a vertex which is part of the cross-tet edge */
860:             er = GetTriMidEdgeInverse_Static(ornt[c], r);
861:             if (er == eint[c]) {
862:               intFaces += 1;
863:             } else {
864:               intFaces += 2;
865:             }
866:           } else {
867:             intFaces += 1;
868:           }
869:         }
870:         DMPlexSetSupportSize(rdm, newp, 2+intFaces);
871:       }
872:     }
873:     /* Interior cell edges have 2 vertices and 4 faces */
874:     for (c = cStart; c < cMax; ++c) {
875:       const PetscInt newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart);

877:       DMPlexSetConeSize(rdm, newp, 2);
878:       DMPlexSetSupportSize(rdm, newp, 4);
879:     }
880:     /* Hybrid edges have 2 vertices and the same faces */
881:     for (e = eMax; e < eEnd; ++e) {
882:       const PetscInt newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (e - eMax);
883:       PetscInt       size;

885:       DMPlexSetConeSize(rdm, newp, 2);
886:       DMPlexGetSupportSize(dm, e, &size);
887:       DMPlexSetSupportSize(rdm, newp, size);
888:     }
889:     /* Hybrid face edges have 2 vertices and 2+2*cells faces */
890:     for (f = fMax; f < fEnd; ++f) {
891:       const PetscInt newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (eEnd - eMax) + (f - fMax);
892:       PetscInt       size;

894:       DMPlexSetConeSize(rdm, newp, 2);
895:       DMPlexGetSupportSize(dm, f, &size);
896:       DMPlexSetSupportSize(rdm, newp, 2+2*size);
897:     }
898:     /* Interior vertices have identical supports */
899:     for (v = vStart; v < vEnd; ++v) {
900:       const PetscInt newp = vStartNew + (v - vStart);
901:       PetscInt       size;

903:       DMPlexGetSupportSize(dm, v, &size);
904:       DMPlexSetSupportSize(rdm, newp, size);
905:     }
906:     /* Interior edge vertices have 2 + interior face*2 + hybrid face + cells*0/1 supports */
907:     for (e = eStart; e < eMax; ++e) {
908:       const PetscInt  newp = vStartNew + (vEnd - vStart) + (e - eStart);
909:       const PetscInt *support;
910:       PetscInt        size, *star = NULL, starSize, s, faceSize = 0, cellSize = 0;

912:       DMPlexGetSupportSize(dm, e, &size);
913:       DMPlexGetSupport(dm, e, &support);
914:       for (s = 0; s < size; ++s) {
915:         if (support[s] < fMax) faceSize += 2;
916:         else                   faceSize += 1;
917:       }
918:       DMPlexGetTransitiveClosure(dm, e, PETSC_FALSE, &starSize, &star);
919:       for (s = 0; s < starSize*2; s += 2) {
920:         const PetscInt *cone, *ornt;
921:         PetscInt        e01, e23;

923:         if ((star[s] >= cStart) && (star[s] < cMax)) {
924:           /* Check edge 0-1 */
925:           DMPlexGetCone(dm, star[s], &cone);
926:           DMPlexGetConeOrientation(dm, star[s], &ornt);
927:           DMPlexGetCone(dm, cone[0], &cone);
928:           e01  = cone[GetTriEdge_Static(ornt[0], 0)];
929:           /* Check edge 2-3 */
930:           DMPlexGetCone(dm, star[s], &cone);
931:           DMPlexGetConeOrientation(dm, star[s], &ornt);
932:           DMPlexGetCone(dm, cone[2], &cone);
933:           e23  = cone[GetTriEdge_Static(ornt[2], 1)];
934:           if ((e01 == e) || (e23 == e)) ++cellSize;
935:         }
936:       }
937:       DMPlexRestoreTransitiveClosure(dm, e, PETSC_FALSE, &starSize, &star);
938:       DMPlexSetSupportSize(rdm, newp, 2 + faceSize + cellSize);
939:     }
940:     break;
941:   case REFINER_SIMPLEX_TO_HEX_3D:
942:     /* All cells have 6 faces */
943:     for (c = cStart; c < cEnd; ++c) {
944:       for (r = 0; r < 4; ++r) {
945:         const PetscInt newp = cStartNew + (c - cStart)*4 + r;

947:         DMPlexSetConeSize(rdm, newp, 6);
948:       }
949:     }
950:     /* Split faces have 4 edges and the same cells as the parent */
951:     for (f = fStart; f < fEnd; ++f) {
952:       for (r = 0; r < 3; ++r) {
953:         const PetscInt newp = fStartNew + (f - fStart)*3 + r;
954:         PetscInt       size;

956:         DMPlexSetConeSize(rdm, newp, 4);
957:         DMPlexGetSupportSize(dm, f, &size);
958:         DMPlexSetSupportSize(rdm, newp, size);
959:       }
960:     }
961:     /* Interior cell faces have 4 edges and 2 cells */
962:     for (c = cStart; c < cEnd; ++c) {
963:       for (r = 0; r < 6; ++r) {
964:         const PetscInt newp = fStartNew + (fEnd - fStart)*3 + (c - cStart)*6 + r;

966:         DMPlexSetConeSize(rdm, newp, 4);
967:         DMPlexSetSupportSize(rdm, newp, 2);
968:       }
969:     }
970:     /* Split edges have 2 vertices and the same faces */
971:     for (e = eStart; e < eEnd; ++e) {
972:       for (r = 0; r < 2; ++r) {
973:         const PetscInt newp = eStartNew + (e - eStart)*2 + r;
974:         PetscInt       size;

976:         DMPlexSetConeSize(rdm, newp, 2);
977:         DMPlexGetSupportSize(dm, e, &size);
978:         DMPlexSetSupportSize(rdm, newp, size);
979:       }
980:     }
981:     /* Face edges have 2 vertices and 2 + cell faces supports */
982:     for (f = fStart; f < fEnd; ++f) {
983:       for (r = 0; r < 3; ++r) {
984:         const PetscInt  newp = eStartNew + (eEnd - eStart)*2 + (f - fStart)*3 + r;
985:         PetscInt        size;

987:         DMPlexSetConeSize(rdm, newp, 2);
988:         DMPlexGetSupportSize(dm, f, &size);
989:         DMPlexSetSupportSize(rdm, newp, 2+size);
990:       }
991:     }
992:     /* Interior cell edges have 2 vertices and 3 faces */
993:     for (c = cStart; c < cEnd; ++c) {
994:       for (r = 0; r < 4; ++r) {
995:         const PetscInt newp = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + r;

997:         DMPlexSetConeSize(rdm, newp, 2);
998:         DMPlexSetSupportSize(rdm, newp, 3);
999:       }
1000:     }
1001:     /* Old vertices have identical supports */
1002:     for (v = vStart; v < vEnd; ++v) {
1003:       const PetscInt newp = vStartNew + (v - vStart);
1004:       PetscInt       size;

1006:       DMPlexGetSupportSize(dm, v, &size);
1007:       DMPlexSetSupportSize(rdm, newp, size);
1008:     }
1009:     /* Edge vertices have 2 + faces supports */
1010:     for (e = eStart; e < eEnd; ++e) {
1011:       const PetscInt newp = vStartNew + (vEnd - vStart) + (e - eStart);
1012:       PetscInt       size;

1014:       DMPlexGetSupportSize(dm, e, &size);
1015:       DMPlexSetSupportSize(rdm, newp, 2 + size);
1016:     }
1017:     /* Face vertices have 3 + cells supports */
1018:     for (f = fStart; f < fEnd; ++f) {
1019:       const PetscInt newp = vStartNew + (vEnd - vStart) + (eEnd - eStart) + f - fStart;
1020:       PetscInt       size;

1022:       DMPlexGetSupportSize(dm, f, &size);
1023:       DMPlexSetSupportSize(rdm, newp, 3 + size);
1024:     }
1025:     /* Interior cell vertices have 4 supports */
1026:     for (c = cStart; c < cEnd; ++c) {
1027:       const PetscInt newp = vStartNew + (vEnd - vStart) + (eEnd - eStart) + fEnd - fStart + c - cStart;

1029:       DMPlexSetSupportSize(rdm, newp, 4);
1030:     }
1031:     break;
1032:   case REFINER_HEX_3D:
1033:     /* All cells have 6 faces */
1034:     for (c = cStart; c < cEnd; ++c) {
1035:       for (r = 0; r < 8; ++r) {
1036:         const PetscInt newp = (c - cStart)*8 + r;

1038:         DMPlexSetConeSize(rdm, newp, 6);
1039:       }
1040:     }
1041:     /* Split faces have 4 edges and the same cells as the parent */
1042:     for (f = fStart; f < fEnd; ++f) {
1043:       for (r = 0; r < 4; ++r) {
1044:         const PetscInt newp = fStartNew + (f - fStart)*4 + r;
1045:         PetscInt       size;

1047:         DMPlexSetConeSize(rdm, newp, 4);
1048:         DMPlexGetSupportSize(dm, f, &size);
1049:         DMPlexSetSupportSize(rdm, newp, size);
1050:       }
1051:     }
1052:     /* Interior faces have 4 edges and 2 cells */
1053:     for (c = cStart; c < cEnd; ++c) {
1054:       for (r = 0; r < 12; ++r) {
1055:         const PetscInt newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + r;

1057:         DMPlexSetConeSize(rdm, newp, 4);
1058:         DMPlexSetSupportSize(rdm, newp, 2);
1059:       }
1060:     }
1061:     /* Split edges have 2 vertices and the same faces as the parent */
1062:     for (e = eStart; e < eEnd; ++e) {
1063:       for (r = 0; r < 2; ++r) {
1064:         const PetscInt newp = eStartNew + (e - eStart)*2 + r;
1065:         PetscInt       size;

1067:         DMPlexSetConeSize(rdm, newp, 2);
1068:         DMPlexGetSupportSize(dm, e, &size);
1069:         DMPlexSetSupportSize(rdm, newp, size);
1070:       }
1071:     }
1072:     /* Face edges have 2 vertices and 2+cells faces */
1073:     for (f = fStart; f < fEnd; ++f) {
1074:       for (r = 0; r < 4; ++r) {
1075:         const PetscInt newp = eStartNew + (eEnd - eStart)*2 + (f - fStart)*4 + r;
1076:         PetscInt       size;

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

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

1097:       DMPlexGetSupportSize(dm, v, &size);
1098:       DMPlexSetSupportSize(rdm, newp, size);
1099:     }
1100:     /* Edge vertices have 2 + faces supports */
1101:     for (e = eStart; e < eEnd; ++e) {
1102:       const PetscInt newp = vStartNew + (vEnd - vStart) + (e - eStart);
1103:       PetscInt       size;

1105:       DMPlexGetSupportSize(dm, e, &size);
1106:       DMPlexSetSupportSize(rdm, newp, 2 + size);
1107:     }
1108:     /* Face vertices have 4 + cells supports */
1109:     for (f = fStart; f < fEnd; ++f) {
1110:       const PetscInt newp = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (f - fStart);
1111:       PetscInt       size;

1113:       DMPlexGetSupportSize(dm, f, &size);
1114:       DMPlexSetSupportSize(rdm, newp, 4 + size);
1115:     }
1116:     /* Cell vertices have 6 supports */
1117:     for (c = cStart; c < cEnd; ++c) {
1118:       const PetscInt newp = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (fEnd - fStart) + (c - cStart);

1120:       DMPlexSetSupportSize(rdm, newp, 6);
1121:     }
1122:     break;
1123:   case REFINER_HYBRID_HEX_3D:
1124:     DMPlexSetHybridBounds(rdm, cStartNew + 8*(cMax-cStart), fStartNew + 4*(fMax - fStart) + 12*(cMax - cStart),
1125:                                  eStartNew + 2*(eMax - eStart) + 4*(fMax - fStart) + 6*(cMax - cStart), PETSC_DETERMINE);
1126:     /* Interior cells have 6 faces */
1127:     for (c = cStart; c < cMax; ++c) {
1128:       for (r = 0; r < 8; ++r) {
1129:         const PetscInt newp = cStartNew + (c - cStart)*8 + r;

1131:         DMPlexSetConeSize(rdm, newp, 6);
1132:       }
1133:     }
1134:     /* Hybrid cells have 6 faces */
1135:     for (c = cMax; c < cEnd; ++c) {
1136:       for (r = 0; r < 4; ++r) {
1137:         const PetscInt newp = cStartNew + (cMax - cStart)*8 + (c - cMax)*4 + r;

1139:         DMPlexSetConeSize(rdm, newp, 6);
1140:       }
1141:     }
1142:     /* Interior split faces have 4 edges and the same cells as the parent */
1143:     for (f = fStart; f < fMax; ++f) {
1144:       for (r = 0; r < 4; ++r) {
1145:         const PetscInt newp = fStartNew + (f - fStart)*4 + r;
1146:         PetscInt       size;

1148:         DMPlexSetConeSize(rdm, newp, 4);
1149:         DMPlexGetSupportSize(dm, f, &size);
1150:         DMPlexSetSupportSize(rdm, newp, size);
1151:       }
1152:     }
1153:     /* Interior cell faces have 4 edges and 2 cells */
1154:     for (c = cStart; c < cMax; ++c) {
1155:       for (r = 0; r < 12; ++r) {
1156:         const PetscInt newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + r;

1158:         DMPlexSetConeSize(rdm, newp, 4);
1159:         DMPlexSetSupportSize(rdm, newp, 2);
1160:       }
1161:     }
1162:     /* Hybrid split faces have 4 edges and the same cells as the parent */
1163:     for (f = fMax; f < fEnd; ++f) {
1164:       for (r = 0; r < 2; ++r) {
1165:         const PetscInt newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (f - fMax)*2 + r;
1166:         PetscInt       size;

1168:         DMPlexSetConeSize(rdm, newp, 4);
1169:         DMPlexGetSupportSize(dm, f, &size);
1170:         DMPlexSetSupportSize(rdm, newp, size);
1171:       }
1172:     }
1173:     /* Hybrid cells faces have 4 edges and 2 cells */
1174:     for (c = cMax; c < cEnd; ++c) {
1175:       for (r = 0; r < 4; ++r) {
1176:         const PetscInt newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd - fMax)*2 + (c - cMax)*4 + r;

1178:         DMPlexSetConeSize(rdm, newp, 4);
1179:         DMPlexSetSupportSize(rdm, newp, 2);
1180:       }
1181:     }
1182:     /* Interior split edges have 2 vertices and the same faces as the parent */
1183:     for (e = eStart; e < eMax; ++e) {
1184:       for (r = 0; r < 2; ++r) {
1185:         const PetscInt newp = eStartNew + (e - eStart)*2 + r;
1186:         PetscInt       size;

1188:         DMPlexSetConeSize(rdm, newp, 2);
1189:         DMPlexGetSupportSize(dm, e, &size);
1190:         DMPlexSetSupportSize(rdm, newp, size);
1191:       }
1192:     }
1193:     /* Interior face edges have 2 vertices and 2+cells faces */
1194:     for (f = fStart; f < fMax; ++f) {
1195:       for (r = 0; r < 4; ++r) {
1196:         const PetscInt newp = eStartNew + (eMax - eStart)*2 + (f - fStart)*4 + r;
1197:         PetscInt       size;

1199:         DMPlexSetConeSize(rdm, newp, 2);
1200:         DMPlexGetSupportSize(dm, f, &size);
1201:         DMPlexSetSupportSize(rdm, newp, 2+size);
1202:       }
1203:     }
1204:     /* Interior cell edges have 2 vertices and 4 faces */
1205:     for (c = cStart; c < cMax; ++c) {
1206:       for (r = 0; r < 6; ++r) {
1207:         const PetscInt newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (c - cStart)*6 + r;

1209:         DMPlexSetConeSize(rdm, newp, 2);
1210:         DMPlexSetSupportSize(rdm, newp, 4);
1211:       }
1212:     }
1213:     /* Hybrid edges have 2 vertices and the same faces */
1214:     for (e = eMax; e < eEnd; ++e) {
1215:       const PetscInt newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (e - eMax);
1216:       PetscInt       size;

1218:       DMPlexSetConeSize(rdm, newp, 2);
1219:       DMPlexGetSupportSize(dm, e, &size);
1220:       DMPlexSetSupportSize(rdm, newp, size);
1221:     }
1222:     /* Hybrid face edges have 2 vertices and 2+cells faces */
1223:     for (f = fMax; f < fEnd; ++f) {
1224:       const PetscInt newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (eEnd - eMax) + (f - fMax);
1225:       PetscInt       size;

1227:       DMPlexSetConeSize(rdm, newp, 2);
1228:       DMPlexGetSupportSize(dm, f, &size);
1229:       DMPlexSetSupportSize(rdm, newp, 2+size);
1230:     }
1231:     /* Hybrid cell edges have 2 vertices and 4 faces */
1232:     for (c = cMax; c < cEnd; ++c) {
1233:       const PetscInt newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (eEnd - eMax) + (fEnd - fMax) + (c - cMax);

1235:       DMPlexSetConeSize(rdm, newp, 2);
1236:       DMPlexSetSupportSize(rdm, newp, 4);
1237:     }
1238:     /* Interior vertices have identical supports */
1239:     for (v = vStart; v < vEnd; ++v) {
1240:       const PetscInt newp = vStartNew + (v - vStart);
1241:       PetscInt       size;

1243:       DMPlexGetSupportSize(dm, v, &size);
1244:       DMPlexSetSupportSize(rdm, newp, size);
1245:     }
1246:     /* Interior edge vertices have 2 + faces supports */
1247:     for (e = eStart; e < eMax; ++e) {
1248:       const PetscInt newp = vStartNew + (vEnd - vStart) + (e - eStart);
1249:       PetscInt       size;

1251:       DMPlexGetSupportSize(dm, e, &size);
1252:       DMPlexSetSupportSize(rdm, newp, 2 + size);
1253:     }
1254:     /* Interior face vertices have 4 + cells supports */
1255:     for (f = fStart; f < fMax; ++f) {
1256:       const PetscInt newp = vStartNew + (vEnd - vStart) + (eMax - eStart) + (f - fStart);
1257:       PetscInt       size;

1259:       DMPlexGetSupportSize(dm, f, &size);
1260:       DMPlexSetSupportSize(rdm, newp, 4 + size);
1261:     }
1262:     /* Interior cell vertices have 6 supports */
1263:     for (c = cStart; c < cMax; ++c) {
1264:       const PetscInt newp = vStartNew + (vEnd - vStart) + (eMax - eStart) + (fMax - fStart) + (c - cStart);

1266:       DMPlexSetSupportSize(rdm, newp, 6);
1267:     }
1268:     break;
1269:   default:
1270:     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
1271:   }
1272:   return(0);
1273: }

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

1284:   if (!refiner) return(0);
1285:   DMPlexGetDepth(dm, &depth);
1286:   DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);
1287:   DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);
1288:   DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);
1289:   DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);
1290:   DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);
1291:   GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);
1292:   GetDepthEnd_Private(depth, depthSize, &cEndNew, &fEndNew, &eEndNew, &vEndNew);
1293:   switch (refiner) {
1294:   case REFINER_SIMPLEX_1D:
1295:     /* Max support size of refined mesh is 2 */
1296:     PetscMalloc1(2, &supportRef);
1297:     /* All cells have 2 vertices */
1298:     for (c = cStart; c < cEnd; ++c) {
1299:       const PetscInt  newv = vStartNew + (vEnd - vStart) + (c - cStart);

1301:       for (r = 0; r < 2; ++r) {
1302:         const PetscInt newp = cStartNew + (c - cStart)*2 + r;
1303:         const PetscInt *cone;
1304:         PetscInt        coneNew[2];

1306:         DMPlexGetCone(dm, c, &cone);
1307:         coneNew[0]       = vStartNew + (cone[0] - vStart);
1308:         coneNew[1]       = vStartNew + (cone[1] - vStart);
1309:         coneNew[(r+1)%2] = newv;
1310:         DMPlexSetCone(rdm, newp, coneNew);
1311: #if 1
1312:         if ((newp < cStartNew) || (newp >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp, cStartNew, cEndNew);
1313:         for (p = 0; p < 2; ++p) {
1314:           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);
1315:         }
1316: #endif
1317:       }
1318:     }
1319:     /* Old vertices have identical supports */
1320:     for (v = vStart; v < vEnd; ++v) {
1321:       const PetscInt  newp = vStartNew + (v - vStart);
1322:       const PetscInt *support, *cone;
1323:       PetscInt        size, s;

1325:       DMPlexGetSupportSize(dm, v, &size);
1326:       DMPlexGetSupport(dm, v, &support);
1327:       for (s = 0; s < size; ++s) {
1328:         PetscInt r = 0;

1330:         DMPlexGetCone(dm, support[s], &cone);
1331:         if (cone[1] == v) r = 1;
1332:         supportRef[s] = cStartNew + (support[s] - cStart)*2 + r;
1333:       }
1334:       DMPlexSetSupport(rdm, newp, supportRef);
1335: #if 1
1336:       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
1337:       for (p = 0; p < size; ++p) {
1338:         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);
1339:       }
1340: #endif
1341:     }
1342:     /* Cell vertices have support of 2 cells */
1343:     for (c = cStart; c < cEnd; ++c) {
1344:       const PetscInt  newp = vStartNew + (vEnd - vStart) + (c - cStart);

1346:       supportRef[0] = cStartNew + (c - cStart)*2 + 0;
1347:       supportRef[1] = cStartNew + (c - cStart)*2 + 1;
1348:       DMPlexSetSupport(rdm, newp, supportRef);
1349: #if 1
1350:       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
1351:       for (p = 0; p < 2; ++p) {
1352:         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);
1353:       }
1354: #endif
1355:     }
1356:     PetscFree(supportRef);
1357:     break;
1358:   case REFINER_SIMPLEX_2D:
1359:     /*
1360:      2
1361:      |\
1362:      | \
1363:      |  \
1364:      |   \
1365:      | C  \
1366:      |     \
1367:      |      \
1368:      2---1---1
1369:      |\  D  / \
1370:      | 2   0   \
1371:      |A \ /  B  \
1372:      0---0-------1
1373:      */
1374:     /* All cells have 3 faces */
1375:     for (c = cStart; c < cEnd; ++c) {
1376:       const PetscInt  newp = cStartNew + (c - cStart)*4;
1377:       const PetscInt *cone, *ornt;
1378:       PetscInt        coneNew[3], orntNew[3];

1380:       DMPlexGetCone(dm, c, &cone);
1381:       DMPlexGetConeOrientation(dm, c, &ornt);
1382:       /* A triangle */
1383:       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
1384:       orntNew[0] = ornt[0];
1385:       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 2;
1386:       orntNew[1] = -2;
1387:       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
1388:       orntNew[2] = ornt[2];
1389:       DMPlexSetCone(rdm, newp+0, coneNew);
1390:       DMPlexSetConeOrientation(rdm, newp+0, orntNew);
1391: #if 1
1392:       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);
1393:       for (p = 0; p < 3; ++p) {
1394:         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);
1395:       }
1396: #endif
1397:       /* B triangle */
1398:       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
1399:       orntNew[0] = ornt[0];
1400:       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
1401:       orntNew[1] = ornt[1];
1402:       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 0;
1403:       orntNew[2] = -2;
1404:       DMPlexSetCone(rdm, newp+1, coneNew);
1405:       DMPlexSetConeOrientation(rdm, newp+1, orntNew);
1406: #if 1
1407:       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);
1408:       for (p = 0; p < 3; ++p) {
1409:         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);
1410:       }
1411: #endif
1412:       /* C triangle */
1413:       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 1;
1414:       orntNew[0] = -2;
1415:       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
1416:       orntNew[1] = ornt[1];
1417:       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
1418:       orntNew[2] = ornt[2];
1419:       DMPlexSetCone(rdm, newp+2, coneNew);
1420:       DMPlexSetConeOrientation(rdm, newp+2, orntNew);
1421: #if 1
1422:       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);
1423:       for (p = 0; p < 3; ++p) {
1424:         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);
1425:       }
1426: #endif
1427:       /* D triangle */
1428:       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 0;
1429:       orntNew[0] = 0;
1430:       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 1;
1431:       orntNew[1] = 0;
1432:       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 2;
1433:       orntNew[2] = 0;
1434:       DMPlexSetCone(rdm, newp+3, coneNew);
1435:       DMPlexSetConeOrientation(rdm, newp+3, orntNew);
1436: #if 1
1437:       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);
1438:       for (p = 0; p < 3; ++p) {
1439:         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);
1440:       }
1441: #endif
1442:     }
1443:     /* Split faces have 2 vertices and the same cells as the parent */
1444:     DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);
1445:     PetscMalloc1(2 + maxSupportSize*2, &supportRef);
1446:     for (f = fStart; f < fEnd; ++f) {
1447:       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);

1449:       for (r = 0; r < 2; ++r) {
1450:         const PetscInt  newp = fStartNew + (f - fStart)*2 + r;
1451:         const PetscInt *cone, *ornt, *support;
1452:         PetscInt        coneNew[2], coneSize, c, supportSize, s;

1454:         DMPlexGetCone(dm, f, &cone);
1455:         coneNew[0]       = vStartNew + (cone[0] - vStart);
1456:         coneNew[1]       = vStartNew + (cone[1] - vStart);
1457:         coneNew[(r+1)%2] = newv;
1458:         DMPlexSetCone(rdm, newp, coneNew);
1459: #if 1
1460:         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1461:         for (p = 0; p < 2; ++p) {
1462:           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);
1463:         }
1464: #endif
1465:         DMPlexGetSupportSize(dm, f, &supportSize);
1466:         DMPlexGetSupport(dm, f, &support);
1467:         for (s = 0; s < supportSize; ++s) {
1468:           DMPlexGetConeSize(dm, support[s], &coneSize);
1469:           DMPlexGetCone(dm, support[s], &cone);
1470:           DMPlexGetConeOrientation(dm, support[s], &ornt);
1471:           for (c = 0; c < coneSize; ++c) {
1472:             if (cone[c] == f) break;
1473:           }
1474:           supportRef[s] = cStartNew + (support[s] - cStart)*4 + (ornt[c] < 0 ? (c+1-r)%3 : (c+r)%3);
1475:         }
1476:         DMPlexSetSupport(rdm, newp, supportRef);
1477: #if 1
1478:         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1479:         for (p = 0; p < supportSize; ++p) {
1480:           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);
1481:         }
1482: #endif
1483:       }
1484:     }
1485:     /* Interior faces have 2 vertices and 2 cells */
1486:     for (c = cStart; c < cEnd; ++c) {
1487:       const PetscInt *cone;

1489:       DMPlexGetCone(dm, c, &cone);
1490:       for (r = 0; r < 3; ++r) {
1491:         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*3 + r;
1492:         PetscInt       coneNew[2];
1493:         PetscInt       supportNew[2];

1495:         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r]       - fStart);
1496:         coneNew[1] = vStartNew + (vEnd - vStart) + (cone[(r+1)%3] - fStart);
1497:         DMPlexSetCone(rdm, newp, coneNew);
1498: #if 1
1499:         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1500:         for (p = 0; p < 2; ++p) {
1501:           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);
1502:         }
1503: #endif
1504:         supportNew[0] = (c - cStart)*4 + (r+1)%3;
1505:         supportNew[1] = (c - cStart)*4 + 3;
1506:         DMPlexSetSupport(rdm, newp, supportNew);
1507: #if 1
1508:         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1509:         for (p = 0; p < 2; ++p) {
1510:           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);
1511:         }
1512: #endif
1513:       }
1514:     }
1515:     /* Old vertices have identical supports */
1516:     for (v = vStart; v < vEnd; ++v) {
1517:       const PetscInt  newp = vStartNew + (v - vStart);
1518:       const PetscInt *support, *cone;
1519:       PetscInt        size, s;

1521:       DMPlexGetSupportSize(dm, v, &size);
1522:       DMPlexGetSupport(dm, v, &support);
1523:       for (s = 0; s < size; ++s) {
1524:         PetscInt r = 0;

1526:         DMPlexGetCone(dm, support[s], &cone);
1527:         if (cone[1] == v) r = 1;
1528:         supportRef[s] = fStartNew + (support[s] - fStart)*2 + r;
1529:       }
1530:       DMPlexSetSupport(rdm, newp, supportRef);
1531: #if 1
1532:       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
1533:       for (p = 0; p < size; ++p) {
1534:         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);
1535:       }
1536: #endif
1537:     }
1538:     /* Face vertices have 2 + cells*2 supports */
1539:     for (f = fStart; f < fEnd; ++f) {
1540:       const PetscInt  newp = vStartNew + (vEnd - vStart) + (f - fStart);
1541:       const PetscInt *cone, *support;
1542:       PetscInt        size, s;

1544:       DMPlexGetSupportSize(dm, f, &size);
1545:       DMPlexGetSupport(dm, f, &support);
1546:       supportRef[0] = fStartNew + (f - fStart)*2 + 0;
1547:       supportRef[1] = fStartNew + (f - fStart)*2 + 1;
1548:       for (s = 0; s < size; ++s) {
1549:         PetscInt r = 0;

1551:         DMPlexGetCone(dm, support[s], &cone);
1552:         if      (cone[1] == f) r = 1;
1553:         else if (cone[2] == f) r = 2;
1554:         supportRef[2+s*2+0] = fStartNew + (fEnd - fStart)*2 + (support[s] - cStart)*3 + (r+2)%3;
1555:         supportRef[2+s*2+1] = fStartNew + (fEnd - fStart)*2 + (support[s] - cStart)*3 + r;
1556:       }
1557:       DMPlexSetSupport(rdm, newp, supportRef);
1558: #if 1
1559:       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
1560:       for (p = 0; p < 2+size*2; ++p) {
1561:         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);
1562:       }
1563: #endif
1564:     }
1565:     PetscFree(supportRef);
1566:     break;
1567:   case REFINER_SIMPLEX_TO_HEX_2D:
1568:     /*
1569:      2
1570:      |\
1571:      | \
1572:      |  \
1573:      |   \
1574:      | C  \
1575:      |     \
1576:      2      1
1577:      |\    / \
1578:      | 2  1   \
1579:      |  \/     \
1580:      |   |      \
1581:      |A  |   B   \
1582:      |   0        \
1583:      |   |         \
1584:      0---0----------1
1585:      */
1586:     /* All cells have 4 faces */
1587:     for (c = cStart; c < cEnd; ++c) {
1588:       const PetscInt  newp = cStartNew + (c - cStart)*3;
1589:       const PetscInt *cone, *ornt;
1590:       PetscInt        coneNew[4], orntNew[4];

1592:       DMPlexGetCone(dm, c, &cone);
1593:       DMPlexGetConeOrientation(dm, c, &ornt);
1594:       /* A quad */
1595:       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
1596:       orntNew[0] = ornt[0];
1597:       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 0;
1598:       orntNew[1] = 0;
1599:       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 2;
1600:       orntNew[2] = -2;
1601:       coneNew[3] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
1602:       orntNew[3] = ornt[2];
1603:       DMPlexSetCone(rdm, newp+0, coneNew);
1604:       DMPlexSetConeOrientation(rdm, newp+0, orntNew);
1605: #if 1
1606:       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);
1607:       for (p = 0; p < 4; ++p) {
1608:         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);
1609:       }
1610: #endif
1611:       /* B quad */
1612:       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
1613:       orntNew[0] = ornt[0];
1614:       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
1615:       orntNew[1] = ornt[1];
1616:       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 1;
1617:       orntNew[2] = 0;
1618:       coneNew[3] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 0;
1619:       orntNew[3] = -2;
1620:       DMPlexSetCone(rdm, newp+1, coneNew);
1621:       DMPlexSetConeOrientation(rdm, newp+1, orntNew);
1622: #if 1
1623:       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);
1624:       for (p = 0; p < 4; ++p) {
1625:         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);
1626:       }
1627: #endif
1628:       /* C quad */
1629:       coneNew[0] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
1630:       orntNew[0] = ornt[1];
1631:       coneNew[1] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
1632:       orntNew[1] = ornt[2];
1633:       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 2;
1634:       orntNew[2] = 0;
1635:       coneNew[3] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 1;
1636:       orntNew[3] = -2;
1637:       DMPlexSetCone(rdm, newp+2, coneNew);
1638:       DMPlexSetConeOrientation(rdm, newp+2, orntNew);
1639: #if 1
1640:       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);
1641:       for (p = 0; p < 4; ++p) {
1642:         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);
1643:       }
1644: #endif
1645:     }
1646:     /* Split faces have 2 vertices and the same cells as the parent */
1647:     DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);
1648:     PetscMalloc1(2 + maxSupportSize*2, &supportRef);
1649:     for (f = fStart; f < fEnd; ++f) {
1650:       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);

1652:       for (r = 0; r < 2; ++r) {
1653:         const PetscInt  newp = fStartNew + (f - fStart)*2 + r;
1654:         const PetscInt *cone, *ornt, *support;
1655:         PetscInt        coneNew[2], coneSize, c, supportSize, s;

1657:         DMPlexGetCone(dm, f, &cone);
1658:         coneNew[0]       = vStartNew + (cone[0] - vStart);
1659:         coneNew[1]       = vStartNew + (cone[1] - vStart);
1660:         coneNew[(r+1)%2] = newv;
1661:         DMPlexSetCone(rdm, newp, coneNew);
1662: #if 1
1663:         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1664:         for (p = 0; p < 2; ++p) {
1665:           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);
1666:         }
1667: #endif
1668:         DMPlexGetSupportSize(dm, f, &supportSize);
1669:         DMPlexGetSupport(dm, f, &support);
1670:         for (s = 0; s < supportSize; ++s) {
1671:           DMPlexGetConeSize(dm, support[s], &coneSize);
1672:           DMPlexGetCone(dm, support[s], &cone);
1673:           DMPlexGetConeOrientation(dm, support[s], &ornt);
1674:           for (c = 0; c < coneSize; ++c) {
1675:             if (cone[c] == f) break;
1676:           }
1677:           supportRef[s] = cStartNew + (support[s] - cStart)*3 + (ornt[c] < 0 ? (c+1-r)%3 : (c+r)%3);
1678:         }
1679:         DMPlexSetSupport(rdm, newp, supportRef);
1680: #if 1
1681:         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1682:         for (p = 0; p < supportSize; ++p) {
1683:           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);
1684:         }
1685: #endif
1686:       }
1687:     }
1688:     /* Interior faces have 2 vertices and 2 cells */
1689:     for (c = cStart; c < cEnd; ++c) {
1690:       const PetscInt *cone;

1692:       DMPlexGetCone(dm, c, &cone);
1693:       for (r = 0; r < 3; ++r) {
1694:         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*3 + r;
1695:         PetscInt       coneNew[2];
1696:         PetscInt       supportNew[2];

1698:         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r] - fStart);
1699:         coneNew[1] = vStartNew + (vEnd - vStart) + (fEnd    - fStart) + (c - cStart);
1700:         DMPlexSetCone(rdm, newp, coneNew);
1701: #if 1
1702:         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1703:         for (p = 0; p < 2; ++p) {
1704:           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);
1705:         }
1706: #endif
1707:         supportNew[0] = (c - cStart)*3 + r%3;
1708:         supportNew[1] = (c - cStart)*3 + (r+1)%3;
1709:         DMPlexSetSupport(rdm, newp, supportNew);
1710: #if 1
1711:         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1712:         for (p = 0; p < 2; ++p) {
1713:           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);
1714:         }
1715: #endif
1716:       }
1717:     }
1718:     /* Old vertices have identical supports */
1719:     for (v = vStart; v < vEnd; ++v) {
1720:       const PetscInt  newp = vStartNew + (v - vStart);
1721:       const PetscInt *support, *cone;
1722:       PetscInt        size, s;

1724:       DMPlexGetSupportSize(dm, v, &size);
1725:       DMPlexGetSupport(dm, v, &support);
1726:       for (s = 0; s < size; ++s) {
1727:         PetscInt r = 0;

1729:         DMPlexGetCone(dm, support[s], &cone);
1730:         if (cone[1] == v) r = 1;
1731:         supportRef[s] = fStartNew + (support[s] - fStart)*2 + r;
1732:       }
1733:       DMPlexSetSupport(rdm, newp, supportRef);
1734: #if 1
1735:       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
1736:       for (p = 0; p < size; ++p) {
1737:         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);
1738:       }
1739: #endif
1740:     }
1741:     /* Split-face vertices have cells + 2 supports */
1742:     for (f = fStart; f < fEnd; ++f) {
1743:       const PetscInt  newp = vStartNew + (vEnd - vStart) + (f - fStart);
1744:       const PetscInt *cone, *support;
1745:       PetscInt        size, s;

1747:       DMPlexGetSupportSize(dm, f, &size);
1748:       DMPlexGetSupport(dm, f, &support);
1749:       supportRef[0] = fStartNew + (f - fStart)*2 + 0;
1750:       supportRef[1] = fStartNew + (f - fStart)*2 + 1;
1751:       for (s = 0; s < size; ++s) {
1752:         PetscInt r = 0;

1754:         DMPlexGetCone(dm, support[s], &cone);
1755:         if      (cone[1] == f) r = 1;
1756:         else if (cone[2] == f) r = 2;
1757:         supportRef[2+s+0] = fStartNew + (fEnd - fStart)*2 + (support[s] - cStart)*3 + r;
1758:       }
1759:       DMPlexSetSupport(rdm, newp, supportRef);
1760: #if 1
1761:       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
1762:       for (p = 0; p < 2+size; ++p) {
1763:         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);
1764:       }
1765: #endif
1766:     }
1767:     /* Interior vertices vertices have 3 supports */
1768:     for (c = cStart; c < cEnd; ++c) {
1769:       const PetscInt newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + c - cStart;

1771:       supportRef[0] = fStartNew + (fEnd - fStart)*2 + (c - cStart)*3 + 0;
1772:       supportRef[1] = fStartNew + (fEnd - fStart)*2 + (c - cStart)*3 + 1;
1773:       supportRef[2] = fStartNew + (fEnd - fStart)*2 + (c - cStart)*3 + 2;
1774:       DMPlexSetSupport(rdm, newp, supportRef);
1775:     }
1776:     PetscFree(supportRef);
1777:     break;
1778:   case REFINER_HEX_2D:
1779:     /*
1780:      3---------2---------2
1781:      |         |         |
1782:      |    D    2    C    |
1783:      |         |         |
1784:      3----3----0----1----1
1785:      |         |         |
1786:      |    A    0    B    |
1787:      |         |         |
1788:      0---------0---------1
1789:      */
1790:     /* All cells have 4 faces */
1791:     for (c = cStart; c < cEnd; ++c) {
1792:       const PetscInt  newp = (c - cStart)*4;
1793:       const PetscInt *cone, *ornt;
1794:       PetscInt        coneNew[4], orntNew[4];

1796:       DMPlexGetCone(dm, c, &cone);
1797:       DMPlexGetConeOrientation(dm, c, &ornt);
1798:       /* A quad */
1799:       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
1800:       orntNew[0] = ornt[0];
1801:       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 0;
1802:       orntNew[1] = 0;
1803:       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 3;
1804:       orntNew[2] = -2;
1805:       coneNew[3] = fStartNew + (cone[3] - fStart)*2 + (ornt[3] < 0 ? 0 : 1);
1806:       orntNew[3] = ornt[3];
1807:       DMPlexSetCone(rdm, newp+0, coneNew);
1808:       DMPlexSetConeOrientation(rdm, newp+0, orntNew);
1809: #if 1
1810:       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);
1811:       for (p = 0; p < 4; ++p) {
1812:         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);
1813:       }
1814: #endif
1815:       /* B quad */
1816:       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
1817:       orntNew[0] = ornt[0];
1818:       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
1819:       orntNew[1] = ornt[1];
1820:       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 1;
1821:       orntNew[2] = -2;
1822:       coneNew[3] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 0;
1823:       orntNew[3] = -2;
1824:       DMPlexSetCone(rdm, newp+1, coneNew);
1825:       DMPlexSetConeOrientation(rdm, newp+1, orntNew);
1826: #if 1
1827:       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);
1828:       for (p = 0; p < 4; ++p) {
1829:         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);
1830:       }
1831: #endif
1832:       /* C quad */
1833:       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 1;
1834:       orntNew[0] = 0;
1835:       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
1836:       orntNew[1] = ornt[1];
1837:       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
1838:       orntNew[2] = ornt[2];
1839:       coneNew[3] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 2;
1840:       orntNew[3] = -2;
1841:       DMPlexSetCone(rdm, newp+2, coneNew);
1842:       DMPlexSetConeOrientation(rdm, newp+2, orntNew);
1843: #if 1
1844:       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);
1845:       for (p = 0; p < 4; ++p) {
1846:         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);
1847:       }
1848: #endif
1849:       /* D quad */
1850:       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 3;
1851:       orntNew[0] = 0;
1852:       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 2;
1853:       orntNew[1] = 0;
1854:       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
1855:       orntNew[2] = ornt[2];
1856:       coneNew[3] = fStartNew + (cone[3] - fStart)*2 + (ornt[3] < 0 ? 1 : 0);
1857:       orntNew[3] = ornt[3];
1858:       DMPlexSetCone(rdm, newp+3, coneNew);
1859:       DMPlexSetConeOrientation(rdm, newp+3, orntNew);
1860: #if 1
1861:       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);
1862:       for (p = 0; p < 4; ++p) {
1863:         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);
1864:       }
1865: #endif
1866:     }
1867:     /* Split faces have 2 vertices and the same cells as the parent */
1868:     DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);
1869:     PetscMalloc1(2 + maxSupportSize*2, &supportRef);
1870:     for (f = fStart; f < fEnd; ++f) {
1871:       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);

1873:       for (r = 0; r < 2; ++r) {
1874:         const PetscInt  newp = fStartNew + (f - fStart)*2 + r;
1875:         const PetscInt *cone, *ornt, *support;
1876:         PetscInt        coneNew[2], coneSize, c, supportSize, s;

1878:         DMPlexGetCone(dm, f, &cone);
1879:         coneNew[0]       = vStartNew + (cone[0] - vStart);
1880:         coneNew[1]       = vStartNew + (cone[1] - vStart);
1881:         coneNew[(r+1)%2] = newv;
1882:         DMPlexSetCone(rdm, newp, coneNew);
1883: #if 1
1884:         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1885:         for (p = 0; p < 2; ++p) {
1886:           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);
1887:         }
1888: #endif
1889:         DMPlexGetSupportSize(dm, f, &supportSize);
1890:         DMPlexGetSupport(dm, f, &support);
1891:         for (s = 0; s < supportSize; ++s) {
1892:           DMPlexGetConeSize(dm, support[s], &coneSize);
1893:           DMPlexGetCone(dm, support[s], &cone);
1894:           DMPlexGetConeOrientation(dm, support[s], &ornt);
1895:           for (c = 0; c < coneSize; ++c) {
1896:             if (cone[c] == f) break;
1897:           }
1898:           supportRef[s] = cStartNew + (support[s] - cStart)*4 + (ornt[c] < 0 ? (c+1-r)%4 : (c+r)%4);
1899:         }
1900:         DMPlexSetSupport(rdm, newp, supportRef);
1901: #if 1
1902:         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1903:         for (p = 0; p < supportSize; ++p) {
1904:           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);
1905:         }
1906: #endif
1907:       }
1908:     }
1909:     /* Interior faces have 2 vertices and 2 cells */
1910:     for (c = cStart; c < cEnd; ++c) {
1911:       const PetscInt *cone;
1912:       PetscInt        coneNew[2], supportNew[2];

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

1918:         if (r==1 || r==2) {
1919:           coneNew[0] = vStartNew + (vEnd - vStart) + (fEnd    - fStart) + (c - cStart);
1920:           coneNew[1] = vStartNew + (vEnd - vStart) + (cone[r] - fStart);
1921:         } else {
1922:           coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r] - fStart);
1923:           coneNew[1] = vStartNew + (vEnd - vStart) + (fEnd    - fStart) + (c - cStart);
1924:         }
1925:         DMPlexSetCone(rdm, newp, coneNew);
1926: #if 1
1927:         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1928:         for (p = 0; p < 2; ++p) {
1929:           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);
1930:         }
1931: #endif
1932:         supportNew[0] = (c - cStart)*4 + r;
1933:         supportNew[1] = (c - cStart)*4 + (r+1)%4;
1934:         DMPlexSetSupport(rdm, newp, supportNew);
1935: #if 1
1936:         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1937:         for (p = 0; p < 2; ++p) {
1938:           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);
1939:         }
1940: #endif
1941:       }
1942:     }
1943:     /* Old vertices have identical supports */
1944:     for (v = vStart; v < vEnd; ++v) {
1945:       const PetscInt  newp = vStartNew + (v - vStart);
1946:       const PetscInt *support, *cone;
1947:       PetscInt        size, s;

1949:       DMPlexGetSupportSize(dm, v, &size);
1950:       DMPlexGetSupport(dm, v, &support);
1951:       for (s = 0; s < size; ++s) {
1952:         PetscInt r = 0;

1954:         DMPlexGetCone(dm, support[s], &cone);
1955:         if (cone[1] == v) r = 1;
1956:         supportRef[s] = fStartNew + (support[s] - fStart)*2 + r;
1957:       }
1958:       DMPlexSetSupport(rdm, newp, supportRef);
1959: #if 1
1960:       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
1961:       for (p = 0; p < size; ++p) {
1962:         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);
1963:       }
1964: #endif
1965:     }
1966:     /* Face vertices have 2 + cells supports */
1967:     for (f = fStart; f < fEnd; ++f) {
1968:       const PetscInt  newp = vStartNew + (vEnd - vStart) + (f - fStart);
1969:       const PetscInt *cone, *support;
1970:       PetscInt        size, s;

1972:       DMPlexGetSupportSize(dm, f, &size);
1973:       DMPlexGetSupport(dm, f, &support);
1974:       supportRef[0] = fStartNew + (f - fStart)*2 + 0;
1975:       supportRef[1] = fStartNew + (f - fStart)*2 + 1;
1976:       for (s = 0; s < size; ++s) {
1977:         PetscInt r = 0;

1979:         DMPlexGetCone(dm, support[s], &cone);
1980:         if      (cone[1] == f) r = 1;
1981:         else if (cone[2] == f) r = 2;
1982:         else if (cone[3] == f) r = 3;
1983:         supportRef[2+s] = fStartNew + (fEnd - fStart)*2 + (support[s] - cStart)*4 + r;
1984:       }
1985:       DMPlexSetSupport(rdm, newp, supportRef);
1986: #if 1
1987:       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
1988:       for (p = 0; p < 2+size; ++p) {
1989:         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);
1990:       }
1991: #endif
1992:     }
1993:     /* Cell vertices have 4 supports */
1994:     for (c = cStart; c < cEnd; ++c) {
1995:       const PetscInt newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (c - cStart);
1996:       PetscInt       supportNew[4];

1998:       for (r = 0; r < 4; ++r) {
1999:         supportNew[r] = fStartNew + (fEnd - fStart)*2 + (c - cStart)*4 + r;
2000:       }
2001:       DMPlexSetSupport(rdm, newp, supportNew);
2002:     }
2003:     PetscFree(supportRef);
2004:     break;
2005:   case REFINER_HYBRID_SIMPLEX_2D:
2006:     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
2007:     cMax = PetscMin(cEnd, cMax);
2008:     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
2009:     fMax = PetscMin(fEnd, fMax);
2010:     DMPlexGetHybridBounds(rdm, &cMaxNew, &fMaxNew, NULL, NULL);
2011:     /* Interior cells have 3 faces */
2012:     for (c = cStart; c < cMax; ++c) {
2013:       const PetscInt  newp = cStartNew + (c - cStart)*4;
2014:       const PetscInt *cone, *ornt;
2015:       PetscInt        coneNew[3], orntNew[3];

2017:       DMPlexGetCone(dm, c, &cone);
2018:       DMPlexGetConeOrientation(dm, c, &ornt);
2019:       /* A triangle */
2020:       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
2021:       orntNew[0] = ornt[0];
2022:       coneNew[1] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 2;
2023:       orntNew[1] = -2;
2024:       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
2025:       orntNew[2] = ornt[2];
2026:       DMPlexSetCone(rdm, newp+0, coneNew);
2027:       DMPlexSetConeOrientation(rdm, newp+0, orntNew);
2028: #if 1
2029:       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);
2030:       for (p = 0; p < 3; ++p) {
2031:         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);
2032:       }
2033: #endif
2034:       /* B triangle */
2035:       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
2036:       orntNew[0] = ornt[0];
2037:       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
2038:       orntNew[1] = ornt[1];
2039:       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 0;
2040:       orntNew[2] = -2;
2041:       DMPlexSetCone(rdm, newp+1, coneNew);
2042:       DMPlexSetConeOrientation(rdm, newp+1, orntNew);
2043: #if 1
2044:       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);
2045:       for (p = 0; p < 3; ++p) {
2046:         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);
2047:       }
2048: #endif
2049:       /* C triangle */
2050:       coneNew[0] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 1;
2051:       orntNew[0] = -2;
2052:       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
2053:       orntNew[1] = ornt[1];
2054:       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
2055:       orntNew[2] = ornt[2];
2056:       DMPlexSetCone(rdm, newp+2, coneNew);
2057:       DMPlexSetConeOrientation(rdm, newp+2, orntNew);
2058: #if 1
2059:       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);
2060:       for (p = 0; p < 3; ++p) {
2061:         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);
2062:       }
2063: #endif
2064:       /* D triangle */
2065:       coneNew[0] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 0;
2066:       orntNew[0] = 0;
2067:       coneNew[1] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 1;
2068:       orntNew[1] = 0;
2069:       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 2;
2070:       orntNew[2] = 0;
2071:       DMPlexSetCone(rdm, newp+3, coneNew);
2072:       DMPlexSetConeOrientation(rdm, newp+3, orntNew);
2073: #if 1
2074:       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);
2075:       for (p = 0; p < 3; ++p) {
2076:         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);
2077:       }
2078: #endif
2079:     }
2080:     /*
2081:      2----3----3
2082:      |         |
2083:      |    B    |
2084:      |         |
2085:      0----4--- 1
2086:      |         |
2087:      |    A    |
2088:      |         |
2089:      0----2----1
2090:      */
2091:     /* Hybrid cells have 4 faces */
2092:     for (c = cMax; c < cEnd; ++c) {
2093:       const PetscInt  newp = cStartNew + (cMax - cStart)*4 + (c - cMax)*2;
2094:       const PetscInt *cone, *ornt;
2095:       PetscInt        coneNew[4], orntNew[4], r;

2097:       DMPlexGetCone(dm, c, &cone);
2098:       DMPlexGetConeOrientation(dm, c, &ornt);
2099:       r    = (ornt[0] < 0 ? 1 : 0);
2100:       /* A quad */
2101:       coneNew[0]   = fStartNew + (cone[0] - fStart)*2 + r;
2102:       orntNew[0]   = ornt[0];
2103:       coneNew[1]   = fStartNew + (cone[1] - fStart)*2 + r;
2104:       orntNew[1]   = ornt[1];
2105:       coneNew[2+r] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (cone[2+r] - fMax);
2106:       orntNew[2+r] = 0;
2107:       coneNew[3-r] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (fEnd    - fMax) + (c - cMax);
2108:       orntNew[3-r] = 0;
2109:       DMPlexSetCone(rdm, newp+0, coneNew);
2110:       DMPlexSetConeOrientation(rdm, newp+0, orntNew);
2111: #if 1
2112:       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);
2113:       for (p = 0; p < 4; ++p) {
2114:         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);
2115:       }
2116: #endif
2117:       /* B quad */
2118:       coneNew[0]   = fStartNew + (cone[0] - fStart)*2 + 1-r;
2119:       orntNew[0]   = ornt[0];
2120:       coneNew[1]   = fStartNew + (cone[1] - fStart)*2 + 1-r;
2121:       orntNew[1]   = ornt[1];
2122:       coneNew[2+r] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (fEnd    - fMax) + (c - cMax);
2123:       orntNew[2+r] = 0;
2124:       coneNew[3-r] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (cone[3-r] - fMax);
2125:       orntNew[3-r] = 0;
2126:       DMPlexSetCone(rdm, newp+1, coneNew);
2127:       DMPlexSetConeOrientation(rdm, newp+1, orntNew);
2128: #if 1
2129:       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);
2130:       for (p = 0; p < 4; ++p) {
2131:         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);
2132:       }
2133: #endif
2134:     }
2135:     /* Interior split faces have 2 vertices and the same cells as the parent */
2136:     DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);
2137:     PetscMalloc1(2 + maxSupportSize*2, &supportRef);
2138:     for (f = fStart; f < fMax; ++f) {
2139:       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);

2141:       for (r = 0; r < 2; ++r) {
2142:         const PetscInt  newp = fStartNew + (f - fStart)*2 + r;
2143:         const PetscInt *cone, *ornt, *support;
2144:         PetscInt        coneNew[2], coneSize, c, supportSize, s;

2146:         DMPlexGetCone(dm, f, &cone);
2147:         coneNew[0]       = vStartNew + (cone[0] - vStart);
2148:         coneNew[1]       = vStartNew + (cone[1] - vStart);
2149:         coneNew[(r+1)%2] = newv;
2150:         DMPlexSetCone(rdm, newp, coneNew);
2151: #if 1
2152:         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2153:         for (p = 0; p < 2; ++p) {
2154:           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);
2155:         }
2156: #endif
2157:         DMPlexGetSupportSize(dm, f, &supportSize);
2158:         DMPlexGetSupport(dm, f, &support);
2159:         for (s = 0; s < supportSize; ++s) {
2160:           DMPlexGetConeSize(dm, support[s], &coneSize);
2161:           DMPlexGetCone(dm, support[s], &cone);
2162:           DMPlexGetConeOrientation(dm, support[s], &ornt);
2163:           for (c = 0; c < coneSize; ++c) if (cone[c] == f) break;
2164:           if (support[s] >= cMax) {
2165:             supportRef[s] = cStartNew + (cMax - cStart)*4 + (support[s] - cMax)*2 + (ornt[c] < 0 ? 1-r : r);
2166:           } else {
2167:             supportRef[s] = cStartNew + (support[s] - cStart)*4 + (ornt[c] < 0 ? (c+1-r)%3 : (c+r)%3);
2168:           }
2169:         }
2170:         DMPlexSetSupport(rdm, newp, supportRef);
2171: #if 1
2172:         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2173:         for (p = 0; p < supportSize; ++p) {
2174:           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);
2175:         }
2176: #endif
2177:       }
2178:     }
2179:     /* Interior cell faces have 2 vertices and 2 cells */
2180:     for (c = cStart; c < cMax; ++c) {
2181:       const PetscInt *cone;

2183:       DMPlexGetCone(dm, c, &cone);
2184:       for (r = 0; r < 3; ++r) {
2185:         const PetscInt newp = fStartNew + (fMax - fStart)*2 + (c - cStart)*3 + r;
2186:         PetscInt       coneNew[2];
2187:         PetscInt       supportNew[2];

2189:         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r]       - fStart);
2190:         coneNew[1] = vStartNew + (vEnd - vStart) + (cone[(r+1)%3] - fStart);
2191:         DMPlexSetCone(rdm, newp, coneNew);
2192: #if 1
2193:         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2194:         for (p = 0; p < 2; ++p) {
2195:           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);
2196:         }
2197: #endif
2198:         supportNew[0] = (c - cStart)*4 + (r+1)%3;
2199:         supportNew[1] = (c - cStart)*4 + 3;
2200:         DMPlexSetSupport(rdm, newp, supportNew);
2201: #if 1
2202:         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2203:         for (p = 0; p < 2; ++p) {
2204:           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);
2205:         }
2206: #endif
2207:       }
2208:     }
2209:     /* Interior hybrid faces have 2 vertices and the same cells */
2210:     for (f = fMax; f < fEnd; ++f) {
2211:       const PetscInt  newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (f - fMax);
2212:       const PetscInt *cone, *ornt;
2213:       const PetscInt *support;
2214:       PetscInt        coneNew[2];
2215:       PetscInt        supportNew[2];
2216:       PetscInt        size, s, r;

2218:       DMPlexGetCone(dm, f, &cone);
2219:       coneNew[0] = vStartNew + (cone[0] - vStart);
2220:       coneNew[1] = vStartNew + (cone[1] - vStart);
2221:       DMPlexSetCone(rdm, newp, coneNew);
2222: #if 1
2223:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2224:       for (p = 0; p < 2; ++p) {
2225:         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);
2226:       }
2227: #endif
2228:       DMPlexGetSupportSize(dm, f, &size);
2229:       DMPlexGetSupport(dm, f, &support);
2230:       for (s = 0; s < size; ++s) {
2231:         DMPlexGetCone(dm, support[s], &cone);
2232:         DMPlexGetConeOrientation(dm, support[s], &ornt);
2233:         for (r = 0; r < 2; ++r) {
2234:           if (cone[r+2] == f) break;
2235:         }
2236:         supportNew[s] = (cMax - cStart)*4 + (support[s] - cMax)*2 + (ornt[0] < 0 ? 1-r : r);
2237:       }
2238:       DMPlexSetSupport(rdm, newp, supportNew);
2239: #if 1
2240:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2241:       for (p = 0; p < size; ++p) {
2242:         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);
2243:       }
2244: #endif
2245:     }
2246:     /* Cell hybrid faces have 2 vertices and 2 cells */
2247:     for (c = cMax; c < cEnd; ++c) {
2248:       const PetscInt  newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (fEnd - fMax) + (c - cMax);
2249:       const PetscInt *cone;
2250:       PetscInt        coneNew[2];
2251:       PetscInt        supportNew[2];

2253:       DMPlexGetCone(dm, c, &cone);
2254:       coneNew[0] = vStartNew + (vEnd - vStart) + (cone[0] - fStart);
2255:       coneNew[1] = vStartNew + (vEnd - vStart) + (cone[1] - fStart);
2256:       DMPlexSetCone(rdm, newp, coneNew);
2257: #if 1
2258:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2259:       for (p = 0; p < 2; ++p) {
2260:         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);
2261:       }
2262: #endif
2263:       supportNew[0] = (cMax - cStart)*4 + (c - cMax)*2 + 0;
2264:       supportNew[1] = (cMax - cStart)*4 + (c - cMax)*2 + 1;
2265:       DMPlexSetSupport(rdm, newp, supportNew);
2266: #if 1
2267:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2268:       for (p = 0; p < 2; ++p) {
2269:         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);
2270:       }
2271: #endif
2272:     }
2273:     /* Old vertices have identical supports */
2274:     for (v = vStart; v < vEnd; ++v) {
2275:       const PetscInt  newp = vStartNew + (v - vStart);
2276:       const PetscInt *support, *cone;
2277:       PetscInt        size, s;

2279:       DMPlexGetSupportSize(dm, v, &size);
2280:       DMPlexGetSupport(dm, v, &support);
2281:       for (s = 0; s < size; ++s) {
2282:         if (support[s] >= fMax) {
2283:           supportRef[s] = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (support[s] - fMax);
2284:         } else {
2285:           PetscInt r = 0;

2287:           DMPlexGetCone(dm, support[s], &cone);
2288:           if (cone[1] == v) r = 1;
2289:           supportRef[s] = fStartNew + (support[s] - fStart)*2 + r;
2290:         }
2291:       }
2292:       DMPlexSetSupport(rdm, newp, supportRef);
2293: #if 1
2294:       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
2295:       for (p = 0; p < size; ++p) {
2296:         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);
2297:       }
2298: #endif
2299:     }
2300:     /* Face vertices have 2 + (2 interior, 1 hybrid) supports */
2301:     for (f = fStart; f < fMax; ++f) {
2302:       const PetscInt  newp = vStartNew + (vEnd - vStart) + (f - fStart);
2303:       const PetscInt *cone, *support;
2304:       PetscInt        size, newSize = 2, s;

2306:       DMPlexGetSupportSize(dm, f, &size);
2307:       DMPlexGetSupport(dm, f, &support);
2308:       supportRef[0] = fStartNew + (f - fStart)*2 + 0;
2309:       supportRef[1] = fStartNew + (f - fStart)*2 + 1;
2310:       for (s = 0; s < size; ++s) {
2311:         PetscInt r = 0;

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

2317:           newSize += 1;
2318:         } else {
2319:           if      (cone[1] == f) r = 1;
2320:           else if (cone[2] == f) r = 2;
2321:           supportRef[newSize+0] = fStartNew + (fMax - fStart)*2 + (support[s] - cStart)*3 + (r+2)%3;
2322:           supportRef[newSize+1] = fStartNew + (fMax - fStart)*2 + (support[s] - cStart)*3 + r;

2324:           newSize += 2;
2325:         }
2326:       }
2327:       DMPlexSetSupport(rdm, newp, supportRef);
2328: #if 1
2329:       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
2330:       for (p = 0; p < newSize; ++p) {
2331:         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);
2332:       }
2333: #endif
2334:     }
2335:     PetscFree(supportRef);
2336:     break;
2337:   case REFINER_HYBRID_HEX_2D:
2338:     /* Hybrid Hex 2D */
2339:     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
2340:     cMax = PetscMin(cEnd, cMax);
2341:     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
2342:     fMax = PetscMin(fEnd, fMax);
2343:     DMPlexGetHybridBounds(rdm, &cMaxNew, &fMaxNew, NULL, NULL);
2344:     /* Interior cells have 4 faces */
2345:     for (c = cStart; c < cMax; ++c) {
2346:       const PetscInt  newp = cStartNew + (c - cStart)*4;
2347:       const PetscInt *cone, *ornt;
2348:       PetscInt        coneNew[4], orntNew[4];

2350:       DMPlexGetCone(dm, c, &cone);
2351:       DMPlexGetConeOrientation(dm, c, &ornt);
2352:       /* A quad */
2353:       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
2354:       orntNew[0] = ornt[0];
2355:       coneNew[1] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*4 + 0;
2356:       orntNew[1] = 0;
2357:       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*4 + 3;
2358:       orntNew[2] = -2;
2359:       coneNew[3] = fStartNew + (cone[3] - fStart)*2 + (ornt[3] < 0 ? 0 : 1);
2360:       orntNew[3] = ornt[3];
2361:       DMPlexSetCone(rdm, newp+0, coneNew);
2362:       DMPlexSetConeOrientation(rdm, newp+0, orntNew);
2363: #if 1
2364:       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);
2365:       for (p = 0; p < 4; ++p) {
2366:         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);
2367:       }
2368: #endif
2369:       /* B quad */
2370:       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
2371:       orntNew[0] = ornt[0];
2372:       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
2373:       orntNew[1] = ornt[1];
2374:       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*4 + 1;
2375:       orntNew[2] = 0;
2376:       coneNew[3] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*4 + 0;
2377:       orntNew[3] = -2;
2378:       DMPlexSetCone(rdm, newp+1, coneNew);
2379:       DMPlexSetConeOrientation(rdm, newp+1, orntNew);
2380: #if 1
2381:       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);
2382:       for (p = 0; p < 4; ++p) {
2383:         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);
2384:       }
2385: #endif
2386:       /* C quad */
2387:       coneNew[0] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*4 + 1;
2388:       orntNew[0] = -2;
2389:       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
2390:       orntNew[1] = ornt[1];
2391:       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
2392:       orntNew[2] = ornt[2];
2393:       coneNew[3] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*4 + 2;
2394:       orntNew[3] = 0;
2395:       DMPlexSetCone(rdm, newp+2, coneNew);
2396:       DMPlexSetConeOrientation(rdm, newp+2, orntNew);
2397: #if 1
2398:       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);
2399:       for (p = 0; p < 4; ++p) {
2400:         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);
2401:       }
2402: #endif
2403:       /* D quad */
2404:       coneNew[0] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*4 + 3;
2405:       orntNew[0] = 0;
2406:       coneNew[1] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*4 + 2;
2407:       orntNew[1] = -2;
2408:       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
2409:       orntNew[2] = ornt[2];
2410:       coneNew[3] = fStartNew + (cone[3] - fStart)*2 + (ornt[3] < 0 ? 1 : 0);
2411:       orntNew[3] = ornt[3];
2412:       DMPlexSetCone(rdm, newp+3, coneNew);
2413:       DMPlexSetConeOrientation(rdm, newp+3, orntNew);
2414: #if 1
2415:       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);
2416:       for (p = 0; p < 4; ++p) {
2417:         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);
2418:       }
2419: #endif
2420:     }
2421:     /*
2422:      2----3----3
2423:      |         |
2424:      |    B    |
2425:      |         |
2426:      0----4--- 1
2427:      |         |
2428:      |    A    |
2429:      |         |
2430:      0----2----1
2431:      */
2432:     /* Hybrid cells have 4 faces */
2433:     for (c = cMax; c < cEnd; ++c) {
2434:       const PetscInt  newp = cStartNew + (cMax - cStart)*4 + (c - cMax)*2;
2435:       const PetscInt *cone, *ornt;
2436:       PetscInt        coneNew[4], orntNew[4];

2438:       DMPlexGetCone(dm, c, &cone);
2439:       DMPlexGetConeOrientation(dm, c, &ornt);
2440:       /* A quad */
2441:       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
2442:       orntNew[0] = ornt[0];
2443:       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
2444:       orntNew[1] = ornt[1];
2445:       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*4 + (cone[2] - fMax);
2446:       orntNew[2] = 0;
2447:       coneNew[3] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*4 + (fEnd    - fMax) + (c - cMax);
2448:       orntNew[3] = 0;
2449:       DMPlexSetCone(rdm, newp+0, coneNew);
2450:       DMPlexSetConeOrientation(rdm, newp+0, orntNew);
2451: #if 1
2452:       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);
2453:       for (p = 0; p < 4; ++p) {
2454:         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);
2455:       }
2456: #endif
2457:       /* B quad */
2458:       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
2459:       orntNew[0] = ornt[0];
2460:       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
2461:       orntNew[1] = ornt[1];
2462:       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*4 + (fEnd    - fMax) + (c - cMax);
2463:       orntNew[2] = 0;
2464:       coneNew[3] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*4 + (cone[3] - fMax);
2465:       orntNew[3] = 0;
2466:       DMPlexSetCone(rdm, newp+1, coneNew);
2467:       DMPlexSetConeOrientation(rdm, newp+1, orntNew);
2468: #if 1
2469:       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);
2470:       for (p = 0; p < 4; ++p) {
2471:         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);
2472:       }
2473: #endif
2474:     }
2475:     /* Interior split faces have 2 vertices and the same cells as the parent */
2476:     DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);
2477:     PetscMalloc1(2 + maxSupportSize*2, &supportRef);
2478:     for (f = fStart; f < fMax; ++f) {
2479:       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);

2481:       for (r = 0; r < 2; ++r) {
2482:         const PetscInt  newp = fStartNew + (f - fStart)*2 + r;
2483:         const PetscInt *cone, *ornt, *support;
2484:         PetscInt        coneNew[2], coneSize, c, supportSize, s;

2486:         DMPlexGetCone(dm, f, &cone);
2487:         coneNew[0]       = vStartNew + (cone[0] - vStart);
2488:         coneNew[1]       = vStartNew + (cone[1] - vStart);
2489:         coneNew[(r+1)%2] = newv;
2490:         DMPlexSetCone(rdm, newp, coneNew);
2491: #if 1
2492:         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2493:         for (p = 0; p < 2; ++p) {
2494:           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);
2495:         }
2496: #endif
2497:         DMPlexGetSupportSize(dm, f, &supportSize);
2498:         DMPlexGetSupport(dm, f, &support);
2499:         for (s = 0; s < supportSize; ++s) {
2500:           if (support[s] >= cMax) {
2501:             supportRef[s] = cStartNew + (cMax - cStart)*4 + (support[s] - cMax)*2 + r;
2502:           } else {
2503:             DMPlexGetConeSize(dm, support[s], &coneSize);
2504:             DMPlexGetCone(dm, support[s], &cone);
2505:             DMPlexGetConeOrientation(dm, support[s], &ornt);
2506:             for (c = 0; c < coneSize; ++c) {
2507:               if (cone[c] == f) break;
2508:             }
2509:             supportRef[s] = cStartNew + (support[s] - cStart)*4 + (ornt[c] < 0 ? (c+1-r)%4 : (c+r)%4);
2510:           }
2511:         }
2512:         DMPlexSetSupport(rdm, newp, supportRef);
2513: #if 1
2514:         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2515:         for (p = 0; p < supportSize; ++p) {
2516:           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);
2517:         }
2518: #endif
2519:       }
2520:     }
2521:     /* Interior cell faces have 2 vertices and 2 cells */
2522:     for (c = cStart; c < cMax; ++c) {
2523:       const PetscInt *cone;

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

2530:         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r] - fStart);
2531:         coneNew[1] = vStartNew + (vEnd - vStart) + (fMax    - fStart) + (c - cStart);
2532:         DMPlexSetCone(rdm, newp, coneNew);
2533: #if 1
2534:         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2535:         for (p = 0; p < 2; ++p) {
2536:           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);
2537:         }
2538: #endif
2539:         supportNew[0] = (c - cStart)*4 + r;
2540:         supportNew[1] = (c - cStart)*4 + (r+1)%4;
2541:         DMPlexSetSupport(rdm, newp, supportNew);
2542: #if 1
2543:         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2544:         for (p = 0; p < 2; ++p) {
2545:           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);
2546:         }
2547: #endif
2548:       }
2549:     }
2550:     /* Hybrid faces have 2 vertices and the same cells */
2551:     for (f = fMax; f < fEnd; ++f) {
2552:       const PetscInt  newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*4 + (f - fMax);
2553:       const PetscInt *cone, *support;
2554:       PetscInt        coneNew[2], supportNew[2];
2555:       PetscInt        size, s, r;

2557:       DMPlexGetCone(dm, f, &cone);
2558:       coneNew[0] = vStartNew + (cone[0] - vStart);
2559:       coneNew[1] = vStartNew + (cone[1] - vStart);
2560:       DMPlexSetCone(rdm, newp, coneNew);
2561: #if 1
2562:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2563:       for (p = 0; p < 2; ++p) {
2564:         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);
2565:       }
2566: #endif
2567:       DMPlexGetSupportSize(dm, f, &size);
2568:       DMPlexGetSupport(dm, f, &support);
2569:       for (s = 0; s < size; ++s) {
2570:         DMPlexGetCone(dm, support[s], &cone);
2571:         for (r = 0; r < 2; ++r) {
2572:           if (cone[r+2] == f) break;
2573:         }
2574:         supportNew[s] = (cMax - cStart)*4 + (support[s] - cMax)*2 + r;
2575:       }
2576:       DMPlexSetSupport(rdm, newp, supportNew);
2577: #if 1
2578:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2579:       for (p = 0; p < size; ++p) {
2580:         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);
2581:       }
2582: #endif
2583:     }
2584:     /* Cell hybrid faces have 2 vertices and 2 cells */
2585:     for (c = cMax; c < cEnd; ++c) {
2586:       const PetscInt  newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*4 + (fEnd - fMax) + (c - cMax);
2587:       const PetscInt *cone;
2588:       PetscInt        coneNew[2], supportNew[2];

2590:       DMPlexGetCone(dm, c, &cone);
2591:       coneNew[0] = vStartNew + (vEnd - vStart) + (cone[0] - fStart);
2592:       coneNew[1] = vStartNew + (vEnd - vStart) + (cone[1] - fStart);
2593:       DMPlexSetCone(rdm, newp, coneNew);
2594: #if 1
2595:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2596:       for (p = 0; p < 2; ++p) {
2597:         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);
2598:       }
2599: #endif
2600:       supportNew[0] = (cMax - cStart)*4 + (c - cMax)*2 + 0;
2601:       supportNew[1] = (cMax - cStart)*4 + (c - cMax)*2 + 1;
2602:       DMPlexSetSupport(rdm, newp, supportNew);
2603: #if 1
2604:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2605:       for (p = 0; p < 2; ++p) {
2606:         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);
2607:       }
2608: #endif
2609:     }
2610:     /* Old vertices have identical supports */
2611:     for (v = vStart; v < vEnd; ++v) {
2612:       const PetscInt  newp = vStartNew + (v - vStart);
2613:       const PetscInt *support, *cone;
2614:       PetscInt        size, s;

2616:       DMPlexGetSupportSize(dm, v, &size);
2617:       DMPlexGetSupport(dm, v, &support);
2618:       for (s = 0; s < size; ++s) {
2619:         if (support[s] >= fMax) {
2620:           supportRef[s] = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*4 + (support[s] - fMax);
2621:         } else {
2622:           PetscInt r = 0;

2624:           DMPlexGetCone(dm, support[s], &cone);
2625:           if (cone[1] == v) r = 1;
2626:           supportRef[s] = fStartNew + (support[s] - fStart)*2 + r;
2627:         }
2628:       }
2629:       DMPlexSetSupport(rdm, newp, supportRef);
2630: #if 1
2631:       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
2632:       for (p = 0; p < size; ++p) {
2633:         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);
2634:       }
2635: #endif
2636:     }
2637:     /* Face vertices have 2 + cells supports */
2638:     for (f = fStart; f < fMax; ++f) {
2639:       const PetscInt  newp = vStartNew + (vEnd - vStart) + (f - fStart);
2640:       const PetscInt *cone, *support;
2641:       PetscInt        size, s;

2643:       DMPlexGetSupportSize(dm, f, &size);
2644:       DMPlexGetSupport(dm, f, &support);
2645:       supportRef[0] = fStartNew + (f - fStart)*2 + 0;
2646:       supportRef[1] = fStartNew + (f - fStart)*2 + 1;
2647:       for (s = 0; s < size; ++s) {
2648:         PetscInt r = 0;

2650:         DMPlexGetCone(dm, support[s], &cone);
2651:         if (support[s] >= cMax) {
2652:           supportRef[2+s] = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*4 + (fEnd - fMax) + (support[s] - cMax);
2653:         } else {
2654:           if      (cone[1] == f) r = 1;
2655:           else if (cone[2] == f) r = 2;
2656:           else if (cone[3] == f) r = 3;
2657:           supportRef[2+s] = fStartNew + (fMax - fStart)*2 + (support[s] - cStart)*4 + r;
2658:         }
2659:       }
2660:       DMPlexSetSupport(rdm, newp, supportRef);
2661: #if 1
2662:       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
2663:       for (p = 0; p < 2+size; ++p) {
2664:         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);
2665:       }
2666: #endif
2667:     }
2668:     /* Cell vertices have 4 supports */
2669:     for (c = cStart; c < cMax; ++c) {
2670:       const PetscInt newp = vStartNew + (vEnd - vStart) + (fMax - fStart) + (c - cStart);
2671:       PetscInt       supportNew[4];

2673:       for (r = 0; r < 4; ++r) {
2674:         supportNew[r] = fStartNew + (fMax - fStart)*2 + (c - cStart)*4 + r;
2675:       }
2676:       DMPlexSetSupport(rdm, newp, supportNew);
2677:     }
2678:     PetscFree(supportRef);
2679:     break;
2680:   case REFINER_SIMPLEX_3D:
2681:     /* All cells have 4 faces: Tet face order is prescribed in DMPlexGetFaces_Internal() */
2682:     DMPlexGetRawFaces_Internal(dm, 3, 4, cellInd, NULL, NULL, &faces);
2683:     for (c = cStart; c < cEnd; ++c) {
2684:       const PetscInt  newp = cStartNew + (c - cStart)*8;
2685:       const PetscInt *cone, *ornt;
2686:       PetscInt        coneNew[4], orntNew[4];

2688:       DMPlexGetCone(dm, c, &cone);
2689:       DMPlexGetConeOrientation(dm, c, &ornt);
2690:       /* A tetrahedron: {0, a, c, d} */
2691:       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetTriSubface_Static(ornt[0], 0); /* A */
2692:       orntNew[0] = ornt[0];
2693:       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetTriSubface_Static(ornt[1], 0); /* A */
2694:       orntNew[1] = ornt[1];
2695:       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetTriSubface_Static(ornt[2], 0); /* A */
2696:       orntNew[2] = ornt[2];
2697:       coneNew[3] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 0;
2698:       orntNew[3] = 0;
2699:       DMPlexSetCone(rdm, newp+0, coneNew);
2700:       DMPlexSetConeOrientation(rdm, newp+0, orntNew);
2701: #if 1
2702:       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);
2703:       for (p = 0; p < 4; ++p) {
2704:         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);
2705:       }
2706: #endif
2707:       /* B tetrahedron: {a, 1, b, e} */
2708:       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetTriSubface_Static(ornt[0], 1); /* B */
2709:       orntNew[0] = ornt[0];
2710:       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetTriSubface_Static(ornt[1], 2); /* C */
2711:       orntNew[1] = ornt[1];
2712:       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 1;
2713:       orntNew[2] = 0;
2714:       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetTriSubface_Static(ornt[3], 1); /* B */
2715:       orntNew[3] = ornt[3];
2716:       DMPlexSetCone(rdm, newp+1, coneNew);
2717:       DMPlexSetConeOrientation(rdm, newp+1, orntNew);
2718: #if 1
2719:       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);
2720:       for (p = 0; p < 4; ++p) {
2721:         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);
2722:       }
2723: #endif
2724:       /* C tetrahedron: {c, b, 2, f} */
2725:       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetTriSubface_Static(ornt[0], 2); /* C */
2726:       orntNew[0] = ornt[0];
2727:       coneNew[1] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 2;
2728:       orntNew[1] = 0;
2729:       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetTriSubface_Static(ornt[2], 1); /* B */
2730:       orntNew[2] = ornt[2];
2731:       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetTriSubface_Static(ornt[3], 0); /* A */
2732:       orntNew[3] = ornt[3];
2733:       DMPlexSetCone(rdm, newp+2, coneNew);
2734:       DMPlexSetConeOrientation(rdm, newp+2, orntNew);
2735: #if 1
2736:       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);
2737:       for (p = 0; p < 4; ++p) {
2738:         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);
2739:       }
2740: #endif
2741:       /* D tetrahedron: {d, e, f, 3} */
2742:       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 3;
2743:       orntNew[0] = 0;
2744:       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetTriSubface_Static(ornt[1], 1); /* B */
2745:       orntNew[1] = ornt[1];
2746:       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetTriSubface_Static(ornt[2], 2); /* C */
2747:       orntNew[2] = ornt[2];
2748:       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetTriSubface_Static(ornt[3], 2); /* C */
2749:       orntNew[3] = ornt[3];
2750:       DMPlexSetCone(rdm, newp+3, coneNew);
2751:       DMPlexSetConeOrientation(rdm, newp+3, orntNew);
2752: #if 1
2753:       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);
2754:       for (p = 0; p < 4; ++p) {
2755:         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);
2756:       }
2757: #endif
2758:       /* A' tetrahedron: {c, d, a, f} */
2759:       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 0;
2760:       orntNew[0] = -3;
2761:       coneNew[1] = fStartNew + (cone[2] - fStart)*4 + 3;
2762:       orntNew[1] = ornt[2] < 0 ? -(GetTriMidEdge_Static(ornt[2], 0)+1) : GetTriMidEdge_Static(ornt[2], 0);
2763:       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 5;
2764:       orntNew[2] = 0;
2765:       coneNew[3] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 4;
2766:       orntNew[3] = 2;
2767:       DMPlexSetCone(rdm, newp+4, coneNew);
2768:       DMPlexSetConeOrientation(rdm, newp+4, orntNew);
2769: #if 1
2770:       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);
2771:       for (p = 0; p < 4; ++p) {
2772:         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);
2773:       }
2774: #endif
2775:       /* B' tetrahedron: {e, b, a, f} */
2776:       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 1;
2777:       orntNew[0] = -2;
2778:       coneNew[1] = fStartNew + (cone[3] - fStart)*4 + 3;
2779:       orntNew[1] = ornt[3] < 0 ? -(GetTriMidEdge_Static(ornt[3], 1)+1) : GetTriMidEdge_Static(ornt[3], 1);
2780:       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 6;
2781:       orntNew[2] = 0;
2782:       coneNew[3] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 7;
2783:       orntNew[3] = 0;
2784:       DMPlexSetCone(rdm, newp+5, coneNew);
2785:       DMPlexSetConeOrientation(rdm, newp+5, orntNew);
2786: #if 1
2787:       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);
2788:       for (p = 0; p < 4; ++p) {
2789:         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);
2790:       }
2791: #endif
2792:       /* C' tetrahedron: {f, a, c, b} */
2793:       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 5;
2794:       orntNew[0] = -2;
2795:       coneNew[1] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 7;
2796:       orntNew[1] = -2;
2797:       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 2;
2798:       orntNew[2] = -1;
2799:       coneNew[3] = fStartNew + (cone[0] - fStart)*4 + 3;
2800:       orntNew[3] = ornt[0] < 0 ? -(GetTriMidEdge_Static(ornt[0], 2)+1) : GetTriMidEdge_Static(ornt[0], 2);
2801:       DMPlexSetCone(rdm, newp+6, coneNew);
2802:       DMPlexSetConeOrientation(rdm, newp+6, orntNew);
2803: #if 1
2804:       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);
2805:       for (p = 0; p < 4; ++p) {
2806:         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);
2807:       }
2808: #endif
2809:       /* D' tetrahedron: {f, a, e, d} */
2810:       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 6;
2811:       orntNew[0] = -2;
2812:       coneNew[1] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 4;
2813:       orntNew[1] = -1;
2814:       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 3;
2815:       orntNew[2] = -2;
2816:       coneNew[3] = fStartNew + (cone[1] - fStart)*4 + 3;
2817:       orntNew[3] = ornt[1] < 0 ? -(GetTriMidEdge_Static(ornt[1], 1)+1) : GetTriMidEdge_Static(ornt[1], 1);
2818:       DMPlexSetCone(rdm, newp+7, coneNew);
2819:       DMPlexSetConeOrientation(rdm, newp+7, orntNew);
2820: #if 1
2821:       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);
2822:       for (p = 0; p < 4; ++p) {
2823:         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);
2824:       }
2825: #endif
2826:     }
2827:     /* Split faces have 3 edges and the same cells as the parent */
2828:     DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);
2829:     PetscMalloc1(2 + maxSupportSize*2, &supportRef);
2830:     for (f = fStart; f < fEnd; ++f) {
2831:       const PetscInt  newp = fStartNew + (f - fStart)*4;
2832:       const PetscInt *cone, *ornt, *support;
2833:       PetscInt        coneNew[3], orntNew[3], coneSize, supportSize, s;

2835:       DMPlexGetCone(dm, f, &cone);
2836:       DMPlexGetConeOrientation(dm, f, &ornt);
2837:       /* A triangle */
2838:       coneNew[0] = eStartNew + (cone[0] - eStart)*2 + (ornt[0] < 0 ? 1 : 0);
2839:       orntNew[0] = ornt[0];
2840:       coneNew[1] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 2;
2841:       orntNew[1] = -2;
2842:       coneNew[2] = eStartNew + (cone[2] - eStart)*2 + (ornt[2] < 0 ? 0 : 1);
2843:       orntNew[2] = ornt[2];
2844:       DMPlexSetCone(rdm, newp+0, coneNew);
2845:       DMPlexSetConeOrientation(rdm, newp+0, orntNew);
2846: #if 1
2847:       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);
2848:       for (p = 0; p < 3; ++p) {
2849:         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);
2850:       }
2851: #endif
2852:       /* B triangle */
2853:       coneNew[0] = eStartNew + (cone[0] - eStart)*2 + (ornt[0] < 0 ? 0 : 1);
2854:       orntNew[0] = ornt[0];
2855:       coneNew[1] = eStartNew + (cone[1] - eStart)*2 + (ornt[1] < 0 ? 1 : 0);
2856:       orntNew[1] = ornt[1];
2857:       coneNew[2] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 0;
2858:       orntNew[2] = -2;
2859:       DMPlexSetCone(rdm, newp+1, coneNew);
2860:       DMPlexSetConeOrientation(rdm, newp+1, orntNew);
2861: #if 1
2862:       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);
2863:       for (p = 0; p < 3; ++p) {
2864:         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);
2865:       }
2866: #endif
2867:       /* C triangle */
2868:       coneNew[0] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 1;
2869:       orntNew[0] = -2;
2870:       coneNew[1] = eStartNew + (cone[1] - eStart)*2 + (ornt[1] < 0 ? 0 : 1);
2871:       orntNew[1] = ornt[1];
2872:       coneNew[2] = eStartNew + (cone[2] - eStart)*2 + (ornt[2] < 0 ? 1 : 0);
2873:       orntNew[2] = ornt[2];
2874:       DMPlexSetCone(rdm, newp+2, coneNew);
2875:       DMPlexSetConeOrientation(rdm, newp+2, orntNew);
2876: #if 1
2877:       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);
2878:       for (p = 0; p < 3; ++p) {
2879:         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);
2880:       }
2881: #endif
2882:       /* D triangle */
2883:       coneNew[0] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 0;
2884:       orntNew[0] = 0;
2885:       coneNew[1] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 1;
2886:       orntNew[1] = 0;
2887:       coneNew[2] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 2;
2888:       orntNew[2] = 0;
2889:       DMPlexSetCone(rdm, newp+3, coneNew);
2890:       DMPlexSetConeOrientation(rdm, newp+3, orntNew);
2891: #if 1
2892:       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);
2893:       for (p = 0; p < 3; ++p) {
2894:         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);
2895:       }
2896: #endif
2897:       DMPlexGetSupportSize(dm, f, &supportSize);
2898:       DMPlexGetSupport(dm, f, &support);
2899:       for (r = 0; r < 4; ++r) {
2900:         for (s = 0; s < supportSize; ++s) {
2901:           PetscInt subf;
2902:           DMPlexGetConeSize(dm, support[s], &coneSize);
2903:           DMPlexGetCone(dm, support[s], &cone);
2904:           DMPlexGetConeOrientation(dm, support[s], &ornt);
2905:           for (c = 0; c < coneSize; ++c) {
2906:             if (cone[c] == f) break;
2907:           }
2908:           subf = GetTriSubfaceInverse_Static(ornt[c], r);
2909:           supportRef[s] = cStartNew + (support[s] - cStart)*8 + (r==3 ? (c+2)%4 + 4 : faces[c*3+subf]);
2910:         }
2911:         DMPlexSetSupport(rdm, newp+r, supportRef);
2912: #if 1
2913:         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);
2914:         for (p = 0; p < supportSize; ++p) {
2915:           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);
2916:         }
2917: #endif
2918:       }
2919:     }
2920:     /* Interior faces have 3 edges and 2 cells */
2921:     for (c = cStart; c < cEnd; ++c) {
2922:       PetscInt        newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*8;
2923:       const PetscInt *cone, *ornt;
2924:       PetscInt        coneNew[3], orntNew[3];
2925:       PetscInt        supportNew[2];

2927:       DMPlexGetCone(dm, c, &cone);
2928:       DMPlexGetConeOrientation(dm, c, &ornt);
2929:       /* Face A: {c, a, d} */
2930:       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*3 + GetTriMidEdge_Static(ornt[0], 2);
2931:       orntNew[0] = ornt[0] < 0 ? -2 : 0;
2932:       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*3 + GetTriMidEdge_Static(ornt[1], 2);
2933:       orntNew[1] = ornt[1] < 0 ? -2 : 0;
2934:       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*3 + GetTriMidEdge_Static(ornt[2], 2);
2935:       orntNew[2] = ornt[2] < 0 ? -2 : 0;
2936:       DMPlexSetCone(rdm, newp, coneNew);
2937:       DMPlexSetConeOrientation(rdm, newp, orntNew);
2938: #if 1
2939:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2940:       for (p = 0; p < 3; ++p) {
2941:         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);
2942:       }
2943: #endif
2944:       supportNew[0] = (c - cStart)*8 + 0;
2945:       supportNew[1] = (c - cStart)*8 + 0+4;
2946:       DMPlexSetSupport(rdm, newp, supportNew);
2947: #if 1
2948:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2949:       for (p = 0; p < 2; ++p) {
2950:         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);
2951:       }
2952: #endif
2953:       ++newp;
2954:       /* Face B: {a, b, e} */
2955:       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*3 + GetTriMidEdge_Static(ornt[0], 0);
2956:       orntNew[0] = ornt[0] < 0 ? -2 : 0;
2957:       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*3 + GetTriMidEdge_Static(ornt[3], 0);
2958:       orntNew[1] = ornt[3] < 0 ? -2 : 0;
2959:       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*3 + GetTriMidEdge_Static(ornt[1], 1);
2960:       orntNew[2] = ornt[1] < 0 ? -2 : 0;
2961:       DMPlexSetCone(rdm, newp, coneNew);
2962:       DMPlexSetConeOrientation(rdm, newp, orntNew);
2963: #if 1
2964:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2965:       for (p = 0; p < 3; ++p) {
2966:         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);
2967:       }
2968: #endif
2969:       supportNew[0] = (c - cStart)*8 + 1;
2970:       supportNew[1] = (c - cStart)*8 + 1+4;
2971:       DMPlexSetSupport(rdm, newp, supportNew);
2972: #if 1
2973:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2974:       for (p = 0; p < 2; ++p) {
2975:         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);
2976:       }
2977: #endif
2978:       ++newp;
2979:       /* Face C: {c, f, b} */
2980:       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*3 + GetTriMidEdge_Static(ornt[2], 0);
2981:       orntNew[0] = ornt[2] < 0 ? -2 : 0;
2982:       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*3 + GetTriMidEdge_Static(ornt[3], 2);
2983:       orntNew[1] = ornt[3] < 0 ? -2 : 0;
2984:       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*3 + GetTriMidEdge_Static(ornt[0], 1);
2985:       orntNew[2] = ornt[0] < 0 ? -2 : 0;
2986:       DMPlexSetCone(rdm, newp, coneNew);
2987:       DMPlexSetConeOrientation(rdm, newp, orntNew);
2988: #if 1
2989:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2990:       for (p = 0; p < 3; ++p) {
2991:         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);
2992:       }
2993: #endif
2994:       supportNew[0] = (c - cStart)*8 + 2;
2995:       supportNew[1] = (c - cStart)*8 + 2+4;
2996:       DMPlexSetSupport(rdm, newp, supportNew);
2997: #if 1
2998:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2999:       for (p = 0; p < 2; ++p) {
3000:         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);
3001:       }
3002: #endif
3003:       ++newp;
3004:       /* Face D: {d, e, f} */
3005:       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*3 + GetTriMidEdge_Static(ornt[1], 0);
3006:       orntNew[0] = ornt[1] < 0 ? -2 : 0;
3007:       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*3 + GetTriMidEdge_Static(ornt[3], 1);
3008:       orntNew[1] = ornt[3] < 0 ? -2 : 0;
3009:       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*3 + GetTriMidEdge_Static(ornt[2], 1);
3010:       orntNew[2] = ornt[2] < 0 ? -2 : 0;
3011:       DMPlexSetCone(rdm, newp, coneNew);
3012:       DMPlexSetConeOrientation(rdm, newp, orntNew);
3013: #if 1
3014:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
3015:       for (p = 0; p < 3; ++p) {
3016:         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);
3017:       }
3018: #endif
3019:       supportNew[0] = (c - cStart)*8 + 3;
3020:       supportNew[1] = (c - cStart)*8 + 3+4;
3021:       DMPlexSetSupport(rdm, newp, supportNew);
3022: #if 1
3023:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
3024:       for (p = 0; p < 2; ++p) {
3025:         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);
3026:       }
3027: #endif
3028:       ++newp;
3029:       /* Face E: {d, f, a} */
3030:       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*3 + GetTriMidEdge_Static(ornt[2], 1);
3031:       orntNew[0] = ornt[2] < 0 ? 0 : -2;
3032:       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart);
3033:       orntNew[1] = -2;
3034:       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*3 + GetTriMidEdge_Static(ornt[1], 2);
3035:       orntNew[2] = ornt[1] < 0 ? -2 : 0;
3036:       DMPlexSetCone(rdm, newp, coneNew);
3037:       DMPlexSetConeOrientation(rdm, newp, orntNew);
3038: #if 1
3039:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
3040:       for (p = 0; p < 3; ++p) {
3041:         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);
3042:       }
3043: #endif
3044:       supportNew[0] = (c - cStart)*8 + 0+4;
3045:       supportNew[1] = (c - cStart)*8 + 3+4;
3046:       DMPlexSetSupport(rdm, newp, supportNew);
3047: #if 1
3048:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
3049:       for (p = 0; p < 2; ++p) {
3050:         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);
3051:       }
3052: #endif
3053:       ++newp;
3054:       /* Face F: {c, a, f} */
3055:       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*3 + GetTriMidEdge_Static(ornt[0], 2);
3056:       orntNew[0] = ornt[0] < 0 ? -2 : 0;
3057:       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart);
3058:       orntNew[1] = 0;
3059:       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*3 + GetTriMidEdge_Static(ornt[2], 0);
3060:       orntNew[2] = ornt[2] < 0 ? 0 : -2;
3061:       DMPlexSetCone(rdm, newp, coneNew);
3062:       DMPlexSetConeOrientation(rdm, newp, orntNew);
3063: #if 1
3064:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
3065:       for (p = 0; p < 3; ++p) {
3066:         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);
3067:       }
3068: #endif
3069:       supportNew[0] = (c - cStart)*8 + 0+4;
3070:       supportNew[1] = (c - cStart)*8 + 2+4;
3071:       DMPlexSetSupport(rdm, newp, supportNew);
3072: #if 1
3073:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
3074:       for (p = 0; p < 2; ++p) {
3075:         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);
3076:       }
3077: #endif
3078:       ++newp;
3079:       /* Face G: {e, a, f} */
3080:       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*3 + GetTriMidEdge_Static(ornt[1], 1);
3081:       orntNew[0] = ornt[1] < 0 ? -2 : 0;
3082:       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart);
3083:       orntNew[1] = 0;
3084:       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*3 + GetTriMidEdge_Static(ornt[3], 1);
3085:       orntNew[2] = ornt[3] < 0 ? 0 : -2;
3086:       DMPlexSetCone(rdm, newp, coneNew);
3087:       DMPlexSetConeOrientation(rdm, newp, orntNew);
3088: #if 1
3089:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
3090:       for (p = 0; p < 3; ++p) {
3091:         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);
3092:       }
3093: #endif
3094:       supportNew[0] = (c - cStart)*8 + 1+4;
3095:       supportNew[1] = (c - cStart)*8 + 3+4;
3096:       DMPlexSetSupport(rdm, newp, supportNew);
3097: #if 1
3098:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
3099:       for (p = 0; p < 2; ++p) {
3100:         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);
3101:       }
3102: #endif
3103:       ++newp;
3104:       /* Face H: {a, b, f} */
3105:       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*3 + GetTriMidEdge_Static(ornt[0], 0);
3106:       orntNew[0] = ornt[0] < 0 ? -2 : 0;
3107:       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*3 + GetTriMidEdge_Static(ornt[3], 2);
3108:       orntNew[1] = ornt[3] < 0 ? 0 : -2;
3109:       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart);
3110:       orntNew[2] = -2;
3111:       DMPlexSetCone(rdm, newp, coneNew);
3112:       DMPlexSetConeOrientation(rdm, newp, orntNew);
3113: #if 1
3114:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
3115:       for (p = 0; p < 3; ++p) {
3116:         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);
3117:       }
3118: #endif
3119:       supportNew[0] = (c - cStart)*8 + 1+4;
3120:       supportNew[1] = (c - cStart)*8 + 2+4;
3121:       DMPlexSetSupport(rdm, newp, supportNew);
3122: #if 1
3123:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
3124:       for (p = 0; p < 2; ++p) {
3125:         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);
3126:       }
3127: #endif
3128:       ++newp;
3129:     }
3130:     /* Split Edges have 2 vertices and the same faces as the parent */
3131:     for (e = eStart; e < eEnd; ++e) {
3132:       const PetscInt newv = vStartNew + (vEnd - vStart) + (e - eStart);

3134:       for (r = 0; r < 2; ++r) {
3135:         const PetscInt  newp = eStartNew + (e - eStart)*2 + r;
3136:         const PetscInt *cone, *ornt, *support;
3137:         PetscInt        coneNew[2], coneSize, c, supportSize, s;

3139:         DMPlexGetCone(dm, e, &cone);
3140:         coneNew[0]       = vStartNew + (cone[0] - vStart);
3141:         coneNew[1]       = vStartNew + (cone[1] - vStart);
3142:         coneNew[(r+1)%2] = newv;
3143:         DMPlexSetCone(rdm, newp, coneNew);
3144: #if 1
3145:         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
3146:         for (p = 0; p < 2; ++p) {
3147:           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);
3148:         }
3149: #endif
3150:         DMPlexGetSupportSize(dm, e, &supportSize);
3151:         DMPlexGetSupport(dm, e, &support);
3152:         for (s = 0; s < supportSize; ++s) {
3153:           DMPlexGetConeSize(dm, support[s], &coneSize);
3154:           DMPlexGetCone(dm, support[s], &cone);
3155:           DMPlexGetConeOrientation(dm, support[s], &ornt);
3156:           for (c = 0; c < coneSize; ++c) {
3157:             if (cone[c] == e) break;
3158:           }
3159:           supportRef[s] = fStartNew + (support[s] - fStart)*4 + (c + (ornt[c] < 0 ? 1-r : r))%3;
3160:         }
3161:         DMPlexSetSupport(rdm, newp, supportRef);
3162: #if 1
3163:         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
3164:         for (p = 0; p < supportSize; ++p) {
3165:           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);
3166:         }
3167: #endif
3168:       }
3169:     }
3170:     /* Face edges have 2 vertices and 2+cells*(1/2) faces */
3171:     for (f = fStart; f < fEnd; ++f) {
3172:       const PetscInt *cone, *ornt, *support;
3173:       PetscInt        coneSize, supportSize, s;

3175:       DMPlexGetSupportSize(dm, f, &supportSize);
3176:       DMPlexGetSupport(dm, f, &support);
3177:       for (r = 0; r < 3; ++r) {
3178:         const PetscInt  newp = eStartNew + (eEnd - eStart)*2 + (f - fStart)*3 + r;
3179:         PetscInt        coneNew[2], intFaces = 0, er, eint[4] = {1, 0, 2, 0};
3180:         PetscInt        fint[24] = { 1,  7, -1, -1,  0,  5,
3181:                                     -1, -1,  1,  6,  0,  4,
3182:                                      2,  5,  3,  4, -1, -1,
3183:                                     -1, -1,  3,  6,  2,  7};

3185:         DMPlexGetCone(dm, f, &cone);
3186:         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[(r+0)%3] - eStart);
3187:         coneNew[1] = vStartNew + (vEnd - vStart) + (cone[(r+1)%3] - eStart);
3188:         DMPlexSetCone(rdm, newp, coneNew);
3189: #if 1
3190:         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
3191:         for (p = 0; p < 2; ++p) {
3192:           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);
3193:         }
3194: #endif
3195:         supportRef[0] = fStartNew + (f - fStart)*4 + (r+1)%3;
3196:         supportRef[1] = fStartNew + (f - fStart)*4 + 3;
3197:         for (s = 0; s < supportSize; ++s) {
3198:           DMPlexGetConeSize(dm, support[s], &coneSize);
3199:           DMPlexGetCone(dm, support[s], &cone);
3200:           DMPlexGetConeOrientation(dm, support[s], &ornt);
3201:           for (c = 0; c < coneSize; ++c) {if (cone[c] == f) break;}
3202:           /* Here we want to determine whether edge newp contains a vertex which is part of the cross-tet edge */
3203:           er = GetTriMidEdgeInverse_Static(ornt[c], r);
3204:           if (er == eint[c]) {
3205:             supportRef[2+intFaces++] = fStartNew + (fEnd - fStart)*4 + (support[s] - cStart)*8 + (c + 2)%4;
3206:           } else {
3207:             supportRef[2+intFaces++] = fStartNew + (fEnd - fStart)*4 + (support[s] - cStart)*8 + fint[(c*3 + er)*2 + 0];
3208:             supportRef[2+intFaces++] = fStartNew + (fEnd - fStart)*4 + (support[s] - cStart)*8 + fint[(c*3 + er)*2 + 1];
3209:           }
3210:         }
3211:         DMPlexSetSupport(rdm, newp, supportRef);
3212: #if 1
3213:         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
3214:         for (p = 0; p < intFaces; ++p) {
3215:           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);
3216:         }
3217: #endif
3218:       }
3219:     }
3220:     /* Interior edges have 2 vertices and 4 faces */
3221:     for (c = cStart; c < cEnd; ++c) {
3222:       const PetscInt  newp = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart);
3223:       const PetscInt *cone, *ornt, *fcone;
3224:       PetscInt        coneNew[2], supportNew[4], find;

3226:       DMPlexGetCone(dm, c, &cone);
3227:       DMPlexGetConeOrientation(dm, c, &ornt);
3228:       DMPlexGetCone(dm, cone[0], &fcone);
3229:       find = GetTriEdge_Static(ornt[0], 0);
3230:       coneNew[0] = vStartNew + (vEnd - vStart) + (fcone[find] - eStart);
3231:       DMPlexGetCone(dm, cone[2], &fcone);
3232:       find = GetTriEdge_Static(ornt[2], 1);
3233:       coneNew[1] = vStartNew + (vEnd - vStart) + (fcone[find] - eStart);
3234:       DMPlexSetCone(rdm, newp, coneNew);
3235: #if 1
3236:       if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
3237:       for (p = 0; p < 2; ++p) {
3238:         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);
3239:       }
3240: #endif
3241:       supportNew[0] = fStartNew + (fEnd - fStart)*4 + (c - cStart)*8 + 4;
3242:       supportNew[1] = fStartNew + (fEnd - fStart)*4 + (c - cStart)*8 + 5;
3243:       supportNew[2] = fStartNew + (fEnd - fStart)*4 + (c - cStart)*8 + 6;
3244:       supportNew[3] = fStartNew + (fEnd - fStart)*4 + (c - cStart)*8 + 7;
3245:       DMPlexSetSupport(rdm, newp, supportNew);
3246: #if 1
3247:       if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
3248:       for (p = 0; p < 4; ++p) {
3249:         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);
3250:       }
3251: #endif
3252:     }
3253:     /* Old vertices have identical supports */
3254:     for (v = vStart; v < vEnd; ++v) {
3255:       const PetscInt  newp = vStartNew + (v - vStart);
3256:       const PetscInt *support, *cone;
3257:       PetscInt        size, s;

3259:       DMPlexGetSupportSize(dm, v, &size);
3260:       DMPlexGetSupport(dm, v, &support);
3261:       for (s = 0; s < size; ++s) {
3262:         PetscInt r = 0;

3264:         DMPlexGetCone(dm, support[s], &cone);
3265:         if (cone[1] == v) r = 1;
3266:         supportRef[s] = eStartNew + (support[s] - eStart)*2 + r;
3267:       }
3268:       DMPlexSetSupport(rdm, newp, supportRef);
3269: #if 1
3270:       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
3271:       for (p = 0; p < size; ++p) {
3272:         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);
3273:       }
3274: #endif
3275:     }
3276:     /* Edge vertices have 2 + face*2 + 0/1 supports */
3277:     for (e = eStart; e < eEnd; ++e) {
3278:       const PetscInt  newp = vStartNew + (vEnd - vStart) + (e - eStart);
3279:       const PetscInt *cone, *support;
3280:       PetscInt       *star = NULL, starSize, cellSize = 0, coneSize, size, s;

3282:       DMPlexGetSupportSize(dm, e, &size);
3283:       DMPlexGetSupport(dm, e, &support);
3284:       supportRef[0] = eStartNew + (e - eStart)*2 + 0;
3285:       supportRef[1] = eStartNew + (e - eStart)*2 + 1;
3286:       for (s = 0; s < size; ++s) {
3287:         PetscInt r = 0;

3289:         DMPlexGetConeSize(dm, support[s], &coneSize);
3290:         DMPlexGetCone(dm, support[s], &cone);
3291:         for (r = 0; r < coneSize; ++r) {if (cone[r] == e) break;}
3292:         supportRef[2+s*2+0] = eStartNew + (eEnd - eStart)*2 + (support[s] - fStart)*3 + (r+0)%3;
3293:         supportRef[2+s*2+1] = eStartNew + (eEnd - eStart)*2 + (support[s] - fStart)*3 + (r+2)%3;
3294:       }
3295:       DMPlexGetTransitiveClosure(dm, e, PETSC_FALSE, &starSize, &star);
3296:       for (s = 0; s < starSize*2; s += 2) {
3297:         const PetscInt *cone, *ornt;
3298:         PetscInt        e01, e23;

3300:         if ((star[s] >= cStart) && (star[s] < cEnd)) {
3301:           /* Check edge 0-1 */
3302:           DMPlexGetCone(dm, star[s], &cone);
3303:           DMPlexGetConeOrientation(dm, star[s], &ornt);
3304:           DMPlexGetCone(dm, cone[0], &cone);
3305:           e01  = cone[GetTriEdge_Static(ornt[0], 0)];
3306:           /* Check edge 2-3 */
3307:           DMPlexGetCone(dm, star[s], &cone);
3308:           DMPlexGetConeOrientation(dm, star[s], &ornt);
3309:           DMPlexGetCone(dm, cone[2], &cone);
3310:           e23  = cone[GetTriEdge_Static(ornt[2], 1)];
3311:           if ((e01 == e) || (e23 == e)) {supportRef[2+size*2+cellSize++] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (star[s] - cStart);}
3312:         }
3313:       }
3314:       DMPlexRestoreTransitiveClosure(dm, e, PETSC_FALSE, &starSize, &star);
3315:       DMPlexSetSupport(rdm, newp, supportRef);
3316: #if 1
3317:       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
3318:       for (p = 0; p < 2+size*2+cellSize; ++p) {
3319:         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);
3320:       }
3321: #endif
3322:     }
3323:     PetscFree(supportRef);
3324:     DMPlexRestoreFaces_Internal(dm, 3, cStart, NULL, NULL, &faces);
3325:     break;
3326:   case REFINER_HYBRID_SIMPLEX_3D:
3327:     DMPlexGetHybridBounds(rdm, &cMaxNew, &fMaxNew, &eMaxNew, NULL);
3328:     /* Interior cells have 4 faces: Tet face order is prescribed in DMPlexGetFaces_Internal() */
3329:     DMPlexGetRawFaces_Internal(dm, 3, 4, cellInd, NULL, NULL, &faces);
3330:     for (c = cStart; c < cMax; ++c) {
3331:       const PetscInt  newp = cStartNew + (c - cStart)*8;
3332:       const PetscInt *cone, *ornt;
3333:       PetscInt        coneNew[4], orntNew[4];

3335:       DMPlexGetCone(dm, c, &cone);
3336:       DMPlexGetConeOrientation(dm, c, &ornt);
3337:       /* A tetrahedron: {0, a, c, d} */
3338:       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetTriSubface_Static(ornt[0], 0); /* A */
3339:       orntNew[0] = ornt[0];
3340:       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetTriSubface_Static(ornt[1], 0); /* A */
3341:       orntNew[1] = ornt[1];
3342:       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetTriSubface_Static(ornt[2], 0); /* A */
3343:       orntNew[2] = ornt[2];
3344:       coneNew[3] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 0;
3345:       orntNew[3] = 0;
3346:       DMPlexSetCone(rdm, newp+0, coneNew);
3347:       DMPlexSetConeOrientation(rdm, newp+0, orntNew);
3348: #if 1
3349:       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);
3350:       for (p = 0; p < 4; ++p) {
3351:         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);
3352:       }
3353: #endif
3354:       /* B tetrahedron: {a, 1, b, e} */
3355:       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetTriSubface_Static(ornt[0], 1); /* B */
3356:       orntNew[0] = ornt[0];
3357:       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetTriSubface_Static(ornt[1], 2); /* C */
3358:       orntNew[1] = ornt[1];
3359:       coneNew[2] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 1;
3360:       orntNew[2] = 0;
3361:       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetTriSubface_Static(ornt[3], 1); /* B */
3362:       orntNew[3] = ornt[3];
3363:       DMPlexSetCone(rdm, newp+1, coneNew);
3364:       DMPlexSetConeOrientation(rdm, newp+1, orntNew);
3365: #if 1
3366:       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);
3367:       for (p = 0; p < 4; ++p) {
3368:         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);
3369:       }
3370: #endif
3371:       /* C tetrahedron: {c, b, 2, f} */
3372:       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetTriSubface_Static(ornt[0], 2); /* C */
3373:       orntNew[0] = ornt[0];
3374:       coneNew[1] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 2;
3375:       orntNew[1] = 0;
3376:       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetTriSubface_Static(ornt[2], 1); /* B */
3377:       orntNew[2] = ornt[2];
3378:       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetTriSubface_Static(ornt[3], 0); /* A */
3379:       orntNew[3] = ornt[3];
3380:       DMPlexSetCone(rdm, newp+2, coneNew);
3381:       DMPlexSetConeOrientation(rdm, newp+2, orntNew);
3382: #if 1
3383:       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);
3384:       for (p = 0; p < 4; ++p) {
3385:         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);
3386:       }
3387: #endif
3388:       /* D tetrahedron: {d, e, f, 3} */
3389:       coneNew[0] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 3;
3390:       orntNew[0] = 0;
3391:       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetTriSubface_Static(ornt[1], 1); /* B */
3392:       orntNew[1] = ornt[1];
3393:       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetTriSubface_Static(ornt[2], 2); /* C */
3394:       orntNew[2] = ornt[2];
3395:       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetTriSubface_Static(ornt[3], 2); /* C */
3396:       orntNew[3] = ornt[3];
3397:       DMPlexSetCone(rdm, newp+3, coneNew);
3398:       DMPlexSetConeOrientation(rdm, newp+3, orntNew);
3399: #if 1
3400:       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);
3401:       for (p = 0; p < 4; ++p) {
3402:         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);
3403:       }
3404: #endif
3405:       /* A' tetrahedron: {d, a, c, f} */
3406:       coneNew[0] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 0;
3407:       orntNew[0] = -3;
3408:       coneNew[1] = fStartNew + (cone[2] - fStart)*4 + 3;
3409:       orntNew[1] = ornt[2] < 0 ? -(GetTriMidEdge_Static(ornt[2], 0)+1) : GetTriMidEdge_Static(ornt[2], 0);
3410:       coneNew[2] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 5;
3411:       orntNew[2] = 0;
3412:       coneNew[3] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 4;
3413:       orntNew[3] = 2;
3414:       DMPlexSetCone(rdm, newp+4, coneNew);
3415:       DMPlexSetConeOrientation(rdm, newp+4, orntNew);
3416: #if 1
3417:       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);
3418:       for (p = 0; p < 4; ++p) {
3419:         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);
3420:       }
3421: #endif
3422:       /* B' tetrahedron: {e, b, a, f} */
3423:       coneNew[0] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 1;
3424:       orntNew[0] = -3;
3425:       coneNew[1] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 6;
3426:       orntNew[1] = 1;
3427:       coneNew[2] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 7;
3428:       orntNew[2] = 0;
3429:       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + 3;
3430:       orntNew[3] = ornt[3] < 0 ? -(GetTriMidEdge_Static(ornt[3], 0)+1) : GetTriMidEdge_Static(ornt[3], 0);
3431:       DMPlexSetCone(rdm, newp+5, coneNew);
3432:       DMPlexSetConeOrientation(rdm, newp+5, orntNew);
3433: #if 1
3434:       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);
3435:       for (p = 0; p < 4; ++p) {
3436:         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);
3437:       }
3438: #endif
3439:       /* C' tetrahedron: {b, f, c, a} */
3440:       coneNew[0] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 2;
3441:       orntNew[0] = -3;
3442:       coneNew[1] = fStartNew + (cone[0] - fStart)*4 + 3;
3443:       orntNew[1] = ornt[0] < 0 ? -(GetTriMidEdge_Static(ornt[0], 2)+1) : GetTriMidEdge_Static(ornt[0], 2);
3444:       coneNew[2] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 5;
3445:       orntNew[2] = -3;
3446:       coneNew[3] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 7;
3447:       orntNew[3] = -2;
3448:       DMPlexSetCone(rdm, newp+6, coneNew);
3449:       DMPlexSetConeOrientation(rdm, newp+6, orntNew);
3450: #if 1
3451:       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);
3452:       for (p = 0; p < 4; ++p) {
3453:         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);
3454:       }
3455: #endif
3456:       /* D' tetrahedron: {f, e, d, a} */
3457:       coneNew[0] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 3;
3458:       orntNew[0] = -3;
3459:       coneNew[1] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 4;
3460:       orntNew[1] = -3;
3461:       coneNew[2] = fStartNew + (cone[1] - fStart)*4 + 3;
3462:       orntNew[2] = ornt[1] < 0 ? -(GetTriMidEdge_Static(ornt[1], 0)+1) : GetTriMidEdge_Static(ornt[1], 0);
3463:       coneNew[3] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 6;
3464:       orntNew[3] = -3;
3465:       DMPlexSetCone(rdm, newp+7, coneNew);
3466:       DMPlexSetConeOrientation(rdm, newp+7, orntNew);
3467: #if 1
3468:       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);
3469:       for (p = 0; p < 4; ++p) {
3470:         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);
3471:       }
3472: #endif
3473:     }
3474:     /* Hybrid cells have 5 faces */
3475:     for (c = cMax; c < cEnd; ++c) {
3476:       const PetscInt  newp = cStartNew + (cMax - cStart)*8 + (c - cMax)*4;
3477:       const PetscInt *cone, *ornt, *fornt;
3478:       PetscInt        coneNew[5], orntNew[5], o, of, i;

3480:       DMPlexGetCone(dm, c, &cone);
3481:       DMPlexGetConeOrientation(dm, c, &ornt);
3482:       DMPlexGetConeOrientation(dm, cone[0], &fornt);
3483:       o = ornt[0] < 0 ? -1 : 1;
3484:       for (r = 0; r < 3; ++r) {
3485:         coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetTriSubface_Static(ornt[0], r);
3486:         orntNew[0] = ornt[0];
3487:         coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetTriSubface_Static(ornt[1], r);
3488:         orntNew[1] = ornt[1];
3489:         of = fornt[GetTriEdge_Static(ornt[0], r)]       < 0 ? -1 : 1;
3490:         i  = GetTriEdgeInverse_Static(ornt[0], r)       + 2;
3491:         coneNew[i] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (cone[2+GetTriEdge_Static(ornt[0], r)]       - fMax)*2 + (o*of < 0 ? 1 : 0);
3492:         orntNew[i] = 0;
3493:         i  = GetTriEdgeInverse_Static(ornt[0], (r+1)%3) + 2;
3494:         coneNew[i] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (c - cMax)*3 + GetTriSubface_Static(ornt[0], r);
3495:         orntNew[i] = 0;
3496:         of = fornt[GetTriEdge_Static(ornt[0], (r+2)%3)] < 0 ? -1 : 1;
3497:         i  = GetTriEdgeInverse_Static(ornt[0], (r+2)%3) + 2;
3498:         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);
3499:         orntNew[i] = 0;
3500:         DMPlexSetCone(rdm, newp+r, coneNew);
3501:         DMPlexSetConeOrientation(rdm, newp+r, orntNew);
3502: #if 1
3503:         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);
3504:         for (p = 0; p < 2; ++p) {
3505:           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);
3506:         }
3507:         for (p = 2; p < 5; ++p) {
3508:           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);
3509:         }
3510: #endif
3511:       }
3512:       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + 3;
3513:       orntNew[0] = 0;
3514:       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + 3;
3515:       orntNew[1] = 0;
3516:       coneNew[2] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (c - cMax)*3 + 1;
3517:       orntNew[2] = 0;
3518:       coneNew[3] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (c - cMax)*3 + 2;
3519:       orntNew[3] = 0;
3520:       coneNew[4] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (c - cMax)*3 + 0;
3521:       orntNew[4] = 0;
3522:       DMPlexSetCone(rdm, newp+3, coneNew);
3523:       DMPlexSetConeOrientation(rdm, newp+3, orntNew);
3524: #if 1
3525:       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);
3526:       for (p = 0; p < 2; ++p) {
3527:         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);
3528:       }
3529:       for (p = 2; p < 5; ++p) {
3530:         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);
3531:       }
3532: #endif
3533:     }
3534:     /* Split faces have 3 edges and the same cells as the parent */
3535:     DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);
3536:     PetscMalloc1(2 + maxSupportSize*2, &supportRef);
3537:     for (f = fStart; f < fMax; ++f) {
3538:       const PetscInt  newp = fStartNew + (f - fStart)*4;
3539:       const PetscInt *cone, *ornt, *support;
3540:       PetscInt        coneNew[3], orntNew[3], coneSize, supportSize, s;

3542:       DMPlexGetCone(dm, f, &cone);
3543:       DMPlexGetConeOrientation(dm, f, &ornt);
3544:       /* A triangle */
3545:       coneNew[0] = eStartNew + (cone[0] - eStart)*2 + (ornt[0] < 0 ? 1 : 0);
3546:       orntNew[0] = ornt[0];
3547:       coneNew[1] = eStartNew + (eMax    - eStart)*2 + (f - fStart)*3 + 2;
3548:       orntNew[1] = -2;
3549:       coneNew[2] = eStartNew + (cone[2] - eStart)*2 + (ornt[2] < 0 ? 0 : 1);
3550:       orntNew[2] = ornt[2];
3551:       DMPlexSetCone(rdm, newp+0, coneNew);
3552:       DMPlexSetConeOrientation(rdm, newp+0, orntNew);
3553: #if 1
3554:       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);
3555:       for (p = 0; p < 3; ++p) {
3556:         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);
3557:       }
3558: #endif
3559:       /* B triangle */
3560:       coneNew[0] = eStartNew + (cone[0] - eStart)*2 + (ornt[0] < 0 ? 0 : 1);
3561:       orntNew[0] = ornt[0];
3562:       coneNew[1] = eStartNew + (cone[1] - eStart)*2 + (ornt[1] < 0 ? 1 : 0);
3563:       orntNew[1] = ornt[1];
3564:       coneNew[2] = eStartNew + (eMax    - eStart)*2 + (f - fStart)*3 + 0;
3565:       orntNew[2] = -2;
3566:       DMPlexSetCone(rdm, newp+1, coneNew);
3567:       DMPlexSetConeOrientation(rdm, newp+1, orntNew);
3568: #if 1
3569:       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);
3570:       for (p = 0; p < 3; ++p) {
3571:         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);
3572:       }
3573: #endif
3574:       /* C triangle */
3575:       coneNew[0] = eStartNew + (eMax    - eStart)*2 + (f - fStart)*3 + 1;
3576:       orntNew[0] = -2;
3577:       coneNew[1] = eStartNew + (cone[1] - eStart)*2 + (ornt[1] < 0 ? 0 : 1);
3578:       orntNew[1] = ornt[1];
3579:       coneNew[2] = eStartNew + (cone[2] - eStart)*2 + (ornt[2] < 0 ? 1 : 0);
3580:       orntNew[2] = ornt[2];
3581:       DMPlexSetCone(rdm, newp+2, coneNew);
3582:       DMPlexSetConeOrientation(rdm, newp+2, orntNew);
3583: #if 1
3584:       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);
3585:       for (p = 0; p < 3; ++p) {
3586:         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);
3587:       }
3588: #endif
3589:       /* D triangle */
3590:       coneNew[0] = eStartNew + (eMax    - eStart)*2 + (f - fStart)*3 + 0;
3591:       orntNew[0] = 0;
3592:       coneNew[1] = eStartNew + (eMax    - eStart)*2 + (f - fStart)*3 + 1;
3593:       orntNew[1] = 0;
3594:       coneNew[2] = eStartNew + (eMax    - eStart)*2 + (f - fStart)*3 + 2;
3595:       orntNew[2] = 0;
3596:       DMPlexSetCone(rdm, newp+3, coneNew);
3597:       DMPlexSetConeOrientation(rdm, newp+3, orntNew);
3598: #if 1
3599:       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);
3600:       for (p = 0; p < 3; ++p) {
3601:         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);
3602:       }
3603: #endif
3604:       DMPlexGetSupportSize(dm, f, &supportSize);
3605:       DMPlexGetSupport(dm, f, &support);
3606:       for (r = 0; r < 4; ++r) {
3607:         for (s = 0; s < supportSize; ++s) {
3608:           PetscInt subf;
3609:           DMPlexGetConeSize(dm, support[s], &coneSize);
3610:           DMPlexGetCone(dm, support[s], &cone);
3611:           DMPlexGetConeOrientation(dm, support[s], &ornt);
3612:           for (c = 0; c < coneSize; ++c) {
3613:             if (cone[c] == f) break;
3614:           }
3615:           subf = GetTriSubfaceInverse_Static(ornt[c], r);
3616:           if (support[s] < cMax) {
3617:             supportRef[s] = cStartNew + (support[s] - cStart)*8 + (r==3 ? (c+2)%4 + 4 : faces[c*3+subf]);
3618:           } else {
3619:             supportRef[s] = cStartNew + (cMax - cStart)*8 + (support[s] - cMax)*4 + (r==3 ? r : subf);
3620:           }
3621:         }
3622:         DMPlexSetSupport(rdm, newp+r, supportRef);
3623: #if 1
3624:         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);
3625:         for (p = 0; p < supportSize; ++p) {
3626:           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);
3627:         }
3628: #endif
3629:       }
3630:     }
3631:     /* Interior cell faces have 3 edges and 2 cells */
3632:     for (c = cStart; c < cMax; ++c) {
3633:       PetscInt        newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*8;
3634:       const PetscInt *cone, *ornt;
3635:       PetscInt        coneNew[3], orntNew[3];
3636:       PetscInt        supportNew[2];

3638:       DMPlexGetCone(dm, c, &cone);
3639:       DMPlexGetConeOrientation(dm, c, &ornt);
3640:       /* Face A: {c, a, d} */
3641:       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*3 + GetTriMidEdge_Static(ornt[0], 2);
3642:       orntNew[0] = ornt[0] < 0 ? -2 : 0;
3643:       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*3 + GetTriMidEdge_Static(ornt[1], 2);
3644:       orntNew[1] = ornt[1] < 0 ? -2 : 0;
3645:       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*3 + GetTriMidEdge_Static(ornt[2], 2);
3646:       orntNew[2] = ornt[2] < 0 ? -2 : 0;
3647:       DMPlexSetCone(rdm, newp, coneNew);
3648:       DMPlexSetConeOrientation(rdm, newp, orntNew);
3649: #if 1
3650:       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
3651:       for (p = 0; p < 3; ++p) {
3652:         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);
3653:       }
3654: #endif
3655:       supportNew[0] = (c - cStart)*8 + 0;
3656:       supportNew[1] = (c - cStart)*8 + 0+4;
3657:       DMPlexSetSupport(rdm, newp, supportNew);
3658: #if 1
3659:       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
3660:       for (p = 0; p < 2; ++p) {
3661:         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);
3662:       }
3663: #endif
3664:       ++newp;
3665:       /* Face B: {a, b, e} */
3666:       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*3 + GetTriMidEdge_Static(ornt[0], 0);
3667:       orntNew[0] = ornt[0] < 0 ? -2 : 0;
3668:       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*3 + GetTriMidEdge_Static(ornt[3], 0);
3669:       orntNew[1] = ornt[3] < 0 ? -2 : 0;
3670:       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*3 + GetTriMidEdge_Static(ornt[1], 1);
3671:       orntNew[2] = ornt[1] < 0 ? -2 : 0;
3672:       DMPlexSetCone(rdm, newp, coneNew);
3673:       DMPlexSetConeOrientation(rdm, newp, orntNew);
3674: #if 1
3675:       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);
3676:       for (p = 0; p < 3; ++p) {
3677:         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);
3678:       }
3679: #endif
3680:       supportNew[0] = (c - cStart)*8 + 1;
3681:       supportNew[1] = (c - cStart)*8 + 1+4;
3682:       DMPlexSetSupport(rdm, newp, supportNew);
3683: #if 1
3684:       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
3685:       for (p = 0; p < 2; ++p) {
3686:         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);
3687:       }
3688: #endif
3689:       ++newp;
3690:       /* Face C: {c, f, b} */
3691:       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*3 + GetTriMidEdge_Static(ornt[2], 0);
3692:       orntNew[0] = ornt[2] < 0 ? -2 : 0;
3693:       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*3 + GetTriMidEdge_Static(ornt[3], 2);
3694:       orntNew[1] = ornt[3] < 0 ? -2 : 0;
3695:       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*3 + GetTriMidEdge_Static(ornt[0], 1);
3696:       orntNew[2] = ornt[0] < 0 ? -2 : 0;
3697:       DMPlexSetCone(rdm, newp, coneNew);
3698:       DMPlexSetConeOrientation(rdm, newp, orntNew);
3699: #if 1
3700:       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
3701:       for (p = 0; p < 3; ++p) {
3702:         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);
3703:       }
3704: #endif
3705:       supportNew[0] = (c - cStart)*8 + 2;
3706:       supportNew[1] = (c - cStart)*8 + 2+4;
3707:       DMPlexSetSupport(rdm, newp, supportNew);
3708: #if 1
3709:       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
3710:       for (p = 0; p < 2; ++p) {
3711:         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);
3712:       }
3713: #endif
3714:       ++newp;
3715:       /* Face D: {d, e, f} */
3716:       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*3 + GetTriMidEdge_Static(ornt[1], 0);
3717:       orntNew[0] = ornt[1] < 0 ? -2 : 0;
3718:       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*3 + GetTriMidEdge_Static(ornt[3], 1);
3719:       orntNew[1] = ornt[3] < 0 ? -2 : 0;
3720:       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*3 + GetTriMidEdge_Static(ornt[2], 1);
3721:       orntNew[2] = ornt[2] < 0 ? -2 : 0;
3722:       DMPlexSetCone(rdm, newp, coneNew);
3723:       DMPlexSetConeOrientation(rdm, newp, orntNew);
3724: #if 1
3725:       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
3726:       for (p = 0; p < 3; ++p) {
3727:         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);
3728:       }
3729: #endif
3730:       supportNew[0] = (c - cStart)*8 + 3;
3731:       supportNew[1] = (c - cStart)*8 + 3+4;
3732:       DMPlexSetSupport(rdm, newp, supportNew);
3733: #if 1
3734:       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
3735:       for (p = 0; p < 2; ++p) {
3736:         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);
3737:       }
3738: #endif
3739:       ++newp;
3740:       /* Face E: {d, f, a} */
3741:       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*3 + GetTriMidEdge_Static(ornt[2], 1);
3742:       orntNew[0] = ornt[2] < 0 ? 0 : -2;
3743:       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart);
3744:       orntNew[1] = -2;
3745:       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*3 + GetTriMidEdge_Static(ornt[1], 2);
3746:       orntNew[2] = ornt[1] < 0 ? -2 : 0;
3747:       DMPlexSetCone(rdm, newp, coneNew);
3748:       DMPlexSetConeOrientation(rdm, newp, orntNew);
3749: #if 1
3750:       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
3751:       for (p = 0; p < 3; ++p) {
3752:         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);
3753:       }
3754: #endif
3755:       supportNew[0] = (c - cStart)*8 + 0+4;
3756:       supportNew[1] = (c - cStart)*8 + 3+4;
3757:       DMPlexSetSupport(rdm, newp, supportNew);
3758: #if 1
3759:       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
3760:       for (p = 0; p < 2; ++p) {
3761:         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);
3762:       }
3763: #endif
3764:       ++newp;
3765:       /* Face F: {c, a, f} */
3766:       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*3 + GetTriMidEdge_Static(ornt[0], 2);
3767:       orntNew[0] = ornt[0] < 0 ? -2 : 0;
3768:       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart);
3769:       orntNew[1] = 0;
3770:       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*3 + GetTriMidEdge_Static(ornt[2], 0);
3771:       orntNew[2] = ornt[2] < 0 ? 0 : -2;
3772:       DMPlexSetCone(rdm, newp, coneNew);
3773:       DMPlexSetConeOrientation(rdm, newp, orntNew);
3774: #if 1
3775:       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
3776:       for (p = 0; p < 3; ++p) {
3777:         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);
3778:       }
3779: #endif
3780:       supportNew[0] = (c - cStart)*8 + 0+4;
3781:       supportNew[1] = (c - cStart)*8 + 2+4;
3782:       DMPlexSetSupport(rdm, newp, supportNew);
3783: #if 1
3784:       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
3785:       for (p = 0; p < 2; ++p) {
3786:         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);
3787:       }
3788: #endif
3789:       ++newp;
3790:       /* Face G: {e, a, f} */
3791:       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*3 + GetTriMidEdge_Static(ornt[1], 1);
3792:       orntNew[0] = ornt[1] < 0 ? -2 : 0;
3793:       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart);
3794:       orntNew[1] = 0;
3795:       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*3 + GetTriMidEdge_Static(ornt[3], 1);
3796:       orntNew[2] = ornt[3] < 0 ? 0 : -2;
3797:       DMPlexSetCone(rdm, newp, coneNew);
3798:       DMPlexSetConeOrientation(rdm, newp, orntNew);
3799: #if 1
3800:       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
3801:       for (p = 0; p < 3; ++p) {
3802:         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);
3803:       }
3804: #endif
3805:       supportNew[0] = (c - cStart)*8 + 1+4;
3806:       supportNew[1] = (c - cStart)*8 + 3+4;
3807:       DMPlexSetSupport(rdm, newp, supportNew);
3808: #if 1
3809:       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
3810:       for (p = 0; p < 2; ++p) {
3811:         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);
3812:       }
3813: #endif
3814:       ++newp;
3815:       /* Face H: {a, b, f} */
3816:       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*3 + GetTriMidEdge_Static(ornt[0], 0);
3817:       orntNew[0] = ornt[0] < 0 ? -2 : 0;
3818:       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*3 + GetTriMidEdge_Static(ornt[3], 2);
3819:       orntNew[1] = ornt[3] < 0 ? 0 : -2;
3820:       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart);
3821:       orntNew[2] = -2;
3822:       DMPlexSetCone(rdm, newp, coneNew);
3823:       DMPlexSetConeOrientation(rdm, newp, orntNew);
3824: #if 1
3825:       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
3826:       for (p = 0; p < 3; ++p) {
3827:         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);
3828:       }
3829: #endif
3830:       supportNew[0] = (c - cStart)*8 + 1+4;
3831:       supportNew[1] = (c - cStart)*8 + 2+4;
3832:       DMPlexSetSupport(rdm, newp, supportNew);
3833: #if 1
3834:       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
3835:       for (p = 0; p < 2; ++p) {
3836:         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);
3837:       }
3838: #endif
3839:       ++newp;
3840:     }
3841:     /* Hybrid split faces have 4 edges and same cells */
3842:     for (f = fMax; f < fEnd; ++f) {
3843:       const PetscInt *cone, *ornt, *support;
3844:       PetscInt        coneNew[4], orntNew[4];
3845:       PetscInt        supportNew[2], size, s, c;

3847:       DMPlexGetCone(dm, f, &cone);
3848:       DMPlexGetConeOrientation(dm, f, &ornt);
3849:       DMPlexGetSupportSize(dm, f, &size);
3850:       DMPlexGetSupport(dm, f, &support);
3851:       for (r = 0; r < 2; ++r) {
3852:         const PetscInt newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (f - fMax)*2 + r;

3854:         coneNew[0]   = eStartNew + (cone[0] - eStart)*2 + (ornt[0] < 0 ? 1-r : r);
3855:         orntNew[0]   = ornt[0];
3856:         coneNew[1]   = eStartNew + (cone[1] - eStart)*2 + (ornt[1] < 0 ? 1-r : r);
3857:         orntNew[1]   = ornt[1];
3858:         coneNew[2+r] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (cone[2+r] - eMax);
3859:         orntNew[2+r] = 0;
3860:         coneNew[3-r] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (eEnd      - eMax) + (f - fMax);
3861:         orntNew[3-r] = 0;
3862:         DMPlexSetCone(rdm, newp, coneNew);
3863:         DMPlexSetConeOrientation(rdm, newp, orntNew);
3864: #if 1
3865:         if ((newp < fMaxNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid face [%d, %d)", newp, fMaxNew, fEndNew);
3866:         for (p = 0; p < 2; ++p) {
3867:           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);
3868:         }
3869:         for (p = 2; p < 4; ++p) {
3870:           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);
3871:         }
3872: #endif
3873:         for (s = 0; s < size; ++s) {
3874:           const PetscInt *coneCell, *orntCell, *fornt;
3875:           PetscInt        o, of;

3877:           DMPlexGetCone(dm, support[s], &coneCell);
3878:           DMPlexGetConeOrientation(dm, support[s], &orntCell);
3879:           o = orntCell[0] < 0 ? -1 : 1;
3880:           for (c = 2; c < 5; ++c) if (coneCell[c] == f) break;
3881:           if (c >= 5) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Could not find face %d in cone of cell %d", f, support[s]);
3882:           DMPlexGetConeOrientation(dm, coneCell[0], &fornt);
3883:           of = fornt[c-2] < 0 ? -1 : 1;
3884:           supportNew[s] = cStartNew + (cMax - cStart)*8 + (support[s] - cMax)*4 + (GetTriEdgeInverse_Static(orntCell[0], c-2) + (o*of < 0 ? 1-r : r))%3;
3885:         }
3886:         DMPlexSetSupport(rdm, newp, supportNew);
3887: #if 1
3888:         if ((newp < fMaxNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid face [%d, %d)", newp, fMaxNew, fEndNew);
3889:         for (p = 0; p < size; ++p) {
3890:           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);
3891:         }
3892: #endif
3893:       }
3894:     }
3895:     /* Hybrid cell faces have 4 edges and 2 cells */
3896:     for (c = cMax; c < cEnd; ++c) {
3897:       PetscInt        newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (c - cMax)*3;
3898:       const PetscInt *cone, *ornt;
3899:       PetscInt        coneNew[4], orntNew[4];
3900:       PetscInt        supportNew[2];

3902:       DMPlexGetCone(dm, c, &cone);
3903:       DMPlexGetConeOrientation(dm, c, &ornt);
3904:       for (r = 0; r < 3; ++r) {
3905:         coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*3 + (r+2)%3;
3906:         orntNew[0] = 0;
3907:         coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*3 + (r+2)%3;
3908:         orntNew[1] = 0;
3909:         coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (eEnd - eMax) + (cone[2+(r+2)%3] - fMax);
3910:         orntNew[2] = 0;
3911:         coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (eEnd - eMax) + (cone[2+r]       - fMax);
3912:         orntNew[3] = 0;
3913:         DMPlexSetCone(rdm, newp+r, coneNew);
3914:         DMPlexSetConeOrientation(rdm, newp+r, orntNew);
3915: #if 1
3916:         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);
3917:         for (p = 0; p < 2; ++p) {
3918:           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);
3919:         }
3920:         for (p = 2; p < 4; ++p) {
3921:           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);
3922:         }
3923: #endif
3924:         supportNew[0] = cStartNew + (cMax - cStart)*8 + (c - cMax)*4 + GetTriSubface_Static(ornt[0], r);
3925:         supportNew[1] = cStartNew + (cMax - cStart)*8 + (c - cMax)*4 + 3;
3926:         DMPlexSetSupport(rdm, newp+r, supportNew);
3927: #if 1
3928:         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);
3929:         for (p = 0; p < 2; ++p) {
3930:           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);
3931:         }
3932: #endif
3933:       }
3934:     }
3935:     /* Interior split edges have 2 vertices and the same faces as the parent */
3936:     for (e = eStart; e < eMax; ++e) {
3937:       const PetscInt newv = vStartNew + (vEnd - vStart) + (e - eStart);

3939:       for (r = 0; r < 2; ++r) {
3940:         const PetscInt  newp = eStartNew + (e - eStart)*2 + r;
3941:         const PetscInt *cone, *ornt, *support;
3942:         PetscInt        coneNew[2], coneSize, c, supportSize, s;

3944:         DMPlexGetCone(dm, e, &cone);
3945:         coneNew[0]       = vStartNew + (cone[0] - vStart);
3946:         coneNew[1]       = vStartNew + (cone[1] - vStart);
3947:         coneNew[(r+1)%2] = newv;
3948:         DMPlexSetCone(rdm, newp, coneNew);
3949: #if 1
3950:         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
3951:         for (p = 0; p < 2; ++p) {
3952:           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);
3953:         }
3954: #endif
3955:         DMPlexGetSupportSize(dm, e, &supportSize);
3956:         DMPlexGetSupport(dm, e, &support);
3957:         for (s = 0; s < supportSize; ++s) {
3958:           DMPlexGetConeSize(dm, support[s], &coneSize);
3959:           DMPlexGetCone(dm, support[s], &cone);
3960:           DMPlexGetConeOrientation(dm, support[s], &ornt);
3961:           for (c = 0; c < coneSize; ++c) if (cone[c] == e) break;
3962:           if (support[s] < fMax) {
3963:             supportRef[s] = fStartNew + (support[s] - fStart)*4 + (c + (ornt[c] < 0 ? 1-r : r))%3;
3964:           } else {
3965:             supportRef[s] = fStartNew + (fMax       - fStart)*4 + (cMax - cStart)*8 + (support[s] - fMax)*2 + (ornt[c] < 0 ? 1-r : r);
3966:           }
3967:         }
3968:         DMPlexSetSupport(rdm, newp, supportRef);
3969: #if 1
3970:         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
3971:         for (p = 0; p < supportSize; ++p) {
3972:           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);
3973:         }
3974: #endif
3975:       }
3976:     }
3977:     /* Interior face edges have 2 vertices and 2+cells*(1/2) faces */
3978:     for (f = fStart; f < fMax; ++f) {
3979:       const PetscInt *cone, *ornt, *support;
3980:       PetscInt        coneSize, supportSize, s;

3982:       DMPlexGetSupportSize(dm, f, &supportSize);
3983:       DMPlexGetSupport(dm, f, &support);
3984:       for (r = 0; r < 3; ++r) {
3985:         const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (f - fStart)*3 + r;
3986:         PetscInt        coneNew[2], intFaces = 0, er, eint[4] = {1, 0, 2, 0};
3987:         PetscInt        fint[24] = { 1,  7, -1, -1,  0,  5,
3988:                                     -1, -1,  1,  6,  0,  4,
3989:                                      2,  5,  3,  4, -1, -1,
3990:                                     -1, -1,  3,  6,  2,  7};

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

4037:       DMPlexGetCone(dm, c, &cone);
4038:       DMPlexGetConeOrientation(dm, c, &ornt);
4039:       DMPlexGetCone(dm, cone[0], &fcone);
4040:       find = GetTriEdge_Static(ornt[0], 0);
4041:       coneNew[0] = vStartNew + (vEnd - vStart) + (fcone[find] - eStart);
4042:       DMPlexGetCone(dm, cone[2], &fcone);
4043:       find = GetTriEdge_Static(ornt[2], 1);
4044:       coneNew[1] = vStartNew + (vEnd - vStart) + (fcone[find] - eStart);
4045:       DMPlexSetCone(rdm, newp, coneNew);
4046: #if 1
4047:       if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
4048:       for (p = 0; p < 2; ++p) {
4049:         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);
4050:       }
4051: #endif
4052:       supportNew[0] = fStartNew + (fMax - fStart)*4 + (c - cStart)*8 + 4;
4053:       supportNew[1] = fStartNew + (fMax - fStart)*4 + (c - cStart)*8 + 5;
4054:       supportNew[2] = fStartNew + (fMax - fStart)*4 + (c - cStart)*8 + 6;
4055:       supportNew[3] = fStartNew + (fMax - fStart)*4 + (c - cStart)*8 + 7;
4056:       DMPlexSetSupport(rdm, newp, supportNew);
4057: #if 1
4058:       if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
4059:       for (p = 0; p < 4; ++p) {
4060:         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);
4061:       }
4062: #endif
4063:     }
4064:     /* Hybrid edges have two vertices and the same faces */
4065:     for (e = eMax; e < eEnd; ++e) {
4066:       const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (e - eMax);
4067:       const PetscInt *cone, *support, *fcone;
4068:       PetscInt        coneNew[2], size, fsize, s;

4070:       DMPlexGetCone(dm, e, &cone);
4071:       DMPlexGetSupportSize(dm, e, &size);
4072:       DMPlexGetSupport(dm, e, &support);
4073:       coneNew[0] = vStartNew + (cone[0] - vStart);
4074:       coneNew[1] = vStartNew + (cone[1] - vStart);
4075:       DMPlexSetCone(rdm, newp, coneNew);
4076: #if 1
4077:       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid edge [%d, %d)", newp, eMaxNew, eEndNew);
4078:       for (p = 0; p < 2; ++p) {
4079:         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);
4080:       }
4081: #endif
4082:       for (s = 0; s < size; ++s) {
4083:         DMPlexGetConeSize(dm, support[s], &fsize);
4084:         DMPlexGetCone(dm, support[s], &fcone);
4085:         for (c = 0; c < fsize; ++c) if (fcone[c] == e) break;
4086:         if ((c < 2) || (c > 3)) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Edge %d not found in cone of face %d", e, support[s]);
4087:         supportRef[s] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (support[s] - fMax)*2 + c-2;
4088:       }
4089:       DMPlexSetSupport(rdm, newp, supportRef);
4090: #if 1
4091:       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid edge [%d, %d)", newp, eMaxNew, eEndNew);
4092:       for (p = 0; p < size; ++p) {
4093:         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);
4094:       }
4095: #endif
4096:     }
4097:     /* Hybrid face edges have 2 vertices and 2+2*cells faces */
4098:     for (f = fMax; f < fEnd; ++f) {
4099:       const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (eEnd - eMax) + (f - fMax);
4100:       const PetscInt *cone, *support, *ccone, *cornt;
4101:       PetscInt        coneNew[2], size, csize, s;

4103:       DMPlexGetCone(dm, f, &cone);
4104:       DMPlexGetSupportSize(dm, f, &size);
4105:       DMPlexGetSupport(dm, f, &support);
4106:       coneNew[0] = vStartNew + (vEnd - vStart) + (cone[0] - eStart);
4107:       coneNew[1] = vStartNew + (vEnd - vStart) + (cone[1] - eStart);
4108:       DMPlexSetCone(rdm, newp, coneNew);
4109: #if 1
4110:       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid edge [%d, %d)", newp, eMaxNew, eEndNew);
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:       supportRef[0] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (f - fMax)*2 + 0;
4116:       supportRef[1] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (f - fMax)*2 + 1;
4117:       for (s = 0; s < size; ++s) {
4118:         DMPlexGetConeSize(dm, support[s], &csize);
4119:         DMPlexGetCone(dm, support[s], &ccone);
4120:         DMPlexGetConeOrientation(dm, support[s], &cornt);
4121:         for (c = 0; c < csize; ++c) if (ccone[c] == f) break;
4122:         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]);
4123:         supportRef[2+s*2+0] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (support[s] - cMax)*3 + c-2;
4124:         supportRef[2+s*2+1] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (support[s] - cMax)*3 + (c-1)%3;
4125:       }
4126:       DMPlexSetSupport(rdm, newp, supportRef);
4127: #if 1
4128:       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid edge [%d, %d)", newp, eMaxNew, eEndNew);
4129:       for (p = 0; p < 2+size*2; ++p) {
4130:         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);
4131:       }
4132: #endif
4133:     }
4134:     /* Interior vertices have identical supports */
4135:     for (v = vStart; v < vEnd; ++v) {
4136:       const PetscInt  newp = vStartNew + (v - vStart);
4137:       const PetscInt *support, *cone;
4138:       PetscInt        size, s;

4140:       DMPlexGetSupportSize(dm, v, &size);
4141:       DMPlexGetSupport(dm, v, &support);
4142:       for (s = 0; s < size; ++s) {
4143:         PetscInt r = 0;

4145:         DMPlexGetCone(dm, support[s], &cone);
4146:         if (cone[1] == v) r = 1;
4147:         if (support[s] < eMax) supportRef[s] = eStartNew + (support[s] - eStart)*2 + r;
4148:         else                   supportRef[s] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (support[s] - eMax);
4149:       }
4150:       DMPlexSetSupport(rdm, newp, supportRef);
4151: #if 1
4152:       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
4153:       for (p = 0; p < size; ++p) {
4154:         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);
4155:       }
4156: #endif
4157:     }
4158:     /* Interior edge vertices have 2 + interior face*2 + hybrid face + cells*0/1 supports */
4159:     for (e = eStart; e < eMax; ++e) {
4160:       const PetscInt  newp = vStartNew + (vEnd - vStart) + (e - eStart);
4161:       const PetscInt *cone, *support;
4162:       PetscInt       *star = NULL, starSize, faceSize = 0, cellSize = 0, coneSize, size, s;

4164:       DMPlexGetSupportSize(dm, e, &size);
4165:       DMPlexGetSupport(dm, e, &support);
4166:       supportRef[0] = eStartNew + (e - eStart)*2 + 0;
4167:       supportRef[1] = eStartNew + (e - eStart)*2 + 1;
4168:       for (s = 0; s < size; ++s) {
4169:         PetscInt r = 0;

4171:         if (support[s] < fMax) {
4172:           DMPlexGetConeSize(dm, support[s], &coneSize);
4173:           DMPlexGetCone(dm, support[s], &cone);
4174:           for (r = 0; r < coneSize; ++r) {if (cone[r] == e) break;}
4175:           supportRef[2+faceSize+0] = eStartNew + (eMax - eStart)*2 + (support[s] - fStart)*3 + (r+0)%3;
4176:           supportRef[2+faceSize+1] = eStartNew + (eMax - eStart)*2 + (support[s] - fStart)*3 + (r+2)%3;
4177:           faceSize += 2;
4178:         } else {
4179:           supportRef[2+faceSize+0] = eStartNew + (eMax - eStart)*2 + (fMax       - fStart)*3 + (cMax - cStart) + (eEnd - eMax) + (support[s] - fMax);
4180:           ++faceSize;
4181:         }
4182:       }
4183:       DMPlexGetTransitiveClosure(dm, e, PETSC_FALSE, &starSize, &star);
4184:       for (s = 0; s < starSize*2; s += 2) {
4185:         const PetscInt *cone, *ornt;
4186:         PetscInt        e01, e23;

4188:         if ((star[s] >= cStart) && (star[s] < cMax)) {
4189:           /* Check edge 0-1 */
4190:           DMPlexGetCone(dm, star[s], &cone);
4191:           DMPlexGetConeOrientation(dm, star[s], &ornt);
4192:           DMPlexGetCone(dm, cone[0], &cone);
4193:           e01  = cone[GetTriEdge_Static(ornt[0], 0)];
4194:           /* Check edge 2-3 */
4195:           DMPlexGetCone(dm, star[s], &cone);
4196:           DMPlexGetConeOrientation(dm, star[s], &ornt);
4197:           DMPlexGetCone(dm, cone[2], &cone);
4198:           e23  = cone[GetTriEdge_Static(ornt[2], 1)];
4199:           if ((e01 == e) || (e23 == e)) {supportRef[2+faceSize+cellSize++] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (star[s] - cStart);}
4200:         }
4201:       }
4202:       DMPlexRestoreTransitiveClosure(dm, e, PETSC_FALSE, &starSize, &star);
4203:       DMPlexSetSupport(rdm, newp, supportRef);
4204: #if 1
4205:       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
4206:       for (p = 0; p < 2+faceSize+cellSize; ++p) {
4207:         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);
4208:       }
4209: #endif
4210:     }
4211:     PetscFree(supportRef);
4212:     DMPlexRestoreFaces_Internal(dm, 3, cStart, NULL, NULL, &faces);
4213:     break;
4214:   case REFINER_SIMPLEX_TO_HEX_3D:
4215:     DMPlexGetRawFaces_Internal(dm, 3, 4, cellInd, NULL, NULL, &faces);
4216:     /* All cells have 6 faces */
4217:     for (c = cStart; c < cEnd; ++c) {
4218:       const PetscInt  newp = cStartNew + (c - cStart)*4;
4219:       const PetscInt *cone, *ornt;
4220:       PetscInt        coneNew[6];
4221:       PetscInt        orntNew[6];

4223:       DMPlexGetCone(dm, c, &cone);
4224:       DMPlexGetConeOrientation(dm, c, &ornt);
4225:       /* A hex */
4226:       coneNew[0] = fStartNew + (cone[0] - fStart)*3 + GetTriSubface_Static(ornt[0], 0); /* B */
4227:       orntNew[0] = ornt[0] < 0 ? -1 : 1;
4228:       coneNew[1] = fStartNew + (fEnd    - fStart)*3 + (c - cStart)*6 + 3;               /* T */
4229:       orntNew[1] = -4;
4230:       coneNew[2] = fStartNew + (cone[2] - fStart)*3 + GetTriSubface_Static(ornt[2], 0); /* F */
4231:       orntNew[2] = ornt[2] < 0 ? -1 : 1;
4232:       coneNew[3] = fStartNew + (fEnd    - fStart)*3 + (c - cStart)*6 + 0;               /* K */
4233:       orntNew[3] = -1;
4234:       coneNew[4] = fStartNew + (fEnd    - fStart)*3 + (c - cStart)*6 + 2;               /* R */
4235:       orntNew[4] = 0;
4236:       coneNew[5] = fStartNew + (cone[1] - fStart)*3 + GetTriSubface_Static(ornt[1], 0); /* L */
4237:       orntNew[5] = ornt[1] < 0 ? -1 : 1;
4238:       DMPlexSetCone(rdm, newp+0, coneNew);
4239:       DMPlexSetConeOrientation(rdm, newp+0, orntNew);
4240: #if 1
4241:       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);
4242:       for (p = 0; p < 6; ++p) {
4243:         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);
4244:       }
4245: #endif
4246:       /* B hex */
4247:       coneNew[0] = fStartNew + (cone[0] - fStart)*3 + GetTriSubface_Static(ornt[0], 1); /* B */
4248:       orntNew[0] = ornt[0] < 0 ? -2 : 0;
4249:       coneNew[1] = fStartNew + (fEnd    - fStart)*3 + (c - cStart)*6 + 4;               /* T */
4250:       orntNew[1] = 0;
4251:       coneNew[2] = fStartNew + (fEnd    - fStart)*3 + (c - cStart)*6 + 0;               /* F */
4252:       orntNew[2] = 0;
4253:       coneNew[3] = fStartNew + (cone[3] - fStart)*3 + GetTriSubface_Static(ornt[3], 1); /* K */
4254:       orntNew[3] = ornt[3] < 0 ? -2 : 0;
4255:       coneNew[4] = fStartNew + (fEnd    - fStart)*3 + (c - cStart)*6 + 1;               /* R */
4256:       orntNew[4] = 0;
4257:       coneNew[5] = fStartNew + (cone[1] - fStart)*3 + GetTriSubface_Static(ornt[1], 2); /* L */
4258:       orntNew[5] = ornt[1] < 0 ? -4 : 2;
4259:       DMPlexSetCone(rdm, newp+1, coneNew);
4260:       DMPlexSetConeOrientation(rdm, newp+1, orntNew);
4261: #if 1
4262:       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);
4263:       for (p = 0; p < 6; ++p) {
4264:         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);
4265:       }
4266: #endif
4267:       /* C hex */
4268:       coneNew[0] = fStartNew + (cone[0] - fStart)*3 + GetTriSubface_Static(ornt[0], 2); /* B */
4269:       orntNew[0] = ornt[0] < 0 ? -4 : 2;
4270:       coneNew[1] = fStartNew + (fEnd    - fStart)*3 + (c - cStart)*6 + 5;               /* T */
4271:       orntNew[1] = -4;
4272:       coneNew[2] = fStartNew + (cone[2] - fStart)*3 + GetTriSubface_Static(ornt[2], 1); /* F */
4273:       orntNew[2] = ornt[2] < 0 ? -2 : 0;
4274:       coneNew[3] = fStartNew + (fEnd    - fStart)*3 + (c - cStart)*6 + 1;               /* K */
4275:       orntNew[3] = -1;
4276:       coneNew[4] = fStartNew + (cone[3] - fStart)*3 + GetTriSubface_Static(ornt[3], 0); /* R */
4277:       orntNew[4] = ornt[3] < 0 ? -1 : 1;
4278:       coneNew[5] = fStartNew + (fEnd    - fStart)*3 + (c - cStart)*6 + 2;               /* L */
4279:       orntNew[5] = -4;
4280:       DMPlexSetCone(rdm, newp+2, coneNew);
4281:       DMPlexSetConeOrientation(rdm, newp+2, orntNew);
4282: #if 1
4283:       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);
4284:       for (p = 0; p < 6; ++p) {
4285:         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);
4286:       }
4287: #endif
4288:       /* D hex */
4289:       coneNew[0] = fStartNew + (fEnd    - fStart)*3 + (c - cStart)*6 + 3;               /* B */
4290:       orntNew[0] = 0;
4291:       coneNew[1] = fStartNew + (cone[3] - fStart)*3 + GetTriSubface_Static(ornt[3], 2); /* T */
4292:       orntNew[1] = ornt[3] < 0 ? -1 : 1;
4293:       coneNew[2] = fStartNew + (cone[2] - fStart)*3 + GetTriSubface_Static(ornt[2], 2); /* F */
4294:       orntNew[2] = ornt[2] < 0 ? -4 : 2;
4295:       coneNew[3] = fStartNew + (fEnd    - fStart)*3 + (c - cStart)*6 + 4;               /* K */
4296:       orntNew[3] = -1;
4297:       coneNew[4] = fStartNew + (fEnd    - fStart)*3 + (c - cStart)*6 + 5;               /* R */
4298:       orntNew[4] = 0;
4299:       coneNew[5] = fStartNew + (cone[1] - fStart)*3 + GetTriSubface_Static(ornt[1], 1); /* L */
4300:       orntNew[5] = ornt[1] < 0 ? -2 : 0;
4301:       DMPlexSetCone(rdm, newp+3, coneNew);
4302:       DMPlexSetConeOrientation(rdm, newp+3, orntNew);
4303: #if 1
4304:       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);
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:     }
4310:     /* Split faces have 4 edges and the same cells as the parent */
4311:     DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);
4312:     PetscMalloc1(2 + maxSupportSize*2, &supportRef);
4313:     for (f = fStart; f < fEnd; ++f) {
4314:       const PetscInt  newp = fStartNew + (f - fStart)*3;
4315:       const PetscInt *cone, *ornt, *support;
4316:       PetscInt        coneNew[4], orntNew[4], coneSize, supportSize, s;

4318:       DMPlexGetCone(dm, f, &cone);
4319:       DMPlexGetConeOrientation(dm, f, &ornt);
4320:       /* A quad */
4321:       coneNew[0] = eStartNew + (cone[2] - eStart)*2 + (ornt[2] < 0 ? 0 : 1);
4322:       orntNew[0] = ornt[2];
4323:       coneNew[1] = eStartNew + (cone[0] - eStart)*2 + (ornt[0] < 0 ? 1 : 0);
4324:       orntNew[1] = ornt[0];
4325:       coneNew[2] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 0;
4326:       orntNew[2] = 0;
4327:       coneNew[3] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 2;
4328:       orntNew[3] = -2;
4329:       DMPlexSetCone(rdm, newp+0, coneNew);
4330:       DMPlexSetConeOrientation(rdm, newp+0, orntNew);
4331: #if 1
4332:       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);
4333:       for (p = 0; p < 4; ++p) {
4334:         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);
4335:       }
4336: #endif
4337:       /* B quad */
4338:       coneNew[0] = eStartNew + (cone[0] - eStart)*2 + (ornt[0] < 0 ? 0 : 1);
4339:       orntNew[0] = ornt[0];
4340:       coneNew[1] = eStartNew + (cone[1] - eStart)*2 + (ornt[1] < 0 ? 1 : 0);
4341:       orntNew[1] = ornt[1];
4342:       coneNew[2] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 1;
4343:       orntNew[2] = 0;
4344:       coneNew[3] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 0;
4345:       orntNew[3] = -2;
4346:       DMPlexSetCone(rdm, newp+1, coneNew);
4347:       DMPlexSetConeOrientation(rdm, newp+1, orntNew);
4348: #if 1
4349:       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);
4350:       for (p = 0; p < 4; ++p) {
4351:         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);
4352:       }
4353: #endif
4354:       /* C quad */
4355:       coneNew[0] = eStartNew + (cone[1] - eStart)*2 + (ornt[1] < 0 ? 0 : 1);
4356:       orntNew[0] = ornt[1];
4357:       coneNew[1] = eStartNew + (cone[2] - eStart)*2 + (ornt[2] < 0 ? 1 : 0);
4358:       orntNew[1] = ornt[2];
4359:       coneNew[2] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 2;
4360:       orntNew[2] = 0;
4361:       coneNew[3] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 1;
4362:       orntNew[3] = -2;
4363:       DMPlexSetCone(rdm, newp+2, coneNew);
4364:       DMPlexSetConeOrientation(rdm, newp+2, orntNew);
4365: #if 1
4366:       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);
4367:       for (p = 0; p < 4; ++p) {
4368:         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);
4369:       }
4370: #endif
4371:       DMPlexGetSupportSize(dm, f, &supportSize);
4372:       DMPlexGetSupport(dm, f, &support);
4373:       for (r = 0; r < 3; ++r) {
4374:         for (s = 0; s < supportSize; ++s) {
4375:           PetscInt subf;
4376:           DMPlexGetConeSize(dm, support[s], &coneSize);
4377:           DMPlexGetCone(dm, support[s], &cone);
4378:           DMPlexGetConeOrientation(dm, support[s], &ornt);
4379:           for (c = 0; c < coneSize; ++c) {
4380:             if (cone[c] == f) break;
4381:           }
4382:           subf = GetTriSubfaceInverse_Static(ornt[c], r);
4383:           supportRef[s] = cStartNew + (support[s] - cStart)*4 + faces[c*3+subf];
4384:         }
4385:         DMPlexSetSupport(rdm, newp+r, supportRef);
4386: #if 1
4387:         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);
4388:         for (p = 0; p < supportSize; ++p) {
4389:           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);
4390:         }
4391: #endif
4392:       }
4393:     }
4394:     /* Interior faces have 4 edges and 2 cells */
4395:     for (c = cStart; c < cEnd; ++c) {
4396:       PetscInt        newp = fStartNew + (fEnd - fStart)*3 + (c - cStart)*6;
4397:       const PetscInt *cone, *ornt;
4398:       PetscInt        coneNew[4], orntNew[4];
4399:       PetscInt        supportNew[2];

4401:       DMPlexGetCone(dm, c, &cone);
4402:       DMPlexGetConeOrientation(dm, c, &ornt);
4403:       /* Face {a, g, m, h} */
4404:       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*3 + GetTriInteriorEdge_Static(ornt[0],0);
4405:       orntNew[0] = 0;
4406:       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + 0;
4407:       orntNew[1] = 0;
4408:       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + 1;
4409:       orntNew[2] = -2;
4410:       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*3 + GetTriInteriorEdge_Static(ornt[1],2);
4411:       orntNew[3] = -2;
4412:       DMPlexSetCone(rdm, newp, coneNew);
4413:       DMPlexSetConeOrientation(rdm, newp, orntNew);
4414: #if 1
4415:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4416:       for (p = 0; p < 4; ++p) {
4417:         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);
4418:       }
4419: #endif
4420:       supportNew[0] = (c - cStart)*4 + 0;
4421:       supportNew[1] = (c - cStart)*4 + 1;
4422:       DMPlexSetSupport(rdm, newp, supportNew);
4423: #if 1
4424:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4425:       for (p = 0; p < 2; ++p) {
4426:         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);
4427:       }
4428: #endif
4429:       ++newp;
4430:       /* Face {g, b, l , m} */
4431:       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*3 + GetTriInteriorEdge_Static(ornt[0],1);
4432:       orntNew[0] = -2;
4433:       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*3 + GetTriInteriorEdge_Static(ornt[3],0);
4434:       orntNew[1] = 0;
4435:       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + 3;
4436:       orntNew[2] = 0;
4437:       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + 0;
4438:       orntNew[3] = -2;
4439:       DMPlexSetCone(rdm, newp, coneNew);
4440:       DMPlexSetConeOrientation(rdm, newp, orntNew);
4441: #if 1
4442:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4443:       for (p = 0; p < 4; ++p) {
4444:         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);
4445:       }
4446: #endif
4447:       supportNew[0] = (c - cStart)*4 + 1;
4448:       supportNew[1] = (c - cStart)*4 + 2;
4449:       DMPlexSetSupport(rdm, newp, supportNew);
4450: #if 1
4451:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4452:       for (p = 0; p < 2; ++p) {
4453:         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);
4454:       }
4455: #endif
4456:       ++newp;
4457:       /* Face {c, g, m, i} */
4458:       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*3 + GetTriInteriorEdge_Static(ornt[0],2);
4459:       orntNew[0] = 0;
4460:       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + 0;
4461:       orntNew[1] = 0;
4462:       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + 2;
4463:       orntNew[2] = -2;
4464:       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*3 + GetTriInteriorEdge_Static(ornt[2],0);
4465:       orntNew[3] = -2;
4466:       DMPlexSetCone(rdm, newp, coneNew);
4467:       DMPlexSetConeOrientation(rdm, newp, orntNew);
4468: #if 1
4469:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4470:       for (p = 0; p < 4; ++p) {
4471:         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);
4472:       }
4473: #endif
4474:       supportNew[0] = (c - cStart)*4 + 0;
4475:       supportNew[1] = (c - cStart)*4 + 2;
4476:       DMPlexSetSupport(rdm, newp, supportNew);
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 < 2; ++p) {
4480:         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);
4481:       }
4482: #endif
4483:       ++newp;
4484:       /* Face {d, h, m, i} */
4485:       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*3 + GetTriInteriorEdge_Static(ornt[1],0);
4486:       orntNew[0] = 0;
4487:       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + 1;
4488:       orntNew[1] = 0;
4489:       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + 2;
4490:       orntNew[2] = -2;
4491:       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*3 + GetTriInteriorEdge_Static(ornt[2],2);
4492:       orntNew[3] = -2;
4493:       DMPlexSetCone(rdm, newp, coneNew);
4494:       DMPlexSetConeOrientation(rdm, newp, orntNew);
4495: #if 1
4496:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4497:       for (p = 0; p < 4; ++p) {
4498:         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);
4499:       }
4500: #endif
4501:       supportNew[0] = (c - cStart)*4 + 0;
4502:       supportNew[1] = (c - cStart)*4 + 3;
4503:       DMPlexSetSupport(rdm, newp, supportNew);
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 < 2; ++p) {
4507:         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);
4508:       }
4509: #endif
4510:       ++newp;
4511:       /* Face {h, m, l, e} */
4512:       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + 1;
4513:       orntNew[0] = 0;
4514:       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + 3;
4515:       orntNew[1] = -2;
4516:       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*3 + GetTriInteriorEdge_Static(ornt[3],1);
4517:       orntNew[2] = -2;
4518:       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*3 + GetTriInteriorEdge_Static(ornt[1],1);
4519:       orntNew[3] = 0;
4520:       DMPlexSetCone(rdm, newp, coneNew);
4521:       DMPlexSetConeOrientation(rdm, newp, orntNew);
4522: #if 1
4523:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4524:       for (p = 0; p < 4; ++p) {
4525:         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);
4526:       }
4527: #endif
4528:       supportNew[0] = (c - cStart)*4 + 1;
4529:       supportNew[1] = (c - cStart)*4 + 3;
4530:       DMPlexSetSupport(rdm, newp, supportNew);
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 < 2; ++p) {
4534:         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);
4535:       }
4536: #endif
4537:       ++newp;
4538:       /* Face {i, m, l, f} */
4539:       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + 2;
4540:       orntNew[0] = 0;
4541:       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + 3;
4542:       orntNew[1] = -2;
4543:       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*3 + GetTriInteriorEdge_Static(ornt[3],2);
4544:       orntNew[2] = -2;
4545:       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*3 + GetTriInteriorEdge_Static(ornt[2],1);
4546:       orntNew[3] = 0;
4547:       DMPlexSetCone(rdm, newp, coneNew);
4548:       DMPlexSetConeOrientation(rdm, newp, orntNew);
4549: #if 1
4550:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4551:       for (p = 0; p < 4; ++p) {
4552:         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);
4553:       }
4554: #endif
4555:       supportNew[0] = (c - cStart)*4 + 2;
4556:       supportNew[1] = (c - cStart)*4 + 3;
4557:       DMPlexSetSupport(rdm, newp, supportNew);
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 < 2; ++p) {
4561:         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);
4562:       }
4563: #endif
4564:       ++newp;
4565:     }
4566:     /* Split Edges have 2 vertices and the same faces as the parent */
4567:     for (e = eStart; e < eEnd; ++e) {
4568:       const PetscInt newv = vStartNew + (vEnd - vStart) + (e - eStart);

4570:       for (r = 0; r < 2; ++r) {
4571:         const PetscInt  newp = eStartNew + (e - eStart)*2 + r;
4572:         const PetscInt *cone, *ornt, *support;
4573:         PetscInt        coneNew[2], coneSize, c, supportSize, s;

4575:         DMPlexGetCone(dm, e, &cone);
4576:         coneNew[0]       = vStartNew + (cone[0] - vStart);
4577:         coneNew[1]       = vStartNew + (cone[1] - vStart);
4578:         coneNew[(r+1)%2] = newv;
4579:         DMPlexSetCone(rdm, newp, coneNew);
4580: #if 1
4581:         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
4582:         for (p = 0; p < 2; ++p) {
4583:           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);
4584:         }
4585: #endif
4586:         DMPlexGetSupportSize(dm, e, &supportSize);
4587:         DMPlexGetSupport(dm, e, &support);
4588:         for (s = 0; s < supportSize; ++s) {
4589:           DMPlexGetConeSize(dm, support[s], &coneSize);
4590:           DMPlexGetCone(dm, support[s], &cone);
4591:           DMPlexGetConeOrientation(dm, support[s], &ornt);
4592:           for (c = 0; c < coneSize; ++c) {
4593:             if (cone[c] == e) break;
4594:           }
4595:           supportRef[s] = fStartNew + (support[s] - fStart)*3 + (c + (ornt[c] < 0 ? 1-r : r))%3;
4596:         }
4597:         DMPlexSetSupport(rdm, newp, supportRef);
4598: #if 1
4599:         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
4600:         for (p = 0; p < supportSize; ++p) {
4601:           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);
4602:         }
4603: #endif
4604:       }
4605:     }
4606:     /* Face edges have 2 vertices and 2 + cell faces supports */
4607:     for (f = fStart; f < fEnd; ++f) {
4608:       const PetscInt *cone, *ornt, *support;
4609:       PetscInt        coneSize, supportSize, s;

4611:       DMPlexGetSupportSize(dm, f, &supportSize);
4612:       DMPlexGetSupport(dm, f, &support);
4613:       for (r = 0; r < 3; ++r) {
4614:         const PetscInt  newp = eStartNew + (eEnd - eStart)*2 + (f - fStart)*3 + r;
4615:         PetscInt        coneNew[2];
4616:         PetscInt        fint[4][3] = { {0, 1, 2},
4617:                                        {3, 4, 0},
4618:                                        {2, 5, 3},
4619:                                        {1, 4, 5} };

4621:         DMPlexGetCone(dm, f, &cone);
4622:         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r] - eStart);
4623:         coneNew[1] = vStartNew + (vEnd - vStart) + (eEnd - eStart) + f - fStart;
4624:         DMPlexSetCone(rdm, newp, coneNew);
4625: #if 1
4626:         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
4627:         for (p = 0; p < 2; ++p) {
4628:           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);
4629:         }
4630: #endif
4631:         supportRef[0] = fStartNew + (f - fStart)*3 + (r+0)%3;
4632:         supportRef[1] = fStartNew + (f - fStart)*3 + (r+1)%3;
4633:         for (s = 0; s < supportSize; ++s) {
4634:           PetscInt er;
4635:           DMPlexGetConeSize(dm, support[s], &coneSize);
4636:           DMPlexGetCone(dm, support[s], &cone);
4637:           DMPlexGetConeOrientation(dm, support[s], &ornt);
4638:           for (c = 0; c < coneSize; ++c) {if (cone[c] == f) break;}
4639:           er = GetTriInteriorEdgeInverse_Static(ornt[c], r);
4640:           supportRef[2+s] = fStartNew + (fEnd - fStart)*3 + (support[s] - cStart)*6 + fint[c][er];
4641:         }
4642:         DMPlexSetSupport(rdm, newp, supportRef);
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 < supportSize + 2; ++p) {
4646:           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);
4647:         }
4648: #endif
4649:       }
4650:     }
4651:     /* Interior cell edges have 2 vertices and 3 faces */
4652:     for (c = cStart; c < cEnd; ++c) {
4653:       const PetscInt *cone;
4654:       PetscInt       fint[4][3] = { {0,1,2},
4655:                                     {0,3,4},
4656:                                     {2,3,5},
4657:                                     {1,4,5} } ;

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

4664:         coneNew[0] = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (cone[r] - fStart);
4665:         coneNew[1] = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (fEnd -fStart) + c - cStart;
4666:         DMPlexSetCone(rdm, newp, coneNew);
4667: #if 1
4668:         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
4669:         for (p = 0; p < 2; ++p) {
4670:           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);
4671:         }
4672: #endif
4673:         supportNew[0] = fStartNew + (fEnd - fStart)*3 + (c - cStart)*6 + fint[r][0];
4674:         supportNew[1] = fStartNew + (fEnd - fStart)*3 + (c - cStart)*6 + fint[r][1];
4675:         supportNew[2] = fStartNew + (fEnd - fStart)*3 + (c - cStart)*6 + fint[r][2];
4676:         DMPlexSetSupport(rdm, newp, supportNew);
4677: #if 1
4678:         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
4679:         for (p = 0; p < 3; ++p) {
4680:           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);
4681:         }
4682: #endif
4683:       }
4684:     }
4685:     /* Old vertices have identical supports */
4686:     for (v = vStart; v < vEnd; ++v) {
4687:       const PetscInt  newp = vStartNew + (v - vStart);
4688:       const PetscInt *support, *cone;
4689:       PetscInt        size, s;

4691:       DMPlexGetSupportSize(dm, v, &size);
4692:       DMPlexGetSupport(dm, v, &support);
4693:       for (s = 0; s < size; ++s) {
4694:         PetscInt r = 0;

4696:         DMPlexGetCone(dm, support[s], &cone);
4697:         if (cone[1] == v) r = 1;
4698:         supportRef[s] = eStartNew + (support[s] - eStart)*2 + r;
4699:       }
4700:       DMPlexSetSupport(rdm, newp, supportRef);
4701: #if 1
4702:       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
4703:       for (p = 0; p < size; ++p) {
4704:         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);
4705:       }
4706: #endif
4707:     }
4708:     /* Edge vertices have 2 + faces supports */
4709:     for (e = eStart; e < eEnd; ++e) {
4710:       const PetscInt  newp = vStartNew + (vEnd - vStart) + (e - eStart);
4711:       const PetscInt *cone, *support;
4712:       PetscInt        size, s;

4714:       DMPlexGetSupportSize(dm, e, &size);
4715:       DMPlexGetSupport(dm, e, &support);
4716:       supportRef[0] = eStartNew + (e - eStart)*2 + 0;
4717:       supportRef[1] = eStartNew + (e - eStart)*2 + 1;
4718:       for (s = 0; s < size; ++s) {
4719:         PetscInt r = 0, coneSize;

4721:         DMPlexGetConeSize(dm, support[s], &coneSize);
4722:         DMPlexGetCone(dm, support[s], &cone);
4723:         for (r = 0; r < coneSize; ++r) {if (cone[r] == e) break;}
4724:         supportRef[2+s] = eStartNew + (eEnd - eStart)*2 + (support[s] - fStart)*3 + r;
4725:       }
4726:       DMPlexSetSupport(rdm, newp, supportRef);
4727: #if 1
4728:       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
4729:       for (p = 0; p < 2+size; ++p) {
4730:         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);
4731:       }
4732: #endif
4733:     }
4734:     /* Face vertices have 3 + cells supports */
4735:     for (f = fStart; f < fEnd; ++f) {
4736:       const PetscInt  newp = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (f - fStart);
4737:       const PetscInt *cone, *support;
4738:       PetscInt        size, s;

4740:       DMPlexGetSupportSize(dm, f, &size);
4741:       DMPlexGetSupport(dm, f, &support);
4742:       supportRef[0] = eStartNew + (eEnd - eStart)*2 + (f - fStart)*3 + 0;
4743:       supportRef[1] = eStartNew + (eEnd - eStart)*2 + (f - fStart)*3 + 1;
4744:       supportRef[2] = eStartNew + (eEnd - eStart)*2 + (f - fStart)*3 + 2;
4745:       for (s = 0; s < size; ++s) {
4746:         PetscInt r = 0, coneSize;

4748:         DMPlexGetConeSize(dm, support[s], &coneSize);
4749:         DMPlexGetCone(dm, support[s], &cone);
4750:         for (r = 0; r < coneSize; ++r) {if (cone[r] == f) break;}
4751:         supportRef[3+s] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (support[s] - cStart)*4 + r;
4752:       }
4753:       DMPlexSetSupport(rdm, newp, supportRef);
4754: #if 1
4755:       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
4756:       for (p = 0; p < 3+size; ++p) {
4757:         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);
4758:       }
4759: #endif
4760:     }
4761:     /* Interior cell vertices have 4 supports */
4762:     for (c = cStart; c < cEnd; ++c) {
4763:       const PetscInt  newp = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (fEnd - fStart) + c - cStart;
4764:       supportRef[0] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + 0;
4765:       supportRef[1] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + 1;
4766:       supportRef[2] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + 2;
4767:       supportRef[3] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + 3;
4768:       DMPlexSetSupport(rdm, newp, supportRef);
4769: #if 1
4770:       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
4771:       for (p = 0; p < 4; ++p) {
4772:         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);
4773:       }
4774: #endif
4775:     }
4776:     PetscFree(supportRef);
4777:     DMPlexRestoreFaces_Internal(dm, 3, cStart, NULL, NULL, &faces);
4778:     break;
4779:   case REFINER_HEX_3D:
4780:     /*
4781:      Bottom (viewed from top)    Top
4782:      1---------2---------2       7---------2---------6
4783:      |         |         |       |         |         |
4784:      |    B    2    C    |       |    H    2    G    |
4785:      |         |         |       |         |         |
4786:      3----3----0----1----1       3----3----0----1----1
4787:      |         |         |       |         |         |
4788:      |    A    0    D    |       |    E    0    F    |
4789:      |         |         |       |         |         |
4790:      0---------0---------3       4---------0---------5
4791:      */
4792:     /* All cells have 6 faces: Bottom, Top, Front, Back, Right, Left */
4793:     for (c = cStart; c < cEnd; ++c) {
4794:       const PetscInt  newp = (c - cStart)*8;
4795:       const PetscInt *cone, *ornt;
4796:       PetscInt        coneNew[6], orntNew[6];

4798:       DMPlexGetCone(dm, c, &cone);
4799:       DMPlexGetConeOrientation(dm, c, &ornt);
4800:       /* A hex */
4801:       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], 0);
4802:       orntNew[0] = ornt[0];
4803:       coneNew[1] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  8; /* AE */
4804:       orntNew[1] = 0;
4805:       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetQuadSubface_Static(ornt[2], 0);
4806:       orntNew[2] = ornt[2];
4807:       coneNew[3] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  3; /* AB */
4808:       orntNew[3] = 0;
4809:       coneNew[4] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  0; /* AD */
4810:       orntNew[4] = 0;
4811:       coneNew[5] = fStartNew + (cone[5] - fStart)*4 + GetQuadSubface_Static(ornt[5], 0);
4812:       orntNew[5] = ornt[5];
4813:       DMPlexSetCone(rdm, newp+0, coneNew);
4814:       DMPlexSetConeOrientation(rdm, newp+0, orntNew);
4815: #if 1
4816:       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);
4817:       for (p = 0; p < 6; ++p) {
4818:         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);
4819:       }
4820: #endif
4821:       /* B hex */
4822:       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], 1);
4823:       orntNew[0] = ornt[0];
4824:       coneNew[1] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 + 11; /* BH */
4825:       orntNew[1] = 0;
4826:       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  3; /* AB */
4827:       orntNew[2] = -1;
4828:       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetQuadSubface_Static(ornt[3], 1);
4829:       orntNew[3] = ornt[3];
4830:       coneNew[4] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  2; /* BC */
4831:       orntNew[4] = 0;
4832:       coneNew[5] = fStartNew + (cone[5] - fStart)*4 + GetQuadSubface_Static(ornt[5], 3);
4833:       orntNew[5] = ornt[5];
4834:       DMPlexSetCone(rdm, newp+1, coneNew);
4835:       DMPlexSetConeOrientation(rdm, newp+1, orntNew);
4836: #if 1
4837:       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);
4838:       for (p = 0; p < 6; ++p) {
4839:         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);
4840:       }
4841: #endif
4842:       /* C hex */
4843:       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], 2);
4844:       orntNew[0] = ornt[0];
4845:       coneNew[1] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 + 10; /* CG */
4846:       orntNew[1] = 0;
4847:       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  1; /* CD */
4848:       orntNew[2] = -1;
4849:       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetQuadSubface_Static(ornt[3], 0);
4850:       orntNew[3] = ornt[3];
4851:       coneNew[4] = fStartNew + (cone[4] - fStart)*4 + GetQuadSubface_Static(ornt[4], 1);
4852:       orntNew[4] = ornt[4];
4853:       coneNew[5] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  2; /* BC */
4854:       orntNew[5] = -4;
4855:       DMPlexSetCone(rdm, newp+2, coneNew);
4856:       DMPlexSetConeOrientation(rdm, newp+2, orntNew);
4857: #if 1
4858:       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);
4859:       for (p = 0; p < 6; ++p) {
4860:         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);
4861:       }
4862: #endif
4863:       /* D hex */
4864:       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], 3);
4865:       orntNew[0] = ornt[0];
4866:       coneNew[1] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  9; /* DF */
4867:       orntNew[1] = 0;
4868:       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetQuadSubface_Static(ornt[2], 1);
4869:       orntNew[2] = ornt[2];
4870:       coneNew[3] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  1; /* CD */
4871:       orntNew[3] = 0;
4872:       coneNew[4] = fStartNew + (cone[4] - fStart)*4 + GetQuadSubface_Static(ornt[4], 0);
4873:       orntNew[4] = ornt[4];
4874:       coneNew[5] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  0; /* AD */
4875:       orntNew[5] = -4;
4876:       DMPlexSetCone(rdm, newp+3, coneNew);
4877:       DMPlexSetConeOrientation(rdm, newp+3, orntNew);
4878: #if 1
4879:       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);
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:       /* E hex */
4885:       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  8; /* AE */
4886:       orntNew[0] = -4;
4887:       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], 0);
4888:       orntNew[1] = ornt[1];
4889:       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetQuadSubface_Static(ornt[2], 3);
4890:       orntNew[2] = ornt[2];
4891:       coneNew[3] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  7; /* EH */
4892:       orntNew[3] = 0;
4893:       coneNew[4] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  4; /* EF */
4894:       orntNew[4] = -1;
4895:       coneNew[5] = fStartNew + (cone[5] - fStart)*4 + GetQuadSubface_Static(ornt[5], 1);
4896:       orntNew[5] = ornt[5];
4897:       DMPlexSetCone(rdm, newp+4, coneNew);
4898:       DMPlexSetConeOrientation(rdm, newp+4, orntNew);
4899: #if 1
4900:       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);
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:       /* F hex */
4906:       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  9; /* DF */
4907:       orntNew[0] = -4;
4908:       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], 1);
4909:       orntNew[1] = ornt[1];
4910:       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetQuadSubface_Static(ornt[2], 2);
4911:       orntNew[2] = ornt[2];
4912:       coneNew[3] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  5; /* FG */
4913:       orntNew[3] = -1;
4914:       coneNew[4] = fStartNew + (cone[4] - fStart)*4 + GetQuadSubface_Static(ornt[4], 3);
4915:       orntNew[4] = ornt[4];
4916:       coneNew[5] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  4; /* EF */
4917:       orntNew[5] = 1;
4918:       DMPlexSetCone(rdm, newp+5, coneNew);
4919:       DMPlexSetConeOrientation(rdm, newp+5, orntNew);
4920: #if 1
4921:       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);
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:       /* G hex */
4927:       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 + 10; /* CG */
4928:       orntNew[0] = -4;
4929:       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], 2);
4930:       orntNew[1] = ornt[1];
4931:       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  5; /* FG */
4932:       orntNew[2] = 0;
4933:       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetQuadSubface_Static(ornt[3], 3);
4934:       orntNew[3] = ornt[3];
4935:       coneNew[4] = fStartNew + (cone[4] - fStart)*4 + GetQuadSubface_Static(ornt[4], 2);
4936:       orntNew[4] = ornt[4];
4937:       coneNew[5] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  6; /* GH */
4938:       orntNew[5] = -3;
4939:       DMPlexSetCone(rdm, newp+6, coneNew);
4940:       DMPlexSetConeOrientation(rdm, newp+6, orntNew);
4941: #if 1
4942:       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);
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:       /* H hex */
4948:       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 + 11; /* BH */
4949:       orntNew[0] = -4;
4950:       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], 3);
4951:       orntNew[1] = ornt[1];
4952:       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  7; /* EH */
4953:       orntNew[2] = -1;
4954:       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetQuadSubface_Static(ornt[3], 2);
4955:       orntNew[3] = ornt[3];
4956:       coneNew[4] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  6; /* GH */
4957:       orntNew[4] = 3;
4958:       coneNew[5] = fStartNew + (cone[5] - fStart)*4 + GetQuadSubface_Static(ornt[5], 2);
4959:       orntNew[5] = ornt[5];
4960:       DMPlexSetCone(rdm, newp+7, coneNew);
4961:       DMPlexSetConeOrientation(rdm, newp+7, orntNew);
4962: #if 1
4963:       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);
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:     }
4969:     /* Split faces have 4 edges and the same cells as the parent */
4970:     DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);
4971:     PetscMalloc1(4 + maxSupportSize*2, &supportRef);
4972:     for (f = fStart; f < fEnd; ++f) {
4973:       for (r = 0; r < 4; ++r) {
4974:         /* TODO: This can come from GetFaces_Internal() */
4975:         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};
4976:         const PetscInt  newp = fStartNew + (f - fStart)*4 + r;
4977:         const PetscInt *cone, *ornt, *support;
4978:         PetscInt        coneNew[4], orntNew[4], coneSize, c, supportSize, s;

4980:         DMPlexGetCone(dm, f, &cone);
4981:         DMPlexGetConeOrientation(dm, f, &ornt);
4982:         coneNew[(r+3)%4] = eStartNew + (cone[(r+3)%4] - eStart)*2 + (ornt[(r+3)%4] < 0 ? 0 : 1);
4983:         orntNew[(r+3)%4] = ornt[(r+3)%4];
4984:         coneNew[(r+0)%4] = eStartNew + (cone[r]       - eStart)*2 + (ornt[r] < 0 ? 1 : 0);
4985:         orntNew[(r+0)%4] = ornt[r];
4986:         coneNew[(r+1)%4] = eStartNew + (eEnd - eStart)*2 + (f - fStart)*4 + r;
4987:         orntNew[(r+1)%4] = 0;
4988:         coneNew[(r+2)%4] = eStartNew + (eEnd - eStart)*2 + (f - fStart)*4 + (r+3)%4;
4989:         orntNew[(r+2)%4] = -2;
4990:         DMPlexSetCone(rdm, newp, coneNew);
4991:         DMPlexSetConeOrientation(rdm, newp, orntNew);
4992: #if 1
4993:         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4994:         for (p = 0; p < 4; ++p) {
4995:           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);
4996:         }
4997: #endif
4998:         DMPlexGetSupportSize(dm, f, &supportSize);
4999:         DMPlexGetSupport(dm, f, &support);
5000:         for (s = 0; s < supportSize; ++s) {
5001:           DMPlexGetConeSize(dm, support[s], &coneSize);
5002:           DMPlexGetCone(dm, support[s], &cone);
5003:           DMPlexGetConeOrientation(dm, support[s], &ornt);
5004:           for (c = 0; c < coneSize; ++c) {
5005:             if (cone[c] == f) break;
5006:           }
5007:           supportRef[s] = cStartNew + (support[s] - cStart)*8 + newCells[c*4+GetQuadSubfaceInverse_Static(ornt[c], r)];
5008:         }
5009:         DMPlexSetSupport(rdm, newp, supportRef);
5010: #if 1
5011:         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5012:         for (p = 0; p < supportSize; ++p) {
5013:           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);
5014:         }
5015: #endif
5016:       }
5017:     }
5018:     /* Interior faces have 4 edges and 2 cells */
5019:     for (c = cStart; c < cEnd; ++c) {
5020:       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};
5021:       const PetscInt *cone, *ornt;
5022:       PetscInt        newp, coneNew[4], orntNew[4], supportNew[2];

5024:       DMPlexGetCone(dm, c, &cone);
5025:       DMPlexGetConeOrientation(dm, c, &ornt);
5026:       /* A-D face */
5027:       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 0;
5028:       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*4 + GetQuadEdge_Static(ornt[0], 3);
5029:       orntNew[0] = 0;
5030:       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 0;
5031:       orntNew[1] = 0;
5032:       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 2;
5033:       orntNew[2] = -2;
5034:       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*4 + GetQuadEdge_Static(ornt[2], 0);
5035:       orntNew[3] = -2;
5036:       DMPlexSetCone(rdm, newp, coneNew);
5037:       DMPlexSetConeOrientation(rdm, newp, orntNew);
5038: #if 1
5039:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5040:       for (p = 0; p < 4; ++p) {
5041:         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);
5042:       }
5043: #endif
5044:       /* C-D face */
5045:       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 1;
5046:       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*4 + GetQuadEdge_Static(ornt[0], 2);
5047:       orntNew[0] = 0;
5048:       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 0;
5049:       orntNew[1] = 0;
5050:       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 4;
5051:       orntNew[2] = -2;
5052:       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (cone[4] - fStart)*4 + GetQuadEdge_Static(ornt[4], 0);
5053:       orntNew[3] = -2;
5054:       DMPlexSetCone(rdm, newp, coneNew);
5055:       DMPlexSetConeOrientation(rdm, newp, orntNew);
5056: #if 1
5057:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5058:       for (p = 0; p < 4; ++p) {
5059:         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);
5060:       }
5061: #endif
5062:       /* B-C face */
5063:       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 2;
5064:       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*4 + GetQuadEdge_Static(ornt[0], 1);
5065:       orntNew[0] = -2;
5066:       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*4 + GetQuadEdge_Static(ornt[3], 0);
5067:       orntNew[1] = 0;
5068:       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 3;
5069:       orntNew[2] = 0;
5070:       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 0;
5071:       orntNew[3] = -2;
5072:       DMPlexSetCone(rdm, newp, coneNew);
5073:       DMPlexSetConeOrientation(rdm, newp, orntNew);
5074: #if 1
5075:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5076:       for (p = 0; p < 4; ++p) {
5077:         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);
5078:       }
5079: #endif
5080:       /* A-B face */
5081:       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 3;
5082:       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*4 + GetQuadEdge_Static(ornt[0], 0);
5083:       orntNew[0] = -2;
5084:       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[5] - fStart)*4 + GetQuadEdge_Static(ornt[5], 3);
5085:       orntNew[1] = 0;
5086:       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 5;
5087:       orntNew[2] = 0;
5088:       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 0;
5089:       orntNew[3] = -2;
5090:       DMPlexSetCone(rdm, newp, coneNew);
5091:       DMPlexSetConeOrientation(rdm, newp, orntNew);
5092: #if 1
5093:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5094:       for (p = 0; p < 4; ++p) {
5095:         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);
5096:       }
5097: #endif
5098:       /* E-F face */
5099:       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 4;
5100:       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 2;
5101:       orntNew[0] = -2;
5102:       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*4 + GetQuadEdge_Static(ornt[2], 2);
5103:       orntNew[1] = -2;
5104:       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*4 + GetQuadEdge_Static(ornt[1], 0);
5105:       orntNew[2] = 0;
5106:       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 1;
5107:       orntNew[3] = 0;
5108:       DMPlexSetCone(rdm, newp, coneNew);
5109:       DMPlexSetConeOrientation(rdm, newp, orntNew);
5110: #if 1
5111:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5112:       for (p = 0; p < 4; ++p) {
5113:         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);
5114:       }
5115: #endif
5116:       /* F-G face */
5117:       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 5;
5118:       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 4;
5119:       orntNew[0] = -2;
5120:       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[4] - fStart)*4 + GetQuadEdge_Static(ornt[4], 2);
5121:       orntNew[1] = -2;
5122:       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*4 + GetQuadEdge_Static(ornt[1], 1);
5123:       orntNew[2] = 0;
5124:       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 1;
5125:       orntNew[3] = 0;
5126:       DMPlexSetCone(rdm, newp, coneNew);
5127:       DMPlexSetConeOrientation(rdm, newp, orntNew);
5128: #if 1
5129:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5130:       for (p = 0; p < 4; ++p) {
5131:         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);
5132:       }
5133: #endif
5134:       /* G-H face */
5135:       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 6;
5136:       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*4 + GetQuadEdge_Static(ornt[3], 2);
5137:       orntNew[0] = -2;
5138:       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*4 + GetQuadEdge_Static(ornt[1], 2);
5139:       orntNew[1] = 0;
5140:       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 1;
5141:       orntNew[2] = 0;
5142:       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 3;
5143:       orntNew[3] = -2;
5144:       DMPlexSetCone(rdm, newp, coneNew);
5145:       DMPlexSetConeOrientation(rdm, newp, orntNew);
5146: #if 1
5147:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5148:       for (p = 0; p < 4; ++p) {
5149:         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);
5150:       }
5151: #endif
5152:       /* E-H face */
5153:       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 7;
5154:       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 5;
5155:       orntNew[0] = -2;
5156:       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[5] - fStart)*4 + GetQuadEdge_Static(ornt[5], 1);
5157:       orntNew[1] = -2;
5158:       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*4 + GetQuadEdge_Static(ornt[1], 3);
5159:       orntNew[2] = 0;
5160:       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 1;
5161:       orntNew[3] = 0;
5162:       DMPlexSetCone(rdm, newp, coneNew);
5163:       DMPlexSetConeOrientation(rdm, newp, orntNew);
5164: #if 1
5165:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5166:       for (p = 0; p < 4; ++p) {
5167:         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);
5168:       }
5169: #endif
5170:       /* A-E face */
5171:       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 8;
5172:       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*4 + GetQuadEdge_Static(ornt[2], 3);
5173:       orntNew[0] = 0;
5174:       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 2;
5175:       orntNew[1] = 0;
5176:       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 5;
5177:       orntNew[2] = -2;
5178:       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (cone[5] - fStart)*4 + GetQuadEdge_Static(ornt[5], 0);
5179:       orntNew[3] = -2;
5180:       DMPlexSetCone(rdm, newp, coneNew);
5181:       DMPlexSetConeOrientation(rdm, newp, orntNew);
5182: #if 1
5183:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5184:       for (p = 0; p < 4; ++p) {
5185:         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);
5186:       }
5187: #endif
5188:       /* D-F face */
5189:       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 9;
5190:       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*4 + GetQuadEdge_Static(ornt[2], 1);
5191:       orntNew[0] = -2;
5192:       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[4] - fStart)*4 + GetQuadEdge_Static(ornt[4], 3);
5193:       orntNew[1] = 0;
5194:       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 4;
5195:       orntNew[2] = 0;
5196:       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 2;
5197:       orntNew[3] = -2;
5198:       DMPlexSetCone(rdm, newp, coneNew);
5199:       DMPlexSetConeOrientation(rdm, newp, orntNew);
5200: #if 1
5201:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5202:       for (p = 0; p < 4; ++p) {
5203:         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);
5204:       }
5205: #endif
5206:       /* C-G face */
5207:       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 10;
5208:       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 4;
5209:       orntNew[0] = -2;
5210:       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[4] - fStart)*4 + GetQuadEdge_Static(ornt[4], 1);
5211:       orntNew[1] = -2;
5212:       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*4 + GetQuadEdge_Static(ornt[3], 3);
5213:       orntNew[2] = 0;
5214:       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 3;
5215:       orntNew[3] = 0;
5216:       DMPlexSetCone(rdm, newp, coneNew);
5217:       DMPlexSetConeOrientation(rdm, newp, orntNew);
5218: #if 1
5219:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5220:       for (p = 0; p < 4; ++p) {
5221:         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);
5222:       }
5223: #endif
5224:       /* B-H face */
5225:       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 11;
5226:       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 5;
5227:       orntNew[0] = 0;
5228:       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 3;
5229:       orntNew[1] = -2;
5230:       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*4 + GetQuadEdge_Static(ornt[3], 1);
5231:       orntNew[2] = -2;
5232:       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (cone[5] - fStart)*4 + GetQuadEdge_Static(ornt[5], 2);
5233:       orntNew[3] = 0;
5234:       DMPlexSetCone(rdm, newp, coneNew);
5235:       DMPlexSetConeOrientation(rdm, newp, orntNew);
5236: #if 1
5237:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5238:       for (p = 0; p < 4; ++p) {
5239:         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);
5240:       }
5241: #endif
5242:       for (r = 0; r < 12; ++r) {
5243:         newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + r;
5244:         supportNew[0] = cStartNew + (c - cStart)*8 + newCells[r*2+0];
5245:         supportNew[1] = cStartNew + (c - cStart)*8 + newCells[r*2+1];
5246:         DMPlexSetSupport(rdm, newp, supportNew);
5247: #if 1
5248:         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5249:         for (p = 0; p < 2; ++p) {
5250:           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);
5251:         }
5252: #endif
5253:       }
5254:     }
5255:     /* Split edges have 2 vertices and the same faces as the parent */
5256:     DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);
5257:     for (e = eStart; e < eEnd; ++e) {
5258:       const PetscInt newv = vStartNew + (vEnd - vStart) + (e - eStart);

5260:       for (r = 0; r < 2; ++r) {
5261:         const PetscInt  newp = eStartNew + (e - eStart)*2 + r;
5262:         const PetscInt *cone, *ornt, *support;
5263:         PetscInt        coneNew[2], coneSize, c, supportSize, s;

5265:         DMPlexGetCone(dm, e, &cone);
5266:         coneNew[0]       = vStartNew + (cone[0] - vStart);
5267:         coneNew[1]       = vStartNew + (cone[1] - vStart);
5268:         coneNew[(r+1)%2] = newv;
5269:         DMPlexSetCone(rdm, newp, coneNew);
5270: #if 1
5271:         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
5272:         for (p = 0; p < 2; ++p) {
5273:           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
5274:         }
5275: #endif
5276:         DMPlexGetSupportSize(dm, e, &supportSize);
5277:         DMPlexGetSupport(dm, e, &support);
5278:         for (s = 0; s < supportSize; ++s) {
5279:           DMPlexGetConeSize(dm, support[s], &coneSize);
5280:           DMPlexGetCone(dm, support[s], &cone);
5281:           DMPlexGetConeOrientation(dm, support[s], &ornt);
5282:           for (c = 0; c < coneSize; ++c) {
5283:             if (cone[c] == e) break;
5284:           }
5285:           supportRef[s] = fStartNew + (support[s] - fStart)*4 + (ornt[c] < 0 ? (c+1-r)%4 : (c+r)%4);
5286:         }
5287:         DMPlexSetSupport(rdm, newp, supportRef);
5288: #if 1
5289:         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
5290:         for (p = 0; p < supportSize; ++p) {
5291:           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);
5292:         }
5293: #endif
5294:       }
5295:     }
5296:     /* Face edges have 2 vertices and 2+cells faces */
5297:     for (f = fStart; f < fEnd; ++f) {
5298:       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};
5299:       const PetscInt  newv = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (f - fStart);
5300:       const PetscInt *cone, *coneCell, *orntCell, *support;
5301:       PetscInt        coneNew[2], coneSize, c, supportSize, s;

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

5307:         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r] - eStart);
5308:         coneNew[1] = newv;
5309:         DMPlexSetCone(rdm, newp, coneNew);
5310: #if 1
5311:         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
5312:         for (p = 0; p < 2; ++p) {
5313:           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);
5314:         }
5315: #endif
5316:         DMPlexGetSupportSize(dm, f, &supportSize);
5317:         DMPlexGetSupport(dm, f, &support);
5318:         supportRef[0] = fStartNew + (f - fStart)*4 + r;
5319:         supportRef[1] = fStartNew + (f - fStart)*4 + (r+1)%4;
5320:         for (s = 0; s < supportSize; ++s) {
5321:           DMPlexGetConeSize(dm, support[s], &coneSize);
5322:           DMPlexGetCone(dm, support[s], &coneCell);
5323:           DMPlexGetConeOrientation(dm, support[s], &orntCell);
5324:           for (c = 0; c < coneSize; ++c) if (coneCell[c] == f) break;
5325:           supportRef[2+s] = fStartNew + (fEnd - fStart)*4 + (support[s] - cStart)*12 + newFaces[c*4 + GetQuadEdgeInverse_Static(orntCell[c], r)];
5326:         }
5327:         DMPlexSetSupport(rdm, newp, supportRef);
5328: #if 1
5329:         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
5330:         for (p = 0; p < 2+supportSize; ++p) {
5331:           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);
5332:         }
5333: #endif
5334:       }
5335:     }
5336:     /* Cell edges have 2 vertices and 4 faces */
5337:     for (c = cStart; c < cEnd; ++c) {
5338:       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};
5339:       const PetscInt  newv = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (fEnd - fStart) + (c - cStart);
5340:       const PetscInt *cone;
5341:       PetscInt        coneNew[2], supportNew[4];

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

5347:         coneNew[0] = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (cone[r] - fStart);
5348:         coneNew[1] = newv;
5349:         DMPlexSetCone(rdm, newp, coneNew);
5350: #if 1
5351:         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
5352:         for (p = 0; p < 2; ++p) {
5353:           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);
5354:         }
5355: #endif
5356:         for (f = 0; f < 4; ++f) supportNew[f] = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + newFaces[r*4+f];
5357:         DMPlexSetSupport(rdm, newp, supportNew);
5358: #if 1
5359:         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
5360:         for (p = 0; p < 4; ++p) {
5361:           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);
5362:         }
5363: #endif
5364:       }
5365:     }
5366:     /* Old vertices have identical supports */
5367:     for (v = vStart; v < vEnd; ++v) {
5368:       const PetscInt  newp = vStartNew + (v - vStart);
5369:       const PetscInt *support, *cone;
5370:       PetscInt        size, s;

5372:       DMPlexGetSupportSize(dm, v, &size);
5373:       DMPlexGetSupport(dm, v, &support);
5374:       for (s = 0; s < size; ++s) {
5375:         PetscInt r = 0;

5377:         DMPlexGetCone(dm, support[s], &cone);
5378:         if (cone[1] == v) r = 1;
5379:         supportRef[s] = eStartNew + (support[s] - eStart)*2 + r;
5380:       }
5381:       DMPlexSetSupport(rdm, newp, supportRef);
5382: #if 1
5383:       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
5384:       for (p = 0; p < size; ++p) {
5385:         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);
5386:       }
5387: #endif
5388:     }
5389:     /* Edge vertices have 2 + faces supports */
5390:     for (e = eStart; e < eEnd; ++e) {
5391:       const PetscInt  newp = vStartNew + (vEnd - vStart) + (e - eStart);
5392:       const PetscInt *cone, *support;
5393:       PetscInt        size, s;

5395:       DMPlexGetSupportSize(dm, e, &size);
5396:       DMPlexGetSupport(dm, e, &support);
5397:       supportRef[0] = eStartNew + (e - eStart)*2 + 0;
5398:       supportRef[1] = eStartNew + (e - eStart)*2 + 1;
5399:       for (s = 0; s < size; ++s) {
5400:         PetscInt r;

5402:         DMPlexGetCone(dm, support[s], &cone);
5403:         for (r = 0; r < 4; ++r) if (cone[r] == e) break;
5404:         supportRef[2+s] = eStartNew + (eEnd - eStart)*2 + (support[s] - fStart)*4 + r;
5405:       }
5406:       DMPlexSetSupport(rdm, newp, supportRef);
5407: #if 1
5408:       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
5409:       for (p = 0; p < 2+size; ++p) {
5410:         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);
5411:       }
5412: #endif
5413:     }
5414:     /* Face vertices have 4 + cells supports */
5415:     for (f = fStart; f < fEnd; ++f) {
5416:       const PetscInt  newp = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (f - fStart);
5417:       const PetscInt *cone, *support;
5418:       PetscInt        size, s;

5420:       DMPlexGetSupportSize(dm, f, &size);
5421:       DMPlexGetSupport(dm, f, &support);
5422:       for (r = 0; r < 4; ++r) supportRef[r] = eStartNew + (eEnd - eStart)*2 +  (f - fStart)*4 + r;
5423:       for (s = 0; s < size; ++s) {
5424:         PetscInt r;

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

5443:       for (r = 0; r < 6; ++r) {
5444:         supportNew[r] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*4 + (c - cStart)*6 + r;
5445:       }
5446:       DMPlexSetSupport(rdm, newp, supportNew);
5447:     }
5448:     PetscFree(supportRef);
5449:     break;
5450:   case REFINER_HYBRID_HEX_3D:
5451:     DMPlexGetHybridBounds(rdm, &cMaxNew, &fMaxNew, &eMaxNew, NULL);
5452:     /*
5453:      Bottom (viewed from top)    Top
5454:      1---------2---------2       7---------2---------6
5455:      |         |         |       |         |         |
5456:      |    B    2    C    |       |    H    2    G    |
5457:      |         |         |       |         |         |
5458:      3----3----0----1----1       3----3----0----1----1
5459:      |         |         |       |         |         |
5460:      |    A    0    D    |       |    E    0    F    |
5461:      |         |         |       |         |         |
5462:      0---------0---------3       4---------0---------5
5463:      */
5464:     /* Interior cells have 6 faces: Bottom, Top, Front, Back, Right, Left */
5465:     for (c = cStart; c < cMax; ++c) {
5466:       const PetscInt  newp = (c - cStart)*8;
5467:       const PetscInt *cone, *ornt;
5468:       PetscInt        coneNew[6], orntNew[6];

5470:       DMPlexGetCone(dm, c, &cone);
5471:       DMPlexGetConeOrientation(dm, c, &ornt);
5472:       /* A hex */
5473:       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], 0);
5474:       orntNew[0] = ornt[0];
5475:       coneNew[1] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  8; /* AE */
5476:       orntNew[1] = 0;
5477:       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetQuadSubface_Static(ornt[2], 0);
5478:       orntNew[2] = ornt[2];
5479:       coneNew[3] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  3; /* AB */
5480:       orntNew[3] = 0;
5481:       coneNew[4] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  0; /* AD */
5482:       orntNew[4] = 0;
5483:       coneNew[5] = fStartNew + (cone[5] - fStart)*4 + GetQuadSubface_Static(ornt[5], 0);
5484:       orntNew[5] = ornt[5];
5485:       DMPlexSetCone(rdm, newp+0, coneNew);
5486:       DMPlexSetConeOrientation(rdm, newp+0, orntNew);
5487: #if 1
5488:       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);
5489:       for (p = 0; p < 6; ++p) {
5490:         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);
5491:       }
5492: #endif
5493:       /* B hex */
5494:       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], 1);
5495:       orntNew[0] = ornt[0];
5496:       coneNew[1] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 + 11; /* BH */
5497:       orntNew[1] = 0;
5498:       coneNew[2] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  3; /* AB */
5499:       orntNew[2] = -1;
5500:       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetQuadSubface_Static(ornt[3], 1);
5501:       orntNew[3] = ornt[3];
5502:       coneNew[4] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  2; /* BC */
5503:       orntNew[4] = 0;
5504:       coneNew[5] = fStartNew + (cone[5] - fStart)*4 + GetQuadSubface_Static(ornt[5], 3);
5505:       orntNew[5] = ornt[5];
5506:       DMPlexSetCone(rdm, newp+1, coneNew);
5507:       DMPlexSetConeOrientation(rdm, newp+1, orntNew);
5508: #if 1
5509:       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);
5510:       for (p = 0; p < 6; ++p) {
5511:         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);
5512:       }
5513: #endif
5514:       /* C hex */
5515:       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], 2);
5516:       orntNew[0] = ornt[0];
5517:       coneNew[1] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 + 10; /* CG */
5518:       orntNew[1] = 0;
5519:       coneNew[2] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  1; /* CD */
5520:       orntNew[2] = -1;
5521:       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetQuadSubface_Static(ornt[3], 0);
5522:       orntNew[3] = ornt[3];
5523:       coneNew[4] = fStartNew + (cone[4] - fStart)*4 + GetQuadSubface_Static(ornt[4], 1);
5524:       orntNew[4] = ornt[4];
5525:       coneNew[5] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  2; /* BC */
5526:       orntNew[5] = -4;
5527:       DMPlexSetCone(rdm, newp+2, coneNew);
5528:       DMPlexSetConeOrientation(rdm, newp+2, orntNew);
5529: #if 1
5530:       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);
5531:       for (p = 0; p < 6; ++p) {
5532:         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);
5533:       }
5534: #endif
5535:       /* D hex */
5536:       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], 3);
5537:       orntNew[0] = ornt[0];
5538:       coneNew[1] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  9; /* DF */
5539:       orntNew[1] = 0;
5540:       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetQuadSubface_Static(ornt[2], 1);
5541:       orntNew[2] = ornt[2];
5542:       coneNew[3] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  1; /* CD */
5543:       orntNew[3] = 0;
5544:       coneNew[4] = fStartNew + (cone[4] - fStart)*4 + GetQuadSubface_Static(ornt[4], 0);
5545:       orntNew[4] = ornt[4];
5546:       coneNew[5] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  0; /* AD */
5547:       orntNew[5] = -4;
5548:       DMPlexSetCone(rdm, newp+3, coneNew);
5549:       DMPlexSetConeOrientation(rdm, newp+3, orntNew);
5550: #if 1
5551:       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);
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:       /* E hex */
5557:       coneNew[0] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  8; /* AE */
5558:       orntNew[0] = -4;
5559:       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], 0);
5560:       orntNew[1] = ornt[1];
5561:       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetQuadSubface_Static(ornt[2], 3);
5562:       orntNew[2] = ornt[2];
5563:       coneNew[3] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  7; /* EH */
5564:       orntNew[3] = 0;
5565:       coneNew[4] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  4; /* EF */
5566:       orntNew[4] = -1;
5567:       coneNew[5] = fStartNew + (cone[5] - fStart)*4 + GetQuadSubface_Static(ornt[5], 1);
5568:       orntNew[5] = ornt[5];
5569:       DMPlexSetCone(rdm, newp+4, coneNew);
5570:       DMPlexSetConeOrientation(rdm, newp+4, orntNew);
5571: #if 1
5572:       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);
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:       /* F hex */
5578:       coneNew[0] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  9; /* DF */
5579:       orntNew[0] = -4;
5580:       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], 1);
5581:       orntNew[1] = ornt[1];
5582:       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetQuadSubface_Static(ornt[2], 2);
5583:       orntNew[2] = ornt[2];
5584:       coneNew[3] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  5; /* FG */
5585:       orntNew[3] = -1;
5586:       coneNew[4] = fStartNew + (cone[4] - fStart)*4 + GetQuadSubface_Static(ornt[4], 3);
5587:       orntNew[4] = ornt[4];
5588:       coneNew[5] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  4; /* EF */
5589:       orntNew[5] = 1;
5590:       DMPlexSetCone(rdm, newp+5, coneNew);
5591:       DMPlexSetConeOrientation(rdm, newp+5, orntNew);
5592: #if 1
5593:       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);
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:       /* G hex */
5599:       coneNew[0] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 + 10; /* CG */
5600:       orntNew[0] = -4;
5601:       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], 2);
5602:       orntNew[1] = ornt[1];
5603:       coneNew[2] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  5; /* FG */
5604:       orntNew[2] = 0;
5605:       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetQuadSubface_Static(ornt[3], 3);
5606:       orntNew[3] = ornt[3];
5607:       coneNew[4] = fStartNew + (cone[4] - fStart)*4 + GetQuadSubface_Static(ornt[4], 2);
5608:       orntNew[4] = ornt[4];
5609:       coneNew[5] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  6; /* GH */
5610:       orntNew[5] = -3;
5611:       DMPlexSetCone(rdm, newp+6, coneNew);
5612:       DMPlexSetConeOrientation(rdm, newp+6, orntNew);
5613: #if 1
5614:       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);
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:       /* H hex */
5620:       coneNew[0] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 + 11; /* BH */
5621:       orntNew[0] = -4;
5622:       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], 3);
5623:       orntNew[1] = ornt[1];
5624:       coneNew[2] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  7; /* EH */
5625:       orntNew[2] = -1;
5626:       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetQuadSubface_Static(ornt[3], 2);
5627:       orntNew[3] = ornt[3];
5628:       coneNew[4] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  6; /* GH */
5629:       orntNew[4] = 3;
5630:       coneNew[5] = fStartNew + (cone[5] - fStart)*4 + GetQuadSubface_Static(ornt[5], 2);
5631:       orntNew[5] = ornt[5];
5632:       DMPlexSetCone(rdm, newp+7, coneNew);
5633:       DMPlexSetConeOrientation(rdm, newp+7, orntNew);
5634: #if 1
5635:       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);
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:     }
5641:     /* Hybrid cells have 6 faces: Front, Back, Sides */
5642:     /*
5643:      3---------2---------2
5644:      |         |         |
5645:      |    D    2    C    |
5646:      |         |         |
5647:      3----3----0----1----1
5648:      |         |         |
5649:      |    A    0    B    |
5650:      |         |         |
5651:      0---------0---------1
5652:      */
5653:     for (c = cMax; c < cEnd; ++c) {
5654:       const PetscInt  newp = (cMax - cStart)*8 + (c - cMax)*4;
5655:       const PetscInt *cone, *ornt, *fornt;
5656:       PetscInt        coneNew[6], orntNew[6], o, of, i;

5658:       DMPlexGetCone(dm, c, &cone);
5659:       DMPlexGetConeOrientation(dm, c, &ornt);
5660:       DMPlexGetConeOrientation(dm, cone[0], &fornt);
5661:       o = ornt[0] < 0 ? -1 : 1;
5662:       for (r = 0; r < 4; ++r) {
5663:         PetscInt subfA = GetQuadSubface_Static(ornt[0], r);
5664:         PetscInt edgeA = GetQuadEdge_Static(ornt[0], r);
5665:         PetscInt edgeB = GetQuadEdge_Static(ornt[0], (r+3)%4);
5666:         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]);
5667:         coneNew[0]         = fStartNew + (cone[0] - fStart)*4 + subfA;
5668:         orntNew[0]         = ornt[0];
5669:         coneNew[1]         = fStartNew + (cone[1] - fStart)*4 + subfA;
5670:         orntNew[1]         = ornt[0];
5671:         of = fornt[edgeA] < 0 ? -1 : 1;
5672:         i  = GetQuadEdgeInverse_Static(ornt[0], r) + 2;
5673:         coneNew[i] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (cone[2+edgeA] - fMax)*2 + (o*of < 0 ? 1 : 0);
5674:         orntNew[i] = ornt[edgeA];
5675:         i  = GetQuadEdgeInverse_Static(ornt[0], (r+1)%4) + 2;
5676:         coneNew[i] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd          - fMax)*2 + (c - cMax)*4 + edgeA;
5677:         orntNew[i] = 0;
5678:         i  = GetQuadEdgeInverse_Static(ornt[0], (r+2)%4) + 2;
5679:         coneNew[i] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd          - fMax)*2 + (c - cMax)*4 + edgeB;
5680:         orntNew[i] = -2;
5681:         of = fornt[edgeB] < 0 ? -1 : 1;
5682:         i  = GetQuadEdgeInverse_Static(ornt[0], (r+3)%4) + 2;
5683:         coneNew[i] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (cone[2+edgeB] - fMax)*2 + (o*of < 0 ? 0 : 1);
5684:         orntNew[i] = ornt[edgeB];
5685:         DMPlexSetCone(rdm, newp+r, coneNew);
5686:         DMPlexSetConeOrientation(rdm, newp+r, orntNew);
5687: #if 1
5688:         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);
5689:         for (p = 0; p < 2; ++p) {
5690:           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);
5691:         }
5692:         for (p = 2; p < 6; ++p) {
5693:           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);
5694:         }
5695: #endif
5696:       }
5697:     }
5698:     /* Interior split faces have 4 edges and the same cells as the parent */
5699:     DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);
5700:     PetscMalloc1(4 + maxSupportSize*2, &supportRef);
5701:     for (f = fStart; f < fMax; ++f) {
5702:       for (r = 0; r < 4; ++r) {
5703:         /* TODO: This can come from GetFaces_Internal() */
5704:         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};
5705:         const PetscInt  newp = fStartNew + (f - fStart)*4 + r;
5706:         const PetscInt *cone, *ornt, *support;
5707:         PetscInt        coneNew[4], orntNew[4], coneSize, c, supportSize, s;

5709:         DMPlexGetCone(dm, f, &cone);
5710:         DMPlexGetConeOrientation(dm, f, &ornt);
5711:         coneNew[(r+3)%4] = eStartNew + (cone[(r+3)%4] - eStart)*2 + (ornt[(r+3)%4] < 0 ? 0 : 1);
5712:         orntNew[(r+3)%4] = ornt[(r+3)%4];
5713:         coneNew[(r+0)%4] = eStartNew + (cone[r]       - eStart)*2 + (ornt[r] < 0 ? 1 : 0);
5714:         orntNew[(r+0)%4] = ornt[r];
5715:         coneNew[(r+1)%4] = eStartNew + (eMax - eStart)*2 + (f - fStart)*4 + r;
5716:         orntNew[(r+1)%4] = 0;
5717:         coneNew[(r+2)%4] = eStartNew + (eMax - eStart)*2 + (f - fStart)*4 + (r+3)%4;
5718:         orntNew[(r+2)%4] = -2;
5719:         DMPlexSetCone(rdm, newp, coneNew);
5720:         DMPlexSetConeOrientation(rdm, newp, orntNew);
5721: #if 1
5722:         if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
5723:         for (p = 0; p < 4; ++p) {
5724:           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);
5725:         }
5726: #endif
5727:         DMPlexGetSupportSize(dm, f, &supportSize);
5728:         DMPlexGetSupport(dm, f, &support);
5729:         for (s = 0; s < supportSize; ++s) {
5730:           PetscInt subf;
5731:           DMPlexGetConeSize(dm, support[s], &coneSize);
5732:           DMPlexGetCone(dm, support[s], &cone);
5733:           DMPlexGetConeOrientation(dm, support[s], &ornt);
5734:           for (c = 0; c < coneSize; ++c) {
5735:             if (cone[c] == f) break;
5736:           }
5737:           subf = GetQuadSubfaceInverse_Static(ornt[c], r);
5738:           if (support[s] < cMax) {
5739:             supportRef[s] = cStartNew + (support[s] - cStart)*8 + newCells[c*4+subf];
5740:           } else {
5741:             supportRef[s] = cStartNew + (cMax       - cStart)*8 + (support[s] - cMax)*4 + subf;
5742:           }
5743:         }
5744:         DMPlexSetSupport(rdm, newp, supportRef);
5745: #if 1
5746:         if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
5747:         for (p = 0; p < supportSize; ++p) {
5748:           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);
5749:         }
5750: #endif
5751:       }
5752:     }
5753:     /* Interior cell faces have 4 edges and 2 cells */
5754:     for (c = cStart; c < cMax; ++c) {
5755:       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};
5756:       const PetscInt *cone, *ornt;
5757:       PetscInt        newp, coneNew[4], orntNew[4], supportNew[2];

5759:       DMPlexGetCone(dm, c, &cone);
5760:       DMPlexGetConeOrientation(dm, c, &ornt);
5761:       /* A-D face */
5762:       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 0;
5763:       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*4 + GetQuadEdge_Static(ornt[0], 3);
5764:       orntNew[0] = 0;
5765:       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 0;
5766:       orntNew[1] = 0;
5767:       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 2;
5768:       orntNew[2] = -2;
5769:       coneNew[3] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*4 + GetQuadEdge_Static(ornt[2], 0);
5770:       orntNew[3] = -2;
5771:       DMPlexSetCone(rdm, newp, coneNew);
5772:       DMPlexSetConeOrientation(rdm, newp, orntNew);
5773: #if 1
5774:       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
5775:       for (p = 0; p < 4; ++p) {
5776:         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);
5777:       }
5778: #endif
5779:       /* C-D face */
5780:       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 1;
5781:       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*4 + GetQuadEdge_Static(ornt[0], 2);
5782:       orntNew[0] = 0;
5783:       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 0;
5784:       orntNew[1] = 0;
5785:       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 4;
5786:       orntNew[2] = -2;
5787:       coneNew[3] = eStartNew + (eMax - eStart)*2 + (cone[4] - fStart)*4 + GetQuadEdge_Static(ornt[4], 0);
5788:       orntNew[3] = -2;
5789:       DMPlexSetCone(rdm, newp, coneNew);
5790:       DMPlexSetConeOrientation(rdm, newp, orntNew);
5791: #if 1
5792:       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
5793:       for (p = 0; p < 4; ++p) {
5794:         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);
5795:       }
5796: #endif
5797:       /* B-C face */
5798:       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 2;
5799:       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*4 + GetQuadEdge_Static(ornt[0], 1);
5800:       orntNew[0] = -2;
5801:       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*4 + GetQuadEdge_Static(ornt[3], 0);
5802:       orntNew[1] = 0;
5803:       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 3;
5804:       orntNew[2] = 0;
5805:       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 0;
5806:       orntNew[3] = -2;
5807:       DMPlexSetCone(rdm, newp, coneNew);
5808:       DMPlexSetConeOrientation(rdm, newp, orntNew);
5809: #if 1
5810:       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
5811:       for (p = 0; p < 4; ++p) {
5812:         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);
5813:       }
5814: #endif
5815:       /* A-B face */
5816:       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 3;
5817:       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*4 + GetQuadEdge_Static(ornt[0], 0);
5818:       orntNew[0] = -2;
5819:       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[5] - fStart)*4 + GetQuadEdge_Static(ornt[5], 3);
5820:       orntNew[1] = 0;
5821:       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 5;
5822:       orntNew[2] = 0;
5823:       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 0;
5824:       orntNew[3] = -2;
5825:       DMPlexSetCone(rdm, newp, coneNew);
5826:       DMPlexSetConeOrientation(rdm, newp, orntNew);
5827: #if 1
5828:       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
5829:       for (p = 0; p < 4; ++p) {
5830:         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);
5831:       }
5832: #endif
5833:       /* E-F face */
5834:       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 4;
5835:       coneNew[0] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 2;
5836:       orntNew[0] = -2;
5837:       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*4 + GetQuadEdge_Static(ornt[2], 2);
5838:       orntNew[1] = -2;
5839:       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*4 + GetQuadEdge_Static(ornt[1], 0);
5840:       orntNew[2] = 0;
5841:       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 1;
5842:       orntNew[3] = 0;
5843:       DMPlexSetCone(rdm, newp, coneNew);
5844:       DMPlexSetConeOrientation(rdm, newp, orntNew);
5845: #if 1
5846:       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
5847:       for (p = 0; p < 4; ++p) {
5848:         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);
5849:       }
5850: #endif
5851:       /* F-G face */
5852:       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 5;
5853:       coneNew[0] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 4;
5854:       orntNew[0] = -2;
5855:       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[4] - fStart)*4 + GetQuadEdge_Static(ornt[4], 2);
5856:       orntNew[1] = -2;
5857:       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*4 + GetQuadEdge_Static(ornt[1], 1);
5858:       orntNew[2] = 0;
5859:       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 1;
5860:       orntNew[3] = 0;
5861:       DMPlexSetCone(rdm, newp, coneNew);
5862:       DMPlexSetConeOrientation(rdm, newp, orntNew);
5863: #if 1
5864:       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
5865:       for (p = 0; p < 4; ++p) {
5866:         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);
5867:       }
5868: #endif
5869:       /* G-H face */
5870:       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 6;
5871:       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*4 + GetQuadEdge_Static(ornt[3], 2);
5872:       orntNew[0] = -2;
5873:       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*4 + GetQuadEdge_Static(ornt[1], 2);
5874:       orntNew[1] = 0;
5875:       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 1;
5876:       orntNew[2] = 0;
5877:       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 3;
5878:       orntNew[3] = -2;
5879:       DMPlexSetCone(rdm, newp, coneNew);
5880:       DMPlexSetConeOrientation(rdm, newp, orntNew);
5881: #if 1
5882:       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
5883:       for (p = 0; p < 4; ++p) {
5884:         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);
5885:       }
5886: #endif
5887:       /* E-H face */
5888:       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 7;
5889:       coneNew[0] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 5;
5890:       orntNew[0] = -2;
5891:       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[5] - fStart)*4 + GetQuadEdge_Static(ornt[5], 1);
5892:       orntNew[1] = -2;
5893:       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*4 + GetQuadEdge_Static(ornt[1], 3);
5894:       orntNew[2] = 0;
5895:       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 1;
5896:       orntNew[3] = 0;
5897:       DMPlexSetCone(rdm, newp, coneNew);
5898:       DMPlexSetConeOrientation(rdm, newp, orntNew);
5899: #if 1
5900:       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
5901:       for (p = 0; p < 4; ++p) {
5902:         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);
5903:       }
5904: #endif
5905:       /* A-E face */
5906:       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 8;
5907:       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*4 + GetQuadEdge_Static(ornt[2], 3);
5908:       orntNew[0] = 0;
5909:       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 2;
5910:       orntNew[1] = 0;
5911:       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 5;
5912:       orntNew[2] = -2;
5913:       coneNew[3] = eStartNew + (eMax - eStart)*2 + (cone[5] - fStart)*4 + GetQuadEdge_Static(ornt[5], 0);
5914:       orntNew[3] = -2;
5915:       DMPlexSetCone(rdm, newp, coneNew);
5916:       DMPlexSetConeOrientation(rdm, newp, orntNew);
5917: #if 1
5918:       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
5919:       for (p = 0; p < 4; ++p) {
5920:         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);
5921:       }
5922: #endif
5923:       /* D-F face */
5924:       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 9;
5925:       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*4 + GetQuadEdge_Static(ornt[2], 1);
5926:       orntNew[0] = -2;
5927:       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[4] - fStart)*4 + GetQuadEdge_Static(ornt[4], 3);
5928:       orntNew[1] = 0;
5929:       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 4;
5930:       orntNew[2] = 0;
5931:       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 2;
5932:       orntNew[3] = -2;
5933:       DMPlexSetCone(rdm, newp, coneNew);
5934:       DMPlexSetConeOrientation(rdm, newp, orntNew);
5935: #if 1
5936:       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
5937:       for (p = 0; p < 4; ++p) {
5938:         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);
5939:       }
5940: #endif
5941:       /* C-G face */
5942:       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 10;
5943:       coneNew[0] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 4;
5944:       orntNew[0] = -2;
5945:       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[4] - fStart)*4 + GetQuadEdge_Static(ornt[4], 1);
5946:       orntNew[1] = -2;
5947:       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*4 + GetQuadEdge_Static(ornt[3], 3);
5948:       orntNew[2] = 0;
5949:       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 3;
5950:       orntNew[3] = 0;
5951:       DMPlexSetCone(rdm, newp, coneNew);
5952:       DMPlexSetConeOrientation(rdm, newp, orntNew);
5953: #if 1
5954:       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
5955:       for (p = 0; p < 4; ++p) {
5956:         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);
5957:       }
5958: #endif
5959:       /* B-H face */
5960:       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 11;
5961:       coneNew[0] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 5;
5962:       orntNew[0] = 0;
5963:       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 3;
5964:       orntNew[1] = -2;
5965:       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*4 + GetQuadEdge_Static(ornt[3], 1);
5966:       orntNew[2] = -2;
5967:       coneNew[3] = eStartNew + (eMax - eStart)*2 + (cone[5] - fStart)*4 + GetQuadEdge_Static(ornt[5], 2);
5968:       orntNew[3] = 0;
5969:       DMPlexSetCone(rdm, newp, coneNew);
5970:       DMPlexSetConeOrientation(rdm, newp, orntNew);
5971: #if 1
5972:       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
5973:       for (p = 0; p < 4; ++p) {
5974:         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);
5975:       }
5976: #endif
5977:       for (r = 0; r < 12; ++r) {
5978:         newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + r;
5979:         supportNew[0] = cStartNew + (c - cStart)*8 + newCells[r*2+0];
5980:         supportNew[1] = cStartNew + (c - cStart)*8 + newCells[r*2+1];
5981:         DMPlexSetSupport(rdm, newp, supportNew);
5982: #if 1
5983:         if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
5984:         for (p = 0; p < 2; ++p) {
5985:           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);
5986:         }
5987: #endif
5988:       }
5989:     }
5990:     /* Hybrid split faces have 4 edges and same cells */
5991:     for (f = fMax; f < fEnd; ++f) {
5992:       const PetscInt *cone, *ornt, *support;
5993:       PetscInt        coneNew[4], orntNew[4];
5994:       PetscInt        supportNew[2], size, s, c;

5996:       DMPlexGetCone(dm, f, &cone);
5997:       DMPlexGetConeOrientation(dm, f, &ornt);
5998:       DMPlexGetSupportSize(dm, f, &size);
5999:       DMPlexGetSupport(dm, f, &support);
6000:       for (r = 0; r < 2; ++r) {
6001:         const PetscInt newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (f - fMax)*2 + r;

6003:         coneNew[0]   = eStartNew + (cone[0] - eStart)*2 + (ornt[0] < 0 ? 1-r : r);
6004:         orntNew[0]   = ornt[0];
6005:         coneNew[1]   = eStartNew + (cone[1] - eStart)*2 + (ornt[1] < 0 ? 1-r : r);
6006:         orntNew[1]   = ornt[1];
6007:         coneNew[2+r] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (cone[2+r] - eMax);
6008:         orntNew[2+r] = 0;
6009:         coneNew[3-r] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (eEnd      - eMax) + (f - fMax);
6010:         orntNew[3-r] = 0;
6011:         DMPlexSetCone(rdm, newp, coneNew);
6012:         DMPlexSetConeOrientation(rdm, newp, orntNew);
6013: #if 1
6014:         if ((newp < fMaxNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid face [%d, %d)", newp, fMaxNew, fEndNew);
6015:         for (p = 0; p < 2; ++p) {
6016:           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);
6017:         }
6018:         for (p = 2; p < 4; ++p) {
6019:           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);
6020:         }
6021: #endif
6022:         for (s = 0; s < size; ++s) {
6023:           const PetscInt *coneCell, *orntCell, *fornt;
6024:           PetscInt        o, of;

6026:           DMPlexGetCone(dm, support[s], &coneCell);
6027:           DMPlexGetConeOrientation(dm, support[s], &orntCell);
6028:           o = orntCell[0] < 0 ? -1 : 1;
6029:           for (c = 2; c < 6; ++c) if (coneCell[c] == f) break;
6030:           if (c >= 6) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Could not find face %d in cone of cell %d", f, support[s]);
6031:           DMPlexGetConeOrientation(dm, coneCell[0], &fornt);
6032:           of = fornt[c-2] < 0 ? -1 : 1;
6033:           supportNew[s] = cStartNew + (cMax - cStart)*8 + (support[s] - cMax)*4 + (GetQuadEdgeInverse_Static(orntCell[0], c-2) + (o*of < 0 ? 1-r : r))%4;
6034:         }
6035:         DMPlexSetSupport(rdm, newp, supportNew);
6036: #if 1
6037:         if ((newp < fMaxNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid face [%d, %d)", newp, fMaxNew, fEndNew);
6038:         for (p = 0; p < size; ++p) {
6039:           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);
6040:         }
6041: #endif
6042:       }
6043:     }
6044:     /* Hybrid cell faces have 4 edges and 2 cells */
6045:     for (c = cMax; c < cEnd; ++c) {
6046:       PetscInt        newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd - fMax)*2 + (c - cMax)*4;
6047:       const PetscInt *cone, *ornt;
6048:       PetscInt        coneNew[4], orntNew[4];
6049:       PetscInt        supportNew[2];

6051:       DMPlexGetCone(dm, c, &cone);
6052:       DMPlexGetConeOrientation(dm, c, &ornt);
6053:       for (r = 0; r < 4; ++r) {
6054: #if 0
6055:         coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], r);
6056:         orntNew[0] = 0;
6057:         coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], r);
6058:         orntNew[1] = 0;
6059:         coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (eEnd - eMax) + (cone[2+GetQuadEdge_Static(ornt[0], r)] - fMax);
6060:         orntNew[2] = 0;
6061:         coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (eEnd - eMax) + (fEnd                                   - fMax) + (c - cMax);
6062:         orntNew[3] = 0;
6063: #else
6064:         coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*4 + r;
6065:         orntNew[0] = 0;
6066:         coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*4 + r;
6067:         orntNew[1] = 0;
6068:         coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (eEnd - eMax) + (cone[2+r] - fMax);
6069:         orntNew[2] = 0;
6070:         coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (eEnd - eMax) + (fEnd      - fMax) + (c - cMax);
6071:         orntNew[3] = 0;
6072: #endif
6073:         DMPlexSetCone(rdm, newp+r, coneNew);
6074:         DMPlexSetConeOrientation(rdm, newp+r, orntNew);
6075: #if 1
6076:         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);
6077:         for (p = 0; p < 2; ++p) {
6078:           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);
6079:         }
6080:         for (p = 2; p < 4; ++p) {
6081:           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);
6082:         }
6083: #endif
6084:         supportNew[0] = cStartNew + (cMax - cStart)*8 + (c - cMax)*4 + GetQuadSubface_Static(ornt[0], r);
6085:         supportNew[1] = cStartNew + (cMax - cStart)*8 + (c - cMax)*4 + GetQuadSubface_Static(ornt[0], (r+1)%4);
6086:         DMPlexSetSupport(rdm, newp+r, supportNew);
6087: #if 1
6088:         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);
6089:         for (p = 0; p < 2; ++p) {
6090:           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);
6091:         }
6092: #endif
6093:       }
6094:     }
6095:     /* Interior split edges have 2 vertices and the same faces as the parent */
6096:     DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);
6097:     for (e = eStart; e < eMax; ++e) {
6098:       const PetscInt newv = vStartNew + (vEnd - vStart) + (e - eStart);

6100:       for (r = 0; r < 2; ++r) {
6101:         const PetscInt  newp = eStartNew + (e - eStart)*2 + r;
6102:         const PetscInt *cone, *ornt, *support;
6103:         PetscInt        coneNew[2], coneSize, c, supportSize, s;

6105:         DMPlexGetCone(dm, e, &cone);
6106:         coneNew[0]       = vStartNew + (cone[0] - vStart);
6107:         coneNew[1]       = vStartNew + (cone[1] - vStart);
6108:         coneNew[(r+1)%2] = newv;
6109:         DMPlexSetCone(rdm, newp, coneNew);
6110: #if 1
6111:         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
6112:         for (p = 0; p < 2; ++p) {
6113:           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);
6114:         }
6115: #endif
6116:         DMPlexGetSupportSize(dm, e, &supportSize);
6117:         DMPlexGetSupport(dm, e, &support);
6118:         for (s = 0; s < supportSize; ++s) {
6119:           DMPlexGetConeSize(dm, support[s], &coneSize);
6120:           DMPlexGetCone(dm, support[s], &cone);
6121:           DMPlexGetConeOrientation(dm, support[s], &ornt);
6122:           for (c = 0; c < coneSize; ++c) {
6123:             if (cone[c] == e) break;
6124:           }
6125:           if (support[s] < fMax) {
6126:             supportRef[s] = fStartNew + (support[s] - fStart)*4 + (c + (ornt[c] < 0 ? 1-r : r))%4;
6127:           } else {
6128:             supportRef[s] = fStartNew + (fMax       - fStart)*4 + (cMax - cStart)*12 + (support[s] - fMax)*2 + (ornt[c] < 0 ? 1-r : r);
6129:           }
6130:         }
6131:         DMPlexSetSupport(rdm, newp, supportRef);
6132: #if 1
6133:         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
6134:         for (p = 0; p < supportSize; ++p) {
6135:           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);
6136:         }
6137: #endif
6138:       }
6139:     }
6140:     /* Interior face edges have 2 vertices and 2+cells faces */
6141:     for (f = fStart; f < fMax; ++f) {
6142:       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};
6143:       const PetscInt  newv = vStartNew + (vEnd - vStart) + (eMax - eStart) + (f - fStart);
6144:       const PetscInt *cone, *coneCell, *orntCell, *support;
6145:       PetscInt        coneNew[2], coneSize, c, supportSize, s;

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

6151:         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r] - eStart);
6152:         coneNew[1] = newv;
6153:         DMPlexSetCone(rdm, newp, coneNew);
6154: #if 1
6155:         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
6156:         for (p = 0; p < 2; ++p) {
6157:           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);
6158:         }
6159: #endif
6160:         DMPlexGetSupportSize(dm, f, &supportSize);
6161:         DMPlexGetSupport(dm, f, &support);
6162:         supportRef[0] = fStartNew + (f - fStart)*4 + r;
6163:         supportRef[1] = fStartNew + (f - fStart)*4 + (r+1)%4;
6164:         for (s = 0; s < supportSize; ++s) {
6165:           DMPlexGetConeSize(dm, support[s], &coneSize);
6166:           DMPlexGetCone(dm, support[s], &coneCell);
6167:           DMPlexGetConeOrientation(dm, support[s], &orntCell);
6168:           for (c = 0; c < coneSize; ++c) if (coneCell[c] == f) break;
6169:           if (support[s] < cMax) {
6170:             supportRef[2+s] = fStartNew + (fMax - fStart)*4 + (support[s] - cStart)*12 + newFaces[c*4 + GetQuadEdgeInverse_Static(orntCell[c], r)];
6171:           } else {
6172:             supportRef[2+s] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd - fMax)*2 + (support[s] - cMax)*4 + r;
6173:           }
6174:         }
6175:         DMPlexSetSupport(rdm, newp, supportRef);
6176: #if 1
6177:         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
6178:         for (p = 0; p < 2+supportSize; ++p) {
6179:           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);
6180:         }
6181: #endif
6182:       }
6183:     }
6184:     /* Interior cell edges have 2 vertices and 4 faces */
6185:     for (c = cStart; c < cMax; ++c) {
6186:       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};
6187:       const PetscInt  newv = vStartNew + (vEnd - vStart) + (eMax - eStart) + (fMax - fStart) + (c - cStart);
6188:       const PetscInt *cone;
6189:       PetscInt        coneNew[2], supportNew[4];

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

6195:         coneNew[0] = vStartNew + (vEnd - vStart) + (eMax - eStart) + (cone[r] - fStart);
6196:         coneNew[1] = newv;
6197:         DMPlexSetCone(rdm, newp, coneNew);
6198: #if 1
6199:         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
6200:         for (p = 0; p < 2; ++p) {
6201:           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);
6202:         }
6203: #endif
6204:         for (f = 0; f < 4; ++f) supportNew[f] = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + newFaces[r*4+f];
6205:         DMPlexSetSupport(rdm, newp, supportNew);
6206: #if 1
6207:         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
6208:         for (p = 0; p < 4; ++p) {
6209:           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);
6210:         }
6211: #endif
6212:       }
6213:     }
6214:     /* Hybrid edges have two vertices and the same faces */
6215:     for (e = eMax; e < eEnd; ++e) {
6216:       const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (e - eMax);
6217:       const PetscInt *cone, *support, *fcone;
6218:       PetscInt        coneNew[2], size, fsize, s;

6220:       DMPlexGetCone(dm, e, &cone);
6221:       DMPlexGetSupportSize(dm, e, &size);
6222:       DMPlexGetSupport(dm, e, &support);
6223:       coneNew[0] = vStartNew + (cone[0] - vStart);
6224:       coneNew[1] = vStartNew + (cone[1] - vStart);
6225:       DMPlexSetCone(rdm, newp, coneNew);
6226: #if 1
6227:       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid edge [%d, %d)", newp, eMaxNew, eEndNew);
6228:       for (p = 0; p < 2; ++p) {
6229:         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);
6230:       }
6231: #endif
6232:       for (s = 0; s < size; ++s) {
6233:         DMPlexGetConeSize(dm, support[s], &fsize);
6234:         DMPlexGetCone(dm, support[s], &fcone);
6235:         for (c = 0; c < fsize; ++c) if (fcone[c] == e) break;
6236:         if ((c < 2) || (c > 3)) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Edge %d not found in cone of face %d", e, support[s]);
6237:         supportRef[s] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (support[s] - fMax)*2 + c-2;
6238:       }
6239:       DMPlexSetSupport(rdm, newp, supportRef);
6240: #if 1
6241:       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid edge [%d, %d)", newp, eMaxNew, eEndNew);
6242:       for (p = 0; p < size; ++p) {
6243:         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);
6244:       }
6245: #endif
6246:     }
6247:     /* Hybrid face edges have 2 vertices and 2+cells faces */
6248:     for (f = fMax; f < fEnd; ++f) {
6249:       const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (eEnd - eMax) + (f - fMax);
6250:       const PetscInt *cone, *support, *ccone, *cornt;
6251:       PetscInt        coneNew[2], size, csize, s;

6253:       DMPlexGetCone(dm, f, &cone);
6254:       DMPlexGetSupportSize(dm, f, &size);
6255:       DMPlexGetSupport(dm, f, &support);
6256:       coneNew[0] = vStartNew + (vEnd - vStart) + (cone[0] - eStart);
6257:       coneNew[1] = vStartNew + (vEnd - vStart) + (cone[1] - eStart);
6258:       DMPlexSetCone(rdm, newp, coneNew);
6259: #if 1
6260:       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid edge [%d, %d)", newp, eMaxNew, eEndNew);
6261:       for (p = 0; p < 2; ++p) {
6262:         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);
6263:       }
6264: #endif
6265:       supportRef[0] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (f - fMax)*2 + 0;
6266:       supportRef[1] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (f - fMax)*2 + 1;
6267:       for (s = 0; s < size; ++s) {
6268:         DMPlexGetConeSize(dm, support[s], &csize);
6269:         DMPlexGetCone(dm, support[s], &ccone);
6270:         DMPlexGetConeOrientation(dm, support[s], &cornt);
6271:         for (c = 0; c < csize; ++c) if (ccone[c] == f) break;
6272:         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]);
6273:         supportRef[2+s] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd - fMax)*2 + (support[s] - cMax)*4 + c-2;
6274:       }
6275:       DMPlexSetSupport(rdm, newp, supportRef);
6276: #if 1
6277:       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid edge [%d, %d)", newp, eMaxNew, eEndNew);
6278:       for (p = 0; p < 2+size; ++p) {
6279:         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);
6280:       }
6281: #endif
6282:     }
6283:     /* Hybrid cell edges have 2 vertices and 4 faces */
6284:     for (c = cMax; c < cEnd; ++c) {
6285:       const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (eEnd - eMax) + (fEnd - fMax) + (c - cMax);
6286:       const PetscInt *cone, *support;
6287:       PetscInt        coneNew[2], size;

6289:       DMPlexGetCone(dm, c, &cone);
6290:       DMPlexGetSupportSize(dm, c, &size);
6291:       DMPlexGetSupport(dm, c, &support);
6292:       coneNew[0] = vStartNew + (vEnd - vStart) + (eMax - eStart) + (cone[0] - fStart);
6293:       coneNew[1] = vStartNew + (vEnd - vStart) + (eMax - eStart) + (cone[1] - fStart);
6294:       DMPlexSetCone(rdm, newp, coneNew);
6295: #if 1
6296:       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid edge [%d, %d)", newp, eMaxNew, eEndNew);
6297:       for (p = 0; p < 2; ++p) {
6298:         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);
6299:       }
6300: #endif
6301:       supportRef[0] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd - fMax)*2 + (c - cMax)*4 + 0;
6302:       supportRef[1] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd - fMax)*2 + (c - cMax)*4 + 1;
6303:       supportRef[2] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd - fMax)*2 + (c - cMax)*4 + 2;
6304:       supportRef[3] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd - fMax)*2 + (c - cMax)*4 + 3;
6305:       DMPlexSetSupport(rdm, newp, supportRef);
6306: #if 1
6307:       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid edge [%d, %d)", newp, eMaxNew, eEndNew);
6308:       for (p = 0; p < 4; ++p) {
6309:         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);
6310:       }
6311: #endif
6312:     }
6313:     /* Interior vertices have identical supports */
6314:     for (v = vStart; v < vEnd; ++v) {
6315:       const PetscInt  newp = vStartNew + (v - vStart);
6316:       const PetscInt *support, *cone;
6317:       PetscInt        size, s;

6319:       DMPlexGetSupportSize(dm, v, &size);
6320:       DMPlexGetSupport(dm, v, &support);
6321:       for (s = 0; s < size; ++s) {
6322:         PetscInt r = 0;

6324:         DMPlexGetCone(dm, support[s], &cone);
6325:         if (cone[1] == v) r = 1;
6326:         if (support[s] < eMax) supportRef[s] = eStartNew + (support[s] - eStart)*2 + r;
6327:         else                   supportRef[s] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (support[s] - eMax);
6328:       }
6329:       DMPlexSetSupport(rdm, newp, supportRef);
6330: #if 1
6331:       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
6332:       for (p = 0; p < size; ++p) {
6333:         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);
6334:       }
6335: #endif
6336:     }
6337:     /* Interior edge vertices have 2 + faces supports */
6338:     for (e = eStart; e < eMax; ++e) {
6339:       const PetscInt  newp = vStartNew + (vEnd - vStart) + (e - eStart);
6340:       const PetscInt *cone, *support;
6341:       PetscInt        size, s;

6343:       DMPlexGetSupportSize(dm, e, &size);
6344:       DMPlexGetSupport(dm, e, &support);
6345:       supportRef[0] = eStartNew + (e - eStart)*2 + 0;
6346:       supportRef[1] = eStartNew + (e - eStart)*2 + 1;
6347:       for (s = 0; s < size; ++s) {
6348:         PetscInt r;

6350:         DMPlexGetCone(dm, support[s], &cone);
6351:         for (r = 0; r < 4; ++r) if (cone[r] == e) break;
6352:         if (support[s] < fMax) {
6353:           supportRef[2+s] = eStartNew + (eMax - eStart)*2 + (support[s] - fStart)*4 + r;
6354:         } else {
6355:           supportRef[2+s] = eStartNew + (eMax - eStart)*2 + (fMax       - fStart)*4 + (cMax - cStart)*6 + (eEnd - eMax) + (support[s] - fMax);
6356:         }
6357:       }
6358:       DMPlexSetSupport(rdm, newp, supportRef);
6359: #if 1
6360:       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
6361:       for (p = 0; p < 2+size; ++p) {
6362:         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);
6363:       }
6364: #endif
6365:     }
6366:     /* Interior face vertices have 4 + cells supports */
6367:     for (f = fStart; f < fMax; ++f) {
6368:       const PetscInt  newp = vStartNew + (vEnd - vStart) + (eMax - eStart) + (f - fStart);
6369:       const PetscInt *cone, *support;
6370:       PetscInt        size, s;

6372:       DMPlexGetSupportSize(dm, f, &size);
6373:       DMPlexGetSupport(dm, f, &support);
6374:       for (r = 0; r < 4; ++r) supportRef[r] = eStartNew + (eMax - eStart)*2 +  (f - fStart)*4 + r;
6375:       for (s = 0; s < size; ++s) {
6376:         PetscInt r;

6378:         DMPlexGetCone(dm, support[s], &cone);
6379:         for (r = 0; r < 6; ++r) if (cone[r] == f) break;
6380:         if (support[s] < cMax) {
6381:           supportRef[4+s] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (support[s] - cStart)*6 + r;
6382:         } else {
6383:           supportRef[4+s] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax       - cStart)*6 + (eEnd - eMax) + (fEnd - fMax) + (support[s] - cMax);
6384:         }
6385:       }
6386:       DMPlexSetSupport(rdm, newp, supportRef);
6387: #if 1
6388:       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
6389:       for (p = 0; p < 4+size; ++p) {
6390:         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);
6391:       }
6392: #endif
6393:     }
6394:     /* Cell vertices have 6 supports */
6395:     for (c = cStart; c < cMax; ++c) {
6396:       const PetscInt newp = vStartNew + (vEnd - vStart) + (eMax - eStart) + (fMax - fStart) + (c - cStart);
6397:       PetscInt       supportNew[6];

6399:       for (r = 0; r < 6; ++r) {
6400:         supportNew[r] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (c - cStart)*6 + r;
6401:       }
6402:       DMPlexSetSupport(rdm, newp, supportNew);
6403:     }
6404:     PetscFree(supportRef);
6405:     break;
6406:   default:
6407:     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
6408:   }
6409:   return(0);
6410: }

6412: static PetscErrorCode CellRefinerSetCoordinates(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
6413: {
6414:   PetscSection          coordSection, coordSectionNew;
6415:   Vec                   coordinates, coordinatesNew;
6416:   PetscScalar          *coords, *coordsNew;
6417:   const PetscInt        numVertices = depthSize ? depthSize[0] : 0;
6418:   PetscInt              dim, spaceDim, depth, bs, coordSizeNew, cStart, cEnd, cMax;
6419:   PetscInt              c, vStart, vStartNew, vEnd, v, eStart, eEnd, eMax, e, fStart, fEnd, fMax, f;
6420:   PetscInt              cStartNew, cEndNew, vEndNew, *parentId = NULL;
6421:   VecType               vtype;
6422:   PetscBool             isperiodic, localize = PETSC_FALSE, needcoords = PETSC_FALSE;
6423:   const PetscReal      *maxCell, *L;
6424:   const DMBoundaryType *bd;
6425:   PetscErrorCode        ierr;

6428:   DMGetDimension(dm, &dim);
6429:   DMPlexGetDepth(dm, &depth);
6430:   DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);
6431:   DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);
6432:   DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);
6433:   DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);
6434:   DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, NULL);
6435:   GetDepthStart_Private(depth, depthSize, &cStartNew, NULL, NULL, &vStartNew);
6436:   GetDepthEnd_Private(depth, depthSize, &cEndNew, NULL, NULL, &vEndNew);
6437:   DMGetCoordinateSection(dm, &coordSection);
6438:   PetscSectionGetFieldComponents(coordSection, 0, &spaceDim);
6439:   PetscSectionCreate(PetscObjectComm((PetscObject)dm), &coordSectionNew);
6440:   PetscSectionSetNumFields(coordSectionNew, 1);
6441:   PetscSectionSetFieldComponents(coordSectionNew, 0, spaceDim);
6442:   DMGetPeriodicity(dm, &isperiodic, &maxCell, &L, &bd);
6443:   DMSetPeriodicity(rdm, isperiodic,  maxCell,  L,  bd);
6444:   /* Determine if we need to localize coordinates when generating them */
6445:   if (isperiodic && !maxCell) {
6446:     DMGetCoordinatesLocalized(dm, &localize);
6447:     if (!localize) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_USER,"Cannot refine if coordinates have not been localized");
6448:   }
6449:   if (localize) {
6450:     PetscInt p, r, newp, *pi;

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

6455:     /* We need the parentId to properly localize coordinates */
6456:     PetscMalloc1(cEndNew-cStartNew,&pi);
6457:     switch (refiner) {
6458:     case REFINER_NOOP:
6459:       break;
6460:     case REFINER_SIMPLEX_1D:
6461:       for (p = cStart; p < cEnd; ++p) {
6462:         for (r = 0; r < 2; ++r) {
6463:           newp     = (p - cStart)*2 + r;
6464:           pi[newp] = p;
6465:         }
6466:       }
6467:       break;
6468:     case REFINER_SIMPLEX_2D:
6469:       for (p = cStart; p < cEnd; ++p) {
6470:         for (r = 0; r < 4; ++r) {
6471:           newp     = (p - cStart)*4 + r;
6472:           pi[newp] = p;
6473:         }
6474:       }
6475:       break;
6476:     case REFINER_HEX_2D:
6477:       for (p = cStart; p < cEnd; ++p) {
6478:         for (r = 0; r < 4; ++r) {
6479:           newp     = (p - cStart)*4 + r;
6480:           pi[newp] = p;
6481:         }
6482:       }
6483:       break;
6484:     case REFINER_SIMPLEX_TO_HEX_2D:
6485:       for (p = cStart; p < cEnd; ++p) {
6486:         for (r = 0; r < 3; ++r) {
6487:           newp     = (p - cStart)*3 + r;
6488:           pi[newp] = p;
6489:         }
6490:       }
6491:       break;
6492:     case REFINER_HYBRID_SIMPLEX_2D:
6493:       for (p = cStart; p < cMax; ++p) {
6494:         for (r = 0; r < 4; ++r) {
6495:           newp     = (p - cStart)*4 + r;
6496:           pi[newp] = p;
6497:         }
6498:       }
6499:       for (p = cMax; p < cEnd; ++p) {
6500:         for (r = 0; r < 2; ++r) {
6501:           newp     = (cMax - cStart)*4 + (p - cMax)*2 + r;
6502:           pi[newp] = p;
6503:         }
6504:       }
6505:       break;
6506:     case REFINER_HYBRID_HEX_2D:
6507:       for (p = cStart; p < cMax; ++p) {
6508:         for (r = 0; r < 4; ++r) {
6509:           newp     = (p - cStart)*4 + r;
6510:           pi[newp] = p;
6511:         }
6512:       }
6513:       for (p = cMax; p < cEnd; ++p) {
6514:         for (r = 0; r < 2; ++r) {
6515:           newp     = (cMax - cStart)*4 + (p - cMax)*2 + r;
6516:           pi[newp] = p;
6517:         }
6518:       }
6519:       break;
6520:     case REFINER_SIMPLEX_3D:
6521:       for (p = cStart; p < cEnd; ++p) {
6522:         for (r = 0; r < 8; ++r) {
6523:           newp     = (p - cStart)*8 + r;
6524:           pi[newp] = p;
6525:         }
6526:       }
6527:       break;
6528:     case REFINER_HYBRID_SIMPLEX_3D:
6529:       for (p = cStart; p < cMax; ++p) {
6530:         for (r = 0; r < 8; ++r) {
6531:           newp     = (p - cStart)*8 + r;
6532:           pi[newp] = p;
6533:         }
6534:       }
6535:       for (p = cMax; p < cEnd; ++p) {
6536:         for (r = 0; r < 4; ++r) {
6537:           newp     = (cMax - cStart)*8 + (p - cMax)*4 + r;
6538:           pi[newp] = p;
6539:         }
6540:       }
6541:       break;
6542:     case REFINER_SIMPLEX_TO_HEX_3D:
6543:       for (p = cStart; p < cEnd; ++p) {
6544:         for (r = 0; r < 4; ++r) {
6545:           newp     = (p - cStart)*4 + r;
6546:           pi[newp] = p;
6547:         }
6548:       }
6549:       break;
6550:     case REFINER_HEX_3D:
6551:       for (p = cStart; p < cEnd; ++p) {
6552:         for (r = 0; r < 8; ++r) {
6553:           newp = (p - cStart)*8 + r;
6554:           pi[newp] = p;
6555:         }
6556:       }
6557:       break;
6558:     case REFINER_HYBRID_HEX_3D:
6559:       for (p = cStart; p < cMax; ++p) {
6560:         for (r = 0; r < 8; ++r) {
6561:           newp = (p - cStart)*8 + r;
6562:           pi[newp] = p;
6563:         }
6564:       }
6565:       for (p = cMax; p < cEnd; ++p) {
6566:         for (r = 0; r < 4; ++r) {
6567:           newp = (cMax - cStart)*8 + (p - cMax)*4 + r;
6568:           pi[newp] = p;
6569:         }
6570:       }
6571:       break;
6572:     default:
6573:       SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
6574:     }
6575:     parentId = pi;
6576:   } else {
6577:     PetscSectionSetChart(coordSectionNew, vStartNew, vStartNew+numVertices);
6578:   }
6579:   if (cMax < 0) cMax = cEnd;
6580:   if (fMax < 0) fMax = fEnd;
6581:   if (eMax < 0) eMax = eEnd;

6583:   /* All vertices have the spaceDim coordinates */
6584:   if (localize) {
6585:     PetscInt c;

6587:     for (c = cStartNew; c < cEndNew; ++c) {
6588:       PetscInt *cone = NULL;
6589:       PetscInt  closureSize, coneSize = 0, p, pdof;

6591:       PetscSectionGetDof(coordSection, parentId[c], &pdof);
6592:       if (pdof) { /* localize on all cells that are refinement of a localized parent cell */
6593:         DMPlexGetTransitiveClosure(rdm, c, PETSC_TRUE, &closureSize, &cone);
6594:         for (p = 0; p < closureSize*2; p += 2) {
6595:           const PetscInt point = cone[p];
6596:           if ((point >= vStartNew) && (point < vEndNew)) coneSize++;
6597:         }
6598:         DMPlexRestoreTransitiveClosure(rdm, c, PETSC_TRUE, &closureSize, &cone);
6599:         PetscSectionSetDof(coordSectionNew, c, coneSize*spaceDim);
6600:         PetscSectionSetFieldDof(coordSectionNew, c, 0, coneSize*spaceDim);
6601:       }
6602:     }
6603:   }
6604:   for (v = vStartNew; v < vStartNew+numVertices; ++v) {
6605:     PetscSectionSetDof(coordSectionNew, v, spaceDim);
6606:     PetscSectionSetFieldDof(coordSectionNew, v, 0, spaceDim);
6607:   }
6608:   PetscSectionSetUp(coordSectionNew);
6609:   DMSetCoordinateSection(rdm, PETSC_DETERMINE, coordSectionNew);
6610:   DMGetCoordinatesLocal(dm, &coordinates);
6611:   PetscSectionGetStorageSize(coordSectionNew, &coordSizeNew);
6612:   VecCreate(PETSC_COMM_SELF, &coordinatesNew);
6613:   PetscObjectSetName((PetscObject) coordinatesNew, "coordinates");
6614:   VecSetSizes(coordinatesNew, coordSizeNew, PETSC_DETERMINE);
6615:   VecGetBlockSize(coordinates, &bs);
6616:   VecSetBlockSize(coordinatesNew, bs);
6617:   VecGetType(coordinates, &vtype);
6618:   VecSetType(coordinatesNew, vtype);
6619:   VecGetArray(coordinates, &coords);
6620:   VecGetArray(coordinatesNew, &coordsNew);

6622:   switch (refiner) {
6623:   case REFINER_NOOP: break;
6624:   case REFINER_SIMPLEX_TO_HEX_3D:
6625:   case REFINER_HEX_3D:
6626:   case REFINER_HYBRID_HEX_3D:
6627:     /* Face vertices have the average of corner coordinates */
6628:     for (f = fStart; f < fMax; ++f) {
6629:       const PetscInt newv = vStartNew + (vEnd - vStart) + (eMax - eStart) + (f - fStart);
6630:       PetscInt      *cone = NULL;
6631:       PetscInt       closureSize, coneSize = 0, off[8], offnew, p, d;

6633:       DMPlexGetTransitiveClosure(dm, f, PETSC_TRUE, &closureSize, &cone);
6634:       for (p = 0; p < closureSize*2; p += 2) {
6635:         const PetscInt point = cone[p];
6636:         if ((point >= vStart) && (point < vEnd)) cone[coneSize++] = point;
6637:       }
6638:       if (localize) {
6639:         const PetscInt *support = NULL;
6640:         PetscInt       *rStar = NULL;
6641:         PetscInt        supportSize, rStarSize, coff, s, ccoff[8];
6642:         PetscBool       cellfound = PETSC_FALSE;

6644:         DMPlexGetTransitiveClosure(rdm, newv, PETSC_FALSE, &rStarSize, &rStar);
6645:         DMPlexGetSupportSize(dm,f,&supportSize);
6646:         DMPlexGetSupport(dm,f,&support);
6647:         /* Compute average of coordinates for each cell sharing the face */
6648:         for (s = 0; s < supportSize; ++s) {
6649:           PetscScalar     coordsNewAux[3] = { 0.0, 0.0, 0.0 };
6650:           PetscInt       *cellCone = NULL;
6651:           PetscInt        cellClosureSize, cellConeSize = 0, cdof;
6652:           const PetscInt  cell = support[s];
6653:           PetscBool       copyoff = PETSC_FALSE;

6655:           DMPlexGetTransitiveClosure(dm, cell, PETSC_TRUE, &cellClosureSize, &cellCone);
6656:           for (p = 0; p < cellClosureSize*2; p += 2) {
6657:             const PetscInt point = cellCone[p];
6658:             if ((point >= vStart) && (point < vEnd)) cellCone[cellConeSize++] = point;
6659:           }
6660:           PetscSectionGetDof(coordSection, cell, &cdof);
6661:           if (!cdof) { /* the parent cell does not have localized coordinates */
6662:             cellfound = PETSC_TRUE;
6663:             for (v = 0; v < coneSize; ++v) {
6664:               PetscSectionGetOffset(coordSection, cone[v], &off[v]);
6665:               for (d = 0; d < spaceDim; ++d) coordsNewAux[d] += coords[off[v]+d];
6666:             }
6667:             for (d = 0; d < spaceDim; ++d) coordsNewAux[d] /= coneSize;
6668:           } else {
6669:             PetscSectionGetOffset(coordSection, cell, &coff);
6670:             for (p = 0; p < coneSize; ++p) {
6671:               const PetscInt tv = cone[p];
6672:               PetscInt       cv, voff;
6673:               PetscBool      locv = PETSC_TRUE;

6675:               for (cv = 0; cv < cellConeSize; ++cv) {
6676:                 if (cellCone[cv] == tv) {
6677:                   ccoff[p] = spaceDim*cv + coff;
6678:                   break;
6679:                 }
6680:               }
6681:               if (cv == cellConeSize) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Unable to map vertex %D\n",tv);

6683:               PetscSectionGetOffset(coordSection, cone[p], &voff);
6684:               for (d = 0; d < spaceDim; ++d) {
6685:                 coordsNewAux[d] += coords[ccoff[p]+d];
6686:                 if (!cellfound && coords[voff+d] != coords[ccoff[p]+d]) locv = PETSC_FALSE;
6687:               }
6688:               if (locv && !cellfound) {
6689:                 cellfound = PETSC_TRUE;
6690:                 copyoff   = PETSC_TRUE;
6691:               }
6692:             }
6693:             for (d = 0; d < spaceDim; ++d) coordsNewAux[d] /= coneSize;

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

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

6706:               PetscSectionGetDof(coordSectionNew, rcell, &rcdof);
6707:               if (!rcdof) continue;
6708:               PetscSectionGetOffset(coordSectionNew, rcell, &rcoff);
6709:               DMPlexGetTransitiveClosure(rdm, rcell, PETSC_TRUE, &rclosureSize, &rcone);
6710:               for (p = 0, lid = 0; p < rclosureSize*2; p += 2) {
6711:                 if (rcone[p] == newv) {
6712:                   for (d = 0; d < spaceDim; d++) coordsNew[rcoff + lid*spaceDim + d] = coordsNewAux[d];
6713:                   break;
6714:                 }
6715:                 if (rcone[p] >= vStartNew && rcone[p] < vEndNew) lid++;
6716:               }
6717:               DMPlexRestoreTransitiveClosure(rdm, rcell, PETSC_TRUE, &rclosureSize, &rcone);
6718:               if (p == closureSize*2) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Unable to map new vertex %D\n",newv);
6719:             }
6720:           }
6721:           DMPlexRestoreTransitiveClosure(dm, cell, PETSC_TRUE, &cellClosureSize, &cellCone);
6722:         }
6723:         DMPlexRestoreTransitiveClosure(rdm, newv, PETSC_FALSE, &rStarSize, &rStar);
6724:         if (!cellfound) {
6725:           /* Could not find a valid face for the vertex part, we will get this vertex later (final reduction) */
6726:           needcoords = PETSC_TRUE;
6727:           coneSize   = 0;
6728:         }
6729:       } else {
6730:         for (v = 0; v < coneSize; ++v) {
6731:           PetscSectionGetOffset(coordSection, cone[v], &off[v]);
6732:         }
6733:       }
6734:       PetscSectionGetOffset(coordSectionNew, newv, &offnew);
6735:       if (coneSize) {
6736:         for (d = 0; d < spaceDim; ++d) coordsNew[offnew+d] = 0.0;
6737:         for (v = 0; v < coneSize; ++v) {DMLocalizeAddCoordinate_Internal(dm, spaceDim, &coords[off[0]], &coords[off[v]], &coordsNew[offnew]);}
6738:         for (d = 0; d < spaceDim; ++d) coordsNew[offnew+d] /= coneSize;
6739:       } else {
6740:         for (d = 0; d < spaceDim; ++d) coordsNew[offnew+d] = PETSC_MIN_REAL;
6741:       }
6742:       DMPlexRestoreTransitiveClosure(dm, f, PETSC_TRUE, &closureSize, &cone);
6743:     }
6744:   case REFINER_SIMPLEX_TO_HEX_2D:
6745:   case REFINER_HEX_2D:
6746:   case REFINER_HYBRID_HEX_2D:
6747:   case REFINER_SIMPLEX_1D:
6748:     /* Cell vertices have the average of corner coordinates */
6749:     for (c = cStart; c < cMax; ++c) {
6750:       const PetscInt newv = vStartNew + (vEnd - vStart) + (dim > 1 ? (eMax - eStart) : 0) + (c - cStart) + (dim > 2 ? (fMax - fStart) : 0);
6751:       PetscInt      *cone = NULL;
6752:       PetscInt       closureSize, coneSize = 0, off[8], offnew, p, d, cdof = 0;

6754:       DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &cone);
6755:       for (p = 0; p < closureSize*2; p += 2) {
6756:         const PetscInt point = cone[p];
6757:         if ((point >= vStart) && (point < vEnd)) cone[coneSize++] = point;
6758:       }
6759:       if (localize) {
6760:         PetscSectionGetDof(coordSection, c, &cdof);
6761:       }
6762:       if (cdof) {
6763:         PetscInt coff;

6765:         PetscSectionGetOffset(coordSection, c, &coff);
6766:         for (v = 0; v < coneSize; ++v) off[v] = spaceDim*v + coff;
6767:       } else {
6768:         for (v = 0; v < coneSize; ++v) {
6769:           PetscSectionGetOffset(coordSection, cone[v], &off[v]);
6770:         }
6771:       }
6772:       PetscSectionGetOffset(coordSectionNew, newv, &offnew);
6773:       for (d = 0; d < spaceDim; ++d) coordsNew[offnew+d] = 0.0;
6774:       for (v = 0; v < coneSize; ++v) {DMLocalizeAddCoordinate_Internal(dm, spaceDim, &coords[off[0]], &coords[off[v]], &coordsNew[offnew]);}
6775:       for (d = 0; d < spaceDim; ++d) coordsNew[offnew+d] /= coneSize;
6776:       DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &cone);

6778:       /* Localize new coordinates on each refined cell */
6779:       if (cdof) {
6780:         PetscInt *rStar = NULL, rStarSize;

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

6787:             rc   = rStar[v];
6788:             PetscSectionGetDof(coordSectionNew, rc, &rcdof);
6789:             if (!rcdof) continue;
6790:             PetscSectionGetOffset(coordSectionNew, rc, &coff);
6791:             DMPlexGetTransitiveClosure(rdm, rc, PETSC_TRUE, &closureSize, &cone);
6792:             for (p = 0, lid = 0; p < closureSize*2; p += 2) {
6793:               if (cone[p] == newv) {
6794:                 for (d = 0; d < spaceDim; d++) coordsNew[coff + lid*spaceDim + d] = coordsNew[offnew + d];
6795:                 break;
6796:               }
6797:               if (cone[p] >= vStartNew && cone[p] < vEndNew) lid++;
6798:             }
6799:             if (p == closureSize*2) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Unable to map new vertex %D\n",newv);
6800:             DMPlexRestoreTransitiveClosure(rdm, rc, PETSC_TRUE, &closureSize, &cone);
6801:           }
6802:         }
6803:         DMPlexRestoreTransitiveClosure(rdm, newv, PETSC_FALSE, &rStarSize, &rStar);
6804:       }
6805:     }
6806:   case REFINER_SIMPLEX_2D:
6807:   case REFINER_HYBRID_SIMPLEX_2D:
6808:   case REFINER_SIMPLEX_3D:
6809:   case REFINER_HYBRID_SIMPLEX_3D:
6810:     /* Edge vertices have the average of endpoint coordinates */
6811:     for (e = eStart; e < eMax; ++e) {
6812:       const PetscInt  newv = vStartNew + (vEnd - vStart) + (e - eStart);
6813:       const PetscInt *cone;
6814:       PetscInt        coneSize, offA, offB, offnew, d;

6816:       DMPlexGetConeSize(dm, e, &coneSize);
6817:       if (coneSize != 2) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Edge %d cone should have two vertices, not %d", e, coneSize);
6818:       DMPlexGetCone(dm, e, &cone);
6819:       if (localize) {
6820:         PetscInt   coff, toffA = -1, toffB = -1, voffA, voffB;
6821:         PetscInt  *eStar = NULL, eStarSize;
6822:         PetscInt  *rStar = NULL, rStarSize;
6823:         PetscBool  cellfound = PETSC_FALSE;

6825:         offA = offB = -1;
6826:         PetscSectionGetOffset(coordSection, cone[0], &voffA);
6827:         PetscSectionGetOffset(coordSection, cone[1], &voffB);
6828:         DMPlexGetTransitiveClosure(dm, e, PETSC_FALSE, &eStarSize, &eStar);
6829:         DMPlexGetTransitiveClosure(rdm, newv, PETSC_FALSE, &rStarSize, &rStar);
6830:         for (v = 0; v < eStarSize*2; v += 2) {
6831:           if ((eStar[v] >= cStart) && (eStar[v] < cEnd)) {
6832:             PetscScalar     coordsNewAux[3];
6833:             PetscInt       *cellCone = NULL;
6834:             PetscInt        cellClosureSize, s, cv, cdof;
6835:             PetscBool       locvA = PETSC_TRUE, locvB = PETSC_TRUE;
6836:             const PetscInt  cell = eStar[v];

6838:             PetscSectionGetDof(coordSection, cell, &cdof);
6839:             if (!cdof) {
6840:               /* Found a valid edge for the "vertex" part of the Section */
6841:               offA = voffA;
6842:               offB = voffB;
6843:               cellfound = PETSC_TRUE;
6844:             } else {
6845:               PetscSectionGetOffset(coordSection, cell, &coff);
6846:               DMPlexGetTransitiveClosure(dm, cell, PETSC_TRUE, &cellClosureSize, &cellCone);
6847:               for (s = 0, cv = 0; s < cellClosureSize*2; s += 2) {
6848:                 const PetscInt point = cellCone[s];
6849:                 if ((point >= vStart) && (point < vEnd)) {
6850:                   if (point == cone[0]) toffA = spaceDim*cv + coff;
6851:                   else if (point == cone[1]) toffB = spaceDim*cv + coff;
6852:                   cv++;
6853:                 }
6854:               }
6855:               DMPlexRestoreTransitiveClosure(dm, cell, PETSC_TRUE, &cellClosureSize, &cellCone);
6856:               for (d = 0; d < spaceDim; ++d) {
6857:                 coordsNewAux[d] = 0.5*(coords[toffA+d] + coords[toffB+d]);
6858:                 if (coords[toffA+d] != coords[voffA+d]) locvA = PETSC_FALSE;
6859:                 if (coords[toffB+d] != coords[voffB+d]) locvB = PETSC_FALSE;
6860:               }
6861:               /* Found a valid edge for the "vertex" part of the Section */
6862:               if (!cellfound && (locvA || locvB)) {
6863:                 cellfound = PETSC_TRUE;
6864:                 offA = toffA;
6865:                 offB = toffB;
6866:               }
6867:             }

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

6875:                 PetscSectionGetDof(coordSectionNew, rcell, &rcdof);
6876:                 if (!rcdof) continue;
6877:                 PetscSectionGetOffset(coordSectionNew, rcell, &coff);
6878:                 DMPlexGetTransitiveClosure(rdm, rcell, PETSC_TRUE, &rclosureSize, &rcone);
6879:                 for (p = 0, lid = 0; p < rclosureSize*2; p += 2) {
6880:                   if (rcone[p] == newv) {
6881:                     for (d = 0; d < spaceDim; d++) coordsNew[coff + lid*spaceDim + d] = coordsNewAux[d];
6882:                     break;
6883:                   }
6884:                   if (rcone[p] >= vStartNew && rcone[p] < vEndNew) lid++;
6885:                 }
6886:                 DMPlexRestoreTransitiveClosure(rdm, rcell, PETSC_TRUE, &rclosureSize, &rcone);
6887:                 if (p == rclosureSize*2) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Unable to map new vertex %D\n",newv);
6888:               }
6889:             }
6890:           }
6891:         }
6892:         DMPlexRestoreTransitiveClosure(dm, e, PETSC_FALSE, &eStarSize, &eStar);
6893:         DMPlexRestoreTransitiveClosure(rdm, newv, PETSC_FALSE, &rStarSize, &rStar);
6894:         if (!cellfound) {
6895:           /* Could not find a valid edge for the vertex part, we will get this vertex later (final reduction) */
6896:           needcoords = PETSC_TRUE;
6897:         }
6898:       } else {
6899:         PetscSectionGetOffset(coordSection, cone[0], &offA);
6900:         PetscSectionGetOffset(coordSection, cone[1], &offB);
6901:       }
6902:       PetscSectionGetOffset(coordSectionNew, newv, &offnew);
6903:       if (offA != -1 && offB != -1) {
6904:         DMLocalizeCoordinate_Internal(dm, spaceDim, &coords[offA], &coords[offB], &coordsNew[offnew]);
6905:         for (d = 0; d < spaceDim; ++d) {
6906:           coordsNew[offnew+d] = 0.5*(coords[offA+d] + coordsNew[offnew+d]);
6907:         }
6908:       } else {
6909:         for (d = 0; d < spaceDim; ++d) coordsNew[offnew+d] = PETSC_MIN_REAL;
6910:       }
6911:     }
6912:     /* Old vertices have the same coordinates */
6913:     for (v = vStart; v < vEnd; ++v) {
6914:       const PetscInt newv = vStartNew + (v - vStart);
6915:       PetscInt       off, offnew, d;

6917:       PetscSectionGetOffset(coordSection, v, &off);
6918:       PetscSectionGetOffset(coordSectionNew, newv, &offnew);
6919:       for (d = 0; d < spaceDim; ++d) {
6920:         coordsNew[offnew+d] = coords[off+d];
6921:       }

6923:       /* Localize new coordinates on each refined cell */
6924:       if (localize) {
6925:         PetscInt  p;
6926:         PetscInt *rStar = NULL, rStarSize;

6928:         DMPlexGetTransitiveClosure(rdm, newv, PETSC_FALSE, &rStarSize, &rStar);
6929:         for (p = 0; p < rStarSize*2; p += 2) {
6930:           if ((rStar[p] >= cStartNew) && (rStar[p] < cEndNew)) {
6931:             PetscScalar  ocoords[3];
6932:             PetscInt    *cone = NULL, closureSize, lid, coff, s, oc, cdof;

6934:             c    = rStar[p];
6935:             oc   = parentId[c-cStartNew];
6936:             PetscSectionGetDof(coordSectionNew, c, &cdof);
6937:             if (!cdof) continue;
6938:             PetscSectionGetDof(coordSection, oc, &cdof);
6939:             if (!cdof) continue;
6940:             PetscSectionGetOffset(coordSection, oc, &coff);
6941:             DMPlexGetTransitiveClosure(dm, oc, PETSC_TRUE, &closureSize, &cone);
6942:             for (s = 0, lid = 0; s < closureSize*2; s += 2) {
6943:               if (cone[s] == v) {
6944:                 for (d = 0; d < spaceDim; d++) ocoords[d] = coords[coff + lid*spaceDim + d];
6945:                 break;
6946:               }
6947:               if (cone[s] >= vStart && cone[s] < vEnd) lid++;
6948:             }
6949:             if (s == closureSize*2) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Unable to map old vertex %D\n",v);
6950:             DMPlexRestoreTransitiveClosure(dm, oc, PETSC_TRUE, &closureSize, &cone);

6952:             PetscSectionGetOffset(coordSectionNew, c, &coff);
6953:             DMPlexGetTransitiveClosure(rdm, c, PETSC_TRUE, &closureSize, &cone);
6954:             for (s = 0, lid = 0; s < closureSize*2; s += 2) {
6955:               if (cone[s] == newv) {
6956:                 for (d = 0; d < spaceDim; d++) coordsNew[coff + lid*spaceDim + d] = ocoords[d];
6957:                 break;
6958:               }
6959:               if (cone[s] >= vStartNew && cone[s] < vEndNew) lid++;
6960:             }
6961:             if (s == closureSize*2) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Unable to map new vertex %D\n",newv);
6962:             DMPlexRestoreTransitiveClosure(rdm, c, PETSC_TRUE, &closureSize, &cone);
6963:           }
6964:         }
6965:         DMPlexRestoreTransitiveClosure(rdm, newv, PETSC_FALSE, &rStarSize, &rStar);
6966:       }
6967:     }
6968:     break;
6969:   default:
6970:     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
6971:   }
6972:   VecRestoreArray(coordinates, &coords);
6973:   VecRestoreArray(coordinatesNew, &coordsNew);
6974:   DMSetCoordinatesLocal(rdm, coordinatesNew);

6976:   /* Final reduction (if needed) if we are localizing */
6977:   if (localize) {
6978:     PetscBool gred;

6980:     MPIU_Allreduce(&needcoords, &gred, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject)rdm));
6981:     if (gred) {
6982:       DM                 cdm;
6983:       Vec                aux;
6984:       PetscSF            sf;
6985:       const PetscScalar *lArray;
6986:       PetscScalar       *gArray;

6988:       DMGetCoordinateDM(rdm, &cdm);
6989:       DMCreateGlobalVector(cdm, &aux);
6990:       DMGetDefaultSF(cdm, &sf);
6991:       VecGetArrayRead(coordinatesNew, &lArray);
6992:       VecSet(aux, PETSC_MIN_REAL);
6993:       VecGetArray(aux, &gArray);
6994:       PetscSFReduceBegin(sf, MPIU_SCALAR, lArray, gArray, MPIU_MAX);
6995:       PetscSFReduceEnd(sf, MPIU_SCALAR, lArray, gArray, MPIU_MAX);
6996:       VecRestoreArrayRead(coordinatesNew, &lArray);
6997:       VecRestoreArray(aux, &gArray);
6998:       DMGlobalToLocalBegin(cdm, aux, INSERT_VALUES, coordinatesNew);
6999:       DMGlobalToLocalEnd(cdm, aux, INSERT_VALUES, coordinatesNew);
7000:       VecDestroy(&aux);
7001:     }
7002:   }
7003:   VecDestroy(&coordinatesNew);
7004:   PetscSectionDestroy(&coordSectionNew);
7005:   PetscFree(parentId);
7006:   return(0);
7007: }

7009: /*@
7010:   DMPlexCreateProcessSF - Create an SF which just has process connectivity

7012:   Collective on DM

7014:   Input Parameters:
7015: + dm      - The DM
7016: - sfPoint - The PetscSF which encodes point connectivity

7018:   Output Parameters:
7019: + processRanks - A list of process neighbors, or NULL
7020: - sfProcess    - An SF encoding the process connectivity, or NULL

7022:   Level: developer

7024: .seealso: PetscSFCreate(), DMPlexCreateTwoSidedProcessSF()
7025: @*/
7026: PetscErrorCode DMPlexCreateProcessSF(DM dm, PetscSF sfPoint, IS *processRanks, PetscSF *sfProcess)
7027: {
7028:   PetscInt           numRoots, numLeaves, l;
7029:   const PetscInt    *localPoints;
7030:   const PetscSFNode *remotePoints;
7031:   PetscInt          *localPointsNew;
7032:   PetscSFNode       *remotePointsNew;
7033:   PetscInt          *ranks, *ranksNew;
7034:   PetscMPIInt        size;
7035:   PetscErrorCode     ierr;

7042:   MPI_Comm_size(PetscObjectComm((PetscObject) dm), &size);
7043:   PetscSFGetGraph(sfPoint, &numRoots, &numLeaves, &localPoints, &remotePoints);
7044:   PetscMalloc1(numLeaves, &ranks);
7045:   for (l = 0; l < numLeaves; ++l) {
7046:     ranks[l] = remotePoints[l].rank;
7047:   }
7048:   PetscSortRemoveDupsInt(&numLeaves, ranks);
7049:   PetscMalloc1(numLeaves, &ranksNew);
7050:   PetscMalloc1(numLeaves, &localPointsNew);
7051:   PetscMalloc1(numLeaves, &remotePointsNew);
7052:   for (l = 0; l < numLeaves; ++l) {
7053:     ranksNew[l]              = ranks[l];
7054:     localPointsNew[l]        = l;
7055:     remotePointsNew[l].index = 0;
7056:     remotePointsNew[l].rank  = ranksNew[l];
7057:   }
7058:   PetscFree(ranks);
7059:   if (processRanks) {ISCreateGeneral(PetscObjectComm((PetscObject)dm), numLeaves, ranksNew, PETSC_OWN_POINTER, processRanks);}
7060:   else              {PetscFree(ranksNew);}
7061:   if (sfProcess) {
7062:     PetscSFCreate(PetscObjectComm((PetscObject)dm), sfProcess);
7063:     PetscObjectSetName((PetscObject) *sfProcess, "Process SF");
7064:     PetscSFSetFromOptions(*sfProcess);
7065:     PetscSFSetGraph(*sfProcess, size, numLeaves, localPointsNew, PETSC_OWN_POINTER, remotePointsNew, PETSC_OWN_POINTER);
7066:   }
7067:   return(0);
7068: }

7070: static PetscErrorCode CellRefinerCreateSF(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
7071: {
7072:   PetscSF            sf, sfNew, sfProcess;
7073:   IS                 processRanks;
7074:   MPI_Datatype       depthType;
7075:   PetscInt           numRoots, numLeaves, numLeavesNew = 0, l, m;
7076:   const PetscInt    *localPoints, *neighbors;
7077:   const PetscSFNode *remotePoints;
7078:   PetscInt          *localPointsNew;
7079:   PetscSFNode       *remotePointsNew;
7080:   PetscInt          *depthSizeOld, *rdepthSize, *rdepthSizeOld, *rdepthMaxOld, *rvStart, *rvStartNew, *reStart, *reStartNew, *rfStart, *rfStartNew, *rcStart, *rcStartNew;
7081:   PetscInt           ldepth, depth, numNeighbors, pStartNew, pEndNew, cStart, cEnd, cMax, vStart, vEnd, vMax, fStart, fEnd, fMax, eStart, eEnd, eMax, r, n;
7082:   PetscInt           cStartNew = 0, vStartNew = 0, fStartNew = 0, eStartNew = 0;
7083:   PetscErrorCode     ierr;

7086:   DMPlexGetChart(rdm, &pStartNew, &pEndNew);
7087:   DMPlexGetDepth(dm, &ldepth);
7088:   MPIU_Allreduce(&ldepth, &depth, 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject) dm));
7089:   if ((ldepth >= 0) && (depth != ldepth)) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Inconsistent Plex depth %d != %d", ldepth, depth);
7090:   DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);
7091:   DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);
7092:   DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);
7093:   DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);
7094:   DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);
7095:   cMax = cMax < 0 ? cEnd : cMax;
7096:   fMax = fMax < 0 ? fEnd : fMax;
7097:   eMax = eMax < 0 ? eEnd : eMax;
7098:   if (refiner) {GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);}
7099:   DMGetPointSF(dm, &sf);
7100:   DMGetPointSF(rdm, &sfNew);
7101:   /* Calculate size of new SF */
7102:   PetscSFGetGraph(sf, &numRoots, &numLeaves, &localPoints, &remotePoints);
7103:   if (numRoots < 0) return(0);
7104:   for (l = 0; l < numLeaves; ++l) {
7105:     const PetscInt p = localPoints[l];

7107:     switch (refiner) {
7108:     case REFINER_SIMPLEX_1D:
7109:       if ((p >= vStart) && (p < vEnd)) {
7110:         /* Interior vertices stay the same */
7111:         ++numLeavesNew;
7112:       } else if ((p >= cStart && p < cMax)) {
7113:         /* Interior cells add new cells and interior vertices */
7114:         numLeavesNew += 2 + 1;
7115:       }
7116:       break;
7117:     case REFINER_SIMPLEX_2D:
7118:     case REFINER_HYBRID_SIMPLEX_2D:
7119:       if ((p >= vStart) && (p < vEnd)) {
7120:         /* Interior vertices stay the same */
7121:         ++numLeavesNew;
7122:       } else if ((p >= fStart) && (p < fMax)) {
7123:         /* Interior faces add new faces and vertex */
7124:         numLeavesNew += 2 + 1;
7125:       } else if ((p >= fMax) && (p < fEnd)) {
7126:         /* Hybrid faces stay the same */
7127:         ++numLeavesNew;
7128:       } else if ((p >= cStart) && (p < cMax)) {
7129:         /* Interior cells add new cells and interior faces */
7130:         numLeavesNew += 4 + 3;
7131:       } else if ((p >= cMax) && (p < cEnd)) {
7132:         /* Hybrid cells add new cells and hybrid face */
7133:         numLeavesNew += 2 + 1;
7134:       }
7135:       break;
7136:     case REFINER_SIMPLEX_TO_HEX_2D:
7137:       if ((p >= vStart) && (p < vEnd)) {
7138:         /* Interior vertices stay the same */
7139:         ++numLeavesNew;
7140:       } else if ((p >= fStart) && (p < fEnd)) {
7141:         /* Interior faces add new faces and vertex */
7142:         numLeavesNew += 2 + 1;
7143:       } else if ((p >= cStart) && (p < cEnd)) {
7144:         /* Interior cells add new cells, interior faces, and vertex */
7145:         numLeavesNew += 3 + 3 + 1;
7146:       }
7147:       break;
7148:     case REFINER_HEX_2D:
7149:     case REFINER_HYBRID_HEX_2D:
7150:       if ((p >= vStart) && (p < vEnd)) {
7151:         /* Interior vertices stay the same */
7152:         ++numLeavesNew;
7153:       } else if ((p >= fStart) && (p < fMax)) {
7154:         /* Interior faces add new faces and vertex */
7155:         numLeavesNew += 2 + 1;
7156:       } else if ((p >= fMax) && (p < fEnd)) {
7157:         /* Hybrid faces stay the same */
7158:         ++numLeavesNew;
7159:       } else if ((p >= cStart) && (p < cMax)) {
7160:         /* Interior cells add new cells, interior faces, and vertex */
7161:         numLeavesNew += 4 + 4 + 1;
7162:       } else if ((p >= cMax) && (p < cEnd)) {
7163:         /* Hybrid cells add new cells and hybrid face */
7164:         numLeavesNew += 2 + 1;
7165:       }
7166:       break;
7167:     case REFINER_SIMPLEX_3D:
7168:     case REFINER_HYBRID_SIMPLEX_3D:
7169:       if ((p >= vStart) && (p < vEnd)) {
7170:         /* Interior vertices stay the same */
7171:         ++numLeavesNew;
7172:       } else if ((p >= eStart) && (p < eMax)) {
7173:         /* Interior edges add new edges and vertex */
7174:         numLeavesNew += 2 + 1;
7175:       } else if ((p >= eMax) && (p < eEnd)) {
7176:         /* Hybrid edges stay the same */
7177:         ++numLeavesNew;
7178:       } else if ((p >= fStart) && (p < fMax)) {
7179:         /* Interior faces add new faces and edges */
7180:         numLeavesNew += 4 + 3;
7181:       } else if ((p >= fMax) && (p < fEnd)) {
7182:         /* Hybrid faces add new faces and edges */
7183:         numLeavesNew += 2 + 1;
7184:       } else if ((p >= cStart) && (p < cMax)) {
7185:         /* Interior cells add new cells, faces, and edges */
7186:         numLeavesNew += 8 + 8 + 1;
7187:       } else if ((p >= cMax) && (p < cEnd)) {
7188:         /* Hybrid cells add new cells and faces */
7189:         numLeavesNew += 4 + 3;
7190:       }
7191:       break;
7192:     case REFINER_SIMPLEX_TO_HEX_3D:
7193:       if ((p >= vStart) && (p < vEnd)) {
7194:         /* Interior vertices stay the same */
7195:         ++numLeavesNew;
7196:       } else if ((p >= eStart) && (p < eEnd)) {
7197:         /* Interior edges add new edges and vertex */
7198:         numLeavesNew += 2 + 1;
7199:       } else if ((p >= fStart) && (p < fEnd)) {
7200:         /* Interior faces add new faces, edges and a vertex */
7201:         numLeavesNew += 3 + 3 + 1;
7202:       } else if ((p >= cStart) && (p < cEnd)) {
7203:         /* Interior cells add new cells, faces, edges and a vertex */
7204:         numLeavesNew += 4 + 6 + 4 + 1;
7205:       }
7206:       break;
7207:     case REFINER_HEX_3D:
7208:     case REFINER_HYBRID_HEX_3D:
7209:       if ((p >= vStart) && (p < vEnd)) {
7210:         /* Old vertices stay the same */
7211:         ++numLeavesNew;
7212:       } else if ((p >= eStart) && (p < eMax)) {
7213:         /* Interior edges add new edges, and vertex */
7214:         numLeavesNew += 2 + 1;
7215:       } else if ((p >= eMax) && (p < eEnd)) {
7216:         /* Hybrid edges stay the same */
7217:         ++numLeavesNew;
7218:       } else if ((p >= fStart) && (p < fMax)) {
7219:         /* Interior faces add new faces, edges, and vertex */
7220:         numLeavesNew += 4 + 4 + 1;
7221:       } else if ((p >= fMax) && (p < fEnd)) {
7222:         /* Hybrid faces add new faces and edges */
7223:         numLeavesNew += 2 + 1;
7224:       } else if ((p >= cStart) && (p < cMax)) {
7225:         /* Interior cells add new cells, faces, edges, and vertex */
7226:         numLeavesNew += 8 + 12 + 6 + 1;
7227:       } else if ((p >= cStart) && (p < cEnd)) {
7228:         /* Hybrid cells add new cells, faces, and edges */
7229:         numLeavesNew += 4 + 4 + 1;
7230:       }
7231:       break;
7232:     default:
7233:       SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
7234:     }
7235:   }
7236:   /* Communicate depthSizes for each remote rank */
7237:   DMPlexCreateProcessSF(dm, sf, &processRanks, &sfProcess);
7238:   ISGetLocalSize(processRanks, &numNeighbors);
7239:   PetscMalloc5((depth+1)*numNeighbors,&rdepthSize,numNeighbors,&rvStartNew,numNeighbors,&reStartNew,numNeighbors,&rfStartNew,numNeighbors,&rcStartNew);
7240:   PetscMalloc7(depth+1,&depthSizeOld,(depth+1)*numNeighbors,&rdepthSizeOld,(depth+1)*numNeighbors,&rdepthMaxOld,numNeighbors,&rvStart,numNeighbors,&reStart,numNeighbors,&rfStart,numNeighbors,&rcStart);
7241:   MPI_Type_contiguous(depth+1, MPIU_INT, &depthType);
7242:   MPI_Type_commit(&depthType);
7243:   PetscSFBcastBegin(sfProcess, depthType, depthSize, rdepthSize);
7244:   PetscSFBcastEnd(sfProcess, depthType, depthSize, rdepthSize);
7245:   for (n = 0; n < numNeighbors; ++n) {
7246:     GetDepthStart_Private(depth, &rdepthSize[n*(depth+1)], &rcStartNew[n], &rfStartNew[n], &reStartNew[n], &rvStartNew[n]);
7247:   }
7248:   depthSizeOld[depth]   = cMax;
7249:   depthSizeOld[0]       = vMax;
7250:   depthSizeOld[depth-1] = fMax;
7251:   depthSizeOld[1]       = eMax;

7253:   PetscSFBcastBegin(sfProcess, depthType, depthSizeOld, rdepthMaxOld);
7254:   PetscSFBcastEnd(sfProcess, depthType, depthSizeOld, rdepthMaxOld);

7256:   depthSizeOld[depth]   = cEnd - cStart;
7257:   depthSizeOld[0]       = vEnd - vStart;
7258:   depthSizeOld[depth-1] = fEnd - fStart;
7259:   depthSizeOld[1]       = eEnd - eStart;

7261:   PetscSFBcastBegin(sfProcess, depthType, depthSizeOld, rdepthSizeOld);
7262:   PetscSFBcastEnd(sfProcess, depthType, depthSizeOld, rdepthSizeOld);
7263:   for (n = 0; n < numNeighbors; ++n) {
7264:     GetDepthStart_Private(depth, &rdepthSizeOld[n*(depth+1)], &rcStart[n], &rfStart[n], &reStart[n], &rvStart[n]);
7265:     rdepthMaxOld[n*(depth+1)+depth]   = rdepthMaxOld[n*(depth+1)+depth]   < 0 ? rdepthSizeOld[n*(depth+1)+depth]  +rcStart[n]: rdepthMaxOld[n*(depth+1)+depth];
7266:     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];
7267:     rdepthMaxOld[n*(depth+1)+1]       = rdepthMaxOld[n*(depth+1)+1]       < 0 ? rdepthSizeOld[n*(depth+1)+1]      +reStart[n]: rdepthMaxOld[n*(depth+1)+1];
7268:   }
7269:   MPI_Type_free(&depthType);
7270:   PetscSFDestroy(&sfProcess);
7271:   /* Calculate new point SF */
7272:   PetscMalloc1(numLeavesNew, &localPointsNew);
7273:   PetscMalloc1(numLeavesNew, &remotePointsNew);
7274:   ISGetIndices(processRanks, &neighbors);
7275:   for (l = 0, m = 0; l < numLeaves; ++l) {
7276:     PetscInt    p     = localPoints[l];
7277:     PetscInt    rp    = remotePoints[l].index, n;
7278:     PetscMPIInt rrank = remotePoints[l].rank;

7280:     PetscFindInt(rrank, numNeighbors, neighbors, &n);
7281:     if (n < 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Could not locate remote rank %d", rrank);
7282:     switch (refiner) {
7283:     case REFINER_SIMPLEX_1D:
7284:       if ((p >= vStart) && (p < vEnd)) {
7285:         /* Old vertices stay the same */
7286:         localPointsNew[m]        = vStartNew     + (p  - vStart);
7287:         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
7288:         remotePointsNew[m].rank  = rrank;
7289:         ++m;
7290:       } else if ((p >= cStart) && (p < cMax)) {
7291:         /* Old interior cells add new cells and vertex */
7292:         for (r = 0; r < 2; ++r, ++m) {
7293:           localPointsNew[m]        = cStartNew     + (p  - cStart)*2     + r;
7294:           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*2 + r;
7295:           remotePointsNew[m].rank  = rrank;
7296:         }
7297:         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - cStart);
7298:         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - rcStart[n]);
7299:         remotePointsNew[m].rank  = rrank;
7300:         ++m;
7301:       }
7302:       break;
7303:     case REFINER_SIMPLEX_2D:
7304:     case REFINER_HYBRID_SIMPLEX_2D:
7305:       if ((p >= vStart) && (p < vEnd)) {
7306:         /* Old vertices stay the same */
7307:         localPointsNew[m]        = vStartNew     + (p  - vStart);
7308:         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
7309:         remotePointsNew[m].rank  = rrank;
7310:         ++m;
7311:       } else if ((p >= fStart) && (p < fMax)) {
7312:         /* Old interior faces add new faces and vertex */
7313:         for (r = 0; r < 2; ++r, ++m) {
7314:           localPointsNew[m]        = fStartNew     + (p  - fStart)*2     + r;
7315:           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*2 + r;
7316:           remotePointsNew[m].rank  = rrank;
7317:         }
7318:         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - fStart);
7319:         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - rfStart[n]);
7320:         remotePointsNew[m].rank  = rrank;
7321:         ++m;
7322:       } else if ((p >= fMax) && (p < fEnd)) {
7323:         /* Old hybrid faces stay the same */
7324:         localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (p  - fMax);
7325:         remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*2 + (rp - rdepthMaxOld[n*(depth+1)+depth-1]);
7326:         remotePointsNew[m].rank  = rrank;
7327:         ++m;
7328:       } else if ((p >= cStart) && (p < cMax)) {
7329:         /* Old interior cells add new cells and interior faces */
7330:         for (r = 0; r < 4; ++r, ++m) {
7331:           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
7332:           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
7333:           remotePointsNew[m].rank  = rrank;
7334:         }
7335:         for (r = 0; r < 3; ++r, ++m) {
7336:           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (p  - cStart)*3     + r;
7337:           remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*2 + (rp - rcStart[n])*3 + r;
7338:           remotePointsNew[m].rank  = rrank;
7339:         }
7340:       } else if ((p >= cMax) && (p < cEnd)) {
7341:         /* Old hybrid cells add new cells and hybrid face */
7342:         for (r = 0; r < 2; ++r, ++m) {
7343:           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
7344:           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
7345:           remotePointsNew[m].rank  = rrank;
7346:         }
7347:         localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (cMax                            - cStart)*3     + (p  - cMax);
7348:         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]);
7349:         remotePointsNew[m].rank  = rrank;
7350:         ++m;
7351:       }
7352:       break;
7353:     case REFINER_SIMPLEX_TO_HEX_2D:
7354:       if ((p >= vStart) && (p < vEnd)) {
7355:         /* Old vertices stay the same */
7356:         localPointsNew[m]        = vStartNew     + (p  - vStart);
7357:         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
7358:         remotePointsNew[m].rank  = rrank;
7359:         ++m;
7360:       } else if ((p >= fStart) && (p < fEnd)) {
7361:         /* Old interior faces add new faces and vertex */
7362:         for (r = 0; r < 2; ++r, ++m) {
7363:           localPointsNew[m]        = fStartNew     + (p  - fStart)*2     + r;
7364:           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*2 + r;
7365:           remotePointsNew[m].rank  = rrank;
7366:         }
7367:         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - fStart);
7368:         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - rfStart[n]);
7369:         remotePointsNew[m].rank  = rrank;
7370:         ++m;
7371:       } else if ((p >= cStart) && (p < cEnd)) {
7372:         /* Old interior cells add new cells, interior faces, and a vertex */
7373:         for (r = 0; r < 3; ++r, ++m) {
7374:           localPointsNew[m]        = cStartNew     + (p  - cStart)*3     + r;
7375:           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*3 + r;
7376:           remotePointsNew[m].rank  = rrank;
7377:         }
7378:         for (r = 0; r < 3; ++r, ++m) {
7379:           localPointsNew[m]        = fStartNew     + (fEnd - fStart)*2                    + (p  - cStart)*3     + r;
7380:           remotePointsNew[m].index = rfStartNew[n] + rdepthSizeOld[n*(depth+1)+depth-1]*2 + (rp - rcStart[n])*3 + r;
7381:           remotePointsNew[m].rank  = rrank;
7382:         }
7383:         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (fEnd - fStart)                    + (p  - cStart);
7384:         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + rdepthSizeOld[n*(depth+1)+depth-1] + (rp - rcStart[n]);
7385:         remotePointsNew[m].rank  = rrank;
7386:         ++m;
7387:       }
7388:       break;
7389:     case REFINER_HEX_2D:
7390:     case REFINER_HYBRID_HEX_2D:
7391:       if ((p >= vStart) && (p < vEnd)) {
7392:         /* Old vertices stay the same */
7393:         localPointsNew[m]        = vStartNew     + (p  - vStart);
7394:         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
7395:         remotePointsNew[m].rank  = rrank;
7396:         ++m;
7397:       } else if ((p >= fStart) && (p < fMax)) {
7398:         /* Old interior faces add new faces and vertex */
7399:         for (r = 0; r < 2; ++r, ++m) {
7400:           localPointsNew[m]        = fStartNew     + (p  - fStart)*2     + r;
7401:           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*2 + r;
7402:           remotePointsNew[m].rank  = rrank;
7403:         }
7404:         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - fStart);
7405:         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - rfStart[n]);
7406:         remotePointsNew[m].rank  = rrank;
7407:         ++m;
7408:       } else if ((p >= fMax) && (p < fEnd)) {
7409:         /* Old hybrid faces stay the same */
7410:         localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (p  - fMax);
7411:         remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*2 + (rp - rdepthMaxOld[n*(depth+1)+depth-1]);
7412:         remotePointsNew[m].rank  = rrank;
7413:         ++m;
7414:       } else if ((p >= cStart) && (p < cMax)) {
7415:         /* Old interior cells add new cells, interior faces, and vertex */
7416:         for (r = 0; r < 4; ++r, ++m) {
7417:           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
7418:           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
7419:           remotePointsNew[m].rank  = rrank;
7420:         }
7421:         for (r = 0; r < 4; ++r, ++m) {
7422:           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (p  - cStart)*4     + r;
7423:           remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*2 + (rp - rcStart[n])*4 + r;
7424:           remotePointsNew[m].rank  = rrank;
7425:         }
7426:         localPointsNew[m]        = vStartNew     + (vEnd - vStart)               + (fMax                              - fStart)     + (p  - cStart);
7427:         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0]  + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n]) + (rp - rcStart[n]);
7428:         remotePointsNew[m].rank  = rrank;
7429:         ++m;
7430:       } else if ((p >= cStart) && (p < cMax)) {
7431:         /* Old hybrid cells add new cells and hybrid face */
7432:         for (r = 0; r < 2; ++r, ++m) {
7433:           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
7434:           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
7435:           remotePointsNew[m].rank  = rrank;
7436:         }
7437:         localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (cMax                            - cStart)*4     + (p  - cMax);
7438:         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]);
7439:         remotePointsNew[m].rank  = rrank;
7440:         ++m;
7441:       }
7442:       break;
7443:     case REFINER_SIMPLEX_3D:
7444:     case REFINER_HYBRID_SIMPLEX_3D:
7445:       if ((p >= vStart) && (p < vEnd)) {
7446:         /* Interior vertices stay the same */
7447:         localPointsNew[m]        = vStartNew     + (p  - vStart);
7448:         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
7449:         remotePointsNew[m].rank  = rrank;
7450:         ++m;
7451:       } else if ((p >= eStart) && (p < eMax)) {
7452:         /* Interior edges add new edges and vertex */
7453:         for (r = 0; r < 2; ++r, ++m) {
7454:           localPointsNew[m]        = eStartNew     + (p  - eStart)*2     + r;
7455:           remotePointsNew[m].index = reStartNew[n] + (rp - reStart[n])*2 + r;
7456:           remotePointsNew[m].rank  = rrank;
7457:         }
7458:         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - eStart);
7459:         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - reStart[n]);
7460:         remotePointsNew[m].rank  = rrank;
7461:         ++m;
7462:       } else if ((p >= eMax) && (p < eEnd)) {
7463:         /* Hybrid edges stay the same */
7464:         localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (fMax                              - fStart)*3     + (cMax                            - cStart)     + (p  - eMax);
7465:         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]);
7466:         remotePointsNew[m].rank  = rrank;
7467:         ++m;
7468:       } else if ((p >= fStart) && (p < fMax)) {
7469:         /* Interior faces add new faces and edges */
7470:         for (r = 0; r < 4; ++r, ++m) {
7471:           localPointsNew[m]        = fStartNew     + (p  - fStart)*4     + r;
7472:           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*4 + r;
7473:           remotePointsNew[m].rank  = rrank;
7474:         }
7475:         for (r = 0; r < 3; ++r, ++m) {
7476:           localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (p  - fStart)*3     + r;
7477:           remotePointsNew[m].index = reStartNew[n] + (rdepthMaxOld[n*(depth+1)+1] - reStart[n])*2 + (rp - rfStart[n])*3 + r;
7478:           remotePointsNew[m].rank  = rrank;
7479:         }
7480:       } else if ((p >= fMax) && (p < fEnd)) {
7481:         /* Hybrid faces add new faces and edges */
7482:         for (r = 0; r < 2; ++r, ++m) {
7483:           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*4     + (cMax                            - cStart)*8     + (p  - fMax)*2                              + r;
7484:           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;
7485:           remotePointsNew[m].rank  = rrank;
7486:         }
7487:         localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (fMax                              - fStart)*3     + (cMax                            - cStart)     + (eEnd                                    - eMax)                        + (p  - fMax);
7488:         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]);
7489:         remotePointsNew[m].rank  = rrank;
7490:         ++m;
7491:       } else if ((p >= cStart) && (p < cMax)) {
7492:         /* Interior cells add new cells, faces, and edges */
7493:         for (r = 0; r < 8; ++r, ++m) {
7494:           localPointsNew[m]        = cStartNew     + (p  - cStart)*8     + r;
7495:           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*8 + r;
7496:           remotePointsNew[m].rank  = rrank;
7497:         }
7498:         for (r = 0; r < 8; ++r, ++m) {
7499:           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*4     + (p  - cStart)*8     + r;
7500:           remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*4 + (rp - rcStart[n])*8 + r;
7501:           remotePointsNew[m].rank  = rrank;
7502:         }
7503:         localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (fMax                              - fStart)*3     + (p  - cStart)*1     + 0;
7504:         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;
7505:         remotePointsNew[m].rank  = rrank;
7506:         ++m;
7507:       } else if ((p >= cMax) && (p < cEnd)) {
7508:         /* Hybrid cells add new cells and faces */
7509:         for (r = 0; r < 4; ++r, ++m) {
7510:           localPointsNew[m]        = cStartNew     + (cMax                            - cStart)*8     + (p  - cMax)*4                            + r;
7511:           remotePointsNew[m].index = rcStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth] - rcStart[n])*8 + (rp - rdepthMaxOld[n*(depth+1)+depth])*4 + r;
7512:           remotePointsNew[m].rank  = rrank;
7513:         }
7514:         for (r = 0; r < 3; ++r, ++m) {
7515:           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*4     + (cMax                            - cStart)*8     + (fEnd                                          - fMax)*2                              + (p  - cMax)*3                            + r;
7516:           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;
7517:           remotePointsNew[m].rank  = rrank;
7518:         }
7519:       }
7520:       break;
7521:     case REFINER_SIMPLEX_TO_HEX_3D:
7522:       if ((p >= vStart) && (p < vEnd)) {
7523:         /* Interior vertices stay the same */
7524:         localPointsNew[m]        = vStartNew     + (p  - vStart);
7525:         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
7526:         remotePointsNew[m].rank  = rrank;
7527:         ++m;
7528:       } else if ((p >= eStart) && (p < eEnd)) {
7529:         /* Interior edges add new edges and vertex */
7530:         for (r = 0; r < 2; ++r, ++m) {
7531:           localPointsNew[m]        = eStartNew     + (p  - eStart)*2     + r;
7532:           remotePointsNew[m].index = reStartNew[n] + (rp - reStart[n])*2 + r;
7533:           remotePointsNew[m].rank  = rrank;
7534:         }
7535:         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - eStart);
7536:         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - reStart[n]);
7537:         remotePointsNew[m].rank  = rrank;
7538:         ++m;
7539:       } else if ((p >= fStart) && (p < fEnd)) {
7540:         /* Interior faces add new faces, edges and a vertex */
7541:         for (r = 0; r < 3; ++r, ++m) {
7542:           localPointsNew[m]        = fStartNew     + (p  - fStart)*3     + r;
7543:           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*3 + r;
7544:           remotePointsNew[m].rank  = rrank;
7545:         }
7546:         for (r = 0; r < 3; ++r, ++m) {
7547:           localPointsNew[m]        = eStartNew     + (eEnd - eStart)*2                + (p  - fStart)*3     + r;
7548:           remotePointsNew[m].index = reStartNew[n] + (rdepthSizeOld[n*(depth+1)+1])*2 + (rp - rfStart[n])*3 + r;
7549:           remotePointsNew[m].rank  = rrank;
7550:         }
7551:         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (eEnd - eStart)              + (p - fStart);
7552:         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + rdepthSizeOld[n*(depth+1)+1] + (rp - rfStart[n]);
7553:         remotePointsNew[m].rank  = rrank;
7554:         ++m;
7555:       } else if ((p >= cStart) && (p < cEnd)) {
7556:         /* Interior cells add new cells, faces, edges, and a vertex */
7557:         for (r = 0; r < 4; ++r, ++m) {
7558:           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
7559:           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
7560:           remotePointsNew[m].rank  = rrank;
7561:         }
7562:         for (r = 0; r < 6; ++r, ++m) {
7563:           localPointsNew[m]        = fStartNew     + (fEnd - fStart)*3                    + (p  - cStart)*6     + r;
7564:           remotePointsNew[m].index = rfStartNew[n] + rdepthSizeOld[n*(depth+1)+depth-1]*3 + (rp - rcStart[n])*6 + r;
7565:           remotePointsNew[m].rank  = rrank;
7566:         }
7567:         for (r = 0; r < 4; ++r, ++m) {
7568:           localPointsNew[m]        = eStartNew     + (eEnd - eStart)*2              + (fEnd - fStart)*3                    + (p  - cStart)*4 + r;
7569:           remotePointsNew[m].index = reStartNew[n] + rdepthSizeOld[n*(depth+1)+1]*2 + rdepthSizeOld[n*(depth+1)+depth-1]*3 + (rp - rcStart[n])*4 + r;
7570:           remotePointsNew[m].rank  = rrank;
7571:         }
7572:         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (eEnd - eStart)              + (fEnd - fStart)                    + (p - cStart);
7573:         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + rdepthSizeOld[n*(depth+1)+1] + rdepthSizeOld[n*(depth+1)+depth-1] + (rp - rcStart[n]);
7574:         remotePointsNew[m].rank  = rrank;
7575:         ++m;
7576:       }
7577:       break;
7578:     case REFINER_HEX_3D:
7579:     case REFINER_HYBRID_HEX_3D:
7580:       if ((p >= vStart) && (p < vEnd)) {
7581:         /* Interior vertices stay the same */
7582:         localPointsNew[m]        = vStartNew     + (p  - vStart);
7583:         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
7584:         remotePointsNew[m].rank  = rrank;
7585:         ++m;
7586:       } else if ((p >= eStart) && (p < eMax)) {
7587:         /* Interior edges add new edges and vertex */
7588:         for (r = 0; r < 2; ++r, ++m) {
7589:           localPointsNew[m]        = eStartNew     + (p  - eStart)*2     + r;
7590:           remotePointsNew[m].index = reStartNew[n] + (rp - reStart[n])*2 + r;
7591:           remotePointsNew[m].rank  = rrank;
7592:         }
7593:         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - eStart);
7594:         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - reStart[n]);
7595:         remotePointsNew[m].rank  = rrank;
7596:         ++m;
7597:       } else if ((p >= eMax) && (p < eEnd)) {
7598:         /* Hybrid edges stay the same */
7599:         localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (fMax                              - fStart)*4     + (cMax                            - cStart)*6     + (p  - eMax);
7600:         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]);
7601:         remotePointsNew[m].rank  = rrank;
7602:         ++m;
7603:       } else if ((p >= fStart) && (p < fMax)) {
7604:         /* Interior faces add new faces, edges, and vertex */
7605:         for (r = 0; r < 4; ++r, ++m) {
7606:           localPointsNew[m]        = fStartNew     + (p  - fStart)*4     + r;
7607:           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*4 + r;
7608:           remotePointsNew[m].rank  = rrank;
7609:         }
7610:         for (r = 0; r < 4; ++r, ++m) {
7611:           localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (p  - fStart)*4     + r;
7612:           remotePointsNew[m].index = reStartNew[n] + (rdepthMaxOld[n*(depth+1)+1] - reStart[n])*2 + (rp - rfStart[n])*4 + r;
7613:           remotePointsNew[m].rank  = rrank;
7614:         }
7615:         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (eMax                        - eStart)     + (p  - fStart);
7616:         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rdepthMaxOld[n*(depth+1)+1] - reStart[n]) + (rp - rfStart[n]);
7617:         remotePointsNew[m].rank  = rrank;
7618:         ++m;
7619:       } else if ((p >= fMax) && (p < fEnd)) {
7620:         /* Hybrid faces add new faces and edges */
7621:         for (r = 0; r < 2; ++r, ++m) {
7622:           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*4     + (cMax                            - cStart)*12     + (p  - fMax)*2                              + r;
7623:           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;
7624:           remotePointsNew[m].rank  = rrank;
7625:         }
7626:         localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (fMax                              - fStart)*4     + (cMax                            - cStart)*6     + (eEnd                                    - eMax)                        + (p  - fMax);
7627:         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]);
7628:         remotePointsNew[m].rank  = rrank;
7629:         ++m;
7630:       } else if ((p >= cStart) && (p < cMax)) {
7631:         /* Interior cells add new cells, faces, edges, and vertex */
7632:         for (r = 0; r < 8; ++r, ++m) {
7633:           localPointsNew[m]        = cStartNew     + (p  - cStart)*8     + r;
7634:           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*8 + r;
7635:           remotePointsNew[m].rank  = rrank;
7636:         }
7637:         for (r = 0; r < 12; ++r, ++m) {
7638:           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*4     + (p  - cStart)*12     + r;
7639:           remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*4 + (rp - rcStart[n])*12 + r;
7640:           remotePointsNew[m].rank  = rrank;
7641:         }
7642:         for (r = 0; r < 6; ++r, ++m) {
7643:           localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (fMax                              - fStart)*4     + (p  - cStart)*6     + r;
7644:           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;
7645:           remotePointsNew[m].rank  = rrank;
7646:         }
7647:         for (r = 0; r < 1; ++r, ++m) {
7648:           localPointsNew[m]        = vStartNew     + (eMax                        - eStart)     + (fMax                              - fStart)     + (p  - cStart)     + r;
7649:           remotePointsNew[m].index = rvStartNew[n] + (rdepthMaxOld[n*(depth+1)+1] - reStart[n]) + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n]) + (rp - rcStart[n]) + r;
7650:           remotePointsNew[m].rank  = rrank;
7651:         }
7652:       } else if ((p >= cMax) && (p < cEnd)) {
7653:         /* Hybrid cells add new cells, faces, and edges */
7654:         for (r = 0; r < 4; ++r, ++m) {
7655:           localPointsNew[m]        = cStartNew     + (cMax                            - cStart)*8     + (p  - cMax)*4                            + r;
7656:           remotePointsNew[m].index = rcStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth] - rcStart[n])*8 + (rp - rdepthMaxOld[n*(depth+1)+depth])*4 + r;
7657:           remotePointsNew[m].rank  = rrank;
7658:         }
7659:         for (r = 0; r < 4; ++r, ++m) {
7660:           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*4     + (cMax                            - cStart)*12     + (fEnd                                          - fMax)*2                              + (p  - cMax)*4                            + r;
7661:           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;
7662:           remotePointsNew[m].rank  = rrank;
7663:         }
7664:         localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (fMax                              - fStart)*4     + (cMax                            - cStart)*6     + (eEnd                                    - eMax)                        + (fEnd                                          - fMax)                              + (p  - cMax);
7665:         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]);
7666:         remotePointsNew[m].rank  = rrank;
7667:         ++m;
7668:       }
7669:       break;
7670:     default:
7671:       SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
7672:     }
7673:   }
7674:   if (m != numLeavesNew) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Number of leaf point %d should be %d", m, numLeavesNew);
7675:   ISRestoreIndices(processRanks, &neighbors);
7676:   ISDestroy(&processRanks);
7677:   {
7678:     PetscSFNode *rp, *rtmp;
7679:     PetscInt    *lp, *idx, *ltmp, i;

7681:     /* SF needs sorted leaves to correct calculate Gather */
7682:     PetscMalloc1(numLeavesNew,&idx);
7683:     PetscMalloc1(numLeavesNew, &lp);
7684:     PetscMalloc1(numLeavesNew, &rp);
7685:     for (i = 0; i < numLeavesNew; ++i) {
7686:       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);
7687:       idx[i] = i;
7688:     }
7689:     PetscSortIntWithPermutation(numLeavesNew, localPointsNew, idx);
7690:     for (i = 0; i < numLeavesNew; ++i) {
7691:       lp[i] = localPointsNew[idx[i]];
7692:       rp[i] = remotePointsNew[idx[i]];
7693:     }
7694:     ltmp            = localPointsNew;
7695:     localPointsNew  = lp;
7696:     rtmp            = remotePointsNew;
7697:     remotePointsNew = rp;
7698:     PetscFree(idx);
7699:     PetscFree(ltmp);
7700:     PetscFree(rtmp);
7701:   }
7702:   PetscSFSetGraph(sfNew, pEndNew-pStartNew, numLeavesNew, localPointsNew, PETSC_OWN_POINTER, remotePointsNew, PETSC_OWN_POINTER);
7703:   PetscFree5(rdepthSize,rvStartNew,reStartNew,rfStartNew,rcStartNew);
7704:   PetscFree7(depthSizeOld,rdepthSizeOld,rdepthMaxOld,rvStart,reStart,rfStart,rcStart);
7705:   return(0);
7706: }

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

7716:   DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);
7717:   DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);
7718:   DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);
7719:   DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);
7720:   DMPlexGetDepth(dm, &depth);
7721:   if (refiner) {GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);}
7722:   DMGetNumLabels(dm, &numLabels);
7723:   DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);
7724:   switch (refiner) {
7725:   case REFINER_NOOP:
7726:   case REFINER_SIMPLEX_1D:
7727:   case REFINER_SIMPLEX_2D:
7728:   case REFINER_SIMPLEX_TO_HEX_2D:
7729:   case REFINER_HEX_2D:
7730:   case REFINER_SIMPLEX_3D:
7731:   case REFINER_HEX_3D:
7732:   case REFINER_SIMPLEX_TO_HEX_3D:
7733:     break;
7734:   case REFINER_HYBRID_SIMPLEX_3D:
7735:   case REFINER_HYBRID_HEX_3D:
7736:     if (eMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No edge maximum specified in hybrid mesh");
7737:   case REFINER_HYBRID_SIMPLEX_2D:
7738:   case REFINER_HYBRID_HEX_2D:
7739:     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
7740:     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
7741:     break;
7742:   default:
7743:     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
7744:   }
7745:   for (l = 0; l < numLabels; ++l) {
7746:     DMLabel         label, labelNew;
7747:     const char     *lname;
7748:     PetscBool       isDepth;
7749:     IS              valueIS;
7750:     const PetscInt *values;
7751:     PetscInt        defVal;
7752:     PetscInt        numValues, val;

7754:     DMGetLabelName(dm, l, &lname);
7755:     PetscStrcmp(lname, "depth", &isDepth);
7756:     if (isDepth) continue;
7757:     DMCreateLabel(rdm, lname);
7758:     DMGetLabel(dm, lname, &label);
7759:     DMGetLabel(rdm, lname, &labelNew);
7760:     DMLabelGetDefaultValue(label,&defVal);
7761:     DMLabelSetDefaultValue(labelNew,defVal);
7762:     DMLabelGetValueIS(label, &valueIS);
7763:     ISGetLocalSize(valueIS, &numValues);
7764:     ISGetIndices(valueIS, &values);
7765:     for (val = 0; val < numValues; ++val) {
7766:       IS              pointIS;
7767:       const PetscInt *points;
7768:       PetscInt        numPoints, n;

7770:       DMLabelGetStratumIS(label, values[val], &pointIS);
7771:       ISGetLocalSize(pointIS, &numPoints);
7772:       ISGetIndices(pointIS, &points);
7773:       /* Ensure refined label is created with same number of strata as
7774:        * original (even if no entries here). */
7775:       DMLabelAddStratum(labelNew, values[val]);
7776:       for (n = 0; n < numPoints; ++n) {
7777:         const PetscInt p = points[n];
7778:         switch (refiner) {
7779:         case REFINER_SIMPLEX_1D:
7780:           if ((p >= vStart) && (p < vEnd)) {
7781:             /* Old vertices stay the same */
7782:             newp = vStartNew + (p - vStart);
7783:             DMLabelSetValue(labelNew, newp, values[val]);
7784:           } else if ((p >= cStart) && (p < cEnd)) {
7785:             /* Old cells add new cells and vertex */
7786:             newp = vStartNew + (vEnd - vStart) + (p - cStart);
7787:             DMLabelSetValue(labelNew, newp, values[val]);
7788:             for (r = 0; r < 2; ++r) {
7789:               newp = cStartNew + (p - cStart)*2 + r;
7790:               DMLabelSetValue(labelNew, newp, values[val]);
7791:             }
7792:           }
7793:           break;
7794:         case REFINER_SIMPLEX_2D:
7795:           if ((p >= vStart) && (p < vEnd)) {
7796:             /* Old vertices stay the same */
7797:             newp = vStartNew + (p - vStart);
7798:             DMLabelSetValue(labelNew, newp, values[val]);
7799:           } else if ((p >= fStart) && (p < fEnd)) {
7800:             /* Old faces add new faces and vertex */
7801:             newp = vStartNew + (vEnd - vStart) + (p - fStart);
7802:             DMLabelSetValue(labelNew, newp, values[val]);
7803:             for (r = 0; r < 2; ++r) {
7804:               newp = fStartNew + (p - fStart)*2 + r;
7805:               DMLabelSetValue(labelNew, newp, values[val]);
7806:             }
7807:           } else if ((p >= cStart) && (p < cEnd)) {
7808:             /* Old cells add new cells and interior faces */
7809:             for (r = 0; r < 4; ++r) {
7810:               newp = cStartNew + (p - cStart)*4 + r;
7811:               DMLabelSetValue(labelNew, newp, values[val]);
7812:             }
7813:             for (r = 0; r < 3; ++r) {
7814:               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*3 + r;
7815:               DMLabelSetValue(labelNew, newp, values[val]);
7816:             }
7817:           }
7818:           break;
7819:         case REFINER_SIMPLEX_TO_HEX_2D:
7820:           if ((p >= vStart) && (p < vEnd)) {
7821:             /* Old vertices stay the same */
7822:             newp = vStartNew + (p - vStart);
7823:             DMLabelSetValue(labelNew, newp, values[val]);
7824:           } else if ((p >= fStart) && (p < fEnd)) {
7825:             /* Old faces add new faces and vertex */
7826:             newp = vStartNew + (vEnd - vStart) + (p - fStart);
7827:             DMLabelSetValue(labelNew, newp, values[val]);
7828:             for (r = 0; r < 2; ++r) {
7829:               newp = fStartNew + (p - fStart)*2 + r;
7830:               DMLabelSetValue(labelNew, newp, values[val]);
7831:             }
7832:           } else if ((p >= cStart) && (p < cEnd)) {
7833:             /* Old cells add new cells, interior faces, and a vertex */
7834:             for (r = 0; r < 3; ++r) {
7835:               newp = cStartNew + (p - cStart)*3 + r;
7836:               DMLabelSetValue(labelNew, newp, values[val]);
7837:             }
7838:             for (r = 0; r < 3; ++r) {
7839:               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*3 + r;
7840:               DMLabelSetValue(labelNew, newp, values[val]);
7841:             }
7842:             newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + p;
7843:             DMLabelSetValue(labelNew, newp, values[val]);
7844:           }
7845:           break;
7846:         case REFINER_HEX_2D:
7847:           if ((p >= vStart) && (p < vEnd)) {
7848:             /* Old vertices stay the same */
7849:             newp = vStartNew + (p - vStart);
7850:             DMLabelSetValue(labelNew, newp, values[val]);
7851:           } else if ((p >= fStart) && (p < fEnd)) {
7852:             /* Old faces add new faces and vertex */
7853:             newp = vStartNew + (vEnd - vStart) + (p - fStart);
7854:             DMLabelSetValue(labelNew, newp, values[val]);
7855:             for (r = 0; r < 2; ++r) {
7856:               newp = fStartNew + (p - fStart)*2 + r;
7857:               DMLabelSetValue(labelNew, newp, values[val]);
7858:             }
7859:           } else if ((p >= cStart) && (p < cEnd)) {
7860:             /* Old cells add new cells and interior faces and vertex */
7861:             for (r = 0; r < 4; ++r) {
7862:               newp = cStartNew + (p - cStart)*4 + r;
7863:               DMLabelSetValue(labelNew, newp, values[val]);
7864:             }
7865:             for (r = 0; r < 4; ++r) {
7866:               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*4 + r;
7867:               DMLabelSetValue(labelNew, newp, values[val]);
7868:             }
7869:             newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (p - cStart);
7870:             DMLabelSetValue(labelNew, newp, values[val]);
7871:           }
7872:           break;
7873:         case REFINER_HYBRID_SIMPLEX_2D:
7874:           if ((p >= vStart) && (p < vEnd)) {
7875:             /* Old vertices stay the same */
7876:             newp = vStartNew + (p - vStart);
7877:             DMLabelSetValue(labelNew, newp, values[val]);
7878:           } else if ((p >= fStart) && (p < fMax)) {
7879:             /* Old interior faces add new faces and vertex */
7880:             newp = vStartNew + (vEnd - vStart) + (p - fStart);
7881:             DMLabelSetValue(labelNew, newp, values[val]);
7882:             for (r = 0; r < 2; ++r) {
7883:               newp = fStartNew + (p - fStart)*2 + r;
7884:               DMLabelSetValue(labelNew, newp, values[val]);
7885:             }
7886:           } else if ((p >= fMax) && (p < fEnd)) {
7887:             /* Old hybrid faces stay the same */
7888:             newp = fStartNew + (fMax - fStart)*2 + (p - fMax);
7889:             DMLabelSetValue(labelNew, newp, values[val]);
7890:           } else if ((p >= cStart) && (p < cMax)) {
7891:             /* Old interior cells add new cells and interior faces */
7892:             for (r = 0; r < 4; ++r) {
7893:               newp = cStartNew + (p - cStart)*4 + r;
7894:               DMLabelSetValue(labelNew, newp, values[val]);
7895:             }
7896:             for (r = 0; r < 3; ++r) {
7897:               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*3 + r;
7898:               DMLabelSetValue(labelNew, newp, values[val]);
7899:             }
7900:           } else if ((p >= cMax) && (p < cEnd)) {
7901:             /* Old hybrid cells add new cells and hybrid face */
7902:             for (r = 0; r < 2; ++r) {
7903:               newp = cStartNew + (cMax - cStart)*4 + (p - cMax)*2 + r;
7904:               DMLabelSetValue(labelNew, newp, values[val]);
7905:             }
7906:             newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (p - cMax);
7907:             DMLabelSetValue(labelNew, newp, values[val]);
7908:           }
7909:           break;
7910:         case REFINER_HYBRID_HEX_2D:
7911:           if ((p >= vStart) && (p < vEnd)) {
7912:             /* Old vertices stay the same */
7913:             newp = vStartNew + (p - vStart);
7914:             DMLabelSetValue(labelNew, newp, values[val]);
7915:           } else if ((p >= fStart) && (p < fMax)) {
7916:             /* Old interior faces add new faces and vertex */
7917:             newp = vStartNew + (vEnd - vStart) + (p - fStart);
7918:             DMLabelSetValue(labelNew, newp, values[val]);
7919:             for (r = 0; r < 2; ++r) {
7920:               newp = fStartNew + (p - fStart)*2 + r;
7921:               DMLabelSetValue(labelNew, newp, values[val]);
7922:             }
7923:           } else if ((p >= fMax) && (p < fEnd)) {
7924:             /* Old hybrid faces stay the same */
7925:             newp = fStartNew + (fMax - fStart)*2 + (p - fMax);
7926:             DMLabelSetValue(labelNew, newp, values[val]);
7927:           } else if ((p >= cStart) && (p < cMax)) {
7928:             /* Old interior cells add new cells, interior faces, and vertex */
7929:             for (r = 0; r < 4; ++r) {
7930:               newp = cStartNew + (p - cStart)*4 + r;
7931:               DMLabelSetValue(labelNew, newp, values[val]);
7932:             }
7933:             for (r = 0; r < 4; ++r) {
7934:               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*4 + r;
7935:               DMLabelSetValue(labelNew, newp, values[val]);
7936:             }
7937:             newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (p - cStart);
7938:             DMLabelSetValue(labelNew, newp, values[val]);
7939:           } else if ((p >= cMax) && (p < cEnd)) {
7940:             /* Old hybrid cells add new cells and hybrid face */
7941:             for (r = 0; r < 2; ++r) {
7942:               newp = cStartNew + (cMax - cStart)*4 + (p - cMax)*2 + r;
7943:               DMLabelSetValue(labelNew, newp, values[val]);
7944:             }
7945:             newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*4 + (p - cMax);
7946:             DMLabelSetValue(labelNew, newp, values[val]);
7947:           }
7948:           break;
7949:         case REFINER_SIMPLEX_3D:
7950:           if ((p >= vStart) && (p < vEnd)) {
7951:             /* Old vertices stay the same */
7952:             newp = vStartNew + (p - vStart);
7953:             DMLabelSetValue(labelNew, newp, values[val]);
7954:           } else if ((p >= eStart) && (p < eEnd)) {
7955:             /* Old edges add new edges and vertex */
7956:             for (r = 0; r < 2; ++r) {
7957:               newp = eStartNew + (p - eStart)*2 + r;
7958:               DMLabelSetValue(labelNew, newp, values[val]);
7959:             }
7960:             newp = vStartNew + (vEnd - vStart) + (p - eStart);
7961:             DMLabelSetValue(labelNew, newp, values[val]);
7962:           } else if ((p >= fStart) && (p < fEnd)) {
7963:             /* Old faces add new faces and edges */
7964:             for (r = 0; r < 4; ++r) {
7965:               newp = fStartNew + (p - fStart)*4 + r;
7966:               DMLabelSetValue(labelNew, newp, values[val]);
7967:             }
7968:             for (r = 0; r < 3; ++r) {
7969:               newp = eStartNew + (eEnd - eStart)*2 + (p - fStart)*3 + r;
7970:               DMLabelSetValue(labelNew, newp, values[val]);
7971:             }
7972:           } else if ((p >= cStart) && (p < cEnd)) {
7973:             /* Old cells add new cells and interior faces and edges */
7974:             for (r = 0; r < 8; ++r) {
7975:               newp = cStartNew + (p - cStart)*8 + r;
7976:               DMLabelSetValue(labelNew, newp, values[val]);
7977:             }
7978:             for (r = 0; r < 8; ++r) {
7979:               newp = fStartNew + (fEnd - fStart)*4 + (p - cStart)*8 + r;
7980:               DMLabelSetValue(labelNew, newp, values[val]);
7981:             }
7982:             for (r = 0; r < 1; ++r) {
7983:               newp = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (p - cStart)*1 + r;
7984:               DMLabelSetValue(labelNew, newp, values[val]);
7985:             }
7986:           }
7987:           break;
7988:         case REFINER_SIMPLEX_TO_HEX_3D:
7989:           if ((p >= vStart) && (p < vEnd)) {
7990:             /* Old vertices stay the same */
7991:             newp = vStartNew + (p - vStart);
7992:             DMLabelSetValue(labelNew, newp, values[val]);
7993:           } else if ((p >= eStart) && (p < eEnd)) {
7994:             /* Old edges add new edges and vertex */
7995:             for (r = 0; r < 2; ++r) {
7996:               newp = eStartNew + (p - eStart)*2 + r;
7997:               DMLabelSetValue(labelNew, newp, values[val]);
7998:             }
7999:             newp = vStartNew + (vEnd - vStart) + (p - eStart);
8000:             DMLabelSetValue(labelNew, newp, values[val]);
8001:           } else if ((p >= fStart) && (p < fEnd)) {
8002:             /* Old faces add new faces, edges and a vertex */
8003:             for (r = 0; r < 3; ++r) {
8004:               newp = fStartNew + (p - fStart)*3 + r;
8005:               DMLabelSetValue(labelNew, newp, values[val]);
8006:             }
8007:             for (r = 0; r < 3; ++r) {
8008:               newp = eStartNew + (eEnd - eStart)*2 + (p - fStart)*3 + r;
8009:               DMLabelSetValue(labelNew, newp, values[val]);
8010:             }
8011:           } else if ((p >= cStart) && (p < cEnd)) {
8012:             /* Old cells add new cells and interior faces and edges and a vertex */
8013:             for (r = 0; r < 4; ++r) {
8014:               newp = cStartNew + (p - cStart)*4 + r;
8015:               DMLabelSetValue(labelNew, newp, values[val]);
8016:             }
8017:             for (r = 0; r < 6; ++r) {
8018:               newp = fStartNew + (fEnd - fStart)*3 + (p - cStart)*6 + r;
8019:               DMLabelSetValue(labelNew, newp, values[val]);
8020:             }
8021:             for (r = 0; r < 4; ++r) {
8022:               newp = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (p - cStart)*4 + r;
8023:               DMLabelSetValue(labelNew, newp, values[val]);
8024:             }
8025:             newp = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (fEnd - fStart) + p - cStart;
8026:             DMLabelSetValue(labelNew, newp, values[val]);
8027:           }
8028:           break;
8029:         case REFINER_HYBRID_SIMPLEX_3D:
8030:           if ((p >= vStart) && (p < vEnd)) {
8031:             /* Interior vertices stay the same */
8032:             newp = vStartNew + (p - vStart);
8033:             DMLabelSetValue(labelNew, newp, values[val]);
8034:           } else if ((p >= eStart) && (p < eMax)) {
8035:             /* Interior edges add new edges and vertex */
8036:             for (r = 0; r < 2; ++r) {
8037:               newp = eStartNew + (p - eStart)*2 + r;
8038:               DMLabelSetValue(labelNew, newp, values[val]);
8039:             }
8040:             newp = vStartNew + (vEnd - vStart) + (p - eStart);
8041:             DMLabelSetValue(labelNew, newp, values[val]);
8042:           } else if ((p >= eMax) && (p < eEnd)) {
8043:             /* Hybrid edges stay the same */
8044:             newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (p - eMax);
8045:             DMLabelSetValue(labelNew, newp, values[val]);
8046:           } else if ((p >= fStart) && (p < fMax)) {
8047:             /* Interior faces add new faces and edges */
8048:             for (r = 0; r < 4; ++r) {
8049:               newp = fStartNew + (p - fStart)*4 + r;
8050:               DMLabelSetValue(labelNew, newp, values[val]);
8051:             }
8052:             for (r = 0; r < 3; ++r) {
8053:               newp = eStartNew + (eMax - eStart)*2 + (p - fStart)*3 + r;
8054:               DMLabelSetValue(labelNew, newp, values[val]);
8055:             }
8056:           } else if ((p >= fMax) && (p < fEnd)) {
8057:             /* Hybrid faces add new faces and edges */
8058:             for (r = 0; r < 2; ++r) {
8059:               newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (p - fMax)*2 + r;
8060:               DMLabelSetValue(labelNew, newp, values[val]);
8061:             }
8062:             newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (p - fMax);
8063:             DMLabelSetValue(labelNew, newp, values[val]);
8064:           } else if ((p >= cStart) && (p < cMax)) {
8065:             /* Interior cells add new cells, faces, and edges */
8066:             for (r = 0; r < 8; ++r) {
8067:               newp = cStartNew + (p - cStart)*8 + r;
8068:               DMLabelSetValue(labelNew, newp, values[val]);
8069:             }
8070:             for (r = 0; r < 8; ++r) {
8071:               newp = fStartNew + (fMax - fStart)*4 + (p - cStart)*8 + r;
8072:               DMLabelSetValue(labelNew, newp, values[val]);
8073:             }
8074:             newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (p - cStart);
8075:             DMLabelSetValue(labelNew, newp, values[val]);
8076:           } else if ((p >= cMax) && (p < cEnd)) {
8077:             /* Hybrid cells add new cells and faces */
8078:             for (r = 0; r < 4; ++r) {
8079:               newp = cStartNew + (cMax - cStart)*8 + (p - cMax)*4 + r;
8080:               DMLabelSetValue(labelNew, newp, values[val]);
8081:             }
8082:             for (r = 0; r < 3; ++r) {
8083:               newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (p - cMax)*3 + r;
8084:               DMLabelSetValue(labelNew, newp, values[val]);
8085:             }
8086:           }
8087:           break;
8088:         case REFINER_HEX_3D:
8089:           if ((p >= vStart) && (p < vEnd)) {
8090:             /* Old vertices stay the same */
8091:             newp = vStartNew + (p - vStart);
8092:             DMLabelSetValue(labelNew, newp, values[val]);
8093:           } else if ((p >= eStart) && (p < eEnd)) {
8094:             /* Old edges add new edges and vertex */
8095:             for (r = 0; r < 2; ++r) {
8096:               newp = eStartNew + (p - eStart)*2 + r;
8097:               DMLabelSetValue(labelNew, newp, values[val]);
8098:             }
8099:             newp = vStartNew + (vEnd - vStart) + (p - eStart);
8100:             DMLabelSetValue(labelNew, newp, values[val]);
8101:           } else if ((p >= fStart) && (p < fEnd)) {
8102:             /* Old faces add new faces, edges, and vertex */
8103:             for (r = 0; r < 4; ++r) {
8104:               newp = fStartNew + (p - fStart)*4 + r;
8105:               DMLabelSetValue(labelNew, newp, values[val]);
8106:             }
8107:             for (r = 0; r < 4; ++r) {
8108:               newp = eStartNew + (eEnd - eStart)*2 + (p - fStart)*4 + r;
8109:               DMLabelSetValue(labelNew, newp, values[val]);
8110:             }
8111:             newp = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (p - fStart);
8112:             DMLabelSetValue(labelNew, newp, values[val]);
8113:           } else if ((p >= cStart) && (p < cEnd)) {
8114:             /* Old cells add new cells, faces, edges, and vertex */
8115:             for (r = 0; r < 8; ++r) {
8116:               newp = cStartNew + (p - cStart)*8 + r;
8117:               DMLabelSetValue(labelNew, newp, values[val]);
8118:             }
8119:             for (r = 0; r < 12; ++r) {
8120:               newp = fStartNew + (fEnd - fStart)*4 + (p - cStart)*12 + r;
8121:               DMLabelSetValue(labelNew, newp, values[val]);
8122:             }
8123:             for (r = 0; r < 6; ++r) {
8124:               newp = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*4 + (p - cStart)*6 + r;
8125:               DMLabelSetValue(labelNew, newp, values[val]);
8126:             }
8127:             newp = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (fEnd - fStart) + (p - cStart);
8128:             DMLabelSetValue(labelNew, newp, values[val]);
8129:           }
8130:           break;
8131:         case REFINER_HYBRID_HEX_3D:
8132:           if ((p >= vStart) && (p < vEnd)) {
8133:             /* Interior vertices stay the same */
8134:             newp = vStartNew + (p - vStart);
8135:             DMLabelSetValue(labelNew, newp, values[val]);
8136:           } else if ((p >= eStart) && (p < eMax)) {
8137:             /* Interior edges add new edges and vertex */
8138:             for (r = 0; r < 2; ++r) {
8139:               newp = eStartNew + (p - eStart)*2 + r;
8140:               DMLabelSetValue(labelNew, newp, values[val]);
8141:             }
8142:             newp = vStartNew + (vEnd - vStart) + (p - eStart);
8143:             DMLabelSetValue(labelNew, newp, values[val]);
8144:           } else if ((p >= eMax) && (p < eEnd)) {
8145:             /* Hybrid edges stay the same */
8146:             newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (p - eMax);
8147:             DMLabelSetValue(labelNew, newp, values[val]);
8148:           } else if ((p >= fStart) && (p < fMax)) {
8149:             /* Interior faces add new faces, edges, and vertex */
8150:             for (r = 0; r < 4; ++r) {
8151:               newp = fStartNew + (p - fStart)*4 + r;
8152:               DMLabelSetValue(labelNew, newp, values[val]);
8153:             }
8154:             for (r = 0; r < 4; ++r) {
8155:               newp = eStartNew + (eMax - eStart)*2 + (p - fStart)*4 + r;
8156:               DMLabelSetValue(labelNew, newp, values[val]);
8157:             }
8158:             newp = vStartNew + (vEnd - vStart) + (eMax - eStart) + (p - fStart);
8159:             DMLabelSetValue(labelNew, newp, values[val]);
8160:           } else if ((p >= fMax) && (p < fEnd)) {
8161:             /* Hybrid faces add new faces and edges */
8162:             for (r = 0; r < 2; ++r) {
8163:               newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (p - fMax)*2 + r;
8164:               DMLabelSetValue(labelNew, newp, values[val]);
8165:             }
8166:             newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (p - fMax);
8167:             DMLabelSetValue(labelNew, newp, values[val]);
8168:           } else if ((p >= cStart) && (p < cMax)) {
8169:             /* Interior cells add new cells, faces, edges, and vertex */
8170:             for (r = 0; r < 8; ++r) {
8171:               newp = cStartNew + (p - cStart)*8 + r;
8172:               DMLabelSetValue(labelNew, newp, values[val]);
8173:             }
8174:             for (r = 0; r < 12; ++r) {
8175:               newp = fStartNew + (fMax - fStart)*4 + (p - cStart)*12 + r;
8176:               DMLabelSetValue(labelNew, newp, values[val]);
8177:             }
8178:             for (r = 0; r < 6; ++r) {
8179:               newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (p - cStart)*6 + r;
8180:               DMLabelSetValue(labelNew, newp, values[val]);
8181:             }
8182:             newp = vStartNew + (vEnd - vStart) + (eMax - eStart) + (fMax - fStart) + (p - cStart);
8183:             DMLabelSetValue(labelNew, newp, values[val]);
8184:           } else if ((p >= cMax) && (p < cEnd)) {
8185:             /* Hybrid cells add new cells, faces, and edges */
8186:             for (r = 0; r < 4; ++r) {
8187:               newp = cStartNew + (cMax - cStart)*8 + (p - cMax)*4 + r;
8188:               DMLabelSetValue(labelNew, newp, values[val]);
8189:             }
8190:             for (r = 0; r < 4; ++r) {
8191:               newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd - fMax)*2 + (p - cMax)*4 + r;
8192:               DMLabelSetValue(labelNew, newp, values[val]);
8193:             }
8194:             newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (fEnd - fMax) + (p - cMax);
8195:             DMLabelSetValue(labelNew, newp, values[val]);
8196:           }
8197:           break;
8198:         default:
8199:           SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
8200:         }
8201:       }
8202:       ISRestoreIndices(pointIS, &points);
8203:       ISDestroy(&pointIS);
8204:     }
8205:     ISRestoreIndices(valueIS, &values);
8206:     ISDestroy(&valueIS);
8207:     if (0) {
8208:       DMLabelView(labelNew, PETSC_VIEWER_STDOUT_WORLD);
8209:     }
8210:   }
8211:   return(0);
8212: }

8214: /* This will only work for interpolated meshes */
8215: PetscErrorCode DMPlexRefineUniform_Internal(DM dm, CellRefiner cellRefiner, DM *dmRefined)
8216: {
8217:   DM             rdm;
8218:   PetscInt      *depthSize;
8219:   PetscInt       dim, depth = 0, d, pStart = 0, pEnd = 0;

8223:   DMCreate(PetscObjectComm((PetscObject)dm), &rdm);
8224:   DMSetType(rdm, DMPLEX);
8225:   DMGetDimension(dm, &dim);
8226:   DMSetDimension(rdm, dim);
8227:   /* Calculate number of new points of each depth */
8228:   DMPlexGetDepth(dm, &depth);
8229:   if (depth >= 0 && dim != depth) SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "Mesh must be interpolated for regular refinement");
8230:   PetscMalloc1(depth+1, &depthSize);
8231:   PetscMemzero(depthSize, (depth+1) * sizeof(PetscInt));
8232:   CellRefinerGetSizes(cellRefiner, dm, depthSize);
8233:   /* Step 1: Set chart */
8234:   for (d = 0; d <= depth; ++d) pEnd += depthSize[d];
8235:   DMPlexSetChart(rdm, pStart, pEnd);
8236:   /* Step 2: Set cone/support sizes */
8237:   CellRefinerSetConeSizes(cellRefiner, dm, depthSize, rdm);
8238:   /* Step 3: Setup refined DM */
8239:   DMSetUp(rdm);
8240:   /* Step 4: Set cones and supports */
8241:   CellRefinerSetCones(cellRefiner, dm, depthSize, rdm);
8242:   /* Step 5: Stratify */
8243:   DMPlexStratify(rdm);
8244:   /* Step 6: Create pointSF */
8245:   CellRefinerCreateSF(cellRefiner, dm, depthSize, rdm);
8246:   /* Step 7: Create labels */
8247:   CellRefinerCreateLabels(cellRefiner, dm, depthSize, rdm);
8248:   /* Step 8: Set coordinates */
8249:   CellRefinerSetCoordinates(cellRefiner, dm, depthSize, rdm);
8250:   PetscFree(depthSize);

8252:   *dmRefined = rdm;
8253:   return(0);
8254: }

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

8259:   Input Parameter:
8260: . dm - The coarse DM

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

8265:   Level: developer

8267: .seealso: DMRefine(), DMPlexSetRefinementUniform(), DMPlexCreateSubpointIS()
8268: @*/
8269: PetscErrorCode DMPlexCreateCoarsePointIS(DM dm, IS *fpointIS)
8270: {
8271:   CellRefiner    cellRefiner;
8272:   PetscInt      *depthSize, *fpoints;
8273:   PetscInt       cStartNew = 0, vStartNew = 0, fStartNew = 0, eStartNew = 0;
8274:   PetscInt       depth, pStart, pEnd, p, vStart, vEnd, v;

8278:   DMPlexGetDepth(dm, &depth);
8279:   DMPlexGetChart(dm, &pStart, &pEnd);
8280:   DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);
8281:   DMPlexGetCellRefiner_Internal(dm, &cellRefiner);
8282:   PetscMalloc1(depth+1, &depthSize);
8283:   CellRefinerGetSizes(cellRefiner, dm, depthSize);
8284:   if (cellRefiner) {GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);}
8285:   PetscMalloc1(pEnd-pStart,&fpoints);
8286:   for (p = 0; p < pEnd-pStart; ++p) fpoints[p] = -1;
8287:   switch (cellRefiner) {
8288:   case REFINER_SIMPLEX_1D:
8289:   case REFINER_SIMPLEX_2D:
8290:   case REFINER_HYBRID_SIMPLEX_2D:
8291:   case REFINER_HEX_2D:
8292:   case REFINER_HYBRID_HEX_2D:
8293:   case REFINER_SIMPLEX_3D:
8294:   case REFINER_HYBRID_SIMPLEX_3D:
8295:   case REFINER_HEX_3D:
8296:   case REFINER_HYBRID_HEX_3D:
8297:     for (v = vStart; v < vEnd; ++v) fpoints[v-pStart] = vStartNew + (v - vStart);
8298:     break;
8299:   default:
8300:     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", cellRefiner);
8301:   }
8302:   ISCreateGeneral(PETSC_COMM_SELF, pEnd-pStart, fpoints, PETSC_OWN_POINTER, fpointIS);
8303:   PetscFree(depthSize);
8304:   return(0);
8305: }

8307: /*@
8308:   DMPlexSetRefinementUniform - Set the flag for uniform refinement

8310:   Input Parameters:
8311: + dm - The DM
8312: - refinementUniform - The flag for uniform refinement

8314:   Level: developer

8316: .seealso: DMRefine(), DMPlexGetRefinementUniform(), DMPlexGetRefinementLimit(), DMPlexSetRefinementLimit()
8317: @*/
8318: PetscErrorCode DMPlexSetRefinementUniform(DM dm, PetscBool refinementUniform)
8319: {
8320:   DM_Plex *mesh = (DM_Plex*) dm->data;

8324:   mesh->refinementUniform = refinementUniform;
8325:   return(0);
8326: }

8328: /*@
8329:   DMPlexGetRefinementUniform - Retrieve the flag for uniform refinement

8331:   Input Parameter:
8332: . dm - The DM

8334:   Output Parameter:
8335: . refinementUniform - The flag for uniform refinement

8337:   Level: developer

8339: .seealso: DMRefine(), DMPlexSetRefinementUniform(), DMPlexGetRefinementLimit(), DMPlexSetRefinementLimit()
8340: @*/
8341: PetscErrorCode DMPlexGetRefinementUniform(DM dm, PetscBool *refinementUniform)
8342: {
8343:   DM_Plex *mesh = (DM_Plex*) dm->data;

8348:   *refinementUniform = mesh->refinementUniform;
8349:   return(0);
8350: }

8352: /*@
8353:   DMPlexSetRefinementLimit - Set the maximum cell volume for refinement

8355:   Input Parameters:
8356: + dm - The DM
8357: - refinementLimit - The maximum cell volume in the refined mesh

8359:   Level: developer

8361: .seealso: DMRefine(), DMPlexGetRefinementLimit(), DMPlexGetRefinementUniform(), DMPlexSetRefinementUniform()
8362: @*/
8363: PetscErrorCode DMPlexSetRefinementLimit(DM dm, PetscReal refinementLimit)
8364: {
8365:   DM_Plex *mesh = (DM_Plex*) dm->data;

8369:   mesh->refinementLimit = refinementLimit;
8370:   return(0);
8371: }

8373: /*@
8374:   DMPlexGetRefinementLimit - Retrieve the maximum cell volume for refinement

8376:   Input Parameter:
8377: . dm - The DM

8379:   Output Parameter:
8380: . refinementLimit - The maximum cell volume in the refined mesh

8382:   Level: developer

8384: .seealso: DMRefine(), DMPlexSetRefinementLimit(), DMPlexGetRefinementUniform(), DMPlexSetRefinementUniform()
8385: @*/
8386: PetscErrorCode DMPlexGetRefinementLimit(DM dm, PetscReal *refinementLimit)
8387: {
8388:   DM_Plex *mesh = (DM_Plex*) dm->data;

8393:   /* if (mesh->refinementLimit < 0) = getMaxVolume()/2.0; */
8394:   *refinementLimit = mesh->refinementLimit;
8395:   return(0);
8396: }

8398: /*@
8399:   DMPlexSetRefinementFunction - Set the function giving the maximum cell volume for refinement

8401:   Input Parameters:
8402: + dm - The DM
8403: - refinementFunc - Function giving the maximum cell volume in the refined mesh

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

8409:   Level: developer

8411: .seealso: DMRefine(), DMPlexGetRefinementFunction(), DMPlexGetRefinementUniform(), DMPlexSetRefinementUniform(), DMPlexGetRefinementLimit(), DMPlexSetRefinementLimit()
8412: @*/
8413: PetscErrorCode DMPlexSetRefinementFunction(DM dm, PetscErrorCode (*refinementFunc)(const PetscReal [], PetscReal *))
8414: {
8415:   DM_Plex *mesh = (DM_Plex*) dm->data;

8419:   mesh->refinementFunc = refinementFunc;
8420:   return(0);
8421: }

8423: /*@
8424:   DMPlexGetRefinementFunction - Get the function giving the maximum cell volume for refinement

8426:   Input Parameter:
8427: . dm - The DM

8429:   Output Parameter:
8430: . refinementFunc - Function giving the maximum cell volume in the refined mesh

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

8436:   Level: developer

8438: .seealso: DMRefine(), DMPlexSetRefinementFunction(), DMPlexGetRefinementUniform(), DMPlexSetRefinementUniform(), DMPlexGetRefinementLimit(), DMPlexSetRefinementLimit()
8439: @*/
8440: PetscErrorCode DMPlexGetRefinementFunction(DM dm, PetscErrorCode (**refinementFunc)(const PetscReal [], PetscReal *))
8441: {
8442:   DM_Plex *mesh = (DM_Plex*) dm->data;

8447:   *refinementFunc = mesh->refinementFunc;
8448:   return(0);
8449: }

8451: PetscErrorCode DMPlexGetCellRefiner_Internal(DM dm, CellRefiner *cellRefiner)
8452: {
8453:   PetscInt       dim, cStart, cEnd, coneSize, cMax, fMax;

8457:   DMGetDimension(dm, &dim);
8458:   DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);
8459:   if (cEnd <= cStart) {*cellRefiner = REFINER_NOOP; return(0);}
8460:   DMPlexGetConeSize(dm, cStart, &coneSize);
8461:   DMPlexGetHybridBounds(dm, &cMax, &fMax, NULL, NULL);
8462:   switch (dim) {
8463:   case 1:
8464:     switch (coneSize) {
8465:     case 2:
8466:       *cellRefiner = REFINER_SIMPLEX_1D;
8467:       break;
8468:     default:
8469:       SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown coneSize %d in dimension %d for cell refiner", coneSize, dim);
8470:     }
8471:     break;
8472:   case 2:
8473:     switch (coneSize) {
8474:     case 3:
8475:       if (cMax >= 0) *cellRefiner = REFINER_HYBRID_SIMPLEX_2D;
8476:       else *cellRefiner = REFINER_SIMPLEX_2D;
8477:       break;
8478:     case 4:
8479:       if (cMax >= 0 && fMax >= 0) *cellRefiner = REFINER_HYBRID_HEX_2D;
8480:       else *cellRefiner = REFINER_HEX_2D;
8481:       break;
8482:     default:
8483:       SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown coneSize %d in dimension %d for cell refiner", coneSize, dim);
8484:     }
8485:     break;
8486:   case 3:
8487:     switch (coneSize) {
8488:     case 4:
8489:       if (cMax >= 0) *cellRefiner = REFINER_HYBRID_SIMPLEX_3D;
8490:       else *cellRefiner = REFINER_SIMPLEX_3D;
8491:       break;
8492:     case 6:
8493:       if (cMax >= 0) *cellRefiner = REFINER_HYBRID_HEX_3D;
8494:       else *cellRefiner = REFINER_HEX_3D;
8495:       break;
8496:     default:
8497:       SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown coneSize %d in dimension %d for cell refiner", coneSize, dim);
8498:     }
8499:     break;
8500:   default:
8501:     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown dimension %d for cell refiner", dim);
8502:   }
8503:   return(0);
8504: }

8506: PetscErrorCode DMRefine_Plex(DM dm, MPI_Comm comm, DM *dmRefined)
8507: {
8508:   PetscBool      isUniform;

8512:   DMPlexGetRefinementUniform(dm, &isUniform);
8513:   if (isUniform) {
8514:     CellRefiner cellRefiner;
8515:     PetscBool   localized;

8517:     DMGetCoordinatesLocalized(dm, &localized);
8518:     DMPlexGetCellRefiner_Internal(dm, &cellRefiner);
8519:     DMPlexRefineUniform_Internal(dm, cellRefiner, dmRefined);
8520:     DMCopyBoundary(dm, *dmRefined);
8521:     if (localized) {DMLocalizeCoordinates(*dmRefined);}
8522:   } else {
8523:     DMPlexRefine_Internal(dm, NULL, dmRefined);
8524:   }
8525:   return(0);
8526: }

8528: PetscErrorCode DMRefineHierarchy_Plex(DM dm, PetscInt nlevels, DM dmRefined[])
8529: {
8530:   DM             cdm = dm;
8531:   PetscInt       r;
8532:   PetscBool      isUniform, localized;

8536:   DMPlexGetRefinementUniform(dm, &isUniform);
8537:   DMGetCoordinatesLocalized(dm, &localized);
8538:   if (isUniform) {
8539:     for (r = 0; r < nlevels; ++r) {
8540:       CellRefiner cellRefiner;

8542:       DMPlexGetCellRefiner_Internal(cdm, &cellRefiner);
8543:       DMPlexRefineUniform_Internal(cdm, cellRefiner, &dmRefined[r]);
8544:       DMCopyBoundary(cdm, dmRefined[r]);
8545:       if (localized) {DMLocalizeCoordinates(dmRefined[r]);}
8546:       DMSetCoarseDM(dmRefined[r], cdm);
8547:       DMPlexSetRegularRefinement(dmRefined[r], PETSC_TRUE);
8548:       cdm  = dmRefined[r];
8549:     }
8550:   } else {
8551:     for (r = 0; r < nlevels; ++r) {
8552:       DMRefine(cdm, PetscObjectComm((PetscObject) dm), &dmRefined[r]);
8553:       DMCopyBoundary(cdm, dmRefined[r]);
8554:       if (localized) {DMLocalizeCoordinates(dmRefined[r]);}
8555:       DMSetCoarseDM(dmRefined[r], cdm);
8556:       cdm  = dmRefined[r];
8557:     }
8558:   }
8559:   return(0);
8560: }