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