xref: /petsc/src/dm/impls/plex/plex.c (revision abb99cbd9c18b27409b73921aa8d16d79a2ee5c1)
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;
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) {
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       ierr = DMGetWorkArray(dm, size, PETSC_SCALAR, &array);CHKERRQ(ierr);
4896     } else {
4897       array = *values;
4898     }
4899     size = 0;
4900     ierr = VecGetArray(v, &vArray);CHKERRQ(ierr);
4901     if ((point >= pStart) && (point < pEnd)) {
4902       PetscInt     dof, off, d;
4903       PetscScalar *varr;
4904       ierr = PetscSectionGetDof(section, point, &dof);CHKERRQ(ierr);
4905       ierr = PetscSectionGetOffset(section, point, &off);CHKERRQ(ierr);
4906       varr = &vArray[off];
4907       for (d = 0; d < dof; ++d, ++offsets[0]) {
4908         array[offsets[0]] = varr[d];
4909       }
4910       size += dof;
4911     }
4912     for (p = 0; p < numPoints; ++p) {
4913       const PetscInt cp = cone[p];
4914       PetscInt       o  = coneO[p];
4915       PetscInt       dof, off, d;
4916       PetscScalar   *varr;
4917 
4918       if ((cp < pStart) || (cp >= pEnd)) continue;
4919       ierr = PetscSectionGetDof(section, cp, &dof);CHKERRQ(ierr);
4920       ierr = PetscSectionGetOffset(section, cp, &off);CHKERRQ(ierr);
4921       varr = &vArray[off];
4922       if (o >= 0) {
4923         for (d = 0; d < dof; ++d, ++offsets[0]) {
4924           array[offsets[0]] = varr[d];
4925         }
4926       } else {
4927         for (d = dof-1; d >= 0; --d, ++offsets[0]) {
4928           array[offsets[0]] = varr[d];
4929         }
4930       }
4931       size += dof;
4932     }
4933     ierr = VecRestoreArray(v, &vArray);CHKERRQ(ierr);
4934     if (!*values) {
4935       if (csize) *csize = size;
4936       *values = array;
4937     } else {
4938       if (size > *csize) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %d < actual size %d", *csize, size);
4939       *csize = size;
4940     }
4941     PetscFunctionReturn(0);
4942   }
4943   ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
4944   /* Compress out points not in the section */
4945   for (p = 0, q = 0; p < numPoints*2; p += 2) {
4946     if ((points[p] >= pStart) && (points[p] < pEnd)) {
4947       points[q*2]   = points[p];
4948       points[q*2+1] = points[p+1];
4949       ++q;
4950     }
4951   }
4952   numPoints = q;
4953   for (p = 0, size = 0; p < numPoints*2; p += 2) {
4954     PetscInt dof, fdof;
4955 
4956     ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
4957     for (f = 0; f < numFields; ++f) {
4958       ierr          = PetscSectionGetFieldDof(section, points[p], f, &fdof);CHKERRQ(ierr);
4959       offsets[f+1] += fdof;
4960     }
4961     size += dof;
4962   }
4963   for (f = 1; f < numFields; ++f) offsets[f+1] += offsets[f];
4964   if (numFields && offsets[numFields] != size) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid size for closure %d should be %d", offsets[numFields], size);
4965   ierr = DMGetWorkArray(dm, size, PETSC_SCALAR, &array);CHKERRQ(ierr);
4966   ierr = VecGetArray(v, &vArray);CHKERRQ(ierr);
4967   for (p = 0; p < numPoints*2; p += 2) {
4968     PetscInt     o = points[p+1];
4969     PetscInt     dof, off, d;
4970     PetscScalar *varr;
4971 
4972     ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
4973     ierr = PetscSectionGetOffset(section, points[p], &off);CHKERRQ(ierr);
4974     varr = &vArray[off];
4975     if (numFields) {
4976       PetscInt fdof, foff, fcomp, f, c;
4977 
4978       for (f = 0, foff = 0; f < numFields; ++f) {
4979         ierr = PetscSectionGetFieldDof(section, points[p], f, &fdof);CHKERRQ(ierr);
4980         if (o >= 0) {
4981           for (d = 0; d < fdof; ++d, ++offsets[f]) {
4982             array[offsets[f]] = varr[foff+d];
4983           }
4984         } else {
4985           ierr = PetscSectionGetFieldComponents(section, f, &fcomp);CHKERRQ(ierr);
4986           for (d = fdof/fcomp-1; d >= 0; --d) {
4987             for (c = 0; c < fcomp; ++c, ++offsets[f]) {
4988               array[offsets[f]] = varr[foff+d*fcomp+c];
4989             }
4990           }
4991         }
4992         foff += fdof;
4993       }
4994     } else {
4995       if (o >= 0) {
4996         for (d = 0; d < dof; ++d, ++offsets[0]) {
4997           array[offsets[0]] = varr[d];
4998         }
4999       } else {
5000         for (d = dof-1; d >= 0; --d, ++offsets[0]) {
5001           array[offsets[0]] = varr[d];
5002         }
5003       }
5004     }
5005   }
5006   ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
5007   ierr = VecRestoreArray(v, &vArray);CHKERRQ(ierr);
5008   if (csize) *csize = size;
5009   *values = array;
5010   PetscFunctionReturn(0);
5011 }
5012 
5013 #undef __FUNCT__
5014 #define __FUNCT__ "DMPlexVecRestoreClosure"
5015 /*@C
5016   DMPlexVecRestoreClosure - Restore the array of the values on the closure of 'point'
5017 
5018   Not collective
5019 
5020   Input Parameters:
5021 + dm - The DM
5022 . section - The section describing the layout in v, or NULL to use the default section
5023 . v - The local vector
5024 . point - The sieve point in the DM
5025 . csize - The number of values in the closure, or NULL
5026 - values - The array of values, which is a borrowed array and should not be freed
5027 
5028   Fortran Notes:
5029   Since it returns an array, this routine is only available in Fortran 90, and you must
5030   include petsc.h90 in your code.
5031 
5032   The csize argument is not present in the Fortran 90 binding since it is internal to the array.
5033 
5034   Level: intermediate
5035 
5036 .seealso DMPlexVecGetClosure(), DMPlexVecSetClosure(), DMPlexMatSetClosure()
5037 @*/
5038 PetscErrorCode DMPlexVecRestoreClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[])
5039 {
5040   PetscInt       size = 0;
5041   PetscErrorCode ierr;
5042 
5043   PetscFunctionBegin;
5044   /* Should work without recalculating size */
5045   ierr = DMRestoreWorkArray(dm, size, PETSC_SCALAR, (void*) values);CHKERRQ(ierr);
5046   PetscFunctionReturn(0);
5047 }
5048 
5049 PETSC_STATIC_INLINE void add   (PetscScalar *x, PetscScalar y) {*x += y;}
5050 PETSC_STATIC_INLINE void insert(PetscScalar *x, PetscScalar y) {*x  = y;}
5051 
5052 #undef __FUNCT__
5053 #define __FUNCT__ "updatePoint_private"
5054 PetscErrorCode updatePoint_private(PetscSection section, PetscInt point, PetscInt dof, void (*fuse)(PetscScalar*, PetscScalar), PetscBool setBC, PetscInt orientation, const PetscScalar values[], PetscScalar array[])
5055 {
5056   PetscInt        cdof;   /* The number of constraints on this point */
5057   const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
5058   PetscScalar    *a;
5059   PetscInt        off, cind = 0, k;
5060   PetscErrorCode  ierr;
5061 
5062   PetscFunctionBegin;
5063   ierr = PetscSectionGetConstraintDof(section, point, &cdof);CHKERRQ(ierr);
5064   ierr = PetscSectionGetOffset(section, point, &off);CHKERRQ(ierr);
5065   a    = &array[off];
5066   if (!cdof || setBC) {
5067     if (orientation >= 0) {
5068       for (k = 0; k < dof; ++k) {
5069         fuse(&a[k], values[k]);
5070       }
5071     } else {
5072       for (k = 0; k < dof; ++k) {
5073         fuse(&a[k], values[dof-k-1]);
5074       }
5075     }
5076   } else {
5077     ierr = PetscSectionGetConstraintIndices(section, point, &cdofs);CHKERRQ(ierr);
5078     if (orientation >= 0) {
5079       for (k = 0; k < dof; ++k) {
5080         if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
5081         fuse(&a[k], values[k]);
5082       }
5083     } else {
5084       for (k = 0; k < dof; ++k) {
5085         if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
5086         fuse(&a[k], values[dof-k-1]);
5087       }
5088     }
5089   }
5090   PetscFunctionReturn(0);
5091 }
5092 
5093 #undef __FUNCT__
5094 #define __FUNCT__ "updatePointFields_private"
5095 PetscErrorCode updatePointFields_private(PetscSection section, PetscInt point, PetscInt foffs[], void (*fuse)(PetscScalar*, PetscScalar), PetscBool setBC, PetscInt orientation, const PetscScalar values[], PetscScalar array[])
5096 {
5097   PetscScalar   *a;
5098   PetscInt       numFields, off, foff, f;
5099   PetscErrorCode ierr;
5100 
5101   PetscFunctionBegin;
5102   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
5103   ierr = PetscSectionGetOffset(section, point, &off);CHKERRQ(ierr);
5104   a    = &array[off];
5105   for (f = 0, foff = 0; f < numFields; ++f) {
5106     PetscInt        fdof, fcomp, fcdof;
5107     const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
5108     PetscInt        cind = 0, k, c;
5109 
5110     ierr = PetscSectionGetFieldComponents(section, f, &fcomp);CHKERRQ(ierr);
5111     ierr = PetscSectionGetFieldDof(section, point, f, &fdof);CHKERRQ(ierr);
5112     ierr = PetscSectionGetFieldConstraintDof(section, point, f, &fcdof);CHKERRQ(ierr);
5113     if (!fcdof || setBC) {
5114       if (orientation >= 0) {
5115         for (k = 0; k < fdof; ++k) {
5116           fuse(&a[foff+k], values[foffs[f]+k]);
5117         }
5118       } else {
5119         for (k = fdof/fcomp-1; k >= 0; --k) {
5120           for (c = 0; c < fcomp; ++c) {
5121             fuse(&a[foff+(fdof/fcomp-1-k)*fcomp+c], values[foffs[f]+k*fcomp+c]);
5122           }
5123         }
5124       }
5125     } else {
5126       ierr = PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);CHKERRQ(ierr);
5127       if (orientation >= 0) {
5128         for (k = 0; k < fdof; ++k) {
5129           if ((cind < fcdof) && (k == fcdofs[cind])) {++cind; continue;}
5130           fuse(&a[foff+k], values[foffs[f]+k]);
5131         }
5132       } else {
5133         for (k = fdof/fcomp-1; k >= 0; --k) {
5134           for (c = 0; c < fcomp; ++c) {
5135             if ((cind < fcdof) && (k*fcomp+c == fcdofs[cind])) {++cind; continue;}
5136             fuse(&a[foff+(fdof/fcomp-1-k)*fcomp+c], values[foffs[f]+k*fcomp+c]);
5137           }
5138         }
5139       }
5140     }
5141     foff     += fdof;
5142     foffs[f] += fdof;
5143   }
5144   PetscFunctionReturn(0);
5145 }
5146 
5147 #undef __FUNCT__
5148 #define __FUNCT__ "DMPlexVecSetClosure"
5149 /*@C
5150   DMPlexVecSetClosure - Set an array of the values on the closure of 'point'
5151 
5152   Not collective
5153 
5154   Input Parameters:
5155 + dm - The DM
5156 . section - The section describing the layout in v, or NULL to use the default section
5157 . v - The local vector
5158 . point - The sieve point in the DM
5159 . values - The array of values
5160 - mode - The insert mode, where INSERT_ALL_VALUES and ADD_ALL_VALUES also overwrite boundary conditions
5161 
5162   Fortran Notes:
5163   This routine is only available in Fortran 90, and you must include petsc.h90 in your code.
5164 
5165   Level: intermediate
5166 
5167 .seealso DMPlexVecGetClosure(), DMPlexMatSetClosure()
5168 @*/
5169 PetscErrorCode DMPlexVecSetClosure(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode)
5170 {
5171   PetscScalar   *array;
5172   PetscInt      *points = NULL;
5173   PetscInt       offsets[32];
5174   PetscInt       depth, numFields, numPoints, off, dof, pStart, pEnd, p, q, f;
5175   PetscErrorCode ierr;
5176 
5177   PetscFunctionBegin;
5178   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5179   PetscValidHeaderSpecific(v, VEC_CLASSID, 3);
5180   if (!section) {
5181     ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
5182   }
5183   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
5184   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
5185   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
5186   if (numFields > 31) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
5187   ierr = PetscMemzero(offsets, 32 * sizeof(PetscInt));CHKERRQ(ierr);
5188   if (depth == 1 && numFields < 2 && mode == ADD_VALUES) {
5189     const PetscInt *cone, *coneO;
5190 
5191     ierr = DMPlexGetConeSize(dm, point, &numPoints);CHKERRQ(ierr);
5192     ierr = DMPlexGetCone(dm, point, &cone);CHKERRQ(ierr);
5193     ierr = DMPlexGetConeOrientation(dm, point, &coneO);CHKERRQ(ierr);
5194     ierr = VecGetArray(v, &array);CHKERRQ(ierr);
5195     for (p = 0, off = 0; p <= numPoints; ++p, off += dof) {
5196       const PetscInt cp = !p ? point : cone[p-1];
5197       const PetscInt o  = !p ? 0     : coneO[p-1];
5198 
5199       if ((cp < pStart) || (cp >= pEnd)) {dof = 0; continue;}
5200       ierr = PetscSectionGetDof(section, cp, &dof);CHKERRQ(ierr);
5201       /* ADD_VALUES */
5202       {
5203         const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
5204         PetscScalar    *a;
5205         PetscInt        cdof, coff, cind = 0, k;
5206 
5207         ierr = PetscSectionGetConstraintDof(section, cp, &cdof);CHKERRQ(ierr);
5208         ierr = PetscSectionGetOffset(section, cp, &coff);CHKERRQ(ierr);
5209         a    = &array[coff];
5210         if (!cdof) {
5211           if (o >= 0) {
5212             for (k = 0; k < dof; ++k) {
5213               a[k] += values[off+k];
5214             }
5215           } else {
5216             for (k = 0; k < dof; ++k) {
5217               a[k] += values[off+dof-k-1];
5218             }
5219           }
5220         } else {
5221           ierr = PetscSectionGetConstraintIndices(section, cp, &cdofs);CHKERRQ(ierr);
5222           if (o >= 0) {
5223             for (k = 0; k < dof; ++k) {
5224               if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
5225               a[k] += values[off+k];
5226             }
5227           } else {
5228             for (k = 0; k < dof; ++k) {
5229               if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
5230               a[k] += values[off+dof-k-1];
5231             }
5232           }
5233         }
5234       }
5235     }
5236     ierr = VecRestoreArray(v, &array);CHKERRQ(ierr);
5237     PetscFunctionReturn(0);
5238   }
5239   ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
5240   /* Compress out points not in the section */
5241   for (p = 0, q = 0; p < numPoints*2; p += 2) {
5242     if ((points[p] >= pStart) && (points[p] < pEnd)) {
5243       points[q*2]   = points[p];
5244       points[q*2+1] = points[p+1];
5245       ++q;
5246     }
5247   }
5248   numPoints = q;
5249   for (p = 0; p < numPoints*2; p += 2) {
5250     PetscInt fdof;
5251 
5252     for (f = 0; f < numFields; ++f) {
5253       ierr          = PetscSectionGetFieldDof(section, points[p], f, &fdof);CHKERRQ(ierr);
5254       offsets[f+1] += fdof;
5255     }
5256   }
5257   for (f = 1; f < numFields; ++f) offsets[f+1] += offsets[f];
5258   ierr = VecGetArray(v, &array);CHKERRQ(ierr);
5259   if (numFields) {
5260     switch (mode) {
5261     case INSERT_VALUES:
5262       for (p = 0; p < numPoints*2; p += 2) {
5263         PetscInt o = points[p+1];
5264         updatePointFields_private(section, points[p], offsets, insert, PETSC_FALSE, o, values, array);
5265       } break;
5266     case INSERT_ALL_VALUES:
5267       for (p = 0; p < numPoints*2; p += 2) {
5268         PetscInt o = points[p+1];
5269         updatePointFields_private(section, points[p], offsets, insert, PETSC_TRUE,  o, values, array);
5270       } break;
5271     case ADD_VALUES:
5272       for (p = 0; p < numPoints*2; p += 2) {
5273         PetscInt o = points[p+1];
5274         updatePointFields_private(section, points[p], offsets, add,    PETSC_FALSE, o, values, array);
5275       } break;
5276     case ADD_ALL_VALUES:
5277       for (p = 0; p < numPoints*2; p += 2) {
5278         PetscInt o = points[p+1];
5279         updatePointFields_private(section, points[p], offsets, add,    PETSC_TRUE,  o, values, array);
5280       } break;
5281     default:
5282       SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %D", mode);
5283     }
5284   } else {
5285     switch (mode) {
5286     case INSERT_VALUES:
5287       for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) {
5288         PetscInt o = points[p+1];
5289         ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
5290         updatePoint_private(section, points[p], dof, insert, PETSC_FALSE, o, &values[off], array);
5291       } break;
5292     case INSERT_ALL_VALUES:
5293       for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) {
5294         PetscInt o = points[p+1];
5295         ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
5296         updatePoint_private(section, points[p], dof, insert, PETSC_TRUE,  o, &values[off], array);
5297       } break;
5298     case ADD_VALUES:
5299       for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) {
5300         PetscInt o = points[p+1];
5301         ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
5302         updatePoint_private(section, points[p], dof, add,    PETSC_FALSE, o, &values[off], array);
5303       } break;
5304     case ADD_ALL_VALUES:
5305       for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) {
5306         PetscInt o = points[p+1];
5307         ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
5308         updatePoint_private(section, points[p], dof, add,    PETSC_TRUE,  o, &values[off], array);
5309       } break;
5310     default:
5311       SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %D", mode);
5312     }
5313   }
5314   ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
5315   ierr = VecRestoreArray(v, &array);CHKERRQ(ierr);
5316   PetscFunctionReturn(0);
5317 }
5318 
5319 #undef __FUNCT__
5320 #define __FUNCT__ "DMPlexPrintMatSetValues"
5321 PetscErrorCode DMPlexPrintMatSetValues(PetscViewer viewer, Mat A, PetscInt point, PetscInt numIndices, const PetscInt indices[], const PetscScalar values[])
5322 {
5323   PetscMPIInt    rank;
5324   PetscInt       i, j;
5325   PetscErrorCode ierr;
5326 
5327   PetscFunctionBegin;
5328   ierr = MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank);CHKERRQ(ierr);
5329   ierr = PetscViewerASCIIPrintf(viewer, "[%D]mat for sieve point %D\n", rank, point);CHKERRQ(ierr);
5330   for (i = 0; i < numIndices; i++) {
5331     ierr = PetscViewerASCIIPrintf(viewer, "[%D]mat indices[%D] = %D\n", rank, i, indices[i]);CHKERRQ(ierr);
5332   }
5333   for (i = 0; i < numIndices; i++) {
5334     ierr = PetscViewerASCIIPrintf(viewer, "[%D]", rank);CHKERRQ(ierr);
5335     for (j = 0; j < numIndices; j++) {
5336 #if defined(PETSC_USE_COMPLEX)
5337       ierr = PetscViewerASCIIPrintf(viewer, " (%G,%G)", PetscRealPart(values[i*numIndices+j]), PetscImaginaryPart(values[i*numIndices+j]));CHKERRQ(ierr);
5338 #else
5339       ierr = PetscViewerASCIIPrintf(viewer, " %G", values[i*numIndices+j]);CHKERRQ(ierr);
5340 #endif
5341     }
5342     ierr = PetscViewerASCIIPrintf(viewer, "\n");CHKERRQ(ierr);
5343   }
5344   PetscFunctionReturn(0);
5345 }
5346 
5347 #undef __FUNCT__
5348 #define __FUNCT__ "indicesPoint_private"
5349 /* . off - The global offset of this point */
5350 PetscErrorCode indicesPoint_private(PetscSection section, PetscInt point, PetscInt off, PetscInt *loff, PetscBool setBC, PetscInt orientation, PetscInt indices[])
5351 {
5352   PetscInt        dof;    /* The number of unknowns on this point */
5353   PetscInt        cdof;   /* The number of constraints on this point */
5354   const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
5355   PetscInt        cind = 0, k;
5356   PetscErrorCode  ierr;
5357 
5358   PetscFunctionBegin;
5359   ierr = PetscSectionGetDof(section, point, &dof);CHKERRQ(ierr);
5360   ierr = PetscSectionGetConstraintDof(section, point, &cdof);CHKERRQ(ierr);
5361   if (!cdof || setBC) {
5362     if (orientation >= 0) {
5363       for (k = 0; k < dof; ++k) indices[*loff+k] = off+k;
5364     } else {
5365       for (k = 0; k < dof; ++k) indices[*loff+dof-k-1] = off+k;
5366     }
5367   } else {
5368     ierr = PetscSectionGetConstraintIndices(section, point, &cdofs);CHKERRQ(ierr);
5369     if (orientation >= 0) {
5370       for (k = 0; k < dof; ++k) {
5371         if ((cind < cdof) && (k == cdofs[cind])) {
5372           /* Insert check for returning constrained indices */
5373           indices[*loff+k] = -(off+k+1);
5374           ++cind;
5375         } else {
5376           indices[*loff+k] = off+k-cind;
5377         }
5378       }
5379     } else {
5380       for (k = 0; k < dof; ++k) {
5381         if ((cind < cdof) && (k == cdofs[cind])) {
5382           /* Insert check for returning constrained indices */
5383           indices[*loff+dof-k-1] = -(off+k+1);
5384           ++cind;
5385         } else {
5386           indices[*loff+dof-k-1] = off+k-cind;
5387         }
5388       }
5389     }
5390   }
5391   *loff += dof;
5392   PetscFunctionReturn(0);
5393 }
5394 
5395 #undef __FUNCT__
5396 #define __FUNCT__ "indicesPointFields_private"
5397 /* . off - The global offset of this point */
5398 PetscErrorCode indicesPointFields_private(PetscSection section, PetscInt point, PetscInt off, PetscInt foffs[], PetscBool setBC, PetscInt orientation, PetscInt indices[])
5399 {
5400   PetscInt       numFields, foff, f;
5401   PetscErrorCode ierr;
5402 
5403   PetscFunctionBegin;
5404   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
5405   for (f = 0, foff = 0; f < numFields; ++f) {
5406     PetscInt        fdof, fcomp, cfdof;
5407     const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
5408     PetscInt        cind = 0, k, c;
5409 
5410     ierr = PetscSectionGetFieldComponents(section, f, &fcomp);CHKERRQ(ierr);
5411     ierr = PetscSectionGetFieldDof(section, point, f, &fdof);CHKERRQ(ierr);
5412     ierr = PetscSectionGetFieldConstraintDof(section, point, f, &cfdof);CHKERRQ(ierr);
5413     if (!cfdof || setBC) {
5414       if (orientation >= 0) {
5415         for (k = 0; k < fdof; ++k) indices[foffs[f]+k] = off+foff+k;
5416       } else {
5417         for (k = fdof/fcomp-1; k >= 0; --k) {
5418           for (c = 0; c < fcomp; ++c) {
5419             indices[foffs[f]+k*fcomp+c] = off+foff+(fdof/fcomp-1-k)*fcomp+c;
5420           }
5421         }
5422       }
5423     } else {
5424       ierr = PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);CHKERRQ(ierr);
5425       if (orientation >= 0) {
5426         for (k = 0; k < fdof; ++k) {
5427           if ((cind < cfdof) && (k == fcdofs[cind])) {
5428             indices[foffs[f]+k] = -(off+foff+k+1);
5429             ++cind;
5430           } else {
5431             indices[foffs[f]+k] = off+foff+k-cind;
5432           }
5433         }
5434       } else {
5435         for (k = fdof/fcomp-1; k >= 0; --k) {
5436           for (c = 0; c < fcomp; ++c) {
5437             if ((cind < cfdof) && ((fdof/fcomp-1-k)*fcomp+c == fcdofs[cind])) {
5438               indices[foffs[f]+k*fcomp+c] = -(off+foff+(fdof/fcomp-1-k)*fcomp+c+1);
5439               ++cind;
5440             } else {
5441               indices[foffs[f]+k*fcomp+c] = off+foff+(fdof/fcomp-1-k)*fcomp+c-cind;
5442             }
5443           }
5444         }
5445       }
5446     }
5447     foff     += fdof - cfdof;
5448     foffs[f] += fdof;
5449   }
5450   PetscFunctionReturn(0);
5451 }
5452 
5453 #undef __FUNCT__
5454 #define __FUNCT__ "DMPlexMatSetClosure"
5455 /*@C
5456   DMPlexMatSetClosure - Set an array of the values on the closure of 'point'
5457 
5458   Not collective
5459 
5460   Input Parameters:
5461 + dm - The DM
5462 . section - The section describing the layout in v
5463 . globalSection - The section describing the layout in v
5464 . A - The matrix
5465 . point - The sieve point in the DM
5466 . values - The array of values
5467 - mode - The insert mode, where INSERT_ALL_VALUES and ADD_ALL_VALUES also overwrite boundary conditions
5468 
5469   Fortran Notes:
5470   This routine is only available in Fortran 90, and you must include petsc.h90 in your code.
5471 
5472   Level: intermediate
5473 
5474 .seealso DMPlexVecGetClosure(), DMPlexVecSetClosure()
5475 @*/
5476 PetscErrorCode DMPlexMatSetClosure(DM dm, PetscSection section, PetscSection globalSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode)
5477 {
5478   DM_Plex       *mesh   = (DM_Plex*) dm->data;
5479   PetscInt      *points = NULL;
5480   PetscInt      *indices;
5481   PetscInt       offsets[32];
5482   PetscInt       numFields, numPoints, numIndices, dof, off, globalOff, pStart, pEnd, p, q, f;
5483   PetscErrorCode ierr;
5484 
5485   PetscFunctionBegin;
5486   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5487   PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2);
5488   PetscValidHeaderSpecific(globalSection, PETSC_SECTION_CLASSID, 3);
5489   PetscValidHeaderSpecific(A, MAT_CLASSID, 4);
5490   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
5491   if (numFields > 31) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
5492   ierr = PetscMemzero(offsets, 32 * sizeof(PetscInt));CHKERRQ(ierr);
5493   ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
5494   /* Compress out points not in the section */
5495   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
5496   for (p = 0, q = 0; p < numPoints*2; p += 2) {
5497     if ((points[p] >= pStart) && (points[p] < pEnd)) {
5498       points[q*2]   = points[p];
5499       points[q*2+1] = points[p+1];
5500       ++q;
5501     }
5502   }
5503   numPoints = q;
5504   for (p = 0, numIndices = 0; p < numPoints*2; p += 2) {
5505     PetscInt fdof;
5506 
5507     ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
5508     for (f = 0; f < numFields; ++f) {
5509       ierr          = PetscSectionGetFieldDof(section, points[p], f, &fdof);CHKERRQ(ierr);
5510       offsets[f+1] += fdof;
5511     }
5512     numIndices += dof;
5513   }
5514   for (f = 1; f < numFields; ++f) offsets[f+1] += offsets[f];
5515 
5516   if (numFields && offsets[numFields] != numIndices) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid size for closure %d should be %d", offsets[numFields], numIndices);
5517   ierr = DMGetWorkArray(dm, numIndices, PETSC_INT, &indices);CHKERRQ(ierr);
5518   if (numFields) {
5519     for (p = 0; p < numPoints*2; p += 2) {
5520       PetscInt o = points[p+1];
5521       ierr = PetscSectionGetOffset(globalSection, points[p], &globalOff);CHKERRQ(ierr);
5522       indicesPointFields_private(section, points[p], globalOff < 0 ? -(globalOff+1) : globalOff, offsets, PETSC_FALSE, o, indices);
5523     }
5524   } else {
5525     for (p = 0, off = 0; p < numPoints*2; p += 2) {
5526       PetscInt o = points[p+1];
5527       ierr = PetscSectionGetOffset(globalSection, points[p], &globalOff);CHKERRQ(ierr);
5528       indicesPoint_private(section, points[p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, o, indices);
5529     }
5530   }
5531   if (mesh->printSetValues) {ierr = DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndices, indices, values);CHKERRQ(ierr);}
5532   ierr = MatSetValues(A, numIndices, indices, numIndices, indices, values, mode);
5533   if (ierr) {
5534     PetscMPIInt    rank;
5535     PetscErrorCode ierr2;
5536 
5537     ierr2 = MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank);CHKERRQ(ierr2);
5538     ierr2 = (*PetscErrorPrintf)("[%D]ERROR in DMPlexMatSetClosure\n", rank);CHKERRQ(ierr2);
5539     ierr2 = DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndices, indices, values);CHKERRQ(ierr2);
5540     ierr2 = DMRestoreWorkArray(dm, numIndices, PETSC_INT, &indices);CHKERRQ(ierr2);
5541     CHKERRQ(ierr);
5542   }
5543   ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
5544   ierr = DMRestoreWorkArray(dm, numIndices, PETSC_INT, &indices);CHKERRQ(ierr);
5545   PetscFunctionReturn(0);
5546 }
5547 
5548 #undef __FUNCT__
5549 #define __FUNCT__ "DMPlexGetHybridBounds"
5550 PetscErrorCode DMPlexGetHybridBounds(DM dm, PetscInt *cMax, PetscInt *fMax, PetscInt *eMax, PetscInt *vMax)
5551 {
5552   DM_Plex       *mesh = (DM_Plex*) dm->data;
5553   PetscInt       dim;
5554   PetscErrorCode ierr;
5555 
5556   PetscFunctionBegin;
5557   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5558   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
5559   if (cMax) *cMax = mesh->hybridPointMax[dim];
5560   if (fMax) *fMax = mesh->hybridPointMax[dim-1];
5561   if (eMax) *eMax = mesh->hybridPointMax[1];
5562   if (vMax) *vMax = mesh->hybridPointMax[0];
5563   PetscFunctionReturn(0);
5564 }
5565 
5566 #undef __FUNCT__
5567 #define __FUNCT__ "DMPlexSetHybridBounds"
5568 PetscErrorCode DMPlexSetHybridBounds(DM dm, PetscInt cMax, PetscInt fMax, PetscInt eMax, PetscInt vMax)
5569 {
5570   DM_Plex       *mesh = (DM_Plex*) dm->data;
5571   PetscInt       dim;
5572   PetscErrorCode ierr;
5573 
5574   PetscFunctionBegin;
5575   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5576   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
5577   if (cMax >= 0) mesh->hybridPointMax[dim]   = cMax;
5578   if (fMax >= 0) mesh->hybridPointMax[dim-1] = fMax;
5579   if (eMax >= 0) mesh->hybridPointMax[1]     = eMax;
5580   if (vMax >= 0) mesh->hybridPointMax[0]     = vMax;
5581   PetscFunctionReturn(0);
5582 }
5583 
5584 #undef __FUNCT__
5585 #define __FUNCT__ "DMPlexGetVTKCellHeight"
5586 PetscErrorCode DMPlexGetVTKCellHeight(DM dm, PetscInt *cellHeight)
5587 {
5588   DM_Plex *mesh = (DM_Plex*) dm->data;
5589 
5590   PetscFunctionBegin;
5591   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5592   PetscValidPointer(cellHeight, 2);
5593   *cellHeight = mesh->vtkCellHeight;
5594   PetscFunctionReturn(0);
5595 }
5596 
5597 #undef __FUNCT__
5598 #define __FUNCT__ "DMPlexSetVTKCellHeight"
5599 PetscErrorCode DMPlexSetVTKCellHeight(DM dm, PetscInt cellHeight)
5600 {
5601   DM_Plex *mesh = (DM_Plex*) dm->data;
5602 
5603   PetscFunctionBegin;
5604   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5605   mesh->vtkCellHeight = cellHeight;
5606   PetscFunctionReturn(0);
5607 }
5608 
5609 #undef __FUNCT__
5610 #define __FUNCT__ "DMPlexCreateNumbering_Private"
5611 /* We can easily have a form that takes an IS instead */
5612 PetscErrorCode DMPlexCreateNumbering_Private(DM dm, PetscInt pStart, PetscInt pEnd, PetscSF sf, IS *numbering)
5613 {
5614   PetscSection   section, globalSection;
5615   PetscInt      *numbers, p;
5616   PetscErrorCode ierr;
5617 
5618   PetscFunctionBegin;
5619   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)dm), &section);CHKERRQ(ierr);
5620   ierr = PetscSectionSetChart(section, pStart, pEnd);CHKERRQ(ierr);
5621   for (p = pStart; p < pEnd; ++p) {
5622     ierr = PetscSectionSetDof(section, p, 1);CHKERRQ(ierr);
5623   }
5624   ierr = PetscSectionSetUp(section);CHKERRQ(ierr);
5625   ierr = PetscSectionCreateGlobalSection(section, sf, PETSC_FALSE, &globalSection);CHKERRQ(ierr);
5626   ierr = PetscMalloc((pEnd - pStart) * sizeof(PetscInt), &numbers);CHKERRQ(ierr);
5627   for (p = pStart; p < pEnd; ++p) {
5628     ierr = PetscSectionGetOffset(globalSection, p, &numbers[p-pStart]);CHKERRQ(ierr);
5629   }
5630   ierr = ISCreateGeneral(PetscObjectComm((PetscObject)dm), pEnd - pStart, numbers, PETSC_OWN_POINTER, numbering);CHKERRQ(ierr);
5631   ierr = PetscSectionDestroy(&section);CHKERRQ(ierr);
5632   ierr = PetscSectionDestroy(&globalSection);CHKERRQ(ierr);
5633   PetscFunctionReturn(0);
5634 }
5635 
5636 #undef __FUNCT__
5637 #define __FUNCT__ "DMPlexGetCellNumbering"
5638 PetscErrorCode DMPlexGetCellNumbering(DM dm, IS *globalCellNumbers)
5639 {
5640   DM_Plex       *mesh = (DM_Plex*) dm->data;
5641   PetscInt       cellHeight, cStart, cEnd, cMax;
5642   PetscErrorCode ierr;
5643 
5644   PetscFunctionBegin;
5645   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5646   if (!mesh->globalCellNumbers) {
5647     ierr = DMPlexGetVTKCellHeight(dm, &cellHeight);CHKERRQ(ierr);
5648     ierr = DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd);CHKERRQ(ierr);
5649     ierr = DMPlexGetHybridBounds(dm, &cMax, NULL, NULL, NULL);CHKERRQ(ierr);
5650     if (cMax >= 0) cEnd = PetscMin(cEnd, cMax);
5651     ierr = DMPlexCreateNumbering_Private(dm, cStart, cEnd, dm->sf, &mesh->globalCellNumbers);CHKERRQ(ierr);
5652   }
5653   *globalCellNumbers = mesh->globalCellNumbers;
5654   PetscFunctionReturn(0);
5655 }
5656 
5657 #undef __FUNCT__
5658 #define __FUNCT__ "DMPlexGetVertexNumbering"
5659 PetscErrorCode DMPlexGetVertexNumbering(DM dm, IS *globalVertexNumbers)
5660 {
5661   DM_Plex       *mesh = (DM_Plex*) dm->data;
5662   PetscInt       vStart, vEnd, vMax;
5663   PetscErrorCode ierr;
5664 
5665   PetscFunctionBegin;
5666   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5667   if (!mesh->globalVertexNumbers) {
5668     ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
5669     ierr = DMPlexGetHybridBounds(dm, NULL, NULL, NULL, &vMax);CHKERRQ(ierr);
5670     if (vMax >= 0) vEnd = PetscMin(vEnd, vMax);
5671     ierr = DMPlexCreateNumbering_Private(dm, vStart, vEnd, dm->sf, &mesh->globalVertexNumbers);CHKERRQ(ierr);
5672   }
5673   *globalVertexNumbers = mesh->globalVertexNumbers;
5674   PetscFunctionReturn(0);
5675 }
5676 
5677 
5678 #undef __FUNCT__
5679 #define __FUNCT__ "PetscSectionCreateGlobalSectionLabel"
5680 /*@C
5681   PetscSectionCreateGlobalSectionLabel - Create a section describing the global field layout using
5682   the local section and an SF describing the section point overlap.
5683 
5684   Input Parameters:
5685   + s - The PetscSection for the local field layout
5686   . sf - The SF describing parallel layout of the section points
5687   . includeConstraints - By default this is PETSC_FALSE, meaning that the global field vector will not possess constrained dofs
5688   . label - The label specifying the points
5689   - labelValue - The label stratum specifying the points
5690 
5691   Output Parameter:
5692   . gsection - The PetscSection for the global field layout
5693 
5694   Note: This gives negative sizes and offsets to points not owned by this process
5695 
5696   Level: developer
5697 
5698 .seealso: PetscSectionCreate()
5699 @*/
5700 PetscErrorCode PetscSectionCreateGlobalSectionLabel(PetscSection s, PetscSF sf, PetscBool includeConstraints, DMLabel label, PetscInt labelValue, PetscSection *gsection)
5701 {
5702   PetscInt      *neg = NULL, *tmpOff = NULL;
5703   PetscInt       pStart, pEnd, p, dof, cdof, off, globalOff = 0, nroots;
5704   PetscErrorCode ierr;
5705 
5706   PetscFunctionBegin;
5707   ierr = PetscSectionCreate(s->atlasLayout.comm, gsection);CHKERRQ(ierr);
5708   ierr = PetscSectionGetChart(s, &pStart, &pEnd);CHKERRQ(ierr);
5709   ierr = PetscSectionSetChart(*gsection, pStart, pEnd);CHKERRQ(ierr);
5710   ierr = PetscSFGetGraph(sf, &nroots, NULL, NULL, NULL);CHKERRQ(ierr);
5711   if (nroots >= 0) {
5712     if (nroots < pEnd-pStart) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "PetscSF nroots %d < %d section size", nroots, pEnd-pStart);
5713     ierr = PetscMalloc(nroots * sizeof(PetscInt), &neg);CHKERRQ(ierr);
5714     ierr = PetscMemzero(neg, nroots * sizeof(PetscInt));CHKERRQ(ierr);
5715     if (nroots > pEnd-pStart) {
5716       ierr = PetscMalloc(nroots * sizeof(PetscInt), &tmpOff);CHKERRQ(ierr);
5717       ierr = PetscMemzero(tmpOff, nroots * sizeof(PetscInt));CHKERRQ(ierr);
5718     } else {
5719       tmpOff = &(*gsection)->atlasDof[-pStart];
5720     }
5721   }
5722   /* Mark ghost points with negative dof */
5723   for (p = pStart; p < pEnd; ++p) {
5724     PetscInt value;
5725 
5726     ierr = DMLabelGetValue(label, p, &value);CHKERRQ(ierr);
5727     if (value != labelValue) continue;
5728     ierr = PetscSectionGetDof(s, p, &dof);CHKERRQ(ierr);
5729     ierr = PetscSectionSetDof(*gsection, p, dof);CHKERRQ(ierr);
5730     ierr = PetscSectionGetConstraintDof(s, p, &cdof);CHKERRQ(ierr);
5731     if (!includeConstraints && cdof > 0) {ierr = PetscSectionSetConstraintDof(*gsection, p, cdof);CHKERRQ(ierr);}
5732     if (neg) neg[p] = -(dof+1);
5733   }
5734   ierr = PetscSectionSetUpBC(*gsection);CHKERRQ(ierr);
5735   if (nroots >= 0) {
5736     ierr = PetscSFBcastBegin(sf, MPIU_INT, neg, tmpOff);CHKERRQ(ierr);
5737     ierr = PetscSFBcastEnd(sf, MPIU_INT, neg, tmpOff);CHKERRQ(ierr);
5738     if (nroots > pEnd-pStart) {
5739       for (p = pStart; p < pEnd; ++p) {if (tmpOff[p] < 0) (*gsection)->atlasDof[p-pStart] = tmpOff[p];}
5740     }
5741   }
5742   /* Calculate new sizes, get proccess offset, and calculate point offsets */
5743   for (p = 0, off = 0; p < pEnd-pStart; ++p) {
5744     cdof = (!includeConstraints && s->bc) ? s->bc->atlasDof[p] : 0;
5745     (*gsection)->atlasOff[p] = off;
5746     off += (*gsection)->atlasDof[p] > 0 ? (*gsection)->atlasDof[p]-cdof : 0;
5747   }
5748   ierr       = MPI_Scan(&off, &globalOff, 1, MPIU_INT, MPI_SUM, s->atlasLayout.comm);CHKERRQ(ierr);
5749   globalOff -= off;
5750   for (p = 0, off = 0; p < pEnd-pStart; ++p) {
5751     (*gsection)->atlasOff[p] += globalOff;
5752     if (neg) neg[p] = -((*gsection)->atlasOff[p]+1);
5753   }
5754   /* Put in negative offsets for ghost points */
5755   if (nroots >= 0) {
5756     ierr = PetscSFBcastBegin(sf, MPIU_INT, neg, tmpOff);CHKERRQ(ierr);
5757     ierr = PetscSFBcastEnd(sf, MPIU_INT, neg, tmpOff);CHKERRQ(ierr);
5758     if (nroots > pEnd-pStart) {
5759       for (p = pStart; p < pEnd; ++p) {if (tmpOff[p] < 0) (*gsection)->atlasOff[p-pStart] = tmpOff[p];}
5760     }
5761   }
5762   if (nroots >= 0 && nroots > pEnd-pStart) {ierr = PetscFree(tmpOff);CHKERRQ(ierr);}
5763   ierr = PetscFree(neg);CHKERRQ(ierr);
5764   PetscFunctionReturn(0);
5765 }
5766