xref: /petsc/src/dm/impls/plex/plex.c (revision c3a59b84b0d9c159b43cf257f7640331cf9945d6)
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   MPI_Aint       lb,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_get_extent(datatype, &lb, &dataSize);CHKERRQ(ierr);
2915   if (lb != 0) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"Datatype with nonzero lower bound %ld\n",(long)lb);
2916   ierr = PetscMalloc(fieldSize * dataSize, newData);CHKERRQ(ierr);
2917 
2918   ierr = PetscSFCreateSectionSF(pointSF, originalSection, remoteOffsets, newSection, &fieldSF);CHKERRQ(ierr);
2919   ierr = PetscSFBcastBegin(fieldSF, datatype, originalData, *newData);CHKERRQ(ierr);
2920   ierr = PetscSFBcastEnd(fieldSF, datatype, originalData, *newData);CHKERRQ(ierr);
2921   ierr = PetscSFDestroy(&fieldSF);CHKERRQ(ierr);
2922   ierr = PetscLogEventEnd(DMPLEX_DistributeData,dm,0,0,0);CHKERRQ(ierr);
2923   PetscFunctionReturn(0);
2924 }
2925 
2926 #undef __FUNCT__
2927 #define __FUNCT__ "DMPlexDistribute"
2928 /*@C
2929   DMPlexDistribute - Distributes the mesh and any associated sections.
2930 
2931   Not Collective
2932 
2933   Input Parameter:
2934 + dm  - The original DMPlex object
2935 . partitioner - The partitioning package, or NULL for the default
2936 - overlap - The overlap of partitions, 0 is the default
2937 
2938   Output Parameter:
2939 + sf - The PetscSF used for point distribution
2940 - parallelMesh - The distributed DMPlex object, or NULL
2941 
2942   Note: If the mesh was not distributed, the return value is NULL
2943 
2944   Level: intermediate
2945 
2946 .keywords: mesh, elements
2947 .seealso: DMPlexCreate(), DMPlexDistributeByFace()
2948 @*/
2949 PetscErrorCode DMPlexDistribute(DM dm, const char partitioner[], PetscInt overlap, PetscSF *sf, DM *dmParallel)
2950 {
2951   DM_Plex               *mesh   = (DM_Plex*) dm->data, *pmesh;
2952   MPI_Comm               comm;
2953   const PetscInt         height = 0;
2954   PetscInt               dim, numRemoteRanks;
2955   IS                     origCellPart,        origPart,        cellPart,        part;
2956   PetscSection           origCellPartSection, origPartSection, cellPartSection, partSection;
2957   PetscSFNode           *remoteRanks;
2958   PetscSF                partSF, pointSF, coneSF;
2959   ISLocalToGlobalMapping renumbering;
2960   PetscSection           originalConeSection, newConeSection;
2961   PetscInt              *remoteOffsets;
2962   PetscInt              *cones, *newCones, newConesSize;
2963   PetscBool              flg;
2964   PetscMPIInt            rank, numProcs, p;
2965   PetscErrorCode         ierr;
2966 
2967   PetscFunctionBegin;
2968   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2969   if (sf) PetscValidPointer(sf,4);
2970   PetscValidPointer(dmParallel,5);
2971 
2972   ierr = PetscLogEventBegin(DMPLEX_Distribute,dm,0,0,0);CHKERRQ(ierr);
2973   ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr);
2974   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
2975   ierr = MPI_Comm_size(comm, &numProcs);CHKERRQ(ierr);
2976 
2977   *dmParallel = NULL;
2978   if (numProcs == 1) PetscFunctionReturn(0);
2979 
2980   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
2981   /* Create cell partition - We need to rewrite to use IS, use the MatPartition stuff */
2982   ierr = PetscLogEventBegin(DMPLEX_Partition,dm,0,0,0);CHKERRQ(ierr);
2983   if (overlap > 1) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Overlap > 1 not yet implemented");
2984   ierr = DMPlexCreatePartition(dm, partitioner, height, overlap > 0 ? PETSC_TRUE : PETSC_FALSE, &cellPartSection, &cellPart, &origCellPartSection, &origCellPart);CHKERRQ(ierr);
2985   /* Create SF assuming a serial partition for all processes: Could check for IS length here */
2986   if (!rank) numRemoteRanks = numProcs;
2987   else       numRemoteRanks = 0;
2988   ierr = PetscMalloc1(numRemoteRanks, &remoteRanks);CHKERRQ(ierr);
2989   for (p = 0; p < numRemoteRanks; ++p) {
2990     remoteRanks[p].rank  = p;
2991     remoteRanks[p].index = 0;
2992   }
2993   ierr = PetscSFCreate(comm, &partSF);CHKERRQ(ierr);
2994   ierr = PetscSFSetGraph(partSF, 1, numRemoteRanks, NULL, PETSC_OWN_POINTER, remoteRanks, PETSC_OWN_POINTER);CHKERRQ(ierr);
2995   ierr = PetscOptionsHasName(((PetscObject) dm)->prefix, "-partition_view", &flg);CHKERRQ(ierr);
2996   if (flg) {
2997     ierr = PetscPrintf(comm, "Cell Partition:\n");CHKERRQ(ierr);
2998     ierr = PetscSectionView(cellPartSection, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
2999     ierr = ISView(cellPart, NULL);CHKERRQ(ierr);
3000     if (origCellPart) {
3001       ierr = PetscPrintf(comm, "Original Cell Partition:\n");CHKERRQ(ierr);
3002       ierr = PetscSectionView(origCellPartSection, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3003       ierr = ISView(origCellPart, NULL);CHKERRQ(ierr);
3004     }
3005     ierr = PetscSFView(partSF, NULL);CHKERRQ(ierr);
3006   }
3007   /* Close the partition over the mesh */
3008   ierr = DMPlexCreatePartitionClosure(dm, cellPartSection, cellPart, &partSection, &part);CHKERRQ(ierr);
3009   ierr = ISDestroy(&cellPart);CHKERRQ(ierr);
3010   ierr = PetscSectionDestroy(&cellPartSection);CHKERRQ(ierr);
3011   /* Create new mesh */
3012   ierr  = DMPlexCreate(comm, dmParallel);CHKERRQ(ierr);
3013   ierr  = DMPlexSetDimension(*dmParallel, dim);CHKERRQ(ierr);
3014   ierr  = PetscObjectSetName((PetscObject) *dmParallel, "Parallel Mesh");CHKERRQ(ierr);
3015   pmesh = (DM_Plex*) (*dmParallel)->data;
3016   /* Distribute sieve points and the global point numbering (replaces creating remote bases) */
3017   ierr = PetscSFConvertPartition(partSF, partSection, part, &renumbering, &pointSF);CHKERRQ(ierr);
3018   if (flg) {
3019     ierr = PetscPrintf(comm, "Point Partition:\n");CHKERRQ(ierr);
3020     ierr = PetscSectionView(partSection, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3021     ierr = ISView(part, NULL);CHKERRQ(ierr);
3022     ierr = PetscSFView(pointSF, NULL);CHKERRQ(ierr);
3023     ierr = PetscPrintf(comm, "Point Renumbering after partition:\n");CHKERRQ(ierr);
3024     ierr = ISLocalToGlobalMappingView(renumbering, NULL);CHKERRQ(ierr);
3025   }
3026   ierr = PetscLogEventEnd(DMPLEX_Partition,dm,0,0,0);CHKERRQ(ierr);
3027   ierr = PetscLogEventBegin(DMPLEX_DistributeCones,dm,0,0,0);CHKERRQ(ierr);
3028   /* Distribute cone section */
3029   ierr = DMPlexGetConeSection(dm, &originalConeSection);CHKERRQ(ierr);
3030   ierr = DMPlexGetConeSection(*dmParallel, &newConeSection);CHKERRQ(ierr);
3031   ierr = PetscSFDistributeSection(pointSF, originalConeSection, &remoteOffsets, newConeSection);CHKERRQ(ierr);
3032   ierr = DMSetUp(*dmParallel);CHKERRQ(ierr);
3033   {
3034     PetscInt pStart, pEnd, p;
3035 
3036     ierr = PetscSectionGetChart(newConeSection, &pStart, &pEnd);CHKERRQ(ierr);
3037     for (p = pStart; p < pEnd; ++p) {
3038       PetscInt coneSize;
3039       ierr               = PetscSectionGetDof(newConeSection, p, &coneSize);CHKERRQ(ierr);
3040       pmesh->maxConeSize = PetscMax(pmesh->maxConeSize, coneSize);
3041     }
3042   }
3043   /* Communicate and renumber cones */
3044   ierr = PetscSFCreateSectionSF(pointSF, originalConeSection, remoteOffsets, newConeSection, &coneSF);CHKERRQ(ierr);
3045   ierr = DMPlexGetCones(dm, &cones);CHKERRQ(ierr);
3046   ierr = DMPlexGetCones(*dmParallel, &newCones);CHKERRQ(ierr);
3047   ierr = PetscSFBcastBegin(coneSF, MPIU_INT, cones, newCones);CHKERRQ(ierr);
3048   ierr = PetscSFBcastEnd(coneSF, MPIU_INT, cones, newCones);CHKERRQ(ierr);
3049   ierr = PetscSectionGetStorageSize(newConeSection, &newConesSize);CHKERRQ(ierr);
3050   ierr = ISGlobalToLocalMappingApply(renumbering, IS_GTOLM_MASK, newConesSize, newCones, NULL, newCones);CHKERRQ(ierr);
3051   ierr = PetscOptionsHasName(((PetscObject) dm)->prefix, "-cones_view", &flg);CHKERRQ(ierr);
3052   if (flg) {
3053     ierr = PetscPrintf(comm, "Serial Cone Section:\n");CHKERRQ(ierr);
3054     ierr = PetscSectionView(originalConeSection, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3055     ierr = PetscPrintf(comm, "Parallel Cone Section:\n");CHKERRQ(ierr);
3056     ierr = PetscSectionView(newConeSection, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3057     ierr = PetscSFView(coneSF, NULL);CHKERRQ(ierr);
3058   }
3059   ierr = DMPlexGetConeOrientations(dm, &cones);CHKERRQ(ierr);
3060   ierr = DMPlexGetConeOrientations(*dmParallel, &newCones);CHKERRQ(ierr);
3061   ierr = PetscSFBcastBegin(coneSF, MPIU_INT, cones, newCones);CHKERRQ(ierr);
3062   ierr = PetscSFBcastEnd(coneSF, MPIU_INT, cones, newCones);CHKERRQ(ierr);
3063   ierr = PetscSFDestroy(&coneSF);CHKERRQ(ierr);
3064   ierr = PetscLogEventEnd(DMPLEX_DistributeCones,dm,0,0,0);CHKERRQ(ierr);
3065   /* Create supports and stratify sieve */
3066   {
3067     PetscInt pStart, pEnd;
3068 
3069     ierr = PetscSectionGetChart(pmesh->coneSection, &pStart, &pEnd);CHKERRQ(ierr);
3070     ierr = PetscSectionSetChart(pmesh->supportSection, pStart, pEnd);CHKERRQ(ierr);
3071   }
3072   ierr = DMPlexSymmetrize(*dmParallel);CHKERRQ(ierr);
3073   ierr = DMPlexStratify(*dmParallel);CHKERRQ(ierr);
3074   /* Distribute Coordinates */
3075   {
3076     PetscSection originalCoordSection, newCoordSection;
3077     Vec          originalCoordinates, newCoordinates;
3078     const char  *name;
3079 
3080     ierr = DMPlexGetCoordinateSection(dm, &originalCoordSection);CHKERRQ(ierr);
3081     ierr = DMPlexGetCoordinateSection(*dmParallel, &newCoordSection);CHKERRQ(ierr);
3082     ierr = DMGetCoordinatesLocal(dm, &originalCoordinates);CHKERRQ(ierr);
3083     ierr = VecCreate(comm, &newCoordinates);CHKERRQ(ierr);
3084     ierr = PetscObjectGetName((PetscObject) originalCoordinates, &name);CHKERRQ(ierr);
3085     ierr = PetscObjectSetName((PetscObject) newCoordinates, name);CHKERRQ(ierr);
3086 
3087     ierr = DMPlexDistributeField(dm, pointSF, originalCoordSection, originalCoordinates, newCoordSection, newCoordinates);CHKERRQ(ierr);
3088     ierr = DMSetCoordinatesLocal(*dmParallel, newCoordinates);CHKERRQ(ierr);
3089     ierr = VecDestroy(&newCoordinates);CHKERRQ(ierr);
3090   }
3091   /* Distribute labels */
3092   ierr = PetscLogEventBegin(DMPLEX_DistributeLabels,dm,0,0,0);CHKERRQ(ierr);
3093   {
3094     DMLabel  next      = mesh->labels, newNext = pmesh->labels;
3095     PetscInt numLabels = 0, l;
3096 
3097     /* Bcast number of labels */
3098     while (next) {++numLabels; next = next->next;}
3099     ierr = MPI_Bcast(&numLabels, 1, MPIU_INT, 0, comm);CHKERRQ(ierr);
3100     next = mesh->labels;
3101     for (l = 0; l < numLabels; ++l) {
3102       DMLabel   labelNew;
3103       PetscBool isdepth;
3104 
3105       /* Skip "depth" because it is recreated */
3106       if (!rank) {ierr = PetscStrcmp(next->name, "depth", &isdepth);CHKERRQ(ierr);}
3107       ierr = MPI_Bcast(&isdepth, 1, MPIU_BOOL, 0, comm);CHKERRQ(ierr);
3108       if (isdepth) {if (!rank) next = next->next; continue;}
3109       ierr = DMLabelDistribute(next, partSection, part, renumbering, &labelNew);CHKERRQ(ierr);
3110       /* Insert into list */
3111       if (newNext) newNext->next = labelNew;
3112       else         pmesh->labels = labelNew;
3113       newNext = labelNew;
3114       if (!rank) next = next->next;
3115     }
3116   }
3117   ierr = PetscLogEventEnd(DMPLEX_DistributeLabels,dm,0,0,0);CHKERRQ(ierr);
3118   /* Setup hybrid structure */
3119   {
3120     const PetscInt *gpoints;
3121     PetscInt        depth, n, d;
3122 
3123     for (d = 0; d <= dim; ++d) {pmesh->hybridPointMax[d] = mesh->hybridPointMax[d];}
3124     ierr = MPI_Bcast(pmesh->hybridPointMax, dim+1, MPIU_INT, 0, comm);CHKERRQ(ierr);
3125     ierr = ISLocalToGlobalMappingGetSize(renumbering, &n);CHKERRQ(ierr);
3126     ierr = ISLocalToGlobalMappingGetIndices(renumbering, &gpoints);CHKERRQ(ierr);
3127     ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3128     for (d = 0; d <= dim; ++d) {
3129       PetscInt pmax = pmesh->hybridPointMax[d], newmax = 0, pEnd, stratum[2], p;
3130 
3131       if (pmax < 0) continue;
3132       ierr = DMPlexGetDepthStratum(dm, d > depth ? depth : d, &stratum[0], &stratum[1]);CHKERRQ(ierr);
3133       ierr = DMPlexGetDepthStratum(*dmParallel, d, NULL, &pEnd);CHKERRQ(ierr);
3134       ierr = MPI_Bcast(stratum, 2, MPIU_INT, 0, comm);CHKERRQ(ierr);
3135       for (p = 0; p < n; ++p) {
3136         const PetscInt point = gpoints[p];
3137 
3138         if ((point >= stratum[0]) && (point < stratum[1]) && (point >= pmax)) ++newmax;
3139       }
3140       if (newmax > 0) pmesh->hybridPointMax[d] = pEnd - newmax;
3141       else            pmesh->hybridPointMax[d] = -1;
3142     }
3143     ierr = ISLocalToGlobalMappingRestoreIndices(renumbering, &gpoints);CHKERRQ(ierr);
3144   }
3145   /* Cleanup Partition */
3146   ierr = ISLocalToGlobalMappingDestroy(&renumbering);CHKERRQ(ierr);
3147   ierr = PetscSFDestroy(&partSF);CHKERRQ(ierr);
3148   ierr = PetscSectionDestroy(&partSection);CHKERRQ(ierr);
3149   ierr = ISDestroy(&part);CHKERRQ(ierr);
3150   /* Create point SF for parallel mesh */
3151   ierr = PetscLogEventBegin(DMPLEX_DistributeSF,dm,0,0,0);CHKERRQ(ierr);
3152   {
3153     const PetscInt *leaves;
3154     PetscSFNode    *remotePoints, *rowners, *lowners;
3155     PetscInt        numRoots, numLeaves, numGhostPoints = 0, p, gp, *ghostPoints;
3156     PetscInt        pStart, pEnd;
3157 
3158     ierr = DMPlexGetChart(*dmParallel, &pStart, &pEnd);CHKERRQ(ierr);
3159     ierr = PetscSFGetGraph(pointSF, &numRoots, &numLeaves, &leaves, NULL);CHKERRQ(ierr);
3160     ierr = PetscMalloc2(numRoots,&rowners,numLeaves,&lowners);CHKERRQ(ierr);
3161     for (p=0; p<numRoots; p++) {
3162       rowners[p].rank  = -1;
3163       rowners[p].index = -1;
3164     }
3165     if (origCellPart) {
3166       /* Make sure points in the original partition are not assigned to other procs */
3167       const PetscInt *origPoints;
3168 
3169       ierr = DMPlexCreatePartitionClosure(dm, origCellPartSection, origCellPart, &origPartSection, &origPart);CHKERRQ(ierr);
3170       ierr = ISGetIndices(origPart, &origPoints);CHKERRQ(ierr);
3171       for (p = 0; p < numProcs; ++p) {
3172         PetscInt dof, off, d;
3173 
3174         ierr = PetscSectionGetDof(origPartSection, p, &dof);CHKERRQ(ierr);
3175         ierr = PetscSectionGetOffset(origPartSection, p, &off);CHKERRQ(ierr);
3176         for (d = off; d < off+dof; ++d) {
3177           rowners[origPoints[d]].rank = p;
3178         }
3179       }
3180       ierr = ISRestoreIndices(origPart, &origPoints);CHKERRQ(ierr);
3181       ierr = ISDestroy(&origPart);CHKERRQ(ierr);
3182       ierr = PetscSectionDestroy(&origPartSection);CHKERRQ(ierr);
3183     }
3184     ierr = ISDestroy(&origCellPart);CHKERRQ(ierr);
3185     ierr = PetscSectionDestroy(&origCellPartSection);CHKERRQ(ierr);
3186 
3187     ierr = PetscSFBcastBegin(pointSF, MPIU_2INT, rowners, lowners);CHKERRQ(ierr);
3188     ierr = PetscSFBcastEnd(pointSF, MPIU_2INT, rowners, lowners);CHKERRQ(ierr);
3189     for (p = 0; p < numLeaves; ++p) {
3190       if (lowners[p].rank < 0 || lowners[p].rank == rank) { /* Either put in a bid or we know we own it */
3191         lowners[p].rank  = rank;
3192         lowners[p].index = leaves ? leaves[p] : p;
3193       } else if (lowners[p].rank >= 0) { /* Point already claimed so flag so that MAXLOC does not listen to us */
3194         lowners[p].rank  = -2;
3195         lowners[p].index = -2;
3196       }
3197     }
3198     for (p=0; p<numRoots; p++) { /* Root must not participate in the rediction, flag so that MAXLOC does not use */
3199       rowners[p].rank  = -3;
3200       rowners[p].index = -3;
3201     }
3202     ierr = PetscSFReduceBegin(pointSF, MPIU_2INT, lowners, rowners, MPI_MAXLOC);CHKERRQ(ierr);
3203     ierr = PetscSFReduceEnd(pointSF, MPIU_2INT, lowners, rowners, MPI_MAXLOC);CHKERRQ(ierr);
3204     ierr = PetscSFBcastBegin(pointSF, MPIU_2INT, rowners, lowners);CHKERRQ(ierr);
3205     ierr = PetscSFBcastEnd(pointSF, MPIU_2INT, rowners, lowners);CHKERRQ(ierr);
3206     for (p = 0; p < numLeaves; ++p) {
3207       if (lowners[p].rank < 0 || lowners[p].index < 0) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Cell partition corrupt: point not claimed");
3208       if (lowners[p].rank != rank) ++numGhostPoints;
3209     }
3210     ierr = PetscMalloc1(numGhostPoints,    &ghostPoints);CHKERRQ(ierr);
3211     ierr = PetscMalloc1(numGhostPoints, &remotePoints);CHKERRQ(ierr);
3212     for (p = 0, gp = 0; p < numLeaves; ++p) {
3213       if (lowners[p].rank != rank) {
3214         ghostPoints[gp]        = leaves ? leaves[p] : p;
3215         remotePoints[gp].rank  = lowners[p].rank;
3216         remotePoints[gp].index = lowners[p].index;
3217         ++gp;
3218       }
3219     }
3220     ierr = PetscFree2(rowners,lowners);CHKERRQ(ierr);
3221     ierr = PetscSFSetGraph((*dmParallel)->sf, pEnd - pStart, numGhostPoints, ghostPoints, PETSC_OWN_POINTER, remotePoints, PETSC_OWN_POINTER);CHKERRQ(ierr);
3222     ierr = PetscSFSetFromOptions((*dmParallel)->sf);CHKERRQ(ierr);
3223   }
3224   ierr = PetscLogEventEnd(DMPLEX_DistributeSF,dm,0,0,0);CHKERRQ(ierr);
3225   /* Cleanup */
3226   if (sf) {*sf = pointSF;}
3227   else    {ierr = PetscSFDestroy(&pointSF);CHKERRQ(ierr);}
3228   ierr = DMSetFromOptions(*dmParallel);CHKERRQ(ierr);
3229   ierr = PetscLogEventEnd(DMPLEX_Distribute,dm,0,0,0);CHKERRQ(ierr);
3230   PetscFunctionReturn(0);
3231 }
3232 
3233 #undef __FUNCT__
3234 #define __FUNCT__ "DMPlexInvertCell"
3235 /*@C
3236   DMPlexInvertCell - This flips tetrahedron and hexahedron orientation since Plex stores them internally with outward normals. Other cells are left untouched.
3237 
3238   Input Parameters:
3239 + numCorners - The number of vertices in a cell
3240 - cone - The incoming cone
3241 
3242   Output Parameter:
3243 . cone - The inverted cone (in-place)
3244 
3245   Level: developer
3246 
3247 .seealso: DMPlexGenerate()
3248 @*/
3249 PetscErrorCode DMPlexInvertCell(PetscInt dim, PetscInt numCorners, int cone[])
3250 {
3251   int tmpc;
3252 
3253   PetscFunctionBegin;
3254   if (dim != 3) PetscFunctionReturn(0);
3255   switch (numCorners) {
3256   case 4:
3257     tmpc    = cone[0];
3258     cone[0] = cone[1];
3259     cone[1] = tmpc;
3260     break;
3261   case 8:
3262     tmpc    = cone[1];
3263     cone[1] = cone[3];
3264     cone[3] = tmpc;
3265     break;
3266   default: break;
3267   }
3268   PetscFunctionReturn(0);
3269 }
3270 
3271 #undef __FUNCT__
3272 #define __FUNCT__ "DMPlexInvertCells_Internal"
3273 /* This is to fix the tetrahedron orientation from TetGen */
3274 PETSC_UNUSED static PetscErrorCode DMPlexInvertCells_Internal(PetscInt dim, PetscInt numCells, PetscInt numCorners, int cells[])
3275 {
3276   PetscInt       bound = numCells*numCorners, coff;
3277   PetscErrorCode ierr;
3278 
3279   PetscFunctionBegin;
3280   for (coff = 0; coff < bound; coff += numCorners) {
3281     ierr = DMPlexInvertCell(dim, numCorners, &cells[coff]);CHKERRQ(ierr);
3282   }
3283   PetscFunctionReturn(0);
3284 }
3285 
3286 #if defined(PETSC_HAVE_TRIANGLE)
3287 #include <triangle.h>
3288 
3289 #undef __FUNCT__
3290 #define __FUNCT__ "InitInput_Triangle"
3291 PetscErrorCode InitInput_Triangle(struct triangulateio *inputCtx)
3292 {
3293   PetscFunctionBegin;
3294   inputCtx->numberofpoints             = 0;
3295   inputCtx->numberofpointattributes    = 0;
3296   inputCtx->pointlist                  = NULL;
3297   inputCtx->pointattributelist         = NULL;
3298   inputCtx->pointmarkerlist            = NULL;
3299   inputCtx->numberofsegments           = 0;
3300   inputCtx->segmentlist                = NULL;
3301   inputCtx->segmentmarkerlist          = NULL;
3302   inputCtx->numberoftriangleattributes = 0;
3303   inputCtx->trianglelist               = NULL;
3304   inputCtx->numberofholes              = 0;
3305   inputCtx->holelist                   = NULL;
3306   inputCtx->numberofregions            = 0;
3307   inputCtx->regionlist                 = NULL;
3308   PetscFunctionReturn(0);
3309 }
3310 
3311 #undef __FUNCT__
3312 #define __FUNCT__ "InitOutput_Triangle"
3313 PetscErrorCode InitOutput_Triangle(struct triangulateio *outputCtx)
3314 {
3315   PetscFunctionBegin;
3316   outputCtx->numberofpoints        = 0;
3317   outputCtx->pointlist             = NULL;
3318   outputCtx->pointattributelist    = NULL;
3319   outputCtx->pointmarkerlist       = NULL;
3320   outputCtx->numberoftriangles     = 0;
3321   outputCtx->trianglelist          = NULL;
3322   outputCtx->triangleattributelist = NULL;
3323   outputCtx->neighborlist          = NULL;
3324   outputCtx->segmentlist           = NULL;
3325   outputCtx->segmentmarkerlist     = NULL;
3326   outputCtx->numberofedges         = 0;
3327   outputCtx->edgelist              = NULL;
3328   outputCtx->edgemarkerlist        = NULL;
3329   PetscFunctionReturn(0);
3330 }
3331 
3332 #undef __FUNCT__
3333 #define __FUNCT__ "FiniOutput_Triangle"
3334 PetscErrorCode FiniOutput_Triangle(struct triangulateio *outputCtx)
3335 {
3336   PetscFunctionBegin;
3337   free(outputCtx->pointmarkerlist);
3338   free(outputCtx->edgelist);
3339   free(outputCtx->edgemarkerlist);
3340   free(outputCtx->trianglelist);
3341   free(outputCtx->neighborlist);
3342   PetscFunctionReturn(0);
3343 }
3344 
3345 #undef __FUNCT__
3346 #define __FUNCT__ "DMPlexGenerate_Triangle"
3347 PetscErrorCode DMPlexGenerate_Triangle(DM boundary, PetscBool interpolate, DM *dm)
3348 {
3349   MPI_Comm             comm;
3350   PetscInt             dim              = 2;
3351   const PetscBool      createConvexHull = PETSC_FALSE;
3352   const PetscBool      constrained      = PETSC_FALSE;
3353   struct triangulateio in;
3354   struct triangulateio out;
3355   PetscInt             vStart, vEnd, v, eStart, eEnd, e;
3356   PetscMPIInt          rank;
3357   PetscErrorCode       ierr;
3358 
3359   PetscFunctionBegin;
3360   ierr = PetscObjectGetComm((PetscObject)boundary,&comm);CHKERRQ(ierr);
3361   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
3362   ierr = InitInput_Triangle(&in);CHKERRQ(ierr);
3363   ierr = InitOutput_Triangle(&out);CHKERRQ(ierr);
3364   ierr = DMPlexGetDepthStratum(boundary, 0, &vStart, &vEnd);CHKERRQ(ierr);
3365 
3366   in.numberofpoints = vEnd - vStart;
3367   if (in.numberofpoints > 0) {
3368     PetscSection coordSection;
3369     Vec          coordinates;
3370     PetscScalar *array;
3371 
3372     ierr = PetscMalloc1(in.numberofpoints*dim, &in.pointlist);CHKERRQ(ierr);
3373     ierr = PetscMalloc1(in.numberofpoints, &in.pointmarkerlist);CHKERRQ(ierr);
3374     ierr = DMGetCoordinatesLocal(boundary, &coordinates);CHKERRQ(ierr);
3375     ierr = DMPlexGetCoordinateSection(boundary, &coordSection);CHKERRQ(ierr);
3376     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
3377     for (v = vStart; v < vEnd; ++v) {
3378       const PetscInt idx = v - vStart;
3379       PetscInt       off, d;
3380 
3381       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
3382       for (d = 0; d < dim; ++d) {
3383         in.pointlist[idx*dim + d] = PetscRealPart(array[off+d]);
3384       }
3385       ierr = DMPlexGetLabelValue(boundary, "marker", v, &in.pointmarkerlist[idx]);CHKERRQ(ierr);
3386     }
3387     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
3388   }
3389   ierr  = DMPlexGetHeightStratum(boundary, 0, &eStart, &eEnd);CHKERRQ(ierr);
3390   in.numberofsegments = eEnd - eStart;
3391   if (in.numberofsegments > 0) {
3392     ierr = PetscMalloc1(in.numberofsegments*2, &in.segmentlist);CHKERRQ(ierr);
3393     ierr = PetscMalloc1(in.numberofsegments, &in.segmentmarkerlist);CHKERRQ(ierr);
3394     for (e = eStart; e < eEnd; ++e) {
3395       const PetscInt  idx = e - eStart;
3396       const PetscInt *cone;
3397 
3398       ierr = DMPlexGetCone(boundary, e, &cone);CHKERRQ(ierr);
3399 
3400       in.segmentlist[idx*2+0] = cone[0] - vStart;
3401       in.segmentlist[idx*2+1] = cone[1] - vStart;
3402 
3403       ierr = DMPlexGetLabelValue(boundary, "marker", e, &in.segmentmarkerlist[idx]);CHKERRQ(ierr);
3404     }
3405   }
3406 #if 0 /* Do not currently support holes */
3407   PetscReal *holeCoords;
3408   PetscInt   h, d;
3409 
3410   ierr = DMPlexGetHoles(boundary, &in.numberofholes, &holeCords);CHKERRQ(ierr);
3411   if (in.numberofholes > 0) {
3412     ierr = PetscMalloc1(in.numberofholes*dim, &in.holelist);CHKERRQ(ierr);
3413     for (h = 0; h < in.numberofholes; ++h) {
3414       for (d = 0; d < dim; ++d) {
3415         in.holelist[h*dim+d] = holeCoords[h*dim+d];
3416       }
3417     }
3418   }
3419 #endif
3420   if (!rank) {
3421     char args[32];
3422 
3423     /* Take away 'Q' for verbose output */
3424     ierr = PetscStrcpy(args, "pqezQ");CHKERRQ(ierr);
3425     if (createConvexHull) {
3426       ierr = PetscStrcat(args, "c");CHKERRQ(ierr);
3427     }
3428     if (constrained) {
3429       ierr = PetscStrcpy(args, "zepDQ");CHKERRQ(ierr);
3430     }
3431     triangulate(args, &in, &out, NULL);
3432   }
3433   ierr = PetscFree(in.pointlist);CHKERRQ(ierr);
3434   ierr = PetscFree(in.pointmarkerlist);CHKERRQ(ierr);
3435   ierr = PetscFree(in.segmentlist);CHKERRQ(ierr);
3436   ierr = PetscFree(in.segmentmarkerlist);CHKERRQ(ierr);
3437   ierr = PetscFree(in.holelist);CHKERRQ(ierr);
3438 
3439   {
3440     const PetscInt numCorners  = 3;
3441     const PetscInt numCells    = out.numberoftriangles;
3442     const PetscInt numVertices = out.numberofpoints;
3443     const int     *cells      = out.trianglelist;
3444     const double  *meshCoords = out.pointlist;
3445 
3446     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, dim, meshCoords, dm);CHKERRQ(ierr);
3447     /* Set labels */
3448     for (v = 0; v < numVertices; ++v) {
3449       if (out.pointmarkerlist[v]) {
3450         ierr = DMPlexSetLabelValue(*dm, "marker", v+numCells, out.pointmarkerlist[v]);CHKERRQ(ierr);
3451       }
3452     }
3453     if (interpolate) {
3454       for (e = 0; e < out.numberofedges; e++) {
3455         if (out.edgemarkerlist[e]) {
3456           const PetscInt  vertices[2] = {out.edgelist[e*2+0]+numCells, out.edgelist[e*2+1]+numCells};
3457           const PetscInt *edges;
3458           PetscInt        numEdges;
3459 
3460           ierr = DMPlexGetJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
3461           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
3462           ierr = DMPlexSetLabelValue(*dm, "marker", edges[0], out.edgemarkerlist[e]);CHKERRQ(ierr);
3463           ierr = DMPlexRestoreJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
3464         }
3465       }
3466     }
3467     ierr = DMPlexSetRefinementUniform(*dm, PETSC_FALSE);CHKERRQ(ierr);
3468   }
3469 #if 0 /* Do not currently support holes */
3470   ierr = DMPlexCopyHoles(*dm, boundary);CHKERRQ(ierr);
3471 #endif
3472   ierr = FiniOutput_Triangle(&out);CHKERRQ(ierr);
3473   PetscFunctionReturn(0);
3474 }
3475 
3476 #undef __FUNCT__
3477 #define __FUNCT__ "DMPlexRefine_Triangle"
3478 PetscErrorCode DMPlexRefine_Triangle(DM dm, double *maxVolumes, DM *dmRefined)
3479 {
3480   MPI_Comm             comm;
3481   PetscInt             dim  = 2;
3482   struct triangulateio in;
3483   struct triangulateio out;
3484   PetscInt             vStart, vEnd, v, cStart, cEnd, c, depth, depthGlobal;
3485   PetscMPIInt          rank;
3486   PetscErrorCode       ierr;
3487 
3488   PetscFunctionBegin;
3489   ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr);
3490   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
3491   ierr = InitInput_Triangle(&in);CHKERRQ(ierr);
3492   ierr = InitOutput_Triangle(&out);CHKERRQ(ierr);
3493   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3494   ierr = MPI_Allreduce(&depth, &depthGlobal, 1, MPIU_INT, MPI_MAX, comm);CHKERRQ(ierr);
3495   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
3496 
3497   in.numberofpoints = vEnd - vStart;
3498   if (in.numberofpoints > 0) {
3499     PetscSection coordSection;
3500     Vec          coordinates;
3501     PetscScalar *array;
3502 
3503     ierr = PetscMalloc1(in.numberofpoints*dim, &in.pointlist);CHKERRQ(ierr);
3504     ierr = PetscMalloc1(in.numberofpoints, &in.pointmarkerlist);CHKERRQ(ierr);
3505     ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
3506     ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
3507     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
3508     for (v = vStart; v < vEnd; ++v) {
3509       const PetscInt idx = v - vStart;
3510       PetscInt       off, d;
3511 
3512       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
3513       for (d = 0; d < dim; ++d) {
3514         in.pointlist[idx*dim + d] = PetscRealPart(array[off+d]);
3515       }
3516       ierr = DMPlexGetLabelValue(dm, "marker", v, &in.pointmarkerlist[idx]);CHKERRQ(ierr);
3517     }
3518     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
3519   }
3520   ierr  = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
3521 
3522   in.numberofcorners   = 3;
3523   in.numberoftriangles = cEnd - cStart;
3524 
3525   in.trianglearealist  = (double*) maxVolumes;
3526   if (in.numberoftriangles > 0) {
3527     ierr = PetscMalloc1(in.numberoftriangles*in.numberofcorners, &in.trianglelist);CHKERRQ(ierr);
3528     for (c = cStart; c < cEnd; ++c) {
3529       const PetscInt idx      = c - cStart;
3530       PetscInt      *closure = NULL;
3531       PetscInt       closureSize;
3532 
3533       ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
3534       if ((closureSize != 4) && (closureSize != 7)) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Mesh has cell which is not a triangle, %D vertices in closure", closureSize);
3535       for (v = 0; v < 3; ++v) {
3536         in.trianglelist[idx*in.numberofcorners + v] = closure[(v+closureSize-3)*2] - vStart;
3537       }
3538       ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
3539     }
3540   }
3541   /* TODO: Segment markers are missing on input */
3542 #if 0 /* Do not currently support holes */
3543   PetscReal *holeCoords;
3544   PetscInt   h, d;
3545 
3546   ierr = DMPlexGetHoles(boundary, &in.numberofholes, &holeCords);CHKERRQ(ierr);
3547   if (in.numberofholes > 0) {
3548     ierr = PetscMalloc1(in.numberofholes*dim, &in.holelist);CHKERRQ(ierr);
3549     for (h = 0; h < in.numberofholes; ++h) {
3550       for (d = 0; d < dim; ++d) {
3551         in.holelist[h*dim+d] = holeCoords[h*dim+d];
3552       }
3553     }
3554   }
3555 #endif
3556   if (!rank) {
3557     char args[32];
3558 
3559     /* Take away 'Q' for verbose output */
3560     ierr = PetscStrcpy(args, "pqezQra");CHKERRQ(ierr);
3561     triangulate(args, &in, &out, NULL);
3562   }
3563   ierr = PetscFree(in.pointlist);CHKERRQ(ierr);
3564   ierr = PetscFree(in.pointmarkerlist);CHKERRQ(ierr);
3565   ierr = PetscFree(in.segmentlist);CHKERRQ(ierr);
3566   ierr = PetscFree(in.segmentmarkerlist);CHKERRQ(ierr);
3567   ierr = PetscFree(in.trianglelist);CHKERRQ(ierr);
3568 
3569   {
3570     const PetscInt numCorners  = 3;
3571     const PetscInt numCells    = out.numberoftriangles;
3572     const PetscInt numVertices = out.numberofpoints;
3573     const int     *cells      = out.trianglelist;
3574     const double  *meshCoords = out.pointlist;
3575     PetscBool      interpolate = depthGlobal > 1 ? PETSC_TRUE : PETSC_FALSE;
3576 
3577     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, dim, meshCoords, dmRefined);CHKERRQ(ierr);
3578     /* Set labels */
3579     for (v = 0; v < numVertices; ++v) {
3580       if (out.pointmarkerlist[v]) {
3581         ierr = DMPlexSetLabelValue(*dmRefined, "marker", v+numCells, out.pointmarkerlist[v]);CHKERRQ(ierr);
3582       }
3583     }
3584     if (interpolate) {
3585       PetscInt e;
3586 
3587       for (e = 0; e < out.numberofedges; e++) {
3588         if (out.edgemarkerlist[e]) {
3589           const PetscInt  vertices[2] = {out.edgelist[e*2+0]+numCells, out.edgelist[e*2+1]+numCells};
3590           const PetscInt *edges;
3591           PetscInt        numEdges;
3592 
3593           ierr = DMPlexGetJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
3594           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
3595           ierr = DMPlexSetLabelValue(*dmRefined, "marker", edges[0], out.edgemarkerlist[e]);CHKERRQ(ierr);
3596           ierr = DMPlexRestoreJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
3597         }
3598       }
3599     }
3600     ierr = DMPlexSetRefinementUniform(*dmRefined, PETSC_FALSE);CHKERRQ(ierr);
3601   }
3602 #if 0 /* Do not currently support holes */
3603   ierr = DMPlexCopyHoles(*dm, boundary);CHKERRQ(ierr);
3604 #endif
3605   ierr = FiniOutput_Triangle(&out);CHKERRQ(ierr);
3606   PetscFunctionReturn(0);
3607 }
3608 #endif
3609 
3610 #if defined(PETSC_HAVE_TETGEN)
3611 #include <tetgen.h>
3612 #undef __FUNCT__
3613 #define __FUNCT__ "DMPlexGenerate_Tetgen"
3614 PetscErrorCode DMPlexGenerate_Tetgen(DM boundary, PetscBool interpolate, DM *dm)
3615 {
3616   MPI_Comm       comm;
3617   const PetscInt dim  = 3;
3618   ::tetgenio     in;
3619   ::tetgenio     out;
3620   PetscInt       vStart, vEnd, v, fStart, fEnd, f;
3621   PetscMPIInt    rank;
3622   PetscErrorCode ierr;
3623 
3624   PetscFunctionBegin;
3625   ierr              = PetscObjectGetComm((PetscObject)boundary,&comm);CHKERRQ(ierr);
3626   ierr              = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
3627   ierr              = DMPlexGetDepthStratum(boundary, 0, &vStart, &vEnd);CHKERRQ(ierr);
3628   in.numberofpoints = vEnd - vStart;
3629   if (in.numberofpoints > 0) {
3630     PetscSection coordSection;
3631     Vec          coordinates;
3632     PetscScalar *array;
3633 
3634     in.pointlist       = new double[in.numberofpoints*dim];
3635     in.pointmarkerlist = new int[in.numberofpoints];
3636 
3637     ierr = DMGetCoordinatesLocal(boundary, &coordinates);CHKERRQ(ierr);
3638     ierr = DMPlexGetCoordinateSection(boundary, &coordSection);CHKERRQ(ierr);
3639     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
3640     for (v = vStart; v < vEnd; ++v) {
3641       const PetscInt idx = v - vStart;
3642       PetscInt       off, d;
3643 
3644       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
3645       for (d = 0; d < dim; ++d) in.pointlist[idx*dim + d] = array[off+d];
3646       ierr = DMPlexGetLabelValue(boundary, "marker", v, &in.pointmarkerlist[idx]);CHKERRQ(ierr);
3647     }
3648     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
3649   }
3650   ierr  = DMPlexGetHeightStratum(boundary, 0, &fStart, &fEnd);CHKERRQ(ierr);
3651 
3652   in.numberoffacets = fEnd - fStart;
3653   if (in.numberoffacets > 0) {
3654     in.facetlist       = new tetgenio::facet[in.numberoffacets];
3655     in.facetmarkerlist = new int[in.numberoffacets];
3656     for (f = fStart; f < fEnd; ++f) {
3657       const PetscInt idx     = f - fStart;
3658       PetscInt      *points = NULL, numPoints, p, numVertices = 0, v;
3659 
3660       in.facetlist[idx].numberofpolygons = 1;
3661       in.facetlist[idx].polygonlist      = new tetgenio::polygon[in.facetlist[idx].numberofpolygons];
3662       in.facetlist[idx].numberofholes    = 0;
3663       in.facetlist[idx].holelist         = NULL;
3664 
3665       ierr = DMPlexGetTransitiveClosure(boundary, f, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
3666       for (p = 0; p < numPoints*2; p += 2) {
3667         const PetscInt point = points[p];
3668         if ((point >= vStart) && (point < vEnd)) points[numVertices++] = point;
3669       }
3670 
3671       tetgenio::polygon *poly = in.facetlist[idx].polygonlist;
3672       poly->numberofvertices = numVertices;
3673       poly->vertexlist       = new int[poly->numberofvertices];
3674       for (v = 0; v < numVertices; ++v) {
3675         const PetscInt vIdx = points[v] - vStart;
3676         poly->vertexlist[v] = vIdx;
3677       }
3678       ierr = DMPlexGetLabelValue(boundary, "marker", f, &in.facetmarkerlist[idx]);CHKERRQ(ierr);
3679       ierr = DMPlexRestoreTransitiveClosure(boundary, f, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
3680     }
3681   }
3682   if (!rank) {
3683     char args[32];
3684 
3685     /* Take away 'Q' for verbose output */
3686     ierr = PetscStrcpy(args, "pqezQ");CHKERRQ(ierr);
3687     ::tetrahedralize(args, &in, &out);
3688   }
3689   {
3690     const PetscInt numCorners  = 4;
3691     const PetscInt numCells    = out.numberoftetrahedra;
3692     const PetscInt numVertices = out.numberofpoints;
3693     const double   *meshCoords = out.pointlist;
3694     int            *cells      = out.tetrahedronlist;
3695 
3696     ierr = DMPlexInvertCells_Internal(dim, numCells, numCorners, cells);CHKERRQ(ierr);
3697     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, dim, meshCoords, dm);CHKERRQ(ierr);
3698     /* Set labels */
3699     for (v = 0; v < numVertices; ++v) {
3700       if (out.pointmarkerlist[v]) {
3701         ierr = DMPlexSetLabelValue(*dm, "marker", v+numCells, out.pointmarkerlist[v]);CHKERRQ(ierr);
3702       }
3703     }
3704     if (interpolate) {
3705       PetscInt e;
3706 
3707       for (e = 0; e < out.numberofedges; e++) {
3708         if (out.edgemarkerlist[e]) {
3709           const PetscInt  vertices[2] = {out.edgelist[e*2+0]+numCells, out.edgelist[e*2+1]+numCells};
3710           const PetscInt *edges;
3711           PetscInt        numEdges;
3712 
3713           ierr = DMPlexGetJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
3714           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
3715           ierr = DMPlexSetLabelValue(*dm, "marker", edges[0], out.edgemarkerlist[e]);CHKERRQ(ierr);
3716           ierr = DMPlexRestoreJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
3717         }
3718       }
3719       for (f = 0; f < out.numberoftrifaces; f++) {
3720         if (out.trifacemarkerlist[f]) {
3721           const PetscInt  vertices[3] = {out.trifacelist[f*3+0]+numCells, out.trifacelist[f*3+1]+numCells, out.trifacelist[f*3+2]+numCells};
3722           const PetscInt *faces;
3723           PetscInt        numFaces;
3724 
3725           ierr = DMPlexGetJoin(*dm, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
3726           if (numFaces != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Three vertices must cover only one face, not %D", numFaces);
3727           ierr = DMPlexSetLabelValue(*dm, "marker", faces[0], out.trifacemarkerlist[f]);CHKERRQ(ierr);
3728           ierr = DMPlexRestoreJoin(*dm, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
3729         }
3730       }
3731     }
3732     ierr = DMPlexSetRefinementUniform(*dm, PETSC_FALSE);CHKERRQ(ierr);
3733   }
3734   PetscFunctionReturn(0);
3735 }
3736 
3737 #undef __FUNCT__
3738 #define __FUNCT__ "DMPlexRefine_Tetgen"
3739 PetscErrorCode DMPlexRefine_Tetgen(DM dm, double *maxVolumes, DM *dmRefined)
3740 {
3741   MPI_Comm       comm;
3742   const PetscInt dim  = 3;
3743   ::tetgenio     in;
3744   ::tetgenio     out;
3745   PetscInt       vStart, vEnd, v, cStart, cEnd, c, depth, depthGlobal;
3746   PetscMPIInt    rank;
3747   PetscErrorCode ierr;
3748 
3749   PetscFunctionBegin;
3750   ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr);
3751   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
3752   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3753   ierr = MPI_Allreduce(&depth, &depthGlobal, 1, MPIU_INT, MPI_MAX, comm);CHKERRQ(ierr);
3754   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
3755 
3756   in.numberofpoints = vEnd - vStart;
3757   if (in.numberofpoints > 0) {
3758     PetscSection coordSection;
3759     Vec          coordinates;
3760     PetscScalar *array;
3761 
3762     in.pointlist       = new double[in.numberofpoints*dim];
3763     in.pointmarkerlist = new int[in.numberofpoints];
3764 
3765     ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
3766     ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
3767     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
3768     for (v = vStart; v < vEnd; ++v) {
3769       const PetscInt idx = v - vStart;
3770       PetscInt       off, d;
3771 
3772       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
3773       for (d = 0; d < dim; ++d) in.pointlist[idx*dim + d] = array[off+d];
3774       ierr = DMPlexGetLabelValue(dm, "marker", v, &in.pointmarkerlist[idx]);CHKERRQ(ierr);
3775     }
3776     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
3777   }
3778   ierr  = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
3779 
3780   in.numberofcorners       = 4;
3781   in.numberoftetrahedra    = cEnd - cStart;
3782   in.tetrahedronvolumelist = (double*) maxVolumes;
3783   if (in.numberoftetrahedra > 0) {
3784     in.tetrahedronlist = new int[in.numberoftetrahedra*in.numberofcorners];
3785     for (c = cStart; c < cEnd; ++c) {
3786       const PetscInt idx      = c - cStart;
3787       PetscInt      *closure = NULL;
3788       PetscInt       closureSize;
3789 
3790       ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
3791       if ((closureSize != 5) && (closureSize != 15)) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Mesh has cell which is not a tetrahedron, %D vertices in closure", closureSize);
3792       for (v = 0; v < 4; ++v) {
3793         in.tetrahedronlist[idx*in.numberofcorners + v] = closure[(v+closureSize-4)*2] - vStart;
3794       }
3795       ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
3796     }
3797   }
3798   /* TODO: Put in boundary faces with markers */
3799   if (!rank) {
3800     char args[32];
3801 
3802     /* Take away 'Q' for verbose output */
3803     /*ierr = PetscStrcpy(args, "qezQra");CHKERRQ(ierr); */
3804     ierr = PetscStrcpy(args, "qezraVVVV");CHKERRQ(ierr);
3805     ::tetrahedralize(args, &in, &out);
3806   }
3807   in.tetrahedronvolumelist = NULL;
3808 
3809   {
3810     const PetscInt numCorners  = 4;
3811     const PetscInt numCells    = out.numberoftetrahedra;
3812     const PetscInt numVertices = out.numberofpoints;
3813     const double   *meshCoords = out.pointlist;
3814     int            *cells      = out.tetrahedronlist;
3815 
3816     PetscBool      interpolate = depthGlobal > 1 ? PETSC_TRUE : PETSC_FALSE;
3817 
3818     ierr = DMPlexInvertCells_Internal(dim, numCells, numCorners, cells);CHKERRQ(ierr);
3819     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, dim, meshCoords, dmRefined);CHKERRQ(ierr);
3820     /* Set labels */
3821     for (v = 0; v < numVertices; ++v) {
3822       if (out.pointmarkerlist[v]) {
3823         ierr = DMPlexSetLabelValue(*dmRefined, "marker", v+numCells, out.pointmarkerlist[v]);CHKERRQ(ierr);
3824       }
3825     }
3826     if (interpolate) {
3827       PetscInt e, f;
3828 
3829       for (e = 0; e < out.numberofedges; e++) {
3830         if (out.edgemarkerlist[e]) {
3831           const PetscInt  vertices[2] = {out.edgelist[e*2+0]+numCells, out.edgelist[e*2+1]+numCells};
3832           const PetscInt *edges;
3833           PetscInt        numEdges;
3834 
3835           ierr = DMPlexGetJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
3836           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
3837           ierr = DMPlexSetLabelValue(*dmRefined, "marker", edges[0], out.edgemarkerlist[e]);CHKERRQ(ierr);
3838           ierr = DMPlexRestoreJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
3839         }
3840       }
3841       for (f = 0; f < out.numberoftrifaces; f++) {
3842         if (out.trifacemarkerlist[f]) {
3843           const PetscInt  vertices[3] = {out.trifacelist[f*3+0]+numCells, out.trifacelist[f*3+1]+numCells, out.trifacelist[f*3+2]+numCells};
3844           const PetscInt *faces;
3845           PetscInt        numFaces;
3846 
3847           ierr = DMPlexGetJoin(*dmRefined, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
3848           if (numFaces != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Three vertices must cover only one face, not %D", numFaces);
3849           ierr = DMPlexSetLabelValue(*dmRefined, "marker", faces[0], out.trifacemarkerlist[f]);CHKERRQ(ierr);
3850           ierr = DMPlexRestoreJoin(*dmRefined, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
3851         }
3852       }
3853     }
3854     ierr = DMPlexSetRefinementUniform(*dmRefined, PETSC_FALSE);CHKERRQ(ierr);
3855   }
3856   PetscFunctionReturn(0);
3857 }
3858 #endif
3859 
3860 #if defined(PETSC_HAVE_CTETGEN)
3861 #include "ctetgen.h"
3862 
3863 #undef __FUNCT__
3864 #define __FUNCT__ "DMPlexGenerate_CTetgen"
3865 PetscErrorCode DMPlexGenerate_CTetgen(DM boundary, PetscBool interpolate, DM *dm)
3866 {
3867   MPI_Comm       comm;
3868   const PetscInt dim  = 3;
3869   PLC           *in, *out;
3870   PetscInt       verbose = 0, vStart, vEnd, v, fStart, fEnd, f;
3871   PetscMPIInt    rank;
3872   PetscErrorCode ierr;
3873 
3874   PetscFunctionBegin;
3875   ierr = PetscObjectGetComm((PetscObject)boundary,&comm);CHKERRQ(ierr);
3876   ierr = PetscOptionsGetInt(((PetscObject) boundary)->prefix, "-ctetgen_verbose", &verbose, NULL);CHKERRQ(ierr);
3877   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
3878   ierr = DMPlexGetDepthStratum(boundary, 0, &vStart, &vEnd);CHKERRQ(ierr);
3879   ierr = PLCCreate(&in);CHKERRQ(ierr);
3880   ierr = PLCCreate(&out);CHKERRQ(ierr);
3881 
3882   in->numberofpoints = vEnd - vStart;
3883   if (in->numberofpoints > 0) {
3884     PetscSection coordSection;
3885     Vec          coordinates;
3886     PetscScalar *array;
3887 
3888     ierr = PetscMalloc1(in->numberofpoints*dim, &in->pointlist);CHKERRQ(ierr);
3889     ierr = PetscMalloc1(in->numberofpoints,       &in->pointmarkerlist);CHKERRQ(ierr);
3890     ierr = DMGetCoordinatesLocal(boundary, &coordinates);CHKERRQ(ierr);
3891     ierr = DMPlexGetCoordinateSection(boundary, &coordSection);CHKERRQ(ierr);
3892     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
3893     for (v = vStart; v < vEnd; ++v) {
3894       const PetscInt idx = v - vStart;
3895       PetscInt       off, d, m;
3896 
3897       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
3898       for (d = 0; d < dim; ++d) {
3899         in->pointlist[idx*dim + d] = PetscRealPart(array[off+d]);
3900       }
3901       ierr = DMPlexGetLabelValue(boundary, "marker", v, &m);CHKERRQ(ierr);
3902 
3903       in->pointmarkerlist[idx] = (int) m;
3904     }
3905     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
3906   }
3907   ierr  = DMPlexGetHeightStratum(boundary, 0, &fStart, &fEnd);CHKERRQ(ierr);
3908 
3909   in->numberoffacets = fEnd - fStart;
3910   if (in->numberoffacets > 0) {
3911     ierr = PetscMalloc1(in->numberoffacets, &in->facetlist);CHKERRQ(ierr);
3912     ierr = PetscMalloc1(in->numberoffacets,   &in->facetmarkerlist);CHKERRQ(ierr);
3913     for (f = fStart; f < fEnd; ++f) {
3914       const PetscInt idx     = f - fStart;
3915       PetscInt      *points = NULL, numPoints, p, numVertices = 0, v, m;
3916       polygon       *poly;
3917 
3918       in->facetlist[idx].numberofpolygons = 1;
3919 
3920       ierr = PetscMalloc1(in->facetlist[idx].numberofpolygons, &in->facetlist[idx].polygonlist);CHKERRQ(ierr);
3921 
3922       in->facetlist[idx].numberofholes    = 0;
3923       in->facetlist[idx].holelist         = NULL;
3924 
3925       ierr = DMPlexGetTransitiveClosure(boundary, f, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
3926       for (p = 0; p < numPoints*2; p += 2) {
3927         const PetscInt point = points[p];
3928         if ((point >= vStart) && (point < vEnd)) points[numVertices++] = point;
3929       }
3930 
3931       poly                   = in->facetlist[idx].polygonlist;
3932       poly->numberofvertices = numVertices;
3933       ierr                   = PetscMalloc1(poly->numberofvertices, &poly->vertexlist);CHKERRQ(ierr);
3934       for (v = 0; v < numVertices; ++v) {
3935         const PetscInt vIdx = points[v] - vStart;
3936         poly->vertexlist[v] = vIdx;
3937       }
3938       ierr                     = DMPlexGetLabelValue(boundary, "marker", f, &m);CHKERRQ(ierr);
3939       in->facetmarkerlist[idx] = (int) m;
3940       ierr                     = DMPlexRestoreTransitiveClosure(boundary, f, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
3941     }
3942   }
3943   if (!rank) {
3944     TetGenOpts t;
3945 
3946     ierr        = TetGenOptsInitialize(&t);CHKERRQ(ierr);
3947     t.in        = boundary; /* Should go away */
3948     t.plc       = 1;
3949     t.quality   = 1;
3950     t.edgesout  = 1;
3951     t.zeroindex = 1;
3952     t.quiet     = 1;
3953     t.verbose   = verbose;
3954     ierr        = TetGenCheckOpts(&t);CHKERRQ(ierr);
3955     ierr        = TetGenTetrahedralize(&t, in, out);CHKERRQ(ierr);
3956   }
3957   {
3958     const PetscInt numCorners  = 4;
3959     const PetscInt numCells    = out->numberoftetrahedra;
3960     const PetscInt numVertices = out->numberofpoints;
3961     const double   *meshCoords = out->pointlist;
3962     int            *cells      = out->tetrahedronlist;
3963 
3964     ierr = DMPlexInvertCells_Internal(dim, numCells, numCorners, cells);CHKERRQ(ierr);
3965     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, dim, meshCoords, dm);CHKERRQ(ierr);
3966     /* Set labels */
3967     for (v = 0; v < numVertices; ++v) {
3968       if (out->pointmarkerlist[v]) {
3969         ierr = DMPlexSetLabelValue(*dm, "marker", v+numCells, out->pointmarkerlist[v]);CHKERRQ(ierr);
3970       }
3971     }
3972     if (interpolate) {
3973       PetscInt e;
3974 
3975       for (e = 0; e < out->numberofedges; e++) {
3976         if (out->edgemarkerlist[e]) {
3977           const PetscInt  vertices[2] = {out->edgelist[e*2+0]+numCells, out->edgelist[e*2+1]+numCells};
3978           const PetscInt *edges;
3979           PetscInt        numEdges;
3980 
3981           ierr = DMPlexGetJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
3982           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
3983           ierr = DMPlexSetLabelValue(*dm, "marker", edges[0], out->edgemarkerlist[e]);CHKERRQ(ierr);
3984           ierr = DMPlexRestoreJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
3985         }
3986       }
3987       for (f = 0; f < out->numberoftrifaces; f++) {
3988         if (out->trifacemarkerlist[f]) {
3989           const PetscInt  vertices[3] = {out->trifacelist[f*3+0]+numCells, out->trifacelist[f*3+1]+numCells, out->trifacelist[f*3+2]+numCells};
3990           const PetscInt *faces;
3991           PetscInt        numFaces;
3992 
3993           ierr = DMPlexGetFullJoin(*dm, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
3994           if (numFaces != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Three vertices must cover only one face, not %D", numFaces);
3995           ierr = DMPlexSetLabelValue(*dm, "marker", faces[0], out->trifacemarkerlist[f]);CHKERRQ(ierr);
3996           ierr = DMPlexRestoreJoin(*dm, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
3997         }
3998       }
3999     }
4000     ierr = DMPlexSetRefinementUniform(*dm, PETSC_FALSE);CHKERRQ(ierr);
4001   }
4002 
4003   ierr = PLCDestroy(&in);CHKERRQ(ierr);
4004   ierr = PLCDestroy(&out);CHKERRQ(ierr);
4005   PetscFunctionReturn(0);
4006 }
4007 
4008 #undef __FUNCT__
4009 #define __FUNCT__ "DMPlexRefine_CTetgen"
4010 PetscErrorCode DMPlexRefine_CTetgen(DM dm, PetscReal *maxVolumes, DM *dmRefined)
4011 {
4012   MPI_Comm       comm;
4013   const PetscInt dim  = 3;
4014   PLC           *in, *out;
4015   PetscInt       verbose = 0, vStart, vEnd, v, cStart, cEnd, c, depth, depthGlobal;
4016   PetscMPIInt    rank;
4017   PetscErrorCode ierr;
4018 
4019   PetscFunctionBegin;
4020   ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr);
4021   ierr = PetscOptionsGetInt(((PetscObject) dm)->prefix, "-ctetgen_verbose", &verbose, NULL);CHKERRQ(ierr);
4022   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
4023   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
4024   ierr = MPI_Allreduce(&depth, &depthGlobal, 1, MPIU_INT, MPI_MAX, comm);CHKERRQ(ierr);
4025   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
4026   ierr = PLCCreate(&in);CHKERRQ(ierr);
4027   ierr = PLCCreate(&out);CHKERRQ(ierr);
4028 
4029   in->numberofpoints = vEnd - vStart;
4030   if (in->numberofpoints > 0) {
4031     PetscSection coordSection;
4032     Vec          coordinates;
4033     PetscScalar *array;
4034 
4035     ierr = PetscMalloc1(in->numberofpoints*dim, &in->pointlist);CHKERRQ(ierr);
4036     ierr = PetscMalloc1(in->numberofpoints,       &in->pointmarkerlist);CHKERRQ(ierr);
4037     ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
4038     ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
4039     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
4040     for (v = vStart; v < vEnd; ++v) {
4041       const PetscInt idx = v - vStart;
4042       PetscInt       off, d, m;
4043 
4044       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
4045       for (d = 0; d < dim; ++d) {
4046         in->pointlist[idx*dim + d] = PetscRealPart(array[off+d]);
4047       }
4048       ierr = DMPlexGetLabelValue(dm, "marker", v, &m);CHKERRQ(ierr);
4049 
4050       in->pointmarkerlist[idx] = (int) m;
4051     }
4052     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
4053   }
4054   ierr  = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
4055 
4056   in->numberofcorners       = 4;
4057   in->numberoftetrahedra    = cEnd - cStart;
4058   in->tetrahedronvolumelist = maxVolumes;
4059   if (in->numberoftetrahedra > 0) {
4060     ierr = PetscMalloc1(in->numberoftetrahedra*in->numberofcorners, &in->tetrahedronlist);CHKERRQ(ierr);
4061     for (c = cStart; c < cEnd; ++c) {
4062       const PetscInt idx      = c - cStart;
4063       PetscInt      *closure = NULL;
4064       PetscInt       closureSize;
4065 
4066       ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
4067       if ((closureSize != 5) && (closureSize != 15)) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Mesh has cell which is not a tetrahedron, %D vertices in closure", closureSize);
4068       for (v = 0; v < 4; ++v) {
4069         in->tetrahedronlist[idx*in->numberofcorners + v] = closure[(v+closureSize-4)*2] - vStart;
4070       }
4071       ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
4072     }
4073   }
4074   if (!rank) {
4075     TetGenOpts t;
4076 
4077     ierr = TetGenOptsInitialize(&t);CHKERRQ(ierr);
4078 
4079     t.in        = dm; /* Should go away */
4080     t.refine    = 1;
4081     t.varvolume = 1;
4082     t.quality   = 1;
4083     t.edgesout  = 1;
4084     t.zeroindex = 1;
4085     t.quiet     = 1;
4086     t.verbose   = verbose; /* Change this */
4087 
4088     ierr = TetGenCheckOpts(&t);CHKERRQ(ierr);
4089     ierr = TetGenTetrahedralize(&t, in, out);CHKERRQ(ierr);
4090   }
4091   {
4092     const PetscInt numCorners  = 4;
4093     const PetscInt numCells    = out->numberoftetrahedra;
4094     const PetscInt numVertices = out->numberofpoints;
4095     const double   *meshCoords = out->pointlist;
4096     int            *cells      = out->tetrahedronlist;
4097     PetscBool      interpolate = depthGlobal > 1 ? PETSC_TRUE : PETSC_FALSE;
4098 
4099     ierr = DMPlexInvertCells_Internal(dim, numCells, numCorners, cells);CHKERRQ(ierr);
4100     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, dim, meshCoords, dmRefined);CHKERRQ(ierr);
4101     /* Set labels */
4102     for (v = 0; v < numVertices; ++v) {
4103       if (out->pointmarkerlist[v]) {
4104         ierr = DMPlexSetLabelValue(*dmRefined, "marker", v+numCells, out->pointmarkerlist[v]);CHKERRQ(ierr);
4105       }
4106     }
4107     if (interpolate) {
4108       PetscInt e, f;
4109 
4110       for (e = 0; e < out->numberofedges; e++) {
4111         if (out->edgemarkerlist[e]) {
4112           const PetscInt  vertices[2] = {out->edgelist[e*2+0]+numCells, out->edgelist[e*2+1]+numCells};
4113           const PetscInt *edges;
4114           PetscInt        numEdges;
4115 
4116           ierr = DMPlexGetJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
4117           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
4118           ierr = DMPlexSetLabelValue(*dmRefined, "marker", edges[0], out->edgemarkerlist[e]);CHKERRQ(ierr);
4119           ierr = DMPlexRestoreJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
4120         }
4121       }
4122       for (f = 0; f < out->numberoftrifaces; f++) {
4123         if (out->trifacemarkerlist[f]) {
4124           const PetscInt  vertices[3] = {out->trifacelist[f*3+0]+numCells, out->trifacelist[f*3+1]+numCells, out->trifacelist[f*3+2]+numCells};
4125           const PetscInt *faces;
4126           PetscInt        numFaces;
4127 
4128           ierr = DMPlexGetFullJoin(*dmRefined, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
4129           if (numFaces != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Three vertices must cover only one face, not %D", numFaces);
4130           ierr = DMPlexSetLabelValue(*dmRefined, "marker", faces[0], out->trifacemarkerlist[f]);CHKERRQ(ierr);
4131           ierr = DMPlexRestoreJoin(*dmRefined, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
4132         }
4133       }
4134     }
4135     ierr = DMPlexSetRefinementUniform(*dmRefined, PETSC_FALSE);CHKERRQ(ierr);
4136   }
4137   ierr = PLCDestroy(&in);CHKERRQ(ierr);
4138   ierr = PLCDestroy(&out);CHKERRQ(ierr);
4139   PetscFunctionReturn(0);
4140 }
4141 #endif
4142 
4143 #undef __FUNCT__
4144 #define __FUNCT__ "DMPlexGenerate"
4145 /*@C
4146   DMPlexGenerate - Generates a mesh.
4147 
4148   Not Collective
4149 
4150   Input Parameters:
4151 + boundary - The DMPlex boundary object
4152 . name - The mesh generation package name
4153 - interpolate - Flag to create intermediate mesh elements
4154 
4155   Output Parameter:
4156 . mesh - The DMPlex object
4157 
4158   Level: intermediate
4159 
4160 .keywords: mesh, elements
4161 .seealso: DMPlexCreate(), DMRefine()
4162 @*/
4163 PetscErrorCode DMPlexGenerate(DM boundary, const char name[], PetscBool interpolate, DM *mesh)
4164 {
4165   PetscInt       dim;
4166   char           genname[1024];
4167   PetscBool      isTriangle = PETSC_FALSE, isTetgen = PETSC_FALSE, isCTetgen = PETSC_FALSE, flg;
4168   PetscErrorCode ierr;
4169 
4170   PetscFunctionBegin;
4171   PetscValidHeaderSpecific(boundary, DM_CLASSID, 1);
4172   PetscValidLogicalCollectiveBool(boundary, interpolate, 2);
4173   ierr = DMPlexGetDimension(boundary, &dim);CHKERRQ(ierr);
4174   ierr = PetscOptionsGetString(((PetscObject) boundary)->prefix, "-dm_plex_generator", genname, 1024, &flg);CHKERRQ(ierr);
4175   if (flg) name = genname;
4176   if (name) {
4177     ierr = PetscStrcmp(name, "triangle", &isTriangle);CHKERRQ(ierr);
4178     ierr = PetscStrcmp(name, "tetgen",   &isTetgen);CHKERRQ(ierr);
4179     ierr = PetscStrcmp(name, "ctetgen",  &isCTetgen);CHKERRQ(ierr);
4180   }
4181   switch (dim) {
4182   case 1:
4183     if (!name || isTriangle) {
4184 #if defined(PETSC_HAVE_TRIANGLE)
4185       ierr = DMPlexGenerate_Triangle(boundary, interpolate, mesh);CHKERRQ(ierr);
4186 #else
4187       SETERRQ(PetscObjectComm((PetscObject)boundary), PETSC_ERR_SUP, "Mesh generation needs external package support.\nPlease reconfigure with --download-triangle.");
4188 #endif
4189     } else SETERRQ1(PetscObjectComm((PetscObject)boundary), PETSC_ERR_SUP, "Unknown 2D mesh generation package %s", name);
4190     break;
4191   case 2:
4192     if (!name || isCTetgen) {
4193 #if defined(PETSC_HAVE_CTETGEN)
4194       ierr = DMPlexGenerate_CTetgen(boundary, interpolate, mesh);CHKERRQ(ierr);
4195 #else
4196       SETERRQ(PetscObjectComm((PetscObject)boundary), PETSC_ERR_SUP, "CTetgen needs external package support.\nPlease reconfigure with --download-ctetgen.");
4197 #endif
4198     } else if (isTetgen) {
4199 #if defined(PETSC_HAVE_TETGEN)
4200       ierr = DMPlexGenerate_Tetgen(boundary, interpolate, mesh);CHKERRQ(ierr);
4201 #else
4202       SETERRQ(PetscObjectComm((PetscObject)boundary), PETSC_ERR_SUP, "Tetgen needs external package support.\nPlease reconfigure with --with-c-language=cxx --download-tetgen.");
4203 #endif
4204     } else SETERRQ1(PetscObjectComm((PetscObject)boundary), PETSC_ERR_SUP, "Unknown 3D mesh generation package %s", name);
4205     break;
4206   default:
4207     SETERRQ1(PetscObjectComm((PetscObject)boundary), PETSC_ERR_SUP, "Mesh generation for a dimension %d boundary is not supported.", dim);
4208   }
4209   PetscFunctionReturn(0);
4210 }
4211 
4212 #undef __FUNCT__
4213 #define __FUNCT__ "DMRefine_Plex"
4214 PetscErrorCode DMRefine_Plex(DM dm, MPI_Comm comm, DM *dmRefined)
4215 {
4216   PetscReal      refinementLimit;
4217   PetscInt       dim, cStart, cEnd;
4218   char           genname[1024], *name = NULL;
4219   PetscBool      isUniform, isTriangle = PETSC_FALSE, isTetgen = PETSC_FALSE, isCTetgen = PETSC_FALSE, flg;
4220   PetscErrorCode ierr;
4221 
4222   PetscFunctionBegin;
4223   ierr = DMPlexGetRefinementUniform(dm, &isUniform);CHKERRQ(ierr);
4224   if (isUniform) {
4225     CellRefiner cellRefiner;
4226 
4227     ierr = DMPlexGetCellRefiner_Internal(dm, &cellRefiner);CHKERRQ(ierr);
4228     ierr = DMPlexRefineUniform_Internal(dm, cellRefiner, dmRefined);CHKERRQ(ierr);
4229     PetscFunctionReturn(0);
4230   }
4231   ierr = DMPlexGetRefinementLimit(dm, &refinementLimit);CHKERRQ(ierr);
4232   if (refinementLimit == 0.0) PetscFunctionReturn(0);
4233   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
4234   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
4235   ierr = PetscOptionsGetString(((PetscObject) dm)->prefix, "-dm_plex_generator", genname, 1024, &flg);CHKERRQ(ierr);
4236   if (flg) name = genname;
4237   if (name) {
4238     ierr = PetscStrcmp(name, "triangle", &isTriangle);CHKERRQ(ierr);
4239     ierr = PetscStrcmp(name, "tetgen",   &isTetgen);CHKERRQ(ierr);
4240     ierr = PetscStrcmp(name, "ctetgen",  &isCTetgen);CHKERRQ(ierr);
4241   }
4242   switch (dim) {
4243   case 2:
4244     if (!name || isTriangle) {
4245 #if defined(PETSC_HAVE_TRIANGLE)
4246       double  *maxVolumes;
4247       PetscInt c;
4248 
4249       ierr = PetscMalloc1((cEnd - cStart), &maxVolumes);CHKERRQ(ierr);
4250       for (c = 0; c < cEnd-cStart; ++c) maxVolumes[c] = refinementLimit;
4251       ierr = DMPlexRefine_Triangle(dm, maxVolumes, dmRefined);CHKERRQ(ierr);
4252       ierr = PetscFree(maxVolumes);CHKERRQ(ierr);
4253 #else
4254       SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Mesh refinement needs external package support.\nPlease reconfigure with --download-triangle.");
4255 #endif
4256     } else SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Unknown 2D mesh generation package %s", name);
4257     break;
4258   case 3:
4259     if (!name || isCTetgen) {
4260 #if defined(PETSC_HAVE_CTETGEN)
4261       PetscReal *maxVolumes;
4262       PetscInt   c;
4263 
4264       ierr = PetscMalloc1((cEnd - cStart), &maxVolumes);CHKERRQ(ierr);
4265       for (c = 0; c < cEnd-cStart; ++c) maxVolumes[c] = refinementLimit;
4266       ierr = DMPlexRefine_CTetgen(dm, maxVolumes, dmRefined);CHKERRQ(ierr);
4267 #else
4268       SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "CTetgen needs external package support.\nPlease reconfigure with --download-ctetgen.");
4269 #endif
4270     } else if (isTetgen) {
4271 #if defined(PETSC_HAVE_TETGEN)
4272       double  *maxVolumes;
4273       PetscInt c;
4274 
4275       ierr = PetscMalloc1((cEnd - cStart), &maxVolumes);CHKERRQ(ierr);
4276       for (c = 0; c < cEnd-cStart; ++c) maxVolumes[c] = refinementLimit;
4277       ierr = DMPlexRefine_Tetgen(dm, maxVolumes, dmRefined);CHKERRQ(ierr);
4278 #else
4279       SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Tetgen needs external package support.\nPlease reconfigure with --with-c-language=cxx --download-tetgen.");
4280 #endif
4281     } else SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Unknown 3D mesh generation package %s", name);
4282     break;
4283   default:
4284     SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Mesh refinement in dimension %d is not supported.", dim);
4285   }
4286   PetscFunctionReturn(0);
4287 }
4288 
4289 #undef __FUNCT__
4290 #define __FUNCT__ "DMPlexGetDepthLabel"
4291 /*@
4292   DMPlexGetDepthLabel - Get the DMLabel recording the depth of each point
4293 
4294   Not Collective
4295 
4296   Input Parameter:
4297 . dm    - The DMPlex object
4298 
4299   Output Parameter:
4300 . depthLabel - The DMLabel recording point depth
4301 
4302   Level: developer
4303 
4304 .keywords: mesh, points
4305 .seealso: DMPlexGetDepth(), DMPlexGetHeightStratum(), DMPlexGetDepthStratum()
4306 @*/
4307 PetscErrorCode DMPlexGetDepthLabel(DM dm, DMLabel *depthLabel)
4308 {
4309   DM_Plex       *mesh = (DM_Plex*) dm->data;
4310   PetscErrorCode ierr;
4311 
4312   PetscFunctionBegin;
4313   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4314   PetscValidPointer(depthLabel, 2);
4315   if (!mesh->depthLabel) {ierr = DMPlexGetLabel(dm, "depth", &mesh->depthLabel);CHKERRQ(ierr);}
4316   *depthLabel = mesh->depthLabel;
4317   PetscFunctionReturn(0);
4318 }
4319 
4320 #undef __FUNCT__
4321 #define __FUNCT__ "DMPlexGetDepth"
4322 /*@
4323   DMPlexGetDepth - Get the depth of the DAG representing this mesh
4324 
4325   Not Collective
4326 
4327   Input Parameter:
4328 . dm    - The DMPlex object
4329 
4330   Output Parameter:
4331 . depth - The number of strata (breadth first levels) in the DAG
4332 
4333   Level: developer
4334 
4335 .keywords: mesh, points
4336 .seealso: DMPlexGetDepthLabel(), DMPlexGetHeightStratum(), DMPlexGetDepthStratum()
4337 @*/
4338 PetscErrorCode DMPlexGetDepth(DM dm, PetscInt *depth)
4339 {
4340   DMLabel        label;
4341   PetscInt       d = 0;
4342   PetscErrorCode ierr;
4343 
4344   PetscFunctionBegin;
4345   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4346   PetscValidPointer(depth, 2);
4347   ierr = DMPlexGetDepthLabel(dm, &label);CHKERRQ(ierr);
4348   if (label) {ierr = DMLabelGetNumValues(label, &d);CHKERRQ(ierr);}
4349   *depth = d-1;
4350   PetscFunctionReturn(0);
4351 }
4352 
4353 #undef __FUNCT__
4354 #define __FUNCT__ "DMPlexGetDepthStratum"
4355 /*@
4356   DMPlexGetDepthStratum - Get the bounds [start, end) for all points at a certain depth.
4357 
4358   Not Collective
4359 
4360   Input Parameters:
4361 + dm           - The DMPlex object
4362 - stratumValue - The requested depth
4363 
4364   Output Parameters:
4365 + start - The first point at this depth
4366 - end   - One beyond the last point at this depth
4367 
4368   Level: developer
4369 
4370 .keywords: mesh, points
4371 .seealso: DMPlexGetHeightStratum(), DMPlexGetDepth()
4372 @*/
4373 PetscErrorCode DMPlexGetDepthStratum(DM dm, PetscInt stratumValue, PetscInt *start, PetscInt *end)
4374 {
4375   DMLabel        label;
4376   PetscInt       pStart, pEnd;
4377   PetscErrorCode ierr;
4378 
4379   PetscFunctionBegin;
4380   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4381   if (start) {PetscValidPointer(start, 3); *start = 0;}
4382   if (end)   {PetscValidPointer(end,   4); *end   = 0;}
4383   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
4384   if (pStart == pEnd) PetscFunctionReturn(0);
4385   if (stratumValue < 0) {
4386     if (start) *start = pStart;
4387     if (end)   *end   = pEnd;
4388     PetscFunctionReturn(0);
4389   }
4390   ierr = DMPlexGetDepthLabel(dm, &label);CHKERRQ(ierr);
4391   if (!label) SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "No label named depth was found");
4392   ierr = DMLabelGetStratumBounds(label, stratumValue, start, end);CHKERRQ(ierr);
4393   PetscFunctionReturn(0);
4394 }
4395 
4396 #undef __FUNCT__
4397 #define __FUNCT__ "DMPlexGetHeightStratum"
4398 /*@
4399   DMPlexGetHeightStratum - Get the bounds [start, end) for all points at a certain height.
4400 
4401   Not Collective
4402 
4403   Input Parameters:
4404 + dm           - The DMPlex object
4405 - stratumValue - The requested height
4406 
4407   Output Parameters:
4408 + start - The first point at this height
4409 - end   - One beyond the last point at this height
4410 
4411   Level: developer
4412 
4413 .keywords: mesh, points
4414 .seealso: DMPlexGetDepthStratum(), DMPlexGetDepth()
4415 @*/
4416 PetscErrorCode DMPlexGetHeightStratum(DM dm, PetscInt stratumValue, PetscInt *start, PetscInt *end)
4417 {
4418   DMLabel        label;
4419   PetscInt       depth, pStart, pEnd;
4420   PetscErrorCode ierr;
4421 
4422   PetscFunctionBegin;
4423   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4424   if (start) {PetscValidPointer(start, 3); *start = 0;}
4425   if (end)   {PetscValidPointer(end,   4); *end   = 0;}
4426   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
4427   if (pStart == pEnd) PetscFunctionReturn(0);
4428   if (stratumValue < 0) {
4429     if (start) *start = pStart;
4430     if (end)   *end   = pEnd;
4431     PetscFunctionReturn(0);
4432   }
4433   ierr = DMPlexGetDepthLabel(dm, &label);CHKERRQ(ierr);
4434   if (!label) SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "No label named depth was found");CHKERRQ(ierr);
4435   ierr = DMLabelGetNumValues(label, &depth);CHKERRQ(ierr);
4436   ierr = DMLabelGetStratumBounds(label, depth-1-stratumValue, start, end);CHKERRQ(ierr);
4437   PetscFunctionReturn(0);
4438 }
4439 
4440 #undef __FUNCT__
4441 #define __FUNCT__ "DMPlexCreateSectionInitial"
4442 /* Set the number of dof on each point and separate by fields */
4443 PetscErrorCode DMPlexCreateSectionInitial(DM dm, PetscInt dim, PetscInt numFields,const PetscInt numComp[],const PetscInt numDof[], PetscSection *section)
4444 {
4445   PetscInt      *numDofTot;
4446   PetscInt       pStart = 0, pEnd = 0;
4447   PetscInt       p, d, f;
4448   PetscErrorCode ierr;
4449 
4450   PetscFunctionBegin;
4451   ierr = PetscMalloc1((dim+1), &numDofTot);CHKERRQ(ierr);
4452   for (d = 0; d <= dim; ++d) {
4453     numDofTot[d] = 0;
4454     for (f = 0; f < numFields; ++f) numDofTot[d] += numDof[f*(dim+1)+d];
4455   }
4456   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)dm), section);CHKERRQ(ierr);
4457   if (numFields > 0) {
4458     ierr = PetscSectionSetNumFields(*section, numFields);CHKERRQ(ierr);
4459     if (numComp) {
4460       for (f = 0; f < numFields; ++f) {
4461         ierr = PetscSectionSetFieldComponents(*section, f, numComp[f]);CHKERRQ(ierr);
4462       }
4463     }
4464   }
4465   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
4466   ierr = PetscSectionSetChart(*section, pStart, pEnd);CHKERRQ(ierr);
4467   for (d = 0; d <= dim; ++d) {
4468     ierr = DMPlexGetDepthStratum(dm, d, &pStart, &pEnd);CHKERRQ(ierr);
4469     for (p = pStart; p < pEnd; ++p) {
4470       for (f = 0; f < numFields; ++f) {
4471         ierr = PetscSectionSetFieldDof(*section, p, f, numDof[f*(dim+1)+d]);CHKERRQ(ierr);
4472       }
4473       ierr = PetscSectionSetDof(*section, p, numDofTot[d]);CHKERRQ(ierr);
4474     }
4475   }
4476   ierr = PetscFree(numDofTot);CHKERRQ(ierr);
4477   PetscFunctionReturn(0);
4478 }
4479 
4480 #undef __FUNCT__
4481 #define __FUNCT__ "DMPlexCreateSectionBCDof"
4482 /* Set the number of dof on each point and separate by fields
4483    If constDof is PETSC_DETERMINE, constrain every dof on the point
4484 */
4485 PetscErrorCode DMPlexCreateSectionBCDof(DM dm, PetscInt numBC,const PetscInt bcField[],const IS bcPoints[], PetscInt constDof, PetscSection section)
4486 {
4487   PetscInt       numFields;
4488   PetscInt       bc;
4489   PetscErrorCode ierr;
4490 
4491   PetscFunctionBegin;
4492   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
4493   for (bc = 0; bc < numBC; ++bc) {
4494     PetscInt        field = 0;
4495     const PetscInt *idx;
4496     PetscInt        n, i;
4497 
4498     if (numFields) field = bcField[bc];
4499     ierr = ISGetLocalSize(bcPoints[bc], &n);CHKERRQ(ierr);
4500     ierr = ISGetIndices(bcPoints[bc], &idx);CHKERRQ(ierr);
4501     for (i = 0; i < n; ++i) {
4502       const PetscInt p        = idx[i];
4503       PetscInt       numConst = constDof;
4504 
4505       /* Constrain every dof on the point */
4506       if (numConst < 0) {
4507         if (numFields) {
4508           ierr = PetscSectionGetFieldDof(section, p, field, &numConst);CHKERRQ(ierr);
4509         } else {
4510           ierr = PetscSectionGetDof(section, p, &numConst);CHKERRQ(ierr);
4511         }
4512       }
4513       if (numFields) {
4514         ierr = PetscSectionAddFieldConstraintDof(section, p, field, numConst);CHKERRQ(ierr);
4515       }
4516       ierr = PetscSectionAddConstraintDof(section, p, numConst);CHKERRQ(ierr);
4517     }
4518     ierr = ISRestoreIndices(bcPoints[bc], &idx);CHKERRQ(ierr);
4519   }
4520   PetscFunctionReturn(0);
4521 }
4522 
4523 #undef __FUNCT__
4524 #define __FUNCT__ "DMPlexCreateSectionBCIndicesAll"
4525 /* Set the constrained indices on each point and separate by fields */
4526 PetscErrorCode DMPlexCreateSectionBCIndicesAll(DM dm, PetscSection section)
4527 {
4528   PetscInt      *maxConstraints;
4529   PetscInt       numFields, f, pStart = 0, pEnd = 0, p;
4530   PetscErrorCode ierr;
4531 
4532   PetscFunctionBegin;
4533   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
4534   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
4535   ierr = PetscMalloc1((numFields+1), &maxConstraints);CHKERRQ(ierr);
4536   for (f = 0; f <= numFields; ++f) maxConstraints[f] = 0;
4537   for (p = pStart; p < pEnd; ++p) {
4538     PetscInt cdof;
4539 
4540     if (numFields) {
4541       for (f = 0; f < numFields; ++f) {
4542         ierr              = PetscSectionGetFieldConstraintDof(section, p, f, &cdof);CHKERRQ(ierr);
4543         maxConstraints[f] = PetscMax(maxConstraints[f], cdof);
4544       }
4545     } else {
4546       ierr              = PetscSectionGetConstraintDof(section, p, &cdof);CHKERRQ(ierr);
4547       maxConstraints[0] = PetscMax(maxConstraints[0], cdof);
4548     }
4549   }
4550   for (f = 0; f < numFields; ++f) {
4551     maxConstraints[numFields] += maxConstraints[f];
4552   }
4553   if (maxConstraints[numFields]) {
4554     PetscInt *indices;
4555 
4556     ierr = PetscMalloc1(maxConstraints[numFields], &indices);CHKERRQ(ierr);
4557     for (p = pStart; p < pEnd; ++p) {
4558       PetscInt cdof, d;
4559 
4560       ierr = PetscSectionGetConstraintDof(section, p, &cdof);CHKERRQ(ierr);
4561       if (cdof) {
4562         if (cdof > maxConstraints[numFields]) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_LIB, "Likely memory corruption, point %D cDof %D > maxConstraints %D", p, cdof, maxConstraints[numFields]);
4563         if (numFields) {
4564           PetscInt numConst = 0, foff = 0;
4565 
4566           for (f = 0; f < numFields; ++f) {
4567             PetscInt cfdof, fdof;
4568 
4569             ierr = PetscSectionGetFieldDof(section, p, f, &fdof);CHKERRQ(ierr);
4570             ierr = PetscSectionGetFieldConstraintDof(section, p, f, &cfdof);CHKERRQ(ierr);
4571             /* Change constraint numbering from absolute local dof number to field relative local dof number */
4572             for (d = 0; d < cfdof; ++d) indices[numConst+d] = d;
4573             ierr = PetscSectionSetFieldConstraintIndices(section, p, f, &indices[numConst]);CHKERRQ(ierr);
4574             for (d = 0; d < cfdof; ++d) indices[numConst+d] += foff;
4575             numConst += cfdof;
4576             foff     += fdof;
4577           }
4578           if (cdof != numConst) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_LIB, "Total number of field constraints %D should be %D", numConst, cdof);
4579         } else {
4580           for (d = 0; d < cdof; ++d) indices[d] = d;
4581         }
4582         ierr = PetscSectionSetConstraintIndices(section, p, indices);CHKERRQ(ierr);
4583       }
4584     }
4585     ierr = PetscFree(indices);CHKERRQ(ierr);
4586   }
4587   ierr = PetscFree(maxConstraints);CHKERRQ(ierr);
4588   PetscFunctionReturn(0);
4589 }
4590 
4591 #undef __FUNCT__
4592 #define __FUNCT__ "DMPlexCreateSectionBCIndicesField"
4593 /* Set the constrained field indices on each point */
4594 PetscErrorCode DMPlexCreateSectionBCIndicesField(DM dm, PetscInt field, IS bcPoints, IS constraintIndices, PetscSection section)
4595 {
4596   const PetscInt *points, *indices;
4597   PetscInt        numFields, maxDof, numPoints, p, numConstraints;
4598   PetscErrorCode  ierr;
4599 
4600   PetscFunctionBegin;
4601   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
4602   if ((field < 0) || (field >= numFields)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Section field %d should be in [%d, %d)", field, 0, numFields);
4603 
4604   ierr = ISGetLocalSize(bcPoints, &numPoints);CHKERRQ(ierr);
4605   ierr = ISGetIndices(bcPoints, &points);CHKERRQ(ierr);
4606   if (!constraintIndices) {
4607     PetscInt *idx, i;
4608 
4609     ierr = PetscSectionGetMaxDof(section, &maxDof);CHKERRQ(ierr);
4610     ierr = PetscMalloc1(maxDof, &idx);CHKERRQ(ierr);
4611     for (i = 0; i < maxDof; ++i) idx[i] = i;
4612     for (p = 0; p < numPoints; ++p) {
4613       ierr = PetscSectionSetFieldConstraintIndices(section, points[p], field, idx);CHKERRQ(ierr);
4614     }
4615     ierr = PetscFree(idx);CHKERRQ(ierr);
4616   } else {
4617     ierr = ISGetLocalSize(constraintIndices, &numConstraints);CHKERRQ(ierr);
4618     ierr = ISGetIndices(constraintIndices, &indices);CHKERRQ(ierr);
4619     for (p = 0; p < numPoints; ++p) {
4620       PetscInt fcdof;
4621 
4622       ierr = PetscSectionGetFieldConstraintDof(section, points[p], field, &fcdof);CHKERRQ(ierr);
4623       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);
4624       ierr = PetscSectionSetFieldConstraintIndices(section, points[p], field, indices);CHKERRQ(ierr);
4625     }
4626     ierr = ISRestoreIndices(constraintIndices, &indices);CHKERRQ(ierr);
4627   }
4628   ierr = ISRestoreIndices(bcPoints, &points);CHKERRQ(ierr);
4629   PetscFunctionReturn(0);
4630 }
4631 
4632 #undef __FUNCT__
4633 #define __FUNCT__ "DMPlexCreateSectionBCIndices"
4634 /* Set the constrained indices on each point and separate by fields */
4635 PetscErrorCode DMPlexCreateSectionBCIndices(DM dm, PetscSection section)
4636 {
4637   PetscInt      *indices;
4638   PetscInt       numFields, maxDof, f, pStart = 0, pEnd = 0, p;
4639   PetscErrorCode ierr;
4640 
4641   PetscFunctionBegin;
4642   ierr = PetscSectionGetMaxDof(section, &maxDof);CHKERRQ(ierr);
4643   ierr = PetscMalloc1(maxDof, &indices);CHKERRQ(ierr);
4644   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
4645   if (!numFields) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "This function only works after users have set field constraint indices.");
4646   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
4647   for (p = pStart; p < pEnd; ++p) {
4648     PetscInt cdof, d;
4649 
4650     ierr = PetscSectionGetConstraintDof(section, p, &cdof);CHKERRQ(ierr);
4651     if (cdof) {
4652       PetscInt numConst = 0, foff = 0;
4653 
4654       for (f = 0; f < numFields; ++f) {
4655         const PetscInt *fcind;
4656         PetscInt        fdof, fcdof;
4657 
4658         ierr = PetscSectionGetFieldDof(section, p, f, &fdof);CHKERRQ(ierr);
4659         ierr = PetscSectionGetFieldConstraintDof(section, p, f, &fcdof);CHKERRQ(ierr);
4660         if (fcdof) {ierr = PetscSectionGetFieldConstraintIndices(section, p, f, &fcind);CHKERRQ(ierr);}
4661         /* Change constraint numbering from field relative local dof number to absolute local dof number */
4662         for (d = 0; d < fcdof; ++d) indices[numConst+d] = fcind[d]+foff;
4663         foff     += fdof;
4664         numConst += fcdof;
4665       }
4666       if (cdof != numConst) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_LIB, "Total number of field constraints %D should be %D", numConst, cdof);
4667       ierr = PetscSectionSetConstraintIndices(section, p, indices);CHKERRQ(ierr);
4668     }
4669   }
4670   ierr = PetscFree(indices);CHKERRQ(ierr);
4671   PetscFunctionReturn(0);
4672 }
4673 
4674 #undef __FUNCT__
4675 #define __FUNCT__ "DMPlexCreateSection"
4676 /*@C
4677   DMPlexCreateSection - Create a PetscSection based upon the dof layout specification provided.
4678 
4679   Not Collective
4680 
4681   Input Parameters:
4682 + dm        - The DMPlex object
4683 . dim       - The spatial dimension of the problem
4684 . numFields - The number of fields in the problem
4685 . numComp   - An array of size numFields that holds the number of components for each field
4686 . numDof    - An array of size numFields*(dim+1) which holds the number of dof for each field on a mesh piece of dimension d
4687 . numBC     - The number of boundary conditions
4688 . bcField   - An array of size numBC giving the field number for each boundry condition
4689 - bcPoints  - An array of size numBC giving an IS holding the sieve points to which each boundary condition applies
4690 
4691   Output Parameter:
4692 . section - The PetscSection object
4693 
4694   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
4695   nubmer of dof for field 0 on each edge.
4696 
4697   Level: developer
4698 
4699   Fortran Notes:
4700   A Fortran 90 version is available as DMPlexCreateSectionF90()
4701 
4702 .keywords: mesh, elements
4703 .seealso: DMPlexCreate(), PetscSectionCreate()
4704 @*/
4705 PetscErrorCode DMPlexCreateSection(DM dm, PetscInt dim, PetscInt numFields,const PetscInt numComp[],const PetscInt numDof[], PetscInt numBC,const PetscInt bcField[],const IS bcPoints[], PetscSection *section)
4706 {
4707   PetscErrorCode ierr;
4708 
4709   PetscFunctionBegin;
4710   ierr = DMPlexCreateSectionInitial(dm, dim, numFields, numComp, numDof, section);CHKERRQ(ierr);
4711   ierr = DMPlexCreateSectionBCDof(dm, numBC, bcField, bcPoints, PETSC_DETERMINE, *section);CHKERRQ(ierr);
4712   ierr = PetscSectionSetUp(*section);CHKERRQ(ierr);
4713   if (numBC) {ierr = DMPlexCreateSectionBCIndicesAll(dm, *section);CHKERRQ(ierr);}
4714   {
4715     PetscBool view = PETSC_FALSE;
4716 
4717     ierr = PetscOptionsHasName(((PetscObject) dm)->prefix, "-section_view", &view);CHKERRQ(ierr);
4718     if (view) {ierr = PetscSectionView(*section, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);}
4719   }
4720   PetscFunctionReturn(0);
4721 }
4722 
4723 #undef __FUNCT__
4724 #define __FUNCT__ "DMCreateCoordinateDM_Plex"
4725 PetscErrorCode DMCreateCoordinateDM_Plex(DM dm, DM *cdm)
4726 {
4727   PetscSection   section;
4728   PetscErrorCode ierr;
4729 
4730   PetscFunctionBegin;
4731   ierr = DMClone(dm, cdm);CHKERRQ(ierr);
4732   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)dm), &section);CHKERRQ(ierr);
4733   ierr = DMSetDefaultSection(*cdm, section);CHKERRQ(ierr);
4734   ierr = PetscSectionDestroy(&section);CHKERRQ(ierr);
4735   PetscFunctionReturn(0);
4736 }
4737 
4738 #undef __FUNCT__
4739 #define __FUNCT__ "DMPlexGetCoordinateSection"
4740 /*@
4741   DMPlexGetCoordinateSection - Retrieve the layout of coordinate values over the mesh.
4742 
4743   Not Collective
4744 
4745   Input Parameter:
4746 . dm - The DMPlex object
4747 
4748   Output Parameter:
4749 . section - The PetscSection object
4750 
4751   Level: intermediate
4752 
4753 .keywords: mesh, coordinates
4754 .seealso: DMGetCoordinateDM(), DMPlexGetDefaultSection(), DMPlexSetDefaultSection()
4755 @*/
4756 PetscErrorCode DMPlexGetCoordinateSection(DM dm, PetscSection *section)
4757 {
4758   DM             cdm;
4759   PetscErrorCode ierr;
4760 
4761   PetscFunctionBegin;
4762   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4763   PetscValidPointer(section, 2);
4764   ierr = DMGetCoordinateDM(dm, &cdm);CHKERRQ(ierr);
4765   ierr = DMGetDefaultSection(cdm, section);CHKERRQ(ierr);
4766   PetscFunctionReturn(0);
4767 }
4768 
4769 #undef __FUNCT__
4770 #define __FUNCT__ "DMPlexSetCoordinateSection"
4771 /*@
4772   DMPlexSetCoordinateSection - Set the layout of coordinate values over the mesh.
4773 
4774   Not Collective
4775 
4776   Input Parameters:
4777 + dm      - The DMPlex object
4778 - section - The PetscSection object
4779 
4780   Level: intermediate
4781 
4782 .keywords: mesh, coordinates
4783 .seealso: DMPlexGetCoordinateSection(), DMPlexGetDefaultSection(), DMPlexSetDefaultSection()
4784 @*/
4785 PetscErrorCode DMPlexSetCoordinateSection(DM dm, PetscSection section)
4786 {
4787   DM             cdm;
4788   PetscErrorCode ierr;
4789 
4790   PetscFunctionBegin;
4791   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
4792   PetscValidHeaderSpecific(section,PETSC_SECTION_CLASSID,2);
4793   ierr = DMGetCoordinateDM(dm, &cdm);CHKERRQ(ierr);
4794   ierr = DMSetDefaultSection(cdm, section);CHKERRQ(ierr);
4795   PetscFunctionReturn(0);
4796 }
4797 
4798 #undef __FUNCT__
4799 #define __FUNCT__ "DMPlexGetConeSection"
4800 PetscErrorCode DMPlexGetConeSection(DM dm, PetscSection *section)
4801 {
4802   DM_Plex *mesh = (DM_Plex*) dm->data;
4803 
4804   PetscFunctionBegin;
4805   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4806   if (section) *section = mesh->coneSection;
4807   PetscFunctionReturn(0);
4808 }
4809 
4810 #undef __FUNCT__
4811 #define __FUNCT__ "DMPlexGetSupportSection"
4812 PetscErrorCode DMPlexGetSupportSection(DM dm, PetscSection *section)
4813 {
4814   DM_Plex *mesh = (DM_Plex*) dm->data;
4815 
4816   PetscFunctionBegin;
4817   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4818   if (section) *section = mesh->supportSection;
4819   PetscFunctionReturn(0);
4820 }
4821 
4822 #undef __FUNCT__
4823 #define __FUNCT__ "DMPlexGetCones"
4824 PetscErrorCode DMPlexGetCones(DM dm, PetscInt *cones[])
4825 {
4826   DM_Plex *mesh = (DM_Plex*) dm->data;
4827 
4828   PetscFunctionBegin;
4829   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4830   if (cones) *cones = mesh->cones;
4831   PetscFunctionReturn(0);
4832 }
4833 
4834 #undef __FUNCT__
4835 #define __FUNCT__ "DMPlexGetConeOrientations"
4836 PetscErrorCode DMPlexGetConeOrientations(DM dm, PetscInt *coneOrientations[])
4837 {
4838   DM_Plex *mesh = (DM_Plex*) dm->data;
4839 
4840   PetscFunctionBegin;
4841   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4842   if (coneOrientations) *coneOrientations = mesh->coneOrientations;
4843   PetscFunctionReturn(0);
4844 }
4845 
4846 /******************************** FEM Support **********************************/
4847 
4848 #undef __FUNCT__
4849 #define __FUNCT__ "DMPlexVecGetClosure"
4850 /*@C
4851   DMPlexVecGetClosure - Get an array of the values on the closure of 'point'
4852 
4853   Not collective
4854 
4855   Input Parameters:
4856 + dm - The DM
4857 . section - The section describing the layout in v, or NULL to use the default section
4858 . v - The local vector
4859 - point - The sieve point in the DM
4860 
4861   Output Parameters:
4862 + csize - The number of values in the closure, or NULL
4863 - values - The array of values, which is a borrowed array and should not be freed
4864 
4865   Fortran Notes:
4866   Since it returns an array, this routine is only available in Fortran 90, and you must
4867   include petsc.h90 in your code.
4868 
4869   The csize argument is not present in the Fortran 90 binding since it is internal to the array.
4870 
4871   Level: intermediate
4872 
4873 .seealso DMPlexVecRestoreClosure(), DMPlexVecSetClosure(), DMPlexMatSetClosure()
4874 @*/
4875 PetscErrorCode DMPlexVecGetClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[])
4876 {
4877   PetscSection   clSection;
4878   IS             clIndices;
4879   PetscScalar   *array, *vArray;
4880   PetscInt      *points = NULL;
4881   PetscInt       offsets[32];
4882   PetscInt       depth, numFields, size = 0, numPoints, pStart, pEnd, p, q, f;
4883   PetscErrorCode ierr;
4884 
4885   PetscFunctionBegin;
4886   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4887   PetscValidHeaderSpecific(v, VEC_CLASSID, 3);
4888   if (!section) {ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);}
4889   ierr = PetscSectionGetClosureIndex(section, (PetscObject) dm, &clSection, &clIndices);CHKERRQ(ierr);
4890   if (clSection) {
4891     const PetscInt *idx;
4892     PetscInt        dof, off;
4893 
4894     ierr = PetscSectionGetDof(clSection, point, &dof);CHKERRQ(ierr);
4895     if (csize) *csize = dof;
4896     if (values) {
4897       if (!*values) {
4898         ierr = DMGetWorkArray(dm, dof, PETSC_SCALAR, &array);CHKERRQ(ierr);
4899         *values = array;
4900       } else {
4901         array = *values;
4902       }
4903       ierr = PetscSectionGetOffset(clSection, point, &off);CHKERRQ(ierr);
4904       ierr = ISGetIndices(clIndices, &idx);CHKERRQ(ierr);
4905       ierr = VecGetArray(v, &vArray);CHKERRQ(ierr);
4906       for (p = 0; p < dof; ++p) array[p] = vArray[idx[off+p]];
4907       ierr = VecRestoreArray(v, &vArray);CHKERRQ(ierr);
4908       ierr = ISRestoreIndices(clIndices, &idx);CHKERRQ(ierr);
4909     }
4910     PetscFunctionReturn(0);
4911   }
4912   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
4913   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
4914   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
4915   if (numFields > 31) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
4916   ierr = PetscMemzero(offsets, 32 * sizeof(PetscInt));CHKERRQ(ierr);
4917   if (depth == 1 && numFields < 2) {
4918     const PetscInt *cone, *coneO;
4919 
4920     ierr = DMPlexGetConeSize(dm, point, &numPoints);CHKERRQ(ierr);
4921     ierr = DMPlexGetCone(dm, point, &cone);CHKERRQ(ierr);
4922     ierr = DMPlexGetConeOrientation(dm, point, &coneO);CHKERRQ(ierr);
4923     if (!values || !*values) {
4924       if ((point >= pStart) && (point < pEnd)) {
4925         PetscInt dof;
4926         ierr = PetscSectionGetDof(section, point, &dof);CHKERRQ(ierr);
4927         size += dof;
4928       }
4929       for (p = 0; p < numPoints; ++p) {
4930         const PetscInt cp = cone[p];
4931         PetscInt       dof;
4932 
4933         if ((cp < pStart) || (cp >= pEnd)) continue;
4934         ierr = PetscSectionGetDof(section, cp, &dof);CHKERRQ(ierr);
4935         size += dof;
4936       }
4937       if (!values) {
4938         if (csize) *csize = size;
4939         PetscFunctionReturn(0);
4940       }
4941       ierr = DMGetWorkArray(dm, size, PETSC_SCALAR, &array);CHKERRQ(ierr);
4942     } else {
4943       array = *values;
4944     }
4945     size = 0;
4946     ierr = VecGetArray(v, &vArray);CHKERRQ(ierr);
4947     if ((point >= pStart) && (point < pEnd)) {
4948       PetscInt     dof, off, d;
4949       PetscScalar *varr;
4950       ierr = PetscSectionGetDof(section, point, &dof);CHKERRQ(ierr);
4951       ierr = PetscSectionGetOffset(section, point, &off);CHKERRQ(ierr);
4952       varr = &vArray[off];
4953       for (d = 0; d < dof; ++d, ++offsets[0]) {
4954         array[offsets[0]] = varr[d];
4955       }
4956       size += dof;
4957     }
4958     for (p = 0; p < numPoints; ++p) {
4959       const PetscInt cp = cone[p];
4960       PetscInt       o  = coneO[p];
4961       PetscInt       dof, off, d;
4962       PetscScalar   *varr;
4963 
4964       if ((cp < pStart) || (cp >= pEnd)) continue;
4965       ierr = PetscSectionGetDof(section, cp, &dof);CHKERRQ(ierr);
4966       ierr = PetscSectionGetOffset(section, cp, &off);CHKERRQ(ierr);
4967       varr = &vArray[off];
4968       if (o >= 0) {
4969         for (d = 0; d < dof; ++d, ++offsets[0]) {
4970           array[offsets[0]] = varr[d];
4971         }
4972       } else {
4973         for (d = dof-1; d >= 0; --d, ++offsets[0]) {
4974           array[offsets[0]] = varr[d];
4975         }
4976       }
4977       size += dof;
4978     }
4979     ierr = VecRestoreArray(v, &vArray);CHKERRQ(ierr);
4980     if (!*values) {
4981       if (csize) *csize = size;
4982       *values = array;
4983     } else {
4984       if (size > *csize) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %d < actual size %d", *csize, size);
4985       *csize = size;
4986     }
4987     PetscFunctionReturn(0);
4988   }
4989   ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
4990   /* Compress out points not in the section */
4991   for (p = 0, q = 0; p < numPoints*2; p += 2) {
4992     if ((points[p] >= pStart) && (points[p] < pEnd)) {
4993       points[q*2]   = points[p];
4994       points[q*2+1] = points[p+1];
4995       ++q;
4996     }
4997   }
4998   numPoints = q;
4999   if (!values || !*values) {
5000     for (p = 0, size = 0; p < numPoints*2; p += 2) {
5001       PetscInt dof, fdof;
5002 
5003       ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
5004       for (f = 0; f < numFields; ++f) {
5005         ierr          = PetscSectionGetFieldDof(section, points[p], f, &fdof);CHKERRQ(ierr);
5006         offsets[f+1] += fdof;
5007       }
5008       size += dof;
5009     }
5010     if (!values) {
5011       ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
5012       if (csize) *csize = size;
5013       PetscFunctionReturn(0);
5014     }
5015     ierr = DMGetWorkArray(dm, size, PETSC_SCALAR, &array);CHKERRQ(ierr);
5016   } else {
5017     array = *values;
5018   }
5019   for (f = 1; f < numFields; ++f) offsets[f+1] += offsets[f];
5020   if (numFields && offsets[numFields] != size) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid size for closure %d should be %d", offsets[numFields], size);
5021   ierr = VecGetArray(v, &vArray);CHKERRQ(ierr);
5022   for (p = 0; p < numPoints*2; p += 2) {
5023     PetscInt     o = points[p+1];
5024     PetscInt     dof, off, d;
5025     PetscScalar *varr;
5026 
5027     ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
5028     ierr = PetscSectionGetOffset(section, points[p], &off);CHKERRQ(ierr);
5029     varr = &vArray[off];
5030     if (numFields) {
5031       PetscInt fdof, foff, fcomp, f, c;
5032 
5033       for (f = 0, foff = 0; f < numFields; ++f) {
5034         ierr = PetscSectionGetFieldDof(section, points[p], f, &fdof);CHKERRQ(ierr);
5035         if (o >= 0) {
5036           for (d = 0; d < fdof; ++d, ++offsets[f]) {
5037             array[offsets[f]] = varr[foff+d];
5038           }
5039         } else {
5040           ierr = PetscSectionGetFieldComponents(section, f, &fcomp);CHKERRQ(ierr);
5041           for (d = fdof/fcomp-1; d >= 0; --d) {
5042             for (c = 0; c < fcomp; ++c, ++offsets[f]) {
5043               array[offsets[f]] = varr[foff+d*fcomp+c];
5044             }
5045           }
5046         }
5047         foff += fdof;
5048       }
5049     } else {
5050       if (o >= 0) {
5051         for (d = 0; d < dof; ++d, ++offsets[0]) {
5052           array[offsets[0]] = varr[d];
5053         }
5054       } else {
5055         for (d = dof-1; d >= 0; --d, ++offsets[0]) {
5056           array[offsets[0]] = varr[d];
5057         }
5058       }
5059     }
5060   }
5061   ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
5062   ierr = VecRestoreArray(v, &vArray);CHKERRQ(ierr);
5063   if (!*values) {
5064     if (csize) *csize = size;
5065     *values = array;
5066   } else {
5067     if (size > *csize) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %d < actual size %d", *csize, size);
5068     *csize = size;
5069   }
5070   PetscFunctionReturn(0);
5071 }
5072 
5073 #undef __FUNCT__
5074 #define __FUNCT__ "DMPlexVecRestoreClosure"
5075 /*@C
5076   DMPlexVecRestoreClosure - Restore the array of the values on the closure of 'point'
5077 
5078   Not collective
5079 
5080   Input Parameters:
5081 + dm - The DM
5082 . section - The section describing the layout in v, or NULL to use the default section
5083 . v - The local vector
5084 . point - The sieve point in the DM
5085 . csize - The number of values in the closure, or NULL
5086 - values - The array of values, which is a borrowed array and should not be freed
5087 
5088   Fortran Notes:
5089   Since it returns an array, this routine is only available in Fortran 90, and you must
5090   include petsc.h90 in your code.
5091 
5092   The csize argument is not present in the Fortran 90 binding since it is internal to the array.
5093 
5094   Level: intermediate
5095 
5096 .seealso DMPlexVecGetClosure(), DMPlexVecSetClosure(), DMPlexMatSetClosure()
5097 @*/
5098 PetscErrorCode DMPlexVecRestoreClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[])
5099 {
5100   PetscInt       size = 0;
5101   PetscErrorCode ierr;
5102 
5103   PetscFunctionBegin;
5104   /* Should work without recalculating size */
5105   ierr = DMRestoreWorkArray(dm, size, PETSC_SCALAR, (void*) values);CHKERRQ(ierr);
5106   PetscFunctionReturn(0);
5107 }
5108 
5109 PETSC_STATIC_INLINE void add   (PetscScalar *x, PetscScalar y) {*x += y;}
5110 PETSC_STATIC_INLINE void insert(PetscScalar *x, PetscScalar y) {*x  = y;}
5111 
5112 #undef __FUNCT__
5113 #define __FUNCT__ "updatePoint_private"
5114 PetscErrorCode updatePoint_private(PetscSection section, PetscInt point, PetscInt dof, void (*fuse)(PetscScalar*, PetscScalar), PetscBool setBC, PetscInt orientation, const PetscScalar values[], PetscScalar array[])
5115 {
5116   PetscInt        cdof;   /* The number of constraints on this point */
5117   const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
5118   PetscScalar    *a;
5119   PetscInt        off, cind = 0, k;
5120   PetscErrorCode  ierr;
5121 
5122   PetscFunctionBegin;
5123   ierr = PetscSectionGetConstraintDof(section, point, &cdof);CHKERRQ(ierr);
5124   ierr = PetscSectionGetOffset(section, point, &off);CHKERRQ(ierr);
5125   a    = &array[off];
5126   if (!cdof || setBC) {
5127     if (orientation >= 0) {
5128       for (k = 0; k < dof; ++k) {
5129         fuse(&a[k], values[k]);
5130       }
5131     } else {
5132       for (k = 0; k < dof; ++k) {
5133         fuse(&a[k], values[dof-k-1]);
5134       }
5135     }
5136   } else {
5137     ierr = PetscSectionGetConstraintIndices(section, point, &cdofs);CHKERRQ(ierr);
5138     if (orientation >= 0) {
5139       for (k = 0; k < dof; ++k) {
5140         if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
5141         fuse(&a[k], values[k]);
5142       }
5143     } else {
5144       for (k = 0; k < dof; ++k) {
5145         if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
5146         fuse(&a[k], values[dof-k-1]);
5147       }
5148     }
5149   }
5150   PetscFunctionReturn(0);
5151 }
5152 
5153 #undef __FUNCT__
5154 #define __FUNCT__ "updatePointBC_private"
5155 PetscErrorCode updatePointBC_private(PetscSection section, PetscInt point, PetscInt dof, void (*fuse)(PetscScalar*, PetscScalar), PetscInt orientation, const PetscScalar values[], PetscScalar array[])
5156 {
5157   PetscInt        cdof;   /* The number of constraints on this point */
5158   const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
5159   PetscScalar    *a;
5160   PetscInt        off, cind = 0, k;
5161   PetscErrorCode  ierr;
5162 
5163   PetscFunctionBegin;
5164   ierr = PetscSectionGetConstraintDof(section, point, &cdof);CHKERRQ(ierr);
5165   ierr = PetscSectionGetOffset(section, point, &off);CHKERRQ(ierr);
5166   a    = &array[off];
5167   if (cdof) {
5168     ierr = PetscSectionGetConstraintIndices(section, point, &cdofs);CHKERRQ(ierr);
5169     if (orientation >= 0) {
5170       for (k = 0; k < dof; ++k) {
5171         if ((cind < cdof) && (k == cdofs[cind])) {
5172           fuse(&a[k], values[k]);
5173           ++cind;
5174         }
5175       }
5176     } else {
5177       for (k = 0; k < dof; ++k) {
5178         if ((cind < cdof) && (k == cdofs[cind])) {
5179           fuse(&a[k], values[dof-k-1]);
5180           ++cind;
5181         }
5182       }
5183     }
5184   }
5185   PetscFunctionReturn(0);
5186 }
5187 
5188 #undef __FUNCT__
5189 #define __FUNCT__ "updatePointFields_private"
5190 PetscErrorCode updatePointFields_private(PetscSection section, PetscInt point, PetscInt foffs[], void (*fuse)(PetscScalar*, PetscScalar), PetscBool setBC, PetscInt orientation, const PetscScalar values[], PetscScalar array[])
5191 {
5192   PetscScalar   *a;
5193   PetscInt       numFields, off, foff, f;
5194   PetscErrorCode ierr;
5195 
5196   PetscFunctionBegin;
5197   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
5198   ierr = PetscSectionGetOffset(section, point, &off);CHKERRQ(ierr);
5199   a    = &array[off];
5200   for (f = 0, foff = 0; f < numFields; ++f) {
5201     PetscInt        fdof, fcomp, fcdof;
5202     const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
5203     PetscInt        cind = 0, k, c;
5204 
5205     ierr = PetscSectionGetFieldComponents(section, f, &fcomp);CHKERRQ(ierr);
5206     ierr = PetscSectionGetFieldDof(section, point, f, &fdof);CHKERRQ(ierr);
5207     ierr = PetscSectionGetFieldConstraintDof(section, point, f, &fcdof);CHKERRQ(ierr);
5208     if (!fcdof || setBC) {
5209       if (orientation >= 0) {
5210         for (k = 0; k < fdof; ++k) {
5211           fuse(&a[foff+k], values[foffs[f]+k]);
5212         }
5213       } else {
5214         for (k = fdof/fcomp-1; k >= 0; --k) {
5215           for (c = 0; c < fcomp; ++c) {
5216             fuse(&a[foff+(fdof/fcomp-1-k)*fcomp+c], values[foffs[f]+k*fcomp+c]);
5217           }
5218         }
5219       }
5220     } else {
5221       ierr = PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);CHKERRQ(ierr);
5222       if (orientation >= 0) {
5223         for (k = 0; k < fdof; ++k) {
5224           if ((cind < fcdof) && (k == fcdofs[cind])) {++cind; continue;}
5225           fuse(&a[foff+k], values[foffs[f]+k]);
5226         }
5227       } else {
5228         for (k = fdof/fcomp-1; k >= 0; --k) {
5229           for (c = 0; c < fcomp; ++c) {
5230             if ((cind < fcdof) && (k*fcomp+c == fcdofs[cind])) {++cind; continue;}
5231             fuse(&a[foff+(fdof/fcomp-1-k)*fcomp+c], values[foffs[f]+k*fcomp+c]);
5232           }
5233         }
5234       }
5235     }
5236     foff     += fdof;
5237     foffs[f] += fdof;
5238   }
5239   PetscFunctionReturn(0);
5240 }
5241 
5242 #undef __FUNCT__
5243 #define __FUNCT__ "updatePointFieldsBC_private"
5244 PetscErrorCode updatePointFieldsBC_private(PetscSection section, PetscInt point, PetscInt foffs[], void (*fuse)(PetscScalar*, PetscScalar), PetscInt orientation, const PetscScalar values[], PetscScalar array[])
5245 {
5246   PetscScalar   *a;
5247   PetscInt       numFields, off, foff, f;
5248   PetscErrorCode ierr;
5249 
5250   PetscFunctionBegin;
5251   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
5252   ierr = PetscSectionGetOffset(section, point, &off);CHKERRQ(ierr);
5253   a    = &array[off];
5254   for (f = 0, foff = 0; f < numFields; ++f) {
5255     PetscInt        fdof, fcomp, fcdof;
5256     const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
5257     PetscInt        cind = 0, k, c;
5258 
5259     ierr = PetscSectionGetFieldComponents(section, f, &fcomp);CHKERRQ(ierr);
5260     ierr = PetscSectionGetFieldDof(section, point, f, &fdof);CHKERRQ(ierr);
5261     ierr = PetscSectionGetFieldConstraintDof(section, point, f, &fcdof);CHKERRQ(ierr);
5262     if (fcdof) {
5263       ierr = PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);CHKERRQ(ierr);
5264       if (orientation >= 0) {
5265         for (k = 0; k < fdof; ++k) {
5266           if ((cind < fcdof) && (k == fcdofs[cind])) {
5267             fuse(&a[foff+k], values[foffs[f]+k]);
5268             ++cind;
5269           }
5270         }
5271       } else {
5272         for (k = fdof/fcomp-1; k >= 0; --k) {
5273           for (c = 0; c < fcomp; ++c) {
5274             if ((cind < fcdof) && (k*fcomp+c == fcdofs[cind])) {
5275               fuse(&a[foff+(fdof/fcomp-1-k)*fcomp+c], values[foffs[f]+k*fcomp+c]);
5276               ++cind;
5277             }
5278           }
5279         }
5280       }
5281     }
5282     foff     += fdof;
5283     foffs[f] += fdof;
5284   }
5285   PetscFunctionReturn(0);
5286 }
5287 
5288 #undef __FUNCT__
5289 #define __FUNCT__ "DMPlexVecSetClosure"
5290 /*@C
5291   DMPlexVecSetClosure - Set an array of the values on the closure of 'point'
5292 
5293   Not collective
5294 
5295   Input Parameters:
5296 + dm - The DM
5297 . section - The section describing the layout in v, or NULL to use the default section
5298 . v - The local vector
5299 . point - The sieve point in the DM
5300 . values - The array of values
5301 - mode - The insert mode, where INSERT_ALL_VALUES and ADD_ALL_VALUES also overwrite boundary conditions
5302 
5303   Fortran Notes:
5304   This routine is only available in Fortran 90, and you must include petsc.h90 in your code.
5305 
5306   Level: intermediate
5307 
5308 .seealso DMPlexVecGetClosure(), DMPlexMatSetClosure()
5309 @*/
5310 PetscErrorCode DMPlexVecSetClosure(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode)
5311 {
5312   PetscScalar   *array;
5313   PetscInt      *points = NULL;
5314   PetscInt       offsets[32];
5315   PetscInt       depth, numFields, numPoints, off, dof, pStart, pEnd, p, q, f;
5316   PetscErrorCode ierr;
5317 
5318   PetscFunctionBegin;
5319   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5320   PetscValidHeaderSpecific(v, VEC_CLASSID, 3);
5321   if (!section) {
5322     ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
5323   }
5324   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
5325   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
5326   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
5327   if (numFields > 31) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
5328   ierr = PetscMemzero(offsets, 32 * sizeof(PetscInt));CHKERRQ(ierr);
5329   if (depth == 1 && numFields < 2 && mode == ADD_VALUES) {
5330     const PetscInt *cone, *coneO;
5331 
5332     ierr = DMPlexGetConeSize(dm, point, &numPoints);CHKERRQ(ierr);
5333     ierr = DMPlexGetCone(dm, point, &cone);CHKERRQ(ierr);
5334     ierr = DMPlexGetConeOrientation(dm, point, &coneO);CHKERRQ(ierr);
5335     ierr = VecGetArray(v, &array);CHKERRQ(ierr);
5336     for (p = 0, off = 0; p <= numPoints; ++p, off += dof) {
5337       const PetscInt cp = !p ? point : cone[p-1];
5338       const PetscInt o  = !p ? 0     : coneO[p-1];
5339 
5340       if ((cp < pStart) || (cp >= pEnd)) {dof = 0; continue;}
5341       ierr = PetscSectionGetDof(section, cp, &dof);CHKERRQ(ierr);
5342       /* ADD_VALUES */
5343       {
5344         const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
5345         PetscScalar    *a;
5346         PetscInt        cdof, coff, cind = 0, k;
5347 
5348         ierr = PetscSectionGetConstraintDof(section, cp, &cdof);CHKERRQ(ierr);
5349         ierr = PetscSectionGetOffset(section, cp, &coff);CHKERRQ(ierr);
5350         a    = &array[coff];
5351         if (!cdof) {
5352           if (o >= 0) {
5353             for (k = 0; k < dof; ++k) {
5354               a[k] += values[off+k];
5355             }
5356           } else {
5357             for (k = 0; k < dof; ++k) {
5358               a[k] += values[off+dof-k-1];
5359             }
5360           }
5361         } else {
5362           ierr = PetscSectionGetConstraintIndices(section, cp, &cdofs);CHKERRQ(ierr);
5363           if (o >= 0) {
5364             for (k = 0; k < dof; ++k) {
5365               if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
5366               a[k] += values[off+k];
5367             }
5368           } else {
5369             for (k = 0; k < dof; ++k) {
5370               if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
5371               a[k] += values[off+dof-k-1];
5372             }
5373           }
5374         }
5375       }
5376     }
5377     ierr = VecRestoreArray(v, &array);CHKERRQ(ierr);
5378     PetscFunctionReturn(0);
5379   }
5380   ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
5381   /* Compress out points not in the section */
5382   for (p = 0, q = 0; p < numPoints*2; p += 2) {
5383     if ((points[p] >= pStart) && (points[p] < pEnd)) {
5384       points[q*2]   = points[p];
5385       points[q*2+1] = points[p+1];
5386       ++q;
5387     }
5388   }
5389   numPoints = q;
5390   for (p = 0; p < numPoints*2; p += 2) {
5391     PetscInt fdof;
5392 
5393     for (f = 0; f < numFields; ++f) {
5394       ierr          = PetscSectionGetFieldDof(section, points[p], f, &fdof);CHKERRQ(ierr);
5395       offsets[f+1] += fdof;
5396     }
5397   }
5398   for (f = 1; f < numFields; ++f) offsets[f+1] += offsets[f];
5399   ierr = VecGetArray(v, &array);CHKERRQ(ierr);
5400   if (numFields) {
5401     switch (mode) {
5402     case INSERT_VALUES:
5403       for (p = 0; p < numPoints*2; p += 2) {
5404         PetscInt o = points[p+1];
5405         updatePointFields_private(section, points[p], offsets, insert, PETSC_FALSE, o, values, array);
5406       } break;
5407     case INSERT_ALL_VALUES:
5408       for (p = 0; p < numPoints*2; p += 2) {
5409         PetscInt o = points[p+1];
5410         updatePointFields_private(section, points[p], offsets, insert, PETSC_TRUE,  o, values, array);
5411       } break;
5412     case INSERT_BC_VALUES:
5413       for (p = 0; p < numPoints*2; p += 2) {
5414         PetscInt o = points[p+1];
5415         updatePointFieldsBC_private(section, points[p], offsets, insert,  o, values, array);
5416       } break;
5417     case ADD_VALUES:
5418       for (p = 0; p < numPoints*2; p += 2) {
5419         PetscInt o = points[p+1];
5420         updatePointFields_private(section, points[p], offsets, add,    PETSC_FALSE, o, values, array);
5421       } break;
5422     case ADD_ALL_VALUES:
5423       for (p = 0; p < numPoints*2; p += 2) {
5424         PetscInt o = points[p+1];
5425         updatePointFields_private(section, points[p], offsets, add,    PETSC_TRUE,  o, values, array);
5426       } break;
5427     default:
5428       SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %D", mode);
5429     }
5430   } else {
5431     switch (mode) {
5432     case INSERT_VALUES:
5433       for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) {
5434         PetscInt o = points[p+1];
5435         ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
5436         updatePoint_private(section, points[p], dof, insert, PETSC_FALSE, o, &values[off], array);
5437       } break;
5438     case INSERT_ALL_VALUES:
5439       for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) {
5440         PetscInt o = points[p+1];
5441         ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
5442         updatePoint_private(section, points[p], dof, insert, PETSC_TRUE,  o, &values[off], array);
5443       } break;
5444     case INSERT_BC_VALUES:
5445       for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) {
5446         PetscInt o = points[p+1];
5447         ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
5448         updatePointBC_private(section, points[p], dof, insert,  o, &values[off], array);
5449       } break;
5450     case ADD_VALUES:
5451       for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) {
5452         PetscInt o = points[p+1];
5453         ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
5454         updatePoint_private(section, points[p], dof, add,    PETSC_FALSE, o, &values[off], array);
5455       } break;
5456     case ADD_ALL_VALUES:
5457       for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) {
5458         PetscInt o = points[p+1];
5459         ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
5460         updatePoint_private(section, points[p], dof, add,    PETSC_TRUE,  o, &values[off], array);
5461       } break;
5462     default:
5463       SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %D", mode);
5464     }
5465   }
5466   ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
5467   ierr = VecRestoreArray(v, &array);CHKERRQ(ierr);
5468   PetscFunctionReturn(0);
5469 }
5470 
5471 #undef __FUNCT__
5472 #define __FUNCT__ "DMPlexCreateClosureIndex"
5473 /*@
5474   DMPlexCreateClosureIndex - Calculate an index for the given PetscSection for the closure operation on the DM
5475 
5476   Not collective
5477 
5478   Input Parameters:
5479 + dm - The DM
5480 - section - The section describing the layout in v, or NULL to use the default section
5481 
5482   Note:
5483   This should greatly improve the performance of the closure operations, at the cost of additional memory.
5484 
5485   Level: intermediate
5486 
5487 .seealso DMPlexVecGetClosure(), DMPlexVecRestoreClosure(), DMPlexVecSetClosure(), DMPlexMatSetClosure()
5488 @*/
5489 PetscErrorCode DMPlexCreateClosureIndex(DM dm, PetscSection section)
5490 {
5491   PetscSection   closureSection;
5492   IS             closureIS;
5493   PetscInt       offsets[32], *clIndices;
5494   PetscInt       depth, numFields, pStart, pEnd, point, clSize;
5495   PetscErrorCode ierr;
5496 
5497   PetscFunctionBegin;
5498   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5499   if (!section) {ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);}
5500   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
5501   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
5502   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
5503   if (numFields > 31) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
5504   ierr = PetscSectionCreate(PetscObjectComm((PetscObject) section), &closureSection);CHKERRQ(ierr);
5505   ierr = PetscSectionSetChart(closureSection, pStart, pEnd);CHKERRQ(ierr);
5506   for (point = pStart; point < pEnd; ++point) {
5507     PetscInt *points = NULL, numPoints, p, dof, cldof = 0;
5508 
5509     ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
5510     for (p = 0; p < numPoints*2; p += 2) {
5511       if ((points[p] >= pStart) && (points[p] < pEnd)) {
5512         ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
5513         cldof += dof;
5514       }
5515     }
5516     ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
5517     ierr = PetscSectionSetDof(closureSection, point, cldof);CHKERRQ(ierr);
5518   }
5519   ierr = PetscSectionSetUp(closureSection);CHKERRQ(ierr);
5520   ierr = PetscSectionGetStorageSize(closureSection, &clSize);CHKERRQ(ierr);
5521   ierr = PetscMalloc1(clSize, &clIndices);CHKERRQ(ierr);
5522   for (point = pStart; point < pEnd; ++point) {
5523     PetscInt *points = NULL, numPoints, p, q, cldof, cloff, fdof, f;
5524 
5525     ierr = PetscSectionGetDof(closureSection, point, &cldof);CHKERRQ(ierr);
5526     ierr = PetscSectionGetOffset(closureSection, point, &cloff);CHKERRQ(ierr);
5527     ierr = PetscMemzero(offsets, 32 * sizeof(PetscInt));CHKERRQ(ierr);
5528     ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
5529     /* Compress out points not in the section, and create field offsets */
5530     for (p = 0, q = 0; p < numPoints*2; p += 2) {
5531       if ((points[p] >= pStart) && (points[p] < pEnd)) {
5532         points[q*2]   = points[p];
5533         points[q*2+1] = points[p+1];
5534         for (f = 0; f < numFields; ++f) {
5535           ierr = PetscSectionGetFieldDof(section, points[p], f, &fdof);CHKERRQ(ierr);
5536           offsets[f+1] += fdof;
5537         }
5538         ++q;
5539       }
5540     }
5541     numPoints = q;
5542     for (f = 1; f < numFields; ++f) offsets[f+1] += offsets[f];
5543     if (numFields && offsets[numFields] != cldof) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid size for closure %d should be %d", offsets[numFields], cldof);
5544     /* Create indices */
5545     for (p = 0; p < numPoints*2; p += 2) {
5546       PetscInt o = points[p+1], dof, off, d;
5547 
5548       ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
5549       ierr = PetscSectionGetOffset(section, points[p], &off);CHKERRQ(ierr);
5550       if (numFields) {
5551         PetscInt fdof, foff, fcomp, f, c;
5552 
5553         for (f = 0, foff = 0; f < numFields; ++f) {
5554           ierr = PetscSectionGetFieldDof(section, points[p], f, &fdof);CHKERRQ(ierr);
5555           if (o >= 0) {
5556             for (d = 0; d < fdof; ++d, ++offsets[f]) clIndices[cloff+offsets[f]] = off+foff+d;
5557           } else {
5558             ierr = PetscSectionGetFieldComponents(section, f, &fcomp);CHKERRQ(ierr);
5559             for (d = fdof/fcomp-1; d >= 0; --d) {
5560               for (c = 0; c < fcomp; ++c, ++offsets[f]) clIndices[cloff+offsets[f]] = off+foff+d*fcomp+c;
5561             }
5562           }
5563           foff += fdof;
5564         }
5565       } else {
5566         if (o >= 0) for (d = 0;     d < dof; ++d) clIndices[cloff+d] = off+d;
5567         else        for (d = dof-1; d >= 0;  --d) clIndices[cloff+d] = off+d;
5568       }
5569     }
5570     ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
5571   }
5572   ierr = ISCreateGeneral(PETSC_COMM_SELF, clSize, clIndices, PETSC_OWN_POINTER, &closureIS);CHKERRQ(ierr);
5573   ierr = PetscSectionSetClosureIndex(section, (PetscObject) dm, closureSection, closureIS);
5574   PetscFunctionReturn(0);
5575 }
5576 
5577 #undef __FUNCT__
5578 #define __FUNCT__ "DMPlexPrintMatSetValues"
5579 PetscErrorCode DMPlexPrintMatSetValues(PetscViewer viewer, Mat A, PetscInt point, PetscInt numIndices, const PetscInt indices[], const PetscScalar values[])
5580 {
5581   PetscMPIInt    rank;
5582   PetscInt       i, j;
5583   PetscErrorCode ierr;
5584 
5585   PetscFunctionBegin;
5586   ierr = MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank);CHKERRQ(ierr);
5587   ierr = PetscViewerASCIIPrintf(viewer, "[%D]mat for sieve point %D\n", rank, point);CHKERRQ(ierr);
5588   for (i = 0; i < numIndices; i++) {
5589     ierr = PetscViewerASCIIPrintf(viewer, "[%D]mat indices[%D] = %D\n", rank, i, indices[i]);CHKERRQ(ierr);
5590   }
5591   for (i = 0; i < numIndices; i++) {
5592     ierr = PetscViewerASCIIPrintf(viewer, "[%D]", rank);CHKERRQ(ierr);
5593     for (j = 0; j < numIndices; j++) {
5594 #if defined(PETSC_USE_COMPLEX)
5595       ierr = PetscViewerASCIIPrintf(viewer, " (%G,%G)", PetscRealPart(values[i*numIndices+j]), PetscImaginaryPart(values[i*numIndices+j]));CHKERRQ(ierr);
5596 #else
5597       ierr = PetscViewerASCIIPrintf(viewer, " %G", values[i*numIndices+j]);CHKERRQ(ierr);
5598 #endif
5599     }
5600     ierr = PetscViewerASCIIPrintf(viewer, "\n");CHKERRQ(ierr);
5601   }
5602   PetscFunctionReturn(0);
5603 }
5604 
5605 #undef __FUNCT__
5606 #define __FUNCT__ "indicesPoint_private"
5607 /* . off - The global offset of this point */
5608 PetscErrorCode indicesPoint_private(PetscSection section, PetscInt point, PetscInt off, PetscInt *loff, PetscBool setBC, PetscInt orientation, PetscInt indices[])
5609 {
5610   PetscInt        dof;    /* The number of unknowns on this point */
5611   PetscInt        cdof;   /* The number of constraints on this point */
5612   const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
5613   PetscInt        cind = 0, k;
5614   PetscErrorCode  ierr;
5615 
5616   PetscFunctionBegin;
5617   ierr = PetscSectionGetDof(section, point, &dof);CHKERRQ(ierr);
5618   ierr = PetscSectionGetConstraintDof(section, point, &cdof);CHKERRQ(ierr);
5619   if (!cdof || setBC) {
5620     if (orientation >= 0) {
5621       for (k = 0; k < dof; ++k) indices[*loff+k] = off+k;
5622     } else {
5623       for (k = 0; k < dof; ++k) indices[*loff+dof-k-1] = off+k;
5624     }
5625   } else {
5626     ierr = PetscSectionGetConstraintIndices(section, point, &cdofs);CHKERRQ(ierr);
5627     if (orientation >= 0) {
5628       for (k = 0; k < dof; ++k) {
5629         if ((cind < cdof) && (k == cdofs[cind])) {
5630           /* Insert check for returning constrained indices */
5631           indices[*loff+k] = -(off+k+1);
5632           ++cind;
5633         } else {
5634           indices[*loff+k] = off+k-cind;
5635         }
5636       }
5637     } else {
5638       for (k = 0; k < dof; ++k) {
5639         if ((cind < cdof) && (k == cdofs[cind])) {
5640           /* Insert check for returning constrained indices */
5641           indices[*loff+dof-k-1] = -(off+k+1);
5642           ++cind;
5643         } else {
5644           indices[*loff+dof-k-1] = off+k-cind;
5645         }
5646       }
5647     }
5648   }
5649   *loff += dof;
5650   PetscFunctionReturn(0);
5651 }
5652 
5653 #undef __FUNCT__
5654 #define __FUNCT__ "indicesPointFields_private"
5655 /* . off - The global offset of this point */
5656 PetscErrorCode indicesPointFields_private(PetscSection section, PetscInt point, PetscInt off, PetscInt foffs[], PetscBool setBC, PetscInt orientation, PetscInt indices[])
5657 {
5658   PetscInt       numFields, foff, f;
5659   PetscErrorCode ierr;
5660 
5661   PetscFunctionBegin;
5662   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
5663   for (f = 0, foff = 0; f < numFields; ++f) {
5664     PetscInt        fdof, fcomp, cfdof;
5665     const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
5666     PetscInt        cind = 0, k, c;
5667 
5668     ierr = PetscSectionGetFieldComponents(section, f, &fcomp);CHKERRQ(ierr);
5669     ierr = PetscSectionGetFieldDof(section, point, f, &fdof);CHKERRQ(ierr);
5670     ierr = PetscSectionGetFieldConstraintDof(section, point, f, &cfdof);CHKERRQ(ierr);
5671     if (!cfdof || setBC) {
5672       if (orientation >= 0) {
5673         for (k = 0; k < fdof; ++k) indices[foffs[f]+k] = off+foff+k;
5674       } else {
5675         for (k = fdof/fcomp-1; k >= 0; --k) {
5676           for (c = 0; c < fcomp; ++c) {
5677             indices[foffs[f]+k*fcomp+c] = off+foff+(fdof/fcomp-1-k)*fcomp+c;
5678           }
5679         }
5680       }
5681     } else {
5682       ierr = PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);CHKERRQ(ierr);
5683       if (orientation >= 0) {
5684         for (k = 0; k < fdof; ++k) {
5685           if ((cind < cfdof) && (k == fcdofs[cind])) {
5686             indices[foffs[f]+k] = -(off+foff+k+1);
5687             ++cind;
5688           } else {
5689             indices[foffs[f]+k] = off+foff+k-cind;
5690           }
5691         }
5692       } else {
5693         for (k = fdof/fcomp-1; k >= 0; --k) {
5694           for (c = 0; c < fcomp; ++c) {
5695             if ((cind < cfdof) && ((fdof/fcomp-1-k)*fcomp+c == fcdofs[cind])) {
5696               indices[foffs[f]+k*fcomp+c] = -(off+foff+(fdof/fcomp-1-k)*fcomp+c+1);
5697               ++cind;
5698             } else {
5699               indices[foffs[f]+k*fcomp+c] = off+foff+(fdof/fcomp-1-k)*fcomp+c-cind;
5700             }
5701           }
5702         }
5703       }
5704     }
5705     foff     += fdof - cfdof;
5706     foffs[f] += fdof;
5707   }
5708   PetscFunctionReturn(0);
5709 }
5710 
5711 #undef __FUNCT__
5712 #define __FUNCT__ "DMPlexMatSetClosure"
5713 /*@C
5714   DMPlexMatSetClosure - Set an array of the values on the closure of 'point'
5715 
5716   Not collective
5717 
5718   Input Parameters:
5719 + dm - The DM
5720 . section - The section describing the layout in v
5721 . globalSection - The section describing the layout in v
5722 . A - The matrix
5723 . point - The sieve point in the DM
5724 . values - The array of values
5725 - mode - The insert mode, where INSERT_ALL_VALUES and ADD_ALL_VALUES also overwrite boundary conditions
5726 
5727   Fortran Notes:
5728   This routine is only available in Fortran 90, and you must include petsc.h90 in your code.
5729 
5730   Level: intermediate
5731 
5732 .seealso DMPlexVecGetClosure(), DMPlexVecSetClosure()
5733 @*/
5734 PetscErrorCode DMPlexMatSetClosure(DM dm, PetscSection section, PetscSection globalSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode)
5735 {
5736   DM_Plex       *mesh   = (DM_Plex*) dm->data;
5737   PetscInt      *points = NULL;
5738   PetscInt      *indices;
5739   PetscInt       offsets[32];
5740   PetscInt       numFields, numPoints, numIndices, dof, off, globalOff, pStart, pEnd, p, q, f;
5741   PetscErrorCode ierr;
5742 
5743   PetscFunctionBegin;
5744   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5745   PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2);
5746   PetscValidHeaderSpecific(globalSection, PETSC_SECTION_CLASSID, 3);
5747   PetscValidHeaderSpecific(A, MAT_CLASSID, 4);
5748   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
5749   if (numFields > 31) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
5750   ierr = PetscMemzero(offsets, 32 * sizeof(PetscInt));CHKERRQ(ierr);
5751   ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
5752   /* Compress out points not in the section */
5753   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
5754   for (p = 0, q = 0; p < numPoints*2; p += 2) {
5755     if ((points[p] >= pStart) && (points[p] < pEnd)) {
5756       points[q*2]   = points[p];
5757       points[q*2+1] = points[p+1];
5758       ++q;
5759     }
5760   }
5761   numPoints = q;
5762   for (p = 0, numIndices = 0; p < numPoints*2; p += 2) {
5763     PetscInt fdof;
5764 
5765     ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
5766     for (f = 0; f < numFields; ++f) {
5767       ierr          = PetscSectionGetFieldDof(section, points[p], f, &fdof);CHKERRQ(ierr);
5768       offsets[f+1] += fdof;
5769     }
5770     numIndices += dof;
5771   }
5772   for (f = 1; f < numFields; ++f) offsets[f+1] += offsets[f];
5773 
5774   if (numFields && offsets[numFields] != numIndices) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid size for closure %d should be %d", offsets[numFields], numIndices);
5775   ierr = DMGetWorkArray(dm, numIndices, PETSC_INT, &indices);CHKERRQ(ierr);
5776   if (numFields) {
5777     for (p = 0; p < numPoints*2; p += 2) {
5778       PetscInt o = points[p+1];
5779       ierr = PetscSectionGetOffset(globalSection, points[p], &globalOff);CHKERRQ(ierr);
5780       indicesPointFields_private(section, points[p], globalOff < 0 ? -(globalOff+1) : globalOff, offsets, PETSC_FALSE, o, indices);
5781     }
5782   } else {
5783     for (p = 0, off = 0; p < numPoints*2; p += 2) {
5784       PetscInt o = points[p+1];
5785       ierr = PetscSectionGetOffset(globalSection, points[p], &globalOff);CHKERRQ(ierr);
5786       indicesPoint_private(section, points[p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, o, indices);
5787     }
5788   }
5789   if (mesh->printSetValues) {ierr = DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndices, indices, values);CHKERRQ(ierr);}
5790   ierr = MatSetValues(A, numIndices, indices, numIndices, indices, values, mode);
5791   if (ierr) {
5792     PetscMPIInt    rank;
5793     PetscErrorCode ierr2;
5794 
5795     ierr2 = MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank);CHKERRQ(ierr2);
5796     ierr2 = (*PetscErrorPrintf)("[%D]ERROR in DMPlexMatSetClosure\n", rank);CHKERRQ(ierr2);
5797     ierr2 = DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndices, indices, values);CHKERRQ(ierr2);
5798     ierr2 = DMRestoreWorkArray(dm, numIndices, PETSC_INT, &indices);CHKERRQ(ierr2);
5799     CHKERRQ(ierr);
5800   }
5801   ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
5802   ierr = DMRestoreWorkArray(dm, numIndices, PETSC_INT, &indices);CHKERRQ(ierr);
5803   PetscFunctionReturn(0);
5804 }
5805 
5806 #undef __FUNCT__
5807 #define __FUNCT__ "DMPlexGetHybridBounds"
5808 /*@
5809   DMPlexGetHybridBounds - Get the first mesh point of each dimension which is a hybrid
5810 
5811   Input Parameter:
5812 . dm - The DMPlex object
5813 
5814   Output Parameters:
5815 + cMax - The first hybrid cell
5816 . cMax - The first hybrid face
5817 . cMax - The first hybrid edge
5818 - cMax - The first hybrid vertex
5819 
5820   Level: developer
5821 
5822 .seealso DMPlexCreateHybridMesh()
5823 @*/
5824 PetscErrorCode DMPlexGetHybridBounds(DM dm, PetscInt *cMax, PetscInt *fMax, PetscInt *eMax, PetscInt *vMax)
5825 {
5826   DM_Plex       *mesh = (DM_Plex*) dm->data;
5827   PetscInt       dim;
5828   PetscErrorCode ierr;
5829 
5830   PetscFunctionBegin;
5831   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5832   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
5833   if (cMax) *cMax = mesh->hybridPointMax[dim];
5834   if (fMax) *fMax = mesh->hybridPointMax[dim-1];
5835   if (eMax) *eMax = mesh->hybridPointMax[1];
5836   if (vMax) *vMax = mesh->hybridPointMax[0];
5837   PetscFunctionReturn(0);
5838 }
5839 
5840 #undef __FUNCT__
5841 #define __FUNCT__ "DMPlexSetHybridBounds"
5842 PetscErrorCode DMPlexSetHybridBounds(DM dm, PetscInt cMax, PetscInt fMax, PetscInt eMax, PetscInt vMax)
5843 {
5844   DM_Plex       *mesh = (DM_Plex*) dm->data;
5845   PetscInt       dim;
5846   PetscErrorCode ierr;
5847 
5848   PetscFunctionBegin;
5849   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5850   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
5851   if (cMax >= 0) mesh->hybridPointMax[dim]   = cMax;
5852   if (fMax >= 0) mesh->hybridPointMax[dim-1] = fMax;
5853   if (eMax >= 0) mesh->hybridPointMax[1]     = eMax;
5854   if (vMax >= 0) mesh->hybridPointMax[0]     = vMax;
5855   PetscFunctionReturn(0);
5856 }
5857 
5858 #undef __FUNCT__
5859 #define __FUNCT__ "DMPlexGetVTKCellHeight"
5860 PetscErrorCode DMPlexGetVTKCellHeight(DM dm, PetscInt *cellHeight)
5861 {
5862   DM_Plex *mesh = (DM_Plex*) dm->data;
5863 
5864   PetscFunctionBegin;
5865   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5866   PetscValidPointer(cellHeight, 2);
5867   *cellHeight = mesh->vtkCellHeight;
5868   PetscFunctionReturn(0);
5869 }
5870 
5871 #undef __FUNCT__
5872 #define __FUNCT__ "DMPlexSetVTKCellHeight"
5873 PetscErrorCode DMPlexSetVTKCellHeight(DM dm, PetscInt cellHeight)
5874 {
5875   DM_Plex *mesh = (DM_Plex*) dm->data;
5876 
5877   PetscFunctionBegin;
5878   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5879   mesh->vtkCellHeight = cellHeight;
5880   PetscFunctionReturn(0);
5881 }
5882 
5883 #undef __FUNCT__
5884 #define __FUNCT__ "DMPlexCreateNumbering_Private"
5885 /* We can easily have a form that takes an IS instead */
5886 PetscErrorCode DMPlexCreateNumbering_Private(DM dm, PetscInt pStart, PetscInt pEnd, PetscSF sf, IS *numbering)
5887 {
5888   PetscSection   section, globalSection;
5889   PetscInt      *numbers, p;
5890   PetscErrorCode ierr;
5891 
5892   PetscFunctionBegin;
5893   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)dm), &section);CHKERRQ(ierr);
5894   ierr = PetscSectionSetChart(section, pStart, pEnd);CHKERRQ(ierr);
5895   for (p = pStart; p < pEnd; ++p) {
5896     ierr = PetscSectionSetDof(section, p, 1);CHKERRQ(ierr);
5897   }
5898   ierr = PetscSectionSetUp(section);CHKERRQ(ierr);
5899   ierr = PetscSectionCreateGlobalSection(section, sf, PETSC_FALSE, &globalSection);CHKERRQ(ierr);
5900   ierr = PetscMalloc1((pEnd - pStart), &numbers);CHKERRQ(ierr);
5901   for (p = pStart; p < pEnd; ++p) {
5902     ierr = PetscSectionGetOffset(globalSection, p, &numbers[p-pStart]);CHKERRQ(ierr);
5903   }
5904   ierr = ISCreateGeneral(PetscObjectComm((PetscObject)dm), pEnd - pStart, numbers, PETSC_OWN_POINTER, numbering);CHKERRQ(ierr);
5905   ierr = PetscSectionDestroy(&section);CHKERRQ(ierr);
5906   ierr = PetscSectionDestroy(&globalSection);CHKERRQ(ierr);
5907   PetscFunctionReturn(0);
5908 }
5909 
5910 #undef __FUNCT__
5911 #define __FUNCT__ "DMPlexGetCellNumbering"
5912 PetscErrorCode DMPlexGetCellNumbering(DM dm, IS *globalCellNumbers)
5913 {
5914   DM_Plex       *mesh = (DM_Plex*) dm->data;
5915   PetscInt       cellHeight, cStart, cEnd, cMax;
5916   PetscErrorCode ierr;
5917 
5918   PetscFunctionBegin;
5919   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5920   if (!mesh->globalCellNumbers) {
5921     ierr = DMPlexGetVTKCellHeight(dm, &cellHeight);CHKERRQ(ierr);
5922     ierr = DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd);CHKERRQ(ierr);
5923     ierr = DMPlexGetHybridBounds(dm, &cMax, NULL, NULL, NULL);CHKERRQ(ierr);
5924     if (cMax >= 0) cEnd = PetscMin(cEnd, cMax);
5925     ierr = DMPlexCreateNumbering_Private(dm, cStart, cEnd, dm->sf, &mesh->globalCellNumbers);CHKERRQ(ierr);
5926   }
5927   *globalCellNumbers = mesh->globalCellNumbers;
5928   PetscFunctionReturn(0);
5929 }
5930 
5931 #undef __FUNCT__
5932 #define __FUNCT__ "DMPlexGetVertexNumbering"
5933 PetscErrorCode DMPlexGetVertexNumbering(DM dm, IS *globalVertexNumbers)
5934 {
5935   DM_Plex       *mesh = (DM_Plex*) dm->data;
5936   PetscInt       vStart, vEnd, vMax;
5937   PetscErrorCode ierr;
5938 
5939   PetscFunctionBegin;
5940   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5941   if (!mesh->globalVertexNumbers) {
5942     ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
5943     ierr = DMPlexGetHybridBounds(dm, NULL, NULL, NULL, &vMax);CHKERRQ(ierr);
5944     if (vMax >= 0) vEnd = PetscMin(vEnd, vMax);
5945     ierr = DMPlexCreateNumbering_Private(dm, vStart, vEnd, dm->sf, &mesh->globalVertexNumbers);CHKERRQ(ierr);
5946   }
5947   *globalVertexNumbers = mesh->globalVertexNumbers;
5948   PetscFunctionReturn(0);
5949 }
5950 
5951 
5952 #undef __FUNCT__
5953 #define __FUNCT__ "PetscSectionCreateGlobalSectionLabel"
5954 /*@C
5955   PetscSectionCreateGlobalSectionLabel - Create a section describing the global field layout using
5956   the local section and an SF describing the section point overlap.
5957 
5958   Input Parameters:
5959   + s - The PetscSection for the local field layout
5960   . sf - The SF describing parallel layout of the section points
5961   . includeConstraints - By default this is PETSC_FALSE, meaning that the global field vector will not possess constrained dofs
5962   . label - The label specifying the points
5963   - labelValue - The label stratum specifying the points
5964 
5965   Output Parameter:
5966   . gsection - The PetscSection for the global field layout
5967 
5968   Note: This gives negative sizes and offsets to points not owned by this process
5969 
5970   Level: developer
5971 
5972 .seealso: PetscSectionCreate()
5973 @*/
5974 PetscErrorCode PetscSectionCreateGlobalSectionLabel(PetscSection s, PetscSF sf, PetscBool includeConstraints, DMLabel label, PetscInt labelValue, PetscSection *gsection)
5975 {
5976   PetscInt      *neg = NULL, *tmpOff = NULL;
5977   PetscInt       pStart, pEnd, p, dof, cdof, off, globalOff = 0, nroots;
5978   PetscErrorCode ierr;
5979 
5980   PetscFunctionBegin;
5981   ierr = PetscSectionCreate(s->atlasLayout.comm, gsection);CHKERRQ(ierr);
5982   ierr = PetscSectionGetChart(s, &pStart, &pEnd);CHKERRQ(ierr);
5983   ierr = PetscSectionSetChart(*gsection, pStart, pEnd);CHKERRQ(ierr);
5984   ierr = PetscSFGetGraph(sf, &nroots, NULL, NULL, NULL);CHKERRQ(ierr);
5985   if (nroots >= 0) {
5986     if (nroots < pEnd-pStart) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "PetscSF nroots %d < %d section size", nroots, pEnd-pStart);
5987     ierr = PetscCalloc1(nroots, &neg);CHKERRQ(ierr);
5988     if (nroots > pEnd-pStart) {
5989       ierr = PetscCalloc1(nroots, &tmpOff);CHKERRQ(ierr);
5990     } else {
5991       tmpOff = &(*gsection)->atlasDof[-pStart];
5992     }
5993   }
5994   /* Mark ghost points with negative dof */
5995   for (p = pStart; p < pEnd; ++p) {
5996     PetscInt value;
5997 
5998     ierr = DMLabelGetValue(label, p, &value);CHKERRQ(ierr);
5999     if (value != labelValue) continue;
6000     ierr = PetscSectionGetDof(s, p, &dof);CHKERRQ(ierr);
6001     ierr = PetscSectionSetDof(*gsection, p, dof);CHKERRQ(ierr);
6002     ierr = PetscSectionGetConstraintDof(s, p, &cdof);CHKERRQ(ierr);
6003     if (!includeConstraints && cdof > 0) {ierr = PetscSectionSetConstraintDof(*gsection, p, cdof);CHKERRQ(ierr);}
6004     if (neg) neg[p] = -(dof+1);
6005   }
6006   ierr = PetscSectionSetUpBC(*gsection);CHKERRQ(ierr);
6007   if (nroots >= 0) {
6008     ierr = PetscSFBcastBegin(sf, MPIU_INT, neg, tmpOff);CHKERRQ(ierr);
6009     ierr = PetscSFBcastEnd(sf, MPIU_INT, neg, tmpOff);CHKERRQ(ierr);
6010     if (nroots > pEnd-pStart) {
6011       for (p = pStart; p < pEnd; ++p) {if (tmpOff[p] < 0) (*gsection)->atlasDof[p-pStart] = tmpOff[p];}
6012     }
6013   }
6014   /* Calculate new sizes, get proccess offset, and calculate point offsets */
6015   for (p = 0, off = 0; p < pEnd-pStart; ++p) {
6016     cdof = (!includeConstraints && s->bc) ? s->bc->atlasDof[p] : 0;
6017     (*gsection)->atlasOff[p] = off;
6018     off += (*gsection)->atlasDof[p] > 0 ? (*gsection)->atlasDof[p]-cdof : 0;
6019   }
6020   ierr       = MPI_Scan(&off, &globalOff, 1, MPIU_INT, MPI_SUM, s->atlasLayout.comm);CHKERRQ(ierr);
6021   globalOff -= off;
6022   for (p = 0, off = 0; p < pEnd-pStart; ++p) {
6023     (*gsection)->atlasOff[p] += globalOff;
6024     if (neg) neg[p] = -((*gsection)->atlasOff[p]+1);
6025   }
6026   /* Put in negative offsets for ghost points */
6027   if (nroots >= 0) {
6028     ierr = PetscSFBcastBegin(sf, MPIU_INT, neg, tmpOff);CHKERRQ(ierr);
6029     ierr = PetscSFBcastEnd(sf, MPIU_INT, neg, tmpOff);CHKERRQ(ierr);
6030     if (nroots > pEnd-pStart) {
6031       for (p = pStart; p < pEnd; ++p) {if (tmpOff[p] < 0) (*gsection)->atlasOff[p-pStart] = tmpOff[p];}
6032     }
6033   }
6034   if (nroots >= 0 && nroots > pEnd-pStart) {ierr = PetscFree(tmpOff);CHKERRQ(ierr);}
6035   ierr = PetscFree(neg);CHKERRQ(ierr);
6036   PetscFunctionReturn(0);
6037 }
6038 
6039 #undef __FUNCT__
6040 #define __FUNCT__ "DMPlexCheckSymmetry"
6041 /*@
6042   DMPlexCheckSymmetry - Check that the adjacency information in the mesh is symmetric.
6043 
6044   Input Parameters:
6045   + dm - The DMPlex object
6046 
6047   Note: This is a useful diagnostic when creating meshes programmatically.
6048 
6049   Level: developer
6050 
6051 .seealso: DMCreate()
6052 @*/
6053 PetscErrorCode DMPlexCheckSymmetry(DM dm)
6054 {
6055   PetscSection    coneSection, supportSection;
6056   const PetscInt *cone, *support;
6057   PetscInt        coneSize, c, supportSize, s;
6058   PetscInt        pStart, pEnd, p, csize, ssize;
6059   PetscErrorCode  ierr;
6060 
6061   PetscFunctionBegin;
6062   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6063   ierr = DMPlexGetConeSection(dm, &coneSection);CHKERRQ(ierr);
6064   ierr = DMPlexGetSupportSection(dm, &supportSection);CHKERRQ(ierr);
6065   /* Check that point p is found in the support of its cone points, and vice versa */
6066   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
6067   for (p = pStart; p < pEnd; ++p) {
6068     ierr = DMPlexGetConeSize(dm, p, &coneSize);CHKERRQ(ierr);
6069     ierr = DMPlexGetCone(dm, p, &cone);CHKERRQ(ierr);
6070     for (c = 0; c < coneSize; ++c) {
6071       ierr = DMPlexGetSupportSize(dm, cone[c], &supportSize);CHKERRQ(ierr);
6072       ierr = DMPlexGetSupport(dm, cone[c], &support);CHKERRQ(ierr);
6073       for (s = 0; s < supportSize; ++s) {
6074         if (support[s] == p) break;
6075       }
6076       if (s >= supportSize) {
6077         ierr = PetscPrintf(PETSC_COMM_SELF, "p: %d cone: ", p);
6078         for (s = 0; s < coneSize; ++s) {
6079           ierr = PetscPrintf(PETSC_COMM_SELF, "%d, ", cone[s]);
6080         }
6081         ierr = PetscPrintf(PETSC_COMM_SELF, "\n");
6082         ierr = PetscPrintf(PETSC_COMM_SELF, "p: %d support: ", cone[c]);
6083         for (s = 0; s < supportSize; ++s) {
6084           ierr = PetscPrintf(PETSC_COMM_SELF, "%d, ", support[s]);
6085         }
6086         ierr = PetscPrintf(PETSC_COMM_SELF, "\n");
6087         SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d not found in support of cone point %d", p, cone[c]);
6088       }
6089     }
6090     ierr = DMPlexGetSupportSize(dm, p, &supportSize);CHKERRQ(ierr);
6091     ierr = DMPlexGetSupport(dm, p, &support);CHKERRQ(ierr);
6092     for (s = 0; s < supportSize; ++s) {
6093       ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
6094       ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6095       for (c = 0; c < coneSize; ++c) {
6096         if (cone[c] == p) break;
6097       }
6098       if (c >= coneSize) {
6099         ierr = PetscPrintf(PETSC_COMM_SELF, "p: %d support: ", p);
6100         for (c = 0; c < supportSize; ++c) {
6101           ierr = PetscPrintf(PETSC_COMM_SELF, "%d, ", support[c]);
6102         }
6103         ierr = PetscPrintf(PETSC_COMM_SELF, "\n");
6104         ierr = PetscPrintf(PETSC_COMM_SELF, "p: %d cone: ", support[s]);
6105         for (c = 0; c < coneSize; ++c) {
6106           ierr = PetscPrintf(PETSC_COMM_SELF, "%d, ", cone[c]);
6107         }
6108         ierr = PetscPrintf(PETSC_COMM_SELF, "\n");
6109         SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d not found in cone of support point %d", p, support[s]);
6110       }
6111     }
6112   }
6113   ierr = PetscSectionGetStorageSize(coneSection, &csize);CHKERRQ(ierr);
6114   ierr = PetscSectionGetStorageSize(supportSection, &ssize);CHKERRQ(ierr);
6115   if (csize != ssize) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Total cone size %d != Total support size %d", csize, ssize);
6116   PetscFunctionReturn(0);
6117 }
6118 
6119 #undef __FUNCT__
6120 #define __FUNCT__ "DMPlexCheckSkeleton"
6121 /*@
6122   DMPlexCheckSkeleton - Check that each cell has the correct number of vertices
6123 
6124   Input Parameters:
6125   + dm - The DMPlex object
6126 
6127   Note: This is a useful diagnostic when creating meshes programmatically.
6128 
6129   Level: developer
6130 
6131 .seealso: DMCreate()
6132 @*/
6133 PetscErrorCode DMPlexCheckSkeleton(DM dm, PetscBool isSimplex)
6134 {
6135   DM             udm;
6136   PetscInt       dim, numCorners, coneSize, cStart, cEnd, cMax, c;
6137   PetscErrorCode ierr;
6138 
6139   PetscFunctionBegin;
6140   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6141   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
6142   switch (dim) {
6143   case 1: numCorners = isSimplex ? 2 : 2; break;
6144   case 2: numCorners = isSimplex ? 3 : 4; break;
6145   case 3: numCorners = isSimplex ? 4 : 8; break;
6146   default:
6147     SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_OUTOFRANGE, "Cannot handle meshes of dimension %d", dim);
6148   }
6149   ierr = DMPlexUninterpolate(dm, &udm);CHKERRQ(ierr);
6150   ierr = PetscObjectSetOptionsPrefix((PetscObject) udm, "un_");CHKERRQ(ierr);
6151   ierr = DMSetFromOptions(udm);CHKERRQ(ierr);
6152   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
6153   ierr = DMPlexGetHybridBounds(dm, &cMax, NULL, NULL, NULL);CHKERRQ(ierr);
6154   cMax = cMax >= 0 ? cMax : cEnd;
6155   for (c = cStart; c < cMax; ++c) {
6156     ierr = DMPlexGetConeSize(udm, c, &coneSize);CHKERRQ(ierr);
6157     if (coneSize != numCorners) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cell %d has  %d vertices != %d", c, coneSize, numCorners);
6158   }
6159   ierr = DMDestroy(&udm);CHKERRQ(ierr);
6160   PetscFunctionReturn(0);
6161 }
6162