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