Actual source code: plexrefine.c

petsc-3.5.4 2015-05-23
Report Typos and Errors
  1: #include <petsc-private/dmpleximpl.h>   /*I      "petscdmplex.h"   I*/
  2: #include <petscsf.h>

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

 18: PETSC_STATIC_INLINE PetscErrorCode GetDepthEnd_Private(PetscInt depth, PetscInt depthSize[], PetscInt *cEnd, PetscInt *fEnd, PetscInt *eEnd, PetscInt *vEnd)
 19: {
 21:   if (cEnd) *cEnd = depthSize[depth];
 22:   if (vEnd) *vEnd = depthSize[depth] + depthSize[0];
 23:   if (fEnd) *fEnd = depthSize[depth] + depthSize[0] + depthSize[depth-1];
 24:   if (eEnd) *eEnd = depthSize[depth] + depthSize[0] + depthSize[depth-1] + depthSize[1];
 25:   return(0);
 26: }

 30: /* Gets the affine map from the original cell to each subcell */
 31: PetscErrorCode CellRefinerGetAffineTransforms_Internal(CellRefiner refiner, PetscInt *numSubcells, PetscReal *v0[], PetscReal *jac[], PetscReal *invjac[])
 32: {
 33:   PetscReal     *v = NULL, *j = NULL, *invj = NULL, detJ;
 34:   PetscInt       dim, s;

 38:   switch (refiner) {
 39:   case 0: break;
 40:   case 1:
 41:     /*
 42:      2
 43:      |\
 44:      | \
 45:      |  \
 46:      |   \
 47:      | C  \
 48:      |     \
 49:      |      \
 50:      2---1---1
 51:      |\  D  / \
 52:      | 2   0   \
 53:      |A \ /  B  \
 54:      0---0-------1
 55:      */
 56:     dim = 2;
 57:     if (numSubcells) *numSubcells = 4;
 58:     if (v0) {
 59:       PetscMalloc3(4*dim,&v,4*dim*dim,&j,4*dim*dim,&invj);
 60:       /* A */
 61:       v[0+0] = -1.0; v[0+1] = -1.0;
 62:       j[0+0] =  0.5; j[0+1] =  0.0;
 63:       j[0+2] =  0.0; j[0+3] =  0.5;
 64:       /* B */
 65:       v[2+0] =  0.0; v[2+1] = -1.0;
 66:       j[4+0] =  0.5; j[4+1] =  0.0;
 67:       j[4+2] =  0.0; j[4+3] =  0.5;
 68:       /* C */
 69:       v[4+0] = -1.0; v[4+1] =  0.0;
 70:       j[8+0] =  0.5; j[8+1] =  0.0;
 71:       j[8+2] =  0.0; j[8+3] =  0.5;
 72:       /* D */
 73:       v[6+0]  =  0.0; v[6+1]  = -1.0;
 74:       j[12+0] =  0.0; j[12+1] = -0.5;
 75:       j[12+2] =  0.5; j[12+3] =  0.5;
 76:       for (s = 0; s < 4; ++s) {
 77:         DMPlex_Det2D_Internal(&detJ, &j[s*dim*dim]);
 78:         DMPlex_Invert2D_Internal(&invj[s*dim*dim], &j[s*dim*dim], detJ);
 79:       }
 80:     }
 81:     break;
 82:   case 2:
 83:     /*
 84:      3---------2---------2
 85:      |         |         |
 86:      |    D    2    C    |
 87:      |         |         |
 88:      3----3----0----1----1
 89:      |         |         |
 90:      |    A    0    B    |
 91:      |         |         |
 92:      0---------0---------1
 93:      */
 94:     dim = 2;
 95:     if (numSubcells) *numSubcells = 4;
 96:     if (v0) {
 97:       PetscMalloc3(4*dim,&v,4*dim*dim,&j,4*dim*dim,&invj);
 98:       /* A */
 99:       v[0+0] = -1.0; v[0+1] = -1.0;
100:       j[0+0] =  0.5; j[0+1] =  0.0;
101:       j[0+2] =  0.0; j[0+3] =  0.5;
102:       /* B */
103:       v[2+0] =  0.0; v[2+1] = -1.0;
104:       j[4+0] =  0.5; j[4+1] =  0.0;
105:       j[4+2] =  0.0; j[4+3] =  0.5;
106:       /* C */
107:       v[4+0] =  0.0; v[4+1] =  0.0;
108:       j[8+0] =  0.5; j[8+1] =  0.0;
109:       j[8+2] =  0.0; j[8+3] =  0.5;
110:       /* D */
111:       v[6+0]  = -1.0; v[6+1]  =  0.0;
112:       j[12+0] =  0.5; j[12+1] =  0.0;
113:       j[12+2] =  0.0; j[12+3] =  0.5;
114:       for (s = 0; s < 4; ++s) {
115:         DMPlex_Det2D_Internal(&detJ, &j[s*dim*dim]);
116:         DMPlex_Invert2D_Internal(&invj[s*dim*dim], &j[s*dim*dim], detJ);
117:       }
118:     }
119:     break;
120:   default:
121:     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
122:   }
123:   if (v0) {*v0 = v; *jac = j; *invjac = invj;}
124:   return(0);
125: }

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

134:   PetscFree3(*v0,*jac,*invjac);
135:   return(0);
136: }

140: /* Should this be here or in the DualSpace somehow? */
141: PetscErrorCode CellRefinerInCellTest_Internal(CellRefiner refiner, const PetscReal point[], PetscBool *inside)
142: {
143:   PetscReal sum = 0.0;
144:   PetscInt  d;

147:   *inside = PETSC_TRUE;
148:   switch (refiner) {
149:   case 0: break;
150:   case 1:
151:     for (d = 0; d < 2; ++d) {
152:       if (point[d] < -1.0) {*inside = PETSC_FALSE; break;}
153:       sum += point[d];
154:     }
155:     if (sum > 0.0) {*inside = PETSC_FALSE; break;}
156:     break;
157:   case 2:
158:     for (d = 0; d < 2; ++d) if ((point[d] < -1.0) || (point[d] > 1.0)) {*inside = PETSC_FALSE; break;}
159:     break;
160:   default:
161:     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
162:   }
163:   return(0);
164: }

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

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

267: /* Return triangle edge for orientation o, if it is r for o == 0 */
268: PETSC_STATIC_INLINE PetscInt GetTriEdge_Static(PetscInt o, PetscInt r) {
269:   return (o < 0 ? 2-(o+r) : o+r)%3;
270: }
271: PETSC_STATIC_INLINE PetscInt GetTriEdgeInverse_Static(PetscInt o, PetscInt s) {
272:   return (o < 0 ? 2-(o+s) : 3+s-o)%3;
273: }

275: /* Return triangle subface for orientation o, if it is r for o == 0 */
276: PETSC_STATIC_INLINE PetscInt GetTriSubface_Static(PetscInt o, PetscInt r) {
277:   return (o < 0 ? 3-(o+r) : o+r)%3;
278: }
279: PETSC_STATIC_INLINE PetscInt GetTriSubfaceInverse_Static(PetscInt o, PetscInt s) {
280:   return (o < 0 ? 3-(o+s) : 3+s-o)%3;
281: }

283: /* I HAVE NO IDEA: Return ??? for orientation o, if it is r for o == 0 */
284: PETSC_STATIC_INLINE PetscInt GetTetSomething_Static(PetscInt o, PetscInt r) {
285:   return (o < 0 ? 1-(o+r) : o+r)%3;
286: }
287: PETSC_STATIC_INLINE PetscInt GetTetSomethingInverse_Static(PetscInt o, PetscInt s) {
288:   return (o < 0 ? 1-(o+s) : 3+s-o)%3;
289: }


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

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

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

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

332:         DMPlexSetConeSize(rdm, newp, 3);
333:       }
334:     }
335:     /* Split faces have 2 vertices and the same cells as the parent */
336:     for (f = fStart; f < fEnd; ++f) {
337:       for (r = 0; r < 2; ++r) {
338:         const PetscInt newp = fStartNew + (f - fStart)*2 + r;
339:         PetscInt       size;

341:         DMPlexSetConeSize(rdm, newp, 2);
342:         DMPlexGetSupportSize(dm, f, &size);
343:         DMPlexSetSupportSize(rdm, newp, size);
344:       }
345:     }
346:     /* Interior faces have 2 vertices and 2 cells */
347:     for (c = cStart; c < cEnd; ++c) {
348:       for (r = 0; r < 3; ++r) {
349:         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*3 + r;

351:         DMPlexSetConeSize(rdm, newp, 2);
352:         DMPlexSetSupportSize(rdm, newp, 2);
353:       }
354:     }
355:     /* Old vertices have identical supports */
356:     for (v = vStart; v < vEnd; ++v) {
357:       const PetscInt newp = vStartNew + (v - vStart);
358:       PetscInt       size;

360:       DMPlexGetSupportSize(dm, v, &size);
361:       DMPlexSetSupportSize(rdm, newp, size);
362:     }
363:     /* Face vertices have 2 + cells*2 supports */
364:     for (f = fStart; f < fEnd; ++f) {
365:       const PetscInt newp = vStartNew + (vEnd - vStart) + (f - fStart);
366:       PetscInt       size;

368:       DMPlexGetSupportSize(dm, f, &size);
369:       DMPlexSetSupportSize(rdm, newp, 2 + size*2);
370:     }
371:     break;
372:   case 2:
373:     /* Hex 2D */
374:     /* All cells have 4 faces */
375:     for (c = cStart; c < cEnd; ++c) {
376:       for (r = 0; r < 4; ++r) {
377:         const PetscInt newp = cStartNew + (c - cStart)*4 + r;

379:         DMPlexSetConeSize(rdm, newp, 4);
380:       }
381:     }
382:     /* Split faces have 2 vertices and the same cells as the parent */
383:     for (f = fStart; f < fEnd; ++f) {
384:       for (r = 0; r < 2; ++r) {
385:         const PetscInt newp = fStartNew + (f - fStart)*2 + r;
386:         PetscInt       size;

388:         DMPlexSetConeSize(rdm, newp, 2);
389:         DMPlexGetSupportSize(dm, f, &size);
390:         DMPlexSetSupportSize(rdm, newp, size);
391:       }
392:     }
393:     /* Interior faces have 2 vertices and 2 cells */
394:     for (c = cStart; c < cEnd; ++c) {
395:       for (r = 0; r < 4; ++r) {
396:         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*4 + r;

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

407:       DMPlexGetSupportSize(dm, v, &size);
408:       DMPlexSetSupportSize(rdm, newp, size);
409:     }
410:     /* Face vertices have 2 + cells supports */
411:     for (f = fStart; f < fEnd; ++f) {
412:       const PetscInt newp = vStartNew + (vEnd - vStart) + (f - fStart);
413:       PetscInt       size;

415:       DMPlexGetSupportSize(dm, f, &size);
416:       DMPlexSetSupportSize(rdm, newp, 2 + size);
417:     }
418:     /* Cell vertices have 4 supports */
419:     for (c = cStart; c < cEnd; ++c) {
420:       const PetscInt newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (c - cStart);

422:       DMPlexSetSupportSize(rdm, newp, 4);
423:     }
424:     break;
425:   case 3:
426:     /* Hybrid Simplicial 2D */
427:     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
428:     cMax = PetscMin(cEnd, cMax);
429:     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
430:     fMax = PetscMin(fEnd, fMax);
431:     DMPlexSetHybridBounds(rdm, cStartNew + (cMax - cStart)*4, fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3, PETSC_DETERMINE, PETSC_DETERMINE);
432:     /* Interior cells have 3 faces */
433:     for (c = cStart; c < cMax; ++c) {
434:       for (r = 0; r < 4; ++r) {
435:         const PetscInt newp = cStartNew + (c - cStart)*4 + r;

437:         DMPlexSetConeSize(rdm, newp, 3);
438:       }
439:     }
440:     /* Hybrid cells have 4 faces */
441:     for (c = cMax; c < cEnd; ++c) {
442:       for (r = 0; r < 2; ++r) {
443:         const PetscInt newp = cStartNew + (cMax - cStart)*4 + (c - cMax)*2 + r;

445:         DMPlexSetConeSize(rdm, newp, 4);
446:       }
447:     }
448:     /* Interior split faces have 2 vertices and the same cells as the parent */
449:     for (f = fStart; f < fMax; ++f) {
450:       for (r = 0; r < 2; ++r) {
451:         const PetscInt newp = fStartNew + (f - fStart)*2 + r;
452:         PetscInt       size;

454:         DMPlexSetConeSize(rdm, newp, 2);
455:         DMPlexGetSupportSize(dm, f, &size);
456:         DMPlexSetSupportSize(rdm, newp, size);
457:       }
458:     }
459:     /* Interior cell faces have 2 vertices and 2 cells */
460:     for (c = cStart; c < cMax; ++c) {
461:       for (r = 0; r < 3; ++r) {
462:         const PetscInt newp = fStartNew + (fMax - fStart)*2 + (c - cStart)*3 + r;

464:         DMPlexSetConeSize(rdm, newp, 2);
465:         DMPlexSetSupportSize(rdm, newp, 2);
466:       }
467:     }
468:     /* Hybrid faces have 2 vertices and the same cells */
469:     for (f = fMax; f < fEnd; ++f) {
470:       const PetscInt newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (f - fMax);
471:       PetscInt       size;

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

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

489:       DMPlexGetSupportSize(dm, v, &size);
490:       DMPlexSetSupportSize(rdm, newp, size);
491:     }
492:     /* Face vertices have 2 + (2 interior, 1 hybrid) supports */
493:     for (f = fStart; f < fMax; ++f) {
494:       const PetscInt newp = vStartNew + (vEnd - vStart) + (f - fStart);
495:       const PetscInt *support;
496:       PetscInt       size, newSize = 2, s;

498:       DMPlexGetSupportSize(dm, f, &size);
499:       DMPlexGetSupport(dm, f, &support);
500:       for (s = 0; s < size; ++s) {
501:         if (support[s] >= cMax) newSize += 1;
502:         else newSize += 2;
503:       }
504:       DMPlexSetSupportSize(rdm, newp, newSize);
505:     }
506:     break;
507:   case 4:
508:     /* Hybrid Hex 2D */
509:     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
510:     cMax = PetscMin(cEnd, cMax);
511:     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
512:     fMax = PetscMin(fEnd, fMax);
513:     DMPlexSetHybridBounds(rdm, cStartNew + (cMax - cStart)*4, fStartNew + (fMax - fStart)*2 + (cMax - cStart)*4, PETSC_DETERMINE, PETSC_DETERMINE);
514:     /* Interior cells have 4 faces */
515:     for (c = cStart; c < cMax; ++c) {
516:       for (r = 0; r < 4; ++r) {
517:         const PetscInt newp = cStartNew + (c - cStart)*4 + r;

519:         DMPlexSetConeSize(rdm, newp, 4);
520:       }
521:     }
522:     /* Hybrid cells have 4 faces */
523:     for (c = cMax; c < cEnd; ++c) {
524:       for (r = 0; r < 2; ++r) {
525:         const PetscInt newp = cStartNew + (cMax - cStart)*4 + (c - cMax)*2 + r;

527:         DMPlexSetConeSize(rdm, newp, 4);
528:       }
529:     }
530:     /* Interior split faces have 2 vertices and the same cells as the parent */
531:     for (f = fStart; f < fMax; ++f) {
532:       for (r = 0; r < 2; ++r) {
533:         const PetscInt newp = fStartNew + (f - fStart)*2 + r;
534:         PetscInt       size;

536:         DMPlexSetConeSize(rdm, newp, 2);
537:         DMPlexGetSupportSize(dm, f, &size);
538:         DMPlexSetSupportSize(rdm, newp, size);
539:       }
540:     }
541:     /* Interior cell faces have 2 vertices and 2 cells */
542:     for (c = cStart; c < cMax; ++c) {
543:       for (r = 0; r < 4; ++r) {
544:         const PetscInt newp = fStartNew + (fMax - fStart)*2 + (c - cStart)*4 + r;

546:         DMPlexSetConeSize(rdm, newp, 2);
547:         DMPlexSetSupportSize(rdm, newp, 2);
548:       }
549:     }
550:     /* Hybrid faces have 2 vertices and the same cells */
551:     for (f = fMax; f < fEnd; ++f) {
552:       const PetscInt newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*4 + (f - fMax);
553:       PetscInt       size;

555:       DMPlexSetConeSize(rdm, newp, 2);
556:       DMPlexGetSupportSize(dm, f, &size);
557:       DMPlexSetSupportSize(rdm, newp, size);
558:     }
559:     /* Hybrid cell faces have 2 vertices and 2 cells */
560:     for (c = cMax; c < cEnd; ++c) {
561:       const PetscInt newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*4 + (fEnd - fMax) + (c - cMax);

563:       DMPlexSetConeSize(rdm, newp, 2);
564:       DMPlexSetSupportSize(rdm, newp, 2);
565:     }
566:     /* Old vertices have identical supports */
567:     for (v = vStart; v < vEnd; ++v) {
568:       const PetscInt newp = vStartNew + (v - vStart);
569:       PetscInt       size;

571:       DMPlexGetSupportSize(dm, v, &size);
572:       DMPlexSetSupportSize(rdm, newp, size);
573:     }
574:     /* Face vertices have 2 + cells supports */
575:     for (f = fStart; f < fMax; ++f) {
576:       const PetscInt newp = vStartNew + (vEnd - vStart) + (f - fStart);
577:       PetscInt       size;

579:       DMPlexGetSupportSize(dm, f, &size);
580:       DMPlexSetSupportSize(rdm, newp, 2 + size);
581:     }
582:     /* Cell vertices have 4 supports */
583:     for (c = cStart; c < cMax; ++c) {
584:       const PetscInt newp = vStartNew + (vEnd - vStart) + (fMax - fStart) + (c - cStart);

586:       DMPlexSetSupportSize(rdm, newp, 4);
587:     }
588:     break;
589:   case 5:
590:     /* Simplicial 3D */
591:     /* All cells have 4 faces */
592:     for (c = cStart; c < cEnd; ++c) {
593:       for (r = 0; r < 8; ++r) {
594:         const PetscInt newp = cStartNew + (c - cStart)*8 + r;

596:         DMPlexSetConeSize(rdm, newp, 4);
597:       }
598:     }
599:     /* Split faces have 3 edges and the same cells as the parent */
600:     for (f = fStart; f < fEnd; ++f) {
601:       for (r = 0; r < 4; ++r) {
602:         const PetscInt newp = fStartNew + (f - fStart)*4 + r;
603:         PetscInt       size;

605:         DMPlexSetConeSize(rdm, newp, 3);
606:         DMPlexGetSupportSize(dm, f, &size);
607:         DMPlexSetSupportSize(rdm, newp, size);
608:       }
609:     }
610:     /* Interior cell faces have 3 edges and 2 cells */
611:     for (c = cStart; c < cEnd; ++c) {
612:       for (r = 0; r < 8; ++r) {
613:         const PetscInt newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*8 + r;

615:         DMPlexSetConeSize(rdm, newp, 3);
616:         DMPlexSetSupportSize(rdm, newp, 2);
617:       }
618:     }
619:     /* Split edges have 2 vertices and the same faces */
620:     for (e = eStart; e < eEnd; ++e) {
621:       for (r = 0; r < 2; ++r) {
622:         const PetscInt newp = eStartNew + (e - eStart)*2 + r;
623:         PetscInt       size;

625:         DMPlexSetConeSize(rdm, newp, 2);
626:         DMPlexGetSupportSize(dm, e, &size);
627:         DMPlexSetSupportSize(rdm, newp, size);
628:       }
629:     }
630:     /* Face edges have 2 vertices and 2+cells*(1/2) faces */
631:     for (f = fStart; f < fEnd; ++f) {
632:       for (r = 0; r < 3; ++r) {
633:         const PetscInt  newp = eStartNew + (eEnd - eStart)*2 + (f - fStart)*3 + r;
634:         const PetscInt *cone, *ornt, *support, eint[4] = {1, 0, 2, 0};
635:         PetscInt        coneSize, c, supportSize, s, er, intFaces = 0;

637:         DMPlexSetConeSize(rdm, newp, 2);
638:         DMPlexGetSupportSize(dm, f, &supportSize);
639:         DMPlexGetSupport(dm, f, &support);
640:         for (s = 0; s < supportSize; ++s) {
641:           DMPlexGetConeSize(dm, support[s], &coneSize);
642:           DMPlexGetCone(dm, support[s], &cone);
643:           DMPlexGetConeOrientation(dm, support[s], &ornt);
644:           for (c = 0; c < coneSize; ++c) {if (cone[c] == f) break;}
645:           /* Here we want to determine whether edge newp contains a vertex which is part of the cross-tet edge */
646:           er = GetTetSomethingInverse_Static(ornt[c], r);
647:           if (er == eint[c]) {
648:             intFaces += 1;
649:           } else {
650:             intFaces += 2;
651:           }
652:         }
653:         DMPlexSetSupportSize(rdm, newp, 2+intFaces);
654:       }
655:     }
656:     /* Interior cell edges have 2 vertices and 4 faces */
657:     for (c = cStart; c < cEnd; ++c) {
658:       const PetscInt newp = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart);

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

668:       DMPlexGetSupportSize(dm, v, &size);
669:       DMPlexSetSupportSize(rdm, newp, size);
670:     }
671:     /* Edge vertices have 2 + faces*2 + cells*0/1 supports */
672:     for (e = eStart; e < eEnd; ++e) {
673:       const PetscInt newp = vStartNew + (vEnd - vStart) + (e - eStart);
674:       PetscInt       size, *star = NULL, starSize, s, cellSize = 0;

676:       DMPlexGetSupportSize(dm, e, &size);
677:       DMPlexGetTransitiveClosure(dm, e, PETSC_FALSE, &starSize, &star);
678:       for (s = 0; s < starSize*2; s += 2) {
679:         const PetscInt *cone, *ornt;
680:         PetscInt        e01, e23;

682:         if ((star[s] >= cStart) && (star[s] < cEnd)) {
683:           /* Check edge 0-1 */
684:           DMPlexGetCone(dm, star[s], &cone);
685:           DMPlexGetConeOrientation(dm, star[s], &ornt);
686:           DMPlexGetCone(dm, cone[0], &cone);
687:           e01  = cone[GetTriEdge_Static(ornt[0], 0)];
688:           /* Check edge 2-3 */
689:           DMPlexGetCone(dm, star[s], &cone);
690:           DMPlexGetConeOrientation(dm, star[s], &ornt);
691:           DMPlexGetCone(dm, cone[2], &cone);
692:           e23  = cone[GetTriEdge_Static(ornt[2], 1)];
693:           if ((e01 == e) || (e23 == e)) ++cellSize;
694:         }
695:       }
696:       DMPlexRestoreTransitiveClosure(dm, e, PETSC_FALSE, &starSize, &star);
697:       DMPlexSetSupportSize(rdm, newp, 2 + size*2 + cellSize);
698:     }
699:     break;
700:   case 7:
701:     /* Hybrid Simplicial 3D */
702:     DMPlexSetHybridBounds(rdm, cStartNew + 8*(cMax-cStart), fStartNew + 4*(fMax - fStart) + 8*(cMax - cStart),
703:                                  eStartNew + 2*(eMax - eStart) + 3*(fMax - fStart) + (cMax - cStart), PETSC_DETERMINE);
704:     /* Interior cells have 4 faces */
705:     for (c = cStart; c < cMax; ++c) {
706:       for (r = 0; r < 8; ++r) {
707:         const PetscInt newp = cStartNew + (c - cStart)*8 + r;

709:         DMPlexSetConeSize(rdm, newp, 4);
710:       }
711:     }
712:     /* Hybrid cells have 5 faces */
713:     for (c = cMax; c < cEnd; ++c) {
714:       for (r = 0; r < 4; ++r) {
715:         const PetscInt newp = cStartNew + (cMax - cStart)*8 + (c - cMax)*4 + r;

717:         DMPlexSetConeSize(rdm, newp, 5);
718:       }
719:     }
720:     /* Interior split faces have 3 edges and the same cells as the parent */
721:     for (f = fStart; f < fMax; ++f) {
722:       for (r = 0; r < 4; ++r) {
723:         const PetscInt newp = fStartNew + (f - fStart)*4 + r;
724:         PetscInt       size;

726:         DMPlexSetConeSize(rdm, newp, 3);
727:         DMPlexGetSupportSize(dm, f, &size);
728:         DMPlexSetSupportSize(rdm, newp, size);
729:       }
730:     }
731:     /* Interior cell faces have 3 edges and 2 cells */
732:     for (c = cStart; c < cMax; ++c) {
733:       for (r = 0; r < 8; ++r) {
734:         const PetscInt newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*8 + r;

736:         DMPlexSetConeSize(rdm, newp, 3);
737:         DMPlexSetSupportSize(rdm, newp, 2);
738:       }
739:     }
740:     /* Hybrid split faces have 4 edges and the same cells as the parent */
741:     for (f = fMax; f < fEnd; ++f) {
742:       for (r = 0; r < 2; ++r) {
743:         const PetscInt newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (f - fMax)*2 + r;
744:         PetscInt       size;

746:         DMPlexSetConeSize(rdm, newp, 4);
747:         DMPlexGetSupportSize(dm, f, &size);
748:         DMPlexSetSupportSize(rdm, newp, size);
749:       }
750:     }
751:     /* Hybrid cells faces have 4 edges and 2 cells */
752:     for (c = cMax; c < cEnd; ++c) {
753:       for (r = 0; r < 3; ++r) {
754:         const PetscInt newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (c - cMax)*3 + r;

756:         DMPlexSetConeSize(rdm, newp, 4);
757:         DMPlexSetSupportSize(rdm, newp, 2);
758:       }
759:     }
760:     /* Interior split edges have 2 vertices and the same faces */
761:     for (e = eStart; e < eMax; ++e) {
762:       for (r = 0; r < 2; ++r) {
763:         const PetscInt newp = eStartNew + (e - eStart)*2 + r;
764:         PetscInt       size;

766:         DMPlexSetConeSize(rdm, newp, 2);
767:         DMPlexGetSupportSize(dm, e, &size);
768:         DMPlexSetSupportSize(rdm, newp, size);
769:       }
770:     }
771:     /* Interior face edges have 2 vertices and 2+cells*(1/2) faces */
772:     for (f = fStart; f < fMax; ++f) {
773:       for (r = 0; r < 3; ++r) {
774:         const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (f - fStart)*3 + r;
775:         const PetscInt *cone, *ornt, *support, eint[4] = {1, 0, 2, 0};
776:         PetscInt        coneSize, c, supportSize, s, er, intFaces = 0;

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

805:       DMPlexSetConeSize(rdm, newp, 2);
806:       DMPlexSetSupportSize(rdm, newp, 4);
807:     }
808:     /* Hybrid edges have 2 vertices and the same faces */
809:     for (e = eMax; e < eEnd; ++e) {
810:       const PetscInt newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (e - eMax);
811:       PetscInt       size;

813:       DMPlexSetConeSize(rdm, newp, 2);
814:       DMPlexGetSupportSize(dm, e, &size);
815:       DMPlexSetSupportSize(rdm, newp, size);
816:     }
817:     /* Hybrid face edges have 2 vertices and 2+2*cells faces */
818:     for (f = fMax; f < fEnd; ++f) {
819:       const PetscInt newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (eEnd - eMax) + (f - fMax);
820:       PetscInt       size;

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

831:       DMPlexGetSupportSize(dm, v, &size);
832:       DMPlexSetSupportSize(rdm, newp, size);
833:     }
834:     /* Interior edge vertices have 2 + interior face*2 + hybrid face + cells*0/1 supports */
835:     for (e = eStart; e < eMax; ++e) {
836:       const PetscInt  newp = vStartNew + (vEnd - vStart) + (e - eStart);
837:       const PetscInt *support;
838:       PetscInt        size, *star = NULL, starSize, s, faceSize = 0, cellSize = 0;

840:       DMPlexGetSupportSize(dm, e, &size);
841:       DMPlexGetSupport(dm, e, &support);
842:       for (s = 0; s < size; ++s) {
843:         if (support[s] < fMax) faceSize += 2;
844:         else                   faceSize += 1;
845:       }
846:       DMPlexGetTransitiveClosure(dm, e, PETSC_FALSE, &starSize, &star);
847:       for (s = 0; s < starSize*2; s += 2) {
848:         const PetscInt *cone, *ornt;
849:         PetscInt        e01, e23;

851:         if ((star[s] >= cStart) && (star[s] < cMax)) {
852:           /* Check edge 0-1 */
853:           DMPlexGetCone(dm, star[s], &cone);
854:           DMPlexGetConeOrientation(dm, star[s], &ornt);
855:           DMPlexGetCone(dm, cone[0], &cone);
856:           e01  = cone[GetTriEdge_Static(ornt[0], 0)];
857:           /* Check edge 2-3 */
858:           DMPlexGetCone(dm, star[s], &cone);
859:           DMPlexGetConeOrientation(dm, star[s], &ornt);
860:           DMPlexGetCone(dm, cone[2], &cone);
861:           e23  = cone[GetTriEdge_Static(ornt[2], 1)];
862:           if ((e01 == e) || (e23 == e)) ++cellSize;
863:         }
864:       }
865:       DMPlexRestoreTransitiveClosure(dm, e, PETSC_FALSE, &starSize, &star);
866:       DMPlexSetSupportSize(rdm, newp, 2 + faceSize + cellSize);
867:     }
868:     break;
869:   case 6:
870:     /* Hex 3D */
871:     /* All cells have 6 faces */
872:     for (c = cStart; c < cEnd; ++c) {
873:       for (r = 0; r < 8; ++r) {
874:         const PetscInt newp = (c - cStart)*8 + r;

876:         DMPlexSetConeSize(rdm, newp, 6);
877:       }
878:     }
879:     /* Split faces have 4 edges and the same cells as the parent */
880:     for (f = fStart; f < fEnd; ++f) {
881:       for (r = 0; r < 4; ++r) {
882:         const PetscInt newp = fStartNew + (f - fStart)*4 + r;
883:         PetscInt       size;

885:         DMPlexSetConeSize(rdm, newp, 4);
886:         DMPlexGetSupportSize(dm, f, &size);
887:         DMPlexSetSupportSize(rdm, newp, size);
888:       }
889:     }
890:     /* Interior faces have 4 edges and 2 cells */
891:     for (c = cStart; c < cEnd; ++c) {
892:       for (r = 0; r < 12; ++r) {
893:         const PetscInt newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + r;

895:         DMPlexSetConeSize(rdm, newp, 4);
896:         DMPlexSetSupportSize(rdm, newp, 2);
897:       }
898:     }
899:     /* Split edges have 2 vertices and the same faces as the parent */
900:     for (e = eStart; e < eEnd; ++e) {
901:       for (r = 0; r < 2; ++r) {
902:         const PetscInt newp = eStartNew + (e - eStart)*2 + r;
903:         PetscInt       size;

905:         DMPlexSetConeSize(rdm, newp, 2);
906:         DMPlexGetSupportSize(dm, e, &size);
907:         DMPlexSetSupportSize(rdm, newp, size);
908:       }
909:     }
910:     /* Face edges have 2 vertices and 2+cells faces */
911:     for (f = fStart; f < fEnd; ++f) {
912:       for (r = 0; r < 4; ++r) {
913:         const PetscInt newp = eStartNew + (eEnd - eStart)*2 + (f - fStart)*4 + r;
914:         PetscInt       size;

916:         DMPlexSetConeSize(rdm, newp, 2);
917:         DMPlexGetSupportSize(dm, f, &size);
918:         DMPlexSetSupportSize(rdm, newp, 2+size);
919:       }
920:     }
921:     /* Cell edges have 2 vertices and 4 faces */
922:     for (c = cStart; c < cEnd; ++c) {
923:       for (r = 0; r < 6; ++r) {
924:         const PetscInt newp = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*4 + (c - cStart)*6 + r;

926:         DMPlexSetConeSize(rdm, newp, 2);
927:         DMPlexSetSupportSize(rdm, newp, 4);
928:       }
929:     }
930:     /* Old vertices have identical supports */
931:     for (v = vStart; v < vEnd; ++v) {
932:       const PetscInt newp = vStartNew + (v - vStart);
933:       PetscInt       size;

935:       DMPlexGetSupportSize(dm, v, &size);
936:       DMPlexSetSupportSize(rdm, newp, size);
937:     }
938:     /* Edge vertices have 2 + faces supports */
939:     for (e = eStart; e < eEnd; ++e) {
940:       const PetscInt newp = vStartNew + (vEnd - vStart) + (e - eStart);
941:       PetscInt       size;

943:       DMPlexGetSupportSize(dm, e, &size);
944:       DMPlexSetSupportSize(rdm, newp, 2 + size);
945:     }
946:     /* Face vertices have 4 + cells supports */
947:     for (f = fStart; f < fEnd; ++f) {
948:       const PetscInt newp = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (f - fStart);
949:       PetscInt       size;

951:       DMPlexGetSupportSize(dm, f, &size);
952:       DMPlexSetSupportSize(rdm, newp, 4 + size);
953:     }
954:     /* Cell vertices have 6 supports */
955:     for (c = cStart; c < cEnd; ++c) {
956:       const PetscInt newp = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (fEnd - fStart) + (c - cStart);

958:       DMPlexSetSupportSize(rdm, newp, 6);
959:     }
960:     break;
961:   case 8:
962:     /* Hybrid Hex 3D */
963:     DMPlexSetHybridBounds(rdm, cStartNew + 8*(cMax-cStart), fStartNew + 4*(fMax - fStart) + 12*(cMax - cStart),
964:                                  eStartNew + 2*(eMax - eStart) + 4*(fMax - fStart) + 6*(cMax - cStart), PETSC_DETERMINE);
965:     /* Interior cells have 6 faces */
966:     for (c = cStart; c < cMax; ++c) {
967:       for (r = 0; r < 8; ++r) {
968:         const PetscInt newp = cStartNew + (c - cStart)*8 + r;

970:         DMPlexSetConeSize(rdm, newp, 6);
971:       }
972:     }
973:     /* Hybrid cells have 6 faces */
974:     for (c = cMax; c < cEnd; ++c) {
975:       for (r = 0; r < 4; ++r) {
976:         const PetscInt newp = cStartNew + (cMax - cStart)*8 + (c - cMax)*4 + r;

978:         DMPlexSetConeSize(rdm, newp, 6);
979:       }
980:     }
981:     /* Interior split faces have 4 edges and the same cells as the parent */
982:     for (f = fStart; f < fMax; ++f) {
983:       for (r = 0; r < 4; ++r) {
984:         const PetscInt newp = fStartNew + (f - fStart)*4 + r;
985:         PetscInt       size;

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

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

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

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

1027:         DMPlexSetConeSize(rdm, newp, 2);
1028:         DMPlexGetSupportSize(dm, e, &size);
1029:         DMPlexSetSupportSize(rdm, newp, size);
1030:       }
1031:     }
1032:     /* Interior face edges have 2 vertices and 2+cells faces */
1033:     for (f = fStart; f < fMax; ++f) {
1034:       for (r = 0; r < 4; ++r) {
1035:         const PetscInt newp = eStartNew + (eMax - eStart)*2 + (f - fStart)*4 + r;
1036:         PetscInt       size;

1038:         DMPlexSetConeSize(rdm, newp, 2);
1039:         DMPlexGetSupportSize(dm, f, &size);
1040:         DMPlexSetSupportSize(rdm, newp, 2+size);
1041:       }
1042:     }
1043:     /* Interior cell edges have 2 vertices and 4 faces */
1044:     for (c = cStart; c < cMax; ++c) {
1045:       for (r = 0; r < 6; ++r) {
1046:         const PetscInt newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (c - cStart)*6 + r;

1048:         DMPlexSetConeSize(rdm, newp, 2);
1049:         DMPlexSetSupportSize(rdm, newp, 4);
1050:       }
1051:     }
1052:     /* Hybrid edges have 2 vertices and the same faces */
1053:     for (e = eMax; e < eEnd; ++e) {
1054:       const PetscInt newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (e - eMax);
1055:       PetscInt       size;

1057:       DMPlexSetConeSize(rdm, newp, 2);
1058:       DMPlexGetSupportSize(dm, e, &size);
1059:       DMPlexSetSupportSize(rdm, newp, size);
1060:     }
1061:     /* Hybrid face edges have 2 vertices and 2+cells faces */
1062:     for (f = fMax; f < fEnd; ++f) {
1063:       const PetscInt newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (eEnd - eMax) + (f - fMax);
1064:       PetscInt       size;

1066:       DMPlexSetConeSize(rdm, newp, 2);
1067:       DMPlexGetSupportSize(dm, f, &size);
1068:       DMPlexSetSupportSize(rdm, newp, 2+size);
1069:     }
1070:     /* Hybrid cell edges have 2 vertices and 4 faces */
1071:     for (c = cMax; c < cEnd; ++c) {
1072:       const PetscInt newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (eEnd - eMax) + (fEnd - fMax) + (c - cMax);

1074:       DMPlexSetConeSize(rdm, newp, 2);
1075:       DMPlexSetSupportSize(rdm, newp, 4);
1076:     }
1077:     /* Interior vertices have identical supports */
1078:     for (v = vStart; v < vEnd; ++v) {
1079:       const PetscInt newp = vStartNew + (v - vStart);
1080:       PetscInt       size;

1082:       DMPlexGetSupportSize(dm, v, &size);
1083:       DMPlexSetSupportSize(rdm, newp, size);
1084:     }
1085:     /* Interior edge vertices have 2 + faces supports */
1086:     for (e = eStart; e < eMax; ++e) {
1087:       const PetscInt newp = vStartNew + (vEnd - vStart) + (e - eStart);
1088:       PetscInt       size;

1090:       DMPlexGetSupportSize(dm, e, &size);
1091:       DMPlexSetSupportSize(rdm, newp, 2 + size);
1092:     }
1093:     /* Interior face vertices have 4 + cells supports */
1094:     for (f = fStart; f < fMax; ++f) {
1095:       const PetscInt newp = vStartNew + (vEnd - vStart) + (eMax - eStart) + (f - fStart);
1096:       PetscInt       size;

1098:       DMPlexGetSupportSize(dm, f, &size);
1099:       DMPlexSetSupportSize(rdm, newp, 4 + size);
1100:     }
1101:     /* Interior cell vertices have 6 supports */
1102:     for (c = cStart; c < cMax; ++c) {
1103:       const PetscInt newp = vStartNew + (vEnd - vStart) + (eMax - eStart) + (fMax - fStart) + (c - cStart);

1105:       DMPlexSetSupportSize(rdm, newp, 6);
1106:     }
1107:     break;
1108:   default:
1109:     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
1110:   }
1111:   return(0);
1112: }

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

1125:   if (!refiner) return(0);
1126:   DMPlexGetDepth(dm, &depth);
1127:   DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);
1128:   DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);
1129:   DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);
1130:   DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);
1131:   DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);
1132:   GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);
1133:   GetDepthEnd_Private(depth, depthSize, &cEndNew, &fEndNew, &eEndNew, &vEndNew);
1134:   switch (refiner) {
1135:   case 1:
1136:     /* Simplicial 2D */
1137:     /*
1138:      2
1139:      |\
1140:      | \
1141:      |  \
1142:      |   \
1143:      | C  \
1144:      |     \
1145:      |      \
1146:      2---1---1
1147:      |\  D  / \
1148:      | 2   0   \
1149:      |A \ /  B  \
1150:      0---0-------1
1151:      */
1152:     /* All cells have 3 faces */
1153:     for (c = cStart; c < cEnd; ++c) {
1154:       const PetscInt  newp = cStartNew + (c - cStart)*4;
1155:       const PetscInt *cone, *ornt;
1156:       PetscInt        coneNew[3], orntNew[3];

1158:       DMPlexGetCone(dm, c, &cone);
1159:       DMPlexGetConeOrientation(dm, c, &ornt);
1160:       /* A triangle */
1161:       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
1162:       orntNew[0] = ornt[0];
1163:       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 2;
1164:       orntNew[1] = -2;
1165:       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
1166:       orntNew[2] = ornt[2];
1167:       DMPlexSetCone(rdm, newp+0, coneNew);
1168:       DMPlexSetConeOrientation(rdm, newp+0, orntNew);
1169: #if 1
1170:       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);
1171:       for (p = 0; p < 3; ++p) {
1172:         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);
1173:       }
1174: #endif
1175:       /* B triangle */
1176:       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
1177:       orntNew[0] = ornt[0];
1178:       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
1179:       orntNew[1] = ornt[1];
1180:       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 0;
1181:       orntNew[2] = -2;
1182:       DMPlexSetCone(rdm, newp+1, coneNew);
1183:       DMPlexSetConeOrientation(rdm, newp+1, orntNew);
1184: #if 1
1185:       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);
1186:       for (p = 0; p < 3; ++p) {
1187:         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);
1188:       }
1189: #endif
1190:       /* C triangle */
1191:       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 1;
1192:       orntNew[0] = -2;
1193:       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
1194:       orntNew[1] = ornt[1];
1195:       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
1196:       orntNew[2] = ornt[2];
1197:       DMPlexSetCone(rdm, newp+2, coneNew);
1198:       DMPlexSetConeOrientation(rdm, newp+2, orntNew);
1199: #if 1
1200:       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);
1201:       for (p = 0; p < 3; ++p) {
1202:         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);
1203:       }
1204: #endif
1205:       /* D triangle */
1206:       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 0;
1207:       orntNew[0] = 0;
1208:       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 1;
1209:       orntNew[1] = 0;
1210:       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 2;
1211:       orntNew[2] = 0;
1212:       DMPlexSetCone(rdm, newp+3, coneNew);
1213:       DMPlexSetConeOrientation(rdm, newp+3, orntNew);
1214: #if 1
1215:       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);
1216:       for (p = 0; p < 3; ++p) {
1217:         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);
1218:       }
1219: #endif
1220:     }
1221:     /* Split faces have 2 vertices and the same cells as the parent */
1222:     DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);
1223:     PetscMalloc1((2 + maxSupportSize*2), &supportRef);
1224:     for (f = fStart; f < fEnd; ++f) {
1225:       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);

1227:       for (r = 0; r < 2; ++r) {
1228:         const PetscInt  newp = fStartNew + (f - fStart)*2 + r;
1229:         const PetscInt *cone, *ornt, *support;
1230:         PetscInt        coneNew[2], coneSize, c, supportSize, s;

1232:         DMPlexGetCone(dm, f, &cone);
1233:         coneNew[0]       = vStartNew + (cone[0] - vStart);
1234:         coneNew[1]       = vStartNew + (cone[1] - vStart);
1235:         coneNew[(r+1)%2] = newv;
1236:         DMPlexSetCone(rdm, newp, coneNew);
1237: #if 1
1238:         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1239:         for (p = 0; p < 2; ++p) {
1240:           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);
1241:         }
1242: #endif
1243:         DMPlexGetSupportSize(dm, f, &supportSize);
1244:         DMPlexGetSupport(dm, f, &support);
1245:         for (s = 0; s < supportSize; ++s) {
1246:           DMPlexGetConeSize(dm, support[s], &coneSize);
1247:           DMPlexGetCone(dm, support[s], &cone);
1248:           DMPlexGetConeOrientation(dm, support[s], &ornt);
1249:           for (c = 0; c < coneSize; ++c) {
1250:             if (cone[c] == f) break;
1251:           }
1252:           supportRef[s] = cStartNew + (support[s] - cStart)*4 + (ornt[c] < 0 ? (c+1-r)%3 : (c+r)%3);
1253:         }
1254:         DMPlexSetSupport(rdm, newp, supportRef);
1255: #if 1
1256:         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1257:         for (p = 0; p < supportSize; ++p) {
1258:           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);
1259:         }
1260: #endif
1261:       }
1262:     }
1263:     /* Interior faces have 2 vertices and 2 cells */
1264:     for (c = cStart; c < cEnd; ++c) {
1265:       const PetscInt *cone;

1267:       DMPlexGetCone(dm, c, &cone);
1268:       for (r = 0; r < 3; ++r) {
1269:         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*3 + r;
1270:         PetscInt       coneNew[2];
1271:         PetscInt       supportNew[2];

1273:         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r]       - fStart);
1274:         coneNew[1] = vStartNew + (vEnd - vStart) + (cone[(r+1)%3] - fStart);
1275:         DMPlexSetCone(rdm, newp, coneNew);
1276: #if 1
1277:         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1278:         for (p = 0; p < 2; ++p) {
1279:           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);
1280:         }
1281: #endif
1282:         supportNew[0] = (c - cStart)*4 + (r+1)%3;
1283:         supportNew[1] = (c - cStart)*4 + 3;
1284:         DMPlexSetSupport(rdm, newp, supportNew);
1285: #if 1
1286:         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1287:         for (p = 0; p < 2; ++p) {
1288:           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);
1289:         }
1290: #endif
1291:       }
1292:     }
1293:     /* Old vertices have identical supports */
1294:     for (v = vStart; v < vEnd; ++v) {
1295:       const PetscInt  newp = vStartNew + (v - vStart);
1296:       const PetscInt *support, *cone;
1297:       PetscInt        size, s;

1299:       DMPlexGetSupportSize(dm, v, &size);
1300:       DMPlexGetSupport(dm, v, &support);
1301:       for (s = 0; s < size; ++s) {
1302:         PetscInt r = 0;

1304:         DMPlexGetCone(dm, support[s], &cone);
1305:         if (cone[1] == v) r = 1;
1306:         supportRef[s] = fStartNew + (support[s] - fStart)*2 + r;
1307:       }
1308:       DMPlexSetSupport(rdm, newp, supportRef);
1309: #if 1
1310:       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
1311:       for (p = 0; p < size; ++p) {
1312:         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);
1313:       }
1314: #endif
1315:     }
1316:     /* Face vertices have 2 + cells*2 supports */
1317:     for (f = fStart; f < fEnd; ++f) {
1318:       const PetscInt  newp = vStartNew + (vEnd - vStart) + (f - fStart);
1319:       const PetscInt *cone, *support;
1320:       PetscInt        size, s;

1322:       DMPlexGetSupportSize(dm, f, &size);
1323:       DMPlexGetSupport(dm, f, &support);
1324:       supportRef[0] = fStartNew + (f - fStart)*2 + 0;
1325:       supportRef[1] = fStartNew + (f - fStart)*2 + 1;
1326:       for (s = 0; s < size; ++s) {
1327:         PetscInt r = 0;

1329:         DMPlexGetCone(dm, support[s], &cone);
1330:         if      (cone[1] == f) r = 1;
1331:         else if (cone[2] == f) r = 2;
1332:         supportRef[2+s*2+0] = fStartNew + (fEnd - fStart)*2 + (support[s] - cStart)*3 + (r+2)%3;
1333:         supportRef[2+s*2+1] = fStartNew + (fEnd - fStart)*2 + (support[s] - cStart)*3 + r;
1334:       }
1335:       DMPlexSetSupport(rdm, newp, supportRef);
1336: #if 1
1337:       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
1338:       for (p = 0; p < 2+size*2; ++p) {
1339:         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);
1340:       }
1341: #endif
1342:     }
1343:     PetscFree(supportRef);
1344:     break;
1345:   case 2:
1346:     /* Hex 2D */
1347:     /*
1348:      3---------2---------2
1349:      |         |         |
1350:      |    D    2    C    |
1351:      |         |         |
1352:      3----3----0----1----1
1353:      |         |         |
1354:      |    A    0    B    |
1355:      |         |         |
1356:      0---------0---------1
1357:      */
1358:     /* All cells have 4 faces */
1359:     for (c = cStart; c < cEnd; ++c) {
1360:       const PetscInt  newp = (c - cStart)*4;
1361:       const PetscInt *cone, *ornt;
1362:       PetscInt        coneNew[4], orntNew[4];

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

1441:       for (r = 0; r < 2; ++r) {
1442:         const PetscInt  newp = fStartNew + (f - fStart)*2 + r;
1443:         const PetscInt *cone, *ornt, *support;
1444:         PetscInt        coneNew[2], coneSize, c, supportSize, s;

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

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

1486:         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r] - fStart);
1487:         coneNew[1] = vStartNew + (vEnd - vStart) + (fEnd    - fStart) + (c - cStart);
1488:         DMPlexSetCone(rdm, newp, coneNew);
1489: #if 1
1490:         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1491:         for (p = 0; p < 2; ++p) {
1492:           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);
1493:         }
1494: #endif
1495:         supportNew[0] = (c - cStart)*4 + r;
1496:         supportNew[1] = (c - cStart)*4 + (r+1)%4;
1497:         DMPlexSetSupport(rdm, newp, supportNew);
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 ((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);
1502:         }
1503: #endif
1504:       }
1505:     }
1506:     /* Old vertices have identical supports */
1507:     for (v = vStart; v < vEnd; ++v) {
1508:       const PetscInt  newp = vStartNew + (v - vStart);
1509:       const PetscInt *support, *cone;
1510:       PetscInt        size, s;

1512:       DMPlexGetSupportSize(dm, v, &size);
1513:       DMPlexGetSupport(dm, v, &support);
1514:       for (s = 0; s < size; ++s) {
1515:         PetscInt r = 0;

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

1535:       DMPlexGetSupportSize(dm, f, &size);
1536:       DMPlexGetSupport(dm, f, &support);
1537:       supportRef[0] = fStartNew + (f - fStart)*2 + 0;
1538:       supportRef[1] = fStartNew + (f - fStart)*2 + 1;
1539:       for (s = 0; s < size; ++s) {
1540:         PetscInt r = 0;

1542:         DMPlexGetCone(dm, support[s], &cone);
1543:         if      (cone[1] == f) r = 1;
1544:         else if (cone[2] == f) r = 2;
1545:         else if (cone[3] == f) r = 3;
1546:         supportRef[2+s] = fStartNew + (fEnd - fStart)*2 + (support[s] - cStart)*4 + r;
1547:       }
1548:       DMPlexSetSupport(rdm, newp, supportRef);
1549: #if 1
1550:       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
1551:       for (p = 0; p < 2+size; ++p) {
1552:         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);
1553:       }
1554: #endif
1555:     }
1556:     /* Cell vertices have 4 supports */
1557:     for (c = cStart; c < cEnd; ++c) {
1558:       const PetscInt newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (c - cStart);
1559:       PetscInt       supportNew[4];

1561:       for (r = 0; r < 4; ++r) {
1562:         supportNew[r] = fStartNew + (fEnd - fStart)*2 + (c - cStart)*4 + r;
1563:       }
1564:       DMPlexSetSupport(rdm, newp, supportNew);
1565:     }
1566:     PetscFree(supportRef);
1567:     break;
1568:   case 3:
1569:     /* Hybrid Simplicial 2D */
1570:     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
1571:     cMax = PetscMin(cEnd, cMax);
1572:     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
1573:     fMax = PetscMin(fEnd, fMax);
1574:     DMPlexGetHybridBounds(rdm, &cMaxNew, &fMaxNew, NULL, NULL);
1575:     /* Interior cells have 3 faces */
1576:     for (c = cStart; c < cMax; ++c) {
1577:       const PetscInt  newp = cStartNew + (c - cStart)*4;
1578:       const PetscInt *cone, *ornt;
1579:       PetscInt        coneNew[3], orntNew[3];

1581:       DMPlexGetCone(dm, c, &cone);
1582:       DMPlexGetConeOrientation(dm, c, &ornt);
1583:       /* A triangle */
1584:       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
1585:       orntNew[0] = ornt[0];
1586:       coneNew[1] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 2;
1587:       orntNew[1] = -2;
1588:       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
1589:       orntNew[2] = ornt[2];
1590:       DMPlexSetCone(rdm, newp+0, coneNew);
1591:       DMPlexSetConeOrientation(rdm, newp+0, orntNew);
1592: #if 1
1593:       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);
1594:       for (p = 0; p < 3; ++p) {
1595:         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);
1596:       }
1597: #endif
1598:       /* B triangle */
1599:       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
1600:       orntNew[0] = ornt[0];
1601:       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
1602:       orntNew[1] = ornt[1];
1603:       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 0;
1604:       orntNew[2] = -2;
1605:       DMPlexSetCone(rdm, newp+1, coneNew);
1606:       DMPlexSetConeOrientation(rdm, newp+1, orntNew);
1607: #if 1
1608:       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);
1609:       for (p = 0; p < 3; ++p) {
1610:         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);
1611:       }
1612: #endif
1613:       /* C triangle */
1614:       coneNew[0] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 1;
1615:       orntNew[0] = -2;
1616:       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
1617:       orntNew[1] = ornt[1];
1618:       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
1619:       orntNew[2] = ornt[2];
1620:       DMPlexSetCone(rdm, newp+2, coneNew);
1621:       DMPlexSetConeOrientation(rdm, newp+2, orntNew);
1622: #if 1
1623:       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);
1624:       for (p = 0; p < 3; ++p) {
1625:         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);
1626:       }
1627: #endif
1628:       /* D triangle */
1629:       coneNew[0] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 0;
1630:       orntNew[0] = 0;
1631:       coneNew[1] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 1;
1632:       orntNew[1] = 0;
1633:       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 2;
1634:       orntNew[2] = 0;
1635:       DMPlexSetCone(rdm, newp+3, coneNew);
1636:       DMPlexSetConeOrientation(rdm, newp+3, orntNew);
1637: #if 1
1638:       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);
1639:       for (p = 0; p < 3; ++p) {
1640:         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);
1641:       }
1642: #endif
1643:     }
1644:     /*
1645:      2----3----3
1646:      |         |
1647:      |    B    |
1648:      |         |
1649:      0----4--- 1
1650:      |         |
1651:      |    A    |
1652:      |         |
1653:      0----2----1
1654:      */
1655:     /* Hybrid cells have 4 faces */
1656:     for (c = cMax; c < cEnd; ++c) {
1657:       const PetscInt  newp = cStartNew + (cMax - cStart)*4 + (c - cMax)*2;
1658:       const PetscInt *cone, *ornt;
1659:       PetscInt        coneNew[4], orntNew[4], r;

1661:       DMPlexGetCone(dm, c, &cone);
1662:       DMPlexGetConeOrientation(dm, c, &ornt);
1663:       r    = (ornt[0] < 0 ? 1 : 0);
1664:       /* A quad */
1665:       coneNew[0]   = fStartNew + (cone[0] - fStart)*2 + r;
1666:       orntNew[0]   = ornt[0];
1667:       coneNew[1]   = fStartNew + (cone[1] - fStart)*2 + r;
1668:       orntNew[1]   = ornt[1];
1669:       coneNew[2+r] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (cone[2+r] - fMax);
1670:       orntNew[2+r] = 0;
1671:       coneNew[3-r] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (fEnd    - fMax) + (c - cMax);
1672:       orntNew[3-r] = 0;
1673:       DMPlexSetCone(rdm, newp+0, coneNew);
1674:       DMPlexSetConeOrientation(rdm, newp+0, orntNew);
1675: #if 1
1676:       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);
1677:       for (p = 0; p < 4; ++p) {
1678:         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);
1679:       }
1680: #endif
1681:       /* B quad */
1682:       coneNew[0]   = fStartNew + (cone[0] - fStart)*2 + 1-r;
1683:       orntNew[0]   = ornt[0];
1684:       coneNew[1]   = fStartNew + (cone[1] - fStart)*2 + 1-r;
1685:       orntNew[1]   = ornt[1];
1686:       coneNew[2+r] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (fEnd    - fMax) + (c - cMax);
1687:       orntNew[2+r] = 0;
1688:       coneNew[3-r] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (cone[3-r] - fMax);
1689:       orntNew[3-r] = 0;
1690:       DMPlexSetCone(rdm, newp+1, coneNew);
1691:       DMPlexSetConeOrientation(rdm, newp+1, orntNew);
1692: #if 1
1693:       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);
1694:       for (p = 0; p < 4; ++p) {
1695:         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);
1696:       }
1697: #endif
1698:     }
1699:     /* Interior split faces have 2 vertices and the same cells as the parent */
1700:     DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);
1701:     PetscMalloc1((2 + maxSupportSize*2), &supportRef);
1702:     for (f = fStart; f < fMax; ++f) {
1703:       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);

1705:       for (r = 0; r < 2; ++r) {
1706:         const PetscInt  newp = fStartNew + (f - fStart)*2 + r;
1707:         const PetscInt *cone, *ornt, *support;
1708:         PetscInt        coneNew[2], coneSize, c, supportSize, s;

1710:         DMPlexGetCone(dm, f, &cone);
1711:         coneNew[0]       = vStartNew + (cone[0] - vStart);
1712:         coneNew[1]       = vStartNew + (cone[1] - vStart);
1713:         coneNew[(r+1)%2] = newv;
1714:         DMPlexSetCone(rdm, newp, coneNew);
1715: #if 1
1716:         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1717:         for (p = 0; p < 2; ++p) {
1718:           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);
1719:         }
1720: #endif
1721:         DMPlexGetSupportSize(dm, f, &supportSize);
1722:         DMPlexGetSupport(dm, f, &support);
1723:         for (s = 0; s < supportSize; ++s) {
1724:           DMPlexGetConeSize(dm, support[s], &coneSize);
1725:           DMPlexGetCone(dm, support[s], &cone);
1726:           DMPlexGetConeOrientation(dm, support[s], &ornt);
1727:           for (c = 0; c < coneSize; ++c) if (cone[c] == f) break;
1728:           if (support[s] >= cMax) {
1729:             supportRef[s] = cStartNew + (cMax - cStart)*4 + (support[s] - cMax)*2 + (ornt[c] < 0 ? 1-r : r);
1730:           } else {
1731:             supportRef[s] = cStartNew + (support[s] - cStart)*4 + (ornt[c] < 0 ? (c+1-r)%3 : (c+r)%3);
1732:           }
1733:         }
1734:         DMPlexSetSupport(rdm, newp, supportRef);
1735: #if 1
1736:         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1737:         for (p = 0; p < supportSize; ++p) {
1738:           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);
1739:         }
1740: #endif
1741:       }
1742:     }
1743:     /* Interior cell faces have 2 vertices and 2 cells */
1744:     for (c = cStart; c < cMax; ++c) {
1745:       const PetscInt *cone;

1747:       DMPlexGetCone(dm, c, &cone);
1748:       for (r = 0; r < 3; ++r) {
1749:         const PetscInt newp = fStartNew + (fMax - fStart)*2 + (c - cStart)*3 + r;
1750:         PetscInt       coneNew[2];
1751:         PetscInt       supportNew[2];

1753:         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r]       - fStart);
1754:         coneNew[1] = vStartNew + (vEnd - vStart) + (cone[(r+1)%3] - fStart);
1755:         DMPlexSetCone(rdm, newp, coneNew);
1756: #if 1
1757:         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1758:         for (p = 0; p < 2; ++p) {
1759:           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);
1760:         }
1761: #endif
1762:         supportNew[0] = (c - cStart)*4 + (r+1)%3;
1763:         supportNew[1] = (c - cStart)*4 + 3;
1764:         DMPlexSetSupport(rdm, newp, supportNew);
1765: #if 1
1766:         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1767:         for (p = 0; p < 2; ++p) {
1768:           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);
1769:         }
1770: #endif
1771:       }
1772:     }
1773:     /* Interior hybrid faces have 2 vertices and the same cells */
1774:     for (f = fMax; f < fEnd; ++f) {
1775:       const PetscInt  newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (f - fMax);
1776:       const PetscInt *cone, *ornt;
1777:       const PetscInt *support;
1778:       PetscInt        coneNew[2];
1779:       PetscInt        supportNew[2];
1780:       PetscInt        size, s, r;

1782:       DMPlexGetCone(dm, f, &cone);
1783:       coneNew[0] = vStartNew + (cone[0] - vStart);
1784:       coneNew[1] = vStartNew + (cone[1] - vStart);
1785:       DMPlexSetCone(rdm, newp, coneNew);
1786: #if 1
1787:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1788:       for (p = 0; p < 2; ++p) {
1789:         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);
1790:       }
1791: #endif
1792:       DMPlexGetSupportSize(dm, f, &size);
1793:       DMPlexGetSupport(dm, f, &support);
1794:       for (s = 0; s < size; ++s) {
1795:         DMPlexGetCone(dm, support[s], &cone);
1796:         DMPlexGetConeOrientation(dm, support[s], &ornt);
1797:         for (r = 0; r < 2; ++r) {
1798:           if (cone[r+2] == f) break;
1799:         }
1800:         supportNew[s] = (cMax - cStart)*4 + (support[s] - cMax)*2 + (ornt[0] < 0 ? 1-r : r);
1801:       }
1802:       DMPlexSetSupport(rdm, newp, supportNew);
1803: #if 1
1804:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1805:       for (p = 0; p < size; ++p) {
1806:         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);
1807:       }
1808: #endif
1809:     }
1810:     /* Cell hybrid faces have 2 vertices and 2 cells */
1811:     for (c = cMax; c < cEnd; ++c) {
1812:       const PetscInt  newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (fEnd - fMax) + (c - cMax);
1813:       const PetscInt *cone;
1814:       PetscInt        coneNew[2];
1815:       PetscInt        supportNew[2];

1817:       DMPlexGetCone(dm, c, &cone);
1818:       coneNew[0] = vStartNew + (vEnd - vStart) + (cone[0] - fStart);
1819:       coneNew[1] = vStartNew + (vEnd - vStart) + (cone[1] - fStart);
1820:       DMPlexSetCone(rdm, newp, coneNew);
1821: #if 1
1822:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1823:       for (p = 0; p < 2; ++p) {
1824:         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);
1825:       }
1826: #endif
1827:       supportNew[0] = (cMax - cStart)*4 + (c - cMax)*2 + 0;
1828:       supportNew[1] = (cMax - cStart)*4 + (c - cMax)*2 + 1;
1829:       DMPlexSetSupport(rdm, newp, supportNew);
1830: #if 1
1831:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1832:       for (p = 0; p < 2; ++p) {
1833:         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);
1834:       }
1835: #endif
1836:     }
1837:     /* Old vertices have identical supports */
1838:     for (v = vStart; v < vEnd; ++v) {
1839:       const PetscInt  newp = vStartNew + (v - vStart);
1840:       const PetscInt *support, *cone;
1841:       PetscInt        size, s;

1843:       DMPlexGetSupportSize(dm, v, &size);
1844:       DMPlexGetSupport(dm, v, &support);
1845:       for (s = 0; s < size; ++s) {
1846:         if (support[s] >= fMax) {
1847:           supportRef[s] = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (support[s] - fMax);
1848:         } else {
1849:           PetscInt r = 0;

1851:           DMPlexGetCone(dm, support[s], &cone);
1852:           if (cone[1] == v) r = 1;
1853:           supportRef[s] = fStartNew + (support[s] - fStart)*2 + r;
1854:         }
1855:       }
1856:       DMPlexSetSupport(rdm, newp, supportRef);
1857: #if 1
1858:       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
1859:       for (p = 0; p < size; ++p) {
1860:         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);
1861:       }
1862: #endif
1863:     }
1864:     /* Face vertices have 2 + (2 interior, 1 hybrid) supports */
1865:     for (f = fStart; f < fMax; ++f) {
1866:       const PetscInt  newp = vStartNew + (vEnd - vStart) + (f - fStart);
1867:       const PetscInt *cone, *support;
1868:       PetscInt        size, newSize = 2, s;

1870:       DMPlexGetSupportSize(dm, f, &size);
1871:       DMPlexGetSupport(dm, f, &support);
1872:       supportRef[0] = fStartNew + (f - fStart)*2 + 0;
1873:       supportRef[1] = fStartNew + (f - fStart)*2 + 1;
1874:       for (s = 0; s < size; ++s) {
1875:         PetscInt r = 0;

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

1881:           newSize += 1;
1882:         } else {
1883:           if      (cone[1] == f) r = 1;
1884:           else if (cone[2] == f) r = 2;
1885:           supportRef[newSize+0] = fStartNew + (fMax - fStart)*2 + (support[s] - cStart)*3 + (r+2)%3;
1886:           supportRef[newSize+1] = fStartNew + (fMax - fStart)*2 + (support[s] - cStart)*3 + r;

1888:           newSize += 2;
1889:         }
1890:       }
1891:       DMPlexSetSupport(rdm, newp, supportRef);
1892: #if 1
1893:       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
1894:       for (p = 0; p < newSize; ++p) {
1895:         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);
1896:       }
1897: #endif
1898:     }
1899:     PetscFree(supportRef);
1900:     break;
1901:   case 4:
1902:     /* Hybrid Hex 2D */
1903:     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
1904:     cMax = PetscMin(cEnd, cMax);
1905:     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
1906:     fMax = PetscMin(fEnd, fMax);
1907:     DMPlexGetHybridBounds(rdm, &cMaxNew, &fMaxNew, NULL, NULL);
1908:     /* Interior cells have 4 faces */
1909:     for (c = cStart; c < cMax; ++c) {
1910:       const PetscInt  newp = cStartNew + (c - cStart)*4;
1911:       const PetscInt *cone, *ornt;
1912:       PetscInt        coneNew[4], orntNew[4];

1914:       DMPlexGetCone(dm, c, &cone);
1915:       DMPlexGetConeOrientation(dm, c, &ornt);
1916:       /* A quad */
1917:       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
1918:       orntNew[0] = ornt[0];
1919:       coneNew[1] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*4 + 0;
1920:       orntNew[1] = 0;
1921:       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*4 + 3;
1922:       orntNew[2] = -2;
1923:       coneNew[3] = fStartNew + (cone[3] - fStart)*2 + (ornt[3] < 0 ? 0 : 1);
1924:       orntNew[3] = ornt[3];
1925:       DMPlexSetCone(rdm, newp+0, coneNew);
1926:       DMPlexSetConeOrientation(rdm, newp+0, orntNew);
1927: #if 1
1928:       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);
1929:       for (p = 0; p < 4; ++p) {
1930:         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);
1931:       }
1932: #endif
1933:       /* B quad */
1934:       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
1935:       orntNew[0] = ornt[0];
1936:       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
1937:       orntNew[1] = ornt[1];
1938:       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*4 + 1;
1939:       orntNew[2] = 0;
1940:       coneNew[3] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*4 + 0;
1941:       orntNew[3] = -2;
1942:       DMPlexSetCone(rdm, newp+1, coneNew);
1943:       DMPlexSetConeOrientation(rdm, newp+1, orntNew);
1944: #if 1
1945:       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);
1946:       for (p = 0; p < 4; ++p) {
1947:         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);
1948:       }
1949: #endif
1950:       /* C quad */
1951:       coneNew[0] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*4 + 1;
1952:       orntNew[0] = -2;
1953:       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
1954:       orntNew[1] = ornt[1];
1955:       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
1956:       orntNew[2] = ornt[2];
1957:       coneNew[3] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*4 + 2;
1958:       orntNew[3] = 0;
1959:       DMPlexSetCone(rdm, newp+2, coneNew);
1960:       DMPlexSetConeOrientation(rdm, newp+2, orntNew);
1961: #if 1
1962:       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);
1963:       for (p = 0; p < 4; ++p) {
1964:         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);
1965:       }
1966: #endif
1967:       /* D quad */
1968:       coneNew[0] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*4 + 3;
1969:       orntNew[0] = 0;
1970:       coneNew[1] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*4 + 2;
1971:       orntNew[1] = -2;
1972:       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
1973:       orntNew[2] = ornt[2];
1974:       coneNew[3] = fStartNew + (cone[3] - fStart)*2 + (ornt[3] < 0 ? 1 : 0);
1975:       orntNew[3] = ornt[3];
1976:       DMPlexSetCone(rdm, newp+3, coneNew);
1977:       DMPlexSetConeOrientation(rdm, newp+3, orntNew);
1978: #if 1
1979:       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);
1980:       for (p = 0; p < 4; ++p) {
1981:         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);
1982:       }
1983: #endif
1984:     }
1985:     /*
1986:      2----3----3
1987:      |         |
1988:      |    B    |
1989:      |         |
1990:      0----4--- 1
1991:      |         |
1992:      |    A    |
1993:      |         |
1994:      0----2----1
1995:      */
1996:     /* Hybrid cells have 4 faces */
1997:     for (c = cMax; c < cEnd; ++c) {
1998:       const PetscInt  newp = cStartNew + (cMax - cStart)*4 + (c - cMax)*2;
1999:       const PetscInt *cone, *ornt;
2000:       PetscInt        coneNew[4], orntNew[4];

2002:       DMPlexGetCone(dm, c, &cone);
2003:       DMPlexGetConeOrientation(dm, c, &ornt);
2004:       /* A quad */
2005:       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
2006:       orntNew[0] = ornt[0];
2007:       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
2008:       orntNew[1] = ornt[1];
2009:       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*4 + (cone[2] - fMax);
2010:       orntNew[2] = 0;
2011:       coneNew[3] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*4 + (fEnd    - fMax) + (c - cMax);
2012:       orntNew[3] = 0;
2013:       DMPlexSetCone(rdm, newp+0, coneNew);
2014:       DMPlexSetConeOrientation(rdm, newp+0, orntNew);
2015: #if 1
2016:       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);
2017:       for (p = 0; p < 4; ++p) {
2018:         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);
2019:       }
2020: #endif
2021:       /* B quad */
2022:       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
2023:       orntNew[0] = ornt[0];
2024:       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
2025:       orntNew[1] = ornt[1];
2026:       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*4 + (fEnd    - fMax) + (c - cMax);
2027:       orntNew[2] = 0;
2028:       coneNew[3] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*4 + (cone[3] - fMax);
2029:       orntNew[3] = 0;
2030:       DMPlexSetCone(rdm, newp+1, coneNew);
2031:       DMPlexSetConeOrientation(rdm, newp+1, orntNew);
2032: #if 1
2033:       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);
2034:       for (p = 0; p < 4; ++p) {
2035:         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);
2036:       }
2037: #endif
2038:     }
2039:     /* Interior split faces have 2 vertices and the same cells as the parent */
2040:     DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);
2041:     PetscMalloc1((2 + maxSupportSize*2), &supportRef);
2042:     for (f = fStart; f < fMax; ++f) {
2043:       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);

2045:       for (r = 0; r < 2; ++r) {
2046:         const PetscInt  newp = fStartNew + (f - fStart)*2 + r;
2047:         const PetscInt *cone, *ornt, *support;
2048:         PetscInt        coneNew[2], coneSize, c, supportSize, s;

2050:         DMPlexGetCone(dm, f, &cone);
2051:         coneNew[0]       = vStartNew + (cone[0] - vStart);
2052:         coneNew[1]       = vStartNew + (cone[1] - vStart);
2053:         coneNew[(r+1)%2] = newv;
2054:         DMPlexSetCone(rdm, newp, coneNew);
2055: #if 1
2056:         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2057:         for (p = 0; p < 2; ++p) {
2058:           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);
2059:         }
2060: #endif
2061:         DMPlexGetSupportSize(dm, f, &supportSize);
2062:         DMPlexGetSupport(dm, f, &support);
2063:         for (s = 0; s < supportSize; ++s) {
2064:           if (support[s] >= cMax) {
2065:             supportRef[s] = cStartNew + (cMax - cStart)*4 + (support[s] - cMax)*2 + r;
2066:           } else {
2067:             DMPlexGetConeSize(dm, support[s], &coneSize);
2068:             DMPlexGetCone(dm, support[s], &cone);
2069:             DMPlexGetConeOrientation(dm, support[s], &ornt);
2070:             for (c = 0; c < coneSize; ++c) {
2071:               if (cone[c] == f) break;
2072:             }
2073:             supportRef[s] = cStartNew + (support[s] - cStart)*4 + (ornt[c] < 0 ? (c+1-r)%4 : (c+r)%4);
2074:           }
2075:         }
2076:         DMPlexSetSupport(rdm, newp, supportRef);
2077: #if 1
2078:         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2079:         for (p = 0; p < supportSize; ++p) {
2080:           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);
2081:         }
2082: #endif
2083:       }
2084:     }
2085:     /* Interior cell faces have 2 vertices and 2 cells */
2086:     for (c = cStart; c < cMax; ++c) {
2087:       const PetscInt *cone;

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

2094:         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r] - fStart);
2095:         coneNew[1] = vStartNew + (vEnd - vStart) + (fMax    - fStart) + (c - cStart);
2096:         DMPlexSetCone(rdm, newp, coneNew);
2097: #if 1
2098:         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2099:         for (p = 0; p < 2; ++p) {
2100:           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);
2101:         }
2102: #endif
2103:         supportNew[0] = (c - cStart)*4 + r;
2104:         supportNew[1] = (c - cStart)*4 + (r+1)%4;
2105:         DMPlexSetSupport(rdm, newp, supportNew);
2106: #if 1
2107:         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2108:         for (p = 0; p < 2; ++p) {
2109:           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);
2110:         }
2111: #endif
2112:       }
2113:     }
2114:     /* Hybrid faces have 2 vertices and the same cells */
2115:     for (f = fMax; f < fEnd; ++f) {
2116:       const PetscInt  newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*4 + (f - fMax);
2117:       const PetscInt *cone, *support;
2118:       PetscInt        coneNew[2], supportNew[2];
2119:       PetscInt        size, s, r;

2121:       DMPlexGetCone(dm, f, &cone);
2122:       coneNew[0] = vStartNew + (cone[0] - vStart);
2123:       coneNew[1] = vStartNew + (cone[1] - vStart);
2124:       DMPlexSetCone(rdm, newp, coneNew);
2125: #if 1
2126:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2127:       for (p = 0; p < 2; ++p) {
2128:         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);
2129:       }
2130: #endif
2131:       DMPlexGetSupportSize(dm, f, &size);
2132:       DMPlexGetSupport(dm, f, &support);
2133:       for (s = 0; s < size; ++s) {
2134:         DMPlexGetCone(dm, support[s], &cone);
2135:         for (r = 0; r < 2; ++r) {
2136:           if (cone[r+2] == f) break;
2137:         }
2138:         supportNew[s] = (cMax - cStart)*4 + (support[s] - cMax)*2 + r;
2139:       }
2140:       DMPlexSetSupport(rdm, newp, supportNew);
2141: #if 1
2142:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2143:       for (p = 0; p < size; ++p) {
2144:         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);
2145:       }
2146: #endif
2147:     }
2148:     /* Cell hybrid faces have 2 vertices and 2 cells */
2149:     for (c = cMax; c < cEnd; ++c) {
2150:       const PetscInt  newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*4 + (fEnd - fMax) + (c - cMax);
2151:       const PetscInt *cone;
2152:       PetscInt        coneNew[2], supportNew[2];

2154:       DMPlexGetCone(dm, c, &cone);
2155:       coneNew[0] = vStartNew + (vEnd - vStart) + (cone[0] - fStart);
2156:       coneNew[1] = vStartNew + (vEnd - vStart) + (cone[1] - fStart);
2157:       DMPlexSetCone(rdm, newp, coneNew);
2158: #if 1
2159:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2160:       for (p = 0; p < 2; ++p) {
2161:         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);
2162:       }
2163: #endif
2164:       supportNew[0] = (cMax - cStart)*4 + (c - cMax)*2 + 0;
2165:       supportNew[1] = (cMax - cStart)*4 + (c - cMax)*2 + 1;
2166:       DMPlexSetSupport(rdm, newp, supportNew);
2167: #if 1
2168:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2169:       for (p = 0; p < 2; ++p) {
2170:         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);
2171:       }
2172: #endif
2173:     }
2174:     /* Old vertices have identical supports */
2175:     for (v = vStart; v < vEnd; ++v) {
2176:       const PetscInt  newp = vStartNew + (v - vStart);
2177:       const PetscInt *support, *cone;
2178:       PetscInt        size, s;

2180:       DMPlexGetSupportSize(dm, v, &size);
2181:       DMPlexGetSupport(dm, v, &support);
2182:       for (s = 0; s < size; ++s) {
2183:         if (support[s] >= fMax) {
2184:           supportRef[s] = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*4 + (support[s] - fMax);
2185:         } else {
2186:           PetscInt r = 0;

2188:           DMPlexGetCone(dm, support[s], &cone);
2189:           if (cone[1] == v) r = 1;
2190:           supportRef[s] = fStartNew + (support[s] - fStart)*2 + r;
2191:         }
2192:       }
2193:       DMPlexSetSupport(rdm, newp, supportRef);
2194: #if 1
2195:       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
2196:       for (p = 0; p < size; ++p) {
2197:         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);
2198:       }
2199: #endif
2200:     }
2201:     /* Face vertices have 2 + cells supports */
2202:     for (f = fStart; f < fMax; ++f) {
2203:       const PetscInt  newp = vStartNew + (vEnd - vStart) + (f - fStart);
2204:       const PetscInt *cone, *support;
2205:       PetscInt        size, s;

2207:       DMPlexGetSupportSize(dm, f, &size);
2208:       DMPlexGetSupport(dm, f, &support);
2209:       supportRef[0] = fStartNew + (f - fStart)*2 + 0;
2210:       supportRef[1] = fStartNew + (f - fStart)*2 + 1;
2211:       for (s = 0; s < size; ++s) {
2212:         PetscInt r = 0;

2214:         DMPlexGetCone(dm, support[s], &cone);
2215:         if (support[s] >= cMax) {
2216:           supportRef[2+s] = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*4 + (fEnd - fMax) + (support[s] - cMax);
2217:         } else {
2218:           if      (cone[1] == f) r = 1;
2219:           else if (cone[2] == f) r = 2;
2220:           else if (cone[3] == f) r = 3;
2221:           supportRef[2+s] = fStartNew + (fMax - fStart)*2 + (support[s] - cStart)*4 + r;
2222:         }
2223:       }
2224:       DMPlexSetSupport(rdm, newp, supportRef);
2225: #if 1
2226:       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
2227:       for (p = 0; p < 2+size; ++p) {
2228:         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);
2229:       }
2230: #endif
2231:     }
2232:     /* Cell vertices have 4 supports */
2233:     for (c = cStart; c < cMax; ++c) {
2234:       const PetscInt newp = vStartNew + (vEnd - vStart) + (fMax - fStart) + (c - cStart);
2235:       PetscInt       supportNew[4];

2237:       for (r = 0; r < 4; ++r) {
2238:         supportNew[r] = fStartNew + (fMax - fStart)*2 + (c - cStart)*4 + r;
2239:       }
2240:       DMPlexSetSupport(rdm, newp, supportNew);
2241:     }
2242:     PetscFree(supportRef);
2243:     break;
2244:   case 5:
2245:     /* Simplicial 3D */
2246:     /* All cells have 4 faces: Tet face order is prescribed in DMPlexGetFaces_Internal() */
2247:     DMPlexGetRawFaces_Internal(dm, 3, 4, cellInd, NULL, NULL, &faces);
2248:     for (c = cStart; c < cEnd; ++c) {
2249:       const PetscInt  newp = cStartNew + (c - cStart)*8;
2250:       const PetscInt *cone, *ornt;
2251:       PetscInt        coneNew[4], orntNew[4];

2253:       DMPlexGetCone(dm, c, &cone);
2254:       DMPlexGetConeOrientation(dm, c, &ornt);
2255:       /* A tetrahedron: {0, a, c, d} */
2256:       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetTriSubface_Static(ornt[0], 0); /* A */
2257:       orntNew[0] = ornt[0];
2258:       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetTriSubface_Static(ornt[1], 0); /* A */
2259:       orntNew[1] = ornt[1];
2260:       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetTriSubface_Static(ornt[2], 0); /* A */
2261:       orntNew[2] = ornt[2];
2262:       coneNew[3] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 0;
2263:       orntNew[3] = 0;
2264:       DMPlexSetCone(rdm, newp+0, coneNew);
2265:       DMPlexSetConeOrientation(rdm, newp+0, orntNew);
2266: #if 1
2267:       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);
2268:       for (p = 0; p < 4; ++p) {
2269:         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);
2270:       }
2271: #endif
2272:       /* B tetrahedron: {a, 1, b, e} */
2273:       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetTriSubface_Static(ornt[0], 1); /* B */
2274:       orntNew[0] = ornt[0];
2275:       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetTriSubface_Static(ornt[1], 2); /* C */
2276:       orntNew[1] = ornt[1];
2277:       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 1;
2278:       orntNew[2] = 0;
2279:       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetTriSubface_Static(ornt[3], 1); /* B */
2280:       orntNew[3] = ornt[3];
2281:       DMPlexSetCone(rdm, newp+1, coneNew);
2282:       DMPlexSetConeOrientation(rdm, newp+1, orntNew);
2283: #if 1
2284:       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);
2285:       for (p = 0; p < 4; ++p) {
2286:         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);
2287:       }
2288: #endif
2289:       /* C tetrahedron: {c, b, 2, f} */
2290:       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetTriSubface_Static(ornt[0], 2); /* C */
2291:       orntNew[0] = ornt[0];
2292:       coneNew[1] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 2;
2293:       orntNew[1] = 0;
2294:       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetTriSubface_Static(ornt[2], 1); /* B */
2295:       orntNew[2] = ornt[2];
2296:       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetTriSubface_Static(ornt[3], 0); /* A */
2297:       orntNew[3] = ornt[3];
2298:       DMPlexSetCone(rdm, newp+2, coneNew);
2299:       DMPlexSetConeOrientation(rdm, newp+2, orntNew);
2300: #if 1
2301:       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);
2302:       for (p = 0; p < 4; ++p) {
2303:         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);
2304:       }
2305: #endif
2306:       /* D tetrahedron: {d, e, f, 3} */
2307:       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 3;
2308:       orntNew[0] = 0;
2309:       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetTriSubface_Static(ornt[1], 1); /* B */
2310:       orntNew[1] = ornt[1];
2311:       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetTriSubface_Static(ornt[2], 2); /* C */
2312:       orntNew[2] = ornt[2];
2313:       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetTriSubface_Static(ornt[3], 2); /* C */
2314:       orntNew[3] = ornt[3];
2315:       DMPlexSetCone(rdm, newp+3, coneNew);
2316:       DMPlexSetConeOrientation(rdm, newp+3, orntNew);
2317: #if 1
2318:       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);
2319:       for (p = 0; p < 4; ++p) {
2320:         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);
2321:       }
2322: #endif
2323:       /* A' tetrahedron: {d, a, c, f} */
2324:       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 0;
2325:       orntNew[0] = -3;
2326:       coneNew[1] = fStartNew + (cone[2] - fStart)*4 + 3;
2327:       orntNew[1] = ornt[2] < 0 ? -(GetTetSomething_Static(ornt[2], 0)+1) : GetTetSomething_Static(ornt[2], 0);
2328:       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 5;
2329:       orntNew[2] = 0;
2330:       coneNew[3] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 4;
2331:       orntNew[3] = 2;
2332:       DMPlexSetCone(rdm, newp+4, coneNew);
2333:       DMPlexSetConeOrientation(rdm, newp+4, orntNew);
2334: #if 1
2335:       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);
2336:       for (p = 0; p < 4; ++p) {
2337:         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);
2338:       }
2339: #endif
2340:       /* B' tetrahedron: {e, b, a, f} */
2341:       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 1;
2342:       orntNew[0] = -3;
2343:       coneNew[1] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 6;
2344:       orntNew[1] = 1;
2345:       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 7;
2346:       orntNew[2] = 0;
2347:       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + 3;
2348:       orntNew[3] = ornt[3] < 0 ? -(GetTetSomething_Static(ornt[3], 0)+1) : GetTetSomething_Static(ornt[3], 0);
2349:       DMPlexSetCone(rdm, newp+5, coneNew);
2350:       DMPlexSetConeOrientation(rdm, newp+5, orntNew);
2351: #if 1
2352:       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);
2353:       for (p = 0; p < 4; ++p) {
2354:         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);
2355:       }
2356: #endif
2357:       /* C' tetrahedron: {b, f, c, a} */
2358:       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 2;
2359:       orntNew[0] = -3;
2360:       coneNew[1] = fStartNew + (cone[0] - fStart)*4 + 3;
2361:       orntNew[1] = ornt[0] < 0 ? -(GetTetSomething_Static(ornt[0], 2)+1) : GetTetSomething_Static(ornt[0], 2);
2362:       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 5;
2363:       orntNew[2] = -3;
2364:       coneNew[3] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 7;
2365:       orntNew[3] = -2;
2366:       DMPlexSetCone(rdm, newp+6, coneNew);
2367:       DMPlexSetConeOrientation(rdm, newp+6, orntNew);
2368: #if 1
2369:       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);
2370:       for (p = 0; p < 4; ++p) {
2371:         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);
2372:       }
2373: #endif
2374:       /* D' tetrahedron: {f, e, d, a} */
2375:       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 3;
2376:       orntNew[0] = -3;
2377:       coneNew[1] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 4;
2378:       orntNew[1] = -3;
2379:       coneNew[2] = fStartNew + (cone[1] - fStart)*4 + 3;
2380:       orntNew[2] = ornt[1] < 0 ? -(GetTetSomething_Static(ornt[1], 0)+1) : GetTetSomething_Static(ornt[1], 0);
2381:       coneNew[3] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 6;
2382:       orntNew[3] = -3;
2383:       DMPlexSetCone(rdm, newp+7, coneNew);
2384:       DMPlexSetConeOrientation(rdm, newp+7, orntNew);
2385: #if 1
2386:       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);
2387:       for (p = 0; p < 4; ++p) {
2388:         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);
2389:       }
2390: #endif
2391:     }
2392:     /* Split faces have 3 edges and the same cells as the parent */
2393:     DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);
2394:     PetscMalloc1((2 + maxSupportSize*2), &supportRef);
2395:     for (f = fStart; f < fEnd; ++f) {
2396:       const PetscInt  newp = fStartNew + (f - fStart)*4;
2397:       const PetscInt *cone, *ornt, *support;
2398:       PetscInt        coneNew[3], orntNew[3], coneSize, supportSize, s;

2400:       DMPlexGetCone(dm, f, &cone);
2401:       DMPlexGetConeOrientation(dm, f, &ornt);
2402:       /* A triangle */
2403:       coneNew[0] = eStartNew + (cone[0] - eStart)*2 + (ornt[0] < 0 ? 1 : 0);
2404:       orntNew[0] = ornt[0];
2405:       coneNew[1] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 2;
2406:       orntNew[1] = -2;
2407:       coneNew[2] = eStartNew + (cone[2] - eStart)*2 + (ornt[2] < 0 ? 0 : 1);
2408:       orntNew[2] = ornt[2];
2409:       DMPlexSetCone(rdm, newp+0, coneNew);
2410:       DMPlexSetConeOrientation(rdm, newp+0, orntNew);
2411: #if 1
2412:       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);
2413:       for (p = 0; p < 3; ++p) {
2414:         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);
2415:       }
2416: #endif
2417:       /* B triangle */
2418:       coneNew[0] = eStartNew + (cone[0] - eStart)*2 + (ornt[0] < 0 ? 0 : 1);
2419:       orntNew[0] = ornt[0];
2420:       coneNew[1] = eStartNew + (cone[1] - eStart)*2 + (ornt[1] < 0 ? 1 : 0);
2421:       orntNew[1] = ornt[1];
2422:       coneNew[2] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 0;
2423:       orntNew[2] = -2;
2424:       DMPlexSetCone(rdm, newp+1, coneNew);
2425:       DMPlexSetConeOrientation(rdm, newp+1, orntNew);
2426: #if 1
2427:       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);
2428:       for (p = 0; p < 3; ++p) {
2429:         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);
2430:       }
2431: #endif
2432:       /* C triangle */
2433:       coneNew[0] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 1;
2434:       orntNew[0] = -2;
2435:       coneNew[1] = eStartNew + (cone[1] - eStart)*2 + (ornt[1] < 0 ? 0 : 1);
2436:       orntNew[1] = ornt[1];
2437:       coneNew[2] = eStartNew + (cone[2] - eStart)*2 + (ornt[2] < 0 ? 1 : 0);
2438:       orntNew[2] = ornt[2];
2439:       DMPlexSetCone(rdm, newp+2, coneNew);
2440:       DMPlexSetConeOrientation(rdm, newp+2, orntNew);
2441: #if 1
2442:       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);
2443:       for (p = 0; p < 3; ++p) {
2444:         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);
2445:       }
2446: #endif
2447:       /* D triangle */
2448:       coneNew[0] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 0;
2449:       orntNew[0] = 0;
2450:       coneNew[1] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 1;
2451:       orntNew[1] = 0;
2452:       coneNew[2] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 2;
2453:       orntNew[2] = 0;
2454:       DMPlexSetCone(rdm, newp+3, coneNew);
2455:       DMPlexSetConeOrientation(rdm, newp+3, orntNew);
2456: #if 1
2457:       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);
2458:       for (p = 0; p < 3; ++p) {
2459:         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);
2460:       }
2461: #endif
2462:       DMPlexGetSupportSize(dm, f, &supportSize);
2463:       DMPlexGetSupport(dm, f, &support);
2464:       for (r = 0; r < 4; ++r) {
2465:         for (s = 0; s < supportSize; ++s) {
2466:           PetscInt subf;
2467:           DMPlexGetConeSize(dm, support[s], &coneSize);
2468:           DMPlexGetCone(dm, support[s], &cone);
2469:           DMPlexGetConeOrientation(dm, support[s], &ornt);
2470:           for (c = 0; c < coneSize; ++c) {
2471:             if (cone[c] == f) break;
2472:           }
2473:           subf = GetTriSubfaceInverse_Static(ornt[c], r);
2474:           supportRef[s] = cStartNew + (support[s] - cStart)*8 + (r==3 ? (c+2)%4 + 4 : faces[c*3+subf]);
2475:         }
2476:         DMPlexSetSupport(rdm, newp+r, supportRef);
2477: #if 1
2478:         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);
2479:         for (p = 0; p < supportSize; ++p) {
2480:           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);
2481:         }
2482: #endif
2483:       }
2484:     }
2485:     /* Interior faces have 3 edges and 2 cells */
2486:     for (c = cStart; c < cEnd; ++c) {
2487:       PetscInt        newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*8;
2488:       const PetscInt *cone, *ornt;
2489:       PetscInt        coneNew[3], orntNew[3];
2490:       PetscInt        supportNew[2];

2492:       DMPlexGetCone(dm, c, &cone);
2493:       DMPlexGetConeOrientation(dm, c, &ornt);
2494:       /* Face A: {c, a, d} */
2495:       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*3 + GetTetSomething_Static(ornt[0], 2);
2496:       orntNew[0] = ornt[0] < 0 ? -2 : 0;
2497:       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*3 + GetTetSomething_Static(ornt[1], 2);
2498:       orntNew[1] = ornt[1] < 0 ? -2 : 0;
2499:       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*3 + GetTetSomething_Static(ornt[2], 2);
2500:       orntNew[2] = ornt[2] < 0 ? -2 : 0;
2501:       DMPlexSetCone(rdm, newp, coneNew);
2502:       DMPlexSetConeOrientation(rdm, newp, orntNew);
2503: #if 1
2504:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2505:       for (p = 0; p < 3; ++p) {
2506:         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);
2507:       }
2508: #endif
2509:       supportNew[0] = (c - cStart)*8 + 0;
2510:       supportNew[1] = (c - cStart)*8 + 0+4;
2511:       DMPlexSetSupport(rdm, newp, supportNew);
2512: #if 1
2513:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2514:       for (p = 0; p < 2; ++p) {
2515:         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);
2516:       }
2517: #endif
2518:       ++newp;
2519:       /* Face B: {a, b, e} */
2520:       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*3 + GetTetSomething_Static(ornt[0], 0);
2521:       orntNew[0] = ornt[0] < 0 ? -2 : 0;
2522:       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*3 + GetTetSomething_Static(ornt[3], 0);
2523:       orntNew[1] = ornt[3] < 0 ? -2 : 0;
2524:       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*3 + GetTetSomething_Static(ornt[1], 1);
2525:       orntNew[2] = ornt[1] < 0 ? -2 : 0;
2526:       DMPlexSetCone(rdm, newp, coneNew);
2527:       DMPlexSetConeOrientation(rdm, newp, orntNew);
2528: #if 1
2529:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2530:       for (p = 0; p < 3; ++p) {
2531:         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);
2532:       }
2533: #endif
2534:       supportNew[0] = (c - cStart)*8 + 1;
2535:       supportNew[1] = (c - cStart)*8 + 1+4;
2536:       DMPlexSetSupport(rdm, newp, supportNew);
2537: #if 1
2538:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2539:       for (p = 0; p < 2; ++p) {
2540:         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);
2541:       }
2542: #endif
2543:       ++newp;
2544:       /* Face C: {c, f, b} */
2545:       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*3 + GetTetSomething_Static(ornt[2], 0);
2546:       orntNew[0] = ornt[2] < 0 ? -2 : 0;
2547:       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*3 + GetTetSomething_Static(ornt[3], 2);
2548:       orntNew[1] = ornt[3] < 0 ? -2 : 0;
2549:       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*3 + GetTetSomething_Static(ornt[0], 1);
2550:       orntNew[2] = ornt[0] < 0 ? -2 : 0;
2551:       DMPlexSetCone(rdm, newp, coneNew);
2552:       DMPlexSetConeOrientation(rdm, newp, orntNew);
2553: #if 1
2554:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2555:       for (p = 0; p < 3; ++p) {
2556:         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);
2557:       }
2558: #endif
2559:       supportNew[0] = (c - cStart)*8 + 2;
2560:       supportNew[1] = (c - cStart)*8 + 2+4;
2561:       DMPlexSetSupport(rdm, newp, supportNew);
2562: #if 1
2563:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2564:       for (p = 0; p < 2; ++p) {
2565:         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);
2566:       }
2567: #endif
2568:       ++newp;
2569:       /* Face D: {d, e, f} */
2570:       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*3 + GetTetSomething_Static(ornt[1], 0);
2571:       orntNew[0] = ornt[1] < 0 ? -2 : 0;
2572:       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*3 + GetTetSomething_Static(ornt[3], 1);
2573:       orntNew[1] = ornt[3] < 0 ? -2 : 0;
2574:       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*3 + GetTetSomething_Static(ornt[2], 1);
2575:       orntNew[2] = ornt[2] < 0 ? -2 : 0;
2576:       DMPlexSetCone(rdm, newp, coneNew);
2577:       DMPlexSetConeOrientation(rdm, newp, orntNew);
2578: #if 1
2579:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2580:       for (p = 0; p < 3; ++p) {
2581:         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);
2582:       }
2583: #endif
2584:       supportNew[0] = (c - cStart)*8 + 3;
2585:       supportNew[1] = (c - cStart)*8 + 3+4;
2586:       DMPlexSetSupport(rdm, newp, supportNew);
2587: #if 1
2588:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2589:       for (p = 0; p < 2; ++p) {
2590:         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);
2591:       }
2592: #endif
2593:       ++newp;
2594:       /* Face E: {d, f, a} */
2595:       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*3 + GetTetSomething_Static(ornt[2], 1);
2596:       orntNew[0] = ornt[2] < 0 ? 0 : -2;
2597:       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart);
2598:       orntNew[1] = -2;
2599:       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*3 + GetTetSomething_Static(ornt[1], 2);
2600:       orntNew[2] = ornt[1] < 0 ? -2 : 0;
2601:       DMPlexSetCone(rdm, newp, coneNew);
2602:       DMPlexSetConeOrientation(rdm, newp, orntNew);
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 < 3; ++p) {
2606:         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);
2607:       }
2608: #endif
2609:       supportNew[0] = (c - cStart)*8 + 0+4;
2610:       supportNew[1] = (c - cStart)*8 + 3+4;
2611:       DMPlexSetSupport(rdm, newp, supportNew);
2612: #if 1
2613:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2614:       for (p = 0; p < 2; ++p) {
2615:         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);
2616:       }
2617: #endif
2618:       ++newp;
2619:       /* Face F: {c, a, f} */
2620:       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*3 + GetTetSomething_Static(ornt[0], 2);
2621:       orntNew[0] = ornt[0] < 0 ? -2 : 0;
2622:       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart);
2623:       orntNew[1] = 0;
2624:       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*3 + GetTetSomething_Static(ornt[2], 0);
2625:       orntNew[2] = ornt[2] < 0 ? 0 : -2;
2626:       DMPlexSetCone(rdm, newp, coneNew);
2627:       DMPlexSetConeOrientation(rdm, newp, orntNew);
2628: #if 1
2629:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2630:       for (p = 0; p < 3; ++p) {
2631:         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);
2632:       }
2633: #endif
2634:       supportNew[0] = (c - cStart)*8 + 0+4;
2635:       supportNew[1] = (c - cStart)*8 + 2+4;
2636:       DMPlexSetSupport(rdm, newp, supportNew);
2637: #if 1
2638:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2639:       for (p = 0; p < 2; ++p) {
2640:         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);
2641:       }
2642: #endif
2643:       ++newp;
2644:       /* Face G: {e, a, f} */
2645:       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*3 + GetTetSomething_Static(ornt[1], 1);
2646:       orntNew[0] = ornt[1] < 0 ? -2 : 0;
2647:       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart);
2648:       orntNew[1] = 0;
2649:       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*3 + GetTetSomething_Static(ornt[3], 1);
2650:       orntNew[2] = ornt[3] < 0 ? 0 : -2;
2651:       DMPlexSetCone(rdm, newp, coneNew);
2652:       DMPlexSetConeOrientation(rdm, newp, orntNew);
2653: #if 1
2654:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2655:       for (p = 0; p < 3; ++p) {
2656:         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);
2657:       }
2658: #endif
2659:       supportNew[0] = (c - cStart)*8 + 1+4;
2660:       supportNew[1] = (c - cStart)*8 + 3+4;
2661:       DMPlexSetSupport(rdm, newp, supportNew);
2662: #if 1
2663:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2664:       for (p = 0; p < 2; ++p) {
2665:         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);
2666:       }
2667: #endif
2668:       ++newp;
2669:       /* Face H: {a, b, f} */
2670:       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*3 + GetTetSomething_Static(ornt[0], 0);
2671:       orntNew[0] = ornt[0] < 0 ? -2 : 0;
2672:       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*3 + GetTetSomething_Static(ornt[3], 2);
2673:       orntNew[1] = ornt[3] < 0 ? 0 : -2;
2674:       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart);
2675:       orntNew[2] = -2;
2676:       DMPlexSetCone(rdm, newp, coneNew);
2677:       DMPlexSetConeOrientation(rdm, newp, orntNew);
2678: #if 1
2679:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2680:       for (p = 0; p < 3; ++p) {
2681:         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);
2682:       }
2683: #endif
2684:       supportNew[0] = (c - cStart)*8 + 1+4;
2685:       supportNew[1] = (c - cStart)*8 + 2+4;
2686:       DMPlexSetSupport(rdm, newp, supportNew);
2687: #if 1
2688:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2689:       for (p = 0; p < 2; ++p) {
2690:         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);
2691:       }
2692: #endif
2693:       ++newp;
2694:     }
2695:     /* Split Edges have 2 vertices and the same faces as the parent */
2696:     for (e = eStart; e < eEnd; ++e) {
2697:       const PetscInt newv = vStartNew + (vEnd - vStart) + (e - eStart);

2699:       for (r = 0; r < 2; ++r) {
2700:         const PetscInt  newp = eStartNew + (e - eStart)*2 + r;
2701:         const PetscInt *cone, *ornt, *support;
2702:         PetscInt        coneNew[2], coneSize, c, supportSize, s;

2704:         DMPlexGetCone(dm, e, &cone);
2705:         coneNew[0]       = vStartNew + (cone[0] - vStart);
2706:         coneNew[1]       = vStartNew + (cone[1] - vStart);
2707:         coneNew[(r+1)%2] = newv;
2708:         DMPlexSetCone(rdm, newp, coneNew);
2709: #if 1
2710:         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
2711:         for (p = 0; p < 2; ++p) {
2712:           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);
2713:         }
2714: #endif
2715:         DMPlexGetSupportSize(dm, e, &supportSize);
2716:         DMPlexGetSupport(dm, e, &support);
2717:         for (s = 0; s < supportSize; ++s) {
2718:           DMPlexGetConeSize(dm, support[s], &coneSize);
2719:           DMPlexGetCone(dm, support[s], &cone);
2720:           DMPlexGetConeOrientation(dm, support[s], &ornt);
2721:           for (c = 0; c < coneSize; ++c) {
2722:             if (cone[c] == e) break;
2723:           }
2724:           supportRef[s] = fStartNew + (support[s] - fStart)*4 + (c + (ornt[c] < 0 ? 1-r : r))%3;
2725:         }
2726:         DMPlexSetSupport(rdm, newp, supportRef);
2727: #if 1
2728:         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
2729:         for (p = 0; p < supportSize; ++p) {
2730:           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);
2731:         }
2732: #endif
2733:       }
2734:     }
2735:     /* Face edges have 2 vertices and 2+cells*(1/2) faces */
2736:     for (f = fStart; f < fEnd; ++f) {
2737:       const PetscInt *cone, *ornt, *support;
2738:       PetscInt        coneSize, supportSize, s;

2740:       DMPlexGetSupportSize(dm, f, &supportSize);
2741:       DMPlexGetSupport(dm, f, &support);
2742:       for (r = 0; r < 3; ++r) {
2743:         const PetscInt  newp = eStartNew + (eEnd - eStart)*2 + (f - fStart)*3 + r;
2744:         PetscInt        coneNew[2], intFaces = 0, er, eint[4] = {1, 0, 2, 0};
2745:         PetscInt        fint[24] = { 1,  7, -1, -1,  0,  5,
2746:                                     -1, -1,  1,  6,  0,  4,
2747:                                      2,  5,  3,  4, -1, -1,
2748:                                     -1, -1,  3,  6,  2,  7};

2750:         DMPlexGetCone(dm, f, &cone);
2751:         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[(r+0)%3] - eStart);
2752:         coneNew[1] = vStartNew + (vEnd - vStart) + (cone[(r+1)%3] - eStart);
2753:         DMPlexSetCone(rdm, newp, coneNew);
2754: #if 1
2755:         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
2756:         for (p = 0; p < 2; ++p) {
2757:           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);
2758:         }
2759: #endif
2760:         supportRef[0] = fStartNew + (f - fStart)*4 + (r+1)%3;
2761:         supportRef[1] = fStartNew + (f - fStart)*4 + 3;
2762:         for (s = 0; s < supportSize; ++s) {
2763:           DMPlexGetConeSize(dm, support[s], &coneSize);
2764:           DMPlexGetCone(dm, support[s], &cone);
2765:           DMPlexGetConeOrientation(dm, support[s], &ornt);
2766:           for (c = 0; c < coneSize; ++c) {if (cone[c] == f) break;}
2767:           /* Here we want to determine whether edge newp contains a vertex which is part of the cross-tet edge */
2768:           er = GetTetSomethingInverse_Static(ornt[c], r);
2769:           if (er == eint[c]) {
2770:             supportRef[2+intFaces++] = fStartNew + (fEnd - fStart)*4 + (support[s] - cStart)*8 + (c + 2)%4;
2771:           } else {
2772:             supportRef[2+intFaces++] = fStartNew + (fEnd - fStart)*4 + (support[s] - cStart)*8 + fint[(c*3 + er)*2 + 0];
2773:             supportRef[2+intFaces++] = fStartNew + (fEnd - fStart)*4 + (support[s] - cStart)*8 + fint[(c*3 + er)*2 + 1];
2774:           }
2775:         }
2776:         DMPlexSetSupport(rdm, newp, supportRef);
2777: #if 1
2778:         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
2779:         for (p = 0; p < intFaces; ++p) {
2780:           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);
2781:         }
2782: #endif
2783:       }
2784:     }
2785:     /* Interior edges have 2 vertices and 4 faces */
2786:     for (c = cStart; c < cEnd; ++c) {
2787:       const PetscInt  newp = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart);
2788:       const PetscInt *cone, *ornt, *fcone;
2789:       PetscInt        coneNew[2], supportNew[4], find;

2791:       DMPlexGetCone(dm, c, &cone);
2792:       DMPlexGetConeOrientation(dm, c, &ornt);
2793:       DMPlexGetCone(dm, cone[0], &fcone);
2794:       find = GetTriEdge_Static(ornt[0], 0);
2795:       coneNew[0] = vStartNew + (vEnd - vStart) + (fcone[find] - eStart);
2796:       DMPlexGetCone(dm, cone[2], &fcone);
2797:       find = GetTriEdge_Static(ornt[2], 1);
2798:       coneNew[1] = vStartNew + (vEnd - vStart) + (fcone[find] - eStart);
2799:       DMPlexSetCone(rdm, newp, coneNew);
2800: #if 1
2801:       if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
2802:       for (p = 0; p < 2; ++p) {
2803:         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);
2804:       }
2805: #endif
2806:       supportNew[0] = fStartNew + (fEnd - fStart)*4 + (c - cStart)*8 + 4;
2807:       supportNew[1] = fStartNew + (fEnd - fStart)*4 + (c - cStart)*8 + 5;
2808:       supportNew[2] = fStartNew + (fEnd - fStart)*4 + (c - cStart)*8 + 6;
2809:       supportNew[3] = fStartNew + (fEnd - fStart)*4 + (c - cStart)*8 + 7;
2810:       DMPlexSetSupport(rdm, newp, supportNew);
2811: #if 1
2812:       if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
2813:       for (p = 0; p < 4; ++p) {
2814:         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);
2815:       }
2816: #endif
2817:     }
2818:     /* Old vertices have identical supports */
2819:     for (v = vStart; v < vEnd; ++v) {
2820:       const PetscInt  newp = vStartNew + (v - vStart);
2821:       const PetscInt *support, *cone;
2822:       PetscInt        size, s;

2824:       DMPlexGetSupportSize(dm, v, &size);
2825:       DMPlexGetSupport(dm, v, &support);
2826:       for (s = 0; s < size; ++s) {
2827:         PetscInt r = 0;

2829:         DMPlexGetCone(dm, support[s], &cone);
2830:         if (cone[1] == v) r = 1;
2831:         supportRef[s] = eStartNew + (support[s] - eStart)*2 + r;
2832:       }
2833:       DMPlexSetSupport(rdm, newp, supportRef);
2834: #if 1
2835:       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
2836:       for (p = 0; p < size; ++p) {
2837:         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);
2838:       }
2839: #endif
2840:     }
2841:     /* Edge vertices have 2 + face*2 + 0/1 supports */
2842:     for (e = eStart; e < eEnd; ++e) {
2843:       const PetscInt  newp = vStartNew + (vEnd - vStart) + (e - eStart);
2844:       const PetscInt *cone, *support;
2845:       PetscInt       *star = NULL, starSize, cellSize = 0, coneSize, size, s;

2847:       DMPlexGetSupportSize(dm, e, &size);
2848:       DMPlexGetSupport(dm, e, &support);
2849:       supportRef[0] = eStartNew + (e - eStart)*2 + 0;
2850:       supportRef[1] = eStartNew + (e - eStart)*2 + 1;
2851:       for (s = 0; s < size; ++s) {
2852:         PetscInt r = 0;

2854:         DMPlexGetConeSize(dm, support[s], &coneSize);
2855:         DMPlexGetCone(dm, support[s], &cone);
2856:         for (r = 0; r < coneSize; ++r) {if (cone[r] == e) break;}
2857:         supportRef[2+s*2+0] = eStartNew + (eEnd - eStart)*2 + (support[s] - fStart)*3 + (r+0)%3;
2858:         supportRef[2+s*2+1] = eStartNew + (eEnd - eStart)*2 + (support[s] - fStart)*3 + (r+2)%3;
2859:       }
2860:       DMPlexGetTransitiveClosure(dm, e, PETSC_FALSE, &starSize, &star);
2861:       for (s = 0; s < starSize*2; s += 2) {
2862:         const PetscInt *cone, *ornt;
2863:         PetscInt        e01, e23;

2865:         if ((star[s] >= cStart) && (star[s] < cEnd)) {
2866:           /* Check edge 0-1 */
2867:           DMPlexGetCone(dm, star[s], &cone);
2868:           DMPlexGetConeOrientation(dm, star[s], &ornt);
2869:           DMPlexGetCone(dm, cone[0], &cone);
2870:           e01  = cone[GetTriEdge_Static(ornt[0], 0)];
2871:           /* Check edge 2-3 */
2872:           DMPlexGetCone(dm, star[s], &cone);
2873:           DMPlexGetConeOrientation(dm, star[s], &ornt);
2874:           DMPlexGetCone(dm, cone[2], &cone);
2875:           e23  = cone[GetTriEdge_Static(ornt[2], 1)];
2876:           if ((e01 == e) || (e23 == e)) {supportRef[2+size*2+cellSize++] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (star[s] - cStart);}
2877:         }
2878:       }
2879:       DMPlexRestoreTransitiveClosure(dm, e, PETSC_FALSE, &starSize, &star);
2880:       DMPlexSetSupport(rdm, newp, supportRef);
2881: #if 1
2882:       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
2883:       for (p = 0; p < 2+size*2+cellSize; ++p) {
2884:         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);
2885:       }
2886: #endif
2887:     }
2888:     PetscFree(supportRef);
2889:     DMPlexRestoreFaces_Internal(dm, 3, cStart, NULL, NULL, &faces);
2890:     break;
2891:   case 7:
2892:     /* Hybrid Simplicial 3D */
2893:     DMPlexGetHybridBounds(rdm, &cMaxNew, &fMaxNew, &eMaxNew, NULL);
2894:     /* Interior cells have 4 faces: Tet face order is prescribed in DMPlexGetFaces_Internal() */
2895:     DMPlexGetRawFaces_Internal(dm, 3, 4, cellInd, NULL, NULL, &faces);
2896:     for (c = cStart; c < cMax; ++c) {
2897:       const PetscInt  newp = cStartNew + (c - cStart)*8;
2898:       const PetscInt *cone, *ornt;
2899:       PetscInt        coneNew[4], orntNew[4];

2901:       DMPlexGetCone(dm, c, &cone);
2902:       DMPlexGetConeOrientation(dm, c, &ornt);
2903:       /* A tetrahedron: {0, a, c, d} */
2904:       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetTriSubface_Static(ornt[0], 0); /* A */
2905:       orntNew[0] = ornt[0];
2906:       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetTriSubface_Static(ornt[1], 0); /* A */
2907:       orntNew[1] = ornt[1];
2908:       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetTriSubface_Static(ornt[2], 0); /* A */
2909:       orntNew[2] = ornt[2];
2910:       coneNew[3] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 0;
2911:       orntNew[3] = 0;
2912:       DMPlexSetCone(rdm, newp+0, coneNew);
2913:       DMPlexSetConeOrientation(rdm, newp+0, orntNew);
2914: #if 1
2915:       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);
2916:       for (p = 0; p < 4; ++p) {
2917:         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);
2918:       }
2919: #endif
2920:       /* B tetrahedron: {a, 1, b, e} */
2921:       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetTriSubface_Static(ornt[0], 1); /* B */
2922:       orntNew[0] = ornt[0];
2923:       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetTriSubface_Static(ornt[1], 2); /* C */
2924:       orntNew[1] = ornt[1];
2925:       coneNew[2] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 1;
2926:       orntNew[2] = 0;
2927:       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetTriSubface_Static(ornt[3], 1); /* B */
2928:       orntNew[3] = ornt[3];
2929:       DMPlexSetCone(rdm, newp+1, coneNew);
2930:       DMPlexSetConeOrientation(rdm, newp+1, orntNew);
2931: #if 1
2932:       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);
2933:       for (p = 0; p < 4; ++p) {
2934:         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);
2935:       }
2936: #endif
2937:       /* C tetrahedron: {c, b, 2, f} */
2938:       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetTriSubface_Static(ornt[0], 2); /* C */
2939:       orntNew[0] = ornt[0];
2940:       coneNew[1] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 2;
2941:       orntNew[1] = 0;
2942:       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetTriSubface_Static(ornt[2], 1); /* B */
2943:       orntNew[2] = ornt[2];
2944:       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetTriSubface_Static(ornt[3], 0); /* A */
2945:       orntNew[3] = ornt[3];
2946:       DMPlexSetCone(rdm, newp+2, coneNew);
2947:       DMPlexSetConeOrientation(rdm, newp+2, orntNew);
2948: #if 1
2949:       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);
2950:       for (p = 0; p < 4; ++p) {
2951:         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);
2952:       }
2953: #endif
2954:       /* D tetrahedron: {d, e, f, 3} */
2955:       coneNew[0] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 3;
2956:       orntNew[0] = 0;
2957:       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetTriSubface_Static(ornt[1], 1); /* B */
2958:       orntNew[1] = ornt[1];
2959:       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetTriSubface_Static(ornt[2], 2); /* C */
2960:       orntNew[2] = ornt[2];
2961:       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetTriSubface_Static(ornt[3], 2); /* C */
2962:       orntNew[3] = ornt[3];
2963:       DMPlexSetCone(rdm, newp+3, coneNew);
2964:       DMPlexSetConeOrientation(rdm, newp+3, orntNew);
2965: #if 1
2966:       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);
2967:       for (p = 0; p < 4; ++p) {
2968:         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);
2969:       }
2970: #endif
2971:       /* A' tetrahedron: {d, a, c, f} */
2972:       coneNew[0] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 0;
2973:       orntNew[0] = -3;
2974:       coneNew[1] = fStartNew + (cone[2] - fStart)*4 + 3;
2975:       orntNew[1] = ornt[2] < 0 ? -(GetTetSomething_Static(ornt[2], 0)+1) : GetTetSomething_Static(ornt[2], 0);
2976:       coneNew[2] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 5;
2977:       orntNew[2] = 0;
2978:       coneNew[3] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 4;
2979:       orntNew[3] = 2;
2980:       DMPlexSetCone(rdm, newp+4, coneNew);
2981:       DMPlexSetConeOrientation(rdm, newp+4, orntNew);
2982: #if 1
2983:       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);
2984:       for (p = 0; p < 4; ++p) {
2985:         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);
2986:       }
2987: #endif
2988:       /* B' tetrahedron: {e, b, a, f} */
2989:       coneNew[0] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 1;
2990:       orntNew[0] = -3;
2991:       coneNew[1] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 6;
2992:       orntNew[1] = 1;
2993:       coneNew[2] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 7;
2994:       orntNew[2] = 0;
2995:       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + 3;
2996:       orntNew[3] = ornt[3] < 0 ? -(GetTetSomething_Static(ornt[3], 0)+1) : GetTetSomething_Static(ornt[3], 0);
2997:       DMPlexSetCone(rdm, newp+5, coneNew);
2998:       DMPlexSetConeOrientation(rdm, newp+5, orntNew);
2999: #if 1
3000:       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);
3001:       for (p = 0; p < 4; ++p) {
3002:         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);
3003:       }
3004: #endif
3005:       /* C' tetrahedron: {b, f, c, a} */
3006:       coneNew[0] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 2;
3007:       orntNew[0] = -3;
3008:       coneNew[1] = fStartNew + (cone[0] - fStart)*4 + 3;
3009:       orntNew[1] = ornt[0] < 0 ? -(GetTetSomething_Static(ornt[0], 2)+1) : GetTetSomething_Static(ornt[0], 2);
3010:       coneNew[2] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 5;
3011:       orntNew[2] = -3;
3012:       coneNew[3] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 7;
3013:       orntNew[3] = -2;
3014:       DMPlexSetCone(rdm, newp+6, coneNew);
3015:       DMPlexSetConeOrientation(rdm, newp+6, orntNew);
3016: #if 1
3017:       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);
3018:       for (p = 0; p < 4; ++p) {
3019:         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);
3020:       }
3021: #endif
3022:       /* D' tetrahedron: {f, e, d, a} */
3023:       coneNew[0] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 3;
3024:       orntNew[0] = -3;
3025:       coneNew[1] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 4;
3026:       orntNew[1] = -3;
3027:       coneNew[2] = fStartNew + (cone[1] - fStart)*4 + 3;
3028:       orntNew[2] = ornt[1] < 0 ? -(GetTetSomething_Static(ornt[1], 0)+1) : GetTetSomething_Static(ornt[1], 0);
3029:       coneNew[3] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 6;
3030:       orntNew[3] = -3;
3031:       DMPlexSetCone(rdm, newp+7, coneNew);
3032:       DMPlexSetConeOrientation(rdm, newp+7, orntNew);
3033: #if 1
3034:       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);
3035:       for (p = 0; p < 4; ++p) {
3036:         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);
3037:       }
3038: #endif
3039:     }
3040:     /* Hybrid cells have 5 faces */
3041:     for (c = cMax; c < cEnd; ++c) {
3042:       const PetscInt  newp = cStartNew + (cMax - cStart)*8 + (c - cMax)*4;
3043:       const PetscInt *cone, *ornt, *fornt;
3044:       PetscInt        coneNew[5], orntNew[5], o, of, i;

3046:       DMPlexGetCone(dm, c, &cone);
3047:       DMPlexGetConeOrientation(dm, c, &ornt);
3048:       DMPlexGetConeOrientation(dm, cone[0], &fornt);
3049:       o = ornt[0] < 0 ? -1 : 1;
3050:       for (r = 0; r < 3; ++r) {
3051:         coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetTriSubface_Static(ornt[0], r);
3052:         orntNew[0] = ornt[0];
3053:         coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetTriSubface_Static(ornt[1], r);
3054:         orntNew[1] = ornt[1];
3055:         of = fornt[GetTriEdge_Static(ornt[0], r)]       < 0 ? -1 : 1;
3056:         i  = GetTriEdgeInverse_Static(ornt[0], r)       + 2;
3057:         coneNew[i] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (cone[2+GetTriEdge_Static(ornt[0], r)]       - fMax)*2 + (o*of < 0 ? 1 : 0);
3058:         orntNew[i] = 0;
3059:         i  = GetTriEdgeInverse_Static(ornt[0], (r+1)%3) + 2;
3060:         coneNew[i] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (c - cMax)*3 + GetTriSubface_Static(ornt[0], r);
3061:         orntNew[i] = 0;
3062:         of = fornt[GetTriEdge_Static(ornt[0], (r+2)%3)] < 0 ? -1 : 1;
3063:         i  = GetTriEdgeInverse_Static(ornt[0], (r+2)%3) + 2;
3064:         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);
3065:         orntNew[i] = 0;
3066:         DMPlexSetCone(rdm, newp+r, coneNew);
3067:         DMPlexSetConeOrientation(rdm, newp+r, orntNew);
3068: #if 1
3069:         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);
3070:         for (p = 0; p < 2; ++p) {
3071:           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);
3072:         }
3073:         for (p = 2; p < 5; ++p) {
3074:           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);
3075:         }
3076: #endif
3077:       }
3078:       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + 3;
3079:       orntNew[0] = 0;
3080:       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + 3;
3081:       orntNew[1] = 0;
3082:       coneNew[2] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (c - cMax)*3 + 1;
3083:       orntNew[2] = 0;
3084:       coneNew[3] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (c - cMax)*3 + 2;
3085:       orntNew[3] = 0;
3086:       coneNew[4] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (c - cMax)*3 + 0;
3087:       orntNew[4] = 0;
3088:       DMPlexSetCone(rdm, newp+3, coneNew);
3089:       DMPlexSetConeOrientation(rdm, newp+3, orntNew);
3090: #if 1
3091:       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);
3092:       for (p = 0; p < 2; ++p) {
3093:         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);
3094:       }
3095:       for (p = 2; p < 5; ++p) {
3096:         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);
3097:       }
3098: #endif
3099:     }
3100:     /* Split faces have 3 edges and the same cells as the parent */
3101:     DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);
3102:     PetscMalloc1((2 + maxSupportSize*2), &supportRef);
3103:     for (f = fStart; f < fMax; ++f) {
3104:       const PetscInt  newp = fStartNew + (f - fStart)*4;
3105:       const PetscInt *cone, *ornt, *support;
3106:       PetscInt        coneNew[3], orntNew[3], coneSize, supportSize, s;

3108:       DMPlexGetCone(dm, f, &cone);
3109:       DMPlexGetConeOrientation(dm, f, &ornt);
3110:       /* A triangle */
3111:       coneNew[0] = eStartNew + (cone[0] - eStart)*2 + (ornt[0] < 0 ? 1 : 0);
3112:       orntNew[0] = ornt[0];
3113:       coneNew[1] = eStartNew + (eMax    - eStart)*2 + (f - fStart)*3 + 2;
3114:       orntNew[1] = -2;
3115:       coneNew[2] = eStartNew + (cone[2] - eStart)*2 + (ornt[2] < 0 ? 0 : 1);
3116:       orntNew[2] = ornt[2];
3117:       DMPlexSetCone(rdm, newp+0, coneNew);
3118:       DMPlexSetConeOrientation(rdm, newp+0, orntNew);
3119: #if 1
3120:       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);
3121:       for (p = 0; p < 3; ++p) {
3122:         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);
3123:       }
3124: #endif
3125:       /* B triangle */
3126:       coneNew[0] = eStartNew + (cone[0] - eStart)*2 + (ornt[0] < 0 ? 0 : 1);
3127:       orntNew[0] = ornt[0];
3128:       coneNew[1] = eStartNew + (cone[1] - eStart)*2 + (ornt[1] < 0 ? 1 : 0);
3129:       orntNew[1] = ornt[1];
3130:       coneNew[2] = eStartNew + (eMax    - eStart)*2 + (f - fStart)*3 + 0;
3131:       orntNew[2] = -2;
3132:       DMPlexSetCone(rdm, newp+1, coneNew);
3133:       DMPlexSetConeOrientation(rdm, newp+1, orntNew);
3134: #if 1
3135:       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);
3136:       for (p = 0; p < 3; ++p) {
3137:         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);
3138:       }
3139: #endif
3140:       /* C triangle */
3141:       coneNew[0] = eStartNew + (eMax    - eStart)*2 + (f - fStart)*3 + 1;
3142:       orntNew[0] = -2;
3143:       coneNew[1] = eStartNew + (cone[1] - eStart)*2 + (ornt[1] < 0 ? 0 : 1);
3144:       orntNew[1] = ornt[1];
3145:       coneNew[2] = eStartNew + (cone[2] - eStart)*2 + (ornt[2] < 0 ? 1 : 0);
3146:       orntNew[2] = ornt[2];
3147:       DMPlexSetCone(rdm, newp+2, coneNew);
3148:       DMPlexSetConeOrientation(rdm, newp+2, orntNew);
3149: #if 1
3150:       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);
3151:       for (p = 0; p < 3; ++p) {
3152:         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);
3153:       }
3154: #endif
3155:       /* D triangle */
3156:       coneNew[0] = eStartNew + (eMax    - eStart)*2 + (f - fStart)*3 + 0;
3157:       orntNew[0] = 0;
3158:       coneNew[1] = eStartNew + (eMax    - eStart)*2 + (f - fStart)*3 + 1;
3159:       orntNew[1] = 0;
3160:       coneNew[2] = eStartNew + (eMax    - eStart)*2 + (f - fStart)*3 + 2;
3161:       orntNew[2] = 0;
3162:       DMPlexSetCone(rdm, newp+3, coneNew);
3163:       DMPlexSetConeOrientation(rdm, newp+3, orntNew);
3164: #if 1
3165:       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);
3166:       for (p = 0; p < 3; ++p) {
3167:         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);
3168:       }
3169: #endif
3170:       DMPlexGetSupportSize(dm, f, &supportSize);
3171:       DMPlexGetSupport(dm, f, &support);
3172:       for (r = 0; r < 4; ++r) {
3173:         for (s = 0; s < supportSize; ++s) {
3174:           PetscInt subf;
3175:           DMPlexGetConeSize(dm, support[s], &coneSize);
3176:           DMPlexGetCone(dm, support[s], &cone);
3177:           DMPlexGetConeOrientation(dm, support[s], &ornt);
3178:           for (c = 0; c < coneSize; ++c) {
3179:             if (cone[c] == f) break;
3180:           }
3181:           subf = GetTriSubfaceInverse_Static(ornt[c], r);
3182:           if (support[s] < cMax) {
3183:             supportRef[s] = cStartNew + (support[s] - cStart)*8 + (r==3 ? (c+2)%4 + 4 : faces[c*3+subf]);
3184:           } else {
3185:             supportRef[s] = cStartNew + (cMax - cStart)*8 + (support[s] - cMax)*4 + (r==3 ? r : subf);
3186:           }
3187:         }
3188:         DMPlexSetSupport(rdm, newp+r, supportRef);
3189: #if 1
3190:         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);
3191:         for (p = 0; p < supportSize; ++p) {
3192:           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);
3193:         }
3194: #endif
3195:       }
3196:     }
3197:     /* Interior cell faces have 3 edges and 2 cells */
3198:     for (c = cStart; c < cMax; ++c) {
3199:       PetscInt        newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*8;
3200:       const PetscInt *cone, *ornt;
3201:       PetscInt        coneNew[3], orntNew[3];
3202:       PetscInt        supportNew[2];

3204:       DMPlexGetCone(dm, c, &cone);
3205:       DMPlexGetConeOrientation(dm, c, &ornt);
3206:       /* Face A: {c, a, d} */
3207:       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*3 + GetTetSomething_Static(ornt[0], 2);
3208:       orntNew[0] = ornt[0] < 0 ? -2 : 0;
3209:       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*3 + GetTetSomething_Static(ornt[1], 2);
3210:       orntNew[1] = ornt[1] < 0 ? -2 : 0;
3211:       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*3 + GetTetSomething_Static(ornt[2], 2);
3212:       orntNew[2] = ornt[2] < 0 ? -2 : 0;
3213:       DMPlexSetCone(rdm, newp, coneNew);
3214:       DMPlexSetConeOrientation(rdm, newp, orntNew);
3215: #if 1
3216:       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
3217:       for (p = 0; p < 3; ++p) {
3218:         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);
3219:       }
3220: #endif
3221:       supportNew[0] = (c - cStart)*8 + 0;
3222:       supportNew[1] = (c - cStart)*8 + 0+4;
3223:       DMPlexSetSupport(rdm, newp, supportNew);
3224: #if 1
3225:       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
3226:       for (p = 0; p < 2; ++p) {
3227:         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);
3228:       }
3229: #endif
3230:       ++newp;
3231:       /* Face B: {a, b, e} */
3232:       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*3 + GetTetSomething_Static(ornt[0], 0);
3233:       orntNew[0] = ornt[0] < 0 ? -2 : 0;
3234:       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*3 + GetTetSomething_Static(ornt[3], 0);
3235:       orntNew[1] = ornt[3] < 0 ? -2 : 0;
3236:       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*3 + GetTetSomething_Static(ornt[1], 1);
3237:       orntNew[2] = ornt[1] < 0 ? -2 : 0;
3238:       DMPlexSetCone(rdm, newp, coneNew);
3239:       DMPlexSetConeOrientation(rdm, newp, orntNew);
3240: #if 1
3241:       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);
3242:       for (p = 0; p < 3; ++p) {
3243:         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);
3244:       }
3245: #endif
3246:       supportNew[0] = (c - cStart)*8 + 1;
3247:       supportNew[1] = (c - cStart)*8 + 1+4;
3248:       DMPlexSetSupport(rdm, newp, supportNew);
3249: #if 1
3250:       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
3251:       for (p = 0; p < 2; ++p) {
3252:         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);
3253:       }
3254: #endif
3255:       ++newp;
3256:       /* Face C: {c, f, b} */
3257:       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*3 + GetTetSomething_Static(ornt[2], 0);
3258:       orntNew[0] = ornt[2] < 0 ? -2 : 0;
3259:       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*3 + GetTetSomething_Static(ornt[3], 2);
3260:       orntNew[1] = ornt[3] < 0 ? -2 : 0;
3261:       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*3 + GetTetSomething_Static(ornt[0], 1);
3262:       orntNew[2] = ornt[0] < 0 ? -2 : 0;
3263:       DMPlexSetCone(rdm, newp, coneNew);
3264:       DMPlexSetConeOrientation(rdm, newp, orntNew);
3265: #if 1
3266:       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
3267:       for (p = 0; p < 3; ++p) {
3268:         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);
3269:       }
3270: #endif
3271:       supportNew[0] = (c - cStart)*8 + 2;
3272:       supportNew[1] = (c - cStart)*8 + 2+4;
3273:       DMPlexSetSupport(rdm, newp, supportNew);
3274: #if 1
3275:       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
3276:       for (p = 0; p < 2; ++p) {
3277:         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);
3278:       }
3279: #endif
3280:       ++newp;
3281:       /* Face D: {d, e, f} */
3282:       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*3 + GetTetSomething_Static(ornt[1], 0);
3283:       orntNew[0] = ornt[1] < 0 ? -2 : 0;
3284:       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*3 + GetTetSomething_Static(ornt[3], 1);
3285:       orntNew[1] = ornt[3] < 0 ? -2 : 0;
3286:       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*3 + GetTetSomething_Static(ornt[2], 1);
3287:       orntNew[2] = ornt[2] < 0 ? -2 : 0;
3288:       DMPlexSetCone(rdm, newp, coneNew);
3289:       DMPlexSetConeOrientation(rdm, newp, orntNew);
3290: #if 1
3291:       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
3292:       for (p = 0; p < 3; ++p) {
3293:         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);
3294:       }
3295: #endif
3296:       supportNew[0] = (c - cStart)*8 + 3;
3297:       supportNew[1] = (c - cStart)*8 + 3+4;
3298:       DMPlexSetSupport(rdm, newp, supportNew);
3299: #if 1
3300:       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
3301:       for (p = 0; p < 2; ++p) {
3302:         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);
3303:       }
3304: #endif
3305:       ++newp;
3306:       /* Face E: {d, f, a} */
3307:       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*3 + GetTetSomething_Static(ornt[2], 1);
3308:       orntNew[0] = ornt[2] < 0 ? 0 : -2;
3309:       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart);
3310:       orntNew[1] = -2;
3311:       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*3 + GetTetSomething_Static(ornt[1], 2);
3312:       orntNew[2] = ornt[1] < 0 ? -2 : 0;
3313:       DMPlexSetCone(rdm, newp, coneNew);
3314:       DMPlexSetConeOrientation(rdm, newp, orntNew);
3315: #if 1
3316:       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
3317:       for (p = 0; p < 3; ++p) {
3318:         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);
3319:       }
3320: #endif
3321:       supportNew[0] = (c - cStart)*8 + 0+4;
3322:       supportNew[1] = (c - cStart)*8 + 3+4;
3323:       DMPlexSetSupport(rdm, newp, supportNew);
3324: #if 1
3325:       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
3326:       for (p = 0; p < 2; ++p) {
3327:         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);
3328:       }
3329: #endif
3330:       ++newp;
3331:       /* Face F: {c, a, f} */
3332:       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*3 + GetTetSomething_Static(ornt[0], 2);
3333:       orntNew[0] = ornt[0] < 0 ? -2 : 0;
3334:       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart);
3335:       orntNew[1] = 0;
3336:       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*3 + GetTetSomething_Static(ornt[2], 0);
3337:       orntNew[2] = ornt[2] < 0 ? 0 : -2;
3338:       DMPlexSetCone(rdm, newp, coneNew);
3339:       DMPlexSetConeOrientation(rdm, newp, orntNew);
3340: #if 1
3341:       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
3342:       for (p = 0; p < 3; ++p) {
3343:         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);
3344:       }
3345: #endif
3346:       supportNew[0] = (c - cStart)*8 + 0+4;
3347:       supportNew[1] = (c - cStart)*8 + 2+4;
3348:       DMPlexSetSupport(rdm, newp, supportNew);
3349: #if 1
3350:       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
3351:       for (p = 0; p < 2; ++p) {
3352:         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);
3353:       }
3354: #endif
3355:       ++newp;
3356:       /* Face G: {e, a, f} */
3357:       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*3 + GetTetSomething_Static(ornt[1], 1);
3358:       orntNew[0] = ornt[1] < 0 ? -2 : 0;
3359:       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart);
3360:       orntNew[1] = 0;
3361:       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*3 + GetTetSomething_Static(ornt[3], 1);
3362:       orntNew[2] = ornt[3] < 0 ? 0 : -2;
3363:       DMPlexSetCone(rdm, newp, coneNew);
3364:       DMPlexSetConeOrientation(rdm, newp, orntNew);
3365: #if 1
3366:       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
3367:       for (p = 0; p < 3; ++p) {
3368:         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);
3369:       }
3370: #endif
3371:       supportNew[0] = (c - cStart)*8 + 1+4;
3372:       supportNew[1] = (c - cStart)*8 + 3+4;
3373:       DMPlexSetSupport(rdm, newp, supportNew);
3374: #if 1
3375:       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
3376:       for (p = 0; p < 2; ++p) {
3377:         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);
3378:       }
3379: #endif
3380:       ++newp;
3381:       /* Face H: {a, b, f} */
3382:       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*3 + GetTetSomething_Static(ornt[0], 0);
3383:       orntNew[0] = ornt[0] < 0 ? -2 : 0;
3384:       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*3 + GetTetSomething_Static(ornt[3], 2);
3385:       orntNew[1] = ornt[3] < 0 ? 0 : -2;
3386:       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart);
3387:       orntNew[2] = -2;
3388:       DMPlexSetCone(rdm, newp, coneNew);
3389:       DMPlexSetConeOrientation(rdm, newp, orntNew);
3390: #if 1
3391:       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
3392:       for (p = 0; p < 3; ++p) {
3393:         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);
3394:       }
3395: #endif
3396:       supportNew[0] = (c - cStart)*8 + 1+4;
3397:       supportNew[1] = (c - cStart)*8 + 2+4;
3398:       DMPlexSetSupport(rdm, newp, supportNew);
3399: #if 1
3400:       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
3401:       for (p = 0; p < 2; ++p) {
3402:         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);
3403:       }
3404: #endif
3405:       ++newp;
3406:     }
3407:     /* Hybrid split faces have 4 edges and same cells */
3408:     for (f = fMax; f < fEnd; ++f) {
3409:       const PetscInt *cone, *ornt, *support;
3410:       PetscInt        coneNew[4], orntNew[4];
3411:       PetscInt        supportNew[2], size, s, c;

3413:       DMPlexGetCone(dm, f, &cone);
3414:       DMPlexGetConeOrientation(dm, f, &ornt);
3415:       DMPlexGetSupportSize(dm, f, &size);
3416:       DMPlexGetSupport(dm, f, &support);
3417:       for (r = 0; r < 2; ++r) {
3418:         const PetscInt newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (f - fMax)*2 + r;

3420:         coneNew[0]   = eStartNew + (cone[0] - eStart)*2 + (ornt[0] < 0 ? 1-r : r);
3421:         orntNew[0]   = ornt[0];
3422:         coneNew[1]   = eStartNew + (cone[1] - eStart)*2 + (ornt[1] < 0 ? 1-r : r);
3423:         orntNew[1]   = ornt[1];
3424:         coneNew[2+r] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (cone[2+r] - eMax);
3425:         orntNew[2+r] = 0;
3426:         coneNew[3-r] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (eEnd      - eMax) + (f - fMax);
3427:         orntNew[3-r] = 0;
3428:         DMPlexSetCone(rdm, newp, coneNew);
3429:         DMPlexSetConeOrientation(rdm, newp, orntNew);
3430: #if 1
3431:         if ((newp < fMaxNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid face [%d, %d)", newp, fMaxNew, fEndNew);
3432:         for (p = 0; p < 2; ++p) {
3433:           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);
3434:         }
3435:         for (p = 2; p < 4; ++p) {
3436:           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);
3437:         }
3438: #endif
3439:         for (s = 0; s < size; ++s) {
3440:           const PetscInt *coneCell, *orntCell, *fornt;
3441:           PetscInt        o, of;

3443:           DMPlexGetCone(dm, support[s], &coneCell);
3444:           DMPlexGetConeOrientation(dm, support[s], &orntCell);
3445:           o = orntCell[0] < 0 ? -1 : 1;
3446:           for (c = 2; c < 5; ++c) if (coneCell[c] == f) break;
3447:           if (c >= 5) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Could not find face %d in cone of cell %d", f, support[s]);
3448:           DMPlexGetConeOrientation(dm, coneCell[0], &fornt);
3449:           of = fornt[c-2] < 0 ? -1 : 1;
3450:           supportNew[s] = cStartNew + (cMax - cStart)*8 + (support[s] - cMax)*4 + (GetTriEdgeInverse_Static(orntCell[0], c-2) + (o*of < 0 ? 1-r : r))%3;
3451:         }
3452:         DMPlexSetSupport(rdm, newp, supportNew);
3453: #if 1
3454:         if ((newp < fMaxNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid face [%d, %d)", newp, fMaxNew, fEndNew);
3455:         for (p = 0; p < size; ++p) {
3456:           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);
3457:         }
3458: #endif
3459:       }
3460:     }
3461:     /* Hybrid cell faces have 4 edges and 2 cells */
3462:     for (c = cMax; c < cEnd; ++c) {
3463:       PetscInt        newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (c - cMax)*3;
3464:       const PetscInt *cone, *ornt;
3465:       PetscInt        coneNew[4], orntNew[4];
3466:       PetscInt        supportNew[2];

3468:       DMPlexGetCone(dm, c, &cone);
3469:       DMPlexGetConeOrientation(dm, c, &ornt);
3470:       for (r = 0; r < 3; ++r) {
3471:         coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*3 + (r+2)%3;
3472:         orntNew[0] = 0;
3473:         coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*3 + (r+2)%3;
3474:         orntNew[1] = 0;
3475:         coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (eEnd - eMax) + (cone[2+(r+2)%3] - fMax);
3476:         orntNew[2] = 0;
3477:         coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (eEnd - eMax) + (cone[2+r]       - fMax);
3478:         orntNew[3] = 0;
3479:         DMPlexSetCone(rdm, newp+r, coneNew);
3480:         DMPlexSetConeOrientation(rdm, newp+r, orntNew);
3481: #if 1
3482:         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);
3483:         for (p = 0; p < 2; ++p) {
3484:           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);
3485:         }
3486:         for (p = 2; p < 4; ++p) {
3487:           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);
3488:         }
3489: #endif
3490:         supportNew[0] = cStartNew + (cMax - cStart)*8 + (c - cMax)*4 + GetTriSubface_Static(ornt[0], r);
3491:         supportNew[1] = cStartNew + (cMax - cStart)*8 + (c - cMax)*4 + 3;
3492:         DMPlexSetSupport(rdm, newp+r, supportNew);
3493: #if 1
3494:         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);
3495:         for (p = 0; p < 2; ++p) {
3496:           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);
3497:         }
3498: #endif
3499:       }
3500:     }
3501:     /* Interior split edges have 2 vertices and the same faces as the parent */
3502:     for (e = eStart; e < eMax; ++e) {
3503:       const PetscInt newv = vStartNew + (vEnd - vStart) + (e - eStart);

3505:       for (r = 0; r < 2; ++r) {
3506:         const PetscInt  newp = eStartNew + (e - eStart)*2 + r;
3507:         const PetscInt *cone, *ornt, *support;
3508:         PetscInt        coneNew[2], coneSize, c, supportSize, s;

3510:         DMPlexGetCone(dm, e, &cone);
3511:         coneNew[0]       = vStartNew + (cone[0] - vStart);
3512:         coneNew[1]       = vStartNew + (cone[1] - vStart);
3513:         coneNew[(r+1)%2] = newv;
3514:         DMPlexSetCone(rdm, newp, coneNew);
3515: #if 1
3516:         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
3517:         for (p = 0; p < 2; ++p) {
3518:           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);
3519:         }
3520: #endif
3521:         DMPlexGetSupportSize(dm, e, &supportSize);
3522:         DMPlexGetSupport(dm, e, &support);
3523:         for (s = 0; s < supportSize; ++s) {
3524:           DMPlexGetConeSize(dm, support[s], &coneSize);
3525:           DMPlexGetCone(dm, support[s], &cone);
3526:           DMPlexGetConeOrientation(dm, support[s], &ornt);
3527:           for (c = 0; c < coneSize; ++c) if (cone[c] == e) break;
3528:           if (support[s] < fMax) {
3529:             supportRef[s] = fStartNew + (support[s] - fStart)*4 + (c + (ornt[c] < 0 ? 1-r : r))%3;
3530:           } else {
3531:             supportRef[s] = fStartNew + (fMax       - fStart)*4 + (cMax - cStart)*8 + (support[s] - fMax)*2 + (ornt[c] < 0 ? 1-r : r);
3532:           }
3533:         }
3534:         DMPlexSetSupport(rdm, newp, supportRef);
3535: #if 1
3536:         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
3537:         for (p = 0; p < supportSize; ++p) {
3538:           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);
3539:         }
3540: #endif
3541:       }
3542:     }
3543:     /* Interior face edges have 2 vertices and 2+cells*(1/2) faces */
3544:     for (f = fStart; f < fMax; ++f) {
3545:       const PetscInt *cone, *ornt, *support;
3546:       PetscInt        coneSize, supportSize, s;

3548:       DMPlexGetSupportSize(dm, f, &supportSize);
3549:       DMPlexGetSupport(dm, f, &support);
3550:       for (r = 0; r < 3; ++r) {
3551:         const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (f - fStart)*3 + r;
3552:         PetscInt        coneNew[2], intFaces = 0, er, eint[4] = {1, 0, 2, 0};
3553:         PetscInt        fint[24] = { 1,  7, -1, -1,  0,  5,
3554:                                     -1, -1,  1,  6,  0,  4,
3555:                                      2,  5,  3,  4, -1, -1,
3556:                                     -1, -1,  3,  6,  2,  7};

3558:         DMPlexGetCone(dm, f, &cone);
3559:         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[(r+0)%3] - eStart);
3560:         coneNew[1] = vStartNew + (vEnd - vStart) + (cone[(r+1)%3] - eStart);
3561:         DMPlexSetCone(rdm, newp, coneNew);
3562: #if 1
3563:         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
3564:         for (p = 0; p < 2; ++p) {
3565:           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);
3566:         }
3567: #endif
3568:         supportRef[0] = fStartNew + (f - fStart)*4 + (r+1)%3;
3569:         supportRef[1] = fStartNew + (f - fStart)*4 + 3;
3570:         for (s = 0; s < supportSize; ++s) {
3571:           DMPlexGetConeSize(dm, support[s], &coneSize);
3572:           DMPlexGetCone(dm, support[s], &cone);
3573:           DMPlexGetConeOrientation(dm, support[s], &ornt);
3574:           for (c = 0; c < coneSize; ++c) {if (cone[c] == f) break;}
3575:           if (support[s] < cMax) {
3576:             /* Here we want to determine whether edge newp contains a vertex which is part of the cross-tet edge */
3577:             er = GetTetSomethingInverse_Static(ornt[c], r);
3578:             if (er == eint[c]) {
3579:               supportRef[2+intFaces++] = fStartNew + (fMax - fStart)*4 + (support[s] - cStart)*8 + (c + 2)%4;
3580:             } else {
3581:               supportRef[2+intFaces++] = fStartNew + (fMax - fStart)*4 + (support[s] - cStart)*8 + fint[(c*3 + er)*2 + 0];
3582:               supportRef[2+intFaces++] = fStartNew + (fMax - fStart)*4 + (support[s] - cStart)*8 + fint[(c*3 + er)*2 + 1];
3583:             }
3584:           } else {
3585:             supportRef[2+intFaces++] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (support[s] - cMax)*3 + (r + 1)%3;
3586:           }
3587:         }
3588:         DMPlexSetSupport(rdm, newp, supportRef);
3589: #if 1
3590:         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
3591:         for (p = 0; p < intFaces; ++p) {
3592:           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);
3593:         }
3594: #endif
3595:       }
3596:     }
3597:     /* Interior cell edges have 2 vertices and 4 faces */
3598:     for (c = cStart; c < cMax; ++c) {
3599:       const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart);
3600:       const PetscInt *cone, *ornt, *fcone;
3601:       PetscInt        coneNew[2], supportNew[4], find;

3603:       DMPlexGetCone(dm, c, &cone);
3604:       DMPlexGetConeOrientation(dm, c, &ornt);
3605:       DMPlexGetCone(dm, cone[0], &fcone);
3606:       find = GetTriEdge_Static(ornt[0], 0);
3607:       coneNew[0] = vStartNew + (vEnd - vStart) + (fcone[find] - eStart);
3608:       DMPlexGetCone(dm, cone[2], &fcone);
3609:       find = GetTriEdge_Static(ornt[2], 1);
3610:       coneNew[1] = vStartNew + (vEnd - vStart) + (fcone[find] - eStart);
3611:       DMPlexSetCone(rdm, newp, coneNew);
3612: #if 1
3613:       if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
3614:       for (p = 0; p < 2; ++p) {
3615:         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);
3616:       }
3617: #endif
3618:       supportNew[0] = fStartNew + (fMax - fStart)*4 + (c - cStart)*8 + 4;
3619:       supportNew[1] = fStartNew + (fMax - fStart)*4 + (c - cStart)*8 + 5;
3620:       supportNew[2] = fStartNew + (fMax - fStart)*4 + (c - cStart)*8 + 6;
3621:       supportNew[3] = fStartNew + (fMax - fStart)*4 + (c - cStart)*8 + 7;
3622:       DMPlexSetSupport(rdm, newp, supportNew);
3623: #if 1
3624:       if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
3625:       for (p = 0; p < 4; ++p) {
3626:         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);
3627:       }
3628: #endif
3629:     }
3630:     /* Hybrid edges have two vertices and the same faces */
3631:     for (e = eMax; e < eEnd; ++e) {
3632:       const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (e - eMax);
3633:       const PetscInt *cone, *support, *fcone;
3634:       PetscInt        coneNew[2], size, fsize, s;

3636:       DMPlexGetCone(dm, e, &cone);
3637:       DMPlexGetSupportSize(dm, e, &size);
3638:       DMPlexGetSupport(dm, e, &support);
3639:       coneNew[0] = vStartNew + (cone[0] - vStart);
3640:       coneNew[1] = vStartNew + (cone[1] - vStart);
3641:       DMPlexSetCone(rdm, newp, coneNew);
3642: #if 1
3643:       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid edge [%d, %d)", newp, eMaxNew, eEndNew);
3644:       for (p = 0; p < 2; ++p) {
3645:         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);
3646:       }
3647: #endif
3648:       for (s = 0; s < size; ++s) {
3649:         DMPlexGetConeSize(dm, support[s], &fsize);
3650:         DMPlexGetCone(dm, support[s], &fcone);
3651:         for (c = 0; c < fsize; ++c) if (fcone[c] == e) break;
3652:         if ((c < 2) || (c > 3)) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Edge %d not found in cone of face %d", e, support[s]);
3653:         supportRef[s] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (support[s] - fMax)*2 + c-2;
3654:       }
3655:       DMPlexSetSupport(rdm, newp, supportRef);
3656: #if 1
3657:       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid edge [%d, %d)", newp, eMaxNew, eEndNew);
3658:       for (p = 0; p < size; ++p) {
3659:         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);
3660:       }
3661: #endif
3662:     }
3663:     /* Hybrid face edges have 2 vertices and 2+2*cells faces */
3664:     for (f = fMax; f < fEnd; ++f) {
3665:       const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (eEnd - eMax) + (f - fMax);
3666:       const PetscInt *cone, *support, *ccone, *cornt;
3667:       PetscInt        coneNew[2], size, csize, s;

3669:       DMPlexGetCone(dm, f, &cone);
3670:       DMPlexGetSupportSize(dm, f, &size);
3671:       DMPlexGetSupport(dm, f, &support);
3672:       coneNew[0] = vStartNew + (vEnd - vStart) + (cone[0] - eStart);
3673:       coneNew[1] = vStartNew + (vEnd - vStart) + (cone[1] - eStart);
3674:       DMPlexSetCone(rdm, newp, coneNew);
3675: #if 1
3676:       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid edge [%d, %d)", newp, eMaxNew, eEndNew);
3677:       for (p = 0; p < 2; ++p) {
3678:         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);
3679:       }
3680: #endif
3681:       supportRef[0] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (f - fMax)*2 + 0;
3682:       supportRef[1] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (f - fMax)*2 + 1;
3683:       for (s = 0; s < size; ++s) {
3684:         DMPlexGetConeSize(dm, support[s], &csize);
3685:         DMPlexGetCone(dm, support[s], &ccone);
3686:         DMPlexGetConeOrientation(dm, support[s], &cornt);
3687:         for (c = 0; c < csize; ++c) if (ccone[c] == f) break;
3688:         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]);
3689:         supportRef[2+s*2+0] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (support[s] - cMax)*3 + c-2;
3690:         supportRef[2+s*2+1] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (support[s] - cMax)*3 + (c-1)%3;
3691:       }
3692:       DMPlexSetSupport(rdm, newp, supportRef);
3693: #if 1
3694:       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid edge [%d, %d)", newp, eMaxNew, eEndNew);
3695:       for (p = 0; p < 2+size*2; ++p) {
3696:         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);
3697:       }
3698: #endif
3699:     }
3700:     /* Interior vertices have identical supports */
3701:     for (v = vStart; v < vEnd; ++v) {
3702:       const PetscInt  newp = vStartNew + (v - vStart);
3703:       const PetscInt *support, *cone;
3704:       PetscInt        size, s;

3706:       DMPlexGetSupportSize(dm, v, &size);
3707:       DMPlexGetSupport(dm, v, &support);
3708:       for (s = 0; s < size; ++s) {
3709:         PetscInt r = 0;

3711:         DMPlexGetCone(dm, support[s], &cone);
3712:         if (cone[1] == v) r = 1;
3713:         if (support[s] < eMax) supportRef[s] = eStartNew + (support[s] - eStart)*2 + r;
3714:         else                   supportRef[s] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (support[s] - eMax);
3715:       }
3716:       DMPlexSetSupport(rdm, newp, supportRef);
3717: #if 1
3718:       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
3719:       for (p = 0; p < size; ++p) {
3720:         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);
3721:       }
3722: #endif
3723:     }
3724:     /* Interior edge vertices have 2 + interior face*2 + hybrid face + cells*0/1 supports */
3725:     for (e = eStart; e < eMax; ++e) {
3726:       const PetscInt  newp = vStartNew + (vEnd - vStart) + (e - eStart);
3727:       const PetscInt *cone, *support;
3728:       PetscInt       *star = NULL, starSize, faceSize = 0, cellSize = 0, coneSize, size, s;

3730:       DMPlexGetSupportSize(dm, e, &size);
3731:       DMPlexGetSupport(dm, e, &support);
3732:       supportRef[0] = eStartNew + (e - eStart)*2 + 0;
3733:       supportRef[1] = eStartNew + (e - eStart)*2 + 1;
3734:       for (s = 0; s < size; ++s) {
3735:         PetscInt r = 0;

3737:         if (support[s] < fMax) {
3738:           DMPlexGetConeSize(dm, support[s], &coneSize);
3739:           DMPlexGetCone(dm, support[s], &cone);
3740:           for (r = 0; r < coneSize; ++r) {if (cone[r] == e) break;}
3741:           supportRef[2+faceSize+0] = eStartNew + (eMax - eStart)*2 + (support[s] - fStart)*3 + (r+0)%3;
3742:           supportRef[2+faceSize+1] = eStartNew + (eMax - eStart)*2 + (support[s] - fStart)*3 + (r+2)%3;
3743:           faceSize += 2;
3744:         } else {
3745:           supportRef[2+faceSize+0] = eStartNew + (eMax - eStart)*2 + (fMax       - fStart)*3 + (cMax - cStart) + (eEnd - eMax) + (support[s] - fMax);
3746:           ++faceSize;
3747:         }
3748:       }
3749:       DMPlexGetTransitiveClosure(dm, e, PETSC_FALSE, &starSize, &star);
3750:       for (s = 0; s < starSize*2; s += 2) {
3751:         const PetscInt *cone, *ornt;
3752:         PetscInt        e01, e23;

3754:         if ((star[s] >= cStart) && (star[s] < cMax)) {
3755:           /* Check edge 0-1 */
3756:           DMPlexGetCone(dm, star[s], &cone);
3757:           DMPlexGetConeOrientation(dm, star[s], &ornt);
3758:           DMPlexGetCone(dm, cone[0], &cone);
3759:           e01  = cone[GetTriEdge_Static(ornt[0], 0)];
3760:           /* Check edge 2-3 */
3761:           DMPlexGetCone(dm, star[s], &cone);
3762:           DMPlexGetConeOrientation(dm, star[s], &ornt);
3763:           DMPlexGetCone(dm, cone[2], &cone);
3764:           e23  = cone[GetTriEdge_Static(ornt[2], 1)];
3765:           if ((e01 == e) || (e23 == e)) {supportRef[2+faceSize+cellSize++] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (star[s] - cStart);}
3766:         }
3767:       }
3768:       DMPlexRestoreTransitiveClosure(dm, e, PETSC_FALSE, &starSize, &star);
3769:       DMPlexSetSupport(rdm, newp, supportRef);
3770: #if 1
3771:       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
3772:       for (p = 0; p < 2+faceSize+cellSize; ++p) {
3773:         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);
3774:       }
3775: #endif
3776:     }
3777:     PetscFree(supportRef);
3778:     DMPlexRestoreFaces_Internal(dm, 3, cStart, NULL, NULL, &faces);
3779:     break;
3780:   case 6:
3781:     /* Hex 3D */
3782:     /*
3783:      Bottom (viewed from top)    Top
3784:      1---------2---------2       7---------2---------6
3785:      |         |         |       |         |         |
3786:      |    B    2    C    |       |    H    2    G    |
3787:      |         |         |       |         |         |
3788:      3----3----0----1----1       3----3----0----1----1
3789:      |         |         |       |         |         |
3790:      |    A    0    D    |       |    E    0    F    |
3791:      |         |         |       |         |         |
3792:      0---------0---------3       4---------0---------5
3793:      */
3794:     /* All cells have 6 faces: Bottom, Top, Front, Back, Right, Left */
3795:     for (c = cStart; c < cEnd; ++c) {
3796:       const PetscInt  newp = (c - cStart)*8;
3797:       const PetscInt *cone, *ornt;
3798:       PetscInt        coneNew[6], orntNew[6];

3800:       DMPlexGetCone(dm, c, &cone);
3801:       DMPlexGetConeOrientation(dm, c, &ornt);
3802:       /* A hex */
3803:       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], 0);
3804:       orntNew[0] = ornt[0];
3805:       coneNew[1] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  8; /* AE */
3806:       orntNew[1] = 0;
3807:       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetQuadSubface_Static(ornt[2], 0);
3808:       orntNew[2] = ornt[2];
3809:       coneNew[3] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  3; /* AB */
3810:       orntNew[3] = 0;
3811:       coneNew[4] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  0; /* AD */
3812:       orntNew[4] = 0;
3813:       coneNew[5] = fStartNew + (cone[5] - fStart)*4 + GetQuadSubface_Static(ornt[5], 0);
3814:       orntNew[5] = ornt[5];
3815:       DMPlexSetCone(rdm, newp+0, coneNew);
3816:       DMPlexSetConeOrientation(rdm, newp+0, orntNew);
3817: #if 1
3818:       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);
3819:       for (p = 0; p < 6; ++p) {
3820:         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);
3821:       }
3822: #endif
3823:       /* B hex */
3824:       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], 1);
3825:       orntNew[0] = ornt[0];
3826:       coneNew[1] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 + 11; /* BH */
3827:       orntNew[1] = 0;
3828:       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  3; /* AB */
3829:       orntNew[2] = -1;
3830:       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetQuadSubface_Static(ornt[3], 1);
3831:       orntNew[3] = ornt[3];
3832:       coneNew[4] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  2; /* BC */
3833:       orntNew[4] = 0;
3834:       coneNew[5] = fStartNew + (cone[5] - fStart)*4 + GetQuadSubface_Static(ornt[5], 3);
3835:       orntNew[5] = ornt[5];
3836:       DMPlexSetCone(rdm, newp+1, coneNew);
3837:       DMPlexSetConeOrientation(rdm, newp+1, orntNew);
3838: #if 1
3839:       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);
3840:       for (p = 0; p < 6; ++p) {
3841:         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);
3842:       }
3843: #endif
3844:       /* C hex */
3845:       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], 2);
3846:       orntNew[0] = ornt[0];
3847:       coneNew[1] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 + 10; /* CG */
3848:       orntNew[1] = 0;
3849:       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  1; /* CD */
3850:       orntNew[2] = -1;
3851:       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetQuadSubface_Static(ornt[3], 0);
3852:       orntNew[3] = ornt[3];
3853:       coneNew[4] = fStartNew + (cone[4] - fStart)*4 + GetQuadSubface_Static(ornt[4], 1);
3854:       orntNew[4] = ornt[4];
3855:       coneNew[5] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  2; /* BC */
3856:       orntNew[5] = -4;
3857:       DMPlexSetCone(rdm, newp+2, coneNew);
3858:       DMPlexSetConeOrientation(rdm, newp+2, orntNew);
3859: #if 1
3860:       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);
3861:       for (p = 0; p < 6; ++p) {
3862:         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);
3863:       }
3864: #endif
3865:       /* D hex */
3866:       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], 3);
3867:       orntNew[0] = ornt[0];
3868:       coneNew[1] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  9; /* DF */
3869:       orntNew[1] = 0;
3870:       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetQuadSubface_Static(ornt[2], 1);
3871:       orntNew[2] = ornt[2];
3872:       coneNew[3] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  1; /* CD */
3873:       orntNew[3] = 0;
3874:       coneNew[4] = fStartNew + (cone[4] - fStart)*4 + GetQuadSubface_Static(ornt[4], 0);
3875:       orntNew[4] = ornt[4];
3876:       coneNew[5] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  0; /* AD */
3877:       orntNew[5] = -4;
3878:       DMPlexSetCone(rdm, newp+3, coneNew);
3879:       DMPlexSetConeOrientation(rdm, newp+3, orntNew);
3880: #if 1
3881:       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);
3882:       for (p = 0; p < 6; ++p) {
3883:         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);
3884:       }
3885: #endif
3886:       /* E hex */
3887:       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  8; /* AE */
3888:       orntNew[0] = -4;
3889:       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], 0);
3890:       orntNew[1] = ornt[1];
3891:       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetQuadSubface_Static(ornt[2], 3);
3892:       orntNew[2] = ornt[2];
3893:       coneNew[3] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  7; /* EH */
3894:       orntNew[3] = 0;
3895:       coneNew[4] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  4; /* EF */
3896:       orntNew[4] = -1;
3897:       coneNew[5] = fStartNew + (cone[5] - fStart)*4 + GetQuadSubface_Static(ornt[5], 1);
3898:       orntNew[5] = ornt[5];
3899:       DMPlexSetCone(rdm, newp+4, coneNew);
3900:       DMPlexSetConeOrientation(rdm, newp+4, orntNew);
3901: #if 1
3902:       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);
3903:       for (p = 0; p < 6; ++p) {
3904:         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);
3905:       }
3906: #endif
3907:       /* F hex */
3908:       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  9; /* DF */
3909:       orntNew[0] = -4;
3910:       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], 1);
3911:       orntNew[1] = ornt[1];
3912:       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetQuadSubface_Static(ornt[2], 2);
3913:       orntNew[2] = ornt[2];
3914:       coneNew[3] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  5; /* FG */
3915:       orntNew[3] = -1;
3916:       coneNew[4] = fStartNew + (cone[4] - fStart)*4 + GetQuadSubface_Static(ornt[4], 3);
3917:       orntNew[4] = ornt[4];
3918:       coneNew[5] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  4; /* EF */
3919:       orntNew[5] = 1;
3920:       DMPlexSetCone(rdm, newp+5, coneNew);
3921:       DMPlexSetConeOrientation(rdm, newp+5, orntNew);
3922: #if 1
3923:       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);
3924:       for (p = 0; p < 6; ++p) {
3925:         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);
3926:       }
3927: #endif
3928:       /* G hex */
3929:       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 + 10; /* CG */
3930:       orntNew[0] = -4;
3931:       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], 2);
3932:       orntNew[1] = ornt[1];
3933:       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  5; /* FG */
3934:       orntNew[2] = 0;
3935:       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetQuadSubface_Static(ornt[3], 3);
3936:       orntNew[3] = ornt[3];
3937:       coneNew[4] = fStartNew + (cone[4] - fStart)*4 + GetQuadSubface_Static(ornt[4], 2);
3938:       orntNew[4] = ornt[4];
3939:       coneNew[5] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  6; /* GH */
3940:       orntNew[5] = -3;
3941:       DMPlexSetCone(rdm, newp+6, coneNew);
3942:       DMPlexSetConeOrientation(rdm, newp+6, orntNew);
3943: #if 1
3944:       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);
3945:       for (p = 0; p < 6; ++p) {
3946:         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);
3947:       }
3948: #endif
3949:       /* H hex */
3950:       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 + 11; /* BH */
3951:       orntNew[0] = -4;
3952:       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], 3);
3953:       orntNew[1] = ornt[1];
3954:       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  7; /* EH */
3955:       orntNew[2] = -1;
3956:       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetQuadSubface_Static(ornt[3], 2);
3957:       orntNew[3] = ornt[3];
3958:       coneNew[4] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  6; /* GH */
3959:       orntNew[4] = 3;
3960:       coneNew[5] = fStartNew + (cone[5] - fStart)*4 + GetQuadSubface_Static(ornt[5], 2);
3961:       orntNew[5] = ornt[5];
3962:       DMPlexSetCone(rdm, newp+7, coneNew);
3963:       DMPlexSetConeOrientation(rdm, newp+7, orntNew);
3964: #if 1
3965:       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);
3966:       for (p = 0; p < 6; ++p) {
3967:         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);
3968:       }
3969: #endif
3970:     }
3971:     /* Split faces have 4 edges and the same cells as the parent */
3972:     DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);
3973:     PetscMalloc1((4 + maxSupportSize*2), &supportRef);
3974:     for (f = fStart; f < fEnd; ++f) {
3975:       for (r = 0; r < 4; ++r) {
3976:         /* TODO: This can come from GetFaces_Internal() */
3977:         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};
3978:         const PetscInt  newp = fStartNew + (f - fStart)*4 + r;
3979:         const PetscInt *cone, *ornt, *support;
3980:         PetscInt        coneNew[4], orntNew[4], coneSize, c, supportSize, s;

3982:         DMPlexGetCone(dm, f, &cone);
3983:         DMPlexGetConeOrientation(dm, f, &ornt);
3984:         coneNew[(r+3)%4] = eStartNew + (cone[(r+3)%4] - eStart)*2 + (ornt[(r+3)%4] < 0 ? 0 : 1);
3985:         orntNew[(r+3)%4] = ornt[(r+3)%4];
3986:         coneNew[(r+0)%4] = eStartNew + (cone[r]       - eStart)*2 + (ornt[r] < 0 ? 1 : 0);
3987:         orntNew[(r+0)%4] = ornt[r];
3988:         coneNew[(r+1)%4] = eStartNew + (eEnd - eStart)*2 + (f - fStart)*4 + r;
3989:         orntNew[(r+1)%4] = 0;
3990:         coneNew[(r+2)%4] = eStartNew + (eEnd - eStart)*2 + (f - fStart)*4 + (r+3)%4;
3991:         orntNew[(r+2)%4] = -2;
3992:         DMPlexSetCone(rdm, newp, coneNew);
3993:         DMPlexSetConeOrientation(rdm, newp, orntNew);
3994: #if 1
3995:         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
3996:         for (p = 0; p < 4; ++p) {
3997:           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);
3998:         }
3999: #endif
4000:         DMPlexGetSupportSize(dm, f, &supportSize);
4001:         DMPlexGetSupport(dm, f, &support);
4002:         for (s = 0; s < supportSize; ++s) {
4003:           DMPlexGetConeSize(dm, support[s], &coneSize);
4004:           DMPlexGetCone(dm, support[s], &cone);
4005:           DMPlexGetConeOrientation(dm, support[s], &ornt);
4006:           for (c = 0; c < coneSize; ++c) {
4007:             if (cone[c] == f) break;
4008:           }
4009:           supportRef[s] = cStartNew + (support[s] - cStart)*8 + newCells[c*4+GetQuadSubfaceInverse_Static(ornt[c], r)];
4010:         }
4011:         DMPlexSetSupport(rdm, newp, supportRef);
4012: #if 1
4013:         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4014:         for (p = 0; p < supportSize; ++p) {
4015:           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);
4016:         }
4017: #endif
4018:       }
4019:     }
4020:     /* Interior faces have 4 edges and 2 cells */
4021:     for (c = cStart; c < cEnd; ++c) {
4022:       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};
4023:       const PetscInt *cone, *ornt;
4024:       PetscInt        newp, coneNew[4], orntNew[4], supportNew[2];

4026:       DMPlexGetCone(dm, c, &cone);
4027:       DMPlexGetConeOrientation(dm, c, &ornt);
4028:       /* A-D face */
4029:       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 0;
4030:       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*4 + GetQuadEdge_Static(ornt[0], 3);
4031:       orntNew[0] = 0;
4032:       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 0;
4033:       orntNew[1] = 0;
4034:       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 2;
4035:       orntNew[2] = -2;
4036:       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*4 + GetQuadEdge_Static(ornt[2], 0);
4037:       orntNew[3] = -2;
4038:       DMPlexSetCone(rdm, newp, coneNew);
4039:       DMPlexSetConeOrientation(rdm, newp, orntNew);
4040: #if 1
4041:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4042:       for (p = 0; p < 4; ++p) {
4043:         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);
4044:       }
4045: #endif
4046:       /* C-D face */
4047:       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 1;
4048:       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*4 + GetQuadEdge_Static(ornt[0], 2);
4049:       orntNew[0] = 0;
4050:       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 0;
4051:       orntNew[1] = 0;
4052:       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 4;
4053:       orntNew[2] = -2;
4054:       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (cone[4] - fStart)*4 + GetQuadEdge_Static(ornt[4], 0);
4055:       orntNew[3] = -2;
4056:       DMPlexSetCone(rdm, newp, coneNew);
4057:       DMPlexSetConeOrientation(rdm, newp, orntNew);
4058: #if 1
4059:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4060:       for (p = 0; p < 4; ++p) {
4061:         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);
4062:       }
4063: #endif
4064:       /* B-C face */
4065:       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 2;
4066:       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*4 + GetQuadEdge_Static(ornt[0], 1);
4067:       orntNew[0] = -2;
4068:       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*4 + GetQuadEdge_Static(ornt[3], 0);
4069:       orntNew[1] = 0;
4070:       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 3;
4071:       orntNew[2] = 0;
4072:       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 0;
4073:       orntNew[3] = -2;
4074:       DMPlexSetCone(rdm, newp, coneNew);
4075:       DMPlexSetConeOrientation(rdm, newp, orntNew);
4076: #if 1
4077:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4078:       for (p = 0; p < 4; ++p) {
4079:         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);
4080:       }
4081: #endif
4082:       /* A-B face */
4083:       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 3;
4084:       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*4 + GetQuadEdge_Static(ornt[0], 0);
4085:       orntNew[0] = -2;
4086:       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[5] - fStart)*4 + GetQuadEdge_Static(ornt[5], 3);
4087:       orntNew[1] = 0;
4088:       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 5;
4089:       orntNew[2] = 0;
4090:       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 0;
4091:       orntNew[3] = -2;
4092:       DMPlexSetCone(rdm, newp, coneNew);
4093:       DMPlexSetConeOrientation(rdm, newp, orntNew);
4094: #if 1
4095:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4096:       for (p = 0; p < 4; ++p) {
4097:         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);
4098:       }
4099: #endif
4100:       /* E-F face */
4101:       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 4;
4102:       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 2;
4103:       orntNew[0] = -2;
4104:       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*4 + GetQuadEdge_Static(ornt[2], 2);
4105:       orntNew[1] = -2;
4106:       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*4 + GetQuadEdge_Static(ornt[1], 0);
4107:       orntNew[2] = 0;
4108:       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 1;
4109:       orntNew[3] = 0;
4110:       DMPlexSetCone(rdm, newp, coneNew);
4111:       DMPlexSetConeOrientation(rdm, newp, orntNew);
4112: #if 1
4113:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4114:       for (p = 0; p < 4; ++p) {
4115:         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);
4116:       }
4117: #endif
4118:       /* F-G face */
4119:       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 5;
4120:       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 4;
4121:       orntNew[0] = -2;
4122:       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[4] - fStart)*4 + GetQuadEdge_Static(ornt[4], 2);
4123:       orntNew[1] = -2;
4124:       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*4 + GetQuadEdge_Static(ornt[1], 1);
4125:       orntNew[2] = 0;
4126:       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 1;
4127:       orntNew[3] = 0;
4128:       DMPlexSetCone(rdm, newp, coneNew);
4129:       DMPlexSetConeOrientation(rdm, newp, orntNew);
4130: #if 1
4131:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4132:       for (p = 0; p < 4; ++p) {
4133:         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);
4134:       }
4135: #endif
4136:       /* G-H face */
4137:       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 6;
4138:       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*4 + GetQuadEdge_Static(ornt[3], 2);
4139:       orntNew[0] = -2;
4140:       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*4 + GetQuadEdge_Static(ornt[1], 2);
4141:       orntNew[1] = 0;
4142:       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 1;
4143:       orntNew[2] = 0;
4144:       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 3;
4145:       orntNew[3] = -2;
4146:       DMPlexSetCone(rdm, newp, coneNew);
4147:       DMPlexSetConeOrientation(rdm, newp, orntNew);
4148: #if 1
4149:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4150:       for (p = 0; p < 4; ++p) {
4151:         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);
4152:       }
4153: #endif
4154:       /* E-H face */
4155:       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 7;
4156:       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 5;
4157:       orntNew[0] = -2;
4158:       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[5] - fStart)*4 + GetQuadEdge_Static(ornt[5], 1);
4159:       orntNew[1] = -2;
4160:       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*4 + GetQuadEdge_Static(ornt[1], 3);
4161:       orntNew[2] = 0;
4162:       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 1;
4163:       orntNew[3] = 0;
4164:       DMPlexSetCone(rdm, newp, coneNew);
4165:       DMPlexSetConeOrientation(rdm, newp, orntNew);
4166: #if 1
4167:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4168:       for (p = 0; p < 4; ++p) {
4169:         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);
4170:       }
4171: #endif
4172:       /* A-E face */
4173:       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 8;
4174:       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*4 + GetQuadEdge_Static(ornt[2], 3);
4175:       orntNew[0] = 0;
4176:       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 2;
4177:       orntNew[1] = 0;
4178:       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 5;
4179:       orntNew[2] = -2;
4180:       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (cone[5] - fStart)*4 + GetQuadEdge_Static(ornt[5], 0);
4181:       orntNew[3] = -2;
4182:       DMPlexSetCone(rdm, newp, coneNew);
4183:       DMPlexSetConeOrientation(rdm, newp, orntNew);
4184: #if 1
4185:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4186:       for (p = 0; p < 4; ++p) {
4187:         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);
4188:       }
4189: #endif
4190:       /* D-F face */
4191:       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 9;
4192:       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*4 + GetQuadEdge_Static(ornt[2], 1);
4193:       orntNew[0] = -2;
4194:       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[4] - fStart)*4 + GetQuadEdge_Static(ornt[4], 3);
4195:       orntNew[1] = 0;
4196:       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 4;
4197:       orntNew[2] = 0;
4198:       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 2;
4199:       orntNew[3] = -2;
4200:       DMPlexSetCone(rdm, newp, coneNew);
4201:       DMPlexSetConeOrientation(rdm, newp, orntNew);
4202: #if 1
4203:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4204:       for (p = 0; p < 4; ++p) {
4205:         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);
4206:       }
4207: #endif
4208:       /* C-G face */
4209:       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 10;
4210:       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 4;
4211:       orntNew[0] = -2;
4212:       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[4] - fStart)*4 + GetQuadEdge_Static(ornt[4], 1);
4213:       orntNew[1] = -2;
4214:       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*4 + GetQuadEdge_Static(ornt[3], 3);
4215:       orntNew[2] = 0;
4216:       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 3;
4217:       orntNew[3] = 0;
4218:       DMPlexSetCone(rdm, newp, coneNew);
4219:       DMPlexSetConeOrientation(rdm, newp, orntNew);
4220: #if 1
4221:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4222:       for (p = 0; p < 4; ++p) {
4223:         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);
4224:       }
4225: #endif
4226:       /* B-H face */
4227:       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 11;
4228:       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 5;
4229:       orntNew[0] = 0;
4230:       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 3;
4231:       orntNew[1] = -2;
4232:       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*4 + GetQuadEdge_Static(ornt[3], 1);
4233:       orntNew[2] = -2;
4234:       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (cone[5] - fStart)*4 + GetQuadEdge_Static(ornt[5], 2);
4235:       orntNew[3] = 0;
4236:       DMPlexSetCone(rdm, newp, coneNew);
4237:       DMPlexSetConeOrientation(rdm, newp, orntNew);
4238: #if 1
4239:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4240:       for (p = 0; p < 4; ++p) {
4241:         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);
4242:       }
4243: #endif
4244:       for (r = 0; r < 12; ++r) {
4245:         newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + r;
4246:         supportNew[0] = cStartNew + (c - cStart)*8 + newCells[r*2+0];
4247:         supportNew[1] = cStartNew + (c - cStart)*8 + newCells[r*2+1];
4248:         DMPlexSetSupport(rdm, newp, supportNew);
4249: #if 1
4250:         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4251:         for (p = 0; p < 2; ++p) {
4252:           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);
4253:         }
4254: #endif
4255:       }
4256:     }
4257:     /* Split edges have 2 vertices and the same faces as the parent */
4258:     DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);
4259:     for (e = eStart; e < eEnd; ++e) {
4260:       const PetscInt newv = vStartNew + (vEnd - vStart) + (e - eStart);

4262:       for (r = 0; r < 2; ++r) {
4263:         const PetscInt  newp = eStartNew + (e - eStart)*2 + r;
4264:         const PetscInt *cone, *ornt, *support;
4265:         PetscInt        coneNew[2], coneSize, c, supportSize, s;

4267:         DMPlexGetCone(dm, e, &cone);
4268:         coneNew[0]       = vStartNew + (cone[0] - vStart);
4269:         coneNew[1]       = vStartNew + (cone[1] - vStart);
4270:         coneNew[(r+1)%2] = newv;
4271:         DMPlexSetCone(rdm, newp, coneNew);
4272: #if 1
4273:         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
4274:         for (p = 0; p < 2; ++p) {
4275:           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);
4276:         }
4277: #endif
4278:         DMPlexGetSupportSize(dm, e, &supportSize);
4279:         DMPlexGetSupport(dm, e, &support);
4280:         for (s = 0; s < supportSize; ++s) {
4281:           DMPlexGetConeSize(dm, support[s], &coneSize);
4282:           DMPlexGetCone(dm, support[s], &cone);
4283:           DMPlexGetConeOrientation(dm, support[s], &ornt);
4284:           for (c = 0; c < coneSize; ++c) {
4285:             if (cone[c] == e) break;
4286:           }
4287:           supportRef[s] = fStartNew + (support[s] - fStart)*4 + (ornt[c] < 0 ? (c+1-r)%4 : (c+r)%4);
4288:         }
4289:         DMPlexSetSupport(rdm, newp, supportRef);
4290: #if 1
4291:         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
4292:         for (p = 0; p < supportSize; ++p) {
4293:           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);
4294:         }
4295: #endif
4296:       }
4297:     }
4298:     /* Face edges have 2 vertices and 2+cells faces */
4299:     for (f = fStart; f < fEnd; ++f) {
4300:       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};
4301:       const PetscInt  newv = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (f - fStart);
4302:       const PetscInt *cone, *coneCell, *orntCell, *support;
4303:       PetscInt        coneNew[2], coneSize, c, supportSize, s;

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

4309:         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r] - eStart);
4310:         coneNew[1] = newv;
4311:         DMPlexSetCone(rdm, newp, coneNew);
4312: #if 1
4313:         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
4314:         for (p = 0; p < 2; ++p) {
4315:           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);
4316:         }
4317: #endif
4318:         DMPlexGetSupportSize(dm, f, &supportSize);
4319:         DMPlexGetSupport(dm, f, &support);
4320:         supportRef[0] = fStartNew + (f - fStart)*4 + r;
4321:         supportRef[1] = fStartNew + (f - fStart)*4 + (r+1)%4;
4322:         for (s = 0; s < supportSize; ++s) {
4323:           DMPlexGetConeSize(dm, support[s], &coneSize);
4324:           DMPlexGetCone(dm, support[s], &coneCell);
4325:           DMPlexGetConeOrientation(dm, support[s], &orntCell);
4326:           for (c = 0; c < coneSize; ++c) if (coneCell[c] == f) break;
4327:           supportRef[2+s] = fStartNew + (fEnd - fStart)*4 + (support[s] - cStart)*12 + newFaces[c*4 + GetQuadEdgeInverse_Static(orntCell[c], r)];
4328:         }
4329:         DMPlexSetSupport(rdm, newp, supportRef);
4330: #if 1
4331:         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
4332:         for (p = 0; p < 2+supportSize; ++p) {
4333:           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);
4334:         }
4335: #endif
4336:       }
4337:     }
4338:     /* Cell edges have 2 vertices and 4 faces */
4339:     for (c = cStart; c < cEnd; ++c) {
4340:       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};
4341:       const PetscInt  newv = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (fEnd - fStart) + (c - cStart);
4342:       const PetscInt *cone;
4343:       PetscInt        coneNew[2], supportNew[4];

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

4349:         coneNew[0] = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (cone[r] - fStart);
4350:         coneNew[1] = newv;
4351:         DMPlexSetCone(rdm, newp, coneNew);
4352: #if 1
4353:         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
4354:         for (p = 0; p < 2; ++p) {
4355:           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);
4356:         }
4357: #endif
4358:         for (f = 0; f < 4; ++f) supportNew[f] = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + newFaces[r*4+f];
4359:         DMPlexSetSupport(rdm, newp, supportNew);
4360: #if 1
4361:         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
4362:         for (p = 0; p < 4; ++p) {
4363:           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);
4364:         }
4365: #endif
4366:       }
4367:     }
4368:     /* Old vertices have identical supports */
4369:     for (v = vStart; v < vEnd; ++v) {
4370:       const PetscInt  newp = vStartNew + (v - vStart);
4371:       const PetscInt *support, *cone;
4372:       PetscInt        size, s;

4374:       DMPlexGetSupportSize(dm, v, &size);
4375:       DMPlexGetSupport(dm, v, &support);
4376:       for (s = 0; s < size; ++s) {
4377:         PetscInt r = 0;

4379:         DMPlexGetCone(dm, support[s], &cone);
4380:         if (cone[1] == v) r = 1;
4381:         supportRef[s] = eStartNew + (support[s] - eStart)*2 + r;
4382:       }
4383:       DMPlexSetSupport(rdm, newp, supportRef);
4384: #if 1
4385:       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
4386:       for (p = 0; p < size; ++p) {
4387:         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);
4388:       }
4389: #endif
4390:     }
4391:     /* Edge vertices have 2 + faces supports */
4392:     for (e = eStart; e < eEnd; ++e) {
4393:       const PetscInt  newp = vStartNew + (vEnd - vStart) + (e - eStart);
4394:       const PetscInt *cone, *support;
4395:       PetscInt        size, s;

4397:       DMPlexGetSupportSize(dm, e, &size);
4398:       DMPlexGetSupport(dm, e, &support);
4399:       supportRef[0] = eStartNew + (e - eStart)*2 + 0;
4400:       supportRef[1] = eStartNew + (e - eStart)*2 + 1;
4401:       for (s = 0; s < size; ++s) {
4402:         PetscInt r;

4404:         DMPlexGetCone(dm, support[s], &cone);
4405:         for (r = 0; r < 4; ++r) if (cone[r] == e) break;
4406:         supportRef[2+s] = eStartNew + (eEnd - eStart)*2 + (support[s] - fStart)*4 + r;
4407:       }
4408:       DMPlexSetSupport(rdm, newp, supportRef);
4409: #if 1
4410:       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
4411:       for (p = 0; p < 2+size; ++p) {
4412:         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);
4413:       }
4414: #endif
4415:     }
4416:     /* Face vertices have 4 + cells supports */
4417:     for (f = fStart; f < fEnd; ++f) {
4418:       const PetscInt  newp = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (f - fStart);
4419:       const PetscInt *cone, *support;
4420:       PetscInt        size, s;

4422:       DMPlexGetSupportSize(dm, f, &size);
4423:       DMPlexGetSupport(dm, f, &support);
4424:       for (r = 0; r < 4; ++r) supportRef[r] = eStartNew + (eEnd - eStart)*2 +  (f - fStart)*4 + r;
4425:       for (s = 0; s < size; ++s) {
4426:         PetscInt r;

4428:         DMPlexGetCone(dm, support[s], &cone);
4429:         for (r = 0; r < 6; ++r) if (cone[r] == f) break;
4430:         supportRef[4+s] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*4 + (support[s] - cStart)*6 + r;
4431:       }
4432:       DMPlexSetSupport(rdm, newp, supportRef);
4433: #if 1
4434:       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
4435:       for (p = 0; p < 4+size; ++p) {
4436:         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);
4437:       }
4438: #endif
4439:     }
4440:     /* Cell vertices have 6 supports */
4441:     for (c = cStart; c < cEnd; ++c) {
4442:       const PetscInt newp = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (fEnd - fStart) + (c - cStart);
4443:       PetscInt       supportNew[6];

4445:       for (r = 0; r < 6; ++r) {
4446:         supportNew[r] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*4 + (c - cStart)*6 + r;
4447:       }
4448:       DMPlexSetSupport(rdm, newp, supportNew);
4449:     }
4450:     PetscFree(supportRef);
4451:     break;
4452:   case 8:
4453:     /* Hybrid Hex 3D */
4454:     DMPlexGetHybridBounds(rdm, &cMaxNew, &fMaxNew, &eMaxNew, NULL);
4455:     /*
4456:      Bottom (viewed from top)    Top
4457:      1---------2---------2       7---------2---------6
4458:      |         |         |       |         |         |
4459:      |    B    2    C    |       |    H    2    G    |
4460:      |         |         |       |         |         |
4461:      3----3----0----1----1       3----3----0----1----1
4462:      |         |         |       |         |         |
4463:      |    A    0    D    |       |    E    0    F    |
4464:      |         |         |       |         |         |
4465:      0---------0---------3       4---------0---------5
4466:      */
4467:     /* Interior cells have 6 faces: Bottom, Top, Front, Back, Right, Left */
4468:     for (c = cStart; c < cMax; ++c) {
4469:       const PetscInt  newp = (c - cStart)*8;
4470:       const PetscInt *cone, *ornt;
4471:       PetscInt        coneNew[6], orntNew[6];

4473:       DMPlexGetCone(dm, c, &cone);
4474:       DMPlexGetConeOrientation(dm, c, &ornt);
4475:       /* A hex */
4476:       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], 0);
4477:       orntNew[0] = ornt[0];
4478:       coneNew[1] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  8; /* AE */
4479:       orntNew[1] = 0;
4480:       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetQuadSubface_Static(ornt[2], 0);
4481:       orntNew[2] = ornt[2];
4482:       coneNew[3] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  3; /* AB */
4483:       orntNew[3] = 0;
4484:       coneNew[4] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  0; /* AD */
4485:       orntNew[4] = 0;
4486:       coneNew[5] = fStartNew + (cone[5] - fStart)*4 + GetQuadSubface_Static(ornt[5], 0);
4487:       orntNew[5] = ornt[5];
4488:       DMPlexSetCone(rdm, newp+0, coneNew);
4489:       DMPlexSetConeOrientation(rdm, newp+0, orntNew);
4490: #if 1
4491:       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);
4492:       for (p = 0; p < 6; ++p) {
4493:         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);
4494:       }
4495: #endif
4496:       /* B hex */
4497:       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], 1);
4498:       orntNew[0] = ornt[0];
4499:       coneNew[1] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 + 11; /* BH */
4500:       orntNew[1] = 0;
4501:       coneNew[2] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  3; /* AB */
4502:       orntNew[2] = -1;
4503:       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetQuadSubface_Static(ornt[3], 1);
4504:       orntNew[3] = ornt[3];
4505:       coneNew[4] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  2; /* BC */
4506:       orntNew[4] = 0;
4507:       coneNew[5] = fStartNew + (cone[5] - fStart)*4 + GetQuadSubface_Static(ornt[5], 3);
4508:       orntNew[5] = ornt[5];
4509:       DMPlexSetCone(rdm, newp+1, coneNew);
4510:       DMPlexSetConeOrientation(rdm, newp+1, orntNew);
4511: #if 1
4512:       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);
4513:       for (p = 0; p < 6; ++p) {
4514:         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);
4515:       }
4516: #endif
4517:       /* C hex */
4518:       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], 2);
4519:       orntNew[0] = ornt[0];
4520:       coneNew[1] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 + 10; /* CG */
4521:       orntNew[1] = 0;
4522:       coneNew[2] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  1; /* CD */
4523:       orntNew[2] = -1;
4524:       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetQuadSubface_Static(ornt[3], 0);
4525:       orntNew[3] = ornt[3];
4526:       coneNew[4] = fStartNew + (cone[4] - fStart)*4 + GetQuadSubface_Static(ornt[4], 1);
4527:       orntNew[4] = ornt[4];
4528:       coneNew[5] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  2; /* BC */
4529:       orntNew[5] = -4;
4530:       DMPlexSetCone(rdm, newp+2, coneNew);
4531:       DMPlexSetConeOrientation(rdm, newp+2, orntNew);
4532: #if 1
4533:       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);
4534:       for (p = 0; p < 6; ++p) {
4535:         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);
4536:       }
4537: #endif
4538:       /* D hex */
4539:       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], 3);
4540:       orntNew[0] = ornt[0];
4541:       coneNew[1] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  9; /* DF */
4542:       orntNew[1] = 0;
4543:       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetQuadSubface_Static(ornt[2], 1);
4544:       orntNew[2] = ornt[2];
4545:       coneNew[3] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  1; /* CD */
4546:       orntNew[3] = 0;
4547:       coneNew[4] = fStartNew + (cone[4] - fStart)*4 + GetQuadSubface_Static(ornt[4], 0);
4548:       orntNew[4] = ornt[4];
4549:       coneNew[5] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  0; /* AD */
4550:       orntNew[5] = -4;
4551:       DMPlexSetCone(rdm, newp+3, coneNew);
4552:       DMPlexSetConeOrientation(rdm, newp+3, orntNew);
4553: #if 1
4554:       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);
4555:       for (p = 0; p < 6; ++p) {
4556:         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);
4557:       }
4558: #endif
4559:       /* E hex */
4560:       coneNew[0] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  8; /* AE */
4561:       orntNew[0] = -4;
4562:       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], 0);
4563:       orntNew[1] = ornt[1];
4564:       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetQuadSubface_Static(ornt[2], 3);
4565:       orntNew[2] = ornt[2];
4566:       coneNew[3] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  7; /* EH */
4567:       orntNew[3] = 0;
4568:       coneNew[4] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  4; /* EF */
4569:       orntNew[4] = -1;
4570:       coneNew[5] = fStartNew + (cone[5] - fStart)*4 + GetQuadSubface_Static(ornt[5], 1);
4571:       orntNew[5] = ornt[5];
4572:       DMPlexSetCone(rdm, newp+4, coneNew);
4573:       DMPlexSetConeOrientation(rdm, newp+4, orntNew);
4574: #if 1
4575:       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);
4576:       for (p = 0; p < 6; ++p) {
4577:         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);
4578:       }
4579: #endif
4580:       /* F hex */
4581:       coneNew[0] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  9; /* DF */
4582:       orntNew[0] = -4;
4583:       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], 1);
4584:       orntNew[1] = ornt[1];
4585:       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetQuadSubface_Static(ornt[2], 2);
4586:       orntNew[2] = ornt[2];
4587:       coneNew[3] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  5; /* FG */
4588:       orntNew[3] = -1;
4589:       coneNew[4] = fStartNew + (cone[4] - fStart)*4 + GetQuadSubface_Static(ornt[4], 3);
4590:       orntNew[4] = ornt[4];
4591:       coneNew[5] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  4; /* EF */
4592:       orntNew[5] = 1;
4593:       DMPlexSetCone(rdm, newp+5, coneNew);
4594:       DMPlexSetConeOrientation(rdm, newp+5, orntNew);
4595: #if 1
4596:       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);
4597:       for (p = 0; p < 6; ++p) {
4598:         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);
4599:       }
4600: #endif
4601:       /* G hex */
4602:       coneNew[0] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 + 10; /* CG */
4603:       orntNew[0] = -4;
4604:       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], 2);
4605:       orntNew[1] = ornt[1];
4606:       coneNew[2] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  5; /* FG */
4607:       orntNew[2] = 0;
4608:       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetQuadSubface_Static(ornt[3], 3);
4609:       orntNew[3] = ornt[3];
4610:       coneNew[4] = fStartNew + (cone[4] - fStart)*4 + GetQuadSubface_Static(ornt[4], 2);
4611:       orntNew[4] = ornt[4];
4612:       coneNew[5] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  6; /* GH */
4613:       orntNew[5] = -3;
4614:       DMPlexSetCone(rdm, newp+6, coneNew);
4615:       DMPlexSetConeOrientation(rdm, newp+6, orntNew);
4616: #if 1
4617:       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);
4618:       for (p = 0; p < 6; ++p) {
4619:         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);
4620:       }
4621: #endif
4622:       /* H hex */
4623:       coneNew[0] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 + 11; /* BH */
4624:       orntNew[0] = -4;
4625:       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], 3);
4626:       orntNew[1] = ornt[1];
4627:       coneNew[2] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  7; /* EH */
4628:       orntNew[2] = -1;
4629:       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetQuadSubface_Static(ornt[3], 2);
4630:       orntNew[3] = ornt[3];
4631:       coneNew[4] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  6; /* GH */
4632:       orntNew[4] = 3;
4633:       coneNew[5] = fStartNew + (cone[5] - fStart)*4 + GetQuadSubface_Static(ornt[5], 2);
4634:       orntNew[5] = ornt[5];
4635:       DMPlexSetCone(rdm, newp+7, coneNew);
4636:       DMPlexSetConeOrientation(rdm, newp+7, orntNew);
4637: #if 1
4638:       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);
4639:       for (p = 0; p < 6; ++p) {
4640:         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);
4641:       }
4642: #endif
4643:     }
4644:     /* Hybrid cells have 6 faces: Front, Back, Sides */
4645:     /*
4646:      3---------2---------2
4647:      |         |         |
4648:      |    D    2    C    |
4649:      |         |         |
4650:      3----3----0----1----1
4651:      |         |         |
4652:      |    A    0    B    |
4653:      |         |         |
4654:      0---------0---------1
4655:      */
4656:     for (c = cMax; c < cEnd; ++c) {
4657:       const PetscInt  newp = (cMax - cStart)*8 + (c - cMax)*4;
4658:       const PetscInt *cone, *ornt, *fornt;
4659:       PetscInt        coneNew[6], orntNew[6], o, of, i;

4661:       DMPlexGetCone(dm, c, &cone);
4662:       DMPlexGetConeOrientation(dm, c, &ornt);
4663:       DMPlexGetConeOrientation(dm, cone[0], &fornt);
4664:       o = ornt[0] < 0 ? -1 : 1;
4665:       for (r = 0; r < 4; ++r) {
4666:         PetscInt subfA = GetQuadSubface_Static(ornt[0], r);
4667:         PetscInt edgeA = GetQuadEdge_Static(ornt[0], r);
4668:         PetscInt edgeB = GetQuadEdge_Static(ornt[0], (r+3)%4);
4669:         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]);
4670:         coneNew[0]         = fStartNew + (cone[0] - fStart)*4 + subfA;
4671:         orntNew[0]         = ornt[0];
4672:         coneNew[1]         = fStartNew + (cone[1] - fStart)*4 + subfA;
4673:         orntNew[1]         = ornt[0];
4674:         of = fornt[edgeA] < 0 ? -1 : 1;
4675:         i  = GetQuadEdgeInverse_Static(ornt[0], r) + 2;
4676:         coneNew[i] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (cone[2+edgeA] - fMax)*2 + (o*of < 0 ? 1 : 0);
4677:         orntNew[i] = ornt[edgeA];
4678:         i  = GetQuadEdgeInverse_Static(ornt[0], (r+1)%4) + 2;
4679:         coneNew[i] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd          - fMax)*2 + (c - cMax)*4 + edgeA;
4680:         orntNew[i] = 0;
4681:         i  = GetQuadEdgeInverse_Static(ornt[0], (r+2)%4) + 2;
4682:         coneNew[i] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd          - fMax)*2 + (c - cMax)*4 + edgeB;
4683:         orntNew[i] = -2;
4684:         of = fornt[edgeB] < 0 ? -1 : 1;
4685:         i  = GetQuadEdgeInverse_Static(ornt[0], (r+3)%4) + 2;
4686:         coneNew[i] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (cone[2+edgeB] - fMax)*2 + (o*of < 0 ? 0 : 1);
4687:         orntNew[i] = ornt[edgeB];
4688:         DMPlexSetCone(rdm, newp+r, coneNew);
4689:         DMPlexSetConeOrientation(rdm, newp+r, orntNew);
4690: #if 1
4691:         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);
4692:         for (p = 0; p < 2; ++p) {
4693:           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);
4694:         }
4695:         for (p = 2; p < 6; ++p) {
4696:           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);
4697:         }
4698: #endif
4699:       }
4700:     }
4701:     /* Interior split faces have 4 edges and the same cells as the parent */
4702:     DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);
4703:     PetscMalloc1((4 + maxSupportSize*2), &supportRef);
4704:     for (f = fStart; f < fMax; ++f) {
4705:       for (r = 0; r < 4; ++r) {
4706:         /* TODO: This can come from GetFaces_Internal() */
4707:         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};
4708:         const PetscInt  newp = fStartNew + (f - fStart)*4 + r;
4709:         const PetscInt *cone, *ornt, *support;
4710:         PetscInt        coneNew[4], orntNew[4], coneSize, c, supportSize, s;

4712:         DMPlexGetCone(dm, f, &cone);
4713:         DMPlexGetConeOrientation(dm, f, &ornt);
4714:         coneNew[(r+3)%4] = eStartNew + (cone[(r+3)%4] - eStart)*2 + (ornt[(r+3)%4] < 0 ? 0 : 1);
4715:         orntNew[(r+3)%4] = ornt[(r+3)%4];
4716:         coneNew[(r+0)%4] = eStartNew + (cone[r]       - eStart)*2 + (ornt[r] < 0 ? 1 : 0);
4717:         orntNew[(r+0)%4] = ornt[r];
4718:         coneNew[(r+1)%4] = eStartNew + (eMax - eStart)*2 + (f - fStart)*4 + r;
4719:         orntNew[(r+1)%4] = 0;
4720:         coneNew[(r+2)%4] = eStartNew + (eMax - eStart)*2 + (f - fStart)*4 + (r+3)%4;
4721:         orntNew[(r+2)%4] = -2;
4722:         DMPlexSetCone(rdm, newp, coneNew);
4723:         DMPlexSetConeOrientation(rdm, newp, orntNew);
4724: #if 1
4725:         if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
4726:         for (p = 0; p < 4; ++p) {
4727:           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);
4728:         }
4729: #endif
4730:         DMPlexGetSupportSize(dm, f, &supportSize);
4731:         DMPlexGetSupport(dm, f, &support);
4732:         for (s = 0; s < supportSize; ++s) {
4733:           PetscInt subf;
4734:           DMPlexGetConeSize(dm, support[s], &coneSize);
4735:           DMPlexGetCone(dm, support[s], &cone);
4736:           DMPlexGetConeOrientation(dm, support[s], &ornt);
4737:           for (c = 0; c < coneSize; ++c) {
4738:             if (cone[c] == f) break;
4739:           }
4740:           subf = GetQuadSubfaceInverse_Static(ornt[c], r);
4741:           if (support[s] < cMax) {
4742:             supportRef[s] = cStartNew + (support[s] - cStart)*8 + newCells[c*4+subf];
4743:           } else {
4744:             supportRef[s] = cStartNew + (cMax       - cStart)*8 + (support[s] - cMax)*4 + subf;
4745:           }
4746:         }
4747:         DMPlexSetSupport(rdm, newp, supportRef);
4748: #if 1
4749:         if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
4750:         for (p = 0; p < supportSize; ++p) {
4751:           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);
4752:         }
4753: #endif
4754:       }
4755:     }
4756:     /* Interior cell faces have 4 edges and 2 cells */
4757:     for (c = cStart; c < cMax; ++c) {
4758:       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};
4759:       const PetscInt *cone, *ornt;
4760:       PetscInt        newp, coneNew[4], orntNew[4], supportNew[2];

4762:       DMPlexGetCone(dm, c, &cone);
4763:       DMPlexGetConeOrientation(dm, c, &ornt);
4764:       /* A-D face */
4765:       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 0;
4766:       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*4 + GetQuadEdge_Static(ornt[0], 3);
4767:       orntNew[0] = 0;
4768:       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 0;
4769:       orntNew[1] = 0;
4770:       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 2;
4771:       orntNew[2] = -2;
4772:       coneNew[3] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*4 + GetQuadEdge_Static(ornt[2], 0);
4773:       orntNew[3] = -2;
4774:       DMPlexSetCone(rdm, newp, coneNew);
4775:       DMPlexSetConeOrientation(rdm, newp, orntNew);
4776: #if 1
4777:       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
4778:       for (p = 0; p < 4; ++p) {
4779:         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);
4780:       }
4781: #endif
4782:       /* C-D face */
4783:       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 1;
4784:       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*4 + GetQuadEdge_Static(ornt[0], 2);
4785:       orntNew[0] = 0;
4786:       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 0;
4787:       orntNew[1] = 0;
4788:       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 4;
4789:       orntNew[2] = -2;
4790:       coneNew[3] = eStartNew + (eMax - eStart)*2 + (cone[4] - fStart)*4 + GetQuadEdge_Static(ornt[4], 0);
4791:       orntNew[3] = -2;
4792:       DMPlexSetCone(rdm, newp, coneNew);
4793:       DMPlexSetConeOrientation(rdm, newp, orntNew);
4794: #if 1
4795:       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
4796:       for (p = 0; p < 4; ++p) {
4797:         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);
4798:       }
4799: #endif
4800:       /* B-C face */
4801:       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 2;
4802:       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*4 + GetQuadEdge_Static(ornt[0], 1);
4803:       orntNew[0] = -2;
4804:       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*4 + GetQuadEdge_Static(ornt[3], 0);
4805:       orntNew[1] = 0;
4806:       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 3;
4807:       orntNew[2] = 0;
4808:       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 0;
4809:       orntNew[3] = -2;
4810:       DMPlexSetCone(rdm, newp, coneNew);
4811:       DMPlexSetConeOrientation(rdm, newp, orntNew);
4812: #if 1
4813:       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
4814:       for (p = 0; p < 4; ++p) {
4815:         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);
4816:       }
4817: #endif
4818:       /* A-B face */
4819:       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 3;
4820:       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*4 + GetQuadEdge_Static(ornt[0], 0);
4821:       orntNew[0] = -2;
4822:       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[5] - fStart)*4 + GetQuadEdge_Static(ornt[5], 3);
4823:       orntNew[1] = 0;
4824:       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 5;
4825:       orntNew[2] = 0;
4826:       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 0;
4827:       orntNew[3] = -2;
4828:       DMPlexSetCone(rdm, newp, coneNew);
4829:       DMPlexSetConeOrientation(rdm, newp, orntNew);
4830: #if 1
4831:       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
4832:       for (p = 0; p < 4; ++p) {
4833:         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);
4834:       }
4835: #endif
4836:       /* E-F face */
4837:       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 4;
4838:       coneNew[0] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 2;
4839:       orntNew[0] = -2;
4840:       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*4 + GetQuadEdge_Static(ornt[2], 2);
4841:       orntNew[1] = -2;
4842:       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*4 + GetQuadEdge_Static(ornt[1], 0);
4843:       orntNew[2] = 0;
4844:       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 1;
4845:       orntNew[3] = 0;
4846:       DMPlexSetCone(rdm, newp, coneNew);
4847:       DMPlexSetConeOrientation(rdm, newp, orntNew);
4848: #if 1
4849:       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
4850:       for (p = 0; p < 4; ++p) {
4851:         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);
4852:       }
4853: #endif
4854:       /* F-G face */
4855:       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 5;
4856:       coneNew[0] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 4;
4857:       orntNew[0] = -2;
4858:       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[4] - fStart)*4 + GetQuadEdge_Static(ornt[4], 2);
4859:       orntNew[1] = -2;
4860:       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*4 + GetQuadEdge_Static(ornt[1], 1);
4861:       orntNew[2] = 0;
4862:       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 1;
4863:       orntNew[3] = 0;
4864:       DMPlexSetCone(rdm, newp, coneNew);
4865:       DMPlexSetConeOrientation(rdm, newp, orntNew);
4866: #if 1
4867:       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
4868:       for (p = 0; p < 4; ++p) {
4869:         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);
4870:       }
4871: #endif
4872:       /* G-H face */
4873:       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 6;
4874:       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*4 + GetQuadEdge_Static(ornt[3], 2);
4875:       orntNew[0] = -2;
4876:       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*4 + GetQuadEdge_Static(ornt[1], 2);
4877:       orntNew[1] = 0;
4878:       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 1;
4879:       orntNew[2] = 0;
4880:       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 3;
4881:       orntNew[3] = -2;
4882:       DMPlexSetCone(rdm, newp, coneNew);
4883:       DMPlexSetConeOrientation(rdm, newp, orntNew);
4884: #if 1
4885:       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
4886:       for (p = 0; p < 4; ++p) {
4887:         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);
4888:       }
4889: #endif
4890:       /* E-H face */
4891:       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 7;
4892:       coneNew[0] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 5;
4893:       orntNew[0] = -2;
4894:       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[5] - fStart)*4 + GetQuadEdge_Static(ornt[5], 1);
4895:       orntNew[1] = -2;
4896:       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*4 + GetQuadEdge_Static(ornt[1], 3);
4897:       orntNew[2] = 0;
4898:       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 1;
4899:       orntNew[3] = 0;
4900:       DMPlexSetCone(rdm, newp, coneNew);
4901:       DMPlexSetConeOrientation(rdm, newp, orntNew);
4902: #if 1
4903:       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
4904:       for (p = 0; p < 4; ++p) {
4905:         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);
4906:       }
4907: #endif
4908:       /* A-E face */
4909:       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 8;
4910:       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*4 + GetQuadEdge_Static(ornt[2], 3);
4911:       orntNew[0] = 0;
4912:       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 2;
4913:       orntNew[1] = 0;
4914:       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 5;
4915:       orntNew[2] = -2;
4916:       coneNew[3] = eStartNew + (eMax - eStart)*2 + (cone[5] - fStart)*4 + GetQuadEdge_Static(ornt[5], 0);
4917:       orntNew[3] = -2;
4918:       DMPlexSetCone(rdm, newp, coneNew);
4919:       DMPlexSetConeOrientation(rdm, newp, orntNew);
4920: #if 1
4921:       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
4922:       for (p = 0; p < 4; ++p) {
4923:         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);
4924:       }
4925: #endif
4926:       /* D-F face */
4927:       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 9;
4928:       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*4 + GetQuadEdge_Static(ornt[2], 1);
4929:       orntNew[0] = -2;
4930:       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[4] - fStart)*4 + GetQuadEdge_Static(ornt[4], 3);
4931:       orntNew[1] = 0;
4932:       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 4;
4933:       orntNew[2] = 0;
4934:       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 2;
4935:       orntNew[3] = -2;
4936:       DMPlexSetCone(rdm, newp, coneNew);
4937:       DMPlexSetConeOrientation(rdm, newp, orntNew);
4938: #if 1
4939:       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
4940:       for (p = 0; p < 4; ++p) {
4941:         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);
4942:       }
4943: #endif
4944:       /* C-G face */
4945:       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 10;
4946:       coneNew[0] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 4;
4947:       orntNew[0] = -2;
4948:       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[4] - fStart)*4 + GetQuadEdge_Static(ornt[4], 1);
4949:       orntNew[1] = -2;
4950:       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*4 + GetQuadEdge_Static(ornt[3], 3);
4951:       orntNew[2] = 0;
4952:       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 3;
4953:       orntNew[3] = 0;
4954:       DMPlexSetCone(rdm, newp, coneNew);
4955:       DMPlexSetConeOrientation(rdm, newp, orntNew);
4956: #if 1
4957:       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
4958:       for (p = 0; p < 4; ++p) {
4959:         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);
4960:       }
4961: #endif
4962:       /* B-H face */
4963:       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 11;
4964:       coneNew[0] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 5;
4965:       orntNew[0] = 0;
4966:       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 3;
4967:       orntNew[1] = -2;
4968:       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*4 + GetQuadEdge_Static(ornt[3], 1);
4969:       orntNew[2] = -2;
4970:       coneNew[3] = eStartNew + (eMax - eStart)*2 + (cone[5] - fStart)*4 + GetQuadEdge_Static(ornt[5], 2);
4971:       orntNew[3] = 0;
4972:       DMPlexSetCone(rdm, newp, coneNew);
4973:       DMPlexSetConeOrientation(rdm, newp, orntNew);
4974: #if 1
4975:       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
4976:       for (p = 0; p < 4; ++p) {
4977:         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);
4978:       }
4979: #endif
4980:       for (r = 0; r < 12; ++r) {
4981:         newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + r;
4982:         supportNew[0] = cStartNew + (c - cStart)*8 + newCells[r*2+0];
4983:         supportNew[1] = cStartNew + (c - cStart)*8 + newCells[r*2+1];
4984:         DMPlexSetSupport(rdm, newp, supportNew);
4985: #if 1
4986:         if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
4987:         for (p = 0; p < 2; ++p) {
4988:           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);
4989:         }
4990: #endif
4991:       }
4992:     }
4993:     /* Hybrid split faces have 4 edges and same cells */
4994:     for (f = fMax; f < fEnd; ++f) {
4995:       const PetscInt *cone, *ornt, *support;
4996:       PetscInt        coneNew[4], orntNew[4];
4997:       PetscInt        supportNew[2], size, s, c;

4999:       DMPlexGetCone(dm, f, &cone);
5000:       DMPlexGetConeOrientation(dm, f, &ornt);
5001:       DMPlexGetSupportSize(dm, f, &size);
5002:       DMPlexGetSupport(dm, f, &support);
5003:       for (r = 0; r < 2; ++r) {
5004:         const PetscInt newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (f - fMax)*2 + r;

5006:         coneNew[0]   = eStartNew + (cone[0] - eStart)*2 + (ornt[0] < 0 ? 1-r : r);
5007:         orntNew[0]   = ornt[0];
5008:         coneNew[1]   = eStartNew + (cone[1] - eStart)*2 + (ornt[1] < 0 ? 1-r : r);
5009:         orntNew[1]   = ornt[1];
5010:         coneNew[2+r] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (cone[2+r] - eMax);
5011:         orntNew[2+r] = 0;
5012:         coneNew[3-r] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (eEnd      - eMax) + (f - fMax);
5013:         orntNew[3-r] = 0;
5014:         DMPlexSetCone(rdm, newp, coneNew);
5015:         DMPlexSetConeOrientation(rdm, newp, orntNew);
5016: #if 1
5017:         if ((newp < fMaxNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid face [%d, %d)", newp, fMaxNew, fEndNew);
5018:         for (p = 0; p < 2; ++p) {
5019:           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);
5020:         }
5021:         for (p = 2; p < 4; ++p) {
5022:           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);
5023:         }
5024: #endif
5025:         for (s = 0; s < size; ++s) {
5026:           const PetscInt *coneCell, *orntCell, *fornt;
5027:           PetscInt        o, of;

5029:           DMPlexGetCone(dm, support[s], &coneCell);
5030:           DMPlexGetConeOrientation(dm, support[s], &orntCell);
5031:           o = orntCell[0] < 0 ? -1 : 1;
5032:           for (c = 2; c < 6; ++c) if (coneCell[c] == f) break;
5033:           if (c >= 6) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Could not find face %d in cone of cell %d", f, support[s]);
5034:           DMPlexGetConeOrientation(dm, coneCell[0], &fornt);
5035:           of = fornt[c-2] < 0 ? -1 : 1;
5036:           supportNew[s] = cStartNew + (cMax - cStart)*8 + (support[s] - cMax)*4 + (GetQuadEdgeInverse_Static(orntCell[0], c-2) + (o*of < 0 ? 1-r : r))%4;
5037:         }
5038:         DMPlexSetSupport(rdm, newp, supportNew);
5039: #if 1
5040:         if ((newp < fMaxNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid face [%d, %d)", newp, fMaxNew, fEndNew);
5041:         for (p = 0; p < size; ++p) {
5042:           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);
5043:         }
5044: #endif
5045:       }
5046:     }
5047:     /* Hybrid cell faces have 4 edges and 2 cells */
5048:     for (c = cMax; c < cEnd; ++c) {
5049:       PetscInt        newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd - fMax)*2 + (c - cMax)*4;
5050:       const PetscInt *cone, *ornt;
5051:       PetscInt        coneNew[4], orntNew[4];
5052:       PetscInt        supportNew[2];

5054:       DMPlexGetCone(dm, c, &cone);
5055:       DMPlexGetConeOrientation(dm, c, &ornt);
5056:       for (r = 0; r < 4; ++r) {
5057: #if 0
5058:         coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], r);
5059:         orntNew[0] = 0;
5060:         coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], r);
5061:         orntNew[1] = 0;
5062:         coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (eEnd - eMax) + (cone[2+GetQuadEdge_Static(ornt[0], r)] - fMax);
5063:         orntNew[2] = 0;
5064:         coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (eEnd - eMax) + (fEnd                                   - fMax) + (c - cMax);
5065:         orntNew[3] = 0;
5066: #else
5067:         coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*4 + r;
5068:         orntNew[0] = 0;
5069:         coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*4 + r;
5070:         orntNew[1] = 0;
5071:         coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (eEnd - eMax) + (cone[2+r] - fMax);
5072:         orntNew[2] = 0;
5073:         coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (eEnd - eMax) + (fEnd      - fMax) + (c - cMax);
5074:         orntNew[3] = 0;
5075: #endif
5076:         DMPlexSetCone(rdm, newp+r, coneNew);
5077:         DMPlexSetConeOrientation(rdm, newp+r, orntNew);
5078: #if 1
5079:         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);
5080:         for (p = 0; p < 2; ++p) {
5081:           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);
5082:         }
5083:         for (p = 2; p < 4; ++p) {
5084:           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);
5085:         }
5086: #endif
5087:         supportNew[0] = cStartNew + (cMax - cStart)*8 + (c - cMax)*4 + GetQuadSubface_Static(ornt[0], r);
5088:         supportNew[1] = cStartNew + (cMax - cStart)*8 + (c - cMax)*4 + GetQuadSubface_Static(ornt[0], (r+1)%4);
5089:         DMPlexSetSupport(rdm, newp+r, supportNew);
5090: #if 1
5091:         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);
5092:         for (p = 0; p < 2; ++p) {
5093:           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);
5094:         }
5095: #endif
5096:       }
5097:     }
5098:     /* Interior split edges have 2 vertices and the same faces as the parent */
5099:     DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);
5100:     for (e = eStart; e < eMax; ++e) {
5101:       const PetscInt newv = vStartNew + (vEnd - vStart) + (e - eStart);

5103:       for (r = 0; r < 2; ++r) {
5104:         const PetscInt  newp = eStartNew + (e - eStart)*2 + r;
5105:         const PetscInt *cone, *ornt, *support;
5106:         PetscInt        coneNew[2], coneSize, c, supportSize, s;

5108:         DMPlexGetCone(dm, e, &cone);
5109:         coneNew[0]       = vStartNew + (cone[0] - vStart);
5110:         coneNew[1]       = vStartNew + (cone[1] - vStart);
5111:         coneNew[(r+1)%2] = newv;
5112:         DMPlexSetCone(rdm, newp, coneNew);
5113: #if 1
5114:         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
5115:         for (p = 0; p < 2; ++p) {
5116:           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);
5117:         }
5118: #endif
5119:         DMPlexGetSupportSize(dm, e, &supportSize);
5120:         DMPlexGetSupport(dm, e, &support);
5121:         for (s = 0; s < supportSize; ++s) {
5122:           DMPlexGetConeSize(dm, support[s], &coneSize);
5123:           DMPlexGetCone(dm, support[s], &cone);
5124:           DMPlexGetConeOrientation(dm, support[s], &ornt);
5125:           for (c = 0; c < coneSize; ++c) {
5126:             if (cone[c] == e) break;
5127:           }
5128:           if (support[s] < fMax) {
5129:             supportRef[s] = fStartNew + (support[s] - fStart)*4 + (c + (ornt[c] < 0 ? 1-r : r))%4;
5130:           } else {
5131:             supportRef[s] = fStartNew + (fMax       - fStart)*4 + (cMax - cStart)*12 + (support[s] - fMax)*2 + (ornt[c] < 0 ? 1-r : r);
5132:           }
5133:         }
5134:         DMPlexSetSupport(rdm, newp, supportRef);
5135: #if 1
5136:         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
5137:         for (p = 0; p < supportSize; ++p) {
5138:           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);
5139:         }
5140: #endif
5141:       }
5142:     }
5143:     /* Interior face edges have 2 vertices and 2+cells faces */
5144:     for (f = fStart; f < fMax; ++f) {
5145:       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};
5146:       const PetscInt  newv = vStartNew + (vEnd - vStart) + (eMax - eStart) + (f - fStart);
5147:       const PetscInt *cone, *coneCell, *orntCell, *support;
5148:       PetscInt        coneNew[2], coneSize, c, supportSize, s;

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

5154:         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r] - eStart);
5155:         coneNew[1] = newv;
5156:         DMPlexSetCone(rdm, newp, coneNew);
5157: #if 1
5158:         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
5159:         for (p = 0; p < 2; ++p) {
5160:           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);
5161:         }
5162: #endif
5163:         DMPlexGetSupportSize(dm, f, &supportSize);
5164:         DMPlexGetSupport(dm, f, &support);
5165:         supportRef[0] = fStartNew + (f - fStart)*4 + r;
5166:         supportRef[1] = fStartNew + (f - fStart)*4 + (r+1)%4;
5167:         for (s = 0; s < supportSize; ++s) {
5168:           DMPlexGetConeSize(dm, support[s], &coneSize);
5169:           DMPlexGetCone(dm, support[s], &coneCell);
5170:           DMPlexGetConeOrientation(dm, support[s], &orntCell);
5171:           for (c = 0; c < coneSize; ++c) if (coneCell[c] == f) break;
5172:           if (support[s] < cMax) {
5173:             supportRef[2+s] = fStartNew + (fMax - fStart)*4 + (support[s] - cStart)*12 + newFaces[c*4 + GetQuadEdgeInverse_Static(orntCell[c], r)];
5174:           } else {
5175:             supportRef[2+s] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd - fMax)*2 + (support[s] - cMax)*4 + r;
5176:           }
5177:         }
5178:         DMPlexSetSupport(rdm, newp, supportRef);
5179: #if 1
5180:         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
5181:         for (p = 0; p < 2+supportSize; ++p) {
5182:           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);
5183:         }
5184: #endif
5185:       }
5186:     }
5187:     /* Interior cell edges have 2 vertices and 4 faces */
5188:     for (c = cStart; c < cMax; ++c) {
5189:       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};
5190:       const PetscInt  newv = vStartNew + (vEnd - vStart) + (eMax - eStart) + (fMax - fStart) + (c - cStart);
5191:       const PetscInt *cone;
5192:       PetscInt        coneNew[2], supportNew[4];

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

5198:         coneNew[0] = vStartNew + (vEnd - vStart) + (eMax - eStart) + (cone[r] - fStart);
5199:         coneNew[1] = newv;
5200:         DMPlexSetCone(rdm, newp, coneNew);
5201: #if 1
5202:         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
5203:         for (p = 0; p < 2; ++p) {
5204:           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);
5205:         }
5206: #endif
5207:         for (f = 0; f < 4; ++f) supportNew[f] = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + newFaces[r*4+f];
5208:         DMPlexSetSupport(rdm, newp, supportNew);
5209: #if 1
5210:         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
5211:         for (p = 0; p < 4; ++p) {
5212:           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);
5213:         }
5214: #endif
5215:       }
5216:     }
5217:     /* Hybrid edges have two vertices and the same faces */
5218:     for (e = eMax; e < eEnd; ++e) {
5219:       const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (e - eMax);
5220:       const PetscInt *cone, *support, *fcone;
5221:       PetscInt        coneNew[2], size, fsize, s;

5223:       DMPlexGetCone(dm, e, &cone);
5224:       DMPlexGetSupportSize(dm, e, &size);
5225:       DMPlexGetSupport(dm, e, &support);
5226:       coneNew[0] = vStartNew + (cone[0] - vStart);
5227:       coneNew[1] = vStartNew + (cone[1] - vStart);
5228:       DMPlexSetCone(rdm, newp, coneNew);
5229: #if 1
5230:       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid edge [%d, %d)", newp, eMaxNew, eEndNew);
5231:       for (p = 0; p < 2; ++p) {
5232:         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);
5233:       }
5234: #endif
5235:       for (s = 0; s < size; ++s) {
5236:         DMPlexGetConeSize(dm, support[s], &fsize);
5237:         DMPlexGetCone(dm, support[s], &fcone);
5238:         for (c = 0; c < fsize; ++c) if (fcone[c] == e) break;
5239:         if ((c < 2) || (c > 3)) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Edge %d not found in cone of face %d", e, support[s]);
5240:         supportRef[s] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (support[s] - fMax)*2 + c-2;
5241:       }
5242:       DMPlexSetSupport(rdm, newp, supportRef);
5243: #if 1
5244:       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid edge [%d, %d)", newp, eMaxNew, eEndNew);
5245:       for (p = 0; p < size; ++p) {
5246:         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);
5247:       }
5248: #endif
5249:     }
5250:     /* Hybrid face edges have 2 vertices and 2+cells faces */
5251:     for (f = fMax; f < fEnd; ++f) {
5252:       const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (eEnd - eMax) + (f - fMax);
5253:       const PetscInt *cone, *support, *ccone, *cornt;
5254:       PetscInt        coneNew[2], size, csize, s;

5256:       DMPlexGetCone(dm, f, &cone);
5257:       DMPlexGetSupportSize(dm, f, &size);
5258:       DMPlexGetSupport(dm, f, &support);
5259:       coneNew[0] = vStartNew + (vEnd - vStart) + (cone[0] - eStart);
5260:       coneNew[1] = vStartNew + (vEnd - vStart) + (cone[1] - eStart);
5261:       DMPlexSetCone(rdm, newp, coneNew);
5262: #if 1
5263:       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid edge [%d, %d)", newp, eMaxNew, eEndNew);
5264:       for (p = 0; p < 2; ++p) {
5265:         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);
5266:       }
5267: #endif
5268:       supportRef[0] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (f - fMax)*2 + 0;
5269:       supportRef[1] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (f - fMax)*2 + 1;
5270:       for (s = 0; s < size; ++s) {
5271:         DMPlexGetConeSize(dm, support[s], &csize);
5272:         DMPlexGetCone(dm, support[s], &ccone);
5273:         DMPlexGetConeOrientation(dm, support[s], &cornt);
5274:         for (c = 0; c < csize; ++c) if (ccone[c] == f) break;
5275:         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]);
5276:         supportRef[2+s] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd - fMax)*2 + (support[s] - cMax)*4 + c-2;
5277:       }
5278:       DMPlexSetSupport(rdm, newp, supportRef);
5279: #if 1
5280:       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid edge [%d, %d)", newp, eMaxNew, eEndNew);
5281:       for (p = 0; p < 2+size; ++p) {
5282:         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);
5283:       }
5284: #endif
5285:     }
5286:     /* Hybrid cell edges have 2 vertices and 4 faces */
5287:     for (c = cMax; c < cEnd; ++c) {
5288:       const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (eEnd - eMax) + (fEnd - fMax) + (c - cMax);
5289:       const PetscInt *cone, *support;
5290:       PetscInt        coneNew[2], size;

5292:       DMPlexGetCone(dm, c, &cone);
5293:       DMPlexGetSupportSize(dm, c, &size);
5294:       DMPlexGetSupport(dm, c, &support);
5295:       coneNew[0] = vStartNew + (vEnd - vStart) + (eMax - eStart) + (cone[0] - fStart);
5296:       coneNew[1] = vStartNew + (vEnd - vStart) + (eMax - eStart) + (cone[1] - fStart);
5297:       DMPlexSetCone(rdm, newp, coneNew);
5298: #if 1
5299:       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid edge [%d, %d)", newp, eMaxNew, eEndNew);
5300:       for (p = 0; p < 2; ++p) {
5301:         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);
5302:       }
5303: #endif
5304:       supportRef[0] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd - fMax)*2 + (c - cMax)*4 + 0;
5305:       supportRef[1] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd - fMax)*2 + (c - cMax)*4 + 1;
5306:       supportRef[2] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd - fMax)*2 + (c - cMax)*4 + 2;
5307:       supportRef[3] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd - fMax)*2 + (c - cMax)*4 + 3;
5308:       DMPlexSetSupport(rdm, newp, supportRef);
5309: #if 1
5310:       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid edge [%d, %d)", newp, eMaxNew, eEndNew);
5311:       for (p = 0; p < 4; ++p) {
5312:         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);
5313:       }
5314: #endif
5315:     }
5316:     /* Interior vertices have identical supports */
5317:     for (v = vStart; v < vEnd; ++v) {
5318:       const PetscInt  newp = vStartNew + (v - vStart);
5319:       const PetscInt *support, *cone;
5320:       PetscInt        size, s;

5322:       DMPlexGetSupportSize(dm, v, &size);
5323:       DMPlexGetSupport(dm, v, &support);
5324:       for (s = 0; s < size; ++s) {
5325:         PetscInt r = 0;

5327:         DMPlexGetCone(dm, support[s], &cone);
5328:         if (cone[1] == v) r = 1;
5329:         if (support[s] < eMax) supportRef[s] = eStartNew + (support[s] - eStart)*2 + r;
5330:         else                   supportRef[s] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (support[s] - eMax);
5331:       }
5332:       DMPlexSetSupport(rdm, newp, supportRef);
5333: #if 1
5334:       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
5335:       for (p = 0; p < size; ++p) {
5336:         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);
5337:       }
5338: #endif
5339:     }
5340:     /* Interior edge vertices have 2 + faces supports */
5341:     for (e = eStart; e < eMax; ++e) {
5342:       const PetscInt  newp = vStartNew + (vEnd - vStart) + (e - eStart);
5343:       const PetscInt *cone, *support;
5344:       PetscInt        size, s;

5346:       DMPlexGetSupportSize(dm, e, &size);
5347:       DMPlexGetSupport(dm, e, &support);
5348:       supportRef[0] = eStartNew + (e - eStart)*2 + 0;
5349:       supportRef[1] = eStartNew + (e - eStart)*2 + 1;
5350:       for (s = 0; s < size; ++s) {
5351:         PetscInt r;

5353:         DMPlexGetCone(dm, support[s], &cone);
5354:         for (r = 0; r < 4; ++r) if (cone[r] == e) break;
5355:         if (support[s] < fMax) {
5356:           supportRef[2+s] = eStartNew + (eMax - eStart)*2 + (support[s] - fStart)*4 + r;
5357:         } else {
5358:           supportRef[2+s] = eStartNew + (eMax - eStart)*2 + (fMax       - fStart)*4 + (cMax - cStart)*6 + (eEnd - eMax) + (support[s] - fMax);
5359:         }
5360:       }
5361:       DMPlexSetSupport(rdm, newp, supportRef);
5362: #if 1
5363:       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
5364:       for (p = 0; p < 2+size; ++p) {
5365:         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);
5366:       }
5367: #endif
5368:     }
5369:     /* Interior face vertices have 4 + cells supports */
5370:     for (f = fStart; f < fMax; ++f) {
5371:       const PetscInt  newp = vStartNew + (vEnd - vStart) + (eMax - eStart) + (f - fStart);
5372:       const PetscInt *cone, *support;
5373:       PetscInt        size, s;

5375:       DMPlexGetSupportSize(dm, f, &size);
5376:       DMPlexGetSupport(dm, f, &support);
5377:       for (r = 0; r < 4; ++r) supportRef[r] = eStartNew + (eMax - eStart)*2 +  (f - fStart)*4 + r;
5378:       for (s = 0; s < size; ++s) {
5379:         PetscInt r;

5381:         DMPlexGetCone(dm, support[s], &cone);
5382:         for (r = 0; r < 6; ++r) if (cone[r] == f) break;
5383:         if (support[s] < cMax) {
5384:           supportRef[4+s] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (support[s] - cStart)*6 + r;
5385:         } else {
5386:           supportRef[4+s] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax       - cStart)*6 + (eEnd - eMax) + (fEnd - fMax) + (support[s] - cMax);
5387:         }
5388:       }
5389:       DMPlexSetSupport(rdm, newp, supportRef);
5390: #if 1
5391:       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
5392:       for (p = 0; p < 4+size; ++p) {
5393:         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);
5394:       }
5395: #endif
5396:     }
5397:     /* Cell vertices have 6 supports */
5398:     for (c = cStart; c < cMax; ++c) {
5399:       const PetscInt newp = vStartNew + (vEnd - vStart) + (eMax - eStart) + (fMax - fStart) + (c - cStart);
5400:       PetscInt       supportNew[6];

5402:       for (r = 0; r < 6; ++r) {
5403:         supportNew[r] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (c - cStart)*6 + r;
5404:       }
5405:       DMPlexSetSupport(rdm, newp, supportNew);
5406:     }
5407:     PetscFree(supportRef);
5408:     break;
5409:   default:
5410:     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
5411:   }
5412:   return(0);
5413: }

5417: static PetscErrorCode CellRefinerSetCoordinates(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
5418: {
5419:   PetscSection   coordSection, coordSectionNew;
5420:   Vec            coordinates, coordinatesNew;
5421:   PetscScalar   *coords, *coordsNew;
5422:   const PetscInt numVertices = depthSize ? depthSize[0] : 0;
5423:   PetscInt       spaceDim, depth, bs, coordSizeNew, cStart, cEnd, cMax, c, vStart, vStartNew, vEnd, v, eStart, eEnd, eMax, e, fStart, fEnd, fMax, f;

5427:   DMPlexGetDepth(dm, &depth);
5428:   DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);
5429:   DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);
5430:   DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);
5431:   DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);
5432:   DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, NULL);
5433:   if (refiner) {GetDepthStart_Private(depth, depthSize, NULL, NULL, NULL, &vStartNew);}
5434:   GetDepthStart_Private(depth, depthSize, NULL, NULL, NULL, &vStartNew);
5435:   DMGetCoordinateSection(dm, &coordSection);
5436:   PetscSectionGetFieldComponents(coordSection, 0, &spaceDim);
5437:   PetscSectionCreate(PetscObjectComm((PetscObject)dm), &coordSectionNew);
5438:   PetscSectionSetNumFields(coordSectionNew, 1);
5439:   PetscSectionSetFieldComponents(coordSectionNew, 0, spaceDim);
5440:   PetscSectionSetChart(coordSectionNew, vStartNew, vStartNew+numVertices);
5441:   if (cMax < 0) cMax = cEnd;
5442:   if (fMax < 0) fMax = fEnd;
5443:   if (eMax < 0) eMax = eEnd;
5444:   /* All vertices have the spaceDim coordinates */
5445:   for (v = vStartNew; v < vStartNew+numVertices; ++v) {
5446:     PetscSectionSetDof(coordSectionNew, v, spaceDim);
5447:     PetscSectionSetFieldDof(coordSectionNew, v, 0, spaceDim);
5448:   }
5449:   PetscSectionSetUp(coordSectionNew);
5450:   DMSetCoordinateSection(rdm, coordSectionNew);
5451:   DMGetCoordinatesLocal(dm, &coordinates);
5452:   PetscSectionGetStorageSize(coordSectionNew, &coordSizeNew);
5453:   VecCreate(PetscObjectComm((PetscObject)dm), &coordinatesNew);
5454:   PetscObjectSetName((PetscObject) coordinatesNew, "coordinates");
5455:   VecSetSizes(coordinatesNew, coordSizeNew, PETSC_DETERMINE);
5456:   VecGetBlockSize(coordinates, &bs);
5457:   VecSetBlockSize(coordinatesNew, bs);
5458:   VecSetFromOptions(coordinatesNew);
5459:   VecGetArray(coordinates, &coords);
5460:   VecGetArray(coordinatesNew, &coordsNew);
5461:   switch (refiner) {
5462:   case 0: break;
5463:   case 6: /* Hex 3D */
5464:   case 8: /* Hybrid Hex 3D */
5465:     /* Face vertices have the average of corner coordinates */
5466:     for (f = fStart; f < fMax; ++f) {
5467:       const PetscInt newv = vStartNew + (vEnd - vStart) + (eMax - eStart) + (f - fStart);
5468:       PetscInt      *cone = NULL;
5469:       PetscInt       closureSize, coneSize = 0, off[8], offnew, p, d;

5471:       DMPlexGetTransitiveClosure(dm, f, PETSC_TRUE, &closureSize, &cone);
5472:       for (p = 0; p < closureSize*2; p += 2) {
5473:         const PetscInt point = cone[p];
5474:         if ((point >= vStart) && (point < vEnd)) cone[coneSize++] = point;
5475:       }
5476:       for (v = 0; v < coneSize; ++v) {
5477:         PetscSectionGetOffset(coordSection, cone[v], &off[v]);
5478:       }
5479:       PetscSectionGetOffset(coordSectionNew, newv, &offnew);
5480:       for (d = 0; d < spaceDim; ++d) coordsNew[offnew+d] = 0.0;
5481:       for (v = 0; v < coneSize; ++v) {DMPlexLocalizeAddCoordinate_Internal(dm, spaceDim, &coords[off[0]], &coords[off[v]], &coordsNew[offnew]);}
5482:       for (d = 0; d < spaceDim; ++d) coordsNew[offnew+d] /= coneSize;
5483:       DMPlexRestoreTransitiveClosure(dm, f, PETSC_TRUE, &closureSize, &cone);
5484:     }
5485:   case 2: /* Hex 2D */
5486:   case 4: /* Hybrid Hex 2D */
5487:     /* Cell vertices have the average of corner coordinates */
5488:     for (c = cStart; c < cMax; ++c) {
5489:       const PetscInt newv = vStartNew + (vEnd - vStart) + (eMax - eStart) + (c - cStart) + (spaceDim > 2 ? (fMax - fStart) : 0);
5490:       PetscInt      *cone = NULL;
5491:       PetscInt       closureSize, coneSize = 0, off[8], offnew, p, d;

5493:       DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &cone);
5494:       for (p = 0; p < closureSize*2; p += 2) {
5495:         const PetscInt point = cone[p];
5496:         if ((point >= vStart) && (point < vEnd)) cone[coneSize++] = point;
5497:       }
5498:       for (v = 0; v < coneSize; ++v) {
5499:         PetscSectionGetOffset(coordSection, cone[v], &off[v]);
5500:       }
5501:       PetscSectionGetOffset(coordSectionNew, newv, &offnew);
5502:       for (d = 0; d < spaceDim; ++d) coordsNew[offnew+d] = 0.0;
5503:       for (v = 0; v < coneSize; ++v) {DMPlexLocalizeAddCoordinate_Internal(dm, spaceDim, &coords[off[0]], &coords[off[v]], &coordsNew[offnew]);}
5504:       for (d = 0; d < spaceDim; ++d) coordsNew[offnew+d] /= coneSize;
5505:       DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &cone);
5506:     }
5507:   case 1: /* Simplicial 2D */
5508:   case 3: /* Hybrid Simplicial 2D */
5509:   case 5: /* Simplicial 3D */
5510:   case 7: /* Hybrid Simplicial 3D */
5511:     /* Edge vertices have the average of endpoint coordinates */
5512:     for (e = eStart; e < eMax; ++e) {
5513:       const PetscInt  newv = vStartNew + (vEnd - vStart) + (e - eStart);
5514:       const PetscInt *cone;
5515:       PetscInt        coneSize, offA, offB, offnew, d;

5517:       DMPlexGetConeSize(dm, e, &coneSize);
5518:       if (coneSize != 2) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Edge %d cone should have two vertices, not %d", e, coneSize);
5519:       DMPlexGetCone(dm, e, &cone);
5520:       PetscSectionGetOffset(coordSection, cone[0], &offA);
5521:       PetscSectionGetOffset(coordSection, cone[1], &offB);
5522:       PetscSectionGetOffset(coordSectionNew, newv, &offnew);
5523:       DMPlexLocalizeCoordinate_Internal(dm, spaceDim, &coords[offA], &coords[offB], &coordsNew[offnew]);
5524:       for (d = 0; d < spaceDim; ++d) {
5525:         coordsNew[offnew+d] = 0.5*(coords[offA+d] + coordsNew[offnew+d]);
5526:       }
5527:     }
5528:     /* Old vertices have the same coordinates */
5529:     for (v = vStart; v < vEnd; ++v) {
5530:       const PetscInt newv = vStartNew + (v - vStart);
5531:       PetscInt       off, offnew, d;

5533:       PetscSectionGetOffset(coordSection, v, &off);
5534:       PetscSectionGetOffset(coordSectionNew, newv, &offnew);
5535:       for (d = 0; d < spaceDim; ++d) {
5536:         coordsNew[offnew+d] = coords[off+d];
5537:       }
5538:     }
5539:     break;
5540:   default:
5541:     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
5542:   }
5543:   VecRestoreArray(coordinates, &coords);
5544:   VecRestoreArray(coordinatesNew, &coordsNew);
5545:   DMSetCoordinatesLocal(rdm, coordinatesNew);
5546:   VecDestroy(&coordinatesNew);
5547:   PetscSectionDestroy(&coordSectionNew);
5548:   if (dm->maxCell) {
5549:     const PetscReal *maxCell, *L;
5550:     DMGetPeriodicity(dm,  &maxCell, &L);
5551:     DMSetPeriodicity(rdm,  maxCell,  L);
5552:   }
5553:   return(0);
5554: }

5558: static PetscErrorCode DMPlexCreateProcessSF(DM dm, PetscSF sfPoint, IS *processRanks, PetscSF *sfProcess)
5559: {
5560:   PetscInt           numRoots, numLeaves, l;
5561:   const PetscInt    *localPoints;
5562:   const PetscSFNode *remotePoints;
5563:   PetscInt          *localPointsNew;
5564:   PetscSFNode       *remotePointsNew;
5565:   PetscInt          *ranks, *ranksNew;
5566:   PetscErrorCode     ierr;

5569:   PetscSFGetGraph(sfPoint, &numRoots, &numLeaves, &localPoints, &remotePoints);
5570:   PetscMalloc1(numLeaves, &ranks);
5571:   for (l = 0; l < numLeaves; ++l) {
5572:     ranks[l] = remotePoints[l].rank;
5573:   }
5574:   PetscSortRemoveDupsInt(&numLeaves, ranks);
5575:   PetscMalloc1(numLeaves,    &ranksNew);
5576:   PetscMalloc1(numLeaves,    &localPointsNew);
5577:   PetscMalloc1(numLeaves, &remotePointsNew);
5578:   for (l = 0; l < numLeaves; ++l) {
5579:     ranksNew[l]              = ranks[l];
5580:     localPointsNew[l]        = l;
5581:     remotePointsNew[l].index = 0;
5582:     remotePointsNew[l].rank  = ranksNew[l];
5583:   }
5584:   PetscFree(ranks);
5585:   ISCreateGeneral(PetscObjectComm((PetscObject)dm), numLeaves, ranksNew, PETSC_OWN_POINTER, processRanks);
5586:   PetscSFCreate(PetscObjectComm((PetscObject)dm), sfProcess);
5587:   PetscSFSetFromOptions(*sfProcess);
5588:   PetscSFSetGraph(*sfProcess, 1, numLeaves, localPointsNew, PETSC_OWN_POINTER, remotePointsNew, PETSC_OWN_POINTER);
5589:   return(0);
5590: }

5594: static PetscErrorCode CellRefinerCreateSF(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
5595: {
5596:   PetscSF            sf, sfNew, sfProcess;
5597:   IS                 processRanks;
5598:   MPI_Datatype       depthType;
5599:   PetscInt           numRoots, numLeaves, numLeavesNew = 0, l, m;
5600:   const PetscInt    *localPoints, *neighbors;
5601:   const PetscSFNode *remotePoints;
5602:   PetscInt          *localPointsNew;
5603:   PetscSFNode       *remotePointsNew;
5604:   PetscInt          *depthSizeOld, *rdepthSize, *rdepthSizeOld, *rdepthMaxOld, *rvStart, *rvStartNew, *reStart, *reStartNew, *rfStart, *rfStartNew, *rcStart, *rcStartNew;
5605:   PetscInt           depth, numNeighbors, pStartNew, pEndNew, cStart, cEnd, cMax, vStart, vEnd, vMax, fStart, fEnd, fMax, eStart, eEnd, eMax, r, n;
5606:   PetscInt           cStartNew = 0, vStartNew = 0, fStartNew = 0, eStartNew = 0;
5607:   PetscErrorCode     ierr;

5610:   DMPlexGetChart(rdm, &pStartNew, &pEndNew);
5611:   DMPlexGetDepth(dm, &depth);
5612:   DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);
5613:   DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);
5614:   DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);
5615:   DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);
5616:   DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);
5617:   cMax = cMax < 0 ? cEnd : cMax;
5618:   fMax = fMax < 0 ? fEnd : fMax;
5619:   eMax = eMax < 0 ? eEnd : eMax;
5620:   if (refiner) {GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);}
5621:   DMGetPointSF(dm, &sf);
5622:   DMGetPointSF(rdm, &sfNew);
5623:   /* Calculate size of new SF */
5624:   PetscSFGetGraph(sf, &numRoots, &numLeaves, &localPoints, &remotePoints);
5625:   if (numRoots < 0) return(0);
5626:   for (l = 0; l < numLeaves; ++l) {
5627:     const PetscInt p = localPoints[l];

5629:     switch (refiner) {
5630:     case 1:
5631:     case 3:
5632:       /* Hybrid Simplicial 2D */
5633:       if ((p >= vStart) && (p < vEnd)) {
5634:         /* Interior vertices stay the same */
5635:         ++numLeavesNew;
5636:       } else if ((p >= fStart) && (p < fMax)) {
5637:         /* Interior faces add new faces and vertex */
5638:         numLeavesNew += 2 + 1;
5639:       } else if ((p >= fMax) && (p < fEnd)) {
5640:         /* Hybrid faces stay the same */
5641:         ++numLeavesNew;
5642:       } else if ((p >= cStart) && (p < cMax)) {
5643:         /* Interior cells add new cells and interior faces */
5644:         numLeavesNew += 4 + 3;
5645:       } else if ((p >= cMax) && (p < cEnd)) {
5646:         /* Hybrid cells add new cells and hybrid face */
5647:         numLeavesNew += 2 + 1;
5648:       }
5649:       break;
5650:     case 2:
5651:     case 4:
5652:       /* Hybrid Hex 2D */
5653:       if ((p >= vStart) && (p < vEnd)) {
5654:         /* Interior vertices stay the same */
5655:         ++numLeavesNew;
5656:       } else if ((p >= fStart) && (p < fMax)) {
5657:         /* Interior faces add new faces and vertex */
5658:         numLeavesNew += 2 + 1;
5659:       } else if ((p >= fMax) && (p < fEnd)) {
5660:         /* Hybrid faces stay the same */
5661:         ++numLeavesNew;
5662:       } else if ((p >= cStart) && (p < cMax)) {
5663:         /* Interior cells add new cells, interior faces, and vertex */
5664:         numLeavesNew += 4 + 4 + 1;
5665:       } else if ((p >= cMax) && (p < cEnd)) {
5666:         /* Hybrid cells add new cells and hybrid face */
5667:         numLeavesNew += 2 + 1;
5668:       }
5669:       break;
5670:     case 5:
5671:     case 7:
5672:       /* Hybrid Simplicial 3D */
5673:       if ((p >= vStart) && (p < vEnd)) {
5674:         /* Interior vertices stay the same */
5675:         ++numLeavesNew;
5676:       } else if ((p >= eStart) && (p < eMax)) {
5677:         /* Interior edges add new edges and vertex */
5678:         numLeavesNew += 2 + 1;
5679:       } else if ((p >= eMax) && (p < eEnd)) {
5680:         /* Hybrid edges stay the same */
5681:         ++numLeavesNew;
5682:       } else if ((p >= fStart) && (p < fMax)) {
5683:         /* Interior faces add new faces and edges */
5684:         numLeavesNew += 4 + 3;
5685:       } else if ((p >= fMax) && (p < fEnd)) {
5686:         /* Hybrid faces add new faces and edges */
5687:         numLeavesNew += 2 + 1;
5688:       } else if ((p >= cStart) && (p < cMax)) {
5689:         /* Interior cells add new cells, faces, and edges */
5690:         numLeavesNew += 8 + 8 + 1;
5691:       } else if ((p >= cMax) && (p < cEnd)) {
5692:         /* Hybrid cells add new cells and faces */
5693:         numLeavesNew += 4 + 3;
5694:       }
5695:       break;
5696:     case 6:
5697:     case 8:
5698:       /* Hybrid Hex 3D */
5699:       if ((p >= vStart) && (p < vEnd)) {
5700:         /* Old vertices stay the same */
5701:         ++numLeavesNew;
5702:       } else if ((p >= eStart) && (p < eMax)) {
5703:         /* Interior edges add new edges, and vertex */
5704:         numLeavesNew += 2 + 1;
5705:       } else if ((p >= eMax) && (p < eEnd)) {
5706:         /* Hybrid edges stay the same */
5707:         ++numLeavesNew;
5708:       } else if ((p >= fStart) && (p < fMax)) {
5709:         /* Interior faces add new faces, edges, and vertex */
5710:         numLeavesNew += 4 + 4 + 1;
5711:       } else if ((p >= fMax) && (p < fEnd)) {
5712:         /* Hybrid faces add new faces and edges */
5713:         numLeavesNew += 2 + 1;
5714:       } else if ((p >= cStart) && (p < cMax)) {
5715:         /* Interior cells add new cells, faces, edges, and vertex */
5716:         numLeavesNew += 8 + 12 + 6 + 1;
5717:       } else if ((p >= cStart) && (p < cEnd)) {
5718:         /* Hybrid cells add new cells, faces, and edges */
5719:         numLeavesNew += 4 + 4 + 1;
5720:       }
5721:       break;
5722:     default:
5723:       SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
5724:     }
5725:   }
5726:   /* Communicate depthSizes for each remote rank */
5727:   DMPlexCreateProcessSF(dm, sf, &processRanks, &sfProcess);
5728:   ISGetLocalSize(processRanks, &numNeighbors);
5729:   PetscMalloc5((depth+1)*numNeighbors,&rdepthSize,numNeighbors,&rvStartNew,numNeighbors,&reStartNew,numNeighbors,&rfStartNew,numNeighbors,&rcStartNew);
5730:   PetscMalloc7(depth+1,&depthSizeOld,(depth+1)*numNeighbors,&rdepthSizeOld,(depth+1)*numNeighbors,&rdepthMaxOld,numNeighbors,&rvStart,numNeighbors,&reStart,numNeighbors,&rfStart,numNeighbors,&rcStart);
5731:   MPI_Type_contiguous(depth+1, MPIU_INT, &depthType);
5732:   MPI_Type_commit(&depthType);
5733:   PetscSFBcastBegin(sfProcess, depthType, depthSize, rdepthSize);
5734:   PetscSFBcastEnd(sfProcess, depthType, depthSize, rdepthSize);
5735:   for (n = 0; n < numNeighbors; ++n) {
5736:     GetDepthStart_Private(depth, &rdepthSize[n*(depth+1)], &rcStartNew[n], &rfStartNew[n], &reStartNew[n], &rvStartNew[n]);
5737:   }
5738:   depthSizeOld[depth]   = cMax;
5739:   depthSizeOld[0]       = vMax;
5740:   depthSizeOld[depth-1] = fMax;
5741:   depthSizeOld[1]       = eMax;

5743:   PetscSFBcastBegin(sfProcess, depthType, depthSizeOld, rdepthMaxOld);
5744:   PetscSFBcastEnd(sfProcess, depthType, depthSizeOld, rdepthMaxOld);

5746:   depthSizeOld[depth]   = cEnd - cStart;
5747:   depthSizeOld[0]       = vEnd - vStart;
5748:   depthSizeOld[depth-1] = fEnd - fStart;
5749:   depthSizeOld[1]       = eEnd - eStart;

5751:   PetscSFBcastBegin(sfProcess, depthType, depthSizeOld, rdepthSizeOld);
5752:   PetscSFBcastEnd(sfProcess, depthType, depthSizeOld, rdepthSizeOld);
5753:   for (n = 0; n < numNeighbors; ++n) {
5754:     GetDepthStart_Private(depth, &rdepthSizeOld[n*(depth+1)], &rcStart[n], &rfStart[n], &reStart[n], &rvStart[n]);
5755:     rdepthMaxOld[n*(depth+1)+depth]   = rdepthMaxOld[n*(depth+1)+depth]   < 0 ? rdepthSizeOld[n*(depth+1)+depth]  +rcStart[n]: rdepthMaxOld[n*(depth+1)+depth];
5756:     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];
5757:     rdepthMaxOld[n*(depth+1)+1]       = rdepthMaxOld[n*(depth+1)+1]       < 0 ? rdepthSizeOld[n*(depth+1)+1]      +reStart[n]: rdepthMaxOld[n*(depth+1)+1];
5758:   }
5759:   MPI_Type_free(&depthType);
5760:   PetscSFDestroy(&sfProcess);
5761:   /* Calculate new point SF */
5762:   PetscMalloc1(numLeavesNew,    &localPointsNew);
5763:   PetscMalloc1(numLeavesNew, &remotePointsNew);
5764:   ISGetIndices(processRanks, &neighbors);
5765:   for (l = 0, m = 0; l < numLeaves; ++l) {
5766:     PetscInt    p     = localPoints[l];
5767:     PetscInt    rp    = remotePoints[l].index, n;
5768:     PetscMPIInt rrank = remotePoints[l].rank;

5770:     PetscFindInt(rrank, numNeighbors, neighbors, &n);
5771:     if (n < 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Could not locate remote rank %d", rrank);
5772:     switch (refiner) {
5773:     case 1:
5774:     case 3:
5775:       /* Hybrid simplicial 2D */
5776:       if ((p >= vStart) && (p < vEnd)) {
5777:         /* Old vertices stay the same */
5778:         localPointsNew[m]        = vStartNew     + (p  - vStart);
5779:         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
5780:         remotePointsNew[m].rank  = rrank;
5781:         ++m;
5782:       } else if ((p >= fStart) && (p < fMax)) {
5783:         /* Old interior faces add new faces and vertex */
5784:         for (r = 0; r < 2; ++r, ++m) {
5785:           localPointsNew[m]        = fStartNew     + (p  - fStart)*2     + r;
5786:           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*2 + r;
5787:           remotePointsNew[m].rank  = rrank;
5788:         }
5789:         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - fStart);
5790:         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - rfStart[n]);
5791:         remotePointsNew[m].rank  = rrank;
5792:         ++m;
5793:       } else if ((p >= fMax) && (p < fEnd)) {
5794:         /* Old hybrid faces stay the same */
5795:         localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (p  - fMax);
5796:         remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*2 + (rp - rdepthMaxOld[n*(depth+1)+depth-1]);
5797:         remotePointsNew[m].rank  = rrank;
5798:         ++m;
5799:       } else if ((p >= cStart) && (p < cMax)) {
5800:         /* Old interior cells add new cells and interior faces */
5801:         for (r = 0; r < 4; ++r, ++m) {
5802:           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
5803:           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
5804:           remotePointsNew[m].rank  = rrank;
5805:         }
5806:         for (r = 0; r < 3; ++r, ++m) {
5807:           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (p  - cStart)*3     + r;
5808:           remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*2 + (rp - rcStart[n])*3 + r;
5809:           remotePointsNew[m].rank  = rrank;
5810:         }
5811:       } else if ((p >= cMax) && (p < cEnd)) {
5812:         /* Old hybrid cells add new cells and hybrid face */
5813:         for (r = 0; r < 2; ++r, ++m) {
5814:           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
5815:           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
5816:           remotePointsNew[m].rank  = rrank;
5817:         }
5818:         localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (cMax                            - cStart)*3     + (p  - cMax);
5819:         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]);
5820:         remotePointsNew[m].rank  = rrank;
5821:         ++m;
5822:       }
5823:       break;
5824:     case 2:
5825:     case 4:
5826:       /* Hybrid Hex 2D */
5827:       if ((p >= vStart) && (p < vEnd)) {
5828:         /* Old vertices stay the same */
5829:         localPointsNew[m]        = vStartNew     + (p  - vStart);
5830:         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
5831:         remotePointsNew[m].rank  = rrank;
5832:         ++m;
5833:       } else if ((p >= fStart) && (p < fMax)) {
5834:         /* Old interior faces add new faces and vertex */
5835:         for (r = 0; r < 2; ++r, ++m) {
5836:           localPointsNew[m]        = fStartNew     + (p  - fStart)*2     + r;
5837:           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*2 + r;
5838:           remotePointsNew[m].rank  = rrank;
5839:         }
5840:         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - fStart);
5841:         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - rfStart[n]);
5842:         remotePointsNew[m].rank  = rrank;
5843:         ++m;
5844:       } else if ((p >= fMax) && (p < fEnd)) {
5845:         /* Old hybrid faces stay the same */
5846:         localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (p  - fMax);
5847:         remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*2 + (rp - rdepthMaxOld[n*(depth+1)+depth-1]);
5848:         remotePointsNew[m].rank  = rrank;
5849:         ++m;
5850:       } else if ((p >= cStart) && (p < cMax)) {
5851:         /* Old interior cells add new cells, interior faces, and vertex */
5852:         for (r = 0; r < 4; ++r, ++m) {
5853:           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
5854:           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
5855:           remotePointsNew[m].rank  = rrank;
5856:         }
5857:         for (r = 0; r < 4; ++r, ++m) {
5858:           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (p  - cStart)*4     + r;
5859:           remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*2 + (rp - rcStart[n])*4 + r;
5860:           remotePointsNew[m].rank  = rrank;
5861:         }
5862:         localPointsNew[m]        = vStartNew     + (vEnd - vStart)               + (fMax                              - fStart)     + (p  - cStart);
5863:         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0]  + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n]) + (rp - rcStart[n]);
5864:         remotePointsNew[m].rank  = rrank;
5865:         ++m;
5866:       } else if ((p >= cStart) && (p < cMax)) {
5867:         /* Old hybrid cells add new cells and hybrid face */
5868:         for (r = 0; r < 2; ++r, ++m) {
5869:           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
5870:           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
5871:           remotePointsNew[m].rank  = rrank;
5872:         }
5873:         localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (cMax                            - cStart)*4     + (p  - cMax);
5874:         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]);
5875:         remotePointsNew[m].rank  = rrank;
5876:         ++m;
5877:       }
5878:       break;
5879:     case 5:
5880:     case 7:
5881:       /* Hybrid Simplicial 3D */
5882:       if ((p >= vStart) && (p < vEnd)) {
5883:         /* Interior vertices stay the same */
5884:         localPointsNew[m]        = vStartNew     + (p  - vStart);
5885:         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
5886:         remotePointsNew[m].rank  = rrank;
5887:         ++m;
5888:       } else if ((p >= eStart) && (p < eMax)) {
5889:         /* Interior edges add new edges and vertex */
5890:         for (r = 0; r < 2; ++r, ++m) {
5891:           localPointsNew[m]        = eStartNew     + (p  - eStart)*2     + r;
5892:           remotePointsNew[m].index = reStartNew[n] + (rp - reStart[n])*2 + r;
5893:           remotePointsNew[m].rank  = rrank;
5894:         }
5895:         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - eStart);
5896:         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - reStart[n]);
5897:         remotePointsNew[m].rank  = rrank;
5898:         ++m;
5899:       } else if ((p >= eMax) && (p < eEnd)) {
5900:         /* Hybrid edges stay the same */
5901:         localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (fMax                              - fStart)*3     + (cMax                            - cStart)     + (p  - eMax);
5902:         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]);
5903:         remotePointsNew[m].rank  = rrank;
5904:         ++m;
5905:       } else if ((p >= fStart) && (p < fMax)) {
5906:         /* Interior faces add new faces and edges */
5907:         for (r = 0; r < 4; ++r, ++m) {
5908:           localPointsNew[m]        = fStartNew     + (p  - fStart)*4     + r;
5909:           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*4 + r;
5910:           remotePointsNew[m].rank  = rrank;
5911:         }
5912:         for (r = 0; r < 3; ++r, ++m) {
5913:           localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (p  - fStart)*3     + r;
5914:           remotePointsNew[m].index = reStartNew[n] + (rdepthMaxOld[n*(depth+1)+1] - reStart[n])*2 + (rp - rfStart[n])*3 + r;
5915:           remotePointsNew[m].rank  = rrank;
5916:         }
5917:       } else if ((p >= fMax) && (p < fEnd)) {
5918:         /* Hybrid faces add new faces and edges */
5919:         for (r = 0; r < 2; ++r, ++m) {
5920:           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*4     + (cMax                            - cStart)*8     + (p  - fMax)*2                              + r;
5921:           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;
5922:           remotePointsNew[m].rank  = rrank;
5923:         }
5924:         localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (fMax                              - fStart)*3     + (cMax                            - cStart)     + (eEnd                                    - eMax)                        + (p  - fMax);
5925:         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]);
5926:         remotePointsNew[m].rank  = rrank;
5927:         ++m;
5928:       } else if ((p >= cStart) && (p < cMax)) {
5929:         /* Interior cells add new cells, faces, and edges */
5930:         for (r = 0; r < 8; ++r, ++m) {
5931:           localPointsNew[m]        = cStartNew     + (p  - cStart)*8     + r;
5932:           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*8 + r;
5933:           remotePointsNew[m].rank  = rrank;
5934:         }
5935:         for (r = 0; r < 8; ++r, ++m) {
5936:           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*4     + (p  - cStart)*8     + r;
5937:           remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*4 + (rp - rcStart[n])*8 + r;
5938:           remotePointsNew[m].rank  = rrank;
5939:         }
5940:         localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (fMax                              - fStart)*3     + (p  - cStart)*1     + r;
5941:         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 + r;
5942:         remotePointsNew[m].rank  = rrank;
5943:         ++m;
5944:       } else if ((p >= cMax) && (p < cEnd)) {
5945:         /* Hybrid cells add new cells and faces */
5946:         for (r = 0; r < 4; ++r, ++m) {
5947:           localPointsNew[m]        = cStartNew     + (cMax                            - cStart)*8     + (p  - cMax)*4                            + r;
5948:           remotePointsNew[m].index = rcStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth] - rcStart[n])*8 + (rp - rdepthMaxOld[n*(depth+1)+depth])*4 + r;
5949:           remotePointsNew[m].rank  = rrank;
5950:         }
5951:         for (r = 0; r < 3; ++r, ++m) {
5952:           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*4     + (cMax                            - cStart)*8     + (fEnd                                          - fMax)*2                              + (p  - cMax)*3                            + r;
5953:           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;
5954:           remotePointsNew[m].rank  = rrank;
5955:         }
5956:       }
5957:       break;
5958:     case 6:
5959:     case 8:
5960:       /* Hybrid Hex 3D */
5961:       if ((p >= vStart) && (p < vEnd)) {
5962:         /* Interior vertices stay the same */
5963:         localPointsNew[m]        = vStartNew     + (p  - vStart);
5964:         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
5965:         remotePointsNew[m].rank  = rrank;
5966:         ++m;
5967:       } else if ((p >= eStart) && (p < eMax)) {
5968:         /* Interior edges add new edges and vertex */
5969:         for (r = 0; r < 2; ++r, ++m) {
5970:           localPointsNew[m]        = eStartNew     + (p  - eStart)*2     + r;
5971:           remotePointsNew[m].index = reStartNew[n] + (rp - reStart[n])*2 + r;
5972:           remotePointsNew[m].rank  = rrank;
5973:         }
5974:         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - eStart);
5975:         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - reStart[n]);
5976:         remotePointsNew[m].rank  = rrank;
5977:         ++m;
5978:       } else if ((p >= eMax) && (p < eEnd)) {
5979:         /* Hybrid edges stay the same */
5980:         localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (fMax                              - fStart)*4     + (cMax                            - cStart)*6     + (p  - eMax);
5981:         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]);
5982:         remotePointsNew[m].rank  = rrank;
5983:         ++m;
5984:       } else if ((p >= fStart) && (p < fMax)) {
5985:         /* Interior faces add new faces, edges, and vertex */
5986:         for (r = 0; r < 4; ++r, ++m) {
5987:           localPointsNew[m]        = fStartNew     + (p  - fStart)*4     + r;
5988:           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*4 + r;
5989:           remotePointsNew[m].rank  = rrank;
5990:         }
5991:         for (r = 0; r < 4; ++r, ++m) {
5992:           localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (p  - fStart)*4     + r;
5993:           remotePointsNew[m].index = reStartNew[n] + (rdepthMaxOld[n*(depth+1)+1] - reStart[n])*2 + (rp - rfStart[n])*4 + r;
5994:           remotePointsNew[m].rank  = rrank;
5995:         }
5996:         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (eMax                        - eStart)     + (p  - fStart);
5997:         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rdepthMaxOld[n*(depth+1)+1] - reStart[n]) + (rp - rfStart[n]);
5998:         remotePointsNew[m].rank  = rrank;
5999:         ++m;
6000:       } else if ((p >= fMax) && (p < fEnd)) {
6001:         /* Hybrid faces add new faces and edges */
6002:         for (r = 0; r < 2; ++r, ++m) {
6003:           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*4     + (cMax                            - cStart)*12     + (p  - fMax)*2                              + r;
6004:           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;
6005:           remotePointsNew[m].rank  = rrank;
6006:         }
6007:         localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (fMax                              - fStart)*4     + (cMax                            - cStart)*6     + (eEnd                                    - eMax)                        + (p  - fMax);
6008:         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]);
6009:         remotePointsNew[m].rank  = rrank;
6010:         ++m;
6011:       } else if ((p >= cStart) && (p < cMax)) {
6012:         /* Interior cells add new cells, faces, edges, and vertex */
6013:         for (r = 0; r < 8; ++r, ++m) {
6014:           localPointsNew[m]        = cStartNew     + (p  - cStart)*8     + r;
6015:           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*8 + r;
6016:           remotePointsNew[m].rank  = rrank;
6017:         }
6018:         for (r = 0; r < 12; ++r, ++m) {
6019:           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*4     + (p  - cStart)*12     + r;
6020:           remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*4 + (rp - rcStart[n])*12 + r;
6021:           remotePointsNew[m].rank  = rrank;
6022:         }
6023:         for (r = 0; r < 6; ++r, ++m) {
6024:           localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (fMax                              - fStart)*4     + (p  - cStart)*6     + r;
6025:           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;
6026:           remotePointsNew[m].rank  = rrank;
6027:         }
6028:         for (r = 0; r < 1; ++r, ++m) {
6029:           localPointsNew[m]        = vStartNew     + (eMax                        - eStart)     + (fMax                              - fStart)     + (p  - cStart)     + r;
6030:           remotePointsNew[m].index = rvStartNew[n] + (rdepthMaxOld[n*(depth+1)+1] - reStart[n]) + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n]) + (rp - rcStart[n]) + r;
6031:           remotePointsNew[m].rank  = rrank;
6032:         }
6033:       } else if ((p >= cMax) && (p < cEnd)) {
6034:         /* Hybrid cells add new cells, faces, and edges */
6035:         for (r = 0; r < 4; ++r, ++m) {
6036:           localPointsNew[m]        = cStartNew     + (cMax                            - cStart)*8     + (p  - cMax)*4                            + r;
6037:           remotePointsNew[m].index = rcStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth] - rcStart[n])*8 + (rp - rdepthMaxOld[n*(depth+1)+depth])*4 + r;
6038:           remotePointsNew[m].rank  = rrank;
6039:         }
6040:         for (r = 0; r < 4; ++r, ++m) {
6041:           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*4     + (cMax                            - cStart)*12     + (fEnd                                          - fMax)*2                              + (p  - cMax)*4                            + r;
6042:           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;
6043:           remotePointsNew[m].rank  = rrank;
6044:         }
6045:         localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (fMax                              - fStart)*4     + (cMax                            - cStart)*6     + (eEnd                                    - eMax)                        + (fEnd                                          - fMax)                              + (p  - cMax);
6046:         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]);
6047:         remotePointsNew[m].rank  = rrank;
6048:         ++m;
6049:       }
6050:       break;
6051:     default:
6052:       SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
6053:     }
6054:   }
6055:   if (m != numLeavesNew) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Number of leaf point %d should be %d", m, numLeavesNew);
6056:   ISRestoreIndices(processRanks, &neighbors);
6057:   ISDestroy(&processRanks);
6058:   {
6059:     PetscSFNode *rp, *rtmp;
6060:     PetscInt    *lp, *idx, *ltmp, i;

6062:     /* SF needs sorted leaves to correct calculate Gather */
6063:     PetscMalloc1(numLeavesNew,&idx);
6064:     PetscMalloc1(numLeavesNew, &lp);
6065:     PetscMalloc1(numLeavesNew, &rp);
6066:     for (i = 0; i < numLeavesNew; ++i) idx[i] = i;
6067:     PetscSortIntWithPermutation(numLeavesNew, localPointsNew, idx);
6068:     for (i = 0; i < numLeavesNew; ++i) {
6069:       lp[i] = localPointsNew[idx[i]];
6070:       rp[i] = remotePointsNew[idx[i]];
6071:     }
6072:     ltmp            = localPointsNew;
6073:     localPointsNew  = lp;
6074:     rtmp            = remotePointsNew;
6075:     remotePointsNew = rp;
6076:     PetscFree(idx);
6077:     PetscFree(ltmp);
6078:     PetscFree(rtmp);
6079:   }
6080:   PetscSFSetGraph(sfNew, pEndNew-pStartNew, numLeavesNew, localPointsNew, PETSC_OWN_POINTER, remotePointsNew, PETSC_OWN_POINTER);
6081:   PetscFree5(rdepthSize,rvStartNew,reStartNew,rfStartNew,rcStartNew);
6082:   PetscFree7(depthSizeOld,rdepthSizeOld,rdepthMaxOld,rvStart,reStart,rfStart,rcStart);
6083:   return(0);
6084: }

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

6096:   DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);
6097:   DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);
6098:   DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);
6099:   DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);
6100:   DMPlexGetDepth(dm, &depth);
6101:   if (refiner) {GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);}
6102:   DMPlexGetNumLabels(dm, &numLabels);
6103:   DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);
6104:   switch (refiner) {
6105:   case 0: break;
6106:   case 7:
6107:   case 8:
6108:     if (eMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No edge maximum specified in hybrid mesh");
6109:   case 3:
6110:   case 4:
6111:     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
6112:     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
6113:   }
6114:   for (l = 0; l < numLabels; ++l) {
6115:     DMLabel         label, labelNew;
6116:     const char     *lname;
6117:     PetscBool       isDepth;
6118:     IS              valueIS;
6119:     const PetscInt *values;
6120:     PetscInt        numValues, val;

6122:     DMPlexGetLabelName(dm, l, &lname);
6123:     PetscStrcmp(lname, "depth", &isDepth);
6124:     if (isDepth) continue;
6125:     DMPlexCreateLabel(rdm, lname);
6126:     DMPlexGetLabel(dm, lname, &label);
6127:     DMPlexGetLabel(rdm, lname, &labelNew);
6128:     DMLabelGetValueIS(label, &valueIS);
6129:     ISGetLocalSize(valueIS, &numValues);
6130:     ISGetIndices(valueIS, &values);
6131:     for (val = 0; val < numValues; ++val) {
6132:       IS              pointIS;
6133:       const PetscInt *points;
6134:       PetscInt        numPoints, n;

6136:       DMLabelGetStratumIS(label, values[val], &pointIS);
6137:       ISGetLocalSize(pointIS, &numPoints);
6138:       ISGetIndices(pointIS, &points);
6139:       for (n = 0; n < numPoints; ++n) {
6140:         const PetscInt p = points[n];
6141:         switch (refiner) {
6142:         case 1:
6143:           /* Simplicial 2D */
6144:           if ((p >= vStart) && (p < vEnd)) {
6145:             /* Old vertices stay the same */
6146:             newp = vStartNew + (p - vStart);
6147:             DMLabelSetValue(labelNew, newp, values[val]);
6148:           } else if ((p >= fStart) && (p < fEnd)) {
6149:             /* Old faces add new faces and vertex */
6150:             newp = vStartNew + (vEnd - vStart) + (p - fStart);
6151:             DMLabelSetValue(labelNew, newp, values[val]);
6152:             for (r = 0; r < 2; ++r) {
6153:               newp = fStartNew + (p - fStart)*2 + r;
6154:               DMLabelSetValue(labelNew, newp, values[val]);
6155:             }
6156:           } else if ((p >= cStart) && (p < cEnd)) {
6157:             /* Old cells add new cells and interior faces */
6158:             for (r = 0; r < 4; ++r) {
6159:               newp = cStartNew + (p - cStart)*4 + r;
6160:               DMLabelSetValue(labelNew, newp, values[val]);
6161:             }
6162:             for (r = 0; r < 3; ++r) {
6163:               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*3 + r;
6164:               DMLabelSetValue(labelNew, newp, values[val]);
6165:             }
6166:           }
6167:           break;
6168:         case 2:
6169:           /* Hex 2D */
6170:           if ((p >= vStart) && (p < vEnd)) {
6171:             /* Old vertices stay the same */
6172:             newp = vStartNew + (p - vStart);
6173:             DMLabelSetValue(labelNew, newp, values[val]);
6174:           } else if ((p >= fStart) && (p < fEnd)) {
6175:             /* Old faces add new faces and vertex */
6176:             newp = vStartNew + (vEnd - vStart) + (p - fStart);
6177:             DMLabelSetValue(labelNew, newp, values[val]);
6178:             for (r = 0; r < 2; ++r) {
6179:               newp = fStartNew + (p - fStart)*2 + r;
6180:               DMLabelSetValue(labelNew, newp, values[val]);
6181:             }
6182:           } else if ((p >= cStart) && (p < cEnd)) {
6183:             /* Old cells add new cells and interior faces and vertex */
6184:             for (r = 0; r < 4; ++r) {
6185:               newp = cStartNew + (p - cStart)*4 + r;
6186:               DMLabelSetValue(labelNew, newp, values[val]);
6187:             }
6188:             for (r = 0; r < 4; ++r) {
6189:               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*4 + r;
6190:               DMLabelSetValue(labelNew, newp, values[val]);
6191:             }
6192:             newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (p - cStart);
6193:             DMLabelSetValue(labelNew, newp, values[val]);
6194:           }
6195:           break;
6196:         case 3:
6197:           /* Hybrid simplicial 2D */
6198:           if ((p >= vStart) && (p < vEnd)) {
6199:             /* Old vertices stay the same */
6200:             newp = vStartNew + (p - vStart);
6201:             DMLabelSetValue(labelNew, newp, values[val]);
6202:           } else if ((p >= fStart) && (p < fMax)) {
6203:             /* Old interior faces add new faces and vertex */
6204:             newp = vStartNew + (vEnd - vStart) + (p - fStart);
6205:             DMLabelSetValue(labelNew, newp, values[val]);
6206:             for (r = 0; r < 2; ++r) {
6207:               newp = fStartNew + (p - fStart)*2 + r;
6208:               DMLabelSetValue(labelNew, newp, values[val]);
6209:             }
6210:           } else if ((p >= fMax) && (p < fEnd)) {
6211:             /* Old hybrid faces stay the same */
6212:             newp = fStartNew + (fMax - fStart)*2 + (p - fMax);
6213:             DMLabelSetValue(labelNew, newp, values[val]);
6214:           } else if ((p >= cStart) && (p < cMax)) {
6215:             /* Old interior cells add new cells and interior faces */
6216:             for (r = 0; r < 4; ++r) {
6217:               newp = cStartNew + (p - cStart)*4 + r;
6218:               DMLabelSetValue(labelNew, newp, values[val]);
6219:             }
6220:             for (r = 0; r < 3; ++r) {
6221:               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*3 + r;
6222:               DMLabelSetValue(labelNew, newp, values[val]);
6223:             }
6224:           } else if ((p >= cMax) && (p < cEnd)) {
6225:             /* Old hybrid cells add new cells and hybrid face */
6226:             for (r = 0; r < 2; ++r) {
6227:               newp = cStartNew + (cMax - cStart)*4 + (p - cMax)*2 + r;
6228:               DMLabelSetValue(labelNew, newp, values[val]);
6229:             }
6230:             newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (p - cMax);
6231:             DMLabelSetValue(labelNew, newp, values[val]);
6232:           }
6233:           break;
6234:         case 4:
6235:           /* Hybrid Hex 2D */
6236:           if ((p >= vStart) && (p < vEnd)) {
6237:             /* Old vertices stay the same */
6238:             newp = vStartNew + (p - vStart);
6239:             DMLabelSetValue(labelNew, newp, values[val]);
6240:           } else if ((p >= fStart) && (p < fMax)) {
6241:             /* Old interior faces add new faces and vertex */
6242:             newp = vStartNew + (vEnd - vStart) + (p - fStart);
6243:             DMLabelSetValue(labelNew, newp, values[val]);
6244:             for (r = 0; r < 2; ++r) {
6245:               newp = fStartNew + (p - fStart)*2 + r;
6246:               DMLabelSetValue(labelNew, newp, values[val]);
6247:             }
6248:           } else if ((p >= fMax) && (p < fEnd)) {
6249:             /* Old hybrid faces stay the same */
6250:             newp = fStartNew + (fMax - fStart)*2 + (p - fMax);
6251:             DMLabelSetValue(labelNew, newp, values[val]);
6252:           } else if ((p >= cStart) && (p < cMax)) {
6253:             /* Old interior cells add new cells, interior faces, and vertex */
6254:             for (r = 0; r < 4; ++r) {
6255:               newp = cStartNew + (p - cStart)*4 + r;
6256:               DMLabelSetValue(labelNew, newp, values[val]);
6257:             }
6258:             for (r = 0; r < 4; ++r) {
6259:               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*4 + r;
6260:               DMLabelSetValue(labelNew, newp, values[val]);
6261:             }
6262:             newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (p - cStart);
6263:             DMLabelSetValue(labelNew, newp, values[val]);
6264:           } else if ((p >= cMax) && (p < cEnd)) {
6265:             /* Old hybrid cells add new cells and hybrid face */
6266:             for (r = 0; r < 2; ++r) {
6267:               newp = cStartNew + (cMax - cStart)*4 + (p - cMax)*2 + r;
6268:               DMLabelSetValue(labelNew, newp, values[val]);
6269:             }
6270:             newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*4 + (p - cMax);
6271:             DMLabelSetValue(labelNew, newp, values[val]);
6272:           }
6273:           break;
6274:         case 5:
6275:           /* Simplicial 3D */
6276:           if ((p >= vStart) && (p < vEnd)) {
6277:             /* Old vertices stay the same */
6278:             newp = vStartNew + (p - vStart);
6279:             DMLabelSetValue(labelNew, newp, values[val]);
6280:           } else if ((p >= eStart) && (p < eEnd)) {
6281:             /* Old edges add new edges and vertex */
6282:             for (r = 0; r < 2; ++r) {
6283:               newp = eStartNew + (p - eStart)*2 + r;
6284:               DMLabelSetValue(labelNew, newp, values[val]);
6285:             }
6286:             newp = vStartNew + (vEnd - vStart) + (p - eStart);
6287:             DMLabelSetValue(labelNew, newp, values[val]);
6288:           } else if ((p >= fStart) && (p < fEnd)) {
6289:             /* Old faces add new faces and edges */
6290:             for (r = 0; r < 4; ++r) {
6291:               newp = fStartNew + (p - fStart)*4 + r;
6292:               DMLabelSetValue(labelNew, newp, values[val]);
6293:             }
6294:             for (r = 0; r < 3; ++r) {
6295:               newp = eStartNew + (eEnd - eStart)*2 + (p - fStart)*3 + r;
6296:               DMLabelSetValue(labelNew, newp, values[val]);
6297:             }
6298:           } else if ((p >= cStart) && (p < cEnd)) {
6299:             /* Old cells add new cells and interior faces and edges */
6300:             for (r = 0; r < 8; ++r) {
6301:               newp = cStartNew + (p - cStart)*8 + r;
6302:               DMLabelSetValue(labelNew, newp, values[val]);
6303:             }
6304:             for (r = 0; r < 8; ++r) {
6305:               newp = fStartNew + (fEnd - fStart)*4 + (p - cStart)*8 + r;
6306:               DMLabelSetValue(labelNew, newp, values[val]);
6307:             }
6308:             for (r = 0; r < 1; ++r) {
6309:               newp = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (p - cStart)*1 + r;
6310:               DMLabelSetValue(labelNew, newp, values[val]);
6311:             }
6312:           }
6313:           break;
6314:         case 7:
6315:           /* Hybrid Simplicial 3D */
6316:           if ((p >= vStart) && (p < vEnd)) {
6317:             /* Interior vertices stay the same */
6318:             newp = vStartNew + (p - vStart);
6319:             DMLabelSetValue(labelNew, newp, values[val]);
6320:           } else if ((p >= eStart) && (p < eMax)) {
6321:             /* Interior edges add new edges and vertex */
6322:             for (r = 0; r < 2; ++r) {
6323:               newp = eStartNew + (p - eStart)*2 + r;
6324:               DMLabelSetValue(labelNew, newp, values[val]);
6325:             }
6326:             newp = vStartNew + (vEnd - vStart) + (p - eStart);
6327:             DMLabelSetValue(labelNew, newp, values[val]);
6328:           } else if ((p >= eMax) && (p < eEnd)) {
6329:             /* Hybrid edges stay the same */
6330:             newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (p - eMax);
6331:             DMLabelSetValue(labelNew, newp, values[val]);
6332:           } else if ((p >= fStart) && (p < fMax)) {
6333:             /* Interior faces add new faces and edges */
6334:             for (r = 0; r < 4; ++r) {
6335:               newp = fStartNew + (p - fStart)*4 + r;
6336:               DMLabelSetValue(labelNew, newp, values[val]);
6337:             }
6338:             for (r = 0; r < 3; ++r) {
6339:               newp = eStartNew + (eMax - eStart)*2 + (p - fStart)*3 + r;
6340:               DMLabelSetValue(labelNew, newp, values[val]);
6341:             }
6342:           } else if ((p >= fMax) && (p < fEnd)) {
6343:             /* Hybrid faces add new faces and edges */
6344:             for (r = 0; r < 2; ++r) {
6345:               newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (p - fMax)*2 + r;
6346:               DMLabelSetValue(labelNew, newp, values[val]);
6347:             }
6348:             newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (p - fMax);
6349:             DMLabelSetValue(labelNew, newp, values[val]);
6350:           } else if ((p >= cStart) && (p < cMax)) {
6351:             /* Interior cells add new cells, faces, and edges */
6352:             for (r = 0; r < 8; ++r) {
6353:               newp = cStartNew + (p - cStart)*8 + r;
6354:               DMLabelSetValue(labelNew, newp, values[val]);
6355:             }
6356:             for (r = 0; r < 8; ++r) {
6357:               newp = fStartNew + (fMax - fStart)*4 + (p - cStart)*8 + r;
6358:               DMLabelSetValue(labelNew, newp, values[val]);
6359:             }
6360:             newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (p - cStart);
6361:             DMLabelSetValue(labelNew, newp, values[val]);
6362:           } else if ((p >= cMax) && (p < cEnd)) {
6363:             /* Hybrid cells add new cells and faces */
6364:             for (r = 0; r < 4; ++r) {
6365:               newp = cStartNew + (cMax - cStart)*8 + (p - cMax)*4 + r;
6366:               DMLabelSetValue(labelNew, newp, values[val]);
6367:             }
6368:             for (r = 0; r < 3; ++r) {
6369:               newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (p - cMax)*3 + r;
6370:               DMLabelSetValue(labelNew, newp, values[val]);
6371:             }
6372:           }
6373:           break;
6374:         case 6:
6375:           /* Hex 3D */
6376:           if ((p >= vStart) && (p < vEnd)) {
6377:             /* Old vertices stay the same */
6378:             newp = vStartNew + (p - vStart);
6379:             DMLabelSetValue(labelNew, newp, values[val]);
6380:           } else if ((p >= eStart) && (p < eEnd)) {
6381:             /* Old edges add new edges and vertex */
6382:             for (r = 0; r < 2; ++r) {
6383:               newp = eStartNew + (p - eStart)*2 + r;
6384:               DMLabelSetValue(labelNew, newp, values[val]);
6385:             }
6386:             newp = vStartNew + (vEnd - vStart) + (p - eStart);
6387:             DMLabelSetValue(labelNew, newp, values[val]);
6388:           } else if ((p >= fStart) && (p < fEnd)) {
6389:             /* Old faces add new faces, edges, and vertex */
6390:             for (r = 0; r < 4; ++r) {
6391:               newp = fStartNew + (p - fStart)*4 + r;
6392:               DMLabelSetValue(labelNew, newp, values[val]);
6393:             }
6394:             for (r = 0; r < 4; ++r) {
6395:               newp = eStartNew + (eEnd - eStart)*2 + (p - fStart)*4 + r;
6396:               DMLabelSetValue(labelNew, newp, values[val]);
6397:             }
6398:             newp = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (p - fStart);
6399:             DMLabelSetValue(labelNew, newp, values[val]);
6400:           } else if ((p >= cStart) && (p < cEnd)) {
6401:             /* Old cells add new cells, faces, edges, and vertex */
6402:             for (r = 0; r < 8; ++r) {
6403:               newp = cStartNew + (p - cStart)*8 + r;
6404:               DMLabelSetValue(labelNew, newp, values[val]);
6405:             }
6406:             for (r = 0; r < 12; ++r) {
6407:               newp = fStartNew + (fEnd - fStart)*4 + (p - cStart)*12 + r;
6408:               DMLabelSetValue(labelNew, newp, values[val]);
6409:             }
6410:             for (r = 0; r < 6; ++r) {
6411:               newp = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*4 + (p - cStart)*6 + r;
6412:               DMLabelSetValue(labelNew, newp, values[val]);
6413:             }
6414:             newp = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (fEnd - fStart) + (p - cStart);
6415:             DMLabelSetValue(labelNew, newp, values[val]);
6416:           }
6417:           break;
6418:         case 8:
6419:           /* Hybrid Hex 3D */
6420:           if ((p >= vStart) && (p < vEnd)) {
6421:             /* Interior vertices stay the same */
6422:             newp = vStartNew + (p - vStart);
6423:             DMLabelSetValue(labelNew, newp, values[val]);
6424:           } else if ((p >= eStart) && (p < eMax)) {
6425:             /* Interior edges add new edges and vertex */
6426:             for (r = 0; r < 2; ++r) {
6427:               newp = eStartNew + (p - eStart)*2 + r;
6428:               DMLabelSetValue(labelNew, newp, values[val]);
6429:             }
6430:             newp = vStartNew + (vEnd - vStart) + (p - eStart);
6431:             DMLabelSetValue(labelNew, newp, values[val]);
6432:           } else if ((p >= eMax) && (p < eEnd)) {
6433:             /* Hybrid edges stay the same */
6434:             newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (p - eMax);
6435:             DMLabelSetValue(labelNew, newp, values[val]);
6436:           } else if ((p >= fStart) && (p < fMax)) {
6437:             /* Interior faces add new faces, edges, and vertex */
6438:             for (r = 0; r < 4; ++r) {
6439:               newp = fStartNew + (p - fStart)*4 + r;
6440:               DMLabelSetValue(labelNew, newp, values[val]);
6441:             }
6442:             for (r = 0; r < 4; ++r) {
6443:               newp = eStartNew + (eMax - eStart)*2 + (p - fStart)*4 + r;
6444:               DMLabelSetValue(labelNew, newp, values[val]);
6445:             }
6446:             newp = vStartNew + (vEnd - vStart) + (eMax - eStart) + (p - fStart);
6447:             DMLabelSetValue(labelNew, newp, values[val]);
6448:           } else if ((p >= fMax) && (p < fEnd)) {
6449:             /* Hybrid faces add new faces and edges */
6450:             for (r = 0; r < 2; ++r) {
6451:               newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (p - fMax)*2 + r;
6452:               DMLabelSetValue(labelNew, newp, values[val]);
6453:             }
6454:             newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (p - fMax);
6455:             DMLabelSetValue(labelNew, newp, values[val]);
6456:           } else if ((p >= cStart) && (p < cMax)) {
6457:             /* Interior cells add new cells, faces, edges, and vertex */
6458:             for (r = 0; r < 8; ++r) {
6459:               newp = cStartNew + (p - cStart)*8 + r;
6460:               DMLabelSetValue(labelNew, newp, values[val]);
6461:             }
6462:             for (r = 0; r < 12; ++r) {
6463:               newp = fStartNew + (fMax - fStart)*4 + (p - cStart)*12 + r;
6464:               DMLabelSetValue(labelNew, newp, values[val]);
6465:             }
6466:             for (r = 0; r < 6; ++r) {
6467:               newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (p - cStart)*6 + r;
6468:               DMLabelSetValue(labelNew, newp, values[val]);
6469:             }
6470:             newp = vStartNew + (vEnd - vStart) + (eMax - eStart) + (fMax - fStart) + (p - cStart);
6471:             DMLabelSetValue(labelNew, newp, values[val]);
6472:           } else if ((p >= cMax) && (p < cEnd)) {
6473:             /* Hybrid cells add new cells, faces, and edges */
6474:             for (r = 0; r < 4; ++r) {
6475:               newp = cStartNew + (cMax - cStart)*8 + (p - cMax)*4 + r;
6476:               DMLabelSetValue(labelNew, newp, values[val]);
6477:             }
6478:             for (r = 0; r < 4; ++r) {
6479:               newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd - fMax)*2 + (p - cMax)*4 + r;
6480:               DMLabelSetValue(labelNew, newp, values[val]);
6481:             }
6482:             newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (fEnd - fMax) + (p - cMax);
6483:             DMLabelSetValue(labelNew, newp, values[val]);
6484:           }
6485:           break;
6486:         default:
6487:           SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
6488:         }
6489:       }
6490:       ISRestoreIndices(pointIS, &points);
6491:       ISDestroy(&pointIS);
6492:     }
6493:     ISRestoreIndices(valueIS, &values);
6494:     ISDestroy(&valueIS);
6495:     if (0) {
6496:       PetscViewerASCIISynchronizedAllow(PETSC_VIEWER_STDOUT_WORLD, PETSC_TRUE);
6497:       DMLabelView(labelNew, PETSC_VIEWER_STDOUT_WORLD);
6498:       PetscViewerFlush(PETSC_VIEWER_STDOUT_WORLD);
6499:     }
6500:   }
6501:   return(0);
6502: }

6506: /* This will only work for interpolated meshes */
6507: PetscErrorCode DMPlexRefineUniform_Internal(DM dm, CellRefiner cellRefiner, DM *dmRefined)
6508: {
6509:   DM             rdm;
6510:   PetscInt      *depthSize;
6511:   PetscInt       dim, depth = 0, d, pStart = 0, pEnd = 0;

6515:   DMCreate(PetscObjectComm((PetscObject)dm), &rdm);
6516:   DMSetType(rdm, DMPLEX);
6517:   DMPlexGetDimension(dm, &dim);
6518:   DMPlexSetDimension(rdm, dim);
6519:   /* Calculate number of new points of each depth */
6520:   DMPlexGetDepth(dm, &depth);
6521:   PetscMalloc1((depth+1), &depthSize);
6522:   PetscMemzero(depthSize, (depth+1) * sizeof(PetscInt));
6523:   CellRefinerGetSizes(cellRefiner, dm, depthSize);
6524:   /* Step 1: Set chart */
6525:   for (d = 0; d <= depth; ++d) pEnd += depthSize[d];
6526:   DMPlexSetChart(rdm, pStart, pEnd);
6527:   /* Step 2: Set cone/support sizes */
6528:   CellRefinerSetConeSizes(cellRefiner, dm, depthSize, rdm);
6529:   /* Step 3: Setup refined DM */
6530:   DMSetUp(rdm);
6531:   /* Step 4: Set cones and supports */
6532:   CellRefinerSetCones(cellRefiner, dm, depthSize, rdm);
6533:   /* Step 5: Stratify */
6534:   DMPlexStratify(rdm);
6535:   /* Step 6: Set coordinates for vertices */
6536:   CellRefinerSetCoordinates(cellRefiner, dm, depthSize, rdm);
6537:   /* Step 7: Create pointSF */
6538:   CellRefinerCreateSF(cellRefiner, dm, depthSize, rdm);
6539:   /* Step 8: Create labels */
6540:   CellRefinerCreateLabels(cellRefiner, dm, depthSize, rdm);
6541:   PetscFree(depthSize);

6543:   *dmRefined = rdm;
6544:   return(0);
6545: }

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

6552:   Input Parameter:
6553: . dm - The coarse DM

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

6558:   Level: developer

6560: .seealso: DMRefine(), DMPlexSetRefinementUniform(), DMPlexCreateSubpointIS()
6561: @*/
6562: PetscErrorCode DMPlexCreateCoarsePointIS(DM dm, IS *fpointIS)
6563: {
6564:   CellRefiner    cellRefiner;
6565:   PetscInt      *depthSize, *fpoints;
6566:   PetscInt       cStartNew = 0, vStartNew = 0, fStartNew = 0, eStartNew = 0;
6567:   PetscInt       depth, pStart, pEnd, p, vStart, vEnd, v;

6571:   DMPlexGetDepth(dm, &depth);
6572:   DMPlexGetChart(dm, &pStart, &pEnd);
6573:   DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);
6574:   DMPlexGetCellRefiner_Internal(dm, &cellRefiner);
6575:   PetscMalloc1((depth+1), &depthSize);
6576:   CellRefinerGetSizes(cellRefiner, dm, depthSize);
6577:   if (cellRefiner) {GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);}
6578:   PetscMalloc1(pEnd-pStart,&fpoints);
6579:   for (p = 0; p < pEnd-pStart; ++p) fpoints[p] = -1;
6580:   switch (cellRefiner) {
6581:   case 1: /* Simplicial 2D */
6582:   case 3: /* Hybrid simplicial 2D */
6583:   case 2: /* Hex 2D */
6584:   case 4: /* Hybrid Hex 2D */
6585:   case 5: /* Simplicial 3D */
6586:   case 7: /* Hybrid Simplicial 3D */
6587:   case 6: /* Hex 3D */
6588:   case 8: /* Hybrid Hex 3D */
6589:     for (v = vStart; v < vEnd; ++v) fpoints[v-pStart] = vStartNew + (v - vStart);
6590:     break;
6591:   default:
6592:     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", cellRefiner);
6593:   }
6594:   ISCreateGeneral(PETSC_COMM_SELF, pEnd-pStart, fpoints, PETSC_OWN_POINTER, fpointIS);
6595:   PetscFree(depthSize);
6596:   return(0);
6597: }

6601: /*@
6602:   DMPlexSetRefinementUniform - Set the flag for uniform refinement

6604:   Input Parameters:
6605: + dm - The DM
6606: - refinementUniform - The flag for uniform refinement

6608:   Level: developer

6610: .seealso: DMRefine(), DMPlexGetRefinementUniform(), DMPlexGetRefinementLimit(), DMPlexSetRefinementLimit()
6611: @*/
6612: PetscErrorCode DMPlexSetRefinementUniform(DM dm, PetscBool refinementUniform)
6613: {
6614:   DM_Plex *mesh = (DM_Plex*) dm->data;

6618:   mesh->refinementUniform = refinementUniform;
6619:   return(0);
6620: }

6624: /*@
6625:   DMPlexGetRefinementUniform - Retrieve the flag for uniform refinement

6627:   Input Parameter:
6628: . dm - The DM

6630:   Output Parameter:
6631: . refinementUniform - The flag for uniform refinement

6633:   Level: developer

6635: .seealso: DMRefine(), DMPlexSetRefinementUniform(), DMPlexGetRefinementLimit(), DMPlexSetRefinementLimit()
6636: @*/
6637: PetscErrorCode DMPlexGetRefinementUniform(DM dm, PetscBool *refinementUniform)
6638: {
6639:   DM_Plex *mesh = (DM_Plex*) dm->data;

6644:   *refinementUniform = mesh->refinementUniform;
6645:   return(0);
6646: }

6650: /*@
6651:   DMPlexSetRefinementLimit - Set the maximum cell volume for refinement

6653:   Input Parameters:
6654: + dm - The DM
6655: - refinementLimit - The maximum cell volume in the refined mesh

6657:   Level: developer

6659: .seealso: DMRefine(), DMPlexGetRefinementLimit(), DMPlexGetRefinementUniform(), DMPlexSetRefinementUniform()
6660: @*/
6661: PetscErrorCode DMPlexSetRefinementLimit(DM dm, PetscReal refinementLimit)
6662: {
6663:   DM_Plex *mesh = (DM_Plex*) dm->data;

6667:   mesh->refinementLimit = refinementLimit;
6668:   return(0);
6669: }

6673: /*@
6674:   DMPlexGetRefinementLimit - Retrieve the maximum cell volume for refinement

6676:   Input Parameter:
6677: . dm - The DM

6679:   Output Parameter:
6680: . refinementLimit - The maximum cell volume in the refined mesh

6682:   Level: developer

6684: .seealso: DMRefine(), DMPlexSetRefinementLimit(), DMPlexGetRefinementUniform(), DMPlexSetRefinementUniform()
6685: @*/
6686: PetscErrorCode DMPlexGetRefinementLimit(DM dm, PetscReal *refinementLimit)
6687: {
6688:   DM_Plex *mesh = (DM_Plex*) dm->data;

6693:   /* if (mesh->refinementLimit < 0) = getMaxVolume()/2.0; */
6694:   *refinementLimit = mesh->refinementLimit;
6695:   return(0);
6696: }

6700: PetscErrorCode DMPlexGetCellRefiner_Internal(DM dm, CellRefiner *cellRefiner)
6701: {
6702:   PetscInt       dim, cStart, cEnd, coneSize, cMax;

6706:   DMPlexGetDimension(dm, &dim);
6707:   DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);
6708:   if (cEnd <= cStart) {*cellRefiner = 0; return(0);}
6709:   DMPlexGetConeSize(dm, cStart, &coneSize);
6710:   DMPlexGetHybridBounds(dm, &cMax, NULL, NULL, NULL);
6711:   switch (dim) {
6712:   case 2:
6713:     switch (coneSize) {
6714:     case 3:
6715:       if (cMax >= 0) *cellRefiner = 3; /* Hybrid */
6716:       else *cellRefiner = 1; /* Triangular */
6717:       break;
6718:     case 4:
6719:       if (cMax >= 0) *cellRefiner = 4; /* Hybrid */
6720:       else *cellRefiner = 2; /* Quadrilateral */
6721:       break;
6722:     default:
6723:       SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown coneSize %d in dimension %d for cell refiner", coneSize, dim);
6724:     }
6725:     break;
6726:   case 3:
6727:     switch (coneSize) {
6728:     case 4:
6729:       if (cMax >= 0) *cellRefiner = 7; /* Hybrid */
6730:       else *cellRefiner = 5; /* Tetrahedral */
6731:       break;
6732:     case 6:
6733:       if (cMax >= 0) *cellRefiner = 8; /* Hybrid */
6734:       else *cellRefiner = 6; /* hexahedral */
6735:       break;
6736:     default:
6737:       SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown coneSize %d in dimension %d for cell refiner", coneSize, dim);
6738:     }
6739:     break;
6740:   default:
6741:     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown dimension %d for cell refiner", dim);
6742:   }
6743:   return(0);
6744: }