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