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