xref: /petsc/src/dm/impls/plex/plex.c (revision 01e13f7363797b80262b2aca243ce72bcaa53640)
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   depths[0] = depth; depths[1] = 0;
4978   for (d = 2; d <= depth; ++d) depths[d] = depth-d+1;
4979   for (d = 0; d <= depth; ++d) {
4980     PetscInt pStart, pEnd, gsize;
4981 
4982     ierr = DMPlexGetDepthStratum(dm, depths[d], &pStart, &pEnd);CHKERRQ(ierr);
4983     ierr = DMPlexCreateNumbering_Private(dm, pStart, pEnd, shift, &gsize, dm->sf, &nums[d]);CHKERRQ(ierr);
4984     shift += gsize;
4985   }
4986   ierr = ISConcatenate(PetscObjectComm((PetscObject) dm), depth+1, nums, globalPointNumbers);
4987   for (d = 0; d <= depth; ++d) {ierr = ISDestroy(&nums[d]);CHKERRQ(ierr);}
4988   PetscFunctionReturn(0);
4989 }
4990 
4991 
4992 #undef __FUNCT__
4993 #define __FUNCT__ "PetscSectionCreateGlobalSectionLabel"
4994 /*@C
4995   PetscSectionCreateGlobalSectionLabel - Create a section describing the global field layout using
4996   the local section and an SF describing the section point overlap.
4997 
4998   Input Parameters:
4999   + s - The PetscSection for the local field layout
5000   . sf - The SF describing parallel layout of the section points
5001   . includeConstraints - By default this is PETSC_FALSE, meaning that the global field vector will not possess constrained dofs
5002   . label - The label specifying the points
5003   - labelValue - The label stratum specifying the points
5004 
5005   Output Parameter:
5006   . gsection - The PetscSection for the global field layout
5007 
5008   Note: This gives negative sizes and offsets to points not owned by this process
5009 
5010   Level: developer
5011 
5012 .seealso: PetscSectionCreate()
5013 @*/
5014 PetscErrorCode PetscSectionCreateGlobalSectionLabel(PetscSection s, PetscSF sf, PetscBool includeConstraints, DMLabel label, PetscInt labelValue, PetscSection *gsection)
5015 {
5016   PetscInt      *neg = NULL, *tmpOff = NULL;
5017   PetscInt       pStart, pEnd, p, dof, cdof, off, globalOff = 0, nroots;
5018   PetscErrorCode ierr;
5019 
5020   PetscFunctionBegin;
5021   ierr = PetscSectionCreate(PetscObjectComm((PetscObject) s), gsection);CHKERRQ(ierr);
5022   ierr = PetscSectionGetChart(s, &pStart, &pEnd);CHKERRQ(ierr);
5023   ierr = PetscSectionSetChart(*gsection, pStart, pEnd);CHKERRQ(ierr);
5024   ierr = PetscSFGetGraph(sf, &nroots, NULL, NULL, NULL);CHKERRQ(ierr);
5025   if (nroots >= 0) {
5026     if (nroots < pEnd-pStart) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "PetscSF nroots %d < %d section size", nroots, pEnd-pStart);
5027     ierr = PetscCalloc1(nroots, &neg);CHKERRQ(ierr);
5028     if (nroots > pEnd-pStart) {
5029       ierr = PetscCalloc1(nroots, &tmpOff);CHKERRQ(ierr);
5030     } else {
5031       tmpOff = &(*gsection)->atlasDof[-pStart];
5032     }
5033   }
5034   /* Mark ghost points with negative dof */
5035   for (p = pStart; p < pEnd; ++p) {
5036     PetscInt value;
5037 
5038     ierr = DMLabelGetValue(label, p, &value);CHKERRQ(ierr);
5039     if (value != labelValue) continue;
5040     ierr = PetscSectionGetDof(s, p, &dof);CHKERRQ(ierr);
5041     ierr = PetscSectionSetDof(*gsection, p, dof);CHKERRQ(ierr);
5042     ierr = PetscSectionGetConstraintDof(s, p, &cdof);CHKERRQ(ierr);
5043     if (!includeConstraints && cdof > 0) {ierr = PetscSectionSetConstraintDof(*gsection, p, cdof);CHKERRQ(ierr);}
5044     if (neg) neg[p] = -(dof+1);
5045   }
5046   ierr = PetscSectionSetUpBC(*gsection);CHKERRQ(ierr);
5047   if (nroots >= 0) {
5048     ierr = PetscSFBcastBegin(sf, MPIU_INT, neg, tmpOff);CHKERRQ(ierr);
5049     ierr = PetscSFBcastEnd(sf, MPIU_INT, neg, tmpOff);CHKERRQ(ierr);
5050     if (nroots > pEnd-pStart) {
5051       for (p = pStart; p < pEnd; ++p) {if (tmpOff[p] < 0) (*gsection)->atlasDof[p-pStart] = tmpOff[p];}
5052     }
5053   }
5054   /* Calculate new sizes, get proccess offset, and calculate point offsets */
5055   for (p = 0, off = 0; p < pEnd-pStart; ++p) {
5056     cdof = (!includeConstraints && s->bc) ? s->bc->atlasDof[p] : 0;
5057     (*gsection)->atlasOff[p] = off;
5058     off += (*gsection)->atlasDof[p] > 0 ? (*gsection)->atlasDof[p]-cdof : 0;
5059   }
5060   ierr       = MPI_Scan(&off, &globalOff, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject) s));CHKERRQ(ierr);
5061   globalOff -= off;
5062   for (p = 0, off = 0; p < pEnd-pStart; ++p) {
5063     (*gsection)->atlasOff[p] += globalOff;
5064     if (neg) neg[p] = -((*gsection)->atlasOff[p]+1);
5065   }
5066   /* Put in negative offsets for ghost points */
5067   if (nroots >= 0) {
5068     ierr = PetscSFBcastBegin(sf, MPIU_INT, neg, tmpOff);CHKERRQ(ierr);
5069     ierr = PetscSFBcastEnd(sf, MPIU_INT, neg, tmpOff);CHKERRQ(ierr);
5070     if (nroots > pEnd-pStart) {
5071       for (p = pStart; p < pEnd; ++p) {if (tmpOff[p] < 0) (*gsection)->atlasOff[p-pStart] = tmpOff[p];}
5072     }
5073   }
5074   if (nroots >= 0 && nroots > pEnd-pStart) {ierr = PetscFree(tmpOff);CHKERRQ(ierr);}
5075   ierr = PetscFree(neg);CHKERRQ(ierr);
5076   PetscFunctionReturn(0);
5077 }
5078 
5079 #undef __FUNCT__
5080 #define __FUNCT__ "DMPlexCheckSymmetry"
5081 /*@
5082   DMPlexCheckSymmetry - Check that the adjacency information in the mesh is symmetric.
5083 
5084   Input Parameters:
5085   + dm - The DMPlex object
5086 
5087   Note: This is a useful diagnostic when creating meshes programmatically.
5088 
5089   Level: developer
5090 
5091 .seealso: DMCreate(), DMCheckSkeleton(), DMCheckFaces()
5092 @*/
5093 PetscErrorCode DMPlexCheckSymmetry(DM dm)
5094 {
5095   PetscSection    coneSection, supportSection;
5096   const PetscInt *cone, *support;
5097   PetscInt        coneSize, c, supportSize, s;
5098   PetscInt        pStart, pEnd, p, csize, ssize;
5099   PetscErrorCode  ierr;
5100 
5101   PetscFunctionBegin;
5102   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5103   ierr = DMPlexGetConeSection(dm, &coneSection);CHKERRQ(ierr);
5104   ierr = DMPlexGetSupportSection(dm, &supportSection);CHKERRQ(ierr);
5105   /* Check that point p is found in the support of its cone points, and vice versa */
5106   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
5107   for (p = pStart; p < pEnd; ++p) {
5108     ierr = DMPlexGetConeSize(dm, p, &coneSize);CHKERRQ(ierr);
5109     ierr = DMPlexGetCone(dm, p, &cone);CHKERRQ(ierr);
5110     for (c = 0; c < coneSize; ++c) {
5111       PetscBool dup = PETSC_FALSE;
5112       PetscInt  d;
5113       for (d = c-1; d >= 0; --d) {
5114         if (cone[c] == cone[d]) {dup = PETSC_TRUE; break;}
5115       }
5116       ierr = DMPlexGetSupportSize(dm, cone[c], &supportSize);CHKERRQ(ierr);
5117       ierr = DMPlexGetSupport(dm, cone[c], &support);CHKERRQ(ierr);
5118       for (s = 0; s < supportSize; ++s) {
5119         if (support[s] == p) break;
5120       }
5121       if ((s >= supportSize) || (dup && (support[s+1] != p))) {
5122         ierr = PetscPrintf(PETSC_COMM_SELF, "p: %d cone: ", p);
5123         for (s = 0; s < coneSize; ++s) {
5124           ierr = PetscPrintf(PETSC_COMM_SELF, "%d, ", cone[s]);
5125         }
5126         ierr = PetscPrintf(PETSC_COMM_SELF, "\n");
5127         ierr = PetscPrintf(PETSC_COMM_SELF, "p: %d support: ", cone[c]);
5128         for (s = 0; s < supportSize; ++s) {
5129           ierr = PetscPrintf(PETSC_COMM_SELF, "%d, ", support[s]);
5130         }
5131         ierr = PetscPrintf(PETSC_COMM_SELF, "\n");
5132         if (dup) {
5133           SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d not repeatedly found in support of repeated cone point %d", p, cone[c]);
5134         } else {
5135           SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d not found in support of cone point %d", p, cone[c]);
5136         }
5137       }
5138     }
5139     ierr = DMPlexGetSupportSize(dm, p, &supportSize);CHKERRQ(ierr);
5140     ierr = DMPlexGetSupport(dm, p, &support);CHKERRQ(ierr);
5141     for (s = 0; s < supportSize; ++s) {
5142       ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
5143       ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
5144       for (c = 0; c < coneSize; ++c) {
5145         if (cone[c] == p) break;
5146       }
5147       if (c >= coneSize) {
5148         ierr = PetscPrintf(PETSC_COMM_SELF, "p: %d support: ", p);
5149         for (c = 0; c < supportSize; ++c) {
5150           ierr = PetscPrintf(PETSC_COMM_SELF, "%d, ", support[c]);
5151         }
5152         ierr = PetscPrintf(PETSC_COMM_SELF, "\n");
5153         ierr = PetscPrintf(PETSC_COMM_SELF, "p: %d cone: ", support[s]);
5154         for (c = 0; c < coneSize; ++c) {
5155           ierr = PetscPrintf(PETSC_COMM_SELF, "%d, ", cone[c]);
5156         }
5157         ierr = PetscPrintf(PETSC_COMM_SELF, "\n");
5158         SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d not found in cone of support point %d", p, support[s]);
5159       }
5160     }
5161   }
5162   ierr = PetscSectionGetStorageSize(coneSection, &csize);CHKERRQ(ierr);
5163   ierr = PetscSectionGetStorageSize(supportSection, &ssize);CHKERRQ(ierr);
5164   if (csize != ssize) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Total cone size %d != Total support size %d", csize, ssize);
5165   PetscFunctionReturn(0);
5166 }
5167 
5168 #undef __FUNCT__
5169 #define __FUNCT__ "DMPlexCheckSkeleton"
5170 /*@
5171   DMPlexCheckSkeleton - Check that each cell has the correct number of vertices
5172 
5173   Input Parameters:
5174 + dm - The DMPlex object
5175 . isSimplex - Are the cells simplices or tensor products
5176 - cellHeight - Normally 0
5177 
5178   Note: This is a useful diagnostic when creating meshes programmatically.
5179 
5180   Level: developer
5181 
5182 .seealso: DMCreate(), DMCheckSymmetry(), DMCheckFaces()
5183 @*/
5184 PetscErrorCode DMPlexCheckSkeleton(DM dm, PetscBool isSimplex, PetscInt cellHeight)
5185 {
5186   PetscInt       dim, numCorners, numHybridCorners, vStart, vEnd, cStart, cEnd, cMax, c;
5187   PetscErrorCode ierr;
5188 
5189   PetscFunctionBegin;
5190   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5191   ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr);
5192   switch (dim) {
5193   case 1: numCorners = isSimplex ? 2 : 2; numHybridCorners = isSimplex ? 2 : 2; break;
5194   case 2: numCorners = isSimplex ? 3 : 4; numHybridCorners = isSimplex ? 4 : 4; break;
5195   case 3: numCorners = isSimplex ? 4 : 8; numHybridCorners = isSimplex ? 6 : 8; break;
5196   default:
5197     SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_OUTOFRANGE, "Cannot handle meshes of dimension %d", dim);
5198   }
5199   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
5200   ierr = DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd);CHKERRQ(ierr);
5201   ierr = DMPlexGetHybridBounds(dm, &cMax, NULL, NULL, NULL);CHKERRQ(ierr);
5202   cMax = cMax >= 0 ? cMax : cEnd;
5203   for (c = cStart; c < cMax; ++c) {
5204     PetscInt *closure = NULL, closureSize, cl, coneSize = 0;
5205 
5206     ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
5207     for (cl = 0; cl < closureSize*2; cl += 2) {
5208       const PetscInt p = closure[cl];
5209       if ((p >= vStart) && (p < vEnd)) ++coneSize;
5210     }
5211     ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
5212     if (coneSize != numCorners) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cell %d has  %d vertices != %d", c, coneSize, numCorners);
5213   }
5214   for (c = cMax; c < cEnd; ++c) {
5215     PetscInt *closure = NULL, closureSize, cl, coneSize = 0;
5216 
5217     ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
5218     for (cl = 0; cl < closureSize*2; cl += 2) {
5219       const PetscInt p = closure[cl];
5220       if ((p >= vStart) && (p < vEnd)) ++coneSize;
5221     }
5222     ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
5223     if (coneSize > numHybridCorners) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Hybrid cell %d has  %d vertices > %d", c, coneSize, numHybridCorners);
5224   }
5225   PetscFunctionReturn(0);
5226 }
5227 
5228 #undef __FUNCT__
5229 #define __FUNCT__ "DMPlexCheckFaces"
5230 /*@
5231   DMPlexCheckFaces - Check that the faces of each cell give a vertex order this is consistent with what we expect from the cell type
5232 
5233   Input Parameters:
5234 + dm - The DMPlex object
5235 . isSimplex - Are the cells simplices or tensor products
5236 - cellHeight - Normally 0
5237 
5238   Note: This is a useful diagnostic when creating meshes programmatically.
5239 
5240   Level: developer
5241 
5242 .seealso: DMCreate(), DMCheckSymmetry(), DMCheckSkeleton()
5243 @*/
5244 PetscErrorCode DMPlexCheckFaces(DM dm, PetscBool isSimplex, PetscInt cellHeight)
5245 {
5246   PetscInt       pMax[4];
5247   PetscInt       dim, vStart, vEnd, cStart, cEnd, c, h;
5248   PetscErrorCode ierr;
5249 
5250   PetscFunctionBegin;
5251   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5252   ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr);
5253   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
5254   ierr = DMPlexGetHybridBounds(dm, &pMax[dim], &pMax[dim-1], &pMax[1], &pMax[0]);CHKERRQ(ierr);
5255   for (h = cellHeight; h < dim; ++h) {
5256     ierr = DMPlexGetHeightStratum(dm, h, &cStart, &cEnd);CHKERRQ(ierr);
5257     for (c = cStart; c < cEnd; ++c) {
5258       const PetscInt *cone, *ornt, *faces;
5259       PetscInt        numFaces, faceSize, coneSize,f;
5260       PetscInt       *closure = NULL, closureSize, cl, numCorners = 0;
5261 
5262       if (pMax[dim-h] >= 0 && c >= pMax[dim-h]) continue;
5263       ierr = DMPlexGetConeSize(dm, c, &coneSize);CHKERRQ(ierr);
5264       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
5265       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
5266       ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
5267       for (cl = 0; cl < closureSize*2; cl += 2) {
5268         const PetscInt p = closure[cl];
5269         if ((p >= vStart) && (p < vEnd)) closure[numCorners++] = p;
5270       }
5271       ierr = DMPlexGetRawFaces_Internal(dm, dim-h, numCorners, closure, &numFaces, &faceSize, &faces);CHKERRQ(ierr);
5272       if (coneSize != numFaces) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cell %d has %d faces but should have %d", c, coneSize, numFaces);
5273       for (f = 0; f < numFaces; ++f) {
5274         PetscInt *fclosure = NULL, fclosureSize, cl, fnumCorners = 0, v;
5275 
5276         ierr = DMPlexGetTransitiveClosure_Internal(dm, cone[f], ornt[f], PETSC_TRUE, &fclosureSize, &fclosure);CHKERRQ(ierr);
5277         for (cl = 0; cl < fclosureSize*2; cl += 2) {
5278           const PetscInt p = fclosure[cl];
5279           if ((p >= vStart) && (p < vEnd)) fclosure[fnumCorners++] = p;
5280         }
5281         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);
5282         for (v = 0; v < fnumCorners; ++v) {
5283           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]);
5284         }
5285         ierr = DMPlexRestoreTransitiveClosure(dm, cone[f], PETSC_TRUE, &fclosureSize, &fclosure);CHKERRQ(ierr);
5286       }
5287       ierr = DMPlexRestoreFaces_Internal(dm, dim, c, &numFaces, &faceSize, &faces);CHKERRQ(ierr);
5288       ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
5289     }
5290   }
5291   PetscFunctionReturn(0);
5292 }
5293 
5294 #undef __FUNCT__
5295 #define __FUNCT__ "DMCreateInterpolation_Plex"
5296 /* Pointwise interpolation
5297      Just code FEM for now
5298      u^f = I u^c
5299      sum_k u^f_k phi^f_k = I sum_j u^c_j phi^c_j
5300      u^f_i = sum_j psi^f_i I phi^c_j u^c_j
5301      I_{ij} = psi^f_i phi^c_j
5302 */
5303 PetscErrorCode DMCreateInterpolation_Plex(DM dmCoarse, DM dmFine, Mat *interpolation, Vec *scaling)
5304 {
5305   PetscSection   gsc, gsf;
5306   PetscInt       m, n;
5307   void          *ctx;
5308   PetscErrorCode ierr;
5309 
5310   PetscFunctionBegin;
5311   /*
5312   Loop over coarse cells
5313     Loop over coarse basis functions
5314       Loop over fine cells in coarse cell
5315         Loop over fine dual basis functions
5316           Evaluate coarse basis on fine dual basis quad points
5317           Sum
5318           Update local element matrix
5319     Accumulate to interpolation matrix
5320 
5321    Can extend PetscFEIntegrateJacobian_Basic() to do a specialized cell loop
5322   */
5323   ierr = DMGetDefaultGlobalSection(dmFine, &gsf);CHKERRQ(ierr);
5324   ierr = PetscSectionGetConstrainedStorageSize(gsf, &m);CHKERRQ(ierr);
5325   ierr = DMGetDefaultGlobalSection(dmCoarse, &gsc);CHKERRQ(ierr);
5326   ierr = PetscSectionGetConstrainedStorageSize(gsc, &n);CHKERRQ(ierr);
5327   /* We need to preallocate properly */
5328   ierr = MatCreate(PetscObjectComm((PetscObject) dmCoarse), interpolation);CHKERRQ(ierr);
5329   ierr = MatSetSizes(*interpolation, m, n, PETSC_DETERMINE, PETSC_DETERMINE);CHKERRQ(ierr);
5330   ierr = MatSetType(*interpolation, dmCoarse->mattype);CHKERRQ(ierr);
5331   ierr = DMGetApplicationContext(dmFine, &ctx);CHKERRQ(ierr);
5332   ierr = DMPlexComputeInterpolatorFEM(dmCoarse, dmFine, *interpolation, ctx);CHKERRQ(ierr);
5333   /* Use naive scaling */
5334   ierr = DMCreateInterpolationScale(dmCoarse, dmFine, *interpolation, scaling);CHKERRQ(ierr);
5335   PetscFunctionReturn(0);
5336 }
5337 
5338 #undef __FUNCT__
5339 #define __FUNCT__ "DMCreateInjection_Plex"
5340 PetscErrorCode DMCreateInjection_Plex(DM dmCoarse, DM dmFine, VecScatter *ctx)
5341 {
5342   PetscErrorCode ierr;
5343 
5344   PetscFunctionBegin;
5345   ierr = DMPlexComputeInjectorFEM(dmCoarse, dmFine, ctx, NULL);CHKERRQ(ierr);
5346   PetscFunctionReturn(0);
5347 }
5348 
5349 #undef __FUNCT__
5350 #define __FUNCT__ "DMCreateDefaultSection_Plex"
5351 PetscErrorCode DMCreateDefaultSection_Plex(DM dm)
5352 {
5353   PetscSection   section;
5354   IS            *bcPoints;
5355   PetscBool     *isFE;
5356   PetscInt      *bcFields, *numComp, *numDof;
5357   PetscInt       depth, dim, numBd, numBC = 0, numFields, bd, bc = 0, f;
5358   PetscInt       cStart, cEnd, cEndInterior;
5359   PetscErrorCode ierr;
5360 
5361   PetscFunctionBegin;
5362   ierr = DMGetNumFields(dm, &numFields);CHKERRQ(ierr);
5363   /* FE and FV boundary conditions are handled slightly differently */
5364   ierr = PetscMalloc1(numFields, &isFE);CHKERRQ(ierr);
5365   for (f = 0; f < numFields; ++f) {
5366     PetscObject  obj;
5367     PetscClassId id;
5368 
5369     ierr = DMGetField(dm, f, &obj);CHKERRQ(ierr);
5370     ierr = PetscObjectGetClassId(obj, &id);CHKERRQ(ierr);
5371     if (id == PETSCFE_CLASSID)      {isFE[f] = PETSC_TRUE;}
5372     else if (id == PETSCFV_CLASSID) {isFE[f] = PETSC_FALSE;}
5373     else SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %d", f);
5374   }
5375   /* Allocate boundary point storage */
5376   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
5377   ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr);
5378   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
5379   ierr = DMPlexGetHybridBounds(dm, &cEndInterior, NULL, NULL, NULL);CHKERRQ(ierr);
5380   ierr = DMPlexGetNumBoundary(dm, &numBd);CHKERRQ(ierr);
5381   for (bd = 0; bd < numBd; ++bd) {
5382     PetscBool isEssential;
5383     ierr = DMPlexGetBoundary(dm, bd, &isEssential, NULL, NULL, NULL, NULL, NULL, NULL, NULL);CHKERRQ(ierr);
5384     if (isEssential) ++numBC;
5385   }
5386   for (f = 0; f < numFields; ++f) if (!isFE[f] && cEndInterior >= 0) ++numBC;
5387   ierr = PetscMalloc2(numBC,&bcFields,numBC,&bcPoints);CHKERRQ(ierr);
5388   /* Constrain ghost cells for FV */
5389   for (f = 0; f < numFields; ++f) {
5390     PetscInt *newidx, c;
5391 
5392     if (isFE[f] || cEndInterior < 0) continue;
5393     ierr = PetscMalloc1(cEnd-cEndInterior,&newidx);CHKERRQ(ierr);
5394     for (c = cEndInterior; c < cEnd; ++c) newidx[c-cEndInterior] = c;
5395     bcFields[bc] = f;
5396     ierr = ISCreateGeneral(PetscObjectComm((PetscObject) dm), cEnd-cEndInterior, newidx, PETSC_OWN_POINTER, &bcPoints[bc++]);CHKERRQ(ierr);
5397   }
5398   /* Handle FEM Dirichlet boundaries */
5399   for (bd = 0; bd < numBd; ++bd) {
5400     const char     *bdLabel;
5401     DMLabel         label;
5402     const PetscInt *values;
5403     PetscInt        bd2, field, numValues;
5404     PetscBool       isEssential, duplicate = PETSC_FALSE;
5405 
5406     ierr = DMPlexGetBoundary(dm, bd, &isEssential, NULL, &bdLabel, &field, NULL, &numValues, &values, NULL);CHKERRQ(ierr);
5407     ierr = DMPlexGetLabel(dm, bdLabel, &label);CHKERRQ(ierr);
5408     /* Only want to modify label once */
5409     for (bd2 = 0; bd2 < bd; ++bd2) {
5410       const char *bdname;
5411       ierr = DMPlexGetBoundary(dm, bd2, NULL, NULL, &bdname, NULL, NULL, NULL, NULL, NULL);CHKERRQ(ierr);
5412       ierr = PetscStrcmp(bdname, bdLabel, &duplicate);CHKERRQ(ierr);
5413       if (duplicate) break;
5414     }
5415     if (!duplicate && (isFE[field])) {
5416       ierr = DMPlexLabelComplete(dm, label);CHKERRQ(ierr);
5417       ierr = DMPlexLabelAddCells(dm, label);CHKERRQ(ierr);
5418     }
5419     /* Filter out cells, if you actually want to constrain cells you need to do things by hand right now */
5420     if (isEssential) {
5421       PetscInt       *newidx;
5422       PetscInt        n, newn = 0, p, v;
5423 
5424       bcFields[bc] = field;
5425       for (v = 0; v < numValues; ++v) {
5426         IS              tmp;
5427         const PetscInt *idx;
5428 
5429         ierr = DMPlexGetStratumIS(dm, bdLabel, values[v], &tmp);CHKERRQ(ierr);
5430         if (!tmp) continue;
5431         ierr = ISGetLocalSize(tmp, &n);CHKERRQ(ierr);
5432         ierr = ISGetIndices(tmp, &idx);CHKERRQ(ierr);
5433         if (isFE[field]) {
5434           for (p = 0; p < n; ++p) if ((idx[p] < cStart) || (idx[p] >= cEnd)) ++newn;
5435         } else {
5436           for (p = 0; p < n; ++p) if ((idx[p] >= cStart) || (idx[p] < cEnd)) ++newn;
5437         }
5438         ierr = ISRestoreIndices(tmp, &idx);CHKERRQ(ierr);
5439         ierr = ISDestroy(&tmp);CHKERRQ(ierr);
5440       }
5441       ierr = PetscMalloc1(newn,&newidx);CHKERRQ(ierr);
5442       newn = 0;
5443       for (v = 0; v < numValues; ++v) {
5444         IS              tmp;
5445         const PetscInt *idx;
5446 
5447         ierr = DMPlexGetStratumIS(dm, bdLabel, values[v], &tmp);CHKERRQ(ierr);
5448         if (!tmp) continue;
5449         ierr = ISGetLocalSize(tmp, &n);CHKERRQ(ierr);
5450         ierr = ISGetIndices(tmp, &idx);CHKERRQ(ierr);
5451         if (isFE[field]) {
5452           for (p = 0; p < n; ++p) if ((idx[p] < cStart) || (idx[p] >= cEnd)) newidx[newn++] = idx[p];
5453         } else {
5454           for (p = 0; p < n; ++p) if ((idx[p] >= cStart) || (idx[p] < cEnd)) newidx[newn++] = idx[p];
5455         }
5456         ierr = ISRestoreIndices(tmp, &idx);CHKERRQ(ierr);
5457         ierr = ISDestroy(&tmp);CHKERRQ(ierr);
5458       }
5459       ierr = ISCreateGeneral(PetscObjectComm((PetscObject) dm), newn, newidx, PETSC_OWN_POINTER, &bcPoints[bc++]);CHKERRQ(ierr);
5460     }
5461   }
5462   /* Handle discretization */
5463   ierr = PetscCalloc2(numFields,&numComp,numFields*(dim+1),&numDof);CHKERRQ(ierr);
5464   for (f = 0; f < numFields; ++f) {
5465     PetscObject obj;
5466 
5467     ierr = DMGetField(dm, f, &obj);CHKERRQ(ierr);
5468     if (isFE[f]) {
5469       PetscFE         fe = (PetscFE) obj;
5470       const PetscInt *numFieldDof;
5471       PetscInt        d;
5472 
5473       ierr = PetscFEGetNumComponents(fe, &numComp[f]);CHKERRQ(ierr);
5474       ierr = PetscFEGetNumDof(fe, &numFieldDof);CHKERRQ(ierr);
5475       for (d = 0; d < dim+1; ++d) numDof[f*(dim+1)+d] = numFieldDof[d];
5476     } else {
5477       PetscFV fv = (PetscFV) obj;
5478 
5479       ierr = PetscFVGetNumComponents(fv, &numComp[f]);CHKERRQ(ierr);
5480       numDof[f*(dim+1)+dim] = numComp[f];
5481     }
5482   }
5483   for (f = 0; f < numFields; ++f) {
5484     PetscInt d;
5485     for (d = 1; d < dim; ++d) {
5486       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.");
5487     }
5488   }
5489   ierr = DMPlexCreateSection(dm, dim, numFields, numComp, numDof, numBC, bcFields, bcPoints, NULL, &section);CHKERRQ(ierr);
5490   for (f = 0; f < numFields; ++f) {
5491     PetscFE     fe;
5492     const char *name;
5493 
5494     ierr = DMGetField(dm, f, (PetscObject *) &fe);CHKERRQ(ierr);
5495     ierr = PetscObjectGetName((PetscObject) fe, &name);CHKERRQ(ierr);
5496     ierr = PetscSectionSetFieldName(section, f, name);CHKERRQ(ierr);
5497   }
5498   ierr = DMSetDefaultSection(dm, section);CHKERRQ(ierr);
5499   ierr = PetscSectionDestroy(&section);CHKERRQ(ierr);
5500   for (bc = 0; bc < numBC; ++bc) {ierr = ISDestroy(&bcPoints[bc]);CHKERRQ(ierr);}
5501   ierr = PetscFree2(bcFields,bcPoints);CHKERRQ(ierr);
5502   ierr = PetscFree2(numComp,numDof);CHKERRQ(ierr);
5503   ierr = PetscFree(isFE);CHKERRQ(ierr);
5504   PetscFunctionReturn(0);
5505 }
5506 
5507 #undef __FUNCT__
5508 #define __FUNCT__ "DMPlexGetCoarseDM"
5509 /*@
5510   DMPlexGetCoarseDM - Get the coarse mesh from which this was obtained by refinement
5511 
5512   Input Parameter:
5513 . dm - The DMPlex object
5514 
5515   Output Parameter:
5516 . cdm - The coarse DM
5517 
5518   Level: intermediate
5519 
5520 .seealso: DMPlexSetCoarseDM()
5521 @*/
5522 PetscErrorCode DMPlexGetCoarseDM(DM dm, DM *cdm)
5523 {
5524   PetscFunctionBegin;
5525   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5526   PetscValidPointer(cdm, 2);
5527   *cdm = ((DM_Plex *) dm->data)->coarseMesh;
5528   PetscFunctionReturn(0);
5529 }
5530 
5531 #undef __FUNCT__
5532 #define __FUNCT__ "DMPlexSetCoarseDM"
5533 /*@
5534   DMPlexSetCoarseDM - Set the coarse mesh from which this was obtained by refinement
5535 
5536   Input Parameters:
5537 + dm - The DMPlex object
5538 - cdm - The coarse DM
5539 
5540   Level: intermediate
5541 
5542 .seealso: DMPlexGetCoarseDM()
5543 @*/
5544 PetscErrorCode DMPlexSetCoarseDM(DM dm, DM cdm)
5545 {
5546   DM_Plex       *mesh;
5547   PetscErrorCode ierr;
5548 
5549   PetscFunctionBegin;
5550   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5551   if (cdm) PetscValidHeaderSpecific(cdm, DM_CLASSID, 2);
5552   mesh = (DM_Plex *) dm->data;
5553   ierr = DMDestroy(&mesh->coarseMesh);CHKERRQ(ierr);
5554   mesh->coarseMesh = cdm;
5555   ierr = PetscObjectReference((PetscObject) mesh->coarseMesh);CHKERRQ(ierr);
5556   PetscFunctionReturn(0);
5557 }
5558 
5559 /* anchors */
5560 #undef __FUNCT__
5561 #define __FUNCT__ "DMPlexGetAnchors"
5562 /*@
5563   DMPlexGetAnchors - Get the layout of the anchor (point-to-point) constraints.  Typically, the user will not have to
5564   call DMPlexGetAnchors() directly: if there are anchors, then DMPlexGetAnchors() is called during DMGetConstraints().
5565 
5566   not collective
5567 
5568   Input Parameters:
5569 . dm - The DMPlex object
5570 
5571   Output Parameters:
5572 + anchorSection - If not NULL, set to the section describing which points anchor the constrained points.
5573 - anchorIS - If not NULL, set to the list of anchors indexed by anchorSection
5574 
5575 
5576   Level: intermediate
5577 
5578 .seealso: DMPlexSetAnchors(), DMGetConstraints(), DMSetConstraints()
5579 @*/
5580 PetscErrorCode DMPlexGetAnchors(DM dm, PetscSection *anchorSection, IS *anchorIS)
5581 {
5582   DM_Plex *plex = (DM_Plex *)dm->data;
5583   PetscErrorCode ierr;
5584 
5585   PetscFunctionBegin;
5586   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5587   if (!plex->anchorSection && !plex->anchorIS && plex->createanchors) {ierr = (*plex->createanchors)(dm);CHKERRQ(ierr);}
5588   if (anchorSection) *anchorSection = plex->anchorSection;
5589   if (anchorIS) *anchorIS = plex->anchorIS;
5590   PetscFunctionReturn(0);
5591 }
5592 
5593 #undef __FUNCT__
5594 #define __FUNCT__ "DMPlexSetAnchors"
5595 /*@
5596   DMPlexSetAnchors - Set the layout of the local anchor (point-to-point) constraints.  Unlike boundary conditions,
5597   when a point's degrees of freedom in a section are constrained to an outside value, the anchor constraints set a
5598   point's degrees of freedom to be a linear combination of other points' degrees of freedom.
5599 
5600   After specifying the layout of constraints with DMPlexSetAnchors(), one specifies the constraints by calling
5601   DMGetConstraints() and filling in the entries in the constraint matrix.
5602 
5603   collective on dm
5604 
5605   Input Parameters:
5606 + dm - The DMPlex object
5607 . 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).
5608 - anchorIS - The list of all anchor points.  Must have a local communicator (PETSC_COMM_SELF or derivative).
5609 
5610   The reference counts of anchorSection and anchorIS are incremented.
5611 
5612   Level: intermediate
5613 
5614 .seealso: DMPlexGetAnchors(), DMGetConstraints(), DMSetConstraints()
5615 @*/
5616 PetscErrorCode DMPlexSetAnchors(DM dm, PetscSection anchorSection, IS anchorIS)
5617 {
5618   DM_Plex *plex = (DM_Plex *)dm->data;
5619   PetscMPIInt result;
5620   PetscErrorCode ierr;
5621 
5622   PetscFunctionBegin;
5623   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5624   if (anchorSection) {
5625     PetscValidHeaderSpecific(anchorSection,PETSC_SECTION_CLASSID,2);
5626     ierr = MPI_Comm_compare(PETSC_COMM_SELF,PetscObjectComm((PetscObject)anchorSection),&result);CHKERRQ(ierr);
5627     if (result != MPI_CONGRUENT) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_NOTSAMECOMM,"anchor section must have local communicator");
5628   }
5629   if (anchorIS) {
5630     PetscValidHeaderSpecific(anchorIS,IS_CLASSID,3);
5631     ierr = MPI_Comm_compare(PETSC_COMM_SELF,PetscObjectComm((PetscObject)anchorIS),&result);CHKERRQ(ierr);
5632     if (result != MPI_CONGRUENT) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_NOTSAMECOMM,"anchor IS must have local communicator");
5633   }
5634 
5635   ierr = PetscObjectReference((PetscObject)anchorSection);CHKERRQ(ierr);
5636   ierr = PetscSectionDestroy(&plex->anchorSection);CHKERRQ(ierr);
5637   plex->anchorSection = anchorSection;
5638 
5639   ierr = PetscObjectReference((PetscObject)anchorIS);CHKERRQ(ierr);
5640   ierr = ISDestroy(&plex->anchorIS);CHKERRQ(ierr);
5641   plex->anchorIS = anchorIS;
5642 
5643 #if defined(PETSC_USE_DEBUG)
5644   if (anchorIS && anchorSection) {
5645     PetscInt size, a, pStart, pEnd;
5646     const PetscInt *anchors;
5647 
5648     ierr = PetscSectionGetChart(anchorSection,&pStart,&pEnd);CHKERRQ(ierr);
5649     ierr = ISGetLocalSize(anchorIS,&size);CHKERRQ(ierr);
5650     ierr = ISGetIndices(anchorIS,&anchors);CHKERRQ(ierr);
5651     for (a = 0; a < size; a++) {
5652       PetscInt p;
5653 
5654       p = anchors[a];
5655       if (p >= pStart && p < pEnd) {
5656         PetscInt dof;
5657 
5658         ierr = PetscSectionGetDof(anchorSection,p,&dof);CHKERRQ(ierr);
5659         if (dof) {
5660           PetscErrorCode ierr2;
5661 
5662           ierr2 = ISRestoreIndices(anchorIS,&anchors);CHKERRQ(ierr2);
5663           SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Point %d cannot be constrained and an anchor",p);
5664         }
5665       }
5666     }
5667     ierr = ISRestoreIndices(anchorIS,&anchors);CHKERRQ(ierr);
5668   }
5669 #endif
5670   /* reset the generic constraints */
5671   ierr = DMSetDefaultConstraints(dm,NULL,NULL);CHKERRQ(ierr);
5672   PetscFunctionReturn(0);
5673 }
5674 
5675 #undef __FUNCT__
5676 #define __FUNCT__ "DMPlexCreateConstraintSection_Anchors"
5677 static PetscErrorCode DMPlexCreateConstraintSection_Anchors(DM dm, PetscSection section, PetscSection *cSec)
5678 {
5679   PetscSection anchorSection;
5680   PetscInt pStart, pEnd, p, dof, numFields, f;
5681   PetscErrorCode ierr;
5682 
5683   PetscFunctionBegin;
5684   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5685   ierr = DMPlexGetAnchors(dm,&anchorSection,NULL);CHKERRQ(ierr);
5686   ierr = PetscSectionCreate(PETSC_COMM_SELF,cSec);CHKERRQ(ierr);
5687   ierr = PetscSectionGetNumFields(section,&numFields);CHKERRQ(ierr);
5688   ierr = PetscSectionSetNumFields(*cSec,numFields);CHKERRQ(ierr);
5689   ierr = PetscSectionGetChart(anchorSection,&pStart,&pEnd);CHKERRQ(ierr);
5690   ierr = PetscSectionSetChart(*cSec,pStart,pEnd);CHKERRQ(ierr);
5691   for (p = pStart; p < pEnd; p++) {
5692     ierr = PetscSectionGetDof(anchorSection,p,&dof);CHKERRQ(ierr);
5693     if (dof) {
5694       ierr = PetscSectionGetDof(section,p,&dof);CHKERRQ(ierr);
5695       ierr = PetscSectionSetDof(*cSec,p,dof);CHKERRQ(ierr);
5696       for (f = 0; f < numFields; f++) {
5697         ierr = PetscSectionGetFieldDof(section,p,f,&dof);CHKERRQ(ierr);
5698         ierr = PetscSectionSetFieldDof(*cSec,p,f,dof);CHKERRQ(ierr);
5699       }
5700     }
5701   }
5702   ierr = PetscSectionSetUp(*cSec);CHKERRQ(ierr);
5703   PetscFunctionReturn(0);
5704 }
5705 
5706 #undef __FUNCT__
5707 #define __FUNCT__ "DMPlexCreateConstraintMatrix_Anchors"
5708 static PetscErrorCode DMPlexCreateConstraintMatrix_Anchors(DM dm, PetscSection section, PetscSection cSec, Mat *cMat)
5709 {
5710   PetscSection aSec;
5711   PetscInt pStart, pEnd, p, dof, aDof, aOff, off, nnz, annz, m, n, q, a, offset, *i, *j;
5712   const PetscInt *anchors;
5713   PetscInt numFields, f;
5714   IS aIS;
5715   PetscErrorCode ierr;
5716 
5717   PetscFunctionBegin;
5718   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5719   ierr = PetscSectionGetStorageSize(cSec, &m);CHKERRQ(ierr);
5720   ierr = PetscSectionGetStorageSize(section, &n);CHKERRQ(ierr);
5721   ierr = MatCreate(PETSC_COMM_SELF,cMat);CHKERRQ(ierr);
5722   ierr = MatSetSizes(*cMat,m,n,m,n);CHKERRQ(ierr);
5723   ierr = MatSetType(*cMat,MATSEQAIJ);
5724   ierr = DMPlexGetAnchors(dm,&aSec,&aIS);CHKERRQ(ierr);
5725   ierr = ISGetIndices(aIS,&anchors);CHKERRQ(ierr);
5726   ierr = PetscSectionGetChart(aSec,&pStart,&pEnd);CHKERRQ(ierr);
5727   ierr = PetscMalloc1(m+1,&i);CHKERRQ(ierr);
5728   i[0] = 0;
5729   ierr = PetscSectionGetNumFields(section,&numFields);CHKERRQ(ierr);
5730   for (p = pStart; p < pEnd; p++) {
5731     ierr = PetscSectionGetDof(aSec,p,&dof);CHKERRQ(ierr);
5732     if (!dof) continue;
5733     ierr = PetscSectionGetOffset(aSec,p,&off);CHKERRQ(ierr);
5734     if (numFields) {
5735       for (f = 0; f < numFields; f++) {
5736         annz = 0;
5737         for (q = 0; q < dof; q++) {
5738           a = anchors[off + q];
5739           ierr = PetscSectionGetFieldDof(section,a,f,&aDof);CHKERRQ(ierr);
5740           annz += aDof;
5741         }
5742         ierr = PetscSectionGetFieldDof(cSec,p,f,&dof);CHKERRQ(ierr);
5743         ierr = PetscSectionGetFieldOffset(cSec,p,f,&off);CHKERRQ(ierr);
5744         for (q = 0; q < dof; q++) {
5745           i[off + q + 1] = i[off + q] + annz;
5746         }
5747       }
5748     }
5749     else {
5750       annz = 0;
5751       for (q = 0; q < dof; q++) {
5752         a = anchors[off + q];
5753         ierr = PetscSectionGetDof(section,a,&aDof);CHKERRQ(ierr);
5754         annz += aDof;
5755       }
5756       ierr = PetscSectionGetDof(cSec,p,&dof);CHKERRQ(ierr);
5757       ierr = PetscSectionGetOffset(cSec,p,&off);CHKERRQ(ierr);
5758       for (q = 0; q < dof; q++) {
5759         i[off + q + 1] = i[off + q] + annz;
5760       }
5761     }
5762   }
5763   nnz = i[m];
5764   ierr = PetscMalloc1(nnz,&j);CHKERRQ(ierr);
5765   offset = 0;
5766   for (p = pStart; p < pEnd; p++) {
5767     if (numFields) {
5768       for (f = 0; f < numFields; f++) {
5769         ierr = PetscSectionGetFieldDof(cSec,p,f,&dof);CHKERRQ(ierr);
5770         for (q = 0; q < dof; q++) {
5771           PetscInt rDof, rOff, r;
5772           ierr = PetscSectionGetDof(aSec,p,&rDof);CHKERRQ(ierr);
5773           ierr = PetscSectionGetOffset(aSec,p,&rOff);CHKERRQ(ierr);
5774           for (r = 0; r < rDof; r++) {
5775             PetscInt s;
5776 
5777             a = anchors[rOff + r];
5778 
5779             ierr = PetscSectionGetFieldDof(section,a,f,&aDof);CHKERRQ(ierr);
5780             ierr = PetscSectionGetFieldOffset(section,a,f,&aOff);CHKERRQ(ierr);
5781             for (s = 0; s < aDof; s++) {
5782               j[offset++] = aOff + s;
5783             }
5784           }
5785         }
5786       }
5787     }
5788     else {
5789       ierr = PetscSectionGetDof(cSec,p,&dof);CHKERRQ(ierr);
5790       for (q = 0; q < dof; q++) {
5791         PetscInt rDof, rOff, r;
5792         ierr = PetscSectionGetDof(aSec,p,&rDof);CHKERRQ(ierr);
5793         ierr = PetscSectionGetOffset(aSec,p,&rOff);CHKERRQ(ierr);
5794         for (r = 0; r < rDof; r++) {
5795           PetscInt s;
5796 
5797           a = anchors[rOff + r];
5798 
5799           ierr = PetscSectionGetDof(section,a,&aDof);CHKERRQ(ierr);
5800           ierr = PetscSectionGetOffset(section,a,&aOff);CHKERRQ(ierr);
5801           for (s = 0; s < aDof; s++) {
5802             j[offset++] = aOff + s;
5803           }
5804         }
5805       }
5806     }
5807   }
5808   ierr = MatSeqAIJSetPreallocationCSR(*cMat,i,j,NULL);CHKERRQ(ierr);
5809   ierr = PetscFree2(i,j);CHKERRQ(ierr);
5810   ierr = ISRestoreIndices(aIS,&anchors);CHKERRQ(ierr);
5811   PetscFunctionReturn(0);
5812 }
5813 
5814 #undef __FUNCT__
5815 #define __FUNCT__ "DMCreateDefaultConstraints_Plex"
5816 PetscErrorCode DMCreateDefaultConstraints_Plex(DM dm)
5817 {
5818   DM_Plex        *plex = (DM_Plex *)dm->data;
5819   PetscSection   anchorSection, section, cSec;
5820   Mat            cMat;
5821   PetscErrorCode ierr;
5822 
5823   PetscFunctionBegin;
5824   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5825   ierr = DMPlexGetAnchors(dm,&anchorSection,NULL);CHKERRQ(ierr);
5826   if (anchorSection) {
5827     PetscDS  ds;
5828     PetscInt nf;
5829 
5830     ierr = DMGetDefaultSection(dm,&section);CHKERRQ(ierr);
5831     ierr = DMPlexCreateConstraintSection_Anchors(dm,section,&cSec);CHKERRQ(ierr);
5832     ierr = DMPlexCreateConstraintMatrix_Anchors(dm,section,cSec,&cMat);CHKERRQ(ierr);
5833     ierr = DMGetDS(dm,&ds);CHKERRQ(ierr);
5834     ierr = PetscDSGetNumFields(ds,&nf);
5835     if (nf && plex->computeanchormatrix) {ierr = (*plex->computeanchormatrix)(dm,section,cSec,cMat);CHKERRQ(ierr);}
5836     ierr = DMSetDefaultConstraints(dm,cSec,cMat);CHKERRQ(ierr);
5837     ierr = PetscSectionDestroy(&cSec);CHKERRQ(ierr);
5838     ierr = MatDestroy(&cMat);CHKERRQ(ierr);
5839   }
5840   PetscFunctionReturn(0);
5841 }
5842