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