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