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