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