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