xref: /petsc/src/dm/impls/plex/plexrefine.c (revision 87fe662889ac83ff5dc7af638d85c0ea6708c3dc)
1 #include <petsc-private/dmpleximpl.h>   /*I      "petscdmplex.h"   I*/
2 #include <petscsf.h>
3 
4 #undef __FUNCT__
5 #define __FUNCT__ "GetDepthStart_Private"
6 PETSC_STATIC_INLINE PetscErrorCode GetDepthStart_Private(PetscInt depth, PetscInt depthSize[], PetscInt *cStart, PetscInt *fStart, PetscInt *eStart, PetscInt *vStart)
7 {
8   PetscFunctionBegin;
9   if (cStart) *cStart = 0;
10   if (vStart) *vStart = depthSize[depth];
11   if (fStart) *fStart = depthSize[depth] + depthSize[0];
12   if (eStart) *eStart = depthSize[depth] + depthSize[0] + depthSize[depth-1];
13   PetscFunctionReturn(0);
14 }
15 
16 #undef __FUNCT__
17 #define __FUNCT__ "GetDepthEnd_Private"
18 PETSC_STATIC_INLINE PetscErrorCode GetDepthEnd_Private(PetscInt depth, PetscInt depthSize[], PetscInt *cEnd, PetscInt *fEnd, PetscInt *eEnd, PetscInt *vEnd)
19 {
20   PetscFunctionBegin;
21   if (cEnd) *cEnd = depthSize[depth];
22   if (vEnd) *vEnd = depthSize[depth] + depthSize[0];
23   if (fEnd) *fEnd = depthSize[depth] + depthSize[0] + depthSize[depth-1];
24   if (eEnd) *eEnd = depthSize[depth] + depthSize[0] + depthSize[depth-1] + depthSize[1];
25   PetscFunctionReturn(0);
26 }
27 
28 #undef __FUNCT__
29 #define __FUNCT__ "DMPlexGetNumHybridFaces_Internal"
30 /* This is a stopgap since we do not currently keep track of faces for hybrid cells */
31 static PetscErrorCode DMPlexGetNumHybridFaces_Internal(DM dm, PetscInt *numHybridFaces)
32 {
33   PetscInt       eStart, eEnd, eMax, cEnd, cMax, c, hEdges = 0;
34   PetscErrorCode ierr;
35 
36   PetscFunctionBegin;
37   *numHybridFaces = 0;
38   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
39   ierr = DMPlexGetHeightStratum(dm, 0, NULL, &cEnd);CHKERRQ(ierr);
40   ierr = DMPlexGetHybridBounds(dm, &cMax, NULL, &eMax, NULL);CHKERRQ(ierr);
41   if (cMax < 0) PetscFunctionReturn(0);
42   /* Count interior edges in hybrid cells */
43   for (c = cMax; c < cEnd; ++c) {
44     PetscInt *closure = NULL, closureSize, cl;
45 
46     ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
47     for (cl = 0; cl < closureSize*2; cl += 2) {
48       const PetscInt p = closure[cl];
49 
50       if ((p >= eStart) && (p < eMax)) ++hEdges;
51     }
52     ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
53   }
54   if (hEdges%2) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Number of interior edges in hybrid cells cannot be odd: %d", hEdges);
55   *numHybridFaces = hEdges/2;
56   PetscFunctionReturn(0);
57 }
58 
59 #undef __FUNCT__
60 #define __FUNCT__ "CellRefinerGetSizes"
61 PetscErrorCode CellRefinerGetSizes(CellRefiner refiner, DM dm, PetscInt depthSize[])
62 {
63   PetscInt       numHybridFaces, cStart, cEnd, cMax, vStart, vEnd, vMax, fStart, fEnd, fMax, eStart, eEnd, eMax;
64   PetscErrorCode ierr;
65 
66   PetscFunctionBegin;
67   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
68   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
69   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
70   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
71   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
72   switch (refiner) {
73   case 1:
74     /* Simplicial 2D */
75     depthSize[0] = vEnd - vStart + fEnd - fStart;         /* Add a vertex on every face */
76     depthSize[1] = 2*(fEnd - fStart) + 3*(cEnd - cStart); /* Every face is split into 2 faces and 3 faces are added for each cell */
77     depthSize[2] = 4*(cEnd - cStart);                     /* Every cell split into 4 cells */
78     break;
79   case 3:
80     /* Hybrid Simplicial 2D */
81     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
82     cMax = PetscMin(cEnd, cMax);
83     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
84     fMax         = PetscMin(fEnd, fMax);
85     depthSize[0] = vEnd - vStart + fMax - fStart;                                         /* Add a vertex on every face, but not hybrid faces */
86     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 */
87     depthSize[2] = 4*(cMax - cStart) + 2*(cEnd - cMax);                                   /* Interior cells split into 4 cells, Hybrid cells split into 2 cells */
88     break;
89   case 2:
90     /* Hex 2D */
91     depthSize[0] = vEnd - vStart + cEnd - cStart + fEnd - fStart; /* Add a vertex on every face and cell */
92     depthSize[1] = 2*(fEnd - fStart) + 4*(cEnd - cStart);         /* Every face is split into 2 faces and 4 faces are added for each cell */
93     depthSize[2] = 4*(cEnd - cStart);                             /* Every cell split into 4 cells */
94     break;
95   case 5:
96     /* Simplicial 3D */
97     depthSize[0] =    vEnd - vStart  +    eEnd - eStart;                    /* Add a vertex on every edge */
98     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 */
99     depthSize[2] = 4*(fEnd - fStart) + 8*(cEnd - cStart);                   /* Every face split into 4 faces and 8 faces are added for each cell */
100     depthSize[3] = 8*(cEnd - cStart);                                       /* Every cell split into 8 cells */
101     break;
102   case 7:
103     /* Hybrid Simplicial 3D */
104     ierr = DMPlexGetNumHybridFaces_Internal(dm, &numHybridFaces);CHKERRQ(ierr);
105     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
106     cMax = PetscMin(cEnd, cMax);
107     if (eMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No edge maximum specified in hybrid mesh");
108     eMax = PetscMin(eEnd, eMax);
109     depthSize[0] =    vEnd - vStart  +     eMax - eStart;  /* Add a vertex on every edge, but not hybrid edges */
110     depthSize[1] = 2*(eMax - eStart) + 13*(cMax - cStart) + (eEnd - eMax) + numHybridFaces; /* Every interior edge is split into 2 edges and 13 edges are added for each interior cell, each hybrid edge stays intact, and one new hybrid edge for each two interior edges (hybrid face) on a hybrid cell */
111     depthSize[2] = 4*(fEnd - fStart) +  8*(cEnd - cStart); /* Every face split into 4 faces and 8 faces are added for each cell */
112     depthSize[3] = 8*(cMax - cStart) +  4*(cEnd - cMax);   /* Every interior cell split into 8 cells, and every hybrid cell split into 4 cells */
113     break;
114   default:
115     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
116   }
117   PetscFunctionReturn(0);
118 }
119 
120 #undef __FUNCT__
121 #define __FUNCT__ "CellRefinerSetConeSizes"
122 PetscErrorCode CellRefinerSetConeSizes(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
123 {
124   PetscInt       depth, cStart, cStartNew, cEnd, cMax, c, vStart, vStartNew, vEnd, vMax, v, fStart, fStartNew, fEnd, fMax, f, eStart, eStartNew, eEnd, eMax, e, r;
125   PetscErrorCode ierr;
126 
127   PetscFunctionBegin;
128   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
129   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
130   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
131   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
132   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
133   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
134   ierr = GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);CHKERRQ(ierr);
135   switch (refiner) {
136   case 1:
137     /* Simplicial 2D */
138     /* All cells have 3 faces */
139     for (c = cStart; c < cEnd; ++c) {
140       for (r = 0; r < 4; ++r) {
141         const PetscInt newp = (c - cStart)*4 + r;
142 
143         ierr = DMPlexSetConeSize(rdm, newp, 3);CHKERRQ(ierr);
144       }
145     }
146     /* Split faces have 2 vertices and the same cells as the parent */
147     for (f = fStart; f < fEnd; ++f) {
148       for (r = 0; r < 2; ++r) {
149         const PetscInt newp = fStartNew + (f - fStart)*2 + r;
150         PetscInt       size;
151 
152         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
153         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
154         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
155       }
156     }
157     /* Interior faces have 2 vertices and 2 cells */
158     for (c = cStart; c < cEnd; ++c) {
159       for (r = 0; r < 3; ++r) {
160         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*3 + r;
161 
162         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
163         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
164       }
165     }
166     /* Old vertices have identical supports */
167     for (v = vStart; v < vEnd; ++v) {
168       const PetscInt newp = vStartNew + (v - vStart);
169       PetscInt       size;
170 
171       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
172       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
173     }
174     /* Face vertices have 2 + cells*2 supports */
175     for (f = fStart; f < fEnd; ++f) {
176       const PetscInt newp = vStartNew + (vEnd - vStart) + (f - fStart);
177       PetscInt       size;
178 
179       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
180       ierr = DMPlexSetSupportSize(rdm, newp, 2 + size*2);CHKERRQ(ierr);
181     }
182     break;
183   case 2:
184     /* Hex 2D */
185     /* All cells have 4 faces */
186     for (c = cStart; c < cEnd; ++c) {
187       for (r = 0; r < 4; ++r) {
188         const PetscInt newp = (c - cStart)*4 + r;
189 
190         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
191       }
192     }
193     /* Split faces have 2 vertices and the same cells as the parent */
194     for (f = fStart; f < fEnd; ++f) {
195       for (r = 0; r < 2; ++r) {
196         const PetscInt newp = fStartNew + (f - fStart)*2 + r;
197         PetscInt       size;
198 
199         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
200         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
201         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
202       }
203     }
204     /* Interior faces have 2 vertices and 2 cells */
205     for (c = cStart; c < cEnd; ++c) {
206       for (r = 0; r < 4; ++r) {
207         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*4 + r;
208 
209         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
210         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
211       }
212     }
213     /* Old vertices have identical supports */
214     for (v = vStart; v < vEnd; ++v) {
215       const PetscInt newp = vStartNew + (v - vStart);
216       PetscInt       size;
217 
218       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
219       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
220     }
221     /* Face vertices have 2 + cells supports */
222     for (f = fStart; f < fEnd; ++f) {
223       const PetscInt newp = vStartNew + (vEnd - vStart) + (f - fStart);
224       PetscInt       size;
225 
226       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
227       ierr = DMPlexSetSupportSize(rdm, newp, 2 + size);CHKERRQ(ierr);
228     }
229     /* Cell vertices have 4 supports */
230     for (c = cStart; c < cEnd; ++c) {
231       const PetscInt newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (c - cStart);
232 
233       ierr = DMPlexSetSupportSize(rdm, newp, 4);CHKERRQ(ierr);
234     }
235     break;
236   case 3:
237     /* Hybrid Simplicial 2D */
238     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
239     cMax = PetscMin(cEnd, cMax);
240     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
241     fMax = PetscMin(fEnd, fMax);
242     ierr = DMPlexSetHybridBounds(rdm, cStartNew + (cMax - cStart)*4, fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3, PETSC_DETERMINE, PETSC_DETERMINE);CHKERRQ(ierr);
243     /* Interior cells have 3 faces */
244     for (c = cStart; c < cMax; ++c) {
245       for (r = 0; r < 4; ++r) {
246         const PetscInt newp = cStartNew + (c - cStart)*4 + r;
247 
248         ierr = DMPlexSetConeSize(rdm, newp, 3);CHKERRQ(ierr);
249       }
250     }
251     /* Hybrid cells have 4 faces */
252     for (c = cMax; c < cEnd; ++c) {
253       for (r = 0; r < 2; ++r) {
254         const PetscInt newp = cStartNew + (cMax - cStart)*4 + (c - cMax)*2 + r;
255 
256         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
257       }
258     }
259     /* Interior split faces have 2 vertices and the same cells as the parent */
260     for (f = fStart; f < fMax; ++f) {
261       for (r = 0; r < 2; ++r) {
262         const PetscInt newp = fStartNew + (f - fStart)*2 + r;
263         PetscInt       size;
264 
265         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
266         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
267         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
268       }
269     }
270     /* Interior cell faces have 2 vertices and 2 cells */
271     for (c = cStart; c < cMax; ++c) {
272       for (r = 0; r < 3; ++r) {
273         const PetscInt newp = fStartNew + (fMax - fStart)*2 + (c - cStart)*3 + r;
274 
275         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
276         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
277       }
278     }
279     /* Hybrid faces have 2 vertices and the same cells */
280     for (f = fMax; f < fEnd; ++f) {
281       const PetscInt newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (f - fMax);
282       PetscInt       size;
283 
284       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
285       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
286       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
287     }
288     /* Hybrid cell faces have 2 vertices and 2 cells */
289     for (c = cMax; c < cEnd; ++c) {
290       const PetscInt newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (fEnd - fMax) + (c - cMax);
291 
292       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
293       ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
294     }
295     /* Old vertices have identical supports */
296     for (v = vStart; v < vEnd; ++v) {
297       const PetscInt newp = vStartNew + (v - vStart);
298       PetscInt       size;
299 
300       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
301       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
302     }
303     /* Face vertices have 2 + (2 interior, 1 hybrid) supports */
304     for (f = fStart; f < fMax; ++f) {
305       const PetscInt newp = vStartNew + (vEnd - vStart) + (f - fStart);
306       const PetscInt *support;
307       PetscInt       size, newSize = 2, s;
308 
309       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
310       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
311       for (s = 0; s < size; ++s) {
312         if (support[s] >= cMax) newSize += 1;
313         else newSize += 2;
314       }
315       ierr = DMPlexSetSupportSize(rdm, newp, newSize);CHKERRQ(ierr);
316     }
317     break;
318   case 5:
319     /* Simplicial 3D */
320     /* All cells have 4 faces */
321     for (c = cStart; c < cEnd; ++c) {
322       for (r = 0; r < 8; ++r) {
323         const PetscInt newp = (c - cStart)*8 + r;
324 
325         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
326       }
327     }
328     /* Split faces have 3 edges and the same cells as the parent */
329     for (f = fStart; f < fEnd; ++f) {
330       for (r = 0; r < 4; ++r) {
331         const PetscInt newp = fStartNew + (f - fStart)*4 + r;
332         PetscInt       size;
333 
334         ierr = DMPlexSetConeSize(rdm, newp, 3);CHKERRQ(ierr);
335         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
336         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
337       }
338     }
339     /* Interior faces have 3 edges and 2 cells */
340     for (c = cStart; c < cEnd; ++c) {
341       for (r = 0; r < 8; ++r) {
342         const PetscInt newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*8 + r;
343 
344         ierr = DMPlexSetConeSize(rdm, newp, 3);CHKERRQ(ierr);
345         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
346       }
347     }
348     /* Split edges have 2 vertices and the same faces */
349     for (e = eStart; e < eEnd; ++e) {
350       for (r = 0; r < 2; ++r) {
351         const PetscInt newp = eStartNew + (e - eStart)*2 + r;
352         PetscInt       size;
353 
354         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
355         ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
356         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
357       }
358     }
359     /* Face edges have 2 vertices and 2+cells*(1/2) faces */
360     for (f = fStart; f < fEnd; ++f) {
361       for (r = 0; r < 3; ++r) {
362         const PetscInt  newp = eStartNew + (eEnd - eStart)*2 + (f - fStart)*3 + r;
363         const PetscInt *cone, *ornt, *support, eint[4] = {1, 0, 2, 0};
364         PetscInt        coneSize, c, supportSize, s, er, intFaces = 0;
365 
366         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
367         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
368         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
369         for (s = 0; s < supportSize; ++s) {
370           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
371           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
372           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
373           for (c = 0; c < coneSize; ++c) {if (cone[c] == f) break;}
374           /* Here we want to determine whether edge newp contains a vertex which is part of the cross-tet edge */
375           er = ornt[c] < 0 ? (-(ornt[c]+1) + 2-r)%3 : (ornt[c] + r)%3;
376           if (er == eint[c]) {
377             intFaces += 1;
378           } else {
379             intFaces += 2;
380           }
381         }
382         ierr = DMPlexSetSupportSize(rdm, newp, 2+intFaces);CHKERRQ(ierr);
383       }
384     }
385     /* Interior edges have 2 vertices and 4 faces */
386     for (c = cStart; c < cEnd; ++c) {
387       const PetscInt newp = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart);
388 
389       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
390       ierr = DMPlexSetSupportSize(rdm, newp, 4);CHKERRQ(ierr);
391     }
392     /* Old vertices have identical supports */
393     for (v = vStart; v < vEnd; ++v) {
394       const PetscInt newp = vStartNew + (v - vStart);
395       PetscInt       size;
396 
397       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
398       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
399     }
400     /* Edge vertices have 2 + faces*2 + cells*0/1 supports */
401     for (e = eStart; e < eEnd; ++e) {
402       const PetscInt newp = vStartNew + (vEnd - vStart) + (e - eStart);
403       PetscInt       size, *star = NULL, starSize, s, cellSize = 0;
404 
405       ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
406       ierr = DMPlexGetTransitiveClosure(dm, e, PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
407       for (s = 0; s < starSize*2; s += 2) {
408         const PetscInt *cone, *ornt;
409         PetscInt        e01, e23;
410 
411         if ((star[s] >= cStart) && (star[s] < cEnd)) {
412           /* Check edge 0-1 */
413           ierr = DMPlexGetCone(dm, star[s], &cone);CHKERRQ(ierr);
414           ierr = DMPlexGetConeOrientation(dm, star[s], &ornt);CHKERRQ(ierr);
415           ierr = DMPlexGetCone(dm, cone[0], &cone);CHKERRQ(ierr);
416           e01  = cone[ornt[0] < 0 ? (-(ornt[0]+1) + 0)%3 : ornt[0]];
417           /* Check edge 2-3 */
418           ierr = DMPlexGetCone(dm, star[s], &cone);CHKERRQ(ierr);
419           ierr = DMPlexGetConeOrientation(dm, star[s], &ornt);CHKERRQ(ierr);
420           ierr = DMPlexGetCone(dm, cone[3], &cone);CHKERRQ(ierr);
421           e23  = cone[ornt[3] < 0 ? (-(ornt[3]+1) + 2)%3 : (ornt[3] + 2)%3];
422           if ((e01 == e) || (e23 == e)) ++cellSize;
423         }
424       }
425       ierr = DMPlexRestoreTransitiveClosure(dm, e, PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
426       ierr = DMPlexSetSupportSize(rdm, newp, 2 + size*2 + cellSize);CHKERRQ(ierr);
427     }
428     break;
429   default:
430     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
431   }
432   PetscFunctionReturn(0);
433 }
434 
435 #undef __FUNCT__
436 #define __FUNCT__ "CellRefinerSetCones"
437 PetscErrorCode CellRefinerSetCones(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
438 {
439   const PetscInt *faces, cellInd[4] = {0, 1, 2, 3};
440   PetscInt        depth, cStart, cEnd, cMax, cStartNew, cEndNew, c, vStart, vEnd, vMax, vStartNew, vEndNew, v, fStart, fEnd, fMax, fStartNew, fEndNew, f, eStart, eEnd, eMax, eStartNew, eEndNew, e, r, p;
441   PetscInt        maxSupportSize, *supportRef;
442   PetscErrorCode  ierr;
443 
444   PetscFunctionBegin;
445   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
446   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
447   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
448   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
449   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
450   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
451   ierr = GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);CHKERRQ(ierr);
452   ierr = GetDepthEnd_Private(depth, depthSize, &cEndNew, &fEndNew, &eEndNew, &vEndNew);CHKERRQ(ierr);
453   switch (refiner) {
454   case 1:
455     /* Simplicial 2D */
456     /*
457      2
458      |\
459      | \
460      |  \
461      |   \
462      | C  \
463      |     \
464      |      \
465      2---1---1
466      |\  D  / \
467      | 2   0   \
468      |A \ /  B  \
469      0---0-------1
470      */
471     /* All cells have 3 faces */
472     for (c = cStart; c < cEnd; ++c) {
473       const PetscInt  newp = cStartNew + (c - cStart)*4;
474       const PetscInt *cone, *ornt;
475       PetscInt        coneNew[3], orntNew[3];
476 
477       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
478       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
479       /* A triangle */
480       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
481       orntNew[0] = ornt[0];
482       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 2;
483       orntNew[1] = -2;
484       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
485       orntNew[2] = ornt[2];
486       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
487       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
488 #if 1
489       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);
490       for (p = 0; p < 3; ++p) {
491         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);
492       }
493 #endif
494       /* B triangle */
495       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
496       orntNew[0] = ornt[0];
497       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
498       orntNew[1] = ornt[1];
499       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 0;
500       orntNew[2] = -2;
501       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
502       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
503 #if 1
504       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);
505       for (p = 0; p < 3; ++p) {
506         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);
507       }
508 #endif
509       /* C triangle */
510       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 1;
511       orntNew[0] = -2;
512       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
513       orntNew[1] = ornt[1];
514       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
515       orntNew[2] = ornt[2];
516       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
517       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
518 #if 1
519       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);
520       for (p = 0; p < 3; ++p) {
521         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);
522       }
523 #endif
524       /* D triangle */
525       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 0;
526       orntNew[0] = 0;
527       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 1;
528       orntNew[1] = 0;
529       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 2;
530       orntNew[2] = 0;
531       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
532       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
533 #if 1
534       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);
535       for (p = 0; p < 3; ++p) {
536         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);
537       }
538 #endif
539     }
540     /* Split faces have 2 vertices and the same cells as the parent */
541     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
542     ierr = PetscMalloc((2 + maxSupportSize*2) * sizeof(PetscInt), &supportRef);CHKERRQ(ierr);
543     for (f = fStart; f < fEnd; ++f) {
544       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);
545 
546       for (r = 0; r < 2; ++r) {
547         const PetscInt  newp = fStartNew + (f - fStart)*2 + r;
548         const PetscInt *cone, *ornt, *support;
549         PetscInt        coneNew[2], coneSize, c, supportSize, s;
550 
551         ierr             = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
552         coneNew[0]       = vStartNew + (cone[0] - vStart);
553         coneNew[1]       = vStartNew + (cone[1] - vStart);
554         coneNew[(r+1)%2] = newv;
555         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
556 #if 1
557         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
558         for (p = 0; p < 2; ++p) {
559           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);
560         }
561 #endif
562         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
563         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
564         for (s = 0; s < supportSize; ++s) {
565           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
566           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
567           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
568           for (c = 0; c < coneSize; ++c) {
569             if (cone[c] == f) break;
570           }
571           supportRef[s] = cStartNew + (support[s] - cStart)*4 + (ornt[c] < 0 ? (c+1-r)%3 : (c+r)%3);
572         }
573         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
574 #if 1
575         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
576         for (p = 0; p < supportSize; ++p) {
577           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);
578         }
579 #endif
580       }
581     }
582     /* Interior faces have 2 vertices and 2 cells */
583     for (c = cStart; c < cEnd; ++c) {
584       const PetscInt *cone;
585 
586       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
587       for (r = 0; r < 3; ++r) {
588         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*3 + r;
589         PetscInt       coneNew[2];
590         PetscInt       supportNew[2];
591 
592         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r]       - fStart);
593         coneNew[1] = vStartNew + (vEnd - vStart) + (cone[(r+1)%3] - fStart);
594         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
595 #if 1
596         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
597         for (p = 0; p < 2; ++p) {
598           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);
599         }
600 #endif
601         supportNew[0] = (c - cStart)*4 + (r+1)%3;
602         supportNew[1] = (c - cStart)*4 + 3;
603         ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
604 #if 1
605         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
606         for (p = 0; p < 2; ++p) {
607           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);
608         }
609 #endif
610       }
611     }
612     /* Old vertices have identical supports */
613     for (v = vStart; v < vEnd; ++v) {
614       const PetscInt  newp = vStartNew + (v - vStart);
615       const PetscInt *support, *cone;
616       PetscInt        size, s;
617 
618       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
619       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
620       for (s = 0; s < size; ++s) {
621         PetscInt r = 0;
622 
623         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
624         if (cone[1] == v) r = 1;
625         supportRef[s] = fStartNew + (support[s] - fStart)*2 + r;
626       }
627       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
628 #if 1
629       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
630       for (p = 0; p < size; ++p) {
631         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);
632       }
633 #endif
634     }
635     /* Face vertices have 2 + cells*2 supports */
636     for (f = fStart; f < fEnd; ++f) {
637       const PetscInt  newp = vStartNew + (vEnd - vStart) + (f - fStart);
638       const PetscInt *cone, *support;
639       PetscInt        size, s;
640 
641       ierr          = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
642       ierr          = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
643       supportRef[0] = fStartNew + (f - fStart)*2 + 0;
644       supportRef[1] = fStartNew + (f - fStart)*2 + 1;
645       for (s = 0; s < size; ++s) {
646         PetscInt r = 0;
647 
648         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
649         if      (cone[1] == f) r = 1;
650         else if (cone[2] == f) r = 2;
651         supportRef[2+s*2+0] = fStartNew + (fEnd - fStart)*2 + (support[s] - cStart)*3 + (r+2)%3;
652         supportRef[2+s*2+1] = fStartNew + (fEnd - fStart)*2 + (support[s] - cStart)*3 + r;
653       }
654       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
655 #if 1
656       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
657       for (p = 0; p < 2+size*2; ++p) {
658         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);
659       }
660 #endif
661     }
662     ierr = PetscFree(supportRef);CHKERRQ(ierr);
663     break;
664   case 2:
665     /* Hex 2D */
666     /*
667      3---------2---------2
668      |         |         |
669      |    D    2    C    |
670      |         |         |
671      3----3----0----1----1
672      |         |         |
673      |    A    0    B    |
674      |         |         |
675      0---------0---------1
676      */
677     /* All cells have 4 faces */
678     for (c = cStart; c < cEnd; ++c) {
679       const PetscInt  newp = (c - cStart)*4;
680       const PetscInt *cone, *ornt;
681       PetscInt        coneNew[4], orntNew[4];
682 
683       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
684       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
685       /* A quad */
686       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
687       orntNew[0] = ornt[0];
688       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 0;
689       orntNew[1] = 0;
690       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 3;
691       orntNew[2] = -2;
692       coneNew[3] = fStartNew + (cone[3] - fStart)*2 + (ornt[3] < 0 ? 0 : 1);
693       orntNew[3] = ornt[3];
694       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
695       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
696 #if 1
697       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);
698       for (p = 0; p < 4; ++p) {
699         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);
700       }
701 #endif
702       /* B quad */
703       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
704       orntNew[0] = ornt[0];
705       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
706       orntNew[1] = ornt[1];
707       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 1;
708       orntNew[2] = 0;
709       coneNew[3] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 0;
710       orntNew[3] = -2;
711       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
712       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
713 #if 1
714       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);
715       for (p = 0; p < 4; ++p) {
716         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);
717       }
718 #endif
719       /* C quad */
720       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 1;
721       orntNew[0] = -2;
722       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
723       orntNew[1] = ornt[1];
724       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
725       orntNew[2] = ornt[2];
726       coneNew[3] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 2;
727       orntNew[3] = 0;
728       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
729       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
730 #if 1
731       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);
732       for (p = 0; p < 4; ++p) {
733         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);
734       }
735 #endif
736       /* D quad */
737       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 3;
738       orntNew[0] = 0;
739       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 2;
740       orntNew[1] = -2;
741       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
742       orntNew[2] = ornt[2];
743       coneNew[3] = fStartNew + (cone[3] - fStart)*2 + (ornt[3] < 0 ? 1 : 0);
744       orntNew[3] = ornt[3];
745       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
746       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
747 #if 1
748       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);
749       for (p = 0; p < 4; ++p) {
750         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);
751       }
752 #endif
753     }
754     /* Split faces have 2 vertices and the same cells as the parent */
755     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
756     ierr = PetscMalloc((2 + maxSupportSize*2) * sizeof(PetscInt), &supportRef);CHKERRQ(ierr);
757     for (f = fStart; f < fEnd; ++f) {
758       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);
759 
760       for (r = 0; r < 2; ++r) {
761         const PetscInt  newp = fStartNew + (f - fStart)*2 + r;
762         const PetscInt *cone, *support;
763         PetscInt        coneNew[2], coneSize, c, supportSize, s;
764 
765         ierr             = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
766         coneNew[0]       = vStartNew + (cone[0] - vStart);
767         coneNew[1]       = vStartNew + (cone[1] - vStart);
768         coneNew[(r+1)%2] = newv;
769         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
770 #if 1
771         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
772         for (p = 0; p < 2; ++p) {
773           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);
774         }
775 #endif
776         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
777         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
778         for (s = 0; s < supportSize; ++s) {
779           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
780           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
781           for (c = 0; c < coneSize; ++c) {
782             if (cone[c] == f) break;
783           }
784           supportRef[s] = cStartNew + (support[s] - cStart)*4 + (c+r)%4;
785         }
786         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
787 #if 1
788         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
789         for (p = 0; p < supportSize; ++p) {
790           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);
791         }
792 #endif
793       }
794     }
795     /* Interior faces have 2 vertices and 2 cells */
796     for (c = cStart; c < cEnd; ++c) {
797       const PetscInt *cone;
798       PetscInt        coneNew[2], supportNew[2];
799 
800       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
801       for (r = 0; r < 4; ++r) {
802         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*4 + r;
803 
804         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r] - fStart);
805         coneNew[1] = vStartNew + (vEnd - vStart) + (fEnd    - fStart) + (c - cStart);
806         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
807 #if 1
808         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
809         for (p = 0; p < 2; ++p) {
810           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);
811         }
812 #endif
813         supportNew[0] = (c - cStart)*4 + r;
814         supportNew[1] = (c - cStart)*4 + (r+1)%4;
815         ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
816 #if 1
817         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
818         for (p = 0; p < 2; ++p) {
819           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);
820         }
821 #endif
822       }
823     }
824     /* Old vertices have identical supports */
825     for (v = vStart; v < vEnd; ++v) {
826       const PetscInt  newp = vStartNew + (v - vStart);
827       const PetscInt *support, *cone;
828       PetscInt        size, s;
829 
830       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
831       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
832       for (s = 0; s < size; ++s) {
833         PetscInt r = 0;
834 
835         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
836         if (cone[1] == v) r = 1;
837         supportRef[s] = fStartNew + (support[s] - fStart)*2 + r;
838       }
839       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
840 #if 1
841       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
842       for (p = 0; p < size; ++p) {
843         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);
844       }
845 #endif
846     }
847     /* Face vertices have 2 + cells supports */
848     for (f = fStart; f < fEnd; ++f) {
849       const PetscInt  newp = vStartNew + (vEnd - vStart) + (f - fStart);
850       const PetscInt *cone, *support;
851       PetscInt        size, s;
852 
853       ierr          = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
854       ierr          = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
855       supportRef[0] = fStartNew + (f - fStart)*2 + 0;
856       supportRef[1] = fStartNew + (f - fStart)*2 + 1;
857       for (s = 0; s < size; ++s) {
858         PetscInt r = 0;
859 
860         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
861         if      (cone[1] == f) r = 1;
862         else if (cone[2] == f) r = 2;
863         else if (cone[3] == f) r = 3;
864         supportRef[2+s] = fStartNew + (fEnd - fStart)*2 + (support[s] - cStart)*4 + r;
865       }
866       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
867 #if 1
868       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
869       for (p = 0; p < 2+size; ++p) {
870         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);
871       }
872 #endif
873     }
874     /* Cell vertices have 4 supports */
875     for (c = cStart; c < cEnd; ++c) {
876       const PetscInt newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (c - cStart);
877       PetscInt       supportNew[4];
878 
879       for (r = 0; r < 4; ++r) {
880         supportNew[r] = fStartNew + (fEnd - fStart)*2 + (c - cStart)*4 + r;
881       }
882       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
883     }
884     break;
885   case 3:
886     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
887     cMax = PetscMin(cEnd, cMax);
888     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
889     fMax = PetscMin(fEnd, fMax);
890     /* Interior cells have 3 faces */
891     for (c = cStart; c < cMax; ++c) {
892       const PetscInt  newp = cStartNew + (c - cStart)*4;
893       const PetscInt *cone, *ornt;
894       PetscInt        coneNew[3], orntNew[3];
895 
896       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
897       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
898       /* A triangle */
899       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
900       orntNew[0] = ornt[0];
901       coneNew[1] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 2;
902       orntNew[1] = -2;
903       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
904       orntNew[2] = ornt[2];
905       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
906       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
907 #if 1
908       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);
909       for (p = 0; p < 3; ++p) {
910         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);
911       }
912 #endif
913       /* B triangle */
914       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
915       orntNew[0] = ornt[0];
916       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
917       orntNew[1] = ornt[1];
918       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 0;
919       orntNew[2] = -2;
920       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
921       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
922 #if 1
923       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);
924       for (p = 0; p < 3; ++p) {
925         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);
926       }
927 #endif
928       /* C triangle */
929       coneNew[0] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 1;
930       orntNew[0] = -2;
931       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
932       orntNew[1] = ornt[1];
933       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
934       orntNew[2] = ornt[2];
935       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
936       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
937 #if 1
938       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);
939       for (p = 0; p < 3; ++p) {
940         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);
941       }
942 #endif
943       /* D triangle */
944       coneNew[0] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 0;
945       orntNew[0] = 0;
946       coneNew[1] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 1;
947       orntNew[1] = 0;
948       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 2;
949       orntNew[2] = 0;
950       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
951       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
952 #if 1
953       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);
954       for (p = 0; p < 3; ++p) {
955         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);
956       }
957 #endif
958     }
959     /*
960      2----3----3
961      |         |
962      |    B    |
963      |         |
964      0----4--- 1
965      |         |
966      |    A    |
967      |         |
968      0----2----1
969      */
970     /* Hybrid cells have 4 faces */
971     for (c = cMax; c < cEnd; ++c) {
972       const PetscInt  newp = cStartNew + (cMax - cStart)*4 + (c - cMax)*2;
973       const PetscInt *cone, *ornt;
974       PetscInt        coneNew[4], orntNew[4];
975 
976       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
977       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
978       /* A quad */
979       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
980       orntNew[0] = ornt[0];
981       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
982       orntNew[1] = ornt[1];
983       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (cone[2] - fMax);
984       orntNew[2] = 0;
985       coneNew[3] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (fEnd    - fMax) + (c - cMax);
986       orntNew[3] = 0;
987       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
988       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
989 #if 1
990       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);
991       for (p = 0; p < 4; ++p) {
992         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);
993       }
994 #endif
995       /* B quad */
996       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
997       orntNew[0] = ornt[0];
998       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
999       orntNew[1] = ornt[1];
1000       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (fEnd    - fMax) + (c - cMax);
1001       orntNew[2] = 0;
1002       coneNew[3] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (cone[3] - fMax);
1003       orntNew[3] = 0;
1004       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
1005       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
1006 #if 1
1007       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);
1008       for (p = 0; p < 4; ++p) {
1009         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);
1010       }
1011 #endif
1012     }
1013     /* Interior split faces have 2 vertices and the same cells as the parent */
1014     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
1015     ierr = PetscMalloc((2 + maxSupportSize*2) * sizeof(PetscInt), &supportRef);CHKERRQ(ierr);
1016     for (f = fStart; f < fMax; ++f) {
1017       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);
1018 
1019       for (r = 0; r < 2; ++r) {
1020         const PetscInt  newp = fStartNew + (f - fStart)*2 + r;
1021         const PetscInt *cone, *ornt, *support;
1022         PetscInt        coneNew[2], coneSize, c, supportSize, s;
1023 
1024         ierr             = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
1025         coneNew[0]       = vStartNew + (cone[0] - vStart);
1026         coneNew[1]       = vStartNew + (cone[1] - vStart);
1027         coneNew[(r+1)%2] = newv;
1028         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
1029 #if 1
1030         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1031         for (p = 0; p < 2; ++p) {
1032           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);
1033         }
1034 #endif
1035         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
1036         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
1037         for (s = 0; s < supportSize; ++s) {
1038           if (support[s] >= cMax) {
1039             supportRef[s] = cStartNew + (cMax - cStart)*4 + (support[s] - cMax)*2 + r;
1040           } else {
1041             ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
1042             ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
1043             ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
1044             for (c = 0; c < coneSize; ++c) {
1045               if (cone[c] == f) break;
1046             }
1047             supportRef[s] = cStartNew + (support[s] - cStart)*4 + (ornt[c] < 0 ? (c+1-r)%3 : (c+r)%3);
1048           }
1049         }
1050         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
1051 #if 1
1052         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1053         for (p = 0; p < supportSize; ++p) {
1054           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);
1055         }
1056 #endif
1057       }
1058     }
1059     /* Interior cell faces have 2 vertices and 2 cells */
1060     for (c = cStart; c < cMax; ++c) {
1061       const PetscInt *cone;
1062 
1063       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
1064       for (r = 0; r < 3; ++r) {
1065         const PetscInt newp = fStartNew + (fMax - fStart)*2 + (c - cStart)*3 + r;
1066         PetscInt       coneNew[2];
1067         PetscInt       supportNew[2];
1068 
1069         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r]       - fStart);
1070         coneNew[1] = vStartNew + (vEnd - vStart) + (cone[(r+1)%3] - fStart);
1071         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
1072 #if 1
1073         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1074         for (p = 0; p < 2; ++p) {
1075           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);
1076         }
1077 #endif
1078         supportNew[0] = (c - cStart)*4 + (r+1)%3;
1079         supportNew[1] = (c - cStart)*4 + 3;
1080         ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
1081 #if 1
1082         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1083         for (p = 0; p < 2; ++p) {
1084           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);
1085         }
1086 #endif
1087       }
1088     }
1089     /* Interior hybrid faces have 2 vertices and the same cells */
1090     for (f = fMax; f < fEnd; ++f) {
1091       const PetscInt  newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (f - fMax);
1092       const PetscInt *cone;
1093       const PetscInt *support;
1094       PetscInt        coneNew[2];
1095       PetscInt        supportNew[2];
1096       PetscInt        size, s, r;
1097 
1098       ierr       = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
1099       coneNew[0] = vStartNew + (cone[0] - vStart);
1100       coneNew[1] = vStartNew + (cone[1] - vStart);
1101       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
1102 #if 1
1103       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1104       for (p = 0; p < 2; ++p) {
1105         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);
1106       }
1107 #endif
1108       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
1109       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
1110       for (s = 0; s < size; ++s) {
1111         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
1112         for (r = 0; r < 2; ++r) {
1113           if (cone[r+2] == f) break;
1114         }
1115         supportNew[s] = (cMax - cStart)*4 + (support[s] - cMax)*2 + r;
1116       }
1117       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
1118 #if 1
1119       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1120       for (p = 0; p < size; ++p) {
1121         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);
1122       }
1123 #endif
1124     }
1125     /* Cell hybrid faces have 2 vertices and 2 cells */
1126     for (c = cMax; c < cEnd; ++c) {
1127       const PetscInt  newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (fEnd - fMax) + (c - cMax);
1128       const PetscInt *cone;
1129       PetscInt        coneNew[2];
1130       PetscInt        supportNew[2];
1131 
1132       ierr       = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
1133       coneNew[0] = vStartNew + (vEnd - vStart) + (cone[0] - fStart);
1134       coneNew[1] = vStartNew + (vEnd - vStart) + (cone[1] - fStart);
1135       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
1136 #if 1
1137       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1138       for (p = 0; p < 2; ++p) {
1139         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);
1140       }
1141 #endif
1142       supportNew[0] = (cMax - cStart)*4 + (c - cMax)*2 + 0;
1143       supportNew[1] = (cMax - cStart)*4 + (c - cMax)*2 + 1;
1144       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
1145 #if 1
1146       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1147       for (p = 0; p < 2; ++p) {
1148         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);
1149       }
1150 #endif
1151     }
1152     /* Old vertices have identical supports */
1153     for (v = vStart; v < vEnd; ++v) {
1154       const PetscInt  newp = vStartNew + (v - vStart);
1155       const PetscInt *support, *cone;
1156       PetscInt        size, s;
1157 
1158       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
1159       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
1160       for (s = 0; s < size; ++s) {
1161         if (support[s] >= fMax) {
1162           supportRef[s] = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (support[s] - fMax);
1163         } else {
1164           PetscInt r = 0;
1165 
1166           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
1167           if (cone[1] == v) r = 1;
1168           supportRef[s] = fStartNew + (support[s] - fStart)*2 + r;
1169         }
1170       }
1171       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
1172 #if 1
1173       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
1174       for (p = 0; p < size; ++p) {
1175         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);
1176       }
1177 #endif
1178     }
1179     /* Face vertices have 2 + (2 interior, 1 hybrid) supports */
1180     for (f = fStart; f < fMax; ++f) {
1181       const PetscInt  newp = vStartNew + (vEnd - vStart) + (f - fStart);
1182       const PetscInt *cone, *support;
1183       PetscInt        size, newSize = 2, s;
1184 
1185       ierr          = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
1186       ierr          = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
1187       supportRef[0] = fStartNew + (f - fStart)*2 + 0;
1188       supportRef[1] = fStartNew + (f - fStart)*2 + 1;
1189       for (s = 0; s < size; ++s) {
1190         PetscInt r = 0;
1191 
1192         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
1193         if (support[s] >= cMax) {
1194           supportRef[newSize+0] = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (fEnd - fMax) + (support[s] - cMax);
1195 
1196           newSize += 1;
1197         } else {
1198           if      (cone[1] == f) r = 1;
1199           else if (cone[2] == f) r = 2;
1200           supportRef[newSize+0] = fStartNew + (fMax - fStart)*2 + (support[s] - cStart)*3 + (r+2)%3;
1201           supportRef[newSize+1] = fStartNew + (fMax - fStart)*2 + (support[s] - cStart)*3 + r;
1202 
1203           newSize += 2;
1204         }
1205       }
1206       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
1207 #if 1
1208       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
1209       for (p = 0; p < newSize; ++p) {
1210         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);
1211       }
1212 #endif
1213     }
1214     ierr = PetscFree(supportRef);CHKERRQ(ierr);
1215     break;
1216   case 5:
1217     /* Simplicial 3D */
1218     /* All cells have 4 faces: Tet face order is prescribed in DMPlexGetFaces_Internal() */
1219     ierr = DMPlexGetRawFaces_Internal(dm, 3, 4, cellInd, NULL, NULL, &faces);CHKERRQ(ierr);
1220     for (c = cStart; c < cEnd; ++c) {
1221       const PetscInt  newp = cStartNew + (c - cStart)*8;
1222       const PetscInt *cone, *ornt;
1223       PetscInt        coneNew[4], orntNew[4];
1224 
1225       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
1226       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
1227       /* A tetrahedron: {0, a, c, d} */
1228       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + (ornt[0] < 0 ? (-(ornt[0]+1)+1)%3 : ornt[0]); /* A */
1229       orntNew[0] = ornt[0];
1230       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + (ornt[1] < 0 ? (-(ornt[1]+1)+1)%3 : ornt[1]); /* A */
1231       orntNew[1] = ornt[1];
1232       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + (ornt[2] < 0 ? (-(ornt[2]+1)+1)%3 : ornt[2]); /* A */
1233       orntNew[2] = ornt[2];
1234       coneNew[3] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 0;
1235       orntNew[3] = 0;
1236       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
1237       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
1238 #if 1
1239       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);
1240       for (p = 0; p < 4; ++p) {
1241         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);
1242       }
1243 #endif
1244       /* B tetrahedron: {a, 1, b, e} */
1245       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + (ornt[0] < 0 ? (-(ornt[0]+1)+0)%3 : (ornt[0]+1)%3); /* B */
1246       orntNew[0] = ornt[0];
1247       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + (ornt[1] < 0 ? (-(ornt[1]+1)+2)%3 : (ornt[1]+2)%3); /* C */
1248       orntNew[1] = ornt[1];
1249       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 1;
1250       orntNew[2] = 0;
1251       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + (ornt[3] < 0 ? (-(ornt[3]+1)+0)%3 : (ornt[3]+1)%3); /* B */
1252       orntNew[3] = ornt[3];
1253       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
1254       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
1255 #if 1
1256       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);
1257       for (p = 0; p < 4; ++p) {
1258         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);
1259       }
1260 #endif
1261       /* C tetrahedron: {c, b, 2, f} */
1262       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + (ornt[0] < 0 ? (-(ornt[0]+1)+2)%3 : (ornt[0]+2)%3); /* C */
1263       orntNew[0] = ornt[0];
1264       coneNew[1] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 2;
1265       orntNew[1] = 0;
1266       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + (ornt[2] < 0 ? (-(ornt[2]+1)+0)%3 : (ornt[2]+1)%3); /* B */
1267       orntNew[2] = ornt[2];
1268       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + (ornt[3] < 0 ? (-(ornt[3]+1)+1)%3 : (ornt[3]+0)%3); /* A */
1269       orntNew[3] = ornt[3];
1270       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
1271       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
1272 #if 1
1273       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);
1274       for (p = 0; p < 4; ++p) {
1275         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);
1276       }
1277 #endif
1278       /* D tetrahedron: {d, e, f, 3} */
1279       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 3;
1280       orntNew[0] = 0;
1281       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + (ornt[1] < 0 ? (-(ornt[1]+1)+0)%3 : (ornt[1]+1)%3); /* B */
1282       orntNew[1] = ornt[1];
1283       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + (ornt[2] < 0 ? (-(ornt[2]+1)+2)%3 : (ornt[2]+2)%3); /* C */
1284       orntNew[2] = ornt[2];
1285       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + (ornt[3] < 0 ? (-(ornt[3]+1)+2)%3 : (ornt[3]+2)%3); /* C */
1286       orntNew[3] = ornt[3];
1287       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
1288       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
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 < 4; ++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       /* A' tetrahedron: {d, a, c, f} */
1296       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 0;
1297       orntNew[0] = -3;
1298       coneNew[1] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 4;
1299       orntNew[1] = 0;
1300       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + 3;
1301       orntNew[2] = ornt[2] < 0 ? -((-(ornt[2]+1)+2)%3+1) : (ornt[2]+2)%3;
1302       coneNew[3] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 5;
1303       orntNew[3] = 0;
1304       ierr       = DMPlexSetCone(rdm, newp+4, coneNew);CHKERRQ(ierr);
1305       ierr       = DMPlexSetConeOrientation(rdm, newp+4, orntNew);CHKERRQ(ierr);
1306 #if 1
1307       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);
1308       for (p = 0; p < 4; ++p) {
1309         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);
1310       }
1311 #endif
1312       /* B' tetrahedron: {e, b, a, f} */
1313       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 1;
1314       orntNew[0] = -3;
1315       coneNew[1] = fStartNew + (cone[3] - fStart)*4 + 3;
1316       orntNew[1] = ornt[3] < 0 ? -((-(ornt[3]+1)+1)%3+1) : (ornt[3]+1)%3;
1317       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 6;
1318       orntNew[2] = 0;
1319       coneNew[3] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 7;
1320       orntNew[3] = 0;
1321       ierr       = DMPlexSetCone(rdm, newp+5, coneNew);CHKERRQ(ierr);
1322       ierr       = DMPlexSetConeOrientation(rdm, newp+5, orntNew);CHKERRQ(ierr);
1323 #if 1
1324       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);
1325       for (p = 0; p < 4; ++p) {
1326         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);
1327       }
1328 #endif
1329       /* C' tetrahedron: {b, f, c, a} */
1330       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 2;
1331       orntNew[0] = -3;
1332       coneNew[1] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 7;
1333       orntNew[1] = -2;
1334       coneNew[2] = fStartNew + (cone[0] - fStart)*4 + 3;
1335       orntNew[2] = ornt[0] < 0 ? (-(ornt[0]+1)+1)%3 : -((ornt[0]+1)%3+1);
1336       coneNew[3] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 5;
1337       orntNew[3] = -1;
1338       ierr       = DMPlexSetCone(rdm, newp+6, coneNew);CHKERRQ(ierr);
1339       ierr       = DMPlexSetConeOrientation(rdm, newp+6, orntNew);CHKERRQ(ierr);
1340 #if 1
1341       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);
1342       for (p = 0; p < 4; ++p) {
1343         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);
1344       }
1345 #endif
1346       /* D' tetrahedron: {f, e, d, a} */
1347       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 3;
1348       orntNew[0] = -3;
1349       coneNew[1] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 6;
1350       orntNew[1] = -3;
1351       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 4;
1352       orntNew[2] = -2;
1353       coneNew[3] = fStartNew + (cone[1] - fStart)*4 + 3;
1354       orntNew[3] = ornt[2];
1355       ierr       = DMPlexSetCone(rdm, newp+7, coneNew);CHKERRQ(ierr);
1356       ierr       = DMPlexSetConeOrientation(rdm, newp+7, orntNew);CHKERRQ(ierr);
1357 #if 1
1358       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);
1359       for (p = 0; p < 4; ++p) {
1360         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);
1361       }
1362 #endif
1363     }
1364     /* Split faces have 3 edges and the same cells as the parent */
1365     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
1366     ierr = PetscMalloc((2 + maxSupportSize*2) * sizeof(PetscInt), &supportRef);CHKERRQ(ierr);
1367     for (f = fStart; f < fEnd; ++f) {
1368       const PetscInt  newp = fStartNew + (f - fStart)*4;
1369       const PetscInt *cone, *ornt, *support;
1370       PetscInt        coneNew[3], orntNew[3], coneSize, supportSize, s;
1371 
1372       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
1373       ierr = DMPlexGetConeOrientation(dm, f, &ornt);CHKERRQ(ierr);
1374       /* A triangle */
1375       coneNew[0] = eStartNew + (cone[0] - eStart)*2 + (ornt[0] < 0 ? 1 : 0);
1376       orntNew[0] = ornt[0];
1377       coneNew[1] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 2;
1378       orntNew[1] = -2;
1379       coneNew[2] = eStartNew + (cone[2] - eStart)*2 + (ornt[2] < 0 ? 0 : 1);
1380       orntNew[2] = ornt[2];
1381       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
1382       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
1383 #if 1
1384       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);
1385       for (p = 0; p < 3; ++p) {
1386         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);
1387       }
1388 #endif
1389       /* B triangle */
1390       coneNew[0] = eStartNew + (cone[0] - eStart)*2 + (ornt[0] < 0 ? 0 : 1);
1391       orntNew[0] = ornt[0];
1392       coneNew[1] = eStartNew + (cone[1] - eStart)*2 + (ornt[1] < 0 ? 1 : 0);
1393       orntNew[1] = ornt[1];
1394       coneNew[2] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 0;
1395       orntNew[2] = -2;
1396       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
1397       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
1398 #if 1
1399       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);
1400       for (p = 0; p < 3; ++p) {
1401         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);
1402       }
1403 #endif
1404       /* C triangle */
1405       coneNew[0] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 1;
1406       orntNew[0] = -2;
1407       coneNew[1] = eStartNew + (cone[1] - eStart)*2 + (ornt[1] < 0 ? 0 : 1);
1408       orntNew[1] = ornt[1];
1409       coneNew[2] = eStartNew + (cone[2] - eStart)*2 + (ornt[2] < 0 ? 1 : 0);
1410       orntNew[2] = ornt[2];
1411       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
1412       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
1413 #if 1
1414       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);
1415       for (p = 0; p < 3; ++p) {
1416         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);
1417       }
1418 #endif
1419       /* D triangle */
1420       coneNew[0] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 0;
1421       orntNew[0] = 0;
1422       coneNew[1] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 1;
1423       orntNew[1] = 0;
1424       coneNew[2] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 2;
1425       orntNew[2] = 0;
1426       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
1427       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
1428 #if 1
1429       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);
1430       for (p = 0; p < 3; ++p) {
1431         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);
1432       }
1433 #endif
1434       ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
1435       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
1436       for (r = 0; r < 4; ++r) {
1437         for (s = 0; s < supportSize; ++s) {
1438           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
1439           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
1440           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
1441           for (c = 0; c < coneSize; ++c) {
1442             if (cone[c] == f) break;
1443           }
1444           supportRef[s] = cStartNew + (support[s] - cStart)*8 + (r==3 ? (c+2)%4 + 4 : (ornt[c] < 0 ? faces[c*3+(-(ornt[c]+1)+1+3-r)%3] : faces[c*3+r]));
1445         }
1446         ierr = DMPlexSetSupport(rdm, newp+r, supportRef);CHKERRQ(ierr);
1447 #if 1
1448         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1449         for (p = 0; p < supportSize; ++p) {
1450           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);
1451         }
1452 #endif
1453       }
1454     }
1455     /* Interior faces have 3 edges and 2 cells */
1456     for (c = cStart; c < cEnd; ++c) {
1457       PetscInt        newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*8;
1458       const PetscInt *cone, *ornt;
1459       PetscInt        coneNew[3], orntNew[3];
1460       PetscInt        supportNew[2];
1461 
1462       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
1463       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
1464       /* Face A: {c, a, d} */
1465       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*3 + (ornt[0] < 0 ? (-(ornt[0]+1)+0)%3 : (ornt[0]+2)%3);
1466       orntNew[0] = ornt[0] < 0 ? -2 : 0;
1467       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*3 + (ornt[1] < 0 ? (-(ornt[1]+1)+0)%3 : (ornt[1]+2)%3);
1468       orntNew[1] = ornt[1] < 0 ? -2 : 0;
1469       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*3 + (ornt[2] < 0 ? (-(ornt[2]+1)+0)%3 : (ornt[2]+2)%3);
1470       orntNew[2] = ornt[2] < 0 ? -2 : 0;
1471       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
1472       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
1473 #if 1
1474       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1475       for (p = 0; p < 3; ++p) {
1476         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);
1477       }
1478 #endif
1479       supportNew[0] = (c - cStart)*8 + 0;
1480       supportNew[1] = (c - cStart)*8 + 0+4;
1481       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
1482 #if 1
1483       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1484       for (p = 0; p < 2; ++p) {
1485         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);
1486       }
1487 #endif
1488       ++newp;
1489       /* Face B: {a, b, e} */
1490       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*3 + (ornt[0] < 0 ? (-(ornt[0]+1)+2)%3 : (ornt[0]+0)%3);
1491       orntNew[0] = ornt[0] < 0 ? -2 : 0;
1492       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*3 + (ornt[3] < 0 ? (-(ornt[3]+1)+2)%3 : (ornt[3]+0)%3);
1493       orntNew[1] = ornt[3] < 0 ? -2 : 0;
1494       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*3 + (ornt[1] < 0 ? (-(ornt[1]+1)+1)%3 : (ornt[1]+1)%3);
1495       orntNew[2] = ornt[1] < 0 ? -2 : 0;
1496       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
1497       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
1498 #if 1
1499       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);
1500       for (p = 0; p < 3; ++p) {
1501         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);
1502       }
1503 #endif
1504       supportNew[0] = (c - cStart)*8 + 1;
1505       supportNew[1] = (c - cStart)*8 + 1+4;
1506       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
1507 #if 1
1508       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1509       for (p = 0; p < 2; ++p) {
1510         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cEndNew);
1511       }
1512 #endif
1513       ++newp;
1514       /* Face C: {c, f, b} */
1515       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*3 + (ornt[2] < 0 ? (-(ornt[2]+1)+2)%3 : (ornt[2]+0)%3);
1516       orntNew[0] = ornt[2] < 0 ? -2 : 0;
1517       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*3 + (ornt[3] < 0 ? (-(ornt[3]+1)+0)%3 : (ornt[3]+2)%3);
1518       orntNew[1] = ornt[3] < 0 ? -2 : 0;
1519       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*3 + (ornt[0] < 0 ? (-(ornt[0]+1)+1)%3 : (ornt[0]+1)%3);
1520       orntNew[2] = ornt[0] < 0 ? -2 : 0;
1521       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
1522       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
1523 #if 1
1524       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1525       for (p = 0; p < 3; ++p) {
1526         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);
1527       }
1528 #endif
1529       supportNew[0] = (c - cStart)*8 + 2;
1530       supportNew[1] = (c - cStart)*8 + 2+4;
1531       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
1532 #if 1
1533       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1534       for (p = 0; p < 2; ++p) {
1535         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);
1536       }
1537 #endif
1538       ++newp;
1539       /* Face D: {d, e, f} */
1540       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*3 + (ornt[1] < 0 ? (-(ornt[1]+1)+2)%3 : (ornt[1]+0)%3);
1541       orntNew[0] = ornt[1] < 0 ? -2 : 0;
1542       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*3 + (ornt[3] < 0 ? (-(ornt[3]+1)+1)%3 : (ornt[3]+1)%3);
1543       orntNew[1] = ornt[3] < 0 ? -2 : 0;
1544       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*3 + (ornt[2] < 0 ? (-(ornt[2]+1)+1)%3 : (ornt[2]+1)%3);
1545       orntNew[2] = ornt[2] < 0 ? -2 : 0;
1546       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
1547       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
1548 #if 1
1549       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1550       for (p = 0; p < 3; ++p) {
1551         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);
1552       }
1553 #endif
1554       supportNew[0] = (c - cStart)*8 + 3;
1555       supportNew[1] = (c - cStart)*8 + 3+4;
1556       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
1557 #if 1
1558       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1559       for (p = 0; p < 2; ++p) {
1560         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);
1561       }
1562 #endif
1563       ++newp;
1564       /* Face E: {d, f, a} */
1565       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*3 + (ornt[2] < 0 ? (-(ornt[2]+1)+1)%3 : (ornt[2]+1)%3);
1566       orntNew[0] = ornt[2] < 0 ? 0 : -2;
1567       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart);
1568       orntNew[1] = 0;
1569       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*3 + (ornt[1] < 0 ? (-(ornt[1]+1)+0)%3 : (ornt[1]+2)%3);
1570       orntNew[2] = ornt[1] < 0 ? -2 : 0;
1571       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
1572       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
1573 #if 1
1574       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1575       for (p = 0; p < 3; ++p) {
1576         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);
1577       }
1578 #endif
1579       supportNew[0] = (c - cStart)*8 + 0+4;
1580       supportNew[1] = (c - cStart)*8 + 3+4;
1581       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
1582 #if 1
1583       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1584       for (p = 0; p < 2; ++p) {
1585         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);
1586       }
1587 #endif
1588       ++newp;
1589       /* Face F: {c, a, f} */
1590       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*3 + (ornt[0] < 0 ? (-(ornt[0]+1)+0)%3 : (ornt[0]+2)%3);
1591       orntNew[0] = ornt[0] < 0 ? -2 : 0;
1592       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart);
1593       orntNew[1] = -2;
1594       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*3 + (ornt[2] < 0 ? (-(ornt[2]+1)+2)%3 : (ornt[2]+0)%3);
1595       orntNew[2] = ornt[1] < 0 ? 0 : -2;
1596       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
1597       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
1598 #if 1
1599       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1600       for (p = 0; p < 3; ++p) {
1601         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);
1602       }
1603 #endif
1604       supportNew[0] = (c - cStart)*8 + 0+4;
1605       supportNew[1] = (c - cStart)*8 + 2+4;
1606       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
1607 #if 1
1608       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1609       for (p = 0; p < 2; ++p) {
1610         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);
1611       }
1612 #endif
1613       ++newp;
1614       /* Face G: {e, a, f} */
1615       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*3 + (ornt[1] < 0 ? (-(ornt[1]+1)+1)%3 : (ornt[1]+1)%3);
1616       orntNew[0] = ornt[1] < 0 ? -2 : 0;
1617       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart);
1618       orntNew[1] = -2;
1619       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*3 + (ornt[3] < 0 ? (-(ornt[3]+1)+1)%3 : (ornt[3]+1)%3);
1620       orntNew[2] = ornt[3] < 0 ? 0 : -2;
1621       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
1622       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
1623 #if 1
1624       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1625       for (p = 0; p < 3; ++p) {
1626         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);
1627       }
1628 #endif
1629       supportNew[0] = (c - cStart)*8 + 1+4;
1630       supportNew[1] = (c - cStart)*8 + 3+4;
1631       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
1632 #if 1
1633       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1634       for (p = 0; p < 2; ++p) {
1635         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);
1636       }
1637 #endif
1638       ++newp;
1639       /* Face H: {a, b, f} */
1640       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*3 + (ornt[0] < 0 ? (-(ornt[0]+1)+2)%3 : (ornt[0]+0)%3);
1641       orntNew[0] = ornt[0] < 0 ? -2 : 0;
1642       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*3 + (ornt[3] < 0 ? (-(ornt[3]+1)+0)%3 : (ornt[3]+2)%3);
1643       orntNew[1] = ornt[3] < 0 ? 0 : -2;
1644       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart);
1645       orntNew[2] = 0;
1646       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
1647       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
1648 #if 1
1649       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1650       for (p = 0; p < 3; ++p) {
1651         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);
1652       }
1653 #endif
1654       supportNew[0] = (c - cStart)*8 + 1+4;
1655       supportNew[1] = (c - cStart)*8 + 2+4;
1656       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
1657 #if 1
1658       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1659       for (p = 0; p < 2; ++p) {
1660         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);
1661       }
1662 #endif
1663       ++newp;
1664     }
1665     /* Split Edges have 2 vertices and the same faces as the parent */
1666     for (e = eStart; e < eEnd; ++e) {
1667       const PetscInt newv = vStartNew + (vEnd - vStart) + (e - eStart);
1668 
1669       for (r = 0; r < 2; ++r) {
1670         const PetscInt  newp = eStartNew + (e - eStart)*2 + r;
1671         const PetscInt *cone, *ornt, *support;
1672         PetscInt        coneNew[2], coneSize, c, supportSize, s;
1673 
1674         ierr             = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
1675         coneNew[0]       = vStartNew + (cone[0] - vStart);
1676         coneNew[1]       = vStartNew + (cone[1] - vStart);
1677         coneNew[(r+1)%2] = newv;
1678         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
1679 #if 1
1680         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
1681         for (p = 0; p < 2; ++p) {
1682           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);
1683         }
1684 #endif
1685         ierr = DMPlexGetSupportSize(dm, e, &supportSize);CHKERRQ(ierr);
1686         ierr = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
1687         for (s = 0; s < supportSize; ++s) {
1688           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
1689           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
1690           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
1691           for (c = 0; c < coneSize; ++c) {
1692             if (cone[c] == e) break;
1693           }
1694           supportRef[s] = fStartNew + (support[s] - fStart)*4 + (c + (ornt[c] < 0 ? 1-r : r))%3;
1695         }
1696         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
1697 #if 1
1698         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
1699         for (p = 0; p < supportSize; ++p) {
1700           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);
1701         }
1702 #endif
1703       }
1704     }
1705     /* Face edges have 2 vertices and 2+cells*(1/2) faces */
1706     for (f = fStart; f < fEnd; ++f) {
1707       const PetscInt *cone, *ornt, *support;
1708       PetscInt        coneSize, supportSize, s;
1709 
1710       ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
1711       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
1712       for (r = 0; r < 3; ++r) {
1713         const PetscInt  newp = eStartNew + (eEnd - eStart)*2 + (f - fStart)*3 + r;
1714         PetscInt        coneNew[2], intFaces = 0, er, eint[4] = {1, 0, 2, 0};
1715         PetscInt        fint[24] = { 1,  7, -1, -1,  0,  5,
1716                                     -1, -1,  1,  6,  0,  4,
1717                                      2,  5,  3,  4, -1, -1,
1718                                     -1, -1,  3,  6,  2,  7};
1719 
1720         ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
1721         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[(r+0)%3] - eStart);
1722         coneNew[1] = vStartNew + (vEnd - vStart) + (cone[(r+1)%3] - eStart);
1723         ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
1724 #if 1
1725         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
1726         for (p = 0; p < 2; ++p) {
1727           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);
1728         }
1729 #endif
1730         supportRef[0] = fStartNew + (f - fStart)*4 + (r+1)%3;
1731         supportRef[1] = fStartNew + (f - fStart)*4 + 3;
1732         for (s = 0; s < supportSize; ++s) {
1733           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
1734           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
1735           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
1736           for (c = 0; c < coneSize; ++c) {if (cone[c] == f) break;}
1737           /* Here we want to determine whether edge newp contains a vertex which is part of the cross-tet edge */
1738           er   = ornt[c] < 0 ? (-(ornt[c]+1) + 2-r)%3 : (ornt[c] + r)%3;
1739           if (er == eint[c]) {
1740             supportRef[2+intFaces++] = fStartNew + (fEnd - fStart)*4 + (support[s] - cStart)*8 + (c + 2)%4;
1741           } else {
1742             supportRef[2+intFaces++] = fStartNew + (fEnd - fStart)*4 + (support[s] - cStart)*8 + fint[(c*3 + er)*2 + 0];
1743             supportRef[2+intFaces++] = fStartNew + (fEnd - fStart)*4 + (support[s] - cStart)*8 + fint[(c*3 + er)*2 + 1];
1744           }
1745         }
1746         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
1747 #if 1
1748         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
1749         for (p = 0; p < intFaces; ++p) {
1750           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);
1751         }
1752 #endif
1753       }
1754     }
1755     /* Interior edges have 2 vertices and 4 faces */
1756     for (c = cStart; c < cEnd; ++c) {
1757       const PetscInt  newp = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart);
1758       const PetscInt *cone, *ornt, *fcone;
1759       PetscInt        coneNew[2], supportNew[4], find;
1760 
1761       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
1762       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
1763       ierr = DMPlexGetCone(dm, cone[0], &fcone);CHKERRQ(ierr);
1764       find = ornt[0] < 0 ? (-(ornt[0]+1) + 0)%3 : ornt[0];
1765       coneNew[0] = vStartNew + (vEnd - vStart) + (fcone[find] - eStart);
1766       ierr = DMPlexGetCone(dm, cone[2], &fcone);CHKERRQ(ierr);
1767       find = ornt[2] < 0 ? (-(ornt[2]+1) + 1)%3 : (ornt[2]+1)%3;
1768       coneNew[1] = vStartNew + (vEnd - vStart) + (fcone[find] - eStart);
1769       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
1770 #if 1
1771       if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
1772       for (p = 0; p < 2; ++p) {
1773         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);
1774       }
1775 #endif
1776       supportNew[0] = fStartNew + (fEnd - fStart)*4 + (c - cStart)*8 + 4;
1777       supportNew[1] = fStartNew + (fEnd - fStart)*4 + (c - cStart)*8 + 5;
1778       supportNew[2] = fStartNew + (fEnd - fStart)*4 + (c - cStart)*8 + 6;
1779       supportNew[3] = fStartNew + (fEnd - fStart)*4 + (c - cStart)*8 + 7;
1780       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
1781 #if 1
1782       if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
1783       for (p = 0; p < 4; ++p) {
1784         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);
1785       }
1786 #endif
1787     }
1788     /* Old vertices have identical supports */
1789     for (v = vStart; v < vEnd; ++v) {
1790       const PetscInt  newp = vStartNew + (v - vStart);
1791       const PetscInt *support, *cone;
1792       PetscInt        size, s;
1793 
1794       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
1795       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
1796       for (s = 0; s < size; ++s) {
1797         PetscInt r = 0;
1798 
1799         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
1800         if (cone[1] == v) r = 1;
1801         supportRef[s] = eStartNew + (support[s] - eStart)*2 + r;
1802       }
1803       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
1804 #if 1
1805       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
1806       for (p = 0; p < size; ++p) {
1807         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);
1808       }
1809 #endif
1810     }
1811     /* Edge vertices have 2 + face*2 + 0/1 supports */
1812     for (e = eStart; e < eEnd; ++e) {
1813       const PetscInt  newp = vStartNew + (vEnd - vStart) + (e - eStart);
1814       const PetscInt *cone, *support;
1815       PetscInt       *star = NULL, starSize, cellSize = 0, coneSize, size, s;
1816 
1817       ierr          = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
1818       ierr          = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
1819       supportRef[0] = eStartNew + (e - eStart)*2 + 0;
1820       supportRef[1] = eStartNew + (e - eStart)*2 + 1;
1821       for (s = 0; s < size; ++s) {
1822         PetscInt r = 0;
1823 
1824         ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
1825         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
1826         for (r = 0; r < coneSize; ++r) {if (cone[r] == e) break;}
1827         supportRef[2+s*2+0] = eStartNew + (eEnd - eStart)*2 + (support[s] - fStart)*3 + (r+0)%3;
1828         supportRef[2+s*2+1] = eStartNew + (eEnd - eStart)*2 + (support[s] - fStart)*3 + (r+2)%3;
1829       }
1830       ierr = DMPlexGetTransitiveClosure(dm, e, PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
1831       for (s = 0; s < starSize*2; s += 2) {
1832         const PetscInt *cone, *ornt;
1833         PetscInt        e01, e23;
1834 
1835         if ((star[s] >= cStart) && (star[s] < cEnd)) {
1836           /* Check edge 0-1 */
1837           ierr = DMPlexGetCone(dm, star[s], &cone);CHKERRQ(ierr);
1838           ierr = DMPlexGetConeOrientation(dm, star[s], &ornt);CHKERRQ(ierr);
1839           ierr = DMPlexGetCone(dm, cone[0], &cone);CHKERRQ(ierr);
1840           e01  = cone[ornt[0] < 0 ? (-(ornt[0]+1) + 0)%3 : ornt[0]];
1841           /* Check edge 2-3 */
1842           ierr = DMPlexGetCone(dm, star[s], &cone);CHKERRQ(ierr);
1843           ierr = DMPlexGetConeOrientation(dm, star[s], &ornt);CHKERRQ(ierr);
1844           ierr = DMPlexGetCone(dm, cone[3], &cone);CHKERRQ(ierr);
1845           e23  = cone[ornt[3] < 0 ? (-(ornt[3]+1) + 2)%3 : (ornt[3] + 2)%3];
1846           if ((e01 == e) || (e23 == e)) {supportRef[2+size*2+cellSize++] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (star[s] - cStart);}
1847         }
1848       }
1849       ierr = DMPlexRestoreTransitiveClosure(dm, e, PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
1850       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
1851 #if 1
1852       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
1853       for (p = 0; p < 2+size*2+cellSize; ++p) {
1854         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);
1855       }
1856 #endif
1857     }
1858     ierr = PetscFree(supportRef);CHKERRQ(ierr);
1859     ierr = DMPlexRestoreFaces_Internal(dm, 3, cStart, NULL, NULL, &faces);CHKERRQ(ierr);
1860     break;
1861   default:
1862     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
1863   }
1864   PetscFunctionReturn(0);
1865 }
1866 
1867 #undef __FUNCT__
1868 #define __FUNCT__ "CellRefinerSetCoordinates"
1869 PetscErrorCode CellRefinerSetCoordinates(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
1870 {
1871   PetscSection   coordSection, coordSectionNew;
1872   Vec            coordinates, coordinatesNew;
1873   PetscScalar   *coords, *coordsNew;
1874   PetscInt       dim, depth, coordSizeNew, cStart, cEnd, c, vStart, vStartNew, vEnd, v, eStart, eEnd, eMax, e, fStart, fEnd, fMax, f;
1875   PetscErrorCode ierr;
1876 
1877   PetscFunctionBegin;
1878   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
1879   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
1880   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
1881   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
1882   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
1883   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
1884   ierr = DMPlexGetHybridBounds(dm, NULL, &fMax, &eMax, NULL);CHKERRQ(ierr);
1885   ierr = GetDepthStart_Private(depth, depthSize, NULL, NULL, NULL, &vStartNew);CHKERRQ(ierr);
1886   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
1887   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)dm), &coordSectionNew);CHKERRQ(ierr);
1888   ierr = PetscSectionSetNumFields(coordSectionNew, 1);CHKERRQ(ierr);
1889   ierr = PetscSectionSetFieldComponents(coordSectionNew, 0, dim);CHKERRQ(ierr);
1890   ierr = PetscSectionSetChart(coordSectionNew, vStartNew, vStartNew+depthSize[0]);CHKERRQ(ierr);
1891   if (fMax < 0) fMax = fEnd;
1892   if (eMax < 0) eMax = eEnd;
1893   /* All vertices have the dim coordinates */
1894   for (v = vStartNew; v < vStartNew+depthSize[0]; ++v) {
1895     ierr = PetscSectionSetDof(coordSectionNew, v, dim);CHKERRQ(ierr);
1896     ierr = PetscSectionSetFieldDof(coordSectionNew, v, 0, dim);CHKERRQ(ierr);
1897   }
1898   ierr = PetscSectionSetUp(coordSectionNew);CHKERRQ(ierr);
1899   ierr = DMPlexSetCoordinateSection(rdm, coordSectionNew);CHKERRQ(ierr);
1900   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
1901   ierr = PetscSectionGetStorageSize(coordSectionNew, &coordSizeNew);CHKERRQ(ierr);
1902   ierr = VecCreate(PetscObjectComm((PetscObject)dm), &coordinatesNew);CHKERRQ(ierr);
1903   ierr = PetscObjectSetName((PetscObject) coordinatesNew, "coordinates");CHKERRQ(ierr);
1904   ierr = VecSetSizes(coordinatesNew, coordSizeNew, PETSC_DETERMINE);CHKERRQ(ierr);
1905   ierr = VecSetFromOptions(coordinatesNew);CHKERRQ(ierr);
1906   ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
1907   ierr = VecGetArray(coordinatesNew, &coordsNew);CHKERRQ(ierr);
1908   switch (refiner) {
1909   case 6: /* Hex 3D */
1910     /* Face vertices have the average of corner coordinates */
1911     for (f = fStart; f < fEnd; ++f) {
1912       const PetscInt newv = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (cEnd - cStart) + (f - fStart);
1913       PetscInt      *cone = NULL;
1914       PetscInt       closureSize, coneSize = 0, off[8], offnew, p, d;
1915 
1916       ierr = DMPlexGetTransitiveClosure(dm, f, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
1917       for (p = 0; p < closureSize*2; p += 2) {
1918         const PetscInt point = cone[p];
1919         if ((point >= vStart) && (point < vEnd)) cone[coneSize++] = point;
1920       }
1921       for (v = 0; v < coneSize; ++v) {
1922         ierr = PetscSectionGetOffset(coordSection, cone[v], &off[v]);CHKERRQ(ierr);
1923       }
1924       ierr = PetscSectionGetOffset(coordSectionNew, newv, &offnew);CHKERRQ(ierr);
1925       for (d = 0; d < dim; ++d) {
1926         coordsNew[offnew+d] = 0.0;
1927         for (v = 0; v < coneSize; ++v) coordsNew[offnew+d] += coords[off[v]+d];
1928         coordsNew[offnew+d] /= coneSize;
1929       }
1930       ierr = DMPlexRestoreTransitiveClosure(dm, f, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
1931     }
1932   case 2: /* Hex 2D */
1933     /* Cell vertices have the average of corner coordinates */
1934     for (c = cStart; c < cEnd; ++c) {
1935       const PetscInt newv = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (c - cStart);
1936       PetscInt      *cone = NULL;
1937       PetscInt       closureSize, coneSize = 0, off[8], offnew, p, d;
1938 
1939       ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
1940       for (p = 0; p < closureSize*2; p += 2) {
1941         const PetscInt point = cone[p];
1942         if ((point >= vStart) && (point < vEnd)) cone[coneSize++] = point;
1943       }
1944       for (v = 0; v < coneSize; ++v) {
1945         ierr = PetscSectionGetOffset(coordSection, cone[v], &off[v]);CHKERRQ(ierr);
1946       }
1947       ierr = PetscSectionGetOffset(coordSectionNew, newv, &offnew);CHKERRQ(ierr);
1948       for (d = 0; d < dim; ++d) {
1949         coordsNew[offnew+d] = 0.0;
1950         for (v = 0; v < coneSize; ++v) coordsNew[offnew+d] += coords[off[v]+d];
1951         coordsNew[offnew+d] /= coneSize;
1952       }
1953       ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
1954     }
1955   case 1: /* Simplicial 2D */
1956   case 3: /* Hybrid Simplicial 2D */
1957   case 5: /* Simplicial 3D */
1958     /* Edge vertices have the average of endpoint coordinates */
1959     for (e = eStart; e < eMax; ++e) {
1960       const PetscInt  newv = vStartNew + (vEnd - vStart) + (e - eStart);
1961       const PetscInt *cone;
1962       PetscInt        coneSize, offA, offB, offnew, d;
1963 
1964       ierr = DMPlexGetConeSize(dm, e, &coneSize);CHKERRQ(ierr);
1965       if (coneSize != 2) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Edge %d cone should have two vertices, not %d", e, coneSize);
1966       ierr = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
1967       ierr = PetscSectionGetOffset(coordSection, cone[0], &offA);CHKERRQ(ierr);
1968       ierr = PetscSectionGetOffset(coordSection, cone[1], &offB);CHKERRQ(ierr);
1969       ierr = PetscSectionGetOffset(coordSectionNew, newv, &offnew);CHKERRQ(ierr);
1970       for (d = 0; d < dim; ++d) {
1971         coordsNew[offnew+d] = 0.5*(coords[offA+d] + coords[offB+d]);
1972       }
1973     }
1974     /* Old vertices have the same coordinates */
1975     for (v = vStart; v < vEnd; ++v) {
1976       const PetscInt newv = vStartNew + (v - vStart);
1977       PetscInt       off, offnew, d;
1978 
1979       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
1980       ierr = PetscSectionGetOffset(coordSectionNew, newv, &offnew);CHKERRQ(ierr);
1981       for (d = 0; d < dim; ++d) {
1982         coordsNew[offnew+d] = coords[off+d];
1983       }
1984     }
1985     break;
1986   default:
1987     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
1988   }
1989   ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
1990   ierr = VecRestoreArray(coordinatesNew, &coordsNew);CHKERRQ(ierr);
1991   ierr = DMSetCoordinatesLocal(rdm, coordinatesNew);CHKERRQ(ierr);
1992   ierr = VecDestroy(&coordinatesNew);CHKERRQ(ierr);
1993   ierr = PetscSectionDestroy(&coordSectionNew);CHKERRQ(ierr);
1994   PetscFunctionReturn(0);
1995 }
1996 
1997 #undef __FUNCT__
1998 #define __FUNCT__ "DMPlexCreateProcessSF"
1999 PetscErrorCode DMPlexCreateProcessSF(DM dm, PetscSF sfPoint, IS *processRanks, PetscSF *sfProcess)
2000 {
2001   PetscInt           numRoots, numLeaves, l;
2002   const PetscInt    *localPoints;
2003   const PetscSFNode *remotePoints;
2004   PetscInt          *localPointsNew;
2005   PetscSFNode       *remotePointsNew;
2006   PetscInt          *ranks, *ranksNew;
2007   PetscErrorCode     ierr;
2008 
2009   PetscFunctionBegin;
2010   ierr = PetscSFGetGraph(sfPoint, &numRoots, &numLeaves, &localPoints, &remotePoints);CHKERRQ(ierr);
2011   ierr = PetscMalloc(numLeaves * sizeof(PetscInt), &ranks);CHKERRQ(ierr);
2012   for (l = 0; l < numLeaves; ++l) {
2013     ranks[l] = remotePoints[l].rank;
2014   }
2015   ierr = PetscSortRemoveDupsInt(&numLeaves, ranks);CHKERRQ(ierr);
2016   ierr = PetscMalloc(numLeaves * sizeof(PetscInt),    &ranksNew);CHKERRQ(ierr);
2017   ierr = PetscMalloc(numLeaves * sizeof(PetscInt),    &localPointsNew);CHKERRQ(ierr);
2018   ierr = PetscMalloc(numLeaves * sizeof(PetscSFNode), &remotePointsNew);CHKERRQ(ierr);
2019   for (l = 0; l < numLeaves; ++l) {
2020     ranksNew[l]              = ranks[l];
2021     localPointsNew[l]        = l;
2022     remotePointsNew[l].index = 0;
2023     remotePointsNew[l].rank  = ranksNew[l];
2024   }
2025   ierr = PetscFree(ranks);CHKERRQ(ierr);
2026   ierr = ISCreateGeneral(PetscObjectComm((PetscObject)dm), numLeaves, ranksNew, PETSC_OWN_POINTER, processRanks);CHKERRQ(ierr);
2027   ierr = PetscSFCreate(PetscObjectComm((PetscObject)dm), sfProcess);CHKERRQ(ierr);
2028   ierr = PetscSFSetFromOptions(*sfProcess);CHKERRQ(ierr);
2029   ierr = PetscSFSetGraph(*sfProcess, 1, numLeaves, localPointsNew, PETSC_OWN_POINTER, remotePointsNew, PETSC_OWN_POINTER);CHKERRQ(ierr);
2030   PetscFunctionReturn(0);
2031 }
2032 
2033 #undef __FUNCT__
2034 #define __FUNCT__ "CellRefinerCreateSF"
2035 PetscErrorCode CellRefinerCreateSF(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
2036 {
2037   PetscSF            sf, sfNew, sfProcess;
2038   IS                 processRanks;
2039   MPI_Datatype       depthType;
2040   PetscInt           numRoots, numLeaves, numLeavesNew = 0, l, m;
2041   const PetscInt    *localPoints, *neighbors;
2042   const PetscSFNode *remotePoints;
2043   PetscInt          *localPointsNew;
2044   PetscSFNode       *remotePointsNew;
2045   PetscInt          *depthSizeOld, *rdepthSize, *rdepthSizeOld, *rdepthMaxOld, *rvStart, *rvStartNew, *reStart, *reStartNew, *rfStart, *rfStartNew, *rcStart, *rcStartNew;
2046   PetscInt           depth, numNeighbors, pStartNew, pEndNew, cStart, cStartNew, cEnd, cMax, vStart, vStartNew, vEnd, vMax, fStart, fStartNew, fEnd, fMax, eStart, eStartNew, eEnd, eMax, r, n;
2047   PetscErrorCode     ierr;
2048 
2049   PetscFunctionBegin;
2050   ierr = DMPlexGetChart(rdm, &pStartNew, &pEndNew);CHKERRQ(ierr);
2051   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
2052   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
2053   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
2054   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
2055   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
2056   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
2057   ierr = GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);CHKERRQ(ierr);
2058   switch (refiner) {
2059   case 3:
2060     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
2061     cMax = PetscMin(cEnd, cMax);
2062     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
2063     fMax = PetscMin(fEnd, fMax);
2064   }
2065   ierr = DMGetPointSF(dm, &sf);CHKERRQ(ierr);
2066   ierr = DMGetPointSF(rdm, &sfNew);CHKERRQ(ierr);
2067   /* Caculate size of new SF */
2068   ierr = PetscSFGetGraph(sf, &numRoots, &numLeaves, &localPoints, &remotePoints);CHKERRQ(ierr);
2069   if (numRoots < 0) PetscFunctionReturn(0);
2070   for (l = 0; l < numLeaves; ++l) {
2071     const PetscInt p = localPoints[l];
2072 
2073     switch (refiner) {
2074     case 1:
2075       /* Simplicial 2D */
2076       if ((p >= vStart) && (p < vEnd)) {
2077         /* Old vertices stay the same */
2078         ++numLeavesNew;
2079       } else if ((p >= fStart) && (p < fEnd)) {
2080         /* Old faces add new faces and vertex */
2081         numLeavesNew += 2 + 1;
2082       } else if ((p >= cStart) && (p < cEnd)) {
2083         /* Old cells add new cells and interior faces */
2084         numLeavesNew += 4 + 3;
2085       }
2086       break;
2087     case 2:
2088       /* Hex 2D */
2089       if ((p >= vStart) && (p < vEnd)) {
2090         /* Old vertices stay the same */
2091         ++numLeavesNew;
2092       } else if ((p >= fStart) && (p < fEnd)) {
2093         /* Old faces add new faces and vertex */
2094         numLeavesNew += 2 + 1;
2095       } else if ((p >= cStart) && (p < cEnd)) {
2096         /* Old cells add new cells and interior faces */
2097         numLeavesNew += 4 + 4;
2098       }
2099       break;
2100     case 5:
2101       /* Simplicial 3D */
2102       if ((p >= vStart) && (p < vEnd)) {
2103         /* Old vertices stay the same */
2104         ++numLeavesNew;
2105       } else if ((p >= eStart) && (p < eEnd)) {
2106         /* Old edges add new edges and vertex */
2107         numLeavesNew += 2 + 1;
2108       } else if ((p >= fStart) && (p < fEnd)) {
2109         /* Old faces add new faces and face edges */
2110         numLeavesNew += 4 + 3;
2111       } else if ((p >= cStart) && (p < cEnd)) {
2112         /* Old cells add new cells and interior faces and edges */
2113         numLeavesNew += 8 + 8 + 1;
2114       }
2115       break;
2116     default:
2117       SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
2118     }
2119   }
2120   /* Communicate depthSizes for each remote rank */
2121   ierr = DMPlexCreateProcessSF(dm, sf, &processRanks, &sfProcess);CHKERRQ(ierr);
2122   ierr = ISGetLocalSize(processRanks, &numNeighbors);CHKERRQ(ierr);
2123   ierr = PetscMalloc5((depth+1)*numNeighbors,PetscInt,&rdepthSize,numNeighbors,PetscInt,&rvStartNew,numNeighbors,PetscInt,&reStartNew,numNeighbors,PetscInt,&rfStartNew,numNeighbors,PetscInt,&rcStartNew);CHKERRQ(ierr);
2124   ierr = PetscMalloc7(depth+1,PetscInt,&depthSizeOld,(depth+1)*numNeighbors,PetscInt,&rdepthSizeOld,(depth+1)*numNeighbors,PetscInt,&rdepthMaxOld,numNeighbors,PetscInt,&rvStart,numNeighbors,PetscInt,&reStart,numNeighbors,PetscInt,&rfStart,numNeighbors,PetscInt,&rcStart);CHKERRQ(ierr);
2125   ierr = MPI_Type_contiguous(depth+1, MPIU_INT, &depthType);CHKERRQ(ierr);
2126   ierr = MPI_Type_commit(&depthType);CHKERRQ(ierr);
2127   ierr = PetscSFBcastBegin(sfProcess, depthType, depthSize, rdepthSize);CHKERRQ(ierr);
2128   ierr = PetscSFBcastEnd(sfProcess, depthType, depthSize, rdepthSize);CHKERRQ(ierr);
2129   for (n = 0; n < numNeighbors; ++n) {
2130     ierr = GetDepthStart_Private(depth, &rdepthSize[n*(depth+1)], &rcStartNew[n], &rfStartNew[n], &reStartNew[n], &rvStartNew[n]);CHKERRQ(ierr);
2131   }
2132   depthSizeOld[depth]   = cMax;
2133   depthSizeOld[0]       = vMax;
2134   depthSizeOld[depth-1] = fMax;
2135   depthSizeOld[1]       = eMax;
2136 
2137   ierr = PetscSFBcastBegin(sfProcess, depthType, depthSizeOld, rdepthMaxOld);CHKERRQ(ierr);
2138   ierr = PetscSFBcastEnd(sfProcess, depthType, depthSizeOld, rdepthMaxOld);CHKERRQ(ierr);
2139 
2140   depthSizeOld[depth]   = cEnd - cStart;
2141   depthSizeOld[0]       = vEnd - vStart;
2142   depthSizeOld[depth-1] = fEnd - fStart;
2143   depthSizeOld[1]       = eEnd - eStart;
2144 
2145   ierr = PetscSFBcastBegin(sfProcess, depthType, depthSizeOld, rdepthSizeOld);CHKERRQ(ierr);
2146   ierr = PetscSFBcastEnd(sfProcess, depthType, depthSizeOld, rdepthSizeOld);CHKERRQ(ierr);
2147   for (n = 0; n < numNeighbors; ++n) {
2148     ierr = GetDepthStart_Private(depth, &rdepthSizeOld[n*(depth+1)], &rcStart[n], &rfStart[n], &reStart[n], &rvStart[n]);CHKERRQ(ierr);
2149   }
2150   ierr = MPI_Type_free(&depthType);CHKERRQ(ierr);
2151   ierr = PetscSFDestroy(&sfProcess);CHKERRQ(ierr);
2152   /* Calculate new point SF */
2153   ierr = PetscMalloc(numLeavesNew * sizeof(PetscInt),    &localPointsNew);CHKERRQ(ierr);
2154   ierr = PetscMalloc(numLeavesNew * sizeof(PetscSFNode), &remotePointsNew);CHKERRQ(ierr);
2155   ierr = ISGetIndices(processRanks, &neighbors);CHKERRQ(ierr);
2156   for (l = 0, m = 0; l < numLeaves; ++l) {
2157     PetscInt    p     = localPoints[l];
2158     PetscInt    rp    = remotePoints[l].index, n;
2159     PetscMPIInt rrank = remotePoints[l].rank;
2160 
2161     ierr = PetscFindInt(rrank, numNeighbors, neighbors, &n);CHKERRQ(ierr);
2162     if (n < 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Could not locate remote rank %d", rrank);
2163     switch (refiner) {
2164     case 1:
2165       /* Simplicial 2D */
2166       if ((p >= vStart) && (p < vEnd)) {
2167         /* Old vertices stay the same */
2168         localPointsNew[m]        = vStartNew     + (p  - vStart);
2169         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
2170         remotePointsNew[m].rank  = rrank;
2171         ++m;
2172       } else if ((p >= fStart) && (p < fEnd)) {
2173         /* Old faces add new faces and vertex */
2174         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - fStart);
2175         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - rfStart[n]);
2176         remotePointsNew[m].rank  = rrank;
2177         ++m;
2178         for (r = 0; r < 2; ++r, ++m) {
2179           localPointsNew[m]        = fStartNew     + (p  - fStart)*2     + r;
2180           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*2 + r;
2181           remotePointsNew[m].rank  = rrank;
2182         }
2183       } else if ((p >= cStart) && (p < cEnd)) {
2184         /* Old cells add new cells and interior faces */
2185         for (r = 0; r < 4; ++r, ++m) {
2186           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
2187           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
2188           remotePointsNew[m].rank  = rrank;
2189         }
2190         for (r = 0; r < 3; ++r, ++m) {
2191           localPointsNew[m]        = fStartNew     + (fEnd - fStart)*2                    + (p  - cStart)*3     + r;
2192           remotePointsNew[m].index = rfStartNew[n] + rdepthSizeOld[n*(depth+1)+depth-1]*2 + (rp - rcStart[n])*3 + r;
2193           remotePointsNew[m].rank  = rrank;
2194         }
2195       }
2196       break;
2197     case 2:
2198       /* Hex 2D */
2199       if ((p >= vStart) && (p < vEnd)) {
2200         /* Old vertices stay the same */
2201         localPointsNew[m]        = vStartNew     + (p  - vStart);
2202         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
2203         remotePointsNew[m].rank  = rrank;
2204         ++m;
2205       } else if ((p >= fStart) && (p < fEnd)) {
2206         /* Old faces add new faces and vertex */
2207         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - fStart);
2208         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - rfStart[n]);
2209         remotePointsNew[m].rank  = rrank;
2210         ++m;
2211         for (r = 0; r < 2; ++r, ++m) {
2212           localPointsNew[m]        = fStartNew     + (p  - fStart)*2     + r;
2213           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*2 + r;
2214           remotePointsNew[m].rank  = rrank;
2215         }
2216       } else if ((p >= cStart) && (p < cEnd)) {
2217         /* Old cells add new cells and interior faces */
2218         for (r = 0; r < 4; ++r, ++m) {
2219           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
2220           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
2221           remotePointsNew[m].rank  = rrank;
2222         }
2223         for (r = 0; r < 4; ++r, ++m) {
2224           localPointsNew[m]        = fStartNew     + (fEnd - fStart)*2                    + (p  - cStart)*4     + r;
2225           remotePointsNew[m].index = rfStartNew[n] + rdepthSizeOld[n*(depth+1)+depth-1]*2 + (rp - rcStart[n])*4 + r;
2226           remotePointsNew[m].rank  = rrank;
2227         }
2228       }
2229       break;
2230     case 3:
2231       /* Hybrid simplicial 2D */
2232       if ((p >= vStart) && (p < vEnd)) {
2233         /* Old vertices stay the same */
2234         localPointsNew[m]        = vStartNew     + (p  - vStart);
2235         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
2236         remotePointsNew[m].rank  = rrank;
2237         ++m;
2238       } else if ((p >= fStart) && (p < fMax)) {
2239         /* Old interior faces add new faces and vertex */
2240         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - fStart);
2241         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - rfStart[n]);
2242         remotePointsNew[m].rank  = rrank;
2243         ++m;
2244         for (r = 0; r < 2; ++r, ++m) {
2245           localPointsNew[m]        = fStartNew     + (p  - fStart)*2     + r;
2246           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*2 + r;
2247           remotePointsNew[m].rank  = rrank;
2248         }
2249       } else if ((p >= fMax) && (p < fEnd)) {
2250         /* Old hybrid faces stay the same */
2251         localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (p  - fMax);
2252         remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*2 + (rp - rdepthMaxOld[n*(depth+1)+depth-1]);
2253         remotePointsNew[m].rank  = rrank;
2254         ++m;
2255       } else if ((p >= cStart) && (p < cMax)) {
2256         /* Old interior cells add new cells and interior faces */
2257         for (r = 0; r < 4; ++r, ++m) {
2258           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
2259           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
2260           remotePointsNew[m].rank  = rrank;
2261         }
2262         for (r = 0; r < 3; ++r, ++m) {
2263           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (p  - cStart)*3     + r;
2264           remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*2 + (rp - rcStart[n])*3 + r;
2265           remotePointsNew[m].rank  = rrank;
2266         }
2267       } else if ((p >= cStart) && (p < cMax)) {
2268         /* Old hybrid cells add new cells and hybrid face */
2269         for (r = 0; r < 2; ++r, ++m) {
2270           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
2271           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
2272           remotePointsNew[m].rank  = rrank;
2273         }
2274         localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (cMax                            - cStart)*3     + (p  - cMax);
2275         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]);
2276         remotePointsNew[m].rank  = rrank;
2277         ++m;
2278       }
2279       break;
2280     case 5:
2281       /* Simplicial 3D */
2282       if ((p >= vStart) && (p < vEnd)) {
2283         /* Old vertices stay the same */
2284         localPointsNew[m]        = vStartNew     + (p  - vStart);
2285         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
2286         remotePointsNew[m].rank  = rrank;
2287         ++m;
2288       } else if ((p >= eStart) && (p < eEnd)) {
2289         /* Old edges add new edges and vertex */
2290         for (r = 0; r < 2; ++r, ++m) {
2291           localPointsNew[m]        = eStartNew     + (p  - eStart)*2     + r;
2292           remotePointsNew[m].index = reStartNew[n] + (rp - reStart[n])*2 + r;
2293           remotePointsNew[m].rank  = rrank;
2294         }
2295         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - eStart);
2296         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - reStart[n]);
2297         remotePointsNew[m].rank  = rrank;
2298         ++m;
2299       } else if ((p >= fStart) && (p < fEnd)) {
2300         /* Old faces add new faces and face edges */
2301         for (r = 0; r < 4; ++r, ++m) {
2302           localPointsNew[m]        = fStartNew     + (p  - fStart)*4     + r;
2303           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*4 + r;
2304           remotePointsNew[m].rank  = rrank;
2305         }
2306         for (r = 0; r < 3; ++r, ++m) {
2307           localPointsNew[m]        = eStartNew     + (eEnd - eStart)*2              + (p  - fStart)*3     + r;
2308           remotePointsNew[m].index = reStartNew[n] + rdepthSizeOld[n*(depth+1)+1]*2 + (rp - rfStart[n])*3 + r;
2309           remotePointsNew[m].rank  = rrank;
2310         }
2311       } else if ((p >= cStart) && (p < cEnd)) {
2312         /* Old cells add new cells and interior faces and edges */
2313         for (r = 0; r < 8; ++r, ++m) {
2314           localPointsNew[m]        = cStartNew     + (p  - cStart)*8     + r;
2315           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*8 + r;
2316           remotePointsNew[m].rank  = rrank;
2317         }
2318         for (r = 0; r < 8; ++r, ++m) {
2319           localPointsNew[m]        = fStartNew     + (fEnd - fStart)*4                    + (p  - cStart)*8     + r;
2320           remotePointsNew[m].index = rfStartNew[n] + rdepthSizeOld[n*(depth+1)+depth-1]*4 + (rp - rcStart[n])*8 + r;
2321           remotePointsNew[m].rank  = rrank;
2322         }
2323         for (r = 0; r < 1; ++r, ++m) {
2324           localPointsNew[m]        = eStartNew     + (eEnd - eStart)*2              + (fEnd - fStart)*3                    + (p  - cStart)*1     + r;
2325           remotePointsNew[m].index = reStartNew[n] + rdepthSizeOld[n*(depth+1)+1]*2 + rdepthSizeOld[n*(depth+1)+depth-1]*3 + (rp - rcStart[n])*1 + r;
2326           remotePointsNew[m].rank  = rrank;
2327         }
2328       }
2329       break;
2330     default:
2331       SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
2332     }
2333   }
2334   ierr = ISRestoreIndices(processRanks, &neighbors);CHKERRQ(ierr);
2335   ierr = ISDestroy(&processRanks);CHKERRQ(ierr);
2336   ierr = PetscSFSetGraph(sfNew, pEndNew-pStartNew, numLeavesNew, localPointsNew, PETSC_OWN_POINTER, remotePointsNew, PETSC_OWN_POINTER);CHKERRQ(ierr);
2337   ierr = PetscFree5(rdepthSize,rvStartNew,reStartNew,rfStartNew,rcStartNew);CHKERRQ(ierr);
2338   ierr = PetscFree6(depthSizeOld,rdepthSizeOld,rvStart,reStart,rfStart,rcStart);CHKERRQ(ierr);
2339   PetscFunctionReturn(0);
2340 }
2341 
2342 #undef __FUNCT__
2343 #define __FUNCT__ "CellRefinerCreateLabels"
2344 PetscErrorCode CellRefinerCreateLabels(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
2345 {
2346   PetscInt       numLabels, l;
2347   PetscInt       depth, newp, cStart, cStartNew, cEnd, cMax, vStart, vStartNew, vEnd, vMax, fStart, fStartNew, fEnd, fMax, eStart, eStartNew, eEnd, eMax, r;
2348   PetscErrorCode ierr;
2349 
2350   PetscFunctionBegin;
2351   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
2352   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
2353   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
2354   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
2355   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
2356   ierr = GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);CHKERRQ(ierr);
2357   ierr = DMPlexGetNumLabels(dm, &numLabels);CHKERRQ(ierr);
2358   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
2359   switch (refiner) {
2360   case 3:
2361     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
2362     cMax = PetscMin(cEnd, cMax);
2363     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
2364     fMax = PetscMin(fEnd, fMax);
2365   }
2366   for (l = 0; l < numLabels; ++l) {
2367     DMLabel         label, labelNew;
2368     const char     *lname;
2369     PetscBool       isDepth;
2370     IS              valueIS;
2371     const PetscInt *values;
2372     PetscInt        numValues, val;
2373 
2374     ierr = DMPlexGetLabelName(dm, l, &lname);CHKERRQ(ierr);
2375     ierr = PetscStrcmp(lname, "depth", &isDepth);CHKERRQ(ierr);
2376     if (isDepth) continue;
2377     ierr = DMPlexCreateLabel(rdm, lname);CHKERRQ(ierr);
2378     ierr = DMPlexGetLabel(dm, lname, &label);CHKERRQ(ierr);
2379     ierr = DMPlexGetLabel(rdm, lname, &labelNew);CHKERRQ(ierr);
2380     ierr = DMLabelGetValueIS(label, &valueIS);CHKERRQ(ierr);
2381     ierr = ISGetLocalSize(valueIS, &numValues);CHKERRQ(ierr);
2382     ierr = ISGetIndices(valueIS, &values);CHKERRQ(ierr);
2383     for (val = 0; val < numValues; ++val) {
2384       IS              pointIS;
2385       const PetscInt *points;
2386       PetscInt        numPoints, n;
2387 
2388       ierr = DMLabelGetStratumIS(label, values[val], &pointIS);CHKERRQ(ierr);
2389       ierr = ISGetLocalSize(pointIS, &numPoints);CHKERRQ(ierr);
2390       ierr = ISGetIndices(pointIS, &points);CHKERRQ(ierr);
2391       for (n = 0; n < numPoints; ++n) {
2392         const PetscInt p = points[n];
2393         switch (refiner) {
2394         case 1:
2395           /* Simplicial 2D */
2396           if ((p >= vStart) && (p < vEnd)) {
2397             /* Old vertices stay the same */
2398             newp = vStartNew + (p - vStart);
2399             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
2400           } else if ((p >= fStart) && (p < fEnd)) {
2401             /* Old faces add new faces and vertex */
2402             newp = vStartNew + (vEnd - vStart) + (p - fStart);
2403             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
2404             for (r = 0; r < 2; ++r) {
2405               newp = fStartNew + (p - fStart)*2 + r;
2406               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
2407             }
2408           } else if ((p >= cStart) && (p < cEnd)) {
2409             /* Old cells add new cells and interior faces */
2410             for (r = 0; r < 4; ++r) {
2411               newp = cStartNew + (p - cStart)*4 + r;
2412               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
2413             }
2414             for (r = 0; r < 3; ++r) {
2415               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*3 + r;
2416               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
2417             }
2418           }
2419           break;
2420         case 2:
2421           /* Hex 2D */
2422           if ((p >= vStart) && (p < vEnd)) {
2423             /* Old vertices stay the same */
2424             newp = vStartNew + (p - vStart);
2425             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
2426           } else if ((p >= fStart) && (p < fEnd)) {
2427             /* Old faces add new faces and vertex */
2428             newp = vStartNew + (vEnd - vStart) + (p - fStart);
2429             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
2430             for (r = 0; r < 2; ++r) {
2431               newp = fStartNew + (p - fStart)*2 + r;
2432               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
2433             }
2434           } else if ((p >= cStart) && (p < cEnd)) {
2435             /* Old cells add new cells and interior faces and vertex */
2436             for (r = 0; r < 4; ++r) {
2437               newp = cStartNew + (p - cStart)*4 + r;
2438               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
2439             }
2440             for (r = 0; r < 4; ++r) {
2441               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*4 + r;
2442               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
2443             }
2444             newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (p - cStart);
2445             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
2446           }
2447           break;
2448         case 3:
2449           /* Hybrid simplicial 2D */
2450           if ((p >= vStart) && (p < vEnd)) {
2451             /* Old vertices stay the same */
2452             newp = vStartNew + (p - vStart);
2453             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
2454           } else if ((p >= fStart) && (p < fMax)) {
2455             /* Old interior faces add new faces and vertex */
2456             newp = vStartNew + (vEnd - vStart) + (p - fStart);
2457             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
2458             for (r = 0; r < 2; ++r) {
2459               newp = fStartNew + (p - fStart)*2 + r;
2460               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
2461             }
2462           } else if ((p >= fMax) && (p < fEnd)) {
2463             /* Old hybrid faces stay the same */
2464             newp = fStartNew + (fMax - fStart)*2 + (p - fMax);
2465             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
2466           } else if ((p >= cStart) && (p < cMax)) {
2467             /* Old interior cells add new cells and interior faces */
2468             for (r = 0; r < 4; ++r) {
2469               newp = cStartNew + (p - cStart)*4 + r;
2470               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
2471             }
2472             for (r = 0; r < 3; ++r) {
2473               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*3 + r;
2474               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
2475             }
2476           } else if ((p >= cMax) && (p < cEnd)) {
2477             /* Old hybrid cells add new cells and hybrid face */
2478             for (r = 0; r < 2; ++r) {
2479               newp = cStartNew + (cMax - cStart)*4 + (p - cMax)*2 + r;
2480               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
2481             }
2482             newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (p - cMax);
2483             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
2484           }
2485           break;
2486         case 5:
2487           /* Simplicial 3D */
2488           if ((p >= vStart) && (p < vEnd)) {
2489             /* Old vertices stay the same */
2490             newp = vStartNew + (p - vStart);
2491             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
2492           } else if ((p >= eStart) && (p < eEnd)) {
2493             /* Old edges add new edges and vertex */
2494             for (r = 0; r < 2; ++r) {
2495               newp = eStartNew + (p - eStart)*2 + r;
2496               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
2497             }
2498             newp = vStartNew + (vEnd - vStart) + (p - eStart);
2499             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
2500           } else if ((p >= fStart) && (p < fEnd)) {
2501             /* Old faces add new faces and edges */
2502             for (r = 0; r < 4; ++r) {
2503               newp = fStartNew + (p - fStart)*4 + r;
2504               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
2505             }
2506             for (r = 0; r < 3; ++r) {
2507               newp = eStartNew + (eEnd - eStart)*2 + (p - fStart)*3 + r;
2508               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
2509             }
2510           } else if ((p >= cStart) && (p < cEnd)) {
2511             /* Old cells add new cells and interior faces and edges */
2512             for (r = 0; r < 8; ++r) {
2513               newp = cStartNew + (p - cStart)*8 + r;
2514               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
2515             }
2516             for (r = 0; r < 8; ++r) {
2517               newp = fStartNew + (fEnd - fStart)*4 + (p - cStart)*8 + r;
2518               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
2519             }
2520             for (r = 0; r < 1; ++r) {
2521               newp = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (p - cStart)*1 + r;
2522               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
2523             }
2524           }
2525           break;
2526         default:
2527           SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
2528         }
2529       }
2530       ierr = ISRestoreIndices(pointIS, &points);CHKERRQ(ierr);
2531       ierr = ISDestroy(&pointIS);CHKERRQ(ierr);
2532     }
2533     ierr = ISRestoreIndices(valueIS, &values);CHKERRQ(ierr);
2534     ierr = ISDestroy(&valueIS);CHKERRQ(ierr);
2535     if (0) {
2536       ierr = PetscViewerASCIISynchronizedAllow(PETSC_VIEWER_STDOUT_WORLD, PETSC_TRUE);CHKERRQ(ierr);
2537       ierr = DMLabelView(labelNew, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
2538       ierr = PetscViewerFlush(PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
2539     }
2540   }
2541   PetscFunctionReturn(0);
2542 }
2543 
2544 #undef __FUNCT__
2545 #define __FUNCT__ "DMPlexRefineUniform_Internal"
2546 /* This will only work for interpolated meshes */
2547 PetscErrorCode DMPlexRefineUniform_Internal(DM dm, CellRefiner cellRefiner, DM *dmRefined)
2548 {
2549   DM             rdm;
2550   PetscInt      *depthSize;
2551   PetscInt       dim, depth = 0, d, pStart = 0, pEnd = 0;
2552   PetscErrorCode ierr;
2553 
2554   PetscFunctionBegin;
2555   ierr = DMCreate(PetscObjectComm((PetscObject)dm), &rdm);CHKERRQ(ierr);
2556   ierr = DMSetType(rdm, DMPLEX);CHKERRQ(ierr);
2557   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
2558   ierr = DMPlexSetDimension(rdm, dim);CHKERRQ(ierr);
2559   /* Calculate number of new points of each depth */
2560   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
2561   ierr = PetscMalloc((depth+1) * sizeof(PetscInt), &depthSize);CHKERRQ(ierr);
2562   ierr = PetscMemzero(depthSize, (depth+1) * sizeof(PetscInt));CHKERRQ(ierr);
2563   ierr = CellRefinerGetSizes(cellRefiner, dm, depthSize);CHKERRQ(ierr);
2564   /* Step 1: Set chart */
2565   for (d = 0; d <= depth; ++d) pEnd += depthSize[d];
2566   ierr = DMPlexSetChart(rdm, pStart, pEnd);CHKERRQ(ierr);
2567   /* Step 2: Set cone/support sizes */
2568   ierr = CellRefinerSetConeSizes(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
2569   /* Step 3: Setup refined DM */
2570   ierr = DMSetUp(rdm);CHKERRQ(ierr);
2571   /* Step 4: Set cones and supports */
2572   ierr = CellRefinerSetCones(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
2573   /* Step 5: Stratify */
2574   ierr = DMPlexStratify(rdm);CHKERRQ(ierr);
2575   /* Step 6: Set coordinates for vertices */
2576   ierr = CellRefinerSetCoordinates(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
2577   /* Step 7: Create pointSF */
2578   ierr = CellRefinerCreateSF(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
2579   /* Step 8: Create labels */
2580   ierr = CellRefinerCreateLabels(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
2581   ierr = PetscFree(depthSize);CHKERRQ(ierr);
2582 
2583   *dmRefined = rdm;
2584   PetscFunctionReturn(0);
2585 }
2586 
2587 #undef __FUNCT__
2588 #define __FUNCT__ "DMPlexSetRefinementUniform"
2589 PetscErrorCode DMPlexSetRefinementUniform(DM dm, PetscBool refinementUniform)
2590 {
2591   DM_Plex *mesh = (DM_Plex*) dm->data;
2592 
2593   PetscFunctionBegin;
2594   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2595   mesh->refinementUniform = refinementUniform;
2596   PetscFunctionReturn(0);
2597 }
2598 
2599 #undef __FUNCT__
2600 #define __FUNCT__ "DMPlexGetRefinementUniform"
2601 PetscErrorCode DMPlexGetRefinementUniform(DM dm, PetscBool *refinementUniform)
2602 {
2603   DM_Plex *mesh = (DM_Plex*) dm->data;
2604 
2605   PetscFunctionBegin;
2606   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2607   PetscValidPointer(refinementUniform,  2);
2608   *refinementUniform = mesh->refinementUniform;
2609   PetscFunctionReturn(0);
2610 }
2611 
2612 #undef __FUNCT__
2613 #define __FUNCT__ "DMPlexSetRefinementLimit"
2614 PetscErrorCode DMPlexSetRefinementLimit(DM dm, PetscReal refinementLimit)
2615 {
2616   DM_Plex *mesh = (DM_Plex*) dm->data;
2617 
2618   PetscFunctionBegin;
2619   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2620   mesh->refinementLimit = refinementLimit;
2621   PetscFunctionReturn(0);
2622 }
2623 
2624 #undef __FUNCT__
2625 #define __FUNCT__ "DMPlexGetRefinementLimit"
2626 PetscErrorCode DMPlexGetRefinementLimit(DM dm, PetscReal *refinementLimit)
2627 {
2628   DM_Plex *mesh = (DM_Plex*) dm->data;
2629 
2630   PetscFunctionBegin;
2631   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2632   PetscValidPointer(refinementLimit,  2);
2633   /* if (mesh->refinementLimit < 0) = getMaxVolume()/2.0; */
2634   *refinementLimit = mesh->refinementLimit;
2635   PetscFunctionReturn(0);
2636 }
2637 
2638 #undef __FUNCT__
2639 #define __FUNCT__ "DMPlexGetCellRefiner_Internal"
2640 PetscErrorCode DMPlexGetCellRefiner_Internal(DM dm, CellRefiner *cellRefiner)
2641 {
2642   PetscInt       dim, cStart, coneSize, cMax;
2643   PetscErrorCode ierr;
2644 
2645   PetscFunctionBegin;
2646   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
2647   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, NULL);CHKERRQ(ierr);
2648   ierr = DMPlexGetConeSize(dm, cStart, &coneSize);CHKERRQ(ierr);
2649   ierr = DMPlexGetHybridBounds(dm, &cMax, NULL, NULL, NULL);CHKERRQ(ierr);
2650   switch (dim) {
2651   case 2:
2652     switch (coneSize) {
2653     case 3:
2654       if (cMax >= 0) *cellRefiner = 3; /* Hybrid */
2655       else *cellRefiner = 1; /* Triangular */
2656       break;
2657     case 4:
2658       if (cMax >= 0) *cellRefiner = 4; /* Hybrid */
2659       else *cellRefiner = 2; /* Quadrilateral */
2660       break;
2661     default:
2662       SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown coneSize %d in dimension %d for cell refiner", coneSize, dim);
2663     }
2664     break;
2665   case 3:
2666     switch (coneSize) {
2667     case 4:
2668       if (cMax >= 0) *cellRefiner = 7; /* Hybrid */
2669       else *cellRefiner = 5; /* Tetrahedral */
2670       break;
2671     default:
2672       SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown coneSize %d in dimension %d for cell refiner", coneSize, dim);
2673     }
2674     break;
2675   default:
2676     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown dimension %d for cell refiner", dim);
2677   }
2678   PetscFunctionReturn(0);
2679 }
2680