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