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