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