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