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