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