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