xref: /petsc/src/dm/impls/plex/plex.c (revision d683dfc26daed7629ed52b5836a1e0adf188a784)
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      *pMax;
2670   PetscInt       depth, pStart = 0, pEnd = 0;
2671   PetscInt       Nf, p, d, dep, f;
2672   PetscBool     *isFE;
2673   PetscErrorCode ierr;
2674 
2675   PetscFunctionBegin;
2676   ierr = PetscMalloc1(numFields, &isFE);CHKERRQ(ierr);
2677   ierr = DMGetNumFields(dm, &Nf);CHKERRQ(ierr);
2678   for (f = 0; f < numFields; ++f) {
2679     PetscObject  obj;
2680     PetscClassId id;
2681 
2682     isFE[f] = PETSC_FALSE;
2683     if (f >= Nf) continue;
2684     ierr = DMGetField(dm, f, &obj);CHKERRQ(ierr);
2685     ierr = PetscObjectGetClassId(obj, &id);CHKERRQ(ierr);
2686     if (id == PETSCFE_CLASSID)      {isFE[f] = PETSC_TRUE;}
2687     else if (id == PETSCFV_CLASSID) {isFE[f] = PETSC_FALSE;}
2688   }
2689   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)dm), section);CHKERRQ(ierr);
2690   if (numFields > 0) {
2691     ierr = PetscSectionSetNumFields(*section, numFields);CHKERRQ(ierr);
2692     if (numComp) {
2693       for (f = 0; f < numFields; ++f) {
2694         ierr = PetscSectionSetFieldComponents(*section, f, numComp[f]);CHKERRQ(ierr);
2695       }
2696     }
2697   }
2698   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
2699   ierr = PetscSectionSetChart(*section, pStart, pEnd);CHKERRQ(ierr);
2700   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
2701   ierr = PetscMalloc1(depth+1,&pMax);CHKERRQ(ierr);
2702   ierr = DMPlexGetHybridBounds(dm, depth >= 0 ? &pMax[depth] : NULL, depth>1 ? &pMax[depth-1] : NULL, depth>2 ? &pMax[1] : NULL, &pMax[0]);CHKERRQ(ierr);
2703   for (dep = 0; dep <= depth; ++dep) {
2704     d    = dim == depth ? dep : (!dep ? 0 : dim);
2705     ierr = DMPlexGetDepthStratum(dm, dep, &pStart, &pEnd);CHKERRQ(ierr);
2706     pMax[dep] = pMax[dep] < 0 ? pEnd : pMax[dep];
2707     for (p = pStart; p < pEnd; ++p) {
2708       PetscInt tot = 0;
2709 
2710       for (f = 0; f < numFields; ++f) {
2711         if (isFE[f] && p >= pMax[dep]) continue;
2712         ierr = PetscSectionSetFieldDof(*section, p, f, numDof[f*(dim+1)+d]);CHKERRQ(ierr);
2713         tot += numDof[f*(dim+1)+d];
2714       }
2715       ierr = PetscSectionSetDof(*section, p, tot);CHKERRQ(ierr);
2716     }
2717   }
2718   ierr = PetscFree(pMax);CHKERRQ(ierr);
2719   ierr = PetscFree(isFE);CHKERRQ(ierr);
2720   PetscFunctionReturn(0);
2721 }
2722 
2723 #undef __FUNCT__
2724 #define __FUNCT__ "DMPlexCreateSectionBCDof"
2725 /* Set the number of dof on each point and separate by fields
2726    If constDof is PETSC_DETERMINE, constrain every dof on the point
2727 */
2728 PetscErrorCode DMPlexCreateSectionBCDof(DM dm, PetscInt numBC,const PetscInt bcField[],const IS bcPoints[], PetscInt constDof, PetscSection section)
2729 {
2730   PetscInt       numFields;
2731   PetscInt       bc;
2732   PetscSection   aSec;
2733   PetscErrorCode ierr;
2734 
2735   PetscFunctionBegin;
2736   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
2737   for (bc = 0; bc < numBC; ++bc) {
2738     PetscInt        field = 0;
2739     const PetscInt *idx;
2740     PetscInt        n, i;
2741 
2742     if (numFields) field = bcField[bc];
2743     ierr = ISGetLocalSize(bcPoints[bc], &n);CHKERRQ(ierr);
2744     ierr = ISGetIndices(bcPoints[bc], &idx);CHKERRQ(ierr);
2745     for (i = 0; i < n; ++i) {
2746       const PetscInt p        = idx[i];
2747       PetscInt       numConst = constDof;
2748 
2749       /* Constrain every dof on the point */
2750       if (numConst < 0) {
2751         if (numFields) {
2752           ierr = PetscSectionGetFieldDof(section, p, field, &numConst);CHKERRQ(ierr);
2753         } else {
2754           ierr = PetscSectionGetDof(section, p, &numConst);CHKERRQ(ierr);
2755         }
2756       }
2757       if (numFields) {
2758         ierr = PetscSectionAddFieldConstraintDof(section, p, field, numConst);CHKERRQ(ierr);
2759       }
2760       ierr = PetscSectionAddConstraintDof(section, p, numConst);CHKERRQ(ierr);
2761     }
2762     ierr = ISRestoreIndices(bcPoints[bc], &idx);CHKERRQ(ierr);
2763   }
2764   ierr = DMPlexGetAnchors(dm, &aSec, NULL);CHKERRQ(ierr);
2765   if (aSec) {
2766     PetscInt aStart, aEnd, a;
2767 
2768     ierr = PetscSectionGetChart(aSec, &aStart, &aEnd);CHKERRQ(ierr);
2769     for (a = aStart; a < aEnd; a++) {
2770       PetscInt dof;
2771 
2772       ierr = PetscSectionGetDof(aSec, a, &dof);CHKERRQ(ierr);
2773       if (dof) {
2774         /* if there are point-to-point constraints, then all dofs are constrained */
2775         ierr = PetscSectionGetDof(section, a, &dof);CHKERRQ(ierr);
2776         ierr = PetscSectionSetConstraintDof(section, a, dof);CHKERRQ(ierr);
2777         if (numFields) {
2778           PetscInt f;
2779 
2780           for (f = 0; f < numFields; f++) {
2781             ierr = PetscSectionGetFieldDof(section, a, f, &dof);CHKERRQ(ierr);
2782             ierr = PetscSectionSetFieldConstraintDof(section, a, f, dof);CHKERRQ(ierr);
2783           }
2784         }
2785       }
2786     }
2787   }
2788   PetscFunctionReturn(0);
2789 }
2790 
2791 #undef __FUNCT__
2792 #define __FUNCT__ "DMPlexCreateSectionBCIndicesAll"
2793 /* Set the constrained indices on each point and separate by fields */
2794 PetscErrorCode DMPlexCreateSectionBCIndicesAll(DM dm, PetscSection section)
2795 {
2796   PetscInt      *maxConstraints;
2797   PetscInt       numFields, f, pStart = 0, pEnd = 0, p;
2798   PetscErrorCode ierr;
2799 
2800   PetscFunctionBegin;
2801   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
2802   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
2803   ierr = PetscMalloc1(numFields+1, &maxConstraints);CHKERRQ(ierr);
2804   for (f = 0; f <= numFields; ++f) maxConstraints[f] = 0;
2805   for (p = pStart; p < pEnd; ++p) {
2806     PetscInt cdof;
2807 
2808     if (numFields) {
2809       for (f = 0; f < numFields; ++f) {
2810         ierr              = PetscSectionGetFieldConstraintDof(section, p, f, &cdof);CHKERRQ(ierr);
2811         maxConstraints[f] = PetscMax(maxConstraints[f], cdof);
2812       }
2813     } else {
2814       ierr              = PetscSectionGetConstraintDof(section, p, &cdof);CHKERRQ(ierr);
2815       maxConstraints[0] = PetscMax(maxConstraints[0], cdof);
2816     }
2817   }
2818   for (f = 0; f < numFields; ++f) {
2819     maxConstraints[numFields] += maxConstraints[f];
2820   }
2821   if (maxConstraints[numFields]) {
2822     PetscInt *indices;
2823 
2824     ierr = PetscMalloc1(maxConstraints[numFields], &indices);CHKERRQ(ierr);
2825     for (p = pStart; p < pEnd; ++p) {
2826       PetscInt cdof, d;
2827 
2828       ierr = PetscSectionGetConstraintDof(section, p, &cdof);CHKERRQ(ierr);
2829       if (cdof) {
2830         if (cdof > maxConstraints[numFields]) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_LIB, "Likely memory corruption, point %D cDof %D > maxConstraints %D", p, cdof, maxConstraints[numFields]);
2831         if (numFields) {
2832           PetscInt numConst = 0, foff = 0;
2833 
2834           for (f = 0; f < numFields; ++f) {
2835             PetscInt cfdof, fdof;
2836 
2837             ierr = PetscSectionGetFieldDof(section, p, f, &fdof);CHKERRQ(ierr);
2838             ierr = PetscSectionGetFieldConstraintDof(section, p, f, &cfdof);CHKERRQ(ierr);
2839             /* Change constraint numbering from absolute local dof number to field relative local dof number */
2840             for (d = 0; d < cfdof; ++d) indices[numConst+d] = d;
2841             ierr = PetscSectionSetFieldConstraintIndices(section, p, f, &indices[numConst]);CHKERRQ(ierr);
2842             for (d = 0; d < cfdof; ++d) indices[numConst+d] += foff;
2843             numConst += cfdof;
2844             foff     += fdof;
2845           }
2846           if (cdof != numConst) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_LIB, "Total number of field constraints %D should be %D", numConst, cdof);
2847         } else {
2848           for (d = 0; d < cdof; ++d) indices[d] = d;
2849         }
2850         ierr = PetscSectionSetConstraintIndices(section, p, indices);CHKERRQ(ierr);
2851       }
2852     }
2853     ierr = PetscFree(indices);CHKERRQ(ierr);
2854   }
2855   ierr = PetscFree(maxConstraints);CHKERRQ(ierr);
2856   PetscFunctionReturn(0);
2857 }
2858 
2859 #undef __FUNCT__
2860 #define __FUNCT__ "DMPlexCreateSectionBCIndicesField"
2861 /* Set the constrained field indices on each point */
2862 PetscErrorCode DMPlexCreateSectionBCIndicesField(DM dm, PetscInt field, IS bcPoints, IS constraintIndices, PetscSection section)
2863 {
2864   const PetscInt *points, *indices;
2865   PetscInt        numFields, maxDof, numPoints, p, numConstraints;
2866   PetscErrorCode  ierr;
2867 
2868   PetscFunctionBegin;
2869   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
2870   if ((field < 0) || (field >= numFields)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Section field %d should be in [%d, %d)", field, 0, numFields);
2871 
2872   ierr = ISGetLocalSize(bcPoints, &numPoints);CHKERRQ(ierr);
2873   ierr = ISGetIndices(bcPoints, &points);CHKERRQ(ierr);
2874   if (!constraintIndices) {
2875     PetscInt *idx, i;
2876 
2877     ierr = PetscSectionGetMaxDof(section, &maxDof);CHKERRQ(ierr);
2878     ierr = PetscMalloc1(maxDof, &idx);CHKERRQ(ierr);
2879     for (i = 0; i < maxDof; ++i) idx[i] = i;
2880     for (p = 0; p < numPoints; ++p) {
2881       ierr = PetscSectionSetFieldConstraintIndices(section, points[p], field, idx);CHKERRQ(ierr);
2882     }
2883     ierr = PetscFree(idx);CHKERRQ(ierr);
2884   } else {
2885     ierr = ISGetLocalSize(constraintIndices, &numConstraints);CHKERRQ(ierr);
2886     ierr = ISGetIndices(constraintIndices, &indices);CHKERRQ(ierr);
2887     for (p = 0; p < numPoints; ++p) {
2888       PetscInt fcdof;
2889 
2890       ierr = PetscSectionGetFieldConstraintDof(section, points[p], field, &fcdof);CHKERRQ(ierr);
2891       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);
2892       ierr = PetscSectionSetFieldConstraintIndices(section, points[p], field, indices);CHKERRQ(ierr);
2893     }
2894     ierr = ISRestoreIndices(constraintIndices, &indices);CHKERRQ(ierr);
2895   }
2896   ierr = ISRestoreIndices(bcPoints, &points);CHKERRQ(ierr);
2897   PetscFunctionReturn(0);
2898 }
2899 
2900 #undef __FUNCT__
2901 #define __FUNCT__ "DMPlexCreateSectionBCIndices"
2902 /* Set the constrained indices on each point and separate by fields */
2903 PetscErrorCode DMPlexCreateSectionBCIndices(DM dm, PetscSection section)
2904 {
2905   PetscInt      *indices;
2906   PetscInt       numFields, maxDof, f, pStart = 0, pEnd = 0, p;
2907   PetscErrorCode ierr;
2908 
2909   PetscFunctionBegin;
2910   ierr = PetscSectionGetMaxDof(section, &maxDof);CHKERRQ(ierr);
2911   ierr = PetscMalloc1(maxDof, &indices);CHKERRQ(ierr);
2912   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
2913   if (!numFields) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "This function only works after users have set field constraint indices.");
2914   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
2915   for (p = pStart; p < pEnd; ++p) {
2916     PetscInt cdof, d;
2917 
2918     ierr = PetscSectionGetConstraintDof(section, p, &cdof);CHKERRQ(ierr);
2919     if (cdof) {
2920       PetscInt numConst = 0, foff = 0;
2921 
2922       for (f = 0; f < numFields; ++f) {
2923         const PetscInt *fcind;
2924         PetscInt        fdof, fcdof;
2925 
2926         ierr = PetscSectionGetFieldDof(section, p, f, &fdof);CHKERRQ(ierr);
2927         ierr = PetscSectionGetFieldConstraintDof(section, p, f, &fcdof);CHKERRQ(ierr);
2928         if (fcdof) {ierr = PetscSectionGetFieldConstraintIndices(section, p, f, &fcind);CHKERRQ(ierr);}
2929         /* Change constraint numbering from field relative local dof number to absolute local dof number */
2930         for (d = 0; d < fcdof; ++d) indices[numConst+d] = fcind[d]+foff;
2931         foff     += fdof;
2932         numConst += fcdof;
2933       }
2934       if (cdof != numConst) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_LIB, "Total number of field constraints %D should be %D", numConst, cdof);
2935       ierr = PetscSectionSetConstraintIndices(section, p, indices);CHKERRQ(ierr);
2936     }
2937   }
2938   ierr = PetscFree(indices);CHKERRQ(ierr);
2939   PetscFunctionReturn(0);
2940 }
2941 
2942 #undef __FUNCT__
2943 #define __FUNCT__ "DMPlexCreateSection"
2944 /*@C
2945   DMPlexCreateSection - Create a PetscSection based upon the dof layout specification provided.
2946 
2947   Not Collective
2948 
2949   Input Parameters:
2950 + dm        - The DMPlex object
2951 . dim       - The spatial dimension of the problem
2952 . numFields - The number of fields in the problem
2953 . numComp   - An array of size numFields that holds the number of components for each field
2954 . numDof    - An array of size numFields*(dim+1) which holds the number of dof for each field on a mesh piece of dimension d
2955 . numBC     - The number of boundary conditions
2956 . bcField   - An array of size numBC giving the field number for each boundry condition
2957 . bcPoints  - An array of size numBC giving an IS holding the sieve points to which each boundary condition applies
2958 - perm      - Optional permutation of the chart, or NULL
2959 
2960   Output Parameter:
2961 . section - The PetscSection object
2962 
2963   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
2964   number of dof for field 0 on each edge.
2965 
2966   The chart permutation is the same one set using PetscSectionSetPermutation()
2967 
2968   Level: developer
2969 
2970   Fortran Notes:
2971   A Fortran 90 version is available as DMPlexCreateSectionF90()
2972 
2973 .keywords: mesh, elements
2974 .seealso: DMPlexCreate(), PetscSectionCreate(), PetscSectionSetPermutation()
2975 @*/
2976 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)
2977 {
2978   PetscSection   aSec;
2979   PetscErrorCode ierr;
2980 
2981   PetscFunctionBegin;
2982   ierr = DMPlexCreateSectionInitial(dm, dim, numFields, numComp, numDof, section);CHKERRQ(ierr);
2983   ierr = DMPlexCreateSectionBCDof(dm, numBC, bcField, bcPoints, PETSC_DETERMINE, *section);CHKERRQ(ierr);
2984   if (perm) {ierr = PetscSectionSetPermutation(*section, perm);CHKERRQ(ierr);}
2985   ierr = PetscSectionSetUp(*section);CHKERRQ(ierr);
2986   ierr = DMPlexGetAnchors(dm,&aSec,NULL);CHKERRQ(ierr);
2987   if (numBC || aSec) {ierr = DMPlexCreateSectionBCIndicesAll(dm, *section);CHKERRQ(ierr);}
2988   ierr = PetscSectionViewFromOptions(*section,NULL,"-section_view");CHKERRQ(ierr);
2989   PetscFunctionReturn(0);
2990 }
2991 
2992 #undef __FUNCT__
2993 #define __FUNCT__ "DMCreateCoordinateDM_Plex"
2994 PetscErrorCode DMCreateCoordinateDM_Plex(DM dm, DM *cdm)
2995 {
2996   PetscSection   section;
2997   PetscErrorCode ierr;
2998 
2999   PetscFunctionBegin;
3000   ierr = DMClone(dm, cdm);CHKERRQ(ierr);
3001   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)dm), &section);CHKERRQ(ierr);
3002   ierr = DMSetDefaultSection(*cdm, section);CHKERRQ(ierr);
3003   ierr = PetscSectionDestroy(&section);CHKERRQ(ierr);
3004   PetscFunctionReturn(0);
3005 }
3006 
3007 #undef __FUNCT__
3008 #define __FUNCT__ "DMPlexGetConeSection"
3009 PetscErrorCode DMPlexGetConeSection(DM dm, PetscSection *section)
3010 {
3011   DM_Plex *mesh = (DM_Plex*) dm->data;
3012 
3013   PetscFunctionBegin;
3014   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3015   if (section) *section = mesh->coneSection;
3016   PetscFunctionReturn(0);
3017 }
3018 
3019 #undef __FUNCT__
3020 #define __FUNCT__ "DMPlexGetSupportSection"
3021 PetscErrorCode DMPlexGetSupportSection(DM dm, PetscSection *section)
3022 {
3023   DM_Plex *mesh = (DM_Plex*) dm->data;
3024 
3025   PetscFunctionBegin;
3026   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3027   if (section) *section = mesh->supportSection;
3028   PetscFunctionReturn(0);
3029 }
3030 
3031 #undef __FUNCT__
3032 #define __FUNCT__ "DMPlexGetCones"
3033 PetscErrorCode DMPlexGetCones(DM dm, PetscInt *cones[])
3034 {
3035   DM_Plex *mesh = (DM_Plex*) dm->data;
3036 
3037   PetscFunctionBegin;
3038   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3039   if (cones) *cones = mesh->cones;
3040   PetscFunctionReturn(0);
3041 }
3042 
3043 #undef __FUNCT__
3044 #define __FUNCT__ "DMPlexGetConeOrientations"
3045 PetscErrorCode DMPlexGetConeOrientations(DM dm, PetscInt *coneOrientations[])
3046 {
3047   DM_Plex *mesh = (DM_Plex*) dm->data;
3048 
3049   PetscFunctionBegin;
3050   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3051   if (coneOrientations) *coneOrientations = mesh->coneOrientations;
3052   PetscFunctionReturn(0);
3053 }
3054 
3055 /******************************** FEM Support **********************************/
3056 
3057 #undef __FUNCT__
3058 #define __FUNCT__ "DMPlexVecGetClosure_Depth1_Static"
3059 PETSC_STATIC_INLINE PetscErrorCode DMPlexVecGetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[])
3060 {
3061   PetscScalar    *array, *vArray;
3062   const PetscInt *cone, *coneO;
3063   PetscInt        pStart, pEnd, p, numPoints, size = 0, offset = 0;
3064   PetscErrorCode  ierr;
3065 
3066   PetscFunctionBeginHot;
3067   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
3068   ierr = DMPlexGetConeSize(dm, point, &numPoints);CHKERRQ(ierr);
3069   ierr = DMPlexGetCone(dm, point, &cone);CHKERRQ(ierr);
3070   ierr = DMPlexGetConeOrientation(dm, point, &coneO);CHKERRQ(ierr);
3071   if (!values || !*values) {
3072     if ((point >= pStart) && (point < pEnd)) {
3073       PetscInt dof;
3074 
3075       ierr = PetscSectionGetDof(section, point, &dof);CHKERRQ(ierr);
3076       size += dof;
3077     }
3078     for (p = 0; p < numPoints; ++p) {
3079       const PetscInt cp = cone[p];
3080       PetscInt       dof;
3081 
3082       if ((cp < pStart) || (cp >= pEnd)) continue;
3083       ierr = PetscSectionGetDof(section, cp, &dof);CHKERRQ(ierr);
3084       size += dof;
3085     }
3086     if (!values) {
3087       if (csize) *csize = size;
3088       PetscFunctionReturn(0);
3089     }
3090     ierr = DMGetWorkArray(dm, size, PETSC_SCALAR, &array);CHKERRQ(ierr);
3091   } else {
3092     array = *values;
3093   }
3094   size = 0;
3095   ierr = VecGetArray(v, &vArray);CHKERRQ(ierr);
3096   if ((point >= pStart) && (point < pEnd)) {
3097     PetscInt     dof, off, d;
3098     PetscScalar *varr;
3099 
3100     ierr = PetscSectionGetDof(section, point, &dof);CHKERRQ(ierr);
3101     ierr = PetscSectionGetOffset(section, point, &off);CHKERRQ(ierr);
3102     varr = &vArray[off];
3103     for (d = 0; d < dof; ++d, ++offset) {
3104       array[offset] = varr[d];
3105     }
3106     size += dof;
3107   }
3108   for (p = 0; p < numPoints; ++p) {
3109     const PetscInt cp = cone[p];
3110     PetscInt       o  = coneO[p];
3111     PetscInt       dof, off, d;
3112     PetscScalar   *varr;
3113 
3114     if ((cp < pStart) || (cp >= pEnd)) continue;
3115     ierr = PetscSectionGetDof(section, cp, &dof);CHKERRQ(ierr);
3116     ierr = PetscSectionGetOffset(section, cp, &off);CHKERRQ(ierr);
3117     varr = &vArray[off];
3118     if (o >= 0) {
3119       for (d = 0; d < dof; ++d, ++offset) {
3120         array[offset] = varr[d];
3121       }
3122     } else {
3123       for (d = dof-1; d >= 0; --d, ++offset) {
3124         array[offset] = varr[d];
3125       }
3126     }
3127     size += dof;
3128   }
3129   ierr = VecRestoreArray(v, &vArray);CHKERRQ(ierr);
3130   if (!*values) {
3131     if (csize) *csize = size;
3132     *values = array;
3133   } else {
3134     if (size > *csize) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %d < actual size %d", *csize, size);
3135     *csize = size;
3136   }
3137   PetscFunctionReturn(0);
3138 }
3139 
3140 #undef __FUNCT__
3141 #define __FUNCT__ "DMPlexVecGetClosure_Static"
3142 PETSC_STATIC_INLINE PetscErrorCode DMPlexVecGetClosure_Static(PetscSection section, PetscInt numPoints, const PetscInt points[], const PetscScalar vArray[], PetscInt *size, PetscScalar array[])
3143 {
3144   PetscInt       offset = 0, p;
3145   PetscErrorCode ierr;
3146 
3147   PetscFunctionBeginHot;
3148   *size = 0;
3149   for (p = 0; p < numPoints*2; p += 2) {
3150     const PetscInt point = points[p];
3151     const PetscInt o     = points[p+1];
3152     PetscInt       dof, off, d;
3153     const PetscScalar *varr;
3154 
3155     ierr = PetscSectionGetDof(section, point, &dof);CHKERRQ(ierr);
3156     ierr = PetscSectionGetOffset(section, point, &off);CHKERRQ(ierr);
3157     varr = &vArray[off];
3158     if (o >= 0) {
3159       for (d = 0; d < dof; ++d, ++offset)    array[offset] = varr[d];
3160     } else {
3161       for (d = dof-1; d >= 0; --d, ++offset) array[offset] = varr[d];
3162     }
3163   }
3164   *size = offset;
3165   PetscFunctionReturn(0);
3166 }
3167 
3168 #undef __FUNCT__
3169 #define __FUNCT__ "DMPlexVecGetClosure_Fields_Static"
3170 PETSC_STATIC_INLINE PetscErrorCode DMPlexVecGetClosure_Fields_Static(PetscSection section, PetscInt numPoints, const PetscInt points[], PetscInt numFields, const PetscScalar vArray[], PetscInt *size, PetscScalar array[])
3171 {
3172   PetscInt       offset = 0, f;
3173   PetscErrorCode ierr;
3174 
3175   PetscFunctionBeginHot;
3176   *size = 0;
3177   for (f = 0; f < numFields; ++f) {
3178     PetscInt fcomp, p;
3179 
3180     ierr = PetscSectionGetFieldComponents(section, f, &fcomp);CHKERRQ(ierr);
3181     for (p = 0; p < numPoints*2; p += 2) {
3182       const PetscInt point = points[p];
3183       const PetscInt o     = points[p+1];
3184       PetscInt       fdof, foff, d, c;
3185       const PetscScalar *varr;
3186 
3187       ierr = PetscSectionGetFieldDof(section, point, f, &fdof);CHKERRQ(ierr);
3188       ierr = PetscSectionGetFieldOffset(section, point, f, &foff);CHKERRQ(ierr);
3189       varr = &vArray[foff];
3190       if (o >= 0) {
3191         for (d = 0; d < fdof; ++d, ++offset) array[offset] = varr[d];
3192       } else {
3193         for (d = fdof/fcomp-1; d >= 0; --d) {
3194           for (c = 0; c < fcomp; ++c, ++offset) {
3195             array[offset] = varr[d*fcomp+c];
3196           }
3197         }
3198       }
3199     }
3200   }
3201   *size = offset;
3202   PetscFunctionReturn(0);
3203 }
3204 
3205 #undef __FUNCT__
3206 #define __FUNCT__ "DMPlexVecGetClosure"
3207 /*@C
3208   DMPlexVecGetClosure - Get an array of the values on the closure of 'point'
3209 
3210   Not collective
3211 
3212   Input Parameters:
3213 + dm - The DM
3214 . section - The section describing the layout in v, or NULL to use the default section
3215 . v - The local vector
3216 - point - The sieve point in the DM
3217 
3218   Output Parameters:
3219 + csize - The number of values in the closure, or NULL
3220 - values - The array of values, which is a borrowed array and should not be freed
3221 
3222   Fortran Notes:
3223   Since it returns an array, this routine is only available in Fortran 90, and you must
3224   include petsc.h90 in your code.
3225 
3226   The csize argument is not present in the Fortran 90 binding since it is internal to the array.
3227 
3228   Level: intermediate
3229 
3230 .seealso DMPlexVecRestoreClosure(), DMPlexVecSetClosure(), DMPlexMatSetClosure()
3231 @*/
3232 PetscErrorCode DMPlexVecGetClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[])
3233 {
3234   PetscSection    clSection;
3235   IS              clPoints;
3236   PetscScalar    *array, *vArray;
3237   PetscInt       *points = NULL;
3238   const PetscInt *clp;
3239   PetscInt        depth, numFields, numPoints, size;
3240   PetscErrorCode  ierr;
3241 
3242   PetscFunctionBeginHot;
3243   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3244   if (!section) {ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);}
3245   PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2);
3246   PetscValidHeaderSpecific(v, VEC_CLASSID, 3);
3247   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3248   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
3249   if (depth == 1 && numFields < 2) {
3250     ierr = DMPlexVecGetClosure_Depth1_Static(dm, section, v, point, csize, values);CHKERRQ(ierr);
3251     PetscFunctionReturn(0);
3252   }
3253   /* Get points */
3254   ierr = PetscSectionGetClosureIndex(section, (PetscObject) dm, &clSection, &clPoints);CHKERRQ(ierr);
3255   if (!clPoints) {
3256     PetscInt pStart, pEnd, p, q;
3257 
3258     ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
3259     ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
3260     /* Compress out points not in the section */
3261     for (p = 0, q = 0; p < numPoints*2; p += 2) {
3262       if ((points[p] >= pStart) && (points[p] < pEnd)) {
3263         points[q*2]   = points[p];
3264         points[q*2+1] = points[p+1];
3265         ++q;
3266       }
3267     }
3268     numPoints = q;
3269   } else {
3270     PetscInt dof, off;
3271 
3272     ierr = PetscSectionGetDof(clSection, point, &dof);CHKERRQ(ierr);
3273     ierr = PetscSectionGetOffset(clSection, point, &off);CHKERRQ(ierr);
3274     ierr = ISGetIndices(clPoints, &clp);CHKERRQ(ierr);
3275     numPoints = dof/2;
3276     points    = (PetscInt *) &clp[off];
3277   }
3278   /* Get array */
3279   if (!values || !*values) {
3280     PetscInt asize = 0, dof, p;
3281 
3282     for (p = 0; p < numPoints*2; p += 2) {
3283       ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
3284       asize += dof;
3285     }
3286     if (!values) {
3287       if (!clPoints) {ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);}
3288       else           {ierr = ISRestoreIndices(clPoints, &clp);CHKERRQ(ierr);}
3289       if (csize) *csize = asize;
3290       PetscFunctionReturn(0);
3291     }
3292     ierr = DMGetWorkArray(dm, asize, PETSC_SCALAR, &array);CHKERRQ(ierr);
3293   } else {
3294     array = *values;
3295   }
3296   ierr = VecGetArray(v, &vArray);CHKERRQ(ierr);
3297   /* Get values */
3298   if (numFields > 0) {ierr = DMPlexVecGetClosure_Fields_Static(section, numPoints, points, numFields, vArray, &size, array);CHKERRQ(ierr);}
3299   else               {ierr = DMPlexVecGetClosure_Static(section, numPoints, points, vArray, &size, array);CHKERRQ(ierr);}
3300   /* Cleanup points */
3301   if (!clPoints) {ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);}
3302   else           {ierr = ISRestoreIndices(clPoints, &clp);CHKERRQ(ierr);}
3303   /* Cleanup array */
3304   ierr = VecRestoreArray(v, &vArray);CHKERRQ(ierr);
3305   if (!*values) {
3306     if (csize) *csize = size;
3307     *values = array;
3308   } else {
3309     if (size > *csize) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %d < actual size %d", *csize, size);
3310     *csize = size;
3311   }
3312   PetscFunctionReturn(0);
3313 }
3314 
3315 #undef __FUNCT__
3316 #define __FUNCT__ "DMPlexVecRestoreClosure"
3317 /*@C
3318   DMPlexVecRestoreClosure - Restore the array of the values on the closure of 'point'
3319 
3320   Not collective
3321 
3322   Input Parameters:
3323 + dm - The DM
3324 . section - The section describing the layout in v, or NULL to use the default section
3325 . v - The local vector
3326 . point - The sieve point in the DM
3327 . csize - The number of values in the closure, or NULL
3328 - values - The array of values, which is a borrowed array and should not be freed
3329 
3330   Fortran Notes:
3331   Since it returns an array, this routine is only available in Fortran 90, and you must
3332   include petsc.h90 in your code.
3333 
3334   The csize argument is not present in the Fortran 90 binding since it is internal to the array.
3335 
3336   Level: intermediate
3337 
3338 .seealso DMPlexVecGetClosure(), DMPlexVecSetClosure(), DMPlexMatSetClosure()
3339 @*/
3340 PetscErrorCode DMPlexVecRestoreClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[])
3341 {
3342   PetscInt       size = 0;
3343   PetscErrorCode ierr;
3344 
3345   PetscFunctionBegin;
3346   /* Should work without recalculating size */
3347   ierr = DMRestoreWorkArray(dm, size, PETSC_SCALAR, (void*) values);CHKERRQ(ierr);
3348   PetscFunctionReturn(0);
3349 }
3350 
3351 PETSC_STATIC_INLINE void add   (PetscScalar *x, PetscScalar y) {*x += y;}
3352 PETSC_STATIC_INLINE void insert(PetscScalar *x, PetscScalar y) {*x  = y;}
3353 
3354 #undef __FUNCT__
3355 #define __FUNCT__ "updatePoint_private"
3356 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[])
3357 {
3358   PetscInt        cdof;   /* The number of constraints on this point */
3359   const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
3360   PetscScalar    *a;
3361   PetscInt        off, cind = 0, k;
3362   PetscErrorCode  ierr;
3363 
3364   PetscFunctionBegin;
3365   ierr = PetscSectionGetConstraintDof(section, point, &cdof);CHKERRQ(ierr);
3366   ierr = PetscSectionGetOffset(section, point, &off);CHKERRQ(ierr);
3367   a    = &array[off];
3368   if (!cdof || setBC) {
3369     if (orientation >= 0) {
3370       for (k = 0; k < dof; ++k) {
3371         fuse(&a[k], values[k]);
3372       }
3373     } else {
3374       for (k = 0; k < dof; ++k) {
3375         fuse(&a[k], values[dof-k-1]);
3376       }
3377     }
3378   } else {
3379     ierr = PetscSectionGetConstraintIndices(section, point, &cdofs);CHKERRQ(ierr);
3380     if (orientation >= 0) {
3381       for (k = 0; k < dof; ++k) {
3382         if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
3383         fuse(&a[k], values[k]);
3384       }
3385     } else {
3386       for (k = 0; k < dof; ++k) {
3387         if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
3388         fuse(&a[k], values[dof-k-1]);
3389       }
3390     }
3391   }
3392   PetscFunctionReturn(0);
3393 }
3394 
3395 #undef __FUNCT__
3396 #define __FUNCT__ "updatePointBC_private"
3397 PETSC_STATIC_INLINE PetscErrorCode updatePointBC_private(PetscSection section, PetscInt point, PetscInt dof, void (*fuse)(PetscScalar*, PetscScalar), PetscInt orientation, const PetscScalar values[], PetscScalar array[])
3398 {
3399   PetscInt        cdof;   /* The number of constraints on this point */
3400   const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
3401   PetscScalar    *a;
3402   PetscInt        off, cind = 0, k;
3403   PetscErrorCode  ierr;
3404 
3405   PetscFunctionBegin;
3406   ierr = PetscSectionGetConstraintDof(section, point, &cdof);CHKERRQ(ierr);
3407   ierr = PetscSectionGetOffset(section, point, &off);CHKERRQ(ierr);
3408   a    = &array[off];
3409   if (cdof) {
3410     ierr = PetscSectionGetConstraintIndices(section, point, &cdofs);CHKERRQ(ierr);
3411     if (orientation >= 0) {
3412       for (k = 0; k < dof; ++k) {
3413         if ((cind < cdof) && (k == cdofs[cind])) {
3414           fuse(&a[k], values[k]);
3415           ++cind;
3416         }
3417       }
3418     } else {
3419       for (k = 0; k < dof; ++k) {
3420         if ((cind < cdof) && (k == cdofs[cind])) {
3421           fuse(&a[k], values[dof-k-1]);
3422           ++cind;
3423         }
3424       }
3425     }
3426   }
3427   PetscFunctionReturn(0);
3428 }
3429 
3430 #undef __FUNCT__
3431 #define __FUNCT__ "updatePointFields_private"
3432 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[])
3433 {
3434   PetscScalar    *a;
3435   PetscInt        fdof, foff, fcdof, foffset = *offset;
3436   const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
3437   PetscInt        cind = 0, k, c;
3438   PetscErrorCode  ierr;
3439 
3440   PetscFunctionBegin;
3441   ierr = PetscSectionGetFieldDof(section, point, f, &fdof);CHKERRQ(ierr);
3442   ierr = PetscSectionGetFieldConstraintDof(section, point, f, &fcdof);CHKERRQ(ierr);
3443   ierr = PetscSectionGetFieldOffset(section, point, f, &foff);CHKERRQ(ierr);
3444   a    = &array[foff];
3445   if (!fcdof || setBC) {
3446     if (o >= 0) {
3447       for (k = 0; k < fdof; ++k) fuse(&a[k], values[foffset+k]);
3448     } else {
3449       for (k = fdof/fcomp-1; k >= 0; --k) {
3450         for (c = 0; c < fcomp; ++c) {
3451           fuse(&a[(fdof/fcomp-1-k)*fcomp+c], values[foffset+k*fcomp+c]);
3452         }
3453       }
3454     }
3455   } else {
3456     ierr = PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);CHKERRQ(ierr);
3457     if (o >= 0) {
3458       for (k = 0; k < fdof; ++k) {
3459         if ((cind < fcdof) && (k == fcdofs[cind])) {++cind; continue;}
3460         fuse(&a[k], values[foffset+k]);
3461       }
3462     } else {
3463       for (k = fdof/fcomp-1; k >= 0; --k) {
3464         for (c = 0; c < fcomp; ++c) {
3465           if ((cind < fcdof) && (k*fcomp+c == fcdofs[cind])) {++cind; continue;}
3466           fuse(&a[(fdof/fcomp-1-k)*fcomp+c], values[foffset+k*fcomp+c]);
3467         }
3468       }
3469     }
3470   }
3471   *offset += fdof;
3472   PetscFunctionReturn(0);
3473 }
3474 
3475 #undef __FUNCT__
3476 #define __FUNCT__ "updatePointFieldsBC_private"
3477 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[])
3478 {
3479   PetscScalar    *a;
3480   PetscInt        fdof, foff, fcdof, foffset = *offset;
3481   const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
3482   PetscInt        cind = 0, k, c;
3483   PetscErrorCode  ierr;
3484 
3485   PetscFunctionBegin;
3486   ierr = PetscSectionGetFieldDof(section, point, f, &fdof);CHKERRQ(ierr);
3487   ierr = PetscSectionGetFieldConstraintDof(section, point, f, &fcdof);CHKERRQ(ierr);
3488   ierr = PetscSectionGetFieldOffset(section, point, f, &foff);CHKERRQ(ierr);
3489   a    = &array[foff];
3490   if (fcdof) {
3491     ierr = PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);CHKERRQ(ierr);
3492     if (o >= 0) {
3493       for (k = 0; k < fdof; ++k) {
3494         if ((cind < fcdof) && (k == fcdofs[cind])) {
3495           fuse(&a[k], values[foffset+k]);
3496           ++cind;
3497         }
3498       }
3499     } else {
3500       for (k = fdof/fcomp-1; k >= 0; --k) {
3501         for (c = 0; c < fcomp; ++c) {
3502           if ((cind < fcdof) && (k*fcomp+c == fcdofs[cind])) {
3503             fuse(&a[(fdof/fcomp-1-k)*fcomp+c], values[foffset+k*fcomp+c]);
3504             ++cind;
3505           }
3506         }
3507       }
3508     }
3509   }
3510   *offset += fdof;
3511   PetscFunctionReturn(0);
3512 }
3513 
3514 #undef __FUNCT__
3515 #define __FUNCT__ "DMPlexVecSetClosure_Static"
3516 PETSC_STATIC_INLINE PetscErrorCode DMPlexVecSetClosure_Static(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode)
3517 {
3518   PetscScalar    *array;
3519   const PetscInt *cone, *coneO;
3520   PetscInt        pStart, pEnd, p, numPoints, off, dof;
3521   PetscErrorCode  ierr;
3522 
3523   PetscFunctionBeginHot;
3524   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
3525   ierr = DMPlexGetConeSize(dm, point, &numPoints);CHKERRQ(ierr);
3526   ierr = DMPlexGetCone(dm, point, &cone);CHKERRQ(ierr);
3527   ierr = DMPlexGetConeOrientation(dm, point, &coneO);CHKERRQ(ierr);
3528   ierr = VecGetArray(v, &array);CHKERRQ(ierr);
3529   for (p = 0, off = 0; p <= numPoints; ++p, off += dof) {
3530     const PetscInt cp = !p ? point : cone[p-1];
3531     const PetscInt o  = !p ? 0     : coneO[p-1];
3532 
3533     if ((cp < pStart) || (cp >= pEnd)) {dof = 0; continue;}
3534     ierr = PetscSectionGetDof(section, cp, &dof);CHKERRQ(ierr);
3535     /* ADD_VALUES */
3536     {
3537       const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
3538       PetscScalar    *a;
3539       PetscInt        cdof, coff, cind = 0, k;
3540 
3541       ierr = PetscSectionGetConstraintDof(section, cp, &cdof);CHKERRQ(ierr);
3542       ierr = PetscSectionGetOffset(section, cp, &coff);CHKERRQ(ierr);
3543       a    = &array[coff];
3544       if (!cdof) {
3545         if (o >= 0) {
3546           for (k = 0; k < dof; ++k) {
3547             a[k] += values[off+k];
3548           }
3549         } else {
3550           for (k = 0; k < dof; ++k) {
3551             a[k] += values[off+dof-k-1];
3552           }
3553         }
3554       } else {
3555         ierr = PetscSectionGetConstraintIndices(section, cp, &cdofs);CHKERRQ(ierr);
3556         if (o >= 0) {
3557           for (k = 0; k < dof; ++k) {
3558             if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
3559             a[k] += values[off+k];
3560           }
3561         } else {
3562           for (k = 0; k < dof; ++k) {
3563             if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
3564             a[k] += values[off+dof-k-1];
3565           }
3566         }
3567       }
3568     }
3569   }
3570   ierr = VecRestoreArray(v, &array);CHKERRQ(ierr);
3571   PetscFunctionReturn(0);
3572 }
3573 
3574 #undef __FUNCT__
3575 #define __FUNCT__ "DMPlexVecSetClosure"
3576 /*@C
3577   DMPlexVecSetClosure - Set an array of the values on the closure of 'point'
3578 
3579   Not collective
3580 
3581   Input Parameters:
3582 + dm - The DM
3583 . section - The section describing the layout in v, or NULL to use the default section
3584 . v - The local vector
3585 . point - The sieve point in the DM
3586 . values - The array of values
3587 - mode - The insert mode, where INSERT_ALL_VALUES and ADD_ALL_VALUES also overwrite boundary conditions
3588 
3589   Fortran Notes:
3590   This routine is only available in Fortran 90, and you must include petsc.h90 in your code.
3591 
3592   Level: intermediate
3593 
3594 .seealso DMPlexVecGetClosure(), DMPlexMatSetClosure()
3595 @*/
3596 PetscErrorCode DMPlexVecSetClosure(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode)
3597 {
3598   PetscSection    clSection;
3599   IS              clPoints;
3600   PetscScalar    *array;
3601   PetscInt       *points = NULL;
3602   const PetscInt *clp;
3603   PetscInt        depth, numFields, numPoints, p;
3604   PetscErrorCode  ierr;
3605 
3606   PetscFunctionBeginHot;
3607   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3608   if (!section) {ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);}
3609   PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2);
3610   PetscValidHeaderSpecific(v, VEC_CLASSID, 3);
3611   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3612   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
3613   if (depth == 1 && numFields < 2 && mode == ADD_VALUES) {
3614     ierr = DMPlexVecSetClosure_Static(dm, section, v, point, values, mode);CHKERRQ(ierr);
3615     PetscFunctionReturn(0);
3616   }
3617   /* Get points */
3618   ierr = PetscSectionGetClosureIndex(section, (PetscObject) dm, &clSection, &clPoints);CHKERRQ(ierr);
3619   if (!clPoints) {
3620     PetscInt pStart, pEnd, q;
3621 
3622     ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
3623     ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
3624     /* Compress out points not in the section */
3625     for (p = 0, q = 0; p < numPoints*2; p += 2) {
3626       if ((points[p] >= pStart) && (points[p] < pEnd)) {
3627         points[q*2]   = points[p];
3628         points[q*2+1] = points[p+1];
3629         ++q;
3630       }
3631     }
3632     numPoints = q;
3633   } else {
3634     PetscInt dof, off;
3635 
3636     ierr = PetscSectionGetDof(clSection, point, &dof);CHKERRQ(ierr);
3637     ierr = PetscSectionGetOffset(clSection, point, &off);CHKERRQ(ierr);
3638     ierr = ISGetIndices(clPoints, &clp);CHKERRQ(ierr);
3639     numPoints = dof/2;
3640     points    = (PetscInt *) &clp[off];
3641   }
3642   /* Get array */
3643   ierr = VecGetArray(v, &array);CHKERRQ(ierr);
3644   /* Get values */
3645   if (numFields > 0) {
3646     PetscInt offset = 0, fcomp, f;
3647     for (f = 0; f < numFields; ++f) {
3648       ierr = PetscSectionGetFieldComponents(section, f, &fcomp);CHKERRQ(ierr);
3649       switch (mode) {
3650       case INSERT_VALUES:
3651         for (p = 0; p < numPoints*2; p += 2) {
3652           const PetscInt point = points[p];
3653           const PetscInt o     = points[p+1];
3654           updatePointFields_private(section, point, o, f, fcomp, insert, PETSC_FALSE, values, &offset, array);
3655         } break;
3656       case INSERT_ALL_VALUES:
3657         for (p = 0; p < numPoints*2; p += 2) {
3658           const PetscInt point = points[p];
3659           const PetscInt o     = points[p+1];
3660           updatePointFields_private(section, point, o, f, fcomp, insert, PETSC_TRUE, values, &offset, array);
3661         } break;
3662       case INSERT_BC_VALUES:
3663         for (p = 0; p < numPoints*2; p += 2) {
3664           const PetscInt point = points[p];
3665           const PetscInt o     = points[p+1];
3666           updatePointFieldsBC_private(section, point, o, f, fcomp, insert, values, &offset, array);
3667         } break;
3668       case ADD_VALUES:
3669         for (p = 0; p < numPoints*2; p += 2) {
3670           const PetscInt point = points[p];
3671           const PetscInt o     = points[p+1];
3672           updatePointFields_private(section, point, o, f, fcomp, add, PETSC_FALSE, values, &offset, array);
3673         } break;
3674       case ADD_ALL_VALUES:
3675         for (p = 0; p < numPoints*2; p += 2) {
3676           const PetscInt point = points[p];
3677           const PetscInt o     = points[p+1];
3678           updatePointFields_private(section, point, o, f, fcomp, add, PETSC_TRUE, values, &offset, array);
3679         } break;
3680       default:
3681         SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %D", mode);
3682       }
3683     }
3684   } else {
3685     PetscInt dof, off;
3686 
3687     switch (mode) {
3688     case INSERT_VALUES:
3689       for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) {
3690         PetscInt o = points[p+1];
3691         ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
3692         updatePoint_private(section, points[p], dof, insert, PETSC_FALSE, o, &values[off], array);
3693       } break;
3694     case INSERT_ALL_VALUES:
3695       for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) {
3696         PetscInt o = points[p+1];
3697         ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
3698         updatePoint_private(section, points[p], dof, insert, PETSC_TRUE,  o, &values[off], array);
3699       } break;
3700     case INSERT_BC_VALUES:
3701       for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) {
3702         PetscInt o = points[p+1];
3703         ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
3704         updatePointBC_private(section, points[p], dof, insert,  o, &values[off], array);
3705       } break;
3706     case ADD_VALUES:
3707       for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) {
3708         PetscInt o = points[p+1];
3709         ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
3710         updatePoint_private(section, points[p], dof, add,    PETSC_FALSE, o, &values[off], array);
3711       } break;
3712     case ADD_ALL_VALUES:
3713       for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) {
3714         PetscInt o = points[p+1];
3715         ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
3716         updatePoint_private(section, points[p], dof, add,    PETSC_TRUE,  o, &values[off], array);
3717       } break;
3718     default:
3719       SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %D", mode);
3720     }
3721   }
3722   /* Cleanup points */
3723   if (!clPoints) {ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);}
3724   else           {ierr = ISRestoreIndices(clPoints, &clp);CHKERRQ(ierr);}
3725   /* Cleanup array */
3726   ierr = VecRestoreArray(v, &array);CHKERRQ(ierr);
3727   PetscFunctionReturn(0);
3728 }
3729 
3730 #undef __FUNCT__
3731 #define __FUNCT__ "DMPlexVecSetFieldClosure_Internal"
3732 PetscErrorCode DMPlexVecSetFieldClosure_Internal(DM dm, PetscSection section, Vec v, PetscBool fieldActive[], PetscInt point, const PetscScalar values[], InsertMode mode)
3733 {
3734   PetscSection    clSection;
3735   IS              clPoints;
3736   PetscScalar    *array;
3737   PetscInt       *points = NULL;
3738   const PetscInt *clp;
3739   PetscInt        numFields, numPoints, p;
3740   PetscInt        offset = 0, fcomp, f;
3741   PetscErrorCode  ierr;
3742 
3743   PetscFunctionBeginHot;
3744   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3745   if (!section) {ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);}
3746   PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2);
3747   PetscValidHeaderSpecific(v, VEC_CLASSID, 3);
3748   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
3749   /* Get points */
3750   ierr = PetscSectionGetClosureIndex(section, (PetscObject) dm, &clSection, &clPoints);CHKERRQ(ierr);
3751   if (!clPoints) {
3752     PetscInt pStart, pEnd, q;
3753 
3754     ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
3755     ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
3756     /* Compress out points not in the section */
3757     for (p = 0, q = 0; p < numPoints*2; p += 2) {
3758       if ((points[p] >= pStart) && (points[p] < pEnd)) {
3759         points[q*2]   = points[p];
3760         points[q*2+1] = points[p+1];
3761         ++q;
3762       }
3763     }
3764     numPoints = q;
3765   } else {
3766     PetscInt dof, off;
3767 
3768     ierr = PetscSectionGetDof(clSection, point, &dof);CHKERRQ(ierr);
3769     ierr = PetscSectionGetOffset(clSection, point, &off);CHKERRQ(ierr);
3770     ierr = ISGetIndices(clPoints, &clp);CHKERRQ(ierr);
3771     numPoints = dof/2;
3772     points    = (PetscInt *) &clp[off];
3773   }
3774   /* Get array */
3775   ierr = VecGetArray(v, &array);CHKERRQ(ierr);
3776   /* Get values */
3777   for (f = 0; f < numFields; ++f) {
3778     ierr = PetscSectionGetFieldComponents(section, f, &fcomp);CHKERRQ(ierr);
3779     if (!fieldActive[f]) {
3780       for (p = 0; p < numPoints*2; p += 2) {
3781         PetscInt fdof;
3782         ierr = PetscSectionGetFieldDof(section, points[p], f, &fdof);CHKERRQ(ierr);
3783         offset += fdof;
3784       }
3785       continue;
3786     }
3787     switch (mode) {
3788     case INSERT_VALUES:
3789       for (p = 0; p < numPoints*2; p += 2) {
3790         const PetscInt point = points[p];
3791         const PetscInt o     = points[p+1];
3792         updatePointFields_private(section, point, o, f, fcomp, insert, PETSC_FALSE, values, &offset, array);
3793       } break;
3794     case INSERT_ALL_VALUES:
3795       for (p = 0; p < numPoints*2; p += 2) {
3796         const PetscInt point = points[p];
3797         const PetscInt o     = points[p+1];
3798         updatePointFields_private(section, point, o, f, fcomp, insert, PETSC_TRUE, values, &offset, array);
3799         } break;
3800     case INSERT_BC_VALUES:
3801       for (p = 0; p < numPoints*2; p += 2) {
3802         const PetscInt point = points[p];
3803         const PetscInt o     = points[p+1];
3804         updatePointFieldsBC_private(section, point, o, f, fcomp, insert, values, &offset, array);
3805       } break;
3806     case ADD_VALUES:
3807       for (p = 0; p < numPoints*2; p += 2) {
3808         const PetscInt point = points[p];
3809         const PetscInt o     = points[p+1];
3810         updatePointFields_private(section, point, o, f, fcomp, add, PETSC_FALSE, values, &offset, array);
3811       } break;
3812     case ADD_ALL_VALUES:
3813       for (p = 0; p < numPoints*2; p += 2) {
3814         const PetscInt point = points[p];
3815         const PetscInt o     = points[p+1];
3816         updatePointFields_private(section, point, o, f, fcomp, add, PETSC_TRUE, values, &offset, array);
3817       } break;
3818     default:
3819       SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %D", mode);
3820     }
3821   }
3822   /* Cleanup points */
3823   if (!clPoints) {ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);}
3824   else           {ierr = ISRestoreIndices(clPoints, &clp);CHKERRQ(ierr);}
3825   /* Cleanup array */
3826   ierr = VecRestoreArray(v, &array);CHKERRQ(ierr);
3827   PetscFunctionReturn(0);
3828 }
3829 
3830 #undef __FUNCT__
3831 #define __FUNCT__ "DMPlexPrintMatSetValues"
3832 PetscErrorCode DMPlexPrintMatSetValues(PetscViewer viewer, Mat A, PetscInt point, PetscInt numRIndices, const PetscInt rindices[], PetscInt numCIndices, const PetscInt cindices[], const PetscScalar values[])
3833 {
3834   PetscMPIInt    rank;
3835   PetscInt       i, j;
3836   PetscErrorCode ierr;
3837 
3838   PetscFunctionBegin;
3839   ierr = MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank);CHKERRQ(ierr);
3840   ierr = PetscViewerASCIIPrintf(viewer, "[%D]mat for sieve point %D\n", rank, point);CHKERRQ(ierr);
3841   for (i = 0; i < numRIndices; i++) {ierr = PetscViewerASCIIPrintf(viewer, "[%D]mat row indices[%D] = %D\n", rank, i, rindices[i]);CHKERRQ(ierr);}
3842   for (i = 0; i < numCIndices; i++) {ierr = PetscViewerASCIIPrintf(viewer, "[%D]mat col indices[%D] = %D\n", rank, i, cindices[i]);CHKERRQ(ierr);}
3843   numCIndices = numCIndices ? numCIndices : numRIndices;
3844   for (i = 0; i < numRIndices; i++) {
3845     ierr = PetscViewerASCIIPrintf(viewer, "[%D]", rank);CHKERRQ(ierr);
3846     for (j = 0; j < numCIndices; j++) {
3847 #if defined(PETSC_USE_COMPLEX)
3848       ierr = PetscViewerASCIIPrintf(viewer, " (%g,%g)", (double)PetscRealPart(values[i*numCIndices+j]), (double)PetscImaginaryPart(values[i*numCIndices+j]));CHKERRQ(ierr);
3849 #else
3850       ierr = PetscViewerASCIIPrintf(viewer, " %g", (double)values[i*numCIndices+j]);CHKERRQ(ierr);
3851 #endif
3852     }
3853     ierr = PetscViewerASCIIPrintf(viewer, "\n");CHKERRQ(ierr);
3854   }
3855   PetscFunctionReturn(0);
3856 }
3857 
3858 #undef __FUNCT__
3859 #define __FUNCT__ "indicesPoint_private"
3860 /* . off - The global offset of this point */
3861 PetscErrorCode indicesPoint_private(PetscSection section, PetscInt point, PetscInt off, PetscInt *loff, PetscBool setBC, PetscInt orientation, PetscInt indices[])
3862 {
3863   PetscInt        dof;    /* The number of unknowns on this point */
3864   PetscInt        cdof;   /* The number of constraints on this point */
3865   const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
3866   PetscInt        cind = 0, k;
3867   PetscErrorCode  ierr;
3868 
3869   PetscFunctionBegin;
3870   ierr = PetscSectionGetDof(section, point, &dof);CHKERRQ(ierr);
3871   ierr = PetscSectionGetConstraintDof(section, point, &cdof);CHKERRQ(ierr);
3872   if (!cdof || setBC) {
3873     if (orientation >= 0) {
3874       for (k = 0; k < dof; ++k) indices[*loff+k] = off+k;
3875     } else {
3876       for (k = 0; k < dof; ++k) indices[*loff+dof-k-1] = off+k;
3877     }
3878   } else {
3879     ierr = PetscSectionGetConstraintIndices(section, point, &cdofs);CHKERRQ(ierr);
3880     if (orientation >= 0) {
3881       for (k = 0; k < dof; ++k) {
3882         if ((cind < cdof) && (k == cdofs[cind])) {
3883           /* Insert check for returning constrained indices */
3884           indices[*loff+k] = -(off+k+1);
3885           ++cind;
3886         } else {
3887           indices[*loff+k] = off+k-cind;
3888         }
3889       }
3890     } else {
3891       for (k = 0; k < dof; ++k) {
3892         if ((cind < cdof) && (k == cdofs[cind])) {
3893           /* Insert check for returning constrained indices */
3894           indices[*loff+dof-k-1] = -(off+k+1);
3895           ++cind;
3896         } else {
3897           indices[*loff+dof-k-1] = off+k-cind;
3898         }
3899       }
3900     }
3901   }
3902   *loff += dof;
3903   PetscFunctionReturn(0);
3904 }
3905 
3906 #undef __FUNCT__
3907 #define __FUNCT__ "indicesPointFields_private"
3908 /* . off - The global offset of this point */
3909 PetscErrorCode indicesPointFields_private(PetscSection section, PetscInt point, PetscInt off, PetscInt foffs[], PetscBool setBC, PetscInt orientation, PetscInt indices[])
3910 {
3911   PetscInt       numFields, foff, f;
3912   PetscErrorCode ierr;
3913 
3914   PetscFunctionBegin;
3915   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
3916   for (f = 0, foff = 0; f < numFields; ++f) {
3917     PetscInt        fdof, fcomp, cfdof;
3918     const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
3919     PetscInt        cind = 0, k, c;
3920 
3921     ierr = PetscSectionGetFieldComponents(section, f, &fcomp);CHKERRQ(ierr);
3922     ierr = PetscSectionGetFieldDof(section, point, f, &fdof);CHKERRQ(ierr);
3923     ierr = PetscSectionGetFieldConstraintDof(section, point, f, &cfdof);CHKERRQ(ierr);
3924     if (!cfdof || setBC) {
3925       if (orientation >= 0) {
3926         for (k = 0; k < fdof; ++k) indices[foffs[f]+k] = off+foff+k;
3927       } else {
3928         for (k = fdof/fcomp-1; k >= 0; --k) {
3929           for (c = 0; c < fcomp; ++c) {
3930             indices[foffs[f]+k*fcomp+c] = off+foff+(fdof/fcomp-1-k)*fcomp+c;
3931           }
3932         }
3933       }
3934     } else {
3935       ierr = PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);CHKERRQ(ierr);
3936       if (orientation >= 0) {
3937         for (k = 0; k < fdof; ++k) {
3938           if ((cind < cfdof) && (k == fcdofs[cind])) {
3939             indices[foffs[f]+k] = -(off+foff+k+1);
3940             ++cind;
3941           } else {
3942             indices[foffs[f]+k] = off+foff+k-cind;
3943           }
3944         }
3945       } else {
3946         for (k = fdof/fcomp-1; k >= 0; --k) {
3947           for (c = 0; c < fcomp; ++c) {
3948             if ((cind < cfdof) && ((fdof/fcomp-1-k)*fcomp+c == fcdofs[cind])) {
3949               indices[foffs[f]+k*fcomp+c] = -(off+foff+(fdof/fcomp-1-k)*fcomp+c+1);
3950               ++cind;
3951             } else {
3952               indices[foffs[f]+k*fcomp+c] = off+foff+(fdof/fcomp-1-k)*fcomp+c-cind;
3953             }
3954           }
3955         }
3956       }
3957     }
3958     foff     += fdof - cfdof;
3959     foffs[f] += fdof;
3960   }
3961   PetscFunctionReturn(0);
3962 }
3963 
3964 #undef __FUNCT__
3965 #define __FUNCT__ "DMPlexAnchorsModifyMat"
3966 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[])
3967 {
3968   Mat             cMat;
3969   PetscSection    aSec, cSec;
3970   IS              aIS;
3971   PetscInt        aStart = -1, aEnd = -1;
3972   const PetscInt  *anchors;
3973   PetscInt        numFields, f, p, q, newP = 0;
3974   PetscInt        newNumPoints = 0, newNumIndices = 0;
3975   PetscInt        *newPoints, *indices, *newIndices;
3976   PetscInt        maxAnchor, maxDof;
3977   PetscInt        newOffsets[32];
3978   PetscInt        *pointMatOffsets[32];
3979   PetscInt        *newPointOffsets[32];
3980   PetscScalar     *pointMat[32];
3981   PetscScalar     *newValues,*tmpValues;
3982   PetscBool       anyConstrained = PETSC_FALSE;
3983   PetscErrorCode  ierr;
3984 
3985   PetscFunctionBegin;
3986   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3987   PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2);
3988   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
3989 
3990   ierr = DMPlexGetAnchors(dm,&aSec,&aIS);CHKERRQ(ierr);
3991   /* if there are point-to-point constraints */
3992   if (aSec) {
3993     ierr = PetscMemzero(newOffsets, 32 * sizeof(PetscInt));CHKERRQ(ierr);
3994     ierr = ISGetIndices(aIS,&anchors);CHKERRQ(ierr);
3995     ierr = PetscSectionGetChart(aSec,&aStart,&aEnd);CHKERRQ(ierr);
3996     /* figure out how many points are going to be in the new element matrix
3997      * (we allow double counting, because it's all just going to be summed
3998      * into the global matrix anyway) */
3999     for (p = 0; p < 2*numPoints; p+=2) {
4000       PetscInt b    = points[p];
4001       PetscInt bDof = 0;
4002 
4003       if (b >= aStart && b < aEnd) {
4004         ierr = PetscSectionGetDof(aSec,b,&bDof);CHKERRQ(ierr);
4005       }
4006       if (bDof) {
4007         /* this point is constrained */
4008         /* it is going to be replaced by its anchors */
4009         PetscInt bOff, q;
4010 
4011         anyConstrained = PETSC_TRUE;
4012         newNumPoints  += bDof;
4013         ierr = PetscSectionGetOffset(aSec,b,&bOff);CHKERRQ(ierr);
4014         for (q = 0; q < bDof; q++) {
4015           PetscInt a = anchors[bOff + q];
4016           PetscInt aDof;
4017 
4018           ierr           = PetscSectionGetDof(section,a,&aDof);CHKERRQ(ierr);
4019           newNumIndices += aDof;
4020           for (f = 0; f < numFields; ++f) {
4021             PetscInt fDof;
4022 
4023             ierr             = PetscSectionGetFieldDof(section, a, f, &fDof);CHKERRQ(ierr);
4024             newOffsets[f+1] += fDof;
4025           }
4026         }
4027       }
4028       else {
4029         /* this point is not constrained */
4030         newNumPoints++;
4031         ierr           = PetscSectionGetDof(section,b,&bDof);CHKERRQ(ierr);
4032         newNumIndices += bDof;
4033         for (f = 0; f < numFields; ++f) {
4034           PetscInt fDof;
4035 
4036           ierr = PetscSectionGetFieldDof(section, b, f, &fDof);CHKERRQ(ierr);
4037           newOffsets[f+1] += fDof;
4038         }
4039       }
4040     }
4041   }
4042   if (!anyConstrained) {
4043     *outNumPoints  = 0;
4044     *outNumIndices = 0;
4045     *outPoints     = NULL;
4046     *outValues     = NULL;
4047     if (aSec) {
4048       ierr = ISRestoreIndices(aIS,&anchors);CHKERRQ(ierr);
4049     }
4050     PetscFunctionReturn(0);
4051   }
4052 
4053   for (f = 1; f < numFields; ++f) newOffsets[f+1] += newOffsets[f];
4054 
4055   if (numFields && newOffsets[numFields] != newNumIndices) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid size for closure %d should be %d", newOffsets[numFields], newNumIndices);
4056 
4057   ierr = DMGetDefaultConstraints(dm, &cSec, &cMat);CHKERRQ(ierr);
4058 
4059   /* output arrays */
4060   ierr = DMGetWorkArray(dm,2*newNumPoints,PETSC_INT,&newPoints);CHKERRQ(ierr);
4061   ierr = DMGetWorkArray(dm,newNumIndices*newNumIndices,PETSC_SCALAR,&newValues);CHKERRQ(ierr);
4062 
4063   /* workspaces */
4064   ierr = DMGetWorkArray(dm,newNumIndices*numIndices,PETSC_SCALAR,&tmpValues);CHKERRQ(ierr);
4065   if (numFields) {
4066     for (f = 0; f < numFields; f++) {
4067       ierr = DMGetWorkArray(dm,numPoints+1,PETSC_INT,&pointMatOffsets[f]);CHKERRQ(ierr);
4068       ierr = DMGetWorkArray(dm,numPoints+1,PETSC_INT,&newPointOffsets[f]);CHKERRQ(ierr);
4069     }
4070   }
4071   else {
4072     ierr = DMGetWorkArray(dm,numPoints+1,PETSC_INT,&pointMatOffsets[0]);CHKERRQ(ierr);
4073     ierr = DMGetWorkArray(dm,numPoints,PETSC_INT,&newPointOffsets[0]);CHKERRQ(ierr);
4074   }
4075 
4076   /* get workspaces for the point-to-point matrices */
4077   if (numFields) {
4078     for (p = 0; p < numPoints; p++) {
4079       PetscInt b    = points[2*p];
4080       PetscInt bDof = 0;
4081 
4082       if (b >= aStart && b < aEnd) {
4083         ierr = PetscSectionGetDof(aSec, b, &bDof);CHKERRQ(ierr);
4084       }
4085       if (bDof) {
4086         for (f = 0; f < numFields; f++) {
4087           PetscInt fDof, q, bOff, allFDof = 0;
4088 
4089           ierr = PetscSectionGetFieldDof(section, b, f, &fDof);CHKERRQ(ierr);
4090           ierr = PetscSectionGetOffset(aSec, b, &bOff);CHKERRQ(ierr);
4091           for (q = 0; q < bDof; q++) {
4092             PetscInt a = anchors[bOff + q];
4093             PetscInt aFDof;
4094 
4095             ierr     = PetscSectionGetFieldDof(section, a, f, &aFDof);CHKERRQ(ierr);
4096             allFDof += aFDof;
4097           }
4098           newPointOffsets[f][p+1] = allFDof;
4099           pointMatOffsets[f][p+1] = fDof * allFDof;
4100         }
4101       }
4102       else {
4103         for (f = 0; f < numFields; f++) {
4104           PetscInt fDof;
4105 
4106           ierr = PetscSectionGetFieldDof(section, b, f, &fDof);CHKERRQ(ierr);
4107           newPointOffsets[f][p+1] = fDof;
4108           pointMatOffsets[f][p+1] = 0;
4109         }
4110       }
4111     }
4112     for (f = 0; f < numFields; f++) {
4113       newPointOffsets[f][0] = 0;
4114       pointMatOffsets[f][0] = 0;
4115       for (p = 0; p < numPoints; p++) {
4116         newPointOffsets[f][p+1] += newPointOffsets[f][p];
4117         pointMatOffsets[f][p+1] += pointMatOffsets[f][p];
4118       }
4119       ierr = DMGetWorkArray(dm,pointMatOffsets[f][numPoints],PETSC_SCALAR,&pointMat[f]);CHKERRQ(ierr);
4120     }
4121   }
4122   else {
4123     for (p = 0; p < numPoints; p++) {
4124       PetscInt b    = points[2*p];
4125       PetscInt bDof = 0;
4126 
4127       if (b >= aStart && b < aEnd) {
4128         ierr = PetscSectionGetDof(aSec, b, &bDof);CHKERRQ(ierr);
4129       }
4130       if (bDof) {
4131         PetscInt dof, bOff, q, allDof = 0;
4132 
4133         ierr = PetscSectionGetDof(section, b, &dof);CHKERRQ(ierr);
4134         ierr = PetscSectionGetOffset(aSec, b, &bOff);CHKERRQ(ierr);
4135         for (q = 0; q < bDof; q++) {
4136           PetscInt a = anchors[bOff + q], aDof;
4137 
4138           ierr    = PetscSectionGetDof(section, a, &aDof);CHKERRQ(ierr);
4139           allDof += aDof;
4140         }
4141         newPointOffsets[0][p+1] = allDof;
4142         pointMatOffsets[0][p+1] = dof * allDof;
4143       }
4144       else {
4145         PetscInt dof;
4146 
4147         ierr = PetscSectionGetDof(section, b, &dof);CHKERRQ(ierr);
4148         newPointOffsets[0][p+1] = dof;
4149         pointMatOffsets[0][p+1] = 0;
4150       }
4151     }
4152     newPointOffsets[0][0] = 0;
4153     pointMatOffsets[0][0] = 0;
4154     for (p = 0; p < numPoints; p++) {
4155       newPointOffsets[0][p+1] += newPointOffsets[0][p];
4156       pointMatOffsets[0][p+1] += pointMatOffsets[0][p];
4157     }
4158     ierr = DMGetWorkArray(dm,pointMatOffsets[0][numPoints],PETSC_SCALAR,&pointMat[0]);CHKERRQ(ierr);
4159   }
4160 
4161   /* get the point-to-point matrices; construct newPoints */
4162   ierr = PetscSectionGetMaxDof(aSec, &maxAnchor);CHKERRQ(ierr);
4163   ierr = PetscSectionGetMaxDof(section, &maxDof);CHKERRQ(ierr);
4164   ierr = DMGetWorkArray(dm,maxDof,PETSC_INT,&indices);CHKERRQ(ierr);
4165   ierr = DMGetWorkArray(dm,maxAnchor*maxDof,PETSC_INT,&newIndices);CHKERRQ(ierr);
4166   if (numFields) {
4167     for (p = 0, newP = 0; p < numPoints; p++) {
4168       PetscInt b    = points[2*p];
4169       PetscInt o    = points[2*p+1];
4170       PetscInt bDof = 0;
4171 
4172       if (b >= aStart && b < aEnd) {
4173         ierr = PetscSectionGetDof(aSec, b, &bDof);CHKERRQ(ierr);
4174       }
4175       if (bDof) {
4176         PetscInt fStart[32], fEnd[32], fAnchorStart[32], fAnchorEnd[32], bOff, q;
4177 
4178         fStart[0] = 0;
4179         fEnd[0]   = 0;
4180         for (f = 0; f < numFields; f++) {
4181           PetscInt fDof;
4182 
4183           ierr        = PetscSectionGetFieldDof(cSec, b, f, &fDof);CHKERRQ(ierr);
4184           fStart[f+1] = fStart[f] + fDof;
4185           fEnd[f+1]   = fStart[f+1];
4186         }
4187         ierr = PetscSectionGetOffset(cSec, b, &bOff);CHKERRQ(ierr);
4188         ierr = indicesPointFields_private(cSec, b, bOff, fEnd, PETSC_TRUE, o, indices);CHKERRQ(ierr);
4189 
4190         fAnchorStart[0] = 0;
4191         fAnchorEnd[0]   = 0;
4192         for (f = 0; f < numFields; f++) {
4193           PetscInt fDof = newPointOffsets[f][p + 1] - newPointOffsets[f][p];
4194 
4195           fAnchorStart[f+1] = fAnchorStart[f] + fDof;
4196           fAnchorEnd[f+1]   = fAnchorStart[f + 1];
4197         }
4198         ierr = PetscSectionGetOffset (aSec, b, &bOff);CHKERRQ(ierr);
4199         for (q = 0; q < bDof; q++) {
4200           PetscInt a = anchors[bOff + q], aOff;
4201 
4202           /* we take the orientation of ap into account in the order that we constructed the indices above: the newly added points have no orientation */
4203           newPoints[2*(newP + q)]     = a;
4204           newPoints[2*(newP + q) + 1] = 0;
4205           ierr = PetscSectionGetOffset(section, a, &aOff);
4206           ierr = indicesPointFields_private(section, a, aOff, fAnchorEnd, PETSC_TRUE, 0, newIndices);CHKERRQ(ierr);
4207         }
4208         newP += bDof;
4209 
4210         /* get the point-to-point submatrix */
4211         for (f = 0; f < numFields; f++) {
4212           ierr = MatGetValues(cMat,fEnd[f]-fStart[f],indices + fStart[f],fAnchorEnd[f] - fAnchorStart[f],newIndices + fAnchorStart[f],pointMat[f] + pointMatOffsets[f][p]);CHKERRQ(ierr);
4213         }
4214       }
4215       else {
4216         newPoints[2 * newP]     = b;
4217         newPoints[2 * newP + 1] = o;
4218         newP++;
4219       }
4220     }
4221   } else {
4222     for (p = 0; p < numPoints; p++) {
4223       PetscInt b    = points[2*p];
4224       PetscInt o    = points[2*p+1];
4225       PetscInt bDof = 0;
4226 
4227       if (b >= aStart && b < aEnd) {
4228         ierr = PetscSectionGetDof(aSec, b, &bDof);CHKERRQ(ierr);
4229       }
4230       if (bDof) {
4231         PetscInt bEnd = 0, bAnchorEnd = 0, bOff;
4232 
4233         ierr = PetscSectionGetOffset(cSec, b, &bOff);CHKERRQ(ierr);
4234         ierr = indicesPoint_private(cSec, b, bOff, &bEnd, PETSC_TRUE, o, indices);CHKERRQ(ierr);
4235 
4236         ierr = PetscSectionGetOffset (aSec, b, &bOff);CHKERRQ(ierr);
4237         for (q = 0; q < bDof; q++) {
4238           PetscInt a = anchors[bOff + q], aOff;
4239 
4240           /* we take the orientation of ap into account in the order that we constructed the indices above: the newly added points have no orientation */
4241 
4242           newPoints[2*(newP + q)]     = a;
4243           newPoints[2*(newP + q) + 1] = 0;
4244           ierr = PetscSectionGetOffset(section, a, &aOff);
4245           ierr = indicesPoint_private(section, a, aOff, &bAnchorEnd, PETSC_TRUE, 0, newIndices);CHKERRQ(ierr);
4246         }
4247         newP += bDof;
4248 
4249         /* get the point-to-point submatrix */
4250         ierr = MatGetValues(cMat,bEnd,indices,bAnchorEnd,newIndices,pointMat[0] + pointMatOffsets[0][p]);CHKERRQ(ierr);
4251       }
4252       else {
4253         newPoints[2 * newP]     = b;
4254         newPoints[2 * newP + 1] = o;
4255         newP++;
4256       }
4257     }
4258   }
4259 
4260   ierr = PetscMemzero(tmpValues,newNumIndices*numIndices*sizeof(*tmpValues));CHKERRQ(ierr);
4261   /* multiply constraints on the right */
4262   if (numFields) {
4263     for (f = 0; f < numFields; f++) {
4264       PetscInt oldOff = offsets[f];
4265 
4266       for (p = 0; p < numPoints; p++) {
4267         PetscInt cStart = newPointOffsets[f][p];
4268         PetscInt b      = points[2 * p];
4269         PetscInt c, r, k;
4270         PetscInt dof;
4271 
4272         ierr = PetscSectionGetFieldDof(section,b,f,&dof);CHKERRQ(ierr);
4273         if (pointMatOffsets[f][p] < pointMatOffsets[f][p + 1]) {
4274           PetscInt nCols         = newPointOffsets[f][p+1]-cStart;
4275           const PetscScalar *mat = pointMat[f] + pointMatOffsets[f][p];
4276 
4277           for (r = 0; r < numIndices; r++) {
4278             for (c = 0; c < nCols; c++) {
4279               for (k = 0; k < dof; k++) {
4280                 tmpValues[r * newNumIndices + cStart + c] += mat[k * nCols + c] * values[r * numIndices + oldOff + k];
4281               }
4282             }
4283           }
4284         }
4285         else {
4286           /* copy this column as is */
4287           for (r = 0; r < numIndices; r++) {
4288             for (c = 0; c < dof; c++) {
4289               tmpValues[r * newNumIndices + cStart + c] = values[r * numIndices + oldOff + c];
4290             }
4291           }
4292         }
4293         oldOff += dof;
4294       }
4295     }
4296   }
4297   else {
4298     PetscInt oldOff = 0;
4299     for (p = 0; p < numPoints; p++) {
4300       PetscInt cStart = newPointOffsets[0][p];
4301       PetscInt b      = points[2 * p];
4302       PetscInt c, r, k;
4303       PetscInt dof;
4304 
4305       ierr = PetscSectionGetDof(section,b,&dof);CHKERRQ(ierr);
4306       if (pointMatOffsets[0][p] < pointMatOffsets[0][p + 1]) {
4307         PetscInt nCols         = newPointOffsets[0][p+1]-cStart;
4308         const PetscScalar *mat = pointMat[0] + pointMatOffsets[0][p];
4309 
4310         for (r = 0; r < numIndices; r++) {
4311           for (c = 0; c < nCols; c++) {
4312             for (k = 0; k < dof; k++) {
4313               tmpValues[r * newNumIndices + cStart + c] += mat[k * nCols + c] * values[r * numIndices + oldOff + k];
4314             }
4315           }
4316         }
4317       }
4318       else {
4319         /* copy this column as is */
4320         for (r = 0; r < numIndices; r++) {
4321           for (c = 0; c < dof; c++) {
4322             tmpValues[r * newNumIndices + cStart + c] = values[r * numIndices + oldOff + c];
4323           }
4324         }
4325       }
4326       oldOff += dof;
4327     }
4328   }
4329 
4330   ierr = PetscMemzero(newValues,newNumIndices*newNumIndices*sizeof(*newValues));CHKERRQ(ierr);
4331   /* multiply constraints transpose on the left */
4332   if (numFields) {
4333     for (f = 0; f < numFields; f++) {
4334       PetscInt oldOff = offsets[f];
4335 
4336       for (p = 0; p < numPoints; p++) {
4337         PetscInt rStart = newPointOffsets[f][p];
4338         PetscInt b      = points[2 * p];
4339         PetscInt c, r, k;
4340         PetscInt dof;
4341 
4342         ierr = PetscSectionGetFieldDof(section,b,f,&dof);CHKERRQ(ierr);
4343         if (pointMatOffsets[f][p] < pointMatOffsets[f][p + 1]) {
4344           PetscInt nRows                        = newPointOffsets[f][p+1]-rStart;
4345           const PetscScalar *PETSC_RESTRICT mat = pointMat[f] + pointMatOffsets[f][p];
4346 
4347           for (r = 0; r < nRows; r++) {
4348             for (c = 0; c < newNumIndices; c++) {
4349               for (k = 0; k < dof; k++) {
4350                 newValues[(rStart + r) * newNumIndices + c] += mat[k * nRows + r] * tmpValues[(oldOff + k) * newNumIndices + c];
4351               }
4352             }
4353           }
4354         }
4355         else {
4356           /* copy this row as is */
4357           for (r = 0; r < dof; r++) {
4358             for (c = 0; c < newNumIndices; c++) {
4359               newValues[(rStart + r) * newNumIndices + c] = tmpValues[(oldOff + r) * newNumIndices + c];
4360             }
4361           }
4362         }
4363         oldOff += dof;
4364       }
4365     }
4366   }
4367   else {
4368     PetscInt oldOff = 0;
4369 
4370     for (p = 0; p < numPoints; p++) {
4371       PetscInt rStart = newPointOffsets[0][p];
4372       PetscInt b      = points[2 * p];
4373       PetscInt c, r, k;
4374       PetscInt dof;
4375 
4376       ierr = PetscSectionGetDof(section,b,&dof);CHKERRQ(ierr);
4377       if (pointMatOffsets[0][p] < pointMatOffsets[0][p + 1]) {
4378         PetscInt nRows                        = newPointOffsets[0][p+1]-rStart;
4379         const PetscScalar *PETSC_RESTRICT mat = pointMat[0] + pointMatOffsets[0][p];
4380 
4381         for (r = 0; r < nRows; r++) {
4382           for (c = 0; c < newNumIndices; c++) {
4383             for (k = 0; k < dof; k++) {
4384               newValues[(rStart + r) * newNumIndices + c] += mat[k * nRows + r] * tmpValues[(oldOff + k) * newNumIndices + c];
4385             }
4386           }
4387         }
4388       }
4389       else {
4390         /* copy this row as is */
4391         for (r = 0; r < dof; c++) {
4392           for (c = 0; c < newNumIndices; c++) {
4393             newValues[(rStart + r) * newNumIndices + c] = tmpValues[(oldOff + r) * newNumIndices + c];
4394           }
4395         }
4396       }
4397       oldOff += dof;
4398     }
4399   }
4400 
4401   /* clean up */
4402   ierr = DMRestoreWorkArray(dm,maxDof,PETSC_INT,&indices);CHKERRQ(ierr);
4403   ierr = DMRestoreWorkArray(dm,maxAnchor*maxDof,PETSC_INT,&newIndices);CHKERRQ(ierr);
4404   if (numFields) {
4405     for (f = 0; f < numFields; f++) {
4406       ierr = DMRestoreWorkArray(dm,pointMatOffsets[f][numPoints],PETSC_SCALAR,&pointMat[f]);CHKERRQ(ierr);
4407       ierr = DMRestoreWorkArray(dm,numPoints+1,PETSC_INT,&pointMatOffsets[f]);CHKERRQ(ierr);
4408       ierr = DMRestoreWorkArray(dm,numPoints+1,PETSC_INT,&newPointOffsets[f]);CHKERRQ(ierr);
4409     }
4410   }
4411   else {
4412     ierr = DMRestoreWorkArray(dm,pointMatOffsets[0][numPoints],PETSC_SCALAR,&pointMat[0]);CHKERRQ(ierr);
4413     ierr = DMRestoreWorkArray(dm,numPoints+1,PETSC_INT,&pointMatOffsets[0]);CHKERRQ(ierr);
4414     ierr = DMRestoreWorkArray(dm,numPoints+1,PETSC_INT,&newPointOffsets[0]);CHKERRQ(ierr);
4415   }
4416   ierr = DMRestoreWorkArray(dm,newNumIndices*numIndices,PETSC_SCALAR,&tmpValues);CHKERRQ(ierr);
4417   ierr = ISRestoreIndices(aIS,&anchors);CHKERRQ(ierr);
4418 
4419   /* output */
4420   *outNumPoints  = newNumPoints;
4421   *outNumIndices = newNumIndices;
4422   *outPoints     = newPoints;
4423   *outValues     = newValues;
4424   for (f = 0; f < numFields; f++) {
4425     offsets[f] = newOffsets[f];
4426   }
4427   PetscFunctionReturn(0);
4428 }
4429 
4430 #undef __FUNCT__
4431 #define __FUNCT__ "DMPlexMatSetClosure"
4432 /*@C
4433   DMPlexMatSetClosure - Set an array of the values on the closure of 'point'
4434 
4435   Not collective
4436 
4437   Input Parameters:
4438 + dm - The DM
4439 . section - The section describing the layout in v, or NULL to use the default section
4440 . globalSection - The section describing the layout in v, or NULL to use the default global section
4441 . A - The matrix
4442 . point - The sieve point in the DM
4443 . values - The array of values
4444 - mode - The insert mode, where INSERT_ALL_VALUES and ADD_ALL_VALUES also overwrite boundary conditions
4445 
4446   Fortran Notes:
4447   This routine is only available in Fortran 90, and you must include petsc.h90 in your code.
4448 
4449   Level: intermediate
4450 
4451 .seealso DMPlexVecGetClosure(), DMPlexVecSetClosure()
4452 @*/
4453 PetscErrorCode DMPlexMatSetClosure(DM dm, PetscSection section, PetscSection globalSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode)
4454 {
4455   DM_Plex        *mesh   = (DM_Plex*) dm->data;
4456   PetscSection    clSection;
4457   IS              clPoints;
4458   PetscInt       *points = NULL, *newPoints;
4459   const PetscInt *clp;
4460   PetscInt       *indices;
4461   PetscInt        offsets[32];
4462   PetscInt        numFields, numPoints, newNumPoints, numIndices, newNumIndices, dof, off, globalOff, pStart, pEnd, p, q, f;
4463   PetscScalar    *newValues;
4464   PetscErrorCode  ierr;
4465 
4466   PetscFunctionBegin;
4467   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4468   if (!section) {ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);}
4469   PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2);
4470   if (!globalSection) {ierr = DMGetDefaultGlobalSection(dm, &globalSection);CHKERRQ(ierr);}
4471   PetscValidHeaderSpecific(globalSection, PETSC_SECTION_CLASSID, 3);
4472   PetscValidHeaderSpecific(A, MAT_CLASSID, 4);
4473   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
4474   if (numFields > 31) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
4475   ierr = PetscMemzero(offsets, 32 * sizeof(PetscInt));CHKERRQ(ierr);
4476   ierr = PetscSectionGetClosureIndex(section, (PetscObject) dm, &clSection, &clPoints);CHKERRQ(ierr);
4477   if (!clPoints) {
4478     ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
4479     /* Compress out points not in the section */
4480     ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
4481     for (p = 0, q = 0; p < numPoints*2; p += 2) {
4482       if ((points[p] >= pStart) && (points[p] < pEnd)) {
4483         points[q*2]   = points[p];
4484         points[q*2+1] = points[p+1];
4485         ++q;
4486       }
4487     }
4488     numPoints = q;
4489   } else {
4490     PetscInt dof, off;
4491 
4492     ierr = PetscSectionGetDof(clSection, point, &dof);CHKERRQ(ierr);
4493     numPoints = dof/2;
4494     ierr = PetscSectionGetOffset(clSection, point, &off);CHKERRQ(ierr);
4495     ierr = ISGetIndices(clPoints, &clp);CHKERRQ(ierr);
4496     points = (PetscInt *) &clp[off];
4497   }
4498   for (p = 0, numIndices = 0; p < numPoints*2; p += 2) {
4499     PetscInt fdof;
4500 
4501     ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
4502     for (f = 0; f < numFields; ++f) {
4503       ierr          = PetscSectionGetFieldDof(section, points[p], f, &fdof);CHKERRQ(ierr);
4504       offsets[f+1] += fdof;
4505     }
4506     numIndices += dof;
4507   }
4508   for (f = 1; f < numFields; ++f) offsets[f+1] += offsets[f];
4509 
4510   if (numFields && offsets[numFields] != numIndices) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid size for closure %d should be %d", offsets[numFields], numIndices);
4511   ierr = DMPlexAnchorsModifyMat(dm,section,numPoints,numIndices,points,values,&newNumPoints,&newNumIndices,&newPoints,&newValues,offsets);CHKERRQ(ierr);
4512   if (newNumPoints) {
4513     if (!clPoints) {
4514       ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
4515     } else {
4516       ierr = ISRestoreIndices(clPoints, &clp);CHKERRQ(ierr);
4517     }
4518     numPoints  = newNumPoints;
4519     numIndices = newNumIndices;
4520     points     = newPoints;
4521     values     = newValues;
4522   }
4523   ierr = DMGetWorkArray(dm, numIndices, PETSC_INT, &indices);CHKERRQ(ierr);
4524   if (numFields) {
4525     for (p = 0; p < numPoints*2; p += 2) {
4526       PetscInt o = points[p+1];
4527       ierr = PetscSectionGetOffset(globalSection, points[p], &globalOff);CHKERRQ(ierr);
4528       indicesPointFields_private(section, points[p], globalOff < 0 ? -(globalOff+1) : globalOff, offsets, PETSC_FALSE, o, indices);
4529     }
4530   } else {
4531     for (p = 0, off = 0; p < numPoints*2; p += 2) {
4532       PetscInt o = points[p+1];
4533       ierr = PetscSectionGetOffset(globalSection, points[p], &globalOff);CHKERRQ(ierr);
4534       indicesPoint_private(section, points[p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, o, indices);
4535     }
4536   }
4537   if (mesh->printSetValues) {ierr = DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndices, indices, 0, NULL, values);CHKERRQ(ierr);}
4538   ierr = MatSetValues(A, numIndices, indices, numIndices, indices, values, mode);
4539   if (ierr) {
4540     PetscMPIInt    rank;
4541     PetscErrorCode ierr2;
4542 
4543     ierr2 = MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank);CHKERRQ(ierr2);
4544     ierr2 = (*PetscErrorPrintf)("[%D]ERROR in DMPlexMatSetClosure\n", rank);CHKERRQ(ierr2);
4545     ierr2 = DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndices, indices, 0, NULL, values);CHKERRQ(ierr2);
4546     ierr2 = DMRestoreWorkArray(dm, numIndices, PETSC_INT, &indices);CHKERRQ(ierr2);
4547     CHKERRQ(ierr);
4548   }
4549   if (newNumPoints) {
4550     ierr = DMRestoreWorkArray(dm,newNumIndices*newNumIndices,PETSC_SCALAR,&newValues);CHKERRQ(ierr);
4551     ierr = DMRestoreWorkArray(dm,2*newNumPoints,PETSC_INT,&newPoints);CHKERRQ(ierr);
4552   }
4553   else {
4554     if (!clPoints) {
4555       ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
4556     } else {
4557       ierr = ISRestoreIndices(clPoints, &clp);CHKERRQ(ierr);
4558     }
4559   }
4560   ierr = DMRestoreWorkArray(dm, numIndices, PETSC_INT, &indices);CHKERRQ(ierr);
4561   PetscFunctionReturn(0);
4562 }
4563 
4564 #undef __FUNCT__
4565 #define __FUNCT__ "DMPlexMatSetClosureRefined"
4566 PetscErrorCode DMPlexMatSetClosureRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode)
4567 {
4568   DM_Plex        *mesh   = (DM_Plex*) dmf->data;
4569   PetscInt       *fpoints = NULL, *ftotpoints = NULL;
4570   PetscInt       *cpoints = NULL;
4571   PetscInt       *findices, *cindices;
4572   PetscInt        foffsets[32], coffsets[32];
4573   CellRefiner     cellRefiner;
4574   PetscInt        numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f;
4575   PetscErrorCode  ierr;
4576 
4577   PetscFunctionBegin;
4578   PetscValidHeaderSpecific(dmf, DM_CLASSID, 1);
4579   PetscValidHeaderSpecific(dmc, DM_CLASSID, 4);
4580   if (!fsection) {ierr = DMGetDefaultSection(dmf, &fsection);CHKERRQ(ierr);}
4581   PetscValidHeaderSpecific(fsection, PETSC_SECTION_CLASSID, 2);
4582   if (!csection) {ierr = DMGetDefaultSection(dmc, &csection);CHKERRQ(ierr);}
4583   PetscValidHeaderSpecific(csection, PETSC_SECTION_CLASSID, 5);
4584   if (!globalFSection) {ierr = DMGetDefaultGlobalSection(dmf, &globalFSection);CHKERRQ(ierr);}
4585   PetscValidHeaderSpecific(globalFSection, PETSC_SECTION_CLASSID, 3);
4586   if (!globalCSection) {ierr = DMGetDefaultGlobalSection(dmc, &globalCSection);CHKERRQ(ierr);}
4587   PetscValidHeaderSpecific(globalCSection, PETSC_SECTION_CLASSID, 6);
4588   PetscValidHeaderSpecific(A, MAT_CLASSID, 7);
4589   ierr = PetscSectionGetNumFields(fsection, &numFields);CHKERRQ(ierr);
4590   if (numFields > 31) SETERRQ1(PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
4591   ierr = PetscMemzero(foffsets, 32 * sizeof(PetscInt));CHKERRQ(ierr);
4592   ierr = PetscMemzero(coffsets, 32 * sizeof(PetscInt));CHKERRQ(ierr);
4593   /* Column indices */
4594   ierr = DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints);CHKERRQ(ierr);
4595   maxFPoints = numCPoints;
4596   /* Compress out points not in the section */
4597   /*   TODO: Squeeze out points with 0 dof as well */
4598   ierr = PetscSectionGetChart(csection, &pStart, &pEnd);CHKERRQ(ierr);
4599   for (p = 0, q = 0; p < numCPoints*2; p += 2) {
4600     if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) {
4601       cpoints[q*2]   = cpoints[p];
4602       cpoints[q*2+1] = cpoints[p+1];
4603       ++q;
4604     }
4605   }
4606   numCPoints = q;
4607   for (p = 0, numCIndices = 0; p < numCPoints*2; p += 2) {
4608     PetscInt fdof;
4609 
4610     ierr = PetscSectionGetDof(csection, cpoints[p], &dof);CHKERRQ(ierr);
4611     if (!dof) continue;
4612     for (f = 0; f < numFields; ++f) {
4613       ierr           = PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof);CHKERRQ(ierr);
4614       coffsets[f+1] += fdof;
4615     }
4616     numCIndices += dof;
4617   }
4618   for (f = 1; f < numFields; ++f) coffsets[f+1] += coffsets[f];
4619   /* Row indices */
4620   ierr = DMPlexGetCellRefiner_Internal(dmc, &cellRefiner);CHKERRQ(ierr);
4621   ierr = CellRefinerGetAffineTransforms_Internal(cellRefiner, &numSubcells, NULL, NULL, NULL);CHKERRQ(ierr);
4622   ierr = DMGetWorkArray(dmf, maxFPoints*2*numSubcells, PETSC_INT, &ftotpoints);CHKERRQ(ierr);
4623   for (r = 0, q = 0; r < numSubcells; ++r) {
4624     /* TODO Map from coarse to fine cells */
4625     ierr = DMPlexGetTransitiveClosure(dmf, point*numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints);CHKERRQ(ierr);
4626     /* Compress out points not in the section */
4627     ierr = PetscSectionGetChart(fsection, &pStart, &pEnd);CHKERRQ(ierr);
4628     for (p = 0; p < numFPoints*2; p += 2) {
4629       if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) {
4630         ierr = PetscSectionGetDof(fsection, fpoints[p], &dof);CHKERRQ(ierr);
4631         if (!dof) continue;
4632         for (s = 0; s < q; ++s) if (fpoints[p] == ftotpoints[s*2]) break;
4633         if (s < q) continue;
4634         ftotpoints[q*2]   = fpoints[p];
4635         ftotpoints[q*2+1] = fpoints[p+1];
4636         ++q;
4637       }
4638     }
4639     ierr = DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints);CHKERRQ(ierr);
4640   }
4641   numFPoints = q;
4642   for (p = 0, numFIndices = 0; p < numFPoints*2; p += 2) {
4643     PetscInt fdof;
4644 
4645     ierr = PetscSectionGetDof(fsection, ftotpoints[p], &dof);CHKERRQ(ierr);
4646     if (!dof) continue;
4647     for (f = 0; f < numFields; ++f) {
4648       ierr           = PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof);CHKERRQ(ierr);
4649       foffsets[f+1] += fdof;
4650     }
4651     numFIndices += dof;
4652   }
4653   for (f = 1; f < numFields; ++f) foffsets[f+1] += foffsets[f];
4654 
4655   if (numFields && foffsets[numFields] != numFIndices) SETERRQ2(PetscObjectComm((PetscObject)dmf), PETSC_ERR_PLIB, "Invalid size for closure %d should be %d", foffsets[numFields], numFIndices);
4656   if (numFields && coffsets[numFields] != numCIndices) SETERRQ2(PetscObjectComm((PetscObject)dmc), PETSC_ERR_PLIB, "Invalid size for closure %d should be %d", coffsets[numFields], numCIndices);
4657   ierr = DMGetWorkArray(dmf, numFIndices, PETSC_INT, &findices);CHKERRQ(ierr);
4658   ierr = DMGetWorkArray(dmc, numCIndices, PETSC_INT, &cindices);CHKERRQ(ierr);
4659   if (numFields) {
4660     for (p = 0; p < numFPoints*2; p += 2) {
4661       PetscInt o = ftotpoints[p+1];
4662       ierr = PetscSectionGetOffset(globalFSection, ftotpoints[p], &globalOff);CHKERRQ(ierr);
4663       indicesPointFields_private(fsection, ftotpoints[p], globalOff < 0 ? -(globalOff+1) : globalOff, foffsets, PETSC_FALSE, o, findices);
4664     }
4665     for (p = 0; p < numCPoints*2; p += 2) {
4666       PetscInt o = cpoints[p+1];
4667       ierr = PetscSectionGetOffset(globalCSection, cpoints[p], &globalOff);CHKERRQ(ierr);
4668       indicesPointFields_private(csection, cpoints[p], globalOff < 0 ? -(globalOff+1) : globalOff, coffsets, PETSC_FALSE, o, cindices);
4669     }
4670   } else {
4671     for (p = 0, off = 0; p < numFPoints*2; p += 2) {
4672       PetscInt o = ftotpoints[p+1];
4673       ierr = PetscSectionGetOffset(globalFSection, ftotpoints[p], &globalOff);CHKERRQ(ierr);
4674       indicesPoint_private(fsection, ftotpoints[p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, o, findices);
4675     }
4676     for (p = 0, off = 0; p < numCPoints*2; p += 2) {
4677       PetscInt o = cpoints[p+1];
4678       ierr = PetscSectionGetOffset(globalCSection, cpoints[p], &globalOff);CHKERRQ(ierr);
4679       indicesPoint_private(csection, cpoints[p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, o, cindices);
4680     }
4681   }
4682   if (mesh->printSetValues) {ierr = DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numFIndices, findices, numCIndices, cindices, values);CHKERRQ(ierr);}
4683   ierr = MatSetValues(A, numFIndices, findices, numCIndices, cindices, values, mode);
4684   if (ierr) {
4685     PetscMPIInt    rank;
4686     PetscErrorCode ierr2;
4687 
4688     ierr2 = MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank);CHKERRQ(ierr2);
4689     ierr2 = (*PetscErrorPrintf)("[%D]ERROR in DMPlexMatSetClosure\n", rank);CHKERRQ(ierr2);
4690     ierr2 = DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numFIndices, findices, numCIndices, cindices, values);CHKERRQ(ierr2);
4691     ierr2 = DMRestoreWorkArray(dmf, numFIndices, PETSC_INT, &findices);CHKERRQ(ierr2);
4692     ierr2 = DMRestoreWorkArray(dmc, numCIndices, PETSC_INT, &cindices);CHKERRQ(ierr2);
4693     CHKERRQ(ierr);
4694   }
4695   ierr = DMRestoreWorkArray(dmf, numCPoints*2*4, PETSC_INT, &ftotpoints);CHKERRQ(ierr);
4696   ierr = DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints);CHKERRQ(ierr);
4697   ierr = DMRestoreWorkArray(dmf, numFIndices, PETSC_INT, &findices);CHKERRQ(ierr);
4698   ierr = DMRestoreWorkArray(dmc, numCIndices, PETSC_INT, &cindices);CHKERRQ(ierr);
4699   PetscFunctionReturn(0);
4700 }
4701 
4702 #undef __FUNCT__
4703 #define __FUNCT__ "DMPlexMatGetClosureIndicesRefined"
4704 PetscErrorCode DMPlexMatGetClosureIndicesRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, PetscInt point, PetscInt cindices[], PetscInt findices[])
4705 {
4706   PetscInt      *fpoints = NULL, *ftotpoints = NULL;
4707   PetscInt      *cpoints = NULL;
4708   PetscInt       foffsets[32], coffsets[32];
4709   CellRefiner    cellRefiner;
4710   PetscInt       numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f;
4711   PetscErrorCode ierr;
4712 
4713   PetscFunctionBegin;
4714   PetscValidHeaderSpecific(dmf, DM_CLASSID, 1);
4715   PetscValidHeaderSpecific(dmc, DM_CLASSID, 4);
4716   if (!fsection) {ierr = DMGetDefaultSection(dmf, &fsection);CHKERRQ(ierr);}
4717   PetscValidHeaderSpecific(fsection, PETSC_SECTION_CLASSID, 2);
4718   if (!csection) {ierr = DMGetDefaultSection(dmc, &csection);CHKERRQ(ierr);}
4719   PetscValidHeaderSpecific(csection, PETSC_SECTION_CLASSID, 5);
4720   if (!globalFSection) {ierr = DMGetDefaultGlobalSection(dmf, &globalFSection);CHKERRQ(ierr);}
4721   PetscValidHeaderSpecific(globalFSection, PETSC_SECTION_CLASSID, 3);
4722   if (!globalCSection) {ierr = DMGetDefaultGlobalSection(dmc, &globalCSection);CHKERRQ(ierr);}
4723   PetscValidHeaderSpecific(globalCSection, PETSC_SECTION_CLASSID, 6);
4724   ierr = PetscSectionGetNumFields(fsection, &numFields);CHKERRQ(ierr);
4725   if (numFields > 31) SETERRQ1(PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
4726   ierr = PetscMemzero(foffsets, 32 * sizeof(PetscInt));CHKERRQ(ierr);
4727   ierr = PetscMemzero(coffsets, 32 * sizeof(PetscInt));CHKERRQ(ierr);
4728   /* Column indices */
4729   ierr = DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints);CHKERRQ(ierr);
4730   maxFPoints = numCPoints;
4731   /* Compress out points not in the section */
4732   /*   TODO: Squeeze out points with 0 dof as well */
4733   ierr = PetscSectionGetChart(csection, &pStart, &pEnd);CHKERRQ(ierr);
4734   for (p = 0, q = 0; p < numCPoints*2; p += 2) {
4735     if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) {
4736       cpoints[q*2]   = cpoints[p];
4737       cpoints[q*2+1] = cpoints[p+1];
4738       ++q;
4739     }
4740   }
4741   numCPoints = q;
4742   for (p = 0, numCIndices = 0; p < numCPoints*2; p += 2) {
4743     PetscInt fdof;
4744 
4745     ierr = PetscSectionGetDof(csection, cpoints[p], &dof);CHKERRQ(ierr);
4746     if (!dof) continue;
4747     for (f = 0; f < numFields; ++f) {
4748       ierr           = PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof);CHKERRQ(ierr);
4749       coffsets[f+1] += fdof;
4750     }
4751     numCIndices += dof;
4752   }
4753   for (f = 1; f < numFields; ++f) coffsets[f+1] += coffsets[f];
4754   /* Row indices */
4755   ierr = DMPlexGetCellRefiner_Internal(dmc, &cellRefiner);CHKERRQ(ierr);
4756   ierr = CellRefinerGetAffineTransforms_Internal(cellRefiner, &numSubcells, NULL, NULL, NULL);CHKERRQ(ierr);
4757   ierr = DMGetWorkArray(dmf, maxFPoints*2*numSubcells, PETSC_INT, &ftotpoints);CHKERRQ(ierr);
4758   for (r = 0, q = 0; r < numSubcells; ++r) {
4759     /* TODO Map from coarse to fine cells */
4760     ierr = DMPlexGetTransitiveClosure(dmf, point*numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints);CHKERRQ(ierr);
4761     /* Compress out points not in the section */
4762     ierr = PetscSectionGetChart(fsection, &pStart, &pEnd);CHKERRQ(ierr);
4763     for (p = 0; p < numFPoints*2; p += 2) {
4764       if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) {
4765         ierr = PetscSectionGetDof(fsection, fpoints[p], &dof);CHKERRQ(ierr);
4766         if (!dof) continue;
4767         for (s = 0; s < q; ++s) if (fpoints[p] == ftotpoints[s*2]) break;
4768         if (s < q) continue;
4769         ftotpoints[q*2]   = fpoints[p];
4770         ftotpoints[q*2+1] = fpoints[p+1];
4771         ++q;
4772       }
4773     }
4774     ierr = DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints);CHKERRQ(ierr);
4775   }
4776   numFPoints = q;
4777   for (p = 0, numFIndices = 0; p < numFPoints*2; p += 2) {
4778     PetscInt fdof;
4779 
4780     ierr = PetscSectionGetDof(fsection, ftotpoints[p], &dof);CHKERRQ(ierr);
4781     if (!dof) continue;
4782     for (f = 0; f < numFields; ++f) {
4783       ierr           = PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof);CHKERRQ(ierr);
4784       foffsets[f+1] += fdof;
4785     }
4786     numFIndices += dof;
4787   }
4788   for (f = 1; f < numFields; ++f) foffsets[f+1] += foffsets[f];
4789 
4790   if (numFields && foffsets[numFields] != numFIndices) SETERRQ2(PetscObjectComm((PetscObject)dmf), PETSC_ERR_PLIB, "Invalid size for closure %d should be %d", foffsets[numFields], numFIndices);
4791   if (numFields && coffsets[numFields] != numCIndices) SETERRQ2(PetscObjectComm((PetscObject)dmc), PETSC_ERR_PLIB, "Invalid size for closure %d should be %d", coffsets[numFields], numCIndices);
4792   if (numFields) {
4793     for (p = 0; p < numFPoints*2; p += 2) {
4794       PetscInt o = ftotpoints[p+1];
4795       ierr = PetscSectionGetOffset(globalFSection, ftotpoints[p], &globalOff);CHKERRQ(ierr);
4796       indicesPointFields_private(fsection, ftotpoints[p], globalOff < 0 ? -(globalOff+1) : globalOff, foffsets, PETSC_FALSE, o, findices);
4797     }
4798     for (p = 0; p < numCPoints*2; p += 2) {
4799       PetscInt o = cpoints[p+1];
4800       ierr = PetscSectionGetOffset(globalCSection, cpoints[p], &globalOff);CHKERRQ(ierr);
4801       indicesPointFields_private(csection, cpoints[p], globalOff < 0 ? -(globalOff+1) : globalOff, coffsets, PETSC_FALSE, o, cindices);
4802     }
4803   } else {
4804     for (p = 0, off = 0; p < numFPoints*2; p += 2) {
4805       PetscInt o = ftotpoints[p+1];
4806       ierr = PetscSectionGetOffset(globalFSection, ftotpoints[p], &globalOff);CHKERRQ(ierr);
4807       indicesPoint_private(fsection, ftotpoints[p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, o, findices);
4808     }
4809     for (p = 0, off = 0; p < numCPoints*2; p += 2) {
4810       PetscInt o = cpoints[p+1];
4811       ierr = PetscSectionGetOffset(globalCSection, cpoints[p], &globalOff);CHKERRQ(ierr);
4812       indicesPoint_private(csection, cpoints[p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, o, cindices);
4813     }
4814   }
4815   ierr = DMRestoreWorkArray(dmf, numCPoints*2*4, PETSC_INT, &ftotpoints);CHKERRQ(ierr);
4816   ierr = DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints);CHKERRQ(ierr);
4817   PetscFunctionReturn(0);
4818 }
4819 
4820 #undef __FUNCT__
4821 #define __FUNCT__ "DMPlexGetHybridBounds"
4822 /*@
4823   DMPlexGetHybridBounds - Get the first mesh point of each dimension which is a hybrid
4824 
4825   Input Parameter:
4826 . dm - The DMPlex object
4827 
4828   Output Parameters:
4829 + cMax - The first hybrid cell
4830 . fMax - The first hybrid face
4831 . eMax - The first hybrid edge
4832 - vMax - The first hybrid vertex
4833 
4834   Level: developer
4835 
4836 .seealso DMPlexCreateHybridMesh(), DMPlexSetHybridBounds()
4837 @*/
4838 PetscErrorCode DMPlexGetHybridBounds(DM dm, PetscInt *cMax, PetscInt *fMax, PetscInt *eMax, PetscInt *vMax)
4839 {
4840   DM_Plex       *mesh = (DM_Plex*) dm->data;
4841   PetscInt       dim;
4842   PetscErrorCode ierr;
4843 
4844   PetscFunctionBegin;
4845   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4846   ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr);
4847   if (cMax) *cMax = mesh->hybridPointMax[dim];
4848   if (fMax) *fMax = mesh->hybridPointMax[dim-1];
4849   if (eMax) *eMax = mesh->hybridPointMax[1];
4850   if (vMax) *vMax = mesh->hybridPointMax[0];
4851   PetscFunctionReturn(0);
4852 }
4853 
4854 #undef __FUNCT__
4855 #define __FUNCT__ "DMPlexSetHybridBounds"
4856 /*@
4857   DMPlexSetHybridBounds - Set the first mesh point of each dimension which is a hybrid
4858 
4859   Input Parameters:
4860 . dm   - The DMPlex object
4861 . cMax - The first hybrid cell
4862 . fMax - The first hybrid face
4863 . eMax - The first hybrid edge
4864 - vMax - The first hybrid vertex
4865 
4866   Level: developer
4867 
4868 .seealso DMPlexCreateHybridMesh(), DMPlexGetHybridBounds()
4869 @*/
4870 PetscErrorCode DMPlexSetHybridBounds(DM dm, PetscInt cMax, PetscInt fMax, PetscInt eMax, PetscInt vMax)
4871 {
4872   DM_Plex       *mesh = (DM_Plex*) dm->data;
4873   PetscInt       dim;
4874   PetscErrorCode ierr;
4875 
4876   PetscFunctionBegin;
4877   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4878   ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr);
4879   if (cMax >= 0) mesh->hybridPointMax[dim]   = cMax;
4880   if (fMax >= 0) mesh->hybridPointMax[dim-1] = fMax;
4881   if (eMax >= 0) mesh->hybridPointMax[1]     = eMax;
4882   if (vMax >= 0) mesh->hybridPointMax[0]     = vMax;
4883   PetscFunctionReturn(0);
4884 }
4885 
4886 #undef __FUNCT__
4887 #define __FUNCT__ "DMPlexGetVTKCellHeight"
4888 PetscErrorCode DMPlexGetVTKCellHeight(DM dm, PetscInt *cellHeight)
4889 {
4890   DM_Plex *mesh = (DM_Plex*) dm->data;
4891 
4892   PetscFunctionBegin;
4893   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4894   PetscValidPointer(cellHeight, 2);
4895   *cellHeight = mesh->vtkCellHeight;
4896   PetscFunctionReturn(0);
4897 }
4898 
4899 #undef __FUNCT__
4900 #define __FUNCT__ "DMPlexSetVTKCellHeight"
4901 PetscErrorCode DMPlexSetVTKCellHeight(DM dm, PetscInt cellHeight)
4902 {
4903   DM_Plex *mesh = (DM_Plex*) dm->data;
4904 
4905   PetscFunctionBegin;
4906   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4907   mesh->vtkCellHeight = cellHeight;
4908   PetscFunctionReturn(0);
4909 }
4910 
4911 #undef __FUNCT__
4912 #define __FUNCT__ "DMPlexCreateNumbering_Private"
4913 /* We can easily have a form that takes an IS instead */
4914 static PetscErrorCode DMPlexCreateNumbering_Private(DM dm, PetscInt pStart, PetscInt pEnd, PetscInt shift, PetscInt *globalSize, PetscSF sf, IS *numbering)
4915 {
4916   PetscSection   section, globalSection;
4917   PetscInt      *numbers, p;
4918   PetscErrorCode ierr;
4919 
4920   PetscFunctionBegin;
4921   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)dm), &section);CHKERRQ(ierr);
4922   ierr = PetscSectionSetChart(section, pStart, pEnd);CHKERRQ(ierr);
4923   for (p = pStart; p < pEnd; ++p) {
4924     ierr = PetscSectionSetDof(section, p, 1);CHKERRQ(ierr);
4925   }
4926   ierr = PetscSectionSetUp(section);CHKERRQ(ierr);
4927   ierr = PetscSectionCreateGlobalSection(section, sf, PETSC_FALSE, &globalSection);CHKERRQ(ierr);
4928   ierr = PetscMalloc1(pEnd - pStart, &numbers);CHKERRQ(ierr);
4929   for (p = pStart; p < pEnd; ++p) {
4930     ierr = PetscSectionGetOffset(globalSection, p, &numbers[p-pStart]);CHKERRQ(ierr);
4931     if (numbers[p-pStart] < 0) numbers[p-pStart] -= shift;
4932     else                       numbers[p-pStart] += shift;
4933   }
4934   ierr = ISCreateGeneral(PetscObjectComm((PetscObject) dm), pEnd - pStart, numbers, PETSC_OWN_POINTER, numbering);CHKERRQ(ierr);
4935   if (globalSize) {
4936     PetscLayout layout;
4937     ierr = PetscSectionGetPointLayout(PetscObjectComm((PetscObject) dm), globalSection, &layout);CHKERRQ(ierr);
4938     ierr = PetscLayoutGetSize(layout, globalSize);CHKERRQ(ierr);
4939     ierr = PetscLayoutDestroy(&layout);CHKERRQ(ierr);
4940   }
4941   ierr = PetscSectionDestroy(&section);CHKERRQ(ierr);
4942   ierr = PetscSectionDestroy(&globalSection);CHKERRQ(ierr);
4943   PetscFunctionReturn(0);
4944 }
4945 
4946 #undef __FUNCT__
4947 #define __FUNCT__ "DMPlexGetCellNumbering"
4948 PetscErrorCode DMPlexGetCellNumbering(DM dm, IS *globalCellNumbers)
4949 {
4950   DM_Plex       *mesh = (DM_Plex*) dm->data;
4951   PetscInt       cellHeight, cStart, cEnd, cMax;
4952   PetscErrorCode ierr;
4953 
4954   PetscFunctionBegin;
4955   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4956   if (!mesh->globalCellNumbers) {
4957     ierr = DMPlexGetVTKCellHeight(dm, &cellHeight);CHKERRQ(ierr);
4958     ierr = DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd);CHKERRQ(ierr);
4959     ierr = DMPlexGetHybridBounds(dm, &cMax, NULL, NULL, NULL);CHKERRQ(ierr);
4960     if (cMax >= 0) cEnd = PetscMin(cEnd, cMax);
4961     ierr = DMPlexCreateNumbering_Private(dm, cStart, cEnd, 0, NULL, dm->sf, &mesh->globalCellNumbers);CHKERRQ(ierr);
4962   }
4963   *globalCellNumbers = mesh->globalCellNumbers;
4964   PetscFunctionReturn(0);
4965 }
4966 
4967 #undef __FUNCT__
4968 #define __FUNCT__ "DMPlexGetVertexNumbering"
4969 PetscErrorCode DMPlexGetVertexNumbering(DM dm, IS *globalVertexNumbers)
4970 {
4971   DM_Plex       *mesh = (DM_Plex*) dm->data;
4972   PetscInt       vStart, vEnd, vMax;
4973   PetscErrorCode ierr;
4974 
4975   PetscFunctionBegin;
4976   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4977   if (!mesh->globalVertexNumbers) {
4978     ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
4979     ierr = DMPlexGetHybridBounds(dm, NULL, NULL, NULL, &vMax);CHKERRQ(ierr);
4980     if (vMax >= 0) vEnd = PetscMin(vEnd, vMax);
4981     ierr = DMPlexCreateNumbering_Private(dm, vStart, vEnd, 0, NULL, dm->sf, &mesh->globalVertexNumbers);CHKERRQ(ierr);
4982   }
4983   *globalVertexNumbers = mesh->globalVertexNumbers;
4984   PetscFunctionReturn(0);
4985 }
4986 
4987 #undef __FUNCT__
4988 #define __FUNCT__ "DMPlexCreatePointNumbering"
4989 PetscErrorCode DMPlexCreatePointNumbering(DM dm, IS *globalPointNumbers)
4990 {
4991   IS             nums[4];
4992   PetscInt       depths[4];
4993   PetscInt       depth, d, shift = 0;
4994   PetscErrorCode ierr;
4995 
4996   PetscFunctionBegin;
4997   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4998   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
4999   /* For unstratified meshes use dim instead of depth */
5000   if (depth < 0) {ierr = DMGetDimension(dm, &depth);CHKERRQ(ierr);}
5001   depths[0] = depth; depths[1] = 0;
5002   for (d = 2; d <= depth; ++d) depths[d] = depth-d+1;
5003   for (d = 0; d <= depth; ++d) {
5004     PetscInt pStart, pEnd, gsize;
5005 
5006     ierr = DMPlexGetDepthStratum(dm, depths[d], &pStart, &pEnd);CHKERRQ(ierr);
5007     ierr = DMPlexCreateNumbering_Private(dm, pStart, pEnd, shift, &gsize, dm->sf, &nums[d]);CHKERRQ(ierr);
5008     shift += gsize;
5009   }
5010   ierr = ISConcatenate(PetscObjectComm((PetscObject) dm), depth+1, nums, globalPointNumbers);
5011   for (d = 0; d <= depth; ++d) {ierr = ISDestroy(&nums[d]);CHKERRQ(ierr);}
5012   PetscFunctionReturn(0);
5013 }
5014 
5015 
5016 #undef __FUNCT__
5017 #define __FUNCT__ "PetscSectionCreateGlobalSectionLabel"
5018 /*@C
5019   PetscSectionCreateGlobalSectionLabel - Create a section describing the global field layout using
5020   the local section and an SF describing the section point overlap.
5021 
5022   Input Parameters:
5023   + s - The PetscSection for the local field layout
5024   . sf - The SF describing parallel layout of the section points
5025   . includeConstraints - By default this is PETSC_FALSE, meaning that the global field vector will not possess constrained dofs
5026   . label - The label specifying the points
5027   - labelValue - The label stratum specifying the points
5028 
5029   Output Parameter:
5030   . gsection - The PetscSection for the global field layout
5031 
5032   Note: This gives negative sizes and offsets to points not owned by this process
5033 
5034   Level: developer
5035 
5036 .seealso: PetscSectionCreate()
5037 @*/
5038 PetscErrorCode PetscSectionCreateGlobalSectionLabel(PetscSection s, PetscSF sf, PetscBool includeConstraints, DMLabel label, PetscInt labelValue, PetscSection *gsection)
5039 {
5040   PetscInt      *neg = NULL, *tmpOff = NULL;
5041   PetscInt       pStart, pEnd, p, dof, cdof, off, globalOff = 0, nroots;
5042   PetscErrorCode ierr;
5043 
5044   PetscFunctionBegin;
5045   ierr = PetscSectionCreate(PetscObjectComm((PetscObject) s), gsection);CHKERRQ(ierr);
5046   ierr = PetscSectionGetChart(s, &pStart, &pEnd);CHKERRQ(ierr);
5047   ierr = PetscSectionSetChart(*gsection, pStart, pEnd);CHKERRQ(ierr);
5048   ierr = PetscSFGetGraph(sf, &nroots, NULL, NULL, NULL);CHKERRQ(ierr);
5049   if (nroots >= 0) {
5050     if (nroots < pEnd-pStart) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "PetscSF nroots %d < %d section size", nroots, pEnd-pStart);
5051     ierr = PetscCalloc1(nroots, &neg);CHKERRQ(ierr);
5052     if (nroots > pEnd-pStart) {
5053       ierr = PetscCalloc1(nroots, &tmpOff);CHKERRQ(ierr);
5054     } else {
5055       tmpOff = &(*gsection)->atlasDof[-pStart];
5056     }
5057   }
5058   /* Mark ghost points with negative dof */
5059   for (p = pStart; p < pEnd; ++p) {
5060     PetscInt value;
5061 
5062     ierr = DMLabelGetValue(label, p, &value);CHKERRQ(ierr);
5063     if (value != labelValue) continue;
5064     ierr = PetscSectionGetDof(s, p, &dof);CHKERRQ(ierr);
5065     ierr = PetscSectionSetDof(*gsection, p, dof);CHKERRQ(ierr);
5066     ierr = PetscSectionGetConstraintDof(s, p, &cdof);CHKERRQ(ierr);
5067     if (!includeConstraints && cdof > 0) {ierr = PetscSectionSetConstraintDof(*gsection, p, cdof);CHKERRQ(ierr);}
5068     if (neg) neg[p] = -(dof+1);
5069   }
5070   ierr = PetscSectionSetUpBC(*gsection);CHKERRQ(ierr);
5071   if (nroots >= 0) {
5072     ierr = PetscSFBcastBegin(sf, MPIU_INT, neg, tmpOff);CHKERRQ(ierr);
5073     ierr = PetscSFBcastEnd(sf, MPIU_INT, neg, tmpOff);CHKERRQ(ierr);
5074     if (nroots > pEnd-pStart) {
5075       for (p = pStart; p < pEnd; ++p) {if (tmpOff[p] < 0) (*gsection)->atlasDof[p-pStart] = tmpOff[p];}
5076     }
5077   }
5078   /* Calculate new sizes, get proccess offset, and calculate point offsets */
5079   for (p = 0, off = 0; p < pEnd-pStart; ++p) {
5080     cdof = (!includeConstraints && s->bc) ? s->bc->atlasDof[p] : 0;
5081     (*gsection)->atlasOff[p] = off;
5082     off += (*gsection)->atlasDof[p] > 0 ? (*gsection)->atlasDof[p]-cdof : 0;
5083   }
5084   ierr       = MPI_Scan(&off, &globalOff, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject) s));CHKERRQ(ierr);
5085   globalOff -= off;
5086   for (p = 0, off = 0; p < pEnd-pStart; ++p) {
5087     (*gsection)->atlasOff[p] += globalOff;
5088     if (neg) neg[p] = -((*gsection)->atlasOff[p]+1);
5089   }
5090   /* Put in negative offsets for ghost points */
5091   if (nroots >= 0) {
5092     ierr = PetscSFBcastBegin(sf, MPIU_INT, neg, tmpOff);CHKERRQ(ierr);
5093     ierr = PetscSFBcastEnd(sf, MPIU_INT, neg, tmpOff);CHKERRQ(ierr);
5094     if (nroots > pEnd-pStart) {
5095       for (p = pStart; p < pEnd; ++p) {if (tmpOff[p] < 0) (*gsection)->atlasOff[p-pStart] = tmpOff[p];}
5096     }
5097   }
5098   if (nroots >= 0 && nroots > pEnd-pStart) {ierr = PetscFree(tmpOff);CHKERRQ(ierr);}
5099   ierr = PetscFree(neg);CHKERRQ(ierr);
5100   PetscFunctionReturn(0);
5101 }
5102 
5103 #undef __FUNCT__
5104 #define __FUNCT__ "DMPlexCheckSymmetry"
5105 /*@
5106   DMPlexCheckSymmetry - Check that the adjacency information in the mesh is symmetric.
5107 
5108   Input Parameters:
5109   + dm - The DMPlex object
5110 
5111   Note: This is a useful diagnostic when creating meshes programmatically.
5112 
5113   Level: developer
5114 
5115 .seealso: DMCreate(), DMCheckSkeleton(), DMCheckFaces()
5116 @*/
5117 PetscErrorCode DMPlexCheckSymmetry(DM dm)
5118 {
5119   PetscSection    coneSection, supportSection;
5120   const PetscInt *cone, *support;
5121   PetscInt        coneSize, c, supportSize, s;
5122   PetscInt        pStart, pEnd, p, csize, ssize;
5123   PetscErrorCode  ierr;
5124 
5125   PetscFunctionBegin;
5126   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5127   ierr = DMPlexGetConeSection(dm, &coneSection);CHKERRQ(ierr);
5128   ierr = DMPlexGetSupportSection(dm, &supportSection);CHKERRQ(ierr);
5129   /* Check that point p is found in the support of its cone points, and vice versa */
5130   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
5131   for (p = pStart; p < pEnd; ++p) {
5132     ierr = DMPlexGetConeSize(dm, p, &coneSize);CHKERRQ(ierr);
5133     ierr = DMPlexGetCone(dm, p, &cone);CHKERRQ(ierr);
5134     for (c = 0; c < coneSize; ++c) {
5135       PetscBool dup = PETSC_FALSE;
5136       PetscInt  d;
5137       for (d = c-1; d >= 0; --d) {
5138         if (cone[c] == cone[d]) {dup = PETSC_TRUE; break;}
5139       }
5140       ierr = DMPlexGetSupportSize(dm, cone[c], &supportSize);CHKERRQ(ierr);
5141       ierr = DMPlexGetSupport(dm, cone[c], &support);CHKERRQ(ierr);
5142       for (s = 0; s < supportSize; ++s) {
5143         if (support[s] == p) break;
5144       }
5145       if ((s >= supportSize) || (dup && (support[s+1] != p))) {
5146         ierr = PetscPrintf(PETSC_COMM_SELF, "p: %d cone: ", p);
5147         for (s = 0; s < coneSize; ++s) {
5148           ierr = PetscPrintf(PETSC_COMM_SELF, "%d, ", cone[s]);
5149         }
5150         ierr = PetscPrintf(PETSC_COMM_SELF, "\n");
5151         ierr = PetscPrintf(PETSC_COMM_SELF, "p: %d support: ", cone[c]);
5152         for (s = 0; s < supportSize; ++s) {
5153           ierr = PetscPrintf(PETSC_COMM_SELF, "%d, ", support[s]);
5154         }
5155         ierr = PetscPrintf(PETSC_COMM_SELF, "\n");
5156         if (dup) {
5157           SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d not repeatedly found in support of repeated cone point %d", p, cone[c]);
5158         } else {
5159           SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d not found in support of cone point %d", p, cone[c]);
5160         }
5161       }
5162     }
5163     ierr = DMPlexGetSupportSize(dm, p, &supportSize);CHKERRQ(ierr);
5164     ierr = DMPlexGetSupport(dm, p, &support);CHKERRQ(ierr);
5165     for (s = 0; s < supportSize; ++s) {
5166       ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
5167       ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
5168       for (c = 0; c < coneSize; ++c) {
5169         if (cone[c] == p) break;
5170       }
5171       if (c >= coneSize) {
5172         ierr = PetscPrintf(PETSC_COMM_SELF, "p: %d support: ", p);
5173         for (c = 0; c < supportSize; ++c) {
5174           ierr = PetscPrintf(PETSC_COMM_SELF, "%d, ", support[c]);
5175         }
5176         ierr = PetscPrintf(PETSC_COMM_SELF, "\n");
5177         ierr = PetscPrintf(PETSC_COMM_SELF, "p: %d cone: ", support[s]);
5178         for (c = 0; c < coneSize; ++c) {
5179           ierr = PetscPrintf(PETSC_COMM_SELF, "%d, ", cone[c]);
5180         }
5181         ierr = PetscPrintf(PETSC_COMM_SELF, "\n");
5182         SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d not found in cone of support point %d", p, support[s]);
5183       }
5184     }
5185   }
5186   ierr = PetscSectionGetStorageSize(coneSection, &csize);CHKERRQ(ierr);
5187   ierr = PetscSectionGetStorageSize(supportSection, &ssize);CHKERRQ(ierr);
5188   if (csize != ssize) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Total cone size %d != Total support size %d", csize, ssize);
5189   PetscFunctionReturn(0);
5190 }
5191 
5192 #undef __FUNCT__
5193 #define __FUNCT__ "DMPlexCheckSkeleton"
5194 /*@
5195   DMPlexCheckSkeleton - Check that each cell has the correct number of vertices
5196 
5197   Input Parameters:
5198 + dm - The DMPlex object
5199 . isSimplex - Are the cells simplices or tensor products
5200 - cellHeight - Normally 0
5201 
5202   Note: This is a useful diagnostic when creating meshes programmatically.
5203 
5204   Level: developer
5205 
5206 .seealso: DMCreate(), DMCheckSymmetry(), DMCheckFaces()
5207 @*/
5208 PetscErrorCode DMPlexCheckSkeleton(DM dm, PetscBool isSimplex, PetscInt cellHeight)
5209 {
5210   PetscInt       dim, numCorners, numHybridCorners, vStart, vEnd, cStart, cEnd, cMax, c;
5211   PetscErrorCode ierr;
5212 
5213   PetscFunctionBegin;
5214   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5215   ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr);
5216   switch (dim) {
5217   case 1: numCorners = isSimplex ? 2 : 2; numHybridCorners = isSimplex ? 2 : 2; break;
5218   case 2: numCorners = isSimplex ? 3 : 4; numHybridCorners = isSimplex ? 4 : 4; break;
5219   case 3: numCorners = isSimplex ? 4 : 8; numHybridCorners = isSimplex ? 6 : 8; break;
5220   default:
5221     SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_OUTOFRANGE, "Cannot handle meshes of dimension %d", dim);
5222   }
5223   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
5224   ierr = DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd);CHKERRQ(ierr);
5225   ierr = DMPlexGetHybridBounds(dm, &cMax, NULL, NULL, NULL);CHKERRQ(ierr);
5226   cMax = cMax >= 0 ? cMax : cEnd;
5227   for (c = cStart; c < cMax; ++c) {
5228     PetscInt *closure = NULL, closureSize, cl, coneSize = 0;
5229 
5230     ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
5231     for (cl = 0; cl < closureSize*2; cl += 2) {
5232       const PetscInt p = closure[cl];
5233       if ((p >= vStart) && (p < vEnd)) ++coneSize;
5234     }
5235     ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
5236     if (coneSize != numCorners) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cell %d has  %d vertices != %d", c, coneSize, numCorners);
5237   }
5238   for (c = cMax; c < cEnd; ++c) {
5239     PetscInt *closure = NULL, closureSize, cl, coneSize = 0;
5240 
5241     ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
5242     for (cl = 0; cl < closureSize*2; cl += 2) {
5243       const PetscInt p = closure[cl];
5244       if ((p >= vStart) && (p < vEnd)) ++coneSize;
5245     }
5246     ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
5247     if (coneSize > numHybridCorners) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Hybrid cell %d has  %d vertices > %d", c, coneSize, numHybridCorners);
5248   }
5249   PetscFunctionReturn(0);
5250 }
5251 
5252 #undef __FUNCT__
5253 #define __FUNCT__ "DMPlexCheckFaces"
5254 /*@
5255   DMPlexCheckFaces - Check that the faces of each cell give a vertex order this is consistent with what we expect from the cell type
5256 
5257   Input Parameters:
5258 + dm - The DMPlex object
5259 . isSimplex - Are the cells simplices or tensor products
5260 - cellHeight - Normally 0
5261 
5262   Note: This is a useful diagnostic when creating meshes programmatically.
5263 
5264   Level: developer
5265 
5266 .seealso: DMCreate(), DMCheckSymmetry(), DMCheckSkeleton()
5267 @*/
5268 PetscErrorCode DMPlexCheckFaces(DM dm, PetscBool isSimplex, PetscInt cellHeight)
5269 {
5270   PetscInt       pMax[4];
5271   PetscInt       dim, vStart, vEnd, cStart, cEnd, c, h;
5272   PetscErrorCode ierr;
5273 
5274   PetscFunctionBegin;
5275   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5276   ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr);
5277   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
5278   ierr = DMPlexGetHybridBounds(dm, &pMax[dim], &pMax[dim-1], &pMax[1], &pMax[0]);CHKERRQ(ierr);
5279   for (h = cellHeight; h < dim; ++h) {
5280     ierr = DMPlexGetHeightStratum(dm, h, &cStart, &cEnd);CHKERRQ(ierr);
5281     for (c = cStart; c < cEnd; ++c) {
5282       const PetscInt *cone, *ornt, *faces;
5283       PetscInt        numFaces, faceSize, coneSize,f;
5284       PetscInt       *closure = NULL, closureSize, cl, numCorners = 0;
5285 
5286       if (pMax[dim-h] >= 0 && c >= pMax[dim-h]) continue;
5287       ierr = DMPlexGetConeSize(dm, c, &coneSize);CHKERRQ(ierr);
5288       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
5289       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
5290       ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
5291       for (cl = 0; cl < closureSize*2; cl += 2) {
5292         const PetscInt p = closure[cl];
5293         if ((p >= vStart) && (p < vEnd)) closure[numCorners++] = p;
5294       }
5295       ierr = DMPlexGetRawFaces_Internal(dm, dim-h, numCorners, closure, &numFaces, &faceSize, &faces);CHKERRQ(ierr);
5296       if (coneSize != numFaces) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cell %d has %d faces but should have %d", c, coneSize, numFaces);
5297       for (f = 0; f < numFaces; ++f) {
5298         PetscInt *fclosure = NULL, fclosureSize, cl, fnumCorners = 0, v;
5299 
5300         ierr = DMPlexGetTransitiveClosure_Internal(dm, cone[f], ornt[f], PETSC_TRUE, &fclosureSize, &fclosure);CHKERRQ(ierr);
5301         for (cl = 0; cl < fclosureSize*2; cl += 2) {
5302           const PetscInt p = fclosure[cl];
5303           if ((p >= vStart) && (p < vEnd)) fclosure[fnumCorners++] = p;
5304         }
5305         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);
5306         for (v = 0; v < fnumCorners; ++v) {
5307           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]);
5308         }
5309         ierr = DMPlexRestoreTransitiveClosure(dm, cone[f], PETSC_TRUE, &fclosureSize, &fclosure);CHKERRQ(ierr);
5310       }
5311       ierr = DMPlexRestoreFaces_Internal(dm, dim, c, &numFaces, &faceSize, &faces);CHKERRQ(ierr);
5312       ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
5313     }
5314   }
5315   PetscFunctionReturn(0);
5316 }
5317 
5318 #undef __FUNCT__
5319 #define __FUNCT__ "DMCreateInterpolation_Plex"
5320 /* Pointwise interpolation
5321      Just code FEM for now
5322      u^f = I u^c
5323      sum_k u^f_k phi^f_k = I sum_j u^c_j phi^c_j
5324      u^f_i = sum_j psi^f_i I phi^c_j u^c_j
5325      I_{ij} = psi^f_i phi^c_j
5326 */
5327 PetscErrorCode DMCreateInterpolation_Plex(DM dmCoarse, DM dmFine, Mat *interpolation, Vec *scaling)
5328 {
5329   PetscSection   gsc, gsf;
5330   PetscInt       m, n;
5331   void          *ctx;
5332   PetscErrorCode ierr;
5333 
5334   PetscFunctionBegin;
5335   /*
5336   Loop over coarse cells
5337     Loop over coarse basis functions
5338       Loop over fine cells in coarse cell
5339         Loop over fine dual basis functions
5340           Evaluate coarse basis on fine dual basis quad points
5341           Sum
5342           Update local element matrix
5343     Accumulate to interpolation matrix
5344 
5345    Can extend PetscFEIntegrateJacobian_Basic() to do a specialized cell loop
5346   */
5347   ierr = DMGetDefaultGlobalSection(dmFine, &gsf);CHKERRQ(ierr);
5348   ierr = PetscSectionGetConstrainedStorageSize(gsf, &m);CHKERRQ(ierr);
5349   ierr = DMGetDefaultGlobalSection(dmCoarse, &gsc);CHKERRQ(ierr);
5350   ierr = PetscSectionGetConstrainedStorageSize(gsc, &n);CHKERRQ(ierr);
5351   /* We need to preallocate properly */
5352   ierr = MatCreate(PetscObjectComm((PetscObject) dmCoarse), interpolation);CHKERRQ(ierr);
5353   ierr = MatSetSizes(*interpolation, m, n, PETSC_DETERMINE, PETSC_DETERMINE);CHKERRQ(ierr);
5354   ierr = MatSetType(*interpolation, dmCoarse->mattype);CHKERRQ(ierr);
5355   ierr = DMGetApplicationContext(dmFine, &ctx);CHKERRQ(ierr);
5356   ierr = DMPlexComputeInterpolatorFEM(dmCoarse, dmFine, *interpolation, ctx);CHKERRQ(ierr);
5357   /* Use naive scaling */
5358   ierr = DMCreateInterpolationScale(dmCoarse, dmFine, *interpolation, scaling);CHKERRQ(ierr);
5359   PetscFunctionReturn(0);
5360 }
5361 
5362 #undef __FUNCT__
5363 #define __FUNCT__ "DMCreateInjection_Plex"
5364 PetscErrorCode DMCreateInjection_Plex(DM dmCoarse, DM dmFine, VecScatter *ctx)
5365 {
5366   PetscErrorCode ierr;
5367 
5368   PetscFunctionBegin;
5369   ierr = DMPlexComputeInjectorFEM(dmCoarse, dmFine, ctx, NULL);CHKERRQ(ierr);
5370   PetscFunctionReturn(0);
5371 }
5372 
5373 #undef __FUNCT__
5374 #define __FUNCT__ "DMCreateDefaultSection_Plex"
5375 PetscErrorCode DMCreateDefaultSection_Plex(DM dm)
5376 {
5377   PetscSection   section;
5378   IS            *bcPoints;
5379   PetscBool     *isFE;
5380   PetscInt      *bcFields, *numComp, *numDof;
5381   PetscInt       depth, dim, numBd, numBC = 0, numFields, bd, bc = 0, f;
5382   PetscInt       cStart, cEnd, cEndInterior;
5383   PetscErrorCode ierr;
5384 
5385   PetscFunctionBegin;
5386   ierr = DMGetNumFields(dm, &numFields);CHKERRQ(ierr);
5387   /* FE and FV boundary conditions are handled slightly differently */
5388   ierr = PetscMalloc1(numFields, &isFE);CHKERRQ(ierr);
5389   for (f = 0; f < numFields; ++f) {
5390     PetscObject  obj;
5391     PetscClassId id;
5392 
5393     ierr = DMGetField(dm, f, &obj);CHKERRQ(ierr);
5394     ierr = PetscObjectGetClassId(obj, &id);CHKERRQ(ierr);
5395     if (id == PETSCFE_CLASSID)      {isFE[f] = PETSC_TRUE;}
5396     else if (id == PETSCFV_CLASSID) {isFE[f] = PETSC_FALSE;}
5397     else SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %d", f);
5398   }
5399   /* Allocate boundary point storage for FEM boundaries */
5400   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
5401   ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr);
5402   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
5403   ierr = DMPlexGetHybridBounds(dm, &cEndInterior, NULL, NULL, NULL);CHKERRQ(ierr);
5404   ierr = DMPlexGetNumBoundary(dm, &numBd);CHKERRQ(ierr);
5405   for (bd = 0; bd < numBd; ++bd) {
5406     PetscInt  field;
5407     PetscBool isEssential;
5408 
5409     ierr = DMPlexGetBoundary(dm, bd, &isEssential, NULL, NULL, &field, NULL, NULL, NULL, NULL);CHKERRQ(ierr);
5410     if (isFE[field] && isEssential) ++numBC;
5411   }
5412   /* Add ghost cell boundaries for FVM */
5413   for (f = 0; f < numFields; ++f) if (!isFE[f] && cEndInterior >= 0) ++numBC;
5414   ierr = PetscMalloc2(numBC,&bcFields,numBC,&bcPoints);CHKERRQ(ierr);
5415   /* Constrain ghost cells for FV */
5416   for (f = 0; f < numFields; ++f) {
5417     PetscInt *newidx, c;
5418 
5419     if (isFE[f] || cEndInterior < 0) continue;
5420     ierr = PetscMalloc1(cEnd-cEndInterior,&newidx);CHKERRQ(ierr);
5421     for (c = cEndInterior; c < cEnd; ++c) newidx[c-cEndInterior] = c;
5422     bcFields[bc] = f;
5423     ierr = ISCreateGeneral(PetscObjectComm((PetscObject) dm), cEnd-cEndInterior, newidx, PETSC_OWN_POINTER, &bcPoints[bc++]);CHKERRQ(ierr);
5424   }
5425   /* Handle FEM Dirichlet boundaries */
5426   for (bd = 0; bd < numBd; ++bd) {
5427     const char     *bdLabel;
5428     DMLabel         label;
5429     const PetscInt *values;
5430     PetscInt        bd2, field, numValues;
5431     PetscBool       isEssential, duplicate = PETSC_FALSE;
5432 
5433     ierr = DMPlexGetBoundary(dm, bd, &isEssential, NULL, &bdLabel, &field, NULL, &numValues, &values, NULL);CHKERRQ(ierr);
5434     if (!isFE[field]) continue;
5435     ierr = DMPlexGetLabel(dm, bdLabel, &label);CHKERRQ(ierr);
5436     /* Only want to modify label once */
5437     for (bd2 = 0; bd2 < bd; ++bd2) {
5438       const char *bdname;
5439       ierr = DMPlexGetBoundary(dm, bd2, NULL, NULL, &bdname, NULL, NULL, NULL, NULL, NULL);CHKERRQ(ierr);
5440       ierr = PetscStrcmp(bdname, bdLabel, &duplicate);CHKERRQ(ierr);
5441       if (duplicate) break;
5442     }
5443     if (!duplicate && (isFE[field])) {
5444       ierr = DMPlexLabelComplete(dm, label);CHKERRQ(ierr);
5445       ierr = DMPlexLabelAddCells(dm, label);CHKERRQ(ierr);
5446     }
5447     /* Filter out cells, if you actually want to constrain cells you need to do things by hand right now */
5448     if (isEssential) {
5449       PetscInt       *newidx;
5450       PetscInt        n, newn = 0, p, v;
5451 
5452       bcFields[bc] = field;
5453       for (v = 0; v < numValues; ++v) {
5454         IS              tmp;
5455         const PetscInt *idx;
5456 
5457         ierr = DMPlexGetStratumIS(dm, bdLabel, values[v], &tmp);CHKERRQ(ierr);
5458         if (!tmp) continue;
5459         ierr = ISGetLocalSize(tmp, &n);CHKERRQ(ierr);
5460         ierr = ISGetIndices(tmp, &idx);CHKERRQ(ierr);
5461         if (isFE[field]) {
5462           for (p = 0; p < n; ++p) if ((idx[p] < cStart) || (idx[p] >= cEnd)) ++newn;
5463         } else {
5464           for (p = 0; p < n; ++p) if ((idx[p] >= cStart) || (idx[p] < cEnd)) ++newn;
5465         }
5466         ierr = ISRestoreIndices(tmp, &idx);CHKERRQ(ierr);
5467         ierr = ISDestroy(&tmp);CHKERRQ(ierr);
5468       }
5469       ierr = PetscMalloc1(newn,&newidx);CHKERRQ(ierr);
5470       newn = 0;
5471       for (v = 0; v < numValues; ++v) {
5472         IS              tmp;
5473         const PetscInt *idx;
5474 
5475         ierr = DMPlexGetStratumIS(dm, bdLabel, values[v], &tmp);CHKERRQ(ierr);
5476         if (!tmp) continue;
5477         ierr = ISGetLocalSize(tmp, &n);CHKERRQ(ierr);
5478         ierr = ISGetIndices(tmp, &idx);CHKERRQ(ierr);
5479         if (isFE[field]) {
5480           for (p = 0; p < n; ++p) if ((idx[p] < cStart) || (idx[p] >= cEnd)) newidx[newn++] = idx[p];
5481         } else {
5482           for (p = 0; p < n; ++p) if ((idx[p] >= cStart) || (idx[p] < cEnd)) newidx[newn++] = idx[p];
5483         }
5484         ierr = ISRestoreIndices(tmp, &idx);CHKERRQ(ierr);
5485         ierr = ISDestroy(&tmp);CHKERRQ(ierr);
5486       }
5487       ierr = ISCreateGeneral(PetscObjectComm((PetscObject) dm), newn, newidx, PETSC_OWN_POINTER, &bcPoints[bc++]);CHKERRQ(ierr);
5488     }
5489   }
5490   /* Handle discretization */
5491   ierr = PetscCalloc2(numFields,&numComp,numFields*(dim+1),&numDof);CHKERRQ(ierr);
5492   for (f = 0; f < numFields; ++f) {
5493     PetscObject obj;
5494 
5495     ierr = DMGetField(dm, f, &obj);CHKERRQ(ierr);
5496     if (isFE[f]) {
5497       PetscFE         fe = (PetscFE) obj;
5498       const PetscInt *numFieldDof;
5499       PetscInt        d;
5500 
5501       ierr = PetscFEGetNumComponents(fe, &numComp[f]);CHKERRQ(ierr);
5502       ierr = PetscFEGetNumDof(fe, &numFieldDof);CHKERRQ(ierr);
5503       for (d = 0; d < dim+1; ++d) numDof[f*(dim+1)+d] = numFieldDof[d];
5504     } else {
5505       PetscFV fv = (PetscFV) obj;
5506 
5507       ierr = PetscFVGetNumComponents(fv, &numComp[f]);CHKERRQ(ierr);
5508       numDof[f*(dim+1)+dim] = numComp[f];
5509     }
5510   }
5511   for (f = 0; f < numFields; ++f) {
5512     PetscInt d;
5513     for (d = 1; d < dim; ++d) {
5514       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.");
5515     }
5516   }
5517   ierr = DMPlexCreateSection(dm, dim, numFields, numComp, numDof, numBC, bcFields, bcPoints, NULL, &section);CHKERRQ(ierr);
5518   for (f = 0; f < numFields; ++f) {
5519     PetscFE     fe;
5520     const char *name;
5521 
5522     ierr = DMGetField(dm, f, (PetscObject *) &fe);CHKERRQ(ierr);
5523     ierr = PetscObjectGetName((PetscObject) fe, &name);CHKERRQ(ierr);
5524     ierr = PetscSectionSetFieldName(section, f, name);CHKERRQ(ierr);
5525   }
5526   ierr = DMSetDefaultSection(dm, section);CHKERRQ(ierr);
5527   ierr = PetscSectionDestroy(&section);CHKERRQ(ierr);
5528   for (bc = 0; bc < numBC; ++bc) {ierr = ISDestroy(&bcPoints[bc]);CHKERRQ(ierr);}
5529   ierr = PetscFree2(bcFields,bcPoints);CHKERRQ(ierr);
5530   ierr = PetscFree2(numComp,numDof);CHKERRQ(ierr);
5531   ierr = PetscFree(isFE);CHKERRQ(ierr);
5532   PetscFunctionReturn(0);
5533 }
5534 
5535 #undef __FUNCT__
5536 #define __FUNCT__ "DMPlexGetCoarseDM"
5537 /*@
5538   DMPlexGetCoarseDM - Get the coarse mesh from which this was obtained by refinement
5539 
5540   Input Parameter:
5541 . dm - The DMPlex object
5542 
5543   Output Parameter:
5544 . cdm - The coarse DM
5545 
5546   Level: intermediate
5547 
5548 .seealso: DMPlexSetCoarseDM()
5549 @*/
5550 PetscErrorCode DMPlexGetCoarseDM(DM dm, DM *cdm)
5551 {
5552   PetscFunctionBegin;
5553   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5554   PetscValidPointer(cdm, 2);
5555   *cdm = ((DM_Plex *) dm->data)->coarseMesh;
5556   PetscFunctionReturn(0);
5557 }
5558 
5559 #undef __FUNCT__
5560 #define __FUNCT__ "DMPlexSetCoarseDM"
5561 /*@
5562   DMPlexSetCoarseDM - Set the coarse mesh from which this was obtained by refinement
5563 
5564   Input Parameters:
5565 + dm - The DMPlex object
5566 - cdm - The coarse DM
5567 
5568   Level: intermediate
5569 
5570 .seealso: DMPlexGetCoarseDM()
5571 @*/
5572 PetscErrorCode DMPlexSetCoarseDM(DM dm, DM cdm)
5573 {
5574   DM_Plex       *mesh;
5575   PetscErrorCode ierr;
5576 
5577   PetscFunctionBegin;
5578   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5579   if (cdm) PetscValidHeaderSpecific(cdm, DM_CLASSID, 2);
5580   mesh = (DM_Plex *) dm->data;
5581   ierr = DMDestroy(&mesh->coarseMesh);CHKERRQ(ierr);
5582   mesh->coarseMesh = cdm;
5583   ierr = PetscObjectReference((PetscObject) mesh->coarseMesh);CHKERRQ(ierr);
5584   PetscFunctionReturn(0);
5585 }
5586 
5587 /* anchors */
5588 #undef __FUNCT__
5589 #define __FUNCT__ "DMPlexGetAnchors"
5590 /*@
5591   DMPlexGetAnchors - Get the layout of the anchor (point-to-point) constraints.  Typically, the user will not have to
5592   call DMPlexGetAnchors() directly: if there are anchors, then DMPlexGetAnchors() is called during DMGetConstraints().
5593 
5594   not collective
5595 
5596   Input Parameters:
5597 . dm - The DMPlex object
5598 
5599   Output Parameters:
5600 + anchorSection - If not NULL, set to the section describing which points anchor the constrained points.
5601 - anchorIS - If not NULL, set to the list of anchors indexed by anchorSection
5602 
5603 
5604   Level: intermediate
5605 
5606 .seealso: DMPlexSetAnchors(), DMGetConstraints(), DMSetConstraints()
5607 @*/
5608 PetscErrorCode DMPlexGetAnchors(DM dm, PetscSection *anchorSection, IS *anchorIS)
5609 {
5610   DM_Plex *plex = (DM_Plex *)dm->data;
5611   PetscErrorCode ierr;
5612 
5613   PetscFunctionBegin;
5614   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5615   if (!plex->anchorSection && !plex->anchorIS && plex->createanchors) {ierr = (*plex->createanchors)(dm);CHKERRQ(ierr);}
5616   if (anchorSection) *anchorSection = plex->anchorSection;
5617   if (anchorIS) *anchorIS = plex->anchorIS;
5618   PetscFunctionReturn(0);
5619 }
5620 
5621 #undef __FUNCT__
5622 #define __FUNCT__ "DMPlexSetAnchors"
5623 /*@
5624   DMPlexSetAnchors - Set the layout of the local anchor (point-to-point) constraints.  Unlike boundary conditions,
5625   when a point's degrees of freedom in a section are constrained to an outside value, the anchor constraints set a
5626   point's degrees of freedom to be a linear combination of other points' degrees of freedom.
5627 
5628   After specifying the layout of constraints with DMPlexSetAnchors(), one specifies the constraints by calling
5629   DMGetConstraints() and filling in the entries in the constraint matrix.
5630 
5631   collective on dm
5632 
5633   Input Parameters:
5634 + dm - The DMPlex object
5635 . 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).
5636 - anchorIS - The list of all anchor points.  Must have a local communicator (PETSC_COMM_SELF or derivative).
5637 
5638   The reference counts of anchorSection and anchorIS are incremented.
5639 
5640   Level: intermediate
5641 
5642 .seealso: DMPlexGetAnchors(), DMGetConstraints(), DMSetConstraints()
5643 @*/
5644 PetscErrorCode DMPlexSetAnchors(DM dm, PetscSection anchorSection, IS anchorIS)
5645 {
5646   DM_Plex *plex = (DM_Plex *)dm->data;
5647   PetscMPIInt result;
5648   PetscErrorCode ierr;
5649 
5650   PetscFunctionBegin;
5651   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5652   if (anchorSection) {
5653     PetscValidHeaderSpecific(anchorSection,PETSC_SECTION_CLASSID,2);
5654     ierr = MPI_Comm_compare(PETSC_COMM_SELF,PetscObjectComm((PetscObject)anchorSection),&result);CHKERRQ(ierr);
5655     if (result != MPI_CONGRUENT) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_NOTSAMECOMM,"anchor section must have local communicator");
5656   }
5657   if (anchorIS) {
5658     PetscValidHeaderSpecific(anchorIS,IS_CLASSID,3);
5659     ierr = MPI_Comm_compare(PETSC_COMM_SELF,PetscObjectComm((PetscObject)anchorIS),&result);CHKERRQ(ierr);
5660     if (result != MPI_CONGRUENT) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_NOTSAMECOMM,"anchor IS must have local communicator");
5661   }
5662 
5663   ierr = PetscObjectReference((PetscObject)anchorSection);CHKERRQ(ierr);
5664   ierr = PetscSectionDestroy(&plex->anchorSection);CHKERRQ(ierr);
5665   plex->anchorSection = anchorSection;
5666 
5667   ierr = PetscObjectReference((PetscObject)anchorIS);CHKERRQ(ierr);
5668   ierr = ISDestroy(&plex->anchorIS);CHKERRQ(ierr);
5669   plex->anchorIS = anchorIS;
5670 
5671 #if defined(PETSC_USE_DEBUG)
5672   if (anchorIS && anchorSection) {
5673     PetscInt size, a, pStart, pEnd;
5674     const PetscInt *anchors;
5675 
5676     ierr = PetscSectionGetChart(anchorSection,&pStart,&pEnd);CHKERRQ(ierr);
5677     ierr = ISGetLocalSize(anchorIS,&size);CHKERRQ(ierr);
5678     ierr = ISGetIndices(anchorIS,&anchors);CHKERRQ(ierr);
5679     for (a = 0; a < size; a++) {
5680       PetscInt p;
5681 
5682       p = anchors[a];
5683       if (p >= pStart && p < pEnd) {
5684         PetscInt dof;
5685 
5686         ierr = PetscSectionGetDof(anchorSection,p,&dof);CHKERRQ(ierr);
5687         if (dof) {
5688           PetscErrorCode ierr2;
5689 
5690           ierr2 = ISRestoreIndices(anchorIS,&anchors);CHKERRQ(ierr2);
5691           SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Point %d cannot be constrained and an anchor",p);
5692         }
5693       }
5694     }
5695     ierr = ISRestoreIndices(anchorIS,&anchors);CHKERRQ(ierr);
5696   }
5697 #endif
5698   /* reset the generic constraints */
5699   ierr = DMSetDefaultConstraints(dm,NULL,NULL);CHKERRQ(ierr);
5700   PetscFunctionReturn(0);
5701 }
5702 
5703 #undef __FUNCT__
5704 #define __FUNCT__ "DMPlexCreateConstraintSection_Anchors"
5705 static PetscErrorCode DMPlexCreateConstraintSection_Anchors(DM dm, PetscSection section, PetscSection *cSec)
5706 {
5707   PetscSection anchorSection;
5708   PetscInt pStart, pEnd, p, dof, numFields, f;
5709   PetscErrorCode ierr;
5710 
5711   PetscFunctionBegin;
5712   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5713   ierr = DMPlexGetAnchors(dm,&anchorSection,NULL);CHKERRQ(ierr);
5714   ierr = PetscSectionCreate(PETSC_COMM_SELF,cSec);CHKERRQ(ierr);
5715   ierr = PetscSectionGetNumFields(section,&numFields);CHKERRQ(ierr);
5716   ierr = PetscSectionSetNumFields(*cSec,numFields);CHKERRQ(ierr);
5717   ierr = PetscSectionGetChart(anchorSection,&pStart,&pEnd);CHKERRQ(ierr);
5718   ierr = PetscSectionSetChart(*cSec,pStart,pEnd);CHKERRQ(ierr);
5719   for (p = pStart; p < pEnd; p++) {
5720     ierr = PetscSectionGetDof(anchorSection,p,&dof);CHKERRQ(ierr);
5721     if (dof) {
5722       ierr = PetscSectionGetDof(section,p,&dof);CHKERRQ(ierr);
5723       ierr = PetscSectionSetDof(*cSec,p,dof);CHKERRQ(ierr);
5724       for (f = 0; f < numFields; f++) {
5725         ierr = PetscSectionGetFieldDof(section,p,f,&dof);CHKERRQ(ierr);
5726         ierr = PetscSectionSetFieldDof(*cSec,p,f,dof);CHKERRQ(ierr);
5727       }
5728     }
5729   }
5730   ierr = PetscSectionSetUp(*cSec);CHKERRQ(ierr);
5731   PetscFunctionReturn(0);
5732 }
5733 
5734 #undef __FUNCT__
5735 #define __FUNCT__ "DMPlexCreateConstraintMatrix_Anchors"
5736 static PetscErrorCode DMPlexCreateConstraintMatrix_Anchors(DM dm, PetscSection section, PetscSection cSec, Mat *cMat)
5737 {
5738   PetscSection aSec;
5739   PetscInt pStart, pEnd, p, dof, aDof, aOff, off, nnz, annz, m, n, q, a, offset, *i, *j;
5740   const PetscInt *anchors;
5741   PetscInt numFields, f;
5742   IS aIS;
5743   PetscErrorCode ierr;
5744 
5745   PetscFunctionBegin;
5746   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5747   ierr = PetscSectionGetStorageSize(cSec, &m);CHKERRQ(ierr);
5748   ierr = PetscSectionGetStorageSize(section, &n);CHKERRQ(ierr);
5749   ierr = MatCreate(PETSC_COMM_SELF,cMat);CHKERRQ(ierr);
5750   ierr = MatSetSizes(*cMat,m,n,m,n);CHKERRQ(ierr);
5751   ierr = MatSetType(*cMat,MATSEQAIJ);
5752   ierr = DMPlexGetAnchors(dm,&aSec,&aIS);CHKERRQ(ierr);
5753   ierr = ISGetIndices(aIS,&anchors);CHKERRQ(ierr);
5754   ierr = PetscSectionGetChart(aSec,&pStart,&pEnd);CHKERRQ(ierr);
5755   ierr = PetscMalloc1(m+1,&i);CHKERRQ(ierr);
5756   i[0] = 0;
5757   ierr = PetscSectionGetNumFields(section,&numFields);CHKERRQ(ierr);
5758   for (p = pStart; p < pEnd; p++) {
5759     ierr = PetscSectionGetDof(aSec,p,&dof);CHKERRQ(ierr);
5760     if (!dof) continue;
5761     ierr = PetscSectionGetOffset(aSec,p,&off);CHKERRQ(ierr);
5762     if (numFields) {
5763       for (f = 0; f < numFields; f++) {
5764         annz = 0;
5765         for (q = 0; q < dof; q++) {
5766           a = anchors[off + q];
5767           ierr = PetscSectionGetFieldDof(section,a,f,&aDof);CHKERRQ(ierr);
5768           annz += aDof;
5769         }
5770         ierr = PetscSectionGetFieldDof(cSec,p,f,&dof);CHKERRQ(ierr);
5771         ierr = PetscSectionGetFieldOffset(cSec,p,f,&off);CHKERRQ(ierr);
5772         for (q = 0; q < dof; q++) {
5773           i[off + q + 1] = i[off + q] + annz;
5774         }
5775       }
5776     }
5777     else {
5778       annz = 0;
5779       for (q = 0; q < dof; q++) {
5780         a = anchors[off + q];
5781         ierr = PetscSectionGetDof(section,a,&aDof);CHKERRQ(ierr);
5782         annz += aDof;
5783       }
5784       ierr = PetscSectionGetDof(cSec,p,&dof);CHKERRQ(ierr);
5785       ierr = PetscSectionGetOffset(cSec,p,&off);CHKERRQ(ierr);
5786       for (q = 0; q < dof; q++) {
5787         i[off + q + 1] = i[off + q] + annz;
5788       }
5789     }
5790   }
5791   nnz = i[m];
5792   ierr = PetscMalloc1(nnz,&j);CHKERRQ(ierr);
5793   offset = 0;
5794   for (p = pStart; p < pEnd; p++) {
5795     if (numFields) {
5796       for (f = 0; f < numFields; f++) {
5797         ierr = PetscSectionGetFieldDof(cSec,p,f,&dof);CHKERRQ(ierr);
5798         for (q = 0; q < dof; q++) {
5799           PetscInt rDof, rOff, r;
5800           ierr = PetscSectionGetDof(aSec,p,&rDof);CHKERRQ(ierr);
5801           ierr = PetscSectionGetOffset(aSec,p,&rOff);CHKERRQ(ierr);
5802           for (r = 0; r < rDof; r++) {
5803             PetscInt s;
5804 
5805             a = anchors[rOff + r];
5806 
5807             ierr = PetscSectionGetFieldDof(section,a,f,&aDof);CHKERRQ(ierr);
5808             ierr = PetscSectionGetFieldOffset(section,a,f,&aOff);CHKERRQ(ierr);
5809             for (s = 0; s < aDof; s++) {
5810               j[offset++] = aOff + s;
5811             }
5812           }
5813         }
5814       }
5815     }
5816     else {
5817       ierr = PetscSectionGetDof(cSec,p,&dof);CHKERRQ(ierr);
5818       for (q = 0; q < dof; q++) {
5819         PetscInt rDof, rOff, r;
5820         ierr = PetscSectionGetDof(aSec,p,&rDof);CHKERRQ(ierr);
5821         ierr = PetscSectionGetOffset(aSec,p,&rOff);CHKERRQ(ierr);
5822         for (r = 0; r < rDof; r++) {
5823           PetscInt s;
5824 
5825           a = anchors[rOff + r];
5826 
5827           ierr = PetscSectionGetDof(section,a,&aDof);CHKERRQ(ierr);
5828           ierr = PetscSectionGetOffset(section,a,&aOff);CHKERRQ(ierr);
5829           for (s = 0; s < aDof; s++) {
5830             j[offset++] = aOff + s;
5831           }
5832         }
5833       }
5834     }
5835   }
5836   ierr = MatSeqAIJSetPreallocationCSR(*cMat,i,j,NULL);CHKERRQ(ierr);
5837   ierr = PetscFree2(i,j);CHKERRQ(ierr);
5838   ierr = ISRestoreIndices(aIS,&anchors);CHKERRQ(ierr);
5839   PetscFunctionReturn(0);
5840 }
5841 
5842 #undef __FUNCT__
5843 #define __FUNCT__ "DMCreateDefaultConstraints_Plex"
5844 PetscErrorCode DMCreateDefaultConstraints_Plex(DM dm)
5845 {
5846   DM_Plex        *plex = (DM_Plex *)dm->data;
5847   PetscSection   anchorSection, section, cSec;
5848   Mat            cMat;
5849   PetscErrorCode ierr;
5850 
5851   PetscFunctionBegin;
5852   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5853   ierr = DMPlexGetAnchors(dm,&anchorSection,NULL);CHKERRQ(ierr);
5854   if (anchorSection) {
5855     PetscDS  ds;
5856     PetscInt nf;
5857 
5858     ierr = DMGetDefaultSection(dm,&section);CHKERRQ(ierr);
5859     ierr = DMPlexCreateConstraintSection_Anchors(dm,section,&cSec);CHKERRQ(ierr);
5860     ierr = DMPlexCreateConstraintMatrix_Anchors(dm,section,cSec,&cMat);CHKERRQ(ierr);
5861     ierr = DMGetDS(dm,&ds);CHKERRQ(ierr);
5862     ierr = PetscDSGetNumFields(ds,&nf);
5863     if (nf && plex->computeanchormatrix) {ierr = (*plex->computeanchormatrix)(dm,section,cSec,cMat);CHKERRQ(ierr);}
5864     ierr = DMSetDefaultConstraints(dm,cSec,cMat);CHKERRQ(ierr);
5865     ierr = PetscSectionDestroy(&cSec);CHKERRQ(ierr);
5866     ierr = MatDestroy(&cMat);CHKERRQ(ierr);
5867   }
5868   PetscFunctionReturn(0);
5869 }
5870