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