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