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