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