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