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