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