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