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