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