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