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