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