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