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