Actual source code: plexrefine.c

petsc-3.7.7 2017-09-25
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 = depth < 0 ? 0 : depthSize[depth];
 11:   if (fStart) *fStart = depth < 0 ? 0 : depthSize[depth] + depthSize[0];
 12:   if (eStart) *eStart = depth < 0 ? 0 : 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 = depth < 0 ? 0 : depthSize[depth];
 22:   if (vEnd) *vEnd = depth < 0 ? 0 : depthSize[depth] + depthSize[0];
 23:   if (fEnd) *fEnd = depth < 0 ? 0 : depthSize[depth] + depthSize[0] + depthSize[depth-1];
 24:   if (eEnd) *eEnd = depth < 0 ? 0 : 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 REFINER_NOOP: break;
 40:   case REFINER_SIMPLEX_2D:
 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 REFINER_HEX_2D:
 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 REFINER_NOOP: break;
150:   case REFINER_SIMPLEX_2D:
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 REFINER_HEX_2D:
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 REFINER_NOOP:
181:     break;
182:   case REFINER_SIMPLEX_1D:
183:     depthSize[0] = vEnd - vStart + cEnd - cStart;         /* Add a vertex on every cell. */
184:     depthSize[1] = 2*(cEnd - cStart);                     /* Split every cell in 2. */
185:     break;
186:   case REFINER_SIMPLEX_2D:
187:     depthSize[0] = vEnd - vStart + fEnd - fStart;         /* Add a vertex on every face */
188:     depthSize[1] = 2*(fEnd - fStart) + 3*(cEnd - cStart); /* Every face is split into 2 faces and 3 faces are added for each cell */
189:     depthSize[2] = 4*(cEnd - cStart);                     /* Every cell split into 4 cells */
190:     break;
191:   case REFINER_HYBRID_SIMPLEX_2D:
192:     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
193:     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
194:     depthSize[0] = vEnd - vStart + fMax - fStart;                                         /* Add a vertex on every face, but not hybrid faces */
195:     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 */
196:     depthSize[2] = 4*(cMax - cStart) + 2*(cEnd - cMax);                                   /* Interior cells split into 4 cells, Hybrid cells split into 2 cells */
197:     break;
198:   case REFINER_HEX_2D:
199:     depthSize[0] = vEnd - vStart + fEnd - fStart + cEnd - cStart; /* Add a vertex on every face and cell */
200:     depthSize[1] = 2*(fEnd - fStart) + 4*(cEnd - cStart);         /* Every face is split into 2 faces and 4 faces are added for each cell */
201:     depthSize[2] = 4*(cEnd - cStart);                             /* Every cell split into 4 cells */
202:     break;
203:   case REFINER_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 REFINER_SIMPLEX_3D:
216:     depthSize[0] =    vEnd - vStart  +    eEnd - eStart;                    /* Add a vertex on every edge */
217:     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 */
218:     depthSize[2] = 4*(fEnd - fStart) + 8*(cEnd - cStart);                   /* Every face split into 4 faces and 8 faces are added for each cell */
219:     depthSize[3] = 8*(cEnd - cStart);                                       /* Every cell split into 8 cells */
220:     break;
221:   case REFINER_HYBRID_SIMPLEX_3D:
222:     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
223:     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
224:     if (eMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No edge maximum specified in hybrid mesh");
225:     /* Tetrahedra */
226:     depthSize[0]  =    vEnd - vStart  +    eMax - eStart;                    /* Add a vertex on every interior edge */
227:     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 */
228:     depthSize[2]  = 4*(fMax - fStart) + 8*(cMax - cStart);                   /* Every interior face split into 4 faces, 8 faces added for each interior cell */
229:     depthSize[3]  = 8*(cMax - cStart);                                       /* Every interior cell split into 8 cells */
230:     /* Triangular Prisms */
231:     depthSize[0] += 0;                                                       /* No hybrid vertices */
232:     depthSize[1] +=   (eEnd - eMax)   +   (fEnd - fMax);                     /* Every hybrid edge remains, 1 edge for every hybrid face */
233:     depthSize[2] += 2*(fEnd - fMax)   + 3*(cEnd - cMax);                     /* Every hybrid face split into 2 faces and 3 faces are added for each hybrid cell */
234:     depthSize[3] += 4*(cEnd - cMax);                                         /* Every hybrid cell split into 4 cells */
235:     break;
236:   case REFINER_HEX_3D:
237:     depthSize[0] = vEnd - vStart + eEnd - eStart + fEnd - fStart + cEnd - cStart; /* Add a vertex on every edge, face and cell */
238:     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 */
239:     depthSize[2] = 4*(fEnd - fStart) + 12*(cEnd - cStart);                        /* Every face is split into 4 faces, and 12 faces are added for each cell */
240:     depthSize[3] = 8*(cEnd - cStart);                                             /* Every cell split into 8 cells */
241:     break;
242:   case REFINER_HYBRID_HEX_3D:
243:     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
244:     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
245:     if (eMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No edge maximum specified in hybrid mesh");
246:     /* Hexahedra */
247:     depthSize[0] = vEnd - vStart + eMax - eStart + fMax - fStart + cMax - cStart; /* Add a vertex on every edge, face and cell */
248:     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 */
249:     depthSize[2] = 4*(fMax - fStart) + 12*(cMax - cStart);                        /* Every face is split into 4 faces, and 12 faces are added for each cell */
250:     depthSize[3] = 8*(cMax - cStart);                                             /* Every cell split into 8 cells */
251:     /* Quadrilateral Prisms */
252:     depthSize[0] += 0;                                                            /* No hybrid vertices */
253:     depthSize[1] +=   (eEnd - eMax)   +   (fEnd - fMax)   +   (cEnd - cMax);      /* Every hybrid edge remains, 1 edge for every hybrid face and hybrid cell */
254:     depthSize[2] += 2*(fEnd - fMax)   + 4*(cEnd - cMax);                          /* Every hybrid face split into 2 faces and 4 faces are added for each hybrid cell */
255:     depthSize[3] += 4*(cEnd - cMax);                                              /* Every hybrid cell split into 4 cells */
256:     break;
257:   default:
258:     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
259:   }
260:   return(0);
261: }

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

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

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


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

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

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

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

327:         DMPlexSetConeSize(rdm, newp, 2);
328:       }
329:     }
330:     /* Old vertices have identical supports */
331:     for (v = vStart; v < vEnd; ++v) {
332:       const PetscInt newp = vStartNew + (v - vStart);
333:       PetscInt       size;

335:       DMPlexGetSupportSize(dm, v, &size);
336:       DMPlexSetSupportSize(rdm, newp, size);
337:     }
338:     /* Cell vertices have support 2 */
339:     for (c = cStart; c < cEnd; ++c) {
340:       const PetscInt newp = vStartNew + (vEnd - vStart) + (c - cStart);

342:       DMPlexSetSupportSize(rdm, newp, 2);
343:     }
344:     break;
345:   case REFINER_SIMPLEX_2D:
346:     /* All cells have 3 faces */
347:     for (c = cStart; c < cEnd; ++c) {
348:       for (r = 0; r < 4; ++r) {
349:         const PetscInt newp = (c - cStart)*4 + r;

351:         DMPlexSetConeSize(rdm, newp, 3);
352:       }
353:     }
354:     /* Split faces have 2 vertices and the same cells as the parent */
355:     for (f = fStart; f < fEnd; ++f) {
356:       for (r = 0; r < 2; ++r) {
357:         const PetscInt newp = fStartNew + (f - fStart)*2 + r;
358:         PetscInt       size;

360:         DMPlexSetConeSize(rdm, newp, 2);
361:         DMPlexGetSupportSize(dm, f, &size);
362:         DMPlexSetSupportSize(rdm, newp, size);
363:       }
364:     }
365:     /* Interior faces have 2 vertices and 2 cells */
366:     for (c = cStart; c < cEnd; ++c) {
367:       for (r = 0; r < 3; ++r) {
368:         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*3 + r;

370:         DMPlexSetConeSize(rdm, newp, 2);
371:         DMPlexSetSupportSize(rdm, newp, 2);
372:       }
373:     }
374:     /* Old vertices have identical supports */
375:     for (v = vStart; v < vEnd; ++v) {
376:       const PetscInt newp = vStartNew + (v - vStart);
377:       PetscInt       size;

379:       DMPlexGetSupportSize(dm, v, &size);
380:       DMPlexSetSupportSize(rdm, newp, size);
381:     }
382:     /* Face vertices have 2 + cells*2 supports */
383:     for (f = fStart; f < fEnd; ++f) {
384:       const PetscInt newp = vStartNew + (vEnd - vStart) + (f - fStart);
385:       PetscInt       size;

387:       DMPlexGetSupportSize(dm, f, &size);
388:       DMPlexSetSupportSize(rdm, newp, 2 + size*2);
389:     }
390:     break;
391:   case REFINER_HEX_2D:
392:     /* All cells have 4 faces */
393:     for (c = cStart; c < cEnd; ++c) {
394:       for (r = 0; r < 4; ++r) {
395:         const PetscInt newp = cStartNew + (c - cStart)*4 + r;

397:         DMPlexSetConeSize(rdm, newp, 4);
398:       }
399:     }
400:     /* Split faces have 2 vertices and the same cells as the parent */
401:     for (f = fStart; f < fEnd; ++f) {
402:       for (r = 0; r < 2; ++r) {
403:         const PetscInt newp = fStartNew + (f - fStart)*2 + r;
404:         PetscInt       size;

406:         DMPlexSetConeSize(rdm, newp, 2);
407:         DMPlexGetSupportSize(dm, f, &size);
408:         DMPlexSetSupportSize(rdm, newp, size);
409:       }
410:     }
411:     /* Interior faces have 2 vertices and 2 cells */
412:     for (c = cStart; c < cEnd; ++c) {
413:       for (r = 0; r < 4; ++r) {
414:         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*4 + r;

416:         DMPlexSetConeSize(rdm, newp, 2);
417:         DMPlexSetSupportSize(rdm, newp, 2);
418:       }
419:     }
420:     /* Old vertices have identical supports */
421:     for (v = vStart; v < vEnd; ++v) {
422:       const PetscInt newp = vStartNew + (v - vStart);
423:       PetscInt       size;

425:       DMPlexGetSupportSize(dm, v, &size);
426:       DMPlexSetSupportSize(rdm, newp, size);
427:     }
428:     /* Face vertices have 2 + cells supports */
429:     for (f = fStart; f < fEnd; ++f) {
430:       const PetscInt newp = vStartNew + (vEnd - vStart) + (f - fStart);
431:       PetscInt       size;

433:       DMPlexGetSupportSize(dm, f, &size);
434:       DMPlexSetSupportSize(rdm, newp, 2 + size);
435:     }
436:     /* Cell vertices have 4 supports */
437:     for (c = cStart; c < cEnd; ++c) {
438:       const PetscInt newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (c - cStart);

440:       DMPlexSetSupportSize(rdm, newp, 4);
441:     }
442:     break;
443:   case REFINER_HYBRID_SIMPLEX_2D:
444:     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
445:     cMax = PetscMin(cEnd, cMax);
446:     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
447:     fMax = PetscMin(fEnd, fMax);
448:     DMPlexSetHybridBounds(rdm, cStartNew + (cMax - cStart)*4, fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3, PETSC_DETERMINE, PETSC_DETERMINE);
449:     /* Interior cells have 3 faces */
450:     for (c = cStart; c < cMax; ++c) {
451:       for (r = 0; r < 4; ++r) {
452:         const PetscInt newp = cStartNew + (c - cStart)*4 + r;

454:         DMPlexSetConeSize(rdm, newp, 3);
455:       }
456:     }
457:     /* Hybrid cells have 4 faces */
458:     for (c = cMax; c < cEnd; ++c) {
459:       for (r = 0; r < 2; ++r) {
460:         const PetscInt newp = cStartNew + (cMax - cStart)*4 + (c - cMax)*2 + r;

462:         DMPlexSetConeSize(rdm, newp, 4);
463:       }
464:     }
465:     /* Interior split faces have 2 vertices and the same cells as the parent */
466:     for (f = fStart; f < fMax; ++f) {
467:       for (r = 0; r < 2; ++r) {
468:         const PetscInt newp = fStartNew + (f - fStart)*2 + r;
469:         PetscInt       size;

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

481:         DMPlexSetConeSize(rdm, newp, 2);
482:         DMPlexSetSupportSize(rdm, newp, 2);
483:       }
484:     }
485:     /* Hybrid faces have 2 vertices and the same cells */
486:     for (f = fMax; f < fEnd; ++f) {
487:       const PetscInt newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (f - fMax);
488:       PetscInt       size;

490:       DMPlexSetConeSize(rdm, newp, 2);
491:       DMPlexGetSupportSize(dm, f, &size);
492:       DMPlexSetSupportSize(rdm, newp, size);
493:     }
494:     /* Hybrid cell faces have 2 vertices and 2 cells */
495:     for (c = cMax; c < cEnd; ++c) {
496:       const PetscInt newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (fEnd - fMax) + (c - cMax);

498:       DMPlexSetConeSize(rdm, newp, 2);
499:       DMPlexSetSupportSize(rdm, newp, 2);
500:     }
501:     /* Old vertices have identical supports */
502:     for (v = vStart; v < vEnd; ++v) {
503:       const PetscInt newp = vStartNew + (v - vStart);
504:       PetscInt       size;

506:       DMPlexGetSupportSize(dm, v, &size);
507:       DMPlexSetSupportSize(rdm, newp, size);
508:     }
509:     /* Face vertices have 2 + (2 interior, 1 hybrid) supports */
510:     for (f = fStart; f < fMax; ++f) {
511:       const PetscInt newp = vStartNew + (vEnd - vStart) + (f - fStart);
512:       const PetscInt *support;
513:       PetscInt       size, newSize = 2, s;

515:       DMPlexGetSupportSize(dm, f, &size);
516:       DMPlexGetSupport(dm, f, &support);
517:       for (s = 0; s < size; ++s) {
518:         if (support[s] >= cMax) newSize += 1;
519:         else newSize += 2;
520:       }
521:       DMPlexSetSupportSize(rdm, newp, newSize);
522:     }
523:     break;
524:   case REFINER_HYBRID_HEX_2D:
525:     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
526:     cMax = PetscMin(cEnd, cMax);
527:     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
528:     fMax = PetscMin(fEnd, fMax);
529:     DMPlexSetHybridBounds(rdm, cStartNew + (cMax - cStart)*4, fStartNew + (fMax - fStart)*2 + (cMax - cStart)*4, PETSC_DETERMINE, PETSC_DETERMINE);
530:     /* Interior cells have 4 faces */
531:     for (c = cStart; c < cMax; ++c) {
532:       for (r = 0; r < 4; ++r) {
533:         const PetscInt newp = cStartNew + (c - cStart)*4 + r;

535:         DMPlexSetConeSize(rdm, newp, 4);
536:       }
537:     }
538:     /* Hybrid cells have 4 faces */
539:     for (c = cMax; c < cEnd; ++c) {
540:       for (r = 0; r < 2; ++r) {
541:         const PetscInt newp = cStartNew + (cMax - cStart)*4 + (c - cMax)*2 + r;

543:         DMPlexSetConeSize(rdm, newp, 4);
544:       }
545:     }
546:     /* Interior split faces have 2 vertices and the same cells as the parent */
547:     for (f = fStart; f < fMax; ++f) {
548:       for (r = 0; r < 2; ++r) {
549:         const PetscInt newp = fStartNew + (f - fStart)*2 + r;
550:         PetscInt       size;

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

562:         DMPlexSetConeSize(rdm, newp, 2);
563:         DMPlexSetSupportSize(rdm, newp, 2);
564:       }
565:     }
566:     /* Hybrid faces have 2 vertices and the same cells */
567:     for (f = fMax; f < fEnd; ++f) {
568:       const PetscInt newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*4 + (f - fMax);
569:       PetscInt       size;

571:       DMPlexSetConeSize(rdm, newp, 2);
572:       DMPlexGetSupportSize(dm, f, &size);
573:       DMPlexSetSupportSize(rdm, newp, size);
574:     }
575:     /* Hybrid cell faces have 2 vertices and 2 cells */
576:     for (c = cMax; c < cEnd; ++c) {
577:       const PetscInt newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*4 + (fEnd - fMax) + (c - cMax);

579:       DMPlexSetConeSize(rdm, newp, 2);
580:       DMPlexSetSupportSize(rdm, newp, 2);
581:     }
582:     /* Old vertices have identical supports */
583:     for (v = vStart; v < vEnd; ++v) {
584:       const PetscInt newp = vStartNew + (v - vStart);
585:       PetscInt       size;

587:       DMPlexGetSupportSize(dm, v, &size);
588:       DMPlexSetSupportSize(rdm, newp, size);
589:     }
590:     /* Face vertices have 2 + cells supports */
591:     for (f = fStart; f < fMax; ++f) {
592:       const PetscInt newp = vStartNew + (vEnd - vStart) + (f - fStart);
593:       PetscInt       size;

595:       DMPlexGetSupportSize(dm, f, &size);
596:       DMPlexSetSupportSize(rdm, newp, 2 + size);
597:     }
598:     /* Cell vertices have 4 supports */
599:     for (c = cStart; c < cMax; ++c) {
600:       const PetscInt newp = vStartNew + (vEnd - vStart) + (fMax - fStart) + (c - cStart);

602:       DMPlexSetSupportSize(rdm, newp, 4);
603:     }
604:     break;
605:   case REFINER_SIMPLEX_3D:
606:     /* All cells have 4 faces */
607:     for (c = cStart; c < cEnd; ++c) {
608:       for (r = 0; r < 8; ++r) {
609:         const PetscInt newp = cStartNew + (c - cStart)*8 + r;

611:         DMPlexSetConeSize(rdm, newp, 4);
612:       }
613:     }
614:     /* Split faces have 3 edges and the same cells as the parent */
615:     for (f = fStart; f < fEnd; ++f) {
616:       for (r = 0; r < 4; ++r) {
617:         const PetscInt newp = fStartNew + (f - fStart)*4 + r;
618:         PetscInt       size;

620:         DMPlexSetConeSize(rdm, newp, 3);
621:         DMPlexGetSupportSize(dm, f, &size);
622:         DMPlexSetSupportSize(rdm, newp, size);
623:       }
624:     }
625:     /* Interior cell faces have 3 edges and 2 cells */
626:     for (c = cStart; c < cEnd; ++c) {
627:       for (r = 0; r < 8; ++r) {
628:         const PetscInt newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*8 + r;

630:         DMPlexSetConeSize(rdm, newp, 3);
631:         DMPlexSetSupportSize(rdm, newp, 2);
632:       }
633:     }
634:     /* Split edges have 2 vertices and the same faces */
635:     for (e = eStart; e < eEnd; ++e) {
636:       for (r = 0; r < 2; ++r) {
637:         const PetscInt newp = eStartNew + (e - eStart)*2 + r;
638:         PetscInt       size;

640:         DMPlexSetConeSize(rdm, newp, 2);
641:         DMPlexGetSupportSize(dm, e, &size);
642:         DMPlexSetSupportSize(rdm, newp, size);
643:       }
644:     }
645:     /* Face edges have 2 vertices and 2+cells*(1/2) faces */
646:     for (f = fStart; f < fEnd; ++f) {
647:       for (r = 0; r < 3; ++r) {
648:         const PetscInt  newp = eStartNew + (eEnd - eStart)*2 + (f - fStart)*3 + r;
649:         const PetscInt *cone, *ornt, *support, eint[4] = {1, 0, 2, 0};
650:         PetscInt        coneSize, c, supportSize, s, er, intFaces = 0;

652:         DMPlexSetConeSize(rdm, newp, 2);
653:         DMPlexGetSupportSize(dm, f, &supportSize);
654:         DMPlexGetSupport(dm, f, &support);
655:         for (s = 0; s < supportSize; ++s) {
656:           DMPlexGetConeSize(dm, support[s], &coneSize);
657:           DMPlexGetCone(dm, support[s], &cone);
658:           DMPlexGetConeOrientation(dm, support[s], &ornt);
659:           for (c = 0; c < coneSize; ++c) {if (cone[c] == f) break;}
660:           /* Here we want to determine whether edge newp contains a vertex which is part of the cross-tet edge */
661:           er = GetTetSomethingInverse_Static(ornt[c], r);
662:           if (er == eint[c]) {
663:             intFaces += 1;
664:           } else {
665:             intFaces += 2;
666:           }
667:         }
668:         DMPlexSetSupportSize(rdm, newp, 2+intFaces);
669:       }
670:     }
671:     /* Interior cell edges have 2 vertices and 4 faces */
672:     for (c = cStart; c < cEnd; ++c) {
673:       const PetscInt newp = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart);

675:       DMPlexSetConeSize(rdm, newp, 2);
676:       DMPlexSetSupportSize(rdm, newp, 4);
677:     }
678:     /* Old vertices have identical supports */
679:     for (v = vStart; v < vEnd; ++v) {
680:       const PetscInt newp = vStartNew + (v - vStart);
681:       PetscInt       size;

683:       DMPlexGetSupportSize(dm, v, &size);
684:       DMPlexSetSupportSize(rdm, newp, size);
685:     }
686:     /* Edge vertices have 2 + faces*2 + cells*0/1 supports */
687:     for (e = eStart; e < eEnd; ++e) {
688:       const PetscInt newp = vStartNew + (vEnd - vStart) + (e - eStart);
689:       PetscInt       size, *star = NULL, starSize, s, cellSize = 0;

691:       DMPlexGetSupportSize(dm, e, &size);
692:       DMPlexGetTransitiveClosure(dm, e, PETSC_FALSE, &starSize, &star);
693:       for (s = 0; s < starSize*2; s += 2) {
694:         const PetscInt *cone, *ornt;
695:         PetscInt        e01, e23;

697:         if ((star[s] >= cStart) && (star[s] < cEnd)) {
698:           /* Check edge 0-1 */
699:           DMPlexGetCone(dm, star[s], &cone);
700:           DMPlexGetConeOrientation(dm, star[s], &ornt);
701:           DMPlexGetCone(dm, cone[0], &cone);
702:           e01  = cone[GetTriEdge_Static(ornt[0], 0)];
703:           /* Check edge 2-3 */
704:           DMPlexGetCone(dm, star[s], &cone);
705:           DMPlexGetConeOrientation(dm, star[s], &ornt);
706:           DMPlexGetCone(dm, cone[2], &cone);
707:           e23  = cone[GetTriEdge_Static(ornt[2], 1)];
708:           if ((e01 == e) || (e23 == e)) ++cellSize;
709:         }
710:       }
711:       DMPlexRestoreTransitiveClosure(dm, e, PETSC_FALSE, &starSize, &star);
712:       DMPlexSetSupportSize(rdm, newp, 2 + size*2 + cellSize);
713:     }
714:     break;
715:   case REFINER_HYBRID_SIMPLEX_3D:
716:     DMPlexSetHybridBounds(rdm, cStartNew + 8*(cMax-cStart), fStartNew + 4*(fMax - fStart) + 8*(cMax - cStart),
717:                                  eStartNew + 2*(eMax - eStart) + 3*(fMax - fStart) + (cMax - cStart), PETSC_DETERMINE);
718:     /* Interior cells have 4 faces */
719:     for (c = cStart; c < cMax; ++c) {
720:       for (r = 0; r < 8; ++r) {
721:         const PetscInt newp = cStartNew + (c - cStart)*8 + r;

723:         DMPlexSetConeSize(rdm, newp, 4);
724:       }
725:     }
726:     /* Hybrid cells have 5 faces */
727:     for (c = cMax; c < cEnd; ++c) {
728:       for (r = 0; r < 4; ++r) {
729:         const PetscInt newp = cStartNew + (cMax - cStart)*8 + (c - cMax)*4 + r;

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

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

750:         DMPlexSetConeSize(rdm, newp, 3);
751:         DMPlexSetSupportSize(rdm, newp, 2);
752:       }
753:     }
754:     /* Hybrid split faces have 4 edges and the same cells as the parent */
755:     for (f = fMax; f < fEnd; ++f) {
756:       for (r = 0; r < 2; ++r) {
757:         const PetscInt newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (f - fMax)*2 + r;
758:         PetscInt       size;

760:         DMPlexSetConeSize(rdm, newp, 4);
761:         DMPlexGetSupportSize(dm, f, &size);
762:         DMPlexSetSupportSize(rdm, newp, size);
763:       }
764:     }
765:     /* Hybrid cells faces have 4 edges and 2 cells */
766:     for (c = cMax; c < cEnd; ++c) {
767:       for (r = 0; r < 3; ++r) {
768:         const PetscInt newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (c - cMax)*3 + r;

770:         DMPlexSetConeSize(rdm, newp, 4);
771:         DMPlexSetSupportSize(rdm, newp, 2);
772:       }
773:     }
774:     /* Interior split edges have 2 vertices and the same faces */
775:     for (e = eStart; e < eMax; ++e) {
776:       for (r = 0; r < 2; ++r) {
777:         const PetscInt newp = eStartNew + (e - eStart)*2 + r;
778:         PetscInt       size;

780:         DMPlexSetConeSize(rdm, newp, 2);
781:         DMPlexGetSupportSize(dm, e, &size);
782:         DMPlexSetSupportSize(rdm, newp, size);
783:       }
784:     }
785:     /* Interior face edges have 2 vertices and 2+cells*(1/2) faces */
786:     for (f = fStart; f < fMax; ++f) {
787:       for (r = 0; r < 3; ++r) {
788:         const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (f - fStart)*3 + r;
789:         const PetscInt *cone, *ornt, *support, eint[4] = {1, 0, 2, 0};
790:         PetscInt        coneSize, c, supportSize, s, er, intFaces = 0;

792:         DMPlexSetConeSize(rdm, newp, 2);
793:         DMPlexGetSupportSize(dm, f, &supportSize);
794:         DMPlexGetSupport(dm, f, &support);
795:         for (s = 0; s < supportSize; ++s) {
796:           DMPlexGetConeSize(dm, support[s], &coneSize);
797:           DMPlexGetCone(dm, support[s], &cone);
798:           DMPlexGetConeOrientation(dm, support[s], &ornt);
799:           for (c = 0; c < coneSize; ++c) {if (cone[c] == f) break;}
800:           if (support[s] < cMax) {
801:             /* Here we want to determine whether edge newp contains a vertex which is part of the cross-tet edge */
802:             er = GetTetSomethingInverse_Static(ornt[c], r);
803:             if (er == eint[c]) {
804:               intFaces += 1;
805:             } else {
806:               intFaces += 2;
807:             }
808:           } else {
809:             intFaces += 1;
810:           }
811:         }
812:         DMPlexSetSupportSize(rdm, newp, 2+intFaces);
813:       }
814:     }
815:     /* Interior cell edges have 2 vertices and 4 faces */
816:     for (c = cStart; c < cMax; ++c) {
817:       const PetscInt newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart);

819:       DMPlexSetConeSize(rdm, newp, 2);
820:       DMPlexSetSupportSize(rdm, newp, 4);
821:     }
822:     /* Hybrid edges have 2 vertices and the same faces */
823:     for (e = eMax; e < eEnd; ++e) {
824:       const PetscInt newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (e - eMax);
825:       PetscInt       size;

827:       DMPlexSetConeSize(rdm, newp, 2);
828:       DMPlexGetSupportSize(dm, e, &size);
829:       DMPlexSetSupportSize(rdm, newp, size);
830:     }
831:     /* Hybrid face edges have 2 vertices and 2+2*cells faces */
832:     for (f = fMax; f < fEnd; ++f) {
833:       const PetscInt newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (eEnd - eMax) + (f - fMax);
834:       PetscInt       size;

836:       DMPlexSetConeSize(rdm, newp, 2);
837:       DMPlexGetSupportSize(dm, f, &size);
838:       DMPlexSetSupportSize(rdm, newp, 2+2*size);
839:     }
840:     /* Interior vertices have identical supports */
841:     for (v = vStart; v < vEnd; ++v) {
842:       const PetscInt newp = vStartNew + (v - vStart);
843:       PetscInt       size;

845:       DMPlexGetSupportSize(dm, v, &size);
846:       DMPlexSetSupportSize(rdm, newp, size);
847:     }
848:     /* Interior edge vertices have 2 + interior face*2 + hybrid face + cells*0/1 supports */
849:     for (e = eStart; e < eMax; ++e) {
850:       const PetscInt  newp = vStartNew + (vEnd - vStart) + (e - eStart);
851:       const PetscInt *support;
852:       PetscInt        size, *star = NULL, starSize, s, faceSize = 0, cellSize = 0;

854:       DMPlexGetSupportSize(dm, e, &size);
855:       DMPlexGetSupport(dm, e, &support);
856:       for (s = 0; s < size; ++s) {
857:         if (support[s] < fMax) faceSize += 2;
858:         else                   faceSize += 1;
859:       }
860:       DMPlexGetTransitiveClosure(dm, e, PETSC_FALSE, &starSize, &star);
861:       for (s = 0; s < starSize*2; s += 2) {
862:         const PetscInt *cone, *ornt;
863:         PetscInt        e01, e23;

865:         if ((star[s] >= cStart) && (star[s] < cMax)) {
866:           /* Check edge 0-1 */
867:           DMPlexGetCone(dm, star[s], &cone);
868:           DMPlexGetConeOrientation(dm, star[s], &ornt);
869:           DMPlexGetCone(dm, cone[0], &cone);
870:           e01  = cone[GetTriEdge_Static(ornt[0], 0)];
871:           /* Check edge 2-3 */
872:           DMPlexGetCone(dm, star[s], &cone);
873:           DMPlexGetConeOrientation(dm, star[s], &ornt);
874:           DMPlexGetCone(dm, cone[2], &cone);
875:           e23  = cone[GetTriEdge_Static(ornt[2], 1)];
876:           if ((e01 == e) || (e23 == e)) ++cellSize;
877:         }
878:       }
879:       DMPlexRestoreTransitiveClosure(dm, e, PETSC_FALSE, &starSize, &star);
880:       DMPlexSetSupportSize(rdm, newp, 2 + faceSize + cellSize);
881:     }
882:     break;
883:   case REFINER_HEX_3D:
884:     /* All cells have 6 faces */
885:     for (c = cStart; c < cEnd; ++c) {
886:       for (r = 0; r < 8; ++r) {
887:         const PetscInt newp = (c - cStart)*8 + r;

889:         DMPlexSetConeSize(rdm, newp, 6);
890:       }
891:     }
892:     /* Split faces have 4 edges and the same cells as the parent */
893:     for (f = fStart; f < fEnd; ++f) {
894:       for (r = 0; r < 4; ++r) {
895:         const PetscInt newp = fStartNew + (f - fStart)*4 + r;
896:         PetscInt       size;

898:         DMPlexSetConeSize(rdm, newp, 4);
899:         DMPlexGetSupportSize(dm, f, &size);
900:         DMPlexSetSupportSize(rdm, newp, size);
901:       }
902:     }
903:     /* Interior faces have 4 edges and 2 cells */
904:     for (c = cStart; c < cEnd; ++c) {
905:       for (r = 0; r < 12; ++r) {
906:         const PetscInt newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + r;

908:         DMPlexSetConeSize(rdm, newp, 4);
909:         DMPlexSetSupportSize(rdm, newp, 2);
910:       }
911:     }
912:     /* Split edges have 2 vertices and the same faces as the parent */
913:     for (e = eStart; e < eEnd; ++e) {
914:       for (r = 0; r < 2; ++r) {
915:         const PetscInt newp = eStartNew + (e - eStart)*2 + r;
916:         PetscInt       size;

918:         DMPlexSetConeSize(rdm, newp, 2);
919:         DMPlexGetSupportSize(dm, e, &size);
920:         DMPlexSetSupportSize(rdm, newp, size);
921:       }
922:     }
923:     /* Face edges have 2 vertices and 2+cells faces */
924:     for (f = fStart; f < fEnd; ++f) {
925:       for (r = 0; r < 4; ++r) {
926:         const PetscInt newp = eStartNew + (eEnd - eStart)*2 + (f - fStart)*4 + r;
927:         PetscInt       size;

929:         DMPlexSetConeSize(rdm, newp, 2);
930:         DMPlexGetSupportSize(dm, f, &size);
931:         DMPlexSetSupportSize(rdm, newp, 2+size);
932:       }
933:     }
934:     /* Cell edges have 2 vertices and 4 faces */
935:     for (c = cStart; c < cEnd; ++c) {
936:       for (r = 0; r < 6; ++r) {
937:         const PetscInt newp = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*4 + (c - cStart)*6 + r;

939:         DMPlexSetConeSize(rdm, newp, 2);
940:         DMPlexSetSupportSize(rdm, newp, 4);
941:       }
942:     }
943:     /* Old vertices have identical supports */
944:     for (v = vStart; v < vEnd; ++v) {
945:       const PetscInt newp = vStartNew + (v - vStart);
946:       PetscInt       size;

948:       DMPlexGetSupportSize(dm, v, &size);
949:       DMPlexSetSupportSize(rdm, newp, size);
950:     }
951:     /* Edge vertices have 2 + faces supports */
952:     for (e = eStart; e < eEnd; ++e) {
953:       const PetscInt newp = vStartNew + (vEnd - vStart) + (e - eStart);
954:       PetscInt       size;

956:       DMPlexGetSupportSize(dm, e, &size);
957:       DMPlexSetSupportSize(rdm, newp, 2 + size);
958:     }
959:     /* Face vertices have 4 + cells supports */
960:     for (f = fStart; f < fEnd; ++f) {
961:       const PetscInt newp = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (f - fStart);
962:       PetscInt       size;

964:       DMPlexGetSupportSize(dm, f, &size);
965:       DMPlexSetSupportSize(rdm, newp, 4 + size);
966:     }
967:     /* Cell vertices have 6 supports */
968:     for (c = cStart; c < cEnd; ++c) {
969:       const PetscInt newp = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (fEnd - fStart) + (c - cStart);

971:       DMPlexSetSupportSize(rdm, newp, 6);
972:     }
973:     break;
974:   case REFINER_HYBRID_HEX_3D:
975:     DMPlexSetHybridBounds(rdm, cStartNew + 8*(cMax-cStart), fStartNew + 4*(fMax - fStart) + 12*(cMax - cStart),
976:                                  eStartNew + 2*(eMax - eStart) + 4*(fMax - fStart) + 6*(cMax - cStart), PETSC_DETERMINE);
977:     /* Interior cells have 6 faces */
978:     for (c = cStart; c < cMax; ++c) {
979:       for (r = 0; r < 8; ++r) {
980:         const PetscInt newp = cStartNew + (c - cStart)*8 + r;

982:         DMPlexSetConeSize(rdm, newp, 6);
983:       }
984:     }
985:     /* Hybrid cells have 6 faces */
986:     for (c = cMax; c < cEnd; ++c) {
987:       for (r = 0; r < 4; ++r) {
988:         const PetscInt newp = cStartNew + (cMax - cStart)*8 + (c - cMax)*4 + r;

990:         DMPlexSetConeSize(rdm, newp, 6);
991:       }
992:     }
993:     /* Interior split faces have 4 edges and the same cells as the parent */
994:     for (f = fStart; f < fMax; ++f) {
995:       for (r = 0; r < 4; ++r) {
996:         const PetscInt newp = fStartNew + (f - fStart)*4 + r;
997:         PetscInt       size;

999:         DMPlexSetConeSize(rdm, newp, 4);
1000:         DMPlexGetSupportSize(dm, f, &size);
1001:         DMPlexSetSupportSize(rdm, newp, size);
1002:       }
1003:     }
1004:     /* Interior cell faces have 4 edges and 2 cells */
1005:     for (c = cStart; c < cMax; ++c) {
1006:       for (r = 0; r < 12; ++r) {
1007:         const PetscInt newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + r;

1009:         DMPlexSetConeSize(rdm, newp, 4);
1010:         DMPlexSetSupportSize(rdm, newp, 2);
1011:       }
1012:     }
1013:     /* Hybrid split faces have 4 edges and the same cells as the parent */
1014:     for (f = fMax; f < fEnd; ++f) {
1015:       for (r = 0; r < 2; ++r) {
1016:         const PetscInt newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (f - fMax)*2 + r;
1017:         PetscInt       size;

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

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

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

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

1060:         DMPlexSetConeSize(rdm, newp, 2);
1061:         DMPlexSetSupportSize(rdm, newp, 4);
1062:       }
1063:     }
1064:     /* Hybrid edges have 2 vertices and the same faces */
1065:     for (e = eMax; e < eEnd; ++e) {
1066:       const PetscInt newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (e - eMax);
1067:       PetscInt       size;

1069:       DMPlexSetConeSize(rdm, newp, 2);
1070:       DMPlexGetSupportSize(dm, e, &size);
1071:       DMPlexSetSupportSize(rdm, newp, size);
1072:     }
1073:     /* Hybrid face edges have 2 vertices and 2+cells faces */
1074:     for (f = fMax; f < fEnd; ++f) {
1075:       const PetscInt newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (eEnd - eMax) + (f - fMax);
1076:       PetscInt       size;

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

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

1094:       DMPlexGetSupportSize(dm, v, &size);
1095:       DMPlexSetSupportSize(rdm, newp, size);
1096:     }
1097:     /* Interior edge vertices have 2 + faces supports */
1098:     for (e = eStart; e < eMax; ++e) {
1099:       const PetscInt newp = vStartNew + (vEnd - vStart) + (e - eStart);
1100:       PetscInt       size;

1102:       DMPlexGetSupportSize(dm, e, &size);
1103:       DMPlexSetSupportSize(rdm, newp, 2 + size);
1104:     }
1105:     /* Interior face vertices have 4 + cells supports */
1106:     for (f = fStart; f < fMax; ++f) {
1107:       const PetscInt newp = vStartNew + (vEnd - vStart) + (eMax - eStart) + (f - fStart);
1108:       PetscInt       size;

1110:       DMPlexGetSupportSize(dm, f, &size);
1111:       DMPlexSetSupportSize(rdm, newp, 4 + size);
1112:     }
1113:     /* Interior cell vertices have 6 supports */
1114:     for (c = cStart; c < cMax; ++c) {
1115:       const PetscInt newp = vStartNew + (vEnd - vStart) + (eMax - eStart) + (fMax - fStart) + (c - cStart);

1117:       DMPlexSetSupportSize(rdm, newp, 6);
1118:     }
1119:     break;
1120:   default:
1121:     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
1122:   }
1123:   return(0);
1124: }

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

1137:   if (!refiner) return(0);
1138:   DMPlexGetDepth(dm, &depth);
1139:   DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);
1140:   DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);
1141:   DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);
1142:   DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);
1143:   DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);
1144:   GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);
1145:   GetDepthEnd_Private(depth, depthSize, &cEndNew, &fEndNew, &eEndNew, &vEndNew);
1146:   switch (refiner) {
1147:   case REFINER_SIMPLEX_1D:
1148:     /* Max support size of refined mesh is 2 */
1149:     PetscMalloc1(2, &supportRef);
1150:     /* All cells have 2 vertices */
1151:     for (c = cStart; c < cEnd; ++c) {
1152:       const PetscInt  newv = vStartNew + (vEnd - vStart) + (c - cStart);

1154:       for (r = 0; r < 2; ++r) {
1155:         const PetscInt newp = cStartNew + (c - cStart)*2 + r;
1156:         const PetscInt *cone;
1157:         PetscInt        coneNew[2];

1159:         DMPlexGetCone(dm, c, &cone);
1160:         coneNew[0]       = vStartNew + (cone[0] - vStart);
1161:         coneNew[1]       = vStartNew + (cone[1] - vStart);
1162:         coneNew[(r+1)%2] = newv;
1163:         DMPlexSetCone(rdm, newp, coneNew);
1164: #if 1
1165:         if ((newp < cStartNew) || (newp >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp, cStartNew, cEndNew);
1166:         for (p = 0; p < 2; ++p) {
1167:           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);
1168:         }
1169: #endif
1170:       }
1171:     }
1172:     /* Old vertices have identical supports */
1173:     for (v = vStart; v < vEnd; ++v) {
1174:       const PetscInt  newp = vStartNew + (v - vStart);
1175:       const PetscInt *support, *cone;
1176:       PetscInt        size, s;

1178:       DMPlexGetSupportSize(dm, v, &size);
1179:       DMPlexGetSupport(dm, v, &support);
1180:       for (s = 0; s < size; ++s) {
1181:         PetscInt r = 0;

1183:         DMPlexGetCone(dm, support[s], &cone);
1184:         if (cone[1] == v) r = 1;
1185:         supportRef[s] = cStartNew + (support[s] - cStart)*2 + r;
1186:       }
1187:       DMPlexSetSupport(rdm, newp, supportRef);
1188: #if 1
1189:       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
1190:       for (p = 0; p < size; ++p) {
1191:         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);
1192:       }
1193: #endif
1194:     }
1195:     /* Cell vertices have support of 2 cells */
1196:     for (c = cStart; c < cEnd; ++c) {
1197:       const PetscInt  newp = vStartNew + (vEnd - vStart) + (c - cStart);

1199:       supportRef[0] = cStartNew + (c - cStart)*2 + 0;
1200:       supportRef[1] = cStartNew + (c - cStart)*2 + 1;
1201:       DMPlexSetSupport(rdm, newp, supportRef);
1202: #if 1
1203:       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
1204:       for (p = 0; p < 2; ++p) {
1205:         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);
1206:       }
1207: #endif
1208:     }
1209:     PetscFree(supportRef);
1210:     break;
1211:   case REFINER_SIMPLEX_2D:
1212:     /*
1213:      2
1214:      |\
1215:      | \
1216:      |  \
1217:      |   \
1218:      | C  \
1219:      |     \
1220:      |      \
1221:      2---1---1
1222:      |\  D  / \
1223:      | 2   0   \
1224:      |A \ /  B  \
1225:      0---0-------1
1226:      */
1227:     /* All cells have 3 faces */
1228:     for (c = cStart; c < cEnd; ++c) {
1229:       const PetscInt  newp = cStartNew + (c - cStart)*4;
1230:       const PetscInt *cone, *ornt;
1231:       PetscInt        coneNew[3], orntNew[3];

1233:       DMPlexGetCone(dm, c, &cone);
1234:       DMPlexGetConeOrientation(dm, c, &ornt);
1235:       /* A triangle */
1236:       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
1237:       orntNew[0] = ornt[0];
1238:       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 2;
1239:       orntNew[1] = -2;
1240:       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
1241:       orntNew[2] = ornt[2];
1242:       DMPlexSetCone(rdm, newp+0, coneNew);
1243:       DMPlexSetConeOrientation(rdm, newp+0, orntNew);
1244: #if 1
1245:       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);
1246:       for (p = 0; p < 3; ++p) {
1247:         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);
1248:       }
1249: #endif
1250:       /* B triangle */
1251:       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
1252:       orntNew[0] = ornt[0];
1253:       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
1254:       orntNew[1] = ornt[1];
1255:       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 0;
1256:       orntNew[2] = -2;
1257:       DMPlexSetCone(rdm, newp+1, coneNew);
1258:       DMPlexSetConeOrientation(rdm, newp+1, orntNew);
1259: #if 1
1260:       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);
1261:       for (p = 0; p < 3; ++p) {
1262:         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);
1263:       }
1264: #endif
1265:       /* C triangle */
1266:       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 1;
1267:       orntNew[0] = -2;
1268:       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
1269:       orntNew[1] = ornt[1];
1270:       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
1271:       orntNew[2] = ornt[2];
1272:       DMPlexSetCone(rdm, newp+2, coneNew);
1273:       DMPlexSetConeOrientation(rdm, newp+2, orntNew);
1274: #if 1
1275:       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);
1276:       for (p = 0; p < 3; ++p) {
1277:         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);
1278:       }
1279: #endif
1280:       /* D triangle */
1281:       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 0;
1282:       orntNew[0] = 0;
1283:       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 1;
1284:       orntNew[1] = 0;
1285:       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 2;
1286:       orntNew[2] = 0;
1287:       DMPlexSetCone(rdm, newp+3, coneNew);
1288:       DMPlexSetConeOrientation(rdm, newp+3, orntNew);
1289: #if 1
1290:       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);
1291:       for (p = 0; p < 3; ++p) {
1292:         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);
1293:       }
1294: #endif
1295:     }
1296:     /* Split faces have 2 vertices and the same cells as the parent */
1297:     DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);
1298:     PetscMalloc1(2 + maxSupportSize*2, &supportRef);
1299:     for (f = fStart; f < fEnd; ++f) {
1300:       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);

1302:       for (r = 0; r < 2; ++r) {
1303:         const PetscInt  newp = fStartNew + (f - fStart)*2 + r;
1304:         const PetscInt *cone, *ornt, *support;
1305:         PetscInt        coneNew[2], coneSize, c, supportSize, s;

1307:         DMPlexGetCone(dm, f, &cone);
1308:         coneNew[0]       = vStartNew + (cone[0] - vStart);
1309:         coneNew[1]       = vStartNew + (cone[1] - vStart);
1310:         coneNew[(r+1)%2] = newv;
1311:         DMPlexSetCone(rdm, newp, coneNew);
1312: #if 1
1313:         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1314:         for (p = 0; p < 2; ++p) {
1315:           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);
1316:         }
1317: #endif
1318:         DMPlexGetSupportSize(dm, f, &supportSize);
1319:         DMPlexGetSupport(dm, f, &support);
1320:         for (s = 0; s < supportSize; ++s) {
1321:           DMPlexGetConeSize(dm, support[s], &coneSize);
1322:           DMPlexGetCone(dm, support[s], &cone);
1323:           DMPlexGetConeOrientation(dm, support[s], &ornt);
1324:           for (c = 0; c < coneSize; ++c) {
1325:             if (cone[c] == f) break;
1326:           }
1327:           supportRef[s] = cStartNew + (support[s] - cStart)*4 + (ornt[c] < 0 ? (c+1-r)%3 : (c+r)%3);
1328:         }
1329:         DMPlexSetSupport(rdm, newp, supportRef);
1330: #if 1
1331:         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1332:         for (p = 0; p < supportSize; ++p) {
1333:           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);
1334:         }
1335: #endif
1336:       }
1337:     }
1338:     /* Interior faces have 2 vertices and 2 cells */
1339:     for (c = cStart; c < cEnd; ++c) {
1340:       const PetscInt *cone;

1342:       DMPlexGetCone(dm, c, &cone);
1343:       for (r = 0; r < 3; ++r) {
1344:         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*3 + r;
1345:         PetscInt       coneNew[2];
1346:         PetscInt       supportNew[2];

1348:         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r]       - fStart);
1349:         coneNew[1] = vStartNew + (vEnd - vStart) + (cone[(r+1)%3] - fStart);
1350:         DMPlexSetCone(rdm, newp, coneNew);
1351: #if 1
1352:         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1353:         for (p = 0; p < 2; ++p) {
1354:           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);
1355:         }
1356: #endif
1357:         supportNew[0] = (c - cStart)*4 + (r+1)%3;
1358:         supportNew[1] = (c - cStart)*4 + 3;
1359:         DMPlexSetSupport(rdm, newp, supportNew);
1360: #if 1
1361:         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1362:         for (p = 0; p < 2; ++p) {
1363:           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);
1364:         }
1365: #endif
1366:       }
1367:     }
1368:     /* Old vertices have identical supports */
1369:     for (v = vStart; v < vEnd; ++v) {
1370:       const PetscInt  newp = vStartNew + (v - vStart);
1371:       const PetscInt *support, *cone;
1372:       PetscInt        size, s;

1374:       DMPlexGetSupportSize(dm, v, &size);
1375:       DMPlexGetSupport(dm, v, &support);
1376:       for (s = 0; s < size; ++s) {
1377:         PetscInt r = 0;

1379:         DMPlexGetCone(dm, support[s], &cone);
1380:         if (cone[1] == v) r = 1;
1381:         supportRef[s] = fStartNew + (support[s] - fStart)*2 + r;
1382:       }
1383:       DMPlexSetSupport(rdm, newp, supportRef);
1384: #if 1
1385:       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
1386:       for (p = 0; p < size; ++p) {
1387:         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);
1388:       }
1389: #endif
1390:     }
1391:     /* Face vertices have 2 + cells*2 supports */
1392:     for (f = fStart; f < fEnd; ++f) {
1393:       const PetscInt  newp = vStartNew + (vEnd - vStart) + (f - fStart);
1394:       const PetscInt *cone, *support;
1395:       PetscInt        size, s;

1397:       DMPlexGetSupportSize(dm, f, &size);
1398:       DMPlexGetSupport(dm, f, &support);
1399:       supportRef[0] = fStartNew + (f - fStart)*2 + 0;
1400:       supportRef[1] = fStartNew + (f - fStart)*2 + 1;
1401:       for (s = 0; s < size; ++s) {
1402:         PetscInt r = 0;

1404:         DMPlexGetCone(dm, support[s], &cone);
1405:         if      (cone[1] == f) r = 1;
1406:         else if (cone[2] == f) r = 2;
1407:         supportRef[2+s*2+0] = fStartNew + (fEnd - fStart)*2 + (support[s] - cStart)*3 + (r+2)%3;
1408:         supportRef[2+s*2+1] = fStartNew + (fEnd - fStart)*2 + (support[s] - cStart)*3 + r;
1409:       }
1410:       DMPlexSetSupport(rdm, newp, supportRef);
1411: #if 1
1412:       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
1413:       for (p = 0; p < 2+size*2; ++p) {
1414:         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);
1415:       }
1416: #endif
1417:     }
1418:     PetscFree(supportRef);
1419:     break;
1420:   case REFINER_HEX_2D:
1421:     /*
1422:      3---------2---------2
1423:      |         |         |
1424:      |    D    2    C    |
1425:      |         |         |
1426:      3----3----0----1----1
1427:      |         |         |
1428:      |    A    0    B    |
1429:      |         |         |
1430:      0---------0---------1
1431:      */
1432:     /* All cells have 4 faces */
1433:     for (c = cStart; c < cEnd; ++c) {
1434:       const PetscInt  newp = (c - cStart)*4;
1435:       const PetscInt *cone, *ornt;
1436:       PetscInt        coneNew[4], orntNew[4];

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

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

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

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

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

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

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

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

1616:         DMPlexGetCone(dm, support[s], &cone);
1617:         if      (cone[1] == f) r = 1;
1618:         else if (cone[2] == f) r = 2;
1619:         else if (cone[3] == f) r = 3;
1620:         supportRef[2+s] = fStartNew + (fEnd - fStart)*2 + (support[s] - cStart)*4 + r;
1621:       }
1622:       DMPlexSetSupport(rdm, newp, supportRef);
1623: #if 1
1624:       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
1625:       for (p = 0; p < 2+size; ++p) {
1626:         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);
1627:       }
1628: #endif
1629:     }
1630:     /* Cell vertices have 4 supports */
1631:     for (c = cStart; c < cEnd; ++c) {
1632:       const PetscInt newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (c - cStart);
1633:       PetscInt       supportNew[4];

1635:       for (r = 0; r < 4; ++r) {
1636:         supportNew[r] = fStartNew + (fEnd - fStart)*2 + (c - cStart)*4 + r;
1637:       }
1638:       DMPlexSetSupport(rdm, newp, supportNew);
1639:     }
1640:     PetscFree(supportRef);
1641:     break;
1642:   case REFINER_HYBRID_SIMPLEX_2D:
1643:     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
1644:     cMax = PetscMin(cEnd, cMax);
1645:     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
1646:     fMax = PetscMin(fEnd, fMax);
1647:     DMPlexGetHybridBounds(rdm, &cMaxNew, &fMaxNew, NULL, NULL);
1648:     /* Interior cells have 3 faces */
1649:     for (c = cStart; c < cMax; ++c) {
1650:       const PetscInt  newp = cStartNew + (c - cStart)*4;
1651:       const PetscInt *cone, *ornt;
1652:       PetscInt        coneNew[3], orntNew[3];

1654:       DMPlexGetCone(dm, c, &cone);
1655:       DMPlexGetConeOrientation(dm, c, &ornt);
1656:       /* A triangle */
1657:       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
1658:       orntNew[0] = ornt[0];
1659:       coneNew[1] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 2;
1660:       orntNew[1] = -2;
1661:       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
1662:       orntNew[2] = ornt[2];
1663:       DMPlexSetCone(rdm, newp+0, coneNew);
1664:       DMPlexSetConeOrientation(rdm, newp+0, orntNew);
1665: #if 1
1666:       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);
1667:       for (p = 0; p < 3; ++p) {
1668:         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);
1669:       }
1670: #endif
1671:       /* B triangle */
1672:       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
1673:       orntNew[0] = ornt[0];
1674:       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
1675:       orntNew[1] = ornt[1];
1676:       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 0;
1677:       orntNew[2] = -2;
1678:       DMPlexSetCone(rdm, newp+1, coneNew);
1679:       DMPlexSetConeOrientation(rdm, newp+1, orntNew);
1680: #if 1
1681:       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);
1682:       for (p = 0; p < 3; ++p) {
1683:         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);
1684:       }
1685: #endif
1686:       /* C triangle */
1687:       coneNew[0] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 1;
1688:       orntNew[0] = -2;
1689:       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
1690:       orntNew[1] = ornt[1];
1691:       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
1692:       orntNew[2] = ornt[2];
1693:       DMPlexSetCone(rdm, newp+2, coneNew);
1694:       DMPlexSetConeOrientation(rdm, newp+2, orntNew);
1695: #if 1
1696:       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);
1697:       for (p = 0; p < 3; ++p) {
1698:         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);
1699:       }
1700: #endif
1701:       /* D triangle */
1702:       coneNew[0] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 0;
1703:       orntNew[0] = 0;
1704:       coneNew[1] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 1;
1705:       orntNew[1] = 0;
1706:       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 2;
1707:       orntNew[2] = 0;
1708:       DMPlexSetCone(rdm, newp+3, coneNew);
1709:       DMPlexSetConeOrientation(rdm, newp+3, orntNew);
1710: #if 1
1711:       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);
1712:       for (p = 0; p < 3; ++p) {
1713:         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);
1714:       }
1715: #endif
1716:     }
1717:     /*
1718:      2----3----3
1719:      |         |
1720:      |    B    |
1721:      |         |
1722:      0----4--- 1
1723:      |         |
1724:      |    A    |
1725:      |         |
1726:      0----2----1
1727:      */
1728:     /* Hybrid cells have 4 faces */
1729:     for (c = cMax; c < cEnd; ++c) {
1730:       const PetscInt  newp = cStartNew + (cMax - cStart)*4 + (c - cMax)*2;
1731:       const PetscInt *cone, *ornt;
1732:       PetscInt        coneNew[4], orntNew[4], r;

1734:       DMPlexGetCone(dm, c, &cone);
1735:       DMPlexGetConeOrientation(dm, c, &ornt);
1736:       r    = (ornt[0] < 0 ? 1 : 0);
1737:       /* A quad */
1738:       coneNew[0]   = fStartNew + (cone[0] - fStart)*2 + r;
1739:       orntNew[0]   = ornt[0];
1740:       coneNew[1]   = fStartNew + (cone[1] - fStart)*2 + r;
1741:       orntNew[1]   = ornt[1];
1742:       coneNew[2+r] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (cone[2+r] - fMax);
1743:       orntNew[2+r] = 0;
1744:       coneNew[3-r] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (fEnd    - fMax) + (c - cMax);
1745:       orntNew[3-r] = 0;
1746:       DMPlexSetCone(rdm, newp+0, coneNew);
1747:       DMPlexSetConeOrientation(rdm, newp+0, orntNew);
1748: #if 1
1749:       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);
1750:       for (p = 0; p < 4; ++p) {
1751:         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);
1752:       }
1753: #endif
1754:       /* B quad */
1755:       coneNew[0]   = fStartNew + (cone[0] - fStart)*2 + 1-r;
1756:       orntNew[0]   = ornt[0];
1757:       coneNew[1]   = fStartNew + (cone[1] - fStart)*2 + 1-r;
1758:       orntNew[1]   = ornt[1];
1759:       coneNew[2+r] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (fEnd    - fMax) + (c - cMax);
1760:       orntNew[2+r] = 0;
1761:       coneNew[3-r] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (cone[3-r] - fMax);
1762:       orntNew[3-r] = 0;
1763:       DMPlexSetCone(rdm, newp+1, coneNew);
1764:       DMPlexSetConeOrientation(rdm, newp+1, orntNew);
1765: #if 1
1766:       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);
1767:       for (p = 0; p < 4; ++p) {
1768:         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);
1769:       }
1770: #endif
1771:     }
1772:     /* Interior split faces have 2 vertices and the same cells as the parent */
1773:     DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);
1774:     PetscMalloc1(2 + maxSupportSize*2, &supportRef);
1775:     for (f = fStart; f < fMax; ++f) {
1776:       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);

1778:       for (r = 0; r < 2; ++r) {
1779:         const PetscInt  newp = fStartNew + (f - fStart)*2 + r;
1780:         const PetscInt *cone, *ornt, *support;
1781:         PetscInt        coneNew[2], coneSize, c, supportSize, s;

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

1820:       DMPlexGetCone(dm, c, &cone);
1821:       for (r = 0; r < 3; ++r) {
1822:         const PetscInt newp = fStartNew + (fMax - fStart)*2 + (c - cStart)*3 + r;
1823:         PetscInt       coneNew[2];
1824:         PetscInt       supportNew[2];

1826:         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r]       - fStart);
1827:         coneNew[1] = vStartNew + (vEnd - vStart) + (cone[(r+1)%3] - fStart);
1828:         DMPlexSetCone(rdm, newp, coneNew);
1829: #if 1
1830:         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1831:         for (p = 0; p < 2; ++p) {
1832:           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);
1833:         }
1834: #endif
1835:         supportNew[0] = (c - cStart)*4 + (r+1)%3;
1836:         supportNew[1] = (c - cStart)*4 + 3;
1837:         DMPlexSetSupport(rdm, newp, supportNew);
1838: #if 1
1839:         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1840:         for (p = 0; p < 2; ++p) {
1841:           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);
1842:         }
1843: #endif
1844:       }
1845:     }
1846:     /* Interior hybrid faces have 2 vertices and the same cells */
1847:     for (f = fMax; f < fEnd; ++f) {
1848:       const PetscInt  newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (f - fMax);
1849:       const PetscInt *cone, *ornt;
1850:       const PetscInt *support;
1851:       PetscInt        coneNew[2];
1852:       PetscInt        supportNew[2];
1853:       PetscInt        size, s, r;

1855:       DMPlexGetCone(dm, f, &cone);
1856:       coneNew[0] = vStartNew + (cone[0] - vStart);
1857:       coneNew[1] = vStartNew + (cone[1] - vStart);
1858:       DMPlexSetCone(rdm, newp, coneNew);
1859: #if 1
1860:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1861:       for (p = 0; p < 2; ++p) {
1862:         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);
1863:       }
1864: #endif
1865:       DMPlexGetSupportSize(dm, f, &size);
1866:       DMPlexGetSupport(dm, f, &support);
1867:       for (s = 0; s < size; ++s) {
1868:         DMPlexGetCone(dm, support[s], &cone);
1869:         DMPlexGetConeOrientation(dm, support[s], &ornt);
1870:         for (r = 0; r < 2; ++r) {
1871:           if (cone[r+2] == f) break;
1872:         }
1873:         supportNew[s] = (cMax - cStart)*4 + (support[s] - cMax)*2 + (ornt[0] < 0 ? 1-r : r);
1874:       }
1875:       DMPlexSetSupport(rdm, newp, supportNew);
1876: #if 1
1877:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1878:       for (p = 0; p < size; ++p) {
1879:         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);
1880:       }
1881: #endif
1882:     }
1883:     /* Cell hybrid faces have 2 vertices and 2 cells */
1884:     for (c = cMax; c < cEnd; ++c) {
1885:       const PetscInt  newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (fEnd - fMax) + (c - cMax);
1886:       const PetscInt *cone;
1887:       PetscInt        coneNew[2];
1888:       PetscInt        supportNew[2];

1890:       DMPlexGetCone(dm, c, &cone);
1891:       coneNew[0] = vStartNew + (vEnd - vStart) + (cone[0] - fStart);
1892:       coneNew[1] = vStartNew + (vEnd - vStart) + (cone[1] - fStart);
1893:       DMPlexSetCone(rdm, newp, coneNew);
1894: #if 1
1895:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1896:       for (p = 0; p < 2; ++p) {
1897:         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);
1898:       }
1899: #endif
1900:       supportNew[0] = (cMax - cStart)*4 + (c - cMax)*2 + 0;
1901:       supportNew[1] = (cMax - cStart)*4 + (c - cMax)*2 + 1;
1902:       DMPlexSetSupport(rdm, newp, supportNew);
1903: #if 1
1904:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1905:       for (p = 0; p < 2; ++p) {
1906:         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);
1907:       }
1908: #endif
1909:     }
1910:     /* Old vertices have identical supports */
1911:     for (v = vStart; v < vEnd; ++v) {
1912:       const PetscInt  newp = vStartNew + (v - vStart);
1913:       const PetscInt *support, *cone;
1914:       PetscInt        size, s;

1916:       DMPlexGetSupportSize(dm, v, &size);
1917:       DMPlexGetSupport(dm, v, &support);
1918:       for (s = 0; s < size; ++s) {
1919:         if (support[s] >= fMax) {
1920:           supportRef[s] = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (support[s] - fMax);
1921:         } else {
1922:           PetscInt r = 0;

1924:           DMPlexGetCone(dm, support[s], &cone);
1925:           if (cone[1] == v) r = 1;
1926:           supportRef[s] = fStartNew + (support[s] - fStart)*2 + r;
1927:         }
1928:       }
1929:       DMPlexSetSupport(rdm, newp, supportRef);
1930: #if 1
1931:       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
1932:       for (p = 0; p < size; ++p) {
1933:         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);
1934:       }
1935: #endif
1936:     }
1937:     /* Face vertices have 2 + (2 interior, 1 hybrid) supports */
1938:     for (f = fStart; f < fMax; ++f) {
1939:       const PetscInt  newp = vStartNew + (vEnd - vStart) + (f - fStart);
1940:       const PetscInt *cone, *support;
1941:       PetscInt        size, newSize = 2, s;

1943:       DMPlexGetSupportSize(dm, f, &size);
1944:       DMPlexGetSupport(dm, f, &support);
1945:       supportRef[0] = fStartNew + (f - fStart)*2 + 0;
1946:       supportRef[1] = fStartNew + (f - fStart)*2 + 1;
1947:       for (s = 0; s < size; ++s) {
1948:         PetscInt r = 0;

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

1954:           newSize += 1;
1955:         } else {
1956:           if      (cone[1] == f) r = 1;
1957:           else if (cone[2] == f) r = 2;
1958:           supportRef[newSize+0] = fStartNew + (fMax - fStart)*2 + (support[s] - cStart)*3 + (r+2)%3;
1959:           supportRef[newSize+1] = fStartNew + (fMax - fStart)*2 + (support[s] - cStart)*3 + r;

1961:           newSize += 2;
1962:         }
1963:       }
1964:       DMPlexSetSupport(rdm, newp, supportRef);
1965: #if 1
1966:       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
1967:       for (p = 0; p < newSize; ++p) {
1968:         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);
1969:       }
1970: #endif
1971:     }
1972:     PetscFree(supportRef);
1973:     break;
1974:   case REFINER_HYBRID_HEX_2D:
1975:     /* Hybrid Hex 2D */
1976:     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
1977:     cMax = PetscMin(cEnd, cMax);
1978:     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
1979:     fMax = PetscMin(fEnd, fMax);
1980:     DMPlexGetHybridBounds(rdm, &cMaxNew, &fMaxNew, NULL, NULL);
1981:     /* Interior cells have 4 faces */
1982:     for (c = cStart; c < cMax; ++c) {
1983:       const PetscInt  newp = cStartNew + (c - cStart)*4;
1984:       const PetscInt *cone, *ornt;
1985:       PetscInt        coneNew[4], orntNew[4];

1987:       DMPlexGetCone(dm, c, &cone);
1988:       DMPlexGetConeOrientation(dm, c, &ornt);
1989:       /* A quad */
1990:       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
1991:       orntNew[0] = ornt[0];
1992:       coneNew[1] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*4 + 0;
1993:       orntNew[1] = 0;
1994:       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*4 + 3;
1995:       orntNew[2] = -2;
1996:       coneNew[3] = fStartNew + (cone[3] - fStart)*2 + (ornt[3] < 0 ? 0 : 1);
1997:       orntNew[3] = ornt[3];
1998:       DMPlexSetCone(rdm, newp+0, coneNew);
1999:       DMPlexSetConeOrientation(rdm, newp+0, orntNew);
2000: #if 1
2001:       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);
2002:       for (p = 0; p < 4; ++p) {
2003:         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);
2004:       }
2005: #endif
2006:       /* B quad */
2007:       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
2008:       orntNew[0] = ornt[0];
2009:       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
2010:       orntNew[1] = ornt[1];
2011:       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*4 + 1;
2012:       orntNew[2] = 0;
2013:       coneNew[3] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*4 + 0;
2014:       orntNew[3] = -2;
2015:       DMPlexSetCone(rdm, newp+1, coneNew);
2016:       DMPlexSetConeOrientation(rdm, newp+1, orntNew);
2017: #if 1
2018:       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);
2019:       for (p = 0; p < 4; ++p) {
2020:         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);
2021:       }
2022: #endif
2023:       /* C quad */
2024:       coneNew[0] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*4 + 1;
2025:       orntNew[0] = -2;
2026:       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
2027:       orntNew[1] = ornt[1];
2028:       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
2029:       orntNew[2] = ornt[2];
2030:       coneNew[3] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*4 + 2;
2031:       orntNew[3] = 0;
2032:       DMPlexSetCone(rdm, newp+2, coneNew);
2033:       DMPlexSetConeOrientation(rdm, newp+2, orntNew);
2034: #if 1
2035:       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);
2036:       for (p = 0; p < 4; ++p) {
2037:         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);
2038:       }
2039: #endif
2040:       /* D quad */
2041:       coneNew[0] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*4 + 3;
2042:       orntNew[0] = 0;
2043:       coneNew[1] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*4 + 2;
2044:       orntNew[1] = -2;
2045:       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
2046:       orntNew[2] = ornt[2];
2047:       coneNew[3] = fStartNew + (cone[3] - fStart)*2 + (ornt[3] < 0 ? 1 : 0);
2048:       orntNew[3] = ornt[3];
2049:       DMPlexSetCone(rdm, newp+3, coneNew);
2050:       DMPlexSetConeOrientation(rdm, newp+3, orntNew);
2051: #if 1
2052:       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);
2053:       for (p = 0; p < 4; ++p) {
2054:         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);
2055:       }
2056: #endif
2057:     }
2058:     /*
2059:      2----3----3
2060:      |         |
2061:      |    B    |
2062:      |         |
2063:      0----4--- 1
2064:      |         |
2065:      |    A    |
2066:      |         |
2067:      0----2----1
2068:      */
2069:     /* Hybrid cells have 4 faces */
2070:     for (c = cMax; c < cEnd; ++c) {
2071:       const PetscInt  newp = cStartNew + (cMax - cStart)*4 + (c - cMax)*2;
2072:       const PetscInt *cone, *ornt;
2073:       PetscInt        coneNew[4], orntNew[4];

2075:       DMPlexGetCone(dm, c, &cone);
2076:       DMPlexGetConeOrientation(dm, c, &ornt);
2077:       /* A quad */
2078:       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
2079:       orntNew[0] = ornt[0];
2080:       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
2081:       orntNew[1] = ornt[1];
2082:       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*4 + (cone[2] - fMax);
2083:       orntNew[2] = 0;
2084:       coneNew[3] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*4 + (fEnd    - fMax) + (c - cMax);
2085:       orntNew[3] = 0;
2086:       DMPlexSetCone(rdm, newp+0, coneNew);
2087:       DMPlexSetConeOrientation(rdm, newp+0, orntNew);
2088: #if 1
2089:       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);
2090:       for (p = 0; p < 4; ++p) {
2091:         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);
2092:       }
2093: #endif
2094:       /* B quad */
2095:       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
2096:       orntNew[0] = ornt[0];
2097:       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
2098:       orntNew[1] = ornt[1];
2099:       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*4 + (fEnd    - fMax) + (c - cMax);
2100:       orntNew[2] = 0;
2101:       coneNew[3] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*4 + (cone[3] - fMax);
2102:       orntNew[3] = 0;
2103:       DMPlexSetCone(rdm, newp+1, coneNew);
2104:       DMPlexSetConeOrientation(rdm, newp+1, orntNew);
2105: #if 1
2106:       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);
2107:       for (p = 0; p < 4; ++p) {
2108:         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);
2109:       }
2110: #endif
2111:     }
2112:     /* Interior split faces have 2 vertices and the same cells as the parent */
2113:     DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);
2114:     PetscMalloc1(2 + maxSupportSize*2, &supportRef);
2115:     for (f = fStart; f < fMax; ++f) {
2116:       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);

2118:       for (r = 0; r < 2; ++r) {
2119:         const PetscInt  newp = fStartNew + (f - fStart)*2 + r;
2120:         const PetscInt *cone, *ornt, *support;
2121:         PetscInt        coneNew[2], coneSize, c, supportSize, s;

2123:         DMPlexGetCone(dm, f, &cone);
2124:         coneNew[0]       = vStartNew + (cone[0] - vStart);
2125:         coneNew[1]       = vStartNew + (cone[1] - vStart);
2126:         coneNew[(r+1)%2] = newv;
2127:         DMPlexSetCone(rdm, newp, coneNew);
2128: #if 1
2129:         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2130:         for (p = 0; p < 2; ++p) {
2131:           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);
2132:         }
2133: #endif
2134:         DMPlexGetSupportSize(dm, f, &supportSize);
2135:         DMPlexGetSupport(dm, f, &support);
2136:         for (s = 0; s < supportSize; ++s) {
2137:           if (support[s] >= cMax) {
2138:             supportRef[s] = cStartNew + (cMax - cStart)*4 + (support[s] - cMax)*2 + r;
2139:           } else {
2140:             DMPlexGetConeSize(dm, support[s], &coneSize);
2141:             DMPlexGetCone(dm, support[s], &cone);
2142:             DMPlexGetConeOrientation(dm, support[s], &ornt);
2143:             for (c = 0; c < coneSize; ++c) {
2144:               if (cone[c] == f) break;
2145:             }
2146:             supportRef[s] = cStartNew + (support[s] - cStart)*4 + (ornt[c] < 0 ? (c+1-r)%4 : (c+r)%4);
2147:           }
2148:         }
2149:         DMPlexSetSupport(rdm, newp, supportRef);
2150: #if 1
2151:         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2152:         for (p = 0; p < supportSize; ++p) {
2153:           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);
2154:         }
2155: #endif
2156:       }
2157:     }
2158:     /* Interior cell faces have 2 vertices and 2 cells */
2159:     for (c = cStart; c < cMax; ++c) {
2160:       const PetscInt *cone;

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

2167:         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r] - fStart);
2168:         coneNew[1] = vStartNew + (vEnd - vStart) + (fMax    - fStart) + (c - cStart);
2169:         DMPlexSetCone(rdm, newp, coneNew);
2170: #if 1
2171:         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2172:         for (p = 0; p < 2; ++p) {
2173:           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);
2174:         }
2175: #endif
2176:         supportNew[0] = (c - cStart)*4 + r;
2177:         supportNew[1] = (c - cStart)*4 + (r+1)%4;
2178:         DMPlexSetSupport(rdm, newp, supportNew);
2179: #if 1
2180:         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2181:         for (p = 0; p < 2; ++p) {
2182:           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);
2183:         }
2184: #endif
2185:       }
2186:     }
2187:     /* Hybrid faces have 2 vertices and the same cells */
2188:     for (f = fMax; f < fEnd; ++f) {
2189:       const PetscInt  newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*4 + (f - fMax);
2190:       const PetscInt *cone, *support;
2191:       PetscInt        coneNew[2], supportNew[2];
2192:       PetscInt        size, s, r;

2194:       DMPlexGetCone(dm, f, &cone);
2195:       coneNew[0] = vStartNew + (cone[0] - vStart);
2196:       coneNew[1] = vStartNew + (cone[1] - vStart);
2197:       DMPlexSetCone(rdm, newp, coneNew);
2198: #if 1
2199:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2200:       for (p = 0; p < 2; ++p) {
2201:         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);
2202:       }
2203: #endif
2204:       DMPlexGetSupportSize(dm, f, &size);
2205:       DMPlexGetSupport(dm, f, &support);
2206:       for (s = 0; s < size; ++s) {
2207:         DMPlexGetCone(dm, support[s], &cone);
2208:         for (r = 0; r < 2; ++r) {
2209:           if (cone[r+2] == f) break;
2210:         }
2211:         supportNew[s] = (cMax - cStart)*4 + (support[s] - cMax)*2 + r;
2212:       }
2213:       DMPlexSetSupport(rdm, newp, supportNew);
2214: #if 1
2215:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2216:       for (p = 0; p < size; ++p) {
2217:         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);
2218:       }
2219: #endif
2220:     }
2221:     /* Cell hybrid faces have 2 vertices and 2 cells */
2222:     for (c = cMax; c < cEnd; ++c) {
2223:       const PetscInt  newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*4 + (fEnd - fMax) + (c - cMax);
2224:       const PetscInt *cone;
2225:       PetscInt        coneNew[2], supportNew[2];

2227:       DMPlexGetCone(dm, c, &cone);
2228:       coneNew[0] = vStartNew + (vEnd - vStart) + (cone[0] - fStart);
2229:       coneNew[1] = vStartNew + (vEnd - vStart) + (cone[1] - fStart);
2230:       DMPlexSetCone(rdm, newp, coneNew);
2231: #if 1
2232:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2233:       for (p = 0; p < 2; ++p) {
2234:         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);
2235:       }
2236: #endif
2237:       supportNew[0] = (cMax - cStart)*4 + (c - cMax)*2 + 0;
2238:       supportNew[1] = (cMax - cStart)*4 + (c - cMax)*2 + 1;
2239:       DMPlexSetSupport(rdm, newp, supportNew);
2240: #if 1
2241:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2242:       for (p = 0; p < 2; ++p) {
2243:         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);
2244:       }
2245: #endif
2246:     }
2247:     /* Old vertices have identical supports */
2248:     for (v = vStart; v < vEnd; ++v) {
2249:       const PetscInt  newp = vStartNew + (v - vStart);
2250:       const PetscInt *support, *cone;
2251:       PetscInt        size, s;

2253:       DMPlexGetSupportSize(dm, v, &size);
2254:       DMPlexGetSupport(dm, v, &support);
2255:       for (s = 0; s < size; ++s) {
2256:         if (support[s] >= fMax) {
2257:           supportRef[s] = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*4 + (support[s] - fMax);
2258:         } else {
2259:           PetscInt r = 0;

2261:           DMPlexGetCone(dm, support[s], &cone);
2262:           if (cone[1] == v) r = 1;
2263:           supportRef[s] = fStartNew + (support[s] - fStart)*2 + r;
2264:         }
2265:       }
2266:       DMPlexSetSupport(rdm, newp, supportRef);
2267: #if 1
2268:       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
2269:       for (p = 0; p < size; ++p) {
2270:         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);
2271:       }
2272: #endif
2273:     }
2274:     /* Face vertices have 2 + cells supports */
2275:     for (f = fStart; f < fMax; ++f) {
2276:       const PetscInt  newp = vStartNew + (vEnd - vStart) + (f - fStart);
2277:       const PetscInt *cone, *support;
2278:       PetscInt        size, s;

2280:       DMPlexGetSupportSize(dm, f, &size);
2281:       DMPlexGetSupport(dm, f, &support);
2282:       supportRef[0] = fStartNew + (f - fStart)*2 + 0;
2283:       supportRef[1] = fStartNew + (f - fStart)*2 + 1;
2284:       for (s = 0; s < size; ++s) {
2285:         PetscInt r = 0;

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

2310:       for (r = 0; r < 4; ++r) {
2311:         supportNew[r] = fStartNew + (fMax - fStart)*2 + (c - cStart)*4 + r;
2312:       }
2313:       DMPlexSetSupport(rdm, newp, supportNew);
2314:     }
2315:     PetscFree(supportRef);
2316:     break;
2317:   case REFINER_SIMPLEX_3D:
2318:     /* All cells have 4 faces: Tet face order is prescribed in DMPlexGetFaces_Internal() */
2319:     DMPlexGetRawFaces_Internal(dm, 3, 4, cellInd, NULL, NULL, &faces);
2320:     for (c = cStart; c < cEnd; ++c) {
2321:       const PetscInt  newp = cStartNew + (c - cStart)*8;
2322:       const PetscInt *cone, *ornt;
2323:       PetscInt        coneNew[4], orntNew[4];

2325:       DMPlexGetCone(dm, c, &cone);
2326:       DMPlexGetConeOrientation(dm, c, &ornt);
2327:       /* A tetrahedron: {0, a, c, d} */
2328:       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetTriSubface_Static(ornt[0], 0); /* A */
2329:       orntNew[0] = ornt[0];
2330:       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetTriSubface_Static(ornt[1], 0); /* A */
2331:       orntNew[1] = ornt[1];
2332:       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetTriSubface_Static(ornt[2], 0); /* A */
2333:       orntNew[2] = ornt[2];
2334:       coneNew[3] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 0;
2335:       orntNew[3] = 0;
2336:       DMPlexSetCone(rdm, newp+0, coneNew);
2337:       DMPlexSetConeOrientation(rdm, newp+0, orntNew);
2338: #if 1
2339:       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);
2340:       for (p = 0; p < 4; ++p) {
2341:         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);
2342:       }
2343: #endif
2344:       /* B tetrahedron: {a, 1, b, e} */
2345:       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetTriSubface_Static(ornt[0], 1); /* B */
2346:       orntNew[0] = ornt[0];
2347:       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetTriSubface_Static(ornt[1], 2); /* C */
2348:       orntNew[1] = ornt[1];
2349:       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 1;
2350:       orntNew[2] = 0;
2351:       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetTriSubface_Static(ornt[3], 1); /* B */
2352:       orntNew[3] = ornt[3];
2353:       DMPlexSetCone(rdm, newp+1, coneNew);
2354:       DMPlexSetConeOrientation(rdm, newp+1, orntNew);
2355: #if 1
2356:       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);
2357:       for (p = 0; p < 4; ++p) {
2358:         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);
2359:       }
2360: #endif
2361:       /* C tetrahedron: {c, b, 2, f} */
2362:       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetTriSubface_Static(ornt[0], 2); /* C */
2363:       orntNew[0] = ornt[0];
2364:       coneNew[1] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 2;
2365:       orntNew[1] = 0;
2366:       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetTriSubface_Static(ornt[2], 1); /* B */
2367:       orntNew[2] = ornt[2];
2368:       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetTriSubface_Static(ornt[3], 0); /* A */
2369:       orntNew[3] = ornt[3];
2370:       DMPlexSetCone(rdm, newp+2, coneNew);
2371:       DMPlexSetConeOrientation(rdm, newp+2, orntNew);
2372: #if 1
2373:       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);
2374:       for (p = 0; p < 4; ++p) {
2375:         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);
2376:       }
2377: #endif
2378:       /* D tetrahedron: {d, e, f, 3} */
2379:       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 3;
2380:       orntNew[0] = 0;
2381:       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetTriSubface_Static(ornt[1], 1); /* B */
2382:       orntNew[1] = ornt[1];
2383:       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetTriSubface_Static(ornt[2], 2); /* C */
2384:       orntNew[2] = ornt[2];
2385:       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetTriSubface_Static(ornt[3], 2); /* C */
2386:       orntNew[3] = ornt[3];
2387:       DMPlexSetCone(rdm, newp+3, coneNew);
2388:       DMPlexSetConeOrientation(rdm, newp+3, orntNew);
2389: #if 1
2390:       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);
2391:       for (p = 0; p < 4; ++p) {
2392:         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);
2393:       }
2394: #endif
2395:       /* A' tetrahedron: {c, d, a, f} */
2396:       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 0;
2397:       orntNew[0] = -3;
2398:       coneNew[1] = fStartNew + (cone[2] - fStart)*4 + 3;
2399:       orntNew[1] = ornt[2] < 0 ? -(GetTetSomething_Static(ornt[2], 0)+1) : GetTetSomething_Static(ornt[2], 0);
2400:       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 5;
2401:       orntNew[2] = 0;
2402:       coneNew[3] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 4;
2403:       orntNew[3] = 2;
2404:       DMPlexSetCone(rdm, newp+4, coneNew);
2405:       DMPlexSetConeOrientation(rdm, newp+4, orntNew);
2406: #if 1
2407:       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);
2408:       for (p = 0; p < 4; ++p) {
2409:         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);
2410:       }
2411: #endif
2412:       /* B' tetrahedron: {e, b, a, f} */
2413:       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 1;
2414:       orntNew[0] = -2;
2415:       coneNew[1] = fStartNew + (cone[3] - fStart)*4 + 3;
2416:       orntNew[1] = ornt[3] < 0 ? -(GetTetSomething_Static(ornt[3], 1)+1) : GetTetSomething_Static(ornt[3], 1);
2417:       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 6;
2418:       orntNew[2] = 0;
2419:       coneNew[3] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 7;
2420:       orntNew[3] = 0;
2421:       DMPlexSetCone(rdm, newp+5, coneNew);
2422:       DMPlexSetConeOrientation(rdm, newp+5, orntNew);
2423: #if 1
2424:       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);
2425:       for (p = 0; p < 4; ++p) {
2426:         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);
2427:       }
2428: #endif
2429:       /* C' tetrahedron: {f, a, c, b} */
2430:       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 5;
2431:       orntNew[0] = -2;
2432:       coneNew[1] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 7;
2433:       orntNew[1] = -2;
2434:       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 2;
2435:       orntNew[2] = -1;
2436:       coneNew[3] = fStartNew + (cone[0] - fStart)*4 + 3;
2437:       orntNew[3] = ornt[0] < 0 ? -(GetTetSomething_Static(ornt[0], 2)+1) : GetTetSomething_Static(ornt[0], 2);
2438:       DMPlexSetCone(rdm, newp+6, coneNew);
2439:       DMPlexSetConeOrientation(rdm, newp+6, orntNew);
2440: #if 1
2441:       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);
2442:       for (p = 0; p < 4; ++p) {
2443:         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);
2444:       }
2445: #endif
2446:       /* D' tetrahedron: {f, a, e, d} */
2447:       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 6;
2448:       orntNew[0] = -2;
2449:       coneNew[1] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 4;
2450:       orntNew[1] = -1;
2451:       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 3;
2452:       orntNew[2] = -2;
2453:       coneNew[3] = fStartNew + (cone[1] - fStart)*4 + 3;
2454:       orntNew[3] = ornt[1] < 0 ? -(GetTetSomething_Static(ornt[1], 1)+1) : GetTetSomething_Static(ornt[1], 1);
2455:       DMPlexSetCone(rdm, newp+7, coneNew);
2456:       DMPlexSetConeOrientation(rdm, newp+7, orntNew);
2457: #if 1
2458:       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);
2459:       for (p = 0; p < 4; ++p) {
2460:         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);
2461:       }
2462: #endif
2463:     }
2464:     /* Split faces have 3 edges and the same cells as the parent */
2465:     DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);
2466:     PetscMalloc1(2 + maxSupportSize*2, &supportRef);
2467:     for (f = fStart; f < fEnd; ++f) {
2468:       const PetscInt  newp = fStartNew + (f - fStart)*4;
2469:       const PetscInt *cone, *ornt, *support;
2470:       PetscInt        coneNew[3], orntNew[3], coneSize, supportSize, s;

2472:       DMPlexGetCone(dm, f, &cone);
2473:       DMPlexGetConeOrientation(dm, f, &ornt);
2474:       /* A triangle */
2475:       coneNew[0] = eStartNew + (cone[0] - eStart)*2 + (ornt[0] < 0 ? 1 : 0);
2476:       orntNew[0] = ornt[0];
2477:       coneNew[1] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 2;
2478:       orntNew[1] = -2;
2479:       coneNew[2] = eStartNew + (cone[2] - eStart)*2 + (ornt[2] < 0 ? 0 : 1);
2480:       orntNew[2] = ornt[2];
2481:       DMPlexSetCone(rdm, newp+0, coneNew);
2482:       DMPlexSetConeOrientation(rdm, newp+0, orntNew);
2483: #if 1
2484:       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);
2485:       for (p = 0; p < 3; ++p) {
2486:         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);
2487:       }
2488: #endif
2489:       /* B triangle */
2490:       coneNew[0] = eStartNew + (cone[0] - eStart)*2 + (ornt[0] < 0 ? 0 : 1);
2491:       orntNew[0] = ornt[0];
2492:       coneNew[1] = eStartNew + (cone[1] - eStart)*2 + (ornt[1] < 0 ? 1 : 0);
2493:       orntNew[1] = ornt[1];
2494:       coneNew[2] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 0;
2495:       orntNew[2] = -2;
2496:       DMPlexSetCone(rdm, newp+1, coneNew);
2497:       DMPlexSetConeOrientation(rdm, newp+1, orntNew);
2498: #if 1
2499:       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);
2500:       for (p = 0; p < 3; ++p) {
2501:         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);
2502:       }
2503: #endif
2504:       /* C triangle */
2505:       coneNew[0] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 1;
2506:       orntNew[0] = -2;
2507:       coneNew[1] = eStartNew + (cone[1] - eStart)*2 + (ornt[1] < 0 ? 0 : 1);
2508:       orntNew[1] = ornt[1];
2509:       coneNew[2] = eStartNew + (cone[2] - eStart)*2 + (ornt[2] < 0 ? 1 : 0);
2510:       orntNew[2] = ornt[2];
2511:       DMPlexSetCone(rdm, newp+2, coneNew);
2512:       DMPlexSetConeOrientation(rdm, newp+2, orntNew);
2513: #if 1
2514:       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);
2515:       for (p = 0; p < 3; ++p) {
2516:         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);
2517:       }
2518: #endif
2519:       /* D triangle */
2520:       coneNew[0] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 0;
2521:       orntNew[0] = 0;
2522:       coneNew[1] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 1;
2523:       orntNew[1] = 0;
2524:       coneNew[2] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 2;
2525:       orntNew[2] = 0;
2526:       DMPlexSetCone(rdm, newp+3, coneNew);
2527:       DMPlexSetConeOrientation(rdm, newp+3, orntNew);
2528: #if 1
2529:       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);
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:       DMPlexGetSupportSize(dm, f, &supportSize);
2535:       DMPlexGetSupport(dm, f, &support);
2536:       for (r = 0; r < 4; ++r) {
2537:         for (s = 0; s < supportSize; ++s) {
2538:           PetscInt subf;
2539:           DMPlexGetConeSize(dm, support[s], &coneSize);
2540:           DMPlexGetCone(dm, support[s], &cone);
2541:           DMPlexGetConeOrientation(dm, support[s], &ornt);
2542:           for (c = 0; c < coneSize; ++c) {
2543:             if (cone[c] == f) break;
2544:           }
2545:           subf = GetTriSubfaceInverse_Static(ornt[c], r);
2546:           supportRef[s] = cStartNew + (support[s] - cStart)*8 + (r==3 ? (c+2)%4 + 4 : faces[c*3+subf]);
2547:         }
2548:         DMPlexSetSupport(rdm, newp+r, supportRef);
2549: #if 1
2550:         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);
2551:         for (p = 0; p < supportSize; ++p) {
2552:           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);
2553:         }
2554: #endif
2555:       }
2556:     }
2557:     /* Interior faces have 3 edges and 2 cells */
2558:     for (c = cStart; c < cEnd; ++c) {
2559:       PetscInt        newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*8;
2560:       const PetscInt *cone, *ornt;
2561:       PetscInt        coneNew[3], orntNew[3];
2562:       PetscInt        supportNew[2];

2564:       DMPlexGetCone(dm, c, &cone);
2565:       DMPlexGetConeOrientation(dm, c, &ornt);
2566:       /* Face A: {c, a, d} */
2567:       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*3 + GetTetSomething_Static(ornt[0], 2);
2568:       orntNew[0] = ornt[0] < 0 ? -2 : 0;
2569:       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*3 + GetTetSomething_Static(ornt[1], 2);
2570:       orntNew[1] = ornt[1] < 0 ? -2 : 0;
2571:       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*3 + GetTetSomething_Static(ornt[2], 2);
2572:       orntNew[2] = ornt[2] < 0 ? -2 : 0;
2573:       DMPlexSetCone(rdm, newp, coneNew);
2574:       DMPlexSetConeOrientation(rdm, newp, orntNew);
2575: #if 1
2576:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2577:       for (p = 0; p < 3; ++p) {
2578:         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);
2579:       }
2580: #endif
2581:       supportNew[0] = (c - cStart)*8 + 0;
2582:       supportNew[1] = (c - cStart)*8 + 0+4;
2583:       DMPlexSetSupport(rdm, newp, supportNew);
2584: #if 1
2585:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2586:       for (p = 0; p < 2; ++p) {
2587:         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);
2588:       }
2589: #endif
2590:       ++newp;
2591:       /* Face B: {a, b, e} */
2592:       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*3 + GetTetSomething_Static(ornt[0], 0);
2593:       orntNew[0] = ornt[0] < 0 ? -2 : 0;
2594:       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*3 + GetTetSomething_Static(ornt[3], 0);
2595:       orntNew[1] = ornt[3] < 0 ? -2 : 0;
2596:       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*3 + GetTetSomething_Static(ornt[1], 1);
2597:       orntNew[2] = ornt[1] < 0 ? -2 : 0;
2598:       DMPlexSetCone(rdm, newp, coneNew);
2599:       DMPlexSetConeOrientation(rdm, newp, orntNew);
2600: #if 1
2601:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2602:       for (p = 0; p < 3; ++p) {
2603:         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);
2604:       }
2605: #endif
2606:       supportNew[0] = (c - cStart)*8 + 1;
2607:       supportNew[1] = (c - cStart)*8 + 1+4;
2608:       DMPlexSetSupport(rdm, newp, supportNew);
2609: #if 1
2610:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2611:       for (p = 0; p < 2; ++p) {
2612:         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);
2613:       }
2614: #endif
2615:       ++newp;
2616:       /* Face C: {c, f, b} */
2617:       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*3 + GetTetSomething_Static(ornt[2], 0);
2618:       orntNew[0] = ornt[2] < 0 ? -2 : 0;
2619:       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*3 + GetTetSomething_Static(ornt[3], 2);
2620:       orntNew[1] = ornt[3] < 0 ? -2 : 0;
2621:       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*3 + GetTetSomething_Static(ornt[0], 1);
2622:       orntNew[2] = ornt[0] < 0 ? -2 : 0;
2623:       DMPlexSetCone(rdm, newp, coneNew);
2624:       DMPlexSetConeOrientation(rdm, newp, orntNew);
2625: #if 1
2626:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2627:       for (p = 0; p < 3; ++p) {
2628:         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);
2629:       }
2630: #endif
2631:       supportNew[0] = (c - cStart)*8 + 2;
2632:       supportNew[1] = (c - cStart)*8 + 2+4;
2633:       DMPlexSetSupport(rdm, newp, supportNew);
2634: #if 1
2635:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2636:       for (p = 0; p < 2; ++p) {
2637:         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);
2638:       }
2639: #endif
2640:       ++newp;
2641:       /* Face D: {d, e, f} */
2642:       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*3 + GetTetSomething_Static(ornt[1], 0);
2643:       orntNew[0] = ornt[1] < 0 ? -2 : 0;
2644:       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*3 + GetTetSomething_Static(ornt[3], 1);
2645:       orntNew[1] = ornt[3] < 0 ? -2 : 0;
2646:       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*3 + GetTetSomething_Static(ornt[2], 1);
2647:       orntNew[2] = ornt[2] < 0 ? -2 : 0;
2648:       DMPlexSetCone(rdm, newp, coneNew);
2649:       DMPlexSetConeOrientation(rdm, newp, orntNew);
2650: #if 1
2651:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2652:       for (p = 0; p < 3; ++p) {
2653:         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);
2654:       }
2655: #endif
2656:       supportNew[0] = (c - cStart)*8 + 3;
2657:       supportNew[1] = (c - cStart)*8 + 3+4;
2658:       DMPlexSetSupport(rdm, newp, supportNew);
2659: #if 1
2660:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2661:       for (p = 0; p < 2; ++p) {
2662:         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);
2663:       }
2664: #endif
2665:       ++newp;
2666:       /* Face E: {d, f, a} */
2667:       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*3 + GetTetSomething_Static(ornt[2], 1);
2668:       orntNew[0] = ornt[2] < 0 ? 0 : -2;
2669:       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart);
2670:       orntNew[1] = -2;
2671:       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*3 + GetTetSomething_Static(ornt[1], 2);
2672:       orntNew[2] = ornt[1] < 0 ? -2 : 0;
2673:       DMPlexSetCone(rdm, newp, coneNew);
2674:       DMPlexSetConeOrientation(rdm, newp, orntNew);
2675: #if 1
2676:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2677:       for (p = 0; p < 3; ++p) {
2678:         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);
2679:       }
2680: #endif
2681:       supportNew[0] = (c - cStart)*8 + 0+4;
2682:       supportNew[1] = (c - cStart)*8 + 3+4;
2683:       DMPlexSetSupport(rdm, newp, supportNew);
2684: #if 1
2685:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2686:       for (p = 0; p < 2; ++p) {
2687:         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);
2688:       }
2689: #endif
2690:       ++newp;
2691:       /* Face F: {c, a, f} */
2692:       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*3 + GetTetSomething_Static(ornt[0], 2);
2693:       orntNew[0] = ornt[0] < 0 ? -2 : 0;
2694:       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart);
2695:       orntNew[1] = 0;
2696:       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*3 + GetTetSomething_Static(ornt[2], 0);
2697:       orntNew[2] = ornt[2] < 0 ? 0 : -2;
2698:       DMPlexSetCone(rdm, newp, coneNew);
2699:       DMPlexSetConeOrientation(rdm, newp, orntNew);
2700: #if 1
2701:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2702:       for (p = 0; p < 3; ++p) {
2703:         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);
2704:       }
2705: #endif
2706:       supportNew[0] = (c - cStart)*8 + 0+4;
2707:       supportNew[1] = (c - cStart)*8 + 2+4;
2708:       DMPlexSetSupport(rdm, newp, supportNew);
2709: #if 1
2710:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2711:       for (p = 0; p < 2; ++p) {
2712:         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);
2713:       }
2714: #endif
2715:       ++newp;
2716:       /* Face G: {e, a, f} */
2717:       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*3 + GetTetSomething_Static(ornt[1], 1);
2718:       orntNew[0] = ornt[1] < 0 ? -2 : 0;
2719:       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart);
2720:       orntNew[1] = 0;
2721:       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*3 + GetTetSomething_Static(ornt[3], 1);
2722:       orntNew[2] = ornt[3] < 0 ? 0 : -2;
2723:       DMPlexSetCone(rdm, newp, coneNew);
2724:       DMPlexSetConeOrientation(rdm, newp, orntNew);
2725: #if 1
2726:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2727:       for (p = 0; p < 3; ++p) {
2728:         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);
2729:       }
2730: #endif
2731:       supportNew[0] = (c - cStart)*8 + 1+4;
2732:       supportNew[1] = (c - cStart)*8 + 3+4;
2733:       DMPlexSetSupport(rdm, newp, supportNew);
2734: #if 1
2735:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2736:       for (p = 0; p < 2; ++p) {
2737:         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);
2738:       }
2739: #endif
2740:       ++newp;
2741:       /* Face H: {a, b, f} */
2742:       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*3 + GetTetSomething_Static(ornt[0], 0);
2743:       orntNew[0] = ornt[0] < 0 ? -2 : 0;
2744:       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*3 + GetTetSomething_Static(ornt[3], 2);
2745:       orntNew[1] = ornt[3] < 0 ? 0 : -2;
2746:       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart);
2747:       orntNew[2] = -2;
2748:       DMPlexSetCone(rdm, newp, coneNew);
2749:       DMPlexSetConeOrientation(rdm, newp, orntNew);
2750: #if 1
2751:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2752:       for (p = 0; p < 3; ++p) {
2753:         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);
2754:       }
2755: #endif
2756:       supportNew[0] = (c - cStart)*8 + 1+4;
2757:       supportNew[1] = (c - cStart)*8 + 2+4;
2758:       DMPlexSetSupport(rdm, newp, supportNew);
2759: #if 1
2760:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2761:       for (p = 0; p < 2; ++p) {
2762:         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);
2763:       }
2764: #endif
2765:       ++newp;
2766:     }
2767:     /* Split Edges have 2 vertices and the same faces as the parent */
2768:     for (e = eStart; e < eEnd; ++e) {
2769:       const PetscInt newv = vStartNew + (vEnd - vStart) + (e - eStart);

2771:       for (r = 0; r < 2; ++r) {
2772:         const PetscInt  newp = eStartNew + (e - eStart)*2 + r;
2773:         const PetscInt *cone, *ornt, *support;
2774:         PetscInt        coneNew[2], coneSize, c, supportSize, s;

2776:         DMPlexGetCone(dm, e, &cone);
2777:         coneNew[0]       = vStartNew + (cone[0] - vStart);
2778:         coneNew[1]       = vStartNew + (cone[1] - vStart);
2779:         coneNew[(r+1)%2] = newv;
2780:         DMPlexSetCone(rdm, newp, coneNew);
2781: #if 1
2782:         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
2783:         for (p = 0; p < 2; ++p) {
2784:           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);
2785:         }
2786: #endif
2787:         DMPlexGetSupportSize(dm, e, &supportSize);
2788:         DMPlexGetSupport(dm, e, &support);
2789:         for (s = 0; s < supportSize; ++s) {
2790:           DMPlexGetConeSize(dm, support[s], &coneSize);
2791:           DMPlexGetCone(dm, support[s], &cone);
2792:           DMPlexGetConeOrientation(dm, support[s], &ornt);
2793:           for (c = 0; c < coneSize; ++c) {
2794:             if (cone[c] == e) break;
2795:           }
2796:           supportRef[s] = fStartNew + (support[s] - fStart)*4 + (c + (ornt[c] < 0 ? 1-r : r))%3;
2797:         }
2798:         DMPlexSetSupport(rdm, newp, supportRef);
2799: #if 1
2800:         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
2801:         for (p = 0; p < supportSize; ++p) {
2802:           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);
2803:         }
2804: #endif
2805:       }
2806:     }
2807:     /* Face edges have 2 vertices and 2+cells*(1/2) faces */
2808:     for (f = fStart; f < fEnd; ++f) {
2809:       const PetscInt *cone, *ornt, *support;
2810:       PetscInt        coneSize, supportSize, s;

2812:       DMPlexGetSupportSize(dm, f, &supportSize);
2813:       DMPlexGetSupport(dm, f, &support);
2814:       for (r = 0; r < 3; ++r) {
2815:         const PetscInt  newp = eStartNew + (eEnd - eStart)*2 + (f - fStart)*3 + r;
2816:         PetscInt        coneNew[2], intFaces = 0, er, eint[4] = {1, 0, 2, 0};
2817:         PetscInt        fint[24] = { 1,  7, -1, -1,  0,  5,
2818:                                     -1, -1,  1,  6,  0,  4,
2819:                                      2,  5,  3,  4, -1, -1,
2820:                                     -1, -1,  3,  6,  2,  7};

2822:         DMPlexGetCone(dm, f, &cone);
2823:         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[(r+0)%3] - eStart);
2824:         coneNew[1] = vStartNew + (vEnd - vStart) + (cone[(r+1)%3] - eStart);
2825:         DMPlexSetCone(rdm, newp, coneNew);
2826: #if 1
2827:         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
2828:         for (p = 0; p < 2; ++p) {
2829:           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);
2830:         }
2831: #endif
2832:         supportRef[0] = fStartNew + (f - fStart)*4 + (r+1)%3;
2833:         supportRef[1] = fStartNew + (f - fStart)*4 + 3;
2834:         for (s = 0; s < supportSize; ++s) {
2835:           DMPlexGetConeSize(dm, support[s], &coneSize);
2836:           DMPlexGetCone(dm, support[s], &cone);
2837:           DMPlexGetConeOrientation(dm, support[s], &ornt);
2838:           for (c = 0; c < coneSize; ++c) {if (cone[c] == f) break;}
2839:           /* Here we want to determine whether edge newp contains a vertex which is part of the cross-tet edge */
2840:           er = GetTetSomethingInverse_Static(ornt[c], r);
2841:           if (er == eint[c]) {
2842:             supportRef[2+intFaces++] = fStartNew + (fEnd - fStart)*4 + (support[s] - cStart)*8 + (c + 2)%4;
2843:           } else {
2844:             supportRef[2+intFaces++] = fStartNew + (fEnd - fStart)*4 + (support[s] - cStart)*8 + fint[(c*3 + er)*2 + 0];
2845:             supportRef[2+intFaces++] = fStartNew + (fEnd - fStart)*4 + (support[s] - cStart)*8 + fint[(c*3 + er)*2 + 1];
2846:           }
2847:         }
2848:         DMPlexSetSupport(rdm, newp, supportRef);
2849: #if 1
2850:         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
2851:         for (p = 0; p < intFaces; ++p) {
2852:           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);
2853:         }
2854: #endif
2855:       }
2856:     }
2857:     /* Interior edges have 2 vertices and 4 faces */
2858:     for (c = cStart; c < cEnd; ++c) {
2859:       const PetscInt  newp = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart);
2860:       const PetscInt *cone, *ornt, *fcone;
2861:       PetscInt        coneNew[2], supportNew[4], find;

2863:       DMPlexGetCone(dm, c, &cone);
2864:       DMPlexGetConeOrientation(dm, c, &ornt);
2865:       DMPlexGetCone(dm, cone[0], &fcone);
2866:       find = GetTriEdge_Static(ornt[0], 0);
2867:       coneNew[0] = vStartNew + (vEnd - vStart) + (fcone[find] - eStart);
2868:       DMPlexGetCone(dm, cone[2], &fcone);
2869:       find = GetTriEdge_Static(ornt[2], 1);
2870:       coneNew[1] = vStartNew + (vEnd - vStart) + (fcone[find] - eStart);
2871:       DMPlexSetCone(rdm, newp, coneNew);
2872: #if 1
2873:       if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
2874:       for (p = 0; p < 2; ++p) {
2875:         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);
2876:       }
2877: #endif
2878:       supportNew[0] = fStartNew + (fEnd - fStart)*4 + (c - cStart)*8 + 4;
2879:       supportNew[1] = fStartNew + (fEnd - fStart)*4 + (c - cStart)*8 + 5;
2880:       supportNew[2] = fStartNew + (fEnd - fStart)*4 + (c - cStart)*8 + 6;
2881:       supportNew[3] = fStartNew + (fEnd - fStart)*4 + (c - cStart)*8 + 7;
2882:       DMPlexSetSupport(rdm, newp, supportNew);
2883: #if 1
2884:       if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
2885:       for (p = 0; p < 4; ++p) {
2886:         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);
2887:       }
2888: #endif
2889:     }
2890:     /* Old vertices have identical supports */
2891:     for (v = vStart; v < vEnd; ++v) {
2892:       const PetscInt  newp = vStartNew + (v - vStart);
2893:       const PetscInt *support, *cone;
2894:       PetscInt        size, s;

2896:       DMPlexGetSupportSize(dm, v, &size);
2897:       DMPlexGetSupport(dm, v, &support);
2898:       for (s = 0; s < size; ++s) {
2899:         PetscInt r = 0;

2901:         DMPlexGetCone(dm, support[s], &cone);
2902:         if (cone[1] == v) r = 1;
2903:         supportRef[s] = eStartNew + (support[s] - eStart)*2 + r;
2904:       }
2905:       DMPlexSetSupport(rdm, newp, supportRef);
2906: #if 1
2907:       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
2908:       for (p = 0; p < size; ++p) {
2909:         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);
2910:       }
2911: #endif
2912:     }
2913:     /* Edge vertices have 2 + face*2 + 0/1 supports */
2914:     for (e = eStart; e < eEnd; ++e) {
2915:       const PetscInt  newp = vStartNew + (vEnd - vStart) + (e - eStart);
2916:       const PetscInt *cone, *support;
2917:       PetscInt       *star = NULL, starSize, cellSize = 0, coneSize, size, s;

2919:       DMPlexGetSupportSize(dm, e, &size);
2920:       DMPlexGetSupport(dm, e, &support);
2921:       supportRef[0] = eStartNew + (e - eStart)*2 + 0;
2922:       supportRef[1] = eStartNew + (e - eStart)*2 + 1;
2923:       for (s = 0; s < size; ++s) {
2924:         PetscInt r = 0;

2926:         DMPlexGetConeSize(dm, support[s], &coneSize);
2927:         DMPlexGetCone(dm, support[s], &cone);
2928:         for (r = 0; r < coneSize; ++r) {if (cone[r] == e) break;}
2929:         supportRef[2+s*2+0] = eStartNew + (eEnd - eStart)*2 + (support[s] - fStart)*3 + (r+0)%3;
2930:         supportRef[2+s*2+1] = eStartNew + (eEnd - eStart)*2 + (support[s] - fStart)*3 + (r+2)%3;
2931:       }
2932:       DMPlexGetTransitiveClosure(dm, e, PETSC_FALSE, &starSize, &star);
2933:       for (s = 0; s < starSize*2; s += 2) {
2934:         const PetscInt *cone, *ornt;
2935:         PetscInt        e01, e23;

2937:         if ((star[s] >= cStart) && (star[s] < cEnd)) {
2938:           /* Check edge 0-1 */
2939:           DMPlexGetCone(dm, star[s], &cone);
2940:           DMPlexGetConeOrientation(dm, star[s], &ornt);
2941:           DMPlexGetCone(dm, cone[0], &cone);
2942:           e01  = cone[GetTriEdge_Static(ornt[0], 0)];
2943:           /* Check edge 2-3 */
2944:           DMPlexGetCone(dm, star[s], &cone);
2945:           DMPlexGetConeOrientation(dm, star[s], &ornt);
2946:           DMPlexGetCone(dm, cone[2], &cone);
2947:           e23  = cone[GetTriEdge_Static(ornt[2], 1)];
2948:           if ((e01 == e) || (e23 == e)) {supportRef[2+size*2+cellSize++] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (star[s] - cStart);}
2949:         }
2950:       }
2951:       DMPlexRestoreTransitiveClosure(dm, e, PETSC_FALSE, &starSize, &star);
2952:       DMPlexSetSupport(rdm, newp, supportRef);
2953: #if 1
2954:       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
2955:       for (p = 0; p < 2+size*2+cellSize; ++p) {
2956:         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);
2957:       }
2958: #endif
2959:     }
2960:     PetscFree(supportRef);
2961:     DMPlexRestoreFaces_Internal(dm, 3, cStart, NULL, NULL, &faces);
2962:     break;
2963:   case REFINER_HYBRID_SIMPLEX_3D:
2964:     DMPlexGetHybridBounds(rdm, &cMaxNew, &fMaxNew, &eMaxNew, NULL);
2965:     /* Interior cells have 4 faces: Tet face order is prescribed in DMPlexGetFaces_Internal() */
2966:     DMPlexGetRawFaces_Internal(dm, 3, 4, cellInd, NULL, NULL, &faces);
2967:     for (c = cStart; c < cMax; ++c) {
2968:       const PetscInt  newp = cStartNew + (c - cStart)*8;
2969:       const PetscInt *cone, *ornt;
2970:       PetscInt        coneNew[4], orntNew[4];

2972:       DMPlexGetCone(dm, c, &cone);
2973:       DMPlexGetConeOrientation(dm, c, &ornt);
2974:       /* A tetrahedron: {0, a, c, d} */
2975:       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetTriSubface_Static(ornt[0], 0); /* A */
2976:       orntNew[0] = ornt[0];
2977:       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetTriSubface_Static(ornt[1], 0); /* A */
2978:       orntNew[1] = ornt[1];
2979:       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetTriSubface_Static(ornt[2], 0); /* A */
2980:       orntNew[2] = ornt[2];
2981:       coneNew[3] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 0;
2982:       orntNew[3] = 0;
2983:       DMPlexSetCone(rdm, newp+0, coneNew);
2984:       DMPlexSetConeOrientation(rdm, newp+0, orntNew);
2985: #if 1
2986:       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);
2987:       for (p = 0; p < 4; ++p) {
2988:         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);
2989:       }
2990: #endif
2991:       /* B tetrahedron: {a, 1, b, e} */
2992:       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetTriSubface_Static(ornt[0], 1); /* B */
2993:       orntNew[0] = ornt[0];
2994:       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetTriSubface_Static(ornt[1], 2); /* C */
2995:       orntNew[1] = ornt[1];
2996:       coneNew[2] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 1;
2997:       orntNew[2] = 0;
2998:       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetTriSubface_Static(ornt[3], 1); /* B */
2999:       orntNew[3] = ornt[3];
3000:       DMPlexSetCone(rdm, newp+1, coneNew);
3001:       DMPlexSetConeOrientation(rdm, newp+1, orntNew);
3002: #if 1
3003:       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);
3004:       for (p = 0; p < 4; ++p) {
3005:         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);
3006:       }
3007: #endif
3008:       /* C tetrahedron: {c, b, 2, f} */
3009:       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetTriSubface_Static(ornt[0], 2); /* C */
3010:       orntNew[0] = ornt[0];
3011:       coneNew[1] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 2;
3012:       orntNew[1] = 0;
3013:       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetTriSubface_Static(ornt[2], 1); /* B */
3014:       orntNew[2] = ornt[2];
3015:       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetTriSubface_Static(ornt[3], 0); /* A */
3016:       orntNew[3] = ornt[3];
3017:       DMPlexSetCone(rdm, newp+2, coneNew);
3018:       DMPlexSetConeOrientation(rdm, newp+2, orntNew);
3019: #if 1
3020:       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);
3021:       for (p = 0; p < 4; ++p) {
3022:         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);
3023:       }
3024: #endif
3025:       /* D tetrahedron: {d, e, f, 3} */
3026:       coneNew[0] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 3;
3027:       orntNew[0] = 0;
3028:       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetTriSubface_Static(ornt[1], 1); /* B */
3029:       orntNew[1] = ornt[1];
3030:       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetTriSubface_Static(ornt[2], 2); /* C */
3031:       orntNew[2] = ornt[2];
3032:       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetTriSubface_Static(ornt[3], 2); /* C */
3033:       orntNew[3] = ornt[3];
3034:       DMPlexSetCone(rdm, newp+3, coneNew);
3035:       DMPlexSetConeOrientation(rdm, newp+3, orntNew);
3036: #if 1
3037:       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);
3038:       for (p = 0; p < 4; ++p) {
3039:         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);
3040:       }
3041: #endif
3042:       /* A' tetrahedron: {d, a, c, f} */
3043:       coneNew[0] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 0;
3044:       orntNew[0] = -3;
3045:       coneNew[1] = fStartNew + (cone[2] - fStart)*4 + 3;
3046:       orntNew[1] = ornt[2] < 0 ? -(GetTetSomething_Static(ornt[2], 0)+1) : GetTetSomething_Static(ornt[2], 0);
3047:       coneNew[2] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 5;
3048:       orntNew[2] = 0;
3049:       coneNew[3] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 4;
3050:       orntNew[3] = 2;
3051:       DMPlexSetCone(rdm, newp+4, coneNew);
3052:       DMPlexSetConeOrientation(rdm, newp+4, orntNew);
3053: #if 1
3054:       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);
3055:       for (p = 0; p < 4; ++p) {
3056:         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);
3057:       }
3058: #endif
3059:       /* B' tetrahedron: {e, b, a, f} */
3060:       coneNew[0] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 1;
3061:       orntNew[0] = -3;
3062:       coneNew[1] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 6;
3063:       orntNew[1] = 1;
3064:       coneNew[2] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 7;
3065:       orntNew[2] = 0;
3066:       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + 3;
3067:       orntNew[3] = ornt[3] < 0 ? -(GetTetSomething_Static(ornt[3], 0)+1) : GetTetSomething_Static(ornt[3], 0);
3068:       DMPlexSetCone(rdm, newp+5, coneNew);
3069:       DMPlexSetConeOrientation(rdm, newp+5, orntNew);
3070: #if 1
3071:       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);
3072:       for (p = 0; p < 4; ++p) {
3073:         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);
3074:       }
3075: #endif
3076:       /* C' tetrahedron: {b, f, c, a} */
3077:       coneNew[0] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 2;
3078:       orntNew[0] = -3;
3079:       coneNew[1] = fStartNew + (cone[0] - fStart)*4 + 3;
3080:       orntNew[1] = ornt[0] < 0 ? -(GetTetSomething_Static(ornt[0], 2)+1) : GetTetSomething_Static(ornt[0], 2);
3081:       coneNew[2] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 5;
3082:       orntNew[2] = -3;
3083:       coneNew[3] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 7;
3084:       orntNew[3] = -2;
3085:       DMPlexSetCone(rdm, newp+6, coneNew);
3086:       DMPlexSetConeOrientation(rdm, newp+6, orntNew);
3087: #if 1
3088:       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);
3089:       for (p = 0; p < 4; ++p) {
3090:         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);
3091:       }
3092: #endif
3093:       /* D' tetrahedron: {f, e, d, a} */
3094:       coneNew[0] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 3;
3095:       orntNew[0] = -3;
3096:       coneNew[1] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 4;
3097:       orntNew[1] = -3;
3098:       coneNew[2] = fStartNew + (cone[1] - fStart)*4 + 3;
3099:       orntNew[2] = ornt[1] < 0 ? -(GetTetSomething_Static(ornt[1], 0)+1) : GetTetSomething_Static(ornt[1], 0);
3100:       coneNew[3] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 6;
3101:       orntNew[3] = -3;
3102:       DMPlexSetCone(rdm, newp+7, coneNew);
3103:       DMPlexSetConeOrientation(rdm, newp+7, orntNew);
3104: #if 1
3105:       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);
3106:       for (p = 0; p < 4; ++p) {
3107:         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);
3108:       }
3109: #endif
3110:     }
3111:     /* Hybrid cells have 5 faces */
3112:     for (c = cMax; c < cEnd; ++c) {
3113:       const PetscInt  newp = cStartNew + (cMax - cStart)*8 + (c - cMax)*4;
3114:       const PetscInt *cone, *ornt, *fornt;
3115:       PetscInt        coneNew[5], orntNew[5], o, of, i;

3117:       DMPlexGetCone(dm, c, &cone);
3118:       DMPlexGetConeOrientation(dm, c, &ornt);
3119:       DMPlexGetConeOrientation(dm, cone[0], &fornt);
3120:       o = ornt[0] < 0 ? -1 : 1;
3121:       for (r = 0; r < 3; ++r) {
3122:         coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetTriSubface_Static(ornt[0], r);
3123:         orntNew[0] = ornt[0];
3124:         coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetTriSubface_Static(ornt[1], r);
3125:         orntNew[1] = ornt[1];
3126:         of = fornt[GetTriEdge_Static(ornt[0], r)]       < 0 ? -1 : 1;
3127:         i  = GetTriEdgeInverse_Static(ornt[0], r)       + 2;
3128:         coneNew[i] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (cone[2+GetTriEdge_Static(ornt[0], r)]       - fMax)*2 + (o*of < 0 ? 1 : 0);
3129:         orntNew[i] = 0;
3130:         i  = GetTriEdgeInverse_Static(ornt[0], (r+1)%3) + 2;
3131:         coneNew[i] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (c - cMax)*3 + GetTriSubface_Static(ornt[0], r);
3132:         orntNew[i] = 0;
3133:         of = fornt[GetTriEdge_Static(ornt[0], (r+2)%3)] < 0 ? -1 : 1;
3134:         i  = GetTriEdgeInverse_Static(ornt[0], (r+2)%3) + 2;
3135:         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);
3136:         orntNew[i] = 0;
3137:         DMPlexSetCone(rdm, newp+r, coneNew);
3138:         DMPlexSetConeOrientation(rdm, newp+r, orntNew);
3139: #if 1
3140:         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);
3141:         for (p = 0; p < 2; ++p) {
3142:           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);
3143:         }
3144:         for (p = 2; p < 5; ++p) {
3145:           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);
3146:         }
3147: #endif
3148:       }
3149:       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + 3;
3150:       orntNew[0] = 0;
3151:       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + 3;
3152:       orntNew[1] = 0;
3153:       coneNew[2] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (c - cMax)*3 + 1;
3154:       orntNew[2] = 0;
3155:       coneNew[3] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (c - cMax)*3 + 2;
3156:       orntNew[3] = 0;
3157:       coneNew[4] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (c - cMax)*3 + 0;
3158:       orntNew[4] = 0;
3159:       DMPlexSetCone(rdm, newp+3, coneNew);
3160:       DMPlexSetConeOrientation(rdm, newp+3, orntNew);
3161: #if 1
3162:       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);
3163:       for (p = 0; p < 2; ++p) {
3164:         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);
3165:       }
3166:       for (p = 2; p < 5; ++p) {
3167:         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);
3168:       }
3169: #endif
3170:     }
3171:     /* Split faces have 3 edges and the same cells as the parent */
3172:     DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);
3173:     PetscMalloc1(2 + maxSupportSize*2, &supportRef);
3174:     for (f = fStart; f < fMax; ++f) {
3175:       const PetscInt  newp = fStartNew + (f - fStart)*4;
3176:       const PetscInt *cone, *ornt, *support;
3177:       PetscInt        coneNew[3], orntNew[3], coneSize, supportSize, s;

3179:       DMPlexGetCone(dm, f, &cone);
3180:       DMPlexGetConeOrientation(dm, f, &ornt);
3181:       /* A triangle */
3182:       coneNew[0] = eStartNew + (cone[0] - eStart)*2 + (ornt[0] < 0 ? 1 : 0);
3183:       orntNew[0] = ornt[0];
3184:       coneNew[1] = eStartNew + (eMax    - eStart)*2 + (f - fStart)*3 + 2;
3185:       orntNew[1] = -2;
3186:       coneNew[2] = eStartNew + (cone[2] - eStart)*2 + (ornt[2] < 0 ? 0 : 1);
3187:       orntNew[2] = ornt[2];
3188:       DMPlexSetCone(rdm, newp+0, coneNew);
3189:       DMPlexSetConeOrientation(rdm, newp+0, orntNew);
3190: #if 1
3191:       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);
3192:       for (p = 0; p < 3; ++p) {
3193:         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);
3194:       }
3195: #endif
3196:       /* B triangle */
3197:       coneNew[0] = eStartNew + (cone[0] - eStart)*2 + (ornt[0] < 0 ? 0 : 1);
3198:       orntNew[0] = ornt[0];
3199:       coneNew[1] = eStartNew + (cone[1] - eStart)*2 + (ornt[1] < 0 ? 1 : 0);
3200:       orntNew[1] = ornt[1];
3201:       coneNew[2] = eStartNew + (eMax    - eStart)*2 + (f - fStart)*3 + 0;
3202:       orntNew[2] = -2;
3203:       DMPlexSetCone(rdm, newp+1, coneNew);
3204:       DMPlexSetConeOrientation(rdm, newp+1, orntNew);
3205: #if 1
3206:       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);
3207:       for (p = 0; p < 3; ++p) {
3208:         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);
3209:       }
3210: #endif
3211:       /* C triangle */
3212:       coneNew[0] = eStartNew + (eMax    - eStart)*2 + (f - fStart)*3 + 1;
3213:       orntNew[0] = -2;
3214:       coneNew[1] = eStartNew + (cone[1] - eStart)*2 + (ornt[1] < 0 ? 0 : 1);
3215:       orntNew[1] = ornt[1];
3216:       coneNew[2] = eStartNew + (cone[2] - eStart)*2 + (ornt[2] < 0 ? 1 : 0);
3217:       orntNew[2] = ornt[2];
3218:       DMPlexSetCone(rdm, newp+2, coneNew);
3219:       DMPlexSetConeOrientation(rdm, newp+2, orntNew);
3220: #if 1
3221:       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);
3222:       for (p = 0; p < 3; ++p) {
3223:         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);
3224:       }
3225: #endif
3226:       /* D triangle */
3227:       coneNew[0] = eStartNew + (eMax    - eStart)*2 + (f - fStart)*3 + 0;
3228:       orntNew[0] = 0;
3229:       coneNew[1] = eStartNew + (eMax    - eStart)*2 + (f - fStart)*3 + 1;
3230:       orntNew[1] = 0;
3231:       coneNew[2] = eStartNew + (eMax    - eStart)*2 + (f - fStart)*3 + 2;
3232:       orntNew[2] = 0;
3233:       DMPlexSetCone(rdm, newp+3, coneNew);
3234:       DMPlexSetConeOrientation(rdm, newp+3, orntNew);
3235: #if 1
3236:       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);
3237:       for (p = 0; p < 3; ++p) {
3238:         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);
3239:       }
3240: #endif
3241:       DMPlexGetSupportSize(dm, f, &supportSize);
3242:       DMPlexGetSupport(dm, f, &support);
3243:       for (r = 0; r < 4; ++r) {
3244:         for (s = 0; s < supportSize; ++s) {
3245:           PetscInt subf;
3246:           DMPlexGetConeSize(dm, support[s], &coneSize);
3247:           DMPlexGetCone(dm, support[s], &cone);
3248:           DMPlexGetConeOrientation(dm, support[s], &ornt);
3249:           for (c = 0; c < coneSize; ++c) {
3250:             if (cone[c] == f) break;
3251:           }
3252:           subf = GetTriSubfaceInverse_Static(ornt[c], r);
3253:           if (support[s] < cMax) {
3254:             supportRef[s] = cStartNew + (support[s] - cStart)*8 + (r==3 ? (c+2)%4 + 4 : faces[c*3+subf]);
3255:           } else {
3256:             supportRef[s] = cStartNew + (cMax - cStart)*8 + (support[s] - cMax)*4 + (r==3 ? r : subf);
3257:           }
3258:         }
3259:         DMPlexSetSupport(rdm, newp+r, supportRef);
3260: #if 1
3261:         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);
3262:         for (p = 0; p < supportSize; ++p) {
3263:           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);
3264:         }
3265: #endif
3266:       }
3267:     }
3268:     /* Interior cell faces have 3 edges and 2 cells */
3269:     for (c = cStart; c < cMax; ++c) {
3270:       PetscInt        newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*8;
3271:       const PetscInt *cone, *ornt;
3272:       PetscInt        coneNew[3], orntNew[3];
3273:       PetscInt        supportNew[2];

3275:       DMPlexGetCone(dm, c, &cone);
3276:       DMPlexGetConeOrientation(dm, c, &ornt);
3277:       /* Face A: {c, a, d} */
3278:       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*3 + GetTetSomething_Static(ornt[0], 2);
3279:       orntNew[0] = ornt[0] < 0 ? -2 : 0;
3280:       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*3 + GetTetSomething_Static(ornt[1], 2);
3281:       orntNew[1] = ornt[1] < 0 ? -2 : 0;
3282:       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*3 + GetTetSomething_Static(ornt[2], 2);
3283:       orntNew[2] = ornt[2] < 0 ? -2 : 0;
3284:       DMPlexSetCone(rdm, newp, coneNew);
3285:       DMPlexSetConeOrientation(rdm, newp, orntNew);
3286: #if 1
3287:       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
3288:       for (p = 0; p < 3; ++p) {
3289:         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);
3290:       }
3291: #endif
3292:       supportNew[0] = (c - cStart)*8 + 0;
3293:       supportNew[1] = (c - cStart)*8 + 0+4;
3294:       DMPlexSetSupport(rdm, newp, supportNew);
3295: #if 1
3296:       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
3297:       for (p = 0; p < 2; ++p) {
3298:         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);
3299:       }
3300: #endif
3301:       ++newp;
3302:       /* Face B: {a, b, e} */
3303:       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*3 + GetTetSomething_Static(ornt[0], 0);
3304:       orntNew[0] = ornt[0] < 0 ? -2 : 0;
3305:       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*3 + GetTetSomething_Static(ornt[3], 0);
3306:       orntNew[1] = ornt[3] < 0 ? -2 : 0;
3307:       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*3 + GetTetSomething_Static(ornt[1], 1);
3308:       orntNew[2] = ornt[1] < 0 ? -2 : 0;
3309:       DMPlexSetCone(rdm, newp, coneNew);
3310:       DMPlexSetConeOrientation(rdm, newp, orntNew);
3311: #if 1
3312:       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);
3313:       for (p = 0; p < 3; ++p) {
3314:         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);
3315:       }
3316: #endif
3317:       supportNew[0] = (c - cStart)*8 + 1;
3318:       supportNew[1] = (c - cStart)*8 + 1+4;
3319:       DMPlexSetSupport(rdm, newp, supportNew);
3320: #if 1
3321:       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
3322:       for (p = 0; p < 2; ++p) {
3323:         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);
3324:       }
3325: #endif
3326:       ++newp;
3327:       /* Face C: {c, f, b} */
3328:       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*3 + GetTetSomething_Static(ornt[2], 0);
3329:       orntNew[0] = ornt[2] < 0 ? -2 : 0;
3330:       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*3 + GetTetSomething_Static(ornt[3], 2);
3331:       orntNew[1] = ornt[3] < 0 ? -2 : 0;
3332:       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*3 + GetTetSomething_Static(ornt[0], 1);
3333:       orntNew[2] = ornt[0] < 0 ? -2 : 0;
3334:       DMPlexSetCone(rdm, newp, coneNew);
3335:       DMPlexSetConeOrientation(rdm, newp, orntNew);
3336: #if 1
3337:       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
3338:       for (p = 0; p < 3; ++p) {
3339:         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);
3340:       }
3341: #endif
3342:       supportNew[0] = (c - cStart)*8 + 2;
3343:       supportNew[1] = (c - cStart)*8 + 2+4;
3344:       DMPlexSetSupport(rdm, newp, supportNew);
3345: #if 1
3346:       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
3347:       for (p = 0; p < 2; ++p) {
3348:         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);
3349:       }
3350: #endif
3351:       ++newp;
3352:       /* Face D: {d, e, f} */
3353:       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*3 + GetTetSomething_Static(ornt[1], 0);
3354:       orntNew[0] = ornt[1] < 0 ? -2 : 0;
3355:       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*3 + GetTetSomething_Static(ornt[3], 1);
3356:       orntNew[1] = ornt[3] < 0 ? -2 : 0;
3357:       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*3 + GetTetSomething_Static(ornt[2], 1);
3358:       orntNew[2] = ornt[2] < 0 ? -2 : 0;
3359:       DMPlexSetCone(rdm, newp, coneNew);
3360:       DMPlexSetConeOrientation(rdm, newp, orntNew);
3361: #if 1
3362:       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
3363:       for (p = 0; p < 3; ++p) {
3364:         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);
3365:       }
3366: #endif
3367:       supportNew[0] = (c - cStart)*8 + 3;
3368:       supportNew[1] = (c - cStart)*8 + 3+4;
3369:       DMPlexSetSupport(rdm, newp, supportNew);
3370: #if 1
3371:       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
3372:       for (p = 0; p < 2; ++p) {
3373:         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);
3374:       }
3375: #endif
3376:       ++newp;
3377:       /* Face E: {d, f, a} */
3378:       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*3 + GetTetSomething_Static(ornt[2], 1);
3379:       orntNew[0] = ornt[2] < 0 ? 0 : -2;
3380:       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart);
3381:       orntNew[1] = -2;
3382:       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*3 + GetTetSomething_Static(ornt[1], 2);
3383:       orntNew[2] = ornt[1] < 0 ? -2 : 0;
3384:       DMPlexSetCone(rdm, newp, coneNew);
3385:       DMPlexSetConeOrientation(rdm, newp, orntNew);
3386: #if 1
3387:       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
3388:       for (p = 0; p < 3; ++p) {
3389:         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);
3390:       }
3391: #endif
3392:       supportNew[0] = (c - cStart)*8 + 0+4;
3393:       supportNew[1] = (c - cStart)*8 + 3+4;
3394:       DMPlexSetSupport(rdm, newp, supportNew);
3395: #if 1
3396:       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
3397:       for (p = 0; p < 2; ++p) {
3398:         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);
3399:       }
3400: #endif
3401:       ++newp;
3402:       /* Face F: {c, a, f} */
3403:       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*3 + GetTetSomething_Static(ornt[0], 2);
3404:       orntNew[0] = ornt[0] < 0 ? -2 : 0;
3405:       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart);
3406:       orntNew[1] = 0;
3407:       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*3 + GetTetSomething_Static(ornt[2], 0);
3408:       orntNew[2] = ornt[2] < 0 ? 0 : -2;
3409:       DMPlexSetCone(rdm, newp, coneNew);
3410:       DMPlexSetConeOrientation(rdm, newp, orntNew);
3411: #if 1
3412:       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
3413:       for (p = 0; p < 3; ++p) {
3414:         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);
3415:       }
3416: #endif
3417:       supportNew[0] = (c - cStart)*8 + 0+4;
3418:       supportNew[1] = (c - cStart)*8 + 2+4;
3419:       DMPlexSetSupport(rdm, newp, supportNew);
3420: #if 1
3421:       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
3422:       for (p = 0; p < 2; ++p) {
3423:         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);
3424:       }
3425: #endif
3426:       ++newp;
3427:       /* Face G: {e, a, f} */
3428:       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*3 + GetTetSomething_Static(ornt[1], 1);
3429:       orntNew[0] = ornt[1] < 0 ? -2 : 0;
3430:       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart);
3431:       orntNew[1] = 0;
3432:       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*3 + GetTetSomething_Static(ornt[3], 1);
3433:       orntNew[2] = ornt[3] < 0 ? 0 : -2;
3434:       DMPlexSetCone(rdm, newp, coneNew);
3435:       DMPlexSetConeOrientation(rdm, newp, orntNew);
3436: #if 1
3437:       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
3438:       for (p = 0; p < 3; ++p) {
3439:         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);
3440:       }
3441: #endif
3442:       supportNew[0] = (c - cStart)*8 + 1+4;
3443:       supportNew[1] = (c - cStart)*8 + 3+4;
3444:       DMPlexSetSupport(rdm, newp, supportNew);
3445: #if 1
3446:       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
3447:       for (p = 0; p < 2; ++p) {
3448:         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);
3449:       }
3450: #endif
3451:       ++newp;
3452:       /* Face H: {a, b, f} */
3453:       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*3 + GetTetSomething_Static(ornt[0], 0);
3454:       orntNew[0] = ornt[0] < 0 ? -2 : 0;
3455:       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*3 + GetTetSomething_Static(ornt[3], 2);
3456:       orntNew[1] = ornt[3] < 0 ? 0 : -2;
3457:       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart);
3458:       orntNew[2] = -2;
3459:       DMPlexSetCone(rdm, newp, coneNew);
3460:       DMPlexSetConeOrientation(rdm, newp, orntNew);
3461: #if 1
3462:       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
3463:       for (p = 0; p < 3; ++p) {
3464:         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);
3465:       }
3466: #endif
3467:       supportNew[0] = (c - cStart)*8 + 1+4;
3468:       supportNew[1] = (c - cStart)*8 + 2+4;
3469:       DMPlexSetSupport(rdm, newp, supportNew);
3470: #if 1
3471:       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
3472:       for (p = 0; p < 2; ++p) {
3473:         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);
3474:       }
3475: #endif
3476:       ++newp;
3477:     }
3478:     /* Hybrid split faces have 4 edges and same cells */
3479:     for (f = fMax; f < fEnd; ++f) {
3480:       const PetscInt *cone, *ornt, *support;
3481:       PetscInt        coneNew[4], orntNew[4];
3482:       PetscInt        supportNew[2], size, s, c;

3484:       DMPlexGetCone(dm, f, &cone);
3485:       DMPlexGetConeOrientation(dm, f, &ornt);
3486:       DMPlexGetSupportSize(dm, f, &size);
3487:       DMPlexGetSupport(dm, f, &support);
3488:       for (r = 0; r < 2; ++r) {
3489:         const PetscInt newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (f - fMax)*2 + r;

3491:         coneNew[0]   = eStartNew + (cone[0] - eStart)*2 + (ornt[0] < 0 ? 1-r : r);
3492:         orntNew[0]   = ornt[0];
3493:         coneNew[1]   = eStartNew + (cone[1] - eStart)*2 + (ornt[1] < 0 ? 1-r : r);
3494:         orntNew[1]   = ornt[1];
3495:         coneNew[2+r] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (cone[2+r] - eMax);
3496:         orntNew[2+r] = 0;
3497:         coneNew[3-r] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (eEnd      - eMax) + (f - fMax);
3498:         orntNew[3-r] = 0;
3499:         DMPlexSetCone(rdm, newp, coneNew);
3500:         DMPlexSetConeOrientation(rdm, newp, orntNew);
3501: #if 1
3502:         if ((newp < fMaxNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid face [%d, %d)", newp, fMaxNew, fEndNew);
3503:         for (p = 0; p < 2; ++p) {
3504:           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);
3505:         }
3506:         for (p = 2; p < 4; ++p) {
3507:           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);
3508:         }
3509: #endif
3510:         for (s = 0; s < size; ++s) {
3511:           const PetscInt *coneCell, *orntCell, *fornt;
3512:           PetscInt        o, of;

3514:           DMPlexGetCone(dm, support[s], &coneCell);
3515:           DMPlexGetConeOrientation(dm, support[s], &orntCell);
3516:           o = orntCell[0] < 0 ? -1 : 1;
3517:           for (c = 2; c < 5; ++c) if (coneCell[c] == f) break;
3518:           if (c >= 5) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Could not find face %d in cone of cell %d", f, support[s]);
3519:           DMPlexGetConeOrientation(dm, coneCell[0], &fornt);
3520:           of = fornt[c-2] < 0 ? -1 : 1;
3521:           supportNew[s] = cStartNew + (cMax - cStart)*8 + (support[s] - cMax)*4 + (GetTriEdgeInverse_Static(orntCell[0], c-2) + (o*of < 0 ? 1-r : r))%3;
3522:         }
3523:         DMPlexSetSupport(rdm, newp, supportNew);
3524: #if 1
3525:         if ((newp < fMaxNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid face [%d, %d)", newp, fMaxNew, fEndNew);
3526:         for (p = 0; p < size; ++p) {
3527:           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);
3528:         }
3529: #endif
3530:       }
3531:     }
3532:     /* Hybrid cell faces have 4 edges and 2 cells */
3533:     for (c = cMax; c < cEnd; ++c) {
3534:       PetscInt        newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (c - cMax)*3;
3535:       const PetscInt *cone, *ornt;
3536:       PetscInt        coneNew[4], orntNew[4];
3537:       PetscInt        supportNew[2];

3539:       DMPlexGetCone(dm, c, &cone);
3540:       DMPlexGetConeOrientation(dm, c, &ornt);
3541:       for (r = 0; r < 3; ++r) {
3542:         coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*3 + (r+2)%3;
3543:         orntNew[0] = 0;
3544:         coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*3 + (r+2)%3;
3545:         orntNew[1] = 0;
3546:         coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (eEnd - eMax) + (cone[2+(r+2)%3] - fMax);
3547:         orntNew[2] = 0;
3548:         coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (eEnd - eMax) + (cone[2+r]       - fMax);
3549:         orntNew[3] = 0;
3550:         DMPlexSetCone(rdm, newp+r, coneNew);
3551:         DMPlexSetConeOrientation(rdm, newp+r, orntNew);
3552: #if 1
3553:         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);
3554:         for (p = 0; p < 2; ++p) {
3555:           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);
3556:         }
3557:         for (p = 2; p < 4; ++p) {
3558:           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);
3559:         }
3560: #endif
3561:         supportNew[0] = cStartNew + (cMax - cStart)*8 + (c - cMax)*4 + GetTriSubface_Static(ornt[0], r);
3562:         supportNew[1] = cStartNew + (cMax - cStart)*8 + (c - cMax)*4 + 3;
3563:         DMPlexSetSupport(rdm, newp+r, supportNew);
3564: #if 1
3565:         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);
3566:         for (p = 0; p < 2; ++p) {
3567:           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);
3568:         }
3569: #endif
3570:       }
3571:     }
3572:     /* Interior split edges have 2 vertices and the same faces as the parent */
3573:     for (e = eStart; e < eMax; ++e) {
3574:       const PetscInt newv = vStartNew + (vEnd - vStart) + (e - eStart);

3576:       for (r = 0; r < 2; ++r) {
3577:         const PetscInt  newp = eStartNew + (e - eStart)*2 + r;
3578:         const PetscInt *cone, *ornt, *support;
3579:         PetscInt        coneNew[2], coneSize, c, supportSize, s;

3581:         DMPlexGetCone(dm, e, &cone);
3582:         coneNew[0]       = vStartNew + (cone[0] - vStart);
3583:         coneNew[1]       = vStartNew + (cone[1] - vStart);
3584:         coneNew[(r+1)%2] = newv;
3585:         DMPlexSetCone(rdm, newp, coneNew);
3586: #if 1
3587:         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
3588:         for (p = 0; p < 2; ++p) {
3589:           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);
3590:         }
3591: #endif
3592:         DMPlexGetSupportSize(dm, e, &supportSize);
3593:         DMPlexGetSupport(dm, e, &support);
3594:         for (s = 0; s < supportSize; ++s) {
3595:           DMPlexGetConeSize(dm, support[s], &coneSize);
3596:           DMPlexGetCone(dm, support[s], &cone);
3597:           DMPlexGetConeOrientation(dm, support[s], &ornt);
3598:           for (c = 0; c < coneSize; ++c) if (cone[c] == e) break;
3599:           if (support[s] < fMax) {
3600:             supportRef[s] = fStartNew + (support[s] - fStart)*4 + (c + (ornt[c] < 0 ? 1-r : r))%3;
3601:           } else {
3602:             supportRef[s] = fStartNew + (fMax       - fStart)*4 + (cMax - cStart)*8 + (support[s] - fMax)*2 + (ornt[c] < 0 ? 1-r : r);
3603:           }
3604:         }
3605:         DMPlexSetSupport(rdm, newp, supportRef);
3606: #if 1
3607:         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
3608:         for (p = 0; p < supportSize; ++p) {
3609:           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);
3610:         }
3611: #endif
3612:       }
3613:     }
3614:     /* Interior face edges have 2 vertices and 2+cells*(1/2) faces */
3615:     for (f = fStart; f < fMax; ++f) {
3616:       const PetscInt *cone, *ornt, *support;
3617:       PetscInt        coneSize, supportSize, s;

3619:       DMPlexGetSupportSize(dm, f, &supportSize);
3620:       DMPlexGetSupport(dm, f, &support);
3621:       for (r = 0; r < 3; ++r) {
3622:         const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (f - fStart)*3 + r;
3623:         PetscInt        coneNew[2], intFaces = 0, er, eint[4] = {1, 0, 2, 0};
3624:         PetscInt        fint[24] = { 1,  7, -1, -1,  0,  5,
3625:                                     -1, -1,  1,  6,  0,  4,
3626:                                      2,  5,  3,  4, -1, -1,
3627:                                     -1, -1,  3,  6,  2,  7};

3629:         DMPlexGetCone(dm, f, &cone);
3630:         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[(r+0)%3] - eStart);
3631:         coneNew[1] = vStartNew + (vEnd - vStart) + (cone[(r+1)%3] - eStart);
3632:         DMPlexSetCone(rdm, newp, coneNew);
3633: #if 1
3634:         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
3635:         for (p = 0; p < 2; ++p) {
3636:           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);
3637:         }
3638: #endif
3639:         supportRef[0] = fStartNew + (f - fStart)*4 + (r+1)%3;
3640:         supportRef[1] = fStartNew + (f - fStart)*4 + 3;
3641:         for (s = 0; s < supportSize; ++s) {
3642:           DMPlexGetConeSize(dm, support[s], &coneSize);
3643:           DMPlexGetCone(dm, support[s], &cone);
3644:           DMPlexGetConeOrientation(dm, support[s], &ornt);
3645:           for (c = 0; c < coneSize; ++c) {if (cone[c] == f) break;}
3646:           if (support[s] < cMax) {
3647:             /* Here we want to determine whether edge newp contains a vertex which is part of the cross-tet edge */
3648:             er = GetTetSomethingInverse_Static(ornt[c], r);
3649:             if (er == eint[c]) {
3650:               supportRef[2+intFaces++] = fStartNew + (fMax - fStart)*4 + (support[s] - cStart)*8 + (c + 2)%4;
3651:             } else {
3652:               supportRef[2+intFaces++] = fStartNew + (fMax - fStart)*4 + (support[s] - cStart)*8 + fint[(c*3 + er)*2 + 0];
3653:               supportRef[2+intFaces++] = fStartNew + (fMax - fStart)*4 + (support[s] - cStart)*8 + fint[(c*3 + er)*2 + 1];
3654:             }
3655:           } else {
3656:             supportRef[2+intFaces++] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (support[s] - cMax)*3 + (r + 1)%3;
3657:           }
3658:         }
3659:         DMPlexSetSupport(rdm, newp, supportRef);
3660: #if 1
3661:         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
3662:         for (p = 0; p < intFaces; ++p) {
3663:           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);
3664:         }
3665: #endif
3666:       }
3667:     }
3668:     /* Interior cell edges have 2 vertices and 4 faces */
3669:     for (c = cStart; c < cMax; ++c) {
3670:       const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart);
3671:       const PetscInt *cone, *ornt, *fcone;
3672:       PetscInt        coneNew[2], supportNew[4], find;

3674:       DMPlexGetCone(dm, c, &cone);
3675:       DMPlexGetConeOrientation(dm, c, &ornt);
3676:       DMPlexGetCone(dm, cone[0], &fcone);
3677:       find = GetTriEdge_Static(ornt[0], 0);
3678:       coneNew[0] = vStartNew + (vEnd - vStart) + (fcone[find] - eStart);
3679:       DMPlexGetCone(dm, cone[2], &fcone);
3680:       find = GetTriEdge_Static(ornt[2], 1);
3681:       coneNew[1] = vStartNew + (vEnd - vStart) + (fcone[find] - eStart);
3682:       DMPlexSetCone(rdm, newp, coneNew);
3683: #if 1
3684:       if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
3685:       for (p = 0; p < 2; ++p) {
3686:         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);
3687:       }
3688: #endif
3689:       supportNew[0] = fStartNew + (fMax - fStart)*4 + (c - cStart)*8 + 4;
3690:       supportNew[1] = fStartNew + (fMax - fStart)*4 + (c - cStart)*8 + 5;
3691:       supportNew[2] = fStartNew + (fMax - fStart)*4 + (c - cStart)*8 + 6;
3692:       supportNew[3] = fStartNew + (fMax - fStart)*4 + (c - cStart)*8 + 7;
3693:       DMPlexSetSupport(rdm, newp, supportNew);
3694: #if 1
3695:       if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
3696:       for (p = 0; p < 4; ++p) {
3697:         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);
3698:       }
3699: #endif
3700:     }
3701:     /* Hybrid edges have two vertices and the same faces */
3702:     for (e = eMax; e < eEnd; ++e) {
3703:       const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (e - eMax);
3704:       const PetscInt *cone, *support, *fcone;
3705:       PetscInt        coneNew[2], size, fsize, s;

3707:       DMPlexGetCone(dm, e, &cone);
3708:       DMPlexGetSupportSize(dm, e, &size);
3709:       DMPlexGetSupport(dm, e, &support);
3710:       coneNew[0] = vStartNew + (cone[0] - vStart);
3711:       coneNew[1] = vStartNew + (cone[1] - vStart);
3712:       DMPlexSetCone(rdm, newp, coneNew);
3713: #if 1
3714:       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid edge [%d, %d)", newp, eMaxNew, eEndNew);
3715:       for (p = 0; p < 2; ++p) {
3716:         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);
3717:       }
3718: #endif
3719:       for (s = 0; s < size; ++s) {
3720:         DMPlexGetConeSize(dm, support[s], &fsize);
3721:         DMPlexGetCone(dm, support[s], &fcone);
3722:         for (c = 0; c < fsize; ++c) if (fcone[c] == e) break;
3723:         if ((c < 2) || (c > 3)) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Edge %d not found in cone of face %d", e, support[s]);
3724:         supportRef[s] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (support[s] - fMax)*2 + c-2;
3725:       }
3726:       DMPlexSetSupport(rdm, newp, supportRef);
3727: #if 1
3728:       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid edge [%d, %d)", newp, eMaxNew, eEndNew);
3729:       for (p = 0; p < size; ++p) {
3730:         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);
3731:       }
3732: #endif
3733:     }
3734:     /* Hybrid face edges have 2 vertices and 2+2*cells faces */
3735:     for (f = fMax; f < fEnd; ++f) {
3736:       const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (eEnd - eMax) + (f - fMax);
3737:       const PetscInt *cone, *support, *ccone, *cornt;
3738:       PetscInt        coneNew[2], size, csize, s;

3740:       DMPlexGetCone(dm, f, &cone);
3741:       DMPlexGetSupportSize(dm, f, &size);
3742:       DMPlexGetSupport(dm, f, &support);
3743:       coneNew[0] = vStartNew + (vEnd - vStart) + (cone[0] - eStart);
3744:       coneNew[1] = vStartNew + (vEnd - vStart) + (cone[1] - eStart);
3745:       DMPlexSetCone(rdm, newp, coneNew);
3746: #if 1
3747:       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid edge [%d, %d)", newp, eMaxNew, eEndNew);
3748:       for (p = 0; p < 2; ++p) {
3749:         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);
3750:       }
3751: #endif
3752:       supportRef[0] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (f - fMax)*2 + 0;
3753:       supportRef[1] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (f - fMax)*2 + 1;
3754:       for (s = 0; s < size; ++s) {
3755:         DMPlexGetConeSize(dm, support[s], &csize);
3756:         DMPlexGetCone(dm, support[s], &ccone);
3757:         DMPlexGetConeOrientation(dm, support[s], &cornt);
3758:         for (c = 0; c < csize; ++c) if (ccone[c] == f) break;
3759:         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]);
3760:         supportRef[2+s*2+0] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (support[s] - cMax)*3 + c-2;
3761:         supportRef[2+s*2+1] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (support[s] - cMax)*3 + (c-1)%3;
3762:       }
3763:       DMPlexSetSupport(rdm, newp, supportRef);
3764: #if 1
3765:       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid edge [%d, %d)", newp, eMaxNew, eEndNew);
3766:       for (p = 0; p < 2+size*2; ++p) {
3767:         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);
3768:       }
3769: #endif
3770:     }
3771:     /* Interior vertices have identical supports */
3772:     for (v = vStart; v < vEnd; ++v) {
3773:       const PetscInt  newp = vStartNew + (v - vStart);
3774:       const PetscInt *support, *cone;
3775:       PetscInt        size, s;

3777:       DMPlexGetSupportSize(dm, v, &size);
3778:       DMPlexGetSupport(dm, v, &support);
3779:       for (s = 0; s < size; ++s) {
3780:         PetscInt r = 0;

3782:         DMPlexGetCone(dm, support[s], &cone);
3783:         if (cone[1] == v) r = 1;
3784:         if (support[s] < eMax) supportRef[s] = eStartNew + (support[s] - eStart)*2 + r;
3785:         else                   supportRef[s] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (support[s] - eMax);
3786:       }
3787:       DMPlexSetSupport(rdm, newp, supportRef);
3788: #if 1
3789:       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
3790:       for (p = 0; p < size; ++p) {
3791:         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);
3792:       }
3793: #endif
3794:     }
3795:     /* Interior edge vertices have 2 + interior face*2 + hybrid face + cells*0/1 supports */
3796:     for (e = eStart; e < eMax; ++e) {
3797:       const PetscInt  newp = vStartNew + (vEnd - vStart) + (e - eStart);
3798:       const PetscInt *cone, *support;
3799:       PetscInt       *star = NULL, starSize, faceSize = 0, cellSize = 0, coneSize, size, s;

3801:       DMPlexGetSupportSize(dm, e, &size);
3802:       DMPlexGetSupport(dm, e, &support);
3803:       supportRef[0] = eStartNew + (e - eStart)*2 + 0;
3804:       supportRef[1] = eStartNew + (e - eStart)*2 + 1;
3805:       for (s = 0; s < size; ++s) {
3806:         PetscInt r = 0;

3808:         if (support[s] < fMax) {
3809:           DMPlexGetConeSize(dm, support[s], &coneSize);
3810:           DMPlexGetCone(dm, support[s], &cone);
3811:           for (r = 0; r < coneSize; ++r) {if (cone[r] == e) break;}
3812:           supportRef[2+faceSize+0] = eStartNew + (eMax - eStart)*2 + (support[s] - fStart)*3 + (r+0)%3;
3813:           supportRef[2+faceSize+1] = eStartNew + (eMax - eStart)*2 + (support[s] - fStart)*3 + (r+2)%3;
3814:           faceSize += 2;
3815:         } else {
3816:           supportRef[2+faceSize+0] = eStartNew + (eMax - eStart)*2 + (fMax       - fStart)*3 + (cMax - cStart) + (eEnd - eMax) + (support[s] - fMax);
3817:           ++faceSize;
3818:         }
3819:       }
3820:       DMPlexGetTransitiveClosure(dm, e, PETSC_FALSE, &starSize, &star);
3821:       for (s = 0; s < starSize*2; s += 2) {
3822:         const PetscInt *cone, *ornt;
3823:         PetscInt        e01, e23;

3825:         if ((star[s] >= cStart) && (star[s] < cMax)) {
3826:           /* Check edge 0-1 */
3827:           DMPlexGetCone(dm, star[s], &cone);
3828:           DMPlexGetConeOrientation(dm, star[s], &ornt);
3829:           DMPlexGetCone(dm, cone[0], &cone);
3830:           e01  = cone[GetTriEdge_Static(ornt[0], 0)];
3831:           /* Check edge 2-3 */
3832:           DMPlexGetCone(dm, star[s], &cone);
3833:           DMPlexGetConeOrientation(dm, star[s], &ornt);
3834:           DMPlexGetCone(dm, cone[2], &cone);
3835:           e23  = cone[GetTriEdge_Static(ornt[2], 1)];
3836:           if ((e01 == e) || (e23 == e)) {supportRef[2+faceSize+cellSize++] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (star[s] - cStart);}
3837:         }
3838:       }
3839:       DMPlexRestoreTransitiveClosure(dm, e, PETSC_FALSE, &starSize, &star);
3840:       DMPlexSetSupport(rdm, newp, supportRef);
3841: #if 1
3842:       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
3843:       for (p = 0; p < 2+faceSize+cellSize; ++p) {
3844:         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);
3845:       }
3846: #endif
3847:     }
3848:     PetscFree(supportRef);
3849:     DMPlexRestoreFaces_Internal(dm, 3, cStart, NULL, NULL, &faces);
3850:     break;
3851:   case REFINER_HEX_3D:
3852:     /*
3853:      Bottom (viewed from top)    Top
3854:      1---------2---------2       7---------2---------6
3855:      |         |         |       |         |         |
3856:      |    B    2    C    |       |    H    2    G    |
3857:      |         |         |       |         |         |
3858:      3----3----0----1----1       3----3----0----1----1
3859:      |         |         |       |         |         |
3860:      |    A    0    D    |       |    E    0    F    |
3861:      |         |         |       |         |         |
3862:      0---------0---------3       4---------0---------5
3863:      */
3864:     /* All cells have 6 faces: Bottom, Top, Front, Back, Right, Left */
3865:     for (c = cStart; c < cEnd; ++c) {
3866:       const PetscInt  newp = (c - cStart)*8;
3867:       const PetscInt *cone, *ornt;
3868:       PetscInt        coneNew[6], orntNew[6];

3870:       DMPlexGetCone(dm, c, &cone);
3871:       DMPlexGetConeOrientation(dm, c, &ornt);
3872:       /* A hex */
3873:       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], 0);
3874:       orntNew[0] = ornt[0];
3875:       coneNew[1] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  8; /* AE */
3876:       orntNew[1] = 0;
3877:       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetQuadSubface_Static(ornt[2], 0);
3878:       orntNew[2] = ornt[2];
3879:       coneNew[3] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  3; /* AB */
3880:       orntNew[3] = 0;
3881:       coneNew[4] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  0; /* AD */
3882:       orntNew[4] = 0;
3883:       coneNew[5] = fStartNew + (cone[5] - fStart)*4 + GetQuadSubface_Static(ornt[5], 0);
3884:       orntNew[5] = ornt[5];
3885:       DMPlexSetCone(rdm, newp+0, coneNew);
3886:       DMPlexSetConeOrientation(rdm, newp+0, orntNew);
3887: #if 1
3888:       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);
3889:       for (p = 0; p < 6; ++p) {
3890:         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);
3891:       }
3892: #endif
3893:       /* B hex */
3894:       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], 1);
3895:       orntNew[0] = ornt[0];
3896:       coneNew[1] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 + 11; /* BH */
3897:       orntNew[1] = 0;
3898:       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  3; /* AB */
3899:       orntNew[2] = -1;
3900:       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetQuadSubface_Static(ornt[3], 1);
3901:       orntNew[3] = ornt[3];
3902:       coneNew[4] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  2; /* BC */
3903:       orntNew[4] = 0;
3904:       coneNew[5] = fStartNew + (cone[5] - fStart)*4 + GetQuadSubface_Static(ornt[5], 3);
3905:       orntNew[5] = ornt[5];
3906:       DMPlexSetCone(rdm, newp+1, coneNew);
3907:       DMPlexSetConeOrientation(rdm, newp+1, orntNew);
3908: #if 1
3909:       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);
3910:       for (p = 0; p < 6; ++p) {
3911:         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);
3912:       }
3913: #endif
3914:       /* C hex */
3915:       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], 2);
3916:       orntNew[0] = ornt[0];
3917:       coneNew[1] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 + 10; /* CG */
3918:       orntNew[1] = 0;
3919:       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  1; /* CD */
3920:       orntNew[2] = -1;
3921:       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetQuadSubface_Static(ornt[3], 0);
3922:       orntNew[3] = ornt[3];
3923:       coneNew[4] = fStartNew + (cone[4] - fStart)*4 + GetQuadSubface_Static(ornt[4], 1);
3924:       orntNew[4] = ornt[4];
3925:       coneNew[5] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  2; /* BC */
3926:       orntNew[5] = -4;
3927:       DMPlexSetCone(rdm, newp+2, coneNew);
3928:       DMPlexSetConeOrientation(rdm, newp+2, orntNew);
3929: #if 1
3930:       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);
3931:       for (p = 0; p < 6; ++p) {
3932:         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);
3933:       }
3934: #endif
3935:       /* D hex */
3936:       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], 3);
3937:       orntNew[0] = ornt[0];
3938:       coneNew[1] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  9; /* DF */
3939:       orntNew[1] = 0;
3940:       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetQuadSubface_Static(ornt[2], 1);
3941:       orntNew[2] = ornt[2];
3942:       coneNew[3] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  1; /* CD */
3943:       orntNew[3] = 0;
3944:       coneNew[4] = fStartNew + (cone[4] - fStart)*4 + GetQuadSubface_Static(ornt[4], 0);
3945:       orntNew[4] = ornt[4];
3946:       coneNew[5] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  0; /* AD */
3947:       orntNew[5] = -4;
3948:       DMPlexSetCone(rdm, newp+3, coneNew);
3949:       DMPlexSetConeOrientation(rdm, newp+3, orntNew);
3950: #if 1
3951:       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);
3952:       for (p = 0; p < 6; ++p) {
3953:         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);
3954:       }
3955: #endif
3956:       /* E hex */
3957:       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  8; /* AE */
3958:       orntNew[0] = -4;
3959:       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], 0);
3960:       orntNew[1] = ornt[1];
3961:       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetQuadSubface_Static(ornt[2], 3);
3962:       orntNew[2] = ornt[2];
3963:       coneNew[3] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  7; /* EH */
3964:       orntNew[3] = 0;
3965:       coneNew[4] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  4; /* EF */
3966:       orntNew[4] = -1;
3967:       coneNew[5] = fStartNew + (cone[5] - fStart)*4 + GetQuadSubface_Static(ornt[5], 1);
3968:       orntNew[5] = ornt[5];
3969:       DMPlexSetCone(rdm, newp+4, coneNew);
3970:       DMPlexSetConeOrientation(rdm, newp+4, orntNew);
3971: #if 1
3972:       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);
3973:       for (p = 0; p < 6; ++p) {
3974:         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);
3975:       }
3976: #endif
3977:       /* F hex */
3978:       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  9; /* DF */
3979:       orntNew[0] = -4;
3980:       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], 1);
3981:       orntNew[1] = ornt[1];
3982:       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetQuadSubface_Static(ornt[2], 2);
3983:       orntNew[2] = ornt[2];
3984:       coneNew[3] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  5; /* FG */
3985:       orntNew[3] = -1;
3986:       coneNew[4] = fStartNew + (cone[4] - fStart)*4 + GetQuadSubface_Static(ornt[4], 3);
3987:       orntNew[4] = ornt[4];
3988:       coneNew[5] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  4; /* EF */
3989:       orntNew[5] = 1;
3990:       DMPlexSetCone(rdm, newp+5, coneNew);
3991:       DMPlexSetConeOrientation(rdm, newp+5, orntNew);
3992: #if 1
3993:       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);
3994:       for (p = 0; p < 6; ++p) {
3995:         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);
3996:       }
3997: #endif
3998:       /* G hex */
3999:       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 + 10; /* CG */
4000:       orntNew[0] = -4;
4001:       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], 2);
4002:       orntNew[1] = ornt[1];
4003:       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  5; /* FG */
4004:       orntNew[2] = 0;
4005:       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetQuadSubface_Static(ornt[3], 3);
4006:       orntNew[3] = ornt[3];
4007:       coneNew[4] = fStartNew + (cone[4] - fStart)*4 + GetQuadSubface_Static(ornt[4], 2);
4008:       orntNew[4] = ornt[4];
4009:       coneNew[5] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  6; /* GH */
4010:       orntNew[5] = -3;
4011:       DMPlexSetCone(rdm, newp+6, coneNew);
4012:       DMPlexSetConeOrientation(rdm, newp+6, orntNew);
4013: #if 1
4014:       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);
4015:       for (p = 0; p < 6; ++p) {
4016:         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);
4017:       }
4018: #endif
4019:       /* H hex */
4020:       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 + 11; /* BH */
4021:       orntNew[0] = -4;
4022:       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], 3);
4023:       orntNew[1] = ornt[1];
4024:       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  7; /* EH */
4025:       orntNew[2] = -1;
4026:       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetQuadSubface_Static(ornt[3], 2);
4027:       orntNew[3] = ornt[3];
4028:       coneNew[4] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  6; /* GH */
4029:       orntNew[4] = 3;
4030:       coneNew[5] = fStartNew + (cone[5] - fStart)*4 + GetQuadSubface_Static(ornt[5], 2);
4031:       orntNew[5] = ornt[5];
4032:       DMPlexSetCone(rdm, newp+7, coneNew);
4033:       DMPlexSetConeOrientation(rdm, newp+7, orntNew);
4034: #if 1
4035:       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);
4036:       for (p = 0; p < 6; ++p) {
4037:         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);
4038:       }
4039: #endif
4040:     }
4041:     /* Split faces have 4 edges and the same cells as the parent */
4042:     DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);
4043:     PetscMalloc1(4 + maxSupportSize*2, &supportRef);
4044:     for (f = fStart; f < fEnd; ++f) {
4045:       for (r = 0; r < 4; ++r) {
4046:         /* TODO: This can come from GetFaces_Internal() */
4047:         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};
4048:         const PetscInt  newp = fStartNew + (f - fStart)*4 + r;
4049:         const PetscInt *cone, *ornt, *support;
4050:         PetscInt        coneNew[4], orntNew[4], coneSize, c, supportSize, s;

4052:         DMPlexGetCone(dm, f, &cone);
4053:         DMPlexGetConeOrientation(dm, f, &ornt);
4054:         coneNew[(r+3)%4] = eStartNew + (cone[(r+3)%4] - eStart)*2 + (ornt[(r+3)%4] < 0 ? 0 : 1);
4055:         orntNew[(r+3)%4] = ornt[(r+3)%4];
4056:         coneNew[(r+0)%4] = eStartNew + (cone[r]       - eStart)*2 + (ornt[r] < 0 ? 1 : 0);
4057:         orntNew[(r+0)%4] = ornt[r];
4058:         coneNew[(r+1)%4] = eStartNew + (eEnd - eStart)*2 + (f - fStart)*4 + r;
4059:         orntNew[(r+1)%4] = 0;
4060:         coneNew[(r+2)%4] = eStartNew + (eEnd - eStart)*2 + (f - fStart)*4 + (r+3)%4;
4061:         orntNew[(r+2)%4] = -2;
4062:         DMPlexSetCone(rdm, newp, coneNew);
4063:         DMPlexSetConeOrientation(rdm, newp, orntNew);
4064: #if 1
4065:         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4066:         for (p = 0; p < 4; ++p) {
4067:           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);
4068:         }
4069: #endif
4070:         DMPlexGetSupportSize(dm, f, &supportSize);
4071:         DMPlexGetSupport(dm, f, &support);
4072:         for (s = 0; s < supportSize; ++s) {
4073:           DMPlexGetConeSize(dm, support[s], &coneSize);
4074:           DMPlexGetCone(dm, support[s], &cone);
4075:           DMPlexGetConeOrientation(dm, support[s], &ornt);
4076:           for (c = 0; c < coneSize; ++c) {
4077:             if (cone[c] == f) break;
4078:           }
4079:           supportRef[s] = cStartNew + (support[s] - cStart)*8 + newCells[c*4+GetQuadSubfaceInverse_Static(ornt[c], r)];
4080:         }
4081:         DMPlexSetSupport(rdm, newp, supportRef);
4082: #if 1
4083:         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4084:         for (p = 0; p < supportSize; ++p) {
4085:           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);
4086:         }
4087: #endif
4088:       }
4089:     }
4090:     /* Interior faces have 4 edges and 2 cells */
4091:     for (c = cStart; c < cEnd; ++c) {
4092:       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};
4093:       const PetscInt *cone, *ornt;
4094:       PetscInt        newp, coneNew[4], orntNew[4], supportNew[2];

4096:       DMPlexGetCone(dm, c, &cone);
4097:       DMPlexGetConeOrientation(dm, c, &ornt);
4098:       /* A-D face */
4099:       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 0;
4100:       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*4 + GetQuadEdge_Static(ornt[0], 3);
4101:       orntNew[0] = 0;
4102:       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 0;
4103:       orntNew[1] = 0;
4104:       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 2;
4105:       orntNew[2] = -2;
4106:       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*4 + GetQuadEdge_Static(ornt[2], 0);
4107:       orntNew[3] = -2;
4108:       DMPlexSetCone(rdm, newp, coneNew);
4109:       DMPlexSetConeOrientation(rdm, newp, orntNew);
4110: #if 1
4111:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4112:       for (p = 0; p < 4; ++p) {
4113:         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);
4114:       }
4115: #endif
4116:       /* C-D face */
4117:       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 1;
4118:       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*4 + GetQuadEdge_Static(ornt[0], 2);
4119:       orntNew[0] = 0;
4120:       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 0;
4121:       orntNew[1] = 0;
4122:       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 4;
4123:       orntNew[2] = -2;
4124:       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (cone[4] - fStart)*4 + GetQuadEdge_Static(ornt[4], 0);
4125:       orntNew[3] = -2;
4126:       DMPlexSetCone(rdm, newp, coneNew);
4127:       DMPlexSetConeOrientation(rdm, newp, orntNew);
4128: #if 1
4129:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4130:       for (p = 0; p < 4; ++p) {
4131:         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);
4132:       }
4133: #endif
4134:       /* B-C face */
4135:       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 2;
4136:       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*4 + GetQuadEdge_Static(ornt[0], 1);
4137:       orntNew[0] = -2;
4138:       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*4 + GetQuadEdge_Static(ornt[3], 0);
4139:       orntNew[1] = 0;
4140:       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 3;
4141:       orntNew[2] = 0;
4142:       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 0;
4143:       orntNew[3] = -2;
4144:       DMPlexSetCone(rdm, newp, coneNew);
4145:       DMPlexSetConeOrientation(rdm, newp, orntNew);
4146: #if 1
4147:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4148:       for (p = 0; p < 4; ++p) {
4149:         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);
4150:       }
4151: #endif
4152:       /* A-B face */
4153:       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 3;
4154:       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*4 + GetQuadEdge_Static(ornt[0], 0);
4155:       orntNew[0] = -2;
4156:       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[5] - fStart)*4 + GetQuadEdge_Static(ornt[5], 3);
4157:       orntNew[1] = 0;
4158:       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 5;
4159:       orntNew[2] = 0;
4160:       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 0;
4161:       orntNew[3] = -2;
4162:       DMPlexSetCone(rdm, newp, coneNew);
4163:       DMPlexSetConeOrientation(rdm, newp, orntNew);
4164: #if 1
4165:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4166:       for (p = 0; p < 4; ++p) {
4167:         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);
4168:       }
4169: #endif
4170:       /* E-F face */
4171:       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 4;
4172:       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 2;
4173:       orntNew[0] = -2;
4174:       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*4 + GetQuadEdge_Static(ornt[2], 2);
4175:       orntNew[1] = -2;
4176:       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*4 + GetQuadEdge_Static(ornt[1], 0);
4177:       orntNew[2] = 0;
4178:       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 1;
4179:       orntNew[3] = 0;
4180:       DMPlexSetCone(rdm, newp, coneNew);
4181:       DMPlexSetConeOrientation(rdm, newp, orntNew);
4182: #if 1
4183:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4184:       for (p = 0; p < 4; ++p) {
4185:         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);
4186:       }
4187: #endif
4188:       /* F-G face */
4189:       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 5;
4190:       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 4;
4191:       orntNew[0] = -2;
4192:       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[4] - fStart)*4 + GetQuadEdge_Static(ornt[4], 2);
4193:       orntNew[1] = -2;
4194:       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*4 + GetQuadEdge_Static(ornt[1], 1);
4195:       orntNew[2] = 0;
4196:       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 1;
4197:       orntNew[3] = 0;
4198:       DMPlexSetCone(rdm, newp, coneNew);
4199:       DMPlexSetConeOrientation(rdm, newp, orntNew);
4200: #if 1
4201:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4202:       for (p = 0; p < 4; ++p) {
4203:         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);
4204:       }
4205: #endif
4206:       /* G-H face */
4207:       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 6;
4208:       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*4 + GetQuadEdge_Static(ornt[3], 2);
4209:       orntNew[0] = -2;
4210:       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*4 + GetQuadEdge_Static(ornt[1], 2);
4211:       orntNew[1] = 0;
4212:       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 1;
4213:       orntNew[2] = 0;
4214:       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 3;
4215:       orntNew[3] = -2;
4216:       DMPlexSetCone(rdm, newp, coneNew);
4217:       DMPlexSetConeOrientation(rdm, newp, orntNew);
4218: #if 1
4219:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4220:       for (p = 0; p < 4; ++p) {
4221:         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);
4222:       }
4223: #endif
4224:       /* E-H face */
4225:       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 7;
4226:       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 5;
4227:       orntNew[0] = -2;
4228:       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[5] - fStart)*4 + GetQuadEdge_Static(ornt[5], 1);
4229:       orntNew[1] = -2;
4230:       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*4 + GetQuadEdge_Static(ornt[1], 3);
4231:       orntNew[2] = 0;
4232:       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 1;
4233:       orntNew[3] = 0;
4234:       DMPlexSetCone(rdm, newp, coneNew);
4235:       DMPlexSetConeOrientation(rdm, newp, orntNew);
4236: #if 1
4237:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4238:       for (p = 0; p < 4; ++p) {
4239:         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);
4240:       }
4241: #endif
4242:       /* A-E face */
4243:       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 8;
4244:       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*4 + GetQuadEdge_Static(ornt[2], 3);
4245:       orntNew[0] = 0;
4246:       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 2;
4247:       orntNew[1] = 0;
4248:       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 5;
4249:       orntNew[2] = -2;
4250:       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (cone[5] - fStart)*4 + GetQuadEdge_Static(ornt[5], 0);
4251:       orntNew[3] = -2;
4252:       DMPlexSetCone(rdm, newp, coneNew);
4253:       DMPlexSetConeOrientation(rdm, newp, orntNew);
4254: #if 1
4255:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4256:       for (p = 0; p < 4; ++p) {
4257:         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);
4258:       }
4259: #endif
4260:       /* D-F face */
4261:       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 9;
4262:       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*4 + GetQuadEdge_Static(ornt[2], 1);
4263:       orntNew[0] = -2;
4264:       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[4] - fStart)*4 + GetQuadEdge_Static(ornt[4], 3);
4265:       orntNew[1] = 0;
4266:       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 4;
4267:       orntNew[2] = 0;
4268:       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 2;
4269:       orntNew[3] = -2;
4270:       DMPlexSetCone(rdm, newp, coneNew);
4271:       DMPlexSetConeOrientation(rdm, newp, orntNew);
4272: #if 1
4273:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4274:       for (p = 0; p < 4; ++p) {
4275:         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);
4276:       }
4277: #endif
4278:       /* C-G face */
4279:       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 10;
4280:       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 4;
4281:       orntNew[0] = -2;
4282:       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[4] - fStart)*4 + GetQuadEdge_Static(ornt[4], 1);
4283:       orntNew[1] = -2;
4284:       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*4 + GetQuadEdge_Static(ornt[3], 3);
4285:       orntNew[2] = 0;
4286:       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 3;
4287:       orntNew[3] = 0;
4288:       DMPlexSetCone(rdm, newp, coneNew);
4289:       DMPlexSetConeOrientation(rdm, newp, orntNew);
4290: #if 1
4291:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4292:       for (p = 0; p < 4; ++p) {
4293:         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);
4294:       }
4295: #endif
4296:       /* B-H face */
4297:       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 11;
4298:       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 5;
4299:       orntNew[0] = 0;
4300:       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 3;
4301:       orntNew[1] = -2;
4302:       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*4 + GetQuadEdge_Static(ornt[3], 1);
4303:       orntNew[2] = -2;
4304:       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (cone[5] - fStart)*4 + GetQuadEdge_Static(ornt[5], 2);
4305:       orntNew[3] = 0;
4306:       DMPlexSetCone(rdm, newp, coneNew);
4307:       DMPlexSetConeOrientation(rdm, newp, orntNew);
4308: #if 1
4309:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4310:       for (p = 0; p < 4; ++p) {
4311:         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);
4312:       }
4313: #endif
4314:       for (r = 0; r < 12; ++r) {
4315:         newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + r;
4316:         supportNew[0] = cStartNew + (c - cStart)*8 + newCells[r*2+0];
4317:         supportNew[1] = cStartNew + (c - cStart)*8 + newCells[r*2+1];
4318:         DMPlexSetSupport(rdm, newp, supportNew);
4319: #if 1
4320:         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4321:         for (p = 0; p < 2; ++p) {
4322:           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);
4323:         }
4324: #endif
4325:       }
4326:     }
4327:     /* Split edges have 2 vertices and the same faces as the parent */
4328:     DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);
4329:     for (e = eStart; e < eEnd; ++e) {
4330:       const PetscInt newv = vStartNew + (vEnd - vStart) + (e - eStart);

4332:       for (r = 0; r < 2; ++r) {
4333:         const PetscInt  newp = eStartNew + (e - eStart)*2 + r;
4334:         const PetscInt *cone, *ornt, *support;
4335:         PetscInt        coneNew[2], coneSize, c, supportSize, s;

4337:         DMPlexGetCone(dm, e, &cone);
4338:         coneNew[0]       = vStartNew + (cone[0] - vStart);
4339:         coneNew[1]       = vStartNew + (cone[1] - vStart);
4340:         coneNew[(r+1)%2] = newv;
4341:         DMPlexSetCone(rdm, newp, coneNew);
4342: #if 1
4343:         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
4344:         for (p = 0; p < 2; ++p) {
4345:           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);
4346:         }
4347: #endif
4348:         DMPlexGetSupportSize(dm, e, &supportSize);
4349:         DMPlexGetSupport(dm, e, &support);
4350:         for (s = 0; s < supportSize; ++s) {
4351:           DMPlexGetConeSize(dm, support[s], &coneSize);
4352:           DMPlexGetCone(dm, support[s], &cone);
4353:           DMPlexGetConeOrientation(dm, support[s], &ornt);
4354:           for (c = 0; c < coneSize; ++c) {
4355:             if (cone[c] == e) break;
4356:           }
4357:           supportRef[s] = fStartNew + (support[s] - fStart)*4 + (ornt[c] < 0 ? (c+1-r)%4 : (c+r)%4);
4358:         }
4359:         DMPlexSetSupport(rdm, newp, supportRef);
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 < supportSize; ++p) {
4363:           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);
4364:         }
4365: #endif
4366:       }
4367:     }
4368:     /* Face edges have 2 vertices and 2+cells faces */
4369:     for (f = fStart; f < fEnd; ++f) {
4370:       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};
4371:       const PetscInt  newv = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (f - fStart);
4372:       const PetscInt *cone, *coneCell, *orntCell, *support;
4373:       PetscInt        coneNew[2], coneSize, c, supportSize, s;

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

4379:         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r] - eStart);
4380:         coneNew[1] = newv;
4381:         DMPlexSetCone(rdm, newp, coneNew);
4382: #if 1
4383:         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
4384:         for (p = 0; p < 2; ++p) {
4385:           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);
4386:         }
4387: #endif
4388:         DMPlexGetSupportSize(dm, f, &supportSize);
4389:         DMPlexGetSupport(dm, f, &support);
4390:         supportRef[0] = fStartNew + (f - fStart)*4 + r;
4391:         supportRef[1] = fStartNew + (f - fStart)*4 + (r+1)%4;
4392:         for (s = 0; s < supportSize; ++s) {
4393:           DMPlexGetConeSize(dm, support[s], &coneSize);
4394:           DMPlexGetCone(dm, support[s], &coneCell);
4395:           DMPlexGetConeOrientation(dm, support[s], &orntCell);
4396:           for (c = 0; c < coneSize; ++c) if (coneCell[c] == f) break;
4397:           supportRef[2+s] = fStartNew + (fEnd - fStart)*4 + (support[s] - cStart)*12 + newFaces[c*4 + GetQuadEdgeInverse_Static(orntCell[c], r)];
4398:         }
4399:         DMPlexSetSupport(rdm, newp, supportRef);
4400: #if 1
4401:         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
4402:         for (p = 0; p < 2+supportSize; ++p) {
4403:           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);
4404:         }
4405: #endif
4406:       }
4407:     }
4408:     /* Cell edges have 2 vertices and 4 faces */
4409:     for (c = cStart; c < cEnd; ++c) {
4410:       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};
4411:       const PetscInt  newv = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (fEnd - fStart) + (c - cStart);
4412:       const PetscInt *cone;
4413:       PetscInt        coneNew[2], supportNew[4];

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

4419:         coneNew[0] = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (cone[r] - fStart);
4420:         coneNew[1] = newv;
4421:         DMPlexSetCone(rdm, newp, coneNew);
4422: #if 1
4423:         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
4424:         for (p = 0; p < 2; ++p) {
4425:           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);
4426:         }
4427: #endif
4428:         for (f = 0; f < 4; ++f) supportNew[f] = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + newFaces[r*4+f];
4429:         DMPlexSetSupport(rdm, newp, supportNew);
4430: #if 1
4431:         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
4432:         for (p = 0; p < 4; ++p) {
4433:           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);
4434:         }
4435: #endif
4436:       }
4437:     }
4438:     /* Old vertices have identical supports */
4439:     for (v = vStart; v < vEnd; ++v) {
4440:       const PetscInt  newp = vStartNew + (v - vStart);
4441:       const PetscInt *support, *cone;
4442:       PetscInt        size, s;

4444:       DMPlexGetSupportSize(dm, v, &size);
4445:       DMPlexGetSupport(dm, v, &support);
4446:       for (s = 0; s < size; ++s) {
4447:         PetscInt r = 0;

4449:         DMPlexGetCone(dm, support[s], &cone);
4450:         if (cone[1] == v) r = 1;
4451:         supportRef[s] = eStartNew + (support[s] - eStart)*2 + r;
4452:       }
4453:       DMPlexSetSupport(rdm, newp, supportRef);
4454: #if 1
4455:       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
4456:       for (p = 0; p < size; ++p) {
4457:         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);
4458:       }
4459: #endif
4460:     }
4461:     /* Edge vertices have 2 + faces supports */
4462:     for (e = eStart; e < eEnd; ++e) {
4463:       const PetscInt  newp = vStartNew + (vEnd - vStart) + (e - eStart);
4464:       const PetscInt *cone, *support;
4465:       PetscInt        size, s;

4467:       DMPlexGetSupportSize(dm, e, &size);
4468:       DMPlexGetSupport(dm, e, &support);
4469:       supportRef[0] = eStartNew + (e - eStart)*2 + 0;
4470:       supportRef[1] = eStartNew + (e - eStart)*2 + 1;
4471:       for (s = 0; s < size; ++s) {
4472:         PetscInt r;

4474:         DMPlexGetCone(dm, support[s], &cone);
4475:         for (r = 0; r < 4; ++r) if (cone[r] == e) break;
4476:         supportRef[2+s] = eStartNew + (eEnd - eStart)*2 + (support[s] - fStart)*4 + r;
4477:       }
4478:       DMPlexSetSupport(rdm, newp, supportRef);
4479: #if 1
4480:       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
4481:       for (p = 0; p < 2+size; ++p) {
4482:         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);
4483:       }
4484: #endif
4485:     }
4486:     /* Face vertices have 4 + cells supports */
4487:     for (f = fStart; f < fEnd; ++f) {
4488:       const PetscInt  newp = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (f - fStart);
4489:       const PetscInt *cone, *support;
4490:       PetscInt        size, s;

4492:       DMPlexGetSupportSize(dm, f, &size);
4493:       DMPlexGetSupport(dm, f, &support);
4494:       for (r = 0; r < 4; ++r) supportRef[r] = eStartNew + (eEnd - eStart)*2 +  (f - fStart)*4 + r;
4495:       for (s = 0; s < size; ++s) {
4496:         PetscInt r;

4498:         DMPlexGetCone(dm, support[s], &cone);
4499:         for (r = 0; r < 6; ++r) if (cone[r] == f) break;
4500:         supportRef[4+s] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*4 + (support[s] - cStart)*6 + r;
4501:       }
4502:       DMPlexSetSupport(rdm, newp, supportRef);
4503: #if 1
4504:       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
4505:       for (p = 0; p < 4+size; ++p) {
4506:         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);
4507:       }
4508: #endif
4509:     }
4510:     /* Cell vertices have 6 supports */
4511:     for (c = cStart; c < cEnd; ++c) {
4512:       const PetscInt newp = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (fEnd - fStart) + (c - cStart);
4513:       PetscInt       supportNew[6];

4515:       for (r = 0; r < 6; ++r) {
4516:         supportNew[r] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*4 + (c - cStart)*6 + r;
4517:       }
4518:       DMPlexSetSupport(rdm, newp, supportNew);
4519:     }
4520:     PetscFree(supportRef);
4521:     break;
4522:   case REFINER_HYBRID_HEX_3D:
4523:     DMPlexGetHybridBounds(rdm, &cMaxNew, &fMaxNew, &eMaxNew, NULL);
4524:     /*
4525:      Bottom (viewed from top)    Top
4526:      1---------2---------2       7---------2---------6
4527:      |         |         |       |         |         |
4528:      |    B    2    C    |       |    H    2    G    |
4529:      |         |         |       |         |         |
4530:      3----3----0----1----1       3----3----0----1----1
4531:      |         |         |       |         |         |
4532:      |    A    0    D    |       |    E    0    F    |
4533:      |         |         |       |         |         |
4534:      0---------0---------3       4---------0---------5
4535:      */
4536:     /* Interior cells have 6 faces: Bottom, Top, Front, Back, Right, Left */
4537:     for (c = cStart; c < cMax; ++c) {
4538:       const PetscInt  newp = (c - cStart)*8;
4539:       const PetscInt *cone, *ornt;
4540:       PetscInt        coneNew[6], orntNew[6];

4542:       DMPlexGetCone(dm, c, &cone);
4543:       DMPlexGetConeOrientation(dm, c, &ornt);
4544:       /* A hex */
4545:       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], 0);
4546:       orntNew[0] = ornt[0];
4547:       coneNew[1] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  8; /* AE */
4548:       orntNew[1] = 0;
4549:       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetQuadSubface_Static(ornt[2], 0);
4550:       orntNew[2] = ornt[2];
4551:       coneNew[3] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  3; /* AB */
4552:       orntNew[3] = 0;
4553:       coneNew[4] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  0; /* AD */
4554:       orntNew[4] = 0;
4555:       coneNew[5] = fStartNew + (cone[5] - fStart)*4 + GetQuadSubface_Static(ornt[5], 0);
4556:       orntNew[5] = ornt[5];
4557:       DMPlexSetCone(rdm, newp+0, coneNew);
4558:       DMPlexSetConeOrientation(rdm, newp+0, orntNew);
4559: #if 1
4560:       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);
4561:       for (p = 0; p < 6; ++p) {
4562:         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);
4563:       }
4564: #endif
4565:       /* B hex */
4566:       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], 1);
4567:       orntNew[0] = ornt[0];
4568:       coneNew[1] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 + 11; /* BH */
4569:       orntNew[1] = 0;
4570:       coneNew[2] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  3; /* AB */
4571:       orntNew[2] = -1;
4572:       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetQuadSubface_Static(ornt[3], 1);
4573:       orntNew[3] = ornt[3];
4574:       coneNew[4] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  2; /* BC */
4575:       orntNew[4] = 0;
4576:       coneNew[5] = fStartNew + (cone[5] - fStart)*4 + GetQuadSubface_Static(ornt[5], 3);
4577:       orntNew[5] = ornt[5];
4578:       DMPlexSetCone(rdm, newp+1, coneNew);
4579:       DMPlexSetConeOrientation(rdm, newp+1, orntNew);
4580: #if 1
4581:       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);
4582:       for (p = 0; p < 6; ++p) {
4583:         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);
4584:       }
4585: #endif
4586:       /* C hex */
4587:       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], 2);
4588:       orntNew[0] = ornt[0];
4589:       coneNew[1] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 + 10; /* CG */
4590:       orntNew[1] = 0;
4591:       coneNew[2] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  1; /* CD */
4592:       orntNew[2] = -1;
4593:       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetQuadSubface_Static(ornt[3], 0);
4594:       orntNew[3] = ornt[3];
4595:       coneNew[4] = fStartNew + (cone[4] - fStart)*4 + GetQuadSubface_Static(ornt[4], 1);
4596:       orntNew[4] = ornt[4];
4597:       coneNew[5] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  2; /* BC */
4598:       orntNew[5] = -4;
4599:       DMPlexSetCone(rdm, newp+2, coneNew);
4600:       DMPlexSetConeOrientation(rdm, newp+2, orntNew);
4601: #if 1
4602:       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);
4603:       for (p = 0; p < 6; ++p) {
4604:         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);
4605:       }
4606: #endif
4607:       /* D hex */
4608:       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], 3);
4609:       orntNew[0] = ornt[0];
4610:       coneNew[1] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  9; /* DF */
4611:       orntNew[1] = 0;
4612:       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetQuadSubface_Static(ornt[2], 1);
4613:       orntNew[2] = ornt[2];
4614:       coneNew[3] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  1; /* CD */
4615:       orntNew[3] = 0;
4616:       coneNew[4] = fStartNew + (cone[4] - fStart)*4 + GetQuadSubface_Static(ornt[4], 0);
4617:       orntNew[4] = ornt[4];
4618:       coneNew[5] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  0; /* AD */
4619:       orntNew[5] = -4;
4620:       DMPlexSetCone(rdm, newp+3, coneNew);
4621:       DMPlexSetConeOrientation(rdm, newp+3, orntNew);
4622: #if 1
4623:       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);
4624:       for (p = 0; p < 6; ++p) {
4625:         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);
4626:       }
4627: #endif
4628:       /* E hex */
4629:       coneNew[0] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  8; /* AE */
4630:       orntNew[0] = -4;
4631:       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], 0);
4632:       orntNew[1] = ornt[1];
4633:       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetQuadSubface_Static(ornt[2], 3);
4634:       orntNew[2] = ornt[2];
4635:       coneNew[3] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  7; /* EH */
4636:       orntNew[3] = 0;
4637:       coneNew[4] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  4; /* EF */
4638:       orntNew[4] = -1;
4639:       coneNew[5] = fStartNew + (cone[5] - fStart)*4 + GetQuadSubface_Static(ornt[5], 1);
4640:       orntNew[5] = ornt[5];
4641:       DMPlexSetCone(rdm, newp+4, coneNew);
4642:       DMPlexSetConeOrientation(rdm, newp+4, orntNew);
4643: #if 1
4644:       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);
4645:       for (p = 0; p < 6; ++p) {
4646:         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);
4647:       }
4648: #endif
4649:       /* F hex */
4650:       coneNew[0] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  9; /* DF */
4651:       orntNew[0] = -4;
4652:       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], 1);
4653:       orntNew[1] = ornt[1];
4654:       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetQuadSubface_Static(ornt[2], 2);
4655:       orntNew[2] = ornt[2];
4656:       coneNew[3] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  5; /* FG */
4657:       orntNew[3] = -1;
4658:       coneNew[4] = fStartNew + (cone[4] - fStart)*4 + GetQuadSubface_Static(ornt[4], 3);
4659:       orntNew[4] = ornt[4];
4660:       coneNew[5] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  4; /* EF */
4661:       orntNew[5] = 1;
4662:       DMPlexSetCone(rdm, newp+5, coneNew);
4663:       DMPlexSetConeOrientation(rdm, newp+5, orntNew);
4664: #if 1
4665:       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);
4666:       for (p = 0; p < 6; ++p) {
4667:         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);
4668:       }
4669: #endif
4670:       /* G hex */
4671:       coneNew[0] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 + 10; /* CG */
4672:       orntNew[0] = -4;
4673:       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], 2);
4674:       orntNew[1] = ornt[1];
4675:       coneNew[2] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  5; /* FG */
4676:       orntNew[2] = 0;
4677:       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetQuadSubface_Static(ornt[3], 3);
4678:       orntNew[3] = ornt[3];
4679:       coneNew[4] = fStartNew + (cone[4] - fStart)*4 + GetQuadSubface_Static(ornt[4], 2);
4680:       orntNew[4] = ornt[4];
4681:       coneNew[5] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  6; /* GH */
4682:       orntNew[5] = -3;
4683:       DMPlexSetCone(rdm, newp+6, coneNew);
4684:       DMPlexSetConeOrientation(rdm, newp+6, orntNew);
4685: #if 1
4686:       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);
4687:       for (p = 0; p < 6; ++p) {
4688:         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);
4689:       }
4690: #endif
4691:       /* H hex */
4692:       coneNew[0] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 + 11; /* BH */
4693:       orntNew[0] = -4;
4694:       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], 3);
4695:       orntNew[1] = ornt[1];
4696:       coneNew[2] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  7; /* EH */
4697:       orntNew[2] = -1;
4698:       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetQuadSubface_Static(ornt[3], 2);
4699:       orntNew[3] = ornt[3];
4700:       coneNew[4] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  6; /* GH */
4701:       orntNew[4] = 3;
4702:       coneNew[5] = fStartNew + (cone[5] - fStart)*4 + GetQuadSubface_Static(ornt[5], 2);
4703:       orntNew[5] = ornt[5];
4704:       DMPlexSetCone(rdm, newp+7, coneNew);
4705:       DMPlexSetConeOrientation(rdm, newp+7, orntNew);
4706: #if 1
4707:       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);
4708:       for (p = 0; p < 6; ++p) {
4709:         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);
4710:       }
4711: #endif
4712:     }
4713:     /* Hybrid cells have 6 faces: Front, Back, Sides */
4714:     /*
4715:      3---------2---------2
4716:      |         |         |
4717:      |    D    2    C    |
4718:      |         |         |
4719:      3----3----0----1----1
4720:      |         |         |
4721:      |    A    0    B    |
4722:      |         |         |
4723:      0---------0---------1
4724:      */
4725:     for (c = cMax; c < cEnd; ++c) {
4726:       const PetscInt  newp = (cMax - cStart)*8 + (c - cMax)*4;
4727:       const PetscInt *cone, *ornt, *fornt;
4728:       PetscInt        coneNew[6], orntNew[6], o, of, i;

4730:       DMPlexGetCone(dm, c, &cone);
4731:       DMPlexGetConeOrientation(dm, c, &ornt);
4732:       DMPlexGetConeOrientation(dm, cone[0], &fornt);
4733:       o = ornt[0] < 0 ? -1 : 1;
4734:       for (r = 0; r < 4; ++r) {
4735:         PetscInt subfA = GetQuadSubface_Static(ornt[0], r);
4736:         PetscInt edgeA = GetQuadEdge_Static(ornt[0], r);
4737:         PetscInt edgeB = GetQuadEdge_Static(ornt[0], (r+3)%4);
4738:         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]);
4739:         coneNew[0]         = fStartNew + (cone[0] - fStart)*4 + subfA;
4740:         orntNew[0]         = ornt[0];
4741:         coneNew[1]         = fStartNew + (cone[1] - fStart)*4 + subfA;
4742:         orntNew[1]         = ornt[0];
4743:         of = fornt[edgeA] < 0 ? -1 : 1;
4744:         i  = GetQuadEdgeInverse_Static(ornt[0], r) + 2;
4745:         coneNew[i] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (cone[2+edgeA] - fMax)*2 + (o*of < 0 ? 1 : 0);
4746:         orntNew[i] = ornt[edgeA];
4747:         i  = GetQuadEdgeInverse_Static(ornt[0], (r+1)%4) + 2;
4748:         coneNew[i] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd          - fMax)*2 + (c - cMax)*4 + edgeA;
4749:         orntNew[i] = 0;
4750:         i  = GetQuadEdgeInverse_Static(ornt[0], (r+2)%4) + 2;
4751:         coneNew[i] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd          - fMax)*2 + (c - cMax)*4 + edgeB;
4752:         orntNew[i] = -2;
4753:         of = fornt[edgeB] < 0 ? -1 : 1;
4754:         i  = GetQuadEdgeInverse_Static(ornt[0], (r+3)%4) + 2;
4755:         coneNew[i] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (cone[2+edgeB] - fMax)*2 + (o*of < 0 ? 0 : 1);
4756:         orntNew[i] = ornt[edgeB];
4757:         DMPlexSetCone(rdm, newp+r, coneNew);
4758:         DMPlexSetConeOrientation(rdm, newp+r, orntNew);
4759: #if 1
4760:         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);
4761:         for (p = 0; p < 2; ++p) {
4762:           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);
4763:         }
4764:         for (p = 2; p < 6; ++p) {
4765:           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);
4766:         }
4767: #endif
4768:       }
4769:     }
4770:     /* Interior split faces have 4 edges and the same cells as the parent */
4771:     DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);
4772:     PetscMalloc1(4 + maxSupportSize*2, &supportRef);
4773:     for (f = fStart; f < fMax; ++f) {
4774:       for (r = 0; r < 4; ++r) {
4775:         /* TODO: This can come from GetFaces_Internal() */
4776:         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};
4777:         const PetscInt  newp = fStartNew + (f - fStart)*4 + r;
4778:         const PetscInt *cone, *ornt, *support;
4779:         PetscInt        coneNew[4], orntNew[4], coneSize, c, supportSize, s;

4781:         DMPlexGetCone(dm, f, &cone);
4782:         DMPlexGetConeOrientation(dm, f, &ornt);
4783:         coneNew[(r+3)%4] = eStartNew + (cone[(r+3)%4] - eStart)*2 + (ornt[(r+3)%4] < 0 ? 0 : 1);
4784:         orntNew[(r+3)%4] = ornt[(r+3)%4];
4785:         coneNew[(r+0)%4] = eStartNew + (cone[r]       - eStart)*2 + (ornt[r] < 0 ? 1 : 0);
4786:         orntNew[(r+0)%4] = ornt[r];
4787:         coneNew[(r+1)%4] = eStartNew + (eMax - eStart)*2 + (f - fStart)*4 + r;
4788:         orntNew[(r+1)%4] = 0;
4789:         coneNew[(r+2)%4] = eStartNew + (eMax - eStart)*2 + (f - fStart)*4 + (r+3)%4;
4790:         orntNew[(r+2)%4] = -2;
4791:         DMPlexSetCone(rdm, newp, coneNew);
4792:         DMPlexSetConeOrientation(rdm, newp, orntNew);
4793: #if 1
4794:         if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
4795:         for (p = 0; p < 4; ++p) {
4796:           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);
4797:         }
4798: #endif
4799:         DMPlexGetSupportSize(dm, f, &supportSize);
4800:         DMPlexGetSupport(dm, f, &support);
4801:         for (s = 0; s < supportSize; ++s) {
4802:           PetscInt subf;
4803:           DMPlexGetConeSize(dm, support[s], &coneSize);
4804:           DMPlexGetCone(dm, support[s], &cone);
4805:           DMPlexGetConeOrientation(dm, support[s], &ornt);
4806:           for (c = 0; c < coneSize; ++c) {
4807:             if (cone[c] == f) break;
4808:           }
4809:           subf = GetQuadSubfaceInverse_Static(ornt[c], r);
4810:           if (support[s] < cMax) {
4811:             supportRef[s] = cStartNew + (support[s] - cStart)*8 + newCells[c*4+subf];
4812:           } else {
4813:             supportRef[s] = cStartNew + (cMax       - cStart)*8 + (support[s] - cMax)*4 + subf;
4814:           }
4815:         }
4816:         DMPlexSetSupport(rdm, newp, supportRef);
4817: #if 1
4818:         if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
4819:         for (p = 0; p < supportSize; ++p) {
4820:           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);
4821:         }
4822: #endif
4823:       }
4824:     }
4825:     /* Interior cell faces have 4 edges and 2 cells */
4826:     for (c = cStart; c < cMax; ++c) {
4827:       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};
4828:       const PetscInt *cone, *ornt;
4829:       PetscInt        newp, coneNew[4], orntNew[4], supportNew[2];

4831:       DMPlexGetCone(dm, c, &cone);
4832:       DMPlexGetConeOrientation(dm, c, &ornt);
4833:       /* A-D face */
4834:       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 0;
4835:       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*4 + GetQuadEdge_Static(ornt[0], 3);
4836:       orntNew[0] = 0;
4837:       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 0;
4838:       orntNew[1] = 0;
4839:       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 2;
4840:       orntNew[2] = -2;
4841:       coneNew[3] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*4 + GetQuadEdge_Static(ornt[2], 0);
4842:       orntNew[3] = -2;
4843:       DMPlexSetCone(rdm, newp, coneNew);
4844:       DMPlexSetConeOrientation(rdm, newp, orntNew);
4845: #if 1
4846:       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
4847:       for (p = 0; p < 4; ++p) {
4848:         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);
4849:       }
4850: #endif
4851:       /* C-D face */
4852:       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 1;
4853:       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*4 + GetQuadEdge_Static(ornt[0], 2);
4854:       orntNew[0] = 0;
4855:       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 0;
4856:       orntNew[1] = 0;
4857:       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 4;
4858:       orntNew[2] = -2;
4859:       coneNew[3] = eStartNew + (eMax - eStart)*2 + (cone[4] - fStart)*4 + GetQuadEdge_Static(ornt[4], 0);
4860:       orntNew[3] = -2;
4861:       DMPlexSetCone(rdm, newp, coneNew);
4862:       DMPlexSetConeOrientation(rdm, newp, orntNew);
4863: #if 1
4864:       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
4865:       for (p = 0; p < 4; ++p) {
4866:         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);
4867:       }
4868: #endif
4869:       /* B-C face */
4870:       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 2;
4871:       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*4 + GetQuadEdge_Static(ornt[0], 1);
4872:       orntNew[0] = -2;
4873:       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*4 + GetQuadEdge_Static(ornt[3], 0);
4874:       orntNew[1] = 0;
4875:       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 3;
4876:       orntNew[2] = 0;
4877:       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 0;
4878:       orntNew[3] = -2;
4879:       DMPlexSetCone(rdm, newp, coneNew);
4880:       DMPlexSetConeOrientation(rdm, newp, orntNew);
4881: #if 1
4882:       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
4883:       for (p = 0; p < 4; ++p) {
4884:         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);
4885:       }
4886: #endif
4887:       /* A-B face */
4888:       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 3;
4889:       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*4 + GetQuadEdge_Static(ornt[0], 0);
4890:       orntNew[0] = -2;
4891:       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[5] - fStart)*4 + GetQuadEdge_Static(ornt[5], 3);
4892:       orntNew[1] = 0;
4893:       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 5;
4894:       orntNew[2] = 0;
4895:       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 0;
4896:       orntNew[3] = -2;
4897:       DMPlexSetCone(rdm, newp, coneNew);
4898:       DMPlexSetConeOrientation(rdm, newp, orntNew);
4899: #if 1
4900:       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
4901:       for (p = 0; p < 4; ++p) {
4902:         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);
4903:       }
4904: #endif
4905:       /* E-F face */
4906:       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 4;
4907:       coneNew[0] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 2;
4908:       orntNew[0] = -2;
4909:       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*4 + GetQuadEdge_Static(ornt[2], 2);
4910:       orntNew[1] = -2;
4911:       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*4 + GetQuadEdge_Static(ornt[1], 0);
4912:       orntNew[2] = 0;
4913:       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 1;
4914:       orntNew[3] = 0;
4915:       DMPlexSetCone(rdm, newp, coneNew);
4916:       DMPlexSetConeOrientation(rdm, newp, orntNew);
4917: #if 1
4918:       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
4919:       for (p = 0; p < 4; ++p) {
4920:         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);
4921:       }
4922: #endif
4923:       /* F-G face */
4924:       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 5;
4925:       coneNew[0] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 4;
4926:       orntNew[0] = -2;
4927:       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[4] - fStart)*4 + GetQuadEdge_Static(ornt[4], 2);
4928:       orntNew[1] = -2;
4929:       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*4 + GetQuadEdge_Static(ornt[1], 1);
4930:       orntNew[2] = 0;
4931:       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 1;
4932:       orntNew[3] = 0;
4933:       DMPlexSetCone(rdm, newp, coneNew);
4934:       DMPlexSetConeOrientation(rdm, newp, orntNew);
4935: #if 1
4936:       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
4937:       for (p = 0; p < 4; ++p) {
4938:         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);
4939:       }
4940: #endif
4941:       /* G-H face */
4942:       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 6;
4943:       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*4 + GetQuadEdge_Static(ornt[3], 2);
4944:       orntNew[0] = -2;
4945:       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*4 + GetQuadEdge_Static(ornt[1], 2);
4946:       orntNew[1] = 0;
4947:       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 1;
4948:       orntNew[2] = 0;
4949:       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 3;
4950:       orntNew[3] = -2;
4951:       DMPlexSetCone(rdm, newp, coneNew);
4952:       DMPlexSetConeOrientation(rdm, newp, orntNew);
4953: #if 1
4954:       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
4955:       for (p = 0; p < 4; ++p) {
4956:         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);
4957:       }
4958: #endif
4959:       /* E-H face */
4960:       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 7;
4961:       coneNew[0] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 5;
4962:       orntNew[0] = -2;
4963:       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[5] - fStart)*4 + GetQuadEdge_Static(ornt[5], 1);
4964:       orntNew[1] = -2;
4965:       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*4 + GetQuadEdge_Static(ornt[1], 3);
4966:       orntNew[2] = 0;
4967:       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 1;
4968:       orntNew[3] = 0;
4969:       DMPlexSetCone(rdm, newp, coneNew);
4970:       DMPlexSetConeOrientation(rdm, newp, orntNew);
4971: #if 1
4972:       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
4973:       for (p = 0; p < 4; ++p) {
4974:         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);
4975:       }
4976: #endif
4977:       /* A-E face */
4978:       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 8;
4979:       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*4 + GetQuadEdge_Static(ornt[2], 3);
4980:       orntNew[0] = 0;
4981:       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 2;
4982:       orntNew[1] = 0;
4983:       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 5;
4984:       orntNew[2] = -2;
4985:       coneNew[3] = eStartNew + (eMax - eStart)*2 + (cone[5] - fStart)*4 + GetQuadEdge_Static(ornt[5], 0);
4986:       orntNew[3] = -2;
4987:       DMPlexSetCone(rdm, newp, coneNew);
4988:       DMPlexSetConeOrientation(rdm, newp, orntNew);
4989: #if 1
4990:       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
4991:       for (p = 0; p < 4; ++p) {
4992:         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);
4993:       }
4994: #endif
4995:       /* D-F face */
4996:       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 9;
4997:       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*4 + GetQuadEdge_Static(ornt[2], 1);
4998:       orntNew[0] = -2;
4999:       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[4] - fStart)*4 + GetQuadEdge_Static(ornt[4], 3);
5000:       orntNew[1] = 0;
5001:       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 4;
5002:       orntNew[2] = 0;
5003:       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 2;
5004:       orntNew[3] = -2;
5005:       DMPlexSetCone(rdm, newp, coneNew);
5006:       DMPlexSetConeOrientation(rdm, newp, orntNew);
5007: #if 1
5008:       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
5009:       for (p = 0; p < 4; ++p) {
5010:         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);
5011:       }
5012: #endif
5013:       /* C-G face */
5014:       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 10;
5015:       coneNew[0] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 4;
5016:       orntNew[0] = -2;
5017:       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[4] - fStart)*4 + GetQuadEdge_Static(ornt[4], 1);
5018:       orntNew[1] = -2;
5019:       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*4 + GetQuadEdge_Static(ornt[3], 3);
5020:       orntNew[2] = 0;
5021:       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 3;
5022:       orntNew[3] = 0;
5023:       DMPlexSetCone(rdm, newp, coneNew);
5024:       DMPlexSetConeOrientation(rdm, newp, orntNew);
5025: #if 1
5026:       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
5027:       for (p = 0; p < 4; ++p) {
5028:         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);
5029:       }
5030: #endif
5031:       /* B-H face */
5032:       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 11;
5033:       coneNew[0] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 5;
5034:       orntNew[0] = 0;
5035:       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 3;
5036:       orntNew[1] = -2;
5037:       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*4 + GetQuadEdge_Static(ornt[3], 1);
5038:       orntNew[2] = -2;
5039:       coneNew[3] = eStartNew + (eMax - eStart)*2 + (cone[5] - fStart)*4 + GetQuadEdge_Static(ornt[5], 2);
5040:       orntNew[3] = 0;
5041:       DMPlexSetCone(rdm, newp, coneNew);
5042:       DMPlexSetConeOrientation(rdm, newp, orntNew);
5043: #if 1
5044:       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
5045:       for (p = 0; p < 4; ++p) {
5046:         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);
5047:       }
5048: #endif
5049:       for (r = 0; r < 12; ++r) {
5050:         newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + r;
5051:         supportNew[0] = cStartNew + (c - cStart)*8 + newCells[r*2+0];
5052:         supportNew[1] = cStartNew + (c - cStart)*8 + newCells[r*2+1];
5053:         DMPlexSetSupport(rdm, newp, supportNew);
5054: #if 1
5055:         if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
5056:         for (p = 0; p < 2; ++p) {
5057:           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);
5058:         }
5059: #endif
5060:       }
5061:     }
5062:     /* Hybrid split faces have 4 edges and same cells */
5063:     for (f = fMax; f < fEnd; ++f) {
5064:       const PetscInt *cone, *ornt, *support;
5065:       PetscInt        coneNew[4], orntNew[4];
5066:       PetscInt        supportNew[2], size, s, c;

5068:       DMPlexGetCone(dm, f, &cone);
5069:       DMPlexGetConeOrientation(dm, f, &ornt);
5070:       DMPlexGetSupportSize(dm, f, &size);
5071:       DMPlexGetSupport(dm, f, &support);
5072:       for (r = 0; r < 2; ++r) {
5073:         const PetscInt newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (f - fMax)*2 + r;

5075:         coneNew[0]   = eStartNew + (cone[0] - eStart)*2 + (ornt[0] < 0 ? 1-r : r);
5076:         orntNew[0]   = ornt[0];
5077:         coneNew[1]   = eStartNew + (cone[1] - eStart)*2 + (ornt[1] < 0 ? 1-r : r);
5078:         orntNew[1]   = ornt[1];
5079:         coneNew[2+r] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (cone[2+r] - eMax);
5080:         orntNew[2+r] = 0;
5081:         coneNew[3-r] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (eEnd      - eMax) + (f - fMax);
5082:         orntNew[3-r] = 0;
5083:         DMPlexSetCone(rdm, newp, coneNew);
5084:         DMPlexSetConeOrientation(rdm, newp, orntNew);
5085: #if 1
5086:         if ((newp < fMaxNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid face [%d, %d)", newp, fMaxNew, fEndNew);
5087:         for (p = 0; p < 2; ++p) {
5088:           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);
5089:         }
5090:         for (p = 2; p < 4; ++p) {
5091:           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);
5092:         }
5093: #endif
5094:         for (s = 0; s < size; ++s) {
5095:           const PetscInt *coneCell, *orntCell, *fornt;
5096:           PetscInt        o, of;

5098:           DMPlexGetCone(dm, support[s], &coneCell);
5099:           DMPlexGetConeOrientation(dm, support[s], &orntCell);
5100:           o = orntCell[0] < 0 ? -1 : 1;
5101:           for (c = 2; c < 6; ++c) if (coneCell[c] == f) break;
5102:           if (c >= 6) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Could not find face %d in cone of cell %d", f, support[s]);
5103:           DMPlexGetConeOrientation(dm, coneCell[0], &fornt);
5104:           of = fornt[c-2] < 0 ? -1 : 1;
5105:           supportNew[s] = cStartNew + (cMax - cStart)*8 + (support[s] - cMax)*4 + (GetQuadEdgeInverse_Static(orntCell[0], c-2) + (o*of < 0 ? 1-r : r))%4;
5106:         }
5107:         DMPlexSetSupport(rdm, newp, supportNew);
5108: #if 1
5109:         if ((newp < fMaxNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid face [%d, %d)", newp, fMaxNew, fEndNew);
5110:         for (p = 0; p < size; ++p) {
5111:           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);
5112:         }
5113: #endif
5114:       }
5115:     }
5116:     /* Hybrid cell faces have 4 edges and 2 cells */
5117:     for (c = cMax; c < cEnd; ++c) {
5118:       PetscInt        newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd - fMax)*2 + (c - cMax)*4;
5119:       const PetscInt *cone, *ornt;
5120:       PetscInt        coneNew[4], orntNew[4];
5121:       PetscInt        supportNew[2];

5123:       DMPlexGetCone(dm, c, &cone);
5124:       DMPlexGetConeOrientation(dm, c, &ornt);
5125:       for (r = 0; r < 4; ++r) {
5126: #if 0
5127:         coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], r);
5128:         orntNew[0] = 0;
5129:         coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], r);
5130:         orntNew[1] = 0;
5131:         coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (eEnd - eMax) + (cone[2+GetQuadEdge_Static(ornt[0], r)] - fMax);
5132:         orntNew[2] = 0;
5133:         coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (eEnd - eMax) + (fEnd                                   - fMax) + (c - cMax);
5134:         orntNew[3] = 0;
5135: #else
5136:         coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*4 + r;
5137:         orntNew[0] = 0;
5138:         coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*4 + r;
5139:         orntNew[1] = 0;
5140:         coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (eEnd - eMax) + (cone[2+r] - fMax);
5141:         orntNew[2] = 0;
5142:         coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (eEnd - eMax) + (fEnd      - fMax) + (c - cMax);
5143:         orntNew[3] = 0;
5144: #endif
5145:         DMPlexSetCone(rdm, newp+r, coneNew);
5146:         DMPlexSetConeOrientation(rdm, newp+r, orntNew);
5147: #if 1
5148:         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);
5149:         for (p = 0; p < 2; ++p) {
5150:           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);
5151:         }
5152:         for (p = 2; p < 4; ++p) {
5153:           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);
5154:         }
5155: #endif
5156:         supportNew[0] = cStartNew + (cMax - cStart)*8 + (c - cMax)*4 + GetQuadSubface_Static(ornt[0], r);
5157:         supportNew[1] = cStartNew + (cMax - cStart)*8 + (c - cMax)*4 + GetQuadSubface_Static(ornt[0], (r+1)%4);
5158:         DMPlexSetSupport(rdm, newp+r, supportNew);
5159: #if 1
5160:         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);
5161:         for (p = 0; p < 2; ++p) {
5162:           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);
5163:         }
5164: #endif
5165:       }
5166:     }
5167:     /* Interior split edges have 2 vertices and the same faces as the parent */
5168:     DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);
5169:     for (e = eStart; e < eMax; ++e) {
5170:       const PetscInt newv = vStartNew + (vEnd - vStart) + (e - eStart);

5172:       for (r = 0; r < 2; ++r) {
5173:         const PetscInt  newp = eStartNew + (e - eStart)*2 + r;
5174:         const PetscInt *cone, *ornt, *support;
5175:         PetscInt        coneNew[2], coneSize, c, supportSize, s;

5177:         DMPlexGetCone(dm, e, &cone);
5178:         coneNew[0]       = vStartNew + (cone[0] - vStart);
5179:         coneNew[1]       = vStartNew + (cone[1] - vStart);
5180:         coneNew[(r+1)%2] = newv;
5181:         DMPlexSetCone(rdm, newp, coneNew);
5182: #if 1
5183:         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
5184:         for (p = 0; p < 2; ++p) {
5185:           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);
5186:         }
5187: #endif
5188:         DMPlexGetSupportSize(dm, e, &supportSize);
5189:         DMPlexGetSupport(dm, e, &support);
5190:         for (s = 0; s < supportSize; ++s) {
5191:           DMPlexGetConeSize(dm, support[s], &coneSize);
5192:           DMPlexGetCone(dm, support[s], &cone);
5193:           DMPlexGetConeOrientation(dm, support[s], &ornt);
5194:           for (c = 0; c < coneSize; ++c) {
5195:             if (cone[c] == e) break;
5196:           }
5197:           if (support[s] < fMax) {
5198:             supportRef[s] = fStartNew + (support[s] - fStart)*4 + (c + (ornt[c] < 0 ? 1-r : r))%4;
5199:           } else {
5200:             supportRef[s] = fStartNew + (fMax       - fStart)*4 + (cMax - cStart)*12 + (support[s] - fMax)*2 + (ornt[c] < 0 ? 1-r : r);
5201:           }
5202:         }
5203:         DMPlexSetSupport(rdm, newp, supportRef);
5204: #if 1
5205:         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
5206:         for (p = 0; p < supportSize; ++p) {
5207:           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);
5208:         }
5209: #endif
5210:       }
5211:     }
5212:     /* Interior face edges have 2 vertices and 2+cells faces */
5213:     for (f = fStart; f < fMax; ++f) {
5214:       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};
5215:       const PetscInt  newv = vStartNew + (vEnd - vStart) + (eMax - eStart) + (f - fStart);
5216:       const PetscInt *cone, *coneCell, *orntCell, *support;
5217:       PetscInt        coneNew[2], coneSize, c, supportSize, s;

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

5223:         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r] - eStart);
5224:         coneNew[1] = newv;
5225:         DMPlexSetCone(rdm, newp, coneNew);
5226: #if 1
5227:         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
5228:         for (p = 0; p < 2; ++p) {
5229:           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);
5230:         }
5231: #endif
5232:         DMPlexGetSupportSize(dm, f, &supportSize);
5233:         DMPlexGetSupport(dm, f, &support);
5234:         supportRef[0] = fStartNew + (f - fStart)*4 + r;
5235:         supportRef[1] = fStartNew + (f - fStart)*4 + (r+1)%4;
5236:         for (s = 0; s < supportSize; ++s) {
5237:           DMPlexGetConeSize(dm, support[s], &coneSize);
5238:           DMPlexGetCone(dm, support[s], &coneCell);
5239:           DMPlexGetConeOrientation(dm, support[s], &orntCell);
5240:           for (c = 0; c < coneSize; ++c) if (coneCell[c] == f) break;
5241:           if (support[s] < cMax) {
5242:             supportRef[2+s] = fStartNew + (fMax - fStart)*4 + (support[s] - cStart)*12 + newFaces[c*4 + GetQuadEdgeInverse_Static(orntCell[c], r)];
5243:           } else {
5244:             supportRef[2+s] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd - fMax)*2 + (support[s] - cMax)*4 + r;
5245:           }
5246:         }
5247:         DMPlexSetSupport(rdm, newp, supportRef);
5248: #if 1
5249:         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
5250:         for (p = 0; p < 2+supportSize; ++p) {
5251:           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);
5252:         }
5253: #endif
5254:       }
5255:     }
5256:     /* Interior cell edges have 2 vertices and 4 faces */
5257:     for (c = cStart; c < cMax; ++c) {
5258:       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};
5259:       const PetscInt  newv = vStartNew + (vEnd - vStart) + (eMax - eStart) + (fMax - fStart) + (c - cStart);
5260:       const PetscInt *cone;
5261:       PetscInt        coneNew[2], supportNew[4];

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

5267:         coneNew[0] = vStartNew + (vEnd - vStart) + (eMax - eStart) + (cone[r] - fStart);
5268:         coneNew[1] = newv;
5269:         DMPlexSetCone(rdm, newp, coneNew);
5270: #if 1
5271:         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
5272:         for (p = 0; p < 2; ++p) {
5273:           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
5274:         }
5275: #endif
5276:         for (f = 0; f < 4; ++f) supportNew[f] = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + newFaces[r*4+f];
5277:         DMPlexSetSupport(rdm, newp, supportNew);
5278: #if 1
5279:         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
5280:         for (p = 0; p < 4; ++p) {
5281:           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);
5282:         }
5283: #endif
5284:       }
5285:     }
5286:     /* Hybrid edges have two vertices and the same faces */
5287:     for (e = eMax; e < eEnd; ++e) {
5288:       const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (e - eMax);
5289:       const PetscInt *cone, *support, *fcone;
5290:       PetscInt        coneNew[2], size, fsize, s;

5292:       DMPlexGetCone(dm, e, &cone);
5293:       DMPlexGetSupportSize(dm, e, &size);
5294:       DMPlexGetSupport(dm, e, &support);
5295:       coneNew[0] = vStartNew + (cone[0] - vStart);
5296:       coneNew[1] = vStartNew + (cone[1] - vStart);
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:       for (s = 0; s < size; ++s) {
5305:         DMPlexGetConeSize(dm, support[s], &fsize);
5306:         DMPlexGetCone(dm, support[s], &fcone);
5307:         for (c = 0; c < fsize; ++c) if (fcone[c] == e) break;
5308:         if ((c < 2) || (c > 3)) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Edge %d not found in cone of face %d", e, support[s]);
5309:         supportRef[s] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (support[s] - fMax)*2 + c-2;
5310:       }
5311:       DMPlexSetSupport(rdm, newp, supportRef);
5312: #if 1
5313:       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid edge [%d, %d)", newp, eMaxNew, eEndNew);
5314:       for (p = 0; p < size; ++p) {
5315:         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);
5316:       }
5317: #endif
5318:     }
5319:     /* Hybrid face edges have 2 vertices and 2+cells faces */
5320:     for (f = fMax; f < fEnd; ++f) {
5321:       const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (eEnd - eMax) + (f - fMax);
5322:       const PetscInt *cone, *support, *ccone, *cornt;
5323:       PetscInt        coneNew[2], size, csize, s;

5325:       DMPlexGetCone(dm, f, &cone);
5326:       DMPlexGetSupportSize(dm, f, &size);
5327:       DMPlexGetSupport(dm, f, &support);
5328:       coneNew[0] = vStartNew + (vEnd - vStart) + (cone[0] - eStart);
5329:       coneNew[1] = vStartNew + (vEnd - vStart) + (cone[1] - eStart);
5330:       DMPlexSetCone(rdm, newp, coneNew);
5331: #if 1
5332:       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid edge [%d, %d)", newp, eMaxNew, eEndNew);
5333:       for (p = 0; p < 2; ++p) {
5334:         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);
5335:       }
5336: #endif
5337:       supportRef[0] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (f - fMax)*2 + 0;
5338:       supportRef[1] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (f - fMax)*2 + 1;
5339:       for (s = 0; s < size; ++s) {
5340:         DMPlexGetConeSize(dm, support[s], &csize);
5341:         DMPlexGetCone(dm, support[s], &ccone);
5342:         DMPlexGetConeOrientation(dm, support[s], &cornt);
5343:         for (c = 0; c < csize; ++c) if (ccone[c] == f) break;
5344:         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]);
5345:         supportRef[2+s] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd - fMax)*2 + (support[s] - cMax)*4 + c-2;
5346:       }
5347:       DMPlexSetSupport(rdm, newp, supportRef);
5348: #if 1
5349:       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid edge [%d, %d)", newp, eMaxNew, eEndNew);
5350:       for (p = 0; p < 2+size; ++p) {
5351:         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);
5352:       }
5353: #endif
5354:     }
5355:     /* Hybrid cell edges have 2 vertices and 4 faces */
5356:     for (c = cMax; c < cEnd; ++c) {
5357:       const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (eEnd - eMax) + (fEnd - fMax) + (c - cMax);
5358:       const PetscInt *cone, *support;
5359:       PetscInt        coneNew[2], size;

5361:       DMPlexGetCone(dm, c, &cone);
5362:       DMPlexGetSupportSize(dm, c, &size);
5363:       DMPlexGetSupport(dm, c, &support);
5364:       coneNew[0] = vStartNew + (vEnd - vStart) + (eMax - eStart) + (cone[0] - fStart);
5365:       coneNew[1] = vStartNew + (vEnd - vStart) + (eMax - eStart) + (cone[1] - fStart);
5366:       DMPlexSetCone(rdm, newp, coneNew);
5367: #if 1
5368:       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid edge [%d, %d)", newp, eMaxNew, eEndNew);
5369:       for (p = 0; p < 2; ++p) {
5370:         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);
5371:       }
5372: #endif
5373:       supportRef[0] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd - fMax)*2 + (c - cMax)*4 + 0;
5374:       supportRef[1] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd - fMax)*2 + (c - cMax)*4 + 1;
5375:       supportRef[2] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd - fMax)*2 + (c - cMax)*4 + 2;
5376:       supportRef[3] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd - fMax)*2 + (c - cMax)*4 + 3;
5377:       DMPlexSetSupport(rdm, newp, supportRef);
5378: #if 1
5379:       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid edge [%d, %d)", newp, eMaxNew, eEndNew);
5380:       for (p = 0; p < 4; ++p) {
5381:         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);
5382:       }
5383: #endif
5384:     }
5385:     /* Interior vertices have identical supports */
5386:     for (v = vStart; v < vEnd; ++v) {
5387:       const PetscInt  newp = vStartNew + (v - vStart);
5388:       const PetscInt *support, *cone;
5389:       PetscInt        size, s;

5391:       DMPlexGetSupportSize(dm, v, &size);
5392:       DMPlexGetSupport(dm, v, &support);
5393:       for (s = 0; s < size; ++s) {
5394:         PetscInt r = 0;

5396:         DMPlexGetCone(dm, support[s], &cone);
5397:         if (cone[1] == v) r = 1;
5398:         if (support[s] < eMax) supportRef[s] = eStartNew + (support[s] - eStart)*2 + r;
5399:         else                   supportRef[s] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (support[s] - eMax);
5400:       }
5401:       DMPlexSetSupport(rdm, newp, supportRef);
5402: #if 1
5403:       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
5404:       for (p = 0; p < size; ++p) {
5405:         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);
5406:       }
5407: #endif
5408:     }
5409:     /* Interior edge vertices have 2 + faces supports */
5410:     for (e = eStart; e < eMax; ++e) {
5411:       const PetscInt  newp = vStartNew + (vEnd - vStart) + (e - eStart);
5412:       const PetscInt *cone, *support;
5413:       PetscInt        size, s;

5415:       DMPlexGetSupportSize(dm, e, &size);
5416:       DMPlexGetSupport(dm, e, &support);
5417:       supportRef[0] = eStartNew + (e - eStart)*2 + 0;
5418:       supportRef[1] = eStartNew + (e - eStart)*2 + 1;
5419:       for (s = 0; s < size; ++s) {
5420:         PetscInt r;

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

5444:       DMPlexGetSupportSize(dm, f, &size);
5445:       DMPlexGetSupport(dm, f, &support);
5446:       for (r = 0; r < 4; ++r) supportRef[r] = eStartNew + (eMax - eStart)*2 +  (f - fStart)*4 + r;
5447:       for (s = 0; s < size; ++s) {
5448:         PetscInt r;

5450:         DMPlexGetCone(dm, support[s], &cone);
5451:         for (r = 0; r < 6; ++r) if (cone[r] == f) break;
5452:         if (support[s] < cMax) {
5453:           supportRef[4+s] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (support[s] - cStart)*6 + r;
5454:         } else {
5455:           supportRef[4+s] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax       - cStart)*6 + (eEnd - eMax) + (fEnd - fMax) + (support[s] - cMax);
5456:         }
5457:       }
5458:       DMPlexSetSupport(rdm, newp, supportRef);
5459: #if 1
5460:       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
5461:       for (p = 0; p < 4+size; ++p) {
5462:         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);
5463:       }
5464: #endif
5465:     }
5466:     /* Cell vertices have 6 supports */
5467:     for (c = cStart; c < cMax; ++c) {
5468:       const PetscInt newp = vStartNew + (vEnd - vStart) + (eMax - eStart) + (fMax - fStart) + (c - cStart);
5469:       PetscInt       supportNew[6];

5471:       for (r = 0; r < 6; ++r) {
5472:         supportNew[r] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (c - cStart)*6 + r;
5473:       }
5474:       DMPlexSetSupport(rdm, newp, supportNew);
5475:     }
5476:     PetscFree(supportRef);
5477:     break;
5478:   default:
5479:     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
5480:   }
5481:   return(0);
5482: }

5486: static PetscErrorCode CellRefinerSetCoordinates(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
5487: {
5488:   PetscSection   coordSection, coordSectionNew;
5489:   Vec            coordinates, coordinatesNew;
5490:   PetscScalar   *coords, *coordsNew;
5491:   const PetscInt numVertices = depthSize ? depthSize[0] : 0;
5492:   PetscInt       dim, spaceDim, depth, bs, coordSizeNew, cStart, cEnd, cMax, c, vStart, vStartNew, vEnd, v, eStart, eEnd, eMax, e, fStart, fEnd, fMax, f;
5493:   VecType        vtype;

5497:   DMGetDimension(dm, &dim);
5498:   DMPlexGetDepth(dm, &depth);
5499:   DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);
5500:   DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);
5501:   DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);
5502:   DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);
5503:   DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, NULL);
5504:   if (refiner) {GetDepthStart_Private(depth, depthSize, NULL, NULL, NULL, &vStartNew);}
5505:   GetDepthStart_Private(depth, depthSize, NULL, NULL, NULL, &vStartNew);
5506:   DMGetCoordinateSection(dm, &coordSection);
5507:   PetscSectionGetFieldComponents(coordSection, 0, &spaceDim);
5508:   PetscSectionCreate(PetscObjectComm((PetscObject)dm), &coordSectionNew);
5509:   PetscSectionSetNumFields(coordSectionNew, 1);
5510:   PetscSectionSetFieldComponents(coordSectionNew, 0, spaceDim);
5511:   PetscSectionSetChart(coordSectionNew, vStartNew, vStartNew+numVertices);
5512:   if (cMax < 0) cMax = cEnd;
5513:   if (fMax < 0) fMax = fEnd;
5514:   if (eMax < 0) eMax = eEnd;
5515:   /* All vertices have the spaceDim coordinates */
5516:   for (v = vStartNew; v < vStartNew+numVertices; ++v) {
5517:     PetscSectionSetDof(coordSectionNew, v, spaceDim);
5518:     PetscSectionSetFieldDof(coordSectionNew, v, 0, spaceDim);
5519:   }
5520:   PetscSectionSetUp(coordSectionNew);
5521:   DMSetCoordinateSection(rdm, PETSC_DETERMINE, coordSectionNew);
5522:   DMGetCoordinatesLocal(dm, &coordinates);
5523:   PetscSectionGetStorageSize(coordSectionNew, &coordSizeNew);
5524:   VecCreate(PETSC_COMM_SELF, &coordinatesNew);
5525:   PetscObjectSetName((PetscObject) coordinatesNew, "coordinates");
5526:   VecSetSizes(coordinatesNew, coordSizeNew, PETSC_DETERMINE);
5527:   VecGetBlockSize(coordinates, &bs);
5528:   VecSetBlockSize(coordinatesNew, bs);
5529:   VecGetType(coordinates, &vtype);
5530:   VecSetType(coordinatesNew, vtype);
5531:   VecGetArray(coordinates, &coords);
5532:   VecGetArray(coordinatesNew, &coordsNew);
5533:   switch (refiner) {
5534:   case REFINER_NOOP: break;
5535:   case REFINER_HEX_3D:
5536:   case REFINER_HYBRID_HEX_3D:
5537:     /* Face vertices have the average of corner coordinates */
5538:     for (f = fStart; f < fMax; ++f) {
5539:       const PetscInt newv = vStartNew + (vEnd - vStart) + (eMax - eStart) + (f - fStart);
5540:       PetscInt      *cone = NULL;
5541:       PetscInt       closureSize, coneSize = 0, off[8], offnew, p, d;

5543:       DMPlexGetTransitiveClosure(dm, f, PETSC_TRUE, &closureSize, &cone);
5544:       for (p = 0; p < closureSize*2; p += 2) {
5545:         const PetscInt point = cone[p];
5546:         if ((point >= vStart) && (point < vEnd)) cone[coneSize++] = point;
5547:       }
5548:       for (v = 0; v < coneSize; ++v) {
5549:         PetscSectionGetOffset(coordSection, cone[v], &off[v]);
5550:       }
5551:       PetscSectionGetOffset(coordSectionNew, newv, &offnew);
5552:       for (d = 0; d < spaceDim; ++d) coordsNew[offnew+d] = 0.0;
5553:       for (v = 0; v < coneSize; ++v) {DMLocalizeAddCoordinate_Internal(dm, spaceDim, &coords[off[0]], &coords[off[v]], &coordsNew[offnew]);}
5554:       for (d = 0; d < spaceDim; ++d) coordsNew[offnew+d] /= coneSize;
5555:       DMPlexRestoreTransitiveClosure(dm, f, PETSC_TRUE, &closureSize, &cone);
5556:     }
5557:   case REFINER_HEX_2D:
5558:   case REFINER_HYBRID_HEX_2D:
5559:   case REFINER_SIMPLEX_1D:
5560:     /* Cell vertices have the average of corner coordinates */
5561:     for (c = cStart; c < cMax; ++c) {
5562:       const PetscInt newv = vStartNew + (vEnd - vStart) + (dim > 1 ? (eMax - eStart) : 0) + (c - cStart) + (dim > 2 ? (fMax - fStart) : 0);
5563:       PetscInt      *cone = NULL;
5564:       PetscInt       closureSize, coneSize = 0, off[8], offnew, p, d;

5566:       DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &cone);
5567:       for (p = 0; p < closureSize*2; p += 2) {
5568:         const PetscInt point = cone[p];
5569:         if ((point >= vStart) && (point < vEnd)) cone[coneSize++] = point;
5570:       }
5571:       for (v = 0; v < coneSize; ++v) {
5572:         PetscSectionGetOffset(coordSection, cone[v], &off[v]);
5573:       }
5574:       PetscSectionGetOffset(coordSectionNew, newv, &offnew);
5575:       for (d = 0; d < spaceDim; ++d) coordsNew[offnew+d] = 0.0;
5576:       for (v = 0; v < coneSize; ++v) {DMLocalizeAddCoordinate_Internal(dm, spaceDim, &coords[off[0]], &coords[off[v]], &coordsNew[offnew]);}
5577:       for (d = 0; d < spaceDim; ++d) coordsNew[offnew+d] /= coneSize;
5578:       DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &cone);
5579:     }
5580:   case REFINER_SIMPLEX_2D:
5581:   case REFINER_HYBRID_SIMPLEX_2D:
5582:   case REFINER_SIMPLEX_3D:
5583:   case REFINER_HYBRID_SIMPLEX_3D:
5584:     /* Edge vertices have the average of endpoint coordinates */
5585:     for (e = eStart; e < eMax; ++e) {
5586:       const PetscInt  newv = vStartNew + (vEnd - vStart) + (e - eStart);
5587:       const PetscInt *cone;
5588:       PetscInt        coneSize, offA, offB, offnew, d;

5590:       DMPlexGetConeSize(dm, e, &coneSize);
5591:       if (coneSize != 2) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Edge %d cone should have two vertices, not %d", e, coneSize);
5592:       DMPlexGetCone(dm, e, &cone);
5593:       PetscSectionGetOffset(coordSection, cone[0], &offA);
5594:       PetscSectionGetOffset(coordSection, cone[1], &offB);
5595:       PetscSectionGetOffset(coordSectionNew, newv, &offnew);
5596:       DMLocalizeCoordinate_Internal(dm, spaceDim, &coords[offA], &coords[offB], &coordsNew[offnew]);
5597:       for (d = 0; d < spaceDim; ++d) {
5598:         coordsNew[offnew+d] = 0.5*(coords[offA+d] + coordsNew[offnew+d]);
5599:       }
5600:     }
5601:     /* Old vertices have the same coordinates */
5602:     for (v = vStart; v < vEnd; ++v) {
5603:       const PetscInt newv = vStartNew + (v - vStart);
5604:       PetscInt       off, offnew, d;

5606:       PetscSectionGetOffset(coordSection, v, &off);
5607:       PetscSectionGetOffset(coordSectionNew, newv, &offnew);
5608:       for (d = 0; d < spaceDim; ++d) {
5609:         coordsNew[offnew+d] = coords[off+d];
5610:       }
5611:     }
5612:     break;
5613:   default:
5614:     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
5615:   }
5616:   VecRestoreArray(coordinates, &coords);
5617:   VecRestoreArray(coordinatesNew, &coordsNew);
5618:   DMSetCoordinatesLocal(rdm, coordinatesNew);
5619:   VecDestroy(&coordinatesNew);
5620:   PetscSectionDestroy(&coordSectionNew);
5621:   if (dm->maxCell) {
5622:     const PetscReal *maxCell, *L;
5623:     const DMBoundaryType *bd;
5624:     DMGetPeriodicity(dm,  &maxCell, &L, &bd);
5625:     DMSetPeriodicity(rdm,  maxCell,  L,  bd);
5626:   }
5627:   return(0);
5628: }

5632: /*@
5633:   DMPlexCreateProcessSF - Create an SF which just has process connectivity

5635:   Collective on DM

5637:   Input Parameters:
5638: + dm      - The DM
5639: - sfPoint - The PetscSF which encodes point connectivity

5641:   Output Parameters:
5642: + processRanks - A list of process neighbors, or NULL
5643: - sfProcess    - An SF encoding the process connectivity, or NULL

5645:   Level: developer

5647: .seealso: PetscSFCreate(), DMPlexCreateTwoSidedProcessSF()
5648: @*/
5649: PetscErrorCode DMPlexCreateProcessSF(DM dm, PetscSF sfPoint, IS *processRanks, PetscSF *sfProcess)
5650: {
5651:   PetscInt           numRoots, numLeaves, l;
5652:   const PetscInt    *localPoints;
5653:   const PetscSFNode *remotePoints;
5654:   PetscInt          *localPointsNew;
5655:   PetscSFNode       *remotePointsNew;
5656:   PetscInt          *ranks, *ranksNew;
5657:   PetscMPIInt        numProcs;
5658:   PetscErrorCode     ierr;

5665:   MPI_Comm_size(PetscObjectComm((PetscObject) dm), &numProcs);
5666:   PetscSFGetGraph(sfPoint, &numRoots, &numLeaves, &localPoints, &remotePoints);
5667:   PetscMalloc1(numLeaves, &ranks);
5668:   for (l = 0; l < numLeaves; ++l) {
5669:     ranks[l] = remotePoints[l].rank;
5670:   }
5671:   PetscSortRemoveDupsInt(&numLeaves, ranks);
5672:   PetscMalloc1(numLeaves, &ranksNew);
5673:   PetscMalloc1(numLeaves, &localPointsNew);
5674:   PetscMalloc1(numLeaves, &remotePointsNew);
5675:   for (l = 0; l < numLeaves; ++l) {
5676:     ranksNew[l]              = ranks[l];
5677:     localPointsNew[l]        = l;
5678:     remotePointsNew[l].index = 0;
5679:     remotePointsNew[l].rank  = ranksNew[l];
5680:   }
5681:   PetscFree(ranks);
5682:   if (processRanks) {ISCreateGeneral(PetscObjectComm((PetscObject)dm), numLeaves, ranksNew, PETSC_OWN_POINTER, processRanks);}
5683:   else              {PetscFree(ranksNew);}
5684:   if (sfProcess) {
5685:     PetscSFCreate(PetscObjectComm((PetscObject)dm), sfProcess);
5686:     PetscObjectSetName((PetscObject) *sfProcess, "Process SF");
5687:     PetscSFSetFromOptions(*sfProcess);
5688:     PetscSFSetGraph(*sfProcess, numProcs, numLeaves, localPointsNew, PETSC_OWN_POINTER, remotePointsNew, PETSC_OWN_POINTER);
5689:   }
5690:   return(0);
5691: }

5695: static PetscErrorCode CellRefinerCreateSF(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
5696: {
5697:   PetscSF            sf, sfNew, sfProcess;
5698:   IS                 processRanks;
5699:   MPI_Datatype       depthType;
5700:   PetscInt           numRoots, numLeaves, numLeavesNew = 0, l, m;
5701:   const PetscInt    *localPoints, *neighbors;
5702:   const PetscSFNode *remotePoints;
5703:   PetscInt          *localPointsNew;
5704:   PetscSFNode       *remotePointsNew;
5705:   PetscInt          *depthSizeOld, *rdepthSize, *rdepthSizeOld, *rdepthMaxOld, *rvStart, *rvStartNew, *reStart, *reStartNew, *rfStart, *rfStartNew, *rcStart, *rcStartNew;
5706:   PetscInt           ldepth, depth, numNeighbors, pStartNew, pEndNew, cStart, cEnd, cMax, vStart, vEnd, vMax, fStart, fEnd, fMax, eStart, eEnd, eMax, r, n;
5707:   PetscInt           cStartNew = 0, vStartNew = 0, fStartNew = 0, eStartNew = 0;
5708:   PetscErrorCode     ierr;

5711:   DMPlexGetChart(rdm, &pStartNew, &pEndNew);
5712:   DMPlexGetDepth(dm, &ldepth);
5713:   MPIU_Allreduce(&ldepth, &depth, 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject) dm));
5714:   if ((ldepth >= 0) && (depth != ldepth)) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Inconsistent Plex depth %d != %d", ldepth, depth);
5715:   DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);
5716:   DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);
5717:   DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);
5718:   DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);
5719:   DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);
5720:   cMax = cMax < 0 ? cEnd : cMax;
5721:   fMax = fMax < 0 ? fEnd : fMax;
5722:   eMax = eMax < 0 ? eEnd : eMax;
5723:   if (refiner) {GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);}
5724:   DMGetPointSF(dm, &sf);
5725:   DMGetPointSF(rdm, &sfNew);
5726:   /* Calculate size of new SF */
5727:   PetscSFGetGraph(sf, &numRoots, &numLeaves, &localPoints, &remotePoints);
5728:   if (numRoots < 0) return(0);
5729:   for (l = 0; l < numLeaves; ++l) {
5730:     const PetscInt p = localPoints[l];

5732:     switch (refiner) {
5733:     case REFINER_SIMPLEX_1D:
5734:       if ((p >= vStart) && (p < vEnd)) {
5735:         /* Interior vertices stay the same */
5736:         ++numLeavesNew;
5737:       } else if ((p >= cStart && p < cMax)) {
5738:         /* Interior cells add new cells and interior vertices */
5739:         numLeavesNew += 2 + 1;
5740:       }
5741:       break;
5742:     case REFINER_SIMPLEX_2D:
5743:     case REFINER_HYBRID_SIMPLEX_2D:
5744:       if ((p >= vStart) && (p < vEnd)) {
5745:         /* Interior vertices stay the same */
5746:         ++numLeavesNew;
5747:       } else if ((p >= fStart) && (p < fMax)) {
5748:         /* Interior faces add new faces and vertex */
5749:         numLeavesNew += 2 + 1;
5750:       } else if ((p >= fMax) && (p < fEnd)) {
5751:         /* Hybrid faces stay the same */
5752:         ++numLeavesNew;
5753:       } else if ((p >= cStart) && (p < cMax)) {
5754:         /* Interior cells add new cells and interior faces */
5755:         numLeavesNew += 4 + 3;
5756:       } else if ((p >= cMax) && (p < cEnd)) {
5757:         /* Hybrid cells add new cells and hybrid face */
5758:         numLeavesNew += 2 + 1;
5759:       }
5760:       break;
5761:     case REFINER_HEX_2D:
5762:     case REFINER_HYBRID_HEX_2D:
5763:       if ((p >= vStart) && (p < vEnd)) {
5764:         /* Interior vertices stay the same */
5765:         ++numLeavesNew;
5766:       } else if ((p >= fStart) && (p < fMax)) {
5767:         /* Interior faces add new faces and vertex */
5768:         numLeavesNew += 2 + 1;
5769:       } else if ((p >= fMax) && (p < fEnd)) {
5770:         /* Hybrid faces stay the same */
5771:         ++numLeavesNew;
5772:       } else if ((p >= cStart) && (p < cMax)) {
5773:         /* Interior cells add new cells, interior faces, and vertex */
5774:         numLeavesNew += 4 + 4 + 1;
5775:       } else if ((p >= cMax) && (p < cEnd)) {
5776:         /* Hybrid cells add new cells and hybrid face */
5777:         numLeavesNew += 2 + 1;
5778:       }
5779:       break;
5780:     case REFINER_SIMPLEX_3D:
5781:     case REFINER_HYBRID_SIMPLEX_3D:
5782:       if ((p >= vStart) && (p < vEnd)) {
5783:         /* Interior vertices stay the same */
5784:         ++numLeavesNew;
5785:       } else if ((p >= eStart) && (p < eMax)) {
5786:         /* Interior edges add new edges and vertex */
5787:         numLeavesNew += 2 + 1;
5788:       } else if ((p >= eMax) && (p < eEnd)) {
5789:         /* Hybrid edges stay the same */
5790:         ++numLeavesNew;
5791:       } else if ((p >= fStart) && (p < fMax)) {
5792:         /* Interior faces add new faces and edges */
5793:         numLeavesNew += 4 + 3;
5794:       } else if ((p >= fMax) && (p < fEnd)) {
5795:         /* Hybrid faces add new faces and edges */
5796:         numLeavesNew += 2 + 1;
5797:       } else if ((p >= cStart) && (p < cMax)) {
5798:         /* Interior cells add new cells, faces, and edges */
5799:         numLeavesNew += 8 + 8 + 1;
5800:       } else if ((p >= cMax) && (p < cEnd)) {
5801:         /* Hybrid cells add new cells and faces */
5802:         numLeavesNew += 4 + 3;
5803:       }
5804:       break;
5805:     case REFINER_HEX_3D:
5806:     case REFINER_HYBRID_HEX_3D:
5807:       if ((p >= vStart) && (p < vEnd)) {
5808:         /* Old vertices stay the same */
5809:         ++numLeavesNew;
5810:       } else if ((p >= eStart) && (p < eMax)) {
5811:         /* Interior edges add new edges, and vertex */
5812:         numLeavesNew += 2 + 1;
5813:       } else if ((p >= eMax) && (p < eEnd)) {
5814:         /* Hybrid edges stay the same */
5815:         ++numLeavesNew;
5816:       } else if ((p >= fStart) && (p < fMax)) {
5817:         /* Interior faces add new faces, edges, and vertex */
5818:         numLeavesNew += 4 + 4 + 1;
5819:       } else if ((p >= fMax) && (p < fEnd)) {
5820:         /* Hybrid faces add new faces and edges */
5821:         numLeavesNew += 2 + 1;
5822:       } else if ((p >= cStart) && (p < cMax)) {
5823:         /* Interior cells add new cells, faces, edges, and vertex */
5824:         numLeavesNew += 8 + 12 + 6 + 1;
5825:       } else if ((p >= cStart) && (p < cEnd)) {
5826:         /* Hybrid cells add new cells, faces, and edges */
5827:         numLeavesNew += 4 + 4 + 1;
5828:       }
5829:       break;
5830:     default:
5831:       SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
5832:     }
5833:   }
5834:   /* Communicate depthSizes for each remote rank */
5835:   DMPlexCreateProcessSF(dm, sf, &processRanks, &sfProcess);
5836:   ISGetLocalSize(processRanks, &numNeighbors);
5837:   PetscMalloc5((depth+1)*numNeighbors,&rdepthSize,numNeighbors,&rvStartNew,numNeighbors,&reStartNew,numNeighbors,&rfStartNew,numNeighbors,&rcStartNew);
5838:   PetscMalloc7(depth+1,&depthSizeOld,(depth+1)*numNeighbors,&rdepthSizeOld,(depth+1)*numNeighbors,&rdepthMaxOld,numNeighbors,&rvStart,numNeighbors,&reStart,numNeighbors,&rfStart,numNeighbors,&rcStart);
5839:   MPI_Type_contiguous(depth+1, MPIU_INT, &depthType);
5840:   MPI_Type_commit(&depthType);
5841:   PetscSFBcastBegin(sfProcess, depthType, depthSize, rdepthSize);
5842:   PetscSFBcastEnd(sfProcess, depthType, depthSize, rdepthSize);
5843:   for (n = 0; n < numNeighbors; ++n) {
5844:     GetDepthStart_Private(depth, &rdepthSize[n*(depth+1)], &rcStartNew[n], &rfStartNew[n], &reStartNew[n], &rvStartNew[n]);
5845:   }
5846:   depthSizeOld[depth]   = cMax;
5847:   depthSizeOld[0]       = vMax;
5848:   depthSizeOld[depth-1] = fMax;
5849:   depthSizeOld[1]       = eMax;

5851:   PetscSFBcastBegin(sfProcess, depthType, depthSizeOld, rdepthMaxOld);
5852:   PetscSFBcastEnd(sfProcess, depthType, depthSizeOld, rdepthMaxOld);

5854:   depthSizeOld[depth]   = cEnd - cStart;
5855:   depthSizeOld[0]       = vEnd - vStart;
5856:   depthSizeOld[depth-1] = fEnd - fStart;
5857:   depthSizeOld[1]       = eEnd - eStart;

5859:   PetscSFBcastBegin(sfProcess, depthType, depthSizeOld, rdepthSizeOld);
5860:   PetscSFBcastEnd(sfProcess, depthType, depthSizeOld, rdepthSizeOld);
5861:   for (n = 0; n < numNeighbors; ++n) {
5862:     GetDepthStart_Private(depth, &rdepthSizeOld[n*(depth+1)], &rcStart[n], &rfStart[n], &reStart[n], &rvStart[n]);
5863:     rdepthMaxOld[n*(depth+1)+depth]   = rdepthMaxOld[n*(depth+1)+depth]   < 0 ? rdepthSizeOld[n*(depth+1)+depth]  +rcStart[n]: rdepthMaxOld[n*(depth+1)+depth];
5864:     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];
5865:     rdepthMaxOld[n*(depth+1)+1]       = rdepthMaxOld[n*(depth+1)+1]       < 0 ? rdepthSizeOld[n*(depth+1)+1]      +reStart[n]: rdepthMaxOld[n*(depth+1)+1];
5866:   }
5867:   MPI_Type_free(&depthType);
5868:   PetscSFDestroy(&sfProcess);
5869:   /* Calculate new point SF */
5870:   PetscMalloc1(numLeavesNew, &localPointsNew);
5871:   PetscMalloc1(numLeavesNew, &remotePointsNew);
5872:   ISGetIndices(processRanks, &neighbors);
5873:   for (l = 0, m = 0; l < numLeaves; ++l) {
5874:     PetscInt    p     = localPoints[l];
5875:     PetscInt    rp    = remotePoints[l].index, n;
5876:     PetscMPIInt rrank = remotePoints[l].rank;

5878:     PetscFindInt(rrank, numNeighbors, neighbors, &n);
5879:     if (n < 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Could not locate remote rank %d", rrank);
5880:     switch (refiner) {
5881:     case REFINER_SIMPLEX_1D:
5882:       if ((p >= vStart) && (p < vEnd)) {
5883:         /* Old 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 >= cStart) && (p < cMax)) {
5889:         /* Old interior cells add new cells and vertex */
5890:         for (r = 0; r < 2; ++r, ++m) {
5891:           localPointsNew[m]        = cStartNew     + (p  - cStart)*2     + r;
5892:           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*2 + r;
5893:           remotePointsNew[m].rank  = rrank;
5894:         }
5895:         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - cStart);
5896:         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - rcStart[n]);
5897:         remotePointsNew[m].rank  = rrank;
5898:         ++m;
5899:       }
5900:       break;
5901:     case REFINER_SIMPLEX_2D:
5902:     case REFINER_HYBRID_SIMPLEX_2D:
5903:       if ((p >= vStart) && (p < vEnd)) {
5904:         /* Old vertices stay the same */
5905:         localPointsNew[m]        = vStartNew     + (p  - vStart);
5906:         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
5907:         remotePointsNew[m].rank  = rrank;
5908:         ++m;
5909:       } else if ((p >= fStart) && (p < fMax)) {
5910:         /* Old interior faces add new faces and vertex */
5911:         for (r = 0; r < 2; ++r, ++m) {
5912:           localPointsNew[m]        = fStartNew     + (p  - fStart)*2     + r;
5913:           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*2 + r;
5914:           remotePointsNew[m].rank  = rrank;
5915:         }
5916:         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - fStart);
5917:         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - rfStart[n]);
5918:         remotePointsNew[m].rank  = rrank;
5919:         ++m;
5920:       } else if ((p >= fMax) && (p < fEnd)) {
5921:         /* Old hybrid faces stay the same */
5922:         localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (p  - fMax);
5923:         remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*2 + (rp - rdepthMaxOld[n*(depth+1)+depth-1]);
5924:         remotePointsNew[m].rank  = rrank;
5925:         ++m;
5926:       } else if ((p >= cStart) && (p < cMax)) {
5927:         /* Old interior cells add new cells and interior faces */
5928:         for (r = 0; r < 4; ++r, ++m) {
5929:           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
5930:           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
5931:           remotePointsNew[m].rank  = rrank;
5932:         }
5933:         for (r = 0; r < 3; ++r, ++m) {
5934:           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (p  - cStart)*3     + r;
5935:           remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*2 + (rp - rcStart[n])*3 + r;
5936:           remotePointsNew[m].rank  = rrank;
5937:         }
5938:       } else if ((p >= cMax) && (p < cEnd)) {
5939:         /* Old hybrid cells add new cells and hybrid face */
5940:         for (r = 0; r < 2; ++r, ++m) {
5941:           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
5942:           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
5943:           remotePointsNew[m].rank  = rrank;
5944:         }
5945:         localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (cMax                            - cStart)*3     + (p  - cMax);
5946:         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]);
5947:         remotePointsNew[m].rank  = rrank;
5948:         ++m;
5949:       }
5950:       break;
5951:     case REFINER_HEX_2D:
5952:     case REFINER_HYBRID_HEX_2D:
5953:       if ((p >= vStart) && (p < vEnd)) {
5954:         /* Old vertices stay the same */
5955:         localPointsNew[m]        = vStartNew     + (p  - vStart);
5956:         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
5957:         remotePointsNew[m].rank  = rrank;
5958:         ++m;
5959:       } else if ((p >= fStart) && (p < fMax)) {
5960:         /* Old interior faces add new faces and vertex */
5961:         for (r = 0; r < 2; ++r, ++m) {
5962:           localPointsNew[m]        = fStartNew     + (p  - fStart)*2     + r;
5963:           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*2 + r;
5964:           remotePointsNew[m].rank  = rrank;
5965:         }
5966:         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - fStart);
5967:         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - rfStart[n]);
5968:         remotePointsNew[m].rank  = rrank;
5969:         ++m;
5970:       } else if ((p >= fMax) && (p < fEnd)) {
5971:         /* Old hybrid faces stay the same */
5972:         localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (p  - fMax);
5973:         remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*2 + (rp - rdepthMaxOld[n*(depth+1)+depth-1]);
5974:         remotePointsNew[m].rank  = rrank;
5975:         ++m;
5976:       } else if ((p >= cStart) && (p < cMax)) {
5977:         /* Old interior cells add new cells, interior faces, and vertex */
5978:         for (r = 0; r < 4; ++r, ++m) {
5979:           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
5980:           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
5981:           remotePointsNew[m].rank  = rrank;
5982:         }
5983:         for (r = 0; r < 4; ++r, ++m) {
5984:           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (p  - cStart)*4     + r;
5985:           remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*2 + (rp - rcStart[n])*4 + r;
5986:           remotePointsNew[m].rank  = rrank;
5987:         }
5988:         localPointsNew[m]        = vStartNew     + (vEnd - vStart)               + (fMax                              - fStart)     + (p  - cStart);
5989:         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0]  + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n]) + (rp - rcStart[n]);
5990:         remotePointsNew[m].rank  = rrank;
5991:         ++m;
5992:       } else if ((p >= cStart) && (p < cMax)) {
5993:         /* Old hybrid cells add new cells and hybrid face */
5994:         for (r = 0; r < 2; ++r, ++m) {
5995:           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
5996:           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
5997:           remotePointsNew[m].rank  = rrank;
5998:         }
5999:         localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (cMax                            - cStart)*4     + (p  - cMax);
6000:         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]);
6001:         remotePointsNew[m].rank  = rrank;
6002:         ++m;
6003:       }
6004:       break;
6005:     case REFINER_SIMPLEX_3D:
6006:     case REFINER_HYBRID_SIMPLEX_3D:
6007:       if ((p >= vStart) && (p < vEnd)) {
6008:         /* Interior vertices stay the same */
6009:         localPointsNew[m]        = vStartNew     + (p  - vStart);
6010:         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
6011:         remotePointsNew[m].rank  = rrank;
6012:         ++m;
6013:       } else if ((p >= eStart) && (p < eMax)) {
6014:         /* Interior edges add new edges and vertex */
6015:         for (r = 0; r < 2; ++r, ++m) {
6016:           localPointsNew[m]        = eStartNew     + (p  - eStart)*2     + r;
6017:           remotePointsNew[m].index = reStartNew[n] + (rp - reStart[n])*2 + r;
6018:           remotePointsNew[m].rank  = rrank;
6019:         }
6020:         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - eStart);
6021:         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - reStart[n]);
6022:         remotePointsNew[m].rank  = rrank;
6023:         ++m;
6024:       } else if ((p >= eMax) && (p < eEnd)) {
6025:         /* Hybrid edges stay the same */
6026:         localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (fMax                              - fStart)*3     + (cMax                            - cStart)     + (p  - eMax);
6027:         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]);
6028:         remotePointsNew[m].rank  = rrank;
6029:         ++m;
6030:       } else if ((p >= fStart) && (p < fMax)) {
6031:         /* Interior faces add new faces and edges */
6032:         for (r = 0; r < 4; ++r, ++m) {
6033:           localPointsNew[m]        = fStartNew     + (p  - fStart)*4     + r;
6034:           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*4 + r;
6035:           remotePointsNew[m].rank  = rrank;
6036:         }
6037:         for (r = 0; r < 3; ++r, ++m) {
6038:           localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (p  - fStart)*3     + r;
6039:           remotePointsNew[m].index = reStartNew[n] + (rdepthMaxOld[n*(depth+1)+1] - reStart[n])*2 + (rp - rfStart[n])*3 + r;
6040:           remotePointsNew[m].rank  = rrank;
6041:         }
6042:       } else if ((p >= fMax) && (p < fEnd)) {
6043:         /* Hybrid faces add new faces and edges */
6044:         for (r = 0; r < 2; ++r, ++m) {
6045:           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*4     + (cMax                            - cStart)*8     + (p  - fMax)*2                              + r;
6046:           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;
6047:           remotePointsNew[m].rank  = rrank;
6048:         }
6049:         localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (fMax                              - fStart)*3     + (cMax                            - cStart)     + (eEnd                                    - eMax)                        + (p  - fMax);
6050:         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]);
6051:         remotePointsNew[m].rank  = rrank;
6052:         ++m;
6053:       } else if ((p >= cStart) && (p < cMax)) {
6054:         /* Interior cells add new cells, faces, and edges */
6055:         for (r = 0; r < 8; ++r, ++m) {
6056:           localPointsNew[m]        = cStartNew     + (p  - cStart)*8     + r;
6057:           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*8 + r;
6058:           remotePointsNew[m].rank  = rrank;
6059:         }
6060:         for (r = 0; r < 8; ++r, ++m) {
6061:           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*4     + (p  - cStart)*8     + r;
6062:           remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*4 + (rp - rcStart[n])*8 + r;
6063:           remotePointsNew[m].rank  = rrank;
6064:         }
6065:         localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (fMax                              - fStart)*3     + (p  - cStart)*1     + 0;
6066:         remotePointsNew[m].index = reStartNew[n] + (rdepthMaxOld[n*(depth+1)+1] - reStart[n])*2 + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*3 + (rp - rcStart[n])*1 + 0;
6067:         remotePointsNew[m].rank  = rrank;
6068:         ++m;
6069:       } else if ((p >= cMax) && (p < cEnd)) {
6070:         /* Hybrid cells add new cells and faces */
6071:         for (r = 0; r < 4; ++r, ++m) {
6072:           localPointsNew[m]        = cStartNew     + (cMax                            - cStart)*8     + (p  - cMax)*4                            + r;
6073:           remotePointsNew[m].index = rcStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth] - rcStart[n])*8 + (rp - rdepthMaxOld[n*(depth+1)+depth])*4 + r;
6074:           remotePointsNew[m].rank  = rrank;
6075:         }
6076:         for (r = 0; r < 3; ++r, ++m) {
6077:           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*4     + (cMax                            - cStart)*8     + (fEnd                                          - fMax)*2                              + (p  - cMax)*3                            + r;
6078:           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;
6079:           remotePointsNew[m].rank  = rrank;
6080:         }
6081:       }
6082:       break;
6083:     case REFINER_HEX_3D:
6084:     case REFINER_HYBRID_HEX_3D:
6085:       if ((p >= vStart) && (p < vEnd)) {
6086:         /* Interior vertices stay the same */
6087:         localPointsNew[m]        = vStartNew     + (p  - vStart);
6088:         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
6089:         remotePointsNew[m].rank  = rrank;
6090:         ++m;
6091:       } else if ((p >= eStart) && (p < eMax)) {
6092:         /* Interior edges add new edges and vertex */
6093:         for (r = 0; r < 2; ++r, ++m) {
6094:           localPointsNew[m]        = eStartNew     + (p  - eStart)*2     + r;
6095:           remotePointsNew[m].index = reStartNew[n] + (rp - reStart[n])*2 + r;
6096:           remotePointsNew[m].rank  = rrank;
6097:         }
6098:         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - eStart);
6099:         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - reStart[n]);
6100:         remotePointsNew[m].rank  = rrank;
6101:         ++m;
6102:       } else if ((p >= eMax) && (p < eEnd)) {
6103:         /* Hybrid edges stay the same */
6104:         localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (fMax                              - fStart)*4     + (cMax                            - cStart)*6     + (p  - eMax);
6105:         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]);
6106:         remotePointsNew[m].rank  = rrank;
6107:         ++m;
6108:       } else if ((p >= fStart) && (p < fMax)) {
6109:         /* Interior faces add new faces, edges, and vertex */
6110:         for (r = 0; r < 4; ++r, ++m) {
6111:           localPointsNew[m]        = fStartNew     + (p  - fStart)*4     + r;
6112:           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*4 + r;
6113:           remotePointsNew[m].rank  = rrank;
6114:         }
6115:         for (r = 0; r < 4; ++r, ++m) {
6116:           localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (p  - fStart)*4     + r;
6117:           remotePointsNew[m].index = reStartNew[n] + (rdepthMaxOld[n*(depth+1)+1] - reStart[n])*2 + (rp - rfStart[n])*4 + r;
6118:           remotePointsNew[m].rank  = rrank;
6119:         }
6120:         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (eMax                        - eStart)     + (p  - fStart);
6121:         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rdepthMaxOld[n*(depth+1)+1] - reStart[n]) + (rp - rfStart[n]);
6122:         remotePointsNew[m].rank  = rrank;
6123:         ++m;
6124:       } else if ((p >= fMax) && (p < fEnd)) {
6125:         /* Hybrid faces add new faces and edges */
6126:         for (r = 0; r < 2; ++r, ++m) {
6127:           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*4     + (cMax                            - cStart)*12     + (p  - fMax)*2                              + r;
6128:           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;
6129:           remotePointsNew[m].rank  = rrank;
6130:         }
6131:         localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (fMax                              - fStart)*4     + (cMax                            - cStart)*6     + (eEnd                                    - eMax)                        + (p  - fMax);
6132:         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]);
6133:         remotePointsNew[m].rank  = rrank;
6134:         ++m;
6135:       } else if ((p >= cStart) && (p < cMax)) {
6136:         /* Interior cells add new cells, faces, edges, and vertex */
6137:         for (r = 0; r < 8; ++r, ++m) {
6138:           localPointsNew[m]        = cStartNew     + (p  - cStart)*8     + r;
6139:           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*8 + r;
6140:           remotePointsNew[m].rank  = rrank;
6141:         }
6142:         for (r = 0; r < 12; ++r, ++m) {
6143:           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*4     + (p  - cStart)*12     + r;
6144:           remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*4 + (rp - rcStart[n])*12 + r;
6145:           remotePointsNew[m].rank  = rrank;
6146:         }
6147:         for (r = 0; r < 6; ++r, ++m) {
6148:           localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (fMax                              - fStart)*4     + (p  - cStart)*6     + r;
6149:           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;
6150:           remotePointsNew[m].rank  = rrank;
6151:         }
6152:         for (r = 0; r < 1; ++r, ++m) {
6153:           localPointsNew[m]        = vStartNew     + (eMax                        - eStart)     + (fMax                              - fStart)     + (p  - cStart)     + r;
6154:           remotePointsNew[m].index = rvStartNew[n] + (rdepthMaxOld[n*(depth+1)+1] - reStart[n]) + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n]) + (rp - rcStart[n]) + r;
6155:           remotePointsNew[m].rank  = rrank;
6156:         }
6157:       } else if ((p >= cMax) && (p < cEnd)) {
6158:         /* Hybrid cells add new cells, faces, and edges */
6159:         for (r = 0; r < 4; ++r, ++m) {
6160:           localPointsNew[m]        = cStartNew     + (cMax                            - cStart)*8     + (p  - cMax)*4                            + r;
6161:           remotePointsNew[m].index = rcStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth] - rcStart[n])*8 + (rp - rdepthMaxOld[n*(depth+1)+depth])*4 + r;
6162:           remotePointsNew[m].rank  = rrank;
6163:         }
6164:         for (r = 0; r < 4; ++r, ++m) {
6165:           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*4     + (cMax                            - cStart)*12     + (fEnd                                          - fMax)*2                              + (p  - cMax)*4                            + r;
6166:           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;
6167:           remotePointsNew[m].rank  = rrank;
6168:         }
6169:         localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (fMax                              - fStart)*4     + (cMax                            - cStart)*6     + (eEnd                                    - eMax)                        + (fEnd                                          - fMax)                              + (p  - cMax);
6170:         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]);
6171:         remotePointsNew[m].rank  = rrank;
6172:         ++m;
6173:       }
6174:       break;
6175:     default:
6176:       SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
6177:     }
6178:   }
6179:   if (m != numLeavesNew) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Number of leaf point %d should be %d", m, numLeavesNew);
6180:   ISRestoreIndices(processRanks, &neighbors);
6181:   ISDestroy(&processRanks);
6182:   {
6183:     PetscSFNode *rp, *rtmp;
6184:     PetscInt    *lp, *idx, *ltmp, i;

6186:     /* SF needs sorted leaves to correct calculate Gather */
6187:     PetscMalloc1(numLeavesNew,&idx);
6188:     PetscMalloc1(numLeavesNew, &lp);
6189:     PetscMalloc1(numLeavesNew, &rp);
6190:     for (i = 0; i < numLeavesNew; ++i) {
6191:       if ((localPointsNew[i] < pStartNew) || (localPointsNew[i] >= pEndNew)) SETERRQ4(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Local SF point %d (%d) not in [%d, %d)", localPointsNew[i], i, pStartNew, pEndNew);
6192:       idx[i] = i;
6193:     }
6194:     PetscSortIntWithPermutation(numLeavesNew, localPointsNew, idx);
6195:     for (i = 0; i < numLeavesNew; ++i) {
6196:       lp[i] = localPointsNew[idx[i]];
6197:       rp[i] = remotePointsNew[idx[i]];
6198:     }
6199:     ltmp            = localPointsNew;
6200:     localPointsNew  = lp;
6201:     rtmp            = remotePointsNew;
6202:     remotePointsNew = rp;
6203:     PetscFree(idx);
6204:     PetscFree(ltmp);
6205:     PetscFree(rtmp);
6206:   }
6207:   PetscSFSetGraph(sfNew, pEndNew-pStartNew, numLeavesNew, localPointsNew, PETSC_OWN_POINTER, remotePointsNew, PETSC_OWN_POINTER);
6208:   PetscFree5(rdepthSize,rvStartNew,reStartNew,rfStartNew,rcStartNew);
6209:   PetscFree7(depthSizeOld,rdepthSizeOld,rdepthMaxOld,rvStart,reStart,rfStart,rcStart);
6210:   return(0);
6211: }

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

6223:   DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);
6224:   DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);
6225:   DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);
6226:   DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);
6227:   DMPlexGetDepth(dm, &depth);
6228:   if (refiner) {GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);}
6229:   DMGetNumLabels(dm, &numLabels);
6230:   DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);
6231:   switch (refiner) {
6232:   case REFINER_NOOP:
6233:   case REFINER_SIMPLEX_1D:
6234:   case REFINER_SIMPLEX_2D:
6235:   case REFINER_HEX_2D:
6236:   case REFINER_SIMPLEX_3D:
6237:   case REFINER_HEX_3D:
6238:     break;
6239:   case REFINER_HYBRID_SIMPLEX_3D:
6240:   case REFINER_HYBRID_HEX_3D:
6241:     if (eMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No edge maximum specified in hybrid mesh");
6242:   case REFINER_HYBRID_SIMPLEX_2D:
6243:   case REFINER_HYBRID_HEX_2D:
6244:     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
6245:     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
6246:     break;
6247:   default:
6248:     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
6249:   }
6250:   for (l = 0; l < numLabels; ++l) {
6251:     DMLabel         label, labelNew;
6252:     const char     *lname;
6253:     PetscBool       isDepth;
6254:     IS              valueIS;
6255:     const PetscInt *values;
6256:     PetscInt        defVal;
6257:     PetscInt        numValues, val;

6259:     DMGetLabelName(dm, l, &lname);
6260:     PetscStrcmp(lname, "depth", &isDepth);
6261:     if (isDepth) continue;
6262:     DMCreateLabel(rdm, lname);
6263:     DMGetLabel(dm, lname, &label);
6264:     DMGetLabel(rdm, lname, &labelNew);
6265:     DMLabelGetDefaultValue(label,&defVal);
6266:     DMLabelSetDefaultValue(labelNew,defVal);
6267:     DMLabelGetValueIS(label, &valueIS);
6268:     ISGetLocalSize(valueIS, &numValues);
6269:     ISGetIndices(valueIS, &values);
6270:     for (val = 0; val < numValues; ++val) {
6271:       IS              pointIS;
6272:       const PetscInt *points;
6273:       PetscInt        numPoints, n;

6275:       DMLabelGetStratumIS(label, values[val], &pointIS);
6276:       ISGetLocalSize(pointIS, &numPoints);
6277:       ISGetIndices(pointIS, &points);
6278:       /* Ensure refined label is created with same number of strata as
6279:        * original (even if no entries here). */
6280:       if (!numPoints) {
6281:         DMLabelSetValue(labelNew, 0, values[val]);
6282:         DMLabelClearValue(labelNew, 0, values[val]);
6283:       }
6284:       for (n = 0; n < numPoints; ++n) {
6285:         const PetscInt p = points[n];
6286:         switch (refiner) {
6287:         case REFINER_SIMPLEX_1D:
6288:           if ((p >= vStart) && (p < vEnd)) {
6289:             /* Old vertices stay the same */
6290:             newp = vStartNew + (p - vStart);
6291:             DMLabelSetValue(labelNew, newp, values[val]);
6292:           } else if ((p >= cStart) && (p < cEnd)) {
6293:             /* Old cells add new cells and vertex */
6294:             newp = vStartNew + (vEnd - vStart) + (p - cStart);
6295:             DMLabelSetValue(labelNew, newp, values[val]);
6296:             for (r = 0; r < 2; ++r) {
6297:               newp = cStartNew + (p - cStart)*2 + r;
6298:               DMLabelSetValue(labelNew, newp, values[val]);
6299:             }
6300:           }
6301:           break;
6302:         case REFINER_SIMPLEX_2D:
6303:           if ((p >= vStart) && (p < vEnd)) {
6304:             /* Old vertices stay the same */
6305:             newp = vStartNew + (p - vStart);
6306:             DMLabelSetValue(labelNew, newp, values[val]);
6307:           } else if ((p >= fStart) && (p < fEnd)) {
6308:             /* Old faces add new faces and vertex */
6309:             newp = vStartNew + (vEnd - vStart) + (p - fStart);
6310:             DMLabelSetValue(labelNew, newp, values[val]);
6311:             for (r = 0; r < 2; ++r) {
6312:               newp = fStartNew + (p - fStart)*2 + r;
6313:               DMLabelSetValue(labelNew, newp, values[val]);
6314:             }
6315:           } else if ((p >= cStart) && (p < cEnd)) {
6316:             /* Old cells add new cells and interior faces */
6317:             for (r = 0; r < 4; ++r) {
6318:               newp = cStartNew + (p - cStart)*4 + r;
6319:               DMLabelSetValue(labelNew, newp, values[val]);
6320:             }
6321:             for (r = 0; r < 3; ++r) {
6322:               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*3 + r;
6323:               DMLabelSetValue(labelNew, newp, values[val]);
6324:             }
6325:           }
6326:           break;
6327:         case REFINER_HEX_2D:
6328:           if ((p >= vStart) && (p < vEnd)) {
6329:             /* Old vertices stay the same */
6330:             newp = vStartNew + (p - vStart);
6331:             DMLabelSetValue(labelNew, newp, values[val]);
6332:           } else if ((p >= fStart) && (p < fEnd)) {
6333:             /* Old faces add new faces and vertex */
6334:             newp = vStartNew + (vEnd - vStart) + (p - fStart);
6335:             DMLabelSetValue(labelNew, newp, values[val]);
6336:             for (r = 0; r < 2; ++r) {
6337:               newp = fStartNew + (p - fStart)*2 + r;
6338:               DMLabelSetValue(labelNew, newp, values[val]);
6339:             }
6340:           } else if ((p >= cStart) && (p < cEnd)) {
6341:             /* Old cells add new cells and interior faces and vertex */
6342:             for (r = 0; r < 4; ++r) {
6343:               newp = cStartNew + (p - cStart)*4 + r;
6344:               DMLabelSetValue(labelNew, newp, values[val]);
6345:             }
6346:             for (r = 0; r < 4; ++r) {
6347:               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*4 + r;
6348:               DMLabelSetValue(labelNew, newp, values[val]);
6349:             }
6350:             newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (p - cStart);
6351:             DMLabelSetValue(labelNew, newp, values[val]);
6352:           }
6353:           break;
6354:         case REFINER_HYBRID_SIMPLEX_2D:
6355:           if ((p >= vStart) && (p < vEnd)) {
6356:             /* Old vertices stay the same */
6357:             newp = vStartNew + (p - vStart);
6358:             DMLabelSetValue(labelNew, newp, values[val]);
6359:           } else if ((p >= fStart) && (p < fMax)) {
6360:             /* Old interior faces add new faces and vertex */
6361:             newp = vStartNew + (vEnd - vStart) + (p - fStart);
6362:             DMLabelSetValue(labelNew, newp, values[val]);
6363:             for (r = 0; r < 2; ++r) {
6364:               newp = fStartNew + (p - fStart)*2 + r;
6365:               DMLabelSetValue(labelNew, newp, values[val]);
6366:             }
6367:           } else if ((p >= fMax) && (p < fEnd)) {
6368:             /* Old hybrid faces stay the same */
6369:             newp = fStartNew + (fMax - fStart)*2 + (p - fMax);
6370:             DMLabelSetValue(labelNew, newp, values[val]);
6371:           } else if ((p >= cStart) && (p < cMax)) {
6372:             /* Old interior cells add new cells and interior faces */
6373:             for (r = 0; r < 4; ++r) {
6374:               newp = cStartNew + (p - cStart)*4 + r;
6375:               DMLabelSetValue(labelNew, newp, values[val]);
6376:             }
6377:             for (r = 0; r < 3; ++r) {
6378:               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*3 + r;
6379:               DMLabelSetValue(labelNew, newp, values[val]);
6380:             }
6381:           } else if ((p >= cMax) && (p < cEnd)) {
6382:             /* Old hybrid cells add new cells and hybrid face */
6383:             for (r = 0; r < 2; ++r) {
6384:               newp = cStartNew + (cMax - cStart)*4 + (p - cMax)*2 + r;
6385:               DMLabelSetValue(labelNew, newp, values[val]);
6386:             }
6387:             newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (p - cMax);
6388:             DMLabelSetValue(labelNew, newp, values[val]);
6389:           }
6390:           break;
6391:         case REFINER_HYBRID_HEX_2D:
6392:           if ((p >= vStart) && (p < vEnd)) {
6393:             /* Old vertices stay the same */
6394:             newp = vStartNew + (p - vStart);
6395:             DMLabelSetValue(labelNew, newp, values[val]);
6396:           } else if ((p >= fStart) && (p < fMax)) {
6397:             /* Old interior faces add new faces and vertex */
6398:             newp = vStartNew + (vEnd - vStart) + (p - fStart);
6399:             DMLabelSetValue(labelNew, newp, values[val]);
6400:             for (r = 0; r < 2; ++r) {
6401:               newp = fStartNew + (p - fStart)*2 + r;
6402:               DMLabelSetValue(labelNew, newp, values[val]);
6403:             }
6404:           } else if ((p >= fMax) && (p < fEnd)) {
6405:             /* Old hybrid faces stay the same */
6406:             newp = fStartNew + (fMax - fStart)*2 + (p - fMax);
6407:             DMLabelSetValue(labelNew, newp, values[val]);
6408:           } else if ((p >= cStart) && (p < cMax)) {
6409:             /* Old interior cells add new cells, interior faces, and vertex */
6410:             for (r = 0; r < 4; ++r) {
6411:               newp = cStartNew + (p - cStart)*4 + r;
6412:               DMLabelSetValue(labelNew, newp, values[val]);
6413:             }
6414:             for (r = 0; r < 4; ++r) {
6415:               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*4 + r;
6416:               DMLabelSetValue(labelNew, newp, values[val]);
6417:             }
6418:             newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (p - cStart);
6419:             DMLabelSetValue(labelNew, newp, values[val]);
6420:           } else if ((p >= cMax) && (p < cEnd)) {
6421:             /* Old hybrid cells add new cells and hybrid face */
6422:             for (r = 0; r < 2; ++r) {
6423:               newp = cStartNew + (cMax - cStart)*4 + (p - cMax)*2 + r;
6424:               DMLabelSetValue(labelNew, newp, values[val]);
6425:             }
6426:             newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*4 + (p - cMax);
6427:             DMLabelSetValue(labelNew, newp, values[val]);
6428:           }
6429:           break;
6430:         case REFINER_SIMPLEX_3D:
6431:           if ((p >= vStart) && (p < vEnd)) {
6432:             /* Old vertices stay the same */
6433:             newp = vStartNew + (p - vStart);
6434:             DMLabelSetValue(labelNew, newp, values[val]);
6435:           } else if ((p >= eStart) && (p < eEnd)) {
6436:             /* Old edges add new edges and vertex */
6437:             for (r = 0; r < 2; ++r) {
6438:               newp = eStartNew + (p - eStart)*2 + r;
6439:               DMLabelSetValue(labelNew, newp, values[val]);
6440:             }
6441:             newp = vStartNew + (vEnd - vStart) + (p - eStart);
6442:             DMLabelSetValue(labelNew, newp, values[val]);
6443:           } else if ((p >= fStart) && (p < fEnd)) {
6444:             /* Old faces add new faces and edges */
6445:             for (r = 0; r < 4; ++r) {
6446:               newp = fStartNew + (p - fStart)*4 + r;
6447:               DMLabelSetValue(labelNew, newp, values[val]);
6448:             }
6449:             for (r = 0; r < 3; ++r) {
6450:               newp = eStartNew + (eEnd - eStart)*2 + (p - fStart)*3 + r;
6451:               DMLabelSetValue(labelNew, newp, values[val]);
6452:             }
6453:           } else if ((p >= cStart) && (p < cEnd)) {
6454:             /* Old cells add new cells and interior faces and edges */
6455:             for (r = 0; r < 8; ++r) {
6456:               newp = cStartNew + (p - cStart)*8 + r;
6457:               DMLabelSetValue(labelNew, newp, values[val]);
6458:             }
6459:             for (r = 0; r < 8; ++r) {
6460:               newp = fStartNew + (fEnd - fStart)*4 + (p - cStart)*8 + r;
6461:               DMLabelSetValue(labelNew, newp, values[val]);
6462:             }
6463:             for (r = 0; r < 1; ++r) {
6464:               newp = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (p - cStart)*1 + r;
6465:               DMLabelSetValue(labelNew, newp, values[val]);
6466:             }
6467:           }
6468:           break;
6469:         case REFINER_HYBRID_SIMPLEX_3D:
6470:           if ((p >= vStart) && (p < vEnd)) {
6471:             /* Interior vertices stay the same */
6472:             newp = vStartNew + (p - vStart);
6473:             DMLabelSetValue(labelNew, newp, values[val]);
6474:           } else if ((p >= eStart) && (p < eMax)) {
6475:             /* Interior edges add new edges and vertex */
6476:             for (r = 0; r < 2; ++r) {
6477:               newp = eStartNew + (p - eStart)*2 + r;
6478:               DMLabelSetValue(labelNew, newp, values[val]);
6479:             }
6480:             newp = vStartNew + (vEnd - vStart) + (p - eStart);
6481:             DMLabelSetValue(labelNew, newp, values[val]);
6482:           } else if ((p >= eMax) && (p < eEnd)) {
6483:             /* Hybrid edges stay the same */
6484:             newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (p - eMax);
6485:             DMLabelSetValue(labelNew, newp, values[val]);
6486:           } else if ((p >= fStart) && (p < fMax)) {
6487:             /* Interior faces add new faces and edges */
6488:             for (r = 0; r < 4; ++r) {
6489:               newp = fStartNew + (p - fStart)*4 + r;
6490:               DMLabelSetValue(labelNew, newp, values[val]);
6491:             }
6492:             for (r = 0; r < 3; ++r) {
6493:               newp = eStartNew + (eMax - eStart)*2 + (p - fStart)*3 + r;
6494:               DMLabelSetValue(labelNew, newp, values[val]);
6495:             }
6496:           } else if ((p >= fMax) && (p < fEnd)) {
6497:             /* Hybrid faces add new faces and edges */
6498:             for (r = 0; r < 2; ++r) {
6499:               newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (p - fMax)*2 + r;
6500:               DMLabelSetValue(labelNew, newp, values[val]);
6501:             }
6502:             newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (p - fMax);
6503:             DMLabelSetValue(labelNew, newp, values[val]);
6504:           } else if ((p >= cStart) && (p < cMax)) {
6505:             /* Interior cells add new cells, faces, and edges */
6506:             for (r = 0; r < 8; ++r) {
6507:               newp = cStartNew + (p - cStart)*8 + r;
6508:               DMLabelSetValue(labelNew, newp, values[val]);
6509:             }
6510:             for (r = 0; r < 8; ++r) {
6511:               newp = fStartNew + (fMax - fStart)*4 + (p - cStart)*8 + r;
6512:               DMLabelSetValue(labelNew, newp, values[val]);
6513:             }
6514:             newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (p - cStart);
6515:             DMLabelSetValue(labelNew, newp, values[val]);
6516:           } else if ((p >= cMax) && (p < cEnd)) {
6517:             /* Hybrid cells add new cells and faces */
6518:             for (r = 0; r < 4; ++r) {
6519:               newp = cStartNew + (cMax - cStart)*8 + (p - cMax)*4 + r;
6520:               DMLabelSetValue(labelNew, newp, values[val]);
6521:             }
6522:             for (r = 0; r < 3; ++r) {
6523:               newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (p - cMax)*3 + r;
6524:               DMLabelSetValue(labelNew, newp, values[val]);
6525:             }
6526:           }
6527:           break;
6528:         case REFINER_HEX_3D:
6529:           if ((p >= vStart) && (p < vEnd)) {
6530:             /* Old vertices stay the same */
6531:             newp = vStartNew + (p - vStart);
6532:             DMLabelSetValue(labelNew, newp, values[val]);
6533:           } else if ((p >= eStart) && (p < eEnd)) {
6534:             /* Old edges add new edges and vertex */
6535:             for (r = 0; r < 2; ++r) {
6536:               newp = eStartNew + (p - eStart)*2 + r;
6537:               DMLabelSetValue(labelNew, newp, values[val]);
6538:             }
6539:             newp = vStartNew + (vEnd - vStart) + (p - eStart);
6540:             DMLabelSetValue(labelNew, newp, values[val]);
6541:           } else if ((p >= fStart) && (p < fEnd)) {
6542:             /* Old faces add new faces, edges, and vertex */
6543:             for (r = 0; r < 4; ++r) {
6544:               newp = fStartNew + (p - fStart)*4 + r;
6545:               DMLabelSetValue(labelNew, newp, values[val]);
6546:             }
6547:             for (r = 0; r < 4; ++r) {
6548:               newp = eStartNew + (eEnd - eStart)*2 + (p - fStart)*4 + r;
6549:               DMLabelSetValue(labelNew, newp, values[val]);
6550:             }
6551:             newp = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (p - fStart);
6552:             DMLabelSetValue(labelNew, newp, values[val]);
6553:           } else if ((p >= cStart) && (p < cEnd)) {
6554:             /* Old cells add new cells, faces, edges, and vertex */
6555:             for (r = 0; r < 8; ++r) {
6556:               newp = cStartNew + (p - cStart)*8 + r;
6557:               DMLabelSetValue(labelNew, newp, values[val]);
6558:             }
6559:             for (r = 0; r < 12; ++r) {
6560:               newp = fStartNew + (fEnd - fStart)*4 + (p - cStart)*12 + r;
6561:               DMLabelSetValue(labelNew, newp, values[val]);
6562:             }
6563:             for (r = 0; r < 6; ++r) {
6564:               newp = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*4 + (p - cStart)*6 + r;
6565:               DMLabelSetValue(labelNew, newp, values[val]);
6566:             }
6567:             newp = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (fEnd - fStart) + (p - cStart);
6568:             DMLabelSetValue(labelNew, newp, values[val]);
6569:           }
6570:           break;
6571:         case REFINER_HYBRID_HEX_3D:
6572:           if ((p >= vStart) && (p < vEnd)) {
6573:             /* Interior vertices stay the same */
6574:             newp = vStartNew + (p - vStart);
6575:             DMLabelSetValue(labelNew, newp, values[val]);
6576:           } else if ((p >= eStart) && (p < eMax)) {
6577:             /* Interior edges add new edges and vertex */
6578:             for (r = 0; r < 2; ++r) {
6579:               newp = eStartNew + (p - eStart)*2 + r;
6580:               DMLabelSetValue(labelNew, newp, values[val]);
6581:             }
6582:             newp = vStartNew + (vEnd - vStart) + (p - eStart);
6583:             DMLabelSetValue(labelNew, newp, values[val]);
6584:           } else if ((p >= eMax) && (p < eEnd)) {
6585:             /* Hybrid edges stay the same */
6586:             newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (p - eMax);
6587:             DMLabelSetValue(labelNew, newp, values[val]);
6588:           } else if ((p >= fStart) && (p < fMax)) {
6589:             /* Interior faces add new faces, edges, and vertex */
6590:             for (r = 0; r < 4; ++r) {
6591:               newp = fStartNew + (p - fStart)*4 + r;
6592:               DMLabelSetValue(labelNew, newp, values[val]);
6593:             }
6594:             for (r = 0; r < 4; ++r) {
6595:               newp = eStartNew + (eMax - eStart)*2 + (p - fStart)*4 + r;
6596:               DMLabelSetValue(labelNew, newp, values[val]);
6597:             }
6598:             newp = vStartNew + (vEnd - vStart) + (eMax - eStart) + (p - fStart);
6599:             DMLabelSetValue(labelNew, newp, values[val]);
6600:           } else if ((p >= fMax) && (p < fEnd)) {
6601:             /* Hybrid faces add new faces and edges */
6602:             for (r = 0; r < 2; ++r) {
6603:               newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (p - fMax)*2 + r;
6604:               DMLabelSetValue(labelNew, newp, values[val]);
6605:             }
6606:             newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (p - fMax);
6607:             DMLabelSetValue(labelNew, newp, values[val]);
6608:           } else if ((p >= cStart) && (p < cMax)) {
6609:             /* Interior cells add new cells, faces, edges, and vertex */
6610:             for (r = 0; r < 8; ++r) {
6611:               newp = cStartNew + (p - cStart)*8 + r;
6612:               DMLabelSetValue(labelNew, newp, values[val]);
6613:             }
6614:             for (r = 0; r < 12; ++r) {
6615:               newp = fStartNew + (fMax - fStart)*4 + (p - cStart)*12 + r;
6616:               DMLabelSetValue(labelNew, newp, values[val]);
6617:             }
6618:             for (r = 0; r < 6; ++r) {
6619:               newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (p - cStart)*6 + r;
6620:               DMLabelSetValue(labelNew, newp, values[val]);
6621:             }
6622:             newp = vStartNew + (vEnd - vStart) + (eMax - eStart) + (fMax - fStart) + (p - cStart);
6623:             DMLabelSetValue(labelNew, newp, values[val]);
6624:           } else if ((p >= cMax) && (p < cEnd)) {
6625:             /* Hybrid cells add new cells, faces, and edges */
6626:             for (r = 0; r < 4; ++r) {
6627:               newp = cStartNew + (cMax - cStart)*8 + (p - cMax)*4 + r;
6628:               DMLabelSetValue(labelNew, newp, values[val]);
6629:             }
6630:             for (r = 0; r < 4; ++r) {
6631:               newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd - fMax)*2 + (p - cMax)*4 + r;
6632:               DMLabelSetValue(labelNew, newp, values[val]);
6633:             }
6634:             newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (fEnd - fMax) + (p - cMax);
6635:             DMLabelSetValue(labelNew, newp, values[val]);
6636:           }
6637:           break;
6638:         default:
6639:           SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
6640:         }
6641:       }
6642:       ISRestoreIndices(pointIS, &points);
6643:       ISDestroy(&pointIS);
6644:     }
6645:     ISRestoreIndices(valueIS, &values);
6646:     ISDestroy(&valueIS);
6647:     if (0) {
6648:       DMLabelView(labelNew, PETSC_VIEWER_STDOUT_WORLD);
6649:     }
6650:   }
6651:   return(0);
6652: }

6656: /* This will only work for interpolated meshes */
6657: PetscErrorCode DMPlexRefineUniform_Internal(DM dm, CellRefiner cellRefiner, DM *dmRefined)
6658: {
6659:   DM             rdm;
6660:   PetscInt      *depthSize;
6661:   PetscInt       dim, depth = 0, d, pStart = 0, pEnd = 0;

6665:   DMCreate(PetscObjectComm((PetscObject)dm), &rdm);
6666:   DMSetType(rdm, DMPLEX);
6667:   DMGetDimension(dm, &dim);
6668:   DMSetDimension(rdm, dim);
6669:   /* Calculate number of new points of each depth */
6670:   DMPlexGetDepth(dm, &depth);
6671:   if (depth >= 0 && dim != depth) SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "Mesh must be interpolated for regular refinement");
6672:   PetscMalloc1(depth+1, &depthSize);
6673:   PetscMemzero(depthSize, (depth+1) * sizeof(PetscInt));
6674:   CellRefinerGetSizes(cellRefiner, dm, depthSize);
6675:   /* Step 1: Set chart */
6676:   for (d = 0; d <= depth; ++d) pEnd += depthSize[d];
6677:   DMPlexSetChart(rdm, pStart, pEnd);
6678:   /* Step 2: Set cone/support sizes */
6679:   CellRefinerSetConeSizes(cellRefiner, dm, depthSize, rdm);
6680:   /* Step 3: Setup refined DM */
6681:   DMSetUp(rdm);
6682:   /* Step 4: Set cones and supports */
6683:   CellRefinerSetCones(cellRefiner, dm, depthSize, rdm);
6684:   /* Step 5: Stratify */
6685:   DMPlexStratify(rdm);
6686:   /* Step 6: Create pointSF */
6687:   CellRefinerCreateSF(cellRefiner, dm, depthSize, rdm);
6688:   /* Step 7: Set coordinates for vertices */
6689:   CellRefinerSetCoordinates(cellRefiner, dm, depthSize, rdm);
6690:   /* Step 8: Create labels */
6691:   CellRefinerCreateLabels(cellRefiner, dm, depthSize, rdm);
6692:   PetscFree(depthSize);

6694:   *dmRefined = rdm;
6695:   return(0);
6696: }

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

6703:   Input Parameter:
6704: . dm - The coarse DM

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

6709:   Level: developer

6711: .seealso: DMRefine(), DMPlexSetRefinementUniform(), DMPlexCreateSubpointIS()
6712: @*/
6713: PetscErrorCode DMPlexCreateCoarsePointIS(DM dm, IS *fpointIS)
6714: {
6715:   CellRefiner    cellRefiner;
6716:   PetscInt      *depthSize, *fpoints;
6717:   PetscInt       cStartNew = 0, vStartNew = 0, fStartNew = 0, eStartNew = 0;
6718:   PetscInt       depth, pStart, pEnd, p, vStart, vEnd, v;

6722:   DMPlexGetDepth(dm, &depth);
6723:   DMPlexGetChart(dm, &pStart, &pEnd);
6724:   DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);
6725:   DMPlexGetCellRefiner_Internal(dm, &cellRefiner);
6726:   PetscMalloc1(depth+1, &depthSize);
6727:   CellRefinerGetSizes(cellRefiner, dm, depthSize);
6728:   if (cellRefiner) {GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);}
6729:   PetscMalloc1(pEnd-pStart,&fpoints);
6730:   for (p = 0; p < pEnd-pStart; ++p) fpoints[p] = -1;
6731:   switch (cellRefiner) {
6732:   case REFINER_SIMPLEX_1D:
6733:   case REFINER_SIMPLEX_2D:
6734:   case REFINER_HYBRID_SIMPLEX_2D:
6735:   case REFINER_HEX_2D:
6736:   case REFINER_HYBRID_HEX_2D:
6737:   case REFINER_SIMPLEX_3D:
6738:   case REFINER_HYBRID_SIMPLEX_3D:
6739:   case REFINER_HEX_3D:
6740:   case REFINER_HYBRID_HEX_3D:
6741:     for (v = vStart; v < vEnd; ++v) fpoints[v-pStart] = vStartNew + (v - vStart);
6742:     break;
6743:   default:
6744:     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", cellRefiner);
6745:   }
6746:   ISCreateGeneral(PETSC_COMM_SELF, pEnd-pStart, fpoints, PETSC_OWN_POINTER, fpointIS);
6747:   PetscFree(depthSize);
6748:   return(0);
6749: }

6753: /*@
6754:   DMPlexSetRefinementUniform - Set the flag for uniform refinement

6756:   Input Parameters:
6757: + dm - The DM
6758: - refinementUniform - The flag for uniform refinement

6760:   Level: developer

6762: .seealso: DMRefine(), DMPlexGetRefinementUniform(), DMPlexGetRefinementLimit(), DMPlexSetRefinementLimit()
6763: @*/
6764: PetscErrorCode DMPlexSetRefinementUniform(DM dm, PetscBool refinementUniform)
6765: {
6766:   DM_Plex *mesh = (DM_Plex*) dm->data;

6770:   mesh->refinementUniform = refinementUniform;
6771:   return(0);
6772: }

6776: /*@
6777:   DMPlexGetRefinementUniform - Retrieve the flag for uniform refinement

6779:   Input Parameter:
6780: . dm - The DM

6782:   Output Parameter:
6783: . refinementUniform - The flag for uniform refinement

6785:   Level: developer

6787: .seealso: DMRefine(), DMPlexSetRefinementUniform(), DMPlexGetRefinementLimit(), DMPlexSetRefinementLimit()
6788: @*/
6789: PetscErrorCode DMPlexGetRefinementUniform(DM dm, PetscBool *refinementUniform)
6790: {
6791:   DM_Plex *mesh = (DM_Plex*) dm->data;

6796:   *refinementUniform = mesh->refinementUniform;
6797:   return(0);
6798: }

6802: /*@
6803:   DMPlexSetRefinementLimit - Set the maximum cell volume for refinement

6805:   Input Parameters:
6806: + dm - The DM
6807: - refinementLimit - The maximum cell volume in the refined mesh

6809:   Level: developer

6811: .seealso: DMRefine(), DMPlexGetRefinementLimit(), DMPlexGetRefinementUniform(), DMPlexSetRefinementUniform()
6812: @*/
6813: PetscErrorCode DMPlexSetRefinementLimit(DM dm, PetscReal refinementLimit)
6814: {
6815:   DM_Plex *mesh = (DM_Plex*) dm->data;

6819:   mesh->refinementLimit = refinementLimit;
6820:   return(0);
6821: }

6825: /*@
6826:   DMPlexGetRefinementLimit - Retrieve the maximum cell volume for refinement

6828:   Input Parameter:
6829: . dm - The DM

6831:   Output Parameter:
6832: . refinementLimit - The maximum cell volume in the refined mesh

6834:   Level: developer

6836: .seealso: DMRefine(), DMPlexSetRefinementLimit(), DMPlexGetRefinementUniform(), DMPlexSetRefinementUniform()
6837: @*/
6838: PetscErrorCode DMPlexGetRefinementLimit(DM dm, PetscReal *refinementLimit)
6839: {
6840:   DM_Plex *mesh = (DM_Plex*) dm->data;

6845:   /* if (mesh->refinementLimit < 0) = getMaxVolume()/2.0; */
6846:   *refinementLimit = mesh->refinementLimit;
6847:   return(0);
6848: }

6852: /*@
6853:   DMPlexSetRefinementFunction - Set the function giving the maximum cell volume for refinement

6855:   Input Parameters:
6856: + dm - The DM
6857: - refinementFunc - Function giving the maximum cell volume in the refined mesh

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

6863:   Level: developer

6865: .seealso: DMRefine(), DMPlexGetRefinementFunction(), DMPlexGetRefinementUniform(), DMPlexSetRefinementUniform(), DMPlexGetRefinementLimit(), DMPlexSetRefinementLimit()
6866: @*/
6867: PetscErrorCode DMPlexSetRefinementFunction(DM dm, PetscErrorCode (*refinementFunc)(const PetscReal [], PetscReal *))
6868: {
6869:   DM_Plex *mesh = (DM_Plex*) dm->data;

6873:   mesh->refinementFunc = refinementFunc;
6874:   return(0);
6875: }

6879: /*@
6880:   DMPlexGetRefinementFunction - Get the function giving the maximum cell volume for refinement

6882:   Input Parameter:
6883: . dm - The DM

6885:   Output Parameter:
6886: . refinementFunc - Function giving the maximum cell volume in the refined mesh

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

6892:   Level: developer

6894: .seealso: DMRefine(), DMPlexSetRefinementFunction(), DMPlexGetRefinementUniform(), DMPlexSetRefinementUniform(), DMPlexGetRefinementLimit(), DMPlexSetRefinementLimit()
6895: @*/
6896: PetscErrorCode DMPlexGetRefinementFunction(DM dm, PetscErrorCode (**refinementFunc)(const PetscReal [], PetscReal *))
6897: {
6898:   DM_Plex *mesh = (DM_Plex*) dm->data;

6903:   *refinementFunc = mesh->refinementFunc;
6904:   return(0);
6905: }

6909: PetscErrorCode DMPlexGetCellRefiner_Internal(DM dm, CellRefiner *cellRefiner)
6910: {
6911:   PetscInt       dim, cStart, cEnd, coneSize, cMax, fMax;

6915:   DMGetDimension(dm, &dim);
6916:   DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);
6917:   if (cEnd <= cStart) {*cellRefiner = REFINER_NOOP; return(0);}
6918:   DMPlexGetConeSize(dm, cStart, &coneSize);
6919:   DMPlexGetHybridBounds(dm, &cMax, &fMax, NULL, NULL);
6920:   switch (dim) {
6921:   case 1:
6922:     switch (coneSize) {
6923:     case 2:
6924:       *cellRefiner = REFINER_SIMPLEX_1D;
6925:       break;
6926:     default:
6927:       SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown coneSize %d in dimension %d for cell refiner", coneSize, dim);
6928:     }
6929:     break;
6930:   case 2:
6931:     switch (coneSize) {
6932:     case 3:
6933:       if (cMax >= 0) *cellRefiner = REFINER_HYBRID_SIMPLEX_2D;
6934:       else *cellRefiner = REFINER_SIMPLEX_2D;
6935:       break;
6936:     case 4:
6937:       if (cMax >= 0 && fMax >= 0) *cellRefiner = REFINER_HYBRID_HEX_2D;
6938:       else *cellRefiner = REFINER_HEX_2D;
6939:       break;
6940:     default:
6941:       SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown coneSize %d in dimension %d for cell refiner", coneSize, dim);
6942:     }
6943:     break;
6944:   case 3:
6945:     switch (coneSize) {
6946:     case 4:
6947:       if (cMax >= 0) *cellRefiner = REFINER_HYBRID_SIMPLEX_3D;
6948:       else *cellRefiner = REFINER_SIMPLEX_3D;
6949:       break;
6950:     case 6:
6951:       if (cMax >= 0) *cellRefiner = REFINER_HYBRID_HEX_3D;
6952:       else *cellRefiner = REFINER_HEX_3D;
6953:       break;
6954:     default:
6955:       SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown coneSize %d in dimension %d for cell refiner", coneSize, dim);
6956:     }
6957:     break;
6958:   default:
6959:     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown dimension %d for cell refiner", dim);
6960:   }
6961:   return(0);
6962: }