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