xref: /petsc/src/dm/impls/plex/plex.c (revision 33562214c30be6a002d9b3dac1ce89304b6b63a2) !
1 #include <petsc-private/dmpleximpl.h>   /*I      "petscdmplex.h"   I*/
2 #include <../src/sys/utils/hash.h>
3 #include <petsc-private/isimpl.h>
4 #include <petscsf.h>
5 
6 /* Logging support */
7 PetscLogEvent DMPLEX_Partition, DMPLEX_Distribute, DMPLEX_DistributeLabels, DMPLEX_DistributeSF, DMPLEX_Stratify, DMPLEX_ResidualFEM, DMPLEX_JacobianFEM;
8 
9 PETSC_EXTERN PetscErrorCode VecView_Seq(Vec, PetscViewer);
10 PETSC_EXTERN PetscErrorCode VecView_MPI(Vec, PetscViewer);
11 
12 #undef __FUNCT__
13 #define __FUNCT__ "VecView_Plex_Local"
14 PetscErrorCode VecView_Plex_Local(Vec v, PetscViewer viewer)
15 {
16   DM             dm;
17   PetscBool      isvtk;
18   PetscErrorCode ierr;
19 
20   PetscFunctionBegin;
21   ierr = VecGetDM(v, &dm);CHKERRQ(ierr);
22   if (!dm) SETERRQ(PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
23   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERVTK, &isvtk);CHKERRQ(ierr);
24   if (isvtk) {
25     PetscViewerVTKFieldType ft = PETSC_VTK_POINT_FIELD;
26     PetscSection            section;
27     PetscInt                dim, pStart, pEnd, cStart, fStart, vStart, cdof = 0, fdof = 0, vdof = 0;
28 
29     ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
30     ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
31     ierr = DMPlexGetHeightStratum(dm, 0, &cStart, NULL);CHKERRQ(ierr);
32     ierr = DMPlexGetHeightStratum(dm, 1, &fStart, NULL);CHKERRQ(ierr);
33     ierr = DMPlexGetDepthStratum(dm, 0, &vStart, NULL);CHKERRQ(ierr);
34     ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
35     /* Assumes that numer of dofs per point of each stratum is constant, natural for VTK */
36     if ((cStart >= pStart) && (cStart < pEnd)) {ierr = PetscSectionGetDof(section, cStart, &cdof);CHKERRQ(ierr);}
37     if ((fStart >= pStart) && (fStart < pEnd)) {ierr = PetscSectionGetDof(section, fStart, &fdof);CHKERRQ(ierr);}
38     if ((vStart >= pStart) && (vStart < pEnd)) {ierr = PetscSectionGetDof(section, vStart, &vdof);CHKERRQ(ierr);}
39     if (cdof && fdof && vdof) { /* Actually Q2 or some such, but visualize as Q1 */
40       ft = (cdof == dim) ? PETSC_VTK_POINT_VECTOR_FIELD : PETSC_VTK_POINT_FIELD;
41     } else if (cdof && vdof) {
42       SETERRQ(PetscObjectComm((PetscObject)viewer),PETSC_ERR_SUP,"No support for viewing mixed space with dofs at both vertices and cells");
43     } else if (cdof) {
44       /* TODO: This assumption should be removed when there is a way of identifying whether a space is conceptually a
45        * vector or just happens to have the same number of dofs as the dimension. */
46       if (cdof == dim) {
47         ft = PETSC_VTK_CELL_VECTOR_FIELD;
48       } else {
49         ft = PETSC_VTK_CELL_FIELD;
50       }
51     } else if (vdof) {
52       if (vdof == dim) {
53         ft = PETSC_VTK_POINT_VECTOR_FIELD;
54       } else {
55         ft = PETSC_VTK_POINT_FIELD;
56       }
57     } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Could not classify input Vec for VTK");
58 
59     ierr = PetscObjectReference((PetscObject) dm);CHKERRQ(ierr); /* viewer drops reference */
60     ierr = PetscObjectReference((PetscObject) v);CHKERRQ(ierr);  /* viewer drops reference */
61     ierr = PetscViewerVTKAddField(viewer, (PetscObject) dm, DMPlexVTKWriteAll, ft, (PetscObject) v);CHKERRQ(ierr);
62   } else {
63     PetscBool isseq;
64 
65     ierr = PetscObjectTypeCompare((PetscObject) v, VECSEQ, &isseq);CHKERRQ(ierr);
66     if (isseq) {
67       ierr = VecView_Seq(v, viewer);CHKERRQ(ierr);
68     } else {
69       ierr = VecView_MPI(v, viewer);CHKERRQ(ierr);
70     }
71   }
72   PetscFunctionReturn(0);
73 }
74 
75 #undef __FUNCT__
76 #define __FUNCT__ "VecView_Plex"
77 PetscErrorCode VecView_Plex(Vec v, PetscViewer viewer)
78 {
79   DM             dm;
80   PetscBool      isvtk;
81   PetscErrorCode ierr;
82 
83   PetscFunctionBegin;
84   ierr = VecGetDM(v, &dm);CHKERRQ(ierr);
85   if (!dm) SETERRQ(PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
86   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERVTK, &isvtk);CHKERRQ(ierr);
87   if (isvtk) {
88     Vec         locv;
89     const char *name;
90 
91     ierr = DMGetLocalVector(dm, &locv);CHKERRQ(ierr);
92     ierr = PetscObjectGetName((PetscObject) v, &name);CHKERRQ(ierr);
93     ierr = PetscObjectSetName((PetscObject) locv, name);CHKERRQ(ierr);
94     ierr = DMGlobalToLocalBegin(dm, v, INSERT_VALUES, locv);CHKERRQ(ierr);
95     ierr = DMGlobalToLocalEnd(dm, v, INSERT_VALUES, locv);CHKERRQ(ierr);
96     ierr = VecView_Plex_Local(locv, viewer);CHKERRQ(ierr);
97     ierr = DMRestoreLocalVector(dm, &locv);CHKERRQ(ierr);
98   } else {
99     PetscBool isseq;
100 
101     ierr = PetscObjectTypeCompare((PetscObject) v, VECSEQ, &isseq);CHKERRQ(ierr);
102     if (isseq) {
103       ierr = VecView_Seq(v, viewer);CHKERRQ(ierr);
104     } else {
105       ierr = VecView_MPI(v, viewer);CHKERRQ(ierr);
106     }
107   }
108   PetscFunctionReturn(0);
109 }
110 
111 #undef __FUNCT__
112 #define __FUNCT__ "DMPlexView_Ascii"
113 PetscErrorCode DMPlexView_Ascii(DM dm, PetscViewer viewer)
114 {
115   DM_Plex          *mesh = (DM_Plex*) dm->data;
116   DM                cdm;
117   DMLabel           markers;
118   PetscSection      coordSection;
119   Vec               coordinates;
120   PetscViewerFormat format;
121   PetscErrorCode    ierr;
122 
123   PetscFunctionBegin;
124   ierr = DMGetCoordinateDM(dm, &cdm);CHKERRQ(ierr);
125   ierr = DMGetDefaultSection(cdm, &coordSection);CHKERRQ(ierr);
126   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
127   ierr = PetscViewerGetFormat(viewer, &format);CHKERRQ(ierr);
128   if (format == PETSC_VIEWER_ASCII_INFO_DETAIL) {
129     const char *name;
130     PetscInt    maxConeSize, maxSupportSize;
131     PetscInt    pStart, pEnd, p;
132     PetscMPIInt rank, size;
133 
134     ierr = MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank);CHKERRQ(ierr);
135     ierr = MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size);CHKERRQ(ierr);
136     ierr = PetscObjectGetName((PetscObject) dm, &name);CHKERRQ(ierr);
137     ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
138     ierr = DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize);CHKERRQ(ierr);
139     ierr = PetscViewerASCIISynchronizedAllow(viewer, PETSC_TRUE);CHKERRQ(ierr);
140     ierr = PetscViewerASCIIPrintf(viewer, "Mesh '%s':\n", name);CHKERRQ(ierr);
141     ierr = PetscViewerASCIISynchronizedPrintf(viewer, "Max sizes cone: %D support: %D\n", maxConeSize, maxSupportSize);CHKERRQ(ierr);
142     ierr = PetscViewerASCIIPrintf(viewer, "orientation is missing\n", name);CHKERRQ(ierr);
143     ierr = PetscViewerASCIIPrintf(viewer, "cap --> base:\n", name);CHKERRQ(ierr);
144     for (p = pStart; p < pEnd; ++p) {
145       PetscInt dof, off, s;
146 
147       ierr = PetscSectionGetDof(mesh->supportSection, p, &dof);CHKERRQ(ierr);
148       ierr = PetscSectionGetOffset(mesh->supportSection, p, &off);CHKERRQ(ierr);
149       for (s = off; s < off+dof; ++s) {
150         ierr = PetscViewerASCIISynchronizedPrintf(viewer, "[%D]: %D ----> %D\n", rank, p, mesh->supports[s]);CHKERRQ(ierr);
151       }
152     }
153     ierr = PetscViewerFlush(viewer);CHKERRQ(ierr);
154     ierr = PetscViewerASCIIPrintf(viewer, "base <-- cap:\n", name);CHKERRQ(ierr);
155     for (p = pStart; p < pEnd; ++p) {
156       PetscInt dof, off, c;
157 
158       ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
159       ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
160       for (c = off; c < off+dof; ++c) {
161         ierr = PetscViewerASCIISynchronizedPrintf(viewer, "[%D]: %D <---- %D (%D)\n", rank, p, mesh->cones[c], mesh->coneOrientations[c]);CHKERRQ(ierr);
162       }
163     }
164     ierr = PetscViewerFlush(viewer);CHKERRQ(ierr);
165     ierr = PetscSectionGetChart(coordSection, &pStart, NULL);CHKERRQ(ierr);
166     if (pStart >= 0) {ierr = PetscSectionVecView(coordSection, coordinates, viewer);CHKERRQ(ierr);}
167     ierr = DMPlexGetLabel(dm, "marker", &markers);CHKERRQ(ierr);
168     ierr = DMLabelView(markers,viewer);CHKERRQ(ierr);
169     if (size > 1) {
170       PetscSF sf;
171 
172       ierr = DMGetPointSF(dm, &sf);CHKERRQ(ierr);
173       ierr = PetscSFView(sf, viewer);CHKERRQ(ierr);
174     }
175     ierr = PetscViewerFlush(viewer);CHKERRQ(ierr);
176   } else if (format == PETSC_VIEWER_ASCII_LATEX) {
177     const char  *name;
178     const char  *colors[3] = {"red", "blue", "green"};
179     const int    numColors  = 3;
180     PetscReal    scale      = 2.0;
181     PetscScalar *coords;
182     PetscInt     depth, cStart, cEnd, c, vStart, vEnd, v, eStart = 0, eEnd = 0, e, p;
183     PetscMPIInt  rank, size;
184 
185     ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
186     ierr = MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank);CHKERRQ(ierr);
187     ierr = MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size);CHKERRQ(ierr);
188     ierr = PetscObjectGetName((PetscObject) dm, &name);CHKERRQ(ierr);
189     ierr = PetscViewerASCIISynchronizedAllow(viewer, PETSC_TRUE);CHKERRQ(ierr);
190     ierr = PetscViewerASCIIPrintf(viewer, "\
191 \\documentclass[crop,multi=false]{standalone}\n\n\
192 \\usepackage{tikz}\n\
193 \\usepackage{pgflibraryshapes}\n\
194 \\usetikzlibrary{backgrounds}\n\
195 \\usetikzlibrary{arrows}\n\
196 \\begin{document}\n\
197 \\section{%s}\n\
198 \\begin{center}\n", name, 8.0/scale);CHKERRQ(ierr);
199     ierr = PetscViewerASCIIPrintf(viewer, "Mesh for process ");CHKERRQ(ierr);
200     for (p = 0; p < size; ++p) {
201       if (p > 0 && p == size-1) {
202         ierr = PetscViewerASCIIPrintf(viewer, ", and ", colors[p%numColors], p);CHKERRQ(ierr);
203       } else if (p > 0) {
204         ierr = PetscViewerASCIIPrintf(viewer, ", ", colors[p%numColors], p);CHKERRQ(ierr);
205       }
206       ierr = PetscViewerASCIIPrintf(viewer, "{\\textcolor{%s}%D}", colors[p%numColors], p);CHKERRQ(ierr);
207     }
208     ierr = PetscViewerASCIIPrintf(viewer, ".\n\n\n\
209 \\begin{tikzpicture}[scale = %g,font=\\fontsize{8}{8}\\selectfont]\n");CHKERRQ(ierr);
210     /* Plot vertices */
211     ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
212     ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
213     ierr = PetscViewerASCIIPrintf(viewer, "\\path\n");CHKERRQ(ierr);
214     for (v = vStart; v < vEnd; ++v) {
215       PetscInt off, dof, d;
216 
217       ierr = PetscSectionGetDof(coordSection, v, &dof);CHKERRQ(ierr);
218       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
219       ierr = PetscViewerASCIISynchronizedPrintf(viewer, "(");CHKERRQ(ierr);
220       for (d = 0; d < dof; ++d) {
221         if (d > 0) {ierr = PetscViewerASCIISynchronizedPrintf(viewer, ",");CHKERRQ(ierr);}
222         ierr = PetscViewerASCIISynchronizedPrintf(viewer, "%G", scale*PetscRealPart(coords[off+d]));CHKERRQ(ierr);
223       }
224       ierr = PetscViewerASCIISynchronizedPrintf(viewer, ") node(%D_%D) [draw,shape=circle,color=%s] {%D} --\n", v, rank, colors[rank%numColors], v);CHKERRQ(ierr);
225     }
226     ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
227     ierr = PetscViewerFlush(viewer);CHKERRQ(ierr);
228     ierr = PetscViewerASCIIPrintf(viewer, "(0,0);\n");CHKERRQ(ierr);
229     /* Plot edges */
230     ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
231     ierr = PetscViewerASCIIPrintf(viewer, "\\path\n");CHKERRQ(ierr);
232     if (depth > 1) {ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);}
233     for (e = eStart; e < eEnd; ++e) {
234       const PetscInt *cone;
235       PetscInt        coneSize, offA, offB, dof, d;
236 
237       ierr = DMPlexGetConeSize(dm, e, &coneSize);CHKERRQ(ierr);
238       if (coneSize != 2) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Edge %d cone should have two vertices, not %d", e, coneSize);
239       ierr = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
240       ierr = PetscSectionGetDof(coordSection, cone[0], &dof);CHKERRQ(ierr);
241       ierr = PetscSectionGetOffset(coordSection, cone[0], &offA);CHKERRQ(ierr);
242       ierr = PetscSectionGetOffset(coordSection, cone[1], &offB);CHKERRQ(ierr);
243       ierr = PetscViewerASCIISynchronizedPrintf(viewer, "(");CHKERRQ(ierr);
244       for (d = 0; d < dof; ++d) {
245         if (d > 0) {ierr = PetscViewerASCIISynchronizedPrintf(viewer, ",");CHKERRQ(ierr);}
246         ierr = PetscViewerASCIISynchronizedPrintf(viewer, "%G", scale*0.5*PetscRealPart(coords[offA+d]+coords[offB+d]));CHKERRQ(ierr);
247       }
248       ierr = PetscViewerASCIISynchronizedPrintf(viewer, ") node(%D_%D) [draw,shape=circle,color=%s] {%D} --\n", e, rank, colors[rank%numColors], e);CHKERRQ(ierr);
249     }
250     ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
251     ierr = PetscViewerFlush(viewer);CHKERRQ(ierr);
252     ierr = PetscViewerASCIIPrintf(viewer, "(0,0);\n");CHKERRQ(ierr);
253     /* Plot cells */
254     ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
255     for (c = cStart; c < cEnd; ++c) {
256       PetscInt *closure = NULL;
257       PetscInt  closureSize, firstPoint = -1;
258 
259       ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
260       ierr = PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] ", colors[rank%numColors]);CHKERRQ(ierr);
261       for (p = 0; p < closureSize*2; p += 2) {
262         const PetscInt point = closure[p];
263 
264         if ((point < vStart) || (point >= vEnd)) continue;
265         if (firstPoint >= 0) {ierr = PetscViewerASCIISynchronizedPrintf(viewer, " -- ");CHKERRQ(ierr);}
266         ierr = PetscViewerASCIISynchronizedPrintf(viewer, "(%D_%D)", point, rank);CHKERRQ(ierr);
267         if (firstPoint < 0) firstPoint = point;
268       }
269       /* Why doesn't this work? ierr = PetscViewerASCIISynchronizedPrintf(viewer, " -- cycle;\n");CHKERRQ(ierr); */
270       ierr = PetscViewerASCIISynchronizedPrintf(viewer, " -- (%D_%D);\n", firstPoint, rank);CHKERRQ(ierr);
271       ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
272     }
273     ierr = PetscViewerFlush(viewer);CHKERRQ(ierr);
274     ierr = PetscViewerASCIIPrintf(viewer, "\\end{tikzpicture}\n\\end{center}\n");CHKERRQ(ierr);
275     ierr = PetscViewerASCIIPrintf(viewer, "\\end{document}\n", name);CHKERRQ(ierr);
276   } else {
277     MPI_Comm    comm;
278     PetscInt   *sizes;
279     PetscInt    locDepth, depth, dim, d;
280     PetscInt    pStart, pEnd, p;
281     PetscInt    numLabels, l;
282     PetscMPIInt size;
283 
284     ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr);
285     ierr = MPI_Comm_size(comm, &size);CHKERRQ(ierr);
286     ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
287     ierr = PetscViewerASCIIPrintf(viewer, "Mesh in %D dimensions:\n", dim);CHKERRQ(ierr);
288     ierr = DMPlexGetDepth(dm, &locDepth);CHKERRQ(ierr);
289     ierr = MPI_Allreduce(&locDepth, &depth, 1, MPIU_INT, MPI_MAX, comm);CHKERRQ(ierr);
290     ierr = PetscMalloc(size * sizeof(PetscInt), &sizes);CHKERRQ(ierr);
291     if (depth == 1) {
292       ierr = DMPlexGetDepthStratum(dm, 0, &pStart, &pEnd);CHKERRQ(ierr);
293       pEnd = pEnd - pStart;
294       ierr = MPI_Gather(&pEnd, 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm);CHKERRQ(ierr);
295       ierr = PetscViewerASCIIPrintf(viewer, "  %D-cells:", 0);CHKERRQ(ierr);
296       for (p = 0; p < size; ++p) {ierr = PetscViewerASCIIPrintf(viewer, " %D", sizes[p]);CHKERRQ(ierr);}
297       ierr = PetscViewerASCIIPrintf(viewer, "\n");CHKERRQ(ierr);
298       ierr = DMPlexGetHeightStratum(dm, 0, &pStart, &pEnd);CHKERRQ(ierr);
299       pEnd = pEnd - pStart;
300       ierr = MPI_Gather(&pEnd, 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm);CHKERRQ(ierr);
301       ierr = PetscViewerASCIIPrintf(viewer, "  %D-cells:", dim);CHKERRQ(ierr);
302       for (p = 0; p < size; ++p) {ierr = PetscViewerASCIIPrintf(viewer, " %D", sizes[p]);CHKERRQ(ierr);}
303       ierr = PetscViewerASCIIPrintf(viewer, "\n");CHKERRQ(ierr);
304     } else {
305       for (d = 0; d <= dim; d++) {
306         ierr = DMPlexGetDepthStratum(dm, d, &pStart, &pEnd);CHKERRQ(ierr);
307         pEnd = pEnd - pStart;
308         ierr = MPI_Gather(&pEnd, 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm);CHKERRQ(ierr);
309         ierr = PetscViewerASCIIPrintf(viewer, "  %D-cells:", d);CHKERRQ(ierr);
310         for (p = 0; p < size; ++p) {ierr = PetscViewerASCIIPrintf(viewer, " %D", sizes[p]);CHKERRQ(ierr);}
311         ierr = PetscViewerASCIIPrintf(viewer, "\n");CHKERRQ(ierr);
312       }
313     }
314     ierr = PetscFree(sizes);CHKERRQ(ierr);
315     ierr = DMPlexGetNumLabels(dm, &numLabels);CHKERRQ(ierr);
316     if (numLabels) {ierr = PetscViewerASCIIPrintf(viewer, "Labels:\n");CHKERRQ(ierr);}
317     for (l = 0; l < numLabels; ++l) {
318       DMLabel         label;
319       const char     *name;
320       IS              valueIS;
321       const PetscInt *values;
322       PetscInt        numValues, v;
323 
324       ierr = DMPlexGetLabelName(dm, l, &name);CHKERRQ(ierr);
325       ierr = DMPlexGetLabel(dm, name, &label);CHKERRQ(ierr);
326       ierr = DMLabelGetNumValues(label, &numValues);CHKERRQ(ierr);
327       ierr = PetscViewerASCIIPrintf(viewer, "  %s: %d strata of sizes (", name, numValues);CHKERRQ(ierr);
328       ierr = DMLabelGetValueIS(label, &valueIS);CHKERRQ(ierr);
329       ierr = ISGetIndices(valueIS, &values);CHKERRQ(ierr);
330       for (v = 0; v < numValues; ++v) {
331         PetscInt size;
332 
333         ierr = DMLabelGetStratumSize(label, values[v], &size);CHKERRQ(ierr);
334         if (v > 0) {ierr = PetscViewerASCIIPrintf(viewer, ", ");CHKERRQ(ierr);}
335         ierr = PetscViewerASCIIPrintf(viewer, "%d", size);CHKERRQ(ierr);
336       }
337       ierr = PetscViewerASCIIPrintf(viewer, ")\n");CHKERRQ(ierr);
338       ierr = ISRestoreIndices(valueIS, &values);CHKERRQ(ierr);
339       ierr = ISDestroy(&valueIS);CHKERRQ(ierr);
340     }
341   }
342   PetscFunctionReturn(0);
343 }
344 
345 #undef __FUNCT__
346 #define __FUNCT__ "DMView_Plex"
347 PetscErrorCode DMView_Plex(DM dm, PetscViewer viewer)
348 {
349   PetscBool      iascii, isbinary;
350   PetscErrorCode ierr;
351 
352   PetscFunctionBegin;
353   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
354   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
355   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERASCII, &iascii);CHKERRQ(ierr);
356   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERBINARY, &isbinary);CHKERRQ(ierr);
357   if (iascii) {
358     ierr = DMPlexView_Ascii(dm, viewer);CHKERRQ(ierr);
359 #if 0
360   } else if (isbinary) {
361     ierr = DMPlexView_Binary(dm, viewer);CHKERRQ(ierr);
362 #endif
363   }
364   PetscFunctionReturn(0);
365 }
366 
367 #undef __FUNCT__
368 #define __FUNCT__ "DMDestroy_Plex"
369 PetscErrorCode DMDestroy_Plex(DM dm)
370 {
371   DM_Plex       *mesh = (DM_Plex*) dm->data;
372   DMLabel        next  = mesh->labels;
373   PetscErrorCode ierr;
374 
375   PetscFunctionBegin;
376   if (--mesh->refct > 0) PetscFunctionReturn(0);
377   ierr = PetscSectionDestroy(&mesh->coneSection);CHKERRQ(ierr);
378   ierr = PetscFree(mesh->cones);CHKERRQ(ierr);
379   ierr = PetscFree(mesh->coneOrientations);CHKERRQ(ierr);
380   ierr = PetscSectionDestroy(&mesh->supportSection);CHKERRQ(ierr);
381   ierr = PetscFree(mesh->supports);CHKERRQ(ierr);
382   ierr = PetscFree(mesh->facesTmp);CHKERRQ(ierr);
383   while (next) {
384     DMLabel tmp = next->next;
385 
386     ierr = DMLabelDestroy(&next);CHKERRQ(ierr);
387     next = tmp;
388   }
389   ierr = DMLabelDestroy(&mesh->subpointMap);CHKERRQ(ierr);
390   ierr = ISDestroy(&mesh->globalVertexNumbers);CHKERRQ(ierr);
391   ierr = ISDestroy(&mesh->globalCellNumbers);CHKERRQ(ierr);
392   /* This was originally freed in DMDestroy(), but that prevents reference counting of backend objects */
393   ierr = PetscFree(mesh);CHKERRQ(ierr);
394   PetscFunctionReturn(0);
395 }
396 
397 #undef __FUNCT__
398 #define __FUNCT__ "DMCreateMatrix_Plex"
399 PetscErrorCode DMCreateMatrix_Plex(DM dm, MatType mtype, Mat *J)
400 {
401   PetscSection   section, sectionGlobal;
402   PetscInt       bs = -1;
403   PetscInt       localSize;
404   PetscBool      isShell, isBlock, isSeqBlock, isMPIBlock, isSymBlock, isSymSeqBlock, isSymMPIBlock;
405   PetscErrorCode ierr;
406 
407   PetscFunctionBegin;
408 #if !defined(PETSC_USE_DYNAMIC_LIBRARIES)
409   ierr = MatInitializePackage();CHKERRQ(ierr);
410 #endif
411   if (!mtype) mtype = MATAIJ;
412   ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
413   ierr = DMGetDefaultGlobalSection(dm, &sectionGlobal);CHKERRQ(ierr);
414   /* ierr = PetscSectionGetStorageSize(sectionGlobal, &localSize);CHKERRQ(ierr); */
415   ierr = PetscSectionGetConstrainedStorageSize(sectionGlobal, &localSize);CHKERRQ(ierr);
416   ierr = MatCreate(PetscObjectComm((PetscObject)dm), J);CHKERRQ(ierr);
417   ierr = MatSetSizes(*J, localSize, localSize, PETSC_DETERMINE, PETSC_DETERMINE);CHKERRQ(ierr);
418   ierr = MatSetType(*J, mtype);CHKERRQ(ierr);
419   ierr = MatSetFromOptions(*J);CHKERRQ(ierr);
420   ierr = PetscStrcmp(mtype, MATSHELL, &isShell);CHKERRQ(ierr);
421   ierr = PetscStrcmp(mtype, MATBAIJ, &isBlock);CHKERRQ(ierr);
422   ierr = PetscStrcmp(mtype, MATSEQBAIJ, &isSeqBlock);CHKERRQ(ierr);
423   ierr = PetscStrcmp(mtype, MATMPIBAIJ, &isMPIBlock);CHKERRQ(ierr);
424   ierr = PetscStrcmp(mtype, MATSBAIJ, &isSymBlock);CHKERRQ(ierr);
425   ierr = PetscStrcmp(mtype, MATSEQSBAIJ, &isSymSeqBlock);CHKERRQ(ierr);
426   ierr = PetscStrcmp(mtype, MATMPISBAIJ, &isSymMPIBlock);CHKERRQ(ierr);
427   if (!isShell) {
428     PetscBool fillMatrix = (PetscBool) !dm->prealloc_only;
429     PetscInt *dnz, *onz, *dnzu, *onzu, bsLocal, bsMax, bsMin;
430 
431     if (bs < 0) {
432       if (isBlock || isSeqBlock || isMPIBlock || isSymBlock || isSymSeqBlock || isSymMPIBlock) {
433         PetscInt pStart, pEnd, p, dof, cdof;
434 
435         ierr = PetscSectionGetChart(sectionGlobal, &pStart, &pEnd);CHKERRQ(ierr);
436         for (p = pStart; p < pEnd; ++p) {
437           ierr = PetscSectionGetDof(sectionGlobal, p, &dof);CHKERRQ(ierr);
438           ierr = PetscSectionGetConstraintDof(sectionGlobal, p, &cdof);CHKERRQ(ierr);
439           if (dof-cdof) {
440             if (bs < 0) {
441               bs = dof-cdof;
442             } else if (bs != dof-cdof) {
443               /* Layout does not admit a pointwise block size */
444               bs = 1;
445               break;
446             }
447           }
448         }
449         /* Must have same blocksize on all procs (some might have no points) */
450         bsLocal = bs;
451         ierr = MPI_Allreduce(&bsLocal, &bsMax, 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm));CHKERRQ(ierr);
452         bsLocal = bs < 0 ? bsMax : bs;
453         ierr = MPI_Allreduce(&bsLocal, &bsMin, 1, MPIU_INT, MPI_MIN, PetscObjectComm((PetscObject)dm));CHKERRQ(ierr);
454         if (bsMin != bsMax) {
455           bs = 1;
456         } else {
457           bs = bsMax;
458         }
459       } else {
460         bs = 1;
461       }
462     }
463     ierr = PetscMalloc4(localSize/bs, PetscInt, &dnz, localSize/bs, PetscInt, &onz, localSize/bs, PetscInt, &dnzu, localSize/bs, PetscInt, &onzu);CHKERRQ(ierr);
464     ierr = PetscMemzero(dnz,  localSize/bs * sizeof(PetscInt));CHKERRQ(ierr);
465     ierr = PetscMemzero(onz,  localSize/bs * sizeof(PetscInt));CHKERRQ(ierr);
466     ierr = PetscMemzero(dnzu, localSize/bs * sizeof(PetscInt));CHKERRQ(ierr);
467     ierr = PetscMemzero(onzu, localSize/bs * sizeof(PetscInt));CHKERRQ(ierr);
468     ierr = DMPlexPreallocateOperator(dm, bs, section, sectionGlobal, dnz, onz, dnzu, onzu, *J, fillMatrix);CHKERRQ(ierr);
469     ierr = PetscFree4(dnz, onz, dnzu, onzu);CHKERRQ(ierr);
470   }
471   PetscFunctionReturn(0);
472 }
473 
474 #undef __FUNCT__
475 #define __FUNCT__ "DMPlexGetDimension"
476 /*@
477   DMPlexGetDimension - Return the topological mesh dimension
478 
479   Not collective
480 
481   Input Parameter:
482 . mesh - The DMPlex
483 
484   Output Parameter:
485 . dim - The topological mesh dimension
486 
487   Level: beginner
488 
489 .seealso: DMPlexCreate()
490 @*/
491 PetscErrorCode DMPlexGetDimension(DM dm, PetscInt *dim)
492 {
493   DM_Plex *mesh = (DM_Plex*) dm->data;
494 
495   PetscFunctionBegin;
496   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
497   PetscValidPointer(dim, 2);
498   *dim = mesh->dim;
499   PetscFunctionReturn(0);
500 }
501 
502 #undef __FUNCT__
503 #define __FUNCT__ "DMPlexSetDimension"
504 /*@
505   DMPlexSetDimension - Set the topological mesh dimension
506 
507   Collective on mesh
508 
509   Input Parameters:
510 + mesh - The DMPlex
511 - dim - The topological mesh dimension
512 
513   Level: beginner
514 
515 .seealso: DMPlexCreate()
516 @*/
517 PetscErrorCode DMPlexSetDimension(DM dm, PetscInt dim)
518 {
519   DM_Plex *mesh = (DM_Plex*) dm->data;
520 
521   PetscFunctionBegin;
522   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
523   PetscValidLogicalCollectiveInt(dm, dim, 2);
524   mesh->dim               = dim;
525   mesh->preallocCenterDim = dim;
526   PetscFunctionReturn(0);
527 }
528 
529 #undef __FUNCT__
530 #define __FUNCT__ "DMPlexGetChart"
531 /*@
532   DMPlexGetChart - Return the interval for all mesh points [pStart, pEnd)
533 
534   Not collective
535 
536   Input Parameter:
537 . mesh - The DMPlex
538 
539   Output Parameters:
540 + pStart - The first mesh point
541 - pEnd   - The upper bound for mesh points
542 
543   Level: beginner
544 
545 .seealso: DMPlexCreate(), DMPlexSetChart()
546 @*/
547 PetscErrorCode DMPlexGetChart(DM dm, PetscInt *pStart, PetscInt *pEnd)
548 {
549   DM_Plex       *mesh = (DM_Plex*) dm->data;
550   PetscErrorCode ierr;
551 
552   PetscFunctionBegin;
553   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
554   ierr = PetscSectionGetChart(mesh->coneSection, pStart, pEnd);CHKERRQ(ierr);
555   PetscFunctionReturn(0);
556 }
557 
558 #undef __FUNCT__
559 #define __FUNCT__ "DMPlexSetChart"
560 /*@
561   DMPlexSetChart - Set the interval for all mesh points [pStart, pEnd)
562 
563   Not collective
564 
565   Input Parameters:
566 + mesh - The DMPlex
567 . pStart - The first mesh point
568 - pEnd   - The upper bound for mesh points
569 
570   Output Parameters:
571 
572   Level: beginner
573 
574 .seealso: DMPlexCreate(), DMPlexGetChart()
575 @*/
576 PetscErrorCode DMPlexSetChart(DM dm, PetscInt pStart, PetscInt pEnd)
577 {
578   DM_Plex       *mesh = (DM_Plex*) dm->data;
579   PetscErrorCode ierr;
580 
581   PetscFunctionBegin;
582   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
583   ierr = PetscSectionSetChart(mesh->coneSection, pStart, pEnd);CHKERRQ(ierr);
584   ierr = PetscSectionSetChart(mesh->supportSection, pStart, pEnd);CHKERRQ(ierr);
585   PetscFunctionReturn(0);
586 }
587 
588 #undef __FUNCT__
589 #define __FUNCT__ "DMPlexGetConeSize"
590 /*@
591   DMPlexGetConeSize - Return the number of in-edges for this point in the Sieve DAG
592 
593   Not collective
594 
595   Input Parameters:
596 + mesh - The DMPlex
597 - p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
598 
599   Output Parameter:
600 . size - The cone size for point p
601 
602   Level: beginner
603 
604 .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexSetChart()
605 @*/
606 PetscErrorCode DMPlexGetConeSize(DM dm, PetscInt p, PetscInt *size)
607 {
608   DM_Plex       *mesh = (DM_Plex*) dm->data;
609   PetscErrorCode ierr;
610 
611   PetscFunctionBegin;
612   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
613   PetscValidPointer(size, 3);
614   ierr = PetscSectionGetDof(mesh->coneSection, p, size);CHKERRQ(ierr);
615   PetscFunctionReturn(0);
616 }
617 
618 #undef __FUNCT__
619 #define __FUNCT__ "DMPlexSetConeSize"
620 /*@
621   DMPlexSetConeSize - Set the number of in-edges for this point in the Sieve DAG
622 
623   Not collective
624 
625   Input Parameters:
626 + mesh - The DMPlex
627 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
628 - size - The cone size for point p
629 
630   Output Parameter:
631 
632   Note:
633   This should be called after DMPlexSetChart().
634 
635   Level: beginner
636 
637 .seealso: DMPlexCreate(), DMPlexGetConeSize(), DMPlexSetChart()
638 @*/
639 PetscErrorCode DMPlexSetConeSize(DM dm, PetscInt p, PetscInt size)
640 {
641   DM_Plex       *mesh = (DM_Plex*) dm->data;
642   PetscErrorCode ierr;
643 
644   PetscFunctionBegin;
645   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
646   ierr = PetscSectionSetDof(mesh->coneSection, p, size);CHKERRQ(ierr);
647 
648   mesh->maxConeSize = PetscMax(mesh->maxConeSize, size);
649   PetscFunctionReturn(0);
650 }
651 
652 #undef __FUNCT__
653 #define __FUNCT__ "DMPlexGetCone"
654 /*@C
655   DMPlexGetCone - Return the points on the in-edges for this point in the Sieve DAG
656 
657   Not collective
658 
659   Input Parameters:
660 + mesh - The DMPlex
661 - p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
662 
663   Output Parameter:
664 . cone - An array of points which are on the in-edges for point p
665 
666   Level: beginner
667 
668   Fortran Notes:
669   Since it returns an array, this routine is only available in Fortran 90, and you must
670   include petsc.h90 in your code.
671 
672   You must also call DMPlexRestoreCone() after you finish using the returned array.
673 
674 .seealso: DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart()
675 @*/
676 PetscErrorCode DMPlexGetCone(DM dm, PetscInt p, const PetscInt *cone[])
677 {
678   DM_Plex       *mesh = (DM_Plex*) dm->data;
679   PetscInt       off;
680   PetscErrorCode ierr;
681 
682   PetscFunctionBegin;
683   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
684   PetscValidPointer(cone, 3);
685   ierr  = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
686   *cone = &mesh->cones[off];
687   PetscFunctionReturn(0);
688 }
689 
690 #undef __FUNCT__
691 #define __FUNCT__ "DMPlexSetCone"
692 /*@
693   DMPlexSetCone - Set the points on the in-edges for this point in the Sieve DAG
694 
695   Not collective
696 
697   Input Parameters:
698 + mesh - The DMPlex
699 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
700 - cone - An array of points which are on the in-edges for point p
701 
702   Output Parameter:
703 
704   Note:
705   This should be called after all calls to DMPlexSetConeSize() and DMSetUp().
706 
707   Level: beginner
708 
709 .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexSetChart(), DMPlexSetConeSize(), DMSetUp()
710 @*/
711 PetscErrorCode DMPlexSetCone(DM dm, PetscInt p, const PetscInt cone[])
712 {
713   DM_Plex       *mesh = (DM_Plex*) dm->data;
714   PetscInt       pStart, pEnd;
715   PetscInt       dof, off, c;
716   PetscErrorCode ierr;
717 
718   PetscFunctionBegin;
719   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
720   ierr = PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);CHKERRQ(ierr);
721   ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
722   if (dof) PetscValidPointer(cone, 3);
723   ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
724   if ((p < pStart) || (p >= pEnd)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %D is not in the valid range [%D, %D)", p, pStart, pEnd);
725   for (c = 0; c < dof; ++c) {
726     if ((cone[c] < pStart) || (cone[c] >= pEnd)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cone point %D is not in the valid range [%D, %D)", cone[c], pStart, pEnd);
727     mesh->cones[off+c] = cone[c];
728   }
729   PetscFunctionReturn(0);
730 }
731 
732 #undef __FUNCT__
733 #define __FUNCT__ "DMPlexGetConeOrientation"
734 /*@C
735   DMPlexGetConeOrientation - Return the orientations on the in-edges for this point in the Sieve DAG
736 
737   Not collective
738 
739   Input Parameters:
740 + mesh - The DMPlex
741 - p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
742 
743   Output Parameter:
744 . coneOrientation - An array of orientations which are on the in-edges for point p. An orientation is an
745                     integer giving the prescription for cone traversal. If it is negative, the cone is
746                     traversed in the opposite direction. Its value 'o', or if negative '-(o+1)', gives
747                     the index of the cone point on which to start.
748 
749   Level: beginner
750 
751   Fortran Notes:
752   Since it returns an array, this routine is only available in Fortran 90, and you must
753   include petsc.h90 in your code.
754 
755   You must also call DMPlexRestoreConeOrientation() after you finish using the returned array.
756 
757 .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexSetCone(), DMPlexSetChart()
758 @*/
759 PetscErrorCode DMPlexGetConeOrientation(DM dm, PetscInt p, const PetscInt *coneOrientation[])
760 {
761   DM_Plex       *mesh = (DM_Plex*) dm->data;
762   PetscInt       off;
763   PetscErrorCode ierr;
764 
765   PetscFunctionBegin;
766   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
767 #if defined(PETSC_USE_DEBUG)
768   {
769     PetscInt dof;
770     ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
771     if (dof) PetscValidPointer(coneOrientation, 3);
772   }
773 #endif
774   ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
775 
776   *coneOrientation = &mesh->coneOrientations[off];
777   PetscFunctionReturn(0);
778 }
779 
780 #undef __FUNCT__
781 #define __FUNCT__ "DMPlexSetConeOrientation"
782 /*@
783   DMPlexSetConeOrientation - Set the orientations on the in-edges for this point in the Sieve DAG
784 
785   Not collective
786 
787   Input Parameters:
788 + mesh - The DMPlex
789 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
790 - coneOrientation - An array of orientations which are on the in-edges for point p. An orientation is an
791                     integer giving the prescription for cone traversal. If it is negative, the cone is
792                     traversed in the opposite direction. Its value 'o', or if negative '-(o+1)', gives
793                     the index of the cone point on which to start.
794 
795   Output Parameter:
796 
797   Note:
798   This should be called after all calls to DMPlexSetConeSize() and DMSetUp().
799 
800   Level: beginner
801 
802 .seealso: DMPlexCreate(), DMPlexGetConeOrientation(), DMPlexSetCone(), DMPlexSetChart(), DMPlexSetConeSize(), DMSetUp()
803 @*/
804 PetscErrorCode DMPlexSetConeOrientation(DM dm, PetscInt p, const PetscInt coneOrientation[])
805 {
806   DM_Plex       *mesh = (DM_Plex*) dm->data;
807   PetscInt       pStart, pEnd;
808   PetscInt       dof, off, c;
809   PetscErrorCode ierr;
810 
811   PetscFunctionBegin;
812   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
813   ierr = PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);CHKERRQ(ierr);
814   ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
815   if (dof) PetscValidPointer(coneOrientation, 3);
816   ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
817   if ((p < pStart) || (p >= pEnd)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %D is not in the valid range [%D, %D)", p, pStart, pEnd);
818   for (c = 0; c < dof; ++c) {
819     PetscInt cdof, o = coneOrientation[c];
820 
821     ierr = PetscSectionGetDof(mesh->coneSection, mesh->cones[off+c], &cdof);CHKERRQ(ierr);
822     if (o && ((o < -(cdof+1)) || (o >= cdof))) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cone orientation %D is not in the valid range [%D. %D)", o, -(cdof+1), cdof);
823     mesh->coneOrientations[off+c] = o;
824   }
825   PetscFunctionReturn(0);
826 }
827 
828 #undef __FUNCT__
829 #define __FUNCT__ "DMPlexInsertCone"
830 PetscErrorCode DMPlexInsertCone(DM dm, PetscInt p, PetscInt conePos, PetscInt conePoint)
831 {
832   DM_Plex       *mesh = (DM_Plex*) dm->data;
833   PetscInt       pStart, pEnd;
834   PetscInt       dof, off;
835   PetscErrorCode ierr;
836 
837   PetscFunctionBegin;
838   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
839   ierr = PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);CHKERRQ(ierr);
840   if ((p < pStart) || (p >= pEnd)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %D is not in the valid range [%D, %D)", p, pStart, pEnd);
841   if ((conePoint < pStart) || (conePoint >= pEnd)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cone point %D is not in the valid range [%D, %D)", conePoint, pStart, pEnd);
842   ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
843   ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
844   if ((conePos < 0) || (conePos >= dof)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cone position %D of point %D is not in the valid range [0, %D)", conePos, p, dof);
845   mesh->cones[off+conePos] = conePoint;
846   PetscFunctionReturn(0);
847 }
848 
849 #undef __FUNCT__
850 #define __FUNCT__ "DMPlexInsertConeOrientation"
851 PetscErrorCode DMPlexInsertConeOrientation(DM dm, PetscInt p, PetscInt conePos, PetscInt coneOrientation)
852 {
853   DM_Plex       *mesh = (DM_Plex*) dm->data;
854   PetscInt       pStart, pEnd;
855   PetscInt       dof, off;
856   PetscErrorCode ierr;
857 
858   PetscFunctionBegin;
859   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
860   ierr = PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);CHKERRQ(ierr);
861   if ((p < pStart) || (p >= pEnd)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %D is not in the valid range [%D, %D)", p, pStart, pEnd);
862   ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
863   ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
864   if ((conePos < 0) || (conePos >= dof)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cone position %D of point %D is not in the valid range [0, %D)", conePos, p, dof);
865   mesh->coneOrientations[off+conePos] = coneOrientation;
866   PetscFunctionReturn(0);
867 }
868 
869 #undef __FUNCT__
870 #define __FUNCT__ "DMPlexGetSupportSize"
871 /*@
872   DMPlexGetSupportSize - Return the number of out-edges for this point in the Sieve DAG
873 
874   Not collective
875 
876   Input Parameters:
877 + mesh - The DMPlex
878 - p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
879 
880   Output Parameter:
881 . size - The support size for point p
882 
883   Level: beginner
884 
885 .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexSetChart(), DMPlexGetConeSize()
886 @*/
887 PetscErrorCode DMPlexGetSupportSize(DM dm, PetscInt p, PetscInt *size)
888 {
889   DM_Plex       *mesh = (DM_Plex*) dm->data;
890   PetscErrorCode ierr;
891 
892   PetscFunctionBegin;
893   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
894   PetscValidPointer(size, 3);
895   ierr = PetscSectionGetDof(mesh->supportSection, p, size);CHKERRQ(ierr);
896   PetscFunctionReturn(0);
897 }
898 
899 #undef __FUNCT__
900 #define __FUNCT__ "DMPlexSetSupportSize"
901 /*@
902   DMPlexSetSupportSize - Set the number of out-edges for this point in the Sieve DAG
903 
904   Not collective
905 
906   Input Parameters:
907 + mesh - The DMPlex
908 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
909 - size - The support size for point p
910 
911   Output Parameter:
912 
913   Note:
914   This should be called after DMPlexSetChart().
915 
916   Level: beginner
917 
918 .seealso: DMPlexCreate(), DMPlexGetSupportSize(), DMPlexSetChart()
919 @*/
920 PetscErrorCode DMPlexSetSupportSize(DM dm, PetscInt p, PetscInt size)
921 {
922   DM_Plex       *mesh = (DM_Plex*) dm->data;
923   PetscErrorCode ierr;
924 
925   PetscFunctionBegin;
926   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
927   ierr = PetscSectionSetDof(mesh->supportSection, p, size);CHKERRQ(ierr);
928 
929   mesh->maxSupportSize = PetscMax(mesh->maxSupportSize, size);
930   PetscFunctionReturn(0);
931 }
932 
933 #undef __FUNCT__
934 #define __FUNCT__ "DMPlexGetSupport"
935 /*@C
936   DMPlexGetSupport - Return the points on the out-edges for this point in the Sieve DAG
937 
938   Not collective
939 
940   Input Parameters:
941 + mesh - The DMPlex
942 - p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
943 
944   Output Parameter:
945 . support - An array of points which are on the out-edges for point p
946 
947   Level: beginner
948 
949   Fortran Notes:
950   Since it returns an array, this routine is only available in Fortran 90, and you must
951   include petsc.h90 in your code.
952 
953   You must also call DMPlexRestoreSupport() after you finish using the returned array.
954 
955 .seealso: DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone()
956 @*/
957 PetscErrorCode DMPlexGetSupport(DM dm, PetscInt p, const PetscInt *support[])
958 {
959   DM_Plex       *mesh = (DM_Plex*) dm->data;
960   PetscInt       off;
961   PetscErrorCode ierr;
962 
963   PetscFunctionBegin;
964   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
965   PetscValidPointer(support, 3);
966   ierr     = PetscSectionGetOffset(mesh->supportSection, p, &off);CHKERRQ(ierr);
967   *support = &mesh->supports[off];
968   PetscFunctionReturn(0);
969 }
970 
971 #undef __FUNCT__
972 #define __FUNCT__ "DMPlexSetSupport"
973 /*@
974   DMPlexSetSupport - Set the points on the out-edges for this point in the Sieve DAG
975 
976   Not collective
977 
978   Input Parameters:
979 + mesh - The DMPlex
980 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
981 - support - An array of points which are on the in-edges for point p
982 
983   Output Parameter:
984 
985   Note:
986   This should be called after all calls to DMPlexSetSupportSize() and DMSetUp().
987 
988   Level: beginner
989 
990 .seealso: DMPlexCreate(), DMPlexGetSupport(), DMPlexSetChart(), DMPlexSetSupportSize(), DMSetUp()
991 @*/
992 PetscErrorCode DMPlexSetSupport(DM dm, PetscInt p, const PetscInt support[])
993 {
994   DM_Plex       *mesh = (DM_Plex*) dm->data;
995   PetscInt       pStart, pEnd;
996   PetscInt       dof, off, c;
997   PetscErrorCode ierr;
998 
999   PetscFunctionBegin;
1000   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1001   ierr = PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd);CHKERRQ(ierr);
1002   ierr = PetscSectionGetDof(mesh->supportSection, p, &dof);CHKERRQ(ierr);
1003   if (dof) PetscValidPointer(support, 3);
1004   ierr = PetscSectionGetOffset(mesh->supportSection, p, &off);CHKERRQ(ierr);
1005   if ((p < pStart) || (p >= pEnd)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %D is not in the valid range [%D, %D)", p, pStart, pEnd);
1006   for (c = 0; c < dof; ++c) {
1007     if ((support[c] < pStart) || (support[c] >= pEnd)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Support point %D is not in the valid range [%D, %D)", support[c], pStart, pEnd);
1008     mesh->supports[off+c] = support[c];
1009   }
1010   PetscFunctionReturn(0);
1011 }
1012 
1013 #undef __FUNCT__
1014 #define __FUNCT__ "DMPlexInsertSupport"
1015 PetscErrorCode DMPlexInsertSupport(DM dm, PetscInt p, PetscInt supportPos, PetscInt supportPoint)
1016 {
1017   DM_Plex       *mesh = (DM_Plex*) dm->data;
1018   PetscInt       pStart, pEnd;
1019   PetscInt       dof, off;
1020   PetscErrorCode ierr;
1021 
1022   PetscFunctionBegin;
1023   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1024   ierr = PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd);CHKERRQ(ierr);
1025   ierr = PetscSectionGetDof(mesh->supportSection, p, &dof);CHKERRQ(ierr);
1026   ierr = PetscSectionGetOffset(mesh->supportSection, p, &off);CHKERRQ(ierr);
1027   if ((p < pStart) || (p >= pEnd)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %D is not in the valid range [%D, %D)", p, pStart, pEnd);
1028   if ((supportPoint < pStart) || (supportPoint >= pEnd)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Support point %D is not in the valid range [%D, %D)", supportPoint, pStart, pEnd);
1029   if (supportPos >= dof) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Support position %D of point %D is not in the valid range [0, %D)", supportPos, p, dof);
1030   mesh->supports[off+supportPos] = supportPoint;
1031   PetscFunctionReturn(0);
1032 }
1033 
1034 #undef __FUNCT__
1035 #define __FUNCT__ "DMPlexGetTransitiveClosure"
1036 /*@C
1037   DMPlexGetTransitiveClosure - Return the points on the transitive closure of the in-edges or out-edges for this point in the Sieve DAG
1038 
1039   Not collective
1040 
1041   Input Parameters:
1042 + mesh - The DMPlex
1043 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1044 . useCone - PETSC_TRUE for in-edges,  otherwise use out-edges
1045 - points - If points is NULL on input, internal storage will be returned, otherwise the provided array is used
1046 
1047   Output Parameters:
1048 + numPoints - The number of points in the closure, so points[] is of size 2*numPoints
1049 - points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...]
1050 
1051   Note:
1052   If using internal storage (points is NULL on input), each call overwrites the last output.
1053 
1054   Fortran Notes:
1055   Since it returns an array, this routine is only available in Fortran 90, and you must
1056   include petsc.h90 in your code.
1057 
1058   The numPoints argument is not present in the Fortran 90 binding since it is internal to the array.
1059 
1060   Level: beginner
1061 
1062 .seealso: DMPlexRestoreTransitiveClosure(), DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone()
1063 @*/
1064 PetscErrorCode DMPlexGetTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[])
1065 {
1066   DM_Plex        *mesh = (DM_Plex*) dm->data;
1067   PetscInt       *closure, *fifo;
1068   const PetscInt *tmp = NULL, *tmpO = NULL;
1069   PetscInt        tmpSize, t;
1070   PetscInt        depth       = 0, maxSize;
1071   PetscInt        closureSize = 2, fifoSize = 0, fifoStart = 0;
1072   PetscErrorCode  ierr;
1073 
1074   PetscFunctionBegin;
1075   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1076   ierr    = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
1077   /* This is only 1-level */
1078   if (useCone) {
1079     ierr = DMPlexGetConeSize(dm, p, &tmpSize);CHKERRQ(ierr);
1080     ierr = DMPlexGetCone(dm, p, &tmp);CHKERRQ(ierr);
1081     ierr = DMPlexGetConeOrientation(dm, p, &tmpO);CHKERRQ(ierr);
1082   } else {
1083     ierr = DMPlexGetSupportSize(dm, p, &tmpSize);CHKERRQ(ierr);
1084     ierr = DMPlexGetSupport(dm, p, &tmp);CHKERRQ(ierr);
1085   }
1086   if (depth == 1) {
1087     if (*points) {
1088       closure = *points;
1089     } else {
1090       maxSize = 2*(PetscMax(mesh->maxConeSize, mesh->maxSupportSize)+1);
1091       ierr = DMGetWorkArray(dm, maxSize, PETSC_INT, &closure);CHKERRQ(ierr);
1092     }
1093     closure[0] = p; closure[1] = 0;
1094     for (t = 0; t < tmpSize; ++t, closureSize += 2) {
1095       closure[closureSize]   = tmp[t];
1096       closure[closureSize+1] = tmpO ? tmpO[t] : 0;
1097     }
1098     if (numPoints) *numPoints = closureSize/2;
1099     if (points)    *points    = closure;
1100     PetscFunctionReturn(0);
1101   }
1102   maxSize = 2*PetscMax(PetscMax(PetscPowInt(mesh->maxConeSize,depth+1),PetscPowInt(mesh->maxSupportSize,depth+1)),depth+1);
1103   ierr    = DMGetWorkArray(dm, maxSize, PETSC_INT, &fifo);CHKERRQ(ierr);
1104   if (*points) {
1105     closure = *points;
1106   } else {
1107     ierr = DMGetWorkArray(dm, maxSize, PETSC_INT, &closure);CHKERRQ(ierr);
1108   }
1109   closure[0] = p; closure[1] = 0;
1110   for (t = 0; t < tmpSize; ++t, closureSize += 2, fifoSize += 2) {
1111     const PetscInt cp = tmp[t];
1112     const PetscInt co = tmpO ? tmpO[t] : 0;
1113 
1114     closure[closureSize]   = cp;
1115     closure[closureSize+1] = co;
1116     fifo[fifoSize]         = cp;
1117     fifo[fifoSize+1]       = co;
1118   }
1119   /* Should kick out early when depth is reached, rather than checking all vertices for empty cones */
1120   while (fifoSize - fifoStart) {
1121     const PetscInt q   = fifo[fifoStart];
1122     const PetscInt o   = fifo[fifoStart+1];
1123     const PetscInt rev = o >= 0 ? 0 : 1;
1124     const PetscInt off = rev ? -(o+1) : o;
1125 
1126     if (useCone) {
1127       ierr = DMPlexGetConeSize(dm, q, &tmpSize);CHKERRQ(ierr);
1128       ierr = DMPlexGetCone(dm, q, &tmp);CHKERRQ(ierr);
1129       ierr = DMPlexGetConeOrientation(dm, q, &tmpO);CHKERRQ(ierr);
1130     } else {
1131       ierr = DMPlexGetSupportSize(dm, q, &tmpSize);CHKERRQ(ierr);
1132       ierr = DMPlexGetSupport(dm, q, &tmp);CHKERRQ(ierr);
1133       tmpO = NULL;
1134     }
1135     for (t = 0; t < tmpSize; ++t) {
1136       const PetscInt i  = ((rev ? tmpSize-t : t) + off)%tmpSize;
1137       const PetscInt cp = tmp[i];
1138       /* Must propogate orientation: When we reverse orientation, we both reverse the direction of iteration and start at the other end of the chain. */
1139       /* HACK: It is worse to get the size here, than to change the interpretation of -(*+1)
1140        const PetscInt co = tmpO ? (rev ? -(tmpO[i]+1) : tmpO[i]) : 0; */
1141       PetscInt       co = tmpO ? tmpO[i] : 0;
1142       PetscInt       c;
1143 
1144       if (rev) {
1145         PetscInt childSize, coff;
1146         ierr = DMPlexGetConeSize(dm, cp, &childSize);CHKERRQ(ierr);
1147         coff = tmpO[i] < 0 ? -(tmpO[i]+1) : tmpO[i];
1148         co   = childSize ? -(((coff+childSize-1)%childSize)+1) : 0;
1149       }
1150       /* Check for duplicate */
1151       for (c = 0; c < closureSize; c += 2) {
1152         if (closure[c] == cp) break;
1153       }
1154       if (c == closureSize) {
1155         closure[closureSize]   = cp;
1156         closure[closureSize+1] = co;
1157         fifo[fifoSize]         = cp;
1158         fifo[fifoSize+1]       = co;
1159         closureSize           += 2;
1160         fifoSize              += 2;
1161       }
1162     }
1163     fifoStart += 2;
1164   }
1165   if (numPoints) *numPoints = closureSize/2;
1166   if (points)    *points    = closure;
1167   ierr = DMRestoreWorkArray(dm, maxSize, PETSC_INT, &fifo);CHKERRQ(ierr);
1168   PetscFunctionReturn(0);
1169 }
1170 
1171 #undef __FUNCT__
1172 #define __FUNCT__ "DMPlexRestoreTransitiveClosure"
1173 /*@C
1174   DMPlexRestoreTransitiveClosure - Restore the array of points on the transitive closure of the in-edges or out-edges for this point in the Sieve DAG
1175 
1176   Not collective
1177 
1178   Input Parameters:
1179 + mesh - The DMPlex
1180 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1181 . useCone - PETSC_TRUE for in-edges,  otherwise use out-edges
1182 - points - If points is NULL on input, internal storage will be returned, otherwise the provided array is used
1183 
1184   Output Parameters:
1185 + numPoints - The number of points in the closure, so points[] is of size 2*numPoints
1186 - points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...]
1187 
1188   Note:
1189   If not using internal storage (points is not NULL on input), this call is unnecessary
1190 
1191   Fortran Notes:
1192   Since it returns an array, this routine is only available in Fortran 90, and you must
1193   include petsc.h90 in your code.
1194 
1195   The numPoints argument is not present in the Fortran 90 binding since it is internal to the array.
1196 
1197   Level: beginner
1198 
1199 .seealso: DMPlexGetTransitiveClosure(), DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone()
1200 @*/
1201 PetscErrorCode DMPlexRestoreTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[])
1202 {
1203   PetscErrorCode ierr;
1204 
1205   PetscFunctionBegin;
1206   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1207   ierr = DMRestoreWorkArray(dm, 0, PETSC_INT, points);CHKERRQ(ierr);
1208   PetscFunctionReturn(0);
1209 }
1210 
1211 #undef __FUNCT__
1212 #define __FUNCT__ "DMPlexGetMaxSizes"
1213 /*@
1214   DMPlexGetMaxSizes - Return the maximum number of in-edges (cone) and out-edges (support) for any point in the Sieve DAG
1215 
1216   Not collective
1217 
1218   Input Parameter:
1219 . mesh - The DMPlex
1220 
1221   Output Parameters:
1222 + maxConeSize - The maximum number of in-edges
1223 - maxSupportSize - The maximum number of out-edges
1224 
1225   Level: beginner
1226 
1227 .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexSetChart()
1228 @*/
1229 PetscErrorCode DMPlexGetMaxSizes(DM dm, PetscInt *maxConeSize, PetscInt *maxSupportSize)
1230 {
1231   DM_Plex *mesh = (DM_Plex*) dm->data;
1232 
1233   PetscFunctionBegin;
1234   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1235   if (maxConeSize)    *maxConeSize    = mesh->maxConeSize;
1236   if (maxSupportSize) *maxSupportSize = mesh->maxSupportSize;
1237   PetscFunctionReturn(0);
1238 }
1239 
1240 #undef __FUNCT__
1241 #define __FUNCT__ "DMSetUp_Plex"
1242 PetscErrorCode DMSetUp_Plex(DM dm)
1243 {
1244   DM_Plex       *mesh = (DM_Plex*) dm->data;
1245   PetscInt       size;
1246   PetscErrorCode ierr;
1247 
1248   PetscFunctionBegin;
1249   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1250   ierr = PetscSectionSetUp(mesh->coneSection);CHKERRQ(ierr);
1251   ierr = PetscSectionGetStorageSize(mesh->coneSection, &size);CHKERRQ(ierr);
1252   ierr = PetscMalloc(size * sizeof(PetscInt), &mesh->cones);CHKERRQ(ierr);
1253   ierr = PetscMalloc(size * sizeof(PetscInt), &mesh->coneOrientations);CHKERRQ(ierr);
1254   ierr = PetscMemzero(mesh->coneOrientations, size * sizeof(PetscInt));CHKERRQ(ierr);
1255   if (mesh->maxSupportSize) {
1256     ierr = PetscSectionSetUp(mesh->supportSection);CHKERRQ(ierr);
1257     ierr = PetscSectionGetStorageSize(mesh->supportSection, &size);CHKERRQ(ierr);
1258     ierr = PetscMalloc(size * sizeof(PetscInt), &mesh->supports);CHKERRQ(ierr);
1259   }
1260   PetscFunctionReturn(0);
1261 }
1262 
1263 #undef __FUNCT__
1264 #define __FUNCT__ "DMCreateSubDM_Plex"
1265 PetscErrorCode DMCreateSubDM_Plex(DM dm, PetscInt numFields, PetscInt fields[], IS *is, DM *subdm)
1266 {
1267   PetscErrorCode ierr;
1268 
1269   PetscFunctionBegin;
1270   if (subdm) {ierr = DMClone(dm, subdm);CHKERRQ(ierr);}
1271   ierr = DMCreateSubDM_Section_Private(dm, numFields, fields, is, subdm);CHKERRQ(ierr);
1272   PetscFunctionReturn(0);
1273 }
1274 
1275 #undef __FUNCT__
1276 #define __FUNCT__ "DMPlexSymmetrize"
1277 /*@
1278   DMPlexSymmetrize - Creates support (out-edge) information from cone (in-edge) inoformation
1279 
1280   Not collective
1281 
1282   Input Parameter:
1283 . mesh - The DMPlex
1284 
1285   Output Parameter:
1286 
1287   Note:
1288   This should be called after all calls to DMPlexSetCone()
1289 
1290   Level: beginner
1291 
1292 .seealso: DMPlexCreate(), DMPlexSetChart(), DMPlexSetConeSize(), DMPlexSetCone()
1293 @*/
1294 PetscErrorCode DMPlexSymmetrize(DM dm)
1295 {
1296   DM_Plex       *mesh = (DM_Plex*) dm->data;
1297   PetscInt      *offsets;
1298   PetscInt       supportSize;
1299   PetscInt       pStart, pEnd, p;
1300   PetscErrorCode ierr;
1301 
1302   PetscFunctionBegin;
1303   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1304   if (mesh->supports) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Supports were already setup in this DMPlex");
1305   /* Calculate support sizes */
1306   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
1307   for (p = pStart; p < pEnd; ++p) {
1308     PetscInt dof, off, c;
1309 
1310     ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
1311     ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
1312     for (c = off; c < off+dof; ++c) {
1313       ierr = PetscSectionAddDof(mesh->supportSection, mesh->cones[c], 1);CHKERRQ(ierr);
1314     }
1315   }
1316   for (p = pStart; p < pEnd; ++p) {
1317     PetscInt dof;
1318 
1319     ierr = PetscSectionGetDof(mesh->supportSection, p, &dof);CHKERRQ(ierr);
1320 
1321     mesh->maxSupportSize = PetscMax(mesh->maxSupportSize, dof);
1322   }
1323   ierr = PetscSectionSetUp(mesh->supportSection);CHKERRQ(ierr);
1324   /* Calculate supports */
1325   ierr = PetscSectionGetStorageSize(mesh->supportSection, &supportSize);CHKERRQ(ierr);
1326   ierr = PetscMalloc(supportSize * sizeof(PetscInt), &mesh->supports);CHKERRQ(ierr);
1327   ierr = PetscMalloc((pEnd - pStart) * sizeof(PetscInt), &offsets);CHKERRQ(ierr);
1328   ierr = PetscMemzero(offsets, (pEnd - pStart) * sizeof(PetscInt));CHKERRQ(ierr);
1329   for (p = pStart; p < pEnd; ++p) {
1330     PetscInt dof, off, c;
1331 
1332     ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
1333     ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
1334     for (c = off; c < off+dof; ++c) {
1335       const PetscInt q = mesh->cones[c];
1336       PetscInt       offS;
1337 
1338       ierr = PetscSectionGetOffset(mesh->supportSection, q, &offS);CHKERRQ(ierr);
1339 
1340       mesh->supports[offS+offsets[q]] = p;
1341       ++offsets[q];
1342     }
1343   }
1344   ierr = PetscFree(offsets);CHKERRQ(ierr);
1345   PetscFunctionReturn(0);
1346 }
1347 
1348 #undef __FUNCT__
1349 #define __FUNCT__ "DMPlexStratify"
1350 /*@
1351   DMPlexStratify - The Sieve DAG for most topologies is a graded poset (http://en.wikipedia.org/wiki/Graded_poset), and
1352   can be illustrated by Hasse Diagram (a http://en.wikipedia.org/wiki/Hasse_diagram). The strata group all points of the
1353   same grade, and this function calculates the strata. This grade can be seen as the height (or depth) of the point in
1354   the DAG.
1355 
1356   Not collective
1357 
1358   Input Parameter:
1359 . mesh - The DMPlex
1360 
1361   Output Parameter:
1362 
1363   Notes:
1364   The normal association for the point grade is element dimension (or co-dimension). For instance, all vertices would
1365   have depth 0, and all edges depth 1. Likewise, all cells heights would have height 0, and all faces height 1.
1366 
1367   This should be called after all calls to DMPlexSymmetrize()
1368 
1369   Level: beginner
1370 
1371 .seealso: DMPlexCreate(), DMPlexSymmetrize()
1372 @*/
1373 PetscErrorCode DMPlexStratify(DM dm)
1374 {
1375   DMLabel        label;
1376   PetscInt       pStart, pEnd, p;
1377   PetscInt       numRoots = 0, numLeaves = 0;
1378   PetscErrorCode ierr;
1379 
1380   PetscFunctionBegin;
1381   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1382   ierr = PetscLogEventBegin(DMPLEX_Stratify,dm,0,0,0);CHKERRQ(ierr);
1383   /* Calculate depth */
1384   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
1385   ierr = DMPlexCreateLabel(dm, "depth");CHKERRQ(ierr);
1386   ierr = DMPlexGetDepthLabel(dm, &label);CHKERRQ(ierr);
1387   /* Initialize roots and count leaves */
1388   for (p = pStart; p < pEnd; ++p) {
1389     PetscInt coneSize, supportSize;
1390 
1391     ierr = DMPlexGetConeSize(dm, p, &coneSize);CHKERRQ(ierr);
1392     ierr = DMPlexGetSupportSize(dm, p, &supportSize);CHKERRQ(ierr);
1393     if (!coneSize && supportSize) {
1394       ++numRoots;
1395       ierr = DMLabelSetValue(label, p, 0);CHKERRQ(ierr);
1396     } else if (!supportSize && coneSize) {
1397       ++numLeaves;
1398     } else if (!supportSize && !coneSize) {
1399       /* Isolated points */
1400       ierr = DMLabelSetValue(label, p, 0);CHKERRQ(ierr);
1401     }
1402   }
1403   if (numRoots + numLeaves == (pEnd - pStart)) {
1404     for (p = pStart; p < pEnd; ++p) {
1405       PetscInt coneSize, supportSize;
1406 
1407       ierr = DMPlexGetConeSize(dm, p, &coneSize);CHKERRQ(ierr);
1408       ierr = DMPlexGetSupportSize(dm, p, &supportSize);CHKERRQ(ierr);
1409       if (!supportSize && coneSize) {
1410         ierr = DMLabelSetValue(label, p, 1);CHKERRQ(ierr);
1411       }
1412     }
1413   } else {
1414     IS       pointIS;
1415     PetscInt numPoints = 0, level = 0;
1416 
1417     ierr = DMLabelGetStratumIS(label, level, &pointIS);CHKERRQ(ierr);
1418     if (pointIS) {ierr = ISGetLocalSize(pointIS, &numPoints);CHKERRQ(ierr);}
1419     while (numPoints) {
1420       const PetscInt *points;
1421       const PetscInt  newLevel = level+1;
1422 
1423       ierr = ISGetIndices(pointIS, &points);CHKERRQ(ierr);
1424       for (p = 0; p < numPoints; ++p) {
1425         const PetscInt  point = points[p];
1426         const PetscInt *support;
1427         PetscInt        supportSize, s;
1428 
1429         ierr = DMPlexGetSupportSize(dm, point, &supportSize);CHKERRQ(ierr);
1430         ierr = DMPlexGetSupport(dm, point, &support);CHKERRQ(ierr);
1431         for (s = 0; s < supportSize; ++s) {
1432           ierr = DMLabelSetValue(label, support[s], newLevel);CHKERRQ(ierr);
1433         }
1434       }
1435       ++level;
1436       ierr = ISDestroy(&pointIS);CHKERRQ(ierr);
1437       ierr = DMLabelGetStratumIS(label, level, &pointIS);CHKERRQ(ierr);
1438       if (pointIS) {ierr = ISGetLocalSize(pointIS, &numPoints);CHKERRQ(ierr);}
1439       else         {numPoints = 0;}
1440     }
1441     ierr = ISDestroy(&pointIS);CHKERRQ(ierr);
1442   }
1443   ierr = PetscLogEventEnd(DMPLEX_Stratify,dm,0,0,0);CHKERRQ(ierr);
1444   PetscFunctionReturn(0);
1445 }
1446 
1447 #undef __FUNCT__
1448 #define __FUNCT__ "DMPlexGetJoin"
1449 /*@C
1450   DMPlexGetJoin - Get an array for the join of the set of points
1451 
1452   Not Collective
1453 
1454   Input Parameters:
1455 + dm - The DMPlex object
1456 . numPoints - The number of input points for the join
1457 - points - The input points
1458 
1459   Output Parameters:
1460 + numCoveredPoints - The number of points in the join
1461 - coveredPoints - The points in the join
1462 
1463   Level: intermediate
1464 
1465   Note: Currently, this is restricted to a single level join
1466 
1467   Fortran Notes:
1468   Since it returns an array, this routine is only available in Fortran 90, and you must
1469   include petsc.h90 in your code.
1470 
1471   The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array.
1472 
1473 .keywords: mesh
1474 .seealso: DMPlexRestoreJoin(), DMPlexGetMeet()
1475 @*/
1476 PetscErrorCode DMPlexGetJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
1477 {
1478   DM_Plex       *mesh = (DM_Plex*) dm->data;
1479   PetscInt      *join[2];
1480   PetscInt       joinSize, i = 0;
1481   PetscInt       dof, off, p, c, m;
1482   PetscErrorCode ierr;
1483 
1484   PetscFunctionBegin;
1485   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1486   PetscValidPointer(points, 2);
1487   PetscValidPointer(numCoveredPoints, 3);
1488   PetscValidPointer(coveredPoints, 4);
1489   ierr = DMGetWorkArray(dm, mesh->maxSupportSize, PETSC_INT, &join[0]);CHKERRQ(ierr);
1490   ierr = DMGetWorkArray(dm, mesh->maxSupportSize, PETSC_INT, &join[1]);CHKERRQ(ierr);
1491   /* Copy in support of first point */
1492   ierr = PetscSectionGetDof(mesh->supportSection, points[0], &dof);CHKERRQ(ierr);
1493   ierr = PetscSectionGetOffset(mesh->supportSection, points[0], &off);CHKERRQ(ierr);
1494   for (joinSize = 0; joinSize < dof; ++joinSize) {
1495     join[i][joinSize] = mesh->supports[off+joinSize];
1496   }
1497   /* Check each successive support */
1498   for (p = 1; p < numPoints; ++p) {
1499     PetscInt newJoinSize = 0;
1500 
1501     ierr = PetscSectionGetDof(mesh->supportSection, points[p], &dof);CHKERRQ(ierr);
1502     ierr = PetscSectionGetOffset(mesh->supportSection, points[p], &off);CHKERRQ(ierr);
1503     for (c = 0; c < dof; ++c) {
1504       const PetscInt point = mesh->supports[off+c];
1505 
1506       for (m = 0; m < joinSize; ++m) {
1507         if (point == join[i][m]) {
1508           join[1-i][newJoinSize++] = point;
1509           break;
1510         }
1511       }
1512     }
1513     joinSize = newJoinSize;
1514     i        = 1-i;
1515   }
1516   *numCoveredPoints = joinSize;
1517   *coveredPoints    = join[i];
1518   ierr              = DMRestoreWorkArray(dm, mesh->maxSupportSize, PETSC_INT, &join[1-i]);CHKERRQ(ierr);
1519   PetscFunctionReturn(0);
1520 }
1521 
1522 #undef __FUNCT__
1523 #define __FUNCT__ "DMPlexRestoreJoin"
1524 /*@C
1525   DMPlexRestoreJoin - Restore an array for the join of the set of points
1526 
1527   Not Collective
1528 
1529   Input Parameters:
1530 + dm - The DMPlex object
1531 . numPoints - The number of input points for the join
1532 - points - The input points
1533 
1534   Output Parameters:
1535 + numCoveredPoints - The number of points in the join
1536 - coveredPoints - The points in the join
1537 
1538   Fortran Notes:
1539   Since it returns an array, this routine is only available in Fortran 90, and you must
1540   include petsc.h90 in your code.
1541 
1542   The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array.
1543 
1544   Level: intermediate
1545 
1546 .keywords: mesh
1547 .seealso: DMPlexGetJoin(), DMPlexGetFullJoin(), DMPlexGetMeet()
1548 @*/
1549 PetscErrorCode DMPlexRestoreJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
1550 {
1551   PetscErrorCode ierr;
1552 
1553   PetscFunctionBegin;
1554   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1555   PetscValidPointer(coveredPoints, 4);
1556   ierr = DMRestoreWorkArray(dm, 0, PETSC_INT, (void*) coveredPoints);CHKERRQ(ierr);
1557   PetscFunctionReturn(0);
1558 }
1559 
1560 #undef __FUNCT__
1561 #define __FUNCT__ "DMPlexGetFullJoin"
1562 /*@C
1563   DMPlexGetFullJoin - Get an array for the join of the set of points
1564 
1565   Not Collective
1566 
1567   Input Parameters:
1568 + dm - The DMPlex object
1569 . numPoints - The number of input points for the join
1570 - points - The input points
1571 
1572   Output Parameters:
1573 + numCoveredPoints - The number of points in the join
1574 - coveredPoints - The points in the join
1575 
1576   Fortran Notes:
1577   Since it returns an array, this routine is only available in Fortran 90, and you must
1578   include petsc.h90 in your code.
1579 
1580   The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array.
1581 
1582   Level: intermediate
1583 
1584 .keywords: mesh
1585 .seealso: DMPlexGetJoin(), DMPlexRestoreJoin(), DMPlexGetMeet()
1586 @*/
1587 PetscErrorCode DMPlexGetFullJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
1588 {
1589   DM_Plex       *mesh = (DM_Plex*) dm->data;
1590   PetscInt      *offsets, **closures;
1591   PetscInt      *join[2];
1592   PetscInt       depth = 0, maxSize, joinSize = 0, i = 0;
1593   PetscInt       p, d, c, m;
1594   PetscErrorCode ierr;
1595 
1596   PetscFunctionBegin;
1597   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1598   PetscValidPointer(points, 2);
1599   PetscValidPointer(numCoveredPoints, 3);
1600   PetscValidPointer(coveredPoints, 4);
1601 
1602   ierr    = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
1603   ierr    = PetscMalloc(numPoints * sizeof(PetscInt*), &closures);CHKERRQ(ierr);
1604   ierr    = PetscMemzero(closures,numPoints*sizeof(PetscInt*));CHKERRQ(ierr);
1605   ierr    = DMGetWorkArray(dm, numPoints*(depth+2), PETSC_INT, &offsets);CHKERRQ(ierr);
1606   maxSize = PetscPowInt(mesh->maxSupportSize,depth+1);
1607   ierr    = DMGetWorkArray(dm, maxSize, PETSC_INT, &join[0]);CHKERRQ(ierr);
1608   ierr    = DMGetWorkArray(dm, maxSize, PETSC_INT, &join[1]);CHKERRQ(ierr);
1609 
1610   for (p = 0; p < numPoints; ++p) {
1611     PetscInt closureSize;
1612 
1613     ierr = DMPlexGetTransitiveClosure(dm, points[p], PETSC_FALSE, &closureSize, &closures[p]);CHKERRQ(ierr);
1614 
1615     offsets[p*(depth+2)+0] = 0;
1616     for (d = 0; d < depth+1; ++d) {
1617       PetscInt pStart, pEnd, i;
1618 
1619       ierr = DMPlexGetDepthStratum(dm, d, &pStart, &pEnd);CHKERRQ(ierr);
1620       for (i = offsets[p*(depth+2)+d]; i < closureSize; ++i) {
1621         if ((pStart > closures[p][i*2]) || (pEnd <= closures[p][i*2])) {
1622           offsets[p*(depth+2)+d+1] = i;
1623           break;
1624         }
1625       }
1626       if (i == closureSize) offsets[p*(depth+2)+d+1] = i;
1627     }
1628     if (offsets[p*(depth+2)+depth+1] != closureSize) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Total size of closure %D should be %D", offsets[p*(depth+2)+depth+1], closureSize);
1629   }
1630   for (d = 0; d < depth+1; ++d) {
1631     PetscInt dof;
1632 
1633     /* Copy in support of first point */
1634     dof = offsets[d+1] - offsets[d];
1635     for (joinSize = 0; joinSize < dof; ++joinSize) {
1636       join[i][joinSize] = closures[0][(offsets[d]+joinSize)*2];
1637     }
1638     /* Check each successive cone */
1639     for (p = 1; p < numPoints && joinSize; ++p) {
1640       PetscInt newJoinSize = 0;
1641 
1642       dof = offsets[p*(depth+2)+d+1] - offsets[p*(depth+2)+d];
1643       for (c = 0; c < dof; ++c) {
1644         const PetscInt point = closures[p][(offsets[p*(depth+2)+d]+c)*2];
1645 
1646         for (m = 0; m < joinSize; ++m) {
1647           if (point == join[i][m]) {
1648             join[1-i][newJoinSize++] = point;
1649             break;
1650           }
1651         }
1652       }
1653       joinSize = newJoinSize;
1654       i        = 1-i;
1655     }
1656     if (joinSize) break;
1657   }
1658   *numCoveredPoints = joinSize;
1659   *coveredPoints    = join[i];
1660   for (p = 0; p < numPoints; ++p) {
1661     ierr = DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_FALSE, NULL, &closures[p]);CHKERRQ(ierr);
1662   }
1663   ierr = PetscFree(closures);CHKERRQ(ierr);
1664   ierr = DMRestoreWorkArray(dm, numPoints*(depth+2), PETSC_INT, &offsets);CHKERRQ(ierr);
1665   ierr = DMRestoreWorkArray(dm, mesh->maxSupportSize, PETSC_INT, &join[1-i]);CHKERRQ(ierr);
1666   PetscFunctionReturn(0);
1667 }
1668 
1669 #undef __FUNCT__
1670 #define __FUNCT__ "DMPlexGetMeet"
1671 /*@C
1672   DMPlexGetMeet - Get an array for the meet of the set of points
1673 
1674   Not Collective
1675 
1676   Input Parameters:
1677 + dm - The DMPlex object
1678 . numPoints - The number of input points for the meet
1679 - points - The input points
1680 
1681   Output Parameters:
1682 + numCoveredPoints - The number of points in the meet
1683 - coveredPoints - The points in the meet
1684 
1685   Level: intermediate
1686 
1687   Note: Currently, this is restricted to a single level meet
1688 
1689   Fortran Notes:
1690   Since it returns an array, this routine is only available in Fortran 90, and you must
1691   include petsc.h90 in your code.
1692 
1693   The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array.
1694 
1695 .keywords: mesh
1696 .seealso: DMPlexRestoreMeet(), DMPlexGetJoin()
1697 @*/
1698 PetscErrorCode DMPlexGetMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveringPoints, const PetscInt **coveringPoints)
1699 {
1700   DM_Plex       *mesh = (DM_Plex*) dm->data;
1701   PetscInt      *meet[2];
1702   PetscInt       meetSize, i = 0;
1703   PetscInt       dof, off, p, c, m;
1704   PetscErrorCode ierr;
1705 
1706   PetscFunctionBegin;
1707   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1708   PetscValidPointer(points, 2);
1709   PetscValidPointer(numCoveringPoints, 3);
1710   PetscValidPointer(coveringPoints, 4);
1711   ierr = DMGetWorkArray(dm, mesh->maxConeSize, PETSC_INT, &meet[0]);CHKERRQ(ierr);
1712   ierr = DMGetWorkArray(dm, mesh->maxConeSize, PETSC_INT, &meet[1]);CHKERRQ(ierr);
1713   /* Copy in cone of first point */
1714   ierr = PetscSectionGetDof(mesh->coneSection, points[0], &dof);CHKERRQ(ierr);
1715   ierr = PetscSectionGetOffset(mesh->coneSection, points[0], &off);CHKERRQ(ierr);
1716   for (meetSize = 0; meetSize < dof; ++meetSize) {
1717     meet[i][meetSize] = mesh->cones[off+meetSize];
1718   }
1719   /* Check each successive cone */
1720   for (p = 1; p < numPoints; ++p) {
1721     PetscInt newMeetSize = 0;
1722 
1723     ierr = PetscSectionGetDof(mesh->coneSection, points[p], &dof);CHKERRQ(ierr);
1724     ierr = PetscSectionGetOffset(mesh->coneSection, points[p], &off);CHKERRQ(ierr);
1725     for (c = 0; c < dof; ++c) {
1726       const PetscInt point = mesh->cones[off+c];
1727 
1728       for (m = 0; m < meetSize; ++m) {
1729         if (point == meet[i][m]) {
1730           meet[1-i][newMeetSize++] = point;
1731           break;
1732         }
1733       }
1734     }
1735     meetSize = newMeetSize;
1736     i        = 1-i;
1737   }
1738   *numCoveringPoints = meetSize;
1739   *coveringPoints    = meet[i];
1740   ierr               = DMRestoreWorkArray(dm, mesh->maxConeSize, PETSC_INT, &meet[1-i]);CHKERRQ(ierr);
1741   PetscFunctionReturn(0);
1742 }
1743 
1744 #undef __FUNCT__
1745 #define __FUNCT__ "DMPlexRestoreMeet"
1746 /*@C
1747   DMPlexRestoreMeet - Restore an array for the meet of the set of points
1748 
1749   Not Collective
1750 
1751   Input Parameters:
1752 + dm - The DMPlex object
1753 . numPoints - The number of input points for the meet
1754 - points - The input points
1755 
1756   Output Parameters:
1757 + numCoveredPoints - The number of points in the meet
1758 - coveredPoints - The points in the meet
1759 
1760   Level: intermediate
1761 
1762   Fortran Notes:
1763   Since it returns an array, this routine is only available in Fortran 90, and you must
1764   include petsc.h90 in your code.
1765 
1766   The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array.
1767 
1768 .keywords: mesh
1769 .seealso: DMPlexGetMeet(), DMPlexGetFullMeet(), DMPlexGetJoin()
1770 @*/
1771 PetscErrorCode DMPlexRestoreMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
1772 {
1773   PetscErrorCode ierr;
1774 
1775   PetscFunctionBegin;
1776   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1777   PetscValidPointer(coveredPoints, 4);
1778   ierr = DMRestoreWorkArray(dm, 0, PETSC_INT, (void*) coveredPoints);CHKERRQ(ierr);
1779   PetscFunctionReturn(0);
1780 }
1781 
1782 #undef __FUNCT__
1783 #define __FUNCT__ "DMPlexGetFullMeet"
1784 /*@C
1785   DMPlexGetFullMeet - Get an array for the meet of the set of points
1786 
1787   Not Collective
1788 
1789   Input Parameters:
1790 + dm - The DMPlex object
1791 . numPoints - The number of input points for the meet
1792 - points - The input points
1793 
1794   Output Parameters:
1795 + numCoveredPoints - The number of points in the meet
1796 - coveredPoints - The points in the meet
1797 
1798   Level: intermediate
1799 
1800   Fortran Notes:
1801   Since it returns an array, this routine is only available in Fortran 90, and you must
1802   include petsc.h90 in your code.
1803 
1804   The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array.
1805 
1806 .keywords: mesh
1807 .seealso: DMPlexGetMeet(), DMPlexRestoreMeet(), DMPlexGetJoin()
1808 @*/
1809 PetscErrorCode DMPlexGetFullMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
1810 {
1811   DM_Plex       *mesh = (DM_Plex*) dm->data;
1812   PetscInt      *offsets, **closures;
1813   PetscInt      *meet[2];
1814   PetscInt       height = 0, maxSize, meetSize = 0, i = 0;
1815   PetscInt       p, h, c, m;
1816   PetscErrorCode ierr;
1817 
1818   PetscFunctionBegin;
1819   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1820   PetscValidPointer(points, 2);
1821   PetscValidPointer(numCoveredPoints, 3);
1822   PetscValidPointer(coveredPoints, 4);
1823 
1824   ierr    = DMPlexGetDepth(dm, &height);CHKERRQ(ierr);
1825   ierr    = PetscMalloc(numPoints * sizeof(PetscInt*), &closures);CHKERRQ(ierr);
1826   ierr    = DMGetWorkArray(dm, numPoints*(height+2), PETSC_INT, &offsets);CHKERRQ(ierr);
1827   maxSize = PetscPowInt(mesh->maxConeSize,height+1);
1828   ierr    = DMGetWorkArray(dm, maxSize, PETSC_INT, &meet[0]);CHKERRQ(ierr);
1829   ierr    = DMGetWorkArray(dm, maxSize, PETSC_INT, &meet[1]);CHKERRQ(ierr);
1830 
1831   for (p = 0; p < numPoints; ++p) {
1832     PetscInt closureSize;
1833 
1834     ierr = DMPlexGetTransitiveClosure(dm, points[p], PETSC_TRUE, &closureSize, &closures[p]);CHKERRQ(ierr);
1835 
1836     offsets[p*(height+2)+0] = 0;
1837     for (h = 0; h < height+1; ++h) {
1838       PetscInt pStart, pEnd, i;
1839 
1840       ierr = DMPlexGetHeightStratum(dm, h, &pStart, &pEnd);CHKERRQ(ierr);
1841       for (i = offsets[p*(height+2)+h]; i < closureSize; ++i) {
1842         if ((pStart > closures[p][i*2]) || (pEnd <= closures[p][i*2])) {
1843           offsets[p*(height+2)+h+1] = i;
1844           break;
1845         }
1846       }
1847       if (i == closureSize) offsets[p*(height+2)+h+1] = i;
1848     }
1849     if (offsets[p*(height+2)+height+1] != closureSize) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Total size of closure %D should be %D", offsets[p*(height+2)+height+1], closureSize);
1850   }
1851   for (h = 0; h < height+1; ++h) {
1852     PetscInt dof;
1853 
1854     /* Copy in cone of first point */
1855     dof = offsets[h+1] - offsets[h];
1856     for (meetSize = 0; meetSize < dof; ++meetSize) {
1857       meet[i][meetSize] = closures[0][(offsets[h]+meetSize)*2];
1858     }
1859     /* Check each successive cone */
1860     for (p = 1; p < numPoints && meetSize; ++p) {
1861       PetscInt newMeetSize = 0;
1862 
1863       dof = offsets[p*(height+2)+h+1] - offsets[p*(height+2)+h];
1864       for (c = 0; c < dof; ++c) {
1865         const PetscInt point = closures[p][(offsets[p*(height+2)+h]+c)*2];
1866 
1867         for (m = 0; m < meetSize; ++m) {
1868           if (point == meet[i][m]) {
1869             meet[1-i][newMeetSize++] = point;
1870             break;
1871           }
1872         }
1873       }
1874       meetSize = newMeetSize;
1875       i        = 1-i;
1876     }
1877     if (meetSize) break;
1878   }
1879   *numCoveredPoints = meetSize;
1880   *coveredPoints    = meet[i];
1881   for (p = 0; p < numPoints; ++p) {
1882     ierr = DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_TRUE, NULL, &closures[p]);CHKERRQ(ierr);
1883   }
1884   ierr = PetscFree(closures);CHKERRQ(ierr);
1885   ierr = DMRestoreWorkArray(dm, numPoints*(height+2), PETSC_INT, &offsets);CHKERRQ(ierr);
1886   ierr = DMRestoreWorkArray(dm, mesh->maxConeSize, PETSC_INT, &meet[1-i]);CHKERRQ(ierr);
1887   PetscFunctionReturn(0);
1888 }
1889 
1890 #undef __FUNCT__
1891 #define __FUNCT__ "DMPlexGetNumFaceVertices"
1892 PetscErrorCode DMPlexGetNumFaceVertices(DM dm, PetscInt cellDim, PetscInt numCorners, PetscInt *numFaceVertices)
1893 {
1894   MPI_Comm       comm;
1895   PetscErrorCode ierr;
1896 
1897   PetscFunctionBegin;
1898   ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr);
1899   PetscValidPointer(numFaceVertices,3);
1900   switch (cellDim) {
1901   case 0:
1902     *numFaceVertices = 0;
1903     break;
1904   case 1:
1905     *numFaceVertices = 1;
1906     break;
1907   case 2:
1908     switch (numCorners) {
1909     case 3: /* triangle */
1910       *numFaceVertices = 2; /* Edge has 2 vertices */
1911       break;
1912     case 4: /* quadrilateral */
1913       *numFaceVertices = 2; /* Edge has 2 vertices */
1914       break;
1915     case 6: /* quadratic triangle, tri and quad cohesive Lagrange cells */
1916       *numFaceVertices = 3; /* Edge has 3 vertices */
1917       break;
1918     case 9: /* quadratic quadrilateral, quadratic quad cohesive Lagrange cells */
1919       *numFaceVertices = 3; /* Edge has 3 vertices */
1920       break;
1921     default:
1922       SETERRQ2(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %d for dimension %d", numCorners, cellDim);
1923     }
1924     break;
1925   case 3:
1926     switch (numCorners) {
1927     case 4: /* tetradehdron */
1928       *numFaceVertices = 3; /* Face has 3 vertices */
1929       break;
1930     case 6: /* tet cohesive cells */
1931       *numFaceVertices = 4; /* Face has 4 vertices */
1932       break;
1933     case 8: /* hexahedron */
1934       *numFaceVertices = 4; /* Face has 4 vertices */
1935       break;
1936     case 9: /* tet cohesive Lagrange cells */
1937       *numFaceVertices = 6; /* Face has 6 vertices */
1938       break;
1939     case 10: /* quadratic tetrahedron */
1940       *numFaceVertices = 6; /* Face has 6 vertices */
1941       break;
1942     case 12: /* hex cohesive Lagrange cells */
1943       *numFaceVertices = 6; /* Face has 6 vertices */
1944       break;
1945     case 18: /* quadratic tet cohesive Lagrange cells */
1946       *numFaceVertices = 6; /* Face has 6 vertices */
1947       break;
1948     case 27: /* quadratic hexahedron, quadratic hex cohesive Lagrange cells */
1949       *numFaceVertices = 9; /* Face has 9 vertices */
1950       break;
1951     default:
1952       SETERRQ2(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %d for dimension %d", numCorners, cellDim);
1953     }
1954     break;
1955   default:
1956     SETERRQ1(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid cell dimension %d", cellDim);
1957   }
1958   PetscFunctionReturn(0);
1959 }
1960 
1961 #undef __FUNCT__
1962 #define __FUNCT__ "DMPlexOrient"
1963 /* Trys to give the mesh a consistent orientation */
1964 PetscErrorCode DMPlexOrient(DM dm)
1965 {
1966   PetscBT        seenCells, flippedCells, seenFaces;
1967   PetscInt      *faceFIFO, fTop, fBottom;
1968   PetscInt       dim, h, cStart, cEnd, c, fStart, fEnd, face, maxConeSize, *revcone, *revconeO;
1969   PetscErrorCode ierr;
1970 
1971   PetscFunctionBegin;
1972   /* Truth Table
1973      mismatch    flips   do action   mismatch   flipA ^ flipB   action
1974          F       0 flips     no         F             F           F
1975          F       1 flip      yes        F             T           T
1976          F       2 flips     no         T             F           T
1977          T       0 flips     yes        T             T           F
1978          T       1 flip      no
1979          T       2 flips     yes
1980   */
1981   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
1982   ierr = DMPlexGetVTKCellHeight(dm, &h);CHKERRQ(ierr);
1983   ierr = DMPlexGetHeightStratum(dm, h,   &cStart, &cEnd);CHKERRQ(ierr);
1984   ierr = DMPlexGetHeightStratum(dm, h+1, &fStart, &fEnd);CHKERRQ(ierr);
1985   ierr = PetscBTCreate(cEnd - cStart, &seenCells);CHKERRQ(ierr);
1986   ierr = PetscBTMemzero(cEnd - cStart, seenCells);CHKERRQ(ierr);
1987   ierr = PetscBTCreate(cEnd - cStart, &flippedCells);CHKERRQ(ierr);
1988   ierr = PetscBTMemzero(cEnd - cStart, flippedCells);CHKERRQ(ierr);
1989   ierr = PetscBTCreate(fEnd - fStart, &seenFaces);CHKERRQ(ierr);
1990   ierr = PetscBTMemzero(fEnd - fStart, seenFaces);CHKERRQ(ierr);
1991   ierr = PetscMalloc((fEnd - fStart) * sizeof(PetscInt), &faceFIFO);CHKERRQ(ierr);
1992   fTop = fBottom = 0;
1993   /* Initialize FIFO with first cell */
1994   if (cEnd > cStart) {
1995     const PetscInt *cone;
1996     PetscInt        coneSize;
1997 
1998     ierr = DMPlexGetConeSize(dm, cStart, &coneSize);CHKERRQ(ierr);
1999     ierr = DMPlexGetCone(dm, cStart, &cone);CHKERRQ(ierr);
2000     for (c = 0; c < coneSize; ++c) {
2001       faceFIFO[fBottom++] = cone[c];
2002       ierr = PetscBTSet(seenFaces, cone[c]-fStart);CHKERRQ(ierr);
2003     }
2004   }
2005   /* Consider each face in FIFO */
2006   while (fTop < fBottom) {
2007     const PetscInt *support, *coneA, *coneB, *coneOA, *coneOB;
2008     PetscInt        supportSize, coneSizeA, coneSizeB, posA = -1, posB = -1;
2009     PetscInt        seenA, flippedA, seenB, flippedB, mismatch;
2010 
2011     face = faceFIFO[fTop++];
2012     ierr = DMPlexGetSupportSize(dm, face, &supportSize);CHKERRQ(ierr);
2013     ierr = DMPlexGetSupport(dm, face, &support);CHKERRQ(ierr);
2014     if (supportSize < 2) continue;
2015     if (supportSize != 2) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Faces should separate only two cells, not %d", supportSize);
2016     seenA    = PetscBTLookup(seenCells,    support[0]-cStart);
2017     flippedA = PetscBTLookup(flippedCells, support[0]-cStart) ? 1 : 0;
2018     seenB    = PetscBTLookup(seenCells,    support[1]-cStart);
2019     flippedB = PetscBTLookup(flippedCells, support[1]-cStart) ? 1 : 0;
2020 
2021     ierr = DMPlexGetConeSize(dm, support[0], &coneSizeA);CHKERRQ(ierr);
2022     ierr = DMPlexGetConeSize(dm, support[1], &coneSizeB);CHKERRQ(ierr);
2023     ierr = DMPlexGetCone(dm, support[0], &coneA);CHKERRQ(ierr);
2024     ierr = DMPlexGetCone(dm, support[1], &coneB);CHKERRQ(ierr);
2025     ierr = DMPlexGetConeOrientation(dm, support[0], &coneOA);CHKERRQ(ierr);
2026     ierr = DMPlexGetConeOrientation(dm, support[1], &coneOB);CHKERRQ(ierr);
2027     for (c = 0; c < coneSizeA; ++c) {
2028       if (!PetscBTLookup(seenFaces, coneA[c]-fStart)) {
2029         faceFIFO[fBottom++] = coneA[c];
2030         ierr = PetscBTSet(seenFaces, coneA[c]-fStart);CHKERRQ(ierr);
2031       }
2032       if (coneA[c] == face) posA = c;
2033       if (fBottom > fEnd-fStart) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Face %d was pushed exceeding capacity %d > %d", coneA[c], fBottom, fEnd-fStart);
2034     }
2035     if (posA < 0) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Face %d could not be located in cell %d", face, support[0]);
2036     for (c = 0; c < coneSizeB; ++c) {
2037       if (!PetscBTLookup(seenFaces, coneB[c]-fStart)) {
2038         faceFIFO[fBottom++] = coneB[c];
2039         ierr = PetscBTSet(seenFaces, coneB[c]-fStart);CHKERRQ(ierr);
2040       }
2041       if (coneB[c] == face) posB = c;
2042       if (fBottom > fEnd-fStart) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Face %d was pushed exceeding capacity %d > %d", coneA[c], fBottom, fEnd-fStart);
2043     }
2044     if (posB < 0) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Face %d could not be located in cell %d", face, support[1]);
2045 
2046     if (dim == 1) {
2047       mismatch = posA == posB;
2048     } else {
2049       mismatch = coneOA[posA] == coneOB[posB];
2050     }
2051 
2052     if (mismatch ^ (flippedA ^ flippedB)) {
2053       if (seenA && seenB) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Previously seen cells %d and %d do not match: Fault mesh is non-orientable", support[0], support[1]);
2054       if (!seenA && !flippedA) {
2055         ierr = PetscBTSet(flippedCells, support[0]-cStart);CHKERRQ(ierr);
2056       } else if (!seenB && !flippedB) {
2057         ierr = PetscBTSet(flippedCells, support[1]-cStart);CHKERRQ(ierr);
2058       } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Inconsistent mesh orientation: Fault mesh is non-orientable");
2059     } else if (mismatch && flippedA && flippedB) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Attempt to flip already flipped cell: Fault mesh is non-orientable");
2060     ierr = PetscBTSet(seenCells, support[0]-cStart);CHKERRQ(ierr);
2061     ierr = PetscBTSet(seenCells, support[1]-cStart);CHKERRQ(ierr);
2062   }
2063 
2064   ierr = DMPlexGetMaxSizes(dm, &maxConeSize, NULL);CHKERRQ(ierr);
2065   ierr = DMGetWorkArray(dm, maxConeSize, PETSC_INT, &revcone);CHKERRQ(ierr);
2066   ierr = DMGetWorkArray(dm, maxConeSize, PETSC_INT, &revconeO);CHKERRQ(ierr);
2067   for (c = cStart; c < cEnd; ++c) {
2068     const PetscInt *cone, *coneO, *support;
2069     PetscInt        coneSize, supportSize, faceSize, cp, sp;
2070 
2071     if (!PetscBTLookup(flippedCells, c-cStart)) continue;
2072     ierr = DMPlexGetConeSize(dm, c, &coneSize);CHKERRQ(ierr);
2073     ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
2074     ierr = DMPlexGetConeOrientation(dm, c, &coneO);CHKERRQ(ierr);
2075     for (cp = 0; cp < coneSize; ++cp) {
2076       const PetscInt rcp = coneSize-cp-1;
2077 
2078       ierr = DMPlexGetConeSize(dm, cone[rcp], &faceSize);CHKERRQ(ierr);
2079       revcone[cp]  = cone[rcp];
2080       revconeO[cp] = coneO[rcp] >= 0 ? -(faceSize-coneO[rcp]) : faceSize+coneO[rcp];
2081     }
2082     ierr = DMPlexSetCone(dm, c, revcone);CHKERRQ(ierr);
2083     ierr = DMPlexSetConeOrientation(dm, c, revconeO);CHKERRQ(ierr);
2084     /* Reverse orientations of support */
2085     faceSize = coneSize;
2086     ierr = DMPlexGetSupportSize(dm, c, &supportSize);CHKERRQ(ierr);
2087     ierr = DMPlexGetSupport(dm, c, &support);CHKERRQ(ierr);
2088     for (sp = 0; sp < supportSize; ++sp) {
2089       ierr = DMPlexGetConeSize(dm, support[sp], &coneSize);CHKERRQ(ierr);
2090       ierr = DMPlexGetCone(dm, support[sp], &cone);CHKERRQ(ierr);
2091       ierr = DMPlexGetConeOrientation(dm, support[sp], &coneO);CHKERRQ(ierr);
2092       for (cp = 0; cp < coneSize; ++cp) {
2093         if (cone[cp] != c) continue;
2094         ierr = DMPlexInsertConeOrientation(dm, support[sp], cp, coneO[cp] >= 0 ? -(faceSize-coneO[cp]) : faceSize+coneO[cp]);CHKERRQ(ierr);
2095       }
2096     }
2097   }
2098   ierr = DMRestoreWorkArray(dm, maxConeSize, PETSC_INT, &revcone);CHKERRQ(ierr);
2099   ierr = DMRestoreWorkArray(dm, maxConeSize, PETSC_INT, &revconeO);CHKERRQ(ierr);
2100   ierr = PetscBTDestroy(&seenCells);CHKERRQ(ierr);
2101   ierr = PetscBTDestroy(&flippedCells);CHKERRQ(ierr);
2102   ierr = PetscBTDestroy(&seenFaces);CHKERRQ(ierr);
2103   ierr = PetscFree(faceFIFO);CHKERRQ(ierr);
2104   PetscFunctionReturn(0);
2105 }
2106 
2107 #undef __FUNCT__
2108 #define __FUNCT__ "DMPlexGetAdjacencySingleLevel_Internal"
2109 static PetscErrorCode DMPlexGetAdjacencySingleLevel_Internal(DM dm, PetscInt p, PetscBool useClosure, const PetscInt *tmpClosure, PetscInt *adjSize, PetscInt adj[])
2110 {
2111   const PetscInt *support = NULL;
2112   PetscInt        numAdj   = 0, maxAdjSize = *adjSize, supportSize, s;
2113   PetscErrorCode  ierr;
2114 
2115   PetscFunctionBegin;
2116   if (useClosure) {
2117     ierr = DMPlexGetConeSize(dm, p, &supportSize);CHKERRQ(ierr);
2118     ierr = DMPlexGetCone(dm, p, &support);CHKERRQ(ierr);
2119     for (s = 0; s < supportSize; ++s) {
2120       const PetscInt *cone = NULL;
2121       PetscInt        coneSize, c, q;
2122 
2123       ierr = DMPlexGetSupportSize(dm, support[s], &coneSize);CHKERRQ(ierr);
2124       ierr = DMPlexGetSupport(dm, support[s], &cone);CHKERRQ(ierr);
2125       for (c = 0; c < coneSize; ++c) {
2126         for (q = 0; q < numAdj || (adj[numAdj++] = cone[c],0); ++q) {
2127           if (cone[c] == adj[q]) break;
2128         }
2129         if (numAdj > maxAdjSize) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid mesh exceeded adjacency allocation (%D)", maxAdjSize);
2130       }
2131     }
2132   } else {
2133     ierr = DMPlexGetSupportSize(dm, p, &supportSize);CHKERRQ(ierr);
2134     ierr = DMPlexGetSupport(dm, p, &support);CHKERRQ(ierr);
2135     for (s = 0; s < supportSize; ++s) {
2136       const PetscInt *cone = NULL;
2137       PetscInt        coneSize, c, q;
2138 
2139       ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
2140       ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
2141       for (c = 0; c < coneSize; ++c) {
2142         for (q = 0; q < numAdj || (adj[numAdj++] = cone[c],0); ++q) {
2143           if (cone[c] == adj[q]) break;
2144         }
2145         if (numAdj > maxAdjSize) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid mesh exceeded adjacency allocation (%D)", maxAdjSize);
2146       }
2147     }
2148   }
2149   *adjSize = numAdj;
2150   PetscFunctionReturn(0);
2151 }
2152 
2153 #undef __FUNCT__
2154 #define __FUNCT__ "DMPlexCreateNeighborCSR"
2155 PetscErrorCode DMPlexCreateNeighborCSR(DM dm, PetscInt cellHeight, PetscInt *numVertices, PetscInt **offsets, PetscInt **adjacency)
2156 {
2157   const PetscInt maxFaceCases = 30;
2158   PetscInt       numFaceCases = 0;
2159   PetscInt       numFaceVertices[30]; /* maxFaceCases, C89 sucks sucks sucks */
2160   PetscInt      *off, *adj;
2161   PetscInt      *neighborCells, *tmpClosure;
2162   PetscInt       maxConeSize, maxSupportSize, maxClosure, maxNeighbors;
2163   PetscInt       dim, cellDim, depth = 0, faceDepth, cStart, cEnd, c, numCells, cell;
2164   PetscErrorCode ierr;
2165 
2166   PetscFunctionBegin;
2167   /* For parallel partitioning, I think you have to communicate supports */
2168   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
2169   cellDim = dim - cellHeight;
2170   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
2171   ierr = DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd);CHKERRQ(ierr);
2172   ierr = DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize);CHKERRQ(ierr);
2173   if (cEnd - cStart == 0) {
2174     if (numVertices) *numVertices = 0;
2175     if (offsets)   *offsets   = NULL;
2176     if (adjacency) *adjacency = NULL;
2177     PetscFunctionReturn(0);
2178   }
2179   numCells  = cEnd - cStart;
2180   faceDepth = depth - cellHeight;
2181   /* Setup face recognition */
2182   if (faceDepth == 1) {
2183     PetscInt cornersSeen[30] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; /* Could use PetscBT */
2184 
2185     for (c = cStart; c < cEnd; ++c) {
2186       PetscInt corners;
2187 
2188       ierr = DMPlexGetConeSize(dm, c, &corners);CHKERRQ(ierr);
2189       if (!cornersSeen[corners]) {
2190         PetscInt nFV;
2191 
2192         if (numFaceCases >= maxFaceCases) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Exceeded maximum number of face recognition cases");
2193         cornersSeen[corners] = 1;
2194 
2195         ierr = DMPlexGetNumFaceVertices(dm, cellDim, corners, &nFV);CHKERRQ(ierr);
2196 
2197         numFaceVertices[numFaceCases++] = nFV;
2198       }
2199     }
2200   }
2201   maxClosure   = 2*PetscMax(PetscPowInt(maxConeSize,depth+1),PetscPowInt(maxSupportSize,depth+1));
2202   maxNeighbors = PetscPowInt(maxConeSize,depth+1)*PetscPowInt(maxSupportSize,depth+1);
2203   ierr         = PetscMalloc2(maxNeighbors,PetscInt,&neighborCells,maxClosure,PetscInt,&tmpClosure);CHKERRQ(ierr);
2204   ierr         = PetscMalloc((numCells+1) * sizeof(PetscInt), &off);CHKERRQ(ierr);
2205   ierr         = PetscMemzero(off, (numCells+1) * sizeof(PetscInt));CHKERRQ(ierr);
2206   /* Count neighboring cells */
2207   for (cell = cStart; cell < cEnd; ++cell) {
2208     PetscInt numNeighbors = maxNeighbors, n;
2209 
2210     ierr = DMPlexGetAdjacencySingleLevel_Internal(dm, cell, PETSC_TRUE, tmpClosure, &numNeighbors, neighborCells);CHKERRQ(ierr);
2211     /* Get meet with each cell, and check with recognizer (could optimize to check each pair only once) */
2212     for (n = 0; n < numNeighbors; ++n) {
2213       PetscInt        cellPair[2];
2214       PetscBool       found    = faceDepth > 1 ? PETSC_TRUE : PETSC_FALSE;
2215       PetscInt        meetSize = 0;
2216       const PetscInt *meet    = NULL;
2217 
2218       cellPair[0] = cell; cellPair[1] = neighborCells[n];
2219       if (cellPair[0] == cellPair[1]) continue;
2220       if (!found) {
2221         ierr = DMPlexGetMeet(dm, 2, cellPair, &meetSize, &meet);CHKERRQ(ierr);
2222         if (meetSize) {
2223           PetscInt f;
2224 
2225           for (f = 0; f < numFaceCases; ++f) {
2226             if (numFaceVertices[f] == meetSize) {
2227               found = PETSC_TRUE;
2228               break;
2229             }
2230           }
2231         }
2232         ierr = DMPlexRestoreMeet(dm, 2, cellPair, &meetSize, &meet);CHKERRQ(ierr);
2233       }
2234       if (found) ++off[cell-cStart+1];
2235     }
2236   }
2237   /* Prefix sum */
2238   for (cell = 1; cell <= numCells; ++cell) off[cell] += off[cell-1];
2239 
2240   if (adjacency) {
2241     ierr = PetscMalloc(off[numCells] * sizeof(PetscInt), &adj);CHKERRQ(ierr);
2242     /* Get neighboring cells */
2243     for (cell = cStart; cell < cEnd; ++cell) {
2244       PetscInt numNeighbors = maxNeighbors, n;
2245       PetscInt cellOffset   = 0;
2246 
2247       ierr = DMPlexGetAdjacencySingleLevel_Internal(dm, cell, PETSC_TRUE, tmpClosure, &numNeighbors, neighborCells);CHKERRQ(ierr);
2248       /* Get meet with each cell, and check with recognizer (could optimize to check each pair only once) */
2249       for (n = 0; n < numNeighbors; ++n) {
2250         PetscInt        cellPair[2];
2251         PetscBool       found    = faceDepth > 1 ? PETSC_TRUE : PETSC_FALSE;
2252         PetscInt        meetSize = 0;
2253         const PetscInt *meet    = NULL;
2254 
2255         cellPair[0] = cell; cellPair[1] = neighborCells[n];
2256         if (cellPair[0] == cellPair[1]) continue;
2257         if (!found) {
2258           ierr = DMPlexGetMeet(dm, 2, cellPair, &meetSize, &meet);CHKERRQ(ierr);
2259           if (meetSize) {
2260             PetscInt f;
2261 
2262             for (f = 0; f < numFaceCases; ++f) {
2263               if (numFaceVertices[f] == meetSize) {
2264                 found = PETSC_TRUE;
2265                 break;
2266               }
2267             }
2268           }
2269           ierr = DMPlexRestoreMeet(dm, 2, cellPair, &meetSize, &meet);CHKERRQ(ierr);
2270         }
2271         if (found) {
2272           adj[off[cell-cStart]+cellOffset] = neighborCells[n];
2273           ++cellOffset;
2274         }
2275       }
2276     }
2277   }
2278   ierr = PetscFree2(neighborCells,tmpClosure);CHKERRQ(ierr);
2279   if (numVertices) *numVertices = numCells;
2280   if (offsets)   *offsets   = off;
2281   if (adjacency) *adjacency = adj;
2282   PetscFunctionReturn(0);
2283 }
2284 
2285 #if defined(PETSC_HAVE_CHACO)
2286 #if defined(PETSC_HAVE_UNISTD_H)
2287 #include <unistd.h>
2288 #endif
2289 /* Chaco does not have an include file */
2290 PETSC_EXTERN int interface(int nvtxs, int *start, int *adjacency, int *vwgts,
2291                        float *ewgts, float *x, float *y, float *z, char *outassignname,
2292                        char *outfilename, short *assignment, int architecture, int ndims_tot,
2293                        int mesh_dims[3], double *goal, int global_method, int local_method,
2294                        int rqi_flag, int vmax, int ndims, double eigtol, long seed);
2295 
2296 extern int FREE_GRAPH;
2297 
2298 #undef __FUNCT__
2299 #define __FUNCT__ "DMPlexPartition_Chaco"
2300 PetscErrorCode DMPlexPartition_Chaco(DM dm, PetscInt numVertices, PetscInt start[], PetscInt adjacency[], PetscSection *partSection, IS *partition)
2301 {
2302   enum {DEFAULT_METHOD = 1, INERTIAL_METHOD = 3};
2303   MPI_Comm       comm;
2304   int            nvtxs          = numVertices; /* number of vertices in full graph */
2305   int           *vwgts          = NULL;   /* weights for all vertices */
2306   float         *ewgts          = NULL;   /* weights for all edges */
2307   float         *x              = NULL, *y = NULL, *z = NULL; /* coordinates for inertial method */
2308   char          *outassignname  = NULL;   /*  name of assignment output file */
2309   char          *outfilename    = NULL;   /* output file name */
2310   int            architecture   = 1;      /* 0 => hypercube, d => d-dimensional mesh */
2311   int            ndims_tot      = 0;      /* total number of cube dimensions to divide */
2312   int            mesh_dims[3];            /* dimensions of mesh of processors */
2313   double        *goal          = NULL;    /* desired set sizes for each set */
2314   int            global_method = 1;       /* global partitioning algorithm */
2315   int            local_method  = 1;       /* local partitioning algorithm */
2316   int            rqi_flag      = 0;       /* should I use RQI/Symmlq eigensolver? */
2317   int            vmax          = 200;     /* how many vertices to coarsen down to? */
2318   int            ndims         = 1;       /* number of eigenvectors (2^d sets) */
2319   double         eigtol        = 0.001;   /* tolerance on eigenvectors */
2320   long           seed          = 123636512; /* for random graph mutations */
2321   short int     *assignment;              /* Output partition */
2322   int            fd_stdout, fd_pipe[2];
2323   PetscInt      *points;
2324   PetscMPIInt    commSize;
2325   int            i, v, p;
2326   PetscErrorCode ierr;
2327 
2328   PetscFunctionBegin;
2329   ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr);
2330   ierr = MPI_Comm_size(comm, &commSize);CHKERRQ(ierr);
2331   if (!numVertices) {
2332     ierr = PetscSectionCreate(comm, partSection);CHKERRQ(ierr);
2333     ierr = PetscSectionSetChart(*partSection, 0, commSize);CHKERRQ(ierr);
2334     ierr = PetscSectionSetUp(*partSection);CHKERRQ(ierr);
2335     ierr = ISCreateGeneral(comm, 0, NULL, PETSC_OWN_POINTER, partition);CHKERRQ(ierr);
2336     PetscFunctionReturn(0);
2337   }
2338   FREE_GRAPH = 0;                         /* Do not let Chaco free my memory */
2339   for (i = 0; i < start[numVertices]; ++i) ++adjacency[i];
2340 
2341   if (global_method == INERTIAL_METHOD) {
2342     /* manager.createCellCoordinates(nvtxs, &x, &y, &z); */
2343     SETERRQ(comm, PETSC_ERR_SUP, "Inertial partitioning not yet supported");
2344   }
2345   mesh_dims[0] = commSize;
2346   mesh_dims[1] = 1;
2347   mesh_dims[2] = 1;
2348   ierr = PetscMalloc(nvtxs * sizeof(short int), &assignment);CHKERRQ(ierr);
2349   /* Chaco outputs to stdout. We redirect this to a buffer. */
2350   /* TODO: check error codes for UNIX calls */
2351 #if defined(PETSC_HAVE_UNISTD_H)
2352   {
2353     int piperet;
2354     piperet = pipe(fd_pipe);
2355     if (piperet) SETERRQ(comm,PETSC_ERR_SYS,"Could not create pipe");
2356     fd_stdout = dup(1);
2357     close(1);
2358     dup2(fd_pipe[1], 1);
2359   }
2360 #endif
2361   ierr = interface(nvtxs, (int*) start, (int*) adjacency, vwgts, ewgts, x, y, z, outassignname, outfilename,
2362                    assignment, architecture, ndims_tot, mesh_dims, goal, global_method, local_method, rqi_flag,
2363                    vmax, ndims, eigtol, seed);
2364 #if defined(PETSC_HAVE_UNISTD_H)
2365   {
2366     char msgLog[10000];
2367     int  count;
2368 
2369     fflush(stdout);
2370     count = read(fd_pipe[0], msgLog, (10000-1)*sizeof(char));
2371     if (count < 0) count = 0;
2372     msgLog[count] = 0;
2373     close(1);
2374     dup2(fd_stdout, 1);
2375     close(fd_stdout);
2376     close(fd_pipe[0]);
2377     close(fd_pipe[1]);
2378     if (ierr) SETERRQ1(comm, PETSC_ERR_LIB, "Error in Chaco library: %s", msgLog);
2379   }
2380 #endif
2381   /* Convert to PetscSection+IS */
2382   ierr = PetscSectionCreate(comm, partSection);CHKERRQ(ierr);
2383   ierr = PetscSectionSetChart(*partSection, 0, commSize);CHKERRQ(ierr);
2384   for (v = 0; v < nvtxs; ++v) {
2385     ierr = PetscSectionAddDof(*partSection, assignment[v], 1);CHKERRQ(ierr);
2386   }
2387   ierr = PetscSectionSetUp(*partSection);CHKERRQ(ierr);
2388   ierr = PetscMalloc(nvtxs * sizeof(PetscInt), &points);CHKERRQ(ierr);
2389   for (p = 0, i = 0; p < commSize; ++p) {
2390     for (v = 0; v < nvtxs; ++v) {
2391       if (assignment[v] == p) points[i++] = v;
2392     }
2393   }
2394   if (i != nvtxs) SETERRQ2(comm, PETSC_ERR_PLIB, "Number of points %D should be %D", i, nvtxs);
2395   ierr = ISCreateGeneral(comm, nvtxs, points, PETSC_OWN_POINTER, partition);CHKERRQ(ierr);
2396   if (global_method == INERTIAL_METHOD) {
2397     /* manager.destroyCellCoordinates(nvtxs, &x, &y, &z); */
2398   }
2399   ierr = PetscFree(assignment);CHKERRQ(ierr);
2400   for (i = 0; i < start[numVertices]; ++i) --adjacency[i];
2401   PetscFunctionReturn(0);
2402 }
2403 #endif
2404 
2405 #if defined(PETSC_HAVE_PARMETIS)
2406 #include <parmetis.h>
2407 
2408 #undef __FUNCT__
2409 #define __FUNCT__ "DMPlexPartition_ParMetis"
2410 PetscErrorCode DMPlexPartition_ParMetis(DM dm, PetscInt numVertices, PetscInt start[], PetscInt adjacency[], PetscSection *partSection, IS *partition)
2411 {
2412   MPI_Comm       comm;
2413   PetscInt       nvtxs      = numVertices; // The number of vertices in full graph
2414   PetscInt      *vtxdist;                  // Distribution of vertices across processes
2415   PetscInt      *xadj       = start;       // Start of edge list for each vertex
2416   PetscInt      *adjncy     = adjacency;   // Edge lists for all vertices
2417   PetscInt      *vwgt       = NULL;        // Vertex weights
2418   PetscInt      *adjwgt     = NULL;        // Edge weights
2419   PetscInt       wgtflag    = 0;           // Indicates which weights are present
2420   PetscInt       numflag    = 0;           // Indicates initial offset (0 or 1)
2421   PetscInt       ncon       = 1;           // The number of weights per vertex
2422   PetscInt       nparts;                   // The number of partitions
2423   PetscReal     *tpwgts;                   // The fraction of vertex weights assigned to each partition
2424   PetscReal     *ubvec;                    // The balance intolerance for vertex weights
2425   PetscInt       options[5];               // Options
2426   // Outputs
2427   PetscInt       edgeCut;                  // The number of edges cut by the partition
2428   PetscInt      *assignment, *points;
2429   PetscMPIInt    commSize, rank, p, v, i;
2430   PetscErrorCode ierr;
2431 
2432   PetscFunctionBegin;
2433   ierr = PetscObjectGetComm((PetscObject) dm, &comm);CHKERRQ(ierr);
2434   ierr = MPI_Comm_size(comm, &commSize);CHKERRQ(ierr);
2435   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
2436   nparts = commSize;
2437   options[0] = 0; /* Use all defaults */
2438   /* Calculate vertex distribution */
2439   ierr = PetscMalloc4(nparts+1,PetscInt,&vtxdist,nparts*ncon,PetscReal,&tpwgts,ncon,PetscReal,&ubvec,nvtxs,PetscInt,&assignment);CHKERRQ(ierr);
2440   vtxdist[0] = 0;
2441   ierr = MPI_Allgather(&nvtxs, 1, MPIU_INT, &vtxdist[1], 1, MPIU_INT, comm);CHKERRQ(ierr);
2442   for (p = 2; p <= nparts; ++p) {
2443     vtxdist[p] += vtxdist[p-1];
2444   }
2445   /* Calculate weights */
2446   for (p = 0; p < nparts; ++p) {
2447     tpwgts[p] = 1.0/nparts;
2448   }
2449   ubvec[0] = 1.05;
2450 
2451   if (nparts == 1) {
2452     ierr = PetscMemzero(assignment, nvtxs * sizeof(PetscInt));
2453   } else {
2454     if (vtxdist[1] == vtxdist[nparts]) {
2455       if (!rank) {
2456         PetscStackPush("METIS_PartGraphKway");
2457         ierr = METIS_PartGraphKway(&nvtxs, &ncon, xadj, adjncy, vwgt, NULL, adjwgt, &nparts, tpwgts, ubvec, NULL, &edgeCut, assignment);
2458         PetscStackPop;
2459         if (ierr != METIS_OK) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_LIB, "Error in METIS_PartGraphKway()");
2460       }
2461     } else {
2462       PetscStackPush("ParMETIS_V3_PartKway");
2463       ierr = ParMETIS_V3_PartKway(vtxdist, xadj, adjncy, vwgt, adjwgt, &wgtflag, &numflag, &ncon, &nparts, tpwgts, ubvec, options, &edgeCut, assignment, &comm);
2464       PetscStackPop;
2465       if (ierr != METIS_OK) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_LIB, "Error in ParMETIS_V3_PartKway()");
2466     }
2467   }
2468   /* Convert to PetscSection+IS */
2469   ierr = PetscSectionCreate(comm, partSection);CHKERRQ(ierr);
2470   ierr = PetscSectionSetChart(*partSection, 0, commSize);CHKERRQ(ierr);
2471   for (v = 0; v < nvtxs; ++v) {
2472     ierr = PetscSectionAddDof(*partSection, assignment[v], 1);CHKERRQ(ierr);
2473   }
2474   ierr = PetscSectionSetUp(*partSection);CHKERRQ(ierr);
2475   ierr = PetscMalloc(nvtxs * sizeof(PetscInt), &points);CHKERRQ(ierr);
2476   for (p = 0, i = 0; p < commSize; ++p) {
2477     for (v = 0; v < nvtxs; ++v) {
2478       if (assignment[v] == p) points[i++] = v;
2479     }
2480   }
2481   if (i != nvtxs) SETERRQ2(comm, PETSC_ERR_PLIB, "Number of points %D should be %D", i, nvtxs);
2482   ierr = ISCreateGeneral(comm, nvtxs, points, PETSC_OWN_POINTER, partition);CHKERRQ(ierr);
2483   ierr = PetscFree4(vtxdist,tpwgts,ubvec,assignment);CHKERRQ(ierr);
2484   PetscFunctionReturn(0);
2485 }
2486 #endif
2487 
2488 #undef __FUNCT__
2489 #define __FUNCT__ "DMPlexEnlargePartition"
2490 /* Expand the partition by BFS on the adjacency graph */
2491 PetscErrorCode DMPlexEnlargePartition(DM dm, const PetscInt start[], const PetscInt adjacency[], PetscSection origPartSection, IS origPartition, PetscSection *partSection, IS *partition)
2492 {
2493   PetscHashI      h;
2494   const PetscInt *points;
2495   PetscInt      **tmpPoints, *newPoints, totPoints = 0;
2496   PetscInt        pStart, pEnd, part, q;
2497   PetscErrorCode  ierr;
2498 
2499   PetscFunctionBegin;
2500   PetscHashICreate(h);
2501   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)dm), partSection);CHKERRQ(ierr);
2502   ierr = PetscSectionGetChart(origPartSection, &pStart, &pEnd);CHKERRQ(ierr);
2503   ierr = PetscSectionSetChart(*partSection, pStart, pEnd);CHKERRQ(ierr);
2504   ierr = ISGetIndices(origPartition, &points);CHKERRQ(ierr);
2505   ierr = PetscMalloc((pEnd - pStart) * sizeof(PetscInt*), &tmpPoints);CHKERRQ(ierr);
2506   for (part = pStart; part < pEnd; ++part) {
2507     PetscInt numPoints, nP, numNewPoints, off, p, n = 0;
2508 
2509     PetscHashIClear(h);
2510     ierr = PetscSectionGetDof(origPartSection, part, &numPoints);CHKERRQ(ierr);
2511     ierr = PetscSectionGetOffset(origPartSection, part, &off);CHKERRQ(ierr);
2512     /* Add all existing points to h */
2513     for (p = 0; p < numPoints; ++p) {
2514       const PetscInt point = points[off+p];
2515       PetscHashIAdd(h, point, 1);
2516     }
2517     PetscHashISize(h, nP);
2518     if (nP != numPoints) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Invalid partition has %d points, but only %d were unique", numPoints, nP);
2519     /* Add all points in next BFS level */
2520     /*   TODO We are brute forcing here, but could check the adjacency size to find the boundary */
2521     for (p = 0; p < numPoints; ++p) {
2522       const PetscInt point = points[off+p];
2523       PetscInt       s     = start[point], e = start[point+1], a;
2524 
2525       for (a = s; a < e; ++a) PetscHashIAdd(h, adjacency[a], 1);
2526     }
2527     PetscHashISize(h, numNewPoints);
2528     ierr = PetscSectionSetDof(*partSection, part, numNewPoints);CHKERRQ(ierr);
2529     ierr = PetscMalloc(numNewPoints * sizeof(PetscInt), &tmpPoints[part]);CHKERRQ(ierr);
2530     if (numNewPoints) PetscHashIGetKeys(h, n, tmpPoints[part]); /* Should not need this conditional */
2531     totPoints += numNewPoints;
2532   }
2533   ierr = ISRestoreIndices(origPartition, &points);CHKERRQ(ierr);
2534   PetscHashIDestroy(h);
2535   ierr = PetscSectionSetUp(*partSection);CHKERRQ(ierr);
2536   ierr = PetscMalloc(totPoints * sizeof(PetscInt), &newPoints);CHKERRQ(ierr);
2537   for (part = pStart, q = 0; part < pEnd; ++part) {
2538     PetscInt numPoints, p;
2539 
2540     ierr = PetscSectionGetDof(*partSection, part, &numPoints);CHKERRQ(ierr);
2541     for (p = 0; p < numPoints; ++p, ++q) newPoints[q] = tmpPoints[part][p];
2542     ierr = PetscFree(tmpPoints[part]);CHKERRQ(ierr);
2543   }
2544   ierr = PetscFree(tmpPoints);CHKERRQ(ierr);
2545   ierr = ISCreateGeneral(PetscObjectComm((PetscObject)dm), totPoints, newPoints, PETSC_OWN_POINTER, partition);CHKERRQ(ierr);
2546   PetscFunctionReturn(0);
2547 }
2548 
2549 #undef __FUNCT__
2550 #define __FUNCT__ "DMPlexCreatePartition"
2551 /*
2552   DMPlexCreatePartition - Create a non-overlapping partition of the points at the given height
2553 
2554   Collective on DM
2555 
2556   Input Parameters:
2557   + dm - The DM
2558   . height - The height for points in the partition
2559   - enlarge - Expand each partition with neighbors
2560 
2561   Output Parameters:
2562   + partSection - The PetscSection giving the division of points by partition
2563   . partition - The list of points by partition
2564   . origPartSection - If enlarge is true, the PetscSection giving the division of points before enlarging by partition, otherwise NULL
2565   - origPartition - If enlarge is true, the list of points before enlarging by partition, otherwise NULL
2566 
2567   Level: developer
2568 
2569 .seealso DMPlexDistribute()
2570 */
2571 PetscErrorCode DMPlexCreatePartition(DM dm, const char name[], PetscInt height, PetscBool enlarge, PetscSection *partSection, IS *partition, PetscSection *origPartSection, IS *origPartition)
2572 {
2573   char           partname[1024];
2574   PetscBool      isChaco = PETSC_FALSE, isMetis = PETSC_FALSE, flg;
2575   PetscMPIInt    size;
2576   PetscErrorCode ierr;
2577 
2578   PetscFunctionBegin;
2579   ierr = MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size);CHKERRQ(ierr);
2580 
2581   *origPartSection = NULL;
2582   *origPartition   = NULL;
2583   if (size == 1) {
2584     PetscInt *points;
2585     PetscInt  cStart, cEnd, c;
2586 
2587     ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
2588     ierr = PetscSectionCreate(PetscObjectComm((PetscObject)dm), partSection);CHKERRQ(ierr);
2589     ierr = PetscSectionSetChart(*partSection, 0, size);CHKERRQ(ierr);
2590     ierr = PetscSectionSetDof(*partSection, 0, cEnd-cStart);CHKERRQ(ierr);
2591     ierr = PetscSectionSetUp(*partSection);CHKERRQ(ierr);
2592     ierr = PetscMalloc((cEnd - cStart) * sizeof(PetscInt), &points);CHKERRQ(ierr);
2593     for (c = cStart; c < cEnd; ++c) points[c] = c;
2594     ierr = ISCreateGeneral(PetscObjectComm((PetscObject)dm), cEnd-cStart, points, PETSC_OWN_POINTER, partition);CHKERRQ(ierr);
2595     PetscFunctionReturn(0);
2596   }
2597   ierr = PetscOptionsGetString(((PetscObject) dm)->prefix, "-dm_plex_partitioner", partname, 1024, &flg);CHKERRQ(ierr);
2598   if (flg) name = partname;
2599   if (name) {
2600     ierr = PetscStrcmp(name, "chaco", &isChaco);CHKERRQ(ierr);
2601     ierr = PetscStrcmp(name, "metis", &isMetis);CHKERRQ(ierr);
2602   }
2603   if (height == 0) {
2604     PetscInt  numVertices;
2605     PetscInt *start     = NULL;
2606     PetscInt *adjacency = NULL;
2607 
2608     ierr = DMPlexCreateNeighborCSR(dm, 0, &numVertices, &start, &adjacency);CHKERRQ(ierr);
2609     if (!name || isChaco) {
2610 #if defined(PETSC_HAVE_CHACO)
2611       ierr = DMPlexPartition_Chaco(dm, numVertices, start, adjacency, partSection, partition);CHKERRQ(ierr);
2612 #else
2613       SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Mesh partitioning needs external package support.\nPlease reconfigure with --download-chaco.");
2614 #endif
2615     } else if (isMetis) {
2616 #if defined(PETSC_HAVE_PARMETIS)
2617       ierr = DMPlexPartition_ParMetis(dm, numVertices, start, adjacency, partSection, partition);CHKERRQ(ierr);
2618 #endif
2619     } else SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Unknown mesh partitioning package %s", name);
2620     if (enlarge) {
2621       *origPartSection = *partSection;
2622       *origPartition   = *partition;
2623 
2624       ierr = DMPlexEnlargePartition(dm, start, adjacency, *origPartSection, *origPartition, partSection, partition);CHKERRQ(ierr);
2625     }
2626     ierr = PetscFree(start);CHKERRQ(ierr);
2627     ierr = PetscFree(adjacency);CHKERRQ(ierr);
2628 # if 0
2629   } else if (height == 1) {
2630     /* Build the dual graph for faces and partition the hypergraph */
2631     PetscInt numEdges;
2632 
2633     buildFaceCSRV(mesh, mesh->getFactory()->getNumbering(mesh, mesh->depth()-1), &numEdges, &start, &adjacency, GraphPartitioner::zeroBase());
2634     GraphPartitioner().partition(numEdges, start, adjacency, partition, manager);
2635     destroyCSR(numEdges, start, adjacency);
2636 #endif
2637   } else SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid partition height %D", height);
2638   PetscFunctionReturn(0);
2639 }
2640 
2641 #undef __FUNCT__
2642 #define __FUNCT__ "DMPlexCreatePartitionClosure"
2643 PetscErrorCode DMPlexCreatePartitionClosure(DM dm, PetscSection pointSection, IS pointPartition, PetscSection *section, IS *partition)
2644 {
2645   /* const PetscInt  height = 0; */
2646   const PetscInt *partArray;
2647   PetscInt       *allPoints, *packPoints;
2648   PetscInt        rStart, rEnd, rank, pStart, pEnd, newSize;
2649   PetscErrorCode  ierr;
2650   PetscBT         bt;
2651   PetscSegBuffer  segpack,segpart;
2652 
2653   PetscFunctionBegin;
2654   ierr = PetscSectionGetChart(pointSection, &rStart, &rEnd);CHKERRQ(ierr);
2655   ierr = ISGetIndices(pointPartition, &partArray);CHKERRQ(ierr);
2656   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)dm), section);CHKERRQ(ierr);
2657   ierr = PetscSectionSetChart(*section, rStart, rEnd);CHKERRQ(ierr);
2658   ierr = DMPlexGetChart(dm,&pStart,&pEnd);CHKERRQ(ierr);
2659   ierr = PetscBTCreate(pEnd-pStart,&bt);CHKERRQ(ierr);
2660   ierr = PetscSegBufferCreate(sizeof(PetscInt),1000,&segpack);CHKERRQ(ierr);
2661   ierr = PetscSegBufferCreate(sizeof(PetscInt),1000,&segpart);CHKERRQ(ierr);
2662   for (rank = rStart; rank < rEnd; ++rank) {
2663     PetscInt partSize = 0, numPoints, offset, p, *PETSC_RESTRICT placePoints;
2664 
2665     ierr = PetscSectionGetDof(pointSection, rank, &numPoints);CHKERRQ(ierr);
2666     ierr = PetscSectionGetOffset(pointSection, rank, &offset);CHKERRQ(ierr);
2667     for (p = 0; p < numPoints; ++p) {
2668       PetscInt  point   = partArray[offset+p], closureSize, c;
2669       PetscInt *closure = NULL;
2670 
2671       /* TODO Include support for height > 0 case */
2672       ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
2673       for (c=0; c<closureSize; c++) {
2674         PetscInt cpoint = closure[c*2];
2675         if (!PetscBTLookupSet(bt,cpoint-pStart)) {
2676           PetscInt *PETSC_RESTRICT pt;
2677           partSize++;
2678           ierr = PetscSegBufferGetInts(segpart,1,&pt);CHKERRQ(ierr);
2679           *pt = cpoint;
2680         }
2681       }
2682       ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
2683     }
2684     ierr = PetscSectionSetDof(*section, rank, partSize);CHKERRQ(ierr);
2685     ierr = PetscSegBufferGetInts(segpack,partSize,&placePoints);CHKERRQ(ierr);
2686     ierr = PetscSegBufferExtractTo(segpart,placePoints);CHKERRQ(ierr);
2687     ierr = PetscSortInt(partSize,placePoints);CHKERRQ(ierr);
2688     for (p=0; p<partSize; p++) {ierr = PetscBTClear(bt,placePoints[p]-pStart);CHKERRQ(ierr);}
2689   }
2690   ierr = PetscBTDestroy(&bt);CHKERRQ(ierr);
2691   ierr = PetscSegBufferDestroy(&segpart);CHKERRQ(ierr);
2692 
2693   ierr = PetscSectionSetUp(*section);CHKERRQ(ierr);
2694   ierr = PetscSectionGetStorageSize(*section, &newSize);CHKERRQ(ierr);
2695   ierr = PetscMalloc(newSize * sizeof(PetscInt), &allPoints);CHKERRQ(ierr);
2696 
2697   ierr = PetscSegBufferExtractInPlace(segpack,&packPoints);CHKERRQ(ierr);
2698   for (rank = rStart; rank < rEnd; ++rank) {
2699     PetscInt numPoints, offset;
2700 
2701     ierr = PetscSectionGetDof(*section, rank, &numPoints);CHKERRQ(ierr);
2702     ierr = PetscSectionGetOffset(*section, rank, &offset);CHKERRQ(ierr);
2703     ierr = PetscMemcpy(&allPoints[offset], packPoints, numPoints * sizeof(PetscInt));CHKERRQ(ierr);
2704     packPoints += numPoints;
2705   }
2706 
2707   ierr = PetscSegBufferDestroy(&segpack);CHKERRQ(ierr);
2708   ierr = ISRestoreIndices(pointPartition, &partArray);CHKERRQ(ierr);
2709   ierr = ISCreateGeneral(PetscObjectComm((PetscObject)dm), newSize, allPoints, PETSC_OWN_POINTER, partition);CHKERRQ(ierr);
2710   PetscFunctionReturn(0);
2711 }
2712 
2713 #undef __FUNCT__
2714 #define __FUNCT__ "DMPlexDistributeField"
2715 /*@
2716   DMPlexDistributeField - Distribute field data to match a given PetscSF, usually the SF from mesh distribution
2717 
2718   Collective on DM
2719 
2720   Input Parameters:
2721 + dm - The DMPlex object
2722 . pointSF - The PetscSF describing the communication pattern
2723 . originalSection - The PetscSection for existing data layout
2724 - originalVec - The existing data
2725 
2726   Output Parameters:
2727 + newSection - The PetscSF describing the new data layout
2728 - newVec - The new data
2729 
2730   Level: developer
2731 
2732 .seealso: DMPlexDistribute(), DMPlexDistributeData()
2733 @*/
2734 PetscErrorCode DMPlexDistributeField(DM dm, PetscSF pointSF, PetscSection originalSection, Vec originalVec, PetscSection newSection, Vec newVec)
2735 {
2736   PetscSF        fieldSF;
2737   PetscInt      *remoteOffsets, fieldSize;
2738   PetscScalar   *originalValues, *newValues;
2739   PetscErrorCode ierr;
2740 
2741   PetscFunctionBegin;
2742   ierr = PetscSFDistributeSection(pointSF, originalSection, &remoteOffsets, newSection);CHKERRQ(ierr);
2743 
2744   ierr = PetscSectionGetStorageSize(newSection, &fieldSize);CHKERRQ(ierr);
2745   ierr = VecSetSizes(newVec, fieldSize, PETSC_DETERMINE);CHKERRQ(ierr);
2746   ierr = VecSetFromOptions(newVec);CHKERRQ(ierr);
2747 
2748   ierr = VecGetArray(originalVec, &originalValues);CHKERRQ(ierr);
2749   ierr = VecGetArray(newVec, &newValues);CHKERRQ(ierr);
2750   ierr = PetscSFCreateSectionSF(pointSF, originalSection, remoteOffsets, newSection, &fieldSF);CHKERRQ(ierr);
2751   ierr = PetscSFBcastBegin(fieldSF, MPIU_SCALAR, originalValues, newValues);CHKERRQ(ierr);
2752   ierr = PetscSFBcastEnd(fieldSF, MPIU_SCALAR, originalValues, newValues);CHKERRQ(ierr);
2753   ierr = PetscSFDestroy(&fieldSF);CHKERRQ(ierr);
2754   ierr = VecRestoreArray(newVec, &newValues);CHKERRQ(ierr);
2755   ierr = VecRestoreArray(originalVec, &originalValues);CHKERRQ(ierr);
2756   PetscFunctionReturn(0);
2757 }
2758 
2759 #undef __FUNCT__
2760 #define __FUNCT__ "DMPlexDistributeData"
2761 /*@
2762   DMPlexDistributeData - Distribute field data to match a given PetscSF, usually the SF from mesh distribution
2763 
2764   Collective on DM
2765 
2766   Input Parameters:
2767 + dm - The DMPlex object
2768 . pointSF - The PetscSF describing the communication pattern
2769 . originalSection - The PetscSection for existing data layout
2770 . datatype - The type of data
2771 - originalData - The existing data
2772 
2773   Output Parameters:
2774 + newSection - The PetscSF describing the new data layout
2775 - newData - The new data
2776 
2777   Level: developer
2778 
2779 .seealso: DMPlexDistribute(), DMPlexDistributeField()
2780 @*/
2781 PetscErrorCode DMPlexDistributeData(DM dm, PetscSF pointSF, PetscSection originalSection, MPI_Datatype datatype, void *originalData, PetscSection newSection, void **newData)
2782 {
2783   PetscSF        fieldSF;
2784   PetscInt      *remoteOffsets, fieldSize;
2785   PetscMPIInt    dataSize;
2786   PetscErrorCode ierr;
2787 
2788   PetscFunctionBegin;
2789   ierr = PetscSFDistributeSection(pointSF, originalSection, &remoteOffsets, newSection);CHKERRQ(ierr);
2790 
2791   ierr = PetscSectionGetStorageSize(newSection, &fieldSize);CHKERRQ(ierr);
2792   ierr = MPI_Type_size(datatype, &dataSize);CHKERRQ(ierr);
2793   ierr = PetscMalloc(fieldSize * dataSize, newData);CHKERRQ(ierr);
2794 
2795   ierr = PetscSFCreateSectionSF(pointSF, originalSection, remoteOffsets, newSection, &fieldSF);CHKERRQ(ierr);
2796   ierr = PetscSFBcastBegin(fieldSF, datatype, originalData, *newData);CHKERRQ(ierr);
2797   ierr = PetscSFBcastEnd(fieldSF, datatype, originalData, *newData);CHKERRQ(ierr);
2798   ierr = PetscSFDestroy(&fieldSF);CHKERRQ(ierr);
2799   PetscFunctionReturn(0);
2800 }
2801 
2802 #undef __FUNCT__
2803 #define __FUNCT__ "DMPlexDistribute"
2804 /*@C
2805   DMPlexDistribute - Distributes the mesh and any associated sections.
2806 
2807   Not Collective
2808 
2809   Input Parameter:
2810 + dm  - The original DMPlex object
2811 . partitioner - The partitioning package, or NULL for the default
2812 - overlap - The overlap of partitions, 0 is the default
2813 
2814   Output Parameter:
2815 + sf - The PetscSF used for point distribution
2816 - parallelMesh - The distributed DMPlex object, or NULL
2817 
2818   Note: If the mesh was not distributed, the return value is NULL
2819 
2820   Level: intermediate
2821 
2822 .keywords: mesh, elements
2823 .seealso: DMPlexCreate(), DMPlexDistributeByFace()
2824 @*/
2825 PetscErrorCode DMPlexDistribute(DM dm, const char partitioner[], PetscInt overlap, PetscSF *sf, DM *dmParallel)
2826 {
2827   DM_Plex               *mesh   = (DM_Plex*) dm->data, *pmesh;
2828   MPI_Comm               comm;
2829   const PetscInt         height = 0;
2830   PetscInt               dim, numRemoteRanks;
2831   IS                     origCellPart,        cellPart,        part;
2832   PetscSection           origCellPartSection, cellPartSection, partSection;
2833   PetscSFNode           *remoteRanks;
2834   PetscSF                partSF, pointSF, coneSF;
2835   ISLocalToGlobalMapping renumbering;
2836   PetscSection           originalConeSection, newConeSection;
2837   PetscInt              *remoteOffsets;
2838   PetscInt              *cones, *newCones, newConesSize;
2839   PetscBool              flg;
2840   PetscMPIInt            rank, numProcs, p;
2841   PetscErrorCode         ierr;
2842 
2843   PetscFunctionBegin;
2844   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2845   if (sf) PetscValidPointer(sf,4);
2846   PetscValidPointer(dmParallel,5);
2847 
2848   ierr = PetscLogEventBegin(DMPLEX_Distribute,dm,0,0,0);CHKERRQ(ierr);
2849   ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr);
2850   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
2851   ierr = MPI_Comm_size(comm, &numProcs);CHKERRQ(ierr);
2852 
2853   *dmParallel = NULL;
2854   if (numProcs == 1) PetscFunctionReturn(0);
2855 
2856   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
2857   /* Create cell partition - We need to rewrite to use IS, use the MatPartition stuff */
2858   ierr = PetscLogEventBegin(DMPLEX_Partition,dm,0,0,0);CHKERRQ(ierr);
2859   if (overlap > 1) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Overlap > 1 not yet implemented");
2860   ierr = DMPlexCreatePartition(dm, partitioner, height, overlap > 0 ? PETSC_TRUE : PETSC_FALSE, &cellPartSection, &cellPart, &origCellPartSection, &origCellPart);CHKERRQ(ierr);
2861   /* Create SF assuming a serial partition for all processes: Could check for IS length here */
2862   if (!rank) numRemoteRanks = numProcs;
2863   else       numRemoteRanks = 0;
2864   ierr = PetscMalloc(numRemoteRanks * sizeof(PetscSFNode), &remoteRanks);CHKERRQ(ierr);
2865   for (p = 0; p < numRemoteRanks; ++p) {
2866     remoteRanks[p].rank  = p;
2867     remoteRanks[p].index = 0;
2868   }
2869   ierr = PetscSFCreate(comm, &partSF);CHKERRQ(ierr);
2870   ierr = PetscSFSetGraph(partSF, 1, numRemoteRanks, NULL, PETSC_OWN_POINTER, remoteRanks, PETSC_OWN_POINTER);CHKERRQ(ierr);
2871   ierr = PetscOptionsHasName(((PetscObject) dm)->prefix, "-partition_view", &flg);CHKERRQ(ierr);
2872   if (flg) {
2873     ierr = PetscPrintf(comm, "Cell Partition:\n");CHKERRQ(ierr);
2874     ierr = PetscSectionView(cellPartSection, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
2875     ierr = ISView(cellPart, NULL);CHKERRQ(ierr);
2876     if (origCellPart) {
2877       ierr = PetscPrintf(comm, "Original Cell Partition:\n");CHKERRQ(ierr);
2878       ierr = PetscSectionView(origCellPartSection, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
2879       ierr = ISView(origCellPart, NULL);CHKERRQ(ierr);
2880     }
2881     ierr = PetscSFView(partSF, NULL);CHKERRQ(ierr);
2882   }
2883   /* Close the partition over the mesh */
2884   ierr = DMPlexCreatePartitionClosure(dm, cellPartSection, cellPart, &partSection, &part);CHKERRQ(ierr);
2885   ierr = ISDestroy(&cellPart);CHKERRQ(ierr);
2886   ierr = PetscSectionDestroy(&cellPartSection);CHKERRQ(ierr);
2887   /* Create new mesh */
2888   ierr  = DMPlexCreate(comm, dmParallel);CHKERRQ(ierr);
2889   ierr  = DMPlexSetDimension(*dmParallel, dim);CHKERRQ(ierr);
2890   ierr  = PetscObjectSetName((PetscObject) *dmParallel, "Parallel Mesh");CHKERRQ(ierr);
2891   pmesh = (DM_Plex*) (*dmParallel)->data;
2892   /* Distribute sieve points and the global point numbering (replaces creating remote bases) */
2893   ierr = PetscSFConvertPartition(partSF, partSection, part, &renumbering, &pointSF);CHKERRQ(ierr);
2894   if (flg) {
2895     ierr = PetscPrintf(comm, "Point Partition:\n");CHKERRQ(ierr);
2896     ierr = PetscSectionView(partSection, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
2897     ierr = ISView(part, NULL);CHKERRQ(ierr);
2898     ierr = PetscSFView(pointSF, NULL);CHKERRQ(ierr);
2899     ierr = PetscPrintf(comm, "Point Renumbering after partition:\n");CHKERRQ(ierr);
2900     ierr = ISLocalToGlobalMappingView(renumbering, NULL);CHKERRQ(ierr);
2901   }
2902   ierr = PetscLogEventEnd(DMPLEX_Partition,dm,0,0,0);CHKERRQ(ierr);
2903   /* Distribute cone section */
2904   ierr = DMPlexGetConeSection(dm, &originalConeSection);CHKERRQ(ierr);
2905   ierr = DMPlexGetConeSection(*dmParallel, &newConeSection);CHKERRQ(ierr);
2906   ierr = PetscSFDistributeSection(pointSF, originalConeSection, &remoteOffsets, newConeSection);CHKERRQ(ierr);
2907   ierr = DMSetUp(*dmParallel);CHKERRQ(ierr);
2908   {
2909     PetscInt pStart, pEnd, p;
2910 
2911     ierr = PetscSectionGetChart(newConeSection, &pStart, &pEnd);CHKERRQ(ierr);
2912     for (p = pStart; p < pEnd; ++p) {
2913       PetscInt coneSize;
2914       ierr               = PetscSectionGetDof(newConeSection, p, &coneSize);CHKERRQ(ierr);
2915       pmesh->maxConeSize = PetscMax(pmesh->maxConeSize, coneSize);
2916     }
2917   }
2918   /* Communicate and renumber cones */
2919   ierr = PetscSFCreateSectionSF(pointSF, originalConeSection, remoteOffsets, newConeSection, &coneSF);CHKERRQ(ierr);
2920   ierr = DMPlexGetCones(dm, &cones);CHKERRQ(ierr);
2921   ierr = DMPlexGetCones(*dmParallel, &newCones);CHKERRQ(ierr);
2922   ierr = PetscSFBcastBegin(coneSF, MPIU_INT, cones, newCones);CHKERRQ(ierr);
2923   ierr = PetscSFBcastEnd(coneSF, MPIU_INT, cones, newCones);CHKERRQ(ierr);
2924   ierr = PetscSectionGetStorageSize(newConeSection, &newConesSize);CHKERRQ(ierr);
2925   ierr = ISGlobalToLocalMappingApply(renumbering, IS_GTOLM_MASK, newConesSize, newCones, NULL, newCones);CHKERRQ(ierr);
2926   ierr = PetscOptionsHasName(((PetscObject) dm)->prefix, "-cones_view", &flg);CHKERRQ(ierr);
2927   if (flg) {
2928     ierr = PetscPrintf(comm, "Serial Cone Section:\n");CHKERRQ(ierr);
2929     ierr = PetscSectionView(originalConeSection, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
2930     ierr = PetscPrintf(comm, "Parallel Cone Section:\n");CHKERRQ(ierr);
2931     ierr = PetscSectionView(newConeSection, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
2932     ierr = PetscSFView(coneSF, NULL);CHKERRQ(ierr);
2933   }
2934   ierr = DMPlexGetConeOrientations(dm, &cones);CHKERRQ(ierr);
2935   ierr = DMPlexGetConeOrientations(*dmParallel, &newCones);CHKERRQ(ierr);
2936   ierr = PetscSFBcastBegin(coneSF, MPIU_INT, cones, newCones);CHKERRQ(ierr);
2937   ierr = PetscSFBcastEnd(coneSF, MPIU_INT, cones, newCones);CHKERRQ(ierr);
2938   ierr = PetscSFDestroy(&coneSF);CHKERRQ(ierr);
2939   /* Create supports and stratify sieve */
2940   {
2941     PetscInt pStart, pEnd;
2942 
2943     ierr = PetscSectionGetChart(pmesh->coneSection, &pStart, &pEnd);CHKERRQ(ierr);
2944     ierr = PetscSectionSetChart(pmesh->supportSection, pStart, pEnd);CHKERRQ(ierr);
2945   }
2946   ierr = DMPlexSymmetrize(*dmParallel);CHKERRQ(ierr);
2947   ierr = DMPlexStratify(*dmParallel);CHKERRQ(ierr);
2948   /* Distribute Coordinates */
2949   {
2950     PetscSection originalCoordSection, newCoordSection;
2951     Vec          originalCoordinates, newCoordinates;
2952     const char  *name;
2953 
2954     ierr = DMPlexGetCoordinateSection(dm, &originalCoordSection);CHKERRQ(ierr);
2955     ierr = DMPlexGetCoordinateSection(*dmParallel, &newCoordSection);CHKERRQ(ierr);
2956     ierr = DMGetCoordinatesLocal(dm, &originalCoordinates);CHKERRQ(ierr);
2957     ierr = VecCreate(comm, &newCoordinates);CHKERRQ(ierr);
2958     ierr = PetscObjectGetName((PetscObject) originalCoordinates, &name);CHKERRQ(ierr);
2959     ierr = PetscObjectSetName((PetscObject) newCoordinates, name);CHKERRQ(ierr);
2960 
2961     ierr = DMPlexDistributeField(dm, pointSF, originalCoordSection, originalCoordinates, newCoordSection, newCoordinates);CHKERRQ(ierr);
2962     ierr = DMSetCoordinatesLocal(*dmParallel, newCoordinates);CHKERRQ(ierr);
2963     ierr = VecDestroy(&newCoordinates);CHKERRQ(ierr);
2964   }
2965   /* Distribute labels */
2966   ierr = PetscLogEventBegin(DMPLEX_DistributeLabels,dm,0,0,0);CHKERRQ(ierr);
2967   {
2968     DMLabel  next      = mesh->labels, newNext = pmesh->labels;
2969     PetscInt numLabels = 0, l;
2970 
2971     /* Bcast number of labels */
2972     while (next) {
2973       ++numLabels; next = next->next;
2974     }
2975     ierr = MPI_Bcast(&numLabels, 1, MPIU_INT, 0, comm);CHKERRQ(ierr);
2976     next = mesh->labels;
2977     for (l = 0; l < numLabels; ++l) {
2978       DMLabel         newLabel;
2979       const PetscInt *partArray;
2980       char           *name;
2981       PetscInt       *stratumSizes = NULL, *points = NULL;
2982       PetscMPIInt    *sendcnts     = NULL, *offsets = NULL, *displs = NULL;
2983       PetscInt        nameSize, s, p, proc;
2984       PetscBool       isdepth;
2985       size_t          len = 0;
2986 
2987       /* Bcast name (could filter for no points) */
2988       if (!rank) {ierr = PetscStrlen(next->name, &len);CHKERRQ(ierr);}
2989       nameSize = len;
2990       ierr     = MPI_Bcast(&nameSize, 1, MPIU_INT, 0, comm);CHKERRQ(ierr);
2991       ierr     = PetscMalloc(nameSize+1, &name);CHKERRQ(ierr);
2992       if (!rank) {ierr = PetscMemcpy(name, next->name, nameSize+1);CHKERRQ(ierr);}
2993       ierr = MPI_Bcast(name, nameSize+1, MPI_CHAR, 0, comm);CHKERRQ(ierr);
2994       ierr = PetscStrcmp(name, "depth", &isdepth);CHKERRQ(ierr);
2995       if (isdepth) {            /* skip because "depth" is not distributed */
2996         ierr = PetscFree(name);CHKERRQ(ierr);
2997         if (!rank) next = next->next;
2998         continue;
2999       }
3000       ierr           = PetscNew(struct _n_DMLabel, &newLabel);CHKERRQ(ierr);
3001       newLabel->name = name;
3002       /* Bcast numStrata (could filter for no points in stratum) */
3003       if (!rank) newLabel->numStrata = next->numStrata;
3004       ierr = MPI_Bcast(&newLabel->numStrata, 1, MPIU_INT, 0, comm);CHKERRQ(ierr);
3005       ierr = PetscMalloc3(newLabel->numStrata,PetscInt,&newLabel->stratumValues,
3006                           newLabel->numStrata,PetscInt,&newLabel->stratumSizes,
3007                           newLabel->numStrata+1,PetscInt,&newLabel->stratumOffsets);CHKERRQ(ierr);
3008       /* Bcast stratumValues (could filter for no points in stratum) */
3009       if (!rank) {ierr = PetscMemcpy(newLabel->stratumValues, next->stratumValues, next->numStrata * sizeof(PetscInt));CHKERRQ(ierr);}
3010       ierr = MPI_Bcast(newLabel->stratumValues, newLabel->numStrata, MPIU_INT, 0, comm);CHKERRQ(ierr);
3011       /* Find size on each process and Scatter
3012            we use the fact that both the stratum points and partArray are sorted */
3013       if (!rank) {
3014         ierr = ISGetIndices(part, &partArray);CHKERRQ(ierr);
3015         ierr = PetscMalloc(numProcs*next->numStrata * sizeof(PetscInt), &stratumSizes);CHKERRQ(ierr);
3016         ierr = PetscMemzero(stratumSizes, numProcs*next->numStrata * sizeof(PetscInt));CHKERRQ(ierr);
3017         /* TODO We should switch to using binary search if the label is a lot smaller than partitions */
3018         for (proc = 0; proc < numProcs; ++proc) {
3019           PetscInt dof, off;
3020 
3021           ierr = PetscSectionGetDof(partSection, proc, &dof);CHKERRQ(ierr);
3022           ierr = PetscSectionGetOffset(partSection, proc, &off);CHKERRQ(ierr);
3023           for (s = 0; s < next->numStrata; ++s) {
3024             PetscInt lStart = next->stratumOffsets[s], lEnd = next->stratumOffsets[s]+next->stratumSizes[s];
3025             PetscInt pStart = off,                     pEnd = off+dof;
3026 
3027             while (pStart < pEnd && lStart < lEnd) {
3028               if (partArray[pStart] > next->points[lStart]) {
3029                 ++lStart;
3030               } else if (next->points[lStart] > partArray[pStart]) {
3031                 ++pStart;
3032               } else {
3033                 ++stratumSizes[proc*next->numStrata+s];
3034                 ++pStart; ++lStart;
3035               }
3036             }
3037           }
3038         }
3039         ierr = ISRestoreIndices(part, &partArray);CHKERRQ(ierr);
3040       }
3041       ierr = MPI_Scatter(stratumSizes, newLabel->numStrata, MPIU_INT, newLabel->stratumSizes, newLabel->numStrata, MPIU_INT, 0, comm);CHKERRQ(ierr);
3042       /* Calculate stratumOffsets */
3043       newLabel->stratumOffsets[0] = 0;
3044       for (s = 0; s < newLabel->numStrata; ++s) {
3045         newLabel->stratumOffsets[s+1] = newLabel->stratumSizes[s] + newLabel->stratumOffsets[s];
3046       }
3047       /* Pack points and Scatter */
3048       if (!rank) {
3049         ierr = PetscMalloc3(numProcs,PetscMPIInt,&sendcnts,numProcs,PetscMPIInt,&offsets,numProcs+1,PetscMPIInt,&displs);CHKERRQ(ierr);
3050         displs[0] = 0;
3051         for (p = 0; p < numProcs; ++p) {
3052           sendcnts[p] = 0;
3053           for (s = 0; s < next->numStrata; ++s) {
3054             sendcnts[p] += stratumSizes[p*next->numStrata+s];
3055           }
3056           offsets[p]  = displs[p];
3057           displs[p+1] = displs[p] + sendcnts[p];
3058         }
3059         ierr = PetscMalloc(displs[numProcs] * sizeof(PetscInt), &points);CHKERRQ(ierr);
3060         /* TODO We should switch to using binary search if the label is a lot smaller than partitions */
3061         for (proc = 0; proc < numProcs; ++proc) {
3062           PetscInt dof, off;
3063 
3064           ierr = PetscSectionGetDof(partSection, proc, &dof);CHKERRQ(ierr);
3065           ierr = PetscSectionGetOffset(partSection, proc, &off);CHKERRQ(ierr);
3066           for (s = 0; s < next->numStrata; ++s) {
3067             PetscInt lStart = next->stratumOffsets[s], lEnd = next->stratumOffsets[s]+next->stratumSizes[s];
3068             PetscInt pStart = off,                     pEnd = off+dof;
3069 
3070             while (pStart < pEnd && lStart < lEnd) {
3071               if (partArray[pStart] > next->points[lStart]) {
3072                 ++lStart;
3073               } else if (next->points[lStart] > partArray[pStart]) {
3074                 ++pStart;
3075               } else {
3076                 points[offsets[proc]++] = next->points[lStart];
3077                 ++pStart; ++lStart;
3078               }
3079             }
3080           }
3081         }
3082       }
3083       ierr = PetscMalloc(newLabel->stratumOffsets[newLabel->numStrata] * sizeof(PetscInt), &newLabel->points);CHKERRQ(ierr);
3084       ierr = MPI_Scatterv(points, sendcnts, displs, MPIU_INT, newLabel->points, newLabel->stratumOffsets[newLabel->numStrata], MPIU_INT, 0, comm);CHKERRQ(ierr);
3085       ierr = PetscFree(points);CHKERRQ(ierr);
3086       ierr = PetscFree3(sendcnts,offsets,displs);CHKERRQ(ierr);
3087       ierr = PetscFree(stratumSizes);CHKERRQ(ierr);
3088       /* Renumber points */
3089       ierr = ISGlobalToLocalMappingApply(renumbering, IS_GTOLM_MASK, newLabel->stratumOffsets[newLabel->numStrata], newLabel->points, NULL, newLabel->points);CHKERRQ(ierr);
3090       /* Sort points */
3091       for (s = 0; s < newLabel->numStrata; ++s) {
3092         ierr = PetscSortInt(newLabel->stratumSizes[s], &newLabel->points[newLabel->stratumOffsets[s]]);CHKERRQ(ierr);
3093       }
3094       /* Insert into list */
3095       if (newNext) newNext->next = newLabel;
3096       else pmesh->labels = newLabel;
3097       newNext = newLabel;
3098       if (!rank) next = next->next;
3099     }
3100   }
3101   ierr = PetscLogEventEnd(DMPLEX_DistributeLabels,dm,0,0,0);CHKERRQ(ierr);
3102   /* Setup hybrid structure */
3103   {
3104     const PetscInt *gpoints;
3105     PetscInt        depth, n, d;
3106 
3107     for (d = 0; d <= dim; ++d) {pmesh->hybridPointMax[d] = mesh->hybridPointMax[d];}
3108     ierr = MPI_Bcast(pmesh->hybridPointMax, dim+1, MPIU_INT, 0, comm);CHKERRQ(ierr);
3109     ierr = ISLocalToGlobalMappingGetSize(renumbering, &n);CHKERRQ(ierr);
3110     ierr = ISLocalToGlobalMappingGetIndices(renumbering, &gpoints);CHKERRQ(ierr);
3111     ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3112     for (d = 0; d <= dim; ++d) {
3113       PetscInt pmax = pmesh->hybridPointMax[d], newmax = 0, pEnd, stratum[2], p;
3114 
3115       if (pmax < 0) continue;
3116       ierr = DMPlexGetDepthStratum(dm, d > depth ? depth : d, &stratum[0], &stratum[1]);CHKERRQ(ierr);
3117       /* This mesh is not interpolated, so there is still a problem here */
3118       ierr = DMPlexGetDepthStratum(*dmParallel, d > 0 ? 1 : d, NULL, &pEnd);CHKERRQ(ierr);
3119       ierr = MPI_Bcast(stratum, 2, MPIU_INT, 0, comm);CHKERRQ(ierr);
3120       for (p = 0; p < n; ++p) {
3121         const PetscInt point = gpoints[p];
3122 
3123         if ((point >= stratum[0]) && (point < stratum[1]) && (point >= pmax)) ++newmax;
3124       }
3125       if (newmax > 0) pmesh->hybridPointMax[d] = pEnd - newmax;
3126       else            pmesh->hybridPointMax[d] = -1;
3127     }
3128     ierr = ISLocalToGlobalMappingRestoreIndices(renumbering, &gpoints);CHKERRQ(ierr);
3129   }
3130   /* Cleanup Partition */
3131   ierr = ISLocalToGlobalMappingDestroy(&renumbering);CHKERRQ(ierr);
3132   ierr = PetscSFDestroy(&partSF);CHKERRQ(ierr);
3133   ierr = PetscSectionDestroy(&partSection);CHKERRQ(ierr);
3134   ierr = ISDestroy(&part);CHKERRQ(ierr);
3135   /* Create point SF for parallel mesh */
3136   ierr = PetscLogEventBegin(DMPLEX_DistributeSF,dm,0,0,0);CHKERRQ(ierr);
3137   {
3138     const PetscInt *leaves;
3139     PetscSFNode    *remotePoints, *rowners, *lowners;
3140     PetscInt        numRoots, numLeaves, numGhostPoints = 0, p, gp, *ghostPoints;
3141     PetscInt        pStart, pEnd;
3142 
3143     ierr = DMPlexGetChart(*dmParallel, &pStart, &pEnd);CHKERRQ(ierr);
3144     ierr = PetscSFGetGraph(pointSF, &numRoots, &numLeaves, &leaves, NULL);CHKERRQ(ierr);
3145     ierr = PetscMalloc2(numRoots,PetscSFNode,&rowners,numLeaves,PetscSFNode,&lowners);CHKERRQ(ierr);
3146     for (p=0; p<numRoots; p++) {
3147       rowners[p].rank  = -1;
3148       rowners[p].index = -1;
3149     }
3150     if (origCellPart) {
3151       /* Make sure cells in the original partition are not assigned to other procs */
3152       const PetscInt *origCells;
3153 
3154       ierr = ISGetIndices(origCellPart, &origCells);CHKERRQ(ierr);
3155       for (p = 0; p < numProcs; ++p) {
3156         PetscInt dof, off, d;
3157 
3158         ierr = PetscSectionGetDof(origCellPartSection, p, &dof);CHKERRQ(ierr);
3159         ierr = PetscSectionGetOffset(origCellPartSection, p, &off);CHKERRQ(ierr);
3160         for (d = off; d < off+dof; ++d) {
3161           rowners[origCells[d]].rank = p;
3162         }
3163       }
3164       ierr = ISRestoreIndices(origCellPart, &origCells);CHKERRQ(ierr);
3165     }
3166     ierr = ISDestroy(&origCellPart);CHKERRQ(ierr);
3167     ierr = PetscSectionDestroy(&origCellPartSection);CHKERRQ(ierr);
3168 
3169     ierr = PetscSFBcastBegin(pointSF, MPIU_2INT, rowners, lowners);CHKERRQ(ierr);
3170     ierr = PetscSFBcastEnd(pointSF, MPIU_2INT, rowners, lowners);CHKERRQ(ierr);
3171     for (p = 0; p < numLeaves; ++p) {
3172       if (lowners[p].rank < 0 || lowners[p].rank == rank) { /* Either put in a bid or we know we own it */
3173         lowners[p].rank  = rank;
3174         lowners[p].index = leaves ? leaves[p] : p;
3175       } else if (lowners[p].rank >= 0) { /* Point already claimed so flag so that MAXLOC does not listen to us */
3176         lowners[p].rank  = -2;
3177         lowners[p].index = -2;
3178       }
3179     }
3180     for (p=0; p<numRoots; p++) { /* Root must not participate in the rediction, flag so that MAXLOC does not use */
3181       rowners[p].rank  = -3;
3182       rowners[p].index = -3;
3183     }
3184     ierr = PetscSFReduceBegin(pointSF, MPIU_2INT, lowners, rowners, MPI_MAXLOC);CHKERRQ(ierr);
3185     ierr = PetscSFReduceEnd(pointSF, MPIU_2INT, lowners, rowners, MPI_MAXLOC);CHKERRQ(ierr);
3186     ierr = PetscSFBcastBegin(pointSF, MPIU_2INT, rowners, lowners);CHKERRQ(ierr);
3187     ierr = PetscSFBcastEnd(pointSF, MPIU_2INT, rowners, lowners);CHKERRQ(ierr);
3188     for (p = 0; p < numLeaves; ++p) {
3189       if (lowners[p].rank < 0 || lowners[p].index < 0) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Cell partition corrupt: point not claimed");
3190       if (lowners[p].rank != rank) ++numGhostPoints;
3191     }
3192     ierr = PetscMalloc(numGhostPoints * sizeof(PetscInt),    &ghostPoints);CHKERRQ(ierr);
3193     ierr = PetscMalloc(numGhostPoints * sizeof(PetscSFNode), &remotePoints);CHKERRQ(ierr);
3194     for (p = 0, gp = 0; p < numLeaves; ++p) {
3195       if (lowners[p].rank != rank) {
3196         ghostPoints[gp]        = leaves ? leaves[p] : p;
3197         remotePoints[gp].rank  = lowners[p].rank;
3198         remotePoints[gp].index = lowners[p].index;
3199         ++gp;
3200       }
3201     }
3202     ierr = PetscFree2(rowners,lowners);CHKERRQ(ierr);
3203     ierr = PetscSFSetGraph((*dmParallel)->sf, pEnd - pStart, numGhostPoints, ghostPoints, PETSC_OWN_POINTER, remotePoints, PETSC_OWN_POINTER);CHKERRQ(ierr);
3204     ierr = PetscSFSetFromOptions((*dmParallel)->sf);CHKERRQ(ierr);
3205   }
3206   ierr = PetscLogEventEnd(DMPLEX_DistributeSF,dm,0,0,0);CHKERRQ(ierr);
3207   /* Cleanup */
3208   if (sf) {*sf = pointSF;}
3209   else    {ierr = PetscSFDestroy(&pointSF);CHKERRQ(ierr);}
3210   ierr = DMSetFromOptions(*dmParallel);CHKERRQ(ierr);
3211   ierr = PetscLogEventEnd(DMPLEX_Distribute,dm,0,0,0);CHKERRQ(ierr);
3212   PetscFunctionReturn(0);
3213 }
3214 
3215 #undef __FUNCT__
3216 #define __FUNCT__ "DMPlexInvertCell"
3217 /*@C
3218   DMPlexInvertCell - This flips tetrahedron and hexahedron orientation since Plex stores them internally with outward normals. Other cells are left untouched.
3219 
3220   Input Parameters:
3221 + numCorners - The number of vertices in a cell
3222 - cone - The incoming cone
3223 
3224   Output Parameter:
3225 . cone - The inverted cone (in-place)
3226 
3227   Level: developer
3228 
3229 .seealso: DMPlexGenerate()
3230 @*/
3231 PetscErrorCode DMPlexInvertCell(PetscInt dim, PetscInt numCorners, int cone[])
3232 {
3233   int tmpc;
3234 
3235   PetscFunctionBegin;
3236   if (dim != 3) PetscFunctionReturn(0);
3237   switch (numCorners) {
3238   case 4:
3239     tmpc    = cone[0];
3240     cone[0] = cone[1];
3241     cone[1] = tmpc;
3242     break;
3243   case 8:
3244     tmpc    = cone[1];
3245     cone[1] = cone[3];
3246     cone[3] = tmpc;
3247     break;
3248   default: break;
3249   }
3250   PetscFunctionReturn(0);
3251 }
3252 
3253 #undef __FUNCT__
3254 #define __FUNCT__ "DMPlexInvertCells_Internal"
3255 /* This is to fix the tetrahedron orientation from TetGen */
3256 PETSC_UNUSED static PetscErrorCode DMPlexInvertCells_Internal(PetscInt dim, PetscInt numCells, PetscInt numCorners, int cells[])
3257 {
3258   PetscInt       bound = numCells*numCorners, coff;
3259   PetscErrorCode ierr;
3260 
3261   PetscFunctionBegin;
3262   for (coff = 0; coff < bound; coff += numCorners) {
3263     ierr = DMPlexInvertCell(dim, numCorners, &cells[coff]);CHKERRQ(ierr);
3264   }
3265   PetscFunctionReturn(0);
3266 }
3267 
3268 #if defined(PETSC_HAVE_TRIANGLE)
3269 #include <triangle.h>
3270 
3271 #undef __FUNCT__
3272 #define __FUNCT__ "InitInput_Triangle"
3273 PetscErrorCode InitInput_Triangle(struct triangulateio *inputCtx)
3274 {
3275   PetscFunctionBegin;
3276   inputCtx->numberofpoints             = 0;
3277   inputCtx->numberofpointattributes    = 0;
3278   inputCtx->pointlist                  = NULL;
3279   inputCtx->pointattributelist         = NULL;
3280   inputCtx->pointmarkerlist            = NULL;
3281   inputCtx->numberofsegments           = 0;
3282   inputCtx->segmentlist                = NULL;
3283   inputCtx->segmentmarkerlist          = NULL;
3284   inputCtx->numberoftriangleattributes = 0;
3285   inputCtx->trianglelist               = NULL;
3286   inputCtx->numberofholes              = 0;
3287   inputCtx->holelist                   = NULL;
3288   inputCtx->numberofregions            = 0;
3289   inputCtx->regionlist                 = NULL;
3290   PetscFunctionReturn(0);
3291 }
3292 
3293 #undef __FUNCT__
3294 #define __FUNCT__ "InitOutput_Triangle"
3295 PetscErrorCode InitOutput_Triangle(struct triangulateio *outputCtx)
3296 {
3297   PetscFunctionBegin;
3298   outputCtx->numberofpoints        = 0;
3299   outputCtx->pointlist             = NULL;
3300   outputCtx->pointattributelist    = NULL;
3301   outputCtx->pointmarkerlist       = NULL;
3302   outputCtx->numberoftriangles     = 0;
3303   outputCtx->trianglelist          = NULL;
3304   outputCtx->triangleattributelist = NULL;
3305   outputCtx->neighborlist          = NULL;
3306   outputCtx->segmentlist           = NULL;
3307   outputCtx->segmentmarkerlist     = NULL;
3308   outputCtx->numberofedges         = 0;
3309   outputCtx->edgelist              = NULL;
3310   outputCtx->edgemarkerlist        = NULL;
3311   PetscFunctionReturn(0);
3312 }
3313 
3314 #undef __FUNCT__
3315 #define __FUNCT__ "FiniOutput_Triangle"
3316 PetscErrorCode FiniOutput_Triangle(struct triangulateio *outputCtx)
3317 {
3318   PetscFunctionBegin;
3319   free(outputCtx->pointmarkerlist);
3320   free(outputCtx->edgelist);
3321   free(outputCtx->edgemarkerlist);
3322   free(outputCtx->trianglelist);
3323   free(outputCtx->neighborlist);
3324   PetscFunctionReturn(0);
3325 }
3326 
3327 #undef __FUNCT__
3328 #define __FUNCT__ "DMPlexGenerate_Triangle"
3329 PetscErrorCode DMPlexGenerate_Triangle(DM boundary, PetscBool interpolate, DM *dm)
3330 {
3331   MPI_Comm             comm;
3332   PetscInt             dim              = 2;
3333   const PetscBool      createConvexHull = PETSC_FALSE;
3334   const PetscBool      constrained      = PETSC_FALSE;
3335   struct triangulateio in;
3336   struct triangulateio out;
3337   PetscInt             vStart, vEnd, v, eStart, eEnd, e;
3338   PetscMPIInt          rank;
3339   PetscErrorCode       ierr;
3340 
3341   PetscFunctionBegin;
3342   ierr = PetscObjectGetComm((PetscObject)boundary,&comm);CHKERRQ(ierr);
3343   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
3344   ierr = InitInput_Triangle(&in);CHKERRQ(ierr);
3345   ierr = InitOutput_Triangle(&out);CHKERRQ(ierr);
3346   ierr = DMPlexGetDepthStratum(boundary, 0, &vStart, &vEnd);CHKERRQ(ierr);
3347 
3348   in.numberofpoints = vEnd - vStart;
3349   if (in.numberofpoints > 0) {
3350     PetscSection coordSection;
3351     Vec          coordinates;
3352     PetscScalar *array;
3353 
3354     ierr = PetscMalloc(in.numberofpoints*dim * sizeof(double), &in.pointlist);CHKERRQ(ierr);
3355     ierr = PetscMalloc(in.numberofpoints * sizeof(int), &in.pointmarkerlist);CHKERRQ(ierr);
3356     ierr = DMGetCoordinatesLocal(boundary, &coordinates);CHKERRQ(ierr);
3357     ierr = DMPlexGetCoordinateSection(boundary, &coordSection);CHKERRQ(ierr);
3358     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
3359     for (v = vStart; v < vEnd; ++v) {
3360       const PetscInt idx = v - vStart;
3361       PetscInt       off, d;
3362 
3363       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
3364       for (d = 0; d < dim; ++d) {
3365         in.pointlist[idx*dim + d] = PetscRealPart(array[off+d]);
3366       }
3367       ierr = DMPlexGetLabelValue(boundary, "marker", v, &in.pointmarkerlist[idx]);CHKERRQ(ierr);
3368     }
3369     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
3370   }
3371   ierr  = DMPlexGetHeightStratum(boundary, 0, &eStart, &eEnd);CHKERRQ(ierr);
3372   in.numberofsegments = eEnd - eStart;
3373   if (in.numberofsegments > 0) {
3374     ierr = PetscMalloc(in.numberofsegments*2 * sizeof(int), &in.segmentlist);CHKERRQ(ierr);
3375     ierr = PetscMalloc(in.numberofsegments   * sizeof(int), &in.segmentmarkerlist);CHKERRQ(ierr);
3376     for (e = eStart; e < eEnd; ++e) {
3377       const PetscInt  idx = e - eStart;
3378       const PetscInt *cone;
3379 
3380       ierr = DMPlexGetCone(boundary, e, &cone);CHKERRQ(ierr);
3381 
3382       in.segmentlist[idx*2+0] = cone[0] - vStart;
3383       in.segmentlist[idx*2+1] = cone[1] - vStart;
3384 
3385       ierr = DMPlexGetLabelValue(boundary, "marker", e, &in.segmentmarkerlist[idx]);CHKERRQ(ierr);
3386     }
3387   }
3388 #if 0 /* Do not currently support holes */
3389   PetscReal *holeCoords;
3390   PetscInt   h, d;
3391 
3392   ierr = DMPlexGetHoles(boundary, &in.numberofholes, &holeCords);CHKERRQ(ierr);
3393   if (in.numberofholes > 0) {
3394     ierr = PetscMalloc(in.numberofholes*dim * sizeof(double), &in.holelist);CHKERRQ(ierr);
3395     for (h = 0; h < in.numberofholes; ++h) {
3396       for (d = 0; d < dim; ++d) {
3397         in.holelist[h*dim+d] = holeCoords[h*dim+d];
3398       }
3399     }
3400   }
3401 #endif
3402   if (!rank) {
3403     char args[32];
3404 
3405     /* Take away 'Q' for verbose output */
3406     ierr = PetscStrcpy(args, "pqezQ");CHKERRQ(ierr);
3407     if (createConvexHull) {
3408       ierr = PetscStrcat(args, "c");CHKERRQ(ierr);
3409     }
3410     if (constrained) {
3411       ierr = PetscStrcpy(args, "zepDQ");CHKERRQ(ierr);
3412     }
3413     triangulate(args, &in, &out, NULL);
3414   }
3415   ierr = PetscFree(in.pointlist);CHKERRQ(ierr);
3416   ierr = PetscFree(in.pointmarkerlist);CHKERRQ(ierr);
3417   ierr = PetscFree(in.segmentlist);CHKERRQ(ierr);
3418   ierr = PetscFree(in.segmentmarkerlist);CHKERRQ(ierr);
3419   ierr = PetscFree(in.holelist);CHKERRQ(ierr);
3420 
3421   {
3422     const PetscInt numCorners  = 3;
3423     const PetscInt numCells    = out.numberoftriangles;
3424     const PetscInt numVertices = out.numberofpoints;
3425     const int     *cells      = out.trianglelist;
3426     const double  *meshCoords = out.pointlist;
3427 
3428     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, dim, meshCoords, dm);CHKERRQ(ierr);
3429     /* Set labels */
3430     for (v = 0; v < numVertices; ++v) {
3431       if (out.pointmarkerlist[v]) {
3432         ierr = DMPlexSetLabelValue(*dm, "marker", v+numCells, out.pointmarkerlist[v]);CHKERRQ(ierr);
3433       }
3434     }
3435     if (interpolate) {
3436       for (e = 0; e < out.numberofedges; e++) {
3437         if (out.edgemarkerlist[e]) {
3438           const PetscInt  vertices[2] = {out.edgelist[e*2+0]+numCells, out.edgelist[e*2+1]+numCells};
3439           const PetscInt *edges;
3440           PetscInt        numEdges;
3441 
3442           ierr = DMPlexGetJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
3443           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
3444           ierr = DMPlexSetLabelValue(*dm, "marker", edges[0], out.edgemarkerlist[e]);CHKERRQ(ierr);
3445           ierr = DMPlexRestoreJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
3446         }
3447       }
3448     }
3449     ierr = DMPlexSetRefinementUniform(*dm, PETSC_FALSE);CHKERRQ(ierr);
3450   }
3451 #if 0 /* Do not currently support holes */
3452   ierr = DMPlexCopyHoles(*dm, boundary);CHKERRQ(ierr);
3453 #endif
3454   ierr = FiniOutput_Triangle(&out);CHKERRQ(ierr);
3455   PetscFunctionReturn(0);
3456 }
3457 
3458 #undef __FUNCT__
3459 #define __FUNCT__ "DMPlexRefine_Triangle"
3460 PetscErrorCode DMPlexRefine_Triangle(DM dm, double *maxVolumes, DM *dmRefined)
3461 {
3462   MPI_Comm             comm;
3463   PetscInt             dim  = 2;
3464   struct triangulateio in;
3465   struct triangulateio out;
3466   PetscInt             vStart, vEnd, v, cStart, cEnd, c, depth, depthGlobal;
3467   PetscMPIInt          rank;
3468   PetscErrorCode       ierr;
3469 
3470   PetscFunctionBegin;
3471   ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr);
3472   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
3473   ierr = InitInput_Triangle(&in);CHKERRQ(ierr);
3474   ierr = InitOutput_Triangle(&out);CHKERRQ(ierr);
3475   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3476   ierr = MPI_Allreduce(&depth, &depthGlobal, 1, MPIU_INT, MPI_MAX, comm);CHKERRQ(ierr);
3477   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
3478 
3479   in.numberofpoints = vEnd - vStart;
3480   if (in.numberofpoints > 0) {
3481     PetscSection coordSection;
3482     Vec          coordinates;
3483     PetscScalar *array;
3484 
3485     ierr = PetscMalloc(in.numberofpoints*dim * sizeof(double), &in.pointlist);CHKERRQ(ierr);
3486     ierr = PetscMalloc(in.numberofpoints * sizeof(int), &in.pointmarkerlist);CHKERRQ(ierr);
3487     ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
3488     ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
3489     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
3490     for (v = vStart; v < vEnd; ++v) {
3491       const PetscInt idx = v - vStart;
3492       PetscInt       off, d;
3493 
3494       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
3495       for (d = 0; d < dim; ++d) {
3496         in.pointlist[idx*dim + d] = PetscRealPart(array[off+d]);
3497       }
3498       ierr = DMPlexGetLabelValue(dm, "marker", v, &in.pointmarkerlist[idx]);CHKERRQ(ierr);
3499     }
3500     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
3501   }
3502   ierr  = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
3503 
3504   in.numberofcorners   = 3;
3505   in.numberoftriangles = cEnd - cStart;
3506 
3507   in.trianglearealist  = (double*) maxVolumes;
3508   if (in.numberoftriangles > 0) {
3509     ierr = PetscMalloc(in.numberoftriangles*in.numberofcorners * sizeof(int), &in.trianglelist);CHKERRQ(ierr);
3510     for (c = cStart; c < cEnd; ++c) {
3511       const PetscInt idx      = c - cStart;
3512       PetscInt      *closure = NULL;
3513       PetscInt       closureSize;
3514 
3515       ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
3516       if ((closureSize != 4) && (closureSize != 7)) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Mesh has cell which is not a triangle, %D vertices in closure", closureSize);
3517       for (v = 0; v < 3; ++v) {
3518         in.trianglelist[idx*in.numberofcorners + v] = closure[(v+closureSize-3)*2] - vStart;
3519       }
3520       ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
3521     }
3522   }
3523   /* TODO: Segment markers are missing on input */
3524 #if 0 /* Do not currently support holes */
3525   PetscReal *holeCoords;
3526   PetscInt   h, d;
3527 
3528   ierr = DMPlexGetHoles(boundary, &in.numberofholes, &holeCords);CHKERRQ(ierr);
3529   if (in.numberofholes > 0) {
3530     ierr = PetscMalloc(in.numberofholes*dim * sizeof(double), &in.holelist);CHKERRQ(ierr);
3531     for (h = 0; h < in.numberofholes; ++h) {
3532       for (d = 0; d < dim; ++d) {
3533         in.holelist[h*dim+d] = holeCoords[h*dim+d];
3534       }
3535     }
3536   }
3537 #endif
3538   if (!rank) {
3539     char args[32];
3540 
3541     /* Take away 'Q' for verbose output */
3542     ierr = PetscStrcpy(args, "pqezQra");CHKERRQ(ierr);
3543     triangulate(args, &in, &out, NULL);
3544   }
3545   ierr = PetscFree(in.pointlist);CHKERRQ(ierr);
3546   ierr = PetscFree(in.pointmarkerlist);CHKERRQ(ierr);
3547   ierr = PetscFree(in.segmentlist);CHKERRQ(ierr);
3548   ierr = PetscFree(in.segmentmarkerlist);CHKERRQ(ierr);
3549   ierr = PetscFree(in.trianglelist);CHKERRQ(ierr);
3550 
3551   {
3552     const PetscInt numCorners  = 3;
3553     const PetscInt numCells    = out.numberoftriangles;
3554     const PetscInt numVertices = out.numberofpoints;
3555     const int     *cells      = out.trianglelist;
3556     const double  *meshCoords = out.pointlist;
3557     PetscBool      interpolate = depthGlobal > 1 ? PETSC_TRUE : PETSC_FALSE;
3558 
3559     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, dim, meshCoords, dmRefined);CHKERRQ(ierr);
3560     /* Set labels */
3561     for (v = 0; v < numVertices; ++v) {
3562       if (out.pointmarkerlist[v]) {
3563         ierr = DMPlexSetLabelValue(*dmRefined, "marker", v+numCells, out.pointmarkerlist[v]);CHKERRQ(ierr);
3564       }
3565     }
3566     if (interpolate) {
3567       PetscInt e;
3568 
3569       for (e = 0; e < out.numberofedges; e++) {
3570         if (out.edgemarkerlist[e]) {
3571           const PetscInt  vertices[2] = {out.edgelist[e*2+0]+numCells, out.edgelist[e*2+1]+numCells};
3572           const PetscInt *edges;
3573           PetscInt        numEdges;
3574 
3575           ierr = DMPlexGetJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
3576           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
3577           ierr = DMPlexSetLabelValue(*dmRefined, "marker", edges[0], out.edgemarkerlist[e]);CHKERRQ(ierr);
3578           ierr = DMPlexRestoreJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
3579         }
3580       }
3581     }
3582     ierr = DMPlexSetRefinementUniform(*dmRefined, PETSC_FALSE);CHKERRQ(ierr);
3583   }
3584 #if 0 /* Do not currently support holes */
3585   ierr = DMPlexCopyHoles(*dm, boundary);CHKERRQ(ierr);
3586 #endif
3587   ierr = FiniOutput_Triangle(&out);CHKERRQ(ierr);
3588   PetscFunctionReturn(0);
3589 }
3590 #endif
3591 
3592 #if defined(PETSC_HAVE_TETGEN)
3593 #include <tetgen.h>
3594 #undef __FUNCT__
3595 #define __FUNCT__ "DMPlexGenerate_Tetgen"
3596 PetscErrorCode DMPlexGenerate_Tetgen(DM boundary, PetscBool interpolate, DM *dm)
3597 {
3598   MPI_Comm       comm;
3599   const PetscInt dim  = 3;
3600   ::tetgenio     in;
3601   ::tetgenio     out;
3602   PetscInt       vStart, vEnd, v, fStart, fEnd, f;
3603   PetscMPIInt    rank;
3604   PetscErrorCode ierr;
3605 
3606   PetscFunctionBegin;
3607   ierr              = PetscObjectGetComm((PetscObject)boundary,&comm);CHKERRQ(ierr);
3608   ierr              = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
3609   ierr              = DMPlexGetDepthStratum(boundary, 0, &vStart, &vEnd);CHKERRQ(ierr);
3610   in.numberofpoints = vEnd - vStart;
3611   if (in.numberofpoints > 0) {
3612     PetscSection coordSection;
3613     Vec          coordinates;
3614     PetscScalar *array;
3615 
3616     in.pointlist       = new double[in.numberofpoints*dim];
3617     in.pointmarkerlist = new int[in.numberofpoints];
3618 
3619     ierr = DMGetCoordinatesLocal(boundary, &coordinates);CHKERRQ(ierr);
3620     ierr = DMPlexGetCoordinateSection(boundary, &coordSection);CHKERRQ(ierr);
3621     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
3622     for (v = vStart; v < vEnd; ++v) {
3623       const PetscInt idx = v - vStart;
3624       PetscInt       off, d;
3625 
3626       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
3627       for (d = 0; d < dim; ++d) in.pointlist[idx*dim + d] = array[off+d];
3628       ierr = DMPlexGetLabelValue(boundary, "marker", v, &in.pointmarkerlist[idx]);CHKERRQ(ierr);
3629     }
3630     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
3631   }
3632   ierr  = DMPlexGetHeightStratum(boundary, 0, &fStart, &fEnd);CHKERRQ(ierr);
3633 
3634   in.numberoffacets = fEnd - fStart;
3635   if (in.numberoffacets > 0) {
3636     in.facetlist       = new tetgenio::facet[in.numberoffacets];
3637     in.facetmarkerlist = new int[in.numberoffacets];
3638     for (f = fStart; f < fEnd; ++f) {
3639       const PetscInt idx     = f - fStart;
3640       PetscInt      *points = NULL, numPoints, p, numVertices = 0, v;
3641 
3642       in.facetlist[idx].numberofpolygons = 1;
3643       in.facetlist[idx].polygonlist      = new tetgenio::polygon[in.facetlist[idx].numberofpolygons];
3644       in.facetlist[idx].numberofholes    = 0;
3645       in.facetlist[idx].holelist         = NULL;
3646 
3647       ierr = DMPlexGetTransitiveClosure(boundary, f, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
3648       for (p = 0; p < numPoints*2; p += 2) {
3649         const PetscInt point = points[p];
3650         if ((point >= vStart) && (point < vEnd)) points[numVertices++] = point;
3651       }
3652 
3653       tetgenio::polygon *poly = in.facetlist[idx].polygonlist;
3654       poly->numberofvertices = numVertices;
3655       poly->vertexlist       = new int[poly->numberofvertices];
3656       for (v = 0; v < numVertices; ++v) {
3657         const PetscInt vIdx = points[v] - vStart;
3658         poly->vertexlist[v] = vIdx;
3659       }
3660       ierr = DMPlexGetLabelValue(boundary, "marker", f, &in.facetmarkerlist[idx]);CHKERRQ(ierr);
3661       ierr = DMPlexRestoreTransitiveClosure(boundary, f, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
3662     }
3663   }
3664   if (!rank) {
3665     char args[32];
3666 
3667     /* Take away 'Q' for verbose output */
3668     ierr = PetscStrcpy(args, "pqezQ");CHKERRQ(ierr);
3669     ::tetrahedralize(args, &in, &out);
3670   }
3671   {
3672     const PetscInt numCorners  = 4;
3673     const PetscInt numCells    = out.numberoftetrahedra;
3674     const PetscInt numVertices = out.numberofpoints;
3675     const double   *meshCoords = out.pointlist;
3676     int            *cells      = out.tetrahedronlist;
3677 
3678     ierr = DMPlexInvertCells_Internal(dim, numCells, numCorners, cells);CHKERRQ(ierr);
3679     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, dim, meshCoords, dm);CHKERRQ(ierr);
3680     /* Set labels */
3681     for (v = 0; v < numVertices; ++v) {
3682       if (out.pointmarkerlist[v]) {
3683         ierr = DMPlexSetLabelValue(*dm, "marker", v+numCells, out.pointmarkerlist[v]);CHKERRQ(ierr);
3684       }
3685     }
3686     if (interpolate) {
3687       PetscInt e;
3688 
3689       for (e = 0; e < out.numberofedges; e++) {
3690         if (out.edgemarkerlist[e]) {
3691           const PetscInt  vertices[2] = {out.edgelist[e*2+0]+numCells, out.edgelist[e*2+1]+numCells};
3692           const PetscInt *edges;
3693           PetscInt        numEdges;
3694 
3695           ierr = DMPlexGetJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
3696           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
3697           ierr = DMPlexSetLabelValue(*dm, "marker", edges[0], out.edgemarkerlist[e]);CHKERRQ(ierr);
3698           ierr = DMPlexRestoreJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
3699         }
3700       }
3701       for (f = 0; f < out.numberoftrifaces; f++) {
3702         if (out.trifacemarkerlist[f]) {
3703           const PetscInt  vertices[3] = {out.trifacelist[f*3+0]+numCells, out.trifacelist[f*3+1]+numCells, out.trifacelist[f*3+2]+numCells};
3704           const PetscInt *faces;
3705           PetscInt        numFaces;
3706 
3707           ierr = DMPlexGetJoin(*dm, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
3708           if (numFaces != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Three vertices must cover only one face, not %D", numFaces);
3709           ierr = DMPlexSetLabelValue(*dm, "marker", faces[0], out.trifacemarkerlist[f]);CHKERRQ(ierr);
3710           ierr = DMPlexRestoreJoin(*dm, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
3711         }
3712       }
3713     }
3714     ierr = DMPlexSetRefinementUniform(*dm, PETSC_FALSE);CHKERRQ(ierr);
3715   }
3716   PetscFunctionReturn(0);
3717 }
3718 
3719 #undef __FUNCT__
3720 #define __FUNCT__ "DMPlexRefine_Tetgen"
3721 PetscErrorCode DMPlexRefine_Tetgen(DM dm, double *maxVolumes, DM *dmRefined)
3722 {
3723   MPI_Comm       comm;
3724   const PetscInt dim  = 3;
3725   ::tetgenio     in;
3726   ::tetgenio     out;
3727   PetscInt       vStart, vEnd, v, cStart, cEnd, c, depth, depthGlobal;
3728   PetscMPIInt    rank;
3729   PetscErrorCode ierr;
3730 
3731   PetscFunctionBegin;
3732   ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr);
3733   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
3734   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3735   ierr = MPI_Allreduce(&depth, &depthGlobal, 1, MPIU_INT, MPI_MAX, comm);CHKERRQ(ierr);
3736   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
3737 
3738   in.numberofpoints = vEnd - vStart;
3739   if (in.numberofpoints > 0) {
3740     PetscSection coordSection;
3741     Vec          coordinates;
3742     PetscScalar *array;
3743 
3744     in.pointlist       = new double[in.numberofpoints*dim];
3745     in.pointmarkerlist = new int[in.numberofpoints];
3746 
3747     ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
3748     ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
3749     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
3750     for (v = vStart; v < vEnd; ++v) {
3751       const PetscInt idx = v - vStart;
3752       PetscInt       off, d;
3753 
3754       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
3755       for (d = 0; d < dim; ++d) in.pointlist[idx*dim + d] = array[off+d];
3756       ierr = DMPlexGetLabelValue(dm, "marker", v, &in.pointmarkerlist[idx]);CHKERRQ(ierr);
3757     }
3758     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
3759   }
3760   ierr  = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
3761 
3762   in.numberofcorners       = 4;
3763   in.numberoftetrahedra    = cEnd - cStart;
3764   in.tetrahedronvolumelist = (double*) maxVolumes;
3765   if (in.numberoftetrahedra > 0) {
3766     in.tetrahedronlist = new int[in.numberoftetrahedra*in.numberofcorners];
3767     for (c = cStart; c < cEnd; ++c) {
3768       const PetscInt idx      = c - cStart;
3769       PetscInt      *closure = NULL;
3770       PetscInt       closureSize;
3771 
3772       ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
3773       if ((closureSize != 5) && (closureSize != 15)) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Mesh has cell which is not a tetrahedron, %D vertices in closure", closureSize);
3774       for (v = 0; v < 4; ++v) {
3775         in.tetrahedronlist[idx*in.numberofcorners + v] = closure[(v+closureSize-4)*2] - vStart;
3776       }
3777       ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
3778     }
3779   }
3780   /* TODO: Put in boundary faces with markers */
3781   if (!rank) {
3782     char args[32];
3783 
3784     /* Take away 'Q' for verbose output */
3785     /*ierr = PetscStrcpy(args, "qezQra");CHKERRQ(ierr); */
3786     ierr = PetscStrcpy(args, "qezraVVVV");CHKERRQ(ierr);
3787     ::tetrahedralize(args, &in, &out);
3788   }
3789   in.tetrahedronvolumelist = NULL;
3790 
3791   {
3792     const PetscInt numCorners  = 4;
3793     const PetscInt numCells    = out.numberoftetrahedra;
3794     const PetscInt numVertices = out.numberofpoints;
3795     const double   *meshCoords = out.pointlist;
3796     int            *cells      = out.tetrahedronlist;
3797 
3798     PetscBool      interpolate = depthGlobal > 1 ? PETSC_TRUE : PETSC_FALSE;
3799 
3800     ierr = DMPlexInvertCells_Internal(dim, numCells, numCorners, cells);CHKERRQ(ierr);
3801     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, dim, meshCoords, dmRefined);CHKERRQ(ierr);
3802     /* Set labels */
3803     for (v = 0; v < numVertices; ++v) {
3804       if (out.pointmarkerlist[v]) {
3805         ierr = DMPlexSetLabelValue(*dmRefined, "marker", v+numCells, out.pointmarkerlist[v]);CHKERRQ(ierr);
3806       }
3807     }
3808     if (interpolate) {
3809       PetscInt e, f;
3810 
3811       for (e = 0; e < out.numberofedges; e++) {
3812         if (out.edgemarkerlist[e]) {
3813           const PetscInt  vertices[2] = {out.edgelist[e*2+0]+numCells, out.edgelist[e*2+1]+numCells};
3814           const PetscInt *edges;
3815           PetscInt        numEdges;
3816 
3817           ierr = DMPlexGetJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
3818           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
3819           ierr = DMPlexSetLabelValue(*dmRefined, "marker", edges[0], out.edgemarkerlist[e]);CHKERRQ(ierr);
3820           ierr = DMPlexRestoreJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
3821         }
3822       }
3823       for (f = 0; f < out.numberoftrifaces; f++) {
3824         if (out.trifacemarkerlist[f]) {
3825           const PetscInt  vertices[3] = {out.trifacelist[f*3+0]+numCells, out.trifacelist[f*3+1]+numCells, out.trifacelist[f*3+2]+numCells};
3826           const PetscInt *faces;
3827           PetscInt        numFaces;
3828 
3829           ierr = DMPlexGetJoin(*dmRefined, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
3830           if (numFaces != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Three vertices must cover only one face, not %D", numFaces);
3831           ierr = DMPlexSetLabelValue(*dmRefined, "marker", faces[0], out.trifacemarkerlist[f]);CHKERRQ(ierr);
3832           ierr = DMPlexRestoreJoin(*dmRefined, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
3833         }
3834       }
3835     }
3836     ierr = DMPlexSetRefinementUniform(*dmRefined, PETSC_FALSE);CHKERRQ(ierr);
3837   }
3838   PetscFunctionReturn(0);
3839 }
3840 #endif
3841 
3842 #if defined(PETSC_HAVE_CTETGEN)
3843 #include "ctetgen.h"
3844 
3845 #undef __FUNCT__
3846 #define __FUNCT__ "DMPlexGenerate_CTetgen"
3847 PetscErrorCode DMPlexGenerate_CTetgen(DM boundary, PetscBool interpolate, DM *dm)
3848 {
3849   MPI_Comm       comm;
3850   const PetscInt dim  = 3;
3851   PLC           *in, *out;
3852   PetscInt       verbose = 0, vStart, vEnd, v, fStart, fEnd, f;
3853   PetscMPIInt    rank;
3854   PetscErrorCode ierr;
3855 
3856   PetscFunctionBegin;
3857   ierr = PetscObjectGetComm((PetscObject)boundary,&comm);CHKERRQ(ierr);
3858   ierr = PetscOptionsGetInt(((PetscObject) boundary)->prefix, "-ctetgen_verbose", &verbose, NULL);CHKERRQ(ierr);
3859   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
3860   ierr = DMPlexGetDepthStratum(boundary, 0, &vStart, &vEnd);CHKERRQ(ierr);
3861   ierr = PLCCreate(&in);CHKERRQ(ierr);
3862   ierr = PLCCreate(&out);CHKERRQ(ierr);
3863 
3864   in->numberofpoints = vEnd - vStart;
3865   if (in->numberofpoints > 0) {
3866     PetscSection coordSection;
3867     Vec          coordinates;
3868     PetscScalar *array;
3869 
3870     ierr = PetscMalloc(in->numberofpoints*dim * sizeof(PetscReal), &in->pointlist);CHKERRQ(ierr);
3871     ierr = PetscMalloc(in->numberofpoints     * sizeof(int),       &in->pointmarkerlist);CHKERRQ(ierr);
3872     ierr = DMGetCoordinatesLocal(boundary, &coordinates);CHKERRQ(ierr);
3873     ierr = DMPlexGetCoordinateSection(boundary, &coordSection);CHKERRQ(ierr);
3874     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
3875     for (v = vStart; v < vEnd; ++v) {
3876       const PetscInt idx = v - vStart;
3877       PetscInt       off, d, m;
3878 
3879       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
3880       for (d = 0; d < dim; ++d) {
3881         in->pointlist[idx*dim + d] = PetscRealPart(array[off+d]);
3882       }
3883       ierr = DMPlexGetLabelValue(boundary, "marker", v, &m);CHKERRQ(ierr);
3884 
3885       in->pointmarkerlist[idx] = (int) m;
3886     }
3887     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
3888   }
3889   ierr  = DMPlexGetHeightStratum(boundary, 0, &fStart, &fEnd);CHKERRQ(ierr);
3890 
3891   in->numberoffacets = fEnd - fStart;
3892   if (in->numberoffacets > 0) {
3893     ierr = PetscMalloc(in->numberoffacets * sizeof(facet), &in->facetlist);CHKERRQ(ierr);
3894     ierr = PetscMalloc(in->numberoffacets * sizeof(int),   &in->facetmarkerlist);CHKERRQ(ierr);
3895     for (f = fStart; f < fEnd; ++f) {
3896       const PetscInt idx     = f - fStart;
3897       PetscInt      *points = NULL, numPoints, p, numVertices = 0, v, m;
3898       polygon       *poly;
3899 
3900       in->facetlist[idx].numberofpolygons = 1;
3901 
3902       ierr = PetscMalloc(in->facetlist[idx].numberofpolygons * sizeof(polygon), &in->facetlist[idx].polygonlist);CHKERRQ(ierr);
3903 
3904       in->facetlist[idx].numberofholes    = 0;
3905       in->facetlist[idx].holelist         = NULL;
3906 
3907       ierr = DMPlexGetTransitiveClosure(boundary, f, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
3908       for (p = 0; p < numPoints*2; p += 2) {
3909         const PetscInt point = points[p];
3910         if ((point >= vStart) && (point < vEnd)) points[numVertices++] = point;
3911       }
3912 
3913       poly                   = in->facetlist[idx].polygonlist;
3914       poly->numberofvertices = numVertices;
3915       ierr                   = PetscMalloc(poly->numberofvertices * sizeof(int), &poly->vertexlist);CHKERRQ(ierr);
3916       for (v = 0; v < numVertices; ++v) {
3917         const PetscInt vIdx = points[v] - vStart;
3918         poly->vertexlist[v] = vIdx;
3919       }
3920       ierr                     = DMPlexGetLabelValue(boundary, "marker", f, &m);CHKERRQ(ierr);
3921       in->facetmarkerlist[idx] = (int) m;
3922       ierr                     = DMPlexRestoreTransitiveClosure(boundary, f, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
3923     }
3924   }
3925   if (!rank) {
3926     TetGenOpts t;
3927 
3928     ierr        = TetGenOptsInitialize(&t);CHKERRQ(ierr);
3929     t.in        = boundary; /* Should go away */
3930     t.plc       = 1;
3931     t.quality   = 1;
3932     t.edgesout  = 1;
3933     t.zeroindex = 1;
3934     t.quiet     = 1;
3935     t.verbose   = verbose;
3936     ierr        = TetGenCheckOpts(&t);CHKERRQ(ierr);
3937     ierr        = TetGenTetrahedralize(&t, in, out);CHKERRQ(ierr);
3938   }
3939   {
3940     const PetscInt numCorners  = 4;
3941     const PetscInt numCells    = out->numberoftetrahedra;
3942     const PetscInt numVertices = out->numberofpoints;
3943     const double   *meshCoords = out->pointlist;
3944     int            *cells      = out->tetrahedronlist;
3945 
3946     ierr = DMPlexInvertCells_Internal(dim, numCells, numCorners, cells);CHKERRQ(ierr);
3947     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, dim, meshCoords, dm);CHKERRQ(ierr);
3948     /* Set labels */
3949     for (v = 0; v < numVertices; ++v) {
3950       if (out->pointmarkerlist[v]) {
3951         ierr = DMPlexSetLabelValue(*dm, "marker", v+numCells, out->pointmarkerlist[v]);CHKERRQ(ierr);
3952       }
3953     }
3954     if (interpolate) {
3955       PetscInt e;
3956 
3957       for (e = 0; e < out->numberofedges; e++) {
3958         if (out->edgemarkerlist[e]) {
3959           const PetscInt  vertices[2] = {out->edgelist[e*2+0]+numCells, out->edgelist[e*2+1]+numCells};
3960           const PetscInt *edges;
3961           PetscInt        numEdges;
3962 
3963           ierr = DMPlexGetJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
3964           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
3965           ierr = DMPlexSetLabelValue(*dm, "marker", edges[0], out->edgemarkerlist[e]);CHKERRQ(ierr);
3966           ierr = DMPlexRestoreJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
3967         }
3968       }
3969       for (f = 0; f < out->numberoftrifaces; f++) {
3970         if (out->trifacemarkerlist[f]) {
3971           const PetscInt  vertices[3] = {out->trifacelist[f*3+0]+numCells, out->trifacelist[f*3+1]+numCells, out->trifacelist[f*3+2]+numCells};
3972           const PetscInt *faces;
3973           PetscInt        numFaces;
3974 
3975           ierr = DMPlexGetFullJoin(*dm, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
3976           if (numFaces != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Three vertices must cover only one face, not %D", numFaces);
3977           ierr = DMPlexSetLabelValue(*dm, "marker", faces[0], out->trifacemarkerlist[f]);CHKERRQ(ierr);
3978           ierr = DMPlexRestoreJoin(*dm, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
3979         }
3980       }
3981     }
3982     ierr = DMPlexSetRefinementUniform(*dm, PETSC_FALSE);CHKERRQ(ierr);
3983   }
3984 
3985   ierr = PLCDestroy(&in);CHKERRQ(ierr);
3986   ierr = PLCDestroy(&out);CHKERRQ(ierr);
3987   PetscFunctionReturn(0);
3988 }
3989 
3990 #undef __FUNCT__
3991 #define __FUNCT__ "DMPlexRefine_CTetgen"
3992 PetscErrorCode DMPlexRefine_CTetgen(DM dm, PetscReal *maxVolumes, DM *dmRefined)
3993 {
3994   MPI_Comm       comm;
3995   const PetscInt dim  = 3;
3996   PLC           *in, *out;
3997   PetscInt       verbose = 0, vStart, vEnd, v, cStart, cEnd, c, depth, depthGlobal;
3998   PetscMPIInt    rank;
3999   PetscErrorCode ierr;
4000 
4001   PetscFunctionBegin;
4002   ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr);
4003   ierr = PetscOptionsGetInt(((PetscObject) dm)->prefix, "-ctetgen_verbose", &verbose, NULL);CHKERRQ(ierr);
4004   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
4005   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
4006   ierr = MPI_Allreduce(&depth, &depthGlobal, 1, MPIU_INT, MPI_MAX, comm);CHKERRQ(ierr);
4007   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
4008   ierr = PLCCreate(&in);CHKERRQ(ierr);
4009   ierr = PLCCreate(&out);CHKERRQ(ierr);
4010 
4011   in->numberofpoints = vEnd - vStart;
4012   if (in->numberofpoints > 0) {
4013     PetscSection coordSection;
4014     Vec          coordinates;
4015     PetscScalar *array;
4016 
4017     ierr = PetscMalloc(in->numberofpoints*dim * sizeof(PetscReal), &in->pointlist);CHKERRQ(ierr);
4018     ierr = PetscMalloc(in->numberofpoints     * sizeof(int),       &in->pointmarkerlist);CHKERRQ(ierr);
4019     ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
4020     ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
4021     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
4022     for (v = vStart; v < vEnd; ++v) {
4023       const PetscInt idx = v - vStart;
4024       PetscInt       off, d, m;
4025 
4026       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
4027       for (d = 0; d < dim; ++d) {
4028         in->pointlist[idx*dim + d] = PetscRealPart(array[off+d]);
4029       }
4030       ierr = DMPlexGetLabelValue(dm, "marker", v, &m);CHKERRQ(ierr);
4031 
4032       in->pointmarkerlist[idx] = (int) m;
4033     }
4034     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
4035   }
4036   ierr  = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
4037 
4038   in->numberofcorners       = 4;
4039   in->numberoftetrahedra    = cEnd - cStart;
4040   in->tetrahedronvolumelist = maxVolumes;
4041   if (in->numberoftetrahedra > 0) {
4042     ierr = PetscMalloc(in->numberoftetrahedra*in->numberofcorners * sizeof(int), &in->tetrahedronlist);CHKERRQ(ierr);
4043     for (c = cStart; c < cEnd; ++c) {
4044       const PetscInt idx      = c - cStart;
4045       PetscInt      *closure = NULL;
4046       PetscInt       closureSize;
4047 
4048       ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
4049       if ((closureSize != 5) && (closureSize != 15)) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Mesh has cell which is not a tetrahedron, %D vertices in closure", closureSize);
4050       for (v = 0; v < 4; ++v) {
4051         in->tetrahedronlist[idx*in->numberofcorners + v] = closure[(v+closureSize-4)*2] - vStart;
4052       }
4053       ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
4054     }
4055   }
4056   if (!rank) {
4057     TetGenOpts t;
4058 
4059     ierr = TetGenOptsInitialize(&t);CHKERRQ(ierr);
4060 
4061     t.in        = dm; /* Should go away */
4062     t.refine    = 1;
4063     t.varvolume = 1;
4064     t.quality   = 1;
4065     t.edgesout  = 1;
4066     t.zeroindex = 1;
4067     t.quiet     = 1;
4068     t.verbose   = verbose; /* Change this */
4069 
4070     ierr = TetGenCheckOpts(&t);CHKERRQ(ierr);
4071     ierr = TetGenTetrahedralize(&t, in, out);CHKERRQ(ierr);
4072   }
4073   {
4074     const PetscInt numCorners  = 4;
4075     const PetscInt numCells    = out->numberoftetrahedra;
4076     const PetscInt numVertices = out->numberofpoints;
4077     const double   *meshCoords = out->pointlist;
4078     int            *cells      = out->tetrahedronlist;
4079     PetscBool      interpolate = depthGlobal > 1 ? PETSC_TRUE : PETSC_FALSE;
4080 
4081     ierr = DMPlexInvertCells_Internal(dim, numCells, numCorners, cells);CHKERRQ(ierr);
4082     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, dim, meshCoords, dmRefined);CHKERRQ(ierr);
4083     /* Set labels */
4084     for (v = 0; v < numVertices; ++v) {
4085       if (out->pointmarkerlist[v]) {
4086         ierr = DMPlexSetLabelValue(*dmRefined, "marker", v+numCells, out->pointmarkerlist[v]);CHKERRQ(ierr);
4087       }
4088     }
4089     if (interpolate) {
4090       PetscInt e, f;
4091 
4092       for (e = 0; e < out->numberofedges; e++) {
4093         if (out->edgemarkerlist[e]) {
4094           const PetscInt  vertices[2] = {out->edgelist[e*2+0]+numCells, out->edgelist[e*2+1]+numCells};
4095           const PetscInt *edges;
4096           PetscInt        numEdges;
4097 
4098           ierr = DMPlexGetJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
4099           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
4100           ierr = DMPlexSetLabelValue(*dmRefined, "marker", edges[0], out->edgemarkerlist[e]);CHKERRQ(ierr);
4101           ierr = DMPlexRestoreJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
4102         }
4103       }
4104       for (f = 0; f < out->numberoftrifaces; f++) {
4105         if (out->trifacemarkerlist[f]) {
4106           const PetscInt  vertices[3] = {out->trifacelist[f*3+0]+numCells, out->trifacelist[f*3+1]+numCells, out->trifacelist[f*3+2]+numCells};
4107           const PetscInt *faces;
4108           PetscInt        numFaces;
4109 
4110           ierr = DMPlexGetFullJoin(*dmRefined, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
4111           if (numFaces != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Three vertices must cover only one face, not %D", numFaces);
4112           ierr = DMPlexSetLabelValue(*dmRefined, "marker", faces[0], out->trifacemarkerlist[f]);CHKERRQ(ierr);
4113           ierr = DMPlexRestoreJoin(*dmRefined, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
4114         }
4115       }
4116     }
4117     ierr = DMPlexSetRefinementUniform(*dmRefined, PETSC_FALSE);CHKERRQ(ierr);
4118   }
4119   ierr = PLCDestroy(&in);CHKERRQ(ierr);
4120   ierr = PLCDestroy(&out);CHKERRQ(ierr);
4121   PetscFunctionReturn(0);
4122 }
4123 #endif
4124 
4125 #undef __FUNCT__
4126 #define __FUNCT__ "DMPlexGenerate"
4127 /*@C
4128   DMPlexGenerate - Generates a mesh.
4129 
4130   Not Collective
4131 
4132   Input Parameters:
4133 + boundary - The DMPlex boundary object
4134 . name - The mesh generation package name
4135 - interpolate - Flag to create intermediate mesh elements
4136 
4137   Output Parameter:
4138 . mesh - The DMPlex object
4139 
4140   Level: intermediate
4141 
4142 .keywords: mesh, elements
4143 .seealso: DMPlexCreate(), DMRefine()
4144 @*/
4145 PetscErrorCode DMPlexGenerate(DM boundary, const char name[], PetscBool interpolate, DM *mesh)
4146 {
4147   PetscInt       dim;
4148   char           genname[1024];
4149   PetscBool      isTriangle = PETSC_FALSE, isTetgen = PETSC_FALSE, isCTetgen = PETSC_FALSE, flg;
4150   PetscErrorCode ierr;
4151 
4152   PetscFunctionBegin;
4153   PetscValidHeaderSpecific(boundary, DM_CLASSID, 1);
4154   PetscValidLogicalCollectiveBool(boundary, interpolate, 2);
4155   ierr = DMPlexGetDimension(boundary, &dim);CHKERRQ(ierr);
4156   ierr = PetscOptionsGetString(((PetscObject) boundary)->prefix, "-dm_plex_generator", genname, 1024, &flg);CHKERRQ(ierr);
4157   if (flg) name = genname;
4158   if (name) {
4159     ierr = PetscStrcmp(name, "triangle", &isTriangle);CHKERRQ(ierr);
4160     ierr = PetscStrcmp(name, "tetgen",   &isTetgen);CHKERRQ(ierr);
4161     ierr = PetscStrcmp(name, "ctetgen",  &isCTetgen);CHKERRQ(ierr);
4162   }
4163   switch (dim) {
4164   case 1:
4165     if (!name || isTriangle) {
4166 #if defined(PETSC_HAVE_TRIANGLE)
4167       ierr = DMPlexGenerate_Triangle(boundary, interpolate, mesh);CHKERRQ(ierr);
4168 #else
4169       SETERRQ(PetscObjectComm((PetscObject)boundary), PETSC_ERR_SUP, "Mesh generation needs external package support.\nPlease reconfigure with --download-triangle.");
4170 #endif
4171     } else SETERRQ1(PetscObjectComm((PetscObject)boundary), PETSC_ERR_SUP, "Unknown 2D mesh generation package %s", name);
4172     break;
4173   case 2:
4174     if (!name || isCTetgen) {
4175 #if defined(PETSC_HAVE_CTETGEN)
4176       ierr = DMPlexGenerate_CTetgen(boundary, interpolate, mesh);CHKERRQ(ierr);
4177 #else
4178       SETERRQ(PetscObjectComm((PetscObject)boundary), PETSC_ERR_SUP, "CTetgen needs external package support.\nPlease reconfigure with --download-ctetgen.");
4179 #endif
4180     } else if (isTetgen) {
4181 #if defined(PETSC_HAVE_TETGEN)
4182       ierr = DMPlexGenerate_Tetgen(boundary, interpolate, mesh);CHKERRQ(ierr);
4183 #else
4184       SETERRQ(PetscObjectComm((PetscObject)boundary), PETSC_ERR_SUP, "Tetgen needs external package support.\nPlease reconfigure with --with-c-language=cxx --download-tetgen.");
4185 #endif
4186     } else SETERRQ1(PetscObjectComm((PetscObject)boundary), PETSC_ERR_SUP, "Unknown 3D mesh generation package %s", name);
4187     break;
4188   default:
4189     SETERRQ1(PetscObjectComm((PetscObject)boundary), PETSC_ERR_SUP, "Mesh generation for a dimension %d boundary is not supported.", dim);
4190   }
4191   PetscFunctionReturn(0);
4192 }
4193 
4194 typedef PetscInt CellRefiner;
4195 
4196 #undef __FUNCT__
4197 #define __FUNCT__ "GetDepthStart_Private"
4198 PETSC_STATIC_INLINE PetscErrorCode GetDepthStart_Private(PetscInt depth, PetscInt depthSize[], PetscInt *cStart, PetscInt *fStart, PetscInt *eStart, PetscInt *vStart)
4199 {
4200   PetscFunctionBegin;
4201   if (cStart) *cStart = 0;
4202   if (vStart) *vStart = depthSize[depth];
4203   if (fStart) *fStart = depthSize[depth] + depthSize[0];
4204   if (eStart) *eStart = depthSize[depth] + depthSize[0] + depthSize[depth-1];
4205   PetscFunctionReturn(0);
4206 }
4207 
4208 #undef __FUNCT__
4209 #define __FUNCT__ "GetDepthEnd_Private"
4210 PETSC_STATIC_INLINE PetscErrorCode GetDepthEnd_Private(PetscInt depth, PetscInt depthSize[], PetscInt *cEnd, PetscInt *fEnd, PetscInt *eEnd, PetscInt *vEnd)
4211 {
4212   PetscFunctionBegin;
4213   if (cEnd) *cEnd = depthSize[depth];
4214   if (vEnd) *vEnd = depthSize[depth] + depthSize[0];
4215   if (fEnd) *fEnd = depthSize[depth] + depthSize[0] + depthSize[depth-1];
4216   if (eEnd) *eEnd = depthSize[depth] + depthSize[0] + depthSize[depth-1] + depthSize[1];
4217   PetscFunctionReturn(0);
4218 }
4219 
4220 #undef __FUNCT__
4221 #define __FUNCT__ "CellRefinerGetSizes"
4222 PetscErrorCode CellRefinerGetSizes(CellRefiner refiner, DM dm, PetscInt depthSize[])
4223 {
4224   PetscInt       cStart, cEnd, cMax, vStart, vEnd, vMax, fStart, fEnd, fMax, eStart, eEnd, eMax;
4225   PetscErrorCode ierr;
4226 
4227   PetscFunctionBegin;
4228   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
4229   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
4230   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
4231   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
4232   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
4233   switch (refiner) {
4234   case 1:
4235     /* Simplicial 2D */
4236     depthSize[0] = vEnd - vStart + fEnd - fStart;         /* Add a vertex on every face */
4237     depthSize[1] = 2*(fEnd - fStart) + 3*(cEnd - cStart); /* Every face is split into 2 faces and 3 faces are added for each cell */
4238     depthSize[2] = 4*(cEnd - cStart);                     /* Every cell split into 4 cells */
4239     break;
4240   case 3:
4241     /* Hybrid 2D */
4242     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
4243     cMax = PetscMin(cEnd, cMax);
4244     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
4245     fMax         = PetscMin(fEnd, fMax);
4246     depthSize[0] = vEnd - vStart + fMax - fStart;                                         /* Add a vertex on every face, but not hybrid faces */
4247     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 */
4248     depthSize[2] = 4*(cMax - cStart) + 2*(cEnd - cMax);                                   /* Interior cells split into 4 cells, Hybrid cells split into 2 cells */
4249     break;
4250   case 2:
4251     /* Hex 2D */
4252     depthSize[0] = vEnd - vStart + cEnd - cStart + fEnd - fStart; /* Add a vertex on every face and cell */
4253     depthSize[1] = 2*(fEnd - fStart) + 4*(cEnd - cStart);         /* Every face is split into 2 faces and 4 faces are added for each cell */
4254     depthSize[2] = 4*(cEnd - cStart);                             /* Every cell split into 4 cells */
4255     break;
4256   default:
4257     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
4258   }
4259   PetscFunctionReturn(0);
4260 }
4261 
4262 #undef __FUNCT__
4263 #define __FUNCT__ "CellRefinerSetConeSizes"
4264 PetscErrorCode CellRefinerSetConeSizes(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
4265 {
4266   PetscInt       depth, cStart, cStartNew, cEnd, cMax, c, vStart, vStartNew, vEnd, vMax, v, fStart, fStartNew, fEnd, fMax, f, eStart, eStartNew, eEnd, eMax, r;
4267   PetscErrorCode ierr;
4268 
4269   PetscFunctionBegin;
4270   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
4271   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
4272   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
4273   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
4274   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
4275   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
4276   ierr = GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);CHKERRQ(ierr);
4277   switch (refiner) {
4278   case 1:
4279     /* Simplicial 2D */
4280     /* All cells have 3 faces */
4281     for (c = cStart; c < cEnd; ++c) {
4282       for (r = 0; r < 4; ++r) {
4283         const PetscInt newp = (c - cStart)*4 + r;
4284 
4285         ierr = DMPlexSetConeSize(rdm, newp, 3);CHKERRQ(ierr);
4286       }
4287     }
4288     /* Split faces have 2 vertices and the same cells as the parent */
4289     for (f = fStart; f < fEnd; ++f) {
4290       for (r = 0; r < 2; ++r) {
4291         const PetscInt newp = fStartNew + (f - fStart)*2 + r;
4292         PetscInt       size;
4293 
4294         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
4295         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
4296         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
4297       }
4298     }
4299     /* Interior faces have 2 vertices and 2 cells */
4300     for (c = cStart; c < cEnd; ++c) {
4301       for (r = 0; r < 3; ++r) {
4302         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*3 + r;
4303 
4304         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
4305         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
4306       }
4307     }
4308     /* Old vertices have identical supports */
4309     for (v = vStart; v < vEnd; ++v) {
4310       const PetscInt newp = vStartNew + (v - vStart);
4311       PetscInt       size;
4312 
4313       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
4314       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
4315     }
4316     /* Face vertices have 2 + cells*2 supports */
4317     for (f = fStart; f < fEnd; ++f) {
4318       const PetscInt newp = vStartNew + (vEnd - vStart) + (f - fStart);
4319       PetscInt       size;
4320 
4321       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
4322       ierr = DMPlexSetSupportSize(rdm, newp, 2 + size*2);CHKERRQ(ierr);
4323     }
4324     break;
4325   case 2:
4326     /* Hex 2D */
4327     /* All cells have 4 faces */
4328     for (c = cStart; c < cEnd; ++c) {
4329       for (r = 0; r < 4; ++r) {
4330         const PetscInt newp = (c - cStart)*4 + r;
4331 
4332         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
4333       }
4334     }
4335     /* Split faces have 2 vertices and the same cells as the parent */
4336     for (f = fStart; f < fEnd; ++f) {
4337       for (r = 0; r < 2; ++r) {
4338         const PetscInt newp = fStartNew + (f - fStart)*2 + r;
4339         PetscInt       size;
4340 
4341         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
4342         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
4343         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
4344       }
4345     }
4346     /* Interior faces have 2 vertices and 2 cells */
4347     for (c = cStart; c < cEnd; ++c) {
4348       for (r = 0; r < 4; ++r) {
4349         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*4 + r;
4350 
4351         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
4352         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
4353       }
4354     }
4355     /* Old vertices have identical supports */
4356     for (v = vStart; v < vEnd; ++v) {
4357       const PetscInt newp = vStartNew + (v - vStart);
4358       PetscInt       size;
4359 
4360       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
4361       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
4362     }
4363     /* Face vertices have 2 + cells supports */
4364     for (f = fStart; f < fEnd; ++f) {
4365       const PetscInt newp = vStartNew + (vEnd - vStart) + (f - fStart);
4366       PetscInt       size;
4367 
4368       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
4369       ierr = DMPlexSetSupportSize(rdm, newp, 2 + size);CHKERRQ(ierr);
4370     }
4371     /* Cell vertices have 4 supports */
4372     for (c = cStart; c < cEnd; ++c) {
4373       const PetscInt newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (c - cStart);
4374 
4375       ierr = DMPlexSetSupportSize(rdm, newp, 4);CHKERRQ(ierr);
4376     }
4377     break;
4378   case 3:
4379     /* Hybrid 2D */
4380     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
4381     cMax = PetscMin(cEnd, cMax);
4382     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
4383     fMax = PetscMin(fEnd, fMax);
4384     ierr = DMPlexSetHybridBounds(rdm, cStartNew + (cMax - cStart)*4, fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3, PETSC_DETERMINE, PETSC_DETERMINE);CHKERRQ(ierr);
4385     /* Interior cells have 3 faces */
4386     for (c = cStart; c < cMax; ++c) {
4387       for (r = 0; r < 4; ++r) {
4388         const PetscInt newp = cStartNew + (c - cStart)*4 + r;
4389 
4390         ierr = DMPlexSetConeSize(rdm, newp, 3);CHKERRQ(ierr);
4391       }
4392     }
4393     /* Hybrid cells have 4 faces */
4394     for (c = cMax; c < cEnd; ++c) {
4395       for (r = 0; r < 2; ++r) {
4396         const PetscInt newp = cStartNew + (cMax - cStart)*4 + (c - cMax)*2 + r;
4397 
4398         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
4399       }
4400     }
4401     /* Interior split faces have 2 vertices and the same cells as the parent */
4402     for (f = fStart; f < fMax; ++f) {
4403       for (r = 0; r < 2; ++r) {
4404         const PetscInt newp = fStartNew + (f - fStart)*2 + r;
4405         PetscInt       size;
4406 
4407         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
4408         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
4409         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
4410       }
4411     }
4412     /* Interior cell faces have 2 vertices and 2 cells */
4413     for (c = cStart; c < cMax; ++c) {
4414       for (r = 0; r < 3; ++r) {
4415         const PetscInt newp = fStartNew + (fMax - fStart)*2 + (c - cStart)*3 + r;
4416 
4417         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
4418         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
4419       }
4420     }
4421     /* Hybrid faces have 2 vertices and the same cells */
4422     for (f = fMax; f < fEnd; ++f) {
4423       const PetscInt newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (f - fMax);
4424       PetscInt       size;
4425 
4426       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
4427       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
4428       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
4429     }
4430     /* Hybrid cell faces have 2 vertices and 2 cells */
4431     for (c = cMax; c < cEnd; ++c) {
4432       const PetscInt newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (fEnd - fMax) + (c - cMax);
4433 
4434       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
4435       ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
4436     }
4437     /* Old vertices have identical supports */
4438     for (v = vStart; v < vEnd; ++v) {
4439       const PetscInt newp = vStartNew + (v - vStart);
4440       PetscInt       size;
4441 
4442       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
4443       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
4444     }
4445     /* Face vertices have 2 + (2 interior, 1 hybrid) supports */
4446     for (f = fStart; f < fMax; ++f) {
4447       const PetscInt newp = vStartNew + (vEnd - vStart) + (f - fStart);
4448       const PetscInt *support;
4449       PetscInt       size, newSize = 2, s;
4450 
4451       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
4452       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
4453       for (s = 0; s < size; ++s) {
4454         if (support[s] >= cMax) newSize += 1;
4455         else newSize += 2;
4456       }
4457       ierr = DMPlexSetSupportSize(rdm, newp, newSize);CHKERRQ(ierr);
4458     }
4459     break;
4460   default:
4461     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
4462   }
4463   PetscFunctionReturn(0);
4464 }
4465 
4466 #undef __FUNCT__
4467 #define __FUNCT__ "CellRefinerSetCones"
4468 PetscErrorCode CellRefinerSetCones(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
4469 {
4470   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, r, p;
4471   PetscInt       maxSupportSize, *supportRef;
4472   PetscErrorCode ierr;
4473 
4474   PetscFunctionBegin;
4475   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
4476   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
4477   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
4478   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
4479   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
4480   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
4481   ierr = GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);CHKERRQ(ierr);
4482   ierr = GetDepthEnd_Private(depth, depthSize, &cEndNew, &fEndNew, &eEndNew, &vEndNew);CHKERRQ(ierr);
4483   switch (refiner) {
4484   case 1:
4485     /* Simplicial 2D */
4486     /*
4487      2
4488      |\
4489      | \
4490      |  \
4491      |   \
4492      | C  \
4493      |     \
4494      |      \
4495      2---1---1
4496      |\  D  / \
4497      | 2   0   \
4498      |A \ /  B  \
4499      0---0-------1
4500      */
4501     /* All cells have 3 faces */
4502     for (c = cStart; c < cEnd; ++c) {
4503       const PetscInt  newp = cStartNew + (c - cStart)*4;
4504       const PetscInt *cone, *ornt;
4505       PetscInt        coneNew[3], orntNew[3];
4506 
4507       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
4508       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
4509       /* A triangle */
4510       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
4511       orntNew[0] = ornt[0];
4512       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 2;
4513       orntNew[1] = -2;
4514       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
4515       orntNew[2] = ornt[2];
4516       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
4517       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
4518 #if 1
4519       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);
4520       for (p = 0; p < 3; ++p) {
4521         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);
4522       }
4523 #endif
4524       /* B triangle */
4525       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
4526       orntNew[0] = ornt[0];
4527       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
4528       orntNew[1] = ornt[1];
4529       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 0;
4530       orntNew[2] = -2;
4531       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
4532       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
4533 #if 1
4534       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);
4535       for (p = 0; p < 3; ++p) {
4536         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);
4537       }
4538 #endif
4539       /* C triangle */
4540       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 1;
4541       orntNew[0] = -2;
4542       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
4543       orntNew[1] = ornt[1];
4544       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
4545       orntNew[2] = ornt[2];
4546       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
4547       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
4548 #if 1
4549       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);
4550       for (p = 0; p < 3; ++p) {
4551         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);
4552       }
4553 #endif
4554       /* D triangle */
4555       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 0;
4556       orntNew[0] = 0;
4557       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 1;
4558       orntNew[1] = 0;
4559       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 2;
4560       orntNew[2] = 0;
4561       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
4562       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
4563 #if 1
4564       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);
4565       for (p = 0; p < 3; ++p) {
4566         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);
4567       }
4568 #endif
4569     }
4570     /* Split faces have 2 vertices and the same cells as the parent */
4571     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
4572     ierr = PetscMalloc((2 + maxSupportSize*2) * sizeof(PetscInt), &supportRef);CHKERRQ(ierr);
4573     for (f = fStart; f < fEnd; ++f) {
4574       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);
4575 
4576       for (r = 0; r < 2; ++r) {
4577         const PetscInt  newp = fStartNew + (f - fStart)*2 + r;
4578         const PetscInt *cone, *support;
4579         PetscInt        coneNew[2], coneSize, c, supportSize, s;
4580 
4581         ierr             = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
4582         coneNew[0]       = vStartNew + (cone[0] - vStart);
4583         coneNew[1]       = vStartNew + (cone[1] - vStart);
4584         coneNew[(r+1)%2] = newv;
4585         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4586 #if 1
4587         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4588         for (p = 0; p < 2; ++p) {
4589           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);
4590         }
4591 #endif
4592         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
4593         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
4594         for (s = 0; s < supportSize; ++s) {
4595           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
4596           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
4597           for (c = 0; c < coneSize; ++c) {
4598             if (cone[c] == f) break;
4599           }
4600           supportRef[s] = cStartNew + (support[s] - cStart)*4 + (c+r)%3;
4601         }
4602         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
4603 #if 1
4604         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4605         for (p = 0; p < supportSize; ++p) {
4606           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);
4607         }
4608 #endif
4609       }
4610     }
4611     /* Interior faces have 2 vertices and 2 cells */
4612     for (c = cStart; c < cEnd; ++c) {
4613       const PetscInt *cone;
4614 
4615       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
4616       for (r = 0; r < 3; ++r) {
4617         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*3 + r;
4618         PetscInt       coneNew[2];
4619         PetscInt       supportNew[2];
4620 
4621         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r]       - fStart);
4622         coneNew[1] = vStartNew + (vEnd - vStart) + (cone[(r+1)%3] - fStart);
4623         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4624 #if 1
4625         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4626         for (p = 0; p < 2; ++p) {
4627           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);
4628         }
4629 #endif
4630         supportNew[0] = (c - cStart)*4 + (r+1)%3;
4631         supportNew[1] = (c - cStart)*4 + 3;
4632         ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
4633 #if 1
4634         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4635         for (p = 0; p < 2; ++p) {
4636           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);
4637         }
4638 #endif
4639       }
4640     }
4641     /* Old vertices have identical supports */
4642     for (v = vStart; v < vEnd; ++v) {
4643       const PetscInt  newp = vStartNew + (v - vStart);
4644       const PetscInt *support, *cone;
4645       PetscInt        size, s;
4646 
4647       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
4648       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
4649       for (s = 0; s < size; ++s) {
4650         PetscInt r = 0;
4651 
4652         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
4653         if (cone[1] == v) r = 1;
4654         supportRef[s] = fStartNew + (support[s] - fStart)*2 + r;
4655       }
4656       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
4657 #if 1
4658       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
4659       for (p = 0; p < size; ++p) {
4660         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);
4661       }
4662 #endif
4663     }
4664     /* Face vertices have 2 + cells*2 supports */
4665     for (f = fStart; f < fEnd; ++f) {
4666       const PetscInt  newp = vStartNew + (vEnd - vStart) + (f - fStart);
4667       const PetscInt *cone, *support;
4668       PetscInt        size, s;
4669 
4670       ierr          = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
4671       ierr          = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
4672       supportRef[0] = fStartNew + (f - fStart)*2 + 0;
4673       supportRef[1] = fStartNew + (f - fStart)*2 + 1;
4674       for (s = 0; s < size; ++s) {
4675         PetscInt r = 0;
4676 
4677         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
4678         if      (cone[1] == f) r = 1;
4679         else if (cone[2] == f) r = 2;
4680         supportRef[2+s*2+0] = fStartNew + (fEnd - fStart)*2 + (support[s] - cStart)*3 + (r+2)%3;
4681         supportRef[2+s*2+1] = fStartNew + (fEnd - fStart)*2 + (support[s] - cStart)*3 + r;
4682       }
4683       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
4684 #if 1
4685       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
4686       for (p = 0; p < 2+size*2; ++p) {
4687         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);
4688       }
4689 #endif
4690     }
4691     ierr = PetscFree(supportRef);CHKERRQ(ierr);
4692     break;
4693   case 2:
4694     /* Hex 2D */
4695     /*
4696      3---------2---------2
4697      |         |         |
4698      |    D    2    C    |
4699      |         |         |
4700      3----3----0----1----1
4701      |         |         |
4702      |    A    0    B    |
4703      |         |         |
4704      0---------0---------1
4705      */
4706     /* All cells have 4 faces */
4707     for (c = cStart; c < cEnd; ++c) {
4708       const PetscInt  newp = (c - cStart)*4;
4709       const PetscInt *cone, *ornt;
4710       PetscInt        coneNew[4], orntNew[4];
4711 
4712       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
4713       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
4714       /* A quad */
4715       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
4716       orntNew[0] = ornt[0];
4717       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 0;
4718       orntNew[1] = 0;
4719       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 3;
4720       orntNew[2] = -2;
4721       coneNew[3] = fStartNew + (cone[3] - fStart)*2 + (ornt[3] < 0 ? 0 : 1);
4722       orntNew[3] = ornt[3];
4723       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
4724       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
4725 #if 1
4726       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);
4727       for (p = 0; p < 4; ++p) {
4728         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);
4729       }
4730 #endif
4731       /* B quad */
4732       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
4733       orntNew[0] = ornt[0];
4734       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
4735       orntNew[1] = ornt[1];
4736       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 1;
4737       orntNew[2] = 0;
4738       coneNew[3] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 0;
4739       orntNew[3] = -2;
4740       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
4741       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
4742 #if 1
4743       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);
4744       for (p = 0; p < 4; ++p) {
4745         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);
4746       }
4747 #endif
4748       /* C quad */
4749       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 1;
4750       orntNew[0] = -2;
4751       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
4752       orntNew[1] = ornt[1];
4753       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
4754       orntNew[2] = ornt[2];
4755       coneNew[3] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 2;
4756       orntNew[3] = 0;
4757       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
4758       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
4759 #if 1
4760       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);
4761       for (p = 0; p < 4; ++p) {
4762         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);
4763       }
4764 #endif
4765       /* D quad */
4766       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 3;
4767       orntNew[0] = 0;
4768       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 2;
4769       orntNew[1] = -2;
4770       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
4771       orntNew[2] = ornt[2];
4772       coneNew[3] = fStartNew + (cone[3] - fStart)*2 + (ornt[3] < 0 ? 1 : 0);
4773       orntNew[3] = ornt[3];
4774       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
4775       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
4776 #if 1
4777       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);
4778       for (p = 0; p < 4; ++p) {
4779         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);
4780       }
4781 #endif
4782     }
4783     /* Split faces have 2 vertices and the same cells as the parent */
4784     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
4785     ierr = PetscMalloc((2 + maxSupportSize*2) * sizeof(PetscInt), &supportRef);CHKERRQ(ierr);
4786     for (f = fStart; f < fEnd; ++f) {
4787       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);
4788 
4789       for (r = 0; r < 2; ++r) {
4790         const PetscInt  newp = fStartNew + (f - fStart)*2 + r;
4791         const PetscInt *cone, *support;
4792         PetscInt        coneNew[2], coneSize, c, supportSize, s;
4793 
4794         ierr             = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
4795         coneNew[0]       = vStartNew + (cone[0] - vStart);
4796         coneNew[1]       = vStartNew + (cone[1] - vStart);
4797         coneNew[(r+1)%2] = newv;
4798         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4799 #if 1
4800         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4801         for (p = 0; p < 2; ++p) {
4802           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);
4803         }
4804 #endif
4805         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
4806         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
4807         for (s = 0; s < supportSize; ++s) {
4808           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
4809           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
4810           for (c = 0; c < coneSize; ++c) {
4811             if (cone[c] == f) break;
4812           }
4813           supportRef[s] = cStartNew + (support[s] - cStart)*4 + (c+r)%4;
4814         }
4815         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
4816 #if 1
4817         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4818         for (p = 0; p < supportSize; ++p) {
4819           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);
4820         }
4821 #endif
4822       }
4823     }
4824     /* Interior faces have 2 vertices and 2 cells */
4825     for (c = cStart; c < cEnd; ++c) {
4826       const PetscInt *cone;
4827       PetscInt        coneNew[2], supportNew[2];
4828 
4829       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
4830       for (r = 0; r < 4; ++r) {
4831         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*4 + r;
4832 
4833         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r] - fStart);
4834         coneNew[1] = vStartNew + (vEnd - vStart) + (fEnd    - fStart) + (c - cStart);
4835         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4836 #if 1
4837         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4838         for (p = 0; p < 2; ++p) {
4839           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);
4840         }
4841 #endif
4842         supportNew[0] = (c - cStart)*4 + r;
4843         supportNew[1] = (c - cStart)*4 + (r+1)%4;
4844         ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
4845 #if 1
4846         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4847         for (p = 0; p < 2; ++p) {
4848           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);
4849         }
4850 #endif
4851       }
4852     }
4853     /* Old vertices have identical supports */
4854     for (v = vStart; v < vEnd; ++v) {
4855       const PetscInt  newp = vStartNew + (v - vStart);
4856       const PetscInt *support, *cone;
4857       PetscInt        size, s;
4858 
4859       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
4860       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
4861       for (s = 0; s < size; ++s) {
4862         PetscInt r = 0;
4863 
4864         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
4865         if (cone[1] == v) r = 1;
4866         supportRef[s] = fStartNew + (support[s] - fStart)*2 + r;
4867       }
4868       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
4869 #if 1
4870       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
4871       for (p = 0; p < size; ++p) {
4872         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);
4873       }
4874 #endif
4875     }
4876     /* Face vertices have 2 + cells supports */
4877     for (f = fStart; f < fEnd; ++f) {
4878       const PetscInt  newp = vStartNew + (vEnd - vStart) + (f - fStart);
4879       const PetscInt *cone, *support;
4880       PetscInt        size, s;
4881 
4882       ierr          = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
4883       ierr          = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
4884       supportRef[0] = fStartNew + (f - fStart)*2 + 0;
4885       supportRef[1] = fStartNew + (f - fStart)*2 + 1;
4886       for (s = 0; s < size; ++s) {
4887         PetscInt r = 0;
4888 
4889         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
4890         if      (cone[1] == f) r = 1;
4891         else if (cone[2] == f) r = 2;
4892         else if (cone[3] == f) r = 3;
4893         supportRef[2+s] = fStartNew + (fEnd - fStart)*2 + (support[s] - cStart)*4 + r;
4894       }
4895       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
4896 #if 1
4897       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
4898       for (p = 0; p < 2+size; ++p) {
4899         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);
4900       }
4901 #endif
4902     }
4903     /* Cell vertices have 4 supports */
4904     for (c = cStart; c < cEnd; ++c) {
4905       const PetscInt newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (c - cStart);
4906       PetscInt       supportNew[4];
4907 
4908       for (r = 0; r < 4; ++r) {
4909         supportNew[r] = fStartNew + (fEnd - fStart)*2 + (c - cStart)*4 + r;
4910       }
4911       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
4912     }
4913     break;
4914   case 3:
4915     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
4916     cMax = PetscMin(cEnd, cMax);
4917     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
4918     fMax = PetscMin(fEnd, fMax);
4919     /* Interior cells have 3 faces */
4920     for (c = cStart; c < cMax; ++c) {
4921       const PetscInt  newp = cStartNew + (c - cStart)*4;
4922       const PetscInt *cone, *ornt;
4923       PetscInt        coneNew[3], orntNew[3];
4924 
4925       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
4926       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
4927       /* A triangle */
4928       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
4929       orntNew[0] = ornt[0];
4930       coneNew[1] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 2;
4931       orntNew[1] = -2;
4932       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
4933       orntNew[2] = ornt[2];
4934       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
4935       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
4936 #if 1
4937       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);
4938       for (p = 0; p < 3; ++p) {
4939         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);
4940       }
4941 #endif
4942       /* B triangle */
4943       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
4944       orntNew[0] = ornt[0];
4945       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
4946       orntNew[1] = ornt[1];
4947       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 0;
4948       orntNew[2] = -2;
4949       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
4950       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
4951 #if 1
4952       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);
4953       for (p = 0; p < 3; ++p) {
4954         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);
4955       }
4956 #endif
4957       /* C triangle */
4958       coneNew[0] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 1;
4959       orntNew[0] = -2;
4960       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
4961       orntNew[1] = ornt[1];
4962       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
4963       orntNew[2] = ornt[2];
4964       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
4965       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
4966 #if 1
4967       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);
4968       for (p = 0; p < 3; ++p) {
4969         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);
4970       }
4971 #endif
4972       /* D triangle */
4973       coneNew[0] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 0;
4974       orntNew[0] = 0;
4975       coneNew[1] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 1;
4976       orntNew[1] = 0;
4977       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 2;
4978       orntNew[2] = 0;
4979       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
4980       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
4981 #if 1
4982       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);
4983       for (p = 0; p < 3; ++p) {
4984         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);
4985       }
4986 #endif
4987     }
4988     /*
4989      2----3----3
4990      |         |
4991      |    B    |
4992      |         |
4993      0----4--- 1
4994      |         |
4995      |    A    |
4996      |         |
4997      0----2----1
4998      */
4999     /* Hybrid cells have 4 faces */
5000     for (c = cMax; c < cEnd; ++c) {
5001       const PetscInt  newp = cStartNew + (cMax - cStart)*4 + (c - cMax)*2;
5002       const PetscInt *cone, *ornt;
5003       PetscInt        coneNew[4], orntNew[4];
5004 
5005       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
5006       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
5007       /* A quad */
5008       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
5009       orntNew[0] = ornt[0];
5010       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
5011       orntNew[1] = ornt[1];
5012       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (cone[2] - fMax);
5013       orntNew[2] = 0;
5014       coneNew[3] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (fEnd    - fMax) + (c - cMax);
5015       orntNew[3] = 0;
5016       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
5017       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
5018 #if 1
5019       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);
5020       for (p = 0; p < 4; ++p) {
5021         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);
5022       }
5023 #endif
5024       /* B quad */
5025       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
5026       orntNew[0] = ornt[0];
5027       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
5028       orntNew[1] = ornt[1];
5029       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (fEnd    - fMax) + (c - cMax);
5030       orntNew[2] = 0;
5031       coneNew[3] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (cone[3] - fMax);
5032       orntNew[3] = 0;
5033       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
5034       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
5035 #if 1
5036       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);
5037       for (p = 0; p < 4; ++p) {
5038         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);
5039       }
5040 #endif
5041     }
5042     /* Interior split faces have 2 vertices and the same cells as the parent */
5043     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
5044     ierr = PetscMalloc((2 + maxSupportSize*2) * sizeof(PetscInt), &supportRef);CHKERRQ(ierr);
5045     for (f = fStart; f < fMax; ++f) {
5046       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);
5047 
5048       for (r = 0; r < 2; ++r) {
5049         const PetscInt  newp = fStartNew + (f - fStart)*2 + r;
5050         const PetscInt *cone, *support;
5051         PetscInt        coneNew[2], coneSize, c, supportSize, s;
5052 
5053         ierr             = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
5054         coneNew[0]       = vStartNew + (cone[0] - vStart);
5055         coneNew[1]       = vStartNew + (cone[1] - vStart);
5056         coneNew[(r+1)%2] = newv;
5057         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5058 #if 1
5059         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5060         for (p = 0; p < 2; ++p) {
5061           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);
5062         }
5063 #endif
5064         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
5065         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
5066         for (s = 0; s < supportSize; ++s) {
5067           if (support[s] >= cMax) {
5068             supportRef[s] = cStartNew + (cMax - cStart)*4 + (support[s] - cMax)*2 + r;
5069           } else {
5070             ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
5071             ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
5072             for (c = 0; c < coneSize; ++c) {
5073               if (cone[c] == f) break;
5074             }
5075             supportRef[s] = cStartNew + (support[s] - cStart)*4 + (c+r)%3;
5076           }
5077         }
5078         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
5079 #if 1
5080         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5081         for (p = 0; p < supportSize; ++p) {
5082           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);
5083         }
5084 #endif
5085       }
5086     }
5087     /* Interior cell faces have 2 vertices and 2 cells */
5088     for (c = cStart; c < cMax; ++c) {
5089       const PetscInt *cone;
5090 
5091       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
5092       for (r = 0; r < 3; ++r) {
5093         const PetscInt newp = fStartNew + (fMax - fStart)*2 + (c - cStart)*3 + r;
5094         PetscInt       coneNew[2];
5095         PetscInt       supportNew[2];
5096 
5097         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r]       - fStart);
5098         coneNew[1] = vStartNew + (vEnd - vStart) + (cone[(r+1)%3] - fStart);
5099         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5100 #if 1
5101         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5102         for (p = 0; p < 2; ++p) {
5103           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);
5104         }
5105 #endif
5106         supportNew[0] = (c - cStart)*4 + (r+1)%3;
5107         supportNew[1] = (c - cStart)*4 + 3;
5108         ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
5109 #if 1
5110         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5111         for (p = 0; p < 2; ++p) {
5112           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);
5113         }
5114 #endif
5115       }
5116     }
5117     /* Interior hybrid faces have 2 vertices and the same cells */
5118     for (f = fMax; f < fEnd; ++f) {
5119       const PetscInt  newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (f - fMax);
5120       const PetscInt *cone;
5121       const PetscInt *support;
5122       PetscInt        coneNew[2];
5123       PetscInt        supportNew[2];
5124       PetscInt        size, s, r;
5125 
5126       ierr       = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
5127       coneNew[0] = vStartNew + (cone[0] - vStart);
5128       coneNew[1] = vStartNew + (cone[1] - vStart);
5129       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5130 #if 1
5131       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5132       for (p = 0; p < 2; ++p) {
5133         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);
5134       }
5135 #endif
5136       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
5137       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
5138       for (s = 0; s < size; ++s) {
5139         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
5140         for (r = 0; r < 2; ++r) {
5141           if (cone[r+2] == f) break;
5142         }
5143         supportNew[s] = (cMax - cStart)*4 + (support[s] - cMax)*2 + r;
5144       }
5145       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
5146 #if 1
5147       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5148       for (p = 0; p < size; ++p) {
5149         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);
5150       }
5151 #endif
5152     }
5153     /* Cell hybrid faces have 2 vertices and 2 cells */
5154     for (c = cMax; c < cEnd; ++c) {
5155       const PetscInt  newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (fEnd - fMax) + (c - cMax);
5156       const PetscInt *cone;
5157       PetscInt        coneNew[2];
5158       PetscInt        supportNew[2];
5159 
5160       ierr       = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
5161       coneNew[0] = vStartNew + (vEnd - vStart) + (cone[0] - fStart);
5162       coneNew[1] = vStartNew + (vEnd - vStart) + (cone[1] - fStart);
5163       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5164 #if 1
5165       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5166       for (p = 0; p < 2; ++p) {
5167         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);
5168       }
5169 #endif
5170       supportNew[0] = (cMax - cStart)*4 + (c - cMax)*2 + 0;
5171       supportNew[1] = (cMax - cStart)*4 + (c - cMax)*2 + 1;
5172       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
5173 #if 1
5174       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5175       for (p = 0; p < 2; ++p) {
5176         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);
5177       }
5178 #endif
5179     }
5180     /* Old vertices have identical supports */
5181     for (v = vStart; v < vEnd; ++v) {
5182       const PetscInt  newp = vStartNew + (v - vStart);
5183       const PetscInt *support, *cone;
5184       PetscInt        size, s;
5185 
5186       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
5187       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
5188       for (s = 0; s < size; ++s) {
5189         if (support[s] >= fMax) {
5190           supportRef[s] = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (support[s] - fMax);
5191         } else {
5192           PetscInt r = 0;
5193 
5194           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
5195           if (cone[1] == v) r = 1;
5196           supportRef[s] = fStartNew + (support[s] - fStart)*2 + r;
5197         }
5198       }
5199       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
5200 #if 1
5201       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
5202       for (p = 0; p < size; ++p) {
5203         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);
5204       }
5205 #endif
5206     }
5207     /* Face vertices have 2 + (2 interior, 1 hybrid) supports */
5208     for (f = fStart; f < fMax; ++f) {
5209       const PetscInt  newp = vStartNew + (vEnd - vStart) + (f - fStart);
5210       const PetscInt *cone, *support;
5211       PetscInt        size, newSize = 2, s;
5212 
5213       ierr          = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
5214       ierr          = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
5215       supportRef[0] = fStartNew + (f - fStart)*2 + 0;
5216       supportRef[1] = fStartNew + (f - fStart)*2 + 1;
5217       for (s = 0; s < size; ++s) {
5218         PetscInt r = 0;
5219 
5220         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
5221         if (support[s] >= cMax) {
5222           supportRef[newSize+0] = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (fEnd - fMax) + (support[s] - cMax);
5223 
5224           newSize += 1;
5225         } else {
5226           if      (cone[1] == f) r = 1;
5227           else if (cone[2] == f) r = 2;
5228           supportRef[newSize+0] = fStartNew + (fMax - fStart)*2 + (support[s] - cStart)*3 + (r+2)%3;
5229           supportRef[newSize+1] = fStartNew + (fMax - fStart)*2 + (support[s] - cStart)*3 + r;
5230 
5231           newSize += 2;
5232         }
5233       }
5234       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
5235 #if 1
5236       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
5237       for (p = 0; p < newSize; ++p) {
5238         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);
5239       }
5240 #endif
5241     }
5242     ierr = PetscFree(supportRef);CHKERRQ(ierr);
5243     break;
5244   default:
5245     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
5246   }
5247   PetscFunctionReturn(0);
5248 }
5249 
5250 #undef __FUNCT__
5251 #define __FUNCT__ "CellRefinerSetCoordinates"
5252 PetscErrorCode CellRefinerSetCoordinates(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
5253 {
5254   PetscSection   coordSection, coordSectionNew;
5255   Vec            coordinates, coordinatesNew;
5256   PetscScalar   *coords, *coordsNew;
5257   PetscInt       dim, depth, coordSizeNew, cStart, cEnd, c, vStart, vStartNew, vEnd, v, fStart, fEnd, fMax, f;
5258   PetscErrorCode ierr;
5259 
5260   PetscFunctionBegin;
5261   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
5262   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
5263   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
5264   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
5265   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
5266   ierr = DMPlexGetHybridBounds(dm, NULL, &fMax, NULL, NULL);CHKERRQ(ierr);
5267   ierr = GetDepthStart_Private(depth, depthSize, NULL, NULL, NULL, &vStartNew);CHKERRQ(ierr);
5268   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
5269   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)dm), &coordSectionNew);CHKERRQ(ierr);
5270   ierr = PetscSectionSetNumFields(coordSectionNew, 1);CHKERRQ(ierr);
5271   ierr = PetscSectionSetFieldComponents(coordSectionNew, 0, dim);CHKERRQ(ierr);
5272   ierr = PetscSectionSetChart(coordSectionNew, vStartNew, vStartNew+depthSize[0]);CHKERRQ(ierr);
5273   if (fMax < 0) fMax = fEnd;
5274   switch (refiner) {
5275   case 1:
5276   case 2:
5277   case 3:
5278     /* Simplicial and Hex 2D */
5279     /* All vertices have the dim coordinates */
5280     for (v = vStartNew; v < vStartNew+depthSize[0]; ++v) {
5281       ierr = PetscSectionSetDof(coordSectionNew, v, dim);CHKERRQ(ierr);
5282       ierr = PetscSectionSetFieldDof(coordSectionNew, v, 0, dim);CHKERRQ(ierr);
5283     }
5284     ierr = PetscSectionSetUp(coordSectionNew);CHKERRQ(ierr);
5285     ierr = DMPlexSetCoordinateSection(rdm, coordSectionNew);CHKERRQ(ierr);
5286     ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
5287     ierr = PetscSectionGetStorageSize(coordSectionNew, &coordSizeNew);CHKERRQ(ierr);
5288     ierr = VecCreate(PetscObjectComm((PetscObject)dm), &coordinatesNew);CHKERRQ(ierr);
5289     ierr = PetscObjectSetName((PetscObject) coordinatesNew, "coordinates");CHKERRQ(ierr);
5290     ierr = VecSetSizes(coordinatesNew, coordSizeNew, PETSC_DETERMINE);CHKERRQ(ierr);
5291     ierr = VecSetFromOptions(coordinatesNew);CHKERRQ(ierr);
5292     ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
5293     ierr = VecGetArray(coordinatesNew, &coordsNew);CHKERRQ(ierr);
5294     /* Old vertices have the same coordinates */
5295     for (v = vStart; v < vEnd; ++v) {
5296       const PetscInt newv = vStartNew + (v - vStart);
5297       PetscInt       off, offnew, d;
5298 
5299       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
5300       ierr = PetscSectionGetOffset(coordSectionNew, newv, &offnew);CHKERRQ(ierr);
5301       for (d = 0; d < dim; ++d) {
5302         coordsNew[offnew+d] = coords[off+d];
5303       }
5304     }
5305     /* Face vertices have the average of endpoint coordinates */
5306     for (f = fStart; f < fMax; ++f) {
5307       const PetscInt  newv = vStartNew + (vEnd - vStart) + (f - fStart);
5308       const PetscInt *cone;
5309       PetscInt        coneSize, offA, offB, offnew, d;
5310 
5311       ierr = DMPlexGetConeSize(dm, f, &coneSize);CHKERRQ(ierr);
5312       if (coneSize != 2) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Face %d cone should have two vertices, not %d", f, coneSize);
5313       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
5314       ierr = PetscSectionGetOffset(coordSection, cone[0], &offA);CHKERRQ(ierr);
5315       ierr = PetscSectionGetOffset(coordSection, cone[1], &offB);CHKERRQ(ierr);
5316       ierr = PetscSectionGetOffset(coordSectionNew, newv, &offnew);CHKERRQ(ierr);
5317       for (d = 0; d < dim; ++d) {
5318         coordsNew[offnew+d] = 0.5*(coords[offA+d] + coords[offB+d]);
5319       }
5320     }
5321     /* Just Hex 2D */
5322     if (refiner == 2) {
5323       /* Cell vertices have the average of corner coordinates */
5324       for (c = cStart; c < cEnd; ++c) {
5325         const PetscInt newv = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (c - cStart);
5326         PetscInt      *cone = NULL;
5327         PetscInt       closureSize, coneSize = 0, offA, offB, offC, offD, offnew, p, d;
5328 
5329         ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
5330         for (p = 0; p < closureSize*2; p += 2) {
5331           const PetscInt point = cone[p];
5332           if ((point >= vStart) && (point < vEnd)) cone[coneSize++] = point;
5333         }
5334         if (coneSize != 4) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Quad %d cone should have four vertices, not %d", c, coneSize);
5335         ierr = PetscSectionGetOffset(coordSection, cone[0], &offA);CHKERRQ(ierr);
5336         ierr = PetscSectionGetOffset(coordSection, cone[1], &offB);CHKERRQ(ierr);
5337         ierr = PetscSectionGetOffset(coordSection, cone[2], &offC);CHKERRQ(ierr);
5338         ierr = PetscSectionGetOffset(coordSection, cone[3], &offD);CHKERRQ(ierr);
5339         ierr = PetscSectionGetOffset(coordSectionNew, newv, &offnew);CHKERRQ(ierr);
5340         for (d = 0; d < dim; ++d) {
5341           coordsNew[offnew+d] = 0.25*(coords[offA+d] + coords[offB+d] + coords[offC+d] + coords[offD+d]);
5342         }
5343         ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
5344       }
5345     }
5346     ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
5347     ierr = VecRestoreArray(coordinatesNew, &coordsNew);CHKERRQ(ierr);
5348     ierr = DMSetCoordinatesLocal(rdm, coordinatesNew);CHKERRQ(ierr);
5349     ierr = VecDestroy(&coordinatesNew);CHKERRQ(ierr);
5350     ierr = PetscSectionDestroy(&coordSectionNew);CHKERRQ(ierr);
5351     break;
5352   default:
5353     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
5354   }
5355   PetscFunctionReturn(0);
5356 }
5357 
5358 #undef __FUNCT__
5359 #define __FUNCT__ "DMPlexCreateProcessSF"
5360 PetscErrorCode DMPlexCreateProcessSF(DM dm, PetscSF sfPoint, IS *processRanks, PetscSF *sfProcess)
5361 {
5362   PetscInt           numRoots, numLeaves, l;
5363   const PetscInt    *localPoints;
5364   const PetscSFNode *remotePoints;
5365   PetscInt          *localPointsNew;
5366   PetscSFNode       *remotePointsNew;
5367   PetscInt          *ranks, *ranksNew;
5368   PetscErrorCode     ierr;
5369 
5370   PetscFunctionBegin;
5371   ierr = PetscSFGetGraph(sfPoint, &numRoots, &numLeaves, &localPoints, &remotePoints);CHKERRQ(ierr);
5372   ierr = PetscMalloc(numLeaves * sizeof(PetscInt), &ranks);CHKERRQ(ierr);
5373   for (l = 0; l < numLeaves; ++l) {
5374     ranks[l] = remotePoints[l].rank;
5375   }
5376   ierr = PetscSortRemoveDupsInt(&numLeaves, ranks);CHKERRQ(ierr);
5377   ierr = PetscMalloc(numLeaves * sizeof(PetscInt),    &ranksNew);CHKERRQ(ierr);
5378   ierr = PetscMalloc(numLeaves * sizeof(PetscInt),    &localPointsNew);CHKERRQ(ierr);
5379   ierr = PetscMalloc(numLeaves * sizeof(PetscSFNode), &remotePointsNew);CHKERRQ(ierr);
5380   for (l = 0; l < numLeaves; ++l) {
5381     ranksNew[l]              = ranks[l];
5382     localPointsNew[l]        = l;
5383     remotePointsNew[l].index = 0;
5384     remotePointsNew[l].rank  = ranksNew[l];
5385   }
5386   ierr = PetscFree(ranks);CHKERRQ(ierr);
5387   ierr = ISCreateGeneral(PetscObjectComm((PetscObject)dm), numLeaves, ranksNew, PETSC_OWN_POINTER, processRanks);CHKERRQ(ierr);
5388   ierr = PetscSFCreate(PetscObjectComm((PetscObject)dm), sfProcess);CHKERRQ(ierr);
5389   ierr = PetscSFSetFromOptions(*sfProcess);CHKERRQ(ierr);
5390   ierr = PetscSFSetGraph(*sfProcess, 1, numLeaves, localPointsNew, PETSC_OWN_POINTER, remotePointsNew, PETSC_OWN_POINTER);CHKERRQ(ierr);
5391   PetscFunctionReturn(0);
5392 }
5393 
5394 #undef __FUNCT__
5395 #define __FUNCT__ "CellRefinerCreateSF"
5396 PetscErrorCode CellRefinerCreateSF(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
5397 {
5398   PetscSF            sf, sfNew, sfProcess;
5399   IS                 processRanks;
5400   MPI_Datatype       depthType;
5401   PetscInt           numRoots, numLeaves, numLeavesNew = 0, l, m;
5402   const PetscInt    *localPoints, *neighbors;
5403   const PetscSFNode *remotePoints;
5404   PetscInt          *localPointsNew;
5405   PetscSFNode       *remotePointsNew;
5406   PetscInt          *depthSizeOld, *rdepthSize, *rdepthSizeOld, *rdepthMaxOld, *rvStart, *rvStartNew, *reStart, *reStartNew, *rfStart, *rfStartNew, *rcStart, *rcStartNew;
5407   PetscInt           depth, numNeighbors, pStartNew, pEndNew, cStart, cStartNew, cEnd, cMax, vStart, vStartNew, vEnd, vMax, fStart, fStartNew, fEnd, fMax, eStart, eStartNew, eEnd, eMax, r, n;
5408   PetscErrorCode     ierr;
5409 
5410   PetscFunctionBegin;
5411   ierr = DMPlexGetChart(rdm, &pStartNew, &pEndNew);CHKERRQ(ierr);
5412   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
5413   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
5414   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
5415   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
5416   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
5417   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
5418   ierr = GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);CHKERRQ(ierr);
5419   switch (refiner) {
5420   case 3:
5421     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
5422     cMax = PetscMin(cEnd, cMax);
5423     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
5424     fMax = PetscMin(fEnd, fMax);
5425   }
5426   ierr = DMGetPointSF(dm, &sf);CHKERRQ(ierr);
5427   ierr = DMGetPointSF(rdm, &sfNew);CHKERRQ(ierr);
5428   /* Caculate size of new SF */
5429   ierr = PetscSFGetGraph(sf, &numRoots, &numLeaves, &localPoints, &remotePoints);CHKERRQ(ierr);
5430   if (numRoots < 0) PetscFunctionReturn(0);
5431   for (l = 0; l < numLeaves; ++l) {
5432     const PetscInt p = localPoints[l];
5433 
5434     switch (refiner) {
5435     case 1:
5436       /* Simplicial 2D */
5437       if ((p >= vStart) && (p < vEnd)) {
5438         /* Old vertices stay the same */
5439         ++numLeavesNew;
5440       } else if ((p >= fStart) && (p < fEnd)) {
5441         /* Old faces add new faces and vertex */
5442         numLeavesNew += 1 + 2;
5443       } else if ((p >= cStart) && (p < cEnd)) {
5444         /* Old cells add new cells and interior faces */
5445         numLeavesNew += 4 + 3;
5446       }
5447       break;
5448     case 2:
5449       /* Hex 2D */
5450       if ((p >= vStart) && (p < vEnd)) {
5451         /* Old vertices stay the same */
5452         ++numLeavesNew;
5453       } else if ((p >= fStart) && (p < fEnd)) {
5454         /* Old faces add new faces and vertex */
5455         numLeavesNew += 1 + 2;
5456       } else if ((p >= cStart) && (p < cEnd)) {
5457         /* Old cells add new cells and interior faces */
5458         numLeavesNew += 4 + 4;
5459       }
5460       break;
5461     default:
5462       SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
5463     }
5464   }
5465   /* Communicate depthSizes for each remote rank */
5466   ierr = DMPlexCreateProcessSF(dm, sf, &processRanks, &sfProcess);CHKERRQ(ierr);
5467   ierr = ISGetLocalSize(processRanks, &numNeighbors);CHKERRQ(ierr);
5468   ierr = PetscMalloc5((depth+1)*numNeighbors,PetscInt,&rdepthSize,numNeighbors,PetscInt,&rvStartNew,numNeighbors,PetscInt,&reStartNew,numNeighbors,PetscInt,&rfStartNew,numNeighbors,PetscInt,&rcStartNew);CHKERRQ(ierr);
5469   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);
5470   ierr = MPI_Type_contiguous(depth+1, MPIU_INT, &depthType);CHKERRQ(ierr);
5471   ierr = MPI_Type_commit(&depthType);CHKERRQ(ierr);
5472   ierr = PetscSFBcastBegin(sfProcess, depthType, depthSize, rdepthSize);CHKERRQ(ierr);
5473   ierr = PetscSFBcastEnd(sfProcess, depthType, depthSize, rdepthSize);CHKERRQ(ierr);
5474   for (n = 0; n < numNeighbors; ++n) {
5475     ierr = GetDepthStart_Private(depth, &rdepthSize[n*(depth+1)], &rcStartNew[n], &rfStartNew[n], &reStartNew[n], &rvStartNew[n]);CHKERRQ(ierr);
5476   }
5477   depthSizeOld[depth]   = cMax;
5478   depthSizeOld[0]       = vMax;
5479   depthSizeOld[depth-1] = fMax;
5480   depthSizeOld[1]       = eMax;
5481 
5482   ierr = PetscSFBcastBegin(sfProcess, depthType, depthSizeOld, rdepthMaxOld);CHKERRQ(ierr);
5483   ierr = PetscSFBcastEnd(sfProcess, depthType, depthSizeOld, rdepthMaxOld);CHKERRQ(ierr);
5484 
5485   depthSizeOld[depth]   = cEnd - cStart;
5486   depthSizeOld[0]       = vEnd - vStart;
5487   depthSizeOld[depth-1] = fEnd - fStart;
5488   depthSizeOld[1]       = eEnd - eStart;
5489 
5490   ierr = PetscSFBcastBegin(sfProcess, depthType, depthSizeOld, rdepthSizeOld);CHKERRQ(ierr);
5491   ierr = PetscSFBcastEnd(sfProcess, depthType, depthSizeOld, rdepthSizeOld);CHKERRQ(ierr);
5492   for (n = 0; n < numNeighbors; ++n) {
5493     ierr = GetDepthStart_Private(depth, &rdepthSizeOld[n*(depth+1)], &rcStart[n], &rfStart[n], &reStart[n], &rvStart[n]);CHKERRQ(ierr);
5494   }
5495   ierr = MPI_Type_free(&depthType);CHKERRQ(ierr);
5496   ierr = PetscSFDestroy(&sfProcess);CHKERRQ(ierr);
5497   /* Calculate new point SF */
5498   ierr = PetscMalloc(numLeavesNew * sizeof(PetscInt),    &localPointsNew);CHKERRQ(ierr);
5499   ierr = PetscMalloc(numLeavesNew * sizeof(PetscSFNode), &remotePointsNew);CHKERRQ(ierr);
5500   ierr = ISGetIndices(processRanks, &neighbors);CHKERRQ(ierr);
5501   for (l = 0, m = 0; l < numLeaves; ++l) {
5502     PetscInt    p     = localPoints[l];
5503     PetscInt    rp    = remotePoints[l].index, n;
5504     PetscMPIInt rrank = remotePoints[l].rank;
5505 
5506     ierr = PetscFindInt(rrank, numNeighbors, neighbors, &n);CHKERRQ(ierr);
5507     if (n < 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Could not locate remote rank %d", rrank);
5508     switch (refiner) {
5509     case 1:
5510       /* Simplicial 2D */
5511       if ((p >= vStart) && (p < vEnd)) {
5512         /* Old vertices stay the same */
5513         localPointsNew[m]        = vStartNew     + (p  - vStart);
5514         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
5515         remotePointsNew[m].rank  = rrank;
5516         ++m;
5517       } else if ((p >= fStart) && (p < fEnd)) {
5518         /* Old faces add new faces and vertex */
5519         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - fStart);
5520         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - rfStart[n]);
5521         remotePointsNew[m].rank  = rrank;
5522         ++m;
5523         for (r = 0; r < 2; ++r, ++m) {
5524           localPointsNew[m]        = fStartNew     + (p  - fStart)*2     + r;
5525           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*2 + r;
5526           remotePointsNew[m].rank  = rrank;
5527         }
5528       } else if ((p >= cStart) && (p < cEnd)) {
5529         /* Old cells add new cells and interior faces */
5530         for (r = 0; r < 4; ++r, ++m) {
5531           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
5532           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
5533           remotePointsNew[m].rank  = rrank;
5534         }
5535         for (r = 0; r < 3; ++r, ++m) {
5536           localPointsNew[m]        = fStartNew     + (fEnd - fStart)*2                    + (p  - cStart)*3     + r;
5537           remotePointsNew[m].index = rfStartNew[n] + rdepthSizeOld[n*(depth+1)+depth-1]*2 + (rp - rcStart[n])*3 + r;
5538           remotePointsNew[m].rank  = rrank;
5539         }
5540       }
5541       break;
5542     case 2:
5543       /* Hex 2D */
5544       if ((p >= vStart) && (p < vEnd)) {
5545         /* Old vertices stay the same */
5546         localPointsNew[m]        = vStartNew     + (p  - vStart);
5547         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
5548         remotePointsNew[m].rank  = rrank;
5549         ++m;
5550       } else if ((p >= fStart) && (p < fEnd)) {
5551         /* Old faces add new faces and vertex */
5552         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - fStart);
5553         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - rfStart[n]);
5554         remotePointsNew[m].rank  = rrank;
5555         ++m;
5556         for (r = 0; r < 2; ++r, ++m) {
5557           localPointsNew[m]        = fStartNew     + (p  - fStart)*2     + r;
5558           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*2 + r;
5559           remotePointsNew[m].rank  = rrank;
5560         }
5561       } else if ((p >= cStart) && (p < cEnd)) {
5562         /* Old cells add new cells and interior faces */
5563         for (r = 0; r < 4; ++r, ++m) {
5564           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
5565           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
5566           remotePointsNew[m].rank  = rrank;
5567         }
5568         for (r = 0; r < 4; ++r, ++m) {
5569           localPointsNew[m]        = fStartNew     + (fEnd - fStart)*2                    + (p  - cStart)*4     + r;
5570           remotePointsNew[m].index = rfStartNew[n] + rdepthSizeOld[n*(depth+1)+depth-1]*2 + (rp - rcStart[n])*4 + r;
5571           remotePointsNew[m].rank  = rrank;
5572         }
5573       }
5574       break;
5575     case 3:
5576       /* Hybrid simplicial 2D */
5577       if ((p >= vStart) && (p < vEnd)) {
5578         /* Old vertices stay the same */
5579         localPointsNew[m]        = vStartNew     + (p  - vStart);
5580         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
5581         remotePointsNew[m].rank  = rrank;
5582         ++m;
5583       } else if ((p >= fStart) && (p < fMax)) {
5584         /* Old interior faces add new faces and vertex */
5585         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - fStart);
5586         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - rfStart[n]);
5587         remotePointsNew[m].rank  = rrank;
5588         ++m;
5589         for (r = 0; r < 2; ++r, ++m) {
5590           localPointsNew[m]        = fStartNew     + (p  - fStart)*2     + r;
5591           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*2 + r;
5592           remotePointsNew[m].rank  = rrank;
5593         }
5594       } else if ((p >= fMax) && (p < fEnd)) {
5595         /* Old hybrid faces stay the same */
5596         localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (p  - fMax);
5597         remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*2 + (rp - rdepthMaxOld[n*(depth+1)+depth-1]);
5598         remotePointsNew[m].rank  = rrank;
5599         ++m;
5600       } else if ((p >= cStart) && (p < cMax)) {
5601         /* Old interior cells add new cells and interior faces */
5602         for (r = 0; r < 4; ++r, ++m) {
5603           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
5604           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
5605           remotePointsNew[m].rank  = rrank;
5606         }
5607         for (r = 0; r < 3; ++r, ++m) {
5608           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (p  - cStart)*3     + r;
5609           remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*2 + (rp - rcStart[n])*3 + r;
5610           remotePointsNew[m].rank  = rrank;
5611         }
5612       } else if ((p >= cStart) && (p < cMax)) {
5613         /* Old hybrid cells add new cells and hybrid face */
5614         for (r = 0; r < 2; ++r, ++m) {
5615           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
5616           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
5617           remotePointsNew[m].rank  = rrank;
5618         }
5619         localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (cMax                            - cStart)*3     + (p  - cMax);
5620         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]);
5621         remotePointsNew[m].rank  = rrank;
5622         ++m;
5623       }
5624       break;
5625     default:
5626       SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
5627     }
5628   }
5629   ierr = ISRestoreIndices(processRanks, &neighbors);CHKERRQ(ierr);
5630   ierr = ISDestroy(&processRanks);CHKERRQ(ierr);
5631   ierr = PetscSFSetGraph(sfNew, pEndNew-pStartNew, numLeavesNew, localPointsNew, PETSC_OWN_POINTER, remotePointsNew, PETSC_OWN_POINTER);CHKERRQ(ierr);
5632   ierr = PetscFree5(rdepthSize,rvStartNew,reStartNew,rfStartNew,rcStartNew);CHKERRQ(ierr);
5633   ierr = PetscFree6(depthSizeOld,rdepthSizeOld,rvStart,reStart,rfStart,rcStart);CHKERRQ(ierr);
5634   PetscFunctionReturn(0);
5635 }
5636 
5637 #undef __FUNCT__
5638 #define __FUNCT__ "CellRefinerCreateLabels"
5639 PetscErrorCode CellRefinerCreateLabels(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
5640 {
5641   PetscInt       numLabels, l;
5642   PetscInt       newp, cStart, cStartNew, cEnd, cMax, vStart, vStartNew, vEnd, vMax, fStart, fStartNew, fEnd, fMax, eStart, eEnd, eMax, r;
5643   PetscErrorCode ierr;
5644 
5645   PetscFunctionBegin;
5646   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
5647   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
5648   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
5649   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
5650 
5651   cStartNew = 0;
5652   vStartNew = depthSize[2];
5653   fStartNew = depthSize[2] + depthSize[0];
5654 
5655   ierr = DMPlexGetNumLabels(dm, &numLabels);CHKERRQ(ierr);
5656   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
5657   switch (refiner) {
5658   case 3:
5659     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
5660     cMax = PetscMin(cEnd, cMax);
5661     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
5662     fMax = PetscMin(fEnd, fMax);
5663   }
5664   for (l = 0; l < numLabels; ++l) {
5665     DMLabel         label, labelNew;
5666     const char     *lname;
5667     PetscBool       isDepth;
5668     IS              valueIS;
5669     const PetscInt *values;
5670     PetscInt        numValues, val;
5671 
5672     ierr = DMPlexGetLabelName(dm, l, &lname);CHKERRQ(ierr);
5673     ierr = PetscStrcmp(lname, "depth", &isDepth);CHKERRQ(ierr);
5674     if (isDepth) continue;
5675     ierr = DMPlexCreateLabel(rdm, lname);CHKERRQ(ierr);
5676     ierr = DMPlexGetLabel(dm, lname, &label);CHKERRQ(ierr);
5677     ierr = DMPlexGetLabel(rdm, lname, &labelNew);CHKERRQ(ierr);
5678     ierr = DMLabelGetValueIS(label, &valueIS);CHKERRQ(ierr);
5679     ierr = ISGetLocalSize(valueIS, &numValues);CHKERRQ(ierr);
5680     ierr = ISGetIndices(valueIS, &values);CHKERRQ(ierr);
5681     for (val = 0; val < numValues; ++val) {
5682       IS              pointIS;
5683       const PetscInt *points;
5684       PetscInt        numPoints, n;
5685 
5686       ierr = DMLabelGetStratumIS(label, values[val], &pointIS);CHKERRQ(ierr);
5687       ierr = ISGetLocalSize(pointIS, &numPoints);CHKERRQ(ierr);
5688       ierr = ISGetIndices(pointIS, &points);CHKERRQ(ierr);
5689       for (n = 0; n < numPoints; ++n) {
5690         const PetscInt p = points[n];
5691         switch (refiner) {
5692         case 1:
5693           /* Simplicial 2D */
5694           if ((p >= vStart) && (p < vEnd)) {
5695             /* Old vertices stay the same */
5696             newp = vStartNew + (p - vStart);
5697             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5698           } else if ((p >= fStart) && (p < fEnd)) {
5699             /* Old faces add new faces and vertex */
5700             newp = vStartNew + (vEnd - vStart) + (p - fStart);
5701             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5702             for (r = 0; r < 2; ++r) {
5703               newp = fStartNew + (p - fStart)*2 + r;
5704               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5705             }
5706           } else if ((p >= cStart) && (p < cEnd)) {
5707             /* Old cells add new cells and interior faces */
5708             for (r = 0; r < 4; ++r) {
5709               newp = cStartNew + (p - cStart)*4 + r;
5710               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5711             }
5712             for (r = 0; r < 3; ++r) {
5713               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*3 + r;
5714               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5715             }
5716           }
5717           break;
5718         case 2:
5719           /* Hex 2D */
5720           if ((p >= vStart) && (p < vEnd)) {
5721             /* Old vertices stay the same */
5722             newp = vStartNew + (p - vStart);
5723             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5724           } else if ((p >= fStart) && (p < fEnd)) {
5725             /* Old faces add new faces and vertex */
5726             newp = vStartNew + (vEnd - vStart) + (p - fStart);
5727             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5728             for (r = 0; r < 2; ++r) {
5729               newp = fStartNew + (p - fStart)*2 + r;
5730               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5731             }
5732           } else if ((p >= cStart) && (p < cEnd)) {
5733             /* Old cells add new cells and interior faces and vertex */
5734             for (r = 0; r < 4; ++r) {
5735               newp = cStartNew + (p - cStart)*4 + r;
5736               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5737             }
5738             for (r = 0; r < 4; ++r) {
5739               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*4 + r;
5740               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5741             }
5742             newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (p - cStart);
5743             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5744           }
5745           break;
5746         case 3:
5747           /* Hybrid simplicial 2D */
5748           if ((p >= vStart) && (p < vEnd)) {
5749             /* Old vertices stay the same */
5750             newp = vStartNew + (p - vStart);
5751             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5752           } else if ((p >= fStart) && (p < fMax)) {
5753             /* Old interior faces add new faces and vertex */
5754             newp = vStartNew + (vEnd - vStart) + (p - fStart);
5755             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5756             for (r = 0; r < 2; ++r) {
5757               newp = fStartNew + (p - fStart)*2 + r;
5758               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5759             }
5760           } else if ((p >= fMax) && (p < fEnd)) {
5761             /* Old hybrid faces stay the same */
5762             newp = fStartNew + (fMax - fStart)*2 + (p - fMax);
5763             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5764           } else if ((p >= cStart) && (p < cMax)) {
5765             /* Old interior cells add new cells and interior faces */
5766             for (r = 0; r < 4; ++r) {
5767               newp = cStartNew + (p - cStart)*4 + r;
5768               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5769             }
5770             for (r = 0; r < 3; ++r) {
5771               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*3 + r;
5772               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5773             }
5774           } else if ((p >= cMax) && (p < cEnd)) {
5775             /* Old hybrid cells add new cells and hybrid face */
5776             for (r = 0; r < 2; ++r) {
5777               newp = cStartNew + (cMax - cStart)*4 + (p - cMax)*2 + r;
5778               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5779             }
5780             newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (p - cMax);
5781             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5782           }
5783           break;
5784         default:
5785           SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
5786         }
5787       }
5788       ierr = ISRestoreIndices(pointIS, &points);CHKERRQ(ierr);
5789       ierr = ISDestroy(&pointIS);CHKERRQ(ierr);
5790     }
5791     ierr = ISRestoreIndices(valueIS, &values);CHKERRQ(ierr);
5792     ierr = ISDestroy(&valueIS);CHKERRQ(ierr);
5793     if (0) {
5794       ierr = PetscViewerASCIISynchronizedAllow(PETSC_VIEWER_STDOUT_WORLD, PETSC_TRUE);CHKERRQ(ierr);
5795       ierr = DMLabelView(labelNew, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
5796       ierr = PetscViewerFlush(PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
5797     }
5798   }
5799   PetscFunctionReturn(0);
5800 }
5801 
5802 #undef __FUNCT__
5803 #define __FUNCT__ "DMPlexRefine_Uniform"
5804 /* This will only work for interpolated meshes */
5805 PetscErrorCode DMPlexRefine_Uniform(DM dm, CellRefiner cellRefiner, DM *dmRefined)
5806 {
5807   DM             rdm;
5808   PetscInt      *depthSize;
5809   PetscInt       dim, depth = 0, d, pStart = 0, pEnd = 0;
5810   PetscErrorCode ierr;
5811 
5812   PetscFunctionBegin;
5813   ierr = DMCreate(PetscObjectComm((PetscObject)dm), &rdm);CHKERRQ(ierr);
5814   ierr = DMSetType(rdm, DMPLEX);CHKERRQ(ierr);
5815   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
5816   ierr = DMPlexSetDimension(rdm, dim);CHKERRQ(ierr);
5817   /* Calculate number of new points of each depth */
5818   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
5819   if (depth != dim) SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "Mesh must be fully interpolated for uniform refinement");
5820   ierr = PetscMalloc((depth+1) * sizeof(PetscInt), &depthSize);CHKERRQ(ierr);
5821   ierr = PetscMemzero(depthSize, (depth+1) * sizeof(PetscInt));CHKERRQ(ierr);
5822   ierr = CellRefinerGetSizes(cellRefiner, dm, depthSize);CHKERRQ(ierr);
5823   /* Step 1: Set chart */
5824   for (d = 0; d <= depth; ++d) pEnd += depthSize[d];
5825   ierr = DMPlexSetChart(rdm, pStart, pEnd);CHKERRQ(ierr);
5826   /* Step 2: Set cone/support sizes */
5827   ierr = CellRefinerSetConeSizes(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
5828   /* Step 3: Setup refined DM */
5829   ierr = DMSetUp(rdm);CHKERRQ(ierr);
5830   /* Step 4: Set cones and supports */
5831   ierr = CellRefinerSetCones(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
5832   /* Step 5: Stratify */
5833   ierr = DMPlexStratify(rdm);CHKERRQ(ierr);
5834   /* Step 6: Set coordinates for vertices */
5835   ierr = CellRefinerSetCoordinates(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
5836   /* Step 7: Create pointSF */
5837   ierr = CellRefinerCreateSF(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
5838   /* Step 8: Create labels */
5839   ierr = CellRefinerCreateLabels(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
5840   ierr = PetscFree(depthSize);CHKERRQ(ierr);
5841 
5842   *dmRefined = rdm;
5843   PetscFunctionReturn(0);
5844 }
5845 
5846 #undef __FUNCT__
5847 #define __FUNCT__ "DMPlexSetRefinementUniform"
5848 PetscErrorCode DMPlexSetRefinementUniform(DM dm, PetscBool refinementUniform)
5849 {
5850   DM_Plex *mesh = (DM_Plex*) dm->data;
5851 
5852   PetscFunctionBegin;
5853   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5854   mesh->refinementUniform = refinementUniform;
5855   PetscFunctionReturn(0);
5856 }
5857 
5858 #undef __FUNCT__
5859 #define __FUNCT__ "DMPlexGetRefinementUniform"
5860 PetscErrorCode DMPlexGetRefinementUniform(DM dm, PetscBool *refinementUniform)
5861 {
5862   DM_Plex *mesh = (DM_Plex*) dm->data;
5863 
5864   PetscFunctionBegin;
5865   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5866   PetscValidPointer(refinementUniform,  2);
5867   *refinementUniform = mesh->refinementUniform;
5868   PetscFunctionReturn(0);
5869 }
5870 
5871 #undef __FUNCT__
5872 #define __FUNCT__ "DMPlexSetRefinementLimit"
5873 PetscErrorCode DMPlexSetRefinementLimit(DM dm, PetscReal refinementLimit)
5874 {
5875   DM_Plex *mesh = (DM_Plex*) dm->data;
5876 
5877   PetscFunctionBegin;
5878   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5879   mesh->refinementLimit = refinementLimit;
5880   PetscFunctionReturn(0);
5881 }
5882 
5883 #undef __FUNCT__
5884 #define __FUNCT__ "DMPlexGetRefinementLimit"
5885 PetscErrorCode DMPlexGetRefinementLimit(DM dm, PetscReal *refinementLimit)
5886 {
5887   DM_Plex *mesh = (DM_Plex*) dm->data;
5888 
5889   PetscFunctionBegin;
5890   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5891   PetscValidPointer(refinementLimit,  2);
5892   /* if (mesh->refinementLimit < 0) = getMaxVolume()/2.0; */
5893   *refinementLimit = mesh->refinementLimit;
5894   PetscFunctionReturn(0);
5895 }
5896 
5897 #undef __FUNCT__
5898 #define __FUNCT__ "DMPlexGetCellRefiner_Private"
5899 PetscErrorCode DMPlexGetCellRefiner_Private(DM dm, CellRefiner *cellRefiner)
5900 {
5901   PetscInt       dim, cStart, coneSize, cMax;
5902   PetscErrorCode ierr;
5903 
5904   PetscFunctionBegin;
5905   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
5906   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, NULL);CHKERRQ(ierr);
5907   ierr = DMPlexGetConeSize(dm, cStart, &coneSize);CHKERRQ(ierr);
5908   ierr = DMPlexGetHybridBounds(dm, &cMax, NULL, NULL, NULL);CHKERRQ(ierr);
5909   switch (dim) {
5910   case 2:
5911     switch (coneSize) {
5912     case 3:
5913       if (cMax >= 0) *cellRefiner = 3; /* Hybrid */
5914       else *cellRefiner = 1; /* Triangular */
5915       break;
5916     case 4:
5917       if (cMax >= 0) *cellRefiner = 4; /* Hybrid */
5918       else *cellRefiner = 2; /* Quadrilateral */
5919       break;
5920     default:
5921       SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown coneSize %d in dimension %d for cell refiner", coneSize, dim);
5922     }
5923     break;
5924   default:
5925     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown dimension %d for cell refiner", dim);
5926   }
5927   PetscFunctionReturn(0);
5928 }
5929 
5930 #undef __FUNCT__
5931 #define __FUNCT__ "DMRefine_Plex"
5932 PetscErrorCode DMRefine_Plex(DM dm, MPI_Comm comm, DM *dmRefined)
5933 {
5934   PetscReal      refinementLimit;
5935   PetscInt       dim, cStart, cEnd;
5936   char           genname[1024], *name = NULL;
5937   PetscBool      isUniform, isTriangle = PETSC_FALSE, isTetgen = PETSC_FALSE, isCTetgen = PETSC_FALSE, flg;
5938   PetscErrorCode ierr;
5939 
5940   PetscFunctionBegin;
5941   ierr = DMPlexGetRefinementUniform(dm, &isUniform);CHKERRQ(ierr);
5942   if (isUniform) {
5943     CellRefiner cellRefiner;
5944 
5945     ierr = DMPlexGetCellRefiner_Private(dm, &cellRefiner);CHKERRQ(ierr);
5946     ierr = DMPlexRefine_Uniform(dm, cellRefiner, dmRefined);CHKERRQ(ierr);
5947     PetscFunctionReturn(0);
5948   }
5949   ierr = DMPlexGetRefinementLimit(dm, &refinementLimit);CHKERRQ(ierr);
5950   if (refinementLimit == 0.0) PetscFunctionReturn(0);
5951   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
5952   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
5953   ierr = PetscOptionsGetString(((PetscObject) dm)->prefix, "-dm_plex_generator", genname, 1024, &flg);CHKERRQ(ierr);
5954   if (flg) name = genname;
5955   if (name) {
5956     ierr = PetscStrcmp(name, "triangle", &isTriangle);CHKERRQ(ierr);
5957     ierr = PetscStrcmp(name, "tetgen",   &isTetgen);CHKERRQ(ierr);
5958     ierr = PetscStrcmp(name, "ctetgen",  &isCTetgen);CHKERRQ(ierr);
5959   }
5960   switch (dim) {
5961   case 2:
5962     if (!name || isTriangle) {
5963 #if defined(PETSC_HAVE_TRIANGLE)
5964       double  *maxVolumes;
5965       PetscInt c;
5966 
5967       ierr = PetscMalloc((cEnd - cStart) * sizeof(double), &maxVolumes);CHKERRQ(ierr);
5968       for (c = 0; c < cEnd-cStart; ++c) maxVolumes[c] = refinementLimit;
5969       ierr = DMPlexRefine_Triangle(dm, maxVolumes, dmRefined);CHKERRQ(ierr);
5970       ierr = PetscFree(maxVolumes);CHKERRQ(ierr);
5971 #else
5972       SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Mesh refinement needs external package support.\nPlease reconfigure with --download-triangle.");
5973 #endif
5974     } else SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Unknown 2D mesh generation package %s", name);
5975     break;
5976   case 3:
5977     if (!name || isCTetgen) {
5978 #if defined(PETSC_HAVE_CTETGEN)
5979       PetscReal *maxVolumes;
5980       PetscInt   c;
5981 
5982       ierr = PetscMalloc((cEnd - cStart) * sizeof(PetscReal), &maxVolumes);CHKERRQ(ierr);
5983       for (c = 0; c < cEnd-cStart; ++c) maxVolumes[c] = refinementLimit;
5984       ierr = DMPlexRefine_CTetgen(dm, maxVolumes, dmRefined);CHKERRQ(ierr);
5985 #else
5986       SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "CTetgen needs external package support.\nPlease reconfigure with --download-ctetgen.");
5987 #endif
5988     } else if (isTetgen) {
5989 #if defined(PETSC_HAVE_TETGEN)
5990       double  *maxVolumes;
5991       PetscInt c;
5992 
5993       ierr = PetscMalloc((cEnd - cStart) * sizeof(double), &maxVolumes);CHKERRQ(ierr);
5994       for (c = 0; c < cEnd-cStart; ++c) maxVolumes[c] = refinementLimit;
5995       ierr = DMPlexRefine_Tetgen(dm, maxVolumes, dmRefined);CHKERRQ(ierr);
5996 #else
5997       SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Tetgen needs external package support.\nPlease reconfigure with --with-c-language=cxx --download-tetgen.");
5998 #endif
5999     } else SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Unknown 3D mesh generation package %s", name);
6000     break;
6001   default:
6002     SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Mesh refinement in dimension %d is not supported.", dim);
6003   }
6004   PetscFunctionReturn(0);
6005 }
6006 
6007 #undef __FUNCT__
6008 #define __FUNCT__ "DMPlexGetDepthLabel"
6009 /*@
6010   DMPlexGetDepthLabel - Get the DMLabel recording the depth of each point
6011 
6012   Not Collective
6013 
6014   Input Parameter:
6015 . dm    - The DMPlex object
6016 
6017   Output Parameter:
6018 . depthLabel - The DMLabel recording point depth
6019 
6020   Level: developer
6021 
6022 .keywords: mesh, points
6023 .seealso: DMPlexGetDepth(), DMPlexGetHeightStratum(), DMPlexGetDepthStratum()
6024 @*/
6025 PetscErrorCode DMPlexGetDepthLabel(DM dm, DMLabel *depthLabel)
6026 {
6027   DM_Plex       *mesh = (DM_Plex*) dm->data;
6028   PetscErrorCode ierr;
6029 
6030   PetscFunctionBegin;
6031   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6032   PetscValidPointer(depthLabel, 2);
6033   if (!mesh->depthLabel) {
6034     ierr = DMPlexGetLabel(dm, "depth", &mesh->depthLabel);CHKERRQ(ierr);
6035   }
6036   *depthLabel = mesh->depthLabel;
6037   PetscFunctionReturn(0);
6038 }
6039 
6040 #undef __FUNCT__
6041 #define __FUNCT__ "DMPlexGetDepth"
6042 /*@
6043   DMPlexGetDepth - Get the depth of the DAG representing this mesh
6044 
6045   Not Collective
6046 
6047   Input Parameter:
6048 . dm    - The DMPlex object
6049 
6050   Output Parameter:
6051 . depth - The number of strata (breadth first levels) in the DAG
6052 
6053   Level: developer
6054 
6055 .keywords: mesh, points
6056 .seealso: DMPlexGetDepthLabel(), DMPlexGetHeightStratum(), DMPlexGetDepthStratum()
6057 @*/
6058 PetscErrorCode DMPlexGetDepth(DM dm, PetscInt *depth)
6059 {
6060   DMLabel        label;
6061   PetscInt       d = 0;
6062   PetscErrorCode ierr;
6063 
6064   PetscFunctionBegin;
6065   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6066   PetscValidPointer(depth, 2);
6067   ierr = DMPlexGetDepthLabel(dm, &label);CHKERRQ(ierr);
6068   if (label) {ierr = DMLabelGetNumValues(label, &d);CHKERRQ(ierr);}
6069   *depth = d-1;
6070   PetscFunctionReturn(0);
6071 }
6072 
6073 #undef __FUNCT__
6074 #define __FUNCT__ "DMPlexGetDepthStratum"
6075 /*@
6076   DMPlexGetDepthStratum - Get the bounds [start, end) for all points at a certain depth.
6077 
6078   Not Collective
6079 
6080   Input Parameters:
6081 + dm           - The DMPlex object
6082 - stratumValue - The requested depth
6083 
6084   Output Parameters:
6085 + start - The first point at this depth
6086 - end   - One beyond the last point at this depth
6087 
6088   Level: developer
6089 
6090 .keywords: mesh, points
6091 .seealso: DMPlexGetHeightStratum(), DMPlexGetDepth()
6092 @*/
6093 PetscErrorCode DMPlexGetDepthStratum(DM dm, PetscInt stratumValue, PetscInt *start, PetscInt *end)
6094 {
6095   DMLabel        label;
6096   PetscInt       depth;
6097   PetscErrorCode ierr;
6098 
6099   PetscFunctionBegin;
6100   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6101   if (stratumValue < 0) {
6102     ierr = DMPlexGetChart(dm, start, end);CHKERRQ(ierr);
6103     PetscFunctionReturn(0);
6104   } else {
6105     PetscInt pStart, pEnd;
6106 
6107     if (start) *start = 0;
6108     if (end)   *end   = 0;
6109     ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
6110     if (pStart == pEnd) PetscFunctionReturn(0);
6111   }
6112   ierr = DMPlexGetDepthLabel(dm, &label);CHKERRQ(ierr);
6113   if (!label) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "No label named depth was found");CHKERRQ(ierr);
6114   /* Strata are sorted and contiguous -- In addition, depth/height is either full or 1-level */
6115   depth = stratumValue;
6116   if ((depth < 0) || (depth >= label->numStrata)) {
6117     if (start) *start = 0;
6118     if (end)   *end   = 0;
6119   } else {
6120     if (start) *start = label->points[label->stratumOffsets[depth]];
6121     if (end)   *end   = label->points[label->stratumOffsets[depth]+label->stratumSizes[depth]-1]+1;
6122   }
6123   PetscFunctionReturn(0);
6124 }
6125 
6126 #undef __FUNCT__
6127 #define __FUNCT__ "DMPlexGetHeightStratum"
6128 /*@
6129   DMPlexGetHeightStratum - Get the bounds [start, end) for all points at a certain height.
6130 
6131   Not Collective
6132 
6133   Input Parameters:
6134 + dm           - The DMPlex object
6135 - stratumValue - The requested height
6136 
6137   Output Parameters:
6138 + start - The first point at this height
6139 - end   - One beyond the last point at this height
6140 
6141   Level: developer
6142 
6143 .keywords: mesh, points
6144 .seealso: DMPlexGetDepthStratum(), DMPlexGetDepth()
6145 @*/
6146 PetscErrorCode DMPlexGetHeightStratum(DM dm, PetscInt stratumValue, PetscInt *start, PetscInt *end)
6147 {
6148   DMLabel        label;
6149   PetscInt       depth;
6150   PetscErrorCode ierr;
6151 
6152   PetscFunctionBegin;
6153   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6154   if (stratumValue < 0) {
6155     ierr = DMPlexGetChart(dm, start, end);CHKERRQ(ierr);
6156   } else {
6157     PetscInt pStart, pEnd;
6158 
6159     if (start) *start = 0;
6160     if (end)   *end   = 0;
6161     ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
6162     if (pStart == pEnd) PetscFunctionReturn(0);
6163   }
6164   ierr = DMPlexGetDepthLabel(dm, &label);CHKERRQ(ierr);
6165   if (!label) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "No label named depth was found");CHKERRQ(ierr);
6166   /* Strata are sorted and contiguous -- In addition, depth/height is either full or 1-level */
6167   depth = label->stratumValues[label->numStrata-1] - stratumValue;
6168   if ((depth < 0) || (depth >= label->numStrata)) {
6169     if (start) *start = 0;
6170     if (end)   *end   = 0;
6171   } else {
6172     if (start) *start = label->points[label->stratumOffsets[depth]];
6173     if (end)   *end   = label->points[label->stratumOffsets[depth]+label->stratumSizes[depth]-1]+1;
6174   }
6175   PetscFunctionReturn(0);
6176 }
6177 
6178 #undef __FUNCT__
6179 #define __FUNCT__ "DMPlexCreateSectionInitial"
6180 /* Set the number of dof on each point and separate by fields */
6181 PetscErrorCode DMPlexCreateSectionInitial(DM dm, PetscInt dim, PetscInt numFields,const PetscInt numComp[],const PetscInt numDof[], PetscSection *section)
6182 {
6183   PetscInt      *numDofTot;
6184   PetscInt       pStart = 0, pEnd = 0;
6185   PetscInt       p, d, f;
6186   PetscErrorCode ierr;
6187 
6188   PetscFunctionBegin;
6189   ierr = PetscMalloc((dim+1) * sizeof(PetscInt), &numDofTot);CHKERRQ(ierr);
6190   for (d = 0; d <= dim; ++d) {
6191     numDofTot[d] = 0;
6192     for (f = 0; f < numFields; ++f) numDofTot[d] += numDof[f*(dim+1)+d];
6193   }
6194   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)dm), section);CHKERRQ(ierr);
6195   if (numFields > 0) {
6196     ierr = PetscSectionSetNumFields(*section, numFields);CHKERRQ(ierr);
6197     if (numComp) {
6198       for (f = 0; f < numFields; ++f) {
6199         ierr = PetscSectionSetFieldComponents(*section, f, numComp[f]);CHKERRQ(ierr);
6200       }
6201     }
6202   }
6203   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
6204   ierr = PetscSectionSetChart(*section, pStart, pEnd);CHKERRQ(ierr);
6205   for (d = 0; d <= dim; ++d) {
6206     ierr = DMPlexGetDepthStratum(dm, d, &pStart, &pEnd);CHKERRQ(ierr);
6207     for (p = pStart; p < pEnd; ++p) {
6208       for (f = 0; f < numFields; ++f) {
6209         ierr = PetscSectionSetFieldDof(*section, p, f, numDof[f*(dim+1)+d]);CHKERRQ(ierr);
6210       }
6211       ierr = PetscSectionSetDof(*section, p, numDofTot[d]);CHKERRQ(ierr);
6212     }
6213   }
6214   ierr = PetscFree(numDofTot);CHKERRQ(ierr);
6215   PetscFunctionReturn(0);
6216 }
6217 
6218 #undef __FUNCT__
6219 #define __FUNCT__ "DMPlexCreateSectionBCDof"
6220 /* Set the number of dof on each point and separate by fields
6221    If constDof is PETSC_DETERMINE, constrain every dof on the point
6222 */
6223 PetscErrorCode DMPlexCreateSectionBCDof(DM dm, PetscInt numBC,const PetscInt bcField[],const IS bcPoints[], PetscInt constDof, PetscSection section)
6224 {
6225   PetscInt       numFields;
6226   PetscInt       bc;
6227   PetscErrorCode ierr;
6228 
6229   PetscFunctionBegin;
6230   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
6231   for (bc = 0; bc < numBC; ++bc) {
6232     PetscInt        field = 0;
6233     const PetscInt *idx;
6234     PetscInt        n, i;
6235 
6236     if (numFields) field = bcField[bc];
6237     ierr = ISGetLocalSize(bcPoints[bc], &n);CHKERRQ(ierr);
6238     ierr = ISGetIndices(bcPoints[bc], &idx);CHKERRQ(ierr);
6239     for (i = 0; i < n; ++i) {
6240       const PetscInt p        = idx[i];
6241       PetscInt       numConst = constDof;
6242 
6243       /* Constrain every dof on the point */
6244       if (numConst < 0) {
6245         if (numFields) {
6246           ierr = PetscSectionGetFieldDof(section, p, field, &numConst);CHKERRQ(ierr);
6247         } else {
6248           ierr = PetscSectionGetDof(section, p, &numConst);CHKERRQ(ierr);
6249         }
6250       }
6251       if (numFields) {
6252         ierr = PetscSectionAddFieldConstraintDof(section, p, field, numConst);CHKERRQ(ierr);
6253       }
6254       ierr = PetscSectionAddConstraintDof(section, p, numConst);CHKERRQ(ierr);
6255     }
6256     ierr = ISRestoreIndices(bcPoints[bc], &idx);CHKERRQ(ierr);
6257   }
6258   PetscFunctionReturn(0);
6259 }
6260 
6261 #undef __FUNCT__
6262 #define __FUNCT__ "DMPlexCreateSectionBCIndicesAll"
6263 /* Set the constrained indices on each point and separate by fields */
6264 PetscErrorCode DMPlexCreateSectionBCIndicesAll(DM dm, PetscSection section)
6265 {
6266   PetscInt      *maxConstraints;
6267   PetscInt       numFields, f, pStart = 0, pEnd = 0, p;
6268   PetscErrorCode ierr;
6269 
6270   PetscFunctionBegin;
6271   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
6272   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
6273   ierr = PetscMalloc((numFields+1) * sizeof(PetscInt), &maxConstraints);CHKERRQ(ierr);
6274   for (f = 0; f <= numFields; ++f) maxConstraints[f] = 0;
6275   for (p = pStart; p < pEnd; ++p) {
6276     PetscInt cdof;
6277 
6278     if (numFields) {
6279       for (f = 0; f < numFields; ++f) {
6280         ierr              = PetscSectionGetFieldConstraintDof(section, p, f, &cdof);CHKERRQ(ierr);
6281         maxConstraints[f] = PetscMax(maxConstraints[f], cdof);
6282       }
6283     } else {
6284       ierr              = PetscSectionGetConstraintDof(section, p, &cdof);CHKERRQ(ierr);
6285       maxConstraints[0] = PetscMax(maxConstraints[0], cdof);
6286     }
6287   }
6288   for (f = 0; f < numFields; ++f) {
6289     maxConstraints[numFields] += maxConstraints[f];
6290   }
6291   if (maxConstraints[numFields]) {
6292     PetscInt *indices;
6293 
6294     ierr = PetscMalloc(maxConstraints[numFields] * sizeof(PetscInt), &indices);CHKERRQ(ierr);
6295     for (p = pStart; p < pEnd; ++p) {
6296       PetscInt cdof, d;
6297 
6298       ierr = PetscSectionGetConstraintDof(section, p, &cdof);CHKERRQ(ierr);
6299       if (cdof) {
6300         if (cdof > maxConstraints[numFields]) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_LIB, "Likely memory corruption, point %D cDof %D > maxConstraints %D", p, cdof, maxConstraints[numFields]);
6301         if (numFields) {
6302           PetscInt numConst = 0, foff = 0;
6303 
6304           for (f = 0; f < numFields; ++f) {
6305             PetscInt cfdof, fdof;
6306 
6307             ierr = PetscSectionGetFieldDof(section, p, f, &fdof);CHKERRQ(ierr);
6308             ierr = PetscSectionGetFieldConstraintDof(section, p, f, &cfdof);CHKERRQ(ierr);
6309             /* Change constraint numbering from absolute local dof number to field relative local dof number */
6310             for (d = 0; d < cfdof; ++d) indices[numConst+d] = d;
6311             ierr = PetscSectionSetFieldConstraintIndices(section, p, f, &indices[numConst]);CHKERRQ(ierr);
6312             for (d = 0; d < cfdof; ++d) indices[numConst+d] += foff;
6313             numConst += cfdof;
6314             foff     += fdof;
6315           }
6316           if (cdof != numConst) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_LIB, "Total number of field constraints %D should be %D", numConst, cdof);
6317         } else {
6318           for (d = 0; d < cdof; ++d) indices[d] = d;
6319         }
6320         ierr = PetscSectionSetConstraintIndices(section, p, indices);CHKERRQ(ierr);
6321       }
6322     }
6323     ierr = PetscFree(indices);CHKERRQ(ierr);
6324   }
6325   ierr = PetscFree(maxConstraints);CHKERRQ(ierr);
6326   PetscFunctionReturn(0);
6327 }
6328 
6329 #undef __FUNCT__
6330 #define __FUNCT__ "DMPlexCreateSectionBCIndicesField"
6331 /* Set the constrained field indices on each point */
6332 PetscErrorCode DMPlexCreateSectionBCIndicesField(DM dm, PetscInt field, IS bcPoints, IS constraintIndices, PetscSection section)
6333 {
6334   const PetscInt *points, *indices;
6335   PetscInt        numFields, maxDof, numPoints, p, numConstraints;
6336   PetscErrorCode  ierr;
6337 
6338   PetscFunctionBegin;
6339   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
6340   if ((field < 0) || (field >= numFields)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Section field %d should be in [%d, %d)", field, 0, numFields);
6341 
6342   ierr = ISGetLocalSize(bcPoints, &numPoints);CHKERRQ(ierr);
6343   ierr = ISGetIndices(bcPoints, &points);CHKERRQ(ierr);
6344   if (!constraintIndices) {
6345     PetscInt *idx, i;
6346 
6347     ierr = PetscSectionGetMaxDof(section, &maxDof);CHKERRQ(ierr);
6348     ierr = PetscMalloc(maxDof * sizeof(PetscInt), &idx);CHKERRQ(ierr);
6349     for (i = 0; i < maxDof; ++i) idx[i] = i;
6350     for (p = 0; p < numPoints; ++p) {
6351       ierr = PetscSectionSetFieldConstraintIndices(section, points[p], field, idx);CHKERRQ(ierr);
6352     }
6353     ierr = PetscFree(idx);CHKERRQ(ierr);
6354   } else {
6355     ierr = ISGetLocalSize(constraintIndices, &numConstraints);CHKERRQ(ierr);
6356     ierr = ISGetIndices(constraintIndices, &indices);CHKERRQ(ierr);
6357     for (p = 0; p < numPoints; ++p) {
6358       PetscInt fcdof;
6359 
6360       ierr = PetscSectionGetFieldConstraintDof(section, points[p], field, &fcdof);CHKERRQ(ierr);
6361       if (fcdof != numConstraints) SETERRQ4(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Section point %d field %d has %d constraints, but yo ugave %d indices", p, field, fcdof, numConstraints);
6362       ierr = PetscSectionSetFieldConstraintIndices(section, points[p], field, indices);CHKERRQ(ierr);
6363     }
6364     ierr = ISRestoreIndices(constraintIndices, &indices);CHKERRQ(ierr);
6365   }
6366   ierr = ISRestoreIndices(bcPoints, &points);CHKERRQ(ierr);
6367   PetscFunctionReturn(0);
6368 }
6369 
6370 #undef __FUNCT__
6371 #define __FUNCT__ "DMPlexCreateSectionBCIndices"
6372 /* Set the constrained indices on each point and separate by fields */
6373 PetscErrorCode DMPlexCreateSectionBCIndices(DM dm, PetscSection section)
6374 {
6375   PetscInt      *indices;
6376   PetscInt       numFields, maxDof, f, pStart = 0, pEnd = 0, p;
6377   PetscErrorCode ierr;
6378 
6379   PetscFunctionBegin;
6380   ierr = PetscSectionGetMaxDof(section, &maxDof);CHKERRQ(ierr);
6381   ierr = PetscMalloc(maxDof * sizeof(PetscInt), &indices);CHKERRQ(ierr);
6382   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
6383   if (!numFields) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "This function only works after users have set field constraint indices.");
6384   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
6385   for (p = pStart; p < pEnd; ++p) {
6386     PetscInt cdof, d;
6387 
6388     ierr = PetscSectionGetConstraintDof(section, p, &cdof);CHKERRQ(ierr);
6389     if (cdof) {
6390       PetscInt numConst = 0, foff = 0;
6391 
6392       for (f = 0; f < numFields; ++f) {
6393         const PetscInt *fcind;
6394         PetscInt        fdof, fcdof;
6395 
6396         ierr = PetscSectionGetFieldDof(section, p, f, &fdof);CHKERRQ(ierr);
6397         ierr = PetscSectionGetFieldConstraintDof(section, p, f, &fcdof);CHKERRQ(ierr);
6398         if (fcdof) {ierr = PetscSectionGetFieldConstraintIndices(section, p, f, &fcind);CHKERRQ(ierr);}
6399         /* Change constraint numbering from field relative local dof number to absolute local dof number */
6400         for (d = 0; d < fcdof; ++d) indices[numConst+d] = fcind[d]+foff;
6401         foff     += fdof;
6402         numConst += fcdof;
6403       }
6404       if (cdof != numConst) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_LIB, "Total number of field constraints %D should be %D", numConst, cdof);
6405       ierr = PetscSectionSetConstraintIndices(section, p, indices);CHKERRQ(ierr);
6406     }
6407   }
6408   ierr = PetscFree(indices);CHKERRQ(ierr);
6409   PetscFunctionReturn(0);
6410 }
6411 
6412 #undef __FUNCT__
6413 #define __FUNCT__ "DMPlexCreateSection"
6414 /*@C
6415   DMPlexCreateSection - Create a PetscSection based upon the dof layout specification provided.
6416 
6417   Not Collective
6418 
6419   Input Parameters:
6420 + dm        - The DMPlex object
6421 . dim       - The spatial dimension of the problem
6422 . numFields - The number of fields in the problem
6423 . numComp   - An array of size numFields that holds the number of components for each field
6424 . numDof    - An array of size numFields*(dim+1) which holds the number of dof for each field on a mesh piece of dimension d
6425 . numBC     - The number of boundary conditions
6426 . bcField   - An array of size numBC giving the field number for each boundry condition
6427 - bcPoints  - An array of size numBC giving an IS holding the sieve points to which each boundary condition applies
6428 
6429   Output Parameter:
6430 . section - The PetscSection object
6431 
6432   Notes: numDof[f*(dim+1)+d] gives the number of dof for field f on sieve points of dimension d. For instance, numDof[1] is the
6433   nubmer of dof for field 0 on each edge.
6434 
6435   Level: developer
6436 
6437   Fortran Notes:
6438   A Fortran 90 version is available as DMPlexCreateSectionF90()
6439 
6440 .keywords: mesh, elements
6441 .seealso: DMPlexCreate(), PetscSectionCreate()
6442 @*/
6443 PetscErrorCode DMPlexCreateSection(DM dm, PetscInt dim, PetscInt numFields,const PetscInt numComp[],const PetscInt numDof[], PetscInt numBC,const PetscInt bcField[],const IS bcPoints[], PetscSection *section)
6444 {
6445   PetscErrorCode ierr;
6446 
6447   PetscFunctionBegin;
6448   ierr = DMPlexCreateSectionInitial(dm, dim, numFields, numComp, numDof, section);CHKERRQ(ierr);
6449   ierr = DMPlexCreateSectionBCDof(dm, numBC, bcField, bcPoints, PETSC_DETERMINE, *section);CHKERRQ(ierr);
6450   ierr = PetscSectionSetUp(*section);CHKERRQ(ierr);
6451   if (numBC) {ierr = DMPlexCreateSectionBCIndicesAll(dm, *section);CHKERRQ(ierr);}
6452   {
6453     PetscBool view = PETSC_FALSE;
6454 
6455     ierr = PetscOptionsHasName(((PetscObject) dm)->prefix, "-section_view", &view);CHKERRQ(ierr);
6456     if (view) {ierr = PetscSectionView(*section, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);}
6457   }
6458   PetscFunctionReturn(0);
6459 }
6460 
6461 #undef __FUNCT__
6462 #define __FUNCT__ "DMCreateCoordinateDM_Plex"
6463 PetscErrorCode DMCreateCoordinateDM_Plex(DM dm, DM *cdm)
6464 {
6465   PetscSection   section;
6466   PetscErrorCode ierr;
6467 
6468   PetscFunctionBegin;
6469   ierr = DMClone(dm, cdm);CHKERRQ(ierr);
6470   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)dm), &section);CHKERRQ(ierr);
6471   ierr = DMSetDefaultSection(*cdm, section);CHKERRQ(ierr);
6472   ierr = PetscSectionDestroy(&section);CHKERRQ(ierr);
6473   PetscFunctionReturn(0);
6474 }
6475 
6476 #undef __FUNCT__
6477 #define __FUNCT__ "DMPlexGetCoordinateSection"
6478 /*@
6479   DMPlexGetCoordinateSection - Retrieve the layout of coordinate values over the mesh.
6480 
6481   Not Collective
6482 
6483   Input Parameter:
6484 . dm - The DMPlex object
6485 
6486   Output Parameter:
6487 . section - The PetscSection object
6488 
6489   Level: intermediate
6490 
6491 .keywords: mesh, coordinates
6492 .seealso: DMGetCoordinateDM(), DMPlexGetDefaultSection(), DMPlexSetDefaultSection()
6493 @*/
6494 PetscErrorCode DMPlexGetCoordinateSection(DM dm, PetscSection *section)
6495 {
6496   DM             cdm;
6497   PetscErrorCode ierr;
6498 
6499   PetscFunctionBegin;
6500   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6501   PetscValidPointer(section, 2);
6502   ierr = DMGetCoordinateDM(dm, &cdm);CHKERRQ(ierr);
6503   ierr = DMGetDefaultSection(cdm, section);CHKERRQ(ierr);
6504   PetscFunctionReturn(0);
6505 }
6506 
6507 #undef __FUNCT__
6508 #define __FUNCT__ "DMPlexSetCoordinateSection"
6509 /*@
6510   DMPlexSetCoordinateSection - Set the layout of coordinate values over the mesh.
6511 
6512   Not Collective
6513 
6514   Input Parameters:
6515 + dm      - The DMPlex object
6516 - section - The PetscSection object
6517 
6518   Level: intermediate
6519 
6520 .keywords: mesh, coordinates
6521 .seealso: DMPlexGetCoordinateSection(), DMPlexGetDefaultSection(), DMPlexSetDefaultSection()
6522 @*/
6523 PetscErrorCode DMPlexSetCoordinateSection(DM dm, PetscSection section)
6524 {
6525   DM             cdm;
6526   PetscErrorCode ierr;
6527 
6528   PetscFunctionBegin;
6529   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
6530   PetscValidHeaderSpecific(section,PETSC_SECTION_CLASSID,2);
6531   ierr = DMGetCoordinateDM(dm, &cdm);CHKERRQ(ierr);
6532   ierr = DMSetDefaultSection(cdm, section);CHKERRQ(ierr);
6533   PetscFunctionReturn(0);
6534 }
6535 
6536 #undef __FUNCT__
6537 #define __FUNCT__ "DMPlexGetConeSection"
6538 PetscErrorCode DMPlexGetConeSection(DM dm, PetscSection *section)
6539 {
6540   DM_Plex *mesh = (DM_Plex*) dm->data;
6541 
6542   PetscFunctionBegin;
6543   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6544   if (section) *section = mesh->coneSection;
6545   PetscFunctionReturn(0);
6546 }
6547 
6548 #undef __FUNCT__
6549 #define __FUNCT__ "DMPlexGetCones"
6550 PetscErrorCode DMPlexGetCones(DM dm, PetscInt *cones[])
6551 {
6552   DM_Plex *mesh = (DM_Plex*) dm->data;
6553 
6554   PetscFunctionBegin;
6555   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6556   if (cones) *cones = mesh->cones;
6557   PetscFunctionReturn(0);
6558 }
6559 
6560 #undef __FUNCT__
6561 #define __FUNCT__ "DMPlexGetConeOrientations"
6562 PetscErrorCode DMPlexGetConeOrientations(DM dm, PetscInt *coneOrientations[])
6563 {
6564   DM_Plex *mesh = (DM_Plex*) dm->data;
6565 
6566   PetscFunctionBegin;
6567   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6568   if (coneOrientations) *coneOrientations = mesh->coneOrientations;
6569   PetscFunctionReturn(0);
6570 }
6571 
6572 /******************************** FEM Support **********************************/
6573 
6574 #undef __FUNCT__
6575 #define __FUNCT__ "DMPlexVecGetClosure"
6576 /*@C
6577   DMPlexVecGetClosure - Get an array of the values on the closure of 'point'
6578 
6579   Not collective
6580 
6581   Input Parameters:
6582 + dm - The DM
6583 . section - The section describing the layout in v, or NULL to use the default section
6584 . v - The local vector
6585 - point - The sieve point in the DM
6586 
6587   Output Parameters:
6588 + csize - The number of values in the closure, or NULL
6589 - values - The array of values, which is a borrowed array and should not be freed
6590 
6591   Fortran Notes:
6592   Since it returns an array, this routine is only available in Fortran 90, and you must
6593   include petsc.h90 in your code.
6594 
6595   The csize argument is not present in the Fortran 90 binding since it is internal to the array.
6596 
6597   Level: intermediate
6598 
6599 .seealso DMPlexVecRestoreClosure(), DMPlexVecSetClosure(), DMPlexMatSetClosure()
6600 @*/
6601 PetscErrorCode DMPlexVecGetClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[])
6602 {
6603   PetscScalar   *array, *vArray;
6604   PetscInt      *points = NULL;
6605   PetscInt       offsets[32];
6606   PetscInt       depth, numFields, size = 0, numPoints, pStart, pEnd, p, q, f;
6607   PetscErrorCode ierr;
6608 
6609   PetscFunctionBegin;
6610   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6611   PetscValidHeaderSpecific(v, VEC_CLASSID, 3);
6612   if (!section) {
6613     ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
6614   }
6615   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
6616   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
6617   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
6618   if (numFields > 31) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
6619   ierr = PetscMemzero(offsets, 32 * sizeof(PetscInt));CHKERRQ(ierr);
6620   if (depth == 1 && numFields < 2) {
6621     const PetscInt *cone, *coneO;
6622 
6623     ierr = DMPlexGetConeSize(dm, point, &numPoints);CHKERRQ(ierr);
6624     ierr = DMPlexGetCone(dm, point, &cone);CHKERRQ(ierr);
6625     ierr = DMPlexGetConeOrientation(dm, point, &coneO);CHKERRQ(ierr);
6626     if (!values || !*values) {
6627       if ((point >= pStart) && (point < pEnd)) {
6628         PetscInt dof;
6629         ierr = PetscSectionGetDof(section, point, &dof);CHKERRQ(ierr);
6630         size += dof;
6631       }
6632       for (p = 0; p < numPoints; ++p) {
6633         const PetscInt cp = cone[p];
6634         PetscInt       dof;
6635 
6636         if ((cp < pStart) || (cp >= pEnd)) continue;
6637         ierr = PetscSectionGetDof(section, cp, &dof);CHKERRQ(ierr);
6638         size += dof;
6639       }
6640       if (!values) {
6641         if (csize) *csize = size;
6642         PetscFunctionReturn(0);
6643       }
6644       ierr = DMGetWorkArray(dm, size, PETSC_SCALAR, &array);CHKERRQ(ierr);
6645     } else {
6646       array = *values;
6647     }
6648     size = 0;
6649     ierr = VecGetArray(v, &vArray);CHKERRQ(ierr);
6650     if ((point >= pStart) && (point < pEnd)) {
6651       PetscInt     dof, off, d;
6652       PetscScalar *varr;
6653       ierr = PetscSectionGetDof(section, point, &dof);CHKERRQ(ierr);
6654       ierr = PetscSectionGetOffset(section, point, &off);CHKERRQ(ierr);
6655       varr = &vArray[off];
6656       for (d = 0; d < dof; ++d, ++offsets[0]) {
6657         array[offsets[0]] = varr[d];
6658       }
6659       size += dof;
6660     }
6661     for (p = 0; p < numPoints; ++p) {
6662       const PetscInt cp = cone[p];
6663       PetscInt       o  = coneO[p];
6664       PetscInt       dof, off, d;
6665       PetscScalar   *varr;
6666 
6667       if ((cp < pStart) || (cp >= pEnd)) continue;
6668       ierr = PetscSectionGetDof(section, cp, &dof);CHKERRQ(ierr);
6669       ierr = PetscSectionGetOffset(section, cp, &off);CHKERRQ(ierr);
6670       varr = &vArray[off];
6671       if (o >= 0) {
6672         for (d = 0; d < dof; ++d, ++offsets[0]) {
6673           array[offsets[0]] = varr[d];
6674         }
6675       } else {
6676         for (d = dof-1; d >= 0; --d, ++offsets[0]) {
6677           array[offsets[0]] = varr[d];
6678         }
6679       }
6680       size += dof;
6681     }
6682     ierr = VecRestoreArray(v, &vArray);CHKERRQ(ierr);
6683     if (!*values) {
6684       if (csize) *csize = size;
6685       *values = array;
6686     } else {
6687       if (size > *csize) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %d < actual size %d", *csize, size);
6688       *csize = size;
6689     }
6690     PetscFunctionReturn(0);
6691   }
6692   ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
6693   /* Compress out points not in the section */
6694   for (p = 0, q = 0; p < numPoints*2; p += 2) {
6695     if ((points[p] >= pStart) && (points[p] < pEnd)) {
6696       points[q*2]   = points[p];
6697       points[q*2+1] = points[p+1];
6698       ++q;
6699     }
6700   }
6701   numPoints = q;
6702   if (!values || !*values) {
6703     for (p = 0, size = 0; p < numPoints*2; p += 2) {
6704       PetscInt dof, fdof;
6705 
6706       ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
6707       for (f = 0; f < numFields; ++f) {
6708         ierr          = PetscSectionGetFieldDof(section, points[p], f, &fdof);CHKERRQ(ierr);
6709         offsets[f+1] += fdof;
6710       }
6711       size += dof;
6712     }
6713     if (!values) {
6714       ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
6715       if (csize) *csize = size;
6716       PetscFunctionReturn(0);
6717     }
6718     ierr = DMGetWorkArray(dm, size, PETSC_SCALAR, &array);CHKERRQ(ierr);
6719   } else {
6720     array = *values;
6721   }
6722   for (f = 1; f < numFields; ++f) offsets[f+1] += offsets[f];
6723   if (numFields && offsets[numFields] != size) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid size for closure %d should be %d", offsets[numFields], size);
6724   ierr = VecGetArray(v, &vArray);CHKERRQ(ierr);
6725   for (p = 0; p < numPoints*2; p += 2) {
6726     PetscInt     o = points[p+1];
6727     PetscInt     dof, off, d;
6728     PetscScalar *varr;
6729 
6730     ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
6731     ierr = PetscSectionGetOffset(section, points[p], &off);CHKERRQ(ierr);
6732     varr = &vArray[off];
6733     if (numFields) {
6734       PetscInt fdof, foff, fcomp, f, c;
6735 
6736       for (f = 0, foff = 0; f < numFields; ++f) {
6737         ierr = PetscSectionGetFieldDof(section, points[p], f, &fdof);CHKERRQ(ierr);
6738         if (o >= 0) {
6739           for (d = 0; d < fdof; ++d, ++offsets[f]) {
6740             array[offsets[f]] = varr[foff+d];
6741           }
6742         } else {
6743           ierr = PetscSectionGetFieldComponents(section, f, &fcomp);CHKERRQ(ierr);
6744           for (d = fdof/fcomp-1; d >= 0; --d) {
6745             for (c = 0; c < fcomp; ++c, ++offsets[f]) {
6746               array[offsets[f]] = varr[foff+d*fcomp+c];
6747             }
6748           }
6749         }
6750         foff += fdof;
6751       }
6752     } else {
6753       if (o >= 0) {
6754         for (d = 0; d < dof; ++d, ++offsets[0]) {
6755           array[offsets[0]] = varr[d];
6756         }
6757       } else {
6758         for (d = dof-1; d >= 0; --d, ++offsets[0]) {
6759           array[offsets[0]] = varr[d];
6760         }
6761       }
6762     }
6763   }
6764   ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
6765   ierr = VecRestoreArray(v, &vArray);CHKERRQ(ierr);
6766   if (!*values) {
6767     if (csize) *csize = size;
6768     *values = array;
6769   } else {
6770     if (size > *csize) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %d < actual size %d", *csize, size);
6771     *csize = size;
6772   }
6773   PetscFunctionReturn(0);
6774 }
6775 
6776 #undef __FUNCT__
6777 #define __FUNCT__ "DMPlexVecRestoreClosure"
6778 /*@C
6779   DMPlexVecRestoreClosure - Restore the array of the values on the closure of 'point'
6780 
6781   Not collective
6782 
6783   Input Parameters:
6784 + dm - The DM
6785 . section - The section describing the layout in v, or NULL to use the default section
6786 . v - The local vector
6787 . point - The sieve point in the DM
6788 . csize - The number of values in the closure, or NULL
6789 - values - The array of values, which is a borrowed array and should not be freed
6790 
6791   Fortran Notes:
6792   Since it returns an array, this routine is only available in Fortran 90, and you must
6793   include petsc.h90 in your code.
6794 
6795   The csize argument is not present in the Fortran 90 binding since it is internal to the array.
6796 
6797   Level: intermediate
6798 
6799 .seealso DMPlexVecGetClosure(), DMPlexVecSetClosure(), DMPlexMatSetClosure()
6800 @*/
6801 PetscErrorCode DMPlexVecRestoreClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[])
6802 {
6803   PetscInt       size = 0;
6804   PetscErrorCode ierr;
6805 
6806   PetscFunctionBegin;
6807   /* Should work without recalculating size */
6808   ierr = DMRestoreWorkArray(dm, size, PETSC_SCALAR, (void*) values);CHKERRQ(ierr);
6809   PetscFunctionReturn(0);
6810 }
6811 
6812 PETSC_STATIC_INLINE void add   (PetscScalar *x, PetscScalar y) {*x += y;}
6813 PETSC_STATIC_INLINE void insert(PetscScalar *x, PetscScalar y) {*x  = y;}
6814 
6815 #undef __FUNCT__
6816 #define __FUNCT__ "updatePoint_private"
6817 PetscErrorCode updatePoint_private(PetscSection section, PetscInt point, PetscInt dof, void (*fuse)(PetscScalar*, PetscScalar), PetscBool setBC, PetscInt orientation, const PetscScalar values[], PetscScalar array[])
6818 {
6819   PetscInt        cdof;   /* The number of constraints on this point */
6820   const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
6821   PetscScalar    *a;
6822   PetscInt        off, cind = 0, k;
6823   PetscErrorCode  ierr;
6824 
6825   PetscFunctionBegin;
6826   ierr = PetscSectionGetConstraintDof(section, point, &cdof);CHKERRQ(ierr);
6827   ierr = PetscSectionGetOffset(section, point, &off);CHKERRQ(ierr);
6828   a    = &array[off];
6829   if (!cdof || setBC) {
6830     if (orientation >= 0) {
6831       for (k = 0; k < dof; ++k) {
6832         fuse(&a[k], values[k]);
6833       }
6834     } else {
6835       for (k = 0; k < dof; ++k) {
6836         fuse(&a[k], values[dof-k-1]);
6837       }
6838     }
6839   } else {
6840     ierr = PetscSectionGetConstraintIndices(section, point, &cdofs);CHKERRQ(ierr);
6841     if (orientation >= 0) {
6842       for (k = 0; k < dof; ++k) {
6843         if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
6844         fuse(&a[k], values[k]);
6845       }
6846     } else {
6847       for (k = 0; k < dof; ++k) {
6848         if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
6849         fuse(&a[k], values[dof-k-1]);
6850       }
6851     }
6852   }
6853   PetscFunctionReturn(0);
6854 }
6855 
6856 #undef __FUNCT__
6857 #define __FUNCT__ "updatePointBC_private"
6858 PetscErrorCode updatePointBC_private(PetscSection section, PetscInt point, PetscInt dof, void (*fuse)(PetscScalar*, PetscScalar), PetscInt orientation, const PetscScalar values[], PetscScalar array[])
6859 {
6860   PetscInt        cdof;   /* The number of constraints on this point */
6861   const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
6862   PetscScalar    *a;
6863   PetscInt        off, cind = 0, k;
6864   PetscErrorCode  ierr;
6865 
6866   PetscFunctionBegin;
6867   ierr = PetscSectionGetConstraintDof(section, point, &cdof);CHKERRQ(ierr);
6868   ierr = PetscSectionGetOffset(section, point, &off);CHKERRQ(ierr);
6869   a    = &array[off];
6870   if (cdof) {
6871     ierr = PetscSectionGetConstraintIndices(section, point, &cdofs);CHKERRQ(ierr);
6872     if (orientation >= 0) {
6873       for (k = 0; k < dof; ++k) {
6874         if ((cind < cdof) && (k == cdofs[cind])) {
6875           fuse(&a[k], values[k]);
6876           ++cind;
6877         }
6878       }
6879     } else {
6880       for (k = 0; k < dof; ++k) {
6881         if ((cind < cdof) && (k == cdofs[cind])) {
6882           fuse(&a[k], values[dof-k-1]);
6883           ++cind;
6884         }
6885       }
6886     }
6887   }
6888   PetscFunctionReturn(0);
6889 }
6890 
6891 #undef __FUNCT__
6892 #define __FUNCT__ "updatePointFields_private"
6893 PetscErrorCode updatePointFields_private(PetscSection section, PetscInt point, PetscInt foffs[], void (*fuse)(PetscScalar*, PetscScalar), PetscBool setBC, PetscInt orientation, const PetscScalar values[], PetscScalar array[])
6894 {
6895   PetscScalar   *a;
6896   PetscInt       numFields, off, foff, f;
6897   PetscErrorCode ierr;
6898 
6899   PetscFunctionBegin;
6900   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
6901   ierr = PetscSectionGetOffset(section, point, &off);CHKERRQ(ierr);
6902   a    = &array[off];
6903   for (f = 0, foff = 0; f < numFields; ++f) {
6904     PetscInt        fdof, fcomp, fcdof;
6905     const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
6906     PetscInt        cind = 0, k, c;
6907 
6908     ierr = PetscSectionGetFieldComponents(section, f, &fcomp);CHKERRQ(ierr);
6909     ierr = PetscSectionGetFieldDof(section, point, f, &fdof);CHKERRQ(ierr);
6910     ierr = PetscSectionGetFieldConstraintDof(section, point, f, &fcdof);CHKERRQ(ierr);
6911     if (!fcdof || setBC) {
6912       if (orientation >= 0) {
6913         for (k = 0; k < fdof; ++k) {
6914           fuse(&a[foff+k], values[foffs[f]+k]);
6915         }
6916       } else {
6917         for (k = fdof/fcomp-1; k >= 0; --k) {
6918           for (c = 0; c < fcomp; ++c) {
6919             fuse(&a[foff+(fdof/fcomp-1-k)*fcomp+c], values[foffs[f]+k*fcomp+c]);
6920           }
6921         }
6922       }
6923     } else {
6924       ierr = PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);CHKERRQ(ierr);
6925       if (orientation >= 0) {
6926         for (k = 0; k < fdof; ++k) {
6927           if ((cind < fcdof) && (k == fcdofs[cind])) {++cind; continue;}
6928           fuse(&a[foff+k], values[foffs[f]+k]);
6929         }
6930       } else {
6931         for (k = fdof/fcomp-1; k >= 0; --k) {
6932           for (c = 0; c < fcomp; ++c) {
6933             if ((cind < fcdof) && (k*fcomp+c == fcdofs[cind])) {++cind; continue;}
6934             fuse(&a[foff+(fdof/fcomp-1-k)*fcomp+c], values[foffs[f]+k*fcomp+c]);
6935           }
6936         }
6937       }
6938     }
6939     foff     += fdof;
6940     foffs[f] += fdof;
6941   }
6942   PetscFunctionReturn(0);
6943 }
6944 
6945 #undef __FUNCT__
6946 #define __FUNCT__ "updatePointFieldsBC_private"
6947 PetscErrorCode updatePointFieldsBC_private(PetscSection section, PetscInt point, PetscInt foffs[], void (*fuse)(PetscScalar*, PetscScalar), PetscInt orientation, const PetscScalar values[], PetscScalar array[])
6948 {
6949   PetscScalar   *a;
6950   PetscInt       numFields, off, foff, f;
6951   PetscErrorCode ierr;
6952 
6953   PetscFunctionBegin;
6954   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
6955   ierr = PetscSectionGetOffset(section, point, &off);CHKERRQ(ierr);
6956   a    = &array[off];
6957   for (f = 0, foff = 0; f < numFields; ++f) {
6958     PetscInt        fdof, fcomp, fcdof;
6959     const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
6960     PetscInt        cind = 0, k, c;
6961 
6962     ierr = PetscSectionGetFieldComponents(section, f, &fcomp);CHKERRQ(ierr);
6963     ierr = PetscSectionGetFieldDof(section, point, f, &fdof);CHKERRQ(ierr);
6964     ierr = PetscSectionGetFieldConstraintDof(section, point, f, &fcdof);CHKERRQ(ierr);
6965     if (fcdof) {
6966       ierr = PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);CHKERRQ(ierr);
6967       if (orientation >= 0) {
6968         for (k = 0; k < fdof; ++k) {
6969           if ((cind < fcdof) && (k == fcdofs[cind])) {
6970             fuse(&a[foff+k], values[foffs[f]+k]);
6971             ++cind;
6972           }
6973         }
6974       } else {
6975         for (k = fdof/fcomp-1; k >= 0; --k) {
6976           for (c = 0; c < fcomp; ++c) {
6977             if ((cind < fcdof) && (k*fcomp+c == fcdofs[cind])) {
6978               fuse(&a[foff+(fdof/fcomp-1-k)*fcomp+c], values[foffs[f]+k*fcomp+c]);
6979               ++cind;
6980             }
6981           }
6982         }
6983       }
6984     }
6985     foff     += fdof;
6986     foffs[f] += fdof;
6987   }
6988   PetscFunctionReturn(0);
6989 }
6990 
6991 #undef __FUNCT__
6992 #define __FUNCT__ "DMPlexVecSetClosure"
6993 /*@C
6994   DMPlexVecSetClosure - Set an array of the values on the closure of 'point'
6995 
6996   Not collective
6997 
6998   Input Parameters:
6999 + dm - The DM
7000 . section - The section describing the layout in v, or NULL to use the default section
7001 . v - The local vector
7002 . point - The sieve point in the DM
7003 . values - The array of values
7004 - mode - The insert mode, where INSERT_ALL_VALUES and ADD_ALL_VALUES also overwrite boundary conditions
7005 
7006   Fortran Notes:
7007   This routine is only available in Fortran 90, and you must include petsc.h90 in your code.
7008 
7009   Level: intermediate
7010 
7011 .seealso DMPlexVecGetClosure(), DMPlexMatSetClosure()
7012 @*/
7013 PetscErrorCode DMPlexVecSetClosure(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode)
7014 {
7015   PetscScalar   *array;
7016   PetscInt      *points = NULL;
7017   PetscInt       offsets[32];
7018   PetscInt       depth, numFields, numPoints, off, dof, pStart, pEnd, p, q, f;
7019   PetscErrorCode ierr;
7020 
7021   PetscFunctionBegin;
7022   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7023   PetscValidHeaderSpecific(v, VEC_CLASSID, 3);
7024   if (!section) {
7025     ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
7026   }
7027   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
7028   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
7029   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
7030   if (numFields > 31) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
7031   ierr = PetscMemzero(offsets, 32 * sizeof(PetscInt));CHKERRQ(ierr);
7032   if (depth == 1 && numFields < 2 && mode == ADD_VALUES) {
7033     const PetscInt *cone, *coneO;
7034 
7035     ierr = DMPlexGetConeSize(dm, point, &numPoints);CHKERRQ(ierr);
7036     ierr = DMPlexGetCone(dm, point, &cone);CHKERRQ(ierr);
7037     ierr = DMPlexGetConeOrientation(dm, point, &coneO);CHKERRQ(ierr);
7038     ierr = VecGetArray(v, &array);CHKERRQ(ierr);
7039     for (p = 0, off = 0; p <= numPoints; ++p, off += dof) {
7040       const PetscInt cp = !p ? point : cone[p-1];
7041       const PetscInt o  = !p ? 0     : coneO[p-1];
7042 
7043       if ((cp < pStart) || (cp >= pEnd)) {dof = 0; continue;}
7044       ierr = PetscSectionGetDof(section, cp, &dof);CHKERRQ(ierr);
7045       /* ADD_VALUES */
7046       {
7047         const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
7048         PetscScalar    *a;
7049         PetscInt        cdof, coff, cind = 0, k;
7050 
7051         ierr = PetscSectionGetConstraintDof(section, cp, &cdof);CHKERRQ(ierr);
7052         ierr = PetscSectionGetOffset(section, cp, &coff);CHKERRQ(ierr);
7053         a    = &array[coff];
7054         if (!cdof) {
7055           if (o >= 0) {
7056             for (k = 0; k < dof; ++k) {
7057               a[k] += values[off+k];
7058             }
7059           } else {
7060             for (k = 0; k < dof; ++k) {
7061               a[k] += values[off+dof-k-1];
7062             }
7063           }
7064         } else {
7065           ierr = PetscSectionGetConstraintIndices(section, cp, &cdofs);CHKERRQ(ierr);
7066           if (o >= 0) {
7067             for (k = 0; k < dof; ++k) {
7068               if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
7069               a[k] += values[off+k];
7070             }
7071           } else {
7072             for (k = 0; k < dof; ++k) {
7073               if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
7074               a[k] += values[off+dof-k-1];
7075             }
7076           }
7077         }
7078       }
7079     }
7080     ierr = VecRestoreArray(v, &array);CHKERRQ(ierr);
7081     PetscFunctionReturn(0);
7082   }
7083   ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
7084   /* Compress out points not in the section */
7085   for (p = 0, q = 0; p < numPoints*2; p += 2) {
7086     if ((points[p] >= pStart) && (points[p] < pEnd)) {
7087       points[q*2]   = points[p];
7088       points[q*2+1] = points[p+1];
7089       ++q;
7090     }
7091   }
7092   numPoints = q;
7093   for (p = 0; p < numPoints*2; p += 2) {
7094     PetscInt fdof;
7095 
7096     for (f = 0; f < numFields; ++f) {
7097       ierr          = PetscSectionGetFieldDof(section, points[p], f, &fdof);CHKERRQ(ierr);
7098       offsets[f+1] += fdof;
7099     }
7100   }
7101   for (f = 1; f < numFields; ++f) offsets[f+1] += offsets[f];
7102   ierr = VecGetArray(v, &array);CHKERRQ(ierr);
7103   if (numFields) {
7104     switch (mode) {
7105     case INSERT_VALUES:
7106       for (p = 0; p < numPoints*2; p += 2) {
7107         PetscInt o = points[p+1];
7108         updatePointFields_private(section, points[p], offsets, insert, PETSC_FALSE, o, values, array);
7109       } break;
7110     case INSERT_ALL_VALUES:
7111       for (p = 0; p < numPoints*2; p += 2) {
7112         PetscInt o = points[p+1];
7113         updatePointFields_private(section, points[p], offsets, insert, PETSC_TRUE,  o, values, array);
7114       } break;
7115     case INSERT_BC_VALUES:
7116       for (p = 0; p < numPoints*2; p += 2) {
7117         PetscInt o = points[p+1];
7118         updatePointFieldsBC_private(section, points[p], offsets, insert,  o, values, array);
7119       } break;
7120     case ADD_VALUES:
7121       for (p = 0; p < numPoints*2; p += 2) {
7122         PetscInt o = points[p+1];
7123         updatePointFields_private(section, points[p], offsets, add,    PETSC_FALSE, o, values, array);
7124       } break;
7125     case ADD_ALL_VALUES:
7126       for (p = 0; p < numPoints*2; p += 2) {
7127         PetscInt o = points[p+1];
7128         updatePointFields_private(section, points[p], offsets, add,    PETSC_TRUE,  o, values, array);
7129       } break;
7130     default:
7131       SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %D", mode);
7132     }
7133   } else {
7134     switch (mode) {
7135     case INSERT_VALUES:
7136       for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) {
7137         PetscInt o = points[p+1];
7138         ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
7139         updatePoint_private(section, points[p], dof, insert, PETSC_FALSE, o, &values[off], array);
7140       } break;
7141     case INSERT_ALL_VALUES:
7142       for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) {
7143         PetscInt o = points[p+1];
7144         ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
7145         updatePoint_private(section, points[p], dof, insert, PETSC_TRUE,  o, &values[off], array);
7146       } break;
7147     case INSERT_BC_VALUES:
7148       for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) {
7149         PetscInt o = points[p+1];
7150         ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
7151         updatePointBC_private(section, points[p], dof, insert,  o, &values[off], array);
7152       } break;
7153     case ADD_VALUES:
7154       for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) {
7155         PetscInt o = points[p+1];
7156         ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
7157         updatePoint_private(section, points[p], dof, add,    PETSC_FALSE, o, &values[off], array);
7158       } break;
7159     case ADD_ALL_VALUES:
7160       for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) {
7161         PetscInt o = points[p+1];
7162         ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
7163         updatePoint_private(section, points[p], dof, add,    PETSC_TRUE,  o, &values[off], array);
7164       } break;
7165     default:
7166       SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %D", mode);
7167     }
7168   }
7169   ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
7170   ierr = VecRestoreArray(v, &array);CHKERRQ(ierr);
7171   PetscFunctionReturn(0);
7172 }
7173 
7174 #undef __FUNCT__
7175 #define __FUNCT__ "DMPlexPrintMatSetValues"
7176 PetscErrorCode DMPlexPrintMatSetValues(PetscViewer viewer, Mat A, PetscInt point, PetscInt numIndices, const PetscInt indices[], const PetscScalar values[])
7177 {
7178   PetscMPIInt    rank;
7179   PetscInt       i, j;
7180   PetscErrorCode ierr;
7181 
7182   PetscFunctionBegin;
7183   ierr = MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank);CHKERRQ(ierr);
7184   ierr = PetscViewerASCIIPrintf(viewer, "[%D]mat for sieve point %D\n", rank, point);CHKERRQ(ierr);
7185   for (i = 0; i < numIndices; i++) {
7186     ierr = PetscViewerASCIIPrintf(viewer, "[%D]mat indices[%D] = %D\n", rank, i, indices[i]);CHKERRQ(ierr);
7187   }
7188   for (i = 0; i < numIndices; i++) {
7189     ierr = PetscViewerASCIIPrintf(viewer, "[%D]", rank);CHKERRQ(ierr);
7190     for (j = 0; j < numIndices; j++) {
7191 #if defined(PETSC_USE_COMPLEX)
7192       ierr = PetscViewerASCIIPrintf(viewer, " (%G,%G)", PetscRealPart(values[i*numIndices+j]), PetscImaginaryPart(values[i*numIndices+j]));CHKERRQ(ierr);
7193 #else
7194       ierr = PetscViewerASCIIPrintf(viewer, " %G", values[i*numIndices+j]);CHKERRQ(ierr);
7195 #endif
7196     }
7197     ierr = PetscViewerASCIIPrintf(viewer, "\n");CHKERRQ(ierr);
7198   }
7199   PetscFunctionReturn(0);
7200 }
7201 
7202 #undef __FUNCT__
7203 #define __FUNCT__ "indicesPoint_private"
7204 /* . off - The global offset of this point */
7205 PetscErrorCode indicesPoint_private(PetscSection section, PetscInt point, PetscInt off, PetscInt *loff, PetscBool setBC, PetscInt orientation, PetscInt indices[])
7206 {
7207   PetscInt        dof;    /* The number of unknowns on this point */
7208   PetscInt        cdof;   /* The number of constraints on this point */
7209   const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
7210   PetscInt        cind = 0, k;
7211   PetscErrorCode  ierr;
7212 
7213   PetscFunctionBegin;
7214   ierr = PetscSectionGetDof(section, point, &dof);CHKERRQ(ierr);
7215   ierr = PetscSectionGetConstraintDof(section, point, &cdof);CHKERRQ(ierr);
7216   if (!cdof || setBC) {
7217     if (orientation >= 0) {
7218       for (k = 0; k < dof; ++k) indices[*loff+k] = off+k;
7219     } else {
7220       for (k = 0; k < dof; ++k) indices[*loff+dof-k-1] = off+k;
7221     }
7222   } else {
7223     ierr = PetscSectionGetConstraintIndices(section, point, &cdofs);CHKERRQ(ierr);
7224     if (orientation >= 0) {
7225       for (k = 0; k < dof; ++k) {
7226         if ((cind < cdof) && (k == cdofs[cind])) {
7227           /* Insert check for returning constrained indices */
7228           indices[*loff+k] = -(off+k+1);
7229           ++cind;
7230         } else {
7231           indices[*loff+k] = off+k-cind;
7232         }
7233       }
7234     } else {
7235       for (k = 0; k < dof; ++k) {
7236         if ((cind < cdof) && (k == cdofs[cind])) {
7237           /* Insert check for returning constrained indices */
7238           indices[*loff+dof-k-1] = -(off+k+1);
7239           ++cind;
7240         } else {
7241           indices[*loff+dof-k-1] = off+k-cind;
7242         }
7243       }
7244     }
7245   }
7246   *loff += dof;
7247   PetscFunctionReturn(0);
7248 }
7249 
7250 #undef __FUNCT__
7251 #define __FUNCT__ "indicesPointFields_private"
7252 /* . off - The global offset of this point */
7253 PetscErrorCode indicesPointFields_private(PetscSection section, PetscInt point, PetscInt off, PetscInt foffs[], PetscBool setBC, PetscInt orientation, PetscInt indices[])
7254 {
7255   PetscInt       numFields, foff, f;
7256   PetscErrorCode ierr;
7257 
7258   PetscFunctionBegin;
7259   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
7260   for (f = 0, foff = 0; f < numFields; ++f) {
7261     PetscInt        fdof, fcomp, cfdof;
7262     const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
7263     PetscInt        cind = 0, k, c;
7264 
7265     ierr = PetscSectionGetFieldComponents(section, f, &fcomp);CHKERRQ(ierr);
7266     ierr = PetscSectionGetFieldDof(section, point, f, &fdof);CHKERRQ(ierr);
7267     ierr = PetscSectionGetFieldConstraintDof(section, point, f, &cfdof);CHKERRQ(ierr);
7268     if (!cfdof || setBC) {
7269       if (orientation >= 0) {
7270         for (k = 0; k < fdof; ++k) indices[foffs[f]+k] = off+foff+k;
7271       } else {
7272         for (k = fdof/fcomp-1; k >= 0; --k) {
7273           for (c = 0; c < fcomp; ++c) {
7274             indices[foffs[f]+k*fcomp+c] = off+foff+(fdof/fcomp-1-k)*fcomp+c;
7275           }
7276         }
7277       }
7278     } else {
7279       ierr = PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);CHKERRQ(ierr);
7280       if (orientation >= 0) {
7281         for (k = 0; k < fdof; ++k) {
7282           if ((cind < cfdof) && (k == fcdofs[cind])) {
7283             indices[foffs[f]+k] = -(off+foff+k+1);
7284             ++cind;
7285           } else {
7286             indices[foffs[f]+k] = off+foff+k-cind;
7287           }
7288         }
7289       } else {
7290         for (k = fdof/fcomp-1; k >= 0; --k) {
7291           for (c = 0; c < fcomp; ++c) {
7292             if ((cind < cfdof) && ((fdof/fcomp-1-k)*fcomp+c == fcdofs[cind])) {
7293               indices[foffs[f]+k*fcomp+c] = -(off+foff+(fdof/fcomp-1-k)*fcomp+c+1);
7294               ++cind;
7295             } else {
7296               indices[foffs[f]+k*fcomp+c] = off+foff+(fdof/fcomp-1-k)*fcomp+c-cind;
7297             }
7298           }
7299         }
7300       }
7301     }
7302     foff     += fdof - cfdof;
7303     foffs[f] += fdof;
7304   }
7305   PetscFunctionReturn(0);
7306 }
7307 
7308 #undef __FUNCT__
7309 #define __FUNCT__ "DMPlexMatSetClosure"
7310 /*@C
7311   DMPlexMatSetClosure - Set an array of the values on the closure of 'point'
7312 
7313   Not collective
7314 
7315   Input Parameters:
7316 + dm - The DM
7317 . section - The section describing the layout in v
7318 . globalSection - The section describing the layout in v
7319 . A - The matrix
7320 . point - The sieve point in the DM
7321 . values - The array of values
7322 - mode - The insert mode, where INSERT_ALL_VALUES and ADD_ALL_VALUES also overwrite boundary conditions
7323 
7324   Fortran Notes:
7325   This routine is only available in Fortran 90, and you must include petsc.h90 in your code.
7326 
7327   Level: intermediate
7328 
7329 .seealso DMPlexVecGetClosure(), DMPlexVecSetClosure()
7330 @*/
7331 PetscErrorCode DMPlexMatSetClosure(DM dm, PetscSection section, PetscSection globalSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode)
7332 {
7333   DM_Plex       *mesh   = (DM_Plex*) dm->data;
7334   PetscInt      *points = NULL;
7335   PetscInt      *indices;
7336   PetscInt       offsets[32];
7337   PetscInt       numFields, numPoints, numIndices, dof, off, globalOff, pStart, pEnd, p, q, f;
7338   PetscErrorCode ierr;
7339 
7340   PetscFunctionBegin;
7341   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7342   PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2);
7343   PetscValidHeaderSpecific(globalSection, PETSC_SECTION_CLASSID, 3);
7344   PetscValidHeaderSpecific(A, MAT_CLASSID, 4);
7345   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
7346   if (numFields > 31) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
7347   ierr = PetscMemzero(offsets, 32 * sizeof(PetscInt));CHKERRQ(ierr);
7348   ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
7349   /* Compress out points not in the section */
7350   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
7351   for (p = 0, q = 0; p < numPoints*2; p += 2) {
7352     if ((points[p] >= pStart) && (points[p] < pEnd)) {
7353       points[q*2]   = points[p];
7354       points[q*2+1] = points[p+1];
7355       ++q;
7356     }
7357   }
7358   numPoints = q;
7359   for (p = 0, numIndices = 0; p < numPoints*2; p += 2) {
7360     PetscInt fdof;
7361 
7362     ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
7363     for (f = 0; f < numFields; ++f) {
7364       ierr          = PetscSectionGetFieldDof(section, points[p], f, &fdof);CHKERRQ(ierr);
7365       offsets[f+1] += fdof;
7366     }
7367     numIndices += dof;
7368   }
7369   for (f = 1; f < numFields; ++f) offsets[f+1] += offsets[f];
7370 
7371   if (numFields && offsets[numFields] != numIndices) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid size for closure %d should be %d", offsets[numFields], numIndices);
7372   ierr = DMGetWorkArray(dm, numIndices, PETSC_INT, &indices);CHKERRQ(ierr);
7373   if (numFields) {
7374     for (p = 0; p < numPoints*2; p += 2) {
7375       PetscInt o = points[p+1];
7376       ierr = PetscSectionGetOffset(globalSection, points[p], &globalOff);CHKERRQ(ierr);
7377       indicesPointFields_private(section, points[p], globalOff < 0 ? -(globalOff+1) : globalOff, offsets, PETSC_FALSE, o, indices);
7378     }
7379   } else {
7380     for (p = 0, off = 0; p < numPoints*2; p += 2) {
7381       PetscInt o = points[p+1];
7382       ierr = PetscSectionGetOffset(globalSection, points[p], &globalOff);CHKERRQ(ierr);
7383       indicesPoint_private(section, points[p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, o, indices);
7384     }
7385   }
7386   if (mesh->printSetValues) {ierr = DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndices, indices, values);CHKERRQ(ierr);}
7387   ierr = MatSetValues(A, numIndices, indices, numIndices, indices, values, mode);
7388   if (ierr) {
7389     PetscMPIInt    rank;
7390     PetscErrorCode ierr2;
7391 
7392     ierr2 = MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank);CHKERRQ(ierr2);
7393     ierr2 = (*PetscErrorPrintf)("[%D]ERROR in DMPlexMatSetClosure\n", rank);CHKERRQ(ierr2);
7394     ierr2 = DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndices, indices, values);CHKERRQ(ierr2);
7395     ierr2 = DMRestoreWorkArray(dm, numIndices, PETSC_INT, &indices);CHKERRQ(ierr2);
7396     CHKERRQ(ierr);
7397   }
7398   ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
7399   ierr = DMRestoreWorkArray(dm, numIndices, PETSC_INT, &indices);CHKERRQ(ierr);
7400   PetscFunctionReturn(0);
7401 }
7402 
7403 #undef __FUNCT__
7404 #define __FUNCT__ "DMPlexGetHybridBounds"
7405 PetscErrorCode DMPlexGetHybridBounds(DM dm, PetscInt *cMax, PetscInt *fMax, PetscInt *eMax, PetscInt *vMax)
7406 {
7407   DM_Plex       *mesh = (DM_Plex*) dm->data;
7408   PetscInt       dim;
7409   PetscErrorCode ierr;
7410 
7411   PetscFunctionBegin;
7412   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7413   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
7414   if (cMax) *cMax = mesh->hybridPointMax[dim];
7415   if (fMax) *fMax = mesh->hybridPointMax[dim-1];
7416   if (eMax) *eMax = mesh->hybridPointMax[1];
7417   if (vMax) *vMax = mesh->hybridPointMax[0];
7418   PetscFunctionReturn(0);
7419 }
7420 
7421 #undef __FUNCT__
7422 #define __FUNCT__ "DMPlexSetHybridBounds"
7423 PetscErrorCode DMPlexSetHybridBounds(DM dm, PetscInt cMax, PetscInt fMax, PetscInt eMax, PetscInt vMax)
7424 {
7425   DM_Plex       *mesh = (DM_Plex*) dm->data;
7426   PetscInt       dim;
7427   PetscErrorCode ierr;
7428 
7429   PetscFunctionBegin;
7430   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7431   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
7432   if (cMax >= 0) mesh->hybridPointMax[dim]   = cMax;
7433   if (fMax >= 0) mesh->hybridPointMax[dim-1] = fMax;
7434   if (eMax >= 0) mesh->hybridPointMax[1]     = eMax;
7435   if (vMax >= 0) mesh->hybridPointMax[0]     = vMax;
7436   PetscFunctionReturn(0);
7437 }
7438 
7439 #undef __FUNCT__
7440 #define __FUNCT__ "DMPlexGetVTKCellHeight"
7441 PetscErrorCode DMPlexGetVTKCellHeight(DM dm, PetscInt *cellHeight)
7442 {
7443   DM_Plex *mesh = (DM_Plex*) dm->data;
7444 
7445   PetscFunctionBegin;
7446   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7447   PetscValidPointer(cellHeight, 2);
7448   *cellHeight = mesh->vtkCellHeight;
7449   PetscFunctionReturn(0);
7450 }
7451 
7452 #undef __FUNCT__
7453 #define __FUNCT__ "DMPlexSetVTKCellHeight"
7454 PetscErrorCode DMPlexSetVTKCellHeight(DM dm, PetscInt cellHeight)
7455 {
7456   DM_Plex *mesh = (DM_Plex*) dm->data;
7457 
7458   PetscFunctionBegin;
7459   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7460   mesh->vtkCellHeight = cellHeight;
7461   PetscFunctionReturn(0);
7462 }
7463 
7464 #undef __FUNCT__
7465 #define __FUNCT__ "DMPlexCreateNumbering_Private"
7466 /* We can easily have a form that takes an IS instead */
7467 PetscErrorCode DMPlexCreateNumbering_Private(DM dm, PetscInt pStart, PetscInt pEnd, PetscSF sf, IS *numbering)
7468 {
7469   PetscSection   section, globalSection;
7470   PetscInt      *numbers, p;
7471   PetscErrorCode ierr;
7472 
7473   PetscFunctionBegin;
7474   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)dm), &section);CHKERRQ(ierr);
7475   ierr = PetscSectionSetChart(section, pStart, pEnd);CHKERRQ(ierr);
7476   for (p = pStart; p < pEnd; ++p) {
7477     ierr = PetscSectionSetDof(section, p, 1);CHKERRQ(ierr);
7478   }
7479   ierr = PetscSectionSetUp(section);CHKERRQ(ierr);
7480   ierr = PetscSectionCreateGlobalSection(section, sf, PETSC_FALSE, &globalSection);CHKERRQ(ierr);
7481   ierr = PetscMalloc((pEnd - pStart) * sizeof(PetscInt), &numbers);CHKERRQ(ierr);
7482   for (p = pStart; p < pEnd; ++p) {
7483     ierr = PetscSectionGetOffset(globalSection, p, &numbers[p-pStart]);CHKERRQ(ierr);
7484   }
7485   ierr = ISCreateGeneral(PetscObjectComm((PetscObject)dm), pEnd - pStart, numbers, PETSC_OWN_POINTER, numbering);CHKERRQ(ierr);
7486   ierr = PetscSectionDestroy(&section);CHKERRQ(ierr);
7487   ierr = PetscSectionDestroy(&globalSection);CHKERRQ(ierr);
7488   PetscFunctionReturn(0);
7489 }
7490 
7491 #undef __FUNCT__
7492 #define __FUNCT__ "DMPlexGetCellNumbering"
7493 PetscErrorCode DMPlexGetCellNumbering(DM dm, IS *globalCellNumbers)
7494 {
7495   DM_Plex       *mesh = (DM_Plex*) dm->data;
7496   PetscInt       cellHeight, cStart, cEnd, cMax;
7497   PetscErrorCode ierr;
7498 
7499   PetscFunctionBegin;
7500   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7501   if (!mesh->globalCellNumbers) {
7502     ierr = DMPlexGetVTKCellHeight(dm, &cellHeight);CHKERRQ(ierr);
7503     ierr = DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd);CHKERRQ(ierr);
7504     ierr = DMPlexGetHybridBounds(dm, &cMax, NULL, NULL, NULL);CHKERRQ(ierr);
7505     if (cMax >= 0) cEnd = PetscMin(cEnd, cMax);
7506     ierr = DMPlexCreateNumbering_Private(dm, cStart, cEnd, dm->sf, &mesh->globalCellNumbers);CHKERRQ(ierr);
7507   }
7508   *globalCellNumbers = mesh->globalCellNumbers;
7509   PetscFunctionReturn(0);
7510 }
7511 
7512 #undef __FUNCT__
7513 #define __FUNCT__ "DMPlexGetVertexNumbering"
7514 PetscErrorCode DMPlexGetVertexNumbering(DM dm, IS *globalVertexNumbers)
7515 {
7516   DM_Plex       *mesh = (DM_Plex*) dm->data;
7517   PetscInt       vStart, vEnd, vMax;
7518   PetscErrorCode ierr;
7519 
7520   PetscFunctionBegin;
7521   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7522   if (!mesh->globalVertexNumbers) {
7523     ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
7524     ierr = DMPlexGetHybridBounds(dm, NULL, NULL, NULL, &vMax);CHKERRQ(ierr);
7525     if (vMax >= 0) vEnd = PetscMin(vEnd, vMax);
7526     ierr = DMPlexCreateNumbering_Private(dm, vStart, vEnd, dm->sf, &mesh->globalVertexNumbers);CHKERRQ(ierr);
7527   }
7528   *globalVertexNumbers = mesh->globalVertexNumbers;
7529   PetscFunctionReturn(0);
7530 }
7531 
7532 
7533 #undef __FUNCT__
7534 #define __FUNCT__ "PetscSectionCreateGlobalSectionLabel"
7535 /*@C
7536   PetscSectionCreateGlobalSectionLabel - Create a section describing the global field layout using
7537   the local section and an SF describing the section point overlap.
7538 
7539   Input Parameters:
7540   + s - The PetscSection for the local field layout
7541   . sf - The SF describing parallel layout of the section points
7542   . includeConstraints - By default this is PETSC_FALSE, meaning that the global field vector will not possess constrained dofs
7543   . label - The label specifying the points
7544   - labelValue - The label stratum specifying the points
7545 
7546   Output Parameter:
7547   . gsection - The PetscSection for the global field layout
7548 
7549   Note: This gives negative sizes and offsets to points not owned by this process
7550 
7551   Level: developer
7552 
7553 .seealso: PetscSectionCreate()
7554 @*/
7555 PetscErrorCode PetscSectionCreateGlobalSectionLabel(PetscSection s, PetscSF sf, PetscBool includeConstraints, DMLabel label, PetscInt labelValue, PetscSection *gsection)
7556 {
7557   PetscInt      *neg = NULL, *tmpOff = NULL;
7558   PetscInt       pStart, pEnd, p, dof, cdof, off, globalOff = 0, nroots;
7559   PetscErrorCode ierr;
7560 
7561   PetscFunctionBegin;
7562   ierr = PetscSectionCreate(s->atlasLayout.comm, gsection);CHKERRQ(ierr);
7563   ierr = PetscSectionGetChart(s, &pStart, &pEnd);CHKERRQ(ierr);
7564   ierr = PetscSectionSetChart(*gsection, pStart, pEnd);CHKERRQ(ierr);
7565   ierr = PetscSFGetGraph(sf, &nroots, NULL, NULL, NULL);CHKERRQ(ierr);
7566   if (nroots >= 0) {
7567     if (nroots < pEnd-pStart) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "PetscSF nroots %d < %d section size", nroots, pEnd-pStart);
7568     ierr = PetscMalloc(nroots * sizeof(PetscInt), &neg);CHKERRQ(ierr);
7569     ierr = PetscMemzero(neg, nroots * sizeof(PetscInt));CHKERRQ(ierr);
7570     if (nroots > pEnd-pStart) {
7571       ierr = PetscMalloc(nroots * sizeof(PetscInt), &tmpOff);CHKERRQ(ierr);
7572       ierr = PetscMemzero(tmpOff, nroots * sizeof(PetscInt));CHKERRQ(ierr);
7573     } else {
7574       tmpOff = &(*gsection)->atlasDof[-pStart];
7575     }
7576   }
7577   /* Mark ghost points with negative dof */
7578   for (p = pStart; p < pEnd; ++p) {
7579     PetscInt value;
7580 
7581     ierr = DMLabelGetValue(label, p, &value);CHKERRQ(ierr);
7582     if (value != labelValue) continue;
7583     ierr = PetscSectionGetDof(s, p, &dof);CHKERRQ(ierr);
7584     ierr = PetscSectionSetDof(*gsection, p, dof);CHKERRQ(ierr);
7585     ierr = PetscSectionGetConstraintDof(s, p, &cdof);CHKERRQ(ierr);
7586     if (!includeConstraints && cdof > 0) {ierr = PetscSectionSetConstraintDof(*gsection, p, cdof);CHKERRQ(ierr);}
7587     if (neg) neg[p] = -(dof+1);
7588   }
7589   ierr = PetscSectionSetUpBC(*gsection);CHKERRQ(ierr);
7590   if (nroots >= 0) {
7591     ierr = PetscSFBcastBegin(sf, MPIU_INT, neg, tmpOff);CHKERRQ(ierr);
7592     ierr = PetscSFBcastEnd(sf, MPIU_INT, neg, tmpOff);CHKERRQ(ierr);
7593     if (nroots > pEnd-pStart) {
7594       for (p = pStart; p < pEnd; ++p) {if (tmpOff[p] < 0) (*gsection)->atlasDof[p-pStart] = tmpOff[p];}
7595     }
7596   }
7597   /* Calculate new sizes, get proccess offset, and calculate point offsets */
7598   for (p = 0, off = 0; p < pEnd-pStart; ++p) {
7599     cdof = (!includeConstraints && s->bc) ? s->bc->atlasDof[p] : 0;
7600     (*gsection)->atlasOff[p] = off;
7601     off += (*gsection)->atlasDof[p] > 0 ? (*gsection)->atlasDof[p]-cdof : 0;
7602   }
7603   ierr       = MPI_Scan(&off, &globalOff, 1, MPIU_INT, MPI_SUM, s->atlasLayout.comm);CHKERRQ(ierr);
7604   globalOff -= off;
7605   for (p = 0, off = 0; p < pEnd-pStart; ++p) {
7606     (*gsection)->atlasOff[p] += globalOff;
7607     if (neg) neg[p] = -((*gsection)->atlasOff[p]+1);
7608   }
7609   /* Put in negative offsets for ghost points */
7610   if (nroots >= 0) {
7611     ierr = PetscSFBcastBegin(sf, MPIU_INT, neg, tmpOff);CHKERRQ(ierr);
7612     ierr = PetscSFBcastEnd(sf, MPIU_INT, neg, tmpOff);CHKERRQ(ierr);
7613     if (nroots > pEnd-pStart) {
7614       for (p = pStart; p < pEnd; ++p) {if (tmpOff[p] < 0) (*gsection)->atlasOff[p-pStart] = tmpOff[p];}
7615     }
7616   }
7617   if (nroots >= 0 && nroots > pEnd-pStart) {ierr = PetscFree(tmpOff);CHKERRQ(ierr);}
7618   ierr = PetscFree(neg);CHKERRQ(ierr);
7619   PetscFunctionReturn(0);
7620 }
7621