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