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