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