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