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