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