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