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