xref: /petsc/src/dm/impls/plex/plex.c (revision ca8062c8847dc425765867e20e145c0bf8cf06c7)
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, *hybsizes;
279     PetscInt    locDepth, depth, dim, d, pMax[4];
280     PetscInt    pStart, pEnd, p;
281     PetscInt    numLabels, l;
282     const char *name;
283     PetscMPIInt size;
284 
285     ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr);
286     ierr = MPI_Comm_size(comm, &size);CHKERRQ(ierr);
287     ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
288     ierr = PetscObjectGetName((PetscObject) dm, &name);CHKERRQ(ierr);
289     if (name) {ierr = PetscViewerASCIIPrintf(viewer, "%s in %D dimensions:\n", name, dim);CHKERRQ(ierr);}
290     else      {ierr = PetscViewerASCIIPrintf(viewer, "Mesh in %D dimensions:\n", dim);CHKERRQ(ierr);}
291     ierr = DMPlexGetDepth(dm, &locDepth);CHKERRQ(ierr);
292     ierr = MPI_Allreduce(&locDepth, &depth, 1, MPIU_INT, MPI_MAX, comm);CHKERRQ(ierr);
293     ierr = DMPlexGetHybridBounds(dm, &pMax[depth], &pMax[depth-1], &pMax[1], &pMax[0]);CHKERRQ(ierr);
294     ierr = PetscMalloc2(size,PetscInt,&sizes,size,PetscInt,&hybsizes);CHKERRQ(ierr);
295     if (depth == 1) {
296       ierr = DMPlexGetDepthStratum(dm, 0, &pStart, &pEnd);CHKERRQ(ierr);
297       pEnd = pEnd - pStart;
298       ierr = MPI_Gather(&pEnd, 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm);CHKERRQ(ierr);
299       ierr = PetscViewerASCIIPrintf(viewer, "  %D-cells:", 0);CHKERRQ(ierr);
300       for (p = 0; p < size; ++p) {ierr = PetscViewerASCIIPrintf(viewer, " %D", sizes[p]);CHKERRQ(ierr);}
301       ierr = PetscViewerASCIIPrintf(viewer, "\n");CHKERRQ(ierr);
302       ierr = DMPlexGetHeightStratum(dm, 0, &pStart, &pEnd);CHKERRQ(ierr);
303       pEnd = pEnd - pStart;
304       ierr = MPI_Gather(&pEnd, 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm);CHKERRQ(ierr);
305       ierr = PetscViewerASCIIPrintf(viewer, "  %D-cells:", dim);CHKERRQ(ierr);
306       for (p = 0; p < size; ++p) {ierr = PetscViewerASCIIPrintf(viewer, " %D", sizes[p]);CHKERRQ(ierr);}
307       ierr = PetscViewerASCIIPrintf(viewer, "\n");CHKERRQ(ierr);
308     } else {
309       for (d = 0; d <= dim; d++) {
310         ierr = DMPlexGetDepthStratum(dm, d, &pStart, &pEnd);CHKERRQ(ierr);
311         pEnd    -= pStart;
312         pMax[d] -= pStart;
313         ierr = MPI_Gather(&pEnd, 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm);CHKERRQ(ierr);
314         ierr = MPI_Gather(&pMax[d], 1, MPIU_INT, hybsizes, 1, MPIU_INT, 0, comm);CHKERRQ(ierr);
315         ierr = PetscViewerASCIIPrintf(viewer, "  %D-cells:", d);CHKERRQ(ierr);
316         for (p = 0; p < size; ++p) {
317           if (hybsizes[p] >= 0) {ierr = PetscViewerASCIIPrintf(viewer, " %D (%D)", sizes[p], sizes[p] - hybsizes[p]);CHKERRQ(ierr);}
318           else                  {ierr = PetscViewerASCIIPrintf(viewer, " %D", sizes[p]);CHKERRQ(ierr);}
319         }
320         ierr = PetscViewerASCIIPrintf(viewer, "\n");CHKERRQ(ierr);
321       }
322     }
323     ierr = PetscFree2(sizes,hybsizes);CHKERRQ(ierr);
324     ierr = DMPlexGetNumLabels(dm, &numLabels);CHKERRQ(ierr);
325     if (numLabels) {ierr = PetscViewerASCIIPrintf(viewer, "Labels:\n");CHKERRQ(ierr);}
326     for (l = 0; l < numLabels; ++l) {
327       DMLabel         label;
328       const char     *name;
329       IS              valueIS;
330       const PetscInt *values;
331       PetscInt        numValues, v;
332 
333       ierr = DMPlexGetLabelName(dm, l, &name);CHKERRQ(ierr);
334       ierr = DMPlexGetLabel(dm, name, &label);CHKERRQ(ierr);
335       ierr = DMLabelGetNumValues(label, &numValues);CHKERRQ(ierr);
336       ierr = PetscViewerASCIIPrintf(viewer, "  %s: %d strata of sizes (", name, numValues);CHKERRQ(ierr);
337       ierr = DMLabelGetValueIS(label, &valueIS);CHKERRQ(ierr);
338       ierr = ISGetIndices(valueIS, &values);CHKERRQ(ierr);
339       for (v = 0; v < numValues; ++v) {
340         PetscInt size;
341 
342         ierr = DMLabelGetStratumSize(label, values[v], &size);CHKERRQ(ierr);
343         if (v > 0) {ierr = PetscViewerASCIIPrintf(viewer, ", ");CHKERRQ(ierr);}
344         ierr = PetscViewerASCIIPrintf(viewer, "%d", size);CHKERRQ(ierr);
345       }
346       ierr = PetscViewerASCIIPrintf(viewer, ")\n");CHKERRQ(ierr);
347       ierr = ISRestoreIndices(valueIS, &values);CHKERRQ(ierr);
348       ierr = ISDestroy(&valueIS);CHKERRQ(ierr);
349     }
350   }
351   PetscFunctionReturn(0);
352 }
353 
354 #undef __FUNCT__
355 #define __FUNCT__ "DMView_Plex"
356 PetscErrorCode DMView_Plex(DM dm, PetscViewer viewer)
357 {
358   PetscBool      iascii, isbinary;
359   PetscErrorCode ierr;
360 
361   PetscFunctionBegin;
362   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
363   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
364   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERASCII, &iascii);CHKERRQ(ierr);
365   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERBINARY, &isbinary);CHKERRQ(ierr);
366   if (iascii) {
367     ierr = DMPlexView_Ascii(dm, viewer);CHKERRQ(ierr);
368 #if 0
369   } else if (isbinary) {
370     ierr = DMPlexView_Binary(dm, viewer);CHKERRQ(ierr);
371 #endif
372   }
373   PetscFunctionReturn(0);
374 }
375 
376 #undef __FUNCT__
377 #define __FUNCT__ "DMDestroy_Plex"
378 PetscErrorCode DMDestroy_Plex(DM dm)
379 {
380   DM_Plex       *mesh = (DM_Plex*) dm->data;
381   DMLabel        next  = mesh->labels;
382   PetscErrorCode ierr;
383 
384   PetscFunctionBegin;
385   if (--mesh->refct > 0) PetscFunctionReturn(0);
386   ierr = PetscSectionDestroy(&mesh->coneSection);CHKERRQ(ierr);
387   ierr = PetscFree(mesh->cones);CHKERRQ(ierr);
388   ierr = PetscFree(mesh->coneOrientations);CHKERRQ(ierr);
389   ierr = PetscSectionDestroy(&mesh->supportSection);CHKERRQ(ierr);
390   ierr = PetscFree(mesh->supports);CHKERRQ(ierr);
391   ierr = PetscFree(mesh->facesTmp);CHKERRQ(ierr);
392   while (next) {
393     DMLabel tmp = next->next;
394 
395     ierr = DMLabelDestroy(&next);CHKERRQ(ierr);
396     next = tmp;
397   }
398   ierr = DMLabelDestroy(&mesh->subpointMap);CHKERRQ(ierr);
399   ierr = ISDestroy(&mesh->globalVertexNumbers);CHKERRQ(ierr);
400   ierr = ISDestroy(&mesh->globalCellNumbers);CHKERRQ(ierr);
401   /* This was originally freed in DMDestroy(), but that prevents reference counting of backend objects */
402   ierr = PetscFree(mesh);CHKERRQ(ierr);
403   PetscFunctionReturn(0);
404 }
405 
406 #undef __FUNCT__
407 #define __FUNCT__ "DMCreateMatrix_Plex"
408 PetscErrorCode DMCreateMatrix_Plex(DM dm, MatType mtype, Mat *J)
409 {
410   PetscSection   section, sectionGlobal;
411   PetscInt       bs = -1;
412   PetscInt       localSize;
413   PetscBool      isShell, isBlock, isSeqBlock, isMPIBlock, isSymBlock, isSymSeqBlock, isSymMPIBlock;
414   PetscErrorCode ierr;
415 
416   PetscFunctionBegin;
417 #if !defined(PETSC_USE_DYNAMIC_LIBRARIES)
418   ierr = MatInitializePackage();CHKERRQ(ierr);
419 #endif
420   if (!mtype) mtype = MATAIJ;
421   ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
422   ierr = DMGetDefaultGlobalSection(dm, &sectionGlobal);CHKERRQ(ierr);
423   /* ierr = PetscSectionGetStorageSize(sectionGlobal, &localSize);CHKERRQ(ierr); */
424   ierr = PetscSectionGetConstrainedStorageSize(sectionGlobal, &localSize);CHKERRQ(ierr);
425   ierr = MatCreate(PetscObjectComm((PetscObject)dm), J);CHKERRQ(ierr);
426   ierr = MatSetSizes(*J, localSize, localSize, PETSC_DETERMINE, PETSC_DETERMINE);CHKERRQ(ierr);
427   ierr = MatSetType(*J, mtype);CHKERRQ(ierr);
428   ierr = MatSetFromOptions(*J);CHKERRQ(ierr);
429   ierr = PetscStrcmp(mtype, MATSHELL, &isShell);CHKERRQ(ierr);
430   ierr = PetscStrcmp(mtype, MATBAIJ, &isBlock);CHKERRQ(ierr);
431   ierr = PetscStrcmp(mtype, MATSEQBAIJ, &isSeqBlock);CHKERRQ(ierr);
432   ierr = PetscStrcmp(mtype, MATMPIBAIJ, &isMPIBlock);CHKERRQ(ierr);
433   ierr = PetscStrcmp(mtype, MATSBAIJ, &isSymBlock);CHKERRQ(ierr);
434   ierr = PetscStrcmp(mtype, MATSEQSBAIJ, &isSymSeqBlock);CHKERRQ(ierr);
435   ierr = PetscStrcmp(mtype, MATMPISBAIJ, &isSymMPIBlock);CHKERRQ(ierr);
436   if (!isShell) {
437     PetscBool fillMatrix = (PetscBool) !dm->prealloc_only;
438     PetscInt *dnz, *onz, *dnzu, *onzu, bsLocal, bsMax, bsMin;
439 
440     if (bs < 0) {
441       if (isBlock || isSeqBlock || isMPIBlock || isSymBlock || isSymSeqBlock || isSymMPIBlock) {
442         PetscInt pStart, pEnd, p, dof, cdof;
443 
444         ierr = PetscSectionGetChart(sectionGlobal, &pStart, &pEnd);CHKERRQ(ierr);
445         for (p = pStart; p < pEnd; ++p) {
446           ierr = PetscSectionGetDof(sectionGlobal, p, &dof);CHKERRQ(ierr);
447           ierr = PetscSectionGetConstraintDof(sectionGlobal, p, &cdof);CHKERRQ(ierr);
448           if (dof-cdof) {
449             if (bs < 0) {
450               bs = dof-cdof;
451             } else if (bs != dof-cdof) {
452               /* Layout does not admit a pointwise block size */
453               bs = 1;
454               break;
455             }
456           }
457         }
458         /* Must have same blocksize on all procs (some might have no points) */
459         bsLocal = bs;
460         ierr = MPI_Allreduce(&bsLocal, &bsMax, 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm));CHKERRQ(ierr);
461         bsLocal = bs < 0 ? bsMax : bs;
462         ierr = MPI_Allreduce(&bsLocal, &bsMin, 1, MPIU_INT, MPI_MIN, PetscObjectComm((PetscObject)dm));CHKERRQ(ierr);
463         if (bsMin != bsMax) {
464           bs = 1;
465         } else {
466           bs = bsMax;
467         }
468       } else {
469         bs = 1;
470       }
471     }
472     ierr = PetscMalloc4(localSize/bs, PetscInt, &dnz, localSize/bs, PetscInt, &onz, localSize/bs, PetscInt, &dnzu, localSize/bs, PetscInt, &onzu);CHKERRQ(ierr);
473     ierr = PetscMemzero(dnz,  localSize/bs * sizeof(PetscInt));CHKERRQ(ierr);
474     ierr = PetscMemzero(onz,  localSize/bs * sizeof(PetscInt));CHKERRQ(ierr);
475     ierr = PetscMemzero(dnzu, localSize/bs * sizeof(PetscInt));CHKERRQ(ierr);
476     ierr = PetscMemzero(onzu, localSize/bs * sizeof(PetscInt));CHKERRQ(ierr);
477     ierr = DMPlexPreallocateOperator(dm, bs, section, sectionGlobal, dnz, onz, dnzu, onzu, *J, fillMatrix);CHKERRQ(ierr);
478     ierr = PetscFree4(dnz, onz, dnzu, onzu);CHKERRQ(ierr);
479   }
480   PetscFunctionReturn(0);
481 }
482 
483 #undef __FUNCT__
484 #define __FUNCT__ "DMPlexGetDimension"
485 /*@
486   DMPlexGetDimension - Return the topological mesh dimension
487 
488   Not collective
489 
490   Input Parameter:
491 . mesh - The DMPlex
492 
493   Output Parameter:
494 . dim - The topological mesh dimension
495 
496   Level: beginner
497 
498 .seealso: DMPlexCreate()
499 @*/
500 PetscErrorCode DMPlexGetDimension(DM dm, PetscInt *dim)
501 {
502   DM_Plex *mesh = (DM_Plex*) dm->data;
503 
504   PetscFunctionBegin;
505   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
506   PetscValidPointer(dim, 2);
507   *dim = mesh->dim;
508   PetscFunctionReturn(0);
509 }
510 
511 #undef __FUNCT__
512 #define __FUNCT__ "DMPlexSetDimension"
513 /*@
514   DMPlexSetDimension - Set the topological mesh dimension
515 
516   Collective on mesh
517 
518   Input Parameters:
519 + mesh - The DMPlex
520 - dim - The topological mesh dimension
521 
522   Level: beginner
523 
524 .seealso: DMPlexCreate()
525 @*/
526 PetscErrorCode DMPlexSetDimension(DM dm, PetscInt dim)
527 {
528   DM_Plex *mesh = (DM_Plex*) dm->data;
529 
530   PetscFunctionBegin;
531   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
532   PetscValidLogicalCollectiveInt(dm, dim, 2);
533   mesh->dim               = dim;
534   mesh->preallocCenterDim = dim;
535   PetscFunctionReturn(0);
536 }
537 
538 #undef __FUNCT__
539 #define __FUNCT__ "DMPlexGetChart"
540 /*@
541   DMPlexGetChart - Return the interval for all mesh points [pStart, pEnd)
542 
543   Not collective
544 
545   Input Parameter:
546 . mesh - The DMPlex
547 
548   Output Parameters:
549 + pStart - The first mesh point
550 - pEnd   - The upper bound for mesh points
551 
552   Level: beginner
553 
554 .seealso: DMPlexCreate(), DMPlexSetChart()
555 @*/
556 PetscErrorCode DMPlexGetChart(DM dm, PetscInt *pStart, PetscInt *pEnd)
557 {
558   DM_Plex       *mesh = (DM_Plex*) dm->data;
559   PetscErrorCode ierr;
560 
561   PetscFunctionBegin;
562   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
563   ierr = PetscSectionGetChart(mesh->coneSection, pStart, pEnd);CHKERRQ(ierr);
564   PetscFunctionReturn(0);
565 }
566 
567 #undef __FUNCT__
568 #define __FUNCT__ "DMPlexSetChart"
569 /*@
570   DMPlexSetChart - Set the interval for all mesh points [pStart, pEnd)
571 
572   Not collective
573 
574   Input Parameters:
575 + mesh - The DMPlex
576 . pStart - The first mesh point
577 - pEnd   - The upper bound for mesh points
578 
579   Output Parameters:
580 
581   Level: beginner
582 
583 .seealso: DMPlexCreate(), DMPlexGetChart()
584 @*/
585 PetscErrorCode DMPlexSetChart(DM dm, PetscInt pStart, PetscInt pEnd)
586 {
587   DM_Plex       *mesh = (DM_Plex*) dm->data;
588   PetscErrorCode ierr;
589 
590   PetscFunctionBegin;
591   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
592   ierr = PetscSectionSetChart(mesh->coneSection, pStart, pEnd);CHKERRQ(ierr);
593   ierr = PetscSectionSetChart(mesh->supportSection, pStart, pEnd);CHKERRQ(ierr);
594   PetscFunctionReturn(0);
595 }
596 
597 #undef __FUNCT__
598 #define __FUNCT__ "DMPlexGetConeSize"
599 /*@
600   DMPlexGetConeSize - Return the number of in-edges for this point in the Sieve DAG
601 
602   Not collective
603 
604   Input Parameters:
605 + mesh - The DMPlex
606 - p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
607 
608   Output Parameter:
609 . size - The cone size for point p
610 
611   Level: beginner
612 
613 .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexSetChart()
614 @*/
615 PetscErrorCode DMPlexGetConeSize(DM dm, PetscInt p, PetscInt *size)
616 {
617   DM_Plex       *mesh = (DM_Plex*) dm->data;
618   PetscErrorCode ierr;
619 
620   PetscFunctionBegin;
621   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
622   PetscValidPointer(size, 3);
623   ierr = PetscSectionGetDof(mesh->coneSection, p, size);CHKERRQ(ierr);
624   PetscFunctionReturn(0);
625 }
626 
627 #undef __FUNCT__
628 #define __FUNCT__ "DMPlexSetConeSize"
629 /*@
630   DMPlexSetConeSize - Set the number of in-edges for this point in the Sieve DAG
631 
632   Not collective
633 
634   Input Parameters:
635 + mesh - The DMPlex
636 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
637 - size - The cone size for point p
638 
639   Output Parameter:
640 
641   Note:
642   This should be called after DMPlexSetChart().
643 
644   Level: beginner
645 
646 .seealso: DMPlexCreate(), DMPlexGetConeSize(), DMPlexSetChart()
647 @*/
648 PetscErrorCode DMPlexSetConeSize(DM dm, PetscInt p, PetscInt size)
649 {
650   DM_Plex       *mesh = (DM_Plex*) dm->data;
651   PetscErrorCode ierr;
652 
653   PetscFunctionBegin;
654   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
655   ierr = PetscSectionSetDof(mesh->coneSection, p, size);CHKERRQ(ierr);
656 
657   mesh->maxConeSize = PetscMax(mesh->maxConeSize, size);
658   PetscFunctionReturn(0);
659 }
660 
661 #undef __FUNCT__
662 #define __FUNCT__ "DMPlexGetCone"
663 /*@C
664   DMPlexGetCone - Return the points on the in-edges for this point in the Sieve DAG
665 
666   Not collective
667 
668   Input Parameters:
669 + mesh - The DMPlex
670 - p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
671 
672   Output Parameter:
673 . cone - An array of points which are on the in-edges for point p
674 
675   Level: beginner
676 
677   Fortran Notes:
678   Since it returns an array, this routine is only available in Fortran 90, and you must
679   include petsc.h90 in your code.
680 
681   You must also call DMPlexRestoreCone() after you finish using the returned array.
682 
683 .seealso: DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart()
684 @*/
685 PetscErrorCode DMPlexGetCone(DM dm, PetscInt p, const PetscInt *cone[])
686 {
687   DM_Plex       *mesh = (DM_Plex*) dm->data;
688   PetscInt       off;
689   PetscErrorCode ierr;
690 
691   PetscFunctionBegin;
692   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
693   PetscValidPointer(cone, 3);
694   ierr  = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
695   *cone = &mesh->cones[off];
696   PetscFunctionReturn(0);
697 }
698 
699 #undef __FUNCT__
700 #define __FUNCT__ "DMPlexSetCone"
701 /*@
702   DMPlexSetCone - Set the points on the in-edges for this point in the Sieve DAG
703 
704   Not collective
705 
706   Input Parameters:
707 + mesh - The DMPlex
708 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
709 - cone - An array of points which are on the in-edges for point p
710 
711   Output Parameter:
712 
713   Note:
714   This should be called after all calls to DMPlexSetConeSize() and DMSetUp().
715 
716   Level: beginner
717 
718 .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexSetChart(), DMPlexSetConeSize(), DMSetUp()
719 @*/
720 PetscErrorCode DMPlexSetCone(DM dm, PetscInt p, const PetscInt cone[])
721 {
722   DM_Plex       *mesh = (DM_Plex*) dm->data;
723   PetscInt       pStart, pEnd;
724   PetscInt       dof, off, c;
725   PetscErrorCode ierr;
726 
727   PetscFunctionBegin;
728   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
729   ierr = PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);CHKERRQ(ierr);
730   ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
731   if (dof) PetscValidPointer(cone, 3);
732   ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
733   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);
734   for (c = 0; c < dof; ++c) {
735     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);
736     mesh->cones[off+c] = cone[c];
737   }
738   PetscFunctionReturn(0);
739 }
740 
741 #undef __FUNCT__
742 #define __FUNCT__ "DMPlexGetConeOrientation"
743 /*@C
744   DMPlexGetConeOrientation - Return the orientations on the in-edges for this point in the Sieve DAG
745 
746   Not collective
747 
748   Input Parameters:
749 + mesh - The DMPlex
750 - p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
751 
752   Output Parameter:
753 . coneOrientation - An array of orientations which are on the in-edges for point p. An orientation is an
754                     integer giving the prescription for cone traversal. If it is negative, the cone is
755                     traversed in the opposite direction. Its value 'o', or if negative '-(o+1)', gives
756                     the index of the cone point on which to start.
757 
758   Level: beginner
759 
760   Fortran Notes:
761   Since it returns an array, this routine is only available in Fortran 90, and you must
762   include petsc.h90 in your code.
763 
764   You must also call DMPlexRestoreConeOrientation() after you finish using the returned array.
765 
766 .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexSetCone(), DMPlexSetChart()
767 @*/
768 PetscErrorCode DMPlexGetConeOrientation(DM dm, PetscInt p, const PetscInt *coneOrientation[])
769 {
770   DM_Plex       *mesh = (DM_Plex*) dm->data;
771   PetscInt       off;
772   PetscErrorCode ierr;
773 
774   PetscFunctionBegin;
775   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
776 #if defined(PETSC_USE_DEBUG)
777   {
778     PetscInt dof;
779     ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
780     if (dof) PetscValidPointer(coneOrientation, 3);
781   }
782 #endif
783   ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
784 
785   *coneOrientation = &mesh->coneOrientations[off];
786   PetscFunctionReturn(0);
787 }
788 
789 #undef __FUNCT__
790 #define __FUNCT__ "DMPlexSetConeOrientation"
791 /*@
792   DMPlexSetConeOrientation - Set the orientations on the in-edges for this point in the Sieve DAG
793 
794   Not collective
795 
796   Input Parameters:
797 + mesh - The DMPlex
798 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
799 - coneOrientation - An array of orientations which are on the in-edges for point p. An orientation is an
800                     integer giving the prescription for cone traversal. If it is negative, the cone is
801                     traversed in the opposite direction. Its value 'o', or if negative '-(o+1)', gives
802                     the index of the cone point on which to start.
803 
804   Output Parameter:
805 
806   Note:
807   This should be called after all calls to DMPlexSetConeSize() and DMSetUp().
808 
809   Level: beginner
810 
811 .seealso: DMPlexCreate(), DMPlexGetConeOrientation(), DMPlexSetCone(), DMPlexSetChart(), DMPlexSetConeSize(), DMSetUp()
812 @*/
813 PetscErrorCode DMPlexSetConeOrientation(DM dm, PetscInt p, const PetscInt coneOrientation[])
814 {
815   DM_Plex       *mesh = (DM_Plex*) dm->data;
816   PetscInt       pStart, pEnd;
817   PetscInt       dof, off, c;
818   PetscErrorCode ierr;
819 
820   PetscFunctionBegin;
821   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
822   ierr = PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);CHKERRQ(ierr);
823   ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
824   if (dof) PetscValidPointer(coneOrientation, 3);
825   ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
826   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);
827   for (c = 0; c < dof; ++c) {
828     PetscInt cdof, o = coneOrientation[c];
829 
830     ierr = PetscSectionGetDof(mesh->coneSection, mesh->cones[off+c], &cdof);CHKERRQ(ierr);
831     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);
832     mesh->coneOrientations[off+c] = o;
833   }
834   PetscFunctionReturn(0);
835 }
836 
837 #undef __FUNCT__
838 #define __FUNCT__ "DMPlexInsertCone"
839 PetscErrorCode DMPlexInsertCone(DM dm, PetscInt p, PetscInt conePos, PetscInt conePoint)
840 {
841   DM_Plex       *mesh = (DM_Plex*) dm->data;
842   PetscInt       pStart, pEnd;
843   PetscInt       dof, off;
844   PetscErrorCode ierr;
845 
846   PetscFunctionBegin;
847   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
848   ierr = PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);CHKERRQ(ierr);
849   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);
850   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);
851   ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
852   ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
853   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);
854   mesh->cones[off+conePos] = conePoint;
855   PetscFunctionReturn(0);
856 }
857 
858 #undef __FUNCT__
859 #define __FUNCT__ "DMPlexInsertConeOrientation"
860 PetscErrorCode DMPlexInsertConeOrientation(DM dm, PetscInt p, PetscInt conePos, PetscInt coneOrientation)
861 {
862   DM_Plex       *mesh = (DM_Plex*) dm->data;
863   PetscInt       pStart, pEnd;
864   PetscInt       dof, off;
865   PetscErrorCode ierr;
866 
867   PetscFunctionBegin;
868   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
869   ierr = PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);CHKERRQ(ierr);
870   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);
871   ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
872   ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
873   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);
874   mesh->coneOrientations[off+conePos] = coneOrientation;
875   PetscFunctionReturn(0);
876 }
877 
878 #undef __FUNCT__
879 #define __FUNCT__ "DMPlexGetSupportSize"
880 /*@
881   DMPlexGetSupportSize - Return the number of out-edges for this point in the Sieve DAG
882 
883   Not collective
884 
885   Input Parameters:
886 + mesh - The DMPlex
887 - p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
888 
889   Output Parameter:
890 . size - The support size for point p
891 
892   Level: beginner
893 
894 .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexSetChart(), DMPlexGetConeSize()
895 @*/
896 PetscErrorCode DMPlexGetSupportSize(DM dm, PetscInt p, PetscInt *size)
897 {
898   DM_Plex       *mesh = (DM_Plex*) dm->data;
899   PetscErrorCode ierr;
900 
901   PetscFunctionBegin;
902   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
903   PetscValidPointer(size, 3);
904   ierr = PetscSectionGetDof(mesh->supportSection, p, size);CHKERRQ(ierr);
905   PetscFunctionReturn(0);
906 }
907 
908 #undef __FUNCT__
909 #define __FUNCT__ "DMPlexSetSupportSize"
910 /*@
911   DMPlexSetSupportSize - Set the number of out-edges for this point in the Sieve DAG
912 
913   Not collective
914 
915   Input Parameters:
916 + mesh - The DMPlex
917 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
918 - size - The support size for point p
919 
920   Output Parameter:
921 
922   Note:
923   This should be called after DMPlexSetChart().
924 
925   Level: beginner
926 
927 .seealso: DMPlexCreate(), DMPlexGetSupportSize(), DMPlexSetChart()
928 @*/
929 PetscErrorCode DMPlexSetSupportSize(DM dm, PetscInt p, PetscInt size)
930 {
931   DM_Plex       *mesh = (DM_Plex*) dm->data;
932   PetscErrorCode ierr;
933 
934   PetscFunctionBegin;
935   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
936   ierr = PetscSectionSetDof(mesh->supportSection, p, size);CHKERRQ(ierr);
937 
938   mesh->maxSupportSize = PetscMax(mesh->maxSupportSize, size);
939   PetscFunctionReturn(0);
940 }
941 
942 #undef __FUNCT__
943 #define __FUNCT__ "DMPlexGetSupport"
944 /*@C
945   DMPlexGetSupport - Return the points on the out-edges for this point in the Sieve DAG
946 
947   Not collective
948 
949   Input Parameters:
950 + mesh - The DMPlex
951 - p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
952 
953   Output Parameter:
954 . support - An array of points which are on the out-edges for point p
955 
956   Level: beginner
957 
958   Fortran Notes:
959   Since it returns an array, this routine is only available in Fortran 90, and you must
960   include petsc.h90 in your code.
961 
962   You must also call DMPlexRestoreSupport() after you finish using the returned array.
963 
964 .seealso: DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone()
965 @*/
966 PetscErrorCode DMPlexGetSupport(DM dm, PetscInt p, const PetscInt *support[])
967 {
968   DM_Plex       *mesh = (DM_Plex*) dm->data;
969   PetscInt       off;
970   PetscErrorCode ierr;
971 
972   PetscFunctionBegin;
973   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
974   PetscValidPointer(support, 3);
975   ierr     = PetscSectionGetOffset(mesh->supportSection, p, &off);CHKERRQ(ierr);
976   *support = &mesh->supports[off];
977   PetscFunctionReturn(0);
978 }
979 
980 #undef __FUNCT__
981 #define __FUNCT__ "DMPlexSetSupport"
982 /*@
983   DMPlexSetSupport - Set the points on the out-edges for this point in the Sieve DAG
984 
985   Not collective
986 
987   Input Parameters:
988 + mesh - The DMPlex
989 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
990 - support - An array of points which are on the in-edges for point p
991 
992   Output Parameter:
993 
994   Note:
995   This should be called after all calls to DMPlexSetSupportSize() and DMSetUp().
996 
997   Level: beginner
998 
999 .seealso: DMPlexCreate(), DMPlexGetSupport(), DMPlexSetChart(), DMPlexSetSupportSize(), DMSetUp()
1000 @*/
1001 PetscErrorCode DMPlexSetSupport(DM dm, PetscInt p, const PetscInt support[])
1002 {
1003   DM_Plex       *mesh = (DM_Plex*) dm->data;
1004   PetscInt       pStart, pEnd;
1005   PetscInt       dof, off, c;
1006   PetscErrorCode ierr;
1007 
1008   PetscFunctionBegin;
1009   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1010   ierr = PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd);CHKERRQ(ierr);
1011   ierr = PetscSectionGetDof(mesh->supportSection, p, &dof);CHKERRQ(ierr);
1012   if (dof) PetscValidPointer(support, 3);
1013   ierr = PetscSectionGetOffset(mesh->supportSection, p, &off);CHKERRQ(ierr);
1014   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);
1015   for (c = 0; c < dof; ++c) {
1016     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);
1017     mesh->supports[off+c] = support[c];
1018   }
1019   PetscFunctionReturn(0);
1020 }
1021 
1022 #undef __FUNCT__
1023 #define __FUNCT__ "DMPlexInsertSupport"
1024 PetscErrorCode DMPlexInsertSupport(DM dm, PetscInt p, PetscInt supportPos, PetscInt supportPoint)
1025 {
1026   DM_Plex       *mesh = (DM_Plex*) dm->data;
1027   PetscInt       pStart, pEnd;
1028   PetscInt       dof, off;
1029   PetscErrorCode ierr;
1030 
1031   PetscFunctionBegin;
1032   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1033   ierr = PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd);CHKERRQ(ierr);
1034   ierr = PetscSectionGetDof(mesh->supportSection, p, &dof);CHKERRQ(ierr);
1035   ierr = PetscSectionGetOffset(mesh->supportSection, p, &off);CHKERRQ(ierr);
1036   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);
1037   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);
1038   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);
1039   mesh->supports[off+supportPos] = supportPoint;
1040   PetscFunctionReturn(0);
1041 }
1042 
1043 #undef __FUNCT__
1044 #define __FUNCT__ "DMPlexGetTransitiveClosure"
1045 /*@C
1046   DMPlexGetTransitiveClosure - Return the points on the transitive closure of the in-edges or out-edges for this point in the Sieve DAG
1047 
1048   Not collective
1049 
1050   Input Parameters:
1051 + mesh - The DMPlex
1052 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1053 . useCone - PETSC_TRUE for in-edges,  otherwise use out-edges
1054 - points - If points is NULL on input, internal storage will be returned, otherwise the provided array is used
1055 
1056   Output Parameters:
1057 + numPoints - The number of points in the closure, so points[] is of size 2*numPoints
1058 - points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...]
1059 
1060   Note:
1061   If using internal storage (points is NULL on input), each call overwrites the last output.
1062 
1063   Fortran Notes:
1064   Since it returns an array, this routine is only available in Fortran 90, and you must
1065   include petsc.h90 in your code.
1066 
1067   The numPoints argument is not present in the Fortran 90 binding since it is internal to the array.
1068 
1069   Level: beginner
1070 
1071 .seealso: DMPlexRestoreTransitiveClosure(), DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone()
1072 @*/
1073 PetscErrorCode DMPlexGetTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[])
1074 {
1075   DM_Plex        *mesh = (DM_Plex*) dm->data;
1076   PetscInt       *closure, *fifo;
1077   const PetscInt *tmp = NULL, *tmpO = NULL;
1078   PetscInt        tmpSize, t;
1079   PetscInt        depth       = 0, maxSize;
1080   PetscInt        closureSize = 2, fifoSize = 0, fifoStart = 0;
1081   PetscErrorCode  ierr;
1082 
1083   PetscFunctionBegin;
1084   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1085   ierr    = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
1086   /* This is only 1-level */
1087   if (useCone) {
1088     ierr = DMPlexGetConeSize(dm, p, &tmpSize);CHKERRQ(ierr);
1089     ierr = DMPlexGetCone(dm, p, &tmp);CHKERRQ(ierr);
1090     ierr = DMPlexGetConeOrientation(dm, p, &tmpO);CHKERRQ(ierr);
1091   } else {
1092     ierr = DMPlexGetSupportSize(dm, p, &tmpSize);CHKERRQ(ierr);
1093     ierr = DMPlexGetSupport(dm, p, &tmp);CHKERRQ(ierr);
1094   }
1095   if (depth == 1) {
1096     if (*points) {
1097       closure = *points;
1098     } else {
1099       maxSize = 2*(PetscMax(mesh->maxConeSize, mesh->maxSupportSize)+1);
1100       ierr = DMGetWorkArray(dm, maxSize, PETSC_INT, &closure);CHKERRQ(ierr);
1101     }
1102     closure[0] = p; closure[1] = 0;
1103     for (t = 0; t < tmpSize; ++t, closureSize += 2) {
1104       closure[closureSize]   = tmp[t];
1105       closure[closureSize+1] = tmpO ? tmpO[t] : 0;
1106     }
1107     if (numPoints) *numPoints = closureSize/2;
1108     if (points)    *points    = closure;
1109     PetscFunctionReturn(0);
1110   }
1111   maxSize = 2*PetscMax(PetscMax(PetscPowInt(mesh->maxConeSize,depth+1),PetscPowInt(mesh->maxSupportSize,depth+1)),depth+1);
1112   ierr    = DMGetWorkArray(dm, maxSize, PETSC_INT, &fifo);CHKERRQ(ierr);
1113   if (*points) {
1114     closure = *points;
1115   } else {
1116     ierr = DMGetWorkArray(dm, maxSize, PETSC_INT, &closure);CHKERRQ(ierr);
1117   }
1118   closure[0] = p; closure[1] = 0;
1119   for (t = 0; t < tmpSize; ++t, closureSize += 2, fifoSize += 2) {
1120     const PetscInt cp = tmp[t];
1121     const PetscInt co = tmpO ? tmpO[t] : 0;
1122 
1123     closure[closureSize]   = cp;
1124     closure[closureSize+1] = co;
1125     fifo[fifoSize]         = cp;
1126     fifo[fifoSize+1]       = co;
1127   }
1128   /* Should kick out early when depth is reached, rather than checking all vertices for empty cones */
1129   while (fifoSize - fifoStart) {
1130     const PetscInt q   = fifo[fifoStart];
1131     const PetscInt o   = fifo[fifoStart+1];
1132     const PetscInt rev = o >= 0 ? 0 : 1;
1133     const PetscInt off = rev ? -(o+1) : o;
1134 
1135     if (useCone) {
1136       ierr = DMPlexGetConeSize(dm, q, &tmpSize);CHKERRQ(ierr);
1137       ierr = DMPlexGetCone(dm, q, &tmp);CHKERRQ(ierr);
1138       ierr = DMPlexGetConeOrientation(dm, q, &tmpO);CHKERRQ(ierr);
1139     } else {
1140       ierr = DMPlexGetSupportSize(dm, q, &tmpSize);CHKERRQ(ierr);
1141       ierr = DMPlexGetSupport(dm, q, &tmp);CHKERRQ(ierr);
1142       tmpO = NULL;
1143     }
1144     for (t = 0; t < tmpSize; ++t) {
1145       const PetscInt i  = ((rev ? tmpSize-t : t) + off)%tmpSize;
1146       const PetscInt cp = tmp[i];
1147       /* Must propogate orientation: When we reverse orientation, we both reverse the direction of iteration and start at the other end of the chain. */
1148       /* HACK: It is worse to get the size here, than to change the interpretation of -(*+1)
1149        const PetscInt co = tmpO ? (rev ? -(tmpO[i]+1) : tmpO[i]) : 0; */
1150       PetscInt       co = tmpO ? tmpO[i] : 0;
1151       PetscInt       c;
1152 
1153       if (rev) {
1154         PetscInt childSize, coff;
1155         ierr = DMPlexGetConeSize(dm, cp, &childSize);CHKERRQ(ierr);
1156         coff = tmpO[i] < 0 ? -(tmpO[i]+1) : tmpO[i];
1157         co   = childSize ? -(((coff+childSize-1)%childSize)+1) : 0;
1158       }
1159       /* Check for duplicate */
1160       for (c = 0; c < closureSize; c += 2) {
1161         if (closure[c] == cp) break;
1162       }
1163       if (c == closureSize) {
1164         closure[closureSize]   = cp;
1165         closure[closureSize+1] = co;
1166         fifo[fifoSize]         = cp;
1167         fifo[fifoSize+1]       = co;
1168         closureSize           += 2;
1169         fifoSize              += 2;
1170       }
1171     }
1172     fifoStart += 2;
1173   }
1174   if (numPoints) *numPoints = closureSize/2;
1175   if (points)    *points    = closure;
1176   ierr = DMRestoreWorkArray(dm, maxSize, PETSC_INT, &fifo);CHKERRQ(ierr);
1177   PetscFunctionReturn(0);
1178 }
1179 
1180 #undef __FUNCT__
1181 #define __FUNCT__ "DMPlexRestoreTransitiveClosure"
1182 /*@C
1183   DMPlexRestoreTransitiveClosure - Restore the array of points on the transitive closure of the in-edges or out-edges for this point in the Sieve DAG
1184 
1185   Not collective
1186 
1187   Input Parameters:
1188 + mesh - The DMPlex
1189 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1190 . useCone - PETSC_TRUE for in-edges,  otherwise use out-edges
1191 - points - If points is NULL on input, internal storage will be returned, otherwise the provided array is used
1192 
1193   Output Parameters:
1194 + numPoints - The number of points in the closure, so points[] is of size 2*numPoints
1195 - points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...]
1196 
1197   Note:
1198   If not using internal storage (points is not NULL on input), this call is unnecessary
1199 
1200   Fortran Notes:
1201   Since it returns an array, this routine is only available in Fortran 90, and you must
1202   include petsc.h90 in your code.
1203 
1204   The numPoints argument is not present in the Fortran 90 binding since it is internal to the array.
1205 
1206   Level: beginner
1207 
1208 .seealso: DMPlexGetTransitiveClosure(), DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone()
1209 @*/
1210 PetscErrorCode DMPlexRestoreTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[])
1211 {
1212   PetscErrorCode ierr;
1213 
1214   PetscFunctionBegin;
1215   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1216   ierr = DMRestoreWorkArray(dm, 0, PETSC_INT, points);CHKERRQ(ierr);
1217   PetscFunctionReturn(0);
1218 }
1219 
1220 #undef __FUNCT__
1221 #define __FUNCT__ "DMPlexGetMaxSizes"
1222 /*@
1223   DMPlexGetMaxSizes - Return the maximum number of in-edges (cone) and out-edges (support) for any point in the Sieve DAG
1224 
1225   Not collective
1226 
1227   Input Parameter:
1228 . mesh - The DMPlex
1229 
1230   Output Parameters:
1231 + maxConeSize - The maximum number of in-edges
1232 - maxSupportSize - The maximum number of out-edges
1233 
1234   Level: beginner
1235 
1236 .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexSetChart()
1237 @*/
1238 PetscErrorCode DMPlexGetMaxSizes(DM dm, PetscInt *maxConeSize, PetscInt *maxSupportSize)
1239 {
1240   DM_Plex *mesh = (DM_Plex*) dm->data;
1241 
1242   PetscFunctionBegin;
1243   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1244   if (maxConeSize)    *maxConeSize    = mesh->maxConeSize;
1245   if (maxSupportSize) *maxSupportSize = mesh->maxSupportSize;
1246   PetscFunctionReturn(0);
1247 }
1248 
1249 #undef __FUNCT__
1250 #define __FUNCT__ "DMSetUp_Plex"
1251 PetscErrorCode DMSetUp_Plex(DM dm)
1252 {
1253   DM_Plex       *mesh = (DM_Plex*) dm->data;
1254   PetscInt       size;
1255   PetscErrorCode ierr;
1256 
1257   PetscFunctionBegin;
1258   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1259   ierr = PetscSectionSetUp(mesh->coneSection);CHKERRQ(ierr);
1260   ierr = PetscSectionGetStorageSize(mesh->coneSection, &size);CHKERRQ(ierr);
1261   ierr = PetscMalloc(size * sizeof(PetscInt), &mesh->cones);CHKERRQ(ierr);
1262   ierr = PetscMalloc(size * sizeof(PetscInt), &mesh->coneOrientations);CHKERRQ(ierr);
1263   ierr = PetscMemzero(mesh->coneOrientations, size * sizeof(PetscInt));CHKERRQ(ierr);
1264   if (mesh->maxSupportSize) {
1265     ierr = PetscSectionSetUp(mesh->supportSection);CHKERRQ(ierr);
1266     ierr = PetscSectionGetStorageSize(mesh->supportSection, &size);CHKERRQ(ierr);
1267     ierr = PetscMalloc(size * sizeof(PetscInt), &mesh->supports);CHKERRQ(ierr);
1268   }
1269   PetscFunctionReturn(0);
1270 }
1271 
1272 #undef __FUNCT__
1273 #define __FUNCT__ "DMCreateSubDM_Plex"
1274 PetscErrorCode DMCreateSubDM_Plex(DM dm, PetscInt numFields, PetscInt fields[], IS *is, DM *subdm)
1275 {
1276   PetscErrorCode ierr;
1277 
1278   PetscFunctionBegin;
1279   if (subdm) {ierr = DMClone(dm, subdm);CHKERRQ(ierr);}
1280   ierr = DMCreateSubDM_Section_Private(dm, numFields, fields, is, subdm);CHKERRQ(ierr);
1281   PetscFunctionReturn(0);
1282 }
1283 
1284 #undef __FUNCT__
1285 #define __FUNCT__ "DMPlexSymmetrize"
1286 /*@
1287   DMPlexSymmetrize - Creates support (out-edge) information from cone (in-edge) inoformation
1288 
1289   Not collective
1290 
1291   Input Parameter:
1292 . mesh - The DMPlex
1293 
1294   Output Parameter:
1295 
1296   Note:
1297   This should be called after all calls to DMPlexSetCone()
1298 
1299   Level: beginner
1300 
1301 .seealso: DMPlexCreate(), DMPlexSetChart(), DMPlexSetConeSize(), DMPlexSetCone()
1302 @*/
1303 PetscErrorCode DMPlexSymmetrize(DM dm)
1304 {
1305   DM_Plex       *mesh = (DM_Plex*) dm->data;
1306   PetscInt      *offsets;
1307   PetscInt       supportSize;
1308   PetscInt       pStart, pEnd, p;
1309   PetscErrorCode ierr;
1310 
1311   PetscFunctionBegin;
1312   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1313   if (mesh->supports) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Supports were already setup in this DMPlex");
1314   /* Calculate support sizes */
1315   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
1316   for (p = pStart; p < pEnd; ++p) {
1317     PetscInt dof, off, c;
1318 
1319     ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
1320     ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
1321     for (c = off; c < off+dof; ++c) {
1322       ierr = PetscSectionAddDof(mesh->supportSection, mesh->cones[c], 1);CHKERRQ(ierr);
1323     }
1324   }
1325   for (p = pStart; p < pEnd; ++p) {
1326     PetscInt dof;
1327 
1328     ierr = PetscSectionGetDof(mesh->supportSection, p, &dof);CHKERRQ(ierr);
1329 
1330     mesh->maxSupportSize = PetscMax(mesh->maxSupportSize, dof);
1331   }
1332   ierr = PetscSectionSetUp(mesh->supportSection);CHKERRQ(ierr);
1333   /* Calculate supports */
1334   ierr = PetscSectionGetStorageSize(mesh->supportSection, &supportSize);CHKERRQ(ierr);
1335   ierr = PetscMalloc(supportSize * sizeof(PetscInt), &mesh->supports);CHKERRQ(ierr);
1336   ierr = PetscMalloc((pEnd - pStart) * sizeof(PetscInt), &offsets);CHKERRQ(ierr);
1337   ierr = PetscMemzero(offsets, (pEnd - pStart) * sizeof(PetscInt));CHKERRQ(ierr);
1338   for (p = pStart; p < pEnd; ++p) {
1339     PetscInt dof, off, c;
1340 
1341     ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
1342     ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
1343     for (c = off; c < off+dof; ++c) {
1344       const PetscInt q = mesh->cones[c];
1345       PetscInt       offS;
1346 
1347       ierr = PetscSectionGetOffset(mesh->supportSection, q, &offS);CHKERRQ(ierr);
1348 
1349       mesh->supports[offS+offsets[q]] = p;
1350       ++offsets[q];
1351     }
1352   }
1353   ierr = PetscFree(offsets);CHKERRQ(ierr);
1354   PetscFunctionReturn(0);
1355 }
1356 
1357 #undef __FUNCT__
1358 #define __FUNCT__ "DMPlexStratify"
1359 /*@
1360   DMPlexStratify - The Sieve DAG for most topologies is a graded poset (http://en.wikipedia.org/wiki/Graded_poset), and
1361   can be illustrated by Hasse Diagram (a http://en.wikipedia.org/wiki/Hasse_diagram). The strata group all points of the
1362   same grade, and this function calculates the strata. This grade can be seen as the height (or depth) of the point in
1363   the DAG.
1364 
1365   Not collective
1366 
1367   Input Parameter:
1368 . mesh - The DMPlex
1369 
1370   Output Parameter:
1371 
1372   Notes:
1373   The normal association for the point grade is element dimension (or co-dimension). For instance, all vertices would
1374   have depth 0, and all edges depth 1. Likewise, all cells heights would have height 0, and all faces height 1.
1375 
1376   This should be called after all calls to DMPlexSymmetrize()
1377 
1378   Level: beginner
1379 
1380 .seealso: DMPlexCreate(), DMPlexSymmetrize()
1381 @*/
1382 PetscErrorCode DMPlexStratify(DM dm)
1383 {
1384   DMLabel        label;
1385   PetscInt       pStart, pEnd, p;
1386   PetscInt       numRoots = 0, numLeaves = 0;
1387   PetscErrorCode ierr;
1388 
1389   PetscFunctionBegin;
1390   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1391   ierr = PetscLogEventBegin(DMPLEX_Stratify,dm,0,0,0);CHKERRQ(ierr);
1392   /* Calculate depth */
1393   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
1394   ierr = DMPlexCreateLabel(dm, "depth");CHKERRQ(ierr);
1395   ierr = DMPlexGetDepthLabel(dm, &label);CHKERRQ(ierr);
1396   /* Initialize roots and count leaves */
1397   for (p = pStart; p < pEnd; ++p) {
1398     PetscInt coneSize, supportSize;
1399 
1400     ierr = DMPlexGetConeSize(dm, p, &coneSize);CHKERRQ(ierr);
1401     ierr = DMPlexGetSupportSize(dm, p, &supportSize);CHKERRQ(ierr);
1402     if (!coneSize && supportSize) {
1403       ++numRoots;
1404       ierr = DMLabelSetValue(label, p, 0);CHKERRQ(ierr);
1405     } else if (!supportSize && coneSize) {
1406       ++numLeaves;
1407     } else if (!supportSize && !coneSize) {
1408       /* Isolated points */
1409       ierr = DMLabelSetValue(label, p, 0);CHKERRQ(ierr);
1410     }
1411   }
1412   if (numRoots + numLeaves == (pEnd - pStart)) {
1413     for (p = pStart; p < pEnd; ++p) {
1414       PetscInt coneSize, supportSize;
1415 
1416       ierr = DMPlexGetConeSize(dm, p, &coneSize);CHKERRQ(ierr);
1417       ierr = DMPlexGetSupportSize(dm, p, &supportSize);CHKERRQ(ierr);
1418       if (!supportSize && coneSize) {
1419         ierr = DMLabelSetValue(label, p, 1);CHKERRQ(ierr);
1420       }
1421     }
1422   } else {
1423     IS       pointIS;
1424     PetscInt numPoints = 0, level = 0;
1425 
1426     ierr = DMLabelGetStratumIS(label, level, &pointIS);CHKERRQ(ierr);
1427     if (pointIS) {ierr = ISGetLocalSize(pointIS, &numPoints);CHKERRQ(ierr);}
1428     while (numPoints) {
1429       const PetscInt *points;
1430       const PetscInt  newLevel = level+1;
1431 
1432       ierr = ISGetIndices(pointIS, &points);CHKERRQ(ierr);
1433       for (p = 0; p < numPoints; ++p) {
1434         const PetscInt  point = points[p];
1435         const PetscInt *support;
1436         PetscInt        supportSize, s;
1437 
1438         ierr = DMPlexGetSupportSize(dm, point, &supportSize);CHKERRQ(ierr);
1439         ierr = DMPlexGetSupport(dm, point, &support);CHKERRQ(ierr);
1440         for (s = 0; s < supportSize; ++s) {
1441           ierr = DMLabelSetValue(label, support[s], newLevel);CHKERRQ(ierr);
1442         }
1443       }
1444       ++level;
1445       ierr = ISDestroy(&pointIS);CHKERRQ(ierr);
1446       ierr = DMLabelGetStratumIS(label, level, &pointIS);CHKERRQ(ierr);
1447       if (pointIS) {ierr = ISGetLocalSize(pointIS, &numPoints);CHKERRQ(ierr);}
1448       else         {numPoints = 0;}
1449     }
1450     ierr = ISDestroy(&pointIS);CHKERRQ(ierr);
1451   }
1452   ierr = PetscLogEventEnd(DMPLEX_Stratify,dm,0,0,0);CHKERRQ(ierr);
1453   PetscFunctionReturn(0);
1454 }
1455 
1456 #undef __FUNCT__
1457 #define __FUNCT__ "DMPlexGetJoin"
1458 /*@C
1459   DMPlexGetJoin - Get an array for the join of the set of points
1460 
1461   Not Collective
1462 
1463   Input Parameters:
1464 + dm - The DMPlex object
1465 . numPoints - The number of input points for the join
1466 - points - The input points
1467 
1468   Output Parameters:
1469 + numCoveredPoints - The number of points in the join
1470 - coveredPoints - The points in the join
1471 
1472   Level: intermediate
1473 
1474   Note: Currently, this is restricted to a single level join
1475 
1476   Fortran Notes:
1477   Since it returns an array, this routine is only available in Fortran 90, and you must
1478   include petsc.h90 in your code.
1479 
1480   The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array.
1481 
1482 .keywords: mesh
1483 .seealso: DMPlexRestoreJoin(), DMPlexGetMeet()
1484 @*/
1485 PetscErrorCode DMPlexGetJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
1486 {
1487   DM_Plex       *mesh = (DM_Plex*) dm->data;
1488   PetscInt      *join[2];
1489   PetscInt       joinSize, i = 0;
1490   PetscInt       dof, off, p, c, m;
1491   PetscErrorCode ierr;
1492 
1493   PetscFunctionBegin;
1494   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1495   PetscValidPointer(points, 2);
1496   PetscValidPointer(numCoveredPoints, 3);
1497   PetscValidPointer(coveredPoints, 4);
1498   ierr = DMGetWorkArray(dm, mesh->maxSupportSize, PETSC_INT, &join[0]);CHKERRQ(ierr);
1499   ierr = DMGetWorkArray(dm, mesh->maxSupportSize, PETSC_INT, &join[1]);CHKERRQ(ierr);
1500   /* Copy in support of first point */
1501   ierr = PetscSectionGetDof(mesh->supportSection, points[0], &dof);CHKERRQ(ierr);
1502   ierr = PetscSectionGetOffset(mesh->supportSection, points[0], &off);CHKERRQ(ierr);
1503   for (joinSize = 0; joinSize < dof; ++joinSize) {
1504     join[i][joinSize] = mesh->supports[off+joinSize];
1505   }
1506   /* Check each successive support */
1507   for (p = 1; p < numPoints; ++p) {
1508     PetscInt newJoinSize = 0;
1509 
1510     ierr = PetscSectionGetDof(mesh->supportSection, points[p], &dof);CHKERRQ(ierr);
1511     ierr = PetscSectionGetOffset(mesh->supportSection, points[p], &off);CHKERRQ(ierr);
1512     for (c = 0; c < dof; ++c) {
1513       const PetscInt point = mesh->supports[off+c];
1514 
1515       for (m = 0; m < joinSize; ++m) {
1516         if (point == join[i][m]) {
1517           join[1-i][newJoinSize++] = point;
1518           break;
1519         }
1520       }
1521     }
1522     joinSize = newJoinSize;
1523     i        = 1-i;
1524   }
1525   *numCoveredPoints = joinSize;
1526   *coveredPoints    = join[i];
1527   ierr              = DMRestoreWorkArray(dm, mesh->maxSupportSize, PETSC_INT, &join[1-i]);CHKERRQ(ierr);
1528   PetscFunctionReturn(0);
1529 }
1530 
1531 #undef __FUNCT__
1532 #define __FUNCT__ "DMPlexRestoreJoin"
1533 /*@C
1534   DMPlexRestoreJoin - Restore an array for the join of the set of points
1535 
1536   Not Collective
1537 
1538   Input Parameters:
1539 + dm - The DMPlex object
1540 . numPoints - The number of input points for the join
1541 - points - The input points
1542 
1543   Output Parameters:
1544 + numCoveredPoints - The number of points in the join
1545 - coveredPoints - The points in the join
1546 
1547   Fortran Notes:
1548   Since it returns an array, this routine is only available in Fortran 90, and you must
1549   include petsc.h90 in your code.
1550 
1551   The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array.
1552 
1553   Level: intermediate
1554 
1555 .keywords: mesh
1556 .seealso: DMPlexGetJoin(), DMPlexGetFullJoin(), DMPlexGetMeet()
1557 @*/
1558 PetscErrorCode DMPlexRestoreJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
1559 {
1560   PetscErrorCode ierr;
1561 
1562   PetscFunctionBegin;
1563   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1564   PetscValidPointer(coveredPoints, 4);
1565   ierr = DMRestoreWorkArray(dm, 0, PETSC_INT, (void*) coveredPoints);CHKERRQ(ierr);
1566   PetscFunctionReturn(0);
1567 }
1568 
1569 #undef __FUNCT__
1570 #define __FUNCT__ "DMPlexGetFullJoin"
1571 /*@C
1572   DMPlexGetFullJoin - Get an array for the join of the set of points
1573 
1574   Not Collective
1575 
1576   Input Parameters:
1577 + dm - The DMPlex object
1578 . numPoints - The number of input points for the join
1579 - points - The input points
1580 
1581   Output Parameters:
1582 + numCoveredPoints - The number of points in the join
1583 - coveredPoints - The points in the join
1584 
1585   Fortran Notes:
1586   Since it returns an array, this routine is only available in Fortran 90, and you must
1587   include petsc.h90 in your code.
1588 
1589   The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array.
1590 
1591   Level: intermediate
1592 
1593 .keywords: mesh
1594 .seealso: DMPlexGetJoin(), DMPlexRestoreJoin(), DMPlexGetMeet()
1595 @*/
1596 PetscErrorCode DMPlexGetFullJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
1597 {
1598   DM_Plex       *mesh = (DM_Plex*) dm->data;
1599   PetscInt      *offsets, **closures;
1600   PetscInt      *join[2];
1601   PetscInt       depth = 0, maxSize, joinSize = 0, i = 0;
1602   PetscInt       p, d, c, m;
1603   PetscErrorCode ierr;
1604 
1605   PetscFunctionBegin;
1606   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1607   PetscValidPointer(points, 2);
1608   PetscValidPointer(numCoveredPoints, 3);
1609   PetscValidPointer(coveredPoints, 4);
1610 
1611   ierr    = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
1612   ierr    = PetscMalloc(numPoints * sizeof(PetscInt*), &closures);CHKERRQ(ierr);
1613   ierr    = PetscMemzero(closures,numPoints*sizeof(PetscInt*));CHKERRQ(ierr);
1614   ierr    = DMGetWorkArray(dm, numPoints*(depth+2), PETSC_INT, &offsets);CHKERRQ(ierr);
1615   maxSize = PetscPowInt(mesh->maxSupportSize,depth+1);
1616   ierr    = DMGetWorkArray(dm, maxSize, PETSC_INT, &join[0]);CHKERRQ(ierr);
1617   ierr    = DMGetWorkArray(dm, maxSize, PETSC_INT, &join[1]);CHKERRQ(ierr);
1618 
1619   for (p = 0; p < numPoints; ++p) {
1620     PetscInt closureSize;
1621 
1622     ierr = DMPlexGetTransitiveClosure(dm, points[p], PETSC_FALSE, &closureSize, &closures[p]);CHKERRQ(ierr);
1623 
1624     offsets[p*(depth+2)+0] = 0;
1625     for (d = 0; d < depth+1; ++d) {
1626       PetscInt pStart, pEnd, i;
1627 
1628       ierr = DMPlexGetDepthStratum(dm, d, &pStart, &pEnd);CHKERRQ(ierr);
1629       for (i = offsets[p*(depth+2)+d]; i < closureSize; ++i) {
1630         if ((pStart > closures[p][i*2]) || (pEnd <= closures[p][i*2])) {
1631           offsets[p*(depth+2)+d+1] = i;
1632           break;
1633         }
1634       }
1635       if (i == closureSize) offsets[p*(depth+2)+d+1] = i;
1636     }
1637     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);
1638   }
1639   for (d = 0; d < depth+1; ++d) {
1640     PetscInt dof;
1641 
1642     /* Copy in support of first point */
1643     dof = offsets[d+1] - offsets[d];
1644     for (joinSize = 0; joinSize < dof; ++joinSize) {
1645       join[i][joinSize] = closures[0][(offsets[d]+joinSize)*2];
1646     }
1647     /* Check each successive cone */
1648     for (p = 1; p < numPoints && joinSize; ++p) {
1649       PetscInt newJoinSize = 0;
1650 
1651       dof = offsets[p*(depth+2)+d+1] - offsets[p*(depth+2)+d];
1652       for (c = 0; c < dof; ++c) {
1653         const PetscInt point = closures[p][(offsets[p*(depth+2)+d]+c)*2];
1654 
1655         for (m = 0; m < joinSize; ++m) {
1656           if (point == join[i][m]) {
1657             join[1-i][newJoinSize++] = point;
1658             break;
1659           }
1660         }
1661       }
1662       joinSize = newJoinSize;
1663       i        = 1-i;
1664     }
1665     if (joinSize) break;
1666   }
1667   *numCoveredPoints = joinSize;
1668   *coveredPoints    = join[i];
1669   for (p = 0; p < numPoints; ++p) {
1670     ierr = DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_FALSE, NULL, &closures[p]);CHKERRQ(ierr);
1671   }
1672   ierr = PetscFree(closures);CHKERRQ(ierr);
1673   ierr = DMRestoreWorkArray(dm, numPoints*(depth+2), PETSC_INT, &offsets);CHKERRQ(ierr);
1674   ierr = DMRestoreWorkArray(dm, mesh->maxSupportSize, PETSC_INT, &join[1-i]);CHKERRQ(ierr);
1675   PetscFunctionReturn(0);
1676 }
1677 
1678 #undef __FUNCT__
1679 #define __FUNCT__ "DMPlexGetMeet"
1680 /*@C
1681   DMPlexGetMeet - Get an array for the meet of the set of points
1682 
1683   Not Collective
1684 
1685   Input Parameters:
1686 + dm - The DMPlex object
1687 . numPoints - The number of input points for the meet
1688 - points - The input points
1689 
1690   Output Parameters:
1691 + numCoveredPoints - The number of points in the meet
1692 - coveredPoints - The points in the meet
1693 
1694   Level: intermediate
1695 
1696   Note: Currently, this is restricted to a single level meet
1697 
1698   Fortran Notes:
1699   Since it returns an array, this routine is only available in Fortran 90, and you must
1700   include petsc.h90 in your code.
1701 
1702   The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array.
1703 
1704 .keywords: mesh
1705 .seealso: DMPlexRestoreMeet(), DMPlexGetJoin()
1706 @*/
1707 PetscErrorCode DMPlexGetMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveringPoints, const PetscInt **coveringPoints)
1708 {
1709   DM_Plex       *mesh = (DM_Plex*) dm->data;
1710   PetscInt      *meet[2];
1711   PetscInt       meetSize, i = 0;
1712   PetscInt       dof, off, p, c, m;
1713   PetscErrorCode ierr;
1714 
1715   PetscFunctionBegin;
1716   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1717   PetscValidPointer(points, 2);
1718   PetscValidPointer(numCoveringPoints, 3);
1719   PetscValidPointer(coveringPoints, 4);
1720   ierr = DMGetWorkArray(dm, mesh->maxConeSize, PETSC_INT, &meet[0]);CHKERRQ(ierr);
1721   ierr = DMGetWorkArray(dm, mesh->maxConeSize, PETSC_INT, &meet[1]);CHKERRQ(ierr);
1722   /* Copy in cone of first point */
1723   ierr = PetscSectionGetDof(mesh->coneSection, points[0], &dof);CHKERRQ(ierr);
1724   ierr = PetscSectionGetOffset(mesh->coneSection, points[0], &off);CHKERRQ(ierr);
1725   for (meetSize = 0; meetSize < dof; ++meetSize) {
1726     meet[i][meetSize] = mesh->cones[off+meetSize];
1727   }
1728   /* Check each successive cone */
1729   for (p = 1; p < numPoints; ++p) {
1730     PetscInt newMeetSize = 0;
1731 
1732     ierr = PetscSectionGetDof(mesh->coneSection, points[p], &dof);CHKERRQ(ierr);
1733     ierr = PetscSectionGetOffset(mesh->coneSection, points[p], &off);CHKERRQ(ierr);
1734     for (c = 0; c < dof; ++c) {
1735       const PetscInt point = mesh->cones[off+c];
1736 
1737       for (m = 0; m < meetSize; ++m) {
1738         if (point == meet[i][m]) {
1739           meet[1-i][newMeetSize++] = point;
1740           break;
1741         }
1742       }
1743     }
1744     meetSize = newMeetSize;
1745     i        = 1-i;
1746   }
1747   *numCoveringPoints = meetSize;
1748   *coveringPoints    = meet[i];
1749   ierr               = DMRestoreWorkArray(dm, mesh->maxConeSize, PETSC_INT, &meet[1-i]);CHKERRQ(ierr);
1750   PetscFunctionReturn(0);
1751 }
1752 
1753 #undef __FUNCT__
1754 #define __FUNCT__ "DMPlexRestoreMeet"
1755 /*@C
1756   DMPlexRestoreMeet - Restore an array for the meet of the set of points
1757 
1758   Not Collective
1759 
1760   Input Parameters:
1761 + dm - The DMPlex object
1762 . numPoints - The number of input points for the meet
1763 - points - The input points
1764 
1765   Output Parameters:
1766 + numCoveredPoints - The number of points in the meet
1767 - coveredPoints - The points in the meet
1768 
1769   Level: intermediate
1770 
1771   Fortran Notes:
1772   Since it returns an array, this routine is only available in Fortran 90, and you must
1773   include petsc.h90 in your code.
1774 
1775   The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array.
1776 
1777 .keywords: mesh
1778 .seealso: DMPlexGetMeet(), DMPlexGetFullMeet(), DMPlexGetJoin()
1779 @*/
1780 PetscErrorCode DMPlexRestoreMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
1781 {
1782   PetscErrorCode ierr;
1783 
1784   PetscFunctionBegin;
1785   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1786   PetscValidPointer(coveredPoints, 4);
1787   ierr = DMRestoreWorkArray(dm, 0, PETSC_INT, (void*) coveredPoints);CHKERRQ(ierr);
1788   PetscFunctionReturn(0);
1789 }
1790 
1791 #undef __FUNCT__
1792 #define __FUNCT__ "DMPlexGetFullMeet"
1793 /*@C
1794   DMPlexGetFullMeet - Get an array for the meet of the set of points
1795 
1796   Not Collective
1797 
1798   Input Parameters:
1799 + dm - The DMPlex object
1800 . numPoints - The number of input points for the meet
1801 - points - The input points
1802 
1803   Output Parameters:
1804 + numCoveredPoints - The number of points in the meet
1805 - coveredPoints - The points in the meet
1806 
1807   Level: intermediate
1808 
1809   Fortran Notes:
1810   Since it returns an array, this routine is only available in Fortran 90, and you must
1811   include petsc.h90 in your code.
1812 
1813   The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array.
1814 
1815 .keywords: mesh
1816 .seealso: DMPlexGetMeet(), DMPlexRestoreMeet(), DMPlexGetJoin()
1817 @*/
1818 PetscErrorCode DMPlexGetFullMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
1819 {
1820   DM_Plex       *mesh = (DM_Plex*) dm->data;
1821   PetscInt      *offsets, **closures;
1822   PetscInt      *meet[2];
1823   PetscInt       height = 0, maxSize, meetSize = 0, i = 0;
1824   PetscInt       p, h, c, m;
1825   PetscErrorCode ierr;
1826 
1827   PetscFunctionBegin;
1828   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1829   PetscValidPointer(points, 2);
1830   PetscValidPointer(numCoveredPoints, 3);
1831   PetscValidPointer(coveredPoints, 4);
1832 
1833   ierr    = DMPlexGetDepth(dm, &height);CHKERRQ(ierr);
1834   ierr    = PetscMalloc(numPoints * sizeof(PetscInt*), &closures);CHKERRQ(ierr);
1835   ierr    = DMGetWorkArray(dm, numPoints*(height+2), PETSC_INT, &offsets);CHKERRQ(ierr);
1836   maxSize = PetscPowInt(mesh->maxConeSize,height+1);
1837   ierr    = DMGetWorkArray(dm, maxSize, PETSC_INT, &meet[0]);CHKERRQ(ierr);
1838   ierr    = DMGetWorkArray(dm, maxSize, PETSC_INT, &meet[1]);CHKERRQ(ierr);
1839 
1840   for (p = 0; p < numPoints; ++p) {
1841     PetscInt closureSize;
1842 
1843     ierr = DMPlexGetTransitiveClosure(dm, points[p], PETSC_TRUE, &closureSize, &closures[p]);CHKERRQ(ierr);
1844 
1845     offsets[p*(height+2)+0] = 0;
1846     for (h = 0; h < height+1; ++h) {
1847       PetscInt pStart, pEnd, i;
1848 
1849       ierr = DMPlexGetHeightStratum(dm, h, &pStart, &pEnd);CHKERRQ(ierr);
1850       for (i = offsets[p*(height+2)+h]; i < closureSize; ++i) {
1851         if ((pStart > closures[p][i*2]) || (pEnd <= closures[p][i*2])) {
1852           offsets[p*(height+2)+h+1] = i;
1853           break;
1854         }
1855       }
1856       if (i == closureSize) offsets[p*(height+2)+h+1] = i;
1857     }
1858     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);
1859   }
1860   for (h = 0; h < height+1; ++h) {
1861     PetscInt dof;
1862 
1863     /* Copy in cone of first point */
1864     dof = offsets[h+1] - offsets[h];
1865     for (meetSize = 0; meetSize < dof; ++meetSize) {
1866       meet[i][meetSize] = closures[0][(offsets[h]+meetSize)*2];
1867     }
1868     /* Check each successive cone */
1869     for (p = 1; p < numPoints && meetSize; ++p) {
1870       PetscInt newMeetSize = 0;
1871 
1872       dof = offsets[p*(height+2)+h+1] - offsets[p*(height+2)+h];
1873       for (c = 0; c < dof; ++c) {
1874         const PetscInt point = closures[p][(offsets[p*(height+2)+h]+c)*2];
1875 
1876         for (m = 0; m < meetSize; ++m) {
1877           if (point == meet[i][m]) {
1878             meet[1-i][newMeetSize++] = point;
1879             break;
1880           }
1881         }
1882       }
1883       meetSize = newMeetSize;
1884       i        = 1-i;
1885     }
1886     if (meetSize) break;
1887   }
1888   *numCoveredPoints = meetSize;
1889   *coveredPoints    = meet[i];
1890   for (p = 0; p < numPoints; ++p) {
1891     ierr = DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_TRUE, NULL, &closures[p]);CHKERRQ(ierr);
1892   }
1893   ierr = PetscFree(closures);CHKERRQ(ierr);
1894   ierr = DMRestoreWorkArray(dm, numPoints*(height+2), PETSC_INT, &offsets);CHKERRQ(ierr);
1895   ierr = DMRestoreWorkArray(dm, mesh->maxConeSize, PETSC_INT, &meet[1-i]);CHKERRQ(ierr);
1896   PetscFunctionReturn(0);
1897 }
1898 
1899 #undef __FUNCT__
1900 #define __FUNCT__ "DMPlexEqual"
1901 /*@C
1902   DMPlexEqual - Determine if two DMs have the same topology
1903 
1904   Not Collective
1905 
1906   Input Parameters:
1907 + dmA - A DMPlex object
1908 - dmB - A DMPlex object
1909 
1910   Output Parameters:
1911 . equal - PETSC_TRUE if the topologies are identical
1912 
1913   Level: intermediate
1914 
1915   Notes:
1916   We are not solving graph isomorphism, so we do not permutation.
1917 
1918 .keywords: mesh
1919 .seealso: DMPlexGetCone()
1920 @*/
1921 PetscErrorCode DMPlexEqual(DM dmA, DM dmB, PetscBool *equal)
1922 {
1923   PetscInt       depth, depthB, pStart, pEnd, pStartB, pEndB, p;
1924   PetscErrorCode ierr;
1925 
1926   PetscFunctionBegin;
1927   PetscValidHeaderSpecific(dmA, DM_CLASSID, 1);
1928   PetscValidHeaderSpecific(dmB, DM_CLASSID, 2);
1929   PetscValidPointer(equal, 3);
1930 
1931   *equal = PETSC_FALSE;
1932   ierr = DMPlexGetDepth(dmA, &depth);CHKERRQ(ierr);
1933   ierr = DMPlexGetDepth(dmB, &depthB);CHKERRQ(ierr);
1934   if (depth != depthB) PetscFunctionReturn(0);
1935   ierr = DMPlexGetChart(dmA, &pStart,  &pEnd);CHKERRQ(ierr);
1936   ierr = DMPlexGetChart(dmB, &pStartB, &pEndB);CHKERRQ(ierr);
1937   if ((pStart != pStartB) || (pEnd != pEndB)) PetscFunctionReturn(0);
1938   for (p = pStart; p < pEnd; ++p) {
1939     const PetscInt *cone, *coneB, *ornt, *orntB, *support, *supportB;
1940     PetscInt        coneSize, coneSizeB, c, supportSize, supportSizeB, s;
1941 
1942     ierr = DMPlexGetConeSize(dmA, p, &coneSize);CHKERRQ(ierr);
1943     ierr = DMPlexGetCone(dmA, p, &cone);CHKERRQ(ierr);
1944     ierr = DMPlexGetConeOrientation(dmA, p, &ornt);CHKERRQ(ierr);
1945     ierr = DMPlexGetConeSize(dmB, p, &coneSizeB);CHKERRQ(ierr);
1946     ierr = DMPlexGetCone(dmB, p, &coneB);CHKERRQ(ierr);
1947     ierr = DMPlexGetConeOrientation(dmB, p, &orntB);CHKERRQ(ierr);
1948     if (coneSize != coneSizeB) PetscFunctionReturn(0);
1949     for (c = 0; c < coneSize; ++c) {
1950       if (cone[c] != coneB[c]) PetscFunctionReturn(0);
1951       if (ornt[c] != orntB[c]) PetscFunctionReturn(0);
1952     }
1953     ierr = DMPlexGetSupportSize(dmA, p, &supportSize);CHKERRQ(ierr);
1954     ierr = DMPlexGetSupport(dmA, p, &support);CHKERRQ(ierr);
1955     ierr = DMPlexGetSupportSize(dmB, p, &supportSizeB);CHKERRQ(ierr);
1956     ierr = DMPlexGetSupport(dmB, p, &supportB);CHKERRQ(ierr);
1957     if (supportSize != supportSizeB) PetscFunctionReturn(0);
1958     for (s = 0; s < supportSize; ++s) {
1959       if (support[s] != supportB[s]) PetscFunctionReturn(0);
1960     }
1961   }
1962   *equal = PETSC_TRUE;
1963   PetscFunctionReturn(0);
1964 }
1965 
1966 #undef __FUNCT__
1967 #define __FUNCT__ "DMPlexGetNumFaceVertices"
1968 PetscErrorCode DMPlexGetNumFaceVertices(DM dm, PetscInt cellDim, PetscInt numCorners, PetscInt *numFaceVertices)
1969 {
1970   MPI_Comm       comm;
1971   PetscErrorCode ierr;
1972 
1973   PetscFunctionBegin;
1974   ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr);
1975   PetscValidPointer(numFaceVertices,3);
1976   switch (cellDim) {
1977   case 0:
1978     *numFaceVertices = 0;
1979     break;
1980   case 1:
1981     *numFaceVertices = 1;
1982     break;
1983   case 2:
1984     switch (numCorners) {
1985     case 3: /* triangle */
1986       *numFaceVertices = 2; /* Edge has 2 vertices */
1987       break;
1988     case 4: /* quadrilateral */
1989       *numFaceVertices = 2; /* Edge has 2 vertices */
1990       break;
1991     case 6: /* quadratic triangle, tri and quad cohesive Lagrange cells */
1992       *numFaceVertices = 3; /* Edge has 3 vertices */
1993       break;
1994     case 9: /* quadratic quadrilateral, quadratic quad cohesive Lagrange cells */
1995       *numFaceVertices = 3; /* Edge has 3 vertices */
1996       break;
1997     default:
1998       SETERRQ2(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %d for dimension %d", numCorners, cellDim);
1999     }
2000     break;
2001   case 3:
2002     switch (numCorners) {
2003     case 4: /* tetradehdron */
2004       *numFaceVertices = 3; /* Face has 3 vertices */
2005       break;
2006     case 6: /* tet cohesive cells */
2007       *numFaceVertices = 4; /* Face has 4 vertices */
2008       break;
2009     case 8: /* hexahedron */
2010       *numFaceVertices = 4; /* Face has 4 vertices */
2011       break;
2012     case 9: /* tet cohesive Lagrange cells */
2013       *numFaceVertices = 6; /* Face has 6 vertices */
2014       break;
2015     case 10: /* quadratic tetrahedron */
2016       *numFaceVertices = 6; /* Face has 6 vertices */
2017       break;
2018     case 12: /* hex cohesive Lagrange cells */
2019       *numFaceVertices = 6; /* Face has 6 vertices */
2020       break;
2021     case 18: /* quadratic tet cohesive Lagrange cells */
2022       *numFaceVertices = 6; /* Face has 6 vertices */
2023       break;
2024     case 27: /* quadratic hexahedron, quadratic hex cohesive Lagrange cells */
2025       *numFaceVertices = 9; /* Face has 9 vertices */
2026       break;
2027     default:
2028       SETERRQ2(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %d for dimension %d", numCorners, cellDim);
2029     }
2030     break;
2031   default:
2032     SETERRQ1(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid cell dimension %d", cellDim);
2033   }
2034   PetscFunctionReturn(0);
2035 }
2036 
2037 #undef __FUNCT__
2038 #define __FUNCT__ "DMPlexOrient"
2039 /* Trys to give the mesh a consistent orientation */
2040 PetscErrorCode DMPlexOrient(DM dm)
2041 {
2042   PetscBT        seenCells, flippedCells, seenFaces;
2043   PetscInt      *faceFIFO, fTop, fBottom;
2044   PetscInt       dim, h, cStart, cEnd, c, fStart, fEnd, face, maxConeSize, *revcone, *revconeO;
2045   PetscErrorCode ierr;
2046 
2047   PetscFunctionBegin;
2048   /* Truth Table
2049      mismatch    flips   do action   mismatch   flipA ^ flipB   action
2050          F       0 flips     no         F             F           F
2051          F       1 flip      yes        F             T           T
2052          F       2 flips     no         T             F           T
2053          T       0 flips     yes        T             T           F
2054          T       1 flip      no
2055          T       2 flips     yes
2056   */
2057   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
2058   ierr = DMPlexGetVTKCellHeight(dm, &h);CHKERRQ(ierr);
2059   ierr = DMPlexGetHeightStratum(dm, h,   &cStart, &cEnd);CHKERRQ(ierr);
2060   ierr = DMPlexGetHeightStratum(dm, h+1, &fStart, &fEnd);CHKERRQ(ierr);
2061   ierr = PetscBTCreate(cEnd - cStart, &seenCells);CHKERRQ(ierr);
2062   ierr = PetscBTMemzero(cEnd - cStart, seenCells);CHKERRQ(ierr);
2063   ierr = PetscBTCreate(cEnd - cStart, &flippedCells);CHKERRQ(ierr);
2064   ierr = PetscBTMemzero(cEnd - cStart, flippedCells);CHKERRQ(ierr);
2065   ierr = PetscBTCreate(fEnd - fStart, &seenFaces);CHKERRQ(ierr);
2066   ierr = PetscBTMemzero(fEnd - fStart, seenFaces);CHKERRQ(ierr);
2067   ierr = PetscMalloc((fEnd - fStart) * sizeof(PetscInt), &faceFIFO);CHKERRQ(ierr);
2068   fTop = fBottom = 0;
2069   /* Initialize FIFO with first cell */
2070   if (cEnd > cStart) {
2071     const PetscInt *cone;
2072     PetscInt        coneSize;
2073 
2074     ierr = DMPlexGetConeSize(dm, cStart, &coneSize);CHKERRQ(ierr);
2075     ierr = DMPlexGetCone(dm, cStart, &cone);CHKERRQ(ierr);
2076     for (c = 0; c < coneSize; ++c) {
2077       faceFIFO[fBottom++] = cone[c];
2078       ierr = PetscBTSet(seenFaces, cone[c]-fStart);CHKERRQ(ierr);
2079     }
2080   }
2081   /* Consider each face in FIFO */
2082   while (fTop < fBottom) {
2083     const PetscInt *support, *coneA, *coneB, *coneOA, *coneOB;
2084     PetscInt        supportSize, coneSizeA, coneSizeB, posA = -1, posB = -1;
2085     PetscInt        seenA, flippedA, seenB, flippedB, mismatch;
2086 
2087     face = faceFIFO[fTop++];
2088     ierr = DMPlexGetSupportSize(dm, face, &supportSize);CHKERRQ(ierr);
2089     ierr = DMPlexGetSupport(dm, face, &support);CHKERRQ(ierr);
2090     if (supportSize < 2) continue;
2091     if (supportSize != 2) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Faces should separate only two cells, not %d", supportSize);
2092     seenA    = PetscBTLookup(seenCells,    support[0]-cStart);
2093     flippedA = PetscBTLookup(flippedCells, support[0]-cStart) ? 1 : 0;
2094     seenB    = PetscBTLookup(seenCells,    support[1]-cStart);
2095     flippedB = PetscBTLookup(flippedCells, support[1]-cStart) ? 1 : 0;
2096 
2097     ierr = DMPlexGetConeSize(dm, support[0], &coneSizeA);CHKERRQ(ierr);
2098     ierr = DMPlexGetConeSize(dm, support[1], &coneSizeB);CHKERRQ(ierr);
2099     ierr = DMPlexGetCone(dm, support[0], &coneA);CHKERRQ(ierr);
2100     ierr = DMPlexGetCone(dm, support[1], &coneB);CHKERRQ(ierr);
2101     ierr = DMPlexGetConeOrientation(dm, support[0], &coneOA);CHKERRQ(ierr);
2102     ierr = DMPlexGetConeOrientation(dm, support[1], &coneOB);CHKERRQ(ierr);
2103     for (c = 0; c < coneSizeA; ++c) {
2104       if (!PetscBTLookup(seenFaces, coneA[c]-fStart)) {
2105         faceFIFO[fBottom++] = coneA[c];
2106         ierr = PetscBTSet(seenFaces, coneA[c]-fStart);CHKERRQ(ierr);
2107       }
2108       if (coneA[c] == face) posA = c;
2109       if (fBottom > fEnd-fStart) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Face %d was pushed exceeding capacity %d > %d", coneA[c], fBottom, fEnd-fStart);
2110     }
2111     if (posA < 0) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Face %d could not be located in cell %d", face, support[0]);
2112     for (c = 0; c < coneSizeB; ++c) {
2113       if (!PetscBTLookup(seenFaces, coneB[c]-fStart)) {
2114         faceFIFO[fBottom++] = coneB[c];
2115         ierr = PetscBTSet(seenFaces, coneB[c]-fStart);CHKERRQ(ierr);
2116       }
2117       if (coneB[c] == face) posB = c;
2118       if (fBottom > fEnd-fStart) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Face %d was pushed exceeding capacity %d > %d", coneA[c], fBottom, fEnd-fStart);
2119     }
2120     if (posB < 0) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Face %d could not be located in cell %d", face, support[1]);
2121 
2122     if (dim == 1) {
2123       mismatch = posA == posB;
2124     } else {
2125       mismatch = coneOA[posA] == coneOB[posB];
2126     }
2127 
2128     if (mismatch ^ (flippedA ^ flippedB)) {
2129       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]);
2130       if (!seenA && !flippedA) {
2131         ierr = PetscBTSet(flippedCells, support[0]-cStart);CHKERRQ(ierr);
2132       } else if (!seenB && !flippedB) {
2133         ierr = PetscBTSet(flippedCells, support[1]-cStart);CHKERRQ(ierr);
2134       } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Inconsistent mesh orientation: Fault mesh is non-orientable");
2135     } else if (mismatch && flippedA && flippedB) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Attempt to flip already flipped cell: Fault mesh is non-orientable");
2136     ierr = PetscBTSet(seenCells, support[0]-cStart);CHKERRQ(ierr);
2137     ierr = PetscBTSet(seenCells, support[1]-cStart);CHKERRQ(ierr);
2138   }
2139 
2140   ierr = DMPlexGetMaxSizes(dm, &maxConeSize, NULL);CHKERRQ(ierr);
2141   ierr = DMGetWorkArray(dm, maxConeSize, PETSC_INT, &revcone);CHKERRQ(ierr);
2142   ierr = DMGetWorkArray(dm, maxConeSize, PETSC_INT, &revconeO);CHKERRQ(ierr);
2143   for (c = cStart; c < cEnd; ++c) {
2144     const PetscInt *cone, *coneO, *support;
2145     PetscInt        coneSize, supportSize, faceSize, cp, sp;
2146 
2147     if (!PetscBTLookup(flippedCells, c-cStart)) continue;
2148     ierr = DMPlexGetConeSize(dm, c, &coneSize);CHKERRQ(ierr);
2149     ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
2150     ierr = DMPlexGetConeOrientation(dm, c, &coneO);CHKERRQ(ierr);
2151     for (cp = 0; cp < coneSize; ++cp) {
2152       const PetscInt rcp = coneSize-cp-1;
2153 
2154       ierr = DMPlexGetConeSize(dm, cone[rcp], &faceSize);CHKERRQ(ierr);
2155       revcone[cp]  = cone[rcp];
2156       revconeO[cp] = coneO[rcp] >= 0 ? -(faceSize-coneO[rcp]) : faceSize+coneO[rcp];
2157     }
2158     ierr = DMPlexSetCone(dm, c, revcone);CHKERRQ(ierr);
2159     ierr = DMPlexSetConeOrientation(dm, c, revconeO);CHKERRQ(ierr);
2160     /* Reverse orientations of support */
2161     faceSize = coneSize;
2162     ierr = DMPlexGetSupportSize(dm, c, &supportSize);CHKERRQ(ierr);
2163     ierr = DMPlexGetSupport(dm, c, &support);CHKERRQ(ierr);
2164     for (sp = 0; sp < supportSize; ++sp) {
2165       ierr = DMPlexGetConeSize(dm, support[sp], &coneSize);CHKERRQ(ierr);
2166       ierr = DMPlexGetCone(dm, support[sp], &cone);CHKERRQ(ierr);
2167       ierr = DMPlexGetConeOrientation(dm, support[sp], &coneO);CHKERRQ(ierr);
2168       for (cp = 0; cp < coneSize; ++cp) {
2169         if (cone[cp] != c) continue;
2170         ierr = DMPlexInsertConeOrientation(dm, support[sp], cp, coneO[cp] >= 0 ? -(faceSize-coneO[cp]) : faceSize+coneO[cp]);CHKERRQ(ierr);
2171       }
2172     }
2173   }
2174   ierr = DMRestoreWorkArray(dm, maxConeSize, PETSC_INT, &revcone);CHKERRQ(ierr);
2175   ierr = DMRestoreWorkArray(dm, maxConeSize, PETSC_INT, &revconeO);CHKERRQ(ierr);
2176   ierr = PetscBTDestroy(&seenCells);CHKERRQ(ierr);
2177   ierr = PetscBTDestroy(&flippedCells);CHKERRQ(ierr);
2178   ierr = PetscBTDestroy(&seenFaces);CHKERRQ(ierr);
2179   ierr = PetscFree(faceFIFO);CHKERRQ(ierr);
2180   PetscFunctionReturn(0);
2181 }
2182 
2183 #undef __FUNCT__
2184 #define __FUNCT__ "DMPlexGetAdjacencySingleLevel_Internal"
2185 static PetscErrorCode DMPlexGetAdjacencySingleLevel_Internal(DM dm, PetscInt p, PetscBool useClosure, const PetscInt *tmpClosure, PetscInt *adjSize, PetscInt adj[])
2186 {
2187   const PetscInt *support = NULL;
2188   PetscInt        numAdj   = 0, maxAdjSize = *adjSize, supportSize, s;
2189   PetscErrorCode  ierr;
2190 
2191   PetscFunctionBegin;
2192   if (useClosure) {
2193     ierr = DMPlexGetConeSize(dm, p, &supportSize);CHKERRQ(ierr);
2194     ierr = DMPlexGetCone(dm, p, &support);CHKERRQ(ierr);
2195     for (s = 0; s < supportSize; ++s) {
2196       const PetscInt *cone = NULL;
2197       PetscInt        coneSize, c, q;
2198 
2199       ierr = DMPlexGetSupportSize(dm, support[s], &coneSize);CHKERRQ(ierr);
2200       ierr = DMPlexGetSupport(dm, support[s], &cone);CHKERRQ(ierr);
2201       for (c = 0; c < coneSize; ++c) {
2202         for (q = 0; q < numAdj || (adj[numAdj++] = cone[c],0); ++q) {
2203           if (cone[c] == adj[q]) break;
2204         }
2205         if (numAdj > maxAdjSize) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid mesh exceeded adjacency allocation (%D)", maxAdjSize);
2206       }
2207     }
2208   } else {
2209     ierr = DMPlexGetSupportSize(dm, p, &supportSize);CHKERRQ(ierr);
2210     ierr = DMPlexGetSupport(dm, p, &support);CHKERRQ(ierr);
2211     for (s = 0; s < supportSize; ++s) {
2212       const PetscInt *cone = NULL;
2213       PetscInt        coneSize, c, q;
2214 
2215       ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
2216       ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
2217       for (c = 0; c < coneSize; ++c) {
2218         for (q = 0; q < numAdj || (adj[numAdj++] = cone[c],0); ++q) {
2219           if (cone[c] == adj[q]) break;
2220         }
2221         if (numAdj > maxAdjSize) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid mesh exceeded adjacency allocation (%D)", maxAdjSize);
2222       }
2223     }
2224   }
2225   *adjSize = numAdj;
2226   PetscFunctionReturn(0);
2227 }
2228 
2229 #undef __FUNCT__
2230 #define __FUNCT__ "DMPlexCreateNeighborCSR"
2231 PetscErrorCode DMPlexCreateNeighborCSR(DM dm, PetscInt cellHeight, PetscInt *numVertices, PetscInt **offsets, PetscInt **adjacency)
2232 {
2233   const PetscInt maxFaceCases = 30;
2234   PetscInt       numFaceCases = 0;
2235   PetscInt       numFaceVertices[30]; /* maxFaceCases, C89 sucks sucks sucks */
2236   PetscInt      *off, *adj;
2237   PetscInt      *neighborCells, *tmpClosure;
2238   PetscInt       maxConeSize, maxSupportSize, maxClosure, maxNeighbors;
2239   PetscInt       dim, cellDim, depth = 0, faceDepth, cStart, cEnd, c, numCells, cell;
2240   PetscErrorCode ierr;
2241 
2242   PetscFunctionBegin;
2243   /* For parallel partitioning, I think you have to communicate supports */
2244   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
2245   cellDim = dim - cellHeight;
2246   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
2247   ierr = DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd);CHKERRQ(ierr);
2248   ierr = DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize);CHKERRQ(ierr);
2249   if (cEnd - cStart == 0) {
2250     if (numVertices) *numVertices = 0;
2251     if (offsets)   *offsets   = NULL;
2252     if (adjacency) *adjacency = NULL;
2253     PetscFunctionReturn(0);
2254   }
2255   numCells  = cEnd - cStart;
2256   faceDepth = depth - cellHeight;
2257   /* Setup face recognition */
2258   if (faceDepth == 1) {
2259     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 */
2260 
2261     for (c = cStart; c < cEnd; ++c) {
2262       PetscInt corners;
2263 
2264       ierr = DMPlexGetConeSize(dm, c, &corners);CHKERRQ(ierr);
2265       if (!cornersSeen[corners]) {
2266         PetscInt nFV;
2267 
2268         if (numFaceCases >= maxFaceCases) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Exceeded maximum number of face recognition cases");
2269         cornersSeen[corners] = 1;
2270 
2271         ierr = DMPlexGetNumFaceVertices(dm, cellDim, corners, &nFV);CHKERRQ(ierr);
2272 
2273         numFaceVertices[numFaceCases++] = nFV;
2274       }
2275     }
2276   }
2277   maxClosure   = 2*PetscMax(PetscPowInt(maxConeSize,depth+1),PetscPowInt(maxSupportSize,depth+1));
2278   maxNeighbors = PetscPowInt(maxConeSize,depth+1)*PetscPowInt(maxSupportSize,depth+1);
2279   ierr         = PetscMalloc2(maxNeighbors,PetscInt,&neighborCells,maxClosure,PetscInt,&tmpClosure);CHKERRQ(ierr);
2280   ierr         = PetscMalloc((numCells+1) * sizeof(PetscInt), &off);CHKERRQ(ierr);
2281   ierr         = PetscMemzero(off, (numCells+1) * sizeof(PetscInt));CHKERRQ(ierr);
2282   /* Count neighboring cells */
2283   for (cell = cStart; cell < cEnd; ++cell) {
2284     PetscInt numNeighbors = maxNeighbors, n;
2285 
2286     ierr = DMPlexGetAdjacencySingleLevel_Internal(dm, cell, PETSC_TRUE, tmpClosure, &numNeighbors, neighborCells);CHKERRQ(ierr);
2287     /* Get meet with each cell, and check with recognizer (could optimize to check each pair only once) */
2288     for (n = 0; n < numNeighbors; ++n) {
2289       PetscInt        cellPair[2];
2290       PetscBool       found    = faceDepth > 1 ? PETSC_TRUE : PETSC_FALSE;
2291       PetscInt        meetSize = 0;
2292       const PetscInt *meet    = NULL;
2293 
2294       cellPair[0] = cell; cellPair[1] = neighborCells[n];
2295       if (cellPair[0] == cellPair[1]) continue;
2296       if (!found) {
2297         ierr = DMPlexGetMeet(dm, 2, cellPair, &meetSize, &meet);CHKERRQ(ierr);
2298         if (meetSize) {
2299           PetscInt f;
2300 
2301           for (f = 0; f < numFaceCases; ++f) {
2302             if (numFaceVertices[f] == meetSize) {
2303               found = PETSC_TRUE;
2304               break;
2305             }
2306           }
2307         }
2308         ierr = DMPlexRestoreMeet(dm, 2, cellPair, &meetSize, &meet);CHKERRQ(ierr);
2309       }
2310       if (found) ++off[cell-cStart+1];
2311     }
2312   }
2313   /* Prefix sum */
2314   for (cell = 1; cell <= numCells; ++cell) off[cell] += off[cell-1];
2315 
2316   if (adjacency) {
2317     ierr = PetscMalloc(off[numCells] * sizeof(PetscInt), &adj);CHKERRQ(ierr);
2318     /* Get neighboring cells */
2319     for (cell = cStart; cell < cEnd; ++cell) {
2320       PetscInt numNeighbors = maxNeighbors, n;
2321       PetscInt cellOffset   = 0;
2322 
2323       ierr = DMPlexGetAdjacencySingleLevel_Internal(dm, cell, PETSC_TRUE, tmpClosure, &numNeighbors, neighborCells);CHKERRQ(ierr);
2324       /* Get meet with each cell, and check with recognizer (could optimize to check each pair only once) */
2325       for (n = 0; n < numNeighbors; ++n) {
2326         PetscInt        cellPair[2];
2327         PetscBool       found    = faceDepth > 1 ? PETSC_TRUE : PETSC_FALSE;
2328         PetscInt        meetSize = 0;
2329         const PetscInt *meet    = NULL;
2330 
2331         cellPair[0] = cell; cellPair[1] = neighborCells[n];
2332         if (cellPair[0] == cellPair[1]) continue;
2333         if (!found) {
2334           ierr = DMPlexGetMeet(dm, 2, cellPair, &meetSize, &meet);CHKERRQ(ierr);
2335           if (meetSize) {
2336             PetscInt f;
2337 
2338             for (f = 0; f < numFaceCases; ++f) {
2339               if (numFaceVertices[f] == meetSize) {
2340                 found = PETSC_TRUE;
2341                 break;
2342               }
2343             }
2344           }
2345           ierr = DMPlexRestoreMeet(dm, 2, cellPair, &meetSize, &meet);CHKERRQ(ierr);
2346         }
2347         if (found) {
2348           adj[off[cell-cStart]+cellOffset] = neighborCells[n];
2349           ++cellOffset;
2350         }
2351       }
2352     }
2353   }
2354   ierr = PetscFree2(neighborCells,tmpClosure);CHKERRQ(ierr);
2355   if (numVertices) *numVertices = numCells;
2356   if (offsets)   *offsets   = off;
2357   if (adjacency) *adjacency = adj;
2358   PetscFunctionReturn(0);
2359 }
2360 
2361 #if defined(PETSC_HAVE_CHACO)
2362 #if defined(PETSC_HAVE_UNISTD_H)
2363 #include <unistd.h>
2364 #endif
2365 /* Chaco does not have an include file */
2366 PETSC_EXTERN int interface(int nvtxs, int *start, int *adjacency, int *vwgts,
2367                        float *ewgts, float *x, float *y, float *z, char *outassignname,
2368                        char *outfilename, short *assignment, int architecture, int ndims_tot,
2369                        int mesh_dims[3], double *goal, int global_method, int local_method,
2370                        int rqi_flag, int vmax, int ndims, double eigtol, long seed);
2371 
2372 extern int FREE_GRAPH;
2373 
2374 #undef __FUNCT__
2375 #define __FUNCT__ "DMPlexPartition_Chaco"
2376 PetscErrorCode DMPlexPartition_Chaco(DM dm, PetscInt numVertices, PetscInt start[], PetscInt adjacency[], PetscSection *partSection, IS *partition)
2377 {
2378   enum {DEFAULT_METHOD = 1, INERTIAL_METHOD = 3};
2379   MPI_Comm       comm;
2380   int            nvtxs          = numVertices; /* number of vertices in full graph */
2381   int           *vwgts          = NULL;   /* weights for all vertices */
2382   float         *ewgts          = NULL;   /* weights for all edges */
2383   float         *x              = NULL, *y = NULL, *z = NULL; /* coordinates for inertial method */
2384   char          *outassignname  = NULL;   /*  name of assignment output file */
2385   char          *outfilename    = NULL;   /* output file name */
2386   int            architecture   = 1;      /* 0 => hypercube, d => d-dimensional mesh */
2387   int            ndims_tot      = 0;      /* total number of cube dimensions to divide */
2388   int            mesh_dims[3];            /* dimensions of mesh of processors */
2389   double        *goal          = NULL;    /* desired set sizes for each set */
2390   int            global_method = 1;       /* global partitioning algorithm */
2391   int            local_method  = 1;       /* local partitioning algorithm */
2392   int            rqi_flag      = 0;       /* should I use RQI/Symmlq eigensolver? */
2393   int            vmax          = 200;     /* how many vertices to coarsen down to? */
2394   int            ndims         = 1;       /* number of eigenvectors (2^d sets) */
2395   double         eigtol        = 0.001;   /* tolerance on eigenvectors */
2396   long           seed          = 123636512; /* for random graph mutations */
2397   short int     *assignment;              /* Output partition */
2398   int            fd_stdout, fd_pipe[2];
2399   PetscInt      *points;
2400   PetscMPIInt    commSize;
2401   int            i, v, p;
2402   PetscErrorCode ierr;
2403 
2404   PetscFunctionBegin;
2405   ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr);
2406   ierr = MPI_Comm_size(comm, &commSize);CHKERRQ(ierr);
2407   if (!numVertices) {
2408     ierr = PetscSectionCreate(comm, partSection);CHKERRQ(ierr);
2409     ierr = PetscSectionSetChart(*partSection, 0, commSize);CHKERRQ(ierr);
2410     ierr = PetscSectionSetUp(*partSection);CHKERRQ(ierr);
2411     ierr = ISCreateGeneral(comm, 0, NULL, PETSC_OWN_POINTER, partition);CHKERRQ(ierr);
2412     PetscFunctionReturn(0);
2413   }
2414   FREE_GRAPH = 0;                         /* Do not let Chaco free my memory */
2415   for (i = 0; i < start[numVertices]; ++i) ++adjacency[i];
2416 
2417   if (global_method == INERTIAL_METHOD) {
2418     /* manager.createCellCoordinates(nvtxs, &x, &y, &z); */
2419     SETERRQ(comm, PETSC_ERR_SUP, "Inertial partitioning not yet supported");
2420   }
2421   mesh_dims[0] = commSize;
2422   mesh_dims[1] = 1;
2423   mesh_dims[2] = 1;
2424   ierr = PetscMalloc(nvtxs * sizeof(short int), &assignment);CHKERRQ(ierr);
2425   /* Chaco outputs to stdout. We redirect this to a buffer. */
2426   /* TODO: check error codes for UNIX calls */
2427 #if defined(PETSC_HAVE_UNISTD_H)
2428   {
2429     int piperet;
2430     piperet = pipe(fd_pipe);
2431     if (piperet) SETERRQ(comm,PETSC_ERR_SYS,"Could not create pipe");
2432     fd_stdout = dup(1);
2433     close(1);
2434     dup2(fd_pipe[1], 1);
2435   }
2436 #endif
2437   ierr = interface(nvtxs, (int*) start, (int*) adjacency, vwgts, ewgts, x, y, z, outassignname, outfilename,
2438                    assignment, architecture, ndims_tot, mesh_dims, goal, global_method, local_method, rqi_flag,
2439                    vmax, ndims, eigtol, seed);
2440 #if defined(PETSC_HAVE_UNISTD_H)
2441   {
2442     char msgLog[10000];
2443     int  count;
2444 
2445     fflush(stdout);
2446     count = read(fd_pipe[0], msgLog, (10000-1)*sizeof(char));
2447     if (count < 0) count = 0;
2448     msgLog[count] = 0;
2449     close(1);
2450     dup2(fd_stdout, 1);
2451     close(fd_stdout);
2452     close(fd_pipe[0]);
2453     close(fd_pipe[1]);
2454     if (ierr) SETERRQ1(comm, PETSC_ERR_LIB, "Error in Chaco library: %s", msgLog);
2455   }
2456 #endif
2457   /* Convert to PetscSection+IS */
2458   ierr = PetscSectionCreate(comm, partSection);CHKERRQ(ierr);
2459   ierr = PetscSectionSetChart(*partSection, 0, commSize);CHKERRQ(ierr);
2460   for (v = 0; v < nvtxs; ++v) {
2461     ierr = PetscSectionAddDof(*partSection, assignment[v], 1);CHKERRQ(ierr);
2462   }
2463   ierr = PetscSectionSetUp(*partSection);CHKERRQ(ierr);
2464   ierr = PetscMalloc(nvtxs * sizeof(PetscInt), &points);CHKERRQ(ierr);
2465   for (p = 0, i = 0; p < commSize; ++p) {
2466     for (v = 0; v < nvtxs; ++v) {
2467       if (assignment[v] == p) points[i++] = v;
2468     }
2469   }
2470   if (i != nvtxs) SETERRQ2(comm, PETSC_ERR_PLIB, "Number of points %D should be %D", i, nvtxs);
2471   ierr = ISCreateGeneral(comm, nvtxs, points, PETSC_OWN_POINTER, partition);CHKERRQ(ierr);
2472   if (global_method == INERTIAL_METHOD) {
2473     /* manager.destroyCellCoordinates(nvtxs, &x, &y, &z); */
2474   }
2475   ierr = PetscFree(assignment);CHKERRQ(ierr);
2476   for (i = 0; i < start[numVertices]; ++i) --adjacency[i];
2477   PetscFunctionReturn(0);
2478 }
2479 #endif
2480 
2481 #if defined(PETSC_HAVE_PARMETIS)
2482 #include <parmetis.h>
2483 
2484 #undef __FUNCT__
2485 #define __FUNCT__ "DMPlexPartition_ParMetis"
2486 PetscErrorCode DMPlexPartition_ParMetis(DM dm, PetscInt numVertices, PetscInt start[], PetscInt adjacency[], PetscSection *partSection, IS *partition)
2487 {
2488   MPI_Comm       comm;
2489   PetscInt       nvtxs      = numVertices; // The number of vertices in full graph
2490   PetscInt      *vtxdist;                  // Distribution of vertices across processes
2491   PetscInt      *xadj       = start;       // Start of edge list for each vertex
2492   PetscInt      *adjncy     = adjacency;   // Edge lists for all vertices
2493   PetscInt      *vwgt       = NULL;        // Vertex weights
2494   PetscInt      *adjwgt     = NULL;        // Edge weights
2495   PetscInt       wgtflag    = 0;           // Indicates which weights are present
2496   PetscInt       numflag    = 0;           // Indicates initial offset (0 or 1)
2497   PetscInt       ncon       = 1;           // The number of weights per vertex
2498   PetscInt       nparts;                   // The number of partitions
2499   PetscReal     *tpwgts;                   // The fraction of vertex weights assigned to each partition
2500   PetscReal     *ubvec;                    // The balance intolerance for vertex weights
2501   PetscInt       options[5];               // Options
2502   // Outputs
2503   PetscInt       edgeCut;                  // The number of edges cut by the partition
2504   PetscInt      *assignment, *points;
2505   PetscMPIInt    commSize, rank, p, v, i;
2506   PetscErrorCode ierr;
2507 
2508   PetscFunctionBegin;
2509   ierr = PetscObjectGetComm((PetscObject) dm, &comm);CHKERRQ(ierr);
2510   ierr = MPI_Comm_size(comm, &commSize);CHKERRQ(ierr);
2511   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
2512   nparts = commSize;
2513   options[0] = 0; /* Use all defaults */
2514   /* Calculate vertex distribution */
2515   ierr = PetscMalloc4(nparts+1,PetscInt,&vtxdist,nparts*ncon,PetscReal,&tpwgts,ncon,PetscReal,&ubvec,nvtxs,PetscInt,&assignment);CHKERRQ(ierr);
2516   vtxdist[0] = 0;
2517   ierr = MPI_Allgather(&nvtxs, 1, MPIU_INT, &vtxdist[1], 1, MPIU_INT, comm);CHKERRQ(ierr);
2518   for (p = 2; p <= nparts; ++p) {
2519     vtxdist[p] += vtxdist[p-1];
2520   }
2521   /* Calculate weights */
2522   for (p = 0; p < nparts; ++p) {
2523     tpwgts[p] = 1.0/nparts;
2524   }
2525   ubvec[0] = 1.05;
2526 
2527   if (nparts == 1) {
2528     ierr = PetscMemzero(assignment, nvtxs * sizeof(PetscInt));
2529   } else {
2530     if (vtxdist[1] == vtxdist[nparts]) {
2531       if (!rank) {
2532         PetscStackPush("METIS_PartGraphKway");
2533         ierr = METIS_PartGraphKway(&nvtxs, &ncon, xadj, adjncy, vwgt, NULL, adjwgt, &nparts, tpwgts, ubvec, NULL, &edgeCut, assignment);
2534         PetscStackPop;
2535         if (ierr != METIS_OK) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_LIB, "Error in METIS_PartGraphKway()");
2536       }
2537     } else {
2538       PetscStackPush("ParMETIS_V3_PartKway");
2539       ierr = ParMETIS_V3_PartKway(vtxdist, xadj, adjncy, vwgt, adjwgt, &wgtflag, &numflag, &ncon, &nparts, tpwgts, ubvec, options, &edgeCut, assignment, &comm);
2540       PetscStackPop;
2541       if (ierr != METIS_OK) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_LIB, "Error in ParMETIS_V3_PartKway()");
2542     }
2543   }
2544   /* Convert to PetscSection+IS */
2545   ierr = PetscSectionCreate(comm, partSection);CHKERRQ(ierr);
2546   ierr = PetscSectionSetChart(*partSection, 0, commSize);CHKERRQ(ierr);
2547   for (v = 0; v < nvtxs; ++v) {
2548     ierr = PetscSectionAddDof(*partSection, assignment[v], 1);CHKERRQ(ierr);
2549   }
2550   ierr = PetscSectionSetUp(*partSection);CHKERRQ(ierr);
2551   ierr = PetscMalloc(nvtxs * sizeof(PetscInt), &points);CHKERRQ(ierr);
2552   for (p = 0, i = 0; p < commSize; ++p) {
2553     for (v = 0; v < nvtxs; ++v) {
2554       if (assignment[v] == p) points[i++] = v;
2555     }
2556   }
2557   if (i != nvtxs) SETERRQ2(comm, PETSC_ERR_PLIB, "Number of points %D should be %D", i, nvtxs);
2558   ierr = ISCreateGeneral(comm, nvtxs, points, PETSC_OWN_POINTER, partition);CHKERRQ(ierr);
2559   ierr = PetscFree4(vtxdist,tpwgts,ubvec,assignment);CHKERRQ(ierr);
2560   PetscFunctionReturn(0);
2561 }
2562 #endif
2563 
2564 #undef __FUNCT__
2565 #define __FUNCT__ "DMPlexEnlargePartition"
2566 /* Expand the partition by BFS on the adjacency graph */
2567 PetscErrorCode DMPlexEnlargePartition(DM dm, const PetscInt start[], const PetscInt adjacency[], PetscSection origPartSection, IS origPartition, PetscSection *partSection, IS *partition)
2568 {
2569   PetscHashI      h;
2570   const PetscInt *points;
2571   PetscInt      **tmpPoints, *newPoints, totPoints = 0;
2572   PetscInt        pStart, pEnd, part, q;
2573   PetscErrorCode  ierr;
2574 
2575   PetscFunctionBegin;
2576   PetscHashICreate(h);
2577   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)dm), partSection);CHKERRQ(ierr);
2578   ierr = PetscSectionGetChart(origPartSection, &pStart, &pEnd);CHKERRQ(ierr);
2579   ierr = PetscSectionSetChart(*partSection, pStart, pEnd);CHKERRQ(ierr);
2580   ierr = ISGetIndices(origPartition, &points);CHKERRQ(ierr);
2581   ierr = PetscMalloc((pEnd - pStart) * sizeof(PetscInt*), &tmpPoints);CHKERRQ(ierr);
2582   for (part = pStart; part < pEnd; ++part) {
2583     PetscInt numPoints, nP, numNewPoints, off, p, n = 0;
2584 
2585     PetscHashIClear(h);
2586     ierr = PetscSectionGetDof(origPartSection, part, &numPoints);CHKERRQ(ierr);
2587     ierr = PetscSectionGetOffset(origPartSection, part, &off);CHKERRQ(ierr);
2588     /* Add all existing points to h */
2589     for (p = 0; p < numPoints; ++p) {
2590       const PetscInt point = points[off+p];
2591       PetscHashIAdd(h, point, 1);
2592     }
2593     PetscHashISize(h, nP);
2594     if (nP != numPoints) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Invalid partition has %d points, but only %d were unique", numPoints, nP);
2595     /* Add all points in next BFS level */
2596     /*   TODO We are brute forcing here, but could check the adjacency size to find the boundary */
2597     for (p = 0; p < numPoints; ++p) {
2598       const PetscInt point = points[off+p];
2599       PetscInt       s     = start[point], e = start[point+1], a;
2600 
2601       for (a = s; a < e; ++a) PetscHashIAdd(h, adjacency[a], 1);
2602     }
2603     PetscHashISize(h, numNewPoints);
2604     ierr = PetscSectionSetDof(*partSection, part, numNewPoints);CHKERRQ(ierr);
2605     ierr = PetscMalloc(numNewPoints * sizeof(PetscInt), &tmpPoints[part]);CHKERRQ(ierr);
2606     if (numNewPoints) PetscHashIGetKeys(h, n, tmpPoints[part]); /* Should not need this conditional */
2607     totPoints += numNewPoints;
2608   }
2609   ierr = ISRestoreIndices(origPartition, &points);CHKERRQ(ierr);
2610   PetscHashIDestroy(h);
2611   ierr = PetscSectionSetUp(*partSection);CHKERRQ(ierr);
2612   ierr = PetscMalloc(totPoints * sizeof(PetscInt), &newPoints);CHKERRQ(ierr);
2613   for (part = pStart, q = 0; part < pEnd; ++part) {
2614     PetscInt numPoints, p;
2615 
2616     ierr = PetscSectionGetDof(*partSection, part, &numPoints);CHKERRQ(ierr);
2617     for (p = 0; p < numPoints; ++p, ++q) newPoints[q] = tmpPoints[part][p];
2618     ierr = PetscFree(tmpPoints[part]);CHKERRQ(ierr);
2619   }
2620   ierr = PetscFree(tmpPoints);CHKERRQ(ierr);
2621   ierr = ISCreateGeneral(PetscObjectComm((PetscObject)dm), totPoints, newPoints, PETSC_OWN_POINTER, partition);CHKERRQ(ierr);
2622   PetscFunctionReturn(0);
2623 }
2624 
2625 #undef __FUNCT__
2626 #define __FUNCT__ "DMPlexCreatePartition"
2627 /*
2628   DMPlexCreatePartition - Create a non-overlapping partition of the points at the given height
2629 
2630   Collective on DM
2631 
2632   Input Parameters:
2633   + dm - The DM
2634   . height - The height for points in the partition
2635   - enlarge - Expand each partition with neighbors
2636 
2637   Output Parameters:
2638   + partSection - The PetscSection giving the division of points by partition
2639   . partition - The list of points by partition
2640   . origPartSection - If enlarge is true, the PetscSection giving the division of points before enlarging by partition, otherwise NULL
2641   - origPartition - If enlarge is true, the list of points before enlarging by partition, otherwise NULL
2642 
2643   Level: developer
2644 
2645 .seealso DMPlexDistribute()
2646 */
2647 PetscErrorCode DMPlexCreatePartition(DM dm, const char name[], PetscInt height, PetscBool enlarge, PetscSection *partSection, IS *partition, PetscSection *origPartSection, IS *origPartition)
2648 {
2649   char           partname[1024];
2650   PetscBool      isChaco = PETSC_FALSE, isMetis = PETSC_FALSE, flg;
2651   PetscMPIInt    size;
2652   PetscErrorCode ierr;
2653 
2654   PetscFunctionBegin;
2655   ierr = MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size);CHKERRQ(ierr);
2656 
2657   *origPartSection = NULL;
2658   *origPartition   = NULL;
2659   if (size == 1) {
2660     PetscInt *points;
2661     PetscInt  cStart, cEnd, c;
2662 
2663     ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
2664     ierr = PetscSectionCreate(PetscObjectComm((PetscObject)dm), partSection);CHKERRQ(ierr);
2665     ierr = PetscSectionSetChart(*partSection, 0, size);CHKERRQ(ierr);
2666     ierr = PetscSectionSetDof(*partSection, 0, cEnd-cStart);CHKERRQ(ierr);
2667     ierr = PetscSectionSetUp(*partSection);CHKERRQ(ierr);
2668     ierr = PetscMalloc((cEnd - cStart) * sizeof(PetscInt), &points);CHKERRQ(ierr);
2669     for (c = cStart; c < cEnd; ++c) points[c] = c;
2670     ierr = ISCreateGeneral(PetscObjectComm((PetscObject)dm), cEnd-cStart, points, PETSC_OWN_POINTER, partition);CHKERRQ(ierr);
2671     PetscFunctionReturn(0);
2672   }
2673   ierr = PetscOptionsGetString(((PetscObject) dm)->prefix, "-dm_plex_partitioner", partname, 1024, &flg);CHKERRQ(ierr);
2674   if (flg) name = partname;
2675   if (name) {
2676     ierr = PetscStrcmp(name, "chaco", &isChaco);CHKERRQ(ierr);
2677     ierr = PetscStrcmp(name, "metis", &isMetis);CHKERRQ(ierr);
2678   }
2679   if (height == 0) {
2680     PetscInt  numVertices;
2681     PetscInt *start     = NULL;
2682     PetscInt *adjacency = NULL;
2683 
2684     ierr = DMPlexCreateNeighborCSR(dm, 0, &numVertices, &start, &adjacency);CHKERRQ(ierr);
2685     if (!name || isChaco) {
2686 #if defined(PETSC_HAVE_CHACO)
2687       ierr = DMPlexPartition_Chaco(dm, numVertices, start, adjacency, partSection, partition);CHKERRQ(ierr);
2688 #else
2689       SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Mesh partitioning needs external package support.\nPlease reconfigure with --download-chaco.");
2690 #endif
2691     } else if (isMetis) {
2692 #if defined(PETSC_HAVE_PARMETIS)
2693       ierr = DMPlexPartition_ParMetis(dm, numVertices, start, adjacency, partSection, partition);CHKERRQ(ierr);
2694 #endif
2695     } else SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Unknown mesh partitioning package %s", name);
2696     if (enlarge) {
2697       *origPartSection = *partSection;
2698       *origPartition   = *partition;
2699 
2700       ierr = DMPlexEnlargePartition(dm, start, adjacency, *origPartSection, *origPartition, partSection, partition);CHKERRQ(ierr);
2701     }
2702     ierr = PetscFree(start);CHKERRQ(ierr);
2703     ierr = PetscFree(adjacency);CHKERRQ(ierr);
2704 # if 0
2705   } else if (height == 1) {
2706     /* Build the dual graph for faces and partition the hypergraph */
2707     PetscInt numEdges;
2708 
2709     buildFaceCSRV(mesh, mesh->getFactory()->getNumbering(mesh, mesh->depth()-1), &numEdges, &start, &adjacency, GraphPartitioner::zeroBase());
2710     GraphPartitioner().partition(numEdges, start, adjacency, partition, manager);
2711     destroyCSR(numEdges, start, adjacency);
2712 #endif
2713   } else SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid partition height %D", height);
2714   PetscFunctionReturn(0);
2715 }
2716 
2717 #undef __FUNCT__
2718 #define __FUNCT__ "DMPlexCreatePartitionClosure"
2719 PetscErrorCode DMPlexCreatePartitionClosure(DM dm, PetscSection pointSection, IS pointPartition, PetscSection *section, IS *partition)
2720 {
2721   /* const PetscInt  height = 0; */
2722   const PetscInt *partArray;
2723   PetscInt       *allPoints, *packPoints;
2724   PetscInt        rStart, rEnd, rank, pStart, pEnd, newSize;
2725   PetscErrorCode  ierr;
2726   PetscBT         bt;
2727   PetscSegBuffer  segpack,segpart;
2728 
2729   PetscFunctionBegin;
2730   ierr = PetscSectionGetChart(pointSection, &rStart, &rEnd);CHKERRQ(ierr);
2731   ierr = ISGetIndices(pointPartition, &partArray);CHKERRQ(ierr);
2732   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)dm), section);CHKERRQ(ierr);
2733   ierr = PetscSectionSetChart(*section, rStart, rEnd);CHKERRQ(ierr);
2734   ierr = DMPlexGetChart(dm,&pStart,&pEnd);CHKERRQ(ierr);
2735   ierr = PetscBTCreate(pEnd-pStart,&bt);CHKERRQ(ierr);
2736   ierr = PetscSegBufferCreate(sizeof(PetscInt),1000,&segpack);CHKERRQ(ierr);
2737   ierr = PetscSegBufferCreate(sizeof(PetscInt),1000,&segpart);CHKERRQ(ierr);
2738   for (rank = rStart; rank < rEnd; ++rank) {
2739     PetscInt partSize = 0, numPoints, offset, p, *PETSC_RESTRICT placePoints;
2740 
2741     ierr = PetscSectionGetDof(pointSection, rank, &numPoints);CHKERRQ(ierr);
2742     ierr = PetscSectionGetOffset(pointSection, rank, &offset);CHKERRQ(ierr);
2743     for (p = 0; p < numPoints; ++p) {
2744       PetscInt  point   = partArray[offset+p], closureSize, c;
2745       PetscInt *closure = NULL;
2746 
2747       /* TODO Include support for height > 0 case */
2748       ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
2749       for (c=0; c<closureSize; c++) {
2750         PetscInt cpoint = closure[c*2];
2751         if (!PetscBTLookupSet(bt,cpoint-pStart)) {
2752           PetscInt *PETSC_RESTRICT pt;
2753           partSize++;
2754           ierr = PetscSegBufferGetInts(segpart,1,&pt);CHKERRQ(ierr);
2755           *pt = cpoint;
2756         }
2757       }
2758       ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
2759     }
2760     ierr = PetscSectionSetDof(*section, rank, partSize);CHKERRQ(ierr);
2761     ierr = PetscSegBufferGetInts(segpack,partSize,&placePoints);CHKERRQ(ierr);
2762     ierr = PetscSegBufferExtractTo(segpart,placePoints);CHKERRQ(ierr);
2763     ierr = PetscSortInt(partSize,placePoints);CHKERRQ(ierr);
2764     for (p=0; p<partSize; p++) {ierr = PetscBTClear(bt,placePoints[p]-pStart);CHKERRQ(ierr);}
2765   }
2766   ierr = PetscBTDestroy(&bt);CHKERRQ(ierr);
2767   ierr = PetscSegBufferDestroy(&segpart);CHKERRQ(ierr);
2768 
2769   ierr = PetscSectionSetUp(*section);CHKERRQ(ierr);
2770   ierr = PetscSectionGetStorageSize(*section, &newSize);CHKERRQ(ierr);
2771   ierr = PetscMalloc(newSize * sizeof(PetscInt), &allPoints);CHKERRQ(ierr);
2772 
2773   ierr = PetscSegBufferExtractInPlace(segpack,&packPoints);CHKERRQ(ierr);
2774   for (rank = rStart; rank < rEnd; ++rank) {
2775     PetscInt numPoints, offset;
2776 
2777     ierr = PetscSectionGetDof(*section, rank, &numPoints);CHKERRQ(ierr);
2778     ierr = PetscSectionGetOffset(*section, rank, &offset);CHKERRQ(ierr);
2779     ierr = PetscMemcpy(&allPoints[offset], packPoints, numPoints * sizeof(PetscInt));CHKERRQ(ierr);
2780     packPoints += numPoints;
2781   }
2782 
2783   ierr = PetscSegBufferDestroy(&segpack);CHKERRQ(ierr);
2784   ierr = ISRestoreIndices(pointPartition, &partArray);CHKERRQ(ierr);
2785   ierr = ISCreateGeneral(PetscObjectComm((PetscObject)dm), newSize, allPoints, PETSC_OWN_POINTER, partition);CHKERRQ(ierr);
2786   PetscFunctionReturn(0);
2787 }
2788 
2789 #undef __FUNCT__
2790 #define __FUNCT__ "DMPlexDistributeField"
2791 /*
2792   Input Parameters:
2793 . originalSection
2794 , originalVec
2795 
2796   Output Parameters:
2797 . newSection
2798 . newVec
2799 */
2800 PetscErrorCode DMPlexDistributeField(DM dm, PetscSF pointSF, PetscSection originalSection, Vec originalVec, PetscSection newSection, Vec newVec)
2801 {
2802   PetscSF        fieldSF;
2803   PetscInt      *remoteOffsets, fieldSize;
2804   PetscScalar   *originalValues, *newValues;
2805   PetscErrorCode ierr;
2806 
2807   PetscFunctionBegin;
2808   ierr = PetscSFDistributeSection(pointSF, originalSection, &remoteOffsets, newSection);CHKERRQ(ierr);
2809 
2810   ierr = PetscSectionGetStorageSize(newSection, &fieldSize);CHKERRQ(ierr);
2811   ierr = VecSetSizes(newVec, fieldSize, PETSC_DETERMINE);CHKERRQ(ierr);
2812   ierr = VecSetFromOptions(newVec);CHKERRQ(ierr);
2813 
2814   ierr = VecGetArray(originalVec, &originalValues);CHKERRQ(ierr);
2815   ierr = VecGetArray(newVec, &newValues);CHKERRQ(ierr);
2816   ierr = PetscSFCreateSectionSF(pointSF, originalSection, remoteOffsets, newSection, &fieldSF);CHKERRQ(ierr);
2817   ierr = PetscSFBcastBegin(fieldSF, MPIU_SCALAR, originalValues, newValues);CHKERRQ(ierr);
2818   ierr = PetscSFBcastEnd(fieldSF, MPIU_SCALAR, originalValues, newValues);CHKERRQ(ierr);
2819   ierr = PetscSFDestroy(&fieldSF);CHKERRQ(ierr);
2820   ierr = VecRestoreArray(newVec, &newValues);CHKERRQ(ierr);
2821   ierr = VecRestoreArray(originalVec, &originalValues);CHKERRQ(ierr);
2822   PetscFunctionReturn(0);
2823 }
2824 
2825 #undef __FUNCT__
2826 #define __FUNCT__ "DMPlexDistribute"
2827 /*@C
2828   DMPlexDistribute - Distributes the mesh and any associated sections.
2829 
2830   Not Collective
2831 
2832   Input Parameter:
2833 + dm  - The original DMPlex object
2834 . partitioner - The partitioning package, or NULL for the default
2835 - overlap - The overlap of partitions, 0 is the default
2836 
2837   Output Parameter:
2838 . parallelMesh - The distributed DMPlex object, or NULL
2839 
2840   Note: If the mesh was not distributed, the return value is NULL
2841 
2842   Level: intermediate
2843 
2844 .keywords: mesh, elements
2845 .seealso: DMPlexCreate(), DMPlexDistributeByFace()
2846 @*/
2847 PetscErrorCode DMPlexDistribute(DM dm, const char partitioner[], PetscInt overlap, DM *dmParallel)
2848 {
2849   DM_Plex               *mesh   = (DM_Plex*) dm->data, *pmesh;
2850   MPI_Comm               comm;
2851   const PetscInt         height = 0;
2852   PetscInt               dim, numRemoteRanks;
2853   IS                     origCellPart,        cellPart,        part;
2854   PetscSection           origCellPartSection, cellPartSection, partSection;
2855   PetscSFNode           *remoteRanks;
2856   PetscSF                partSF, pointSF, coneSF;
2857   ISLocalToGlobalMapping renumbering;
2858   PetscSection           originalConeSection, newConeSection;
2859   PetscInt              *remoteOffsets;
2860   PetscInt              *cones, *newCones, newConesSize;
2861   PetscBool              flg;
2862   PetscMPIInt            rank, numProcs, p;
2863   PetscErrorCode         ierr;
2864 
2865   PetscFunctionBegin;
2866   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2867   PetscValidPointer(dmParallel,4);
2868 
2869   ierr = PetscLogEventBegin(DMPLEX_Distribute,dm,0,0,0);CHKERRQ(ierr);
2870   ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr);
2871   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
2872   ierr = MPI_Comm_size(comm, &numProcs);CHKERRQ(ierr);
2873 
2874   *dmParallel = NULL;
2875   if (numProcs == 1) PetscFunctionReturn(0);
2876 
2877   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
2878   /* Create cell partition - We need to rewrite to use IS, use the MatPartition stuff */
2879   ierr = PetscLogEventBegin(DMPLEX_Partition,dm,0,0,0);CHKERRQ(ierr);
2880   if (overlap > 1) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Overlap > 1 not yet implemented");
2881   ierr = DMPlexCreatePartition(dm, partitioner, height, overlap > 0 ? PETSC_TRUE : PETSC_FALSE, &cellPartSection, &cellPart, &origCellPartSection, &origCellPart);CHKERRQ(ierr);
2882   /* Create SF assuming a serial partition for all processes: Could check for IS length here */
2883   if (!rank) numRemoteRanks = numProcs;
2884   else       numRemoteRanks = 0;
2885   ierr = PetscMalloc(numRemoteRanks * sizeof(PetscSFNode), &remoteRanks);CHKERRQ(ierr);
2886   for (p = 0; p < numRemoteRanks; ++p) {
2887     remoteRanks[p].rank  = p;
2888     remoteRanks[p].index = 0;
2889   }
2890   ierr = PetscSFCreate(comm, &partSF);CHKERRQ(ierr);
2891   ierr = PetscSFSetGraph(partSF, 1, numRemoteRanks, NULL, PETSC_OWN_POINTER, remoteRanks, PETSC_OWN_POINTER);CHKERRQ(ierr);
2892   ierr = PetscOptionsHasName(((PetscObject) dm)->prefix, "-partition_view", &flg);CHKERRQ(ierr);
2893   if (flg) {
2894     ierr = PetscPrintf(comm, "Cell Partition:\n");CHKERRQ(ierr);
2895     ierr = PetscSectionView(cellPartSection, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
2896     ierr = ISView(cellPart, NULL);CHKERRQ(ierr);
2897     if (origCellPart) {
2898       ierr = PetscPrintf(comm, "Original Cell Partition:\n");CHKERRQ(ierr);
2899       ierr = PetscSectionView(origCellPartSection, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
2900       ierr = ISView(origCellPart, NULL);CHKERRQ(ierr);
2901     }
2902     ierr = PetscSFView(partSF, NULL);CHKERRQ(ierr);
2903   }
2904   /* Close the partition over the mesh */
2905   ierr = DMPlexCreatePartitionClosure(dm, cellPartSection, cellPart, &partSection, &part);CHKERRQ(ierr);
2906   ierr = ISDestroy(&cellPart);CHKERRQ(ierr);
2907   ierr = PetscSectionDestroy(&cellPartSection);CHKERRQ(ierr);
2908   /* Create new mesh */
2909   ierr  = DMPlexCreate(comm, dmParallel);CHKERRQ(ierr);
2910   ierr  = DMPlexSetDimension(*dmParallel, dim);CHKERRQ(ierr);
2911   ierr  = PetscObjectSetName((PetscObject) *dmParallel, "Parallel Mesh");CHKERRQ(ierr);
2912   pmesh = (DM_Plex*) (*dmParallel)->data;
2913   /* Distribute sieve points and the global point numbering (replaces creating remote bases) */
2914   ierr = PetscSFConvertPartition(partSF, partSection, part, &renumbering, &pointSF);CHKERRQ(ierr);
2915   if (flg) {
2916     ierr = PetscPrintf(comm, "Point Partition:\n");CHKERRQ(ierr);
2917     ierr = PetscSectionView(partSection, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
2918     ierr = ISView(part, NULL);CHKERRQ(ierr);
2919     ierr = PetscSFView(pointSF, NULL);CHKERRQ(ierr);
2920     ierr = PetscPrintf(comm, "Point Renumbering after partition:\n");CHKERRQ(ierr);
2921     ierr = ISLocalToGlobalMappingView(renumbering, NULL);CHKERRQ(ierr);
2922   }
2923   ierr = PetscLogEventEnd(DMPLEX_Partition,dm,0,0,0);CHKERRQ(ierr);
2924   /* Distribute cone section */
2925   ierr = DMPlexGetConeSection(dm, &originalConeSection);CHKERRQ(ierr);
2926   ierr = DMPlexGetConeSection(*dmParallel, &newConeSection);CHKERRQ(ierr);
2927   ierr = PetscSFDistributeSection(pointSF, originalConeSection, &remoteOffsets, newConeSection);CHKERRQ(ierr);
2928   ierr = DMSetUp(*dmParallel);CHKERRQ(ierr);
2929   {
2930     PetscInt pStart, pEnd, p;
2931 
2932     ierr = PetscSectionGetChart(newConeSection, &pStart, &pEnd);CHKERRQ(ierr);
2933     for (p = pStart; p < pEnd; ++p) {
2934       PetscInt coneSize;
2935       ierr               = PetscSectionGetDof(newConeSection, p, &coneSize);CHKERRQ(ierr);
2936       pmesh->maxConeSize = PetscMax(pmesh->maxConeSize, coneSize);
2937     }
2938   }
2939   /* Communicate and renumber cones */
2940   ierr = PetscSFCreateSectionSF(pointSF, originalConeSection, remoteOffsets, newConeSection, &coneSF);CHKERRQ(ierr);
2941   ierr = DMPlexGetCones(dm, &cones);CHKERRQ(ierr);
2942   ierr = DMPlexGetCones(*dmParallel, &newCones);CHKERRQ(ierr);
2943   ierr = PetscSFBcastBegin(coneSF, MPIU_INT, cones, newCones);CHKERRQ(ierr);
2944   ierr = PetscSFBcastEnd(coneSF, MPIU_INT, cones, newCones);CHKERRQ(ierr);
2945   ierr = PetscSectionGetStorageSize(newConeSection, &newConesSize);CHKERRQ(ierr);
2946   ierr = ISGlobalToLocalMappingApply(renumbering, IS_GTOLM_MASK, newConesSize, newCones, NULL, newCones);CHKERRQ(ierr);
2947   ierr = PetscOptionsHasName(((PetscObject) dm)->prefix, "-cones_view", &flg);CHKERRQ(ierr);
2948   if (flg) {
2949     ierr = PetscPrintf(comm, "Serial Cone Section:\n");CHKERRQ(ierr);
2950     ierr = PetscSectionView(originalConeSection, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
2951     ierr = PetscPrintf(comm, "Parallel Cone Section:\n");CHKERRQ(ierr);
2952     ierr = PetscSectionView(newConeSection, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
2953     ierr = PetscSFView(coneSF, NULL);CHKERRQ(ierr);
2954   }
2955   ierr = DMPlexGetConeOrientations(dm, &cones);CHKERRQ(ierr);
2956   ierr = DMPlexGetConeOrientations(*dmParallel, &newCones);CHKERRQ(ierr);
2957   ierr = PetscSFBcastBegin(coneSF, MPIU_INT, cones, newCones);CHKERRQ(ierr);
2958   ierr = PetscSFBcastEnd(coneSF, MPIU_INT, cones, newCones);CHKERRQ(ierr);
2959   ierr = PetscSFDestroy(&coneSF);CHKERRQ(ierr);
2960   /* Create supports and stratify sieve */
2961   {
2962     PetscInt pStart, pEnd;
2963 
2964     ierr = PetscSectionGetChart(pmesh->coneSection, &pStart, &pEnd);CHKERRQ(ierr);
2965     ierr = PetscSectionSetChart(pmesh->supportSection, pStart, pEnd);CHKERRQ(ierr);
2966   }
2967   ierr = DMPlexSymmetrize(*dmParallel);CHKERRQ(ierr);
2968   ierr = DMPlexStratify(*dmParallel);CHKERRQ(ierr);
2969   /* Distribute Coordinates */
2970   {
2971     PetscSection originalCoordSection, newCoordSection;
2972     Vec          originalCoordinates, newCoordinates;
2973     const char  *name;
2974 
2975     ierr = DMPlexGetCoordinateSection(dm, &originalCoordSection);CHKERRQ(ierr);
2976     ierr = DMPlexGetCoordinateSection(*dmParallel, &newCoordSection);CHKERRQ(ierr);
2977     ierr = DMGetCoordinatesLocal(dm, &originalCoordinates);CHKERRQ(ierr);
2978     ierr = VecCreate(comm, &newCoordinates);CHKERRQ(ierr);
2979     ierr = PetscObjectGetName((PetscObject) originalCoordinates, &name);CHKERRQ(ierr);
2980     ierr = PetscObjectSetName((PetscObject) newCoordinates, name);CHKERRQ(ierr);
2981 
2982     ierr = DMPlexDistributeField(dm, pointSF, originalCoordSection, originalCoordinates, newCoordSection, newCoordinates);CHKERRQ(ierr);
2983     ierr = DMSetCoordinatesLocal(*dmParallel, newCoordinates);CHKERRQ(ierr);
2984     ierr = VecDestroy(&newCoordinates);CHKERRQ(ierr);
2985   }
2986   /* Distribute labels */
2987   ierr = PetscLogEventBegin(DMPLEX_DistributeLabels,dm,0,0,0);CHKERRQ(ierr);
2988   {
2989     DMLabel  next      = mesh->labels, newNext = pmesh->labels;
2990     PetscInt numLabels = 0, l;
2991 
2992     /* Bcast number of labels */
2993     while (next) {
2994       ++numLabels; next = next->next;
2995     }
2996     ierr = MPI_Bcast(&numLabels, 1, MPIU_INT, 0, comm);CHKERRQ(ierr);
2997     next = mesh->labels;
2998     for (l = 0; l < numLabels; ++l) {
2999       DMLabel         newLabel;
3000       const PetscInt *partArray;
3001       char           *name;
3002       PetscInt       *stratumSizes = NULL, *points = NULL;
3003       PetscMPIInt    *sendcnts     = NULL, *offsets = NULL, *displs = NULL;
3004       PetscInt        nameSize, s, p;
3005       PetscBool       isdepth;
3006       size_t          len = 0;
3007 
3008       /* Bcast name (could filter for no points) */
3009       if (!rank) {ierr = PetscStrlen(next->name, &len);CHKERRQ(ierr);}
3010       nameSize = len;
3011       ierr     = MPI_Bcast(&nameSize, 1, MPIU_INT, 0, comm);CHKERRQ(ierr);
3012       ierr     = PetscMalloc(nameSize+1, &name);CHKERRQ(ierr);
3013       if (!rank) {ierr = PetscMemcpy(name, next->name, nameSize+1);CHKERRQ(ierr);}
3014       ierr = MPI_Bcast(name, nameSize+1, MPI_CHAR, 0, comm);CHKERRQ(ierr);
3015       ierr = PetscStrcmp(name, "depth", &isdepth);CHKERRQ(ierr);
3016       if (isdepth) {            /* skip because "depth" is not distributed */
3017         ierr = PetscFree(name);CHKERRQ(ierr);
3018         if (!rank) next = next->next;
3019         continue;
3020       }
3021       ierr           = PetscNew(struct _n_DMLabel, &newLabel);CHKERRQ(ierr);
3022       newLabel->name = name;
3023       /* Bcast numStrata (could filter for no points in stratum) */
3024       if (!rank) newLabel->numStrata = next->numStrata;
3025       ierr = MPI_Bcast(&newLabel->numStrata, 1, MPIU_INT, 0, comm);CHKERRQ(ierr);
3026       ierr = PetscMalloc3(newLabel->numStrata,PetscInt,&newLabel->stratumValues,
3027                           newLabel->numStrata,PetscInt,&newLabel->stratumSizes,
3028                           newLabel->numStrata+1,PetscInt,&newLabel->stratumOffsets);CHKERRQ(ierr);
3029       /* Bcast stratumValues (could filter for no points in stratum) */
3030       if (!rank) {ierr = PetscMemcpy(newLabel->stratumValues, next->stratumValues, next->numStrata * sizeof(PetscInt));CHKERRQ(ierr);}
3031       ierr = MPI_Bcast(newLabel->stratumValues, newLabel->numStrata, MPIU_INT, 0, comm);CHKERRQ(ierr);
3032       /* Find size on each process and Scatter */
3033       if (!rank) {
3034         ierr = ISGetIndices(part, &partArray);CHKERRQ(ierr);
3035         ierr = PetscMalloc(numProcs*next->numStrata * sizeof(PetscInt), &stratumSizes);CHKERRQ(ierr);
3036         ierr = PetscMemzero(stratumSizes, numProcs*next->numStrata * sizeof(PetscInt));CHKERRQ(ierr);
3037         for (s = 0; s < next->numStrata; ++s) {
3038           for (p = next->stratumOffsets[s]; p < next->stratumOffsets[s]+next->stratumSizes[s]; ++p) {
3039             const PetscInt point = next->points[p];
3040             PetscInt       proc;
3041 
3042             for (proc = 0; proc < numProcs; ++proc) {
3043               PetscInt dof, off, pPart;
3044 
3045               ierr = PetscSectionGetDof(partSection, proc, &dof);CHKERRQ(ierr);
3046               ierr = PetscSectionGetOffset(partSection, proc, &off);CHKERRQ(ierr);
3047               for (pPart = off; pPart < off+dof; ++pPart) {
3048                 if (partArray[pPart] == point) {
3049                   ++stratumSizes[proc*next->numStrata+s];
3050                   break;
3051                 }
3052               }
3053             }
3054           }
3055         }
3056         ierr = ISRestoreIndices(part, &partArray);CHKERRQ(ierr);
3057       }
3058       ierr = MPI_Scatter(stratumSizes, newLabel->numStrata, MPIU_INT, newLabel->stratumSizes, newLabel->numStrata, MPIU_INT, 0, comm);CHKERRQ(ierr);
3059       /* Calculate stratumOffsets */
3060       newLabel->stratumOffsets[0] = 0;
3061       for (s = 0; s < newLabel->numStrata; ++s) {
3062         newLabel->stratumOffsets[s+1] = newLabel->stratumSizes[s] + newLabel->stratumOffsets[s];
3063       }
3064       /* Pack points and Scatter */
3065       if (!rank) {
3066         ierr = PetscMalloc3(numProcs,PetscMPIInt,&sendcnts,numProcs,PetscMPIInt,&offsets,numProcs+1,PetscMPIInt,&displs);CHKERRQ(ierr);
3067         displs[0] = 0;
3068         for (p = 0; p < numProcs; ++p) {
3069           sendcnts[p] = 0;
3070           for (s = 0; s < next->numStrata; ++s) {
3071             sendcnts[p] += stratumSizes[p*next->numStrata+s];
3072           }
3073           offsets[p]  = displs[p];
3074           displs[p+1] = displs[p] + sendcnts[p];
3075         }
3076         ierr = PetscMalloc(displs[numProcs] * sizeof(PetscInt), &points);CHKERRQ(ierr);
3077         for (s = 0; s < next->numStrata; ++s) {
3078           for (p = next->stratumOffsets[s]; p < next->stratumOffsets[s]+next->stratumSizes[s]; ++p) {
3079             const PetscInt point = next->points[p];
3080             PetscInt       proc;
3081 
3082             for (proc = 0; proc < numProcs; ++proc) {
3083               PetscInt dof, off, pPart;
3084 
3085               ierr = PetscSectionGetDof(partSection, proc, &dof);CHKERRQ(ierr);
3086               ierr = PetscSectionGetOffset(partSection, proc, &off);CHKERRQ(ierr);
3087               for (pPart = off; pPart < off+dof; ++pPart) {
3088                 if (partArray[pPart] == point) {
3089                   points[offsets[proc]++] = point;
3090                   break;
3091                 }
3092               }
3093             }
3094           }
3095         }
3096       }
3097       ierr = PetscMalloc(newLabel->stratumOffsets[newLabel->numStrata] * sizeof(PetscInt), &newLabel->points);CHKERRQ(ierr);
3098       ierr = MPI_Scatterv(points, sendcnts, displs, MPIU_INT, newLabel->points, newLabel->stratumOffsets[newLabel->numStrata], MPIU_INT, 0, comm);CHKERRQ(ierr);
3099       ierr = PetscFree(points);CHKERRQ(ierr);
3100       ierr = PetscFree3(sendcnts,offsets,displs);CHKERRQ(ierr);
3101       ierr = PetscFree(stratumSizes);CHKERRQ(ierr);
3102       /* Renumber points */
3103       ierr = ISGlobalToLocalMappingApply(renumbering, IS_GTOLM_MASK, newLabel->stratumOffsets[newLabel->numStrata], newLabel->points, NULL, newLabel->points);CHKERRQ(ierr);
3104       /* Sort points */
3105       for (s = 0; s < newLabel->numStrata; ++s) {
3106         ierr = PetscSortInt(newLabel->stratumSizes[s], &newLabel->points[newLabel->stratumOffsets[s]]);CHKERRQ(ierr);
3107       }
3108       /* Insert into list */
3109       if (newNext) newNext->next = newLabel;
3110       else pmesh->labels = newLabel;
3111       newNext = newLabel;
3112       if (!rank) next = next->next;
3113     }
3114   }
3115   ierr = PetscLogEventEnd(DMPLEX_DistributeLabels,dm,0,0,0);CHKERRQ(ierr);
3116   /* Cleanup Partition */
3117   ierr = ISLocalToGlobalMappingDestroy(&renumbering);CHKERRQ(ierr);
3118   ierr = PetscSFDestroy(&partSF);CHKERRQ(ierr);
3119   ierr = PetscSectionDestroy(&partSection);CHKERRQ(ierr);
3120   ierr = ISDestroy(&part);CHKERRQ(ierr);
3121   /* Create point SF for parallel mesh */
3122   ierr = PetscLogEventBegin(DMPLEX_DistributeSF,dm,0,0,0);CHKERRQ(ierr);
3123   {
3124     const PetscInt *leaves;
3125     PetscSFNode    *remotePoints, *rowners, *lowners;
3126     PetscInt        numRoots, numLeaves, numGhostPoints = 0, p, gp, *ghostPoints;
3127     PetscInt        pStart, pEnd;
3128 
3129     ierr = DMPlexGetChart(*dmParallel, &pStart, &pEnd);CHKERRQ(ierr);
3130     ierr = PetscSFGetGraph(pointSF, &numRoots, &numLeaves, &leaves, NULL);CHKERRQ(ierr);
3131     ierr = PetscMalloc2(numRoots,PetscSFNode,&rowners,numLeaves,PetscSFNode,&lowners);CHKERRQ(ierr);
3132     for (p=0; p<numRoots; p++) {
3133       rowners[p].rank  = -1;
3134       rowners[p].index = -1;
3135     }
3136     if (origCellPart) {
3137       /* Make sure cells in the original partition are not assigned to other procs */
3138       const PetscInt *origCells;
3139 
3140       ierr = ISGetIndices(origCellPart, &origCells);CHKERRQ(ierr);
3141       for (p = 0; p < numProcs; ++p) {
3142         PetscInt dof, off, d;
3143 
3144         ierr = PetscSectionGetDof(origCellPartSection, p, &dof);CHKERRQ(ierr);
3145         ierr = PetscSectionGetOffset(origCellPartSection, p, &off);CHKERRQ(ierr);
3146         for (d = off; d < off+dof; ++d) {
3147           rowners[origCells[d]].rank = p;
3148         }
3149       }
3150       ierr = ISRestoreIndices(origCellPart, &origCells);CHKERRQ(ierr);
3151     }
3152     ierr = ISDestroy(&origCellPart);CHKERRQ(ierr);
3153     ierr = PetscSectionDestroy(&origCellPartSection);CHKERRQ(ierr);
3154 
3155     ierr = PetscSFBcastBegin(pointSF, MPIU_2INT, rowners, lowners);CHKERRQ(ierr);
3156     ierr = PetscSFBcastEnd(pointSF, MPIU_2INT, rowners, lowners);CHKERRQ(ierr);
3157     for (p = 0; p < numLeaves; ++p) {
3158       if (lowners[p].rank < 0 || lowners[p].rank == rank) { /* Either put in a bid or we know we own it */
3159         lowners[p].rank  = rank;
3160         lowners[p].index = leaves ? leaves[p] : p;
3161       } else if (lowners[p].rank >= 0) { /* Point already claimed so flag so that MAXLOC does not listen to us */
3162         lowners[p].rank  = -2;
3163         lowners[p].index = -2;
3164       }
3165     }
3166     for (p=0; p<numRoots; p++) { /* Root must not participate in the rediction, flag so that MAXLOC does not use */
3167       rowners[p].rank  = -3;
3168       rowners[p].index = -3;
3169     }
3170     ierr = PetscSFReduceBegin(pointSF, MPIU_2INT, lowners, rowners, MPI_MAXLOC);CHKERRQ(ierr);
3171     ierr = PetscSFReduceEnd(pointSF, MPIU_2INT, lowners, rowners, MPI_MAXLOC);CHKERRQ(ierr);
3172     ierr = PetscSFBcastBegin(pointSF, MPIU_2INT, rowners, lowners);CHKERRQ(ierr);
3173     ierr = PetscSFBcastEnd(pointSF, MPIU_2INT, rowners, lowners);CHKERRQ(ierr);
3174     for (p = 0; p < numLeaves; ++p) {
3175       if (lowners[p].rank < 0 || lowners[p].index < 0) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Cell partition corrupt: point not claimed");
3176       if (lowners[p].rank != rank) ++numGhostPoints;
3177     }
3178     ierr = PetscMalloc(numGhostPoints * sizeof(PetscInt),    &ghostPoints);CHKERRQ(ierr);
3179     ierr = PetscMalloc(numGhostPoints * sizeof(PetscSFNode), &remotePoints);CHKERRQ(ierr);
3180     for (p = 0, gp = 0; p < numLeaves; ++p) {
3181       if (lowners[p].rank != rank) {
3182         ghostPoints[gp]        = leaves ? leaves[p] : p;
3183         remotePoints[gp].rank  = lowners[p].rank;
3184         remotePoints[gp].index = lowners[p].index;
3185         ++gp;
3186       }
3187     }
3188     ierr = PetscFree2(rowners,lowners);CHKERRQ(ierr);
3189     ierr = PetscSFSetGraph((*dmParallel)->sf, pEnd - pStart, numGhostPoints, ghostPoints, PETSC_OWN_POINTER, remotePoints, PETSC_OWN_POINTER);CHKERRQ(ierr);
3190     ierr = PetscSFSetFromOptions((*dmParallel)->sf);CHKERRQ(ierr);
3191   }
3192   ierr = PetscLogEventEnd(DMPLEX_DistributeSF,dm,0,0,0);CHKERRQ(ierr);
3193   /* Cleanup */
3194   ierr = PetscSFDestroy(&pointSF);CHKERRQ(ierr);
3195   ierr = DMSetFromOptions(*dmParallel);CHKERRQ(ierr);
3196   ierr = PetscLogEventEnd(DMPLEX_Distribute,dm,0,0,0);CHKERRQ(ierr);
3197   PetscFunctionReturn(0);
3198 }
3199 
3200 #undef __FUNCT__
3201 #define __FUNCT__ "DMPlexInvertCell"
3202 /*@C
3203   DMPlexInvertCell - This flips tetrahedron and hexahedron orientation since Plex stores them internally with outward normals. Other cells are left untouched.
3204 
3205   Input Parameters:
3206 + numCorners - The number of vertices in a cell
3207 - cone - The incoming cone
3208 
3209   Output Parameter:
3210 . cone - The inverted cone (in-place)
3211 
3212   Level: developer
3213 
3214 .seealso: DMPlexGenerate()
3215 @*/
3216 PetscErrorCode DMPlexInvertCell(PetscInt dim, PetscInt numCorners, int cone[])
3217 {
3218   int tmpc;
3219 
3220   PetscFunctionBegin;
3221   if (dim != 3) PetscFunctionReturn(0);
3222   switch (numCorners) {
3223   case 4:
3224     tmpc    = cone[0];
3225     cone[0] = cone[1];
3226     cone[1] = tmpc;
3227     break;
3228   case 8:
3229     tmpc    = cone[1];
3230     cone[1] = cone[3];
3231     cone[3] = tmpc;
3232     break;
3233   default: break;
3234   }
3235   PetscFunctionReturn(0);
3236 }
3237 
3238 #undef __FUNCT__
3239 #define __FUNCT__ "DMPlexInvertCells_Internal"
3240 /* This is to fix the tetrahedron orientation from TetGen */
3241 PETSC_UNUSED static PetscErrorCode DMPlexInvertCells_Internal(PetscInt dim, PetscInt numCells, PetscInt numCorners, int cells[])
3242 {
3243   PetscInt       bound = numCells*numCorners, coff;
3244   PetscErrorCode ierr;
3245 
3246   PetscFunctionBegin;
3247   for (coff = 0; coff < bound; coff += numCorners) {
3248     ierr = DMPlexInvertCell(dim, numCorners, &cells[coff]);CHKERRQ(ierr);
3249   }
3250   PetscFunctionReturn(0);
3251 }
3252 
3253 #if defined(PETSC_HAVE_TRIANGLE)
3254 #include <triangle.h>
3255 
3256 #undef __FUNCT__
3257 #define __FUNCT__ "InitInput_Triangle"
3258 PetscErrorCode InitInput_Triangle(struct triangulateio *inputCtx)
3259 {
3260   PetscFunctionBegin;
3261   inputCtx->numberofpoints             = 0;
3262   inputCtx->numberofpointattributes    = 0;
3263   inputCtx->pointlist                  = NULL;
3264   inputCtx->pointattributelist         = NULL;
3265   inputCtx->pointmarkerlist            = NULL;
3266   inputCtx->numberofsegments           = 0;
3267   inputCtx->segmentlist                = NULL;
3268   inputCtx->segmentmarkerlist          = NULL;
3269   inputCtx->numberoftriangleattributes = 0;
3270   inputCtx->trianglelist               = NULL;
3271   inputCtx->numberofholes              = 0;
3272   inputCtx->holelist                   = NULL;
3273   inputCtx->numberofregions            = 0;
3274   inputCtx->regionlist                 = NULL;
3275   PetscFunctionReturn(0);
3276 }
3277 
3278 #undef __FUNCT__
3279 #define __FUNCT__ "InitOutput_Triangle"
3280 PetscErrorCode InitOutput_Triangle(struct triangulateio *outputCtx)
3281 {
3282   PetscFunctionBegin;
3283   outputCtx->numberofpoints        = 0;
3284   outputCtx->pointlist             = NULL;
3285   outputCtx->pointattributelist    = NULL;
3286   outputCtx->pointmarkerlist       = NULL;
3287   outputCtx->numberoftriangles     = 0;
3288   outputCtx->trianglelist          = NULL;
3289   outputCtx->triangleattributelist = NULL;
3290   outputCtx->neighborlist          = NULL;
3291   outputCtx->segmentlist           = NULL;
3292   outputCtx->segmentmarkerlist     = NULL;
3293   outputCtx->numberofedges         = 0;
3294   outputCtx->edgelist              = NULL;
3295   outputCtx->edgemarkerlist        = NULL;
3296   PetscFunctionReturn(0);
3297 }
3298 
3299 #undef __FUNCT__
3300 #define __FUNCT__ "FiniOutput_Triangle"
3301 PetscErrorCode FiniOutput_Triangle(struct triangulateio *outputCtx)
3302 {
3303   PetscFunctionBegin;
3304   free(outputCtx->pointmarkerlist);
3305   free(outputCtx->edgelist);
3306   free(outputCtx->edgemarkerlist);
3307   free(outputCtx->trianglelist);
3308   free(outputCtx->neighborlist);
3309   PetscFunctionReturn(0);
3310 }
3311 
3312 #undef __FUNCT__
3313 #define __FUNCT__ "DMPlexGenerate_Triangle"
3314 PetscErrorCode DMPlexGenerate_Triangle(DM boundary, PetscBool interpolate, DM *dm)
3315 {
3316   MPI_Comm             comm;
3317   PetscInt             dim              = 2;
3318   const PetscBool      createConvexHull = PETSC_FALSE;
3319   const PetscBool      constrained      = PETSC_FALSE;
3320   struct triangulateio in;
3321   struct triangulateio out;
3322   PetscInt             vStart, vEnd, v, eStart, eEnd, e;
3323   PetscMPIInt          rank;
3324   PetscErrorCode       ierr;
3325 
3326   PetscFunctionBegin;
3327   ierr = PetscObjectGetComm((PetscObject)boundary,&comm);CHKERRQ(ierr);
3328   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
3329   ierr = InitInput_Triangle(&in);CHKERRQ(ierr);
3330   ierr = InitOutput_Triangle(&out);CHKERRQ(ierr);
3331   ierr = DMPlexGetDepthStratum(boundary, 0, &vStart, &vEnd);CHKERRQ(ierr);
3332 
3333   in.numberofpoints = vEnd - vStart;
3334   if (in.numberofpoints > 0) {
3335     PetscSection coordSection;
3336     Vec          coordinates;
3337     PetscScalar *array;
3338 
3339     ierr = PetscMalloc(in.numberofpoints*dim * sizeof(double), &in.pointlist);CHKERRQ(ierr);
3340     ierr = PetscMalloc(in.numberofpoints * sizeof(int), &in.pointmarkerlist);CHKERRQ(ierr);
3341     ierr = DMGetCoordinatesLocal(boundary, &coordinates);CHKERRQ(ierr);
3342     ierr = DMPlexGetCoordinateSection(boundary, &coordSection);CHKERRQ(ierr);
3343     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
3344     for (v = vStart; v < vEnd; ++v) {
3345       const PetscInt idx = v - vStart;
3346       PetscInt       off, d;
3347 
3348       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
3349       for (d = 0; d < dim; ++d) {
3350         in.pointlist[idx*dim + d] = PetscRealPart(array[off+d]);
3351       }
3352       ierr = DMPlexGetLabelValue(boundary, "marker", v, &in.pointmarkerlist[idx]);CHKERRQ(ierr);
3353     }
3354     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
3355   }
3356   ierr  = DMPlexGetHeightStratum(boundary, 0, &eStart, &eEnd);CHKERRQ(ierr);
3357   in.numberofsegments = eEnd - eStart;
3358   if (in.numberofsegments > 0) {
3359     ierr = PetscMalloc(in.numberofsegments*2 * sizeof(int), &in.segmentlist);CHKERRQ(ierr);
3360     ierr = PetscMalloc(in.numberofsegments   * sizeof(int), &in.segmentmarkerlist);CHKERRQ(ierr);
3361     for (e = eStart; e < eEnd; ++e) {
3362       const PetscInt  idx = e - eStart;
3363       const PetscInt *cone;
3364 
3365       ierr = DMPlexGetCone(boundary, e, &cone);CHKERRQ(ierr);
3366 
3367       in.segmentlist[idx*2+0] = cone[0] - vStart;
3368       in.segmentlist[idx*2+1] = cone[1] - vStart;
3369 
3370       ierr = DMPlexGetLabelValue(boundary, "marker", e, &in.segmentmarkerlist[idx]);CHKERRQ(ierr);
3371     }
3372   }
3373 #if 0 /* Do not currently support holes */
3374   PetscReal *holeCoords;
3375   PetscInt   h, d;
3376 
3377   ierr = DMPlexGetHoles(boundary, &in.numberofholes, &holeCords);CHKERRQ(ierr);
3378   if (in.numberofholes > 0) {
3379     ierr = PetscMalloc(in.numberofholes*dim * sizeof(double), &in.holelist);CHKERRQ(ierr);
3380     for (h = 0; h < in.numberofholes; ++h) {
3381       for (d = 0; d < dim; ++d) {
3382         in.holelist[h*dim+d] = holeCoords[h*dim+d];
3383       }
3384     }
3385   }
3386 #endif
3387   if (!rank) {
3388     char args[32];
3389 
3390     /* Take away 'Q' for verbose output */
3391     ierr = PetscStrcpy(args, "pqezQ");CHKERRQ(ierr);
3392     if (createConvexHull) {
3393       ierr = PetscStrcat(args, "c");CHKERRQ(ierr);
3394     }
3395     if (constrained) {
3396       ierr = PetscStrcpy(args, "zepDQ");CHKERRQ(ierr);
3397     }
3398     triangulate(args, &in, &out, NULL);
3399   }
3400   ierr = PetscFree(in.pointlist);CHKERRQ(ierr);
3401   ierr = PetscFree(in.pointmarkerlist);CHKERRQ(ierr);
3402   ierr = PetscFree(in.segmentlist);CHKERRQ(ierr);
3403   ierr = PetscFree(in.segmentmarkerlist);CHKERRQ(ierr);
3404   ierr = PetscFree(in.holelist);CHKERRQ(ierr);
3405 
3406   {
3407     const PetscInt numCorners  = 3;
3408     const PetscInt numCells    = out.numberoftriangles;
3409     const PetscInt numVertices = out.numberofpoints;
3410     const int     *cells      = out.trianglelist;
3411     const double  *meshCoords = out.pointlist;
3412 
3413     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, dim, meshCoords, dm);CHKERRQ(ierr);
3414     /* Set labels */
3415     for (v = 0; v < numVertices; ++v) {
3416       if (out.pointmarkerlist[v]) {
3417         ierr = DMPlexSetLabelValue(*dm, "marker", v+numCells, out.pointmarkerlist[v]);CHKERRQ(ierr);
3418       }
3419     }
3420     if (interpolate) {
3421       for (e = 0; e < out.numberofedges; e++) {
3422         if (out.edgemarkerlist[e]) {
3423           const PetscInt  vertices[2] = {out.edgelist[e*2+0]+numCells, out.edgelist[e*2+1]+numCells};
3424           const PetscInt *edges;
3425           PetscInt        numEdges;
3426 
3427           ierr = DMPlexGetJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
3428           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
3429           ierr = DMPlexSetLabelValue(*dm, "marker", edges[0], out.edgemarkerlist[e]);CHKERRQ(ierr);
3430           ierr = DMPlexRestoreJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
3431         }
3432       }
3433     }
3434     ierr = DMPlexSetRefinementUniform(*dm, PETSC_FALSE);CHKERRQ(ierr);
3435   }
3436 #if 0 /* Do not currently support holes */
3437   ierr = DMPlexCopyHoles(*dm, boundary);CHKERRQ(ierr);
3438 #endif
3439   ierr = FiniOutput_Triangle(&out);CHKERRQ(ierr);
3440   PetscFunctionReturn(0);
3441 }
3442 
3443 #undef __FUNCT__
3444 #define __FUNCT__ "DMPlexRefine_Triangle"
3445 PetscErrorCode DMPlexRefine_Triangle(DM dm, double *maxVolumes, DM *dmRefined)
3446 {
3447   MPI_Comm             comm;
3448   PetscInt             dim  = 2;
3449   struct triangulateio in;
3450   struct triangulateio out;
3451   PetscInt             vStart, vEnd, v, cStart, cEnd, c, depth, depthGlobal;
3452   PetscMPIInt          rank;
3453   PetscErrorCode       ierr;
3454 
3455   PetscFunctionBegin;
3456   ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr);
3457   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
3458   ierr = InitInput_Triangle(&in);CHKERRQ(ierr);
3459   ierr = InitOutput_Triangle(&out);CHKERRQ(ierr);
3460   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3461   ierr = MPI_Allreduce(&depth, &depthGlobal, 1, MPIU_INT, MPI_MAX, comm);CHKERRQ(ierr);
3462   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
3463 
3464   in.numberofpoints = vEnd - vStart;
3465   if (in.numberofpoints > 0) {
3466     PetscSection coordSection;
3467     Vec          coordinates;
3468     PetscScalar *array;
3469 
3470     ierr = PetscMalloc(in.numberofpoints*dim * sizeof(double), &in.pointlist);CHKERRQ(ierr);
3471     ierr = PetscMalloc(in.numberofpoints * sizeof(int), &in.pointmarkerlist);CHKERRQ(ierr);
3472     ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
3473     ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
3474     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
3475     for (v = vStart; v < vEnd; ++v) {
3476       const PetscInt idx = v - vStart;
3477       PetscInt       off, d;
3478 
3479       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
3480       for (d = 0; d < dim; ++d) {
3481         in.pointlist[idx*dim + d] = PetscRealPart(array[off+d]);
3482       }
3483       ierr = DMPlexGetLabelValue(dm, "marker", v, &in.pointmarkerlist[idx]);CHKERRQ(ierr);
3484     }
3485     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
3486   }
3487   ierr  = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
3488 
3489   in.numberofcorners   = 3;
3490   in.numberoftriangles = cEnd - cStart;
3491 
3492   in.trianglearealist  = (double*) maxVolumes;
3493   if (in.numberoftriangles > 0) {
3494     ierr = PetscMalloc(in.numberoftriangles*in.numberofcorners * sizeof(int), &in.trianglelist);CHKERRQ(ierr);
3495     for (c = cStart; c < cEnd; ++c) {
3496       const PetscInt idx      = c - cStart;
3497       PetscInt      *closure = NULL;
3498       PetscInt       closureSize;
3499 
3500       ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
3501       if ((closureSize != 4) && (closureSize != 7)) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Mesh has cell which is not a triangle, %D vertices in closure", closureSize);
3502       for (v = 0; v < 3; ++v) {
3503         in.trianglelist[idx*in.numberofcorners + v] = closure[(v+closureSize-3)*2] - vStart;
3504       }
3505       ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
3506     }
3507   }
3508   /* TODO: Segment markers are missing on input */
3509 #if 0 /* Do not currently support holes */
3510   PetscReal *holeCoords;
3511   PetscInt   h, d;
3512 
3513   ierr = DMPlexGetHoles(boundary, &in.numberofholes, &holeCords);CHKERRQ(ierr);
3514   if (in.numberofholes > 0) {
3515     ierr = PetscMalloc(in.numberofholes*dim * sizeof(double), &in.holelist);CHKERRQ(ierr);
3516     for (h = 0; h < in.numberofholes; ++h) {
3517       for (d = 0; d < dim; ++d) {
3518         in.holelist[h*dim+d] = holeCoords[h*dim+d];
3519       }
3520     }
3521   }
3522 #endif
3523   if (!rank) {
3524     char args[32];
3525 
3526     /* Take away 'Q' for verbose output */
3527     ierr = PetscStrcpy(args, "pqezQra");CHKERRQ(ierr);
3528     triangulate(args, &in, &out, NULL);
3529   }
3530   ierr = PetscFree(in.pointlist);CHKERRQ(ierr);
3531   ierr = PetscFree(in.pointmarkerlist);CHKERRQ(ierr);
3532   ierr = PetscFree(in.segmentlist);CHKERRQ(ierr);
3533   ierr = PetscFree(in.segmentmarkerlist);CHKERRQ(ierr);
3534   ierr = PetscFree(in.trianglelist);CHKERRQ(ierr);
3535 
3536   {
3537     const PetscInt numCorners  = 3;
3538     const PetscInt numCells    = out.numberoftriangles;
3539     const PetscInt numVertices = out.numberofpoints;
3540     const int     *cells      = out.trianglelist;
3541     const double  *meshCoords = out.pointlist;
3542     PetscBool      interpolate = depthGlobal > 1 ? PETSC_TRUE : PETSC_FALSE;
3543 
3544     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, dim, meshCoords, dmRefined);CHKERRQ(ierr);
3545     /* Set labels */
3546     for (v = 0; v < numVertices; ++v) {
3547       if (out.pointmarkerlist[v]) {
3548         ierr = DMPlexSetLabelValue(*dmRefined, "marker", v+numCells, out.pointmarkerlist[v]);CHKERRQ(ierr);
3549       }
3550     }
3551     if (interpolate) {
3552       PetscInt e;
3553 
3554       for (e = 0; e < out.numberofedges; e++) {
3555         if (out.edgemarkerlist[e]) {
3556           const PetscInt  vertices[2] = {out.edgelist[e*2+0]+numCells, out.edgelist[e*2+1]+numCells};
3557           const PetscInt *edges;
3558           PetscInt        numEdges;
3559 
3560           ierr = DMPlexGetJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
3561           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
3562           ierr = DMPlexSetLabelValue(*dmRefined, "marker", edges[0], out.edgemarkerlist[e]);CHKERRQ(ierr);
3563           ierr = DMPlexRestoreJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
3564         }
3565       }
3566     }
3567     ierr = DMPlexSetRefinementUniform(*dmRefined, PETSC_FALSE);CHKERRQ(ierr);
3568   }
3569 #if 0 /* Do not currently support holes */
3570   ierr = DMPlexCopyHoles(*dm, boundary);CHKERRQ(ierr);
3571 #endif
3572   ierr = FiniOutput_Triangle(&out);CHKERRQ(ierr);
3573   PetscFunctionReturn(0);
3574 }
3575 #endif
3576 
3577 #if defined(PETSC_HAVE_TETGEN)
3578 #include <tetgen.h>
3579 #undef __FUNCT__
3580 #define __FUNCT__ "DMPlexGenerate_Tetgen"
3581 PetscErrorCode DMPlexGenerate_Tetgen(DM boundary, PetscBool interpolate, DM *dm)
3582 {
3583   MPI_Comm       comm;
3584   const PetscInt dim  = 3;
3585   ::tetgenio     in;
3586   ::tetgenio     out;
3587   PetscInt       vStart, vEnd, v, fStart, fEnd, f;
3588   PetscMPIInt    rank;
3589   PetscErrorCode ierr;
3590 
3591   PetscFunctionBegin;
3592   ierr              = PetscObjectGetComm((PetscObject)boundary,&comm);CHKERRQ(ierr);
3593   ierr              = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
3594   ierr              = DMPlexGetDepthStratum(boundary, 0, &vStart, &vEnd);CHKERRQ(ierr);
3595   in.numberofpoints = vEnd - vStart;
3596   if (in.numberofpoints > 0) {
3597     PetscSection coordSection;
3598     Vec          coordinates;
3599     PetscScalar *array;
3600 
3601     in.pointlist       = new double[in.numberofpoints*dim];
3602     in.pointmarkerlist = new int[in.numberofpoints];
3603 
3604     ierr = DMGetCoordinatesLocal(boundary, &coordinates);CHKERRQ(ierr);
3605     ierr = DMPlexGetCoordinateSection(boundary, &coordSection);CHKERRQ(ierr);
3606     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
3607     for (v = vStart; v < vEnd; ++v) {
3608       const PetscInt idx = v - vStart;
3609       PetscInt       off, d;
3610 
3611       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
3612       for (d = 0; d < dim; ++d) in.pointlist[idx*dim + d] = array[off+d];
3613       ierr = DMPlexGetLabelValue(boundary, "marker", v, &in.pointmarkerlist[idx]);CHKERRQ(ierr);
3614     }
3615     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
3616   }
3617   ierr  = DMPlexGetHeightStratum(boundary, 0, &fStart, &fEnd);CHKERRQ(ierr);
3618 
3619   in.numberoffacets = fEnd - fStart;
3620   if (in.numberoffacets > 0) {
3621     in.facetlist       = new tetgenio::facet[in.numberoffacets];
3622     in.facetmarkerlist = new int[in.numberoffacets];
3623     for (f = fStart; f < fEnd; ++f) {
3624       const PetscInt idx     = f - fStart;
3625       PetscInt      *points = NULL, numPoints, p, numVertices = 0, v;
3626 
3627       in.facetlist[idx].numberofpolygons = 1;
3628       in.facetlist[idx].polygonlist      = new tetgenio::polygon[in.facetlist[idx].numberofpolygons];
3629       in.facetlist[idx].numberofholes    = 0;
3630       in.facetlist[idx].holelist         = NULL;
3631 
3632       ierr = DMPlexGetTransitiveClosure(boundary, f, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
3633       for (p = 0; p < numPoints*2; p += 2) {
3634         const PetscInt point = points[p];
3635         if ((point >= vStart) && (point < vEnd)) points[numVertices++] = point;
3636       }
3637 
3638       tetgenio::polygon *poly = in.facetlist[idx].polygonlist;
3639       poly->numberofvertices = numVertices;
3640       poly->vertexlist       = new int[poly->numberofvertices];
3641       for (v = 0; v < numVertices; ++v) {
3642         const PetscInt vIdx = points[v] - vStart;
3643         poly->vertexlist[v] = vIdx;
3644       }
3645       ierr = DMPlexGetLabelValue(boundary, "marker", f, &in.facetmarkerlist[idx]);CHKERRQ(ierr);
3646       ierr = DMPlexRestoreTransitiveClosure(boundary, f, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
3647     }
3648   }
3649   if (!rank) {
3650     char args[32];
3651 
3652     /* Take away 'Q' for verbose output */
3653     ierr = PetscStrcpy(args, "pqezQ");CHKERRQ(ierr);
3654     ::tetrahedralize(args, &in, &out);
3655   }
3656   {
3657     const PetscInt numCorners  = 4;
3658     const PetscInt numCells    = out.numberoftetrahedra;
3659     const PetscInt numVertices = out.numberofpoints;
3660     const double   *meshCoords = out.pointlist;
3661     int            *cells      = out.tetrahedronlist;
3662 
3663     ierr = DMPlexInvertCells_Internal(dim, numCells, numCorners, cells);CHKERRQ(ierr);
3664     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, dim, meshCoords, dm);CHKERRQ(ierr);
3665     /* Set labels */
3666     for (v = 0; v < numVertices; ++v) {
3667       if (out.pointmarkerlist[v]) {
3668         ierr = DMPlexSetLabelValue(*dm, "marker", v+numCells, out.pointmarkerlist[v]);CHKERRQ(ierr);
3669       }
3670     }
3671     if (interpolate) {
3672       PetscInt e;
3673 
3674       for (e = 0; e < out.numberofedges; e++) {
3675         if (out.edgemarkerlist[e]) {
3676           const PetscInt  vertices[2] = {out.edgelist[e*2+0]+numCells, out.edgelist[e*2+1]+numCells};
3677           const PetscInt *edges;
3678           PetscInt        numEdges;
3679 
3680           ierr = DMPlexGetJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
3681           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
3682           ierr = DMPlexSetLabelValue(*dm, "marker", edges[0], out.edgemarkerlist[e]);CHKERRQ(ierr);
3683           ierr = DMPlexRestoreJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
3684         }
3685       }
3686       for (f = 0; f < out.numberoftrifaces; f++) {
3687         if (out.trifacemarkerlist[f]) {
3688           const PetscInt  vertices[3] = {out.trifacelist[f*3+0]+numCells, out.trifacelist[f*3+1]+numCells, out.trifacelist[f*3+2]+numCells};
3689           const PetscInt *faces;
3690           PetscInt        numFaces;
3691 
3692           ierr = DMPlexGetJoin(*dm, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
3693           if (numFaces != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Three vertices must cover only one face, not %D", numFaces);
3694           ierr = DMPlexSetLabelValue(*dm, "marker", faces[0], out.trifacemarkerlist[f]);CHKERRQ(ierr);
3695           ierr = DMPlexRestoreJoin(*dm, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
3696         }
3697       }
3698     }
3699     ierr = DMPlexSetRefinementUniform(*dm, PETSC_FALSE);CHKERRQ(ierr);
3700   }
3701   PetscFunctionReturn(0);
3702 }
3703 
3704 #undef __FUNCT__
3705 #define __FUNCT__ "DMPlexRefine_Tetgen"
3706 PetscErrorCode DMPlexRefine_Tetgen(DM dm, double *maxVolumes, DM *dmRefined)
3707 {
3708   MPI_Comm       comm;
3709   const PetscInt dim  = 3;
3710   ::tetgenio     in;
3711   ::tetgenio     out;
3712   PetscInt       vStart, vEnd, v, cStart, cEnd, c, depth, depthGlobal;
3713   PetscMPIInt    rank;
3714   PetscErrorCode ierr;
3715 
3716   PetscFunctionBegin;
3717   ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr);
3718   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
3719   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3720   ierr = MPI_Allreduce(&depth, &depthGlobal, 1, MPIU_INT, MPI_MAX, comm);CHKERRQ(ierr);
3721   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
3722 
3723   in.numberofpoints = vEnd - vStart;
3724   if (in.numberofpoints > 0) {
3725     PetscSection coordSection;
3726     Vec          coordinates;
3727     PetscScalar *array;
3728 
3729     in.pointlist       = new double[in.numberofpoints*dim];
3730     in.pointmarkerlist = new int[in.numberofpoints];
3731 
3732     ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
3733     ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
3734     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
3735     for (v = vStart; v < vEnd; ++v) {
3736       const PetscInt idx = v - vStart;
3737       PetscInt       off, d;
3738 
3739       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
3740       for (d = 0; d < dim; ++d) in.pointlist[idx*dim + d] = array[off+d];
3741       ierr = DMPlexGetLabelValue(dm, "marker", v, &in.pointmarkerlist[idx]);CHKERRQ(ierr);
3742     }
3743     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
3744   }
3745   ierr  = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
3746 
3747   in.numberofcorners       = 4;
3748   in.numberoftetrahedra    = cEnd - cStart;
3749   in.tetrahedronvolumelist = (double*) maxVolumes;
3750   if (in.numberoftetrahedra > 0) {
3751     in.tetrahedronlist = new int[in.numberoftetrahedra*in.numberofcorners];
3752     for (c = cStart; c < cEnd; ++c) {
3753       const PetscInt idx      = c - cStart;
3754       PetscInt      *closure = NULL;
3755       PetscInt       closureSize;
3756 
3757       ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
3758       if ((closureSize != 5) && (closureSize != 15)) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Mesh has cell which is not a tetrahedron, %D vertices in closure", closureSize);
3759       for (v = 0; v < 4; ++v) {
3760         in.tetrahedronlist[idx*in.numberofcorners + v] = closure[(v+closureSize-4)*2] - vStart;
3761       }
3762       ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
3763     }
3764   }
3765   /* TODO: Put in boundary faces with markers */
3766   if (!rank) {
3767     char args[32];
3768 
3769     /* Take away 'Q' for verbose output */
3770     /*ierr = PetscStrcpy(args, "qezQra");CHKERRQ(ierr); */
3771     ierr = PetscStrcpy(args, "qezraVVVV");CHKERRQ(ierr);
3772     ::tetrahedralize(args, &in, &out);
3773   }
3774   in.tetrahedronvolumelist = NULL;
3775 
3776   {
3777     const PetscInt numCorners  = 4;
3778     const PetscInt numCells    = out.numberoftetrahedra;
3779     const PetscInt numVertices = out.numberofpoints;
3780     const double   *meshCoords = out.pointlist;
3781     int            *cells      = out.tetrahedronlist;
3782 
3783     PetscBool      interpolate = depthGlobal > 1 ? PETSC_TRUE : PETSC_FALSE;
3784 
3785     ierr = DMPlexInvertCells_Internal(dim, numCells, numCorners, cells);CHKERRQ(ierr);
3786     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, dim, meshCoords, dmRefined);CHKERRQ(ierr);
3787     /* Set labels */
3788     for (v = 0; v < numVertices; ++v) {
3789       if (out.pointmarkerlist[v]) {
3790         ierr = DMPlexSetLabelValue(*dmRefined, "marker", v+numCells, out.pointmarkerlist[v]);CHKERRQ(ierr);
3791       }
3792     }
3793     if (interpolate) {
3794       PetscInt e, f;
3795 
3796       for (e = 0; e < out.numberofedges; e++) {
3797         if (out.edgemarkerlist[e]) {
3798           const PetscInt  vertices[2] = {out.edgelist[e*2+0]+numCells, out.edgelist[e*2+1]+numCells};
3799           const PetscInt *edges;
3800           PetscInt        numEdges;
3801 
3802           ierr = DMPlexGetJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
3803           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
3804           ierr = DMPlexSetLabelValue(*dmRefined, "marker", edges[0], out.edgemarkerlist[e]);CHKERRQ(ierr);
3805           ierr = DMPlexRestoreJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
3806         }
3807       }
3808       for (f = 0; f < out.numberoftrifaces; f++) {
3809         if (out.trifacemarkerlist[f]) {
3810           const PetscInt  vertices[3] = {out.trifacelist[f*3+0]+numCells, out.trifacelist[f*3+1]+numCells, out.trifacelist[f*3+2]+numCells};
3811           const PetscInt *faces;
3812           PetscInt        numFaces;
3813 
3814           ierr = DMPlexGetJoin(*dmRefined, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
3815           if (numFaces != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Three vertices must cover only one face, not %D", numFaces);
3816           ierr = DMPlexSetLabelValue(*dmRefined, "marker", faces[0], out.trifacemarkerlist[f]);CHKERRQ(ierr);
3817           ierr = DMPlexRestoreJoin(*dmRefined, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
3818         }
3819       }
3820     }
3821     ierr = DMPlexSetRefinementUniform(*dmRefined, PETSC_FALSE);CHKERRQ(ierr);
3822   }
3823   PetscFunctionReturn(0);
3824 }
3825 #endif
3826 
3827 #if defined(PETSC_HAVE_CTETGEN)
3828 #include "ctetgen.h"
3829 
3830 #undef __FUNCT__
3831 #define __FUNCT__ "DMPlexGenerate_CTetgen"
3832 PetscErrorCode DMPlexGenerate_CTetgen(DM boundary, PetscBool interpolate, DM *dm)
3833 {
3834   MPI_Comm       comm;
3835   const PetscInt dim  = 3;
3836   PLC           *in, *out;
3837   PetscInt       verbose = 0, vStart, vEnd, v, fStart, fEnd, f;
3838   PetscMPIInt    rank;
3839   PetscErrorCode ierr;
3840 
3841   PetscFunctionBegin;
3842   ierr = PetscObjectGetComm((PetscObject)boundary,&comm);CHKERRQ(ierr);
3843   ierr = PetscOptionsGetInt(((PetscObject) boundary)->prefix, "-ctetgen_verbose", &verbose, NULL);CHKERRQ(ierr);
3844   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
3845   ierr = DMPlexGetDepthStratum(boundary, 0, &vStart, &vEnd);CHKERRQ(ierr);
3846   ierr = PLCCreate(&in);CHKERRQ(ierr);
3847   ierr = PLCCreate(&out);CHKERRQ(ierr);
3848 
3849   in->numberofpoints = vEnd - vStart;
3850   if (in->numberofpoints > 0) {
3851     PetscSection coordSection;
3852     Vec          coordinates;
3853     PetscScalar *array;
3854 
3855     ierr = PetscMalloc(in->numberofpoints*dim * sizeof(PetscReal), &in->pointlist);CHKERRQ(ierr);
3856     ierr = PetscMalloc(in->numberofpoints     * sizeof(int),       &in->pointmarkerlist);CHKERRQ(ierr);
3857     ierr = DMGetCoordinatesLocal(boundary, &coordinates);CHKERRQ(ierr);
3858     ierr = DMPlexGetCoordinateSection(boundary, &coordSection);CHKERRQ(ierr);
3859     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
3860     for (v = vStart; v < vEnd; ++v) {
3861       const PetscInt idx = v - vStart;
3862       PetscInt       off, d, m;
3863 
3864       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
3865       for (d = 0; d < dim; ++d) {
3866         in->pointlist[idx*dim + d] = PetscRealPart(array[off+d]);
3867       }
3868       ierr = DMPlexGetLabelValue(boundary, "marker", v, &m);CHKERRQ(ierr);
3869 
3870       in->pointmarkerlist[idx] = (int) m;
3871     }
3872     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
3873   }
3874   ierr  = DMPlexGetHeightStratum(boundary, 0, &fStart, &fEnd);CHKERRQ(ierr);
3875 
3876   in->numberoffacets = fEnd - fStart;
3877   if (in->numberoffacets > 0) {
3878     ierr = PetscMalloc(in->numberoffacets * sizeof(facet), &in->facetlist);CHKERRQ(ierr);
3879     ierr = PetscMalloc(in->numberoffacets * sizeof(int),   &in->facetmarkerlist);CHKERRQ(ierr);
3880     for (f = fStart; f < fEnd; ++f) {
3881       const PetscInt idx     = f - fStart;
3882       PetscInt      *points = NULL, numPoints, p, numVertices = 0, v, m;
3883       polygon       *poly;
3884 
3885       in->facetlist[idx].numberofpolygons = 1;
3886 
3887       ierr = PetscMalloc(in->facetlist[idx].numberofpolygons * sizeof(polygon), &in->facetlist[idx].polygonlist);CHKERRQ(ierr);
3888 
3889       in->facetlist[idx].numberofholes    = 0;
3890       in->facetlist[idx].holelist         = NULL;
3891 
3892       ierr = DMPlexGetTransitiveClosure(boundary, f, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
3893       for (p = 0; p < numPoints*2; p += 2) {
3894         const PetscInt point = points[p];
3895         if ((point >= vStart) && (point < vEnd)) points[numVertices++] = point;
3896       }
3897 
3898       poly                   = in->facetlist[idx].polygonlist;
3899       poly->numberofvertices = numVertices;
3900       ierr                   = PetscMalloc(poly->numberofvertices * sizeof(int), &poly->vertexlist);CHKERRQ(ierr);
3901       for (v = 0; v < numVertices; ++v) {
3902         const PetscInt vIdx = points[v] - vStart;
3903         poly->vertexlist[v] = vIdx;
3904       }
3905       ierr                     = DMPlexGetLabelValue(boundary, "marker", f, &m);CHKERRQ(ierr);
3906       in->facetmarkerlist[idx] = (int) m;
3907       ierr                     = DMPlexRestoreTransitiveClosure(boundary, f, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
3908     }
3909   }
3910   if (!rank) {
3911     TetGenOpts t;
3912 
3913     ierr        = TetGenOptsInitialize(&t);CHKERRQ(ierr);
3914     t.in        = boundary; /* Should go away */
3915     t.plc       = 1;
3916     t.quality   = 1;
3917     t.edgesout  = 1;
3918     t.zeroindex = 1;
3919     t.quiet     = 1;
3920     t.verbose   = verbose;
3921     ierr        = TetGenCheckOpts(&t);CHKERRQ(ierr);
3922     ierr        = TetGenTetrahedralize(&t, in, out);CHKERRQ(ierr);
3923   }
3924   {
3925     const PetscInt numCorners  = 4;
3926     const PetscInt numCells    = out->numberoftetrahedra;
3927     const PetscInt numVertices = out->numberofpoints;
3928     const double   *meshCoords = out->pointlist;
3929     int            *cells      = out->tetrahedronlist;
3930 
3931     ierr = DMPlexInvertCells_Internal(dim, numCells, numCorners, cells);CHKERRQ(ierr);
3932     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, dim, meshCoords, dm);CHKERRQ(ierr);
3933     /* Set labels */
3934     for (v = 0; v < numVertices; ++v) {
3935       if (out->pointmarkerlist[v]) {
3936         ierr = DMPlexSetLabelValue(*dm, "marker", v+numCells, out->pointmarkerlist[v]);CHKERRQ(ierr);
3937       }
3938     }
3939     if (interpolate) {
3940       PetscInt e;
3941 
3942       for (e = 0; e < out->numberofedges; e++) {
3943         if (out->edgemarkerlist[e]) {
3944           const PetscInt  vertices[2] = {out->edgelist[e*2+0]+numCells, out->edgelist[e*2+1]+numCells};
3945           const PetscInt *edges;
3946           PetscInt        numEdges;
3947 
3948           ierr = DMPlexGetJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
3949           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
3950           ierr = DMPlexSetLabelValue(*dm, "marker", edges[0], out->edgemarkerlist[e]);CHKERRQ(ierr);
3951           ierr = DMPlexRestoreJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
3952         }
3953       }
3954       for (f = 0; f < out->numberoftrifaces; f++) {
3955         if (out->trifacemarkerlist[f]) {
3956           const PetscInt  vertices[3] = {out->trifacelist[f*3+0]+numCells, out->trifacelist[f*3+1]+numCells, out->trifacelist[f*3+2]+numCells};
3957           const PetscInt *faces;
3958           PetscInt        numFaces;
3959 
3960           ierr = DMPlexGetFullJoin(*dm, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
3961           if (numFaces != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Three vertices must cover only one face, not %D", numFaces);
3962           ierr = DMPlexSetLabelValue(*dm, "marker", faces[0], out->trifacemarkerlist[f]);CHKERRQ(ierr);
3963           ierr = DMPlexRestoreJoin(*dm, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
3964         }
3965       }
3966     }
3967     ierr = DMPlexSetRefinementUniform(*dm, PETSC_FALSE);CHKERRQ(ierr);
3968   }
3969 
3970   ierr = PLCDestroy(&in);CHKERRQ(ierr);
3971   ierr = PLCDestroy(&out);CHKERRQ(ierr);
3972   PetscFunctionReturn(0);
3973 }
3974 
3975 #undef __FUNCT__
3976 #define __FUNCT__ "DMPlexRefine_CTetgen"
3977 PetscErrorCode DMPlexRefine_CTetgen(DM dm, PetscReal *maxVolumes, DM *dmRefined)
3978 {
3979   MPI_Comm       comm;
3980   const PetscInt dim  = 3;
3981   PLC           *in, *out;
3982   PetscInt       verbose = 0, vStart, vEnd, v, cStart, cEnd, c, depth, depthGlobal;
3983   PetscMPIInt    rank;
3984   PetscErrorCode ierr;
3985 
3986   PetscFunctionBegin;
3987   ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr);
3988   ierr = PetscOptionsGetInt(((PetscObject) dm)->prefix, "-ctetgen_verbose", &verbose, NULL);CHKERRQ(ierr);
3989   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
3990   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3991   ierr = MPI_Allreduce(&depth, &depthGlobal, 1, MPIU_INT, MPI_MAX, comm);CHKERRQ(ierr);
3992   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
3993   ierr = PLCCreate(&in);CHKERRQ(ierr);
3994   ierr = PLCCreate(&out);CHKERRQ(ierr);
3995 
3996   in->numberofpoints = vEnd - vStart;
3997   if (in->numberofpoints > 0) {
3998     PetscSection coordSection;
3999     Vec          coordinates;
4000     PetscScalar *array;
4001 
4002     ierr = PetscMalloc(in->numberofpoints*dim * sizeof(PetscReal), &in->pointlist);CHKERRQ(ierr);
4003     ierr = PetscMalloc(in->numberofpoints     * sizeof(int),       &in->pointmarkerlist);CHKERRQ(ierr);
4004     ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
4005     ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
4006     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
4007     for (v = vStart; v < vEnd; ++v) {
4008       const PetscInt idx = v - vStart;
4009       PetscInt       off, d, m;
4010 
4011       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
4012       for (d = 0; d < dim; ++d) {
4013         in->pointlist[idx*dim + d] = PetscRealPart(array[off+d]);
4014       }
4015       ierr = DMPlexGetLabelValue(dm, "marker", v, &m);CHKERRQ(ierr);
4016 
4017       in->pointmarkerlist[idx] = (int) m;
4018     }
4019     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
4020   }
4021   ierr  = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
4022 
4023   in->numberofcorners       = 4;
4024   in->numberoftetrahedra    = cEnd - cStart;
4025   in->tetrahedronvolumelist = maxVolumes;
4026   if (in->numberoftetrahedra > 0) {
4027     ierr = PetscMalloc(in->numberoftetrahedra*in->numberofcorners * sizeof(int), &in->tetrahedronlist);CHKERRQ(ierr);
4028     for (c = cStart; c < cEnd; ++c) {
4029       const PetscInt idx      = c - cStart;
4030       PetscInt      *closure = NULL;
4031       PetscInt       closureSize;
4032 
4033       ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
4034       if ((closureSize != 5) && (closureSize != 15)) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Mesh has cell which is not a tetrahedron, %D vertices in closure", closureSize);
4035       for (v = 0; v < 4; ++v) {
4036         in->tetrahedronlist[idx*in->numberofcorners + v] = closure[(v+closureSize-4)*2] - vStart;
4037       }
4038       ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
4039     }
4040   }
4041   if (!rank) {
4042     TetGenOpts t;
4043 
4044     ierr = TetGenOptsInitialize(&t);CHKERRQ(ierr);
4045 
4046     t.in        = dm; /* Should go away */
4047     t.refine    = 1;
4048     t.varvolume = 1;
4049     t.quality   = 1;
4050     t.edgesout  = 1;
4051     t.zeroindex = 1;
4052     t.quiet     = 1;
4053     t.verbose   = verbose; /* Change this */
4054 
4055     ierr = TetGenCheckOpts(&t);CHKERRQ(ierr);
4056     ierr = TetGenTetrahedralize(&t, in, out);CHKERRQ(ierr);
4057   }
4058   {
4059     const PetscInt numCorners  = 4;
4060     const PetscInt numCells    = out->numberoftetrahedra;
4061     const PetscInt numVertices = out->numberofpoints;
4062     const double   *meshCoords = out->pointlist;
4063     int            *cells      = out->tetrahedronlist;
4064     PetscBool      interpolate = depthGlobal > 1 ? PETSC_TRUE : PETSC_FALSE;
4065 
4066     ierr = DMPlexInvertCells_Internal(dim, numCells, numCorners, cells);CHKERRQ(ierr);
4067     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, dim, meshCoords, dmRefined);CHKERRQ(ierr);
4068     /* Set labels */
4069     for (v = 0; v < numVertices; ++v) {
4070       if (out->pointmarkerlist[v]) {
4071         ierr = DMPlexSetLabelValue(*dmRefined, "marker", v+numCells, out->pointmarkerlist[v]);CHKERRQ(ierr);
4072       }
4073     }
4074     if (interpolate) {
4075       PetscInt e, f;
4076 
4077       for (e = 0; e < out->numberofedges; e++) {
4078         if (out->edgemarkerlist[e]) {
4079           const PetscInt  vertices[2] = {out->edgelist[e*2+0]+numCells, out->edgelist[e*2+1]+numCells};
4080           const PetscInt *edges;
4081           PetscInt        numEdges;
4082 
4083           ierr = DMPlexGetJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
4084           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
4085           ierr = DMPlexSetLabelValue(*dmRefined, "marker", edges[0], out->edgemarkerlist[e]);CHKERRQ(ierr);
4086           ierr = DMPlexRestoreJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
4087         }
4088       }
4089       for (f = 0; f < out->numberoftrifaces; f++) {
4090         if (out->trifacemarkerlist[f]) {
4091           const PetscInt  vertices[3] = {out->trifacelist[f*3+0]+numCells, out->trifacelist[f*3+1]+numCells, out->trifacelist[f*3+2]+numCells};
4092           const PetscInt *faces;
4093           PetscInt        numFaces;
4094 
4095           ierr = DMPlexGetFullJoin(*dmRefined, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
4096           if (numFaces != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Three vertices must cover only one face, not %D", numFaces);
4097           ierr = DMPlexSetLabelValue(*dmRefined, "marker", faces[0], out->trifacemarkerlist[f]);CHKERRQ(ierr);
4098           ierr = DMPlexRestoreJoin(*dmRefined, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
4099         }
4100       }
4101     }
4102     ierr = DMPlexSetRefinementUniform(*dmRefined, PETSC_FALSE);CHKERRQ(ierr);
4103   }
4104   ierr = PLCDestroy(&in);CHKERRQ(ierr);
4105   ierr = PLCDestroy(&out);CHKERRQ(ierr);
4106   PetscFunctionReturn(0);
4107 }
4108 #endif
4109 
4110 #undef __FUNCT__
4111 #define __FUNCT__ "DMPlexGenerate"
4112 /*@C
4113   DMPlexGenerate - Generates a mesh.
4114 
4115   Not Collective
4116 
4117   Input Parameters:
4118 + boundary - The DMPlex boundary object
4119 . name - The mesh generation package name
4120 - interpolate - Flag to create intermediate mesh elements
4121 
4122   Output Parameter:
4123 . mesh - The DMPlex object
4124 
4125   Level: intermediate
4126 
4127 .keywords: mesh, elements
4128 .seealso: DMPlexCreate(), DMRefine()
4129 @*/
4130 PetscErrorCode DMPlexGenerate(DM boundary, const char name[], PetscBool interpolate, DM *mesh)
4131 {
4132   PetscInt       dim;
4133   char           genname[1024];
4134   PetscBool      isTriangle = PETSC_FALSE, isTetgen = PETSC_FALSE, isCTetgen = PETSC_FALSE, flg;
4135   PetscErrorCode ierr;
4136 
4137   PetscFunctionBegin;
4138   PetscValidHeaderSpecific(boundary, DM_CLASSID, 1);
4139   PetscValidLogicalCollectiveBool(boundary, interpolate, 2);
4140   ierr = DMPlexGetDimension(boundary, &dim);CHKERRQ(ierr);
4141   ierr = PetscOptionsGetString(((PetscObject) boundary)->prefix, "-dm_plex_generator", genname, 1024, &flg);CHKERRQ(ierr);
4142   if (flg) name = genname;
4143   if (name) {
4144     ierr = PetscStrcmp(name, "triangle", &isTriangle);CHKERRQ(ierr);
4145     ierr = PetscStrcmp(name, "tetgen",   &isTetgen);CHKERRQ(ierr);
4146     ierr = PetscStrcmp(name, "ctetgen",  &isCTetgen);CHKERRQ(ierr);
4147   }
4148   switch (dim) {
4149   case 1:
4150     if (!name || isTriangle) {
4151 #if defined(PETSC_HAVE_TRIANGLE)
4152       ierr = DMPlexGenerate_Triangle(boundary, interpolate, mesh);CHKERRQ(ierr);
4153 #else
4154       SETERRQ(PetscObjectComm((PetscObject)boundary), PETSC_ERR_SUP, "Mesh generation needs external package support.\nPlease reconfigure with --download-triangle.");
4155 #endif
4156     } else SETERRQ1(PetscObjectComm((PetscObject)boundary), PETSC_ERR_SUP, "Unknown 2D mesh generation package %s", name);
4157     break;
4158   case 2:
4159     if (!name || isCTetgen) {
4160 #if defined(PETSC_HAVE_CTETGEN)
4161       ierr = DMPlexGenerate_CTetgen(boundary, interpolate, mesh);CHKERRQ(ierr);
4162 #else
4163       SETERRQ(PetscObjectComm((PetscObject)boundary), PETSC_ERR_SUP, "CTetgen needs external package support.\nPlease reconfigure with --download-ctetgen.");
4164 #endif
4165     } else if (isTetgen) {
4166 #if defined(PETSC_HAVE_TETGEN)
4167       ierr = DMPlexGenerate_Tetgen(boundary, interpolate, mesh);CHKERRQ(ierr);
4168 #else
4169       SETERRQ(PetscObjectComm((PetscObject)boundary), PETSC_ERR_SUP, "Tetgen needs external package support.\nPlease reconfigure with --with-c-language=cxx --download-tetgen.");
4170 #endif
4171     } else SETERRQ1(PetscObjectComm((PetscObject)boundary), PETSC_ERR_SUP, "Unknown 3D mesh generation package %s", name);
4172     break;
4173   default:
4174     SETERRQ1(PetscObjectComm((PetscObject)boundary), PETSC_ERR_SUP, "Mesh generation for a dimension %d boundary is not supported.", dim);
4175   }
4176   PetscFunctionReturn(0);
4177 }
4178 
4179 #undef __FUNCT__
4180 #define __FUNCT__ "DMRefine_Plex"
4181 PetscErrorCode DMRefine_Plex(DM dm, MPI_Comm comm, DM *dmRefined)
4182 {
4183   PetscReal      refinementLimit;
4184   PetscInt       dim, cStart, cEnd;
4185   char           genname[1024], *name = NULL;
4186   PetscBool      isUniform, isTriangle = PETSC_FALSE, isTetgen = PETSC_FALSE, isCTetgen = PETSC_FALSE, flg;
4187   PetscErrorCode ierr;
4188 
4189   PetscFunctionBegin;
4190   ierr = DMPlexGetRefinementUniform(dm, &isUniform);CHKERRQ(ierr);
4191   if (isUniform) {
4192     CellRefiner cellRefiner;
4193 
4194     ierr = DMPlexGetCellRefiner_Internal(dm, &cellRefiner);CHKERRQ(ierr);
4195     ierr = DMPlexRefineUniform_Internal(dm, cellRefiner, dmRefined);CHKERRQ(ierr);
4196     PetscFunctionReturn(0);
4197   }
4198   ierr = DMPlexGetRefinementLimit(dm, &refinementLimit);CHKERRQ(ierr);
4199   if (refinementLimit == 0.0) PetscFunctionReturn(0);
4200   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
4201   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
4202   ierr = PetscOptionsGetString(((PetscObject) dm)->prefix, "-dm_plex_generator", genname, 1024, &flg);CHKERRQ(ierr);
4203   if (flg) name = genname;
4204   if (name) {
4205     ierr = PetscStrcmp(name, "triangle", &isTriangle);CHKERRQ(ierr);
4206     ierr = PetscStrcmp(name, "tetgen",   &isTetgen);CHKERRQ(ierr);
4207     ierr = PetscStrcmp(name, "ctetgen",  &isCTetgen);CHKERRQ(ierr);
4208   }
4209   switch (dim) {
4210   case 2:
4211     if (!name || isTriangle) {
4212 #if defined(PETSC_HAVE_TRIANGLE)
4213       double  *maxVolumes;
4214       PetscInt c;
4215 
4216       ierr = PetscMalloc((cEnd - cStart) * sizeof(double), &maxVolumes);CHKERRQ(ierr);
4217       for (c = 0; c < cEnd-cStart; ++c) maxVolumes[c] = refinementLimit;
4218       ierr = DMPlexRefine_Triangle(dm, maxVolumes, dmRefined);CHKERRQ(ierr);
4219       ierr = PetscFree(maxVolumes);CHKERRQ(ierr);
4220 #else
4221       SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Mesh refinement needs external package support.\nPlease reconfigure with --download-triangle.");
4222 #endif
4223     } else SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Unknown 2D mesh generation package %s", name);
4224     break;
4225   case 3:
4226     if (!name || isCTetgen) {
4227 #if defined(PETSC_HAVE_CTETGEN)
4228       PetscReal *maxVolumes;
4229       PetscInt   c;
4230 
4231       ierr = PetscMalloc((cEnd - cStart) * sizeof(PetscReal), &maxVolumes);CHKERRQ(ierr);
4232       for (c = 0; c < cEnd-cStart; ++c) maxVolumes[c] = refinementLimit;
4233       ierr = DMPlexRefine_CTetgen(dm, maxVolumes, dmRefined);CHKERRQ(ierr);
4234 #else
4235       SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "CTetgen needs external package support.\nPlease reconfigure with --download-ctetgen.");
4236 #endif
4237     } else if (isTetgen) {
4238 #if defined(PETSC_HAVE_TETGEN)
4239       double  *maxVolumes;
4240       PetscInt c;
4241 
4242       ierr = PetscMalloc((cEnd - cStart) * sizeof(double), &maxVolumes);CHKERRQ(ierr);
4243       for (c = 0; c < cEnd-cStart; ++c) maxVolumes[c] = refinementLimit;
4244       ierr = DMPlexRefine_Tetgen(dm, maxVolumes, dmRefined);CHKERRQ(ierr);
4245 #else
4246       SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Tetgen needs external package support.\nPlease reconfigure with --with-c-language=cxx --download-tetgen.");
4247 #endif
4248     } else SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Unknown 3D mesh generation package %s", name);
4249     break;
4250   default:
4251     SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Mesh refinement in dimension %d is not supported.", dim);
4252   }
4253   PetscFunctionReturn(0);
4254 }
4255 
4256 #undef __FUNCT__
4257 #define __FUNCT__ "DMPlexGetDepthLabel"
4258 /*@
4259   DMPlexGetDepthLabel - Get the DMLabel recording the depth of each point
4260 
4261   Not Collective
4262 
4263   Input Parameter:
4264 . dm    - The DMPlex object
4265 
4266   Output Parameter:
4267 . depthLabel - The DMLabel recording point depth
4268 
4269   Level: developer
4270 
4271 .keywords: mesh, points
4272 .seealso: DMPlexGetDepth(), DMPlexGetHeightStratum(), DMPlexGetDepthStratum()
4273 @*/
4274 PetscErrorCode DMPlexGetDepthLabel(DM dm, DMLabel *depthLabel)
4275 {
4276   DM_Plex       *mesh = (DM_Plex*) dm->data;
4277   PetscErrorCode ierr;
4278 
4279   PetscFunctionBegin;
4280   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4281   PetscValidPointer(depthLabel, 2);
4282   if (!mesh->depthLabel) {
4283     ierr = DMPlexGetLabel(dm, "depth", &mesh->depthLabel);CHKERRQ(ierr);
4284   }
4285   *depthLabel = mesh->depthLabel;
4286   PetscFunctionReturn(0);
4287 }
4288 
4289 #undef __FUNCT__
4290 #define __FUNCT__ "DMPlexGetDepth"
4291 /*@
4292   DMPlexGetDepth - Get the depth of the DAG representing this mesh
4293 
4294   Not Collective
4295 
4296   Input Parameter:
4297 . dm    - The DMPlex object
4298 
4299   Output Parameter:
4300 . depth - The number of strata (breadth first levels) in the DAG
4301 
4302   Level: developer
4303 
4304 .keywords: mesh, points
4305 .seealso: DMPlexGetDepthLabel(), DMPlexGetHeightStratum(), DMPlexGetDepthStratum()
4306 @*/
4307 PetscErrorCode DMPlexGetDepth(DM dm, PetscInt *depth)
4308 {
4309   DMLabel        label;
4310   PetscInt       d = 0;
4311   PetscErrorCode ierr;
4312 
4313   PetscFunctionBegin;
4314   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4315   PetscValidPointer(depth, 2);
4316   ierr = DMPlexGetDepthLabel(dm, &label);CHKERRQ(ierr);
4317   if (label) {ierr = DMLabelGetNumValues(label, &d);CHKERRQ(ierr);}
4318   *depth = d-1;
4319   PetscFunctionReturn(0);
4320 }
4321 
4322 #undef __FUNCT__
4323 #define __FUNCT__ "DMPlexGetDepthStratum"
4324 /*@
4325   DMPlexGetDepthStratum - Get the bounds [start, end) for all points at a certain depth.
4326 
4327   Not Collective
4328 
4329   Input Parameters:
4330 + dm           - The DMPlex object
4331 - stratumValue - The requested depth
4332 
4333   Output Parameters:
4334 + start - The first point at this depth
4335 - end   - One beyond the last point at this depth
4336 
4337   Level: developer
4338 
4339 .keywords: mesh, points
4340 .seealso: DMPlexGetHeightStratum(), DMPlexGetDepth()
4341 @*/
4342 PetscErrorCode DMPlexGetDepthStratum(DM dm, PetscInt stratumValue, PetscInt *start, PetscInt *end)
4343 {
4344   DMLabel        label;
4345   PetscInt       depth;
4346   PetscErrorCode ierr;
4347 
4348   PetscFunctionBegin;
4349   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4350   if (stratumValue < 0) {
4351     ierr = DMPlexGetChart(dm, start, end);CHKERRQ(ierr);
4352     PetscFunctionReturn(0);
4353   } else {
4354     PetscInt pStart, pEnd;
4355 
4356     if (start) *start = 0;
4357     if (end)   *end   = 0;
4358     ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
4359     if (pStart == pEnd) PetscFunctionReturn(0);
4360   }
4361   ierr = DMPlexGetDepthLabel(dm, &label);CHKERRQ(ierr);
4362   if (!label) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "No label named depth was found");CHKERRQ(ierr);
4363   /* Strata are sorted and contiguous -- In addition, depth/height is either full or 1-level */
4364   depth = stratumValue;
4365   if ((depth < 0) || (depth >= label->numStrata)) {
4366     if (start) *start = 0;
4367     if (end)   *end   = 0;
4368   } else {
4369     if (start) *start = label->points[label->stratumOffsets[depth]];
4370     if (end)   *end   = label->points[label->stratumOffsets[depth]+label->stratumSizes[depth]-1]+1;
4371   }
4372   PetscFunctionReturn(0);
4373 }
4374 
4375 #undef __FUNCT__
4376 #define __FUNCT__ "DMPlexGetHeightStratum"
4377 /*@
4378   DMPlexGetHeightStratum - Get the bounds [start, end) for all points at a certain height.
4379 
4380   Not Collective
4381 
4382   Input Parameters:
4383 + dm           - The DMPlex object
4384 - stratumValue - The requested height
4385 
4386   Output Parameters:
4387 + start - The first point at this height
4388 - end   - One beyond the last point at this height
4389 
4390   Level: developer
4391 
4392 .keywords: mesh, points
4393 .seealso: DMPlexGetDepthStratum(), DMPlexGetDepth()
4394 @*/
4395 PetscErrorCode DMPlexGetHeightStratum(DM dm, PetscInt stratumValue, PetscInt *start, PetscInt *end)
4396 {
4397   DMLabel        label;
4398   PetscInt       depth;
4399   PetscErrorCode ierr;
4400 
4401   PetscFunctionBegin;
4402   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4403   if (stratumValue < 0) {
4404     ierr = DMPlexGetChart(dm, start, end);CHKERRQ(ierr);
4405   } else {
4406     PetscInt pStart, pEnd;
4407 
4408     if (start) *start = 0;
4409     if (end)   *end   = 0;
4410     ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
4411     if (pStart == pEnd) PetscFunctionReturn(0);
4412   }
4413   ierr = DMPlexGetDepthLabel(dm, &label);CHKERRQ(ierr);
4414   if (!label) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "No label named depth was found");CHKERRQ(ierr);
4415   /* Strata are sorted and contiguous -- In addition, depth/height is either full or 1-level */
4416   depth = label->stratumValues[label->numStrata-1] - stratumValue;
4417   if ((depth < 0) || (depth >= label->numStrata)) {
4418     if (start) *start = 0;
4419     if (end)   *end   = 0;
4420   } else {
4421     if (start) *start = label->points[label->stratumOffsets[depth]];
4422     if (end)   *end   = label->points[label->stratumOffsets[depth]+label->stratumSizes[depth]-1]+1;
4423   }
4424   PetscFunctionReturn(0);
4425 }
4426 
4427 #undef __FUNCT__
4428 #define __FUNCT__ "DMPlexCreateSectionInitial"
4429 /* Set the number of dof on each point and separate by fields */
4430 PetscErrorCode DMPlexCreateSectionInitial(DM dm, PetscInt dim, PetscInt numFields,const PetscInt numComp[],const PetscInt numDof[], PetscSection *section)
4431 {
4432   PetscInt      *numDofTot;
4433   PetscInt       pStart = 0, pEnd = 0;
4434   PetscInt       p, d, f;
4435   PetscErrorCode ierr;
4436 
4437   PetscFunctionBegin;
4438   ierr = PetscMalloc((dim+1) * sizeof(PetscInt), &numDofTot);CHKERRQ(ierr);
4439   for (d = 0; d <= dim; ++d) {
4440     numDofTot[d] = 0;
4441     for (f = 0; f < numFields; ++f) numDofTot[d] += numDof[f*(dim+1)+d];
4442   }
4443   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)dm), section);CHKERRQ(ierr);
4444   if (numFields > 0) {
4445     ierr = PetscSectionSetNumFields(*section, numFields);CHKERRQ(ierr);
4446     if (numComp) {
4447       for (f = 0; f < numFields; ++f) {
4448         ierr = PetscSectionSetFieldComponents(*section, f, numComp[f]);CHKERRQ(ierr);
4449       }
4450     }
4451   }
4452   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
4453   ierr = PetscSectionSetChart(*section, pStart, pEnd);CHKERRQ(ierr);
4454   for (d = 0; d <= dim; ++d) {
4455     ierr = DMPlexGetDepthStratum(dm, d, &pStart, &pEnd);CHKERRQ(ierr);
4456     for (p = pStart; p < pEnd; ++p) {
4457       for (f = 0; f < numFields; ++f) {
4458         ierr = PetscSectionSetFieldDof(*section, p, f, numDof[f*(dim+1)+d]);CHKERRQ(ierr);
4459       }
4460       ierr = PetscSectionSetDof(*section, p, numDofTot[d]);CHKERRQ(ierr);
4461     }
4462   }
4463   ierr = PetscFree(numDofTot);CHKERRQ(ierr);
4464   PetscFunctionReturn(0);
4465 }
4466 
4467 #undef __FUNCT__
4468 #define __FUNCT__ "DMPlexCreateSectionBCDof"
4469 /* Set the number of dof on each point and separate by fields
4470    If constDof is PETSC_DETERMINE, constrain every dof on the point
4471 */
4472 PetscErrorCode DMPlexCreateSectionBCDof(DM dm, PetscInt numBC,const PetscInt bcField[],const IS bcPoints[], PetscInt constDof, PetscSection section)
4473 {
4474   PetscInt       numFields;
4475   PetscInt       bc;
4476   PetscErrorCode ierr;
4477 
4478   PetscFunctionBegin;
4479   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
4480   for (bc = 0; bc < numBC; ++bc) {
4481     PetscInt        field = 0;
4482     const PetscInt *idx;
4483     PetscInt        n, i;
4484 
4485     if (numFields) field = bcField[bc];
4486     ierr = ISGetLocalSize(bcPoints[bc], &n);CHKERRQ(ierr);
4487     ierr = ISGetIndices(bcPoints[bc], &idx);CHKERRQ(ierr);
4488     for (i = 0; i < n; ++i) {
4489       const PetscInt p        = idx[i];
4490       PetscInt       numConst = constDof;
4491 
4492       /* Constrain every dof on the point */
4493       if (numConst < 0) {
4494         if (numFields) {
4495           ierr = PetscSectionGetFieldDof(section, p, field, &numConst);CHKERRQ(ierr);
4496         } else {
4497           ierr = PetscSectionGetDof(section, p, &numConst);CHKERRQ(ierr);
4498         }
4499       }
4500       if (numFields) {
4501         ierr = PetscSectionAddFieldConstraintDof(section, p, field, numConst);CHKERRQ(ierr);
4502       }
4503       ierr = PetscSectionAddConstraintDof(section, p, numConst);CHKERRQ(ierr);
4504     }
4505     ierr = ISRestoreIndices(bcPoints[bc], &idx);CHKERRQ(ierr);
4506   }
4507   PetscFunctionReturn(0);
4508 }
4509 
4510 #undef __FUNCT__
4511 #define __FUNCT__ "DMPlexCreateSectionBCIndicesAll"
4512 /* Set the constrained indices on each point and separate by fields */
4513 PetscErrorCode DMPlexCreateSectionBCIndicesAll(DM dm, PetscSection section)
4514 {
4515   PetscInt      *maxConstraints;
4516   PetscInt       numFields, f, pStart = 0, pEnd = 0, p;
4517   PetscErrorCode ierr;
4518 
4519   PetscFunctionBegin;
4520   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
4521   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
4522   ierr = PetscMalloc((numFields+1) * sizeof(PetscInt), &maxConstraints);CHKERRQ(ierr);
4523   for (f = 0; f <= numFields; ++f) maxConstraints[f] = 0;
4524   for (p = pStart; p < pEnd; ++p) {
4525     PetscInt cdof;
4526 
4527     if (numFields) {
4528       for (f = 0; f < numFields; ++f) {
4529         ierr              = PetscSectionGetFieldConstraintDof(section, p, f, &cdof);CHKERRQ(ierr);
4530         maxConstraints[f] = PetscMax(maxConstraints[f], cdof);
4531       }
4532     } else {
4533       ierr              = PetscSectionGetConstraintDof(section, p, &cdof);CHKERRQ(ierr);
4534       maxConstraints[0] = PetscMax(maxConstraints[0], cdof);
4535     }
4536   }
4537   for (f = 0; f < numFields; ++f) {
4538     maxConstraints[numFields] += maxConstraints[f];
4539   }
4540   if (maxConstraints[numFields]) {
4541     PetscInt *indices;
4542 
4543     ierr = PetscMalloc(maxConstraints[numFields] * sizeof(PetscInt), &indices);CHKERRQ(ierr);
4544     for (p = pStart; p < pEnd; ++p) {
4545       PetscInt cdof, d;
4546 
4547       ierr = PetscSectionGetConstraintDof(section, p, &cdof);CHKERRQ(ierr);
4548       if (cdof) {
4549         if (cdof > maxConstraints[numFields]) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_LIB, "Likely memory corruption, point %D cDof %D > maxConstraints %D", p, cdof, maxConstraints[numFields]);
4550         if (numFields) {
4551           PetscInt numConst = 0, foff = 0;
4552 
4553           for (f = 0; f < numFields; ++f) {
4554             PetscInt cfdof, fdof;
4555 
4556             ierr = PetscSectionGetFieldDof(section, p, f, &fdof);CHKERRQ(ierr);
4557             ierr = PetscSectionGetFieldConstraintDof(section, p, f, &cfdof);CHKERRQ(ierr);
4558             /* Change constraint numbering from absolute local dof number to field relative local dof number */
4559             for (d = 0; d < cfdof; ++d) indices[numConst+d] = d;
4560             ierr = PetscSectionSetFieldConstraintIndices(section, p, f, &indices[numConst]);CHKERRQ(ierr);
4561             for (d = 0; d < cfdof; ++d) indices[numConst+d] += foff;
4562             numConst += cfdof;
4563             foff     += fdof;
4564           }
4565           if (cdof != numConst) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_LIB, "Total number of field constraints %D should be %D", numConst, cdof);
4566         } else {
4567           for (d = 0; d < cdof; ++d) indices[d] = d;
4568         }
4569         ierr = PetscSectionSetConstraintIndices(section, p, indices);CHKERRQ(ierr);
4570       }
4571     }
4572     ierr = PetscFree(indices);CHKERRQ(ierr);
4573   }
4574   ierr = PetscFree(maxConstraints);CHKERRQ(ierr);
4575   PetscFunctionReturn(0);
4576 }
4577 
4578 #undef __FUNCT__
4579 #define __FUNCT__ "DMPlexCreateSectionBCIndicesField"
4580 /* Set the constrained field indices on each point */
4581 PetscErrorCode DMPlexCreateSectionBCIndicesField(DM dm, PetscInt field, IS bcPoints, IS constraintIndices, PetscSection section)
4582 {
4583   const PetscInt *points, *indices;
4584   PetscInt        numFields, maxDof, numPoints, p, numConstraints;
4585   PetscErrorCode  ierr;
4586 
4587   PetscFunctionBegin;
4588   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
4589   if ((field < 0) || (field >= numFields)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Section field %d should be in [%d, %d)", field, 0, numFields);
4590 
4591   ierr = ISGetLocalSize(bcPoints, &numPoints);CHKERRQ(ierr);
4592   ierr = ISGetIndices(bcPoints, &points);CHKERRQ(ierr);
4593   if (!constraintIndices) {
4594     PetscInt *idx, i;
4595 
4596     ierr = PetscSectionGetMaxDof(section, &maxDof);CHKERRQ(ierr);
4597     ierr = PetscMalloc(maxDof * sizeof(PetscInt), &idx);CHKERRQ(ierr);
4598     for (i = 0; i < maxDof; ++i) idx[i] = i;
4599     for (p = 0; p < numPoints; ++p) {
4600       ierr = PetscSectionSetFieldConstraintIndices(section, points[p], field, idx);CHKERRQ(ierr);
4601     }
4602     ierr = PetscFree(idx);CHKERRQ(ierr);
4603   } else {
4604     ierr = ISGetLocalSize(constraintIndices, &numConstraints);CHKERRQ(ierr);
4605     ierr = ISGetIndices(constraintIndices, &indices);CHKERRQ(ierr);
4606     for (p = 0; p < numPoints; ++p) {
4607       PetscInt fcdof;
4608 
4609       ierr = PetscSectionGetFieldConstraintDof(section, points[p], field, &fcdof);CHKERRQ(ierr);
4610       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);
4611       ierr = PetscSectionSetFieldConstraintIndices(section, points[p], field, indices);CHKERRQ(ierr);
4612     }
4613     ierr = ISRestoreIndices(constraintIndices, &indices);CHKERRQ(ierr);
4614   }
4615   ierr = ISRestoreIndices(bcPoints, &points);CHKERRQ(ierr);
4616   PetscFunctionReturn(0);
4617 }
4618 
4619 #undef __FUNCT__
4620 #define __FUNCT__ "DMPlexCreateSectionBCIndices"
4621 /* Set the constrained indices on each point and separate by fields */
4622 PetscErrorCode DMPlexCreateSectionBCIndices(DM dm, PetscSection section)
4623 {
4624   PetscInt      *indices;
4625   PetscInt       numFields, maxDof, f, pStart = 0, pEnd = 0, p;
4626   PetscErrorCode ierr;
4627 
4628   PetscFunctionBegin;
4629   ierr = PetscSectionGetMaxDof(section, &maxDof);CHKERRQ(ierr);
4630   ierr = PetscMalloc(maxDof * sizeof(PetscInt), &indices);CHKERRQ(ierr);
4631   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
4632   if (!numFields) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "This function only works after users have set field constraint indices.");
4633   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
4634   for (p = pStart; p < pEnd; ++p) {
4635     PetscInt cdof, d;
4636 
4637     ierr = PetscSectionGetConstraintDof(section, p, &cdof);CHKERRQ(ierr);
4638     if (cdof) {
4639       PetscInt numConst = 0, foff = 0;
4640 
4641       for (f = 0; f < numFields; ++f) {
4642         const PetscInt *fcind;
4643         PetscInt        fdof, fcdof;
4644 
4645         ierr = PetscSectionGetFieldDof(section, p, f, &fdof);CHKERRQ(ierr);
4646         ierr = PetscSectionGetFieldConstraintDof(section, p, f, &fcdof);CHKERRQ(ierr);
4647         if (fcdof) {ierr = PetscSectionGetFieldConstraintIndices(section, p, f, &fcind);CHKERRQ(ierr);}
4648         /* Change constraint numbering from field relative local dof number to absolute local dof number */
4649         for (d = 0; d < fcdof; ++d) indices[numConst+d] = fcind[d]+foff;
4650         foff     += fdof;
4651         numConst += fcdof;
4652       }
4653       if (cdof != numConst) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_LIB, "Total number of field constraints %D should be %D", numConst, cdof);
4654       ierr = PetscSectionSetConstraintIndices(section, p, indices);CHKERRQ(ierr);
4655     }
4656   }
4657   ierr = PetscFree(indices);CHKERRQ(ierr);
4658   PetscFunctionReturn(0);
4659 }
4660 
4661 #undef __FUNCT__
4662 #define __FUNCT__ "DMPlexCreateSection"
4663 /*@C
4664   DMPlexCreateSection - Create a PetscSection based upon the dof layout specification provided.
4665 
4666   Not Collective
4667 
4668   Input Parameters:
4669 + dm        - The DMPlex object
4670 . dim       - The spatial dimension of the problem
4671 . numFields - The number of fields in the problem
4672 . numComp   - An array of size numFields that holds the number of components for each field
4673 . numDof    - An array of size numFields*(dim+1) which holds the number of dof for each field on a mesh piece of dimension d
4674 . numBC     - The number of boundary conditions
4675 . bcField   - An array of size numBC giving the field number for each boundry condition
4676 - bcPoints  - An array of size numBC giving an IS holding the sieve points to which each boundary condition applies
4677 
4678   Output Parameter:
4679 . section - The PetscSection object
4680 
4681   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
4682   nubmer of dof for field 0 on each edge.
4683 
4684   Level: developer
4685 
4686   Fortran Notes:
4687   A Fortran 90 version is available as DMPlexCreateSectionF90()
4688 
4689 .keywords: mesh, elements
4690 .seealso: DMPlexCreate(), PetscSectionCreate()
4691 @*/
4692 PetscErrorCode DMPlexCreateSection(DM dm, PetscInt dim, PetscInt numFields,const PetscInt numComp[],const PetscInt numDof[], PetscInt numBC,const PetscInt bcField[],const IS bcPoints[], PetscSection *section)
4693 {
4694   PetscErrorCode ierr;
4695 
4696   PetscFunctionBegin;
4697   ierr = DMPlexCreateSectionInitial(dm, dim, numFields, numComp, numDof, section);CHKERRQ(ierr);
4698   ierr = DMPlexCreateSectionBCDof(dm, numBC, bcField, bcPoints, PETSC_DETERMINE, *section);CHKERRQ(ierr);
4699   ierr = PetscSectionSetUp(*section);CHKERRQ(ierr);
4700   if (numBC) {ierr = DMPlexCreateSectionBCIndicesAll(dm, *section);CHKERRQ(ierr);}
4701   {
4702     PetscBool view = PETSC_FALSE;
4703 
4704     ierr = PetscOptionsHasName(((PetscObject) dm)->prefix, "-section_view", &view);CHKERRQ(ierr);
4705     if (view) {ierr = PetscSectionView(*section, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);}
4706   }
4707   PetscFunctionReturn(0);
4708 }
4709 
4710 #undef __FUNCT__
4711 #define __FUNCT__ "DMCreateCoordinateDM_Plex"
4712 PetscErrorCode DMCreateCoordinateDM_Plex(DM dm, DM *cdm)
4713 {
4714   PetscSection   section;
4715   PetscErrorCode ierr;
4716 
4717   PetscFunctionBegin;
4718   ierr = DMClone(dm, cdm);CHKERRQ(ierr);
4719   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)dm), &section);CHKERRQ(ierr);
4720   ierr = DMSetDefaultSection(*cdm, section);CHKERRQ(ierr);
4721   ierr = PetscSectionDestroy(&section);CHKERRQ(ierr);
4722   PetscFunctionReturn(0);
4723 }
4724 
4725 #undef __FUNCT__
4726 #define __FUNCT__ "DMPlexGetCoordinateSection"
4727 /*@
4728   DMPlexGetCoordinateSection - Retrieve the layout of coordinate values over the mesh.
4729 
4730   Not Collective
4731 
4732   Input Parameter:
4733 . dm - The DMPlex object
4734 
4735   Output Parameter:
4736 . section - The PetscSection object
4737 
4738   Level: intermediate
4739 
4740 .keywords: mesh, coordinates
4741 .seealso: DMGetCoordinateDM(), DMPlexGetDefaultSection(), DMPlexSetDefaultSection()
4742 @*/
4743 PetscErrorCode DMPlexGetCoordinateSection(DM dm, PetscSection *section)
4744 {
4745   DM             cdm;
4746   PetscErrorCode ierr;
4747 
4748   PetscFunctionBegin;
4749   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4750   PetscValidPointer(section, 2);
4751   ierr = DMGetCoordinateDM(dm, &cdm);CHKERRQ(ierr);
4752   ierr = DMGetDefaultSection(cdm, section);CHKERRQ(ierr);
4753   PetscFunctionReturn(0);
4754 }
4755 
4756 #undef __FUNCT__
4757 #define __FUNCT__ "DMPlexSetCoordinateSection"
4758 /*@
4759   DMPlexSetCoordinateSection - Set the layout of coordinate values over the mesh.
4760 
4761   Not Collective
4762 
4763   Input Parameters:
4764 + dm      - The DMPlex object
4765 - section - The PetscSection object
4766 
4767   Level: intermediate
4768 
4769 .keywords: mesh, coordinates
4770 .seealso: DMPlexGetCoordinateSection(), DMPlexGetDefaultSection(), DMPlexSetDefaultSection()
4771 @*/
4772 PetscErrorCode DMPlexSetCoordinateSection(DM dm, PetscSection section)
4773 {
4774   DM             cdm;
4775   PetscErrorCode ierr;
4776 
4777   PetscFunctionBegin;
4778   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
4779   PetscValidHeaderSpecific(section,PETSC_SECTION_CLASSID,2);
4780   ierr = DMGetCoordinateDM(dm, &cdm);CHKERRQ(ierr);
4781   ierr = DMSetDefaultSection(cdm, section);CHKERRQ(ierr);
4782   PetscFunctionReturn(0);
4783 }
4784 
4785 #undef __FUNCT__
4786 #define __FUNCT__ "DMPlexGetConeSection"
4787 PetscErrorCode DMPlexGetConeSection(DM dm, PetscSection *section)
4788 {
4789   DM_Plex *mesh = (DM_Plex*) dm->data;
4790 
4791   PetscFunctionBegin;
4792   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4793   if (section) *section = mesh->coneSection;
4794   PetscFunctionReturn(0);
4795 }
4796 
4797 #undef __FUNCT__
4798 #define __FUNCT__ "DMPlexGetSupportSection"
4799 PetscErrorCode DMPlexGetSupportSection(DM dm, PetscSection *section)
4800 {
4801   DM_Plex *mesh = (DM_Plex*) dm->data;
4802 
4803   PetscFunctionBegin;
4804   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4805   if (section) *section = mesh->supportSection;
4806   PetscFunctionReturn(0);
4807 }
4808 
4809 #undef __FUNCT__
4810 #define __FUNCT__ "DMPlexGetCones"
4811 PetscErrorCode DMPlexGetCones(DM dm, PetscInt *cones[])
4812 {
4813   DM_Plex *mesh = (DM_Plex*) dm->data;
4814 
4815   PetscFunctionBegin;
4816   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4817   if (cones) *cones = mesh->cones;
4818   PetscFunctionReturn(0);
4819 }
4820 
4821 #undef __FUNCT__
4822 #define __FUNCT__ "DMPlexGetConeOrientations"
4823 PetscErrorCode DMPlexGetConeOrientations(DM dm, PetscInt *coneOrientations[])
4824 {
4825   DM_Plex *mesh = (DM_Plex*) dm->data;
4826 
4827   PetscFunctionBegin;
4828   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4829   if (coneOrientations) *coneOrientations = mesh->coneOrientations;
4830   PetscFunctionReturn(0);
4831 }
4832 
4833 /******************************** FEM Support **********************************/
4834 
4835 #undef __FUNCT__
4836 #define __FUNCT__ "DMPlexVecGetClosure"
4837 /*@C
4838   DMPlexVecGetClosure - Get an array of the values on the closure of 'point'
4839 
4840   Not collective
4841 
4842   Input Parameters:
4843 + dm - The DM
4844 . section - The section describing the layout in v, or NULL to use the default section
4845 . v - The local vector
4846 - point - The sieve point in the DM
4847 
4848   Output Parameters:
4849 + csize - The number of values in the closure, or NULL
4850 - values - The array of values, which is a borrowed array and should not be freed
4851 
4852   Fortran Notes:
4853   Since it returns an array, this routine is only available in Fortran 90, and you must
4854   include petsc.h90 in your code.
4855 
4856   The csize argument is not present in the Fortran 90 binding since it is internal to the array.
4857 
4858   Level: intermediate
4859 
4860 .seealso DMPlexVecRestoreClosure(), DMPlexVecSetClosure(), DMPlexMatSetClosure()
4861 @*/
4862 PetscErrorCode DMPlexVecGetClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[])
4863 {
4864   PetscScalar   *array, *vArray;
4865   PetscInt      *points = NULL;
4866   PetscInt       offsets[32];
4867   PetscInt       depth, numFields, size = 0, numPoints, pStart, pEnd, p, q, f;
4868   PetscErrorCode ierr;
4869 
4870   PetscFunctionBegin;
4871   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4872   PetscValidHeaderSpecific(v, VEC_CLASSID, 3);
4873   if (!section) {
4874     ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
4875   }
4876   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
4877   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
4878   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
4879   if (numFields > 31) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
4880   ierr = PetscMemzero(offsets, 32 * sizeof(PetscInt));CHKERRQ(ierr);
4881   if (depth == 1 && numFields < 2) {
4882     const PetscInt *cone, *coneO;
4883 
4884     ierr = DMPlexGetConeSize(dm, point, &numPoints);CHKERRQ(ierr);
4885     ierr = DMPlexGetCone(dm, point, &cone);CHKERRQ(ierr);
4886     ierr = DMPlexGetConeOrientation(dm, point, &coneO);CHKERRQ(ierr);
4887     if (!values || !*values) {
4888       if ((point >= pStart) && (point < pEnd)) {
4889         PetscInt dof;
4890         ierr = PetscSectionGetDof(section, point, &dof);CHKERRQ(ierr);
4891         size += dof;
4892       }
4893       for (p = 0; p < numPoints; ++p) {
4894         const PetscInt cp = cone[p];
4895         PetscInt       dof;
4896 
4897         if ((cp < pStart) || (cp >= pEnd)) continue;
4898         ierr = PetscSectionGetDof(section, cp, &dof);CHKERRQ(ierr);
4899         size += dof;
4900       }
4901       if (!values) {
4902         if (csize) *csize = size;
4903         PetscFunctionReturn(0);
4904       }
4905       ierr = DMGetWorkArray(dm, size, PETSC_SCALAR, &array);CHKERRQ(ierr);
4906     } else {
4907       array = *values;
4908     }
4909     size = 0;
4910     ierr = VecGetArray(v, &vArray);CHKERRQ(ierr);
4911     if ((point >= pStart) && (point < pEnd)) {
4912       PetscInt     dof, off, d;
4913       PetscScalar *varr;
4914       ierr = PetscSectionGetDof(section, point, &dof);CHKERRQ(ierr);
4915       ierr = PetscSectionGetOffset(section, point, &off);CHKERRQ(ierr);
4916       varr = &vArray[off];
4917       for (d = 0; d < dof; ++d, ++offsets[0]) {
4918         array[offsets[0]] = varr[d];
4919       }
4920       size += dof;
4921     }
4922     for (p = 0; p < numPoints; ++p) {
4923       const PetscInt cp = cone[p];
4924       PetscInt       o  = coneO[p];
4925       PetscInt       dof, off, d;
4926       PetscScalar   *varr;
4927 
4928       if ((cp < pStart) || (cp >= pEnd)) continue;
4929       ierr = PetscSectionGetDof(section, cp, &dof);CHKERRQ(ierr);
4930       ierr = PetscSectionGetOffset(section, cp, &off);CHKERRQ(ierr);
4931       varr = &vArray[off];
4932       if (o >= 0) {
4933         for (d = 0; d < dof; ++d, ++offsets[0]) {
4934           array[offsets[0]] = varr[d];
4935         }
4936       } else {
4937         for (d = dof-1; d >= 0; --d, ++offsets[0]) {
4938           array[offsets[0]] = varr[d];
4939         }
4940       }
4941       size += dof;
4942     }
4943     ierr = VecRestoreArray(v, &vArray);CHKERRQ(ierr);
4944     if (!*values) {
4945       if (csize) *csize = size;
4946       *values = array;
4947     } else {
4948       if (size > *csize) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %d < actual size %d", *csize, size);
4949       *csize = size;
4950     }
4951     PetscFunctionReturn(0);
4952   }
4953   ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
4954   /* Compress out points not in the section */
4955   for (p = 0, q = 0; p < numPoints*2; p += 2) {
4956     if ((points[p] >= pStart) && (points[p] < pEnd)) {
4957       points[q*2]   = points[p];
4958       points[q*2+1] = points[p+1];
4959       ++q;
4960     }
4961   }
4962   numPoints = q;
4963   if (!values || !*values) {
4964     for (p = 0, size = 0; p < numPoints*2; p += 2) {
4965       PetscInt dof, fdof;
4966 
4967       ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
4968       for (f = 0; f < numFields; ++f) {
4969         ierr          = PetscSectionGetFieldDof(section, points[p], f, &fdof);CHKERRQ(ierr);
4970         offsets[f+1] += fdof;
4971       }
4972       size += dof;
4973     }
4974     if (!values) {
4975       ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
4976       if (csize) *csize = size;
4977       PetscFunctionReturn(0);
4978     }
4979     ierr = DMGetWorkArray(dm, size, PETSC_SCALAR, &array);CHKERRQ(ierr);
4980   } else {
4981     array = *values;
4982   }
4983   for (f = 1; f < numFields; ++f) offsets[f+1] += offsets[f];
4984   if (numFields && offsets[numFields] != size) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid size for closure %d should be %d", offsets[numFields], size);
4985   ierr = VecGetArray(v, &vArray);CHKERRQ(ierr);
4986   for (p = 0; p < numPoints*2; p += 2) {
4987     PetscInt     o = points[p+1];
4988     PetscInt     dof, off, d;
4989     PetscScalar *varr;
4990 
4991     ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
4992     ierr = PetscSectionGetOffset(section, points[p], &off);CHKERRQ(ierr);
4993     varr = &vArray[off];
4994     if (numFields) {
4995       PetscInt fdof, foff, fcomp, f, c;
4996 
4997       for (f = 0, foff = 0; f < numFields; ++f) {
4998         ierr = PetscSectionGetFieldDof(section, points[p], f, &fdof);CHKERRQ(ierr);
4999         if (o >= 0) {
5000           for (d = 0; d < fdof; ++d, ++offsets[f]) {
5001             array[offsets[f]] = varr[foff+d];
5002           }
5003         } else {
5004           ierr = PetscSectionGetFieldComponents(section, f, &fcomp);CHKERRQ(ierr);
5005           for (d = fdof/fcomp-1; d >= 0; --d) {
5006             for (c = 0; c < fcomp; ++c, ++offsets[f]) {
5007               array[offsets[f]] = varr[foff+d*fcomp+c];
5008             }
5009           }
5010         }
5011         foff += fdof;
5012       }
5013     } else {
5014       if (o >= 0) {
5015         for (d = 0; d < dof; ++d, ++offsets[0]) {
5016           array[offsets[0]] = varr[d];
5017         }
5018       } else {
5019         for (d = dof-1; d >= 0; --d, ++offsets[0]) {
5020           array[offsets[0]] = varr[d];
5021         }
5022       }
5023     }
5024   }
5025   ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
5026   ierr = VecRestoreArray(v, &vArray);CHKERRQ(ierr);
5027   if (!*values) {
5028     if (csize) *csize = size;
5029     *values = array;
5030   } else {
5031     if (size > *csize) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %d < actual size %d", *csize, size);
5032     *csize = size;
5033   }
5034   PetscFunctionReturn(0);
5035 }
5036 
5037 #undef __FUNCT__
5038 #define __FUNCT__ "DMPlexVecRestoreClosure"
5039 /*@C
5040   DMPlexVecRestoreClosure - Restore the array of the values on the closure of 'point'
5041 
5042   Not collective
5043 
5044   Input Parameters:
5045 + dm - The DM
5046 . section - The section describing the layout in v, or NULL to use the default section
5047 . v - The local vector
5048 . point - The sieve point in the DM
5049 . csize - The number of values in the closure, or NULL
5050 - values - The array of values, which is a borrowed array and should not be freed
5051 
5052   Fortran Notes:
5053   Since it returns an array, this routine is only available in Fortran 90, and you must
5054   include petsc.h90 in your code.
5055 
5056   The csize argument is not present in the Fortran 90 binding since it is internal to the array.
5057 
5058   Level: intermediate
5059 
5060 .seealso DMPlexVecGetClosure(), DMPlexVecSetClosure(), DMPlexMatSetClosure()
5061 @*/
5062 PetscErrorCode DMPlexVecRestoreClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[])
5063 {
5064   PetscInt       size = 0;
5065   PetscErrorCode ierr;
5066 
5067   PetscFunctionBegin;
5068   /* Should work without recalculating size */
5069   ierr = DMRestoreWorkArray(dm, size, PETSC_SCALAR, (void*) values);CHKERRQ(ierr);
5070   PetscFunctionReturn(0);
5071 }
5072 
5073 PETSC_STATIC_INLINE void add   (PetscScalar *x, PetscScalar y) {*x += y;}
5074 PETSC_STATIC_INLINE void insert(PetscScalar *x, PetscScalar y) {*x  = y;}
5075 
5076 #undef __FUNCT__
5077 #define __FUNCT__ "updatePoint_private"
5078 PetscErrorCode updatePoint_private(PetscSection section, PetscInt point, PetscInt dof, void (*fuse)(PetscScalar*, PetscScalar), PetscBool setBC, PetscInt orientation, const PetscScalar values[], PetscScalar array[])
5079 {
5080   PetscInt        cdof;   /* The number of constraints on this point */
5081   const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
5082   PetscScalar    *a;
5083   PetscInt        off, cind = 0, k;
5084   PetscErrorCode  ierr;
5085 
5086   PetscFunctionBegin;
5087   ierr = PetscSectionGetConstraintDof(section, point, &cdof);CHKERRQ(ierr);
5088   ierr = PetscSectionGetOffset(section, point, &off);CHKERRQ(ierr);
5089   a    = &array[off];
5090   if (!cdof || setBC) {
5091     if (orientation >= 0) {
5092       for (k = 0; k < dof; ++k) {
5093         fuse(&a[k], values[k]);
5094       }
5095     } else {
5096       for (k = 0; k < dof; ++k) {
5097         fuse(&a[k], values[dof-k-1]);
5098       }
5099     }
5100   } else {
5101     ierr = PetscSectionGetConstraintIndices(section, point, &cdofs);CHKERRQ(ierr);
5102     if (orientation >= 0) {
5103       for (k = 0; k < dof; ++k) {
5104         if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
5105         fuse(&a[k], values[k]);
5106       }
5107     } else {
5108       for (k = 0; k < dof; ++k) {
5109         if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
5110         fuse(&a[k], values[dof-k-1]);
5111       }
5112     }
5113   }
5114   PetscFunctionReturn(0);
5115 }
5116 
5117 #undef __FUNCT__
5118 #define __FUNCT__ "updatePointBC_private"
5119 PetscErrorCode updatePointBC_private(PetscSection section, PetscInt point, PetscInt dof, void (*fuse)(PetscScalar*, PetscScalar), PetscInt orientation, const PetscScalar values[], PetscScalar array[])
5120 {
5121   PetscInt        cdof;   /* The number of constraints on this point */
5122   const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
5123   PetscScalar    *a;
5124   PetscInt        off, cind = 0, k;
5125   PetscErrorCode  ierr;
5126 
5127   PetscFunctionBegin;
5128   ierr = PetscSectionGetConstraintDof(section, point, &cdof);CHKERRQ(ierr);
5129   ierr = PetscSectionGetOffset(section, point, &off);CHKERRQ(ierr);
5130   a    = &array[off];
5131   if (cdof) {
5132     ierr = PetscSectionGetConstraintIndices(section, point, &cdofs);CHKERRQ(ierr);
5133     if (orientation >= 0) {
5134       for (k = 0; k < dof; ++k) {
5135         if ((cind < cdof) && (k == cdofs[cind])) {
5136           fuse(&a[k], values[k]);
5137           ++cind;
5138         }
5139       }
5140     } else {
5141       for (k = 0; k < dof; ++k) {
5142         if ((cind < cdof) && (k == cdofs[cind])) {
5143           fuse(&a[k], values[dof-k-1]);
5144           ++cind;
5145         }
5146       }
5147     }
5148   }
5149   PetscFunctionReturn(0);
5150 }
5151 
5152 #undef __FUNCT__
5153 #define __FUNCT__ "updatePointFields_private"
5154 PetscErrorCode updatePointFields_private(PetscSection section, PetscInt point, PetscInt foffs[], void (*fuse)(PetscScalar*, PetscScalar), PetscBool setBC, PetscInt orientation, const PetscScalar values[], PetscScalar array[])
5155 {
5156   PetscScalar   *a;
5157   PetscInt       numFields, off, foff, f;
5158   PetscErrorCode ierr;
5159 
5160   PetscFunctionBegin;
5161   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
5162   ierr = PetscSectionGetOffset(section, point, &off);CHKERRQ(ierr);
5163   a    = &array[off];
5164   for (f = 0, foff = 0; f < numFields; ++f) {
5165     PetscInt        fdof, fcomp, fcdof;
5166     const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
5167     PetscInt        cind = 0, k, c;
5168 
5169     ierr = PetscSectionGetFieldComponents(section, f, &fcomp);CHKERRQ(ierr);
5170     ierr = PetscSectionGetFieldDof(section, point, f, &fdof);CHKERRQ(ierr);
5171     ierr = PetscSectionGetFieldConstraintDof(section, point, f, &fcdof);CHKERRQ(ierr);
5172     if (!fcdof || setBC) {
5173       if (orientation >= 0) {
5174         for (k = 0; k < fdof; ++k) {
5175           fuse(&a[foff+k], values[foffs[f]+k]);
5176         }
5177       } else {
5178         for (k = fdof/fcomp-1; k >= 0; --k) {
5179           for (c = 0; c < fcomp; ++c) {
5180             fuse(&a[foff+(fdof/fcomp-1-k)*fcomp+c], values[foffs[f]+k*fcomp+c]);
5181           }
5182         }
5183       }
5184     } else {
5185       ierr = PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);CHKERRQ(ierr);
5186       if (orientation >= 0) {
5187         for (k = 0; k < fdof; ++k) {
5188           if ((cind < fcdof) && (k == fcdofs[cind])) {++cind; continue;}
5189           fuse(&a[foff+k], values[foffs[f]+k]);
5190         }
5191       } else {
5192         for (k = fdof/fcomp-1; k >= 0; --k) {
5193           for (c = 0; c < fcomp; ++c) {
5194             if ((cind < fcdof) && (k*fcomp+c == fcdofs[cind])) {++cind; continue;}
5195             fuse(&a[foff+(fdof/fcomp-1-k)*fcomp+c], values[foffs[f]+k*fcomp+c]);
5196           }
5197         }
5198       }
5199     }
5200     foff     += fdof;
5201     foffs[f] += fdof;
5202   }
5203   PetscFunctionReturn(0);
5204 }
5205 
5206 #undef __FUNCT__
5207 #define __FUNCT__ "updatePointFieldsBC_private"
5208 PetscErrorCode updatePointFieldsBC_private(PetscSection section, PetscInt point, PetscInt foffs[], void (*fuse)(PetscScalar*, PetscScalar), PetscInt orientation, const PetscScalar values[], PetscScalar array[])
5209 {
5210   PetscScalar   *a;
5211   PetscInt       numFields, off, foff, f;
5212   PetscErrorCode ierr;
5213 
5214   PetscFunctionBegin;
5215   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
5216   ierr = PetscSectionGetOffset(section, point, &off);CHKERRQ(ierr);
5217   a    = &array[off];
5218   for (f = 0, foff = 0; f < numFields; ++f) {
5219     PetscInt        fdof, fcomp, fcdof;
5220     const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
5221     PetscInt        cind = 0, k, c;
5222 
5223     ierr = PetscSectionGetFieldComponents(section, f, &fcomp);CHKERRQ(ierr);
5224     ierr = PetscSectionGetFieldDof(section, point, f, &fdof);CHKERRQ(ierr);
5225     ierr = PetscSectionGetFieldConstraintDof(section, point, f, &fcdof);CHKERRQ(ierr);
5226     if (fcdof) {
5227       ierr = PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);CHKERRQ(ierr);
5228       if (orientation >= 0) {
5229         for (k = 0; k < fdof; ++k) {
5230           if ((cind < fcdof) && (k == fcdofs[cind])) {
5231             fuse(&a[foff+k], values[foffs[f]+k]);
5232             ++cind;
5233           }
5234         }
5235       } else {
5236         for (k = fdof/fcomp-1; k >= 0; --k) {
5237           for (c = 0; c < fcomp; ++c) {
5238             if ((cind < fcdof) && (k*fcomp+c == fcdofs[cind])) {
5239               fuse(&a[foff+(fdof/fcomp-1-k)*fcomp+c], values[foffs[f]+k*fcomp+c]);
5240               ++cind;
5241             }
5242           }
5243         }
5244       }
5245     }
5246     foff     += fdof;
5247     foffs[f] += fdof;
5248   }
5249   PetscFunctionReturn(0);
5250 }
5251 
5252 #undef __FUNCT__
5253 #define __FUNCT__ "DMPlexVecSetClosure"
5254 /*@C
5255   DMPlexVecSetClosure - Set an array of the values on the closure of 'point'
5256 
5257   Not collective
5258 
5259   Input Parameters:
5260 + dm - The DM
5261 . section - The section describing the layout in v, or NULL to use the default section
5262 . v - The local vector
5263 . point - The sieve point in the DM
5264 . values - The array of values
5265 - mode - The insert mode, where INSERT_ALL_VALUES and ADD_ALL_VALUES also overwrite boundary conditions
5266 
5267   Fortran Notes:
5268   This routine is only available in Fortran 90, and you must include petsc.h90 in your code.
5269 
5270   Level: intermediate
5271 
5272 .seealso DMPlexVecGetClosure(), DMPlexMatSetClosure()
5273 @*/
5274 PetscErrorCode DMPlexVecSetClosure(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode)
5275 {
5276   PetscScalar   *array;
5277   PetscInt      *points = NULL;
5278   PetscInt       offsets[32];
5279   PetscInt       depth, numFields, numPoints, off, dof, pStart, pEnd, p, q, f;
5280   PetscErrorCode ierr;
5281 
5282   PetscFunctionBegin;
5283   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5284   PetscValidHeaderSpecific(v, VEC_CLASSID, 3);
5285   if (!section) {
5286     ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
5287   }
5288   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
5289   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
5290   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
5291   if (numFields > 31) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
5292   ierr = PetscMemzero(offsets, 32 * sizeof(PetscInt));CHKERRQ(ierr);
5293   if (depth == 1 && numFields < 2 && mode == ADD_VALUES) {
5294     const PetscInt *cone, *coneO;
5295 
5296     ierr = DMPlexGetConeSize(dm, point, &numPoints);CHKERRQ(ierr);
5297     ierr = DMPlexGetCone(dm, point, &cone);CHKERRQ(ierr);
5298     ierr = DMPlexGetConeOrientation(dm, point, &coneO);CHKERRQ(ierr);
5299     ierr = VecGetArray(v, &array);CHKERRQ(ierr);
5300     for (p = 0, off = 0; p <= numPoints; ++p, off += dof) {
5301       const PetscInt cp = !p ? point : cone[p-1];
5302       const PetscInt o  = !p ? 0     : coneO[p-1];
5303 
5304       if ((cp < pStart) || (cp >= pEnd)) {dof = 0; continue;}
5305       ierr = PetscSectionGetDof(section, cp, &dof);CHKERRQ(ierr);
5306       /* ADD_VALUES */
5307       {
5308         const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
5309         PetscScalar    *a;
5310         PetscInt        cdof, coff, cind = 0, k;
5311 
5312         ierr = PetscSectionGetConstraintDof(section, cp, &cdof);CHKERRQ(ierr);
5313         ierr = PetscSectionGetOffset(section, cp, &coff);CHKERRQ(ierr);
5314         a    = &array[coff];
5315         if (!cdof) {
5316           if (o >= 0) {
5317             for (k = 0; k < dof; ++k) {
5318               a[k] += values[off+k];
5319             }
5320           } else {
5321             for (k = 0; k < dof; ++k) {
5322               a[k] += values[off+dof-k-1];
5323             }
5324           }
5325         } else {
5326           ierr = PetscSectionGetConstraintIndices(section, cp, &cdofs);CHKERRQ(ierr);
5327           if (o >= 0) {
5328             for (k = 0; k < dof; ++k) {
5329               if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
5330               a[k] += values[off+k];
5331             }
5332           } else {
5333             for (k = 0; k < dof; ++k) {
5334               if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
5335               a[k] += values[off+dof-k-1];
5336             }
5337           }
5338         }
5339       }
5340     }
5341     ierr = VecRestoreArray(v, &array);CHKERRQ(ierr);
5342     PetscFunctionReturn(0);
5343   }
5344   ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
5345   /* Compress out points not in the section */
5346   for (p = 0, q = 0; p < numPoints*2; p += 2) {
5347     if ((points[p] >= pStart) && (points[p] < pEnd)) {
5348       points[q*2]   = points[p];
5349       points[q*2+1] = points[p+1];
5350       ++q;
5351     }
5352   }
5353   numPoints = q;
5354   for (p = 0; p < numPoints*2; p += 2) {
5355     PetscInt fdof;
5356 
5357     for (f = 0; f < numFields; ++f) {
5358       ierr          = PetscSectionGetFieldDof(section, points[p], f, &fdof);CHKERRQ(ierr);
5359       offsets[f+1] += fdof;
5360     }
5361   }
5362   for (f = 1; f < numFields; ++f) offsets[f+1] += offsets[f];
5363   ierr = VecGetArray(v, &array);CHKERRQ(ierr);
5364   if (numFields) {
5365     switch (mode) {
5366     case INSERT_VALUES:
5367       for (p = 0; p < numPoints*2; p += 2) {
5368         PetscInt o = points[p+1];
5369         updatePointFields_private(section, points[p], offsets, insert, PETSC_FALSE, o, values, array);
5370       } break;
5371     case INSERT_ALL_VALUES:
5372       for (p = 0; p < numPoints*2; p += 2) {
5373         PetscInt o = points[p+1];
5374         updatePointFields_private(section, points[p], offsets, insert, PETSC_TRUE,  o, values, array);
5375       } break;
5376     case INSERT_BC_VALUES:
5377       for (p = 0; p < numPoints*2; p += 2) {
5378         PetscInt o = points[p+1];
5379         updatePointFieldsBC_private(section, points[p], offsets, insert,  o, values, array);
5380       } break;
5381     case ADD_VALUES:
5382       for (p = 0; p < numPoints*2; p += 2) {
5383         PetscInt o = points[p+1];
5384         updatePointFields_private(section, points[p], offsets, add,    PETSC_FALSE, o, values, array);
5385       } break;
5386     case ADD_ALL_VALUES:
5387       for (p = 0; p < numPoints*2; p += 2) {
5388         PetscInt o = points[p+1];
5389         updatePointFields_private(section, points[p], offsets, add,    PETSC_TRUE,  o, values, array);
5390       } break;
5391     default:
5392       SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %D", mode);
5393     }
5394   } else {
5395     switch (mode) {
5396     case INSERT_VALUES:
5397       for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) {
5398         PetscInt o = points[p+1];
5399         ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
5400         updatePoint_private(section, points[p], dof, insert, PETSC_FALSE, o, &values[off], array);
5401       } break;
5402     case INSERT_ALL_VALUES:
5403       for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) {
5404         PetscInt o = points[p+1];
5405         ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
5406         updatePoint_private(section, points[p], dof, insert, PETSC_TRUE,  o, &values[off], array);
5407       } break;
5408     case INSERT_BC_VALUES:
5409       for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) {
5410         PetscInt o = points[p+1];
5411         ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
5412         updatePointBC_private(section, points[p], dof, insert,  o, &values[off], array);
5413       } break;
5414     case ADD_VALUES:
5415       for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) {
5416         PetscInt o = points[p+1];
5417         ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
5418         updatePoint_private(section, points[p], dof, add,    PETSC_FALSE, o, &values[off], array);
5419       } break;
5420     case ADD_ALL_VALUES:
5421       for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) {
5422         PetscInt o = points[p+1];
5423         ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
5424         updatePoint_private(section, points[p], dof, add,    PETSC_TRUE,  o, &values[off], array);
5425       } break;
5426     default:
5427       SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %D", mode);
5428     }
5429   }
5430   ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
5431   ierr = VecRestoreArray(v, &array);CHKERRQ(ierr);
5432   PetscFunctionReturn(0);
5433 }
5434 
5435 #undef __FUNCT__
5436 #define __FUNCT__ "DMPlexPrintMatSetValues"
5437 PetscErrorCode DMPlexPrintMatSetValues(PetscViewer viewer, Mat A, PetscInt point, PetscInt numIndices, const PetscInt indices[], const PetscScalar values[])
5438 {
5439   PetscMPIInt    rank;
5440   PetscInt       i, j;
5441   PetscErrorCode ierr;
5442 
5443   PetscFunctionBegin;
5444   ierr = MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank);CHKERRQ(ierr);
5445   ierr = PetscViewerASCIIPrintf(viewer, "[%D]mat for sieve point %D\n", rank, point);CHKERRQ(ierr);
5446   for (i = 0; i < numIndices; i++) {
5447     ierr = PetscViewerASCIIPrintf(viewer, "[%D]mat indices[%D] = %D\n", rank, i, indices[i]);CHKERRQ(ierr);
5448   }
5449   for (i = 0; i < numIndices; i++) {
5450     ierr = PetscViewerASCIIPrintf(viewer, "[%D]", rank);CHKERRQ(ierr);
5451     for (j = 0; j < numIndices; j++) {
5452 #if defined(PETSC_USE_COMPLEX)
5453       ierr = PetscViewerASCIIPrintf(viewer, " (%G,%G)", PetscRealPart(values[i*numIndices+j]), PetscImaginaryPart(values[i*numIndices+j]));CHKERRQ(ierr);
5454 #else
5455       ierr = PetscViewerASCIIPrintf(viewer, " %G", values[i*numIndices+j]);CHKERRQ(ierr);
5456 #endif
5457     }
5458     ierr = PetscViewerASCIIPrintf(viewer, "\n");CHKERRQ(ierr);
5459   }
5460   PetscFunctionReturn(0);
5461 }
5462 
5463 #undef __FUNCT__
5464 #define __FUNCT__ "indicesPoint_private"
5465 /* . off - The global offset of this point */
5466 PetscErrorCode indicesPoint_private(PetscSection section, PetscInt point, PetscInt off, PetscInt *loff, PetscBool setBC, PetscInt orientation, PetscInt indices[])
5467 {
5468   PetscInt        dof;    /* The number of unknowns on this point */
5469   PetscInt        cdof;   /* The number of constraints on this point */
5470   const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
5471   PetscInt        cind = 0, k;
5472   PetscErrorCode  ierr;
5473 
5474   PetscFunctionBegin;
5475   ierr = PetscSectionGetDof(section, point, &dof);CHKERRQ(ierr);
5476   ierr = PetscSectionGetConstraintDof(section, point, &cdof);CHKERRQ(ierr);
5477   if (!cdof || setBC) {
5478     if (orientation >= 0) {
5479       for (k = 0; k < dof; ++k) indices[*loff+k] = off+k;
5480     } else {
5481       for (k = 0; k < dof; ++k) indices[*loff+dof-k-1] = off+k;
5482     }
5483   } else {
5484     ierr = PetscSectionGetConstraintIndices(section, point, &cdofs);CHKERRQ(ierr);
5485     if (orientation >= 0) {
5486       for (k = 0; k < dof; ++k) {
5487         if ((cind < cdof) && (k == cdofs[cind])) {
5488           /* Insert check for returning constrained indices */
5489           indices[*loff+k] = -(off+k+1);
5490           ++cind;
5491         } else {
5492           indices[*loff+k] = off+k-cind;
5493         }
5494       }
5495     } else {
5496       for (k = 0; k < dof; ++k) {
5497         if ((cind < cdof) && (k == cdofs[cind])) {
5498           /* Insert check for returning constrained indices */
5499           indices[*loff+dof-k-1] = -(off+k+1);
5500           ++cind;
5501         } else {
5502           indices[*loff+dof-k-1] = off+k-cind;
5503         }
5504       }
5505     }
5506   }
5507   *loff += dof;
5508   PetscFunctionReturn(0);
5509 }
5510 
5511 #undef __FUNCT__
5512 #define __FUNCT__ "indicesPointFields_private"
5513 /* . off - The global offset of this point */
5514 PetscErrorCode indicesPointFields_private(PetscSection section, PetscInt point, PetscInt off, PetscInt foffs[], PetscBool setBC, PetscInt orientation, PetscInt indices[])
5515 {
5516   PetscInt       numFields, foff, f;
5517   PetscErrorCode ierr;
5518 
5519   PetscFunctionBegin;
5520   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
5521   for (f = 0, foff = 0; f < numFields; ++f) {
5522     PetscInt        fdof, fcomp, cfdof;
5523     const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
5524     PetscInt        cind = 0, k, c;
5525 
5526     ierr = PetscSectionGetFieldComponents(section, f, &fcomp);CHKERRQ(ierr);
5527     ierr = PetscSectionGetFieldDof(section, point, f, &fdof);CHKERRQ(ierr);
5528     ierr = PetscSectionGetFieldConstraintDof(section, point, f, &cfdof);CHKERRQ(ierr);
5529     if (!cfdof || setBC) {
5530       if (orientation >= 0) {
5531         for (k = 0; k < fdof; ++k) indices[foffs[f]+k] = off+foff+k;
5532       } else {
5533         for (k = fdof/fcomp-1; k >= 0; --k) {
5534           for (c = 0; c < fcomp; ++c) {
5535             indices[foffs[f]+k*fcomp+c] = off+foff+(fdof/fcomp-1-k)*fcomp+c;
5536           }
5537         }
5538       }
5539     } else {
5540       ierr = PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);CHKERRQ(ierr);
5541       if (orientation >= 0) {
5542         for (k = 0; k < fdof; ++k) {
5543           if ((cind < cfdof) && (k == fcdofs[cind])) {
5544             indices[foffs[f]+k] = -(off+foff+k+1);
5545             ++cind;
5546           } else {
5547             indices[foffs[f]+k] = off+foff+k-cind;
5548           }
5549         }
5550       } else {
5551         for (k = fdof/fcomp-1; k >= 0; --k) {
5552           for (c = 0; c < fcomp; ++c) {
5553             if ((cind < cfdof) && ((fdof/fcomp-1-k)*fcomp+c == fcdofs[cind])) {
5554               indices[foffs[f]+k*fcomp+c] = -(off+foff+(fdof/fcomp-1-k)*fcomp+c+1);
5555               ++cind;
5556             } else {
5557               indices[foffs[f]+k*fcomp+c] = off+foff+(fdof/fcomp-1-k)*fcomp+c-cind;
5558             }
5559           }
5560         }
5561       }
5562     }
5563     foff     += fdof - cfdof;
5564     foffs[f] += fdof;
5565   }
5566   PetscFunctionReturn(0);
5567 }
5568 
5569 #undef __FUNCT__
5570 #define __FUNCT__ "DMPlexMatSetClosure"
5571 /*@C
5572   DMPlexMatSetClosure - Set an array of the values on the closure of 'point'
5573 
5574   Not collective
5575 
5576   Input Parameters:
5577 + dm - The DM
5578 . section - The section describing the layout in v
5579 . globalSection - The section describing the layout in v
5580 . A - The matrix
5581 . point - The sieve point in the DM
5582 . values - The array of values
5583 - mode - The insert mode, where INSERT_ALL_VALUES and ADD_ALL_VALUES also overwrite boundary conditions
5584 
5585   Fortran Notes:
5586   This routine is only available in Fortran 90, and you must include petsc.h90 in your code.
5587 
5588   Level: intermediate
5589 
5590 .seealso DMPlexVecGetClosure(), DMPlexVecSetClosure()
5591 @*/
5592 PetscErrorCode DMPlexMatSetClosure(DM dm, PetscSection section, PetscSection globalSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode)
5593 {
5594   DM_Plex       *mesh   = (DM_Plex*) dm->data;
5595   PetscInt      *points = NULL;
5596   PetscInt      *indices;
5597   PetscInt       offsets[32];
5598   PetscInt       numFields, numPoints, numIndices, dof, off, globalOff, pStart, pEnd, p, q, f;
5599   PetscErrorCode ierr;
5600 
5601   PetscFunctionBegin;
5602   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5603   PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2);
5604   PetscValidHeaderSpecific(globalSection, PETSC_SECTION_CLASSID, 3);
5605   PetscValidHeaderSpecific(A, MAT_CLASSID, 4);
5606   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
5607   if (numFields > 31) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
5608   ierr = PetscMemzero(offsets, 32 * sizeof(PetscInt));CHKERRQ(ierr);
5609   ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
5610   /* Compress out points not in the section */
5611   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
5612   for (p = 0, q = 0; p < numPoints*2; p += 2) {
5613     if ((points[p] >= pStart) && (points[p] < pEnd)) {
5614       points[q*2]   = points[p];
5615       points[q*2+1] = points[p+1];
5616       ++q;
5617     }
5618   }
5619   numPoints = q;
5620   for (p = 0, numIndices = 0; p < numPoints*2; p += 2) {
5621     PetscInt fdof;
5622 
5623     ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
5624     for (f = 0; f < numFields; ++f) {
5625       ierr          = PetscSectionGetFieldDof(section, points[p], f, &fdof);CHKERRQ(ierr);
5626       offsets[f+1] += fdof;
5627     }
5628     numIndices += dof;
5629   }
5630   for (f = 1; f < numFields; ++f) offsets[f+1] += offsets[f];
5631 
5632   if (numFields && offsets[numFields] != numIndices) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid size for closure %d should be %d", offsets[numFields], numIndices);
5633   ierr = DMGetWorkArray(dm, numIndices, PETSC_INT, &indices);CHKERRQ(ierr);
5634   if (numFields) {
5635     for (p = 0; p < numPoints*2; p += 2) {
5636       PetscInt o = points[p+1];
5637       ierr = PetscSectionGetOffset(globalSection, points[p], &globalOff);CHKERRQ(ierr);
5638       indicesPointFields_private(section, points[p], globalOff < 0 ? -(globalOff+1) : globalOff, offsets, PETSC_FALSE, o, indices);
5639     }
5640   } else {
5641     for (p = 0, off = 0; p < numPoints*2; p += 2) {
5642       PetscInt o = points[p+1];
5643       ierr = PetscSectionGetOffset(globalSection, points[p], &globalOff);CHKERRQ(ierr);
5644       indicesPoint_private(section, points[p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, o, indices);
5645     }
5646   }
5647   if (mesh->printSetValues) {ierr = DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndices, indices, values);CHKERRQ(ierr);}
5648   ierr = MatSetValues(A, numIndices, indices, numIndices, indices, values, mode);
5649   if (ierr) {
5650     PetscMPIInt    rank;
5651     PetscErrorCode ierr2;
5652 
5653     ierr2 = MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank);CHKERRQ(ierr2);
5654     ierr2 = (*PetscErrorPrintf)("[%D]ERROR in DMPlexMatSetClosure\n", rank);CHKERRQ(ierr2);
5655     ierr2 = DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndices, indices, values);CHKERRQ(ierr2);
5656     ierr2 = DMRestoreWorkArray(dm, numIndices, PETSC_INT, &indices);CHKERRQ(ierr2);
5657     CHKERRQ(ierr);
5658   }
5659   ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
5660   ierr = DMRestoreWorkArray(dm, numIndices, PETSC_INT, &indices);CHKERRQ(ierr);
5661   PetscFunctionReturn(0);
5662 }
5663 
5664 #undef __FUNCT__
5665 #define __FUNCT__ "DMPlexGetHybridBounds"
5666 PetscErrorCode DMPlexGetHybridBounds(DM dm, PetscInt *cMax, PetscInt *fMax, PetscInt *eMax, PetscInt *vMax)
5667 {
5668   DM_Plex       *mesh = (DM_Plex*) dm->data;
5669   PetscInt       dim;
5670   PetscErrorCode ierr;
5671 
5672   PetscFunctionBegin;
5673   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5674   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
5675   if (cMax) *cMax = mesh->hybridPointMax[dim];
5676   if (fMax) *fMax = mesh->hybridPointMax[dim-1];
5677   if (eMax) *eMax = mesh->hybridPointMax[1];
5678   if (vMax) *vMax = mesh->hybridPointMax[0];
5679   PetscFunctionReturn(0);
5680 }
5681 
5682 #undef __FUNCT__
5683 #define __FUNCT__ "DMPlexSetHybridBounds"
5684 PetscErrorCode DMPlexSetHybridBounds(DM dm, PetscInt cMax, PetscInt fMax, PetscInt eMax, PetscInt vMax)
5685 {
5686   DM_Plex       *mesh = (DM_Plex*) dm->data;
5687   PetscInt       dim;
5688   PetscErrorCode ierr;
5689 
5690   PetscFunctionBegin;
5691   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5692   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
5693   if (cMax >= 0) mesh->hybridPointMax[dim]   = cMax;
5694   if (fMax >= 0) mesh->hybridPointMax[dim-1] = fMax;
5695   if (eMax >= 0) mesh->hybridPointMax[1]     = eMax;
5696   if (vMax >= 0) mesh->hybridPointMax[0]     = vMax;
5697   PetscFunctionReturn(0);
5698 }
5699 
5700 #undef __FUNCT__
5701 #define __FUNCT__ "DMPlexGetVTKCellHeight"
5702 PetscErrorCode DMPlexGetVTKCellHeight(DM dm, PetscInt *cellHeight)
5703 {
5704   DM_Plex *mesh = (DM_Plex*) dm->data;
5705 
5706   PetscFunctionBegin;
5707   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5708   PetscValidPointer(cellHeight, 2);
5709   *cellHeight = mesh->vtkCellHeight;
5710   PetscFunctionReturn(0);
5711 }
5712 
5713 #undef __FUNCT__
5714 #define __FUNCT__ "DMPlexSetVTKCellHeight"
5715 PetscErrorCode DMPlexSetVTKCellHeight(DM dm, PetscInt cellHeight)
5716 {
5717   DM_Plex *mesh = (DM_Plex*) dm->data;
5718 
5719   PetscFunctionBegin;
5720   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5721   mesh->vtkCellHeight = cellHeight;
5722   PetscFunctionReturn(0);
5723 }
5724 
5725 #undef __FUNCT__
5726 #define __FUNCT__ "DMPlexCreateNumbering_Private"
5727 /* We can easily have a form that takes an IS instead */
5728 PetscErrorCode DMPlexCreateNumbering_Private(DM dm, PetscInt pStart, PetscInt pEnd, PetscSF sf, IS *numbering)
5729 {
5730   PetscSection   section, globalSection;
5731   PetscInt      *numbers, p;
5732   PetscErrorCode ierr;
5733 
5734   PetscFunctionBegin;
5735   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)dm), &section);CHKERRQ(ierr);
5736   ierr = PetscSectionSetChart(section, pStart, pEnd);CHKERRQ(ierr);
5737   for (p = pStart; p < pEnd; ++p) {
5738     ierr = PetscSectionSetDof(section, p, 1);CHKERRQ(ierr);
5739   }
5740   ierr = PetscSectionSetUp(section);CHKERRQ(ierr);
5741   ierr = PetscSectionCreateGlobalSection(section, sf, PETSC_FALSE, &globalSection);CHKERRQ(ierr);
5742   ierr = PetscMalloc((pEnd - pStart) * sizeof(PetscInt), &numbers);CHKERRQ(ierr);
5743   for (p = pStart; p < pEnd; ++p) {
5744     ierr = PetscSectionGetOffset(globalSection, p, &numbers[p-pStart]);CHKERRQ(ierr);
5745   }
5746   ierr = ISCreateGeneral(PetscObjectComm((PetscObject)dm), pEnd - pStart, numbers, PETSC_OWN_POINTER, numbering);CHKERRQ(ierr);
5747   ierr = PetscSectionDestroy(&section);CHKERRQ(ierr);
5748   ierr = PetscSectionDestroy(&globalSection);CHKERRQ(ierr);
5749   PetscFunctionReturn(0);
5750 }
5751 
5752 #undef __FUNCT__
5753 #define __FUNCT__ "DMPlexGetCellNumbering"
5754 PetscErrorCode DMPlexGetCellNumbering(DM dm, IS *globalCellNumbers)
5755 {
5756   DM_Plex       *mesh = (DM_Plex*) dm->data;
5757   PetscInt       cellHeight, cStart, cEnd, cMax;
5758   PetscErrorCode ierr;
5759 
5760   PetscFunctionBegin;
5761   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5762   if (!mesh->globalCellNumbers) {
5763     ierr = DMPlexGetVTKCellHeight(dm, &cellHeight);CHKERRQ(ierr);
5764     ierr = DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd);CHKERRQ(ierr);
5765     ierr = DMPlexGetHybridBounds(dm, &cMax, NULL, NULL, NULL);CHKERRQ(ierr);
5766     if (cMax >= 0) cEnd = PetscMin(cEnd, cMax);
5767     ierr = DMPlexCreateNumbering_Private(dm, cStart, cEnd, dm->sf, &mesh->globalCellNumbers);CHKERRQ(ierr);
5768   }
5769   *globalCellNumbers = mesh->globalCellNumbers;
5770   PetscFunctionReturn(0);
5771 }
5772 
5773 #undef __FUNCT__
5774 #define __FUNCT__ "DMPlexGetVertexNumbering"
5775 PetscErrorCode DMPlexGetVertexNumbering(DM dm, IS *globalVertexNumbers)
5776 {
5777   DM_Plex       *mesh = (DM_Plex*) dm->data;
5778   PetscInt       vStart, vEnd, vMax;
5779   PetscErrorCode ierr;
5780 
5781   PetscFunctionBegin;
5782   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5783   if (!mesh->globalVertexNumbers) {
5784     ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
5785     ierr = DMPlexGetHybridBounds(dm, NULL, NULL, NULL, &vMax);CHKERRQ(ierr);
5786     if (vMax >= 0) vEnd = PetscMin(vEnd, vMax);
5787     ierr = DMPlexCreateNumbering_Private(dm, vStart, vEnd, dm->sf, &mesh->globalVertexNumbers);CHKERRQ(ierr);
5788   }
5789   *globalVertexNumbers = mesh->globalVertexNumbers;
5790   PetscFunctionReturn(0);
5791 }
5792 
5793 
5794 #undef __FUNCT__
5795 #define __FUNCT__ "PetscSectionCreateGlobalSectionLabel"
5796 /*@C
5797   PetscSectionCreateGlobalSectionLabel - Create a section describing the global field layout using
5798   the local section and an SF describing the section point overlap.
5799 
5800   Input Parameters:
5801   + s - The PetscSection for the local field layout
5802   . sf - The SF describing parallel layout of the section points
5803   . includeConstraints - By default this is PETSC_FALSE, meaning that the global field vector will not possess constrained dofs
5804   . label - The label specifying the points
5805   - labelValue - The label stratum specifying the points
5806 
5807   Output Parameter:
5808   . gsection - The PetscSection for the global field layout
5809 
5810   Note: This gives negative sizes and offsets to points not owned by this process
5811 
5812   Level: developer
5813 
5814 .seealso: PetscSectionCreate()
5815 @*/
5816 PetscErrorCode PetscSectionCreateGlobalSectionLabel(PetscSection s, PetscSF sf, PetscBool includeConstraints, DMLabel label, PetscInt labelValue, PetscSection *gsection)
5817 {
5818   PetscInt      *neg = NULL, *tmpOff = NULL;
5819   PetscInt       pStart, pEnd, p, dof, cdof, off, globalOff = 0, nroots;
5820   PetscErrorCode ierr;
5821 
5822   PetscFunctionBegin;
5823   ierr = PetscSectionCreate(s->atlasLayout.comm, gsection);CHKERRQ(ierr);
5824   ierr = PetscSectionGetChart(s, &pStart, &pEnd);CHKERRQ(ierr);
5825   ierr = PetscSectionSetChart(*gsection, pStart, pEnd);CHKERRQ(ierr);
5826   ierr = PetscSFGetGraph(sf, &nroots, NULL, NULL, NULL);CHKERRQ(ierr);
5827   if (nroots >= 0) {
5828     if (nroots < pEnd-pStart) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "PetscSF nroots %d < %d section size", nroots, pEnd-pStart);
5829     ierr = PetscMalloc(nroots * sizeof(PetscInt), &neg);CHKERRQ(ierr);
5830     ierr = PetscMemzero(neg, nroots * sizeof(PetscInt));CHKERRQ(ierr);
5831     if (nroots > pEnd-pStart) {
5832       ierr = PetscMalloc(nroots * sizeof(PetscInt), &tmpOff);CHKERRQ(ierr);
5833       ierr = PetscMemzero(tmpOff, nroots * sizeof(PetscInt));CHKERRQ(ierr);
5834     } else {
5835       tmpOff = &(*gsection)->atlasDof[-pStart];
5836     }
5837   }
5838   /* Mark ghost points with negative dof */
5839   for (p = pStart; p < pEnd; ++p) {
5840     PetscInt value;
5841 
5842     ierr = DMLabelGetValue(label, p, &value);CHKERRQ(ierr);
5843     if (value != labelValue) continue;
5844     ierr = PetscSectionGetDof(s, p, &dof);CHKERRQ(ierr);
5845     ierr = PetscSectionSetDof(*gsection, p, dof);CHKERRQ(ierr);
5846     ierr = PetscSectionGetConstraintDof(s, p, &cdof);CHKERRQ(ierr);
5847     if (!includeConstraints && cdof > 0) {ierr = PetscSectionSetConstraintDof(*gsection, p, cdof);CHKERRQ(ierr);}
5848     if (neg) neg[p] = -(dof+1);
5849   }
5850   ierr = PetscSectionSetUpBC(*gsection);CHKERRQ(ierr);
5851   if (nroots >= 0) {
5852     ierr = PetscSFBcastBegin(sf, MPIU_INT, neg, tmpOff);CHKERRQ(ierr);
5853     ierr = PetscSFBcastEnd(sf, MPIU_INT, neg, tmpOff);CHKERRQ(ierr);
5854     if (nroots > pEnd-pStart) {
5855       for (p = pStart; p < pEnd; ++p) {if (tmpOff[p] < 0) (*gsection)->atlasDof[p-pStart] = tmpOff[p];}
5856     }
5857   }
5858   /* Calculate new sizes, get proccess offset, and calculate point offsets */
5859   for (p = 0, off = 0; p < pEnd-pStart; ++p) {
5860     cdof = (!includeConstraints && s->bc) ? s->bc->atlasDof[p] : 0;
5861     (*gsection)->atlasOff[p] = off;
5862     off += (*gsection)->atlasDof[p] > 0 ? (*gsection)->atlasDof[p]-cdof : 0;
5863   }
5864   ierr       = MPI_Scan(&off, &globalOff, 1, MPIU_INT, MPI_SUM, s->atlasLayout.comm);CHKERRQ(ierr);
5865   globalOff -= off;
5866   for (p = 0, off = 0; p < pEnd-pStart; ++p) {
5867     (*gsection)->atlasOff[p] += globalOff;
5868     if (neg) neg[p] = -((*gsection)->atlasOff[p]+1);
5869   }
5870   /* Put in negative offsets for ghost points */
5871   if (nroots >= 0) {
5872     ierr = PetscSFBcastBegin(sf, MPIU_INT, neg, tmpOff);CHKERRQ(ierr);
5873     ierr = PetscSFBcastEnd(sf, MPIU_INT, neg, tmpOff);CHKERRQ(ierr);
5874     if (nroots > pEnd-pStart) {
5875       for (p = pStart; p < pEnd; ++p) {if (tmpOff[p] < 0) (*gsection)->atlasOff[p-pStart] = tmpOff[p];}
5876     }
5877   }
5878   if (nroots >= 0 && nroots > pEnd-pStart) {ierr = PetscFree(tmpOff);CHKERRQ(ierr);}
5879   ierr = PetscFree(neg);CHKERRQ(ierr);
5880   PetscFunctionReturn(0);
5881 }
5882 
5883 #undef __FUNCT__
5884 #define __FUNCT__ "DMPlexCheckSymmetry"
5885 /*@
5886   DMPlexCheckSymmetry - Check that the adjacency information in the mesh is symmetric.
5887 
5888   Input Parameters:
5889   + dm - The DMPlex object
5890 
5891   Note: This is a useful diagnostic when creating meshes programmatically.
5892 
5893   Level: developer
5894 
5895 .seealso: DMCreate()
5896 @*/
5897 PetscErrorCode DMPlexCheckSymmetry(DM dm)
5898 {
5899   PetscSection    coneSection, supportSection;
5900   const PetscInt *cone, *support;
5901   PetscInt        coneSize, c, supportSize, s;
5902   PetscInt        pStart, pEnd, p, csize, ssize;
5903   PetscErrorCode  ierr;
5904 
5905   PetscFunctionBegin;
5906   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5907   ierr = DMPlexGetConeSection(dm, &coneSection);CHKERRQ(ierr);
5908   ierr = DMPlexGetSupportSection(dm, &supportSection);CHKERRQ(ierr);
5909   /* Check that point p is found in the support of its cone points, and vice versa */
5910   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
5911   for (p = pStart; p < pEnd; ++p) {
5912     ierr = DMPlexGetConeSize(dm, p, &coneSize);CHKERRQ(ierr);
5913     ierr = DMPlexGetCone(dm, p, &cone);CHKERRQ(ierr);
5914     for (c = 0; c < coneSize; ++c) {
5915       ierr = DMPlexGetSupportSize(dm, cone[c], &supportSize);CHKERRQ(ierr);
5916       ierr = DMPlexGetSupport(dm, cone[c], &support);CHKERRQ(ierr);
5917       for (s = 0; s < supportSize; ++s) {
5918         if (support[s] == p) break;
5919       }
5920       if (s >= supportSize) {
5921         ierr = PetscPrintf(PETSC_COMM_SELF, "p: %d cone: ", p);
5922         for (s = 0; s < coneSize; ++s) {
5923           ierr = PetscPrintf(PETSC_COMM_SELF, "%d, ", cone[s]);
5924         }
5925         ierr = PetscPrintf(PETSC_COMM_SELF, "\n");
5926         ierr = PetscPrintf(PETSC_COMM_SELF, "p: %d support: ", cone[c]);
5927         for (s = 0; s < supportSize; ++s) {
5928           ierr = PetscPrintf(PETSC_COMM_SELF, "%d, ", support[s]);
5929         }
5930         ierr = PetscPrintf(PETSC_COMM_SELF, "\n");
5931         SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d not found in support of cone point %d", p, cone[c]);
5932       }
5933     }
5934     ierr = DMPlexGetSupportSize(dm, p, &supportSize);CHKERRQ(ierr);
5935     ierr = DMPlexGetSupport(dm, p, &support);CHKERRQ(ierr);
5936     for (s = 0; s < supportSize; ++s) {
5937       ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
5938       ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
5939       for (c = 0; c < coneSize; ++c) {
5940         if (cone[c] == p) break;
5941       }
5942       if (c >= coneSize) {
5943         ierr = PetscPrintf(PETSC_COMM_SELF, "p: %d support: ", p);
5944         for (c = 0; c < supportSize; ++c) {
5945           ierr = PetscPrintf(PETSC_COMM_SELF, "%d, ", support[c]);
5946         }
5947         ierr = PetscPrintf(PETSC_COMM_SELF, "\n");
5948         ierr = PetscPrintf(PETSC_COMM_SELF, "p: %d cone: ", support[s]);
5949         for (c = 0; c < coneSize; ++c) {
5950           ierr = PetscPrintf(PETSC_COMM_SELF, "%d, ", cone[c]);
5951         }
5952         ierr = PetscPrintf(PETSC_COMM_SELF, "\n");
5953         SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d not found in cone of support point %d", p, support[s]);
5954       }
5955     }
5956   }
5957   ierr = PetscSectionGetStorageSize(coneSection, &csize);CHKERRQ(ierr);
5958   ierr = PetscSectionGetStorageSize(supportSection, &ssize);CHKERRQ(ierr);
5959   if (csize != ssize) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Total cone size %d != Total support size %d", csize, ssize);
5960   PetscFunctionReturn(0);
5961 }
5962 
5963 #undef __FUNCT__
5964 #define __FUNCT__ "DMPlexCheckSkeleton"
5965 /*@
5966   DMPlexCheckSkeleton - Check that each cell has the correct number of vertices
5967 
5968   Input Parameters:
5969   + dm - The DMPlex object
5970 
5971   Note: This is a useful diagnostic when creating meshes programmatically.
5972 
5973   Level: developer
5974 
5975 .seealso: DMCreate()
5976 @*/
5977 PetscErrorCode DMPlexCheckSkeleton(DM dm, PetscBool isSimplex)
5978 {
5979   DM             udm;
5980   PetscInt       dim, numCorners, coneSize, cStart, cEnd, cMax, c;
5981   PetscErrorCode ierr;
5982 
5983   PetscFunctionBegin;
5984   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5985   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
5986   switch (dim) {
5987   case 2: numCorners = isSimplex ? 3 : 4; break;
5988   case 3: numCorners = isSimplex ? 4 : 8; break;
5989   default:
5990     SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_OUTOFRANGE, "Cannot handle meshes of dimension %d", dim);
5991   }
5992   ierr = DMPlexUninterpolate(dm, &udm);CHKERRQ(ierr);
5993   ierr = PetscObjectSetOptionsPrefix((PetscObject) udm, "un_");CHKERRQ(ierr);
5994   ierr = DMSetFromOptions(udm);CHKERRQ(ierr);
5995   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
5996   ierr = DMPlexGetHybridBounds(dm, &cMax, NULL, NULL, NULL);CHKERRQ(ierr);
5997   cMax = cMax >= 0 ? cMax : cEnd;
5998   for (c = cStart; c < cMax; ++c) {
5999     ierr = DMPlexGetConeSize(udm, c, &coneSize);CHKERRQ(ierr);
6000     if (coneSize != numCorners) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cell %d has  %d vertices != %d", c, coneSize, numCorners);
6001   }
6002   ierr = DMDestroy(&udm);CHKERRQ(ierr);
6003   PetscFunctionReturn(0);
6004 }
6005