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