xref: /petsc/src/dm/impls/plex/plex.c (revision 4fc747eaadbeca11629f314a99edccbc2ed7b3d3)
1 #include <petsc/private/dmpleximpl.h>   /*I      "petscdmplex.h"   I*/
2 #include <petsc/private/isimpl.h>
3 #include <petsc/private/vecimpl.h>
4 #include <petscsf.h>
5 #include <petscds.h>
6 
7 /* Logging support */
8 PetscLogEvent DMPLEX_Interpolate, PETSCPARTITIONER_Partition, DMPLEX_Distribute, DMPLEX_DistributeCones, DMPLEX_DistributeLabels, DMPLEX_DistributeSF, DMPLEX_DistributeOverlap, DMPLEX_DistributeField, DMPLEX_DistributeData, DMPLEX_Migrate, DMPLEX_GlobalToNaturalBegin, DMPLEX_GlobalToNaturalEnd, DMPLEX_NaturalToGlobalBegin, DMPLEX_NaturalToGlobalEnd, DMPLEX_Stratify, DMPLEX_Preallocate, DMPLEX_ResidualFEM, DMPLEX_JacobianFEM, DMPLEX_InterpolatorFEM, DMPLEX_InjectorFEM, DMPLEX_IntegralFEM, DMPLEX_CreateGmsh;
9 
10 PETSC_EXTERN PetscErrorCode VecView_MPI(Vec, PetscViewer);
11 PETSC_EXTERN PetscErrorCode VecLoad_Default(Vec, PetscViewer);
12 
13 #undef __FUNCT__
14 #define __FUNCT__ "DMPlexGetFieldType_Internal"
15 PetscErrorCode DMPlexGetFieldType_Internal(DM dm, PetscSection section, PetscInt field, PetscInt *sStart, PetscInt *sEnd, PetscViewerVTKFieldType *ft)
16 {
17   PetscInt       dim, pStart, pEnd, vStart, vEnd, cStart, cEnd, cEndInterior, vdof = 0, cdof = 0;
18   PetscErrorCode ierr;
19 
20   PetscFunctionBegin;
21   *ft  = PETSC_VTK_POINT_FIELD;
22   ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr);
23   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
24   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
25   ierr = DMPlexGetHybridBounds(dm, &cEndInterior, NULL, NULL, NULL);CHKERRQ(ierr);
26   cEnd = cEndInterior < 0 ? cEnd : cEndInterior;
27   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
28   if (field >= 0) {
29     if ((vStart >= pStart) && (vStart < pEnd)) {ierr = PetscSectionGetFieldDof(section, vStart, field, &vdof);CHKERRQ(ierr);}
30     if ((cStart >= pStart) && (cStart < pEnd)) {ierr = PetscSectionGetFieldDof(section, cStart, field, &cdof);CHKERRQ(ierr);}
31   } else {
32     if ((vStart >= pStart) && (vStart < pEnd)) {ierr = PetscSectionGetDof(section, vStart, &vdof);CHKERRQ(ierr);}
33     if ((cStart >= pStart) && (cStart < pEnd)) {ierr = PetscSectionGetDof(section, cStart, &cdof);CHKERRQ(ierr);}
34   }
35   if (vdof) {
36     *sStart = vStart;
37     *sEnd   = vEnd;
38     if (vdof == dim) *ft = PETSC_VTK_POINT_VECTOR_FIELD;
39     else             *ft = PETSC_VTK_POINT_FIELD;
40   } else if (cdof) {
41     *sStart = cStart;
42     *sEnd   = cEnd;
43     if (cdof == dim) *ft = PETSC_VTK_CELL_VECTOR_FIELD;
44     else             *ft = PETSC_VTK_CELL_FIELD;
45   } else SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "Could not classify input Vec for VTK");
46   PetscFunctionReturn(0);
47 }
48 
49 #undef __FUNCT__
50 #define __FUNCT__ "VecView_Plex_Local"
51 PetscErrorCode VecView_Plex_Local(Vec v, PetscViewer viewer)
52 {
53   DM             dm;
54   PetscBool      isvtk, ishdf5, isseq;
55   PetscErrorCode ierr;
56 
57   PetscFunctionBegin;
58   ierr = VecGetDM(v, &dm);CHKERRQ(ierr);
59   if (!dm) SETERRQ(PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
60   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERVTK,  &isvtk);CHKERRQ(ierr);
61   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5);CHKERRQ(ierr);
62   ierr = PetscObjectTypeCompare((PetscObject) v, VECSEQ, &isseq);CHKERRQ(ierr);
63   if (isvtk || ishdf5) {
64     PetscInt  numFields;
65     PetscBool fem = PETSC_FALSE;
66 
67     ierr = DMGetNumFields(dm, &numFields);CHKERRQ(ierr);
68     if (numFields) {
69       PetscObject fe;
70 
71       ierr = DMGetField(dm, 0, &fe);CHKERRQ(ierr);
72       if (fe->classid == PETSCFE_CLASSID) fem = PETSC_TRUE;
73     }
74     if (fem) {ierr = DMPlexInsertBoundaryValues(dm, PETSC_TRUE, v, 0.0, NULL, NULL, NULL);CHKERRQ(ierr);}
75   }
76   if (isvtk) {
77     PetscSection            section;
78     PetscViewerVTKFieldType ft;
79     PetscInt                pStart, pEnd;
80 
81     ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
82     ierr = DMPlexGetFieldType_Internal(dm, section, PETSC_DETERMINE, &pStart, &pEnd, &ft);CHKERRQ(ierr);
83     ierr = PetscObjectReference((PetscObject) dm);CHKERRQ(ierr); /* viewer drops reference */
84     ierr = PetscObjectReference((PetscObject) v);CHKERRQ(ierr);  /* viewer drops reference */
85     ierr = PetscViewerVTKAddField(viewer, (PetscObject) dm, DMPlexVTKWriteAll, ft, (PetscObject) v);CHKERRQ(ierr);
86   } else if (ishdf5) {
87 #if defined(PETSC_HAVE_HDF5)
88     ierr = VecView_Plex_Local_HDF5(v, viewer);CHKERRQ(ierr);
89 #else
90     SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
91 #endif
92   } else {
93     if (isseq) {ierr = VecView_Seq(v, viewer);CHKERRQ(ierr);}
94     else       {ierr = VecView_MPI(v, viewer);CHKERRQ(ierr);}
95   }
96   PetscFunctionReturn(0);
97 }
98 
99 #undef __FUNCT__
100 #define __FUNCT__ "VecView_Plex"
101 PetscErrorCode VecView_Plex(Vec v, PetscViewer viewer)
102 {
103   DM             dm;
104   PetscBool      isvtk, ishdf5, isseq;
105   PetscErrorCode ierr;
106 
107   PetscFunctionBegin;
108   ierr = VecGetDM(v, &dm);CHKERRQ(ierr);
109   if (!dm) SETERRQ(PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
110   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERVTK,  &isvtk);CHKERRQ(ierr);
111   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5);CHKERRQ(ierr);
112   ierr = PetscObjectTypeCompare((PetscObject) v, VECSEQ, &isseq);CHKERRQ(ierr);
113   if (isvtk) {
114     Vec         locv;
115     const char *name;
116 
117     ierr = DMGetLocalVector(dm, &locv);CHKERRQ(ierr);
118     ierr = PetscObjectGetName((PetscObject) v, &name);CHKERRQ(ierr);
119     ierr = PetscObjectSetName((PetscObject) locv, name);CHKERRQ(ierr);
120     ierr = DMGlobalToLocalBegin(dm, v, INSERT_VALUES, locv);CHKERRQ(ierr);
121     ierr = DMGlobalToLocalEnd(dm, v, INSERT_VALUES, locv);CHKERRQ(ierr);
122     ierr = VecView_Plex_Local(locv, viewer);CHKERRQ(ierr);
123     ierr = DMRestoreLocalVector(dm, &locv);CHKERRQ(ierr);
124   } else if (ishdf5) {
125 #if defined(PETSC_HAVE_HDF5)
126     ierr = VecView_Plex_HDF5(v, viewer);CHKERRQ(ierr);
127 #else
128     SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
129 #endif
130   } else {
131     if (isseq) {ierr = VecView_Seq(v, viewer);CHKERRQ(ierr);}
132     else       {ierr = VecView_MPI(v, viewer);CHKERRQ(ierr);}
133   }
134   PetscFunctionReturn(0);
135 }
136 
137 #undef __FUNCT__
138 #define __FUNCT__ "VecView_Plex_Native"
139 PetscErrorCode VecView_Plex_Native(Vec originalv, PetscViewer viewer)
140 {
141   DM                dm;
142   MPI_Comm          comm;
143   PetscViewerFormat format;
144   Vec               v;
145   PetscBool         isvtk, ishdf5;
146   PetscErrorCode    ierr;
147 
148   PetscFunctionBegin;
149   ierr = VecGetDM(originalv, &dm);CHKERRQ(ierr);
150   ierr = PetscObjectGetComm((PetscObject) originalv, &comm);CHKERRQ(ierr);
151   if (!dm) SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
152   ierr = PetscViewerGetFormat(viewer, &format);CHKERRQ(ierr);
153   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5);CHKERRQ(ierr);
154   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERVTK,  &isvtk);CHKERRQ(ierr);
155   if (format == PETSC_VIEWER_NATIVE) {
156     const char *vecname;
157     PetscInt    n, nroots;
158 
159     if (dm->sfNatural) {
160       ierr = VecGetLocalSize(originalv, &n);CHKERRQ(ierr);
161       ierr = PetscSFGetGraph(dm->sfNatural, &nroots, NULL, NULL, NULL);CHKERRQ(ierr);
162       if (n == nroots) {
163         ierr = DMGetGlobalVector(dm, &v);CHKERRQ(ierr);
164         ierr = DMPlexGlobalToNaturalBegin(dm, originalv, v);CHKERRQ(ierr);
165         ierr = DMPlexGlobalToNaturalEnd(dm, originalv, v);CHKERRQ(ierr);
166         ierr = PetscObjectGetName((PetscObject) originalv, &vecname);CHKERRQ(ierr);
167         ierr = PetscObjectSetName((PetscObject) v, vecname);CHKERRQ(ierr);
168       } else SETERRQ(comm, PETSC_ERR_ARG_WRONG, "DM global to natural SF only handles global vectors");
169     } else SETERRQ(comm, PETSC_ERR_ARG_WRONGSTATE, "DM global to natural SF was not created");
170   } else {
171     /* we are viewing a natural DMPlex vec. */
172     v = originalv;
173   }
174   if (ishdf5) {
175 #if defined(PETSC_HAVE_HDF5)
176     ierr = VecView_Plex_HDF5_Native(v, viewer);CHKERRQ(ierr);
177 #else
178     SETERRQ(comm, PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
179 #endif
180   } else if (isvtk) {
181     SETERRQ(comm, PETSC_ERR_SUP, "VTK format does not support viewing in natural order. Please switch to HDF5.");
182   } else {
183     PetscBool isseq;
184 
185     ierr = PetscObjectTypeCompare((PetscObject) v, VECSEQ, &isseq);CHKERRQ(ierr);
186     if (isseq) {ierr = VecView_Seq(v, viewer);CHKERRQ(ierr);}
187     else       {ierr = VecView_MPI(v, viewer);CHKERRQ(ierr);}
188   }
189   if (format == PETSC_VIEWER_NATIVE) {ierr = DMRestoreGlobalVector(dm, &v);CHKERRQ(ierr);}
190   PetscFunctionReturn(0);
191 }
192 
193 #undef __FUNCT__
194 #define __FUNCT__ "VecLoad_Plex_Local"
195 PetscErrorCode VecLoad_Plex_Local(Vec v, PetscViewer viewer)
196 {
197   DM             dm;
198   PetscBool      ishdf5;
199   PetscErrorCode ierr;
200 
201   PetscFunctionBegin;
202   ierr = VecGetDM(v, &dm);CHKERRQ(ierr);
203   if (!dm) SETERRQ(PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
204   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5);CHKERRQ(ierr);
205   if (ishdf5) {
206     DM          dmBC;
207     Vec         gv;
208     const char *name;
209 
210     ierr = DMGetOutputDM(dm, &dmBC);CHKERRQ(ierr);
211     ierr = DMGetGlobalVector(dmBC, &gv);CHKERRQ(ierr);
212     ierr = PetscObjectGetName((PetscObject) v, &name);CHKERRQ(ierr);
213     ierr = PetscObjectSetName((PetscObject) gv, name);CHKERRQ(ierr);
214     ierr = VecLoad_Default(gv, viewer);CHKERRQ(ierr);
215     ierr = DMGlobalToLocalBegin(dmBC, gv, INSERT_VALUES, v);CHKERRQ(ierr);
216     ierr = DMGlobalToLocalEnd(dmBC, gv, INSERT_VALUES, v);CHKERRQ(ierr);
217     ierr = DMRestoreGlobalVector(dmBC, &gv);CHKERRQ(ierr);
218   } else {
219     ierr = VecLoad_Default(v, viewer);CHKERRQ(ierr);
220   }
221   PetscFunctionReturn(0);
222 }
223 
224 #undef __FUNCT__
225 #define __FUNCT__ "VecLoad_Plex"
226 PetscErrorCode VecLoad_Plex(Vec v, PetscViewer viewer)
227 {
228   DM             dm;
229   PetscBool      ishdf5;
230   PetscErrorCode ierr;
231 
232   PetscFunctionBegin;
233   ierr = VecGetDM(v, &dm);CHKERRQ(ierr);
234   if (!dm) SETERRQ(PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
235   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5);CHKERRQ(ierr);
236   if (ishdf5) {
237 #if defined(PETSC_HAVE_HDF5)
238     ierr = VecLoad_Plex_HDF5(v, viewer);CHKERRQ(ierr);
239 #else
240     SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
241 #endif
242   } else {
243     ierr = VecLoad_Default(v, viewer);CHKERRQ(ierr);
244   }
245   PetscFunctionReturn(0);
246 }
247 
248 #undef __FUNCT__
249 #define __FUNCT__ "VecLoad_Plex_Native"
250 PetscErrorCode VecLoad_Plex_Native(Vec originalv, PetscViewer viewer)
251 {
252   DM                dm;
253   PetscViewerFormat format;
254   PetscBool         ishdf5;
255   PetscErrorCode    ierr;
256 
257   PetscFunctionBegin;
258   ierr = VecGetDM(originalv, &dm);CHKERRQ(ierr);
259   if (!dm) SETERRQ(PetscObjectComm((PetscObject) originalv), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
260   ierr = PetscViewerGetFormat(viewer, &format);CHKERRQ(ierr);
261   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5);CHKERRQ(ierr);
262   if (format == PETSC_VIEWER_NATIVE) {
263     if (dm->sfNatural) {
264       if (ishdf5) {
265 #if defined(PETSC_HAVE_HDF5)
266         Vec         v;
267         const char *vecname;
268 
269         ierr = DMGetGlobalVector(dm, &v);CHKERRQ(ierr);
270         ierr = PetscObjectGetName((PetscObject) originalv, &vecname);CHKERRQ(ierr);
271         ierr = PetscObjectSetName((PetscObject) v, vecname);CHKERRQ(ierr);
272         ierr = VecLoad_Plex_HDF5_Native(v, viewer);CHKERRQ(ierr);
273         ierr = DMPlexNaturalToGlobalBegin(dm, v, originalv);CHKERRQ(ierr);
274         ierr = DMPlexNaturalToGlobalEnd(dm, v, originalv);CHKERRQ(ierr);
275         ierr = DMRestoreGlobalVector(dm, &v);CHKERRQ(ierr);
276 #else
277         SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
278 #endif
279       } else SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Reading in natural order is not supported for anything but HDF5.");
280     }
281   }
282   PetscFunctionReturn(0);
283 }
284 
285 #undef __FUNCT__
286 #define __FUNCT__ "DMPlexView_Ascii_Geometry"
287 PetscErrorCode DMPlexView_Ascii_Geometry(DM dm, PetscViewer viewer)
288 {
289   PetscSection       coordSection;
290   Vec                coordinates;
291   DMLabel            depthLabel;
292   const char        *name[4];
293   const PetscScalar *a;
294   PetscInt           dim, pStart, pEnd, cStart, cEnd, c;
295   PetscErrorCode     ierr;
296 
297   PetscFunctionBegin;
298   ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr);
299   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
300   ierr = DMGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
301   ierr = DMPlexGetDepthLabel(dm, &depthLabel);CHKERRQ(ierr);
302   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
303   ierr = PetscSectionGetChart(coordSection, &pStart, &pEnd);CHKERRQ(ierr);
304   ierr = VecGetArrayRead(coordinates, &a);CHKERRQ(ierr);
305   name[0]     = "vertex";
306   name[1]     = "edge";
307   name[dim-1] = "face";
308   name[dim]   = "cell";
309   for (c = cStart; c < cEnd; ++c) {
310     PetscInt *closure = NULL;
311     PetscInt  closureSize, cl;
312 
313     ierr = PetscViewerASCIIPrintf(viewer, "Geometry for cell %D:\n", c);CHKERRQ(ierr);
314     ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
315     ierr = PetscViewerASCIIPushTab(viewer);CHKERRQ(ierr);
316     for (cl = 0; cl < closureSize*2; cl += 2) {
317       PetscInt point = closure[cl], depth, dof, off, d, p;
318 
319       if ((point < pStart) || (point >= pEnd)) continue;
320       ierr = PetscSectionGetDof(coordSection, point, &dof);CHKERRQ(ierr);
321       if (!dof) continue;
322       ierr = DMLabelGetValue(depthLabel, point, &depth);CHKERRQ(ierr);
323       ierr = PetscSectionGetOffset(coordSection, point, &off);CHKERRQ(ierr);
324       ierr = PetscViewerASCIIPrintf(viewer, "%s %D coords:", name[depth], point);CHKERRQ(ierr);
325       for (p = 0; p < dof/dim; ++p) {
326         ierr = PetscViewerASCIIPrintf(viewer, " (");CHKERRQ(ierr);
327         for (d = 0; d < dim; ++d) {
328           if (d > 0) {ierr = PetscViewerASCIIPrintf(viewer, ", ");CHKERRQ(ierr);}
329           ierr = PetscViewerASCIIPrintf(viewer, "%g", PetscRealPart(a[off+p*dim+d]));CHKERRQ(ierr);
330         }
331         ierr = PetscViewerASCIIPrintf(viewer, ")");CHKERRQ(ierr);
332       }
333       ierr = PetscViewerASCIIPrintf(viewer, "\n");CHKERRQ(ierr);
334     }
335     ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
336     ierr = PetscViewerASCIIPopTab(viewer);CHKERRQ(ierr);
337   }
338   ierr = VecRestoreArrayRead(coordinates, &a);CHKERRQ(ierr);
339   PetscFunctionReturn(0);
340 }
341 
342 #undef __FUNCT__
343 #define __FUNCT__ "DMPlexView_Ascii"
344 PetscErrorCode DMPlexView_Ascii(DM dm, PetscViewer viewer)
345 {
346   DM_Plex          *mesh = (DM_Plex*) dm->data;
347   DM                cdm;
348   DMLabel           markers;
349   PetscSection      coordSection;
350   Vec               coordinates;
351   PetscViewerFormat format;
352   PetscErrorCode    ierr;
353 
354   PetscFunctionBegin;
355   ierr = DMGetCoordinateDM(dm, &cdm);CHKERRQ(ierr);
356   ierr = DMGetDefaultSection(cdm, &coordSection);CHKERRQ(ierr);
357   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
358   ierr = PetscViewerGetFormat(viewer, &format);CHKERRQ(ierr);
359   if (format == PETSC_VIEWER_ASCII_INFO_DETAIL) {
360     const char *name;
361     PetscInt    maxConeSize, maxSupportSize;
362     PetscInt    pStart, pEnd, p;
363     PetscMPIInt rank, size;
364 
365     ierr = MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank);CHKERRQ(ierr);
366     ierr = MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size);CHKERRQ(ierr);
367     ierr = PetscObjectGetName((PetscObject) dm, &name);CHKERRQ(ierr);
368     ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
369     ierr = DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize);CHKERRQ(ierr);
370     ierr = PetscViewerASCIIPrintf(viewer, "Mesh '%s':\n", name);CHKERRQ(ierr);
371     ierr = PetscViewerASCIIPrintf(viewer, "orientation is missing\n", name);CHKERRQ(ierr);
372     ierr = PetscViewerASCIIPrintf(viewer, "cap --> base:\n", name);CHKERRQ(ierr);
373     ierr = PetscViewerASCIIPushSynchronized(viewer);CHKERRQ(ierr);
374     ierr = PetscViewerASCIISynchronizedPrintf(viewer, "[%d] Max sizes cone: %D support: %D\n", rank,maxConeSize, maxSupportSize);CHKERRQ(ierr);
375     for (p = pStart; p < pEnd; ++p) {
376       PetscInt dof, off, s;
377 
378       ierr = PetscSectionGetDof(mesh->supportSection, p, &dof);CHKERRQ(ierr);
379       ierr = PetscSectionGetOffset(mesh->supportSection, p, &off);CHKERRQ(ierr);
380       for (s = off; s < off+dof; ++s) {
381         ierr = PetscViewerASCIISynchronizedPrintf(viewer, "[%d]: %D ----> %D\n", rank, p, mesh->supports[s]);CHKERRQ(ierr);
382       }
383     }
384     ierr = PetscViewerFlush(viewer);CHKERRQ(ierr);
385     ierr = PetscViewerASCIIPrintf(viewer, "base <-- cap:\n", name);CHKERRQ(ierr);
386     for (p = pStart; p < pEnd; ++p) {
387       PetscInt dof, off, c;
388 
389       ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
390       ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
391       for (c = off; c < off+dof; ++c) {
392         ierr = PetscViewerASCIISynchronizedPrintf(viewer, "[%d]: %D <---- %D (%D)\n", rank, p, mesh->cones[c], mesh->coneOrientations[c]);CHKERRQ(ierr);
393       }
394     }
395     ierr = PetscViewerFlush(viewer);CHKERRQ(ierr);
396     ierr = PetscViewerASCIIPopSynchronized(viewer);CHKERRQ(ierr);
397     ierr = PetscSectionGetChart(coordSection, &pStart, NULL);CHKERRQ(ierr);
398     if (pStart >= 0) {ierr = PetscSectionVecView(coordSection, coordinates, viewer);CHKERRQ(ierr);}
399     ierr = DMGetLabel(dm, "marker", &markers);CHKERRQ(ierr);
400     ierr = DMLabelView(markers,viewer);CHKERRQ(ierr);
401     if (size > 1) {
402       PetscSF sf;
403 
404       ierr = DMGetPointSF(dm, &sf);CHKERRQ(ierr);
405       ierr = PetscSFView(sf, viewer);CHKERRQ(ierr);
406     }
407     ierr = PetscViewerFlush(viewer);CHKERRQ(ierr);
408   } else if (format == PETSC_VIEWER_ASCII_LATEX) {
409     const char  *name, *color;
410     const char  *defcolors[3]  = {"gray", "orange", "green"};
411     const char  *deflcolors[4] = {"blue", "cyan", "red", "magenta"};
412     PetscReal    scale         = 2.0;
413     PetscBool    useNumbers    = PETSC_TRUE, useLabels, useColors;
414     double       tcoords[3];
415     PetscScalar *coords;
416     PetscInt     numLabels, l, numColors, numLColors, dim, depth, cStart, cEnd, c, vStart, vEnd, v, eStart = 0, eEnd = 0, e, p;
417     PetscMPIInt  rank, size;
418     char         **names, **colors, **lcolors;
419 
420     ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr);
421     ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
422     ierr = DMGetNumLabels(dm, &numLabels);CHKERRQ(ierr);
423     numLabels  = PetscMax(numLabels, 10);
424     numColors  = 10;
425     numLColors = 10;
426     ierr = PetscCalloc3(numLabels, &names, numColors, &colors, numLColors, &lcolors);CHKERRQ(ierr);
427     ierr = PetscOptionsGetReal(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_scale", &scale, NULL);CHKERRQ(ierr);
428     ierr = PetscOptionsGetBool(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_numbers", &useNumbers, NULL);CHKERRQ(ierr);
429     ierr = PetscOptionsGetStringArray(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_labels", names, &numLabels, &useLabels);CHKERRQ(ierr);
430     if (!useLabels) numLabels = 0;
431     ierr = PetscOptionsGetStringArray(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_colors", colors, &numColors, &useColors);CHKERRQ(ierr);
432     if (!useColors) {
433       numColors = 3;
434       for (c = 0; c < numColors; ++c) {ierr = PetscStrallocpy(defcolors[c], &colors[c]);CHKERRQ(ierr);}
435     }
436     ierr = PetscOptionsGetStringArray(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_lcolors", lcolors, &numLColors, &useColors);CHKERRQ(ierr);
437     if (!useColors) {
438       numLColors = 4;
439       for (c = 0; c < numLColors; ++c) {ierr = PetscStrallocpy(deflcolors[c], &lcolors[c]);CHKERRQ(ierr);}
440     }
441     ierr = MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank);CHKERRQ(ierr);
442     ierr = MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size);CHKERRQ(ierr);
443     ierr = PetscObjectGetName((PetscObject) dm, &name);CHKERRQ(ierr);
444     ierr = PetscViewerASCIIPrintf(viewer, "\
445 \\documentclass[tikz]{standalone}\n\n\
446 \\usepackage{pgflibraryshapes}\n\
447 \\usetikzlibrary{backgrounds}\n\
448 \\usetikzlibrary{arrows}\n\
449 \\begin{document}\n");CHKERRQ(ierr);
450     if (size > 1) {
451       ierr = PetscViewerASCIIPrintf(viewer, "%s for process ", name);CHKERRQ(ierr);
452       for (p = 0; p < size; ++p) {
453         if (p > 0 && p == size-1) {
454           ierr = PetscViewerASCIIPrintf(viewer, ", and ", colors[p%numColors], p);CHKERRQ(ierr);
455         } else if (p > 0) {
456           ierr = PetscViewerASCIIPrintf(viewer, ", ", colors[p%numColors], p);CHKERRQ(ierr);
457         }
458         ierr = PetscViewerASCIIPrintf(viewer, "{\\textcolor{%s}%D}", colors[p%numColors], p);CHKERRQ(ierr);
459       }
460       ierr = PetscViewerASCIIPrintf(viewer, ".\n\n\n");CHKERRQ(ierr);
461     }
462     ierr = PetscViewerASCIIPrintf(viewer, "\\begin{tikzpicture}[scale = %g,font=\\fontsize{8}{8}\\selectfont]\n", 1.0);CHKERRQ(ierr);
463     /* Plot vertices */
464     ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
465     ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
466     ierr = PetscViewerASCIIPushSynchronized(viewer);CHKERRQ(ierr);
467     for (v = vStart; v < vEnd; ++v) {
468       PetscInt  off, dof, d;
469       PetscBool isLabeled = PETSC_FALSE;
470 
471       ierr = PetscSectionGetDof(coordSection, v, &dof);CHKERRQ(ierr);
472       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
473       ierr = PetscViewerASCIISynchronizedPrintf(viewer, "\\path (");CHKERRQ(ierr);
474       if (PetscUnlikely(dof > 3)) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_PLIB,"coordSection vertex %D has dof %D > 3",v,dof);
475       for (d = 0; d < dof; ++d) {
476         tcoords[d] = (double) (scale*PetscRealPart(coords[off+d]));
477         tcoords[d] = PetscAbsReal(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d];
478       }
479       /* Rotate coordinates since PGF makes z point out of the page instead of up */
480       if (dim == 3) {PetscReal tmp = tcoords[1]; tcoords[1] = tcoords[2]; tcoords[2] = -tmp;}
481       for (d = 0; d < dof; ++d) {
482         if (d > 0) {ierr = PetscViewerASCIISynchronizedPrintf(viewer, ",");CHKERRQ(ierr);}
483         ierr = PetscViewerASCIISynchronizedPrintf(viewer, "%g", tcoords[d]);CHKERRQ(ierr);
484       }
485       color = colors[rank%numColors];
486       for (l = 0; l < numLabels; ++l) {
487         PetscInt val;
488         ierr = DMGetLabelValue(dm, names[l], v, &val);CHKERRQ(ierr);
489         if (val >= 0) {color = lcolors[l%numLColors]; isLabeled = PETSC_TRUE; break;}
490       }
491       if (useNumbers) {
492         ierr = PetscViewerASCIISynchronizedPrintf(viewer, ") node(%D_%d) [draw,shape=circle,color=%s] {%D};\n", v, rank, color, v);CHKERRQ(ierr);
493       } else {
494         ierr = PetscViewerASCIISynchronizedPrintf(viewer, ") node(%D_%d) [fill,inner sep=%dpt,shape=circle,color=%s] {};\n", v, rank, !isLabeled ? 1 : 2, color);CHKERRQ(ierr);
495       }
496     }
497     ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
498     ierr = PetscViewerFlush(viewer);CHKERRQ(ierr);
499     /* Plot edges */
500     if (depth > 1) {ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);}
501     if (dim < 3 && useNumbers) {
502       ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
503       ierr = PetscViewerASCIIPrintf(viewer, "\\path\n");CHKERRQ(ierr);
504       for (e = eStart; e < eEnd; ++e) {
505         const PetscInt *cone;
506         PetscInt        coneSize, offA, offB, dof, d;
507 
508         ierr = DMPlexGetConeSize(dm, e, &coneSize);CHKERRQ(ierr);
509         if (coneSize != 2) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Edge %D cone should have two vertices, not %D", e, coneSize);
510         ierr = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
511         ierr = PetscSectionGetDof(coordSection, cone[0], &dof);CHKERRQ(ierr);
512         ierr = PetscSectionGetOffset(coordSection, cone[0], &offA);CHKERRQ(ierr);
513         ierr = PetscSectionGetOffset(coordSection, cone[1], &offB);CHKERRQ(ierr);
514         ierr = PetscViewerASCIISynchronizedPrintf(viewer, "(");CHKERRQ(ierr);
515         for (d = 0; d < dof; ++d) {
516           tcoords[d] = (double) (scale*PetscRealPart(coords[offA+d]+coords[offB+d]));
517           tcoords[d] = PetscAbsReal(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d];
518         }
519         /* Rotate coordinates since PGF makes z point out of the page instead of up */
520         if (dim == 3) {PetscReal tmp = tcoords[1]; tcoords[1] = tcoords[2]; tcoords[2] = -tmp;}
521         for (d = 0; d < dof; ++d) {
522           if (d > 0) {ierr = PetscViewerASCIISynchronizedPrintf(viewer, ",");CHKERRQ(ierr);}
523           ierr = PetscViewerASCIISynchronizedPrintf(viewer, "%g", (double)tcoords[d]);CHKERRQ(ierr);
524         }
525         color = colors[rank%numColors];
526         for (l = 0; l < numLabels; ++l) {
527           PetscInt val;
528           ierr = DMGetLabelValue(dm, names[l], v, &val);CHKERRQ(ierr);
529           if (val >= 0) {color = lcolors[l%numLColors]; break;}
530         }
531         ierr = PetscViewerASCIISynchronizedPrintf(viewer, ") node(%D_%d) [draw,shape=circle,color=%s] {%D} --\n", e, rank, color, e);CHKERRQ(ierr);
532       }
533       ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
534       ierr = PetscViewerFlush(viewer);CHKERRQ(ierr);
535       ierr = PetscViewerASCIIPrintf(viewer, "(0,0);\n");CHKERRQ(ierr);
536     }
537     /* Plot cells */
538     if (dim == 3 || !useNumbers) {
539       for (e = eStart; e < eEnd; ++e) {
540         const PetscInt *cone;
541 
542         color = colors[rank%numColors];
543         for (l = 0; l < numLabels; ++l) {
544           PetscInt val;
545           ierr = DMGetLabelValue(dm, names[l], e, &val);CHKERRQ(ierr);
546           if (val >= 0) {color = lcolors[l%numLColors]; break;}
547         }
548         ierr = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
549         ierr = PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] (%D_%d) -- (%D_%d);\n", color, cone[0], rank, cone[1], rank);CHKERRQ(ierr);
550       }
551     } else {
552       ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
553       for (c = cStart; c < cEnd; ++c) {
554         PetscInt *closure = NULL;
555         PetscInt  closureSize, firstPoint = -1;
556 
557         ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
558         ierr = PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] ", colors[rank%numColors]);CHKERRQ(ierr);
559         for (p = 0; p < closureSize*2; p += 2) {
560           const PetscInt point = closure[p];
561 
562           if ((point < vStart) || (point >= vEnd)) continue;
563           if (firstPoint >= 0) {ierr = PetscViewerASCIISynchronizedPrintf(viewer, " -- ");CHKERRQ(ierr);}
564           ierr = PetscViewerASCIISynchronizedPrintf(viewer, "(%D_%d)", point, rank);CHKERRQ(ierr);
565           if (firstPoint < 0) firstPoint = point;
566         }
567         /* Why doesn't this work? ierr = PetscViewerASCIISynchronizedPrintf(viewer, " -- cycle;\n");CHKERRQ(ierr); */
568         ierr = PetscViewerASCIISynchronizedPrintf(viewer, " -- (%D_%d);\n", firstPoint, rank);CHKERRQ(ierr);
569         ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
570       }
571     }
572     ierr = PetscViewerFlush(viewer);CHKERRQ(ierr);
573     ierr = PetscViewerASCIIPopSynchronized(viewer);CHKERRQ(ierr);
574     ierr = PetscViewerASCIIPrintf(viewer, "\\end{tikzpicture}\n");CHKERRQ(ierr);
575     ierr = PetscViewerASCIIPrintf(viewer, "\\end{document}\n", name);CHKERRQ(ierr);
576     for (l = 0; l < numLabels;  ++l) {ierr = PetscFree(names[l]);CHKERRQ(ierr);}
577     for (c = 0; c < numColors;  ++c) {ierr = PetscFree(colors[c]);CHKERRQ(ierr);}
578     for (c = 0; c < numLColors; ++c) {ierr = PetscFree(lcolors[c]);CHKERRQ(ierr);}
579     ierr = PetscFree3(names, colors, lcolors);CHKERRQ(ierr);
580   } else {
581     MPI_Comm    comm;
582     PetscInt   *sizes, *hybsizes;
583     PetscInt    locDepth, depth, dim, d, pMax[4];
584     PetscInt    pStart, pEnd, p;
585     PetscInt    numLabels, l;
586     const char *name;
587     PetscMPIInt size;
588 
589     ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr);
590     ierr = MPI_Comm_size(comm, &size);CHKERRQ(ierr);
591     ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr);
592     ierr = PetscObjectGetName((PetscObject) dm, &name);CHKERRQ(ierr);
593     if (name) {ierr = PetscViewerASCIIPrintf(viewer, "%s in %D dimensions:\n", name, dim);CHKERRQ(ierr);}
594     else      {ierr = PetscViewerASCIIPrintf(viewer, "Mesh in %D dimensions:\n", dim);CHKERRQ(ierr);}
595     ierr = DMPlexGetDepth(dm, &locDepth);CHKERRQ(ierr);
596     ierr = MPIU_Allreduce(&locDepth, &depth, 1, MPIU_INT, MPI_MAX, comm);CHKERRQ(ierr);
597     ierr = DMPlexGetHybridBounds(dm, &pMax[depth], depth > 0 ? &pMax[depth-1] : NULL, &pMax[1], &pMax[0]);CHKERRQ(ierr);
598     ierr = PetscMalloc2(size,&sizes,size,&hybsizes);CHKERRQ(ierr);
599     if (depth == 1) {
600       ierr = DMPlexGetDepthStratum(dm, 0, &pStart, &pEnd);CHKERRQ(ierr);
601       pEnd = pEnd - pStart;
602       ierr = MPI_Gather(&pEnd, 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm);CHKERRQ(ierr);
603       ierr = PetscViewerASCIIPrintf(viewer, "  %d-cells:", 0);CHKERRQ(ierr);
604       for (p = 0; p < size; ++p) {ierr = PetscViewerASCIIPrintf(viewer, " %D", sizes[p]);CHKERRQ(ierr);}
605       ierr = PetscViewerASCIIPrintf(viewer, "\n");CHKERRQ(ierr);
606       ierr = DMPlexGetHeightStratum(dm, 0, &pStart, &pEnd);CHKERRQ(ierr);
607       pEnd = pEnd - pStart;
608       ierr = MPI_Gather(&pEnd, 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm);CHKERRQ(ierr);
609       ierr = PetscViewerASCIIPrintf(viewer, "  %D-cells:", dim);CHKERRQ(ierr);
610       for (p = 0; p < size; ++p) {ierr = PetscViewerASCIIPrintf(viewer, " %D", sizes[p]);CHKERRQ(ierr);}
611       ierr = PetscViewerASCIIPrintf(viewer, "\n");CHKERRQ(ierr);
612     } else {
613       for (d = 0; d <= dim; d++) {
614         ierr = DMPlexGetDepthStratum(dm, d, &pStart, &pEnd);CHKERRQ(ierr);
615         pEnd    -= pStart;
616         pMax[d] -= pStart;
617         ierr = MPI_Gather(&pEnd, 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm);CHKERRQ(ierr);
618         ierr = MPI_Gather(&pMax[d], 1, MPIU_INT, hybsizes, 1, MPIU_INT, 0, comm);CHKERRQ(ierr);
619         ierr = PetscViewerASCIIPrintf(viewer, "  %D-cells:", d);CHKERRQ(ierr);
620         for (p = 0; p < size; ++p) {
621           if (hybsizes[p] >= 0) {ierr = PetscViewerASCIIPrintf(viewer, " %D (%D)", sizes[p], sizes[p] - hybsizes[p]);CHKERRQ(ierr);}
622           else                  {ierr = PetscViewerASCIIPrintf(viewer, " %D", sizes[p]);CHKERRQ(ierr);}
623         }
624         ierr = PetscViewerASCIIPrintf(viewer, "\n");CHKERRQ(ierr);
625       }
626     }
627     ierr = PetscFree2(sizes,hybsizes);CHKERRQ(ierr);
628     ierr = DMGetNumLabels(dm, &numLabels);CHKERRQ(ierr);
629     if (numLabels) {ierr = PetscViewerASCIIPrintf(viewer, "Labels:\n");CHKERRQ(ierr);}
630     for (l = 0; l < numLabels; ++l) {
631       DMLabel         label;
632       const char     *name;
633       IS              valueIS;
634       const PetscInt *values;
635       PetscInt        numValues, v;
636 
637       ierr = DMGetLabelName(dm, l, &name);CHKERRQ(ierr);
638       ierr = DMGetLabel(dm, name, &label);CHKERRQ(ierr);
639       ierr = DMLabelGetNumValues(label, &numValues);CHKERRQ(ierr);
640       ierr = PetscViewerASCIIPrintf(viewer, "  %s: %D strata of sizes (", name, numValues);CHKERRQ(ierr);
641       ierr = DMLabelGetValueIS(label, &valueIS);CHKERRQ(ierr);
642       ierr = ISGetIndices(valueIS, &values);CHKERRQ(ierr);
643       ierr = PetscViewerASCIIUseTabs(viewer, PETSC_FALSE);CHKERRQ(ierr);
644       for (v = 0; v < numValues; ++v) {
645         PetscInt size;
646 
647         ierr = DMLabelGetStratumSize(label, values[v], &size);CHKERRQ(ierr);
648         if (v > 0) {ierr = PetscViewerASCIIPrintf(viewer, ", ");CHKERRQ(ierr);}
649         ierr = PetscViewerASCIIPrintf(viewer, "%D", size);CHKERRQ(ierr);
650       }
651       ierr = PetscViewerASCIIPrintf(viewer, ")\n");CHKERRQ(ierr);
652       ierr = PetscViewerASCIIUseTabs(viewer, PETSC_TRUE);CHKERRQ(ierr);
653       ierr = ISRestoreIndices(valueIS, &values);CHKERRQ(ierr);
654       ierr = ISDestroy(&valueIS);CHKERRQ(ierr);
655     }
656     ierr = DMGetCoarseDM(dm, &cdm);CHKERRQ(ierr);
657     if (cdm) {
658       ierr = PetscViewerASCIIPushTab(viewer);CHKERRQ(ierr);
659       ierr = DMPlexView_Ascii(cdm, viewer);CHKERRQ(ierr);
660       ierr = PetscViewerASCIIPopTab(viewer);CHKERRQ(ierr);
661     }
662   }
663   PetscFunctionReturn(0);
664 }
665 
666 #undef __FUNCT__
667 #define __FUNCT__ "DMView_Plex"
668 PetscErrorCode DMView_Plex(DM dm, PetscViewer viewer)
669 {
670   PetscBool      iascii, ishdf5, isvtk;
671   PetscErrorCode ierr;
672 
673   PetscFunctionBegin;
674   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
675   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
676   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERASCII, &iascii);CHKERRQ(ierr);
677   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERVTK,   &isvtk);CHKERRQ(ierr);
678   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5,  &ishdf5);CHKERRQ(ierr);
679   if (iascii) {
680     ierr = DMPlexView_Ascii(dm, viewer);CHKERRQ(ierr);
681   } else if (ishdf5) {
682 #if defined(PETSC_HAVE_HDF5)
683     ierr = PetscViewerPushFormat(viewer, PETSC_VIEWER_HDF5_VIZ);CHKERRQ(ierr);
684     ierr = DMPlexView_HDF5(dm, viewer);CHKERRQ(ierr);
685     ierr = PetscViewerPopFormat(viewer);CHKERRQ(ierr);
686 #else
687     SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
688 #endif
689   }
690   else if (isvtk) {
691     ierr = DMPlexVTKWriteAll((PetscObject) dm,viewer);CHKERRQ(ierr);
692   }
693   PetscFunctionReturn(0);
694 }
695 
696 #undef __FUNCT__
697 #define __FUNCT__ "DMLoad_Plex"
698 PetscErrorCode DMLoad_Plex(DM dm, PetscViewer viewer)
699 {
700   PetscBool      isbinary, ishdf5;
701   PetscErrorCode ierr;
702 
703   PetscFunctionBegin;
704   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
705   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
706   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERBINARY, &isbinary);CHKERRQ(ierr);
707   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5,   &ishdf5);CHKERRQ(ierr);
708   if (isbinary) {SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Do not yet support binary viewers");}
709   else if (ishdf5) {
710 #if defined(PETSC_HAVE_HDF5)
711     ierr = DMPlexLoad_HDF5(dm, viewer);CHKERRQ(ierr);
712 #else
713     SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
714 #endif
715   }
716   PetscFunctionReturn(0);
717 }
718 
719 
720 #undef __FUNCT__
721 #define __FUNCT__ "DMDestroy_Plex"
722 PetscErrorCode DMDestroy_Plex(DM dm)
723 {
724   DM_Plex       *mesh = (DM_Plex*) dm->data;
725   PetscErrorCode ierr;
726 
727   PetscFunctionBegin;
728   if (--mesh->refct > 0) PetscFunctionReturn(0);
729   ierr = PetscSectionDestroy(&mesh->coneSection);CHKERRQ(ierr);
730   ierr = PetscFree(mesh->cones);CHKERRQ(ierr);
731   ierr = PetscFree(mesh->coneOrientations);CHKERRQ(ierr);
732   ierr = PetscSectionDestroy(&mesh->supportSection);CHKERRQ(ierr);
733   ierr = PetscFree(mesh->supports);CHKERRQ(ierr);
734   ierr = PetscFree(mesh->facesTmp);CHKERRQ(ierr);
735   ierr = PetscFree(mesh->tetgenOpts);CHKERRQ(ierr);
736   ierr = PetscFree(mesh->triangleOpts);CHKERRQ(ierr);
737   ierr = PetscPartitionerDestroy(&mesh->partitioner);CHKERRQ(ierr);
738   ierr = DMLabelDestroy(&mesh->subpointMap);CHKERRQ(ierr);
739   ierr = ISDestroy(&mesh->globalVertexNumbers);CHKERRQ(ierr);
740   ierr = ISDestroy(&mesh->globalCellNumbers);CHKERRQ(ierr);
741   ierr = PetscSectionDestroy(&mesh->anchorSection);CHKERRQ(ierr);
742   ierr = ISDestroy(&mesh->anchorIS);CHKERRQ(ierr);
743   ierr = PetscSectionDestroy(&mesh->parentSection);CHKERRQ(ierr);
744   ierr = PetscFree(mesh->parents);CHKERRQ(ierr);
745   ierr = PetscFree(mesh->childIDs);CHKERRQ(ierr);
746   ierr = PetscSectionDestroy(&mesh->childSection);CHKERRQ(ierr);
747   ierr = PetscFree(mesh->children);CHKERRQ(ierr);
748   ierr = DMDestroy(&mesh->referenceTree);CHKERRQ(ierr);
749   ierr = PetscGridHashDestroy(&mesh->lbox);CHKERRQ(ierr);
750   /* This was originally freed in DMDestroy(), but that prevents reference counting of backend objects */
751   ierr = PetscFree(mesh);CHKERRQ(ierr);
752   PetscFunctionReturn(0);
753 }
754 
755 #undef __FUNCT__
756 #define __FUNCT__ "DMCreateMatrix_Plex"
757 PetscErrorCode DMCreateMatrix_Plex(DM dm, Mat *J)
758 {
759   PetscSection   sectionGlobal;
760   PetscInt       bs = -1, mbs;
761   PetscInt       localSize;
762   PetscBool      isShell, isBlock, isSeqBlock, isMPIBlock, isSymBlock, isSymSeqBlock, isSymMPIBlock;
763   PetscErrorCode ierr;
764   MatType        mtype;
765   ISLocalToGlobalMapping ltog;
766 
767   PetscFunctionBegin;
768   ierr = MatInitializePackage();CHKERRQ(ierr);
769   mtype = dm->mattype;
770   ierr = DMGetDefaultGlobalSection(dm, &sectionGlobal);CHKERRQ(ierr);
771   /* ierr = PetscSectionGetStorageSize(sectionGlobal, &localSize);CHKERRQ(ierr); */
772   ierr = PetscSectionGetConstrainedStorageSize(sectionGlobal, &localSize);CHKERRQ(ierr);
773   ierr = MatCreate(PetscObjectComm((PetscObject)dm), J);CHKERRQ(ierr);
774   ierr = MatSetSizes(*J, localSize, localSize, PETSC_DETERMINE, PETSC_DETERMINE);CHKERRQ(ierr);
775   ierr = MatSetType(*J, mtype);CHKERRQ(ierr);
776   ierr = MatSetFromOptions(*J);CHKERRQ(ierr);
777   ierr = MatGetBlockSize(*J, &mbs);CHKERRQ(ierr);
778   if (mbs > 1) bs = mbs;
779   ierr = PetscStrcmp(mtype, MATSHELL, &isShell);CHKERRQ(ierr);
780   ierr = PetscStrcmp(mtype, MATBAIJ, &isBlock);CHKERRQ(ierr);
781   ierr = PetscStrcmp(mtype, MATSEQBAIJ, &isSeqBlock);CHKERRQ(ierr);
782   ierr = PetscStrcmp(mtype, MATMPIBAIJ, &isMPIBlock);CHKERRQ(ierr);
783   ierr = PetscStrcmp(mtype, MATSBAIJ, &isSymBlock);CHKERRQ(ierr);
784   ierr = PetscStrcmp(mtype, MATSEQSBAIJ, &isSymSeqBlock);CHKERRQ(ierr);
785   ierr = PetscStrcmp(mtype, MATMPISBAIJ, &isSymMPIBlock);CHKERRQ(ierr);
786   if (!isShell) {
787     PetscBool fillMatrix = (PetscBool) !dm->prealloc_only;
788     PetscInt *dnz, *onz, *dnzu, *onzu, bsLocal, bsMax, bsMin;
789     PetscInt  pStart, pEnd, p, dof, cdof;
790 
791     ierr = PetscSectionGetChart(sectionGlobal, &pStart, &pEnd);CHKERRQ(ierr);
792     for (p = pStart; p < pEnd; ++p) {
793       PetscInt bdof;
794 
795       ierr = PetscSectionGetDof(sectionGlobal, p, &dof);CHKERRQ(ierr);
796       ierr = PetscSectionGetConstraintDof(sectionGlobal, p, &cdof);CHKERRQ(ierr);
797       dof  = dof < 0 ? -(dof+1) : dof;
798       bdof = cdof && (dof-cdof) ? 1 : dof;
799       if (dof) {
800         if (bs < 0)          {bs = bdof;}
801         else if (bs != bdof) {bs = 1; break;}
802       }
803     }
804     /* Must have same blocksize on all procs (some might have no points) */
805     bsLocal = bs;
806     ierr = MPIU_Allreduce(&bsLocal, &bsMax, 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm));CHKERRQ(ierr);
807     bsLocal = bs < 0 ? bsMax : bs;
808     ierr = MPIU_Allreduce(&bsLocal, &bsMin, 1, MPIU_INT, MPI_MIN, PetscObjectComm((PetscObject)dm));CHKERRQ(ierr);
809     if (bsMin != bsMax) {bs = 1;}
810     else                {bs = bsMax;}
811     ierr = PetscCalloc4(localSize/bs, &dnz, localSize/bs, &onz, localSize/bs, &dnzu, localSize/bs, &onzu);CHKERRQ(ierr);
812     ierr = DMPlexPreallocateOperator(dm, bs, dnz, onz, dnzu, onzu, *J, fillMatrix);CHKERRQ(ierr);
813     ierr = PetscFree4(dnz, onz, dnzu, onzu);CHKERRQ(ierr);
814 
815     /* Set localtoglobalmapping on the matrix for MatSetValuesLocal() to work */
816     ierr = DMGetLocalToGlobalMapping(dm,&ltog);CHKERRQ(ierr);
817     ierr = MatSetLocalToGlobalMapping(*J,ltog,ltog);CHKERRQ(ierr);
818   }
819   PetscFunctionReturn(0);
820 }
821 
822 #undef __FUNCT__
823 #define __FUNCT__ "DMPlexGetChart"
824 /*@
825   DMPlexGetChart - Return the interval for all mesh points [pStart, pEnd)
826 
827   Not collective
828 
829   Input Parameter:
830 . mesh - The DMPlex
831 
832   Output Parameters:
833 + pStart - The first mesh point
834 - pEnd   - The upper bound for mesh points
835 
836   Level: beginner
837 
838 .seealso: DMPlexCreate(), DMPlexSetChart()
839 @*/
840 PetscErrorCode DMPlexGetChart(DM dm, PetscInt *pStart, PetscInt *pEnd)
841 {
842   DM_Plex       *mesh = (DM_Plex*) dm->data;
843   PetscErrorCode ierr;
844 
845   PetscFunctionBegin;
846   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
847   ierr = PetscSectionGetChart(mesh->coneSection, pStart, pEnd);CHKERRQ(ierr);
848   PetscFunctionReturn(0);
849 }
850 
851 #undef __FUNCT__
852 #define __FUNCT__ "DMPlexSetChart"
853 /*@
854   DMPlexSetChart - Set the interval for all mesh points [pStart, pEnd)
855 
856   Not collective
857 
858   Input Parameters:
859 + mesh - The DMPlex
860 . pStart - The first mesh point
861 - pEnd   - The upper bound for mesh points
862 
863   Output Parameters:
864 
865   Level: beginner
866 
867 .seealso: DMPlexCreate(), DMPlexGetChart()
868 @*/
869 PetscErrorCode DMPlexSetChart(DM dm, PetscInt pStart, PetscInt pEnd)
870 {
871   DM_Plex       *mesh = (DM_Plex*) dm->data;
872   PetscErrorCode ierr;
873 
874   PetscFunctionBegin;
875   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
876   ierr = PetscSectionSetChart(mesh->coneSection, pStart, pEnd);CHKERRQ(ierr);
877   ierr = PetscSectionSetChart(mesh->supportSection, pStart, pEnd);CHKERRQ(ierr);
878   PetscFunctionReturn(0);
879 }
880 
881 #undef __FUNCT__
882 #define __FUNCT__ "DMPlexGetConeSize"
883 /*@
884   DMPlexGetConeSize - Return the number of in-edges for this point in the Sieve DAG
885 
886   Not collective
887 
888   Input Parameters:
889 + mesh - The DMPlex
890 - p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
891 
892   Output Parameter:
893 . size - The cone size for point p
894 
895   Level: beginner
896 
897 .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexSetChart()
898 @*/
899 PetscErrorCode DMPlexGetConeSize(DM dm, PetscInt p, PetscInt *size)
900 {
901   DM_Plex       *mesh = (DM_Plex*) dm->data;
902   PetscErrorCode ierr;
903 
904   PetscFunctionBegin;
905   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
906   PetscValidPointer(size, 3);
907   ierr = PetscSectionGetDof(mesh->coneSection, p, size);CHKERRQ(ierr);
908   PetscFunctionReturn(0);
909 }
910 
911 #undef __FUNCT__
912 #define __FUNCT__ "DMPlexSetConeSize"
913 /*@
914   DMPlexSetConeSize - Set the number of in-edges for this point in the Sieve DAG
915 
916   Not collective
917 
918   Input Parameters:
919 + mesh - The DMPlex
920 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
921 - size - The cone size for point p
922 
923   Output Parameter:
924 
925   Note:
926   This should be called after DMPlexSetChart().
927 
928   Level: beginner
929 
930 .seealso: DMPlexCreate(), DMPlexGetConeSize(), DMPlexSetChart()
931 @*/
932 PetscErrorCode DMPlexSetConeSize(DM dm, PetscInt p, PetscInt size)
933 {
934   DM_Plex       *mesh = (DM_Plex*) dm->data;
935   PetscErrorCode ierr;
936 
937   PetscFunctionBegin;
938   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
939   ierr = PetscSectionSetDof(mesh->coneSection, p, size);CHKERRQ(ierr);
940 
941   mesh->maxConeSize = PetscMax(mesh->maxConeSize, size);
942   PetscFunctionReturn(0);
943 }
944 
945 #undef __FUNCT__
946 #define __FUNCT__ "DMPlexAddConeSize"
947 /*@
948   DMPlexAddConeSize - Add the given number of in-edges to this point in the Sieve DAG
949 
950   Not collective
951 
952   Input Parameters:
953 + mesh - The DMPlex
954 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
955 - size - The additional cone size for point p
956 
957   Output Parameter:
958 
959   Note:
960   This should be called after DMPlexSetChart().
961 
962   Level: beginner
963 
964 .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexGetConeSize(), DMPlexSetChart()
965 @*/
966 PetscErrorCode DMPlexAddConeSize(DM dm, PetscInt p, PetscInt size)
967 {
968   DM_Plex       *mesh = (DM_Plex*) dm->data;
969   PetscInt       csize;
970   PetscErrorCode ierr;
971 
972   PetscFunctionBegin;
973   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
974   ierr = PetscSectionAddDof(mesh->coneSection, p, size);CHKERRQ(ierr);
975   ierr = PetscSectionGetDof(mesh->coneSection, p, &csize);CHKERRQ(ierr);
976 
977   mesh->maxConeSize = PetscMax(mesh->maxConeSize, csize);
978   PetscFunctionReturn(0);
979 }
980 
981 #undef __FUNCT__
982 #define __FUNCT__ "DMPlexGetCone"
983 /*@C
984   DMPlexGetCone - Return the points on the in-edges for this point in the Sieve DAG
985 
986   Not collective
987 
988   Input Parameters:
989 + mesh - The DMPlex
990 - p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
991 
992   Output Parameter:
993 . cone - An array of points which are on the in-edges for point p
994 
995   Level: beginner
996 
997   Fortran Notes:
998   Since it returns an array, this routine is only available in Fortran 90, and you must
999   include petsc.h90 in your code.
1000 
1001   You must also call DMPlexRestoreCone() after you finish using the returned array.
1002 
1003 .seealso: DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart()
1004 @*/
1005 PetscErrorCode DMPlexGetCone(DM dm, PetscInt p, const PetscInt *cone[])
1006 {
1007   DM_Plex       *mesh = (DM_Plex*) dm->data;
1008   PetscInt       off;
1009   PetscErrorCode ierr;
1010 
1011   PetscFunctionBegin;
1012   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1013   PetscValidPointer(cone, 3);
1014   ierr  = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
1015   *cone = &mesh->cones[off];
1016   PetscFunctionReturn(0);
1017 }
1018 
1019 #undef __FUNCT__
1020 #define __FUNCT__ "DMPlexSetCone"
1021 /*@
1022   DMPlexSetCone - Set the points on the in-edges for this point in the Sieve DAG
1023 
1024   Not collective
1025 
1026   Input Parameters:
1027 + mesh - The DMPlex
1028 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1029 - cone - An array of points which are on the in-edges for point p
1030 
1031   Output Parameter:
1032 
1033   Note:
1034   This should be called after all calls to DMPlexSetConeSize() and DMSetUp().
1035 
1036   Level: beginner
1037 
1038 .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexSetChart(), DMPlexSetConeSize(), DMSetUp()
1039 @*/
1040 PetscErrorCode DMPlexSetCone(DM dm, PetscInt p, const PetscInt cone[])
1041 {
1042   DM_Plex       *mesh = (DM_Plex*) dm->data;
1043   PetscInt       pStart, pEnd;
1044   PetscInt       dof, off, c;
1045   PetscErrorCode ierr;
1046 
1047   PetscFunctionBegin;
1048   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1049   ierr = PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);CHKERRQ(ierr);
1050   ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
1051   if (dof) PetscValidPointer(cone, 3);
1052   ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
1053   if ((p < pStart) || (p >= pEnd)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %D is not in the valid range [%D, %D)", p, pStart, pEnd);
1054   for (c = 0; c < dof; ++c) {
1055     if ((cone[c] < pStart) || (cone[c] >= pEnd)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cone point %D is not in the valid range [%D, %D)", cone[c], pStart, pEnd);
1056     mesh->cones[off+c] = cone[c];
1057   }
1058   PetscFunctionReturn(0);
1059 }
1060 
1061 #undef __FUNCT__
1062 #define __FUNCT__ "DMPlexGetConeOrientation"
1063 /*@C
1064   DMPlexGetConeOrientation - Return the orientations on the in-edges for this point in the Sieve DAG
1065 
1066   Not collective
1067 
1068   Input Parameters:
1069 + mesh - The DMPlex
1070 - p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1071 
1072   Output Parameter:
1073 . coneOrientation - An array of orientations which are on the in-edges for point p. An orientation is an
1074                     integer giving the prescription for cone traversal. If it is negative, the cone is
1075                     traversed in the opposite direction. Its value 'o', or if negative '-(o+1)', gives
1076                     the index of the cone point on which to start.
1077 
1078   Level: beginner
1079 
1080   Fortran Notes:
1081   Since it returns an array, this routine is only available in Fortran 90, and you must
1082   include petsc.h90 in your code.
1083 
1084   You must also call DMPlexRestoreConeOrientation() after you finish using the returned array.
1085 
1086 .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexSetCone(), DMPlexSetChart()
1087 @*/
1088 PetscErrorCode DMPlexGetConeOrientation(DM dm, PetscInt p, const PetscInt *coneOrientation[])
1089 {
1090   DM_Plex       *mesh = (DM_Plex*) dm->data;
1091   PetscInt       off;
1092   PetscErrorCode ierr;
1093 
1094   PetscFunctionBegin;
1095   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1096 #if defined(PETSC_USE_DEBUG)
1097   {
1098     PetscInt dof;
1099     ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
1100     if (dof) PetscValidPointer(coneOrientation, 3);
1101   }
1102 #endif
1103   ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
1104 
1105   *coneOrientation = &mesh->coneOrientations[off];
1106   PetscFunctionReturn(0);
1107 }
1108 
1109 #undef __FUNCT__
1110 #define __FUNCT__ "DMPlexSetConeOrientation"
1111 /*@
1112   DMPlexSetConeOrientation - Set the orientations on the in-edges for this point in the Sieve DAG
1113 
1114   Not collective
1115 
1116   Input Parameters:
1117 + mesh - The DMPlex
1118 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1119 - coneOrientation - An array of orientations which are on the in-edges for point p. An orientation is an
1120                     integer giving the prescription for cone traversal. If it is negative, the cone is
1121                     traversed in the opposite direction. Its value 'o', or if negative '-(o+1)', gives
1122                     the index of the cone point on which to start.
1123 
1124   Output Parameter:
1125 
1126   Note:
1127   This should be called after all calls to DMPlexSetConeSize() and DMSetUp().
1128 
1129   Level: beginner
1130 
1131 .seealso: DMPlexCreate(), DMPlexGetConeOrientation(), DMPlexSetCone(), DMPlexSetChart(), DMPlexSetConeSize(), DMSetUp()
1132 @*/
1133 PetscErrorCode DMPlexSetConeOrientation(DM dm, PetscInt p, const PetscInt coneOrientation[])
1134 {
1135   DM_Plex       *mesh = (DM_Plex*) dm->data;
1136   PetscInt       pStart, pEnd;
1137   PetscInt       dof, off, c;
1138   PetscErrorCode ierr;
1139 
1140   PetscFunctionBegin;
1141   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1142   ierr = PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);CHKERRQ(ierr);
1143   ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
1144   if (dof) PetscValidPointer(coneOrientation, 3);
1145   ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
1146   if ((p < pStart) || (p >= pEnd)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %D is not in the valid range [%D, %D)", p, pStart, pEnd);
1147   for (c = 0; c < dof; ++c) {
1148     PetscInt cdof, o = coneOrientation[c];
1149 
1150     ierr = PetscSectionGetDof(mesh->coneSection, mesh->cones[off+c], &cdof);CHKERRQ(ierr);
1151     if (o && ((o < -(cdof+1)) || (o >= cdof))) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cone orientation %D is not in the valid range [%D. %D)", o, -(cdof+1), cdof);
1152     mesh->coneOrientations[off+c] = o;
1153   }
1154   PetscFunctionReturn(0);
1155 }
1156 
1157 #undef __FUNCT__
1158 #define __FUNCT__ "DMPlexInsertCone"
1159 PetscErrorCode DMPlexInsertCone(DM dm, PetscInt p, PetscInt conePos, PetscInt conePoint)
1160 {
1161   DM_Plex       *mesh = (DM_Plex*) dm->data;
1162   PetscInt       pStart, pEnd;
1163   PetscInt       dof, off;
1164   PetscErrorCode ierr;
1165 
1166   PetscFunctionBegin;
1167   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1168   ierr = PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);CHKERRQ(ierr);
1169   if ((p < pStart) || (p >= pEnd)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %D is not in the valid range [%D, %D)", p, pStart, pEnd);
1170   if ((conePoint < pStart) || (conePoint >= pEnd)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cone point %D is not in the valid range [%D, %D)", conePoint, pStart, pEnd);
1171   ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
1172   ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
1173   if ((conePos < 0) || (conePos >= dof)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cone position %D of point %D is not in the valid range [0, %D)", conePos, p, dof);
1174   mesh->cones[off+conePos] = conePoint;
1175   PetscFunctionReturn(0);
1176 }
1177 
1178 #undef __FUNCT__
1179 #define __FUNCT__ "DMPlexInsertConeOrientation"
1180 PetscErrorCode DMPlexInsertConeOrientation(DM dm, PetscInt p, PetscInt conePos, PetscInt coneOrientation)
1181 {
1182   DM_Plex       *mesh = (DM_Plex*) dm->data;
1183   PetscInt       pStart, pEnd;
1184   PetscInt       dof, off;
1185   PetscErrorCode ierr;
1186 
1187   PetscFunctionBegin;
1188   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1189   ierr = PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);CHKERRQ(ierr);
1190   if ((p < pStart) || (p >= pEnd)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %D is not in the valid range [%D, %D)", p, pStart, pEnd);
1191   ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
1192   ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
1193   if ((conePos < 0) || (conePos >= dof)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cone position %D of point %D is not in the valid range [0, %D)", conePos, p, dof);
1194   mesh->coneOrientations[off+conePos] = coneOrientation;
1195   PetscFunctionReturn(0);
1196 }
1197 
1198 #undef __FUNCT__
1199 #define __FUNCT__ "DMPlexGetSupportSize"
1200 /*@
1201   DMPlexGetSupportSize - Return the number of out-edges for this point in the Sieve DAG
1202 
1203   Not collective
1204 
1205   Input Parameters:
1206 + mesh - The DMPlex
1207 - p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1208 
1209   Output Parameter:
1210 . size - The support size for point p
1211 
1212   Level: beginner
1213 
1214 .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexSetChart(), DMPlexGetConeSize()
1215 @*/
1216 PetscErrorCode DMPlexGetSupportSize(DM dm, PetscInt p, PetscInt *size)
1217 {
1218   DM_Plex       *mesh = (DM_Plex*) dm->data;
1219   PetscErrorCode ierr;
1220 
1221   PetscFunctionBegin;
1222   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1223   PetscValidPointer(size, 3);
1224   ierr = PetscSectionGetDof(mesh->supportSection, p, size);CHKERRQ(ierr);
1225   PetscFunctionReturn(0);
1226 }
1227 
1228 #undef __FUNCT__
1229 #define __FUNCT__ "DMPlexSetSupportSize"
1230 /*@
1231   DMPlexSetSupportSize - Set the number of out-edges for this point in the Sieve DAG
1232 
1233   Not collective
1234 
1235   Input Parameters:
1236 + mesh - The DMPlex
1237 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1238 - size - The support size for point p
1239 
1240   Output Parameter:
1241 
1242   Note:
1243   This should be called after DMPlexSetChart().
1244 
1245   Level: beginner
1246 
1247 .seealso: DMPlexCreate(), DMPlexGetSupportSize(), DMPlexSetChart()
1248 @*/
1249 PetscErrorCode DMPlexSetSupportSize(DM dm, PetscInt p, PetscInt size)
1250 {
1251   DM_Plex       *mesh = (DM_Plex*) dm->data;
1252   PetscErrorCode ierr;
1253 
1254   PetscFunctionBegin;
1255   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1256   ierr = PetscSectionSetDof(mesh->supportSection, p, size);CHKERRQ(ierr);
1257 
1258   mesh->maxSupportSize = PetscMax(mesh->maxSupportSize, size);
1259   PetscFunctionReturn(0);
1260 }
1261 
1262 #undef __FUNCT__
1263 #define __FUNCT__ "DMPlexGetSupport"
1264 /*@C
1265   DMPlexGetSupport - Return the points on the out-edges for this point in the Sieve DAG
1266 
1267   Not collective
1268 
1269   Input Parameters:
1270 + mesh - The DMPlex
1271 - p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1272 
1273   Output Parameter:
1274 . support - An array of points which are on the out-edges for point p
1275 
1276   Level: beginner
1277 
1278   Fortran Notes:
1279   Since it returns an array, this routine is only available in Fortran 90, and you must
1280   include petsc.h90 in your code.
1281 
1282   You must also call DMPlexRestoreSupport() after you finish using the returned array.
1283 
1284 .seealso: DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone()
1285 @*/
1286 PetscErrorCode DMPlexGetSupport(DM dm, PetscInt p, const PetscInt *support[])
1287 {
1288   DM_Plex       *mesh = (DM_Plex*) dm->data;
1289   PetscInt       off;
1290   PetscErrorCode ierr;
1291 
1292   PetscFunctionBegin;
1293   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1294   PetscValidPointer(support, 3);
1295   ierr     = PetscSectionGetOffset(mesh->supportSection, p, &off);CHKERRQ(ierr);
1296   *support = &mesh->supports[off];
1297   PetscFunctionReturn(0);
1298 }
1299 
1300 #undef __FUNCT__
1301 #define __FUNCT__ "DMPlexSetSupport"
1302 /*@
1303   DMPlexSetSupport - Set the points on the out-edges for this point in the Sieve DAG
1304 
1305   Not collective
1306 
1307   Input Parameters:
1308 + mesh - The DMPlex
1309 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1310 - support - An array of points which are on the in-edges for point p
1311 
1312   Output Parameter:
1313 
1314   Note:
1315   This should be called after all calls to DMPlexSetSupportSize() and DMSetUp().
1316 
1317   Level: beginner
1318 
1319 .seealso: DMPlexCreate(), DMPlexGetSupport(), DMPlexSetChart(), DMPlexSetSupportSize(), DMSetUp()
1320 @*/
1321 PetscErrorCode DMPlexSetSupport(DM dm, PetscInt p, const PetscInt support[])
1322 {
1323   DM_Plex       *mesh = (DM_Plex*) dm->data;
1324   PetscInt       pStart, pEnd;
1325   PetscInt       dof, off, c;
1326   PetscErrorCode ierr;
1327 
1328   PetscFunctionBegin;
1329   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1330   ierr = PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd);CHKERRQ(ierr);
1331   ierr = PetscSectionGetDof(mesh->supportSection, p, &dof);CHKERRQ(ierr);
1332   if (dof) PetscValidPointer(support, 3);
1333   ierr = PetscSectionGetOffset(mesh->supportSection, p, &off);CHKERRQ(ierr);
1334   if ((p < pStart) || (p >= pEnd)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %D is not in the valid range [%D, %D)", p, pStart, pEnd);
1335   for (c = 0; c < dof; ++c) {
1336     if ((support[c] < pStart) || (support[c] >= pEnd)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Support point %D is not in the valid range [%D, %D)", support[c], pStart, pEnd);
1337     mesh->supports[off+c] = support[c];
1338   }
1339   PetscFunctionReturn(0);
1340 }
1341 
1342 #undef __FUNCT__
1343 #define __FUNCT__ "DMPlexInsertSupport"
1344 PetscErrorCode DMPlexInsertSupport(DM dm, PetscInt p, PetscInt supportPos, PetscInt supportPoint)
1345 {
1346   DM_Plex       *mesh = (DM_Plex*) dm->data;
1347   PetscInt       pStart, pEnd;
1348   PetscInt       dof, off;
1349   PetscErrorCode ierr;
1350 
1351   PetscFunctionBegin;
1352   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1353   ierr = PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd);CHKERRQ(ierr);
1354   ierr = PetscSectionGetDof(mesh->supportSection, p, &dof);CHKERRQ(ierr);
1355   ierr = PetscSectionGetOffset(mesh->supportSection, p, &off);CHKERRQ(ierr);
1356   if ((p < pStart) || (p >= pEnd)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %D is not in the valid range [%D, %D)", p, pStart, pEnd);
1357   if ((supportPoint < pStart) || (supportPoint >= pEnd)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Support point %D is not in the valid range [%D, %D)", supportPoint, pStart, pEnd);
1358   if (supportPos >= dof) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Support position %D of point %D is not in the valid range [0, %D)", supportPos, p, dof);
1359   mesh->supports[off+supportPos] = supportPoint;
1360   PetscFunctionReturn(0);
1361 }
1362 
1363 #undef __FUNCT__
1364 #define __FUNCT__ "DMPlexGetTransitiveClosure"
1365 /*@C
1366   DMPlexGetTransitiveClosure - Return the points on the transitive closure of the in-edges or out-edges for this point in the Sieve DAG
1367 
1368   Not collective
1369 
1370   Input Parameters:
1371 + mesh - The DMPlex
1372 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1373 . useCone - PETSC_TRUE for in-edges,  otherwise use out-edges
1374 - points - If points is NULL on input, internal storage will be returned, otherwise the provided array is used
1375 
1376   Output Parameters:
1377 + numPoints - The number of points in the closure, so points[] is of size 2*numPoints
1378 - points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...]
1379 
1380   Note:
1381   If using internal storage (points is NULL on input), each call overwrites the last output.
1382 
1383   Fortran Notes:
1384   Since it returns an array, this routine is only available in Fortran 90, and you must
1385   include petsc.h90 in your code.
1386 
1387   The numPoints argument is not present in the Fortran 90 binding since it is internal to the array.
1388 
1389   Level: beginner
1390 
1391 .seealso: DMPlexRestoreTransitiveClosure(), DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone()
1392 @*/
1393 PetscErrorCode DMPlexGetTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[])
1394 {
1395   DM_Plex        *mesh = (DM_Plex*) dm->data;
1396   PetscInt       *closure, *fifo;
1397   const PetscInt *tmp = NULL, *tmpO = NULL;
1398   PetscInt        tmpSize, t;
1399   PetscInt        depth       = 0, maxSize;
1400   PetscInt        closureSize = 2, fifoSize = 0, fifoStart = 0;
1401   PetscErrorCode  ierr;
1402 
1403   PetscFunctionBegin;
1404   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1405   ierr    = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
1406   /* This is only 1-level */
1407   if (useCone) {
1408     ierr = DMPlexGetConeSize(dm, p, &tmpSize);CHKERRQ(ierr);
1409     ierr = DMPlexGetCone(dm, p, &tmp);CHKERRQ(ierr);
1410     ierr = DMPlexGetConeOrientation(dm, p, &tmpO);CHKERRQ(ierr);
1411   } else {
1412     ierr = DMPlexGetSupportSize(dm, p, &tmpSize);CHKERRQ(ierr);
1413     ierr = DMPlexGetSupport(dm, p, &tmp);CHKERRQ(ierr);
1414   }
1415   if (depth == 1) {
1416     if (*points) {
1417       closure = *points;
1418     } else {
1419       maxSize = 2*(PetscMax(mesh->maxConeSize, mesh->maxSupportSize)+1);
1420       ierr = DMGetWorkArray(dm, maxSize, PETSC_INT, &closure);CHKERRQ(ierr);
1421     }
1422     closure[0] = p; closure[1] = 0;
1423     for (t = 0; t < tmpSize; ++t, closureSize += 2) {
1424       closure[closureSize]   = tmp[t];
1425       closure[closureSize+1] = tmpO ? tmpO[t] : 0;
1426     }
1427     if (numPoints) *numPoints = closureSize/2;
1428     if (points)    *points    = closure;
1429     PetscFunctionReturn(0);
1430   }
1431   {
1432     PetscInt c, coneSeries, s,supportSeries;
1433 
1434     c = mesh->maxConeSize;
1435     coneSeries = (c > 1) ? ((PetscPowInt(c,depth+1)-1)/(c-1)) : depth+1;
1436     s = mesh->maxSupportSize;
1437     supportSeries = (s > 1) ? ((PetscPowInt(s,depth+1)-1)/(s-1)) : depth+1;
1438     maxSize = 2*PetscMax(coneSeries,supportSeries);
1439   }
1440   ierr    = DMGetWorkArray(dm, maxSize, PETSC_INT, &fifo);CHKERRQ(ierr);
1441   if (*points) {
1442     closure = *points;
1443   } else {
1444     ierr = DMGetWorkArray(dm, maxSize, PETSC_INT, &closure);CHKERRQ(ierr);
1445   }
1446   closure[0] = p; closure[1] = 0;
1447   for (t = 0; t < tmpSize; ++t, closureSize += 2, fifoSize += 2) {
1448     const PetscInt cp = tmp[t];
1449     const PetscInt co = tmpO ? tmpO[t] : 0;
1450 
1451     closure[closureSize]   = cp;
1452     closure[closureSize+1] = co;
1453     fifo[fifoSize]         = cp;
1454     fifo[fifoSize+1]       = co;
1455   }
1456   /* Should kick out early when depth is reached, rather than checking all vertices for empty cones */
1457   while (fifoSize - fifoStart) {
1458     const PetscInt q   = fifo[fifoStart];
1459     const PetscInt o   = fifo[fifoStart+1];
1460     const PetscInt rev = o >= 0 ? 0 : 1;
1461     const PetscInt off = rev ? -(o+1) : o;
1462 
1463     if (useCone) {
1464       ierr = DMPlexGetConeSize(dm, q, &tmpSize);CHKERRQ(ierr);
1465       ierr = DMPlexGetCone(dm, q, &tmp);CHKERRQ(ierr);
1466       ierr = DMPlexGetConeOrientation(dm, q, &tmpO);CHKERRQ(ierr);
1467     } else {
1468       ierr = DMPlexGetSupportSize(dm, q, &tmpSize);CHKERRQ(ierr);
1469       ierr = DMPlexGetSupport(dm, q, &tmp);CHKERRQ(ierr);
1470       tmpO = NULL;
1471     }
1472     for (t = 0; t < tmpSize; ++t) {
1473       const PetscInt i  = ((rev ? tmpSize-t : t) + off)%tmpSize;
1474       const PetscInt cp = tmp[i];
1475       /* Must propogate orientation: When we reverse orientation, we both reverse the direction of iteration and start at the other end of the chain. */
1476       /* HACK: It is worse to get the size here, than to change the interpretation of -(*+1)
1477        const PetscInt co = tmpO ? (rev ? -(tmpO[i]+1) : tmpO[i]) : 0; */
1478       PetscInt       co = tmpO ? tmpO[i] : 0;
1479       PetscInt       c;
1480 
1481       if (rev) {
1482         PetscInt childSize, coff;
1483         ierr = DMPlexGetConeSize(dm, cp, &childSize);CHKERRQ(ierr);
1484         coff = tmpO[i] < 0 ? -(tmpO[i]+1) : tmpO[i];
1485         co   = childSize ? -(((coff+childSize-1)%childSize)+1) : 0;
1486       }
1487       /* Check for duplicate */
1488       for (c = 0; c < closureSize; c += 2) {
1489         if (closure[c] == cp) break;
1490       }
1491       if (c == closureSize) {
1492         closure[closureSize]   = cp;
1493         closure[closureSize+1] = co;
1494         fifo[fifoSize]         = cp;
1495         fifo[fifoSize+1]       = co;
1496         closureSize           += 2;
1497         fifoSize              += 2;
1498       }
1499     }
1500     fifoStart += 2;
1501   }
1502   if (numPoints) *numPoints = closureSize/2;
1503   if (points)    *points    = closure;
1504   ierr = DMRestoreWorkArray(dm, maxSize, PETSC_INT, &fifo);CHKERRQ(ierr);
1505   PetscFunctionReturn(0);
1506 }
1507 
1508 #undef __FUNCT__
1509 #define __FUNCT__ "DMPlexGetTransitiveClosure_Internal"
1510 /*@C
1511   DMPlexGetTransitiveClosure_Internal - Return the points on the transitive closure of the in-edges or out-edges for this point in the Sieve DAG with a specified initial orientation
1512 
1513   Not collective
1514 
1515   Input Parameters:
1516 + mesh - The DMPlex
1517 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1518 . orientation - The orientation of the point
1519 . useCone - PETSC_TRUE for in-edges,  otherwise use out-edges
1520 - points - If points is NULL on input, internal storage will be returned, otherwise the provided array is used
1521 
1522   Output Parameters:
1523 + numPoints - The number of points in the closure, so points[] is of size 2*numPoints
1524 - points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...]
1525 
1526   Note:
1527   If using internal storage (points is NULL on input), each call overwrites the last output.
1528 
1529   Fortran Notes:
1530   Since it returns an array, this routine is only available in Fortran 90, and you must
1531   include petsc.h90 in your code.
1532 
1533   The numPoints argument is not present in the Fortran 90 binding since it is internal to the array.
1534 
1535   Level: beginner
1536 
1537 .seealso: DMPlexRestoreTransitiveClosure(), DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone()
1538 @*/
1539 PetscErrorCode DMPlexGetTransitiveClosure_Internal(DM dm, PetscInt p, PetscInt ornt, PetscBool useCone, PetscInt *numPoints, PetscInt *points[])
1540 {
1541   DM_Plex        *mesh = (DM_Plex*) dm->data;
1542   PetscInt       *closure, *fifo;
1543   const PetscInt *tmp = NULL, *tmpO = NULL;
1544   PetscInt        tmpSize, t;
1545   PetscInt        depth       = 0, maxSize;
1546   PetscInt        closureSize = 2, fifoSize = 0, fifoStart = 0;
1547   PetscErrorCode  ierr;
1548 
1549   PetscFunctionBegin;
1550   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1551   ierr    = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
1552   /* This is only 1-level */
1553   if (useCone) {
1554     ierr = DMPlexGetConeSize(dm, p, &tmpSize);CHKERRQ(ierr);
1555     ierr = DMPlexGetCone(dm, p, &tmp);CHKERRQ(ierr);
1556     ierr = DMPlexGetConeOrientation(dm, p, &tmpO);CHKERRQ(ierr);
1557   } else {
1558     ierr = DMPlexGetSupportSize(dm, p, &tmpSize);CHKERRQ(ierr);
1559     ierr = DMPlexGetSupport(dm, p, &tmp);CHKERRQ(ierr);
1560   }
1561   if (depth == 1) {
1562     if (*points) {
1563       closure = *points;
1564     } else {
1565       maxSize = 2*(PetscMax(mesh->maxConeSize, mesh->maxSupportSize)+1);
1566       ierr = DMGetWorkArray(dm, maxSize, PETSC_INT, &closure);CHKERRQ(ierr);
1567     }
1568     closure[0] = p; closure[1] = ornt;
1569     for (t = 0; t < tmpSize; ++t, closureSize += 2) {
1570       const PetscInt i = ornt >= 0 ? (t+ornt)%tmpSize : (-(ornt+1) + tmpSize-t)%tmpSize;
1571       closure[closureSize]   = tmp[i];
1572       closure[closureSize+1] = tmpO ? tmpO[i] : 0;
1573     }
1574     if (numPoints) *numPoints = closureSize/2;
1575     if (points)    *points    = closure;
1576     PetscFunctionReturn(0);
1577   }
1578   {
1579     PetscInt c, coneSeries, s,supportSeries;
1580 
1581     c = mesh->maxConeSize;
1582     coneSeries = (c > 1) ? ((PetscPowInt(c,depth+1)-1)/(c-1)) : depth+1;
1583     s = mesh->maxSupportSize;
1584     supportSeries = (s > 1) ? ((PetscPowInt(s,depth+1)-1)/(s-1)) : depth+1;
1585     maxSize = 2*PetscMax(coneSeries,supportSeries);
1586   }
1587   ierr    = DMGetWorkArray(dm, maxSize, PETSC_INT, &fifo);CHKERRQ(ierr);
1588   if (*points) {
1589     closure = *points;
1590   } else {
1591     ierr = DMGetWorkArray(dm, maxSize, PETSC_INT, &closure);CHKERRQ(ierr);
1592   }
1593   closure[0] = p; closure[1] = ornt;
1594   for (t = 0; t < tmpSize; ++t, closureSize += 2, fifoSize += 2) {
1595     const PetscInt i  = ornt >= 0 ? (t+ornt)%tmpSize : (-(ornt+1) + tmpSize-t)%tmpSize;
1596     const PetscInt cp = tmp[i];
1597     PetscInt       co = tmpO ? tmpO[i] : 0;
1598 
1599     if (ornt < 0) {
1600       PetscInt childSize, coff;
1601       ierr = DMPlexGetConeSize(dm, cp, &childSize);CHKERRQ(ierr);
1602       coff = co < 0 ? -(tmpO[i]+1) : tmpO[i];
1603       co   = childSize ? -(((coff+childSize-1)%childSize)+1) : 0;
1604     }
1605     closure[closureSize]   = cp;
1606     closure[closureSize+1] = co;
1607     fifo[fifoSize]         = cp;
1608     fifo[fifoSize+1]       = co;
1609   }
1610   /* Should kick out early when depth is reached, rather than checking all vertices for empty cones */
1611   while (fifoSize - fifoStart) {
1612     const PetscInt q   = fifo[fifoStart];
1613     const PetscInt o   = fifo[fifoStart+1];
1614     const PetscInt rev = o >= 0 ? 0 : 1;
1615     const PetscInt off = rev ? -(o+1) : o;
1616 
1617     if (useCone) {
1618       ierr = DMPlexGetConeSize(dm, q, &tmpSize);CHKERRQ(ierr);
1619       ierr = DMPlexGetCone(dm, q, &tmp);CHKERRQ(ierr);
1620       ierr = DMPlexGetConeOrientation(dm, q, &tmpO);CHKERRQ(ierr);
1621     } else {
1622       ierr = DMPlexGetSupportSize(dm, q, &tmpSize);CHKERRQ(ierr);
1623       ierr = DMPlexGetSupport(dm, q, &tmp);CHKERRQ(ierr);
1624       tmpO = NULL;
1625     }
1626     for (t = 0; t < tmpSize; ++t) {
1627       const PetscInt i  = ((rev ? tmpSize-t : t) + off)%tmpSize;
1628       const PetscInt cp = tmp[i];
1629       /* Must propogate orientation: When we reverse orientation, we both reverse the direction of iteration and start at the other end of the chain. */
1630       /* HACK: It is worse to get the size here, than to change the interpretation of -(*+1)
1631        const PetscInt co = tmpO ? (rev ? -(tmpO[i]+1) : tmpO[i]) : 0; */
1632       PetscInt       co = tmpO ? tmpO[i] : 0;
1633       PetscInt       c;
1634 
1635       if (rev) {
1636         PetscInt childSize, coff;
1637         ierr = DMPlexGetConeSize(dm, cp, &childSize);CHKERRQ(ierr);
1638         coff = tmpO[i] < 0 ? -(tmpO[i]+1) : tmpO[i];
1639         co   = childSize ? -(((coff+childSize-1)%childSize)+1) : 0;
1640       }
1641       /* Check for duplicate */
1642       for (c = 0; c < closureSize; c += 2) {
1643         if (closure[c] == cp) break;
1644       }
1645       if (c == closureSize) {
1646         closure[closureSize]   = cp;
1647         closure[closureSize+1] = co;
1648         fifo[fifoSize]         = cp;
1649         fifo[fifoSize+1]       = co;
1650         closureSize           += 2;
1651         fifoSize              += 2;
1652       }
1653     }
1654     fifoStart += 2;
1655   }
1656   if (numPoints) *numPoints = closureSize/2;
1657   if (points)    *points    = closure;
1658   ierr = DMRestoreWorkArray(dm, maxSize, PETSC_INT, &fifo);CHKERRQ(ierr);
1659   PetscFunctionReturn(0);
1660 }
1661 
1662 #undef __FUNCT__
1663 #define __FUNCT__ "DMPlexRestoreTransitiveClosure"
1664 /*@C
1665   DMPlexRestoreTransitiveClosure - Restore the array of points on the transitive closure of the in-edges or out-edges for this point in the Sieve DAG
1666 
1667   Not collective
1668 
1669   Input Parameters:
1670 + mesh - The DMPlex
1671 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1672 . useCone - PETSC_TRUE for in-edges,  otherwise use out-edges
1673 . numPoints - The number of points in the closure, so points[] is of size 2*numPoints, zeroed on exit
1674 - points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...], zeroed on exit
1675 
1676   Note:
1677   If not using internal storage (points is not NULL on input), this call is unnecessary
1678 
1679   Fortran Notes:
1680   Since it returns an array, this routine is only available in Fortran 90, and you must
1681   include petsc.h90 in your code.
1682 
1683   The numPoints argument is not present in the Fortran 90 binding since it is internal to the array.
1684 
1685   Level: beginner
1686 
1687 .seealso: DMPlexGetTransitiveClosure(), DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone()
1688 @*/
1689 PetscErrorCode DMPlexRestoreTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[])
1690 {
1691   PetscErrorCode ierr;
1692 
1693   PetscFunctionBegin;
1694   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1695   if (numPoints) PetscValidIntPointer(numPoints,4);
1696   if (points) PetscValidPointer(points,5);
1697   ierr = DMRestoreWorkArray(dm, 0, PETSC_INT, points);CHKERRQ(ierr);
1698   if (numPoints) *numPoints = 0;
1699   PetscFunctionReturn(0);
1700 }
1701 
1702 #undef __FUNCT__
1703 #define __FUNCT__ "DMPlexGetMaxSizes"
1704 /*@
1705   DMPlexGetMaxSizes - Return the maximum number of in-edges (cone) and out-edges (support) for any point in the Sieve DAG
1706 
1707   Not collective
1708 
1709   Input Parameter:
1710 . mesh - The DMPlex
1711 
1712   Output Parameters:
1713 + maxConeSize - The maximum number of in-edges
1714 - maxSupportSize - The maximum number of out-edges
1715 
1716   Level: beginner
1717 
1718 .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexSetChart()
1719 @*/
1720 PetscErrorCode DMPlexGetMaxSizes(DM dm, PetscInt *maxConeSize, PetscInt *maxSupportSize)
1721 {
1722   DM_Plex *mesh = (DM_Plex*) dm->data;
1723 
1724   PetscFunctionBegin;
1725   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1726   if (maxConeSize)    *maxConeSize    = mesh->maxConeSize;
1727   if (maxSupportSize) *maxSupportSize = mesh->maxSupportSize;
1728   PetscFunctionReturn(0);
1729 }
1730 
1731 #undef __FUNCT__
1732 #define __FUNCT__ "DMSetUp_Plex"
1733 PetscErrorCode DMSetUp_Plex(DM dm)
1734 {
1735   DM_Plex       *mesh = (DM_Plex*) dm->data;
1736   PetscInt       size;
1737   PetscErrorCode ierr;
1738 
1739   PetscFunctionBegin;
1740   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1741   ierr = PetscSectionSetUp(mesh->coneSection);CHKERRQ(ierr);
1742   ierr = PetscSectionGetStorageSize(mesh->coneSection, &size);CHKERRQ(ierr);
1743   ierr = PetscMalloc1(size, &mesh->cones);CHKERRQ(ierr);
1744   ierr = PetscCalloc1(size, &mesh->coneOrientations);CHKERRQ(ierr);
1745   if (mesh->maxSupportSize) {
1746     ierr = PetscSectionSetUp(mesh->supportSection);CHKERRQ(ierr);
1747     ierr = PetscSectionGetStorageSize(mesh->supportSection, &size);CHKERRQ(ierr);
1748     ierr = PetscMalloc1(size, &mesh->supports);CHKERRQ(ierr);
1749   }
1750   PetscFunctionReturn(0);
1751 }
1752 
1753 #undef __FUNCT__
1754 #define __FUNCT__ "DMCreateSubDM_Plex"
1755 PetscErrorCode DMCreateSubDM_Plex(DM dm, PetscInt numFields, PetscInt fields[], IS *is, DM *subdm)
1756 {
1757   PetscErrorCode ierr;
1758 
1759   PetscFunctionBegin;
1760   if (subdm) {ierr = DMClone(dm, subdm);CHKERRQ(ierr);}
1761   ierr = DMCreateSubDM_Section_Private(dm, numFields, fields, is, subdm);CHKERRQ(ierr);
1762   PetscFunctionReturn(0);
1763 }
1764 
1765 #undef __FUNCT__
1766 #define __FUNCT__ "DMPlexSymmetrize"
1767 /*@
1768   DMPlexSymmetrize - Creates support (out-edge) information from cone (in-edge) inoformation
1769 
1770   Not collective
1771 
1772   Input Parameter:
1773 . mesh - The DMPlex
1774 
1775   Output Parameter:
1776 
1777   Note:
1778   This should be called after all calls to DMPlexSetCone()
1779 
1780   Level: beginner
1781 
1782 .seealso: DMPlexCreate(), DMPlexSetChart(), DMPlexSetConeSize(), DMPlexSetCone()
1783 @*/
1784 PetscErrorCode DMPlexSymmetrize(DM dm)
1785 {
1786   DM_Plex       *mesh = (DM_Plex*) dm->data;
1787   PetscInt      *offsets;
1788   PetscInt       supportSize;
1789   PetscInt       pStart, pEnd, p;
1790   PetscErrorCode ierr;
1791 
1792   PetscFunctionBegin;
1793   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1794   if (mesh->supports) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Supports were already setup in this DMPlex");
1795   /* Calculate support sizes */
1796   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
1797   for (p = pStart; p < pEnd; ++p) {
1798     PetscInt dof, off, c;
1799 
1800     ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
1801     ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
1802     for (c = off; c < off+dof; ++c) {
1803       ierr = PetscSectionAddDof(mesh->supportSection, mesh->cones[c], 1);CHKERRQ(ierr);
1804     }
1805   }
1806   for (p = pStart; p < pEnd; ++p) {
1807     PetscInt dof;
1808 
1809     ierr = PetscSectionGetDof(mesh->supportSection, p, &dof);CHKERRQ(ierr);
1810 
1811     mesh->maxSupportSize = PetscMax(mesh->maxSupportSize, dof);
1812   }
1813   ierr = PetscSectionSetUp(mesh->supportSection);CHKERRQ(ierr);
1814   /* Calculate supports */
1815   ierr = PetscSectionGetStorageSize(mesh->supportSection, &supportSize);CHKERRQ(ierr);
1816   ierr = PetscMalloc1(supportSize, &mesh->supports);CHKERRQ(ierr);
1817   ierr = PetscCalloc1(pEnd - pStart, &offsets);CHKERRQ(ierr);
1818   for (p = pStart; p < pEnd; ++p) {
1819     PetscInt dof, off, c;
1820 
1821     ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
1822     ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
1823     for (c = off; c < off+dof; ++c) {
1824       const PetscInt q = mesh->cones[c];
1825       PetscInt       offS;
1826 
1827       ierr = PetscSectionGetOffset(mesh->supportSection, q, &offS);CHKERRQ(ierr);
1828 
1829       mesh->supports[offS+offsets[q]] = p;
1830       ++offsets[q];
1831     }
1832   }
1833   ierr = PetscFree(offsets);CHKERRQ(ierr);
1834   PetscFunctionReturn(0);
1835 }
1836 
1837 #undef __FUNCT__
1838 #define __FUNCT__ "DMPlexStratify"
1839 /*@
1840   DMPlexStratify - The Sieve DAG for most topologies is a graded poset (http://en.wikipedia.org/wiki/Graded_poset), and
1841   can be illustrated by Hasse Diagram (a http://en.wikipedia.org/wiki/Hasse_diagram). The strata group all points of the
1842   same grade, and this function calculates the strata. This grade can be seen as the height (or depth) of the point in
1843   the DAG.
1844 
1845   Collective on dm
1846 
1847   Input Parameter:
1848 . mesh - The DMPlex
1849 
1850   Output Parameter:
1851 
1852   Notes:
1853   Concretely, DMPlexStratify() creates a new label named "depth" containing the dimension of each element: 0 for vertices,
1854   1 for edges, and so on.  The depth label can be accessed through DMPlexGetDepthLabel() or DMPlexGetDepthStratum(), or
1855   manually via DMGetLabel().  The height is defined implicitly by height = maxDimension - depth, and can be accessed
1856   via DMPlexGetHeightStratum().  For example, cells have height 0 and faces have height 1.
1857 
1858   DMPlexStratify() should be called after all calls to DMPlexSymmetrize()
1859 
1860   Level: beginner
1861 
1862 .seealso: DMPlexCreate(), DMPlexSymmetrize()
1863 @*/
1864 PetscErrorCode DMPlexStratify(DM dm)
1865 {
1866   DM_Plex       *mesh = (DM_Plex*) dm->data;
1867   DMLabel        label;
1868   PetscInt       pStart, pEnd, p;
1869   PetscInt       numRoots = 0, numLeaves = 0;
1870   PetscErrorCode ierr;
1871 
1872   PetscFunctionBegin;
1873   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1874   ierr = PetscLogEventBegin(DMPLEX_Stratify,dm,0,0,0);CHKERRQ(ierr);
1875   /* Calculate depth */
1876   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
1877   ierr = DMCreateLabel(dm, "depth");CHKERRQ(ierr);
1878   ierr = DMPlexGetDepthLabel(dm, &label);CHKERRQ(ierr);
1879   /* Initialize roots and count leaves */
1880   for (p = pStart; p < pEnd; ++p) {
1881     PetscInt coneSize, supportSize;
1882 
1883     ierr = DMPlexGetConeSize(dm, p, &coneSize);CHKERRQ(ierr);
1884     ierr = DMPlexGetSupportSize(dm, p, &supportSize);CHKERRQ(ierr);
1885     if (!coneSize && supportSize) {
1886       ++numRoots;
1887       ierr = DMLabelSetValue(label, p, 0);CHKERRQ(ierr);
1888     } else if (!supportSize && coneSize) {
1889       ++numLeaves;
1890     } else if (!supportSize && !coneSize) {
1891       /* Isolated points */
1892       ierr = DMLabelSetValue(label, p, 0);CHKERRQ(ierr);
1893     }
1894   }
1895   if (numRoots + numLeaves == (pEnd - pStart)) {
1896     for (p = pStart; p < pEnd; ++p) {
1897       PetscInt coneSize, supportSize;
1898 
1899       ierr = DMPlexGetConeSize(dm, p, &coneSize);CHKERRQ(ierr);
1900       ierr = DMPlexGetSupportSize(dm, p, &supportSize);CHKERRQ(ierr);
1901       if (!supportSize && coneSize) {
1902         ierr = DMLabelSetValue(label, p, 1);CHKERRQ(ierr);
1903       }
1904     }
1905   } else {
1906     IS       pointIS;
1907     PetscInt numPoints = 0, level = 0;
1908 
1909     ierr = DMLabelGetStratumIS(label, level, &pointIS);CHKERRQ(ierr);
1910     if (pointIS) {ierr = ISGetLocalSize(pointIS, &numPoints);CHKERRQ(ierr);}
1911     while (numPoints) {
1912       const PetscInt *points;
1913       const PetscInt  newLevel = level+1;
1914 
1915       ierr = ISGetIndices(pointIS, &points);CHKERRQ(ierr);
1916       for (p = 0; p < numPoints; ++p) {
1917         const PetscInt  point = points[p];
1918         const PetscInt *support;
1919         PetscInt        supportSize, s;
1920 
1921         ierr = DMPlexGetSupportSize(dm, point, &supportSize);CHKERRQ(ierr);
1922         ierr = DMPlexGetSupport(dm, point, &support);CHKERRQ(ierr);
1923         for (s = 0; s < supportSize; ++s) {
1924           ierr = DMLabelSetValue(label, support[s], newLevel);CHKERRQ(ierr);
1925         }
1926       }
1927       ierr = ISRestoreIndices(pointIS, &points);CHKERRQ(ierr);
1928       ++level;
1929       ierr = ISDestroy(&pointIS);CHKERRQ(ierr);
1930       ierr = DMLabelGetStratumIS(label, level, &pointIS);CHKERRQ(ierr);
1931       if (pointIS) {ierr = ISGetLocalSize(pointIS, &numPoints);CHKERRQ(ierr);}
1932       else         {numPoints = 0;}
1933     }
1934     ierr = ISDestroy(&pointIS);CHKERRQ(ierr);
1935   }
1936   { /* just in case there is an empty process */
1937     PetscInt numValues, maxValues = 0, v;
1938 
1939     ierr = DMLabelGetNumValues(label,&numValues);CHKERRQ(ierr);
1940     ierr = MPI_Allreduce(&numValues,&maxValues,1,MPIU_INT,MPI_MAX,PetscObjectComm((PetscObject)dm));CHKERRQ(ierr);
1941     for (v = numValues; v < maxValues; v++) {
1942       DMLabelAddStratum(label,v);CHKERRQ(ierr);
1943     }
1944   }
1945 
1946   ierr = DMLabelGetState(label, &mesh->depthState);CHKERRQ(ierr);
1947   ierr = PetscLogEventEnd(DMPLEX_Stratify,dm,0,0,0);CHKERRQ(ierr);
1948   PetscFunctionReturn(0);
1949 }
1950 
1951 #undef __FUNCT__
1952 #define __FUNCT__ "DMPlexGetJoin"
1953 /*@C
1954   DMPlexGetJoin - Get an array for the join of the set of points
1955 
1956   Not Collective
1957 
1958   Input Parameters:
1959 + dm - The DMPlex object
1960 . numPoints - The number of input points for the join
1961 - points - The input points
1962 
1963   Output Parameters:
1964 + numCoveredPoints - The number of points in the join
1965 - coveredPoints - The points in the join
1966 
1967   Level: intermediate
1968 
1969   Note: Currently, this is restricted to a single level join
1970 
1971   Fortran Notes:
1972   Since it returns an array, this routine is only available in Fortran 90, and you must
1973   include petsc.h90 in your code.
1974 
1975   The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array.
1976 
1977 .keywords: mesh
1978 .seealso: DMPlexRestoreJoin(), DMPlexGetMeet()
1979 @*/
1980 PetscErrorCode DMPlexGetJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
1981 {
1982   DM_Plex       *mesh = (DM_Plex*) dm->data;
1983   PetscInt      *join[2];
1984   PetscInt       joinSize, i = 0;
1985   PetscInt       dof, off, p, c, m;
1986   PetscErrorCode ierr;
1987 
1988   PetscFunctionBegin;
1989   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1990   PetscValidPointer(points, 2);
1991   PetscValidPointer(numCoveredPoints, 3);
1992   PetscValidPointer(coveredPoints, 4);
1993   ierr = DMGetWorkArray(dm, mesh->maxSupportSize, PETSC_INT, &join[0]);CHKERRQ(ierr);
1994   ierr = DMGetWorkArray(dm, mesh->maxSupportSize, PETSC_INT, &join[1]);CHKERRQ(ierr);
1995   /* Copy in support of first point */
1996   ierr = PetscSectionGetDof(mesh->supportSection, points[0], &dof);CHKERRQ(ierr);
1997   ierr = PetscSectionGetOffset(mesh->supportSection, points[0], &off);CHKERRQ(ierr);
1998   for (joinSize = 0; joinSize < dof; ++joinSize) {
1999     join[i][joinSize] = mesh->supports[off+joinSize];
2000   }
2001   /* Check each successive support */
2002   for (p = 1; p < numPoints; ++p) {
2003     PetscInt newJoinSize = 0;
2004 
2005     ierr = PetscSectionGetDof(mesh->supportSection, points[p], &dof);CHKERRQ(ierr);
2006     ierr = PetscSectionGetOffset(mesh->supportSection, points[p], &off);CHKERRQ(ierr);
2007     for (c = 0; c < dof; ++c) {
2008       const PetscInt point = mesh->supports[off+c];
2009 
2010       for (m = 0; m < joinSize; ++m) {
2011         if (point == join[i][m]) {
2012           join[1-i][newJoinSize++] = point;
2013           break;
2014         }
2015       }
2016     }
2017     joinSize = newJoinSize;
2018     i        = 1-i;
2019   }
2020   *numCoveredPoints = joinSize;
2021   *coveredPoints    = join[i];
2022   ierr              = DMRestoreWorkArray(dm, mesh->maxSupportSize, PETSC_INT, &join[1-i]);CHKERRQ(ierr);
2023   PetscFunctionReturn(0);
2024 }
2025 
2026 #undef __FUNCT__
2027 #define __FUNCT__ "DMPlexRestoreJoin"
2028 /*@C
2029   DMPlexRestoreJoin - Restore an array for the join of the set of points
2030 
2031   Not Collective
2032 
2033   Input Parameters:
2034 + dm - The DMPlex object
2035 . numPoints - The number of input points for the join
2036 - points - The input points
2037 
2038   Output Parameters:
2039 + numCoveredPoints - The number of points in the join
2040 - coveredPoints - The points in the join
2041 
2042   Fortran Notes:
2043   Since it returns an array, this routine is only available in Fortran 90, and you must
2044   include petsc.h90 in your code.
2045 
2046   The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array.
2047 
2048   Level: intermediate
2049 
2050 .keywords: mesh
2051 .seealso: DMPlexGetJoin(), DMPlexGetFullJoin(), DMPlexGetMeet()
2052 @*/
2053 PetscErrorCode DMPlexRestoreJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
2054 {
2055   PetscErrorCode ierr;
2056 
2057   PetscFunctionBegin;
2058   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2059   if (points) PetscValidIntPointer(points,3);
2060   if (numCoveredPoints) PetscValidIntPointer(numCoveredPoints,4);
2061   PetscValidPointer(coveredPoints, 5);
2062   ierr = DMRestoreWorkArray(dm, 0, PETSC_INT, (void*) coveredPoints);CHKERRQ(ierr);
2063   if (numCoveredPoints) *numCoveredPoints = 0;
2064   PetscFunctionReturn(0);
2065 }
2066 
2067 #undef __FUNCT__
2068 #define __FUNCT__ "DMPlexGetFullJoin"
2069 /*@C
2070   DMPlexGetFullJoin - Get an array for the join of the set of points
2071 
2072   Not Collective
2073 
2074   Input Parameters:
2075 + dm - The DMPlex object
2076 . numPoints - The number of input points for the join
2077 - points - The input points
2078 
2079   Output Parameters:
2080 + numCoveredPoints - The number of points in the join
2081 - coveredPoints - The points in the join
2082 
2083   Fortran Notes:
2084   Since it returns an array, this routine is only available in Fortran 90, and you must
2085   include petsc.h90 in your code.
2086 
2087   The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array.
2088 
2089   Level: intermediate
2090 
2091 .keywords: mesh
2092 .seealso: DMPlexGetJoin(), DMPlexRestoreJoin(), DMPlexGetMeet()
2093 @*/
2094 PetscErrorCode DMPlexGetFullJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
2095 {
2096   DM_Plex       *mesh = (DM_Plex*) dm->data;
2097   PetscInt      *offsets, **closures;
2098   PetscInt      *join[2];
2099   PetscInt       depth = 0, maxSize, joinSize = 0, i = 0;
2100   PetscInt       p, d, c, m, ms;
2101   PetscErrorCode ierr;
2102 
2103   PetscFunctionBegin;
2104   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2105   PetscValidPointer(points, 2);
2106   PetscValidPointer(numCoveredPoints, 3);
2107   PetscValidPointer(coveredPoints, 4);
2108 
2109   ierr    = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
2110   ierr    = PetscCalloc1(numPoints, &closures);CHKERRQ(ierr);
2111   ierr    = DMGetWorkArray(dm, numPoints*(depth+2), PETSC_INT, &offsets);CHKERRQ(ierr);
2112   ms      = mesh->maxSupportSize;
2113   maxSize = (ms > 1) ? ((PetscPowInt(ms,depth+1)-1)/(ms-1)) : depth + 1;
2114   ierr    = DMGetWorkArray(dm, maxSize, PETSC_INT, &join[0]);CHKERRQ(ierr);
2115   ierr    = DMGetWorkArray(dm, maxSize, PETSC_INT, &join[1]);CHKERRQ(ierr);
2116 
2117   for (p = 0; p < numPoints; ++p) {
2118     PetscInt closureSize;
2119 
2120     ierr = DMPlexGetTransitiveClosure(dm, points[p], PETSC_FALSE, &closureSize, &closures[p]);CHKERRQ(ierr);
2121 
2122     offsets[p*(depth+2)+0] = 0;
2123     for (d = 0; d < depth+1; ++d) {
2124       PetscInt pStart, pEnd, i;
2125 
2126       ierr = DMPlexGetDepthStratum(dm, d, &pStart, &pEnd);CHKERRQ(ierr);
2127       for (i = offsets[p*(depth+2)+d]; i < closureSize; ++i) {
2128         if ((pStart > closures[p][i*2]) || (pEnd <= closures[p][i*2])) {
2129           offsets[p*(depth+2)+d+1] = i;
2130           break;
2131         }
2132       }
2133       if (i == closureSize) offsets[p*(depth+2)+d+1] = i;
2134     }
2135     if (offsets[p*(depth+2)+depth+1] != closureSize) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Total size of closure %D should be %D", offsets[p*(depth+2)+depth+1], closureSize);
2136   }
2137   for (d = 0; d < depth+1; ++d) {
2138     PetscInt dof;
2139 
2140     /* Copy in support of first point */
2141     dof = offsets[d+1] - offsets[d];
2142     for (joinSize = 0; joinSize < dof; ++joinSize) {
2143       join[i][joinSize] = closures[0][(offsets[d]+joinSize)*2];
2144     }
2145     /* Check each successive cone */
2146     for (p = 1; p < numPoints && joinSize; ++p) {
2147       PetscInt newJoinSize = 0;
2148 
2149       dof = offsets[p*(depth+2)+d+1] - offsets[p*(depth+2)+d];
2150       for (c = 0; c < dof; ++c) {
2151         const PetscInt point = closures[p][(offsets[p*(depth+2)+d]+c)*2];
2152 
2153         for (m = 0; m < joinSize; ++m) {
2154           if (point == join[i][m]) {
2155             join[1-i][newJoinSize++] = point;
2156             break;
2157           }
2158         }
2159       }
2160       joinSize = newJoinSize;
2161       i        = 1-i;
2162     }
2163     if (joinSize) break;
2164   }
2165   *numCoveredPoints = joinSize;
2166   *coveredPoints    = join[i];
2167   for (p = 0; p < numPoints; ++p) {
2168     ierr = DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_FALSE, NULL, &closures[p]);CHKERRQ(ierr);
2169   }
2170   ierr = PetscFree(closures);CHKERRQ(ierr);
2171   ierr = DMRestoreWorkArray(dm, numPoints*(depth+2), PETSC_INT, &offsets);CHKERRQ(ierr);
2172   ierr = DMRestoreWorkArray(dm, mesh->maxSupportSize, PETSC_INT, &join[1-i]);CHKERRQ(ierr);
2173   PetscFunctionReturn(0);
2174 }
2175 
2176 #undef __FUNCT__
2177 #define __FUNCT__ "DMPlexGetMeet"
2178 /*@C
2179   DMPlexGetMeet - Get an array for the meet of the set of points
2180 
2181   Not Collective
2182 
2183   Input Parameters:
2184 + dm - The DMPlex object
2185 . numPoints - The number of input points for the meet
2186 - points - The input points
2187 
2188   Output Parameters:
2189 + numCoveredPoints - The number of points in the meet
2190 - coveredPoints - The points in the meet
2191 
2192   Level: intermediate
2193 
2194   Note: Currently, this is restricted to a single level meet
2195 
2196   Fortran Notes:
2197   Since it returns an array, this routine is only available in Fortran 90, and you must
2198   include petsc.h90 in your code.
2199 
2200   The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array.
2201 
2202 .keywords: mesh
2203 .seealso: DMPlexRestoreMeet(), DMPlexGetJoin()
2204 @*/
2205 PetscErrorCode DMPlexGetMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveringPoints, const PetscInt **coveringPoints)
2206 {
2207   DM_Plex       *mesh = (DM_Plex*) dm->data;
2208   PetscInt      *meet[2];
2209   PetscInt       meetSize, i = 0;
2210   PetscInt       dof, off, p, c, m;
2211   PetscErrorCode ierr;
2212 
2213   PetscFunctionBegin;
2214   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2215   PetscValidPointer(points, 2);
2216   PetscValidPointer(numCoveringPoints, 3);
2217   PetscValidPointer(coveringPoints, 4);
2218   ierr = DMGetWorkArray(dm, mesh->maxConeSize, PETSC_INT, &meet[0]);CHKERRQ(ierr);
2219   ierr = DMGetWorkArray(dm, mesh->maxConeSize, PETSC_INT, &meet[1]);CHKERRQ(ierr);
2220   /* Copy in cone of first point */
2221   ierr = PetscSectionGetDof(mesh->coneSection, points[0], &dof);CHKERRQ(ierr);
2222   ierr = PetscSectionGetOffset(mesh->coneSection, points[0], &off);CHKERRQ(ierr);
2223   for (meetSize = 0; meetSize < dof; ++meetSize) {
2224     meet[i][meetSize] = mesh->cones[off+meetSize];
2225   }
2226   /* Check each successive cone */
2227   for (p = 1; p < numPoints; ++p) {
2228     PetscInt newMeetSize = 0;
2229 
2230     ierr = PetscSectionGetDof(mesh->coneSection, points[p], &dof);CHKERRQ(ierr);
2231     ierr = PetscSectionGetOffset(mesh->coneSection, points[p], &off);CHKERRQ(ierr);
2232     for (c = 0; c < dof; ++c) {
2233       const PetscInt point = mesh->cones[off+c];
2234 
2235       for (m = 0; m < meetSize; ++m) {
2236         if (point == meet[i][m]) {
2237           meet[1-i][newMeetSize++] = point;
2238           break;
2239         }
2240       }
2241     }
2242     meetSize = newMeetSize;
2243     i        = 1-i;
2244   }
2245   *numCoveringPoints = meetSize;
2246   *coveringPoints    = meet[i];
2247   ierr               = DMRestoreWorkArray(dm, mesh->maxConeSize, PETSC_INT, &meet[1-i]);CHKERRQ(ierr);
2248   PetscFunctionReturn(0);
2249 }
2250 
2251 #undef __FUNCT__
2252 #define __FUNCT__ "DMPlexRestoreMeet"
2253 /*@C
2254   DMPlexRestoreMeet - Restore an array for the meet of the set of points
2255 
2256   Not Collective
2257 
2258   Input Parameters:
2259 + dm - The DMPlex object
2260 . numPoints - The number of input points for the meet
2261 - points - The input points
2262 
2263   Output Parameters:
2264 + numCoveredPoints - The number of points in the meet
2265 - coveredPoints - The points in the meet
2266 
2267   Level: intermediate
2268 
2269   Fortran Notes:
2270   Since it returns an array, this routine is only available in Fortran 90, and you must
2271   include petsc.h90 in your code.
2272 
2273   The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array.
2274 
2275 .keywords: mesh
2276 .seealso: DMPlexGetMeet(), DMPlexGetFullMeet(), DMPlexGetJoin()
2277 @*/
2278 PetscErrorCode DMPlexRestoreMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
2279 {
2280   PetscErrorCode ierr;
2281 
2282   PetscFunctionBegin;
2283   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2284   if (points) PetscValidIntPointer(points,3);
2285   if (numCoveredPoints) PetscValidIntPointer(numCoveredPoints,4);
2286   PetscValidPointer(coveredPoints,5);
2287   ierr = DMRestoreWorkArray(dm, 0, PETSC_INT, (void*) coveredPoints);CHKERRQ(ierr);
2288   if (numCoveredPoints) *numCoveredPoints = 0;
2289   PetscFunctionReturn(0);
2290 }
2291 
2292 #undef __FUNCT__
2293 #define __FUNCT__ "DMPlexGetFullMeet"
2294 /*@C
2295   DMPlexGetFullMeet - Get an array for the meet of the set of points
2296 
2297   Not Collective
2298 
2299   Input Parameters:
2300 + dm - The DMPlex object
2301 . numPoints - The number of input points for the meet
2302 - points - The input points
2303 
2304   Output Parameters:
2305 + numCoveredPoints - The number of points in the meet
2306 - coveredPoints - The points in the meet
2307 
2308   Level: intermediate
2309 
2310   Fortran Notes:
2311   Since it returns an array, this routine is only available in Fortran 90, and you must
2312   include petsc.h90 in your code.
2313 
2314   The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array.
2315 
2316 .keywords: mesh
2317 .seealso: DMPlexGetMeet(), DMPlexRestoreMeet(), DMPlexGetJoin()
2318 @*/
2319 PetscErrorCode DMPlexGetFullMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
2320 {
2321   DM_Plex       *mesh = (DM_Plex*) dm->data;
2322   PetscInt      *offsets, **closures;
2323   PetscInt      *meet[2];
2324   PetscInt       height = 0, maxSize, meetSize = 0, i = 0;
2325   PetscInt       p, h, c, m, mc;
2326   PetscErrorCode ierr;
2327 
2328   PetscFunctionBegin;
2329   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2330   PetscValidPointer(points, 2);
2331   PetscValidPointer(numCoveredPoints, 3);
2332   PetscValidPointer(coveredPoints, 4);
2333 
2334   ierr    = DMPlexGetDepth(dm, &height);CHKERRQ(ierr);
2335   ierr    = PetscMalloc1(numPoints, &closures);CHKERRQ(ierr);
2336   ierr    = DMGetWorkArray(dm, numPoints*(height+2), PETSC_INT, &offsets);CHKERRQ(ierr);
2337   mc      = mesh->maxConeSize;
2338   maxSize = (mc > 1) ? ((PetscPowInt(mc,height+1)-1)/(mc-1)) : height + 1;
2339   ierr    = DMGetWorkArray(dm, maxSize, PETSC_INT, &meet[0]);CHKERRQ(ierr);
2340   ierr    = DMGetWorkArray(dm, maxSize, PETSC_INT, &meet[1]);CHKERRQ(ierr);
2341 
2342   for (p = 0; p < numPoints; ++p) {
2343     PetscInt closureSize;
2344 
2345     ierr = DMPlexGetTransitiveClosure(dm, points[p], PETSC_TRUE, &closureSize, &closures[p]);CHKERRQ(ierr);
2346 
2347     offsets[p*(height+2)+0] = 0;
2348     for (h = 0; h < height+1; ++h) {
2349       PetscInt pStart, pEnd, i;
2350 
2351       ierr = DMPlexGetHeightStratum(dm, h, &pStart, &pEnd);CHKERRQ(ierr);
2352       for (i = offsets[p*(height+2)+h]; i < closureSize; ++i) {
2353         if ((pStart > closures[p][i*2]) || (pEnd <= closures[p][i*2])) {
2354           offsets[p*(height+2)+h+1] = i;
2355           break;
2356         }
2357       }
2358       if (i == closureSize) offsets[p*(height+2)+h+1] = i;
2359     }
2360     if (offsets[p*(height+2)+height+1] != closureSize) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Total size of closure %D should be %D", offsets[p*(height+2)+height+1], closureSize);
2361   }
2362   for (h = 0; h < height+1; ++h) {
2363     PetscInt dof;
2364 
2365     /* Copy in cone of first point */
2366     dof = offsets[h+1] - offsets[h];
2367     for (meetSize = 0; meetSize < dof; ++meetSize) {
2368       meet[i][meetSize] = closures[0][(offsets[h]+meetSize)*2];
2369     }
2370     /* Check each successive cone */
2371     for (p = 1; p < numPoints && meetSize; ++p) {
2372       PetscInt newMeetSize = 0;
2373 
2374       dof = offsets[p*(height+2)+h+1] - offsets[p*(height+2)+h];
2375       for (c = 0; c < dof; ++c) {
2376         const PetscInt point = closures[p][(offsets[p*(height+2)+h]+c)*2];
2377 
2378         for (m = 0; m < meetSize; ++m) {
2379           if (point == meet[i][m]) {
2380             meet[1-i][newMeetSize++] = point;
2381             break;
2382           }
2383         }
2384       }
2385       meetSize = newMeetSize;
2386       i        = 1-i;
2387     }
2388     if (meetSize) break;
2389   }
2390   *numCoveredPoints = meetSize;
2391   *coveredPoints    = meet[i];
2392   for (p = 0; p < numPoints; ++p) {
2393     ierr = DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_TRUE, NULL, &closures[p]);CHKERRQ(ierr);
2394   }
2395   ierr = PetscFree(closures);CHKERRQ(ierr);
2396   ierr = DMRestoreWorkArray(dm, numPoints*(height+2), PETSC_INT, &offsets);CHKERRQ(ierr);
2397   ierr = DMRestoreWorkArray(dm, mesh->maxConeSize, PETSC_INT, &meet[1-i]);CHKERRQ(ierr);
2398   PetscFunctionReturn(0);
2399 }
2400 
2401 #undef __FUNCT__
2402 #define __FUNCT__ "DMPlexEqual"
2403 /*@C
2404   DMPlexEqual - Determine if two DMs have the same topology
2405 
2406   Not Collective
2407 
2408   Input Parameters:
2409 + dmA - A DMPlex object
2410 - dmB - A DMPlex object
2411 
2412   Output Parameters:
2413 . equal - PETSC_TRUE if the topologies are identical
2414 
2415   Level: intermediate
2416 
2417   Notes:
2418   We are not solving graph isomorphism, so we do not permutation.
2419 
2420 .keywords: mesh
2421 .seealso: DMPlexGetCone()
2422 @*/
2423 PetscErrorCode DMPlexEqual(DM dmA, DM dmB, PetscBool *equal)
2424 {
2425   PetscInt       depth, depthB, pStart, pEnd, pStartB, pEndB, p;
2426   PetscErrorCode ierr;
2427 
2428   PetscFunctionBegin;
2429   PetscValidHeaderSpecific(dmA, DM_CLASSID, 1);
2430   PetscValidHeaderSpecific(dmB, DM_CLASSID, 2);
2431   PetscValidPointer(equal, 3);
2432 
2433   *equal = PETSC_FALSE;
2434   ierr = DMPlexGetDepth(dmA, &depth);CHKERRQ(ierr);
2435   ierr = DMPlexGetDepth(dmB, &depthB);CHKERRQ(ierr);
2436   if (depth != depthB) PetscFunctionReturn(0);
2437   ierr = DMPlexGetChart(dmA, &pStart,  &pEnd);CHKERRQ(ierr);
2438   ierr = DMPlexGetChart(dmB, &pStartB, &pEndB);CHKERRQ(ierr);
2439   if ((pStart != pStartB) || (pEnd != pEndB)) PetscFunctionReturn(0);
2440   for (p = pStart; p < pEnd; ++p) {
2441     const PetscInt *cone, *coneB, *ornt, *orntB, *support, *supportB;
2442     PetscInt        coneSize, coneSizeB, c, supportSize, supportSizeB, s;
2443 
2444     ierr = DMPlexGetConeSize(dmA, p, &coneSize);CHKERRQ(ierr);
2445     ierr = DMPlexGetCone(dmA, p, &cone);CHKERRQ(ierr);
2446     ierr = DMPlexGetConeOrientation(dmA, p, &ornt);CHKERRQ(ierr);
2447     ierr = DMPlexGetConeSize(dmB, p, &coneSizeB);CHKERRQ(ierr);
2448     ierr = DMPlexGetCone(dmB, p, &coneB);CHKERRQ(ierr);
2449     ierr = DMPlexGetConeOrientation(dmB, p, &orntB);CHKERRQ(ierr);
2450     if (coneSize != coneSizeB) PetscFunctionReturn(0);
2451     for (c = 0; c < coneSize; ++c) {
2452       if (cone[c] != coneB[c]) PetscFunctionReturn(0);
2453       if (ornt[c] != orntB[c]) PetscFunctionReturn(0);
2454     }
2455     ierr = DMPlexGetSupportSize(dmA, p, &supportSize);CHKERRQ(ierr);
2456     ierr = DMPlexGetSupport(dmA, p, &support);CHKERRQ(ierr);
2457     ierr = DMPlexGetSupportSize(dmB, p, &supportSizeB);CHKERRQ(ierr);
2458     ierr = DMPlexGetSupport(dmB, p, &supportB);CHKERRQ(ierr);
2459     if (supportSize != supportSizeB) PetscFunctionReturn(0);
2460     for (s = 0; s < supportSize; ++s) {
2461       if (support[s] != supportB[s]) PetscFunctionReturn(0);
2462     }
2463   }
2464   *equal = PETSC_TRUE;
2465   PetscFunctionReturn(0);
2466 }
2467 
2468 #undef __FUNCT__
2469 #define __FUNCT__ "DMPlexGetNumFaceVertices"
2470 PetscErrorCode DMPlexGetNumFaceVertices(DM dm, PetscInt cellDim, PetscInt numCorners, PetscInt *numFaceVertices)
2471 {
2472   MPI_Comm       comm;
2473   PetscErrorCode ierr;
2474 
2475   PetscFunctionBegin;
2476   ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr);
2477   PetscValidPointer(numFaceVertices,3);
2478   switch (cellDim) {
2479   case 0:
2480     *numFaceVertices = 0;
2481     break;
2482   case 1:
2483     *numFaceVertices = 1;
2484     break;
2485   case 2:
2486     switch (numCorners) {
2487     case 3: /* triangle */
2488       *numFaceVertices = 2; /* Edge has 2 vertices */
2489       break;
2490     case 4: /* quadrilateral */
2491       *numFaceVertices = 2; /* Edge has 2 vertices */
2492       break;
2493     case 6: /* quadratic triangle, tri and quad cohesive Lagrange cells */
2494       *numFaceVertices = 3; /* Edge has 3 vertices */
2495       break;
2496     case 9: /* quadratic quadrilateral, quadratic quad cohesive Lagrange cells */
2497       *numFaceVertices = 3; /* Edge has 3 vertices */
2498       break;
2499     default:
2500       SETERRQ2(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %D for dimension %D", numCorners, cellDim);
2501     }
2502     break;
2503   case 3:
2504     switch (numCorners) {
2505     case 4: /* tetradehdron */
2506       *numFaceVertices = 3; /* Face has 3 vertices */
2507       break;
2508     case 6: /* tet cohesive cells */
2509       *numFaceVertices = 4; /* Face has 4 vertices */
2510       break;
2511     case 8: /* hexahedron */
2512       *numFaceVertices = 4; /* Face has 4 vertices */
2513       break;
2514     case 9: /* tet cohesive Lagrange cells */
2515       *numFaceVertices = 6; /* Face has 6 vertices */
2516       break;
2517     case 10: /* quadratic tetrahedron */
2518       *numFaceVertices = 6; /* Face has 6 vertices */
2519       break;
2520     case 12: /* hex cohesive Lagrange cells */
2521       *numFaceVertices = 6; /* Face has 6 vertices */
2522       break;
2523     case 18: /* quadratic tet cohesive Lagrange cells */
2524       *numFaceVertices = 6; /* Face has 6 vertices */
2525       break;
2526     case 27: /* quadratic hexahedron, quadratic hex cohesive Lagrange cells */
2527       *numFaceVertices = 9; /* Face has 9 vertices */
2528       break;
2529     default:
2530       SETERRQ2(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %D for dimension %D", numCorners, cellDim);
2531     }
2532     break;
2533   default:
2534     SETERRQ1(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid cell dimension %D", cellDim);
2535   }
2536   PetscFunctionReturn(0);
2537 }
2538 
2539 #undef __FUNCT__
2540 #define __FUNCT__ "DMPlexGetDepthLabel"
2541 /*@
2542   DMPlexGetDepthLabel - Get the DMLabel recording the depth of each point
2543 
2544   Not Collective
2545 
2546   Input Parameter:
2547 . dm    - The DMPlex object
2548 
2549   Output Parameter:
2550 . depthLabel - The DMLabel recording point depth
2551 
2552   Level: developer
2553 
2554 .keywords: mesh, points
2555 .seealso: DMPlexGetDepth(), DMPlexGetHeightStratum(), DMPlexGetDepthStratum()
2556 @*/
2557 PetscErrorCode DMPlexGetDepthLabel(DM dm, DMLabel *depthLabel)
2558 {
2559   PetscErrorCode ierr;
2560 
2561   PetscFunctionBegin;
2562   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2563   PetscValidPointer(depthLabel, 2);
2564   if (!dm->depthLabel) {ierr = DMGetLabel(dm, "depth", &dm->depthLabel);CHKERRQ(ierr);}
2565   *depthLabel = dm->depthLabel;
2566   PetscFunctionReturn(0);
2567 }
2568 
2569 #undef __FUNCT__
2570 #define __FUNCT__ "DMPlexGetDepth"
2571 /*@
2572   DMPlexGetDepth - Get the depth of the DAG representing this mesh
2573 
2574   Not Collective
2575 
2576   Input Parameter:
2577 . dm    - The DMPlex object
2578 
2579   Output Parameter:
2580 . depth - The number of strata (breadth first levels) in the DAG
2581 
2582   Level: developer
2583 
2584 .keywords: mesh, points
2585 .seealso: DMPlexGetDepthLabel(), DMPlexGetHeightStratum(), DMPlexGetDepthStratum()
2586 @*/
2587 PetscErrorCode DMPlexGetDepth(DM dm, PetscInt *depth)
2588 {
2589   DMLabel        label;
2590   PetscInt       d = 0;
2591   PetscErrorCode ierr;
2592 
2593   PetscFunctionBegin;
2594   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2595   PetscValidPointer(depth, 2);
2596   ierr = DMPlexGetDepthLabel(dm, &label);CHKERRQ(ierr);
2597   if (label) {ierr = DMLabelGetNumValues(label, &d);CHKERRQ(ierr);}
2598   *depth = d-1;
2599   PetscFunctionReturn(0);
2600 }
2601 
2602 #undef __FUNCT__
2603 #define __FUNCT__ "DMPlexGetDepthStratum"
2604 /*@
2605   DMPlexGetDepthStratum - Get the bounds [start, end) for all points at a certain depth.
2606 
2607   Not Collective
2608 
2609   Input Parameters:
2610 + dm           - The DMPlex object
2611 - stratumValue - The requested depth
2612 
2613   Output Parameters:
2614 + start - The first point at this depth
2615 - end   - One beyond the last point at this depth
2616 
2617   Level: developer
2618 
2619 .keywords: mesh, points
2620 .seealso: DMPlexGetHeightStratum(), DMPlexGetDepth()
2621 @*/
2622 PetscErrorCode DMPlexGetDepthStratum(DM dm, PetscInt stratumValue, PetscInt *start, PetscInt *end)
2623 {
2624   DMLabel        label;
2625   PetscInt       pStart, pEnd;
2626   PetscErrorCode ierr;
2627 
2628   PetscFunctionBegin;
2629   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2630   if (start) {PetscValidPointer(start, 3); *start = 0;}
2631   if (end)   {PetscValidPointer(end,   4); *end   = 0;}
2632   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
2633   if (pStart == pEnd) PetscFunctionReturn(0);
2634   if (stratumValue < 0) {
2635     if (start) *start = pStart;
2636     if (end)   *end   = pEnd;
2637     PetscFunctionReturn(0);
2638   }
2639   ierr = DMPlexGetDepthLabel(dm, &label);CHKERRQ(ierr);
2640   if (!label) SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "No label named depth was found");
2641   ierr = DMLabelGetStratumBounds(label, stratumValue, start, end);CHKERRQ(ierr);
2642   PetscFunctionReturn(0);
2643 }
2644 
2645 #undef __FUNCT__
2646 #define __FUNCT__ "DMPlexGetHeightStratum"
2647 /*@
2648   DMPlexGetHeightStratum - Get the bounds [start, end) for all points at a certain height.
2649 
2650   Not Collective
2651 
2652   Input Parameters:
2653 + dm           - The DMPlex object
2654 - stratumValue - The requested height
2655 
2656   Output Parameters:
2657 + start - The first point at this height
2658 - end   - One beyond the last point at this height
2659 
2660   Level: developer
2661 
2662 .keywords: mesh, points
2663 .seealso: DMPlexGetDepthStratum(), DMPlexGetDepth()
2664 @*/
2665 PetscErrorCode DMPlexGetHeightStratum(DM dm, PetscInt stratumValue, PetscInt *start, PetscInt *end)
2666 {
2667   DMLabel        label;
2668   PetscInt       depth, pStart, pEnd;
2669   PetscErrorCode ierr;
2670 
2671   PetscFunctionBegin;
2672   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2673   if (start) {PetscValidPointer(start, 3); *start = 0;}
2674   if (end)   {PetscValidPointer(end,   4); *end   = 0;}
2675   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
2676   if (pStart == pEnd) PetscFunctionReturn(0);
2677   if (stratumValue < 0) {
2678     if (start) *start = pStart;
2679     if (end)   *end   = pEnd;
2680     PetscFunctionReturn(0);
2681   }
2682   ierr = DMPlexGetDepthLabel(dm, &label);CHKERRQ(ierr);
2683   if (!label) SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "No label named depth was found");CHKERRQ(ierr);
2684   ierr = DMLabelGetNumValues(label, &depth);CHKERRQ(ierr);
2685   ierr = DMLabelGetStratumBounds(label, depth-1-stratumValue, start, end);CHKERRQ(ierr);
2686   PetscFunctionReturn(0);
2687 }
2688 
2689 #undef __FUNCT__
2690 #define __FUNCT__ "DMPlexCreateSectionInitial"
2691 /* Set the number of dof on each point and separate by fields */
2692 PetscErrorCode DMPlexCreateSectionInitial(DM dm, PetscInt dim, PetscInt numFields,const PetscInt numComp[],const PetscInt numDof[], PetscSection *section)
2693 {
2694   PetscInt      *pMax;
2695   PetscInt       depth, pStart = 0, pEnd = 0;
2696   PetscInt       Nf, p, d, dep, f;
2697   PetscBool     *isFE;
2698   PetscErrorCode ierr;
2699 
2700   PetscFunctionBegin;
2701   ierr = PetscMalloc1(numFields, &isFE);CHKERRQ(ierr);
2702   ierr = DMGetNumFields(dm, &Nf);CHKERRQ(ierr);
2703   for (f = 0; f < numFields; ++f) {
2704     PetscObject  obj;
2705     PetscClassId id;
2706 
2707     isFE[f] = PETSC_FALSE;
2708     if (f >= Nf) continue;
2709     ierr = DMGetField(dm, f, &obj);CHKERRQ(ierr);
2710     ierr = PetscObjectGetClassId(obj, &id);CHKERRQ(ierr);
2711     if (id == PETSCFE_CLASSID)      {isFE[f] = PETSC_TRUE;}
2712     else if (id == PETSCFV_CLASSID) {isFE[f] = PETSC_FALSE;}
2713   }
2714   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)dm), section);CHKERRQ(ierr);
2715   if (numFields > 0) {
2716     ierr = PetscSectionSetNumFields(*section, numFields);CHKERRQ(ierr);
2717     if (numComp) {
2718       for (f = 0; f < numFields; ++f) {
2719         ierr = PetscSectionSetFieldComponents(*section, f, numComp[f]);CHKERRQ(ierr);
2720       }
2721     }
2722   }
2723   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
2724   ierr = PetscSectionSetChart(*section, pStart, pEnd);CHKERRQ(ierr);
2725   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
2726   ierr = PetscMalloc1(depth+1,&pMax);CHKERRQ(ierr);
2727   ierr = DMPlexGetHybridBounds(dm, depth >= 0 ? &pMax[depth] : NULL, depth>1 ? &pMax[depth-1] : NULL, depth>2 ? &pMax[1] : NULL, &pMax[0]);CHKERRQ(ierr);
2728   for (dep = 0; dep <= depth; ++dep) {
2729     d    = dim == depth ? dep : (!dep ? 0 : dim);
2730     ierr = DMPlexGetDepthStratum(dm, dep, &pStart, &pEnd);CHKERRQ(ierr);
2731     pMax[dep] = pMax[dep] < 0 ? pEnd : pMax[dep];
2732     for (p = pStart; p < pEnd; ++p) {
2733       PetscInt tot = 0;
2734 
2735       for (f = 0; f < numFields; ++f) {
2736         if (isFE[f] && p >= pMax[dep]) continue;
2737         ierr = PetscSectionSetFieldDof(*section, p, f, numDof[f*(dim+1)+d]);CHKERRQ(ierr);
2738         tot += numDof[f*(dim+1)+d];
2739       }
2740       ierr = PetscSectionSetDof(*section, p, tot);CHKERRQ(ierr);
2741     }
2742   }
2743   ierr = PetscFree(pMax);CHKERRQ(ierr);
2744   ierr = PetscFree(isFE);CHKERRQ(ierr);
2745   PetscFunctionReturn(0);
2746 }
2747 
2748 #undef __FUNCT__
2749 #define __FUNCT__ "DMPlexCreateSectionBCDof"
2750 /* Set the number of dof on each point and separate by fields
2751    If bcComps is NULL or the IS is NULL, constrain every dof on the point
2752 */
2753 PetscErrorCode DMPlexCreateSectionBCDof(DM dm, PetscInt numBC, const PetscInt bcField[], const IS bcComps[], const IS bcPoints[], PetscSection section)
2754 {
2755   PetscInt       numFields;
2756   PetscInt       bc;
2757   PetscSection   aSec;
2758   PetscErrorCode ierr;
2759 
2760   PetscFunctionBegin;
2761   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
2762   for (bc = 0; bc < numBC; ++bc) {
2763     PetscInt        field = 0;
2764     const PetscInt *comp;
2765     const PetscInt *idx;
2766     PetscInt        Nc = -1, n, i;
2767 
2768     if (numFields) field = bcField[bc];
2769     if (bcComps && bcComps[bc]) {ierr = ISGetLocalSize(bcComps[bc], &Nc);CHKERRQ(ierr);}
2770     if (bcComps && bcComps[bc]) {ierr = ISGetIndices(bcComps[bc], &comp);CHKERRQ(ierr);}
2771     ierr = ISGetLocalSize(bcPoints[bc], &n);CHKERRQ(ierr);
2772     ierr = ISGetIndices(bcPoints[bc], &idx);CHKERRQ(ierr);
2773     for (i = 0; i < n; ++i) {
2774       const PetscInt p = idx[i];
2775       PetscInt       numConst;
2776 
2777       if (numFields) {
2778         ierr = PetscSectionGetFieldDof(section, p, field, &numConst);CHKERRQ(ierr);
2779       } else {
2780         ierr = PetscSectionGetDof(section, p, &numConst);CHKERRQ(ierr);
2781       }
2782       /* If Nc < 0, constrain every dof on the point */
2783       if (Nc > 0) numConst = PetscMin(numConst, Nc);
2784       if (numFields) {ierr = PetscSectionAddFieldConstraintDof(section, p, field, numConst);CHKERRQ(ierr);}
2785       ierr = PetscSectionAddConstraintDof(section, p, numConst);CHKERRQ(ierr);
2786     }
2787     ierr = ISRestoreIndices(bcPoints[bc], &idx);CHKERRQ(ierr);
2788     if (bcComps && bcComps[bc]) {ierr = ISRestoreIndices(bcComps[bc], &comp);CHKERRQ(ierr);}
2789   }
2790   ierr = DMPlexGetAnchors(dm, &aSec, NULL);CHKERRQ(ierr);
2791   if (aSec) {
2792     PetscInt aStart, aEnd, a;
2793 
2794     ierr = PetscSectionGetChart(aSec, &aStart, &aEnd);CHKERRQ(ierr);
2795     for (a = aStart; a < aEnd; a++) {
2796       PetscInt dof, f;
2797 
2798       ierr = PetscSectionGetDof(aSec, a, &dof);CHKERRQ(ierr);
2799       if (dof) {
2800         /* if there are point-to-point constraints, then all dofs are constrained */
2801         ierr = PetscSectionGetDof(section, a, &dof);CHKERRQ(ierr);
2802         ierr = PetscSectionSetConstraintDof(section, a, dof);CHKERRQ(ierr);
2803         for (f = 0; f < numFields; f++) {
2804           ierr = PetscSectionGetFieldDof(section, a, f, &dof);CHKERRQ(ierr);
2805           ierr = PetscSectionSetFieldConstraintDof(section, a, f, dof);CHKERRQ(ierr);
2806         }
2807       }
2808     }
2809   }
2810   PetscFunctionReturn(0);
2811 }
2812 
2813 #undef __FUNCT__
2814 #define __FUNCT__ "DMPlexCreateSectionBCIndicesField"
2815 /* Set the constrained field indices on each point
2816    If bcComps is NULL or the IS is NULL, constrain every dof on the point
2817 */
2818 PetscErrorCode DMPlexCreateSectionBCIndicesField(DM dm, PetscInt numBC,const PetscInt bcField[], const IS bcComps[], const IS bcPoints[], PetscSection section)
2819 {
2820   PetscSection   aSec;
2821   PetscInt      *indices;
2822   PetscInt       numFields, maxDof, pStart, pEnd, p, bc, f, d;
2823   PetscErrorCode ierr;
2824 
2825   PetscFunctionBegin;
2826   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
2827   if (!numFields) PetscFunctionReturn(0);
2828   /* Initialize all field indices to -1 */
2829   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
2830   ierr = PetscSectionGetMaxDof(section, &maxDof);CHKERRQ(ierr);
2831   ierr = PetscMalloc1(maxDof, &indices);CHKERRQ(ierr);
2832   for (d = 0; d < maxDof; ++d) indices[d] = -1;
2833   for (p = pStart; p < pEnd; ++p) for (f = 0; f < numFields; ++f) {ierr = PetscSectionSetFieldConstraintIndices(section, p, f, indices);CHKERRQ(ierr);}
2834   /* Handle BC constraints */
2835   for (bc = 0; bc < numBC; ++bc) {
2836     const PetscInt  field = bcField[bc];
2837     const PetscInt *comp, *idx;
2838     PetscInt        Nc = -1, n, i;
2839 
2840     if (bcComps && bcComps[bc]) {ierr = ISGetLocalSize(bcComps[bc], &Nc);CHKERRQ(ierr);}
2841     if (bcComps && bcComps[bc]) {ierr = ISGetIndices(bcComps[bc], &comp);CHKERRQ(ierr);}
2842     ierr = ISGetLocalSize(bcPoints[bc], &n);CHKERRQ(ierr);
2843     ierr = ISGetIndices(bcPoints[bc], &idx);CHKERRQ(ierr);
2844     for (i = 0; i < n; ++i) {
2845       const PetscInt  p = idx[i];
2846       const PetscInt *find;
2847       PetscInt        fcdof, c;
2848 
2849       ierr = PetscSectionGetFieldConstraintDof(section, p, field, &fcdof);CHKERRQ(ierr);
2850       if (Nc < 0) {
2851         for (d = 0; d < fcdof; ++d) indices[d] = d;
2852       } else {
2853         ierr = PetscSectionGetFieldConstraintIndices(section, p, field, &find);CHKERRQ(ierr);
2854         for (d = 0; d < fcdof; ++d) {if (find[d] < 0) break; indices[d] = find[d];}
2855         for (c = 0; c < Nc; ++c) indices[d+c] = comp[c];
2856         ierr = PetscSortInt(d+Nc, indices);CHKERRQ(ierr);
2857         for (c = d+Nc; c < fcdof; ++c) indices[c] = -1;
2858       }
2859       ierr = PetscSectionSetFieldConstraintIndices(section, p, field, indices);CHKERRQ(ierr);
2860     }
2861     if (bcComps && bcComps[bc]) {ierr = ISRestoreIndices(bcComps[bc], &comp);CHKERRQ(ierr);}
2862     ierr = ISRestoreIndices(bcPoints[bc], &idx);CHKERRQ(ierr);
2863   }
2864   /* Handle anchors */
2865   ierr = DMPlexGetAnchors(dm, &aSec, NULL);CHKERRQ(ierr);
2866   if (aSec) {
2867     PetscInt aStart, aEnd, a;
2868 
2869     for (d = 0; d < maxDof; ++d) indices[d] = d;
2870     ierr = PetscSectionGetChart(aSec, &aStart, &aEnd);CHKERRQ(ierr);
2871     for (a = aStart; a < aEnd; a++) {
2872       PetscInt dof, fdof, f;
2873 
2874       ierr = PetscSectionGetDof(aSec, a, &dof);CHKERRQ(ierr);
2875       if (dof) {
2876         /* if there are point-to-point constraints, then all dofs are constrained */
2877         for (f = 0; f < numFields; f++) {
2878           ierr = PetscSectionGetFieldDof(section, a, f, &fdof);CHKERRQ(ierr);
2879           ierr = PetscSectionSetFieldConstraintIndices(section, a, f, indices);CHKERRQ(ierr);
2880         }
2881       }
2882     }
2883   }
2884   ierr = PetscFree(indices);CHKERRQ(ierr);
2885   PetscFunctionReturn(0);
2886 }
2887 
2888 #undef __FUNCT__
2889 #define __FUNCT__ "DMPlexCreateSectionBCIndices"
2890 /* Set the constrained indices on each point */
2891 PetscErrorCode DMPlexCreateSectionBCIndices(DM dm, PetscSection section)
2892 {
2893   PetscInt      *indices;
2894   PetscInt       numFields, maxDof, pStart, pEnd, p, f, d;
2895   PetscErrorCode ierr;
2896 
2897   PetscFunctionBegin;
2898   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
2899   ierr = PetscSectionGetMaxDof(section, &maxDof);CHKERRQ(ierr);
2900   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
2901   ierr = PetscMalloc1(maxDof, &indices);CHKERRQ(ierr);
2902   for (d = 0; d < maxDof; ++d) indices[d] = -1;
2903   for (p = pStart; p < pEnd; ++p) {
2904     PetscInt cdof, d;
2905 
2906     ierr = PetscSectionGetConstraintDof(section, p, &cdof);CHKERRQ(ierr);
2907     if (cdof) {
2908       if (numFields) {
2909         PetscInt numConst = 0, foff = 0;
2910 
2911         for (f = 0; f < numFields; ++f) {
2912           const PetscInt *find;
2913           PetscInt        fcdof, fdof;
2914 
2915           ierr = PetscSectionGetFieldDof(section, p, f, &fdof);CHKERRQ(ierr);
2916           ierr = PetscSectionGetFieldConstraintDof(section, p, f, &fcdof);CHKERRQ(ierr);
2917           /* Change constraint numbering from field component to local dof number */
2918           ierr = PetscSectionGetFieldConstraintIndices(section, p, f, &find);CHKERRQ(ierr);
2919           for (d = 0; d < fcdof; ++d) indices[numConst+d] = find[d] + foff;
2920           numConst += fcdof;
2921           foff     += fdof;
2922         }
2923         if (cdof != numConst) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_LIB, "Total number of field constraints %D should be %D", numConst, cdof);
2924       } else {
2925         for (d = 0; d < cdof; ++d) indices[d] = d;
2926       }
2927       ierr = PetscSectionSetConstraintIndices(section, p, indices);CHKERRQ(ierr);
2928     }
2929   }
2930   ierr = PetscFree(indices);CHKERRQ(ierr);
2931   PetscFunctionReturn(0);
2932 }
2933 
2934 #undef __FUNCT__
2935 #define __FUNCT__ "DMPlexCreateSection"
2936 /*@C
2937   DMPlexCreateSection - Create a PetscSection based upon the dof layout specification provided.
2938 
2939   Not Collective
2940 
2941   Input Parameters:
2942 + dm        - The DMPlex object
2943 . dim       - The spatial dimension of the problem
2944 . numFields - The number of fields in the problem
2945 . numComp   - An array of size numFields that holds the number of components for each field
2946 . numDof    - An array of size numFields*(dim+1) which holds the number of dof for each field on a mesh piece of dimension d
2947 . numBC     - The number of boundary conditions
2948 . bcField   - An array of size numBC giving the field number for each boundry condition
2949 . bcComps   - [Optional] An array of size numBC giving an IS holding the field components to which each boundary condition applies
2950 . bcPoints  - An array of size numBC giving an IS holding the Plex points to which each boundary condition applies
2951 - perm      - Optional permutation of the chart, or NULL
2952 
2953   Output Parameter:
2954 . section - The PetscSection object
2955 
2956   Notes: numDof[f*(dim+1)+d] gives the number of dof for field f on sieve points of dimension d. For instance, numDof[1] is the
2957   number of dof for field 0 on each edge.
2958 
2959   The chart permutation is the same one set using PetscSectionSetPermutation()
2960 
2961   Level: developer
2962 
2963   Fortran Notes:
2964   A Fortran 90 version is available as DMPlexCreateSectionF90()
2965 
2966 .keywords: mesh, elements
2967 .seealso: DMPlexCreate(), PetscSectionCreate(), PetscSectionSetPermutation()
2968 @*/
2969 PetscErrorCode DMPlexCreateSection(DM dm, PetscInt dim, PetscInt numFields,const PetscInt numComp[],const PetscInt numDof[], PetscInt numBC,const PetscInt bcField[], const IS bcComps[], const IS bcPoints[], IS perm, PetscSection *section)
2970 {
2971   PetscSection   aSec;
2972   PetscErrorCode ierr;
2973 
2974   PetscFunctionBegin;
2975   ierr = DMPlexCreateSectionInitial(dm, dim, numFields, numComp, numDof, section);CHKERRQ(ierr);
2976   ierr = DMPlexCreateSectionBCDof(dm, numBC, bcField, bcComps, bcPoints, *section);CHKERRQ(ierr);
2977   if (perm) {ierr = PetscSectionSetPermutation(*section, perm);CHKERRQ(ierr);}
2978   ierr = PetscSectionSetUp(*section);CHKERRQ(ierr);
2979   ierr = DMPlexGetAnchors(dm,&aSec,NULL);CHKERRQ(ierr);
2980   if (numBC || aSec) {
2981     ierr = DMPlexCreateSectionBCIndicesField(dm, numBC, bcField, bcComps, bcPoints, *section);CHKERRQ(ierr);
2982     ierr = DMPlexCreateSectionBCIndices(dm, *section);CHKERRQ(ierr);
2983   }
2984   ierr = PetscSectionViewFromOptions(*section,NULL,"-section_view");CHKERRQ(ierr);
2985   PetscFunctionReturn(0);
2986 }
2987 
2988 #undef __FUNCT__
2989 #define __FUNCT__ "DMCreateCoordinateDM_Plex"
2990 PetscErrorCode DMCreateCoordinateDM_Plex(DM dm, DM *cdm)
2991 {
2992   PetscSection   section, s;
2993   Mat            m;
2994   PetscInt       maxHeight;
2995   PetscErrorCode ierr;
2996 
2997   PetscFunctionBegin;
2998   ierr = DMClone(dm, cdm);CHKERRQ(ierr);
2999   ierr = DMPlexGetMaxProjectionHeight(dm, &maxHeight);CHKERRQ(ierr);
3000   ierr = DMPlexSetMaxProjectionHeight(*cdm, maxHeight);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 = 0; 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   for (f = 0; f <= numFields; f++) {
4502     offsets[f] = newOffsets[f];
4503   }
4504   PetscFunctionReturn(0);
4505 }
4506 
4507 #undef __FUNCT__
4508 #define __FUNCT__ "DMPlexGetClosureIndices"
4509 PetscErrorCode DMPlexGetClosureIndices(DM dm, PetscSection section, PetscSection globalSection, PetscInt point, PetscInt *numIndices, PetscInt **indices, PetscInt *outOffsets)
4510 {
4511   PetscSection    clSection;
4512   IS              clPoints;
4513   const PetscInt *clp;
4514   PetscInt       *points = NULL, *pointsNew;
4515   PetscInt        numPoints, numPointsNew;
4516   PetscInt        offsets[32];
4517   PetscInt        Nf, Nind, NindNew, off, globalOff, f, p;
4518   PetscErrorCode  ierr;
4519 
4520   PetscFunctionBegin;
4521   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4522   PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2);
4523   PetscValidHeaderSpecific(globalSection, PETSC_SECTION_CLASSID, 3);
4524   if (numIndices) PetscValidPointer(numIndices, 4);
4525   PetscValidPointer(indices, 5);
4526   ierr = PetscSectionGetNumFields(section, &Nf);CHKERRQ(ierr);
4527   if (Nf > 31) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", Nf);
4528   ierr = PetscMemzero(offsets, 32 * sizeof(PetscInt));CHKERRQ(ierr);
4529   /* Get points in closure */
4530   ierr = PetscSectionGetClosureIndex(section, (PetscObject) dm, &clSection, &clPoints);CHKERRQ(ierr);
4531   if (!clPoints) {
4532     PetscInt pStart, pEnd, q;
4533 
4534     ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
4535     /* Compress out points not in the section */
4536     ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
4537     for (p = 0, q = 0; p < numPoints*2; p += 2) {
4538       if ((points[p] >= pStart) && (points[p] < pEnd)) {
4539         points[q*2]   = points[p];
4540         points[q*2+1] = points[p+1];
4541         ++q;
4542       }
4543     }
4544     numPoints = q;
4545   } else {
4546     PetscInt dof, off;
4547 
4548     ierr = PetscSectionGetDof(clSection, point, &dof);CHKERRQ(ierr);
4549     numPoints = dof/2;
4550     ierr = PetscSectionGetOffset(clSection, point, &off);CHKERRQ(ierr);
4551     ierr = ISGetIndices(clPoints, &clp);CHKERRQ(ierr);
4552     points = (PetscInt *) &clp[off];
4553   }
4554   /* Get number of indices and indices per field */
4555   for (p = 0, Nind = 0; p < numPoints*2; p += 2) {
4556     PetscInt dof, fdof;
4557 
4558     ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
4559     for (f = 0; f < Nf; ++f) {
4560       ierr = PetscSectionGetFieldDof(section, points[p], f, &fdof);CHKERRQ(ierr);
4561       offsets[f+1] += fdof;
4562     }
4563     Nind += dof;
4564   }
4565   for (f = 1; f < Nf; ++f) offsets[f+1] += offsets[f];
4566   if (Nf && offsets[Nf] != Nind) SETERRQ2(PetscObjectComm((PetscObject) dm), PETSC_ERR_PLIB, "Invalid size for closure %d should be %d", offsets[Nf], Nind);
4567   /* Correct for hanging node constraints */
4568   {
4569     ierr = DMPlexAnchorsModifyMat(dm, section, numPoints, Nind, points, NULL, &numPointsNew, &NindNew, &pointsNew, NULL, offsets, PETSC_TRUE);CHKERRQ(ierr);
4570     if (numPointsNew) {
4571       if (!clPoints) {ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);}
4572       else           {ierr = ISRestoreIndices(clPoints, &clp);CHKERRQ(ierr);}
4573       numPoints = numPointsNew;
4574       Nind      = NindNew;
4575       points    = pointsNew;
4576     }
4577   }
4578   /* Calculate indices */
4579   ierr = DMGetWorkArray(dm, Nind, PETSC_INT, indices);CHKERRQ(ierr);
4580   if (Nf) {
4581     if (outOffsets) {
4582       PetscInt f;
4583 
4584       for (f = 0; f <= Nf; f++) {
4585         outOffsets[f] = offsets[f];
4586       }
4587     }
4588     for (p = 0; p < numPoints*2; p += 2) {
4589       PetscInt o = points[p+1];
4590       ierr = PetscSectionGetOffset(globalSection, points[p], &globalOff);CHKERRQ(ierr);
4591       DMPlexGetIndicesPointFields_Internal(section, points[p], globalOff < 0 ? -(globalOff+1) : globalOff, offsets, PETSC_FALSE, o, *indices);
4592     }
4593   } else {
4594     for (p = 0, off = 0; p < numPoints*2; p += 2) {
4595       PetscInt o = points[p+1];
4596       ierr = PetscSectionGetOffset(globalSection, points[p], &globalOff);CHKERRQ(ierr);
4597       DMPlexGetIndicesPoint_Internal(section, points[p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, o, *indices);
4598     }
4599   }
4600   /* Cleanup points */
4601   if (numPointsNew) {
4602     ierr = DMRestoreWorkArray(dm, 2*numPointsNew, PETSC_INT, &pointsNew);CHKERRQ(ierr);
4603   } else {
4604     if (!clPoints) {ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);}
4605     else           {ierr = ISRestoreIndices(clPoints, &clp);CHKERRQ(ierr);}
4606   }
4607   if (numIndices) *numIndices = Nind;
4608   PetscFunctionReturn(0);
4609 }
4610 
4611 #undef __FUNCT__
4612 #define __FUNCT__ "DMPlexRestoreClosureIndices"
4613 PetscErrorCode DMPlexRestoreClosureIndices(DM dm, PetscSection section, PetscSection globalSection, PetscInt point, PetscInt *numIndices, PetscInt **indices,PetscInt *outOffsets)
4614 {
4615   PetscErrorCode ierr;
4616 
4617   PetscFunctionBegin;
4618   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4619   PetscValidPointer(indices, 5);
4620   ierr = DMRestoreWorkArray(dm, 0, PETSC_INT, indices);CHKERRQ(ierr);
4621   PetscFunctionReturn(0);
4622 }
4623 
4624 #undef __FUNCT__
4625 #define __FUNCT__ "DMPlexMatSetClosure"
4626 /*@C
4627   DMPlexMatSetClosure - Set an array of the values on the closure of 'point'
4628 
4629   Not collective
4630 
4631   Input Parameters:
4632 + dm - The DM
4633 . section - The section describing the layout in v, or NULL to use the default section
4634 . globalSection - The section describing the layout in v, or NULL to use the default global section
4635 . A - The matrix
4636 . point - The sieve point in the DM
4637 . values - The array of values
4638 - mode - The insert mode, where INSERT_ALL_VALUES and ADD_ALL_VALUES also overwrite boundary conditions
4639 
4640   Fortran Notes:
4641   This routine is only available in Fortran 90, and you must include petsc.h90 in your code.
4642 
4643   Level: intermediate
4644 
4645 .seealso DMPlexVecGetClosure(), DMPlexVecSetClosure()
4646 @*/
4647 PetscErrorCode DMPlexMatSetClosure(DM dm, PetscSection section, PetscSection globalSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode)
4648 {
4649   DM_Plex        *mesh   = (DM_Plex*) dm->data;
4650   PetscSection    clSection;
4651   IS              clPoints;
4652   PetscInt       *points = NULL, *newPoints;
4653   const PetscInt *clp;
4654   PetscInt       *indices;
4655   PetscInt        offsets[32];
4656   PetscInt        numFields, numPoints, newNumPoints, numIndices, newNumIndices, dof, off, globalOff, pStart, pEnd, p, q, f;
4657   PetscScalar    *newValues;
4658   PetscErrorCode  ierr;
4659 
4660   PetscFunctionBegin;
4661   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4662   if (!section) {ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);}
4663   PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2);
4664   if (!globalSection) {ierr = DMGetDefaultGlobalSection(dm, &globalSection);CHKERRQ(ierr);}
4665   PetscValidHeaderSpecific(globalSection, PETSC_SECTION_CLASSID, 3);
4666   PetscValidHeaderSpecific(A, MAT_CLASSID, 4);
4667   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
4668   if (numFields > 31) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
4669   ierr = PetscMemzero(offsets, 32 * sizeof(PetscInt));CHKERRQ(ierr);
4670   ierr = PetscSectionGetClosureIndex(section, (PetscObject) dm, &clSection, &clPoints);CHKERRQ(ierr);
4671   if (!clPoints) {
4672     ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
4673     /* Compress out points not in the section */
4674     ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
4675     for (p = 0, q = 0; p < numPoints*2; p += 2) {
4676       if ((points[p] >= pStart) && (points[p] < pEnd)) {
4677         points[q*2]   = points[p];
4678         points[q*2+1] = points[p+1];
4679         ++q;
4680       }
4681     }
4682     numPoints = q;
4683   } else {
4684     PetscInt dof, off;
4685 
4686     ierr = PetscSectionGetDof(clSection, point, &dof);CHKERRQ(ierr);
4687     numPoints = dof/2;
4688     ierr = PetscSectionGetOffset(clSection, point, &off);CHKERRQ(ierr);
4689     ierr = ISGetIndices(clPoints, &clp);CHKERRQ(ierr);
4690     points = (PetscInt *) &clp[off];
4691   }
4692   for (p = 0, numIndices = 0; p < numPoints*2; p += 2) {
4693     PetscInt fdof;
4694 
4695     ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
4696     for (f = 0; f < numFields; ++f) {
4697       ierr          = PetscSectionGetFieldDof(section, points[p], f, &fdof);CHKERRQ(ierr);
4698       offsets[f+1] += fdof;
4699     }
4700     numIndices += dof;
4701   }
4702   for (f = 1; f < numFields; ++f) offsets[f+1] += offsets[f];
4703 
4704   if (numFields && offsets[numFields] != numIndices) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid size for closure %d should be %d", offsets[numFields], numIndices);
4705   ierr = DMPlexAnchorsModifyMat(dm,section,numPoints,numIndices,points,values,&newNumPoints,&newNumIndices,&newPoints,&newValues,offsets,PETSC_TRUE);CHKERRQ(ierr);
4706   if (newNumPoints) {
4707     if (!clPoints) {
4708       ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
4709     } else {
4710       ierr = ISRestoreIndices(clPoints, &clp);CHKERRQ(ierr);
4711     }
4712     numPoints  = newNumPoints;
4713     numIndices = newNumIndices;
4714     points     = newPoints;
4715     values     = newValues;
4716   }
4717   ierr = DMGetWorkArray(dm, numIndices, PETSC_INT, &indices);CHKERRQ(ierr);
4718   if (numFields) {
4719     for (p = 0; p < numPoints*2; p += 2) {
4720       PetscInt o = points[p+1];
4721       ierr = PetscSectionGetOffset(globalSection, points[p], &globalOff);CHKERRQ(ierr);
4722       DMPlexGetIndicesPointFields_Internal(section, points[p], globalOff < 0 ? -(globalOff+1) : globalOff, offsets, PETSC_FALSE, o, indices);
4723     }
4724   } else {
4725     for (p = 0, off = 0; p < numPoints*2; p += 2) {
4726       PetscInt o = points[p+1];
4727       ierr = PetscSectionGetOffset(globalSection, points[p], &globalOff);CHKERRQ(ierr);
4728       DMPlexGetIndicesPoint_Internal(section, points[p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, o, indices);
4729     }
4730   }
4731   if (mesh->printSetValues) {ierr = DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndices, indices, 0, NULL, values);CHKERRQ(ierr);}
4732   ierr = MatSetValues(A, numIndices, indices, numIndices, indices, values, mode);
4733   if (mesh->printFEM > 1) {
4734     PetscInt i;
4735     ierr = PetscPrintf(PETSC_COMM_SELF, "  Indices:");CHKERRQ(ierr);
4736     for (i = 0; i < numIndices; ++i) {ierr = PetscPrintf(PETSC_COMM_SELF, " %d", indices[i]);CHKERRQ(ierr);}
4737     ierr = PetscPrintf(PETSC_COMM_SELF, "\n");CHKERRQ(ierr);
4738   }
4739   if (ierr) {
4740     PetscMPIInt    rank;
4741     PetscErrorCode ierr2;
4742 
4743     ierr2 = MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank);CHKERRQ(ierr2);
4744     ierr2 = (*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank);CHKERRQ(ierr2);
4745     ierr2 = DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndices, indices, 0, NULL, values);CHKERRQ(ierr2);
4746     ierr2 = DMRestoreWorkArray(dm, numIndices, PETSC_INT, &indices);CHKERRQ(ierr2);
4747     CHKERRQ(ierr);
4748   }
4749   if (newNumPoints) {
4750     ierr = DMRestoreWorkArray(dm,newNumIndices*newNumIndices,PETSC_SCALAR,&newValues);CHKERRQ(ierr);
4751     ierr = DMRestoreWorkArray(dm,2*newNumPoints,PETSC_INT,&newPoints);CHKERRQ(ierr);
4752   }
4753   else {
4754     if (!clPoints) {
4755       ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
4756     } else {
4757       ierr = ISRestoreIndices(clPoints, &clp);CHKERRQ(ierr);
4758     }
4759   }
4760   ierr = DMRestoreWorkArray(dm, numIndices, PETSC_INT, &indices);CHKERRQ(ierr);
4761   PetscFunctionReturn(0);
4762 }
4763 
4764 #undef __FUNCT__
4765 #define __FUNCT__ "DMPlexMatSetClosureRefined"
4766 PetscErrorCode DMPlexMatSetClosureRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode)
4767 {
4768   DM_Plex        *mesh   = (DM_Plex*) dmf->data;
4769   PetscInt       *fpoints = NULL, *ftotpoints = NULL;
4770   PetscInt       *cpoints = NULL;
4771   PetscInt       *findices, *cindices;
4772   PetscInt        foffsets[32], coffsets[32];
4773   CellRefiner     cellRefiner;
4774   PetscInt        numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f;
4775   PetscErrorCode  ierr;
4776 
4777   PetscFunctionBegin;
4778   PetscValidHeaderSpecific(dmf, DM_CLASSID, 1);
4779   PetscValidHeaderSpecific(dmc, DM_CLASSID, 4);
4780   if (!fsection) {ierr = DMGetDefaultSection(dmf, &fsection);CHKERRQ(ierr);}
4781   PetscValidHeaderSpecific(fsection, PETSC_SECTION_CLASSID, 2);
4782   if (!csection) {ierr = DMGetDefaultSection(dmc, &csection);CHKERRQ(ierr);}
4783   PetscValidHeaderSpecific(csection, PETSC_SECTION_CLASSID, 5);
4784   if (!globalFSection) {ierr = DMGetDefaultGlobalSection(dmf, &globalFSection);CHKERRQ(ierr);}
4785   PetscValidHeaderSpecific(globalFSection, PETSC_SECTION_CLASSID, 3);
4786   if (!globalCSection) {ierr = DMGetDefaultGlobalSection(dmc, &globalCSection);CHKERRQ(ierr);}
4787   PetscValidHeaderSpecific(globalCSection, PETSC_SECTION_CLASSID, 6);
4788   PetscValidHeaderSpecific(A, MAT_CLASSID, 7);
4789   ierr = PetscSectionGetNumFields(fsection, &numFields);CHKERRQ(ierr);
4790   if (numFields > 31) SETERRQ1(PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
4791   ierr = PetscMemzero(foffsets, 32 * sizeof(PetscInt));CHKERRQ(ierr);
4792   ierr = PetscMemzero(coffsets, 32 * sizeof(PetscInt));CHKERRQ(ierr);
4793   /* Column indices */
4794   ierr = DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints);CHKERRQ(ierr);
4795   maxFPoints = numCPoints;
4796   /* Compress out points not in the section */
4797   /*   TODO: Squeeze out points with 0 dof as well */
4798   ierr = PetscSectionGetChart(csection, &pStart, &pEnd);CHKERRQ(ierr);
4799   for (p = 0, q = 0; p < numCPoints*2; p += 2) {
4800     if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) {
4801       cpoints[q*2]   = cpoints[p];
4802       cpoints[q*2+1] = cpoints[p+1];
4803       ++q;
4804     }
4805   }
4806   numCPoints = q;
4807   for (p = 0, numCIndices = 0; p < numCPoints*2; p += 2) {
4808     PetscInt fdof;
4809 
4810     ierr = PetscSectionGetDof(csection, cpoints[p], &dof);CHKERRQ(ierr);
4811     if (!dof) continue;
4812     for (f = 0; f < numFields; ++f) {
4813       ierr           = PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof);CHKERRQ(ierr);
4814       coffsets[f+1] += fdof;
4815     }
4816     numCIndices += dof;
4817   }
4818   for (f = 1; f < numFields; ++f) coffsets[f+1] += coffsets[f];
4819   /* Row indices */
4820   ierr = DMPlexGetCellRefiner_Internal(dmc, &cellRefiner);CHKERRQ(ierr);
4821   ierr = CellRefinerGetAffineTransforms_Internal(cellRefiner, &numSubcells, NULL, NULL, NULL);CHKERRQ(ierr);
4822   ierr = DMGetWorkArray(dmf, maxFPoints*2*numSubcells, PETSC_INT, &ftotpoints);CHKERRQ(ierr);
4823   for (r = 0, q = 0; r < numSubcells; ++r) {
4824     /* TODO Map from coarse to fine cells */
4825     ierr = DMPlexGetTransitiveClosure(dmf, point*numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints);CHKERRQ(ierr);
4826     /* Compress out points not in the section */
4827     ierr = PetscSectionGetChart(fsection, &pStart, &pEnd);CHKERRQ(ierr);
4828     for (p = 0; p < numFPoints*2; p += 2) {
4829       if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) {
4830         ierr = PetscSectionGetDof(fsection, fpoints[p], &dof);CHKERRQ(ierr);
4831         if (!dof) continue;
4832         for (s = 0; s < q; ++s) if (fpoints[p] == ftotpoints[s*2]) break;
4833         if (s < q) continue;
4834         ftotpoints[q*2]   = fpoints[p];
4835         ftotpoints[q*2+1] = fpoints[p+1];
4836         ++q;
4837       }
4838     }
4839     ierr = DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints);CHKERRQ(ierr);
4840   }
4841   numFPoints = q;
4842   for (p = 0, numFIndices = 0; p < numFPoints*2; p += 2) {
4843     PetscInt fdof;
4844 
4845     ierr = PetscSectionGetDof(fsection, ftotpoints[p], &dof);CHKERRQ(ierr);
4846     if (!dof) continue;
4847     for (f = 0; f < numFields; ++f) {
4848       ierr           = PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof);CHKERRQ(ierr);
4849       foffsets[f+1] += fdof;
4850     }
4851     numFIndices += dof;
4852   }
4853   for (f = 1; f < numFields; ++f) foffsets[f+1] += foffsets[f];
4854 
4855   if (numFields && foffsets[numFields] != numFIndices) SETERRQ2(PetscObjectComm((PetscObject)dmf), PETSC_ERR_PLIB, "Invalid size for closure %d should be %d", foffsets[numFields], numFIndices);
4856   if (numFields && coffsets[numFields] != numCIndices) SETERRQ2(PetscObjectComm((PetscObject)dmc), PETSC_ERR_PLIB, "Invalid size for closure %d should be %d", coffsets[numFields], numCIndices);
4857   ierr = DMGetWorkArray(dmf, numFIndices, PETSC_INT, &findices);CHKERRQ(ierr);
4858   ierr = DMGetWorkArray(dmc, numCIndices, PETSC_INT, &cindices);CHKERRQ(ierr);
4859   if (numFields) {
4860     for (p = 0; p < numFPoints*2; p += 2) {
4861       PetscInt o = ftotpoints[p+1];
4862       ierr = PetscSectionGetOffset(globalFSection, ftotpoints[p], &globalOff);CHKERRQ(ierr);
4863       DMPlexGetIndicesPointFields_Internal(fsection, ftotpoints[p], globalOff < 0 ? -(globalOff+1) : globalOff, foffsets, PETSC_FALSE, o, findices);
4864     }
4865     for (p = 0; p < numCPoints*2; p += 2) {
4866       PetscInt o = cpoints[p+1];
4867       ierr = PetscSectionGetOffset(globalCSection, cpoints[p], &globalOff);CHKERRQ(ierr);
4868       DMPlexGetIndicesPointFields_Internal(csection, cpoints[p], globalOff < 0 ? -(globalOff+1) : globalOff, coffsets, PETSC_FALSE, o, cindices);
4869     }
4870   } else {
4871     for (p = 0, off = 0; p < numFPoints*2; p += 2) {
4872       PetscInt o = ftotpoints[p+1];
4873       ierr = PetscSectionGetOffset(globalFSection, ftotpoints[p], &globalOff);CHKERRQ(ierr);
4874       DMPlexGetIndicesPoint_Internal(fsection, ftotpoints[p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, o, findices);
4875     }
4876     for (p = 0, off = 0; p < numCPoints*2; p += 2) {
4877       PetscInt o = cpoints[p+1];
4878       ierr = PetscSectionGetOffset(globalCSection, cpoints[p], &globalOff);CHKERRQ(ierr);
4879       DMPlexGetIndicesPoint_Internal(csection, cpoints[p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, o, cindices);
4880     }
4881   }
4882   if (mesh->printSetValues) {ierr = DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numFIndices, findices, numCIndices, cindices, values);CHKERRQ(ierr);}
4883   ierr = MatSetValues(A, numFIndices, findices, numCIndices, cindices, values, mode);
4884   if (ierr) {
4885     PetscMPIInt    rank;
4886     PetscErrorCode ierr2;
4887 
4888     ierr2 = MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank);CHKERRQ(ierr2);
4889     ierr2 = (*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank);CHKERRQ(ierr2);
4890     ierr2 = DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numFIndices, findices, numCIndices, cindices, values);CHKERRQ(ierr2);
4891     ierr2 = DMRestoreWorkArray(dmf, numFIndices, PETSC_INT, &findices);CHKERRQ(ierr2);
4892     ierr2 = DMRestoreWorkArray(dmc, numCIndices, PETSC_INT, &cindices);CHKERRQ(ierr2);
4893     CHKERRQ(ierr);
4894   }
4895   ierr = DMRestoreWorkArray(dmf, numCPoints*2*4, PETSC_INT, &ftotpoints);CHKERRQ(ierr);
4896   ierr = DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints);CHKERRQ(ierr);
4897   ierr = DMRestoreWorkArray(dmf, numFIndices, PETSC_INT, &findices);CHKERRQ(ierr);
4898   ierr = DMRestoreWorkArray(dmc, numCIndices, PETSC_INT, &cindices);CHKERRQ(ierr);
4899   PetscFunctionReturn(0);
4900 }
4901 
4902 #undef __FUNCT__
4903 #define __FUNCT__ "DMPlexMatGetClosureIndicesRefined"
4904 PetscErrorCode DMPlexMatGetClosureIndicesRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, PetscInt point, PetscInt cindices[], PetscInt findices[])
4905 {
4906   PetscInt      *fpoints = NULL, *ftotpoints = NULL;
4907   PetscInt      *cpoints = NULL;
4908   PetscInt       foffsets[32], coffsets[32];
4909   CellRefiner    cellRefiner;
4910   PetscInt       numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f;
4911   PetscErrorCode ierr;
4912 
4913   PetscFunctionBegin;
4914   PetscValidHeaderSpecific(dmf, DM_CLASSID, 1);
4915   PetscValidHeaderSpecific(dmc, DM_CLASSID, 4);
4916   if (!fsection) {ierr = DMGetDefaultSection(dmf, &fsection);CHKERRQ(ierr);}
4917   PetscValidHeaderSpecific(fsection, PETSC_SECTION_CLASSID, 2);
4918   if (!csection) {ierr = DMGetDefaultSection(dmc, &csection);CHKERRQ(ierr);}
4919   PetscValidHeaderSpecific(csection, PETSC_SECTION_CLASSID, 5);
4920   if (!globalFSection) {ierr = DMGetDefaultGlobalSection(dmf, &globalFSection);CHKERRQ(ierr);}
4921   PetscValidHeaderSpecific(globalFSection, PETSC_SECTION_CLASSID, 3);
4922   if (!globalCSection) {ierr = DMGetDefaultGlobalSection(dmc, &globalCSection);CHKERRQ(ierr);}
4923   PetscValidHeaderSpecific(globalCSection, PETSC_SECTION_CLASSID, 6);
4924   ierr = PetscSectionGetNumFields(fsection, &numFields);CHKERRQ(ierr);
4925   if (numFields > 31) SETERRQ1(PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
4926   ierr = PetscMemzero(foffsets, 32 * sizeof(PetscInt));CHKERRQ(ierr);
4927   ierr = PetscMemzero(coffsets, 32 * sizeof(PetscInt));CHKERRQ(ierr);
4928   /* Column indices */
4929   ierr = DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints);CHKERRQ(ierr);
4930   maxFPoints = numCPoints;
4931   /* Compress out points not in the section */
4932   /*   TODO: Squeeze out points with 0 dof as well */
4933   ierr = PetscSectionGetChart(csection, &pStart, &pEnd);CHKERRQ(ierr);
4934   for (p = 0, q = 0; p < numCPoints*2; p += 2) {
4935     if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) {
4936       cpoints[q*2]   = cpoints[p];
4937       cpoints[q*2+1] = cpoints[p+1];
4938       ++q;
4939     }
4940   }
4941   numCPoints = q;
4942   for (p = 0, numCIndices = 0; p < numCPoints*2; p += 2) {
4943     PetscInt fdof;
4944 
4945     ierr = PetscSectionGetDof(csection, cpoints[p], &dof);CHKERRQ(ierr);
4946     if (!dof) continue;
4947     for (f = 0; f < numFields; ++f) {
4948       ierr           = PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof);CHKERRQ(ierr);
4949       coffsets[f+1] += fdof;
4950     }
4951     numCIndices += dof;
4952   }
4953   for (f = 1; f < numFields; ++f) coffsets[f+1] += coffsets[f];
4954   /* Row indices */
4955   ierr = DMPlexGetCellRefiner_Internal(dmc, &cellRefiner);CHKERRQ(ierr);
4956   ierr = CellRefinerGetAffineTransforms_Internal(cellRefiner, &numSubcells, NULL, NULL, NULL);CHKERRQ(ierr);
4957   ierr = DMGetWorkArray(dmf, maxFPoints*2*numSubcells, PETSC_INT, &ftotpoints);CHKERRQ(ierr);
4958   for (r = 0, q = 0; r < numSubcells; ++r) {
4959     /* TODO Map from coarse to fine cells */
4960     ierr = DMPlexGetTransitiveClosure(dmf, point*numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints);CHKERRQ(ierr);
4961     /* Compress out points not in the section */
4962     ierr = PetscSectionGetChart(fsection, &pStart, &pEnd);CHKERRQ(ierr);
4963     for (p = 0; p < numFPoints*2; p += 2) {
4964       if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) {
4965         ierr = PetscSectionGetDof(fsection, fpoints[p], &dof);CHKERRQ(ierr);
4966         if (!dof) continue;
4967         for (s = 0; s < q; ++s) if (fpoints[p] == ftotpoints[s*2]) break;
4968         if (s < q) continue;
4969         ftotpoints[q*2]   = fpoints[p];
4970         ftotpoints[q*2+1] = fpoints[p+1];
4971         ++q;
4972       }
4973     }
4974     ierr = DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints);CHKERRQ(ierr);
4975   }
4976   numFPoints = q;
4977   for (p = 0, numFIndices = 0; p < numFPoints*2; p += 2) {
4978     PetscInt fdof;
4979 
4980     ierr = PetscSectionGetDof(fsection, ftotpoints[p], &dof);CHKERRQ(ierr);
4981     if (!dof) continue;
4982     for (f = 0; f < numFields; ++f) {
4983       ierr           = PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof);CHKERRQ(ierr);
4984       foffsets[f+1] += fdof;
4985     }
4986     numFIndices += dof;
4987   }
4988   for (f = 1; f < numFields; ++f) foffsets[f+1] += foffsets[f];
4989 
4990   if (numFields && foffsets[numFields] != numFIndices) SETERRQ2(PetscObjectComm((PetscObject)dmf), PETSC_ERR_PLIB, "Invalid size for closure %d should be %d", foffsets[numFields], numFIndices);
4991   if (numFields && coffsets[numFields] != numCIndices) SETERRQ2(PetscObjectComm((PetscObject)dmc), PETSC_ERR_PLIB, "Invalid size for closure %d should be %d", coffsets[numFields], numCIndices);
4992   if (numFields) {
4993     for (p = 0; p < numFPoints*2; p += 2) {
4994       PetscInt o = ftotpoints[p+1];
4995       ierr = PetscSectionGetOffset(globalFSection, ftotpoints[p], &globalOff);CHKERRQ(ierr);
4996       DMPlexGetIndicesPointFields_Internal(fsection, ftotpoints[p], globalOff < 0 ? -(globalOff+1) : globalOff, foffsets, PETSC_FALSE, o, findices);
4997     }
4998     for (p = 0; p < numCPoints*2; p += 2) {
4999       PetscInt o = cpoints[p+1];
5000       ierr = PetscSectionGetOffset(globalCSection, cpoints[p], &globalOff);CHKERRQ(ierr);
5001       DMPlexGetIndicesPointFields_Internal(csection, cpoints[p], globalOff < 0 ? -(globalOff+1) : globalOff, coffsets, PETSC_FALSE, o, cindices);
5002     }
5003   } else {
5004     for (p = 0, off = 0; p < numFPoints*2; p += 2) {
5005       PetscInt o = ftotpoints[p+1];
5006       ierr = PetscSectionGetOffset(globalFSection, ftotpoints[p], &globalOff);CHKERRQ(ierr);
5007       DMPlexGetIndicesPoint_Internal(fsection, ftotpoints[p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, o, findices);
5008     }
5009     for (p = 0, off = 0; p < numCPoints*2; p += 2) {
5010       PetscInt o = cpoints[p+1];
5011       ierr = PetscSectionGetOffset(globalCSection, cpoints[p], &globalOff);CHKERRQ(ierr);
5012       DMPlexGetIndicesPoint_Internal(csection, cpoints[p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, o, cindices);
5013     }
5014   }
5015   ierr = DMRestoreWorkArray(dmf, numCPoints*2*4, PETSC_INT, &ftotpoints);CHKERRQ(ierr);
5016   ierr = DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints);CHKERRQ(ierr);
5017   PetscFunctionReturn(0);
5018 }
5019 
5020 #undef __FUNCT__
5021 #define __FUNCT__ "DMPlexGetHybridBounds"
5022 /*@
5023   DMPlexGetHybridBounds - Get the first mesh point of each dimension which is a hybrid
5024 
5025   Input Parameter:
5026 . dm - The DMPlex object
5027 
5028   Output Parameters:
5029 + cMax - The first hybrid cell
5030 . fMax - The first hybrid face
5031 . eMax - The first hybrid edge
5032 - vMax - The first hybrid vertex
5033 
5034   Level: developer
5035 
5036 .seealso DMPlexCreateHybridMesh(), DMPlexSetHybridBounds()
5037 @*/
5038 PetscErrorCode DMPlexGetHybridBounds(DM dm, PetscInt *cMax, PetscInt *fMax, PetscInt *eMax, PetscInt *vMax)
5039 {
5040   DM_Plex       *mesh = (DM_Plex*) dm->data;
5041   PetscInt       dim;
5042   PetscErrorCode ierr;
5043 
5044   PetscFunctionBegin;
5045   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5046   ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr);
5047   if (cMax) *cMax = mesh->hybridPointMax[dim];
5048   if (fMax) *fMax = mesh->hybridPointMax[dim-1];
5049   if (eMax) *eMax = mesh->hybridPointMax[1];
5050   if (vMax) *vMax = mesh->hybridPointMax[0];
5051   PetscFunctionReturn(0);
5052 }
5053 
5054 #undef __FUNCT__
5055 #define __FUNCT__ "DMPlexSetHybridBounds"
5056 /*@
5057   DMPlexSetHybridBounds - Set the first mesh point of each dimension which is a hybrid
5058 
5059   Input Parameters:
5060 . dm   - The DMPlex object
5061 . cMax - The first hybrid cell
5062 . fMax - The first hybrid face
5063 . eMax - The first hybrid edge
5064 - vMax - The first hybrid vertex
5065 
5066   Level: developer
5067 
5068 .seealso DMPlexCreateHybridMesh(), DMPlexGetHybridBounds()
5069 @*/
5070 PetscErrorCode DMPlexSetHybridBounds(DM dm, PetscInt cMax, PetscInt fMax, PetscInt eMax, PetscInt vMax)
5071 {
5072   DM_Plex       *mesh = (DM_Plex*) dm->data;
5073   PetscInt       dim;
5074   PetscErrorCode ierr;
5075 
5076   PetscFunctionBegin;
5077   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5078   ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr);
5079   if (cMax >= 0) mesh->hybridPointMax[dim]   = cMax;
5080   if (fMax >= 0) mesh->hybridPointMax[dim-1] = fMax;
5081   if (eMax >= 0) mesh->hybridPointMax[1]     = eMax;
5082   if (vMax >= 0) mesh->hybridPointMax[0]     = vMax;
5083   PetscFunctionReturn(0);
5084 }
5085 
5086 #undef __FUNCT__
5087 #define __FUNCT__ "DMPlexGetVTKCellHeight"
5088 PetscErrorCode DMPlexGetVTKCellHeight(DM dm, PetscInt *cellHeight)
5089 {
5090   DM_Plex *mesh = (DM_Plex*) dm->data;
5091 
5092   PetscFunctionBegin;
5093   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5094   PetscValidPointer(cellHeight, 2);
5095   *cellHeight = mesh->vtkCellHeight;
5096   PetscFunctionReturn(0);
5097 }
5098 
5099 #undef __FUNCT__
5100 #define __FUNCT__ "DMPlexSetVTKCellHeight"
5101 PetscErrorCode DMPlexSetVTKCellHeight(DM dm, PetscInt cellHeight)
5102 {
5103   DM_Plex *mesh = (DM_Plex*) dm->data;
5104 
5105   PetscFunctionBegin;
5106   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5107   mesh->vtkCellHeight = cellHeight;
5108   PetscFunctionReturn(0);
5109 }
5110 
5111 #undef __FUNCT__
5112 #define __FUNCT__ "DMPlexCreateNumbering_Private"
5113 /* We can easily have a form that takes an IS instead */
5114 static PetscErrorCode DMPlexCreateNumbering_Private(DM dm, PetscInt pStart, PetscInt pEnd, PetscInt shift, PetscInt *globalSize, PetscSF sf, IS *numbering)
5115 {
5116   PetscSection   section, globalSection;
5117   PetscInt      *numbers, p;
5118   PetscErrorCode ierr;
5119 
5120   PetscFunctionBegin;
5121   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)dm), &section);CHKERRQ(ierr);
5122   ierr = PetscSectionSetChart(section, pStart, pEnd);CHKERRQ(ierr);
5123   for (p = pStart; p < pEnd; ++p) {
5124     ierr = PetscSectionSetDof(section, p, 1);CHKERRQ(ierr);
5125   }
5126   ierr = PetscSectionSetUp(section);CHKERRQ(ierr);
5127   ierr = PetscSectionCreateGlobalSection(section, sf, PETSC_FALSE, PETSC_FALSE, &globalSection);CHKERRQ(ierr);
5128   ierr = PetscMalloc1(pEnd - pStart, &numbers);CHKERRQ(ierr);
5129   for (p = pStart; p < pEnd; ++p) {
5130     ierr = PetscSectionGetOffset(globalSection, p, &numbers[p-pStart]);CHKERRQ(ierr);
5131     if (numbers[p-pStart] < 0) numbers[p-pStart] -= shift;
5132     else                       numbers[p-pStart] += shift;
5133   }
5134   ierr = ISCreateGeneral(PetscObjectComm((PetscObject) dm), pEnd - pStart, numbers, PETSC_OWN_POINTER, numbering);CHKERRQ(ierr);
5135   if (globalSize) {
5136     PetscLayout layout;
5137     ierr = PetscSectionGetPointLayout(PetscObjectComm((PetscObject) dm), globalSection, &layout);CHKERRQ(ierr);
5138     ierr = PetscLayoutGetSize(layout, globalSize);CHKERRQ(ierr);
5139     ierr = PetscLayoutDestroy(&layout);CHKERRQ(ierr);
5140   }
5141   ierr = PetscSectionDestroy(&section);CHKERRQ(ierr);
5142   ierr = PetscSectionDestroy(&globalSection);CHKERRQ(ierr);
5143   PetscFunctionReturn(0);
5144 }
5145 
5146 #undef __FUNCT__
5147 #define __FUNCT__ "DMPlexCreateCellNumbering_Internal"
5148 PetscErrorCode DMPlexCreateCellNumbering_Internal(DM dm, PetscBool includeHybrid, IS *globalCellNumbers)
5149 {
5150   PetscInt       cellHeight, cStart, cEnd, cMax;
5151   PetscErrorCode ierr;
5152 
5153   PetscFunctionBegin;
5154   ierr = DMPlexGetVTKCellHeight(dm, &cellHeight);CHKERRQ(ierr);
5155   ierr = DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd);CHKERRQ(ierr);
5156   ierr = DMPlexGetHybridBounds(dm, &cMax, NULL, NULL, NULL);CHKERRQ(ierr);
5157   if (cMax >= 0 && !includeHybrid) cEnd = PetscMin(cEnd, cMax);
5158   ierr = DMPlexCreateNumbering_Private(dm, cStart, cEnd, 0, NULL, dm->sf, globalCellNumbers);CHKERRQ(ierr);
5159   PetscFunctionReturn(0);
5160 }
5161 
5162 #undef __FUNCT__
5163 #define __FUNCT__ "DMPlexGetCellNumbering"
5164 PetscErrorCode DMPlexGetCellNumbering(DM dm, IS *globalCellNumbers)
5165 {
5166   DM_Plex       *mesh = (DM_Plex*) dm->data;
5167   PetscErrorCode ierr;
5168 
5169   PetscFunctionBegin;
5170   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5171   if (!mesh->globalCellNumbers) {ierr = DMPlexCreateCellNumbering_Internal(dm, PETSC_FALSE, &mesh->globalCellNumbers);CHKERRQ(ierr);}
5172   *globalCellNumbers = mesh->globalCellNumbers;
5173   PetscFunctionReturn(0);
5174 }
5175 
5176 #undef __FUNCT__
5177 #define __FUNCT__ "DMPlexCreateVertexNumbering_Internal"
5178 PetscErrorCode DMPlexCreateVertexNumbering_Internal(DM dm, PetscBool includeHybrid, IS *globalVertexNumbers)
5179 {
5180   PetscInt       vStart, vEnd, vMax;
5181   PetscErrorCode ierr;
5182 
5183   PetscFunctionBegin;
5184   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5185   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
5186   ierr = DMPlexGetHybridBounds(dm, NULL, NULL, NULL, &vMax);CHKERRQ(ierr);
5187   if (vMax >= 0 && !includeHybrid) vEnd = PetscMin(vEnd, vMax);
5188   ierr = DMPlexCreateNumbering_Private(dm, vStart, vEnd, 0, NULL, dm->sf, globalVertexNumbers);CHKERRQ(ierr);
5189   PetscFunctionReturn(0);
5190 }
5191 
5192 #undef __FUNCT__
5193 #define __FUNCT__ "DMPlexGetVertexNumbering"
5194 PetscErrorCode DMPlexGetVertexNumbering(DM dm, IS *globalVertexNumbers)
5195 {
5196   DM_Plex       *mesh = (DM_Plex*) dm->data;
5197   PetscErrorCode ierr;
5198 
5199   PetscFunctionBegin;
5200   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5201   if (!mesh->globalVertexNumbers) {ierr = DMPlexCreateVertexNumbering_Internal(dm, PETSC_FALSE, &mesh->globalVertexNumbers);CHKERRQ(ierr);}
5202   *globalVertexNumbers = mesh->globalVertexNumbers;
5203   PetscFunctionReturn(0);
5204 }
5205 
5206 #undef __FUNCT__
5207 #define __FUNCT__ "DMPlexCreatePointNumbering"
5208 PetscErrorCode DMPlexCreatePointNumbering(DM dm, IS *globalPointNumbers)
5209 {
5210   IS             nums[4];
5211   PetscInt       depths[4];
5212   PetscInt       depth, d, shift = 0;
5213   PetscErrorCode ierr;
5214 
5215   PetscFunctionBegin;
5216   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5217   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
5218   /* For unstratified meshes use dim instead of depth */
5219   if (depth < 0) {ierr = DMGetDimension(dm, &depth);CHKERRQ(ierr);}
5220   depths[0] = depth; depths[1] = 0;
5221   for (d = 2; d <= depth; ++d) depths[d] = depth-d+1;
5222   for (d = 0; d <= depth; ++d) {
5223     PetscInt pStart, pEnd, gsize;
5224 
5225     ierr = DMPlexGetDepthStratum(dm, depths[d], &pStart, &pEnd);CHKERRQ(ierr);
5226     ierr = DMPlexCreateNumbering_Private(dm, pStart, pEnd, shift, &gsize, dm->sf, &nums[d]);CHKERRQ(ierr);
5227     shift += gsize;
5228   }
5229   ierr = ISConcatenate(PetscObjectComm((PetscObject) dm), depth+1, nums, globalPointNumbers);CHKERRQ(ierr);
5230   for (d = 0; d <= depth; ++d) {ierr = ISDestroy(&nums[d]);CHKERRQ(ierr);}
5231   PetscFunctionReturn(0);
5232 }
5233 
5234 #undef __FUNCT__
5235 #define __FUNCT__ "DMPlexCheckSymmetry"
5236 /*@
5237   DMPlexCheckSymmetry - Check that the adjacency information in the mesh is symmetric.
5238 
5239   Input Parameters:
5240   + dm - The DMPlex object
5241 
5242   Note: This is a useful diagnostic when creating meshes programmatically.
5243 
5244   Level: developer
5245 
5246 .seealso: DMCreate(), DMCheckSkeleton(), DMCheckFaces()
5247 @*/
5248 PetscErrorCode DMPlexCheckSymmetry(DM dm)
5249 {
5250   PetscSection    coneSection, supportSection;
5251   const PetscInt *cone, *support;
5252   PetscInt        coneSize, c, supportSize, s;
5253   PetscInt        pStart, pEnd, p, csize, ssize;
5254   PetscErrorCode  ierr;
5255 
5256   PetscFunctionBegin;
5257   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5258   ierr = DMPlexGetConeSection(dm, &coneSection);CHKERRQ(ierr);
5259   ierr = DMPlexGetSupportSection(dm, &supportSection);CHKERRQ(ierr);
5260   /* Check that point p is found in the support of its cone points, and vice versa */
5261   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
5262   for (p = pStart; p < pEnd; ++p) {
5263     ierr = DMPlexGetConeSize(dm, p, &coneSize);CHKERRQ(ierr);
5264     ierr = DMPlexGetCone(dm, p, &cone);CHKERRQ(ierr);
5265     for (c = 0; c < coneSize; ++c) {
5266       PetscBool dup = PETSC_FALSE;
5267       PetscInt  d;
5268       for (d = c-1; d >= 0; --d) {
5269         if (cone[c] == cone[d]) {dup = PETSC_TRUE; break;}
5270       }
5271       ierr = DMPlexGetSupportSize(dm, cone[c], &supportSize);CHKERRQ(ierr);
5272       ierr = DMPlexGetSupport(dm, cone[c], &support);CHKERRQ(ierr);
5273       for (s = 0; s < supportSize; ++s) {
5274         if (support[s] == p) break;
5275       }
5276       if ((s >= supportSize) || (dup && (support[s+1] != p))) {
5277         ierr = PetscPrintf(PETSC_COMM_SELF, "p: %d cone: ", p);CHKERRQ(ierr);
5278         for (s = 0; s < coneSize; ++s) {
5279           ierr = PetscPrintf(PETSC_COMM_SELF, "%d, ", cone[s]);CHKERRQ(ierr);
5280         }
5281         ierr = PetscPrintf(PETSC_COMM_SELF, "\n");CHKERRQ(ierr);
5282         ierr = PetscPrintf(PETSC_COMM_SELF, "p: %d support: ", cone[c]);CHKERRQ(ierr);
5283         for (s = 0; s < supportSize; ++s) {
5284           ierr = PetscPrintf(PETSC_COMM_SELF, "%d, ", support[s]);CHKERRQ(ierr);
5285         }
5286         ierr = PetscPrintf(PETSC_COMM_SELF, "\n");CHKERRQ(ierr);
5287         if (dup) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d not repeatedly found in support of repeated cone point %d", p, cone[c]);
5288         else SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d not found in support of cone point %d", p, cone[c]);
5289       }
5290     }
5291     ierr = DMPlexGetSupportSize(dm, p, &supportSize);CHKERRQ(ierr);
5292     ierr = DMPlexGetSupport(dm, p, &support);CHKERRQ(ierr);
5293     for (s = 0; s < supportSize; ++s) {
5294       ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
5295       ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
5296       for (c = 0; c < coneSize; ++c) {
5297         if (cone[c] == p) break;
5298       }
5299       if (c >= coneSize) {
5300         ierr = PetscPrintf(PETSC_COMM_SELF, "p: %d support: ", p);CHKERRQ(ierr);
5301         for (c = 0; c < supportSize; ++c) {
5302           ierr = PetscPrintf(PETSC_COMM_SELF, "%d, ", support[c]);CHKERRQ(ierr);
5303         }
5304         ierr = PetscPrintf(PETSC_COMM_SELF, "\n");CHKERRQ(ierr);
5305         ierr = PetscPrintf(PETSC_COMM_SELF, "p: %d cone: ", support[s]);CHKERRQ(ierr);
5306         for (c = 0; c < coneSize; ++c) {
5307           ierr = PetscPrintf(PETSC_COMM_SELF, "%d, ", cone[c]);CHKERRQ(ierr);
5308         }
5309         ierr = PetscPrintf(PETSC_COMM_SELF, "\n");CHKERRQ(ierr);
5310         SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d not found in cone of support point %d", p, support[s]);
5311       }
5312     }
5313   }
5314   ierr = PetscSectionGetStorageSize(coneSection, &csize);CHKERRQ(ierr);
5315   ierr = PetscSectionGetStorageSize(supportSection, &ssize);CHKERRQ(ierr);
5316   if (csize != ssize) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Total cone size %d != Total support size %d", csize, ssize);
5317   PetscFunctionReturn(0);
5318 }
5319 
5320 #undef __FUNCT__
5321 #define __FUNCT__ "DMPlexCheckSkeleton"
5322 /*@
5323   DMPlexCheckSkeleton - Check that each cell has the correct number of vertices
5324 
5325   Input Parameters:
5326 + dm - The DMPlex object
5327 . isSimplex - Are the cells simplices or tensor products
5328 - cellHeight - Normally 0
5329 
5330   Note: This is a useful diagnostic when creating meshes programmatically.
5331 
5332   Level: developer
5333 
5334 .seealso: DMCreate(), DMCheckSymmetry(), DMCheckFaces()
5335 @*/
5336 PetscErrorCode DMPlexCheckSkeleton(DM dm, PetscBool isSimplex, PetscInt cellHeight)
5337 {
5338   PetscInt       dim, numCorners, numHybridCorners, vStart, vEnd, cStart, cEnd, cMax, c;
5339   PetscErrorCode ierr;
5340 
5341   PetscFunctionBegin;
5342   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5343   ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr);
5344   switch (dim) {
5345   case 1: numCorners = isSimplex ? 2 : 2; numHybridCorners = isSimplex ? 2 : 2; break;
5346   case 2: numCorners = isSimplex ? 3 : 4; numHybridCorners = isSimplex ? 4 : 4; break;
5347   case 3: numCorners = isSimplex ? 4 : 8; numHybridCorners = isSimplex ? 6 : 8; break;
5348   default:
5349     SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_OUTOFRANGE, "Cannot handle meshes of dimension %d", dim);
5350   }
5351   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
5352   ierr = DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd);CHKERRQ(ierr);
5353   ierr = DMPlexGetHybridBounds(dm, &cMax, NULL, NULL, NULL);CHKERRQ(ierr);
5354   cMax = cMax >= 0 ? cMax : cEnd;
5355   for (c = cStart; c < cMax; ++c) {
5356     PetscInt *closure = NULL, closureSize, cl, coneSize = 0;
5357 
5358     ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
5359     for (cl = 0; cl < closureSize*2; cl += 2) {
5360       const PetscInt p = closure[cl];
5361       if ((p >= vStart) && (p < vEnd)) ++coneSize;
5362     }
5363     ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
5364     if (coneSize != numCorners) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cell %d has  %d vertices != %d", c, coneSize, numCorners);
5365   }
5366   for (c = cMax; c < cEnd; ++c) {
5367     PetscInt *closure = NULL, closureSize, cl, coneSize = 0;
5368 
5369     ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
5370     for (cl = 0; cl < closureSize*2; cl += 2) {
5371       const PetscInt p = closure[cl];
5372       if ((p >= vStart) && (p < vEnd)) ++coneSize;
5373     }
5374     ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
5375     if (coneSize > numHybridCorners) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Hybrid cell %d has  %d vertices > %d", c, coneSize, numHybridCorners);
5376   }
5377   PetscFunctionReturn(0);
5378 }
5379 
5380 #undef __FUNCT__
5381 #define __FUNCT__ "DMPlexCheckFaces"
5382 /*@
5383   DMPlexCheckFaces - Check that the faces of each cell give a vertex order this is consistent with what we expect from the cell type
5384 
5385   Input Parameters:
5386 + dm - The DMPlex object
5387 . isSimplex - Are the cells simplices or tensor products
5388 - cellHeight - Normally 0
5389 
5390   Note: This is a useful diagnostic when creating meshes programmatically.
5391 
5392   Level: developer
5393 
5394 .seealso: DMCreate(), DMCheckSymmetry(), DMCheckSkeleton()
5395 @*/
5396 PetscErrorCode DMPlexCheckFaces(DM dm, PetscBool isSimplex, PetscInt cellHeight)
5397 {
5398   PetscInt       pMax[4];
5399   PetscInt       dim, vStart, vEnd, cStart, cEnd, c, h;
5400   PetscErrorCode ierr;
5401 
5402   PetscFunctionBegin;
5403   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5404   ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr);
5405   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
5406   ierr = DMPlexGetHybridBounds(dm, &pMax[dim], &pMax[dim-1], &pMax[1], &pMax[0]);CHKERRQ(ierr);
5407   for (h = cellHeight; h < dim; ++h) {
5408     ierr = DMPlexGetHeightStratum(dm, h, &cStart, &cEnd);CHKERRQ(ierr);
5409     for (c = cStart; c < cEnd; ++c) {
5410       const PetscInt *cone, *ornt, *faces;
5411       PetscInt        numFaces, faceSize, coneSize,f;
5412       PetscInt       *closure = NULL, closureSize, cl, numCorners = 0;
5413 
5414       if (pMax[dim-h] >= 0 && c >= pMax[dim-h]) continue;
5415       ierr = DMPlexGetConeSize(dm, c, &coneSize);CHKERRQ(ierr);
5416       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
5417       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
5418       ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
5419       for (cl = 0; cl < closureSize*2; cl += 2) {
5420         const PetscInt p = closure[cl];
5421         if ((p >= vStart) && (p < vEnd)) closure[numCorners++] = p;
5422       }
5423       ierr = DMPlexGetRawFaces_Internal(dm, dim-h, numCorners, closure, &numFaces, &faceSize, &faces);CHKERRQ(ierr);
5424       if (coneSize != numFaces) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cell %d has %d faces but should have %d", c, coneSize, numFaces);
5425       for (f = 0; f < numFaces; ++f) {
5426         PetscInt *fclosure = NULL, fclosureSize, cl, fnumCorners = 0, v;
5427 
5428         ierr = DMPlexGetTransitiveClosure_Internal(dm, cone[f], ornt[f], PETSC_TRUE, &fclosureSize, &fclosure);CHKERRQ(ierr);
5429         for (cl = 0; cl < fclosureSize*2; cl += 2) {
5430           const PetscInt p = fclosure[cl];
5431           if ((p >= vStart) && (p < vEnd)) fclosure[fnumCorners++] = p;
5432         }
5433         if (fnumCorners != faceSize) SETERRQ5(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Face %d (%d) of cell %d has %d vertices but should have %d", cone[f], f, c, fnumCorners, faceSize);
5434         for (v = 0; v < fnumCorners; ++v) {
5435           if (fclosure[v] != faces[f*faceSize+v]) SETERRQ6(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Face %d (%d) of cell %d vertex %d, %d != %d", cone[f], f, c, v, fclosure[v], faces[f*faceSize+v]);
5436         }
5437         ierr = DMPlexRestoreTransitiveClosure(dm, cone[f], PETSC_TRUE, &fclosureSize, &fclosure);CHKERRQ(ierr);
5438       }
5439       ierr = DMPlexRestoreFaces_Internal(dm, dim, c, &numFaces, &faceSize, &faces);CHKERRQ(ierr);
5440       ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
5441     }
5442   }
5443   PetscFunctionReturn(0);
5444 }
5445 
5446 #undef __FUNCT__
5447 #define __FUNCT__ "DMCreateInterpolation_Plex"
5448 /* Pointwise interpolation
5449      Just code FEM for now
5450      u^f = I u^c
5451      sum_k u^f_k phi^f_k = I sum_j u^c_j phi^c_j
5452      u^f_i = sum_j psi^f_i I phi^c_j u^c_j
5453      I_{ij} = psi^f_i phi^c_j
5454 */
5455 PetscErrorCode DMCreateInterpolation_Plex(DM dmCoarse, DM dmFine, Mat *interpolation, Vec *scaling)
5456 {
5457   PetscSection   gsc, gsf;
5458   PetscInt       m, n;
5459   void          *ctx;
5460   DM             cdm;
5461   PetscBool      regular;
5462   PetscErrorCode ierr;
5463 
5464   PetscFunctionBegin;
5465   ierr = DMGetDefaultGlobalSection(dmFine, &gsf);CHKERRQ(ierr);
5466   ierr = PetscSectionGetConstrainedStorageSize(gsf, &m);CHKERRQ(ierr);
5467   ierr = DMGetDefaultGlobalSection(dmCoarse, &gsc);CHKERRQ(ierr);
5468   ierr = PetscSectionGetConstrainedStorageSize(gsc, &n);CHKERRQ(ierr);
5469 
5470   ierr = MatCreate(PetscObjectComm((PetscObject) dmCoarse), interpolation);CHKERRQ(ierr);
5471   ierr = MatSetSizes(*interpolation, m, n, PETSC_DETERMINE, PETSC_DETERMINE);CHKERRQ(ierr);
5472   ierr = MatSetType(*interpolation, dmCoarse->mattype);CHKERRQ(ierr);
5473   ierr = DMGetApplicationContext(dmFine, &ctx);CHKERRQ(ierr);
5474 
5475   ierr = DMGetCoarseDM(dmFine, &cdm);CHKERRQ(ierr);
5476   ierr = DMPlexGetRegularRefinement(dmFine, &regular);CHKERRQ(ierr);
5477   if (regular && cdm == dmCoarse) {ierr = DMPlexComputeInterpolatorNested(dmCoarse, dmFine, *interpolation, ctx);CHKERRQ(ierr);}
5478   else                            {ierr = DMPlexComputeInterpolatorGeneral(dmCoarse, dmFine, *interpolation, ctx);CHKERRQ(ierr);}
5479   ierr = MatViewFromOptions(*interpolation, NULL, "-interp_mat_view");CHKERRQ(ierr);
5480   /* Use naive scaling */
5481   ierr = DMCreateInterpolationScale(dmCoarse, dmFine, *interpolation, scaling);CHKERRQ(ierr);
5482   PetscFunctionReturn(0);
5483 }
5484 
5485 #undef __FUNCT__
5486 #define __FUNCT__ "DMCreateInjection_Plex"
5487 PetscErrorCode DMCreateInjection_Plex(DM dmCoarse, DM dmFine, Mat *mat)
5488 {
5489   PetscErrorCode ierr;
5490   VecScatter     ctx;
5491 
5492   PetscFunctionBegin;
5493   ierr = DMPlexComputeInjectorFEM(dmCoarse, dmFine, &ctx, NULL);CHKERRQ(ierr);
5494   ierr = MatCreateScatter(PetscObjectComm((PetscObject)ctx), ctx, mat);CHKERRQ(ierr);
5495   ierr = VecScatterDestroy(&ctx);CHKERRQ(ierr);
5496   PetscFunctionReturn(0);
5497 }
5498 
5499 #undef __FUNCT__
5500 #define __FUNCT__ "DMCreateDefaultSection_Plex"
5501 PetscErrorCode DMCreateDefaultSection_Plex(DM dm)
5502 {
5503   PetscSection   section;
5504   IS            *bcPoints, *bcComps;
5505   PetscBool     *isFE;
5506   PetscInt      *bcFields, *numComp, *numDof;
5507   PetscInt       depth, dim, numBd, numBC = 0, numFields, bd, bc = 0, f;
5508   PetscInt       cStart, cEnd, cEndInterior;
5509   PetscErrorCode ierr;
5510 
5511   PetscFunctionBegin;
5512   ierr = DMGetNumFields(dm, &numFields);CHKERRQ(ierr);
5513   if (!numFields) PetscFunctionReturn(0);
5514   /* FE and FV boundary conditions are handled slightly differently */
5515   ierr = PetscMalloc1(numFields, &isFE);CHKERRQ(ierr);
5516   for (f = 0; f < numFields; ++f) {
5517     PetscObject  obj;
5518     PetscClassId id;
5519 
5520     ierr = DMGetField(dm, f, &obj);CHKERRQ(ierr);
5521     ierr = PetscObjectGetClassId(obj, &id);CHKERRQ(ierr);
5522     if (id == PETSCFE_CLASSID)      {isFE[f] = PETSC_TRUE;}
5523     else if (id == PETSCFV_CLASSID) {isFE[f] = PETSC_FALSE;}
5524     else SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %d", f);
5525   }
5526   /* Allocate boundary point storage for FEM boundaries */
5527   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
5528   ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr);
5529   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
5530   ierr = DMPlexGetHybridBounds(dm, &cEndInterior, NULL, NULL, NULL);CHKERRQ(ierr);
5531   ierr = DMGetNumBoundary(dm, &numBd);CHKERRQ(ierr);
5532   for (bd = 0; bd < numBd; ++bd) {
5533     PetscInt  field;
5534     PetscBool isEssential;
5535 
5536     ierr = DMGetBoundary(dm, bd, &isEssential, NULL, NULL, &field, NULL, NULL, NULL, NULL, NULL, NULL);CHKERRQ(ierr);
5537     if (isFE[field] && isEssential) ++numBC;
5538   }
5539   /* Add ghost cell boundaries for FVM */
5540   for (f = 0; f < numFields; ++f) if (!isFE[f] && cEndInterior >= 0) ++numBC;
5541   ierr = PetscCalloc3(numBC,&bcFields,numBC,&bcPoints,numBC,&bcComps);CHKERRQ(ierr);
5542   /* Constrain ghost cells for FV */
5543   for (f = 0; f < numFields; ++f) {
5544     PetscInt *newidx, c;
5545 
5546     if (isFE[f] || cEndInterior < 0) continue;
5547     ierr = PetscMalloc1(cEnd-cEndInterior,&newidx);CHKERRQ(ierr);
5548     for (c = cEndInterior; c < cEnd; ++c) newidx[c-cEndInterior] = c;
5549     bcFields[bc] = f;
5550     ierr = ISCreateGeneral(PetscObjectComm((PetscObject) dm), cEnd-cEndInterior, newidx, PETSC_OWN_POINTER, &bcPoints[bc++]);CHKERRQ(ierr);
5551   }
5552   /* Handle FEM Dirichlet boundaries */
5553   for (bd = 0; bd < numBd; ++bd) {
5554     const char     *bdLabel;
5555     DMLabel         label;
5556     const PetscInt *comps;
5557     const PetscInt *values;
5558     PetscInt        bd2, field, numComps, numValues;
5559     PetscBool       isEssential, duplicate = PETSC_FALSE;
5560 
5561     ierr = DMGetBoundary(dm, bd, &isEssential, NULL, &bdLabel, &field, &numComps, &comps, NULL, &numValues, &values, NULL);CHKERRQ(ierr);
5562     if (!isFE[field]) continue;
5563     ierr = DMGetLabel(dm, bdLabel, &label);CHKERRQ(ierr);
5564     /* Only want to modify label once */
5565     for (bd2 = 0; bd2 < bd; ++bd2) {
5566       const char *bdname;
5567       ierr = DMGetBoundary(dm, bd2, NULL, NULL, &bdname, NULL, NULL, NULL, NULL, NULL, NULL, NULL);CHKERRQ(ierr);
5568       ierr = PetscStrcmp(bdname, bdLabel, &duplicate);CHKERRQ(ierr);
5569       if (duplicate) break;
5570     }
5571     if (!duplicate && (isFE[field])) {
5572       /* don't complete cells, which are just present to give orientation to the boundary */
5573       ierr = DMPlexLabelComplete(dm, label);CHKERRQ(ierr);
5574     }
5575     /* Filter out cells, if you actually want to constrain cells you need to do things by hand right now */
5576     if (isEssential) {
5577       PetscInt       *newidx;
5578       PetscInt        n, newn = 0, p, v;
5579 
5580       bcFields[bc] = field;
5581       if (numComps) {ierr = ISCreateGeneral(PetscObjectComm((PetscObject) dm), numComps, comps, PETSC_COPY_VALUES, &bcComps[bc]);CHKERRQ(ierr);}
5582       for (v = 0; v < numValues; ++v) {
5583         IS              tmp;
5584         const PetscInt *idx;
5585 
5586         ierr = DMGetStratumIS(dm, bdLabel, values[v], &tmp);CHKERRQ(ierr);
5587         if (!tmp) continue;
5588         ierr = ISGetLocalSize(tmp, &n);CHKERRQ(ierr);
5589         ierr = ISGetIndices(tmp, &idx);CHKERRQ(ierr);
5590         if (isFE[field]) {
5591           for (p = 0; p < n; ++p) if ((idx[p] < cStart) || (idx[p] >= cEnd)) ++newn;
5592         } else {
5593           for (p = 0; p < n; ++p) if ((idx[p] >= cStart) || (idx[p] < cEnd)) ++newn;
5594         }
5595         ierr = ISRestoreIndices(tmp, &idx);CHKERRQ(ierr);
5596         ierr = ISDestroy(&tmp);CHKERRQ(ierr);
5597       }
5598       ierr = PetscMalloc1(newn,&newidx);CHKERRQ(ierr);
5599       newn = 0;
5600       for (v = 0; v < numValues; ++v) {
5601         IS              tmp;
5602         const PetscInt *idx;
5603 
5604         ierr = DMGetStratumIS(dm, bdLabel, values[v], &tmp);CHKERRQ(ierr);
5605         if (!tmp) continue;
5606         ierr = ISGetLocalSize(tmp, &n);CHKERRQ(ierr);
5607         ierr = ISGetIndices(tmp, &idx);CHKERRQ(ierr);
5608         if (isFE[field]) {
5609           for (p = 0; p < n; ++p) if ((idx[p] < cStart) || (idx[p] >= cEnd)) newidx[newn++] = idx[p];
5610         } else {
5611           for (p = 0; p < n; ++p) if ((idx[p] >= cStart) || (idx[p] < cEnd)) newidx[newn++] = idx[p];
5612         }
5613         ierr = ISRestoreIndices(tmp, &idx);CHKERRQ(ierr);
5614         ierr = ISDestroy(&tmp);CHKERRQ(ierr);
5615       }
5616       ierr = ISCreateGeneral(PetscObjectComm((PetscObject) dm), newn, newidx, PETSC_OWN_POINTER, &bcPoints[bc++]);CHKERRQ(ierr);
5617     }
5618   }
5619   /* Handle discretization */
5620   ierr = PetscCalloc2(numFields,&numComp,numFields*(dim+1),&numDof);CHKERRQ(ierr);
5621   for (f = 0; f < numFields; ++f) {
5622     PetscObject obj;
5623 
5624     ierr = DMGetField(dm, f, &obj);CHKERRQ(ierr);
5625     if (isFE[f]) {
5626       PetscFE         fe = (PetscFE) obj;
5627       const PetscInt *numFieldDof;
5628       PetscInt        d;
5629 
5630       ierr = PetscFEGetNumComponents(fe, &numComp[f]);CHKERRQ(ierr);
5631       ierr = PetscFEGetNumDof(fe, &numFieldDof);CHKERRQ(ierr);
5632       for (d = 0; d < dim+1; ++d) numDof[f*(dim+1)+d] = numFieldDof[d];
5633     } else {
5634       PetscFV fv = (PetscFV) obj;
5635 
5636       ierr = PetscFVGetNumComponents(fv, &numComp[f]);CHKERRQ(ierr);
5637       numDof[f*(dim+1)+dim] = numComp[f];
5638     }
5639   }
5640   for (f = 0; f < numFields; ++f) {
5641     PetscInt d;
5642     for (d = 1; d < dim; ++d) {
5643       if ((numDof[f*(dim+1)+d] > 0) && (depth < dim)) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Mesh must be interpolated when unknowns are specified on edges or faces.");
5644     }
5645   }
5646   ierr = DMPlexCreateSection(dm, dim, numFields, numComp, numDof, numBC, bcFields, bcComps, bcPoints, NULL, &section);CHKERRQ(ierr);
5647   for (f = 0; f < numFields; ++f) {
5648     PetscFE     fe;
5649     const char *name;
5650 
5651     ierr = DMGetField(dm, f, (PetscObject *) &fe);CHKERRQ(ierr);
5652     ierr = PetscObjectGetName((PetscObject) fe, &name);CHKERRQ(ierr);
5653     ierr = PetscSectionSetFieldName(section, f, name);CHKERRQ(ierr);
5654   }
5655   ierr = DMSetDefaultSection(dm, section);CHKERRQ(ierr);
5656   ierr = PetscSectionDestroy(&section);CHKERRQ(ierr);
5657   for (bc = 0; bc < numBC; ++bc) {ierr = ISDestroy(&bcPoints[bc]);CHKERRQ(ierr);ierr = ISDestroy(&bcComps[bc]);CHKERRQ(ierr);}
5658   ierr = PetscFree3(bcFields,bcPoints,bcComps);CHKERRQ(ierr);
5659   ierr = PetscFree2(numComp,numDof);CHKERRQ(ierr);
5660   ierr = PetscFree(isFE);CHKERRQ(ierr);
5661   PetscFunctionReturn(0);
5662 }
5663 
5664 #undef __FUNCT__
5665 #define __FUNCT__ "DMPlexGetRegularRefinement"
5666 /*@
5667   DMPlexGetRegularRefinement - Get the flag indicating that this mesh was obtained by regular refinement from its coarse mesh
5668 
5669   Input Parameter:
5670 . dm - The DMPlex object
5671 
5672   Output Parameter:
5673 . regular - The flag
5674 
5675   Level: intermediate
5676 
5677 .seealso: DMPlexSetRegularRefinement()
5678 @*/
5679 PetscErrorCode DMPlexGetRegularRefinement(DM dm, PetscBool *regular)
5680 {
5681   PetscFunctionBegin;
5682   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5683   PetscValidPointer(regular, 2);
5684   *regular = ((DM_Plex *) dm->data)->regularRefinement;
5685   PetscFunctionReturn(0);
5686 }
5687 
5688 #undef __FUNCT__
5689 #define __FUNCT__ "DMPlexSetRegularRefinement"
5690 /*@
5691   DMPlexSetRegularRefinement - Set the flag indicating that this mesh was obtained by regular refinement from its coarse mesh
5692 
5693   Input Parameters:
5694 + dm - The DMPlex object
5695 - regular - The flag
5696 
5697   Level: intermediate
5698 
5699 .seealso: DMPlexGetRegularRefinement()
5700 @*/
5701 PetscErrorCode DMPlexSetRegularRefinement(DM dm, PetscBool regular)
5702 {
5703   PetscFunctionBegin;
5704   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5705   ((DM_Plex *) dm->data)->regularRefinement = regular;
5706   PetscFunctionReturn(0);
5707 }
5708 
5709 /* anchors */
5710 #undef __FUNCT__
5711 #define __FUNCT__ "DMPlexGetAnchors"
5712 /*@
5713   DMPlexGetAnchors - Get the layout of the anchor (point-to-point) constraints.  Typically, the user will not have to
5714   call DMPlexGetAnchors() directly: if there are anchors, then DMPlexGetAnchors() is called during DMGetConstraints().
5715 
5716   not collective
5717 
5718   Input Parameters:
5719 . dm - The DMPlex object
5720 
5721   Output Parameters:
5722 + anchorSection - If not NULL, set to the section describing which points anchor the constrained points.
5723 - anchorIS - If not NULL, set to the list of anchors indexed by anchorSection
5724 
5725 
5726   Level: intermediate
5727 
5728 .seealso: DMPlexSetAnchors(), DMGetConstraints(), DMSetConstraints()
5729 @*/
5730 PetscErrorCode DMPlexGetAnchors(DM dm, PetscSection *anchorSection, IS *anchorIS)
5731 {
5732   DM_Plex *plex = (DM_Plex *)dm->data;
5733   PetscErrorCode ierr;
5734 
5735   PetscFunctionBegin;
5736   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5737   if (!plex->anchorSection && !plex->anchorIS && plex->createanchors) {ierr = (*plex->createanchors)(dm);CHKERRQ(ierr);}
5738   if (anchorSection) *anchorSection = plex->anchorSection;
5739   if (anchorIS) *anchorIS = plex->anchorIS;
5740   PetscFunctionReturn(0);
5741 }
5742 
5743 #undef __FUNCT__
5744 #define __FUNCT__ "DMPlexSetAnchors"
5745 /*@
5746   DMPlexSetAnchors - Set the layout of the local anchor (point-to-point) constraints.  Unlike boundary conditions,
5747   when a point's degrees of freedom in a section are constrained to an outside value, the anchor constraints set a
5748   point's degrees of freedom to be a linear combination of other points' degrees of freedom.
5749 
5750   After specifying the layout of constraints with DMPlexSetAnchors(), one specifies the constraints by calling
5751   DMGetConstraints() and filling in the entries in the constraint matrix.
5752 
5753   collective on dm
5754 
5755   Input Parameters:
5756 + dm - The DMPlex object
5757 . anchorSection - The section that describes the mapping from constrained points to the anchor points listed in anchorIS.  Must have a local communicator (PETSC_COMM_SELF or derivative).
5758 - anchorIS - The list of all anchor points.  Must have a local communicator (PETSC_COMM_SELF or derivative).
5759 
5760   The reference counts of anchorSection and anchorIS are incremented.
5761 
5762   Level: intermediate
5763 
5764 .seealso: DMPlexGetAnchors(), DMGetConstraints(), DMSetConstraints()
5765 @*/
5766 PetscErrorCode DMPlexSetAnchors(DM dm, PetscSection anchorSection, IS anchorIS)
5767 {
5768   DM_Plex        *plex = (DM_Plex *)dm->data;
5769   PetscMPIInt    result;
5770   PetscErrorCode ierr;
5771 
5772   PetscFunctionBegin;
5773   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5774   if (anchorSection) {
5775     PetscValidHeaderSpecific(anchorSection,PETSC_SECTION_CLASSID,2);
5776     ierr = MPI_Comm_compare(PETSC_COMM_SELF,PetscObjectComm((PetscObject)anchorSection),&result);CHKERRQ(ierr);
5777     if (result != MPI_CONGRUENT) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_NOTSAMECOMM,"anchor section must have local communicator");
5778   }
5779   if (anchorIS) {
5780     PetscValidHeaderSpecific(anchorIS,IS_CLASSID,3);
5781     ierr = MPI_Comm_compare(PETSC_COMM_SELF,PetscObjectComm((PetscObject)anchorIS),&result);CHKERRQ(ierr);
5782     if (result != MPI_CONGRUENT) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_NOTSAMECOMM,"anchor IS must have local communicator");
5783   }
5784 
5785   ierr = PetscObjectReference((PetscObject)anchorSection);CHKERRQ(ierr);
5786   ierr = PetscSectionDestroy(&plex->anchorSection);CHKERRQ(ierr);
5787   plex->anchorSection = anchorSection;
5788 
5789   ierr = PetscObjectReference((PetscObject)anchorIS);CHKERRQ(ierr);
5790   ierr = ISDestroy(&plex->anchorIS);CHKERRQ(ierr);
5791   plex->anchorIS = anchorIS;
5792 
5793 #if defined(PETSC_USE_DEBUG)
5794   if (anchorIS && anchorSection) {
5795     PetscInt size, a, pStart, pEnd;
5796     const PetscInt *anchors;
5797 
5798     ierr = PetscSectionGetChart(anchorSection,&pStart,&pEnd);CHKERRQ(ierr);
5799     ierr = ISGetLocalSize(anchorIS,&size);CHKERRQ(ierr);
5800     ierr = ISGetIndices(anchorIS,&anchors);CHKERRQ(ierr);
5801     for (a = 0; a < size; a++) {
5802       PetscInt p;
5803 
5804       p = anchors[a];
5805       if (p >= pStart && p < pEnd) {
5806         PetscInt dof;
5807 
5808         ierr = PetscSectionGetDof(anchorSection,p,&dof);CHKERRQ(ierr);
5809         if (dof) {
5810           PetscErrorCode ierr2;
5811 
5812           ierr2 = ISRestoreIndices(anchorIS,&anchors);CHKERRQ(ierr2);
5813           SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Point %d cannot be constrained and an anchor",p);
5814         }
5815       }
5816     }
5817     ierr = ISRestoreIndices(anchorIS,&anchors);CHKERRQ(ierr);
5818   }
5819 #endif
5820   /* reset the generic constraints */
5821   ierr = DMSetDefaultConstraints(dm,NULL,NULL);CHKERRQ(ierr);
5822   PetscFunctionReturn(0);
5823 }
5824 
5825 #undef __FUNCT__
5826 #define __FUNCT__ "DMPlexCreateConstraintSection_Anchors"
5827 static PetscErrorCode DMPlexCreateConstraintSection_Anchors(DM dm, PetscSection section, PetscSection *cSec)
5828 {
5829   PetscSection anchorSection;
5830   PetscInt pStart, pEnd, sStart, sEnd, p, dof, numFields, f;
5831   PetscErrorCode ierr;
5832 
5833   PetscFunctionBegin;
5834   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5835   ierr = DMPlexGetAnchors(dm,&anchorSection,NULL);CHKERRQ(ierr);
5836   ierr = PetscSectionCreate(PETSC_COMM_SELF,cSec);CHKERRQ(ierr);
5837   ierr = PetscSectionGetNumFields(section,&numFields);CHKERRQ(ierr);
5838   if (numFields) {
5839     PetscInt f;
5840     ierr = PetscSectionSetNumFields(*cSec,numFields);CHKERRQ(ierr);
5841 
5842     for (f = 0; f < numFields; f++) {
5843       PetscInt numComp;
5844 
5845       ierr = PetscSectionGetFieldComponents(section,f,&numComp);CHKERRQ(ierr);
5846       ierr = PetscSectionSetFieldComponents(*cSec,f,numComp);CHKERRQ(ierr);
5847     }
5848   }
5849   ierr = PetscSectionGetChart(anchorSection,&pStart,&pEnd);CHKERRQ(ierr);
5850   ierr = PetscSectionGetChart(section,&sStart,&sEnd);CHKERRQ(ierr);
5851   pStart = PetscMax(pStart,sStart);
5852   pEnd   = PetscMin(pEnd,sEnd);
5853   pEnd   = PetscMax(pStart,pEnd);
5854   ierr = PetscSectionSetChart(*cSec,pStart,pEnd);CHKERRQ(ierr);
5855   for (p = pStart; p < pEnd; p++) {
5856     ierr = PetscSectionGetDof(anchorSection,p,&dof);CHKERRQ(ierr);
5857     if (dof) {
5858       ierr = PetscSectionGetDof(section,p,&dof);CHKERRQ(ierr);
5859       ierr = PetscSectionSetDof(*cSec,p,dof);CHKERRQ(ierr);
5860       for (f = 0; f < numFields; f++) {
5861         ierr = PetscSectionGetFieldDof(section,p,f,&dof);CHKERRQ(ierr);
5862         ierr = PetscSectionSetFieldDof(*cSec,p,f,dof);CHKERRQ(ierr);
5863       }
5864     }
5865   }
5866   ierr = PetscSectionSetUp(*cSec);CHKERRQ(ierr);
5867   PetscFunctionReturn(0);
5868 }
5869 
5870 #undef __FUNCT__
5871 #define __FUNCT__ "DMPlexCreateConstraintMatrix_Anchors"
5872 static PetscErrorCode DMPlexCreateConstraintMatrix_Anchors(DM dm, PetscSection section, PetscSection cSec, Mat *cMat)
5873 {
5874   PetscSection aSec;
5875   PetscInt pStart, pEnd, p, dof, aDof, aOff, off, nnz, annz, m, n, q, a, offset, *i, *j;
5876   const PetscInt *anchors;
5877   PetscInt numFields, f;
5878   IS aIS;
5879   PetscErrorCode ierr;
5880 
5881   PetscFunctionBegin;
5882   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5883   ierr = PetscSectionGetStorageSize(cSec, &m);CHKERRQ(ierr);
5884   ierr = PetscSectionGetStorageSize(section, &n);CHKERRQ(ierr);
5885   ierr = MatCreate(PETSC_COMM_SELF,cMat);CHKERRQ(ierr);
5886   ierr = MatSetSizes(*cMat,m,n,m,n);CHKERRQ(ierr);
5887   ierr = MatSetType(*cMat,MATSEQAIJ);CHKERRQ(ierr);
5888   ierr = DMPlexGetAnchors(dm,&aSec,&aIS);CHKERRQ(ierr);
5889   ierr = ISGetIndices(aIS,&anchors);CHKERRQ(ierr);
5890   /* cSec will be a subset of aSec and section */
5891   ierr = PetscSectionGetChart(cSec,&pStart,&pEnd);CHKERRQ(ierr);
5892   ierr = PetscMalloc1(m+1,&i);CHKERRQ(ierr);
5893   i[0] = 0;
5894   ierr = PetscSectionGetNumFields(section,&numFields);CHKERRQ(ierr);
5895   for (p = pStart; p < pEnd; p++) {
5896     PetscInt rDof, rOff, r;
5897 
5898     ierr = PetscSectionGetDof(aSec,p,&rDof);CHKERRQ(ierr);
5899     if (!rDof) continue;
5900     ierr = PetscSectionGetOffset(aSec,p,&rOff);CHKERRQ(ierr);
5901     if (numFields) {
5902       for (f = 0; f < numFields; f++) {
5903         annz = 0;
5904         for (r = 0; r < rDof; r++) {
5905           a = anchors[rOff + r];
5906           ierr = PetscSectionGetFieldDof(section,a,f,&aDof);CHKERRQ(ierr);
5907           annz += aDof;
5908         }
5909         ierr = PetscSectionGetFieldDof(cSec,p,f,&dof);CHKERRQ(ierr);
5910         ierr = PetscSectionGetFieldOffset(cSec,p,f,&off);CHKERRQ(ierr);
5911         for (q = 0; q < dof; q++) {
5912           i[off + q + 1] = i[off + q] + annz;
5913         }
5914       }
5915     }
5916     else {
5917       annz = 0;
5918       for (q = 0; q < dof; q++) {
5919         a = anchors[off + q];
5920         ierr = PetscSectionGetDof(section,a,&aDof);CHKERRQ(ierr);
5921         annz += aDof;
5922       }
5923       ierr = PetscSectionGetDof(cSec,p,&dof);CHKERRQ(ierr);
5924       ierr = PetscSectionGetOffset(cSec,p,&off);CHKERRQ(ierr);
5925       for (q = 0; q < dof; q++) {
5926         i[off + q + 1] = i[off + q] + annz;
5927       }
5928     }
5929   }
5930   nnz = i[m];
5931   ierr = PetscMalloc1(nnz,&j);CHKERRQ(ierr);
5932   offset = 0;
5933   for (p = pStart; p < pEnd; p++) {
5934     if (numFields) {
5935       for (f = 0; f < numFields; f++) {
5936         ierr = PetscSectionGetFieldDof(cSec,p,f,&dof);CHKERRQ(ierr);
5937         for (q = 0; q < dof; q++) {
5938           PetscInt rDof, rOff, r;
5939           ierr = PetscSectionGetDof(aSec,p,&rDof);CHKERRQ(ierr);
5940           ierr = PetscSectionGetOffset(aSec,p,&rOff);CHKERRQ(ierr);
5941           for (r = 0; r < rDof; r++) {
5942             PetscInt s;
5943 
5944             a = anchors[rOff + r];
5945             ierr = PetscSectionGetFieldDof(section,a,f,&aDof);CHKERRQ(ierr);
5946             ierr = PetscSectionGetFieldOffset(section,a,f,&aOff);CHKERRQ(ierr);
5947             for (s = 0; s < aDof; s++) {
5948               j[offset++] = aOff + s;
5949             }
5950           }
5951         }
5952       }
5953     }
5954     else {
5955       ierr = PetscSectionGetDof(cSec,p,&dof);CHKERRQ(ierr);
5956       for (q = 0; q < dof; q++) {
5957         PetscInt rDof, rOff, r;
5958         ierr = PetscSectionGetDof(aSec,p,&rDof);CHKERRQ(ierr);
5959         ierr = PetscSectionGetOffset(aSec,p,&rOff);CHKERRQ(ierr);
5960         for (r = 0; r < rDof; r++) {
5961           PetscInt s;
5962 
5963           a = anchors[rOff + r];
5964           ierr = PetscSectionGetDof(section,a,&aDof);CHKERRQ(ierr);
5965           ierr = PetscSectionGetOffset(section,a,&aOff);CHKERRQ(ierr);
5966           for (s = 0; s < aDof; s++) {
5967             j[offset++] = aOff + s;
5968           }
5969         }
5970       }
5971     }
5972   }
5973   ierr = MatSeqAIJSetPreallocationCSR(*cMat,i,j,NULL);CHKERRQ(ierr);
5974   ierr = PetscFree(i);CHKERRQ(ierr);
5975   ierr = PetscFree(j);CHKERRQ(ierr);
5976   ierr = ISRestoreIndices(aIS,&anchors);CHKERRQ(ierr);
5977   PetscFunctionReturn(0);
5978 }
5979 
5980 #undef __FUNCT__
5981 #define __FUNCT__ "DMCreateDefaultConstraints_Plex"
5982 PetscErrorCode DMCreateDefaultConstraints_Plex(DM dm)
5983 {
5984   DM_Plex        *plex = (DM_Plex *)dm->data;
5985   PetscSection   anchorSection, section, cSec;
5986   Mat            cMat;
5987   PetscErrorCode ierr;
5988 
5989   PetscFunctionBegin;
5990   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5991   ierr = DMPlexGetAnchors(dm,&anchorSection,NULL);CHKERRQ(ierr);
5992   if (anchorSection) {
5993     PetscDS  ds;
5994     PetscInt nf;
5995 
5996     ierr = DMGetDefaultSection(dm,&section);CHKERRQ(ierr);
5997     ierr = DMPlexCreateConstraintSection_Anchors(dm,section,&cSec);CHKERRQ(ierr);
5998     ierr = DMPlexCreateConstraintMatrix_Anchors(dm,section,cSec,&cMat);CHKERRQ(ierr);
5999     ierr = DMGetDS(dm,&ds);CHKERRQ(ierr);
6000     ierr = PetscDSGetNumFields(ds,&nf);CHKERRQ(ierr);
6001     if (nf && plex->computeanchormatrix) {ierr = (*plex->computeanchormatrix)(dm,section,cSec,cMat);CHKERRQ(ierr);}
6002     ierr = DMSetDefaultConstraints(dm,cSec,cMat);CHKERRQ(ierr);
6003     ierr = PetscSectionDestroy(&cSec);CHKERRQ(ierr);
6004     ierr = MatDestroy(&cMat);CHKERRQ(ierr);
6005   }
6006   PetscFunctionReturn(0);
6007 }
6008