Actual source code: plexrefine.c

petsc-3.8.0 2017-09-26
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_HYBRID_SIMPLEX_2D:
6485:       for (p = cStart; p < cMax; ++p) {
6486:         for (r = 0; r < 4; ++r) {
6487:           newp     = (p - cStart)*4 + r;
6488:           pi[newp] = p;
6489:         }
6490:       }
6491:       for (p = cMax; p < cEnd; ++p) {
6492:         for (r = 0; r < 2; ++r) {
6493:           newp     = (cMax - cStart)*4 + (p - cMax)*2 + r;
6494:           pi[newp] = p;
6495:         }
6496:       }
6497:       break;
6498:     case REFINER_HYBRID_HEX_2D:
6499:       for (p = cStart; p < cMax; ++p) {
6500:         for (r = 0; r < 4; ++r) {
6501:           newp     = (p - cStart)*4 + r;
6502:           pi[newp] = p;
6503:         }
6504:       }
6505:       for (p = cMax; p < cEnd; ++p) {
6506:         for (r = 0; r < 2; ++r) {
6507:           newp     = (cMax - cStart)*4 + (p - cMax)*2 + r;
6508:           pi[newp] = p;
6509:         }
6510:       }
6511:       break;
6512:     case REFINER_SIMPLEX_3D:
6513:       for (p = cStart; p < cEnd; ++p) {
6514:         for (r = 0; r < 8; ++r) {
6515:           newp     = (p - cStart)*8 + r;
6516:           pi[newp] = p;
6517:         }
6518:       }
6519:       break;
6520:     case REFINER_HYBRID_SIMPLEX_3D:
6521:       for (p = cStart; p < cMax; ++p) {
6522:         for (r = 0; r < 8; ++r) {
6523:           newp     = (p - cStart)*8 + r;
6524:           pi[newp] = p;
6525:         }
6526:       }
6527:       for (p = cMax; p < cEnd; ++p) {
6528:         for (r = 0; r < 4; ++r) {
6529:           newp     = (cMax - cStart)*8 + (p - cMax)*4 + r;
6530:           pi[newp] = p;
6531:         }
6532:       }
6533:       break;
6534:     case REFINER_HEX_3D:
6535:       for (p = cStart; p < cEnd; ++p) {
6536:         for (r = 0; r < 8; ++r) {
6537:           newp = (p - cStart)*8 + r;
6538:           pi[newp] = p;
6539:         }
6540:       }
6541:       break;
6542:     case REFINER_HYBRID_HEX_3D:
6543:       for (p = cStart; p < cMax; ++p) {
6544:         for (r = 0; r < 8; ++r) {
6545:           newp = (p - cStart)*8 + r;
6546:           pi[newp] = p;
6547:         }
6548:       }
6549:       for (p = cMax; p < cEnd; ++p) {
6550:         for (r = 0; r < 4; ++r) {
6551:           newp = (cMax - cStart)*8 + (p - cMax)*4 + r;
6552:           pi[newp] = p;
6553:         }
6554:       }
6555:       break;
6556:     default:
6557:       SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
6558:     }
6559:     parentId = pi;
6560:   } else {
6561:     PetscSectionSetChart(coordSectionNew, vStartNew, vStartNew+numVertices);
6562:   }
6563:   if (cMax < 0) cMax = cEnd;
6564:   if (fMax < 0) fMax = fEnd;
6565:   if (eMax < 0) eMax = eEnd;

6567:   /* All vertices have the spaceDim coordinates */
6568:   if (localize) {
6569:     PetscInt c;

6571:     for (c = cStartNew; c < cEndNew; ++c) {
6572:       PetscInt *cone = NULL;
6573:       PetscInt  closureSize, coneSize = 0, p, pdof;

6575:       PetscSectionGetDof(coordSection, parentId[c], &pdof);
6576:       if (pdof) { /* localize on all cells that are refinement of a localized parent cell */
6577:         DMPlexGetTransitiveClosure(rdm, c, PETSC_TRUE, &closureSize, &cone);
6578:         for (p = 0; p < closureSize*2; p += 2) {
6579:           const PetscInt point = cone[p];
6580:           if ((point >= vStartNew) && (point < vEndNew)) coneSize++;
6581:         }
6582:         DMPlexRestoreTransitiveClosure(rdm, c, PETSC_TRUE, &closureSize, &cone);
6583:         PetscSectionSetDof(coordSectionNew, c, coneSize*spaceDim);
6584:         PetscSectionSetFieldDof(coordSectionNew, c, 0, coneSize*spaceDim);
6585:       }
6586:     }
6587:   }
6588:   for (v = vStartNew; v < vStartNew+numVertices; ++v) {
6589:     PetscSectionSetDof(coordSectionNew, v, spaceDim);
6590:     PetscSectionSetFieldDof(coordSectionNew, v, 0, spaceDim);
6591:   }
6592:   PetscSectionSetUp(coordSectionNew);
6593:   DMSetCoordinateSection(rdm, PETSC_DETERMINE, coordSectionNew);
6594:   DMGetCoordinatesLocal(dm, &coordinates);
6595:   PetscSectionGetStorageSize(coordSectionNew, &coordSizeNew);
6596:   VecCreate(PETSC_COMM_SELF, &coordinatesNew);
6597:   PetscObjectSetName((PetscObject) coordinatesNew, "coordinates");
6598:   VecSetSizes(coordinatesNew, coordSizeNew, PETSC_DETERMINE);
6599:   VecGetBlockSize(coordinates, &bs);
6600:   VecSetBlockSize(coordinatesNew, bs);
6601:   VecGetType(coordinates, &vtype);
6602:   VecSetType(coordinatesNew, vtype);
6603:   VecGetArray(coordinates, &coords);
6604:   VecGetArray(coordinatesNew, &coordsNew);

6606:   switch (refiner) {
6607:   case REFINER_NOOP: break;
6608:   case REFINER_SIMPLEX_TO_HEX_3D:
6609:   case REFINER_HEX_3D:
6610:   case REFINER_HYBRID_HEX_3D:
6611:     /* Face vertices have the average of corner coordinates */
6612:     for (f = fStart; f < fMax; ++f) {
6613:       const PetscInt newv = vStartNew + (vEnd - vStart) + (eMax - eStart) + (f - fStart);
6614:       PetscInt      *cone = NULL;
6615:       PetscInt       closureSize, coneSize = 0, off[8], offnew, p, d;

6617:       DMPlexGetTransitiveClosure(dm, f, PETSC_TRUE, &closureSize, &cone);
6618:       for (p = 0; p < closureSize*2; p += 2) {
6619:         const PetscInt point = cone[p];
6620:         if ((point >= vStart) && (point < vEnd)) cone[coneSize++] = point;
6621:       }
6622:       if (localize) {
6623:         const PetscInt *support = NULL;
6624:         PetscInt       *rStar = NULL;
6625:         PetscInt        supportSize, rStarSize, coff, s, ccoff[8];
6626:         PetscBool       cellfound = PETSC_FALSE;

6628:         DMPlexGetTransitiveClosure(rdm, newv, PETSC_FALSE, &rStarSize, &rStar);
6629:         DMPlexGetSupportSize(dm,f,&supportSize);
6630:         DMPlexGetSupport(dm,f,&support);
6631:         /* Compute average of coordinates for each cell sharing the face */
6632:         for (s = 0; s < supportSize; ++s) {
6633:           PetscScalar     coordsNewAux[3] = { 0.0, 0.0, 0.0 };
6634:           PetscInt       *cellCone = NULL;
6635:           PetscInt        cellClosureSize, cellConeSize = 0, cdof;
6636:           const PetscInt  cell = support[s];
6637:           PetscBool       copyoff = PETSC_FALSE;

6639:           DMPlexGetTransitiveClosure(dm, cell, PETSC_TRUE, &cellClosureSize, &cellCone);
6640:           for (p = 0; p < cellClosureSize*2; p += 2) {
6641:             const PetscInt point = cellCone[p];
6642:             if ((point >= vStart) && (point < vEnd)) cellCone[cellConeSize++] = point;
6643:           }
6644:           PetscSectionGetDof(coordSection, cell, &cdof);
6645:           if (!cdof) { /* the parent cell does not have localized coordinates */
6646:             cellfound = PETSC_TRUE;
6647:             for (v = 0; v < coneSize; ++v) {
6648:               PetscSectionGetOffset(coordSection, cone[v], &off[v]);
6649:               for (d = 0; d < spaceDim; ++d) coordsNewAux[d] += coords[off[v]+d];
6650:             }
6651:             for (d = 0; d < spaceDim; ++d) coordsNewAux[d] /= coneSize;
6652:           } else {
6653:             PetscSectionGetOffset(coordSection, cell, &coff);
6654:             for (p = 0; p < coneSize; ++p) {
6655:               const PetscInt tv = cone[p];
6656:               PetscInt       cv, voff;
6657:               PetscBool      locv = PETSC_TRUE;

6659:               for (cv = 0; cv < cellConeSize; ++cv) {
6660:                 if (cellCone[cv] == tv) {
6661:                   ccoff[p] = spaceDim*cv + coff;
6662:                   break;
6663:                 }
6664:               }
6665:               if (cv == cellConeSize) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Unable to map vertex %D\n",tv);

6667:               PetscSectionGetOffset(coordSection, cone[p], &voff);
6668:               for (d = 0; d < spaceDim; ++d) {
6669:                 coordsNewAux[d] += coords[ccoff[p]+d];
6670:                 if (!cellfound && coords[voff+d] != coords[ccoff[p]+d]) locv = PETSC_FALSE;
6671:               }
6672:               if (locv && !cellfound) {
6673:                 cellfound = PETSC_TRUE;
6674:                 copyoff   = PETSC_TRUE;
6675:               }
6676:             }
6677:             for (d = 0; d < spaceDim; ++d) coordsNewAux[d] /= coneSize;

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

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

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

6738:       DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &cone);
6739:       for (p = 0; p < closureSize*2; p += 2) {
6740:         const PetscInt point = cone[p];
6741:         if ((point >= vStart) && (point < vEnd)) cone[coneSize++] = point;
6742:       }
6743:       if (localize) {
6744:         PetscSectionGetDof(coordSection, c, &cdof);
6745:       }
6746:       if (cdof) {
6747:         PetscInt coff;

6749:         PetscSectionGetOffset(coordSection, c, &coff);
6750:         for (v = 0; v < coneSize; ++v) off[v] = spaceDim*v + coff;
6751:       } else {
6752:         for (v = 0; v < coneSize; ++v) {
6753:           PetscSectionGetOffset(coordSection, cone[v], &off[v]);
6754:         }
6755:       }
6756:       PetscSectionGetOffset(coordSectionNew, newv, &offnew);
6757:       for (d = 0; d < spaceDim; ++d) coordsNew[offnew+d] = 0.0;
6758:       for (v = 0; v < coneSize; ++v) {DMLocalizeAddCoordinate_Internal(dm, spaceDim, &coords[off[0]], &coords[off[v]], &coordsNew[offnew]);}
6759:       for (d = 0; d < spaceDim; ++d) coordsNew[offnew+d] /= coneSize;
6760:       DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &cone);

6762:       /* Localize new coordinates on each refined cell */
6763:       if (cdof) {
6764:         PetscInt *rStar = NULL, rStarSize;

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

6771:             rc   = rStar[v];
6772:             PetscSectionGetDof(coordSectionNew, rc, &rcdof);
6773:             if (!rcdof) continue;
6774:             PetscSectionGetOffset(coordSectionNew, rc, &coff);
6775:             DMPlexGetTransitiveClosure(rdm, rc, PETSC_TRUE, &closureSize, &cone);
6776:             for (p = 0, lid = 0; p < closureSize*2; p += 2) {
6777:               if (cone[p] == newv) {
6778:                 for (d = 0; d < spaceDim; d++) coordsNew[coff + lid*spaceDim + d] = coordsNew[offnew + d];
6779:                 break;
6780:               }
6781:               if (cone[p] >= vStartNew && cone[p] < vEndNew) lid++;
6782:             }
6783:             if (p == closureSize*2) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Unable to map new vertex %D\n",newv);
6784:             DMPlexRestoreTransitiveClosure(rdm, rc, PETSC_TRUE, &closureSize, &cone);
6785:           }
6786:         }
6787:         DMPlexRestoreTransitiveClosure(rdm, newv, PETSC_FALSE, &rStarSize, &rStar);
6788:       }
6789:     }
6790:   case REFINER_SIMPLEX_2D:
6791:   case REFINER_HYBRID_SIMPLEX_2D:
6792:   case REFINER_SIMPLEX_3D:
6793:   case REFINER_HYBRID_SIMPLEX_3D:
6794:     /* Edge vertices have the average of endpoint coordinates */
6795:     for (e = eStart; e < eMax; ++e) {
6796:       const PetscInt  newv = vStartNew + (vEnd - vStart) + (e - eStart);
6797:       const PetscInt *cone;
6798:       PetscInt        coneSize, offA, offB, offnew, d;

6800:       DMPlexGetConeSize(dm, e, &coneSize);
6801:       if (coneSize != 2) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Edge %d cone should have two vertices, not %d", e, coneSize);
6802:       DMPlexGetCone(dm, e, &cone);
6803:       if (localize) {
6804:         PetscInt   coff, toffA = -1, toffB = -1, voffA, voffB;
6805:         PetscInt  *eStar = NULL, eStarSize;
6806:         PetscInt  *rStar = NULL, rStarSize;
6807:         PetscBool  cellfound = PETSC_FALSE;

6809:         offA = offB = -1;
6810:         PetscSectionGetOffset(coordSection, cone[0], &voffA);
6811:         PetscSectionGetOffset(coordSection, cone[1], &voffB);
6812:         DMPlexGetTransitiveClosure(dm, e, PETSC_FALSE, &eStarSize, &eStar);
6813:         DMPlexGetTransitiveClosure(rdm, newv, PETSC_FALSE, &rStarSize, &rStar);
6814:         for (v = 0; v < eStarSize*2; v += 2) {
6815:           if ((eStar[v] >= cStart) && (eStar[v] < cEnd)) {
6816:             PetscScalar     coordsNewAux[3];
6817:             PetscInt       *cellCone = NULL;
6818:             PetscInt        cellClosureSize, s, cv, cdof;
6819:             PetscBool       locvA = PETSC_TRUE, locvB = PETSC_TRUE;
6820:             const PetscInt  cell = eStar[v];

6822:             PetscSectionGetDof(coordSection, cell, &cdof);
6823:             if (!cdof) {
6824:               /* Found a valid edge for the "vertex" part of the Section */
6825:               offA = voffA;
6826:               offB = voffB;
6827:               cellfound = PETSC_TRUE;
6828:             } else {
6829:               PetscSectionGetOffset(coordSection, cell, &coff);
6830:               DMPlexGetTransitiveClosure(dm, cell, PETSC_TRUE, &cellClosureSize, &cellCone);
6831:               for (s = 0, cv = 0; s < cellClosureSize*2; s += 2) {
6832:                 const PetscInt point = cellCone[s];
6833:                 if ((point >= vStart) && (point < vEnd)) {
6834:                   if (point == cone[0]) toffA = spaceDim*cv + coff;
6835:                   else if (point == cone[1]) toffB = spaceDim*cv + coff;
6836:                   cv++;
6837:                 }
6838:               }
6839:               DMPlexRestoreTransitiveClosure(dm, cell, PETSC_TRUE, &cellClosureSize, &cellCone);
6840:               for (d = 0; d < spaceDim; ++d) {
6841:                 coordsNewAux[d] = 0.5*(coords[toffA+d] + coords[toffB+d]);
6842:                 if (coords[toffA+d] != coords[voffA+d]) locvA = PETSC_FALSE;
6843:                 if (coords[toffB+d] != coords[voffB+d]) locvB = PETSC_FALSE;
6844:               }
6845:               /* Found a valid edge for the "vertex" part of the Section */
6846:               if (!cellfound && (locvA || locvB)) {
6847:                 cellfound = PETSC_TRUE;
6848:                 offA = toffA;
6849:                 offB = toffB;
6850:               }
6851:             }

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

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

6901:       PetscSectionGetOffset(coordSection, v, &off);
6902:       PetscSectionGetOffset(coordSectionNew, newv, &offnew);
6903:       for (d = 0; d < spaceDim; ++d) {
6904:         coordsNew[offnew+d] = coords[off+d];
6905:       }

6907:       /* Localize new coordinates on each refined cell */
6908:       if (localize) {
6909:         PetscInt  p;
6910:         PetscInt *rStar = NULL, rStarSize;

6912:         DMPlexGetTransitiveClosure(rdm, newv, PETSC_FALSE, &rStarSize, &rStar);
6913:         for (p = 0; p < rStarSize*2; p += 2) {
6914:           if ((rStar[p] >= cStartNew) && (rStar[p] < cEndNew)) {
6915:             PetscScalar  ocoords[3];
6916:             PetscInt    *cone = NULL, closureSize, lid, coff, s, oc, cdof;

6918:             c    = rStar[p];
6919:             oc   = parentId[c-cStartNew];
6920:             PetscSectionGetDof(coordSectionNew, c, &cdof);
6921:             if (!cdof) continue;
6922:             PetscSectionGetDof(coordSection, oc, &cdof);
6923:             if (!cdof) continue;
6924:             PetscSectionGetOffset(coordSection, oc, &coff);
6925:             DMPlexGetTransitiveClosure(dm, oc, PETSC_TRUE, &closureSize, &cone);
6926:             for (s = 0, lid = 0; s < closureSize*2; s += 2) {
6927:               if (cone[s] == v) {
6928:                 for (d = 0; d < spaceDim; d++) ocoords[d] = coords[coff + lid*spaceDim + d];
6929:                 break;
6930:               }
6931:               if (cone[s] >= vStart && cone[s] < vEnd) lid++;
6932:             }
6933:             if (s == closureSize*2) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Unable to map old vertex %D\n",v);
6934:             DMPlexRestoreTransitiveClosure(dm, oc, PETSC_TRUE, &closureSize, &cone);

6936:             PetscSectionGetOffset(coordSectionNew, c, &coff);
6937:             DMPlexGetTransitiveClosure(rdm, c, PETSC_TRUE, &closureSize, &cone);
6938:             for (s = 0, lid = 0; s < closureSize*2; s += 2) {
6939:               if (cone[s] == newv) {
6940:                 for (d = 0; d < spaceDim; d++) coordsNew[coff + lid*spaceDim + d] = ocoords[d];
6941:                 break;
6942:               }
6943:               if (cone[s] >= vStartNew && cone[s] < vEndNew) lid++;
6944:             }
6945:             if (s == closureSize*2) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Unable to map new vertex %D\n",newv);
6946:             DMPlexRestoreTransitiveClosure(rdm, c, PETSC_TRUE, &closureSize, &cone);
6947:           }
6948:         }
6949:         DMPlexRestoreTransitiveClosure(rdm, newv, PETSC_FALSE, &rStarSize, &rStar);
6950:       }
6951:     }
6952:     break;
6953:   default:
6954:     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
6955:   }
6956:   VecRestoreArray(coordinates, &coords);
6957:   VecRestoreArray(coordinatesNew, &coordsNew);
6958:   DMSetCoordinatesLocal(rdm, coordinatesNew);

6960:   /* Final reduction (if needed) if we are localizing */
6961:   if (localize) {
6962:     PetscBool gred;

6964:     MPIU_Allreduce(&needcoords, &gred, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject)rdm));
6965:     if (gred) {
6966:       DM                 cdm;
6967:       Vec                aux;
6968:       PetscSF            sf;
6969:       const PetscScalar *lArray;
6970:       PetscScalar       *gArray;

6972:       DMGetCoordinateDM(rdm, &cdm);
6973:       DMCreateGlobalVector(cdm, &aux);
6974:       DMGetDefaultSF(cdm, &sf);
6975:       VecGetArrayRead(coordinatesNew, &lArray);
6976:       VecSet(aux, PETSC_MIN_REAL);
6977:       VecGetArray(aux, &gArray);
6978:       PetscSFReduceBegin(sf, MPIU_SCALAR, lArray, gArray, MPIU_MAX);
6979:       PetscSFReduceEnd(sf, MPIU_SCALAR, lArray, gArray, MPIU_MAX);
6980:       VecRestoreArrayRead(coordinatesNew, &lArray);
6981:       VecRestoreArray(aux, &gArray);
6982:       DMGlobalToLocalBegin(cdm, aux, INSERT_VALUES, coordinatesNew);
6983:       DMGlobalToLocalEnd(cdm, aux, INSERT_VALUES, coordinatesNew);
6984:       VecDestroy(&aux);
6985:     }
6986:   }
6987:   VecDestroy(&coordinatesNew);
6988:   PetscSectionDestroy(&coordSectionNew);
6989:   PetscFree(parentId);
6990:   return(0);
6991: }

6993: /*@
6994:   DMPlexCreateProcessSF - Create an SF which just has process connectivity

6996:   Collective on DM

6998:   Input Parameters:
6999: + dm      - The DM
7000: - sfPoint - The PetscSF which encodes point connectivity

7002:   Output Parameters:
7003: + processRanks - A list of process neighbors, or NULL
7004: - sfProcess    - An SF encoding the process connectivity, or NULL

7006:   Level: developer

7008: .seealso: PetscSFCreate(), DMPlexCreateTwoSidedProcessSF()
7009: @*/
7010: PetscErrorCode DMPlexCreateProcessSF(DM dm, PetscSF sfPoint, IS *processRanks, PetscSF *sfProcess)
7011: {
7012:   PetscInt           numRoots, numLeaves, l;
7013:   const PetscInt    *localPoints;
7014:   const PetscSFNode *remotePoints;
7015:   PetscInt          *localPointsNew;
7016:   PetscSFNode       *remotePointsNew;
7017:   PetscInt          *ranks, *ranksNew;
7018:   PetscMPIInt        size;
7019:   PetscErrorCode     ierr;

7026:   MPI_Comm_size(PetscObjectComm((PetscObject) dm), &size);
7027:   PetscSFGetGraph(sfPoint, &numRoots, &numLeaves, &localPoints, &remotePoints);
7028:   PetscMalloc1(numLeaves, &ranks);
7029:   for (l = 0; l < numLeaves; ++l) {
7030:     ranks[l] = remotePoints[l].rank;
7031:   }
7032:   PetscSortRemoveDupsInt(&numLeaves, ranks);
7033:   PetscMalloc1(numLeaves, &ranksNew);
7034:   PetscMalloc1(numLeaves, &localPointsNew);
7035:   PetscMalloc1(numLeaves, &remotePointsNew);
7036:   for (l = 0; l < numLeaves; ++l) {
7037:     ranksNew[l]              = ranks[l];
7038:     localPointsNew[l]        = l;
7039:     remotePointsNew[l].index = 0;
7040:     remotePointsNew[l].rank  = ranksNew[l];
7041:   }
7042:   PetscFree(ranks);
7043:   if (processRanks) {ISCreateGeneral(PetscObjectComm((PetscObject)dm), numLeaves, ranksNew, PETSC_OWN_POINTER, processRanks);}
7044:   else              {PetscFree(ranksNew);}
7045:   if (sfProcess) {
7046:     PetscSFCreate(PetscObjectComm((PetscObject)dm), sfProcess);
7047:     PetscObjectSetName((PetscObject) *sfProcess, "Process SF");
7048:     PetscSFSetFromOptions(*sfProcess);
7049:     PetscSFSetGraph(*sfProcess, size, numLeaves, localPointsNew, PETSC_OWN_POINTER, remotePointsNew, PETSC_OWN_POINTER);
7050:   }
7051:   return(0);
7052: }

7054: static PetscErrorCode CellRefinerCreateSF(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
7055: {
7056:   PetscSF            sf, sfNew, sfProcess;
7057:   IS                 processRanks;
7058:   MPI_Datatype       depthType;
7059:   PetscInt           numRoots, numLeaves, numLeavesNew = 0, l, m;
7060:   const PetscInt    *localPoints, *neighbors;
7061:   const PetscSFNode *remotePoints;
7062:   PetscInt          *localPointsNew;
7063:   PetscSFNode       *remotePointsNew;
7064:   PetscInt          *depthSizeOld, *rdepthSize, *rdepthSizeOld, *rdepthMaxOld, *rvStart, *rvStartNew, *reStart, *reStartNew, *rfStart, *rfStartNew, *rcStart, *rcStartNew;
7065:   PetscInt           ldepth, depth, numNeighbors, pStartNew, pEndNew, cStart, cEnd, cMax, vStart, vEnd, vMax, fStart, fEnd, fMax, eStart, eEnd, eMax, r, n;
7066:   PetscInt           cStartNew = 0, vStartNew = 0, fStartNew = 0, eStartNew = 0;
7067:   PetscErrorCode     ierr;

7070:   DMPlexGetChart(rdm, &pStartNew, &pEndNew);
7071:   DMPlexGetDepth(dm, &ldepth);
7072:   MPIU_Allreduce(&ldepth, &depth, 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject) dm));
7073:   if ((ldepth >= 0) && (depth != ldepth)) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Inconsistent Plex depth %d != %d", ldepth, depth);
7074:   DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);
7075:   DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);
7076:   DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);
7077:   DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);
7078:   DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);
7079:   cMax = cMax < 0 ? cEnd : cMax;
7080:   fMax = fMax < 0 ? fEnd : fMax;
7081:   eMax = eMax < 0 ? eEnd : eMax;
7082:   if (refiner) {GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);}
7083:   DMGetPointSF(dm, &sf);
7084:   DMGetPointSF(rdm, &sfNew);
7085:   /* Calculate size of new SF */
7086:   PetscSFGetGraph(sf, &numRoots, &numLeaves, &localPoints, &remotePoints);
7087:   if (numRoots < 0) return(0);
7088:   for (l = 0; l < numLeaves; ++l) {
7089:     const PetscInt p = localPoints[l];

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

7237:   PetscSFBcastBegin(sfProcess, depthType, depthSizeOld, rdepthMaxOld);
7238:   PetscSFBcastEnd(sfProcess, depthType, depthSizeOld, rdepthMaxOld);

7240:   depthSizeOld[depth]   = cEnd - cStart;
7241:   depthSizeOld[0]       = vEnd - vStart;
7242:   depthSizeOld[depth-1] = fEnd - fStart;
7243:   depthSizeOld[1]       = eEnd - eStart;

7245:   PetscSFBcastBegin(sfProcess, depthType, depthSizeOld, rdepthSizeOld);
7246:   PetscSFBcastEnd(sfProcess, depthType, depthSizeOld, rdepthSizeOld);
7247:   for (n = 0; n < numNeighbors; ++n) {
7248:     GetDepthStart_Private(depth, &rdepthSizeOld[n*(depth+1)], &rcStart[n], &rfStart[n], &reStart[n], &rvStart[n]);
7249:     rdepthMaxOld[n*(depth+1)+depth]   = rdepthMaxOld[n*(depth+1)+depth]   < 0 ? rdepthSizeOld[n*(depth+1)+depth]  +rcStart[n]: rdepthMaxOld[n*(depth+1)+depth];
7250:     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];
7251:     rdepthMaxOld[n*(depth+1)+1]       = rdepthMaxOld[n*(depth+1)+1]       < 0 ? rdepthSizeOld[n*(depth+1)+1]      +reStart[n]: rdepthMaxOld[n*(depth+1)+1];
7252:   }
7253:   MPI_Type_free(&depthType);
7254:   PetscSFDestroy(&sfProcess);
7255:   /* Calculate new point SF */
7256:   PetscMalloc1(numLeavesNew, &localPointsNew);
7257:   PetscMalloc1(numLeavesNew, &remotePointsNew);
7258:   ISGetIndices(processRanks, &neighbors);
7259:   for (l = 0, m = 0; l < numLeaves; ++l) {
7260:     PetscInt    p     = localPoints[l];
7261:     PetscInt    rp    = remotePoints[l].index, n;
7262:     PetscMPIInt rrank = remotePoints[l].rank;

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

7665:     /* SF needs sorted leaves to correct calculate Gather */
7666:     PetscMalloc1(numLeavesNew,&idx);
7667:     PetscMalloc1(numLeavesNew, &lp);
7668:     PetscMalloc1(numLeavesNew, &rp);
7669:     for (i = 0; i < numLeavesNew; ++i) {
7670:       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);
7671:       idx[i] = i;
7672:     }
7673:     PetscSortIntWithPermutation(numLeavesNew, localPointsNew, idx);
7674:     for (i = 0; i < numLeavesNew; ++i) {
7675:       lp[i] = localPointsNew[idx[i]];
7676:       rp[i] = remotePointsNew[idx[i]];
7677:     }
7678:     ltmp            = localPointsNew;
7679:     localPointsNew  = lp;
7680:     rtmp            = remotePointsNew;
7681:     remotePointsNew = rp;
7682:     PetscFree(idx);
7683:     PetscFree(ltmp);
7684:     PetscFree(rtmp);
7685:   }
7686:   PetscSFSetGraph(sfNew, pEndNew-pStartNew, numLeavesNew, localPointsNew, PETSC_OWN_POINTER, remotePointsNew, PETSC_OWN_POINTER);
7687:   PetscFree5(rdepthSize,rvStartNew,reStartNew,rfStartNew,rcStartNew);
7688:   PetscFree7(depthSizeOld,rdepthSizeOld,rdepthMaxOld,rvStart,reStart,rfStart,rcStart);
7689:   return(0);
7690: }

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

7700:   DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);
7701:   DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);
7702:   DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);
7703:   DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);
7704:   DMPlexGetDepth(dm, &depth);
7705:   if (refiner) {GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);}
7706:   DMGetNumLabels(dm, &numLabels);
7707:   DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);
7708:   switch (refiner) {
7709:   case REFINER_NOOP:
7710:   case REFINER_SIMPLEX_1D:
7711:   case REFINER_SIMPLEX_2D:
7712:   case REFINER_SIMPLEX_TO_HEX_2D:
7713:   case REFINER_HEX_2D:
7714:   case REFINER_SIMPLEX_3D:
7715:   case REFINER_HEX_3D:
7716:   case REFINER_SIMPLEX_TO_HEX_3D:
7717:     break;
7718:   case REFINER_HYBRID_SIMPLEX_3D:
7719:   case REFINER_HYBRID_HEX_3D:
7720:     if (eMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No edge maximum specified in hybrid mesh");
7721:   case REFINER_HYBRID_SIMPLEX_2D:
7722:   case REFINER_HYBRID_HEX_2D:
7723:     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
7724:     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
7725:     break;
7726:   default:
7727:     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
7728:   }
7729:   for (l = 0; l < numLabels; ++l) {
7730:     DMLabel         label, labelNew;
7731:     const char     *lname;
7732:     PetscBool       isDepth;
7733:     IS              valueIS;
7734:     const PetscInt *values;
7735:     PetscInt        defVal;
7736:     PetscInt        numValues, val;

7738:     DMGetLabelName(dm, l, &lname);
7739:     PetscStrcmp(lname, "depth", &isDepth);
7740:     if (isDepth) continue;
7741:     DMCreateLabel(rdm, lname);
7742:     DMGetLabel(dm, lname, &label);
7743:     DMGetLabel(rdm, lname, &labelNew);
7744:     DMLabelGetDefaultValue(label,&defVal);
7745:     DMLabelSetDefaultValue(labelNew,defVal);
7746:     DMLabelGetValueIS(label, &valueIS);
7747:     ISGetLocalSize(valueIS, &numValues);
7748:     ISGetIndices(valueIS, &values);
7749:     for (val = 0; val < numValues; ++val) {
7750:       IS              pointIS;
7751:       const PetscInt *points;
7752:       PetscInt        numPoints, n;

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

8198: /* This will only work for interpolated meshes */
8199: PetscErrorCode DMPlexRefineUniform_Internal(DM dm, CellRefiner cellRefiner, DM *dmRefined)
8200: {
8201:   DM             rdm;
8202:   PetscInt      *depthSize;
8203:   PetscInt       dim, depth = 0, d, pStart = 0, pEnd = 0;

8207:   DMCreate(PetscObjectComm((PetscObject)dm), &rdm);
8208:   DMSetType(rdm, DMPLEX);
8209:   DMGetDimension(dm, &dim);
8210:   DMSetDimension(rdm, dim);
8211:   /* Calculate number of new points of each depth */
8212:   DMPlexGetDepth(dm, &depth);
8213:   if (depth >= 0 && dim != depth) SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "Mesh must be interpolated for regular refinement");
8214:   PetscMalloc1(depth+1, &depthSize);
8215:   PetscMemzero(depthSize, (depth+1) * sizeof(PetscInt));
8216:   CellRefinerGetSizes(cellRefiner, dm, depthSize);
8217:   /* Step 1: Set chart */
8218:   for (d = 0; d <= depth; ++d) pEnd += depthSize[d];
8219:   DMPlexSetChart(rdm, pStart, pEnd);
8220:   /* Step 2: Set cone/support sizes */
8221:   CellRefinerSetConeSizes(cellRefiner, dm, depthSize, rdm);
8222:   /* Step 3: Setup refined DM */
8223:   DMSetUp(rdm);
8224:   /* Step 4: Set cones and supports */
8225:   CellRefinerSetCones(cellRefiner, dm, depthSize, rdm);
8226:   /* Step 5: Stratify */
8227:   DMPlexStratify(rdm);
8228:   /* Step 6: Create pointSF */
8229:   CellRefinerCreateSF(cellRefiner, dm, depthSize, rdm);
8230:   /* Step 7: Create labels */
8231:   CellRefinerCreateLabels(cellRefiner, dm, depthSize, rdm);
8232:   /* Step 8: Set coordinates */
8233:   CellRefinerSetCoordinates(cellRefiner, dm, depthSize, rdm);
8234:   PetscFree(depthSize);

8236:   *dmRefined = rdm;
8237:   return(0);
8238: }

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

8243:   Input Parameter:
8244: . dm - The coarse DM

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

8249:   Level: developer

8251: .seealso: DMRefine(), DMPlexSetRefinementUniform(), DMPlexCreateSubpointIS()
8252: @*/
8253: PetscErrorCode DMPlexCreateCoarsePointIS(DM dm, IS *fpointIS)
8254: {
8255:   CellRefiner    cellRefiner;
8256:   PetscInt      *depthSize, *fpoints;
8257:   PetscInt       cStartNew = 0, vStartNew = 0, fStartNew = 0, eStartNew = 0;
8258:   PetscInt       depth, pStart, pEnd, p, vStart, vEnd, v;

8262:   DMPlexGetDepth(dm, &depth);
8263:   DMPlexGetChart(dm, &pStart, &pEnd);
8264:   DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);
8265:   DMPlexGetCellRefiner_Internal(dm, &cellRefiner);
8266:   PetscMalloc1(depth+1, &depthSize);
8267:   CellRefinerGetSizes(cellRefiner, dm, depthSize);
8268:   if (cellRefiner) {GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);}
8269:   PetscMalloc1(pEnd-pStart,&fpoints);
8270:   for (p = 0; p < pEnd-pStart; ++p) fpoints[p] = -1;
8271:   switch (cellRefiner) {
8272:   case REFINER_SIMPLEX_1D:
8273:   case REFINER_SIMPLEX_2D:
8274:   case REFINER_HYBRID_SIMPLEX_2D:
8275:   case REFINER_HEX_2D:
8276:   case REFINER_HYBRID_HEX_2D:
8277:   case REFINER_SIMPLEX_3D:
8278:   case REFINER_HYBRID_SIMPLEX_3D:
8279:   case REFINER_HEX_3D:
8280:   case REFINER_HYBRID_HEX_3D:
8281:     for (v = vStart; v < vEnd; ++v) fpoints[v-pStart] = vStartNew + (v - vStart);
8282:     break;
8283:   default:
8284:     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", cellRefiner);
8285:   }
8286:   ISCreateGeneral(PETSC_COMM_SELF, pEnd-pStart, fpoints, PETSC_OWN_POINTER, fpointIS);
8287:   PetscFree(depthSize);
8288:   return(0);
8289: }

8291: /*@
8292:   DMPlexSetRefinementUniform - Set the flag for uniform refinement

8294:   Input Parameters:
8295: + dm - The DM
8296: - refinementUniform - The flag for uniform refinement

8298:   Level: developer

8300: .seealso: DMRefine(), DMPlexGetRefinementUniform(), DMPlexGetRefinementLimit(), DMPlexSetRefinementLimit()
8301: @*/
8302: PetscErrorCode DMPlexSetRefinementUniform(DM dm, PetscBool refinementUniform)
8303: {
8304:   DM_Plex *mesh = (DM_Plex*) dm->data;

8308:   mesh->refinementUniform = refinementUniform;
8309:   return(0);
8310: }

8312: /*@
8313:   DMPlexGetRefinementUniform - Retrieve the flag for uniform refinement

8315:   Input Parameter:
8316: . dm - The DM

8318:   Output Parameter:
8319: . refinementUniform - The flag for uniform refinement

8321:   Level: developer

8323: .seealso: DMRefine(), DMPlexSetRefinementUniform(), DMPlexGetRefinementLimit(), DMPlexSetRefinementLimit()
8324: @*/
8325: PetscErrorCode DMPlexGetRefinementUniform(DM dm, PetscBool *refinementUniform)
8326: {
8327:   DM_Plex *mesh = (DM_Plex*) dm->data;

8332:   *refinementUniform = mesh->refinementUniform;
8333:   return(0);
8334: }

8336: /*@
8337:   DMPlexSetRefinementLimit - Set the maximum cell volume for refinement

8339:   Input Parameters:
8340: + dm - The DM
8341: - refinementLimit - The maximum cell volume in the refined mesh

8343:   Level: developer

8345: .seealso: DMRefine(), DMPlexGetRefinementLimit(), DMPlexGetRefinementUniform(), DMPlexSetRefinementUniform()
8346: @*/
8347: PetscErrorCode DMPlexSetRefinementLimit(DM dm, PetscReal refinementLimit)
8348: {
8349:   DM_Plex *mesh = (DM_Plex*) dm->data;

8353:   mesh->refinementLimit = refinementLimit;
8354:   return(0);
8355: }

8357: /*@
8358:   DMPlexGetRefinementLimit - Retrieve the maximum cell volume for refinement

8360:   Input Parameter:
8361: . dm - The DM

8363:   Output Parameter:
8364: . refinementLimit - The maximum cell volume in the refined mesh

8366:   Level: developer

8368: .seealso: DMRefine(), DMPlexSetRefinementLimit(), DMPlexGetRefinementUniform(), DMPlexSetRefinementUniform()
8369: @*/
8370: PetscErrorCode DMPlexGetRefinementLimit(DM dm, PetscReal *refinementLimit)
8371: {
8372:   DM_Plex *mesh = (DM_Plex*) dm->data;

8377:   /* if (mesh->refinementLimit < 0) = getMaxVolume()/2.0; */
8378:   *refinementLimit = mesh->refinementLimit;
8379:   return(0);
8380: }

8382: /*@
8383:   DMPlexSetRefinementFunction - Set the function giving the maximum cell volume for refinement

8385:   Input Parameters:
8386: + dm - The DM
8387: - refinementFunc - Function giving the maximum cell volume in the refined mesh

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

8393:   Level: developer

8395: .seealso: DMRefine(), DMPlexGetRefinementFunction(), DMPlexGetRefinementUniform(), DMPlexSetRefinementUniform(), DMPlexGetRefinementLimit(), DMPlexSetRefinementLimit()
8396: @*/
8397: PetscErrorCode DMPlexSetRefinementFunction(DM dm, PetscErrorCode (*refinementFunc)(const PetscReal [], PetscReal *))
8398: {
8399:   DM_Plex *mesh = (DM_Plex*) dm->data;

8403:   mesh->refinementFunc = refinementFunc;
8404:   return(0);
8405: }

8407: /*@
8408:   DMPlexGetRefinementFunction - Get the function giving the maximum cell volume for refinement

8410:   Input Parameter:
8411: . dm - The DM

8413:   Output Parameter:
8414: . refinementFunc - Function giving the maximum cell volume in the refined mesh

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

8420:   Level: developer

8422: .seealso: DMRefine(), DMPlexSetRefinementFunction(), DMPlexGetRefinementUniform(), DMPlexSetRefinementUniform(), DMPlexGetRefinementLimit(), DMPlexSetRefinementLimit()
8423: @*/
8424: PetscErrorCode DMPlexGetRefinementFunction(DM dm, PetscErrorCode (**refinementFunc)(const PetscReal [], PetscReal *))
8425: {
8426:   DM_Plex *mesh = (DM_Plex*) dm->data;

8431:   *refinementFunc = mesh->refinementFunc;
8432:   return(0);
8433: }

8435: PetscErrorCode DMPlexGetCellRefiner_Internal(DM dm, CellRefiner *cellRefiner)
8436: {
8437:   PetscInt       dim, cStart, cEnd, coneSize, cMax, fMax;

8441:   DMGetDimension(dm, &dim);
8442:   DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);
8443:   if (cEnd <= cStart) {*cellRefiner = REFINER_NOOP; return(0);}
8444:   DMPlexGetConeSize(dm, cStart, &coneSize);
8445:   DMPlexGetHybridBounds(dm, &cMax, &fMax, NULL, NULL);
8446:   switch (dim) {
8447:   case 1:
8448:     switch (coneSize) {
8449:     case 2:
8450:       *cellRefiner = REFINER_SIMPLEX_1D;
8451:       break;
8452:     default:
8453:       SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown coneSize %d in dimension %d for cell refiner", coneSize, dim);
8454:     }
8455:     break;
8456:   case 2:
8457:     switch (coneSize) {
8458:     case 3:
8459:       if (cMax >= 0) *cellRefiner = REFINER_HYBRID_SIMPLEX_2D;
8460:       else *cellRefiner = REFINER_SIMPLEX_2D;
8461:       break;
8462:     case 4:
8463:       if (cMax >= 0 && fMax >= 0) *cellRefiner = REFINER_HYBRID_HEX_2D;
8464:       else *cellRefiner = REFINER_HEX_2D;
8465:       break;
8466:     default:
8467:       SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown coneSize %d in dimension %d for cell refiner", coneSize, dim);
8468:     }
8469:     break;
8470:   case 3:
8471:     switch (coneSize) {
8472:     case 4:
8473:       if (cMax >= 0) *cellRefiner = REFINER_HYBRID_SIMPLEX_3D;
8474:       else *cellRefiner = REFINER_SIMPLEX_3D;
8475:       break;
8476:     case 6:
8477:       if (cMax >= 0) *cellRefiner = REFINER_HYBRID_HEX_3D;
8478:       else *cellRefiner = REFINER_HEX_3D;
8479:       break;
8480:     default:
8481:       SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown coneSize %d in dimension %d for cell refiner", coneSize, dim);
8482:     }
8483:     break;
8484:   default:
8485:     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown dimension %d for cell refiner", dim);
8486:   }
8487:   return(0);
8488: }

8490: PetscErrorCode DMRefine_Plex(DM dm, MPI_Comm comm, DM *dmRefined)
8491: {
8492:   PetscBool      isUniform, localized;

8496:   DMPlexGetRefinementUniform(dm, &isUniform);
8497:   DMGetCoordinatesLocalized(dm, &localized);
8498:   if (isUniform) {
8499:     CellRefiner cellRefiner;

8501:     DMPlexGetCellRefiner_Internal(dm, &cellRefiner);
8502:     DMPlexRefineUniform_Internal(dm, cellRefiner, dmRefined);
8503:     DMCopyBoundary(dm, *dmRefined);
8504:     if (localized) {DMLocalizeCoordinates(*dmRefined);}
8505:   } else {
8506:     DMPlexRefine_Internal(dm, NULL, dmRefined);
8507:   }
8508:   return(0);
8509: }

8511: PetscErrorCode DMRefineHierarchy_Plex(DM dm, PetscInt nlevels, DM dmRefined[])
8512: {
8513:   DM             cdm = dm;
8514:   PetscInt       r;
8515:   PetscBool      isUniform, localized;

8519:   DMPlexGetRefinementUniform(dm, &isUniform);
8520:   DMGetCoordinatesLocalized(dm, &localized);
8521:   if (isUniform) {
8522:     for (r = 0; r < nlevels; ++r) {
8523:       CellRefiner cellRefiner;

8525:       DMPlexGetCellRefiner_Internal(cdm, &cellRefiner);
8526:       DMPlexRefineUniform_Internal(cdm, cellRefiner, &dmRefined[r]);
8527:       DMCopyBoundary(cdm, dmRefined[r]);
8528:       if (localized) {DMLocalizeCoordinates(dmRefined[r]);}
8529:       DMSetCoarseDM(dmRefined[r], cdm);
8530:       DMPlexSetRegularRefinement(dmRefined[r], PETSC_TRUE);
8531:       cdm  = dmRefined[r];
8532:     }
8533:   } else {
8534:     for (r = 0; r < nlevels; ++r) {
8535:       DMRefine(cdm, PetscObjectComm((PetscObject) dm), &dmRefined[r]);
8536:       DMCopyBoundary(cdm, dmRefined[r]);
8537:       if (localized) {DMLocalizeCoordinates(dmRefined[r]);}
8538:       DMSetCoarseDM(dmRefined[r], cdm);
8539:       cdm  = dmRefined[r];
8540:     }
8541:   }
8542:   return(0);
8543: }