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