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