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