xref: /petsc/src/dm/impls/plex/plex.c (revision 24640c55e535a827c545161bba819e069fe16aff)
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 = MPIU_Allreduce(&locDepth, &depth, 1, MPIU_INT, MPI_MAX, comm);CHKERRQ(ierr);
597     ierr = DMPlexGetHybridBounds(dm, &pMax[depth], depth > 0 ? &pMax[depth-1] : NULL, &pMax[1], &pMax[0]);CHKERRQ(ierr);
598     ierr = PetscMalloc2(size,&sizes,size,&hybsizes);CHKERRQ(ierr);
599     if (depth == 1) {
600       ierr = DMPlexGetDepthStratum(dm, 0, &pStart, &pEnd);CHKERRQ(ierr);
601       pEnd = pEnd - pStart;
602       ierr = MPI_Gather(&pEnd, 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm);CHKERRQ(ierr);
603       ierr = PetscViewerASCIIPrintf(viewer, "  %d-cells:", 0);CHKERRQ(ierr);
604       for (p = 0; p < size; ++p) {ierr = PetscViewerASCIIPrintf(viewer, " %D", sizes[p]);CHKERRQ(ierr);}
605       ierr = PetscViewerASCIIPrintf(viewer, "\n");CHKERRQ(ierr);
606       ierr = DMPlexGetHeightStratum(dm, 0, &pStart, &pEnd);CHKERRQ(ierr);
607       pEnd = pEnd - pStart;
608       ierr = MPI_Gather(&pEnd, 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm);CHKERRQ(ierr);
609       ierr = PetscViewerASCIIPrintf(viewer, "  %D-cells:", dim);CHKERRQ(ierr);
610       for (p = 0; p < size; ++p) {ierr = PetscViewerASCIIPrintf(viewer, " %D", sizes[p]);CHKERRQ(ierr);}
611       ierr = PetscViewerASCIIPrintf(viewer, "\n");CHKERRQ(ierr);
612     } else {
613       for (d = 0; d <= dim; d++) {
614         ierr = DMPlexGetDepthStratum(dm, d, &pStart, &pEnd);CHKERRQ(ierr);
615         pEnd    -= pStart;
616         pMax[d] -= pStart;
617         ierr = MPI_Gather(&pEnd, 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm);CHKERRQ(ierr);
618         ierr = MPI_Gather(&pMax[d], 1, MPIU_INT, hybsizes, 1, MPIU_INT, 0, comm);CHKERRQ(ierr);
619         ierr = PetscViewerASCIIPrintf(viewer, "  %D-cells:", d);CHKERRQ(ierr);
620         for (p = 0; p < size; ++p) {
621           if (hybsizes[p] >= 0) {ierr = PetscViewerASCIIPrintf(viewer, " %D (%D)", sizes[p], sizes[p] - hybsizes[p]);CHKERRQ(ierr);}
622           else                  {ierr = PetscViewerASCIIPrintf(viewer, " %D", sizes[p]);CHKERRQ(ierr);}
623         }
624         ierr = PetscViewerASCIIPrintf(viewer, "\n");CHKERRQ(ierr);
625       }
626     }
627     ierr = PetscFree2(sizes,hybsizes);CHKERRQ(ierr);
628     ierr = 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 = MPIU_Allreduce(&bsLocal, &bsMax, 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm));CHKERRQ(ierr);
838         bsLocal = bs < 0 ? bsMax : bs;
839         ierr = MPIU_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   DM_Plex       *mesh = (DM_Plex*) dm->data;
1905   DMLabel        label;
1906   PetscInt       pStart, pEnd, p;
1907   PetscInt       numRoots = 0, numLeaves = 0;
1908   PetscErrorCode ierr;
1909 
1910   PetscFunctionBegin;
1911   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1912   ierr = PetscLogEventBegin(DMPLEX_Stratify,dm,0,0,0);CHKERRQ(ierr);
1913   /* Calculate depth */
1914   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
1915   ierr = DMPlexCreateLabel(dm, "depth");CHKERRQ(ierr);
1916   ierr = DMPlexGetDepthLabel(dm, &label);CHKERRQ(ierr);
1917   /* Initialize roots and count leaves */
1918   for (p = pStart; p < pEnd; ++p) {
1919     PetscInt coneSize, supportSize;
1920 
1921     ierr = DMPlexGetConeSize(dm, p, &coneSize);CHKERRQ(ierr);
1922     ierr = DMPlexGetSupportSize(dm, p, &supportSize);CHKERRQ(ierr);
1923     if (!coneSize && supportSize) {
1924       ++numRoots;
1925       ierr = DMLabelSetValue(label, p, 0);CHKERRQ(ierr);
1926     } else if (!supportSize && coneSize) {
1927       ++numLeaves;
1928     } else if (!supportSize && !coneSize) {
1929       /* Isolated points */
1930       ierr = DMLabelSetValue(label, p, 0);CHKERRQ(ierr);
1931     }
1932   }
1933   if (numRoots + numLeaves == (pEnd - pStart)) {
1934     for (p = pStart; p < pEnd; ++p) {
1935       PetscInt coneSize, supportSize;
1936 
1937       ierr = DMPlexGetConeSize(dm, p, &coneSize);CHKERRQ(ierr);
1938       ierr = DMPlexGetSupportSize(dm, p, &supportSize);CHKERRQ(ierr);
1939       if (!supportSize && coneSize) {
1940         ierr = DMLabelSetValue(label, p, 1);CHKERRQ(ierr);
1941       }
1942     }
1943   } else {
1944     IS       pointIS;
1945     PetscInt numPoints = 0, level = 0;
1946 
1947     ierr = DMLabelGetStratumIS(label, level, &pointIS);CHKERRQ(ierr);
1948     if (pointIS) {ierr = ISGetLocalSize(pointIS, &numPoints);CHKERRQ(ierr);}
1949     while (numPoints) {
1950       const PetscInt *points;
1951       const PetscInt  newLevel = level+1;
1952 
1953       ierr = ISGetIndices(pointIS, &points);CHKERRQ(ierr);
1954       for (p = 0; p < numPoints; ++p) {
1955         const PetscInt  point = points[p];
1956         const PetscInt *support;
1957         PetscInt        supportSize, s;
1958 
1959         ierr = DMPlexGetSupportSize(dm, point, &supportSize);CHKERRQ(ierr);
1960         ierr = DMPlexGetSupport(dm, point, &support);CHKERRQ(ierr);
1961         for (s = 0; s < supportSize; ++s) {
1962           ierr = DMLabelSetValue(label, support[s], newLevel);CHKERRQ(ierr);
1963         }
1964       }
1965       ierr = ISRestoreIndices(pointIS, &points);CHKERRQ(ierr);
1966       ++level;
1967       ierr = ISDestroy(&pointIS);CHKERRQ(ierr);
1968       ierr = DMLabelGetStratumIS(label, level, &pointIS);CHKERRQ(ierr);
1969       if (pointIS) {ierr = ISGetLocalSize(pointIS, &numPoints);CHKERRQ(ierr);}
1970       else         {numPoints = 0;}
1971     }
1972     ierr = ISDestroy(&pointIS);CHKERRQ(ierr);
1973   }
1974   ierr = DMLabelGetState(label, &mesh->depthState);CHKERRQ(ierr);
1975   ierr = PetscLogEventEnd(DMPLEX_Stratify,dm,0,0,0);CHKERRQ(ierr);
1976   PetscFunctionReturn(0);
1977 }
1978 
1979 #undef __FUNCT__
1980 #define __FUNCT__ "DMPlexGetJoin"
1981 /*@C
1982   DMPlexGetJoin - Get an array for the join of the set of points
1983 
1984   Not Collective
1985 
1986   Input Parameters:
1987 + dm - The DMPlex object
1988 . numPoints - The number of input points for the join
1989 - points - The input points
1990 
1991   Output Parameters:
1992 + numCoveredPoints - The number of points in the join
1993 - coveredPoints - The points in the join
1994 
1995   Level: intermediate
1996 
1997   Note: Currently, this is restricted to a single level join
1998 
1999   Fortran Notes:
2000   Since it returns an array, this routine is only available in Fortran 90, and you must
2001   include petsc.h90 in your code.
2002 
2003   The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array.
2004 
2005 .keywords: mesh
2006 .seealso: DMPlexRestoreJoin(), DMPlexGetMeet()
2007 @*/
2008 PetscErrorCode DMPlexGetJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
2009 {
2010   DM_Plex       *mesh = (DM_Plex*) dm->data;
2011   PetscInt      *join[2];
2012   PetscInt       joinSize, i = 0;
2013   PetscInt       dof, off, p, c, m;
2014   PetscErrorCode ierr;
2015 
2016   PetscFunctionBegin;
2017   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2018   PetscValidPointer(points, 2);
2019   PetscValidPointer(numCoveredPoints, 3);
2020   PetscValidPointer(coveredPoints, 4);
2021   ierr = DMGetWorkArray(dm, mesh->maxSupportSize, PETSC_INT, &join[0]);CHKERRQ(ierr);
2022   ierr = DMGetWorkArray(dm, mesh->maxSupportSize, PETSC_INT, &join[1]);CHKERRQ(ierr);
2023   /* Copy in support of first point */
2024   ierr = PetscSectionGetDof(mesh->supportSection, points[0], &dof);CHKERRQ(ierr);
2025   ierr = PetscSectionGetOffset(mesh->supportSection, points[0], &off);CHKERRQ(ierr);
2026   for (joinSize = 0; joinSize < dof; ++joinSize) {
2027     join[i][joinSize] = mesh->supports[off+joinSize];
2028   }
2029   /* Check each successive support */
2030   for (p = 1; p < numPoints; ++p) {
2031     PetscInt newJoinSize = 0;
2032 
2033     ierr = PetscSectionGetDof(mesh->supportSection, points[p], &dof);CHKERRQ(ierr);
2034     ierr = PetscSectionGetOffset(mesh->supportSection, points[p], &off);CHKERRQ(ierr);
2035     for (c = 0; c < dof; ++c) {
2036       const PetscInt point = mesh->supports[off+c];
2037 
2038       for (m = 0; m < joinSize; ++m) {
2039         if (point == join[i][m]) {
2040           join[1-i][newJoinSize++] = point;
2041           break;
2042         }
2043       }
2044     }
2045     joinSize = newJoinSize;
2046     i        = 1-i;
2047   }
2048   *numCoveredPoints = joinSize;
2049   *coveredPoints    = join[i];
2050   ierr              = DMRestoreWorkArray(dm, mesh->maxSupportSize, PETSC_INT, &join[1-i]);CHKERRQ(ierr);
2051   PetscFunctionReturn(0);
2052 }
2053 
2054 #undef __FUNCT__
2055 #define __FUNCT__ "DMPlexRestoreJoin"
2056 /*@C
2057   DMPlexRestoreJoin - Restore an array for the join of the set of points
2058 
2059   Not Collective
2060 
2061   Input Parameters:
2062 + dm - The DMPlex object
2063 . numPoints - The number of input points for the join
2064 - points - The input points
2065 
2066   Output Parameters:
2067 + numCoveredPoints - The number of points in the join
2068 - coveredPoints - The points in the join
2069 
2070   Fortran Notes:
2071   Since it returns an array, this routine is only available in Fortran 90, and you must
2072   include petsc.h90 in your code.
2073 
2074   The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array.
2075 
2076   Level: intermediate
2077 
2078 .keywords: mesh
2079 .seealso: DMPlexGetJoin(), DMPlexGetFullJoin(), DMPlexGetMeet()
2080 @*/
2081 PetscErrorCode DMPlexRestoreJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
2082 {
2083   PetscErrorCode ierr;
2084 
2085   PetscFunctionBegin;
2086   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2087   if (points) PetscValidIntPointer(points,3);
2088   if (numCoveredPoints) PetscValidIntPointer(numCoveredPoints,4);
2089   PetscValidPointer(coveredPoints, 5);
2090   ierr = DMRestoreWorkArray(dm, 0, PETSC_INT, (void*) coveredPoints);CHKERRQ(ierr);
2091   if (numCoveredPoints) *numCoveredPoints = 0;
2092   PetscFunctionReturn(0);
2093 }
2094 
2095 #undef __FUNCT__
2096 #define __FUNCT__ "DMPlexGetFullJoin"
2097 /*@C
2098   DMPlexGetFullJoin - Get an array for the join of the set of points
2099 
2100   Not Collective
2101 
2102   Input Parameters:
2103 + dm - The DMPlex object
2104 . numPoints - The number of input points for the join
2105 - points - The input points
2106 
2107   Output Parameters:
2108 + numCoveredPoints - The number of points in the join
2109 - coveredPoints - The points in the join
2110 
2111   Fortran Notes:
2112   Since it returns an array, this routine is only available in Fortran 90, and you must
2113   include petsc.h90 in your code.
2114 
2115   The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array.
2116 
2117   Level: intermediate
2118 
2119 .keywords: mesh
2120 .seealso: DMPlexGetJoin(), DMPlexRestoreJoin(), DMPlexGetMeet()
2121 @*/
2122 PetscErrorCode DMPlexGetFullJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
2123 {
2124   DM_Plex       *mesh = (DM_Plex*) dm->data;
2125   PetscInt      *offsets, **closures;
2126   PetscInt      *join[2];
2127   PetscInt       depth = 0, maxSize, joinSize = 0, i = 0;
2128   PetscInt       p, d, c, m, ms;
2129   PetscErrorCode ierr;
2130 
2131   PetscFunctionBegin;
2132   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2133   PetscValidPointer(points, 2);
2134   PetscValidPointer(numCoveredPoints, 3);
2135   PetscValidPointer(coveredPoints, 4);
2136 
2137   ierr    = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
2138   ierr    = PetscCalloc1(numPoints, &closures);CHKERRQ(ierr);
2139   ierr    = DMGetWorkArray(dm, numPoints*(depth+2), PETSC_INT, &offsets);CHKERRQ(ierr);
2140   ms      = mesh->maxSupportSize;
2141   maxSize = (ms > 1) ? ((PetscPowInt(ms,depth+1)-1)/(ms-1)) : depth + 1;
2142   ierr    = DMGetWorkArray(dm, maxSize, PETSC_INT, &join[0]);CHKERRQ(ierr);
2143   ierr    = DMGetWorkArray(dm, maxSize, PETSC_INT, &join[1]);CHKERRQ(ierr);
2144 
2145   for (p = 0; p < numPoints; ++p) {
2146     PetscInt closureSize;
2147 
2148     ierr = DMPlexGetTransitiveClosure(dm, points[p], PETSC_FALSE, &closureSize, &closures[p]);CHKERRQ(ierr);
2149 
2150     offsets[p*(depth+2)+0] = 0;
2151     for (d = 0; d < depth+1; ++d) {
2152       PetscInt pStart, pEnd, i;
2153 
2154       ierr = DMPlexGetDepthStratum(dm, d, &pStart, &pEnd);CHKERRQ(ierr);
2155       for (i = offsets[p*(depth+2)+d]; i < closureSize; ++i) {
2156         if ((pStart > closures[p][i*2]) || (pEnd <= closures[p][i*2])) {
2157           offsets[p*(depth+2)+d+1] = i;
2158           break;
2159         }
2160       }
2161       if (i == closureSize) offsets[p*(depth+2)+d+1] = i;
2162     }
2163     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);
2164   }
2165   for (d = 0; d < depth+1; ++d) {
2166     PetscInt dof;
2167 
2168     /* Copy in support of first point */
2169     dof = offsets[d+1] - offsets[d];
2170     for (joinSize = 0; joinSize < dof; ++joinSize) {
2171       join[i][joinSize] = closures[0][(offsets[d]+joinSize)*2];
2172     }
2173     /* Check each successive cone */
2174     for (p = 1; p < numPoints && joinSize; ++p) {
2175       PetscInt newJoinSize = 0;
2176 
2177       dof = offsets[p*(depth+2)+d+1] - offsets[p*(depth+2)+d];
2178       for (c = 0; c < dof; ++c) {
2179         const PetscInt point = closures[p][(offsets[p*(depth+2)+d]+c)*2];
2180 
2181         for (m = 0; m < joinSize; ++m) {
2182           if (point == join[i][m]) {
2183             join[1-i][newJoinSize++] = point;
2184             break;
2185           }
2186         }
2187       }
2188       joinSize = newJoinSize;
2189       i        = 1-i;
2190     }
2191     if (joinSize) break;
2192   }
2193   *numCoveredPoints = joinSize;
2194   *coveredPoints    = join[i];
2195   for (p = 0; p < numPoints; ++p) {
2196     ierr = DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_FALSE, NULL, &closures[p]);CHKERRQ(ierr);
2197   }
2198   ierr = PetscFree(closures);CHKERRQ(ierr);
2199   ierr = DMRestoreWorkArray(dm, numPoints*(depth+2), PETSC_INT, &offsets);CHKERRQ(ierr);
2200   ierr = DMRestoreWorkArray(dm, mesh->maxSupportSize, PETSC_INT, &join[1-i]);CHKERRQ(ierr);
2201   PetscFunctionReturn(0);
2202 }
2203 
2204 #undef __FUNCT__
2205 #define __FUNCT__ "DMPlexGetMeet"
2206 /*@C
2207   DMPlexGetMeet - Get an array for the meet of the set of points
2208 
2209   Not Collective
2210 
2211   Input Parameters:
2212 + dm - The DMPlex object
2213 . numPoints - The number of input points for the meet
2214 - points - The input points
2215 
2216   Output Parameters:
2217 + numCoveredPoints - The number of points in the meet
2218 - coveredPoints - The points in the meet
2219 
2220   Level: intermediate
2221 
2222   Note: Currently, this is restricted to a single level meet
2223 
2224   Fortran Notes:
2225   Since it returns an array, this routine is only available in Fortran 90, and you must
2226   include petsc.h90 in your code.
2227 
2228   The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array.
2229 
2230 .keywords: mesh
2231 .seealso: DMPlexRestoreMeet(), DMPlexGetJoin()
2232 @*/
2233 PetscErrorCode DMPlexGetMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveringPoints, const PetscInt **coveringPoints)
2234 {
2235   DM_Plex       *mesh = (DM_Plex*) dm->data;
2236   PetscInt      *meet[2];
2237   PetscInt       meetSize, i = 0;
2238   PetscInt       dof, off, p, c, m;
2239   PetscErrorCode ierr;
2240 
2241   PetscFunctionBegin;
2242   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2243   PetscValidPointer(points, 2);
2244   PetscValidPointer(numCoveringPoints, 3);
2245   PetscValidPointer(coveringPoints, 4);
2246   ierr = DMGetWorkArray(dm, mesh->maxConeSize, PETSC_INT, &meet[0]);CHKERRQ(ierr);
2247   ierr = DMGetWorkArray(dm, mesh->maxConeSize, PETSC_INT, &meet[1]);CHKERRQ(ierr);
2248   /* Copy in cone of first point */
2249   ierr = PetscSectionGetDof(mesh->coneSection, points[0], &dof);CHKERRQ(ierr);
2250   ierr = PetscSectionGetOffset(mesh->coneSection, points[0], &off);CHKERRQ(ierr);
2251   for (meetSize = 0; meetSize < dof; ++meetSize) {
2252     meet[i][meetSize] = mesh->cones[off+meetSize];
2253   }
2254   /* Check each successive cone */
2255   for (p = 1; p < numPoints; ++p) {
2256     PetscInt newMeetSize = 0;
2257 
2258     ierr = PetscSectionGetDof(mesh->coneSection, points[p], &dof);CHKERRQ(ierr);
2259     ierr = PetscSectionGetOffset(mesh->coneSection, points[p], &off);CHKERRQ(ierr);
2260     for (c = 0; c < dof; ++c) {
2261       const PetscInt point = mesh->cones[off+c];
2262 
2263       for (m = 0; m < meetSize; ++m) {
2264         if (point == meet[i][m]) {
2265           meet[1-i][newMeetSize++] = point;
2266           break;
2267         }
2268       }
2269     }
2270     meetSize = newMeetSize;
2271     i        = 1-i;
2272   }
2273   *numCoveringPoints = meetSize;
2274   *coveringPoints    = meet[i];
2275   ierr               = DMRestoreWorkArray(dm, mesh->maxConeSize, PETSC_INT, &meet[1-i]);CHKERRQ(ierr);
2276   PetscFunctionReturn(0);
2277 }
2278 
2279 #undef __FUNCT__
2280 #define __FUNCT__ "DMPlexRestoreMeet"
2281 /*@C
2282   DMPlexRestoreMeet - Restore an array for the meet of the set of points
2283 
2284   Not Collective
2285 
2286   Input Parameters:
2287 + dm - The DMPlex object
2288 . numPoints - The number of input points for the meet
2289 - points - The input points
2290 
2291   Output Parameters:
2292 + numCoveredPoints - The number of points in the meet
2293 - coveredPoints - The points in the meet
2294 
2295   Level: intermediate
2296 
2297   Fortran Notes:
2298   Since it returns an array, this routine is only available in Fortran 90, and you must
2299   include petsc.h90 in your code.
2300 
2301   The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array.
2302 
2303 .keywords: mesh
2304 .seealso: DMPlexGetMeet(), DMPlexGetFullMeet(), DMPlexGetJoin()
2305 @*/
2306 PetscErrorCode DMPlexRestoreMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
2307 {
2308   PetscErrorCode ierr;
2309 
2310   PetscFunctionBegin;
2311   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2312   if (points) PetscValidIntPointer(points,3);
2313   if (numCoveredPoints) PetscValidIntPointer(numCoveredPoints,4);
2314   PetscValidPointer(coveredPoints,5);
2315   ierr = DMRestoreWorkArray(dm, 0, PETSC_INT, (void*) coveredPoints);CHKERRQ(ierr);
2316   if (numCoveredPoints) *numCoveredPoints = 0;
2317   PetscFunctionReturn(0);
2318 }
2319 
2320 #undef __FUNCT__
2321 #define __FUNCT__ "DMPlexGetFullMeet"
2322 /*@C
2323   DMPlexGetFullMeet - Get an array for the meet of the set of points
2324 
2325   Not Collective
2326 
2327   Input Parameters:
2328 + dm - The DMPlex object
2329 . numPoints - The number of input points for the meet
2330 - points - The input points
2331 
2332   Output Parameters:
2333 + numCoveredPoints - The number of points in the meet
2334 - coveredPoints - The points in the meet
2335 
2336   Level: intermediate
2337 
2338   Fortran Notes:
2339   Since it returns an array, this routine is only available in Fortran 90, and you must
2340   include petsc.h90 in your code.
2341 
2342   The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array.
2343 
2344 .keywords: mesh
2345 .seealso: DMPlexGetMeet(), DMPlexRestoreMeet(), DMPlexGetJoin()
2346 @*/
2347 PetscErrorCode DMPlexGetFullMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
2348 {
2349   DM_Plex       *mesh = (DM_Plex*) dm->data;
2350   PetscInt      *offsets, **closures;
2351   PetscInt      *meet[2];
2352   PetscInt       height = 0, maxSize, meetSize = 0, i = 0;
2353   PetscInt       p, h, c, m, mc;
2354   PetscErrorCode ierr;
2355 
2356   PetscFunctionBegin;
2357   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2358   PetscValidPointer(points, 2);
2359   PetscValidPointer(numCoveredPoints, 3);
2360   PetscValidPointer(coveredPoints, 4);
2361 
2362   ierr    = DMPlexGetDepth(dm, &height);CHKERRQ(ierr);
2363   ierr    = PetscMalloc1(numPoints, &closures);CHKERRQ(ierr);
2364   ierr    = DMGetWorkArray(dm, numPoints*(height+2), PETSC_INT, &offsets);CHKERRQ(ierr);
2365   mc      = mesh->maxConeSize;
2366   maxSize = (mc > 1) ? ((PetscPowInt(mc,height+1)-1)/(mc-1)) : height + 1;
2367   ierr    = DMGetWorkArray(dm, maxSize, PETSC_INT, &meet[0]);CHKERRQ(ierr);
2368   ierr    = DMGetWorkArray(dm, maxSize, PETSC_INT, &meet[1]);CHKERRQ(ierr);
2369 
2370   for (p = 0; p < numPoints; ++p) {
2371     PetscInt closureSize;
2372 
2373     ierr = DMPlexGetTransitiveClosure(dm, points[p], PETSC_TRUE, &closureSize, &closures[p]);CHKERRQ(ierr);
2374 
2375     offsets[p*(height+2)+0] = 0;
2376     for (h = 0; h < height+1; ++h) {
2377       PetscInt pStart, pEnd, i;
2378 
2379       ierr = DMPlexGetHeightStratum(dm, h, &pStart, &pEnd);CHKERRQ(ierr);
2380       for (i = offsets[p*(height+2)+h]; i < closureSize; ++i) {
2381         if ((pStart > closures[p][i*2]) || (pEnd <= closures[p][i*2])) {
2382           offsets[p*(height+2)+h+1] = i;
2383           break;
2384         }
2385       }
2386       if (i == closureSize) offsets[p*(height+2)+h+1] = i;
2387     }
2388     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);
2389   }
2390   for (h = 0; h < height+1; ++h) {
2391     PetscInt dof;
2392 
2393     /* Copy in cone of first point */
2394     dof = offsets[h+1] - offsets[h];
2395     for (meetSize = 0; meetSize < dof; ++meetSize) {
2396       meet[i][meetSize] = closures[0][(offsets[h]+meetSize)*2];
2397     }
2398     /* Check each successive cone */
2399     for (p = 1; p < numPoints && meetSize; ++p) {
2400       PetscInt newMeetSize = 0;
2401 
2402       dof = offsets[p*(height+2)+h+1] - offsets[p*(height+2)+h];
2403       for (c = 0; c < dof; ++c) {
2404         const PetscInt point = closures[p][(offsets[p*(height+2)+h]+c)*2];
2405 
2406         for (m = 0; m < meetSize; ++m) {
2407           if (point == meet[i][m]) {
2408             meet[1-i][newMeetSize++] = point;
2409             break;
2410           }
2411         }
2412       }
2413       meetSize = newMeetSize;
2414       i        = 1-i;
2415     }
2416     if (meetSize) break;
2417   }
2418   *numCoveredPoints = meetSize;
2419   *coveredPoints    = meet[i];
2420   for (p = 0; p < numPoints; ++p) {
2421     ierr = DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_TRUE, NULL, &closures[p]);CHKERRQ(ierr);
2422   }
2423   ierr = PetscFree(closures);CHKERRQ(ierr);
2424   ierr = DMRestoreWorkArray(dm, numPoints*(height+2), PETSC_INT, &offsets);CHKERRQ(ierr);
2425   ierr = DMRestoreWorkArray(dm, mesh->maxConeSize, PETSC_INT, &meet[1-i]);CHKERRQ(ierr);
2426   PetscFunctionReturn(0);
2427 }
2428 
2429 #undef __FUNCT__
2430 #define __FUNCT__ "DMPlexEqual"
2431 /*@C
2432   DMPlexEqual - Determine if two DMs have the same topology
2433 
2434   Not Collective
2435 
2436   Input Parameters:
2437 + dmA - A DMPlex object
2438 - dmB - A DMPlex object
2439 
2440   Output Parameters:
2441 . equal - PETSC_TRUE if the topologies are identical
2442 
2443   Level: intermediate
2444 
2445   Notes:
2446   We are not solving graph isomorphism, so we do not permutation.
2447 
2448 .keywords: mesh
2449 .seealso: DMPlexGetCone()
2450 @*/
2451 PetscErrorCode DMPlexEqual(DM dmA, DM dmB, PetscBool *equal)
2452 {
2453   PetscInt       depth, depthB, pStart, pEnd, pStartB, pEndB, p;
2454   PetscErrorCode ierr;
2455 
2456   PetscFunctionBegin;
2457   PetscValidHeaderSpecific(dmA, DM_CLASSID, 1);
2458   PetscValidHeaderSpecific(dmB, DM_CLASSID, 2);
2459   PetscValidPointer(equal, 3);
2460 
2461   *equal = PETSC_FALSE;
2462   ierr = DMPlexGetDepth(dmA, &depth);CHKERRQ(ierr);
2463   ierr = DMPlexGetDepth(dmB, &depthB);CHKERRQ(ierr);
2464   if (depth != depthB) PetscFunctionReturn(0);
2465   ierr = DMPlexGetChart(dmA, &pStart,  &pEnd);CHKERRQ(ierr);
2466   ierr = DMPlexGetChart(dmB, &pStartB, &pEndB);CHKERRQ(ierr);
2467   if ((pStart != pStartB) || (pEnd != pEndB)) PetscFunctionReturn(0);
2468   for (p = pStart; p < pEnd; ++p) {
2469     const PetscInt *cone, *coneB, *ornt, *orntB, *support, *supportB;
2470     PetscInt        coneSize, coneSizeB, c, supportSize, supportSizeB, s;
2471 
2472     ierr = DMPlexGetConeSize(dmA, p, &coneSize);CHKERRQ(ierr);
2473     ierr = DMPlexGetCone(dmA, p, &cone);CHKERRQ(ierr);
2474     ierr = DMPlexGetConeOrientation(dmA, p, &ornt);CHKERRQ(ierr);
2475     ierr = DMPlexGetConeSize(dmB, p, &coneSizeB);CHKERRQ(ierr);
2476     ierr = DMPlexGetCone(dmB, p, &coneB);CHKERRQ(ierr);
2477     ierr = DMPlexGetConeOrientation(dmB, p, &orntB);CHKERRQ(ierr);
2478     if (coneSize != coneSizeB) PetscFunctionReturn(0);
2479     for (c = 0; c < coneSize; ++c) {
2480       if (cone[c] != coneB[c]) PetscFunctionReturn(0);
2481       if (ornt[c] != orntB[c]) PetscFunctionReturn(0);
2482     }
2483     ierr = DMPlexGetSupportSize(dmA, p, &supportSize);CHKERRQ(ierr);
2484     ierr = DMPlexGetSupport(dmA, p, &support);CHKERRQ(ierr);
2485     ierr = DMPlexGetSupportSize(dmB, p, &supportSizeB);CHKERRQ(ierr);
2486     ierr = DMPlexGetSupport(dmB, p, &supportB);CHKERRQ(ierr);
2487     if (supportSize != supportSizeB) PetscFunctionReturn(0);
2488     for (s = 0; s < supportSize; ++s) {
2489       if (support[s] != supportB[s]) PetscFunctionReturn(0);
2490     }
2491   }
2492   *equal = PETSC_TRUE;
2493   PetscFunctionReturn(0);
2494 }
2495 
2496 #undef __FUNCT__
2497 #define __FUNCT__ "DMPlexGetNumFaceVertices"
2498 PetscErrorCode DMPlexGetNumFaceVertices(DM dm, PetscInt cellDim, PetscInt numCorners, PetscInt *numFaceVertices)
2499 {
2500   MPI_Comm       comm;
2501   PetscErrorCode ierr;
2502 
2503   PetscFunctionBegin;
2504   ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr);
2505   PetscValidPointer(numFaceVertices,3);
2506   switch (cellDim) {
2507   case 0:
2508     *numFaceVertices = 0;
2509     break;
2510   case 1:
2511     *numFaceVertices = 1;
2512     break;
2513   case 2:
2514     switch (numCorners) {
2515     case 3: /* triangle */
2516       *numFaceVertices = 2; /* Edge has 2 vertices */
2517       break;
2518     case 4: /* quadrilateral */
2519       *numFaceVertices = 2; /* Edge has 2 vertices */
2520       break;
2521     case 6: /* quadratic triangle, tri and quad cohesive Lagrange cells */
2522       *numFaceVertices = 3; /* Edge has 3 vertices */
2523       break;
2524     case 9: /* quadratic quadrilateral, quadratic quad cohesive Lagrange cells */
2525       *numFaceVertices = 3; /* Edge has 3 vertices */
2526       break;
2527     default:
2528       SETERRQ2(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %D for dimension %D", numCorners, cellDim);
2529     }
2530     break;
2531   case 3:
2532     switch (numCorners) {
2533     case 4: /* tetradehdron */
2534       *numFaceVertices = 3; /* Face has 3 vertices */
2535       break;
2536     case 6: /* tet cohesive cells */
2537       *numFaceVertices = 4; /* Face has 4 vertices */
2538       break;
2539     case 8: /* hexahedron */
2540       *numFaceVertices = 4; /* Face has 4 vertices */
2541       break;
2542     case 9: /* tet cohesive Lagrange cells */
2543       *numFaceVertices = 6; /* Face has 6 vertices */
2544       break;
2545     case 10: /* quadratic tetrahedron */
2546       *numFaceVertices = 6; /* Face has 6 vertices */
2547       break;
2548     case 12: /* hex cohesive Lagrange cells */
2549       *numFaceVertices = 6; /* Face has 6 vertices */
2550       break;
2551     case 18: /* quadratic tet cohesive Lagrange cells */
2552       *numFaceVertices = 6; /* Face has 6 vertices */
2553       break;
2554     case 27: /* quadratic hexahedron, quadratic hex cohesive Lagrange cells */
2555       *numFaceVertices = 9; /* Face has 9 vertices */
2556       break;
2557     default:
2558       SETERRQ2(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %D for dimension %D", numCorners, cellDim);
2559     }
2560     break;
2561   default:
2562     SETERRQ1(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid cell dimension %D", cellDim);
2563   }
2564   PetscFunctionReturn(0);
2565 }
2566 
2567 #undef __FUNCT__
2568 #define __FUNCT__ "DMPlexLocalizeCoordinate"
2569 /*@
2570   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.
2571 
2572   Input Parameters:
2573 + dm     - The DM
2574 - in     - The input coordinate point (dim numbers)
2575 
2576   Output Parameter:
2577 . out - The localized coordinate point
2578 
2579   Level: developer
2580 
2581 .seealso: DMPlexLocalizeCoordinates(), DMPlexLocalizeAddCoordinate()
2582 @*/
2583 PetscErrorCode DMPlexLocalizeCoordinate(DM dm, const PetscScalar in[], PetscScalar out[])
2584 {
2585   PetscInt       dim, d;
2586   PetscErrorCode ierr;
2587 
2588   PetscFunctionBegin;
2589   ierr = DMGetCoordinateDim(dm, &dim);CHKERRQ(ierr);
2590   if (!dm->maxCell) {
2591     for (d = 0; d < dim; ++d) out[d] = in[d];
2592   } else {
2593     for (d = 0; d < dim; ++d) {
2594       out[d] = in[d] - dm->L[d]*floor(PetscRealPart(in[d])/dm->L[d]);
2595     }
2596   }
2597   PetscFunctionReturn(0);
2598 }
2599 
2600 #undef __FUNCT__
2601 #define __FUNCT__ "DMPlexLocalizeCoordinate_Internal"
2602 /*
2603   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.
2604 
2605   Input Parameters:
2606 + dm     - The DM
2607 . dim    - The spatial dimension
2608 . anchor - The anchor point, the input point can be no more than maxCell away from it
2609 - in     - The input coordinate point (dim numbers)
2610 
2611   Output Parameter:
2612 . out - The localized coordinate point
2613 
2614   Level: developer
2615 
2616   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
2617 
2618 .seealso: DMPlexLocalizeCoordinates(), DMPlexLocalizeAddCoordinate()
2619 */
2620 PetscErrorCode DMPlexLocalizeCoordinate_Internal(DM dm, PetscInt dim, const PetscScalar anchor[], const PetscScalar in[], PetscScalar out[])
2621 {
2622   PetscInt d;
2623 
2624   PetscFunctionBegin;
2625   if (!dm->maxCell) {
2626     for (d = 0; d < dim; ++d) out[d] = in[d];
2627   } else {
2628     for (d = 0; d < dim; ++d) {
2629       if (PetscAbsScalar(anchor[d] - in[d]) > dm->maxCell[d]) {
2630         out[d] = PetscRealPart(anchor[d]) > PetscRealPart(in[d]) ? dm->L[d] + in[d] : in[d] - dm->L[d];
2631       } else {
2632         out[d] = in[d];
2633       }
2634     }
2635   }
2636   PetscFunctionReturn(0);
2637 }
2638 #undef __FUNCT__
2639 #define __FUNCT__ "DMPlexLocalizeCoordinateReal_Internal"
2640 PetscErrorCode DMPlexLocalizeCoordinateReal_Internal(DM dm, PetscInt dim, const PetscReal anchor[], const PetscReal in[], PetscReal out[])
2641 {
2642   PetscInt d;
2643 
2644   PetscFunctionBegin;
2645   if (!dm->maxCell) {
2646     for (d = 0; d < dim; ++d) out[d] = in[d];
2647   } else {
2648     for (d = 0; d < dim; ++d) {
2649       if (PetscAbsReal(anchor[d] - in[d]) > dm->maxCell[d]) {
2650         out[d] = anchor[d] > in[d] ? dm->L[d] + in[d] : in[d] - dm->L[d];
2651       } else {
2652         out[d] = in[d];
2653       }
2654     }
2655   }
2656   PetscFunctionReturn(0);
2657 }
2658 
2659 #undef __FUNCT__
2660 #define __FUNCT__ "DMPlexLocalizeAddCoordinate_Internal"
2661 /*
2662   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.
2663 
2664   Input Parameters:
2665 + dm     - The DM
2666 . dim    - The spatial dimension
2667 . anchor - The anchor point, the input point can be no more than maxCell away from it
2668 . in     - The input coordinate delta (dim numbers)
2669 - out    - The input coordinate point (dim numbers)
2670 
2671   Output Parameter:
2672 . out    - The localized coordinate in + out
2673 
2674   Level: developer
2675 
2676   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
2677 
2678 .seealso: DMPlexLocalizeCoordinates(), DMPlexLocalizeCoordinate()
2679 */
2680 PetscErrorCode DMPlexLocalizeAddCoordinate_Internal(DM dm, PetscInt dim, const PetscScalar anchor[], const PetscScalar in[], PetscScalar out[])
2681 {
2682   PetscInt d;
2683 
2684   PetscFunctionBegin;
2685   if (!dm->maxCell) {
2686     for (d = 0; d < dim; ++d) out[d] += in[d];
2687   } else {
2688     for (d = 0; d < dim; ++d) {
2689       if (PetscAbsScalar(anchor[d] - in[d]) > dm->maxCell[d]) {
2690         out[d] += PetscRealPart(anchor[d]) > PetscRealPart(in[d]) ? dm->L[d] + in[d] : in[d] - dm->L[d];
2691       } else {
2692         out[d] += in[d];
2693       }
2694     }
2695   }
2696   PetscFunctionReturn(0);
2697 }
2698 
2699 #undef __FUNCT__
2700 #define __FUNCT__ "DMPlexLocalizeCoordinates"
2701 /*@
2702   DMPlexLocalizeCoordinates - If a mesh is periodic, create local coordinates for each cell
2703 
2704   Input Parameter:
2705 . dm - The DM
2706 
2707   Level: developer
2708 
2709 .seealso: DMPlexLocalizeCoordinate(), DMPlexLocalizeAddCoordinate()
2710 @*/
2711 PetscErrorCode DMPlexLocalizeCoordinates(DM dm)
2712 {
2713   PetscSection   coordSection, cSection;
2714   Vec            coordinates,  cVec;
2715   PetscScalar   *coords, *coords2, *anchor;
2716   PetscInt       Nc, cStart, cEnd, c, vStart, vEnd, v, dof, d, off, off2, bs, coordSize;
2717   PetscErrorCode ierr;
2718 
2719   PetscFunctionBegin;
2720   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2721   if (!dm->maxCell) PetscFunctionReturn(0);
2722   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
2723   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
2724   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
2725   ierr = DMGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
2726   ierr = PetscSectionCreate(PetscObjectComm((PetscObject) dm), &cSection);CHKERRQ(ierr);
2727   ierr = PetscSectionSetNumFields(cSection, 1);CHKERRQ(ierr);
2728   ierr = PetscSectionGetFieldComponents(coordSection, 0, &Nc);CHKERRQ(ierr);
2729   ierr = PetscSectionSetFieldComponents(cSection, 0, Nc);CHKERRQ(ierr);
2730   ierr = PetscSectionSetChart(cSection, cStart, vEnd);CHKERRQ(ierr);
2731   for (v = vStart; v < vEnd; ++v) {
2732     ierr = PetscSectionGetDof(coordSection, v, &dof);CHKERRQ(ierr);
2733     ierr = PetscSectionSetDof(cSection,     v,  dof);CHKERRQ(ierr);
2734     ierr = PetscSectionSetFieldDof(cSection, v, 0, dof);CHKERRQ(ierr);
2735   }
2736   for (c = cStart; c < cEnd; ++c) {
2737     ierr = DMPlexVecGetClosure(dm, coordSection, coordinates, c, &dof, NULL);CHKERRQ(ierr);
2738     ierr = PetscSectionSetDof(cSection, c, dof);CHKERRQ(ierr);
2739     ierr = PetscSectionSetFieldDof(cSection, c, 0, dof);CHKERRQ(ierr);
2740   }
2741   ierr = PetscSectionSetUp(cSection);CHKERRQ(ierr);
2742   ierr = PetscSectionGetStorageSize(cSection, &coordSize);CHKERRQ(ierr);
2743   ierr = VecCreate(PetscObjectComm((PetscObject) dm), &cVec);CHKERRQ(ierr);
2744   ierr = PetscObjectSetName((PetscObject)cVec,"coordinates");CHKERRQ(ierr);
2745   ierr = VecGetBlockSize(coordinates, &bs);CHKERRQ(ierr);
2746   ierr = VecSetBlockSize(cVec,         bs);CHKERRQ(ierr);
2747   ierr = VecSetSizes(cVec, coordSize, PETSC_DETERMINE);CHKERRQ(ierr);
2748   ierr = VecSetType(cVec,VECSTANDARD);CHKERRQ(ierr);
2749   ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
2750   ierr = VecGetArray(cVec,        &coords2);CHKERRQ(ierr);
2751   for (v = vStart; v < vEnd; ++v) {
2752     ierr = PetscSectionGetDof(coordSection, v, &dof);CHKERRQ(ierr);
2753     ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
2754     ierr = PetscSectionGetOffset(cSection,     v, &off2);CHKERRQ(ierr);
2755     for (d = 0; d < dof; ++d) coords2[off2+d] = coords[off+d];
2756   }
2757   ierr = DMGetWorkArray(dm, 3, PETSC_SCALAR, &anchor);CHKERRQ(ierr);
2758   for (c = cStart; c < cEnd; ++c) {
2759     PetscScalar *cellCoords = NULL;
2760     PetscInt     b;
2761 
2762     ierr = DMPlexVecGetClosure(dm, coordSection, coordinates, c, &dof, &cellCoords);CHKERRQ(ierr);
2763     ierr = PetscSectionGetOffset(cSection, c, &off2);CHKERRQ(ierr);
2764     for (b = 0; b < bs; ++b) anchor[b] = cellCoords[b];
2765     for (d = 0; d < dof/bs; ++d) {ierr = DMPlexLocalizeCoordinate_Internal(dm, bs, anchor, &cellCoords[d*bs], &coords2[off2+d*bs]);CHKERRQ(ierr);}
2766     ierr = DMPlexVecRestoreClosure(dm, coordSection, coordinates, c, &dof, &cellCoords);CHKERRQ(ierr);
2767   }
2768   ierr = DMRestoreWorkArray(dm, 3, PETSC_SCALAR, &anchor);CHKERRQ(ierr);
2769   ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
2770   ierr = VecRestoreArray(cVec,        &coords2);CHKERRQ(ierr);
2771   ierr = DMSetCoordinateSection(dm, PETSC_DETERMINE, cSection);CHKERRQ(ierr);
2772   ierr = DMSetCoordinatesLocal(dm, cVec);CHKERRQ(ierr);
2773   ierr = VecDestroy(&cVec);CHKERRQ(ierr);
2774   ierr = PetscSectionDestroy(&cSection);CHKERRQ(ierr);
2775   PetscFunctionReturn(0);
2776 }
2777 
2778 #undef __FUNCT__
2779 #define __FUNCT__ "DMPlexGetDepthLabel"
2780 /*@
2781   DMPlexGetDepthLabel - Get the DMLabel recording the depth of each point
2782 
2783   Not Collective
2784 
2785   Input Parameter:
2786 . dm    - The DMPlex object
2787 
2788   Output Parameter:
2789 . depthLabel - The DMLabel recording point depth
2790 
2791   Level: developer
2792 
2793 .keywords: mesh, points
2794 .seealso: DMPlexGetDepth(), DMPlexGetHeightStratum(), DMPlexGetDepthStratum()
2795 @*/
2796 PetscErrorCode DMPlexGetDepthLabel(DM dm, DMLabel *depthLabel)
2797 {
2798   DM_Plex       *mesh = (DM_Plex*) dm->data;
2799   PetscErrorCode ierr;
2800 
2801   PetscFunctionBegin;
2802   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2803   PetscValidPointer(depthLabel, 2);
2804   if (!mesh->depthLabel) {ierr = DMPlexGetLabel(dm, "depth", &mesh->depthLabel);CHKERRQ(ierr);}
2805   *depthLabel = mesh->depthLabel;
2806   PetscFunctionReturn(0);
2807 }
2808 
2809 #undef __FUNCT__
2810 #define __FUNCT__ "DMPlexGetDepth"
2811 /*@
2812   DMPlexGetDepth - Get the depth of the DAG representing this mesh
2813 
2814   Not Collective
2815 
2816   Input Parameter:
2817 . dm    - The DMPlex object
2818 
2819   Output Parameter:
2820 . depth - The number of strata (breadth first levels) in the DAG
2821 
2822   Level: developer
2823 
2824 .keywords: mesh, points
2825 .seealso: DMPlexGetDepthLabel(), DMPlexGetHeightStratum(), DMPlexGetDepthStratum()
2826 @*/
2827 PetscErrorCode DMPlexGetDepth(DM dm, PetscInt *depth)
2828 {
2829   DMLabel        label;
2830   PetscInt       d = 0;
2831   PetscErrorCode ierr;
2832 
2833   PetscFunctionBegin;
2834   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2835   PetscValidPointer(depth, 2);
2836   ierr = DMPlexGetDepthLabel(dm, &label);CHKERRQ(ierr);
2837   if (label) {ierr = DMLabelGetNumValues(label, &d);CHKERRQ(ierr);}
2838   *depth = d-1;
2839   PetscFunctionReturn(0);
2840 }
2841 
2842 #undef __FUNCT__
2843 #define __FUNCT__ "DMPlexGetDepthStratum"
2844 /*@
2845   DMPlexGetDepthStratum - Get the bounds [start, end) for all points at a certain depth.
2846 
2847   Not Collective
2848 
2849   Input Parameters:
2850 + dm           - The DMPlex object
2851 - stratumValue - The requested depth
2852 
2853   Output Parameters:
2854 + start - The first point at this depth
2855 - end   - One beyond the last point at this depth
2856 
2857   Level: developer
2858 
2859 .keywords: mesh, points
2860 .seealso: DMPlexGetHeightStratum(), DMPlexGetDepth()
2861 @*/
2862 PetscErrorCode DMPlexGetDepthStratum(DM dm, PetscInt stratumValue, PetscInt *start, PetscInt *end)
2863 {
2864   DMLabel        label;
2865   PetscInt       pStart, pEnd;
2866   PetscErrorCode ierr;
2867 
2868   PetscFunctionBegin;
2869   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2870   if (start) {PetscValidPointer(start, 3); *start = 0;}
2871   if (end)   {PetscValidPointer(end,   4); *end   = 0;}
2872   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
2873   if (pStart == pEnd) PetscFunctionReturn(0);
2874   if (stratumValue < 0) {
2875     if (start) *start = pStart;
2876     if (end)   *end   = pEnd;
2877     PetscFunctionReturn(0);
2878   }
2879   ierr = DMPlexGetDepthLabel(dm, &label);CHKERRQ(ierr);
2880   if (!label) SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "No label named depth was found");
2881   ierr = DMLabelGetStratumBounds(label, stratumValue, start, end);CHKERRQ(ierr);
2882   PetscFunctionReturn(0);
2883 }
2884 
2885 #undef __FUNCT__
2886 #define __FUNCT__ "DMPlexGetHeightStratum"
2887 /*@
2888   DMPlexGetHeightStratum - Get the bounds [start, end) for all points at a certain height.
2889 
2890   Not Collective
2891 
2892   Input Parameters:
2893 + dm           - The DMPlex object
2894 - stratumValue - The requested height
2895 
2896   Output Parameters:
2897 + start - The first point at this height
2898 - end   - One beyond the last point at this height
2899 
2900   Level: developer
2901 
2902 .keywords: mesh, points
2903 .seealso: DMPlexGetDepthStratum(), DMPlexGetDepth()
2904 @*/
2905 PetscErrorCode DMPlexGetHeightStratum(DM dm, PetscInt stratumValue, PetscInt *start, PetscInt *end)
2906 {
2907   DMLabel        label;
2908   PetscInt       depth, pStart, pEnd;
2909   PetscErrorCode ierr;
2910 
2911   PetscFunctionBegin;
2912   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2913   if (start) {PetscValidPointer(start, 3); *start = 0;}
2914   if (end)   {PetscValidPointer(end,   4); *end   = 0;}
2915   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
2916   if (pStart == pEnd) PetscFunctionReturn(0);
2917   if (stratumValue < 0) {
2918     if (start) *start = pStart;
2919     if (end)   *end   = pEnd;
2920     PetscFunctionReturn(0);
2921   }
2922   ierr = DMPlexGetDepthLabel(dm, &label);CHKERRQ(ierr);
2923   if (!label) SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "No label named depth was found");CHKERRQ(ierr);
2924   ierr = DMLabelGetNumValues(label, &depth);CHKERRQ(ierr);
2925   ierr = DMLabelGetStratumBounds(label, depth-1-stratumValue, start, end);CHKERRQ(ierr);
2926   PetscFunctionReturn(0);
2927 }
2928 
2929 #undef __FUNCT__
2930 #define __FUNCT__ "DMPlexCreateSectionInitial"
2931 /* Set the number of dof on each point and separate by fields */
2932 PetscErrorCode DMPlexCreateSectionInitial(DM dm, PetscInt dim, PetscInt numFields,const PetscInt numComp[],const PetscInt numDof[], PetscSection *section)
2933 {
2934   PetscInt      *pMax;
2935   PetscInt       depth, pStart = 0, pEnd = 0;
2936   PetscInt       Nf, p, d, dep, f;
2937   PetscBool     *isFE;
2938   PetscErrorCode ierr;
2939 
2940   PetscFunctionBegin;
2941   ierr = PetscMalloc1(numFields, &isFE);CHKERRQ(ierr);
2942   ierr = DMGetNumFields(dm, &Nf);CHKERRQ(ierr);
2943   for (f = 0; f < numFields; ++f) {
2944     PetscObject  obj;
2945     PetscClassId id;
2946 
2947     isFE[f] = PETSC_FALSE;
2948     if (f >= Nf) continue;
2949     ierr = DMGetField(dm, f, &obj);CHKERRQ(ierr);
2950     ierr = PetscObjectGetClassId(obj, &id);CHKERRQ(ierr);
2951     if (id == PETSCFE_CLASSID)      {isFE[f] = PETSC_TRUE;}
2952     else if (id == PETSCFV_CLASSID) {isFE[f] = PETSC_FALSE;}
2953   }
2954   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)dm), section);CHKERRQ(ierr);
2955   if (numFields > 0) {
2956     ierr = PetscSectionSetNumFields(*section, numFields);CHKERRQ(ierr);
2957     if (numComp) {
2958       for (f = 0; f < numFields; ++f) {
2959         ierr = PetscSectionSetFieldComponents(*section, f, numComp[f]);CHKERRQ(ierr);
2960       }
2961     }
2962   }
2963   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
2964   ierr = PetscSectionSetChart(*section, pStart, pEnd);CHKERRQ(ierr);
2965   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
2966   ierr = PetscMalloc1(depth+1,&pMax);CHKERRQ(ierr);
2967   ierr = DMPlexGetHybridBounds(dm, depth >= 0 ? &pMax[depth] : NULL, depth>1 ? &pMax[depth-1] : NULL, depth>2 ? &pMax[1] : NULL, &pMax[0]);CHKERRQ(ierr);
2968   for (dep = 0; dep <= depth; ++dep) {
2969     d    = dim == depth ? dep : (!dep ? 0 : dim);
2970     ierr = DMPlexGetDepthStratum(dm, dep, &pStart, &pEnd);CHKERRQ(ierr);
2971     pMax[dep] = pMax[dep] < 0 ? pEnd : pMax[dep];
2972     for (p = pStart; p < pEnd; ++p) {
2973       PetscInt tot = 0;
2974 
2975       for (f = 0; f < numFields; ++f) {
2976         if (isFE[f] && p >= pMax[dep]) continue;
2977         ierr = PetscSectionSetFieldDof(*section, p, f, numDof[f*(dim+1)+d]);CHKERRQ(ierr);
2978         tot += numDof[f*(dim+1)+d];
2979       }
2980       ierr = PetscSectionSetDof(*section, p, tot);CHKERRQ(ierr);
2981     }
2982   }
2983   ierr = PetscFree(pMax);CHKERRQ(ierr);
2984   ierr = PetscFree(isFE);CHKERRQ(ierr);
2985   PetscFunctionReturn(0);
2986 }
2987 
2988 #undef __FUNCT__
2989 #define __FUNCT__ "DMPlexCreateSectionBCDof"
2990 /* Set the number of dof on each point and separate by fields
2991    If bcComps is NULL or the IS is NULL, constrain every dof on the point
2992 */
2993 PetscErrorCode DMPlexCreateSectionBCDof(DM dm, PetscInt numBC, const PetscInt bcField[], const IS bcComps[], const IS bcPoints[], PetscSection section)
2994 {
2995   PetscInt       numFields;
2996   PetscInt       bc;
2997   PetscSection   aSec;
2998   PetscErrorCode ierr;
2999 
3000   PetscFunctionBegin;
3001   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
3002   for (bc = 0; bc < numBC; ++bc) {
3003     PetscInt        field = 0;
3004     const PetscInt *comp;
3005     const PetscInt *idx;
3006     PetscInt        Nc = -1, n, i;
3007 
3008     if (numFields) field = bcField[bc];
3009     if (bcComps && bcComps[bc]) {ierr = ISGetLocalSize(bcComps[bc], &Nc);CHKERRQ(ierr);}
3010     if (bcComps && bcComps[bc]) {ierr = ISGetIndices(bcComps[bc], &comp);CHKERRQ(ierr);}
3011     ierr = ISGetLocalSize(bcPoints[bc], &n);CHKERRQ(ierr);
3012     ierr = ISGetIndices(bcPoints[bc], &idx);CHKERRQ(ierr);
3013     for (i = 0; i < n; ++i) {
3014       const PetscInt p = idx[i];
3015       PetscInt       numConst;
3016 
3017       if (numFields) {
3018         ierr = PetscSectionGetFieldDof(section, p, field, &numConst);CHKERRQ(ierr);
3019       } else {
3020         ierr = PetscSectionGetDof(section, p, &numConst);CHKERRQ(ierr);
3021       }
3022       /* If Nc < 0, constrain every dof on the point */
3023       if (Nc > 0) numConst = PetscMin(numConst, Nc);
3024       if (numFields) {ierr = PetscSectionAddFieldConstraintDof(section, p, field, numConst);CHKERRQ(ierr);}
3025       ierr = PetscSectionAddConstraintDof(section, p, numConst);CHKERRQ(ierr);
3026     }
3027     ierr = ISRestoreIndices(bcPoints[bc], &idx);CHKERRQ(ierr);
3028     if (bcComps && bcComps[bc]) {ierr = ISRestoreIndices(bcComps[bc], &comp);CHKERRQ(ierr);}
3029   }
3030   ierr = DMPlexGetAnchors(dm, &aSec, NULL);CHKERRQ(ierr);
3031   if (aSec) {
3032     PetscInt aStart, aEnd, a;
3033 
3034     ierr = PetscSectionGetChart(aSec, &aStart, &aEnd);CHKERRQ(ierr);
3035     for (a = aStart; a < aEnd; a++) {
3036       PetscInt dof, f;
3037 
3038       ierr = PetscSectionGetDof(aSec, a, &dof);CHKERRQ(ierr);
3039       if (dof) {
3040         /* if there are point-to-point constraints, then all dofs are constrained */
3041         ierr = PetscSectionGetDof(section, a, &dof);CHKERRQ(ierr);
3042         ierr = PetscSectionSetConstraintDof(section, a, dof);CHKERRQ(ierr);
3043         for (f = 0; f < numFields; f++) {
3044           ierr = PetscSectionGetFieldDof(section, a, f, &dof);CHKERRQ(ierr);
3045           ierr = PetscSectionSetFieldConstraintDof(section, a, f, dof);CHKERRQ(ierr);
3046         }
3047       }
3048     }
3049   }
3050   PetscFunctionReturn(0);
3051 }
3052 
3053 #undef __FUNCT__
3054 #define __FUNCT__ "DMPlexCreateSectionBCIndicesField"
3055 /* Set the constrained field indices on each point
3056    If bcComps is NULL or the IS is NULL, constrain every dof on the point
3057 */
3058 PetscErrorCode DMPlexCreateSectionBCIndicesField(DM dm, PetscInt numBC,const PetscInt bcField[], const IS bcComps[], const IS bcPoints[], PetscSection section)
3059 {
3060   PetscSection   aSec;
3061   PetscInt      *indices;
3062   PetscInt       numFields, maxDof, pStart, pEnd, p, bc, f, d;
3063   PetscErrorCode ierr;
3064 
3065   PetscFunctionBegin;
3066   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
3067   if (!numFields) PetscFunctionReturn(0);
3068   /* Initialize all field indices to -1 */
3069   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
3070   ierr = PetscSectionGetMaxDof(section, &maxDof);CHKERRQ(ierr);
3071   ierr = PetscMalloc1(maxDof, &indices);CHKERRQ(ierr);
3072   for (d = 0; d < maxDof; ++d) indices[d] = -1;
3073   for (p = pStart; p < pEnd; ++p) for (f = 0; f < numFields; ++f) {ierr = PetscSectionSetFieldConstraintIndices(section, p, f, indices);CHKERRQ(ierr);}
3074   /* Handle BC constraints */
3075   for (bc = 0; bc < numBC; ++bc) {
3076     const PetscInt  field = bcField[bc];
3077     const PetscInt *comp, *idx;
3078     PetscInt        Nc = -1, n, i;
3079 
3080     if (bcComps && bcComps[bc]) {ierr = ISGetLocalSize(bcComps[bc], &Nc);CHKERRQ(ierr);}
3081     if (bcComps && bcComps[bc]) {ierr = ISGetIndices(bcComps[bc], &comp);CHKERRQ(ierr);}
3082     ierr = ISGetLocalSize(bcPoints[bc], &n);CHKERRQ(ierr);
3083     ierr = ISGetIndices(bcPoints[bc], &idx);CHKERRQ(ierr);
3084     for (i = 0; i < n; ++i) {
3085       const PetscInt  p = idx[i];
3086       const PetscInt *find;
3087       PetscInt        fcdof, c;
3088 
3089       ierr = PetscSectionGetFieldConstraintDof(section, p, field, &fcdof);CHKERRQ(ierr);
3090       if (Nc < 0) {
3091         for (d = 0; d < fcdof; ++d) indices[d] = d;
3092       } else {
3093         ierr = PetscSectionGetFieldConstraintIndices(section, p, field, &find);CHKERRQ(ierr);
3094         for (d = 0; d < fcdof; ++d) {if (find[d] < 0) break; indices[d] = find[d];}
3095         for (c = 0; c < Nc; ++c) indices[d+c] = comp[c];
3096         ierr = PetscSortInt(d+Nc, indices);CHKERRQ(ierr);
3097         for (c = d+Nc; c < fcdof; ++c) indices[c] = -1;
3098       }
3099       ierr = PetscSectionSetFieldConstraintIndices(section, p, field, indices);CHKERRQ(ierr);
3100     }
3101     if (bcComps && bcComps[bc]) {ierr = ISRestoreIndices(bcComps[bc], &comp);CHKERRQ(ierr);}
3102     ierr = ISRestoreIndices(bcPoints[bc], &idx);CHKERRQ(ierr);
3103   }
3104   /* Handle anchors */
3105   ierr = DMPlexGetAnchors(dm, &aSec, NULL);CHKERRQ(ierr);
3106   if (aSec) {
3107     PetscInt aStart, aEnd, a;
3108 
3109     for (d = 0; d < maxDof; ++d) indices[d] = d;
3110     ierr = PetscSectionGetChart(aSec, &aStart, &aEnd);CHKERRQ(ierr);
3111     for (a = aStart; a < aEnd; a++) {
3112       PetscInt dof, fdof, f;
3113 
3114       ierr = PetscSectionGetDof(aSec, a, &dof);CHKERRQ(ierr);
3115       if (dof) {
3116         /* if there are point-to-point constraints, then all dofs are constrained */
3117         for (f = 0; f < numFields; f++) {
3118           ierr = PetscSectionGetFieldDof(section, a, f, &fdof);CHKERRQ(ierr);
3119           ierr = PetscSectionSetFieldConstraintIndices(section, a, f, indices);CHKERRQ(ierr);
3120         }
3121       }
3122     }
3123   }
3124   ierr = PetscFree(indices);CHKERRQ(ierr);
3125   PetscFunctionReturn(0);
3126 }
3127 
3128 #undef __FUNCT__
3129 #define __FUNCT__ "DMPlexCreateSectionBCIndices"
3130 /* Set the constrained indices on each point */
3131 PetscErrorCode DMPlexCreateSectionBCIndices(DM dm, PetscSection section)
3132 {
3133   PetscInt      *indices;
3134   PetscInt       numFields, maxDof, pStart, pEnd, p, f, d;
3135   PetscErrorCode ierr;
3136 
3137   PetscFunctionBegin;
3138   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
3139   ierr = PetscSectionGetMaxDof(section, &maxDof);CHKERRQ(ierr);
3140   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
3141   ierr = PetscMalloc1(maxDof, &indices);CHKERRQ(ierr);
3142   for (d = 0; d < maxDof; ++d) indices[d] = -1;
3143   for (p = pStart; p < pEnd; ++p) {
3144     PetscInt cdof, d;
3145 
3146     ierr = PetscSectionGetConstraintDof(section, p, &cdof);CHKERRQ(ierr);
3147     if (cdof) {
3148       if (numFields) {
3149         PetscInt numConst = 0, foff = 0;
3150 
3151         for (f = 0; f < numFields; ++f) {
3152           const PetscInt *find;
3153           PetscInt        fcdof, fdof;
3154 
3155           ierr = PetscSectionGetFieldDof(section, p, f, &fdof);CHKERRQ(ierr);
3156           ierr = PetscSectionGetFieldConstraintDof(section, p, f, &fcdof);CHKERRQ(ierr);
3157           /* Change constraint numbering from field component to local dof number */
3158           ierr = PetscSectionGetFieldConstraintIndices(section, p, f, &find);CHKERRQ(ierr);
3159           for (d = 0; d < fcdof; ++d) indices[numConst+d] = find[d] + foff;
3160           numConst += fcdof;
3161           foff     += fdof;
3162         }
3163         if (cdof != numConst) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_LIB, "Total number of field constraints %D should be %D", numConst, cdof);
3164       } else {
3165         for (d = 0; d < cdof; ++d) indices[d] = d;
3166       }
3167       ierr = PetscSectionSetConstraintIndices(section, p, indices);CHKERRQ(ierr);
3168     }
3169   }
3170   ierr = PetscFree(indices);CHKERRQ(ierr);
3171   PetscFunctionReturn(0);
3172 }
3173 
3174 #undef __FUNCT__
3175 #define __FUNCT__ "DMPlexCreateSection"
3176 /*@C
3177   DMPlexCreateSection - Create a PetscSection based upon the dof layout specification provided.
3178 
3179   Not Collective
3180 
3181   Input Parameters:
3182 + dm        - The DMPlex object
3183 . dim       - The spatial dimension of the problem
3184 . numFields - The number of fields in the problem
3185 . numComp   - An array of size numFields that holds the number of components for each field
3186 . numDof    - An array of size numFields*(dim+1) which holds the number of dof for each field on a mesh piece of dimension d
3187 . numBC     - The number of boundary conditions
3188 . bcField   - An array of size numBC giving the field number for each boundry condition
3189 . bcComps   - [Optional] An array of size numBC giving an IS holding the field components to which each boundary condition applies
3190 . bcPoints  - An array of size numBC giving an IS holding the Plex points to which each boundary condition applies
3191 - perm      - Optional permutation of the chart, or NULL
3192 
3193   Output Parameter:
3194 . section - The PetscSection object
3195 
3196   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
3197   number of dof for field 0 on each edge.
3198 
3199   The chart permutation is the same one set using PetscSectionSetPermutation()
3200 
3201   Level: developer
3202 
3203   Fortran Notes:
3204   A Fortran 90 version is available as DMPlexCreateSectionF90()
3205 
3206 .keywords: mesh, elements
3207 .seealso: DMPlexCreate(), PetscSectionCreate(), PetscSectionSetPermutation()
3208 @*/
3209 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)
3210 {
3211   PetscSection   aSec;
3212   PetscErrorCode ierr;
3213 
3214   PetscFunctionBegin;
3215   ierr = DMPlexCreateSectionInitial(dm, dim, numFields, numComp, numDof, section);CHKERRQ(ierr);
3216   ierr = DMPlexCreateSectionBCDof(dm, numBC, bcField, bcComps, bcPoints, *section);CHKERRQ(ierr);
3217   if (perm) {ierr = PetscSectionSetPermutation(*section, perm);CHKERRQ(ierr);}
3218   ierr = PetscSectionSetUp(*section);CHKERRQ(ierr);
3219   ierr = DMPlexGetAnchors(dm,&aSec,NULL);CHKERRQ(ierr);
3220   if (numBC || aSec) {
3221     ierr = DMPlexCreateSectionBCIndicesField(dm, numBC, bcField, bcComps, bcPoints, *section);CHKERRQ(ierr);
3222     ierr = DMPlexCreateSectionBCIndices(dm, *section);CHKERRQ(ierr);
3223   }
3224   ierr = PetscSectionViewFromOptions(*section,NULL,"-section_view");CHKERRQ(ierr);
3225   PetscFunctionReturn(0);
3226 }
3227 
3228 #undef __FUNCT__
3229 #define __FUNCT__ "DMCreateCoordinateDM_Plex"
3230 PetscErrorCode DMCreateCoordinateDM_Plex(DM dm, DM *cdm)
3231 {
3232   PetscSection   section;
3233   PetscErrorCode ierr;
3234 
3235   PetscFunctionBegin;
3236   ierr = DMClone(dm, cdm);CHKERRQ(ierr);
3237   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)dm), &section);CHKERRQ(ierr);
3238   ierr = DMSetDefaultSection(*cdm, section);CHKERRQ(ierr);
3239   ierr = PetscSectionDestroy(&section);CHKERRQ(ierr);
3240   PetscFunctionReturn(0);
3241 }
3242 
3243 #undef __FUNCT__
3244 #define __FUNCT__ "DMPlexGetConeSection"
3245 PetscErrorCode DMPlexGetConeSection(DM dm, PetscSection *section)
3246 {
3247   DM_Plex *mesh = (DM_Plex*) dm->data;
3248 
3249   PetscFunctionBegin;
3250   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3251   if (section) *section = mesh->coneSection;
3252   PetscFunctionReturn(0);
3253 }
3254 
3255 #undef __FUNCT__
3256 #define __FUNCT__ "DMPlexGetSupportSection"
3257 PetscErrorCode DMPlexGetSupportSection(DM dm, PetscSection *section)
3258 {
3259   DM_Plex *mesh = (DM_Plex*) dm->data;
3260 
3261   PetscFunctionBegin;
3262   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3263   if (section) *section = mesh->supportSection;
3264   PetscFunctionReturn(0);
3265 }
3266 
3267 #undef __FUNCT__
3268 #define __FUNCT__ "DMPlexGetCones"
3269 PetscErrorCode DMPlexGetCones(DM dm, PetscInt *cones[])
3270 {
3271   DM_Plex *mesh = (DM_Plex*) dm->data;
3272 
3273   PetscFunctionBegin;
3274   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3275   if (cones) *cones = mesh->cones;
3276   PetscFunctionReturn(0);
3277 }
3278 
3279 #undef __FUNCT__
3280 #define __FUNCT__ "DMPlexGetConeOrientations"
3281 PetscErrorCode DMPlexGetConeOrientations(DM dm, PetscInt *coneOrientations[])
3282 {
3283   DM_Plex *mesh = (DM_Plex*) dm->data;
3284 
3285   PetscFunctionBegin;
3286   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3287   if (coneOrientations) *coneOrientations = mesh->coneOrientations;
3288   PetscFunctionReturn(0);
3289 }
3290 
3291 /******************************** FEM Support **********************************/
3292 
3293 #undef __FUNCT__
3294 #define __FUNCT__ "DMPlexVecGetClosure_Depth1_Static"
3295 PETSC_STATIC_INLINE PetscErrorCode DMPlexVecGetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[])
3296 {
3297   PetscScalar    *array, *vArray;
3298   const PetscInt *cone, *coneO;
3299   PetscInt        pStart, pEnd, p, numPoints, size = 0, offset = 0;
3300   PetscErrorCode  ierr;
3301 
3302   PetscFunctionBeginHot;
3303   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
3304   ierr = DMPlexGetConeSize(dm, point, &numPoints);CHKERRQ(ierr);
3305   ierr = DMPlexGetCone(dm, point, &cone);CHKERRQ(ierr);
3306   ierr = DMPlexGetConeOrientation(dm, point, &coneO);CHKERRQ(ierr);
3307   if (!values || !*values) {
3308     if ((point >= pStart) && (point < pEnd)) {
3309       PetscInt dof;
3310 
3311       ierr = PetscSectionGetDof(section, point, &dof);CHKERRQ(ierr);
3312       size += dof;
3313     }
3314     for (p = 0; p < numPoints; ++p) {
3315       const PetscInt cp = cone[p];
3316       PetscInt       dof;
3317 
3318       if ((cp < pStart) || (cp >= pEnd)) continue;
3319       ierr = PetscSectionGetDof(section, cp, &dof);CHKERRQ(ierr);
3320       size += dof;
3321     }
3322     if (!values) {
3323       if (csize) *csize = size;
3324       PetscFunctionReturn(0);
3325     }
3326     ierr = DMGetWorkArray(dm, size, PETSC_SCALAR, &array);CHKERRQ(ierr);
3327   } else {
3328     array = *values;
3329   }
3330   size = 0;
3331   ierr = VecGetArray(v, &vArray);CHKERRQ(ierr);
3332   if ((point >= pStart) && (point < pEnd)) {
3333     PetscInt     dof, off, d;
3334     PetscScalar *varr;
3335 
3336     ierr = PetscSectionGetDof(section, point, &dof);CHKERRQ(ierr);
3337     ierr = PetscSectionGetOffset(section, point, &off);CHKERRQ(ierr);
3338     varr = &vArray[off];
3339     for (d = 0; d < dof; ++d, ++offset) {
3340       array[offset] = varr[d];
3341     }
3342     size += dof;
3343   }
3344   for (p = 0; p < numPoints; ++p) {
3345     const PetscInt cp = cone[p];
3346     PetscInt       o  = coneO[p];
3347     PetscInt       dof, off, d;
3348     PetscScalar   *varr;
3349 
3350     if ((cp < pStart) || (cp >= pEnd)) continue;
3351     ierr = PetscSectionGetDof(section, cp, &dof);CHKERRQ(ierr);
3352     ierr = PetscSectionGetOffset(section, cp, &off);CHKERRQ(ierr);
3353     varr = &vArray[off];
3354     if (o >= 0) {
3355       for (d = 0; d < dof; ++d, ++offset) {
3356         array[offset] = varr[d];
3357       }
3358     } else {
3359       for (d = dof-1; d >= 0; --d, ++offset) {
3360         array[offset] = varr[d];
3361       }
3362     }
3363     size += dof;
3364   }
3365   ierr = VecRestoreArray(v, &vArray);CHKERRQ(ierr);
3366   if (!*values) {
3367     if (csize) *csize = size;
3368     *values = array;
3369   } else {
3370     if (size > *csize) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %d < actual size %d", *csize, size);
3371     *csize = size;
3372   }
3373   PetscFunctionReturn(0);
3374 }
3375 
3376 #undef __FUNCT__
3377 #define __FUNCT__ "DMPlexVecGetClosure_Static"
3378 PETSC_STATIC_INLINE PetscErrorCode DMPlexVecGetClosure_Static(PetscSection section, PetscInt numPoints, const PetscInt points[], const PetscScalar vArray[], PetscInt *size, PetscScalar array[])
3379 {
3380   PetscInt       offset = 0, p;
3381   PetscErrorCode ierr;
3382 
3383   PetscFunctionBeginHot;
3384   *size = 0;
3385   for (p = 0; p < numPoints*2; p += 2) {
3386     const PetscInt point = points[p];
3387     const PetscInt o     = points[p+1];
3388     PetscInt       dof, off, d;
3389     const PetscScalar *varr;
3390 
3391     ierr = PetscSectionGetDof(section, point, &dof);CHKERRQ(ierr);
3392     ierr = PetscSectionGetOffset(section, point, &off);CHKERRQ(ierr);
3393     varr = &vArray[off];
3394     if (o >= 0) {
3395       for (d = 0; d < dof; ++d, ++offset)    array[offset] = varr[d];
3396     } else {
3397       for (d = dof-1; d >= 0; --d, ++offset) array[offset] = varr[d];
3398     }
3399   }
3400   *size = offset;
3401   PetscFunctionReturn(0);
3402 }
3403 
3404 #undef __FUNCT__
3405 #define __FUNCT__ "DMPlexVecGetClosure_Fields_Static"
3406 PETSC_STATIC_INLINE PetscErrorCode DMPlexVecGetClosure_Fields_Static(PetscSection section, PetscInt numPoints, const PetscInt points[], PetscInt numFields, const PetscScalar vArray[], PetscInt *size, PetscScalar array[])
3407 {
3408   PetscInt       offset = 0, f;
3409   PetscErrorCode ierr;
3410 
3411   PetscFunctionBeginHot;
3412   *size = 0;
3413   for (f = 0; f < numFields; ++f) {
3414     PetscInt fcomp, p;
3415 
3416     ierr = PetscSectionGetFieldComponents(section, f, &fcomp);CHKERRQ(ierr);
3417     for (p = 0; p < numPoints*2; p += 2) {
3418       const PetscInt point = points[p];
3419       const PetscInt o     = points[p+1];
3420       PetscInt       fdof, foff, d, c;
3421       const PetscScalar *varr;
3422 
3423       ierr = PetscSectionGetFieldDof(section, point, f, &fdof);CHKERRQ(ierr);
3424       ierr = PetscSectionGetFieldOffset(section, point, f, &foff);CHKERRQ(ierr);
3425       varr = &vArray[foff];
3426       if (o >= 0) {
3427         for (d = 0; d < fdof; ++d, ++offset) array[offset] = varr[d];
3428       } else {
3429         for (d = fdof/fcomp-1; d >= 0; --d) {
3430           for (c = 0; c < fcomp; ++c, ++offset) {
3431             array[offset] = varr[d*fcomp+c];
3432           }
3433         }
3434       }
3435     }
3436   }
3437   *size = offset;
3438   PetscFunctionReturn(0);
3439 }
3440 
3441 #undef __FUNCT__
3442 #define __FUNCT__ "DMPlexVecGetClosure"
3443 /*@C
3444   DMPlexVecGetClosure - Get an array of the values on the closure of 'point'
3445 
3446   Not collective
3447 
3448   Input Parameters:
3449 + dm - The DM
3450 . section - The section describing the layout in v, or NULL to use the default section
3451 . v - The local vector
3452 - point - The sieve point in the DM
3453 
3454   Output Parameters:
3455 + csize - The number of values in the closure, or NULL
3456 - values - The array of values, which is a borrowed array and should not be freed
3457 
3458   Fortran Notes:
3459   Since it returns an array, this routine is only available in Fortran 90, and you must
3460   include petsc.h90 in your code.
3461 
3462   The csize argument is not present in the Fortran 90 binding since it is internal to the array.
3463 
3464   Level: intermediate
3465 
3466 .seealso DMPlexVecRestoreClosure(), DMPlexVecSetClosure(), DMPlexMatSetClosure()
3467 @*/
3468 PetscErrorCode DMPlexVecGetClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[])
3469 {
3470   PetscSection    clSection;
3471   IS              clPoints;
3472   PetscScalar    *array, *vArray;
3473   PetscInt       *points = NULL;
3474   const PetscInt *clp;
3475   PetscInt        depth, numFields, numPoints, size;
3476   PetscErrorCode  ierr;
3477 
3478   PetscFunctionBeginHot;
3479   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3480   if (!section) {ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);}
3481   PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2);
3482   PetscValidHeaderSpecific(v, VEC_CLASSID, 3);
3483   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3484   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
3485   if (depth == 1 && numFields < 2) {
3486     ierr = DMPlexVecGetClosure_Depth1_Static(dm, section, v, point, csize, values);CHKERRQ(ierr);
3487     PetscFunctionReturn(0);
3488   }
3489   /* Get points */
3490   ierr = PetscSectionGetClosureIndex(section, (PetscObject) dm, &clSection, &clPoints);CHKERRQ(ierr);
3491   if (!clPoints) {
3492     PetscInt pStart, pEnd, p, q;
3493 
3494     ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
3495     ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
3496     /* Compress out points not in the section */
3497     for (p = 0, q = 0; p < numPoints*2; p += 2) {
3498       if ((points[p] >= pStart) && (points[p] < pEnd)) {
3499         points[q*2]   = points[p];
3500         points[q*2+1] = points[p+1];
3501         ++q;
3502       }
3503     }
3504     numPoints = q;
3505   } else {
3506     PetscInt dof, off;
3507 
3508     ierr = PetscSectionGetDof(clSection, point, &dof);CHKERRQ(ierr);
3509     ierr = PetscSectionGetOffset(clSection, point, &off);CHKERRQ(ierr);
3510     ierr = ISGetIndices(clPoints, &clp);CHKERRQ(ierr);
3511     numPoints = dof/2;
3512     points    = (PetscInt *) &clp[off];
3513   }
3514   /* Get array */
3515   if (!values || !*values) {
3516     PetscInt asize = 0, dof, p;
3517 
3518     for (p = 0; p < numPoints*2; p += 2) {
3519       ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
3520       asize += dof;
3521     }
3522     if (!values) {
3523       if (!clPoints) {ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);}
3524       else           {ierr = ISRestoreIndices(clPoints, &clp);CHKERRQ(ierr);}
3525       if (csize) *csize = asize;
3526       PetscFunctionReturn(0);
3527     }
3528     ierr = DMGetWorkArray(dm, asize, PETSC_SCALAR, &array);CHKERRQ(ierr);
3529   } else {
3530     array = *values;
3531   }
3532   ierr = VecGetArray(v, &vArray);CHKERRQ(ierr);
3533   /* Get values */
3534   if (numFields > 0) {ierr = DMPlexVecGetClosure_Fields_Static(section, numPoints, points, numFields, vArray, &size, array);CHKERRQ(ierr);}
3535   else               {ierr = DMPlexVecGetClosure_Static(section, numPoints, points, vArray, &size, array);CHKERRQ(ierr);}
3536   /* Cleanup points */
3537   if (!clPoints) {ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);}
3538   else           {ierr = ISRestoreIndices(clPoints, &clp);CHKERRQ(ierr);}
3539   /* Cleanup array */
3540   ierr = VecRestoreArray(v, &vArray);CHKERRQ(ierr);
3541   if (!*values) {
3542     if (csize) *csize = size;
3543     *values = array;
3544   } else {
3545     if (size > *csize) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %D < actual size %D", *csize, size);
3546     *csize = size;
3547   }
3548   PetscFunctionReturn(0);
3549 }
3550 
3551 #undef __FUNCT__
3552 #define __FUNCT__ "DMPlexVecRestoreClosure"
3553 /*@C
3554   DMPlexVecRestoreClosure - Restore the array of the values on the closure of 'point'
3555 
3556   Not collective
3557 
3558   Input Parameters:
3559 + dm - The DM
3560 . section - The section describing the layout in v, or NULL to use the default section
3561 . v - The local vector
3562 . point - The sieve point in the DM
3563 . csize - The number of values in the closure, or NULL
3564 - values - The array of values, which is a borrowed array and should not be freed
3565 
3566   Fortran Notes:
3567   Since it returns an array, this routine is only available in Fortran 90, and you must
3568   include petsc.h90 in your code.
3569 
3570   The csize argument is not present in the Fortran 90 binding since it is internal to the array.
3571 
3572   Level: intermediate
3573 
3574 .seealso DMPlexVecGetClosure(), DMPlexVecSetClosure(), DMPlexMatSetClosure()
3575 @*/
3576 PetscErrorCode DMPlexVecRestoreClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[])
3577 {
3578   PetscInt       size = 0;
3579   PetscErrorCode ierr;
3580 
3581   PetscFunctionBegin;
3582   /* Should work without recalculating size */
3583   ierr = DMRestoreWorkArray(dm, size, PETSC_SCALAR, (void*) values);CHKERRQ(ierr);
3584   PetscFunctionReturn(0);
3585 }
3586 
3587 PETSC_STATIC_INLINE void add   (PetscScalar *x, PetscScalar y) {*x += y;}
3588 PETSC_STATIC_INLINE void insert(PetscScalar *x, PetscScalar y) {*x  = y;}
3589 
3590 #undef __FUNCT__
3591 #define __FUNCT__ "updatePoint_private"
3592 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[])
3593 {
3594   PetscInt        cdof;   /* The number of constraints on this point */
3595   const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
3596   PetscScalar    *a;
3597   PetscInt        off, cind = 0, k;
3598   PetscErrorCode  ierr;
3599 
3600   PetscFunctionBegin;
3601   ierr = PetscSectionGetConstraintDof(section, point, &cdof);CHKERRQ(ierr);
3602   ierr = PetscSectionGetOffset(section, point, &off);CHKERRQ(ierr);
3603   a    = &array[off];
3604   if (!cdof || setBC) {
3605     if (orientation >= 0) {
3606       for (k = 0; k < dof; ++k) {
3607         fuse(&a[k], values[k]);
3608       }
3609     } else {
3610       for (k = 0; k < dof; ++k) {
3611         fuse(&a[k], values[dof-k-1]);
3612       }
3613     }
3614   } else {
3615     ierr = PetscSectionGetConstraintIndices(section, point, &cdofs);CHKERRQ(ierr);
3616     if (orientation >= 0) {
3617       for (k = 0; k < dof; ++k) {
3618         if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
3619         fuse(&a[k], values[k]);
3620       }
3621     } else {
3622       for (k = 0; k < dof; ++k) {
3623         if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
3624         fuse(&a[k], values[dof-k-1]);
3625       }
3626     }
3627   }
3628   PetscFunctionReturn(0);
3629 }
3630 
3631 #undef __FUNCT__
3632 #define __FUNCT__ "updatePointBC_private"
3633 PETSC_STATIC_INLINE PetscErrorCode updatePointBC_private(PetscSection section, PetscInt point, PetscInt dof, void (*fuse)(PetscScalar*, PetscScalar), PetscInt orientation, const PetscScalar values[], PetscScalar array[])
3634 {
3635   PetscInt        cdof;   /* The number of constraints on this point */
3636   const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
3637   PetscScalar    *a;
3638   PetscInt        off, cind = 0, k;
3639   PetscErrorCode  ierr;
3640 
3641   PetscFunctionBegin;
3642   ierr = PetscSectionGetConstraintDof(section, point, &cdof);CHKERRQ(ierr);
3643   ierr = PetscSectionGetOffset(section, point, &off);CHKERRQ(ierr);
3644   a    = &array[off];
3645   if (cdof) {
3646     ierr = PetscSectionGetConstraintIndices(section, point, &cdofs);CHKERRQ(ierr);
3647     if (orientation >= 0) {
3648       for (k = 0; k < dof; ++k) {
3649         if ((cind < cdof) && (k == cdofs[cind])) {
3650           fuse(&a[k], values[k]);
3651           ++cind;
3652         }
3653       }
3654     } else {
3655       for (k = 0; k < dof; ++k) {
3656         if ((cind < cdof) && (k == cdofs[cind])) {
3657           fuse(&a[k], values[dof-k-1]);
3658           ++cind;
3659         }
3660       }
3661     }
3662   }
3663   PetscFunctionReturn(0);
3664 }
3665 
3666 #undef __FUNCT__
3667 #define __FUNCT__ "updatePointFields_private"
3668 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[])
3669 {
3670   PetscScalar    *a;
3671   PetscInt        fdof, foff, fcdof, foffset = *offset;
3672   const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
3673   PetscInt        cind = 0, k, c;
3674   PetscErrorCode  ierr;
3675 
3676   PetscFunctionBegin;
3677   ierr = PetscSectionGetFieldDof(section, point, f, &fdof);CHKERRQ(ierr);
3678   ierr = PetscSectionGetFieldConstraintDof(section, point, f, &fcdof);CHKERRQ(ierr);
3679   ierr = PetscSectionGetFieldOffset(section, point, f, &foff);CHKERRQ(ierr);
3680   a    = &array[foff];
3681   if (!fcdof || setBC) {
3682     if (o >= 0) {
3683       for (k = 0; k < fdof; ++k) fuse(&a[k], values[foffset+k]);
3684     } else {
3685       for (k = fdof/fcomp-1; k >= 0; --k) {
3686         for (c = 0; c < fcomp; ++c) {
3687           fuse(&a[(fdof/fcomp-1-k)*fcomp+c], values[foffset+k*fcomp+c]);
3688         }
3689       }
3690     }
3691   } else {
3692     ierr = PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);CHKERRQ(ierr);
3693     if (o >= 0) {
3694       for (k = 0; k < fdof; ++k) {
3695         if ((cind < fcdof) && (k == fcdofs[cind])) {++cind; continue;}
3696         fuse(&a[k], values[foffset+k]);
3697       }
3698     } else {
3699       for (k = fdof/fcomp-1; k >= 0; --k) {
3700         for (c = 0; c < fcomp; ++c) {
3701           if ((cind < fcdof) && (k*fcomp+c == fcdofs[cind])) {++cind; continue;}
3702           fuse(&a[(fdof/fcomp-1-k)*fcomp+c], values[foffset+k*fcomp+c]);
3703         }
3704       }
3705     }
3706   }
3707   *offset += fdof;
3708   PetscFunctionReturn(0);
3709 }
3710 
3711 #undef __FUNCT__
3712 #define __FUNCT__ "updatePointFieldsBC_private"
3713 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[])
3714 {
3715   PetscScalar    *a;
3716   PetscInt        fdof, foff, fcdof, foffset = *offset;
3717   const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
3718   PetscInt        cind = 0, k, c;
3719   PetscErrorCode  ierr;
3720 
3721   PetscFunctionBegin;
3722   ierr = PetscSectionGetFieldDof(section, point, f, &fdof);CHKERRQ(ierr);
3723   ierr = PetscSectionGetFieldConstraintDof(section, point, f, &fcdof);CHKERRQ(ierr);
3724   ierr = PetscSectionGetFieldOffset(section, point, f, &foff);CHKERRQ(ierr);
3725   a    = &array[foff];
3726   if (fcdof) {
3727     ierr = PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);CHKERRQ(ierr);
3728     if (o >= 0) {
3729       for (k = 0; k < fdof; ++k) {
3730         if ((cind < fcdof) && (k == fcdofs[cind])) {
3731           fuse(&a[k], values[foffset+k]);
3732           ++cind;
3733         }
3734       }
3735     } else {
3736       for (k = fdof/fcomp-1; k >= 0; --k) {
3737         for (c = 0; c < fcomp; ++c) {
3738           if ((cind < fcdof) && (k*fcomp+c == fcdofs[cind])) {
3739             fuse(&a[(fdof/fcomp-1-k)*fcomp+c], values[foffset+k*fcomp+c]);
3740             ++cind;
3741           }
3742         }
3743       }
3744     }
3745   }
3746   *offset += fdof;
3747   PetscFunctionReturn(0);
3748 }
3749 
3750 #undef __FUNCT__
3751 #define __FUNCT__ "DMPlexVecSetClosure_Static"
3752 PETSC_STATIC_INLINE PetscErrorCode DMPlexVecSetClosure_Static(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode)
3753 {
3754   PetscScalar    *array;
3755   const PetscInt *cone, *coneO;
3756   PetscInt        pStart, pEnd, p, numPoints, off, dof;
3757   PetscErrorCode  ierr;
3758 
3759   PetscFunctionBeginHot;
3760   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
3761   ierr = DMPlexGetConeSize(dm, point, &numPoints);CHKERRQ(ierr);
3762   ierr = DMPlexGetCone(dm, point, &cone);CHKERRQ(ierr);
3763   ierr = DMPlexGetConeOrientation(dm, point, &coneO);CHKERRQ(ierr);
3764   ierr = VecGetArray(v, &array);CHKERRQ(ierr);
3765   for (p = 0, off = 0; p <= numPoints; ++p, off += dof) {
3766     const PetscInt cp = !p ? point : cone[p-1];
3767     const PetscInt o  = !p ? 0     : coneO[p-1];
3768 
3769     if ((cp < pStart) || (cp >= pEnd)) {dof = 0; continue;}
3770     ierr = PetscSectionGetDof(section, cp, &dof);CHKERRQ(ierr);
3771     /* ADD_VALUES */
3772     {
3773       const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
3774       PetscScalar    *a;
3775       PetscInt        cdof, coff, cind = 0, k;
3776 
3777       ierr = PetscSectionGetConstraintDof(section, cp, &cdof);CHKERRQ(ierr);
3778       ierr = PetscSectionGetOffset(section, cp, &coff);CHKERRQ(ierr);
3779       a    = &array[coff];
3780       if (!cdof) {
3781         if (o >= 0) {
3782           for (k = 0; k < dof; ++k) {
3783             a[k] += values[off+k];
3784           }
3785         } else {
3786           for (k = 0; k < dof; ++k) {
3787             a[k] += values[off+dof-k-1];
3788           }
3789         }
3790       } else {
3791         ierr = PetscSectionGetConstraintIndices(section, cp, &cdofs);CHKERRQ(ierr);
3792         if (o >= 0) {
3793           for (k = 0; k < dof; ++k) {
3794             if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
3795             a[k] += values[off+k];
3796           }
3797         } else {
3798           for (k = 0; k < dof; ++k) {
3799             if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
3800             a[k] += values[off+dof-k-1];
3801           }
3802         }
3803       }
3804     }
3805   }
3806   ierr = VecRestoreArray(v, &array);CHKERRQ(ierr);
3807   PetscFunctionReturn(0);
3808 }
3809 
3810 #undef __FUNCT__
3811 #define __FUNCT__ "DMPlexVecSetClosure"
3812 /*@C
3813   DMPlexVecSetClosure - Set an array of the values on the closure of 'point'
3814 
3815   Not collective
3816 
3817   Input Parameters:
3818 + dm - The DM
3819 . section - The section describing the layout in v, or NULL to use the default section
3820 . v - The local vector
3821 . point - The sieve point in the DM
3822 . values - The array of values
3823 - mode - The insert mode, where INSERT_ALL_VALUES and ADD_ALL_VALUES also overwrite boundary conditions
3824 
3825   Fortran Notes:
3826   This routine is only available in Fortran 90, and you must include petsc.h90 in your code.
3827 
3828   Level: intermediate
3829 
3830 .seealso DMPlexVecGetClosure(), DMPlexMatSetClosure()
3831 @*/
3832 PetscErrorCode DMPlexVecSetClosure(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode)
3833 {
3834   PetscSection    clSection;
3835   IS              clPoints;
3836   PetscScalar    *array;
3837   PetscInt       *points = NULL;
3838   const PetscInt *clp;
3839   PetscInt        depth, numFields, numPoints, p;
3840   PetscErrorCode  ierr;
3841 
3842   PetscFunctionBeginHot;
3843   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3844   if (!section) {ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);}
3845   PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2);
3846   PetscValidHeaderSpecific(v, VEC_CLASSID, 3);
3847   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3848   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
3849   if (depth == 1 && numFields < 2 && mode == ADD_VALUES) {
3850     ierr = DMPlexVecSetClosure_Static(dm, section, v, point, values, mode);CHKERRQ(ierr);
3851     PetscFunctionReturn(0);
3852   }
3853   /* Get points */
3854   ierr = PetscSectionGetClosureIndex(section, (PetscObject) dm, &clSection, &clPoints);CHKERRQ(ierr);
3855   if (!clPoints) {
3856     PetscInt pStart, pEnd, q;
3857 
3858     ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
3859     ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
3860     /* Compress out points not in the section */
3861     for (p = 0, q = 0; p < numPoints*2; p += 2) {
3862       if ((points[p] >= pStart) && (points[p] < pEnd)) {
3863         points[q*2]   = points[p];
3864         points[q*2+1] = points[p+1];
3865         ++q;
3866       }
3867     }
3868     numPoints = q;
3869   } else {
3870     PetscInt dof, off;
3871 
3872     ierr = PetscSectionGetDof(clSection, point, &dof);CHKERRQ(ierr);
3873     ierr = PetscSectionGetOffset(clSection, point, &off);CHKERRQ(ierr);
3874     ierr = ISGetIndices(clPoints, &clp);CHKERRQ(ierr);
3875     numPoints = dof/2;
3876     points    = (PetscInt *) &clp[off];
3877   }
3878   /* Get array */
3879   ierr = VecGetArray(v, &array);CHKERRQ(ierr);
3880   /* Get values */
3881   if (numFields > 0) {
3882     PetscInt offset = 0, fcomp, f;
3883     for (f = 0; f < numFields; ++f) {
3884       ierr = PetscSectionGetFieldComponents(section, f, &fcomp);CHKERRQ(ierr);
3885       switch (mode) {
3886       case INSERT_VALUES:
3887         for (p = 0; p < numPoints*2; p += 2) {
3888           const PetscInt point = points[p];
3889           const PetscInt o     = points[p+1];
3890           updatePointFields_private(section, point, o, f, fcomp, insert, PETSC_FALSE, values, &offset, array);
3891         } break;
3892       case INSERT_ALL_VALUES:
3893         for (p = 0; p < numPoints*2; p += 2) {
3894           const PetscInt point = points[p];
3895           const PetscInt o     = points[p+1];
3896           updatePointFields_private(section, point, o, f, fcomp, insert, PETSC_TRUE, values, &offset, array);
3897         } break;
3898       case INSERT_BC_VALUES:
3899         for (p = 0; p < numPoints*2; p += 2) {
3900           const PetscInt point = points[p];
3901           const PetscInt o     = points[p+1];
3902           updatePointFieldsBC_private(section, point, o, f, fcomp, insert, values, &offset, array);
3903         } break;
3904       case ADD_VALUES:
3905         for (p = 0; p < numPoints*2; p += 2) {
3906           const PetscInt point = points[p];
3907           const PetscInt o     = points[p+1];
3908           updatePointFields_private(section, point, o, f, fcomp, add, PETSC_FALSE, values, &offset, array);
3909         } break;
3910       case ADD_ALL_VALUES:
3911         for (p = 0; p < numPoints*2; p += 2) {
3912           const PetscInt point = points[p];
3913           const PetscInt o     = points[p+1];
3914           updatePointFields_private(section, point, o, f, fcomp, add, PETSC_TRUE, values, &offset, array);
3915         } break;
3916       default:
3917         SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode);
3918       }
3919     }
3920   } else {
3921     PetscInt dof, off;
3922 
3923     switch (mode) {
3924     case INSERT_VALUES:
3925       for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) {
3926         PetscInt o = points[p+1];
3927         ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
3928         updatePoint_private(section, points[p], dof, insert, PETSC_FALSE, o, &values[off], array);
3929       } break;
3930     case INSERT_ALL_VALUES:
3931       for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) {
3932         PetscInt o = points[p+1];
3933         ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
3934         updatePoint_private(section, points[p], dof, insert, PETSC_TRUE,  o, &values[off], array);
3935       } break;
3936     case INSERT_BC_VALUES:
3937       for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) {
3938         PetscInt o = points[p+1];
3939         ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
3940         updatePointBC_private(section, points[p], dof, insert,  o, &values[off], array);
3941       } break;
3942     case ADD_VALUES:
3943       for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) {
3944         PetscInt o = points[p+1];
3945         ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
3946         updatePoint_private(section, points[p], dof, add,    PETSC_FALSE, o, &values[off], array);
3947       } break;
3948     case ADD_ALL_VALUES:
3949       for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) {
3950         PetscInt o = points[p+1];
3951         ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
3952         updatePoint_private(section, points[p], dof, add,    PETSC_TRUE,  o, &values[off], array);
3953       } break;
3954     default:
3955       SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode);
3956     }
3957   }
3958   /* Cleanup points */
3959   if (!clPoints) {ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);}
3960   else           {ierr = ISRestoreIndices(clPoints, &clp);CHKERRQ(ierr);}
3961   /* Cleanup array */
3962   ierr = VecRestoreArray(v, &array);CHKERRQ(ierr);
3963   PetscFunctionReturn(0);
3964 }
3965 
3966 #undef __FUNCT__
3967 #define __FUNCT__ "DMPlexVecSetFieldClosure_Internal"
3968 PetscErrorCode DMPlexVecSetFieldClosure_Internal(DM dm, PetscSection section, Vec v, PetscBool fieldActive[], PetscInt point, const PetscScalar values[], InsertMode mode)
3969 {
3970   PetscSection    clSection;
3971   IS              clPoints;
3972   PetscScalar    *array;
3973   PetscInt       *points = NULL;
3974   const PetscInt *clp;
3975   PetscInt        numFields, numPoints, p;
3976   PetscInt        offset = 0, fcomp, f;
3977   PetscErrorCode  ierr;
3978 
3979   PetscFunctionBeginHot;
3980   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3981   if (!section) {ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);}
3982   PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2);
3983   PetscValidHeaderSpecific(v, VEC_CLASSID, 3);
3984   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
3985   /* Get points */
3986   ierr = PetscSectionGetClosureIndex(section, (PetscObject) dm, &clSection, &clPoints);CHKERRQ(ierr);
3987   if (!clPoints) {
3988     PetscInt pStart, pEnd, q;
3989 
3990     ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
3991     ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
3992     /* Compress out points not in the section */
3993     for (p = 0, q = 0; p < numPoints*2; p += 2) {
3994       if ((points[p] >= pStart) && (points[p] < pEnd)) {
3995         points[q*2]   = points[p];
3996         points[q*2+1] = points[p+1];
3997         ++q;
3998       }
3999     }
4000     numPoints = q;
4001   } else {
4002     PetscInt dof, off;
4003 
4004     ierr = PetscSectionGetDof(clSection, point, &dof);CHKERRQ(ierr);
4005     ierr = PetscSectionGetOffset(clSection, point, &off);CHKERRQ(ierr);
4006     ierr = ISGetIndices(clPoints, &clp);CHKERRQ(ierr);
4007     numPoints = dof/2;
4008     points    = (PetscInt *) &clp[off];
4009   }
4010   /* Get array */
4011   ierr = VecGetArray(v, &array);CHKERRQ(ierr);
4012   /* Get values */
4013   for (f = 0; f < numFields; ++f) {
4014     ierr = PetscSectionGetFieldComponents(section, f, &fcomp);CHKERRQ(ierr);
4015     if (!fieldActive[f]) {
4016       for (p = 0; p < numPoints*2; p += 2) {
4017         PetscInt fdof;
4018         ierr = PetscSectionGetFieldDof(section, points[p], f, &fdof);CHKERRQ(ierr);
4019         offset += fdof;
4020       }
4021       continue;
4022     }
4023     switch (mode) {
4024     case INSERT_VALUES:
4025       for (p = 0; p < numPoints*2; p += 2) {
4026         const PetscInt point = points[p];
4027         const PetscInt o     = points[p+1];
4028         updatePointFields_private(section, point, o, f, fcomp, insert, PETSC_FALSE, values, &offset, array);
4029       } break;
4030     case INSERT_ALL_VALUES:
4031       for (p = 0; p < numPoints*2; p += 2) {
4032         const PetscInt point = points[p];
4033         const PetscInt o     = points[p+1];
4034         updatePointFields_private(section, point, o, f, fcomp, insert, PETSC_TRUE, values, &offset, array);
4035         } break;
4036     case INSERT_BC_VALUES:
4037       for (p = 0; p < numPoints*2; p += 2) {
4038         const PetscInt point = points[p];
4039         const PetscInt o     = points[p+1];
4040         updatePointFieldsBC_private(section, point, o, f, fcomp, insert, values, &offset, array);
4041       } break;
4042     case ADD_VALUES:
4043       for (p = 0; p < numPoints*2; p += 2) {
4044         const PetscInt point = points[p];
4045         const PetscInt o     = points[p+1];
4046         updatePointFields_private(section, point, o, f, fcomp, add, PETSC_FALSE, values, &offset, array);
4047       } break;
4048     case ADD_ALL_VALUES:
4049       for (p = 0; p < numPoints*2; p += 2) {
4050         const PetscInt point = points[p];
4051         const PetscInt o     = points[p+1];
4052         updatePointFields_private(section, point, o, f, fcomp, add, PETSC_TRUE, values, &offset, array);
4053       } break;
4054     default:
4055       SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode);
4056     }
4057   }
4058   /* Cleanup points */
4059   if (!clPoints) {ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);}
4060   else           {ierr = ISRestoreIndices(clPoints, &clp);CHKERRQ(ierr);}
4061   /* Cleanup array */
4062   ierr = VecRestoreArray(v, &array);CHKERRQ(ierr);
4063   PetscFunctionReturn(0);
4064 }
4065 
4066 #undef __FUNCT__
4067 #define __FUNCT__ "DMPlexPrintMatSetValues"
4068 PetscErrorCode DMPlexPrintMatSetValues(PetscViewer viewer, Mat A, PetscInt point, PetscInt numRIndices, const PetscInt rindices[], PetscInt numCIndices, const PetscInt cindices[], const PetscScalar values[])
4069 {
4070   PetscMPIInt    rank;
4071   PetscInt       i, j;
4072   PetscErrorCode ierr;
4073 
4074   PetscFunctionBegin;
4075   ierr = MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank);CHKERRQ(ierr);
4076   ierr = PetscViewerASCIIPrintf(viewer, "[%d]mat for sieve point %D\n", rank, point);CHKERRQ(ierr);
4077   for (i = 0; i < numRIndices; i++) {ierr = PetscViewerASCIIPrintf(viewer, "[%d]mat row indices[%D] = %D\n", rank, i, rindices[i]);CHKERRQ(ierr);}
4078   for (i = 0; i < numCIndices; i++) {ierr = PetscViewerASCIIPrintf(viewer, "[%d]mat col indices[%D] = %D\n", rank, i, cindices[i]);CHKERRQ(ierr);}
4079   numCIndices = numCIndices ? numCIndices : numRIndices;
4080   for (i = 0; i < numRIndices; i++) {
4081     ierr = PetscViewerASCIIPrintf(viewer, "[%d]", rank);CHKERRQ(ierr);
4082     for (j = 0; j < numCIndices; j++) {
4083 #if defined(PETSC_USE_COMPLEX)
4084       ierr = PetscViewerASCIIPrintf(viewer, " (%g,%g)", (double)PetscRealPart(values[i*numCIndices+j]), (double)PetscImaginaryPart(values[i*numCIndices+j]));CHKERRQ(ierr);
4085 #else
4086       ierr = PetscViewerASCIIPrintf(viewer, " %g", (double)values[i*numCIndices+j]);CHKERRQ(ierr);
4087 #endif
4088     }
4089     ierr = PetscViewerASCIIPrintf(viewer, "\n");CHKERRQ(ierr);
4090   }
4091   PetscFunctionReturn(0);
4092 }
4093 
4094 #undef __FUNCT__
4095 #define __FUNCT__ "indicesPoint_private"
4096 /* . off - The global offset of this point */
4097 PetscErrorCode indicesPoint_private(PetscSection section, PetscInt point, PetscInt off, PetscInt *loff, PetscBool setBC, PetscInt orientation, PetscInt indices[])
4098 {
4099   PetscInt        dof;    /* The number of unknowns on this point */
4100   PetscInt        cdof;   /* The number of constraints on this point */
4101   const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
4102   PetscInt        cind = 0, k;
4103   PetscErrorCode  ierr;
4104 
4105   PetscFunctionBegin;
4106   ierr = PetscSectionGetDof(section, point, &dof);CHKERRQ(ierr);
4107   ierr = PetscSectionGetConstraintDof(section, point, &cdof);CHKERRQ(ierr);
4108   if (!cdof || setBC) {
4109     if (orientation >= 0) {
4110       for (k = 0; k < dof; ++k) indices[*loff+k] = off+k;
4111     } else {
4112       for (k = 0; k < dof; ++k) indices[*loff+dof-k-1] = off+k;
4113     }
4114   } else {
4115     ierr = PetscSectionGetConstraintIndices(section, point, &cdofs);CHKERRQ(ierr);
4116     if (orientation >= 0) {
4117       for (k = 0; k < dof; ++k) {
4118         if ((cind < cdof) && (k == cdofs[cind])) {
4119           /* Insert check for returning constrained indices */
4120           indices[*loff+k] = -(off+k+1);
4121           ++cind;
4122         } else {
4123           indices[*loff+k] = off+k-cind;
4124         }
4125       }
4126     } else {
4127       for (k = 0; k < dof; ++k) {
4128         if ((cind < cdof) && (k == cdofs[cind])) {
4129           /* Insert check for returning constrained indices */
4130           indices[*loff+dof-k-1] = -(off+k+1);
4131           ++cind;
4132         } else {
4133           indices[*loff+dof-k-1] = off+k-cind;
4134         }
4135       }
4136     }
4137   }
4138   *loff += dof;
4139   PetscFunctionReturn(0);
4140 }
4141 
4142 #undef __FUNCT__
4143 #define __FUNCT__ "indicesPointFields_private"
4144 /* . off - The global offset of this point */
4145 PetscErrorCode indicesPointFields_private(PetscSection section, PetscInt point, PetscInt off, PetscInt foffs[], PetscBool setBC, PetscInt orientation, PetscInt indices[])
4146 {
4147   PetscInt       numFields, foff, f;
4148   PetscErrorCode ierr;
4149 
4150   PetscFunctionBegin;
4151   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
4152   for (f = 0, foff = 0; f < numFields; ++f) {
4153     PetscInt        fdof, fcomp, cfdof;
4154     const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
4155     PetscInt        cind = 0, k, c;
4156 
4157     ierr = PetscSectionGetFieldComponents(section, f, &fcomp);CHKERRQ(ierr);
4158     ierr = PetscSectionGetFieldDof(section, point, f, &fdof);CHKERRQ(ierr);
4159     ierr = PetscSectionGetFieldConstraintDof(section, point, f, &cfdof);CHKERRQ(ierr);
4160     if (!cfdof || setBC) {
4161       if (orientation >= 0) {
4162         for (k = 0; k < fdof; ++k) indices[foffs[f]+k] = off+foff+k;
4163       } else {
4164         for (k = fdof/fcomp-1; k >= 0; --k) {
4165           for (c = 0; c < fcomp; ++c) {
4166             indices[foffs[f]+k*fcomp+c] = off+foff+(fdof/fcomp-1-k)*fcomp+c;
4167           }
4168         }
4169       }
4170     } else {
4171       ierr = PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);CHKERRQ(ierr);
4172       if (orientation >= 0) {
4173         for (k = 0; k < fdof; ++k) {
4174           if ((cind < cfdof) && (k == fcdofs[cind])) {
4175             indices[foffs[f]+k] = -(off+foff+k+1);
4176             ++cind;
4177           } else {
4178             indices[foffs[f]+k] = off+foff+k-cind;
4179           }
4180         }
4181       } else {
4182         for (k = fdof/fcomp-1; k >= 0; --k) {
4183           for (c = 0; c < fcomp; ++c) {
4184             if ((cind < cfdof) && ((fdof/fcomp-1-k)*fcomp+c == fcdofs[cind])) {
4185               indices[foffs[f]+k*fcomp+c] = -(off+foff+(fdof/fcomp-1-k)*fcomp+c+1);
4186               ++cind;
4187             } else {
4188               indices[foffs[f]+k*fcomp+c] = off+foff+(fdof/fcomp-1-k)*fcomp+c-cind;
4189             }
4190           }
4191         }
4192       }
4193     }
4194     foff     += fdof - cfdof;
4195     foffs[f] += fdof;
4196   }
4197   PetscFunctionReturn(0);
4198 }
4199 
4200 #undef __FUNCT__
4201 #define __FUNCT__ "DMPlexAnchorsModifyMat"
4202 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[])
4203 {
4204   Mat             cMat;
4205   PetscSection    aSec, cSec;
4206   IS              aIS;
4207   PetscInt        aStart = -1, aEnd = -1;
4208   const PetscInt  *anchors;
4209   PetscInt        numFields, f, p, q, newP = 0;
4210   PetscInt        newNumPoints = 0, newNumIndices = 0;
4211   PetscInt        *newPoints, *indices, *newIndices;
4212   PetscInt        maxAnchor, maxDof;
4213   PetscInt        newOffsets[32];
4214   PetscInt        *pointMatOffsets[32];
4215   PetscInt        *newPointOffsets[32];
4216   PetscScalar     *pointMat[32];
4217   PetscScalar     *newValues,*tmpValues;
4218   PetscBool       anyConstrained = PETSC_FALSE;
4219   PetscErrorCode  ierr;
4220 
4221   PetscFunctionBegin;
4222   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4223   PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2);
4224   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
4225 
4226   ierr = DMPlexGetAnchors(dm,&aSec,&aIS);CHKERRQ(ierr);
4227   /* if there are point-to-point constraints */
4228   if (aSec) {
4229     ierr = PetscMemzero(newOffsets, 32 * sizeof(PetscInt));CHKERRQ(ierr);
4230     ierr = ISGetIndices(aIS,&anchors);CHKERRQ(ierr);
4231     ierr = PetscSectionGetChart(aSec,&aStart,&aEnd);CHKERRQ(ierr);
4232     /* figure out how many points are going to be in the new element matrix
4233      * (we allow double counting, because it's all just going to be summed
4234      * into the global matrix anyway) */
4235     for (p = 0; p < 2*numPoints; p+=2) {
4236       PetscInt b    = points[p];
4237       PetscInt bDof = 0;
4238 
4239       if (b >= aStart && b < aEnd) {
4240         ierr = PetscSectionGetDof(aSec,b,&bDof);CHKERRQ(ierr);
4241       }
4242       if (bDof) {
4243         /* this point is constrained */
4244         /* it is going to be replaced by its anchors */
4245         PetscInt bOff, q;
4246 
4247         anyConstrained = PETSC_TRUE;
4248         newNumPoints  += bDof;
4249         ierr = PetscSectionGetOffset(aSec,b,&bOff);CHKERRQ(ierr);
4250         for (q = 0; q < bDof; q++) {
4251           PetscInt a = anchors[bOff + q];
4252           PetscInt aDof;
4253 
4254           ierr           = PetscSectionGetDof(section,a,&aDof);CHKERRQ(ierr);
4255           newNumIndices += aDof;
4256           for (f = 0; f < numFields; ++f) {
4257             PetscInt fDof;
4258 
4259             ierr             = PetscSectionGetFieldDof(section, a, f, &fDof);CHKERRQ(ierr);
4260             newOffsets[f+1] += fDof;
4261           }
4262         }
4263       }
4264       else {
4265         /* this point is not constrained */
4266         newNumPoints++;
4267         ierr           = PetscSectionGetDof(section,b,&bDof);CHKERRQ(ierr);
4268         newNumIndices += bDof;
4269         for (f = 0; f < numFields; ++f) {
4270           PetscInt fDof;
4271 
4272           ierr = PetscSectionGetFieldDof(section, b, f, &fDof);CHKERRQ(ierr);
4273           newOffsets[f+1] += fDof;
4274         }
4275       }
4276     }
4277   }
4278   if (!anyConstrained) {
4279     if (outNumPoints)  *outNumPoints  = 0;
4280     if (outNumIndices) *outNumIndices = 0;
4281     if (outPoints)     *outPoints     = NULL;
4282     if (outValues)     *outValues     = NULL;
4283     if (aSec) {ierr = ISRestoreIndices(aIS,&anchors);CHKERRQ(ierr);}
4284     PetscFunctionReturn(0);
4285   }
4286 
4287   for (f = 1; f < numFields; ++f) newOffsets[f+1] += newOffsets[f];
4288 
4289   if (numFields && newOffsets[numFields] != newNumIndices) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid size for closure %D should be %D", newOffsets[numFields], newNumIndices);
4290 
4291   ierr = DMGetDefaultConstraints(dm, &cSec, &cMat);CHKERRQ(ierr);
4292 
4293   /* output arrays */
4294   ierr = DMGetWorkArray(dm,2*newNumPoints,PETSC_INT,&newPoints);CHKERRQ(ierr);
4295   ierr = DMGetWorkArray(dm,newNumIndices*newNumIndices,PETSC_SCALAR,&newValues);CHKERRQ(ierr);
4296 
4297   /* workspaces */
4298   ierr = DMGetWorkArray(dm,newNumIndices*numIndices,PETSC_SCALAR,&tmpValues);CHKERRQ(ierr);
4299   if (numFields) {
4300     for (f = 0; f < numFields; f++) {
4301       ierr = DMGetWorkArray(dm,numPoints+1,PETSC_INT,&pointMatOffsets[f]);CHKERRQ(ierr);
4302       ierr = DMGetWorkArray(dm,numPoints+1,PETSC_INT,&newPointOffsets[f]);CHKERRQ(ierr);
4303     }
4304   }
4305   else {
4306     ierr = DMGetWorkArray(dm,numPoints+1,PETSC_INT,&pointMatOffsets[0]);CHKERRQ(ierr);
4307     ierr = DMGetWorkArray(dm,numPoints,PETSC_INT,&newPointOffsets[0]);CHKERRQ(ierr);
4308   }
4309 
4310   /* get workspaces for the point-to-point matrices */
4311   if (numFields) {
4312     for (p = 0; p < numPoints; p++) {
4313       PetscInt b    = points[2*p];
4314       PetscInt bDof = 0;
4315 
4316       if (b >= aStart && b < aEnd) {
4317         ierr = PetscSectionGetDof(aSec, b, &bDof);CHKERRQ(ierr);
4318       }
4319       if (bDof) {
4320         for (f = 0; f < numFields; f++) {
4321           PetscInt fDof, q, bOff, allFDof = 0;
4322 
4323           ierr = PetscSectionGetFieldDof(section, b, f, &fDof);CHKERRQ(ierr);
4324           ierr = PetscSectionGetOffset(aSec, b, &bOff);CHKERRQ(ierr);
4325           for (q = 0; q < bDof; q++) {
4326             PetscInt a = anchors[bOff + q];
4327             PetscInt aFDof;
4328 
4329             ierr     = PetscSectionGetFieldDof(section, a, f, &aFDof);CHKERRQ(ierr);
4330             allFDof += aFDof;
4331           }
4332           newPointOffsets[f][p+1] = allFDof;
4333           pointMatOffsets[f][p+1] = fDof * allFDof;
4334         }
4335       }
4336       else {
4337         for (f = 0; f < numFields; f++) {
4338           PetscInt fDof;
4339 
4340           ierr = PetscSectionGetFieldDof(section, b, f, &fDof);CHKERRQ(ierr);
4341           newPointOffsets[f][p+1] = fDof;
4342           pointMatOffsets[f][p+1] = 0;
4343         }
4344       }
4345     }
4346     for (f = 0; f < numFields; f++) {
4347       newPointOffsets[f][0] = 0;
4348       pointMatOffsets[f][0] = 0;
4349       for (p = 0; p < numPoints; p++) {
4350         newPointOffsets[f][p+1] += newPointOffsets[f][p];
4351         pointMatOffsets[f][p+1] += pointMatOffsets[f][p];
4352       }
4353       ierr = DMGetWorkArray(dm,pointMatOffsets[f][numPoints],PETSC_SCALAR,&pointMat[f]);CHKERRQ(ierr);
4354     }
4355   }
4356   else {
4357     for (p = 0; p < numPoints; p++) {
4358       PetscInt b    = points[2*p];
4359       PetscInt bDof = 0;
4360 
4361       if (b >= aStart && b < aEnd) {
4362         ierr = PetscSectionGetDof(aSec, b, &bDof);CHKERRQ(ierr);
4363       }
4364       if (bDof) {
4365         PetscInt dof, bOff, q, allDof = 0;
4366 
4367         ierr = PetscSectionGetDof(section, b, &dof);CHKERRQ(ierr);
4368         ierr = PetscSectionGetOffset(aSec, b, &bOff);CHKERRQ(ierr);
4369         for (q = 0; q < bDof; q++) {
4370           PetscInt a = anchors[bOff + q], aDof;
4371 
4372           ierr    = PetscSectionGetDof(section, a, &aDof);CHKERRQ(ierr);
4373           allDof += aDof;
4374         }
4375         newPointOffsets[0][p+1] = allDof;
4376         pointMatOffsets[0][p+1] = dof * allDof;
4377       }
4378       else {
4379         PetscInt dof;
4380 
4381         ierr = PetscSectionGetDof(section, b, &dof);CHKERRQ(ierr);
4382         newPointOffsets[0][p+1] = dof;
4383         pointMatOffsets[0][p+1] = 0;
4384       }
4385     }
4386     newPointOffsets[0][0] = 0;
4387     pointMatOffsets[0][0] = 0;
4388     for (p = 0; p < numPoints; p++) {
4389       newPointOffsets[0][p+1] += newPointOffsets[0][p];
4390       pointMatOffsets[0][p+1] += pointMatOffsets[0][p];
4391     }
4392     ierr = DMGetWorkArray(dm,pointMatOffsets[0][numPoints],PETSC_SCALAR,&pointMat[0]);CHKERRQ(ierr);
4393   }
4394 
4395   /* get the point-to-point matrices; construct newPoints */
4396   ierr = PetscSectionGetMaxDof(aSec, &maxAnchor);CHKERRQ(ierr);
4397   ierr = PetscSectionGetMaxDof(section, &maxDof);CHKERRQ(ierr);
4398   ierr = DMGetWorkArray(dm,maxDof,PETSC_INT,&indices);CHKERRQ(ierr);
4399   ierr = DMGetWorkArray(dm,maxAnchor*maxDof,PETSC_INT,&newIndices);CHKERRQ(ierr);
4400   if (numFields) {
4401     for (p = 0, newP = 0; p < numPoints; p++) {
4402       PetscInt b    = points[2*p];
4403       PetscInt o    = points[2*p+1];
4404       PetscInt bDof = 0;
4405 
4406       if (b >= aStart && b < aEnd) {
4407         ierr = PetscSectionGetDof(aSec, b, &bDof);CHKERRQ(ierr);
4408       }
4409       if (bDof) {
4410         PetscInt fStart[32], fEnd[32], fAnchorStart[32], fAnchorEnd[32], bOff, q;
4411 
4412         fStart[0] = 0;
4413         fEnd[0]   = 0;
4414         for (f = 0; f < numFields; f++) {
4415           PetscInt fDof;
4416 
4417           ierr        = PetscSectionGetFieldDof(cSec, b, f, &fDof);CHKERRQ(ierr);
4418           fStart[f+1] = fStart[f] + fDof;
4419           fEnd[f+1]   = fStart[f+1];
4420         }
4421         ierr = PetscSectionGetOffset(cSec, b, &bOff);CHKERRQ(ierr);
4422         ierr = indicesPointFields_private(cSec, b, bOff, fEnd, PETSC_TRUE, o, indices);CHKERRQ(ierr);
4423 
4424         fAnchorStart[0] = 0;
4425         fAnchorEnd[0]   = 0;
4426         for (f = 0; f < numFields; f++) {
4427           PetscInt fDof = newPointOffsets[f][p + 1] - newPointOffsets[f][p];
4428 
4429           fAnchorStart[f+1] = fAnchorStart[f] + fDof;
4430           fAnchorEnd[f+1]   = fAnchorStart[f + 1];
4431         }
4432         ierr = PetscSectionGetOffset (aSec, b, &bOff);CHKERRQ(ierr);
4433         for (q = 0; q < bDof; q++) {
4434           PetscInt a = anchors[bOff + q], aOff;
4435 
4436           /* we take the orientation of ap into account in the order that we constructed the indices above: the newly added points have no orientation */
4437           newPoints[2*(newP + q)]     = a;
4438           newPoints[2*(newP + q) + 1] = 0;
4439           ierr = PetscSectionGetOffset(section, a, &aOff);CHKERRQ(ierr);
4440           ierr = indicesPointFields_private(section, a, aOff, fAnchorEnd, PETSC_TRUE, 0, newIndices);CHKERRQ(ierr);
4441         }
4442         newP += bDof;
4443 
4444         /* get the point-to-point submatrix */
4445         for (f = 0; f < numFields; f++) {
4446           ierr = MatGetValues(cMat,fEnd[f]-fStart[f],indices + fStart[f],fAnchorEnd[f] - fAnchorStart[f],newIndices + fAnchorStart[f],pointMat[f] + pointMatOffsets[f][p]);CHKERRQ(ierr);
4447         }
4448       }
4449       else {
4450         newPoints[2 * newP]     = b;
4451         newPoints[2 * newP + 1] = o;
4452         newP++;
4453       }
4454     }
4455   } else {
4456     for (p = 0; p < numPoints; p++) {
4457       PetscInt b    = points[2*p];
4458       PetscInt o    = points[2*p+1];
4459       PetscInt bDof = 0;
4460 
4461       if (b >= aStart && b < aEnd) {
4462         ierr = PetscSectionGetDof(aSec, b, &bDof);CHKERRQ(ierr);
4463       }
4464       if (bDof) {
4465         PetscInt bEnd = 0, bAnchorEnd = 0, bOff;
4466 
4467         ierr = PetscSectionGetOffset(cSec, b, &bOff);CHKERRQ(ierr);
4468         ierr = indicesPoint_private(cSec, b, bOff, &bEnd, PETSC_TRUE, o, indices);CHKERRQ(ierr);
4469 
4470         ierr = PetscSectionGetOffset (aSec, b, &bOff);CHKERRQ(ierr);
4471         for (q = 0; q < bDof; q++) {
4472           PetscInt a = anchors[bOff + q], aOff;
4473 
4474           /* we take the orientation of ap into account in the order that we constructed the indices above: the newly added points have no orientation */
4475 
4476           newPoints[2*(newP + q)]     = a;
4477           newPoints[2*(newP + q) + 1] = 0;
4478           ierr = PetscSectionGetOffset(section, a, &aOff);CHKERRQ(ierr);
4479           ierr = indicesPoint_private(section, a, aOff, &bAnchorEnd, PETSC_TRUE, 0, newIndices);CHKERRQ(ierr);
4480         }
4481         newP += bDof;
4482 
4483         /* get the point-to-point submatrix */
4484         ierr = MatGetValues(cMat,bEnd,indices,bAnchorEnd,newIndices,pointMat[0] + pointMatOffsets[0][p]);CHKERRQ(ierr);
4485       }
4486       else {
4487         newPoints[2 * newP]     = b;
4488         newPoints[2 * newP + 1] = o;
4489         newP++;
4490       }
4491     }
4492   }
4493 
4494   ierr = PetscMemzero(tmpValues,newNumIndices*numIndices*sizeof(*tmpValues));CHKERRQ(ierr);
4495   /* multiply constraints on the right */
4496   if (numFields) {
4497     for (f = 0; f < numFields; f++) {
4498       PetscInt oldOff = offsets[f];
4499 
4500       for (p = 0; p < numPoints; p++) {
4501         PetscInt cStart = newPointOffsets[f][p];
4502         PetscInt b      = points[2 * p];
4503         PetscInt c, r, k;
4504         PetscInt dof;
4505 
4506         ierr = PetscSectionGetFieldDof(section,b,f,&dof);CHKERRQ(ierr);
4507         if (pointMatOffsets[f][p] < pointMatOffsets[f][p + 1]) {
4508           PetscInt nCols         = newPointOffsets[f][p+1]-cStart;
4509           const PetscScalar *mat = pointMat[f] + pointMatOffsets[f][p];
4510 
4511           for (r = 0; r < numIndices; r++) {
4512             for (c = 0; c < nCols; c++) {
4513               for (k = 0; k < dof; k++) {
4514                 tmpValues[r * newNumIndices + cStart + c] += mat[k * nCols + c] * values[r * numIndices + oldOff + k];
4515               }
4516             }
4517           }
4518         }
4519         else {
4520           /* copy this column as is */
4521           for (r = 0; r < numIndices; r++) {
4522             for (c = 0; c < dof; c++) {
4523               tmpValues[r * newNumIndices + cStart + c] = values[r * numIndices + oldOff + c];
4524             }
4525           }
4526         }
4527         oldOff += dof;
4528       }
4529     }
4530   }
4531   else {
4532     PetscInt oldOff = 0;
4533     for (p = 0; p < numPoints; p++) {
4534       PetscInt cStart = newPointOffsets[0][p];
4535       PetscInt b      = points[2 * p];
4536       PetscInt c, r, k;
4537       PetscInt dof;
4538 
4539       ierr = PetscSectionGetDof(section,b,&dof);CHKERRQ(ierr);
4540       if (pointMatOffsets[0][p] < pointMatOffsets[0][p + 1]) {
4541         PetscInt nCols         = newPointOffsets[0][p+1]-cStart;
4542         const PetscScalar *mat = pointMat[0] + pointMatOffsets[0][p];
4543 
4544         for (r = 0; r < numIndices; r++) {
4545           for (c = 0; c < nCols; c++) {
4546             for (k = 0; k < dof; k++) {
4547               tmpValues[r * newNumIndices + cStart + c] += mat[k * nCols + c] * values[r * numIndices + oldOff + k];
4548             }
4549           }
4550         }
4551       }
4552       else {
4553         /* copy this column as is */
4554         for (r = 0; r < numIndices; r++) {
4555           for (c = 0; c < dof; c++) {
4556             tmpValues[r * newNumIndices + cStart + c] = values[r * numIndices + oldOff + c];
4557           }
4558         }
4559       }
4560       oldOff += dof;
4561     }
4562   }
4563 
4564   ierr = PetscMemzero(newValues,newNumIndices*newNumIndices*sizeof(*newValues));CHKERRQ(ierr);
4565   /* multiply constraints transpose on the left */
4566   if (numFields) {
4567     for (f = 0; f < numFields; f++) {
4568       PetscInt oldOff = offsets[f];
4569 
4570       for (p = 0; p < numPoints; p++) {
4571         PetscInt rStart = newPointOffsets[f][p];
4572         PetscInt b      = points[2 * p];
4573         PetscInt c, r, k;
4574         PetscInt dof;
4575 
4576         ierr = PetscSectionGetFieldDof(section,b,f,&dof);CHKERRQ(ierr);
4577         if (pointMatOffsets[f][p] < pointMatOffsets[f][p + 1]) {
4578           PetscInt nRows                        = newPointOffsets[f][p+1]-rStart;
4579           const PetscScalar *PETSC_RESTRICT mat = pointMat[f] + pointMatOffsets[f][p];
4580 
4581           for (r = 0; r < nRows; r++) {
4582             for (c = 0; c < newNumIndices; c++) {
4583               for (k = 0; k < dof; k++) {
4584                 newValues[(rStart + r) * newNumIndices + c] += mat[k * nRows + r] * tmpValues[(oldOff + k) * newNumIndices + c];
4585               }
4586             }
4587           }
4588         }
4589         else {
4590           /* copy this row as is */
4591           for (r = 0; r < dof; r++) {
4592             for (c = 0; c < newNumIndices; c++) {
4593               newValues[(rStart + r) * newNumIndices + c] = tmpValues[(oldOff + r) * newNumIndices + c];
4594             }
4595           }
4596         }
4597         oldOff += dof;
4598       }
4599     }
4600   }
4601   else {
4602     PetscInt oldOff = 0;
4603 
4604     for (p = 0; p < numPoints; p++) {
4605       PetscInt rStart = newPointOffsets[0][p];
4606       PetscInt b      = points[2 * p];
4607       PetscInt c, r, k;
4608       PetscInt dof;
4609 
4610       ierr = PetscSectionGetDof(section,b,&dof);CHKERRQ(ierr);
4611       if (pointMatOffsets[0][p] < pointMatOffsets[0][p + 1]) {
4612         PetscInt nRows                        = newPointOffsets[0][p+1]-rStart;
4613         const PetscScalar *PETSC_RESTRICT mat = pointMat[0] + pointMatOffsets[0][p];
4614 
4615         for (r = 0; r < nRows; r++) {
4616           for (c = 0; c < newNumIndices; c++) {
4617             for (k = 0; k < dof; k++) {
4618               newValues[(rStart + r) * newNumIndices + c] += mat[k * nRows + r] * tmpValues[(oldOff + k) * newNumIndices + c];
4619             }
4620           }
4621         }
4622       }
4623       else {
4624         /* copy this row as is */
4625         for (r = 0; r < dof; c++) {
4626           for (c = 0; c < newNumIndices; c++) {
4627             newValues[(rStart + r) * newNumIndices + c] = tmpValues[(oldOff + r) * newNumIndices + c];
4628           }
4629         }
4630       }
4631       oldOff += dof;
4632     }
4633   }
4634 
4635   /* clean up */
4636   ierr = DMRestoreWorkArray(dm,maxDof,PETSC_INT,&indices);CHKERRQ(ierr);
4637   ierr = DMRestoreWorkArray(dm,maxAnchor*maxDof,PETSC_INT,&newIndices);CHKERRQ(ierr);
4638   if (numFields) {
4639     for (f = 0; f < numFields; f++) {
4640       ierr = DMRestoreWorkArray(dm,pointMatOffsets[f][numPoints],PETSC_SCALAR,&pointMat[f]);CHKERRQ(ierr);
4641       ierr = DMRestoreWorkArray(dm,numPoints+1,PETSC_INT,&pointMatOffsets[f]);CHKERRQ(ierr);
4642       ierr = DMRestoreWorkArray(dm,numPoints+1,PETSC_INT,&newPointOffsets[f]);CHKERRQ(ierr);
4643     }
4644   }
4645   else {
4646     ierr = DMRestoreWorkArray(dm,pointMatOffsets[0][numPoints],PETSC_SCALAR,&pointMat[0]);CHKERRQ(ierr);
4647     ierr = DMRestoreWorkArray(dm,numPoints+1,PETSC_INT,&pointMatOffsets[0]);CHKERRQ(ierr);
4648     ierr = DMRestoreWorkArray(dm,numPoints+1,PETSC_INT,&newPointOffsets[0]);CHKERRQ(ierr);
4649   }
4650   ierr = DMRestoreWorkArray(dm,newNumIndices*numIndices,PETSC_SCALAR,&tmpValues);CHKERRQ(ierr);
4651   ierr = ISRestoreIndices(aIS,&anchors);CHKERRQ(ierr);
4652 
4653   /* output */
4654   *outNumPoints  = newNumPoints;
4655   *outNumIndices = newNumIndices;
4656   *outPoints     = newPoints;
4657   *outValues     = newValues;
4658   for (f = 0; f < numFields; f++) {
4659     offsets[f] = newOffsets[f];
4660   }
4661   PetscFunctionReturn(0);
4662 }
4663 
4664 #undef __FUNCT__
4665 #define __FUNCT__ "DMPlexGetClosureIndices"
4666 PetscErrorCode DMPlexGetClosureIndices(DM dm, PetscSection section, PetscSection globalSection, PetscInt point, PetscInt *numIndices, PetscInt **indices)
4667 {
4668   PetscSection    clSection;
4669   IS              clPoints;
4670   const PetscInt *clp;
4671   PetscInt       *points = NULL, *pointsNew;
4672   PetscInt        numPoints, numPointsNew;
4673   PetscInt        offsets[32];
4674   PetscInt        Nf, Nind, NindNew, off, globalOff, f, p;
4675   PetscErrorCode  ierr;
4676 
4677   PetscFunctionBegin;
4678   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4679   PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2);
4680   PetscValidHeaderSpecific(globalSection, PETSC_SECTION_CLASSID, 3);
4681   if (numIndices) PetscValidPointer(numIndices, 4);
4682   PetscValidPointer(indices, 5);
4683   ierr = PetscSectionGetNumFields(section, &Nf);CHKERRQ(ierr);
4684   if (Nf > 31) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", Nf);
4685   ierr = PetscMemzero(offsets, 32 * sizeof(PetscInt));CHKERRQ(ierr);
4686   /* Get points in closure */
4687   ierr = PetscSectionGetClosureIndex(section, (PetscObject) dm, &clSection, &clPoints);CHKERRQ(ierr);
4688   if (!clPoints) {
4689     PetscInt pStart, pEnd, q;
4690 
4691     ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
4692     /* Compress out points not in the section */
4693     ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
4694     for (p = 0, q = 0; p < numPoints*2; p += 2) {
4695       if ((points[p] >= pStart) && (points[p] < pEnd)) {
4696         points[q*2]   = points[p];
4697         points[q*2+1] = points[p+1];
4698         ++q;
4699       }
4700     }
4701     numPoints = q;
4702   } else {
4703     PetscInt dof, off;
4704 
4705     ierr = PetscSectionGetDof(clSection, point, &dof);CHKERRQ(ierr);
4706     numPoints = dof/2;
4707     ierr = PetscSectionGetOffset(clSection, point, &off);CHKERRQ(ierr);
4708     ierr = ISGetIndices(clPoints, &clp);CHKERRQ(ierr);
4709     points = (PetscInt *) &clp[off];
4710   }
4711   /* Get number of indices and indices per field */
4712   for (p = 0, Nind = 0; p < numPoints*2; p += 2) {
4713     PetscInt dof, fdof;
4714 
4715     ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
4716     for (f = 0; f < Nf; ++f) {
4717       ierr = PetscSectionGetFieldDof(section, points[p], f, &fdof);CHKERRQ(ierr);
4718       offsets[f+1] += fdof;
4719     }
4720     Nind += dof;
4721   }
4722   for (f = 1; f < Nf; ++f) offsets[f+1] += offsets[f];
4723   if (Nf && offsets[Nf] != Nind) SETERRQ2(PetscObjectComm((PetscObject) dm), PETSC_ERR_PLIB, "Invalid size for closure %d should be %d", offsets[Nf], Nind);
4724   /* Correct for hanging node constraints */
4725   {
4726     ierr = DMPlexAnchorsModifyMat(dm, section, numPoints, Nind, points, NULL, &numPointsNew, &NindNew, &pointsNew, NULL, offsets);CHKERRQ(ierr);
4727     if (numPointsNew) {
4728       if (!clPoints) {ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);}
4729       else           {ierr = ISRestoreIndices(clPoints, &clp);CHKERRQ(ierr);}
4730       numPoints = numPointsNew;
4731       Nind      = NindNew;
4732       points    = pointsNew;
4733     }
4734   }
4735   /* Calculate indices */
4736   ierr = DMGetWorkArray(dm, Nind, PETSC_INT, indices);CHKERRQ(ierr);
4737   if (Nf) {
4738     for (p = 0; p < numPoints*2; p += 2) {
4739       PetscInt o = points[p+1];
4740       ierr = PetscSectionGetOffset(globalSection, points[p], &globalOff);CHKERRQ(ierr);
4741       indicesPointFields_private(section, points[p], globalOff < 0 ? -(globalOff+1) : globalOff, offsets, PETSC_FALSE, o, *indices);
4742     }
4743   } else {
4744     for (p = 0, off = 0; p < numPoints*2; p += 2) {
4745       PetscInt o = points[p+1];
4746       ierr = PetscSectionGetOffset(globalSection, points[p], &globalOff);CHKERRQ(ierr);
4747       indicesPoint_private(section, points[p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, o, *indices);
4748     }
4749   }
4750   /* Cleanup points */
4751   if (numPointsNew) {
4752     ierr = DMRestoreWorkArray(dm, 2*numPointsNew, PETSC_INT, &pointsNew);CHKERRQ(ierr);
4753   } else {
4754     if (!clPoints) {ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);}
4755     else           {ierr = ISRestoreIndices(clPoints, &clp);CHKERRQ(ierr);}
4756   }
4757   if (numIndices) *numIndices = Nind;
4758   PetscFunctionReturn(0);
4759 }
4760 
4761 #undef __FUNCT__
4762 #define __FUNCT__ "DMPlexRestoreClosureIndices"
4763 PetscErrorCode DMPlexRestoreClosureIndices(DM dm, PetscSection section, PetscSection globalSection, PetscInt point, PetscInt *numIndices, PetscInt **indices)
4764 {
4765   PetscErrorCode ierr;
4766 
4767   PetscFunctionBegin;
4768   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4769   PetscValidPointer(indices, 5);
4770   ierr = DMRestoreWorkArray(dm, 0, PETSC_INT, indices);CHKERRQ(ierr);
4771   PetscFunctionReturn(0);
4772 }
4773 
4774 #undef __FUNCT__
4775 #define __FUNCT__ "DMPlexMatSetClosure"
4776 /*@C
4777   DMPlexMatSetClosure - Set an array of the values on the closure of 'point'
4778 
4779   Not collective
4780 
4781   Input Parameters:
4782 + dm - The DM
4783 . section - The section describing the layout in v, or NULL to use the default section
4784 . globalSection - The section describing the layout in v, or NULL to use the default global section
4785 . A - The matrix
4786 . point - The sieve point in the DM
4787 . values - The array of values
4788 - mode - The insert mode, where INSERT_ALL_VALUES and ADD_ALL_VALUES also overwrite boundary conditions
4789 
4790   Fortran Notes:
4791   This routine is only available in Fortran 90, and you must include petsc.h90 in your code.
4792 
4793   Level: intermediate
4794 
4795 .seealso DMPlexVecGetClosure(), DMPlexVecSetClosure()
4796 @*/
4797 PetscErrorCode DMPlexMatSetClosure(DM dm, PetscSection section, PetscSection globalSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode)
4798 {
4799   DM_Plex        *mesh   = (DM_Plex*) dm->data;
4800   PetscSection    clSection;
4801   IS              clPoints;
4802   PetscInt       *points = NULL, *newPoints;
4803   const PetscInt *clp;
4804   PetscInt       *indices;
4805   PetscInt        offsets[32];
4806   PetscInt        numFields, numPoints, newNumPoints, numIndices, newNumIndices, dof, off, globalOff, pStart, pEnd, p, q, f;
4807   PetscScalar    *newValues;
4808   PetscErrorCode  ierr;
4809 
4810   PetscFunctionBegin;
4811   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4812   if (!section) {ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);}
4813   PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2);
4814   if (!globalSection) {ierr = DMGetDefaultGlobalSection(dm, &globalSection);CHKERRQ(ierr);}
4815   PetscValidHeaderSpecific(globalSection, PETSC_SECTION_CLASSID, 3);
4816   PetscValidHeaderSpecific(A, MAT_CLASSID, 4);
4817   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
4818   if (numFields > 31) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
4819   ierr = PetscMemzero(offsets, 32 * sizeof(PetscInt));CHKERRQ(ierr);
4820   ierr = PetscSectionGetClosureIndex(section, (PetscObject) dm, &clSection, &clPoints);CHKERRQ(ierr);
4821   if (!clPoints) {
4822     ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
4823     /* Compress out points not in the section */
4824     ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
4825     for (p = 0, q = 0; p < numPoints*2; p += 2) {
4826       if ((points[p] >= pStart) && (points[p] < pEnd)) {
4827         points[q*2]   = points[p];
4828         points[q*2+1] = points[p+1];
4829         ++q;
4830       }
4831     }
4832     numPoints = q;
4833   } else {
4834     PetscInt dof, off;
4835 
4836     ierr = PetscSectionGetDof(clSection, point, &dof);CHKERRQ(ierr);
4837     numPoints = dof/2;
4838     ierr = PetscSectionGetOffset(clSection, point, &off);CHKERRQ(ierr);
4839     ierr = ISGetIndices(clPoints, &clp);CHKERRQ(ierr);
4840     points = (PetscInt *) &clp[off];
4841   }
4842   for (p = 0, numIndices = 0; p < numPoints*2; p += 2) {
4843     PetscInt fdof;
4844 
4845     ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
4846     for (f = 0; f < numFields; ++f) {
4847       ierr          = PetscSectionGetFieldDof(section, points[p], f, &fdof);CHKERRQ(ierr);
4848       offsets[f+1] += fdof;
4849     }
4850     numIndices += dof;
4851   }
4852   for (f = 1; f < numFields; ++f) offsets[f+1] += offsets[f];
4853 
4854   if (numFields && offsets[numFields] != numIndices) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid size for closure %d should be %d", offsets[numFields], numIndices);
4855   ierr = DMPlexAnchorsModifyMat(dm,section,numPoints,numIndices,points,values,&newNumPoints,&newNumIndices,&newPoints,&newValues,offsets);CHKERRQ(ierr);
4856   if (newNumPoints) {
4857     if (!clPoints) {
4858       ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
4859     } else {
4860       ierr = ISRestoreIndices(clPoints, &clp);CHKERRQ(ierr);
4861     }
4862     numPoints  = newNumPoints;
4863     numIndices = newNumIndices;
4864     points     = newPoints;
4865     values     = newValues;
4866   }
4867   ierr = DMGetWorkArray(dm, numIndices, PETSC_INT, &indices);CHKERRQ(ierr);
4868   if (numFields) {
4869     for (p = 0; p < numPoints*2; p += 2) {
4870       PetscInt o = points[p+1];
4871       ierr = PetscSectionGetOffset(globalSection, points[p], &globalOff);CHKERRQ(ierr);
4872       indicesPointFields_private(section, points[p], globalOff < 0 ? -(globalOff+1) : globalOff, offsets, PETSC_FALSE, o, indices);
4873     }
4874   } else {
4875     for (p = 0, off = 0; p < numPoints*2; p += 2) {
4876       PetscInt o = points[p+1];
4877       ierr = PetscSectionGetOffset(globalSection, points[p], &globalOff);CHKERRQ(ierr);
4878       indicesPoint_private(section, points[p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, o, indices);
4879     }
4880   }
4881   if (mesh->printSetValues) {ierr = DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndices, indices, 0, NULL, values);CHKERRQ(ierr);}
4882   ierr = MatSetValues(A, numIndices, indices, numIndices, indices, values, mode);
4883   if (mesh->printFEM > 1) {
4884     PetscInt i;
4885     ierr = PetscPrintf(PETSC_COMM_SELF, "  Indices:");CHKERRQ(ierr);
4886     for (i = 0; i < numIndices; ++i) {ierr = PetscPrintf(PETSC_COMM_SELF, " %d", indices[i]);CHKERRQ(ierr);}
4887     ierr = PetscPrintf(PETSC_COMM_SELF, "\n");CHKERRQ(ierr);
4888   }
4889   if (ierr) {
4890     PetscMPIInt    rank;
4891     PetscErrorCode ierr2;
4892 
4893     ierr2 = MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank);CHKERRQ(ierr2);
4894     ierr2 = (*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank);CHKERRQ(ierr2);
4895     ierr2 = DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndices, indices, 0, NULL, values);CHKERRQ(ierr2);
4896     ierr2 = DMRestoreWorkArray(dm, numIndices, PETSC_INT, &indices);CHKERRQ(ierr2);
4897     CHKERRQ(ierr);
4898   }
4899   if (newNumPoints) {
4900     ierr = DMRestoreWorkArray(dm,newNumIndices*newNumIndices,PETSC_SCALAR,&newValues);CHKERRQ(ierr);
4901     ierr = DMRestoreWorkArray(dm,2*newNumPoints,PETSC_INT,&newPoints);CHKERRQ(ierr);
4902   }
4903   else {
4904     if (!clPoints) {
4905       ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
4906     } else {
4907       ierr = ISRestoreIndices(clPoints, &clp);CHKERRQ(ierr);
4908     }
4909   }
4910   ierr = DMRestoreWorkArray(dm, numIndices, PETSC_INT, &indices);CHKERRQ(ierr);
4911   PetscFunctionReturn(0);
4912 }
4913 
4914 #undef __FUNCT__
4915 #define __FUNCT__ "DMPlexMatSetClosureRefined"
4916 PetscErrorCode DMPlexMatSetClosureRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode)
4917 {
4918   DM_Plex        *mesh   = (DM_Plex*) dmf->data;
4919   PetscInt       *fpoints = NULL, *ftotpoints = NULL;
4920   PetscInt       *cpoints = NULL;
4921   PetscInt       *findices, *cindices;
4922   PetscInt        foffsets[32], coffsets[32];
4923   CellRefiner     cellRefiner;
4924   PetscInt        numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f;
4925   PetscErrorCode  ierr;
4926 
4927   PetscFunctionBegin;
4928   PetscValidHeaderSpecific(dmf, DM_CLASSID, 1);
4929   PetscValidHeaderSpecific(dmc, DM_CLASSID, 4);
4930   if (!fsection) {ierr = DMGetDefaultSection(dmf, &fsection);CHKERRQ(ierr);}
4931   PetscValidHeaderSpecific(fsection, PETSC_SECTION_CLASSID, 2);
4932   if (!csection) {ierr = DMGetDefaultSection(dmc, &csection);CHKERRQ(ierr);}
4933   PetscValidHeaderSpecific(csection, PETSC_SECTION_CLASSID, 5);
4934   if (!globalFSection) {ierr = DMGetDefaultGlobalSection(dmf, &globalFSection);CHKERRQ(ierr);}
4935   PetscValidHeaderSpecific(globalFSection, PETSC_SECTION_CLASSID, 3);
4936   if (!globalCSection) {ierr = DMGetDefaultGlobalSection(dmc, &globalCSection);CHKERRQ(ierr);}
4937   PetscValidHeaderSpecific(globalCSection, PETSC_SECTION_CLASSID, 6);
4938   PetscValidHeaderSpecific(A, MAT_CLASSID, 7);
4939   ierr = PetscSectionGetNumFields(fsection, &numFields);CHKERRQ(ierr);
4940   if (numFields > 31) SETERRQ1(PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
4941   ierr = PetscMemzero(foffsets, 32 * sizeof(PetscInt));CHKERRQ(ierr);
4942   ierr = PetscMemzero(coffsets, 32 * sizeof(PetscInt));CHKERRQ(ierr);
4943   /* Column indices */
4944   ierr = DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints);CHKERRQ(ierr);
4945   maxFPoints = numCPoints;
4946   /* Compress out points not in the section */
4947   /*   TODO: Squeeze out points with 0 dof as well */
4948   ierr = PetscSectionGetChart(csection, &pStart, &pEnd);CHKERRQ(ierr);
4949   for (p = 0, q = 0; p < numCPoints*2; p += 2) {
4950     if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) {
4951       cpoints[q*2]   = cpoints[p];
4952       cpoints[q*2+1] = cpoints[p+1];
4953       ++q;
4954     }
4955   }
4956   numCPoints = q;
4957   for (p = 0, numCIndices = 0; p < numCPoints*2; p += 2) {
4958     PetscInt fdof;
4959 
4960     ierr = PetscSectionGetDof(csection, cpoints[p], &dof);CHKERRQ(ierr);
4961     if (!dof) continue;
4962     for (f = 0; f < numFields; ++f) {
4963       ierr           = PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof);CHKERRQ(ierr);
4964       coffsets[f+1] += fdof;
4965     }
4966     numCIndices += dof;
4967   }
4968   for (f = 1; f < numFields; ++f) coffsets[f+1] += coffsets[f];
4969   /* Row indices */
4970   ierr = DMPlexGetCellRefiner_Internal(dmc, &cellRefiner);CHKERRQ(ierr);
4971   ierr = CellRefinerGetAffineTransforms_Internal(cellRefiner, &numSubcells, NULL, NULL, NULL);CHKERRQ(ierr);
4972   ierr = DMGetWorkArray(dmf, maxFPoints*2*numSubcells, PETSC_INT, &ftotpoints);CHKERRQ(ierr);
4973   for (r = 0, q = 0; r < numSubcells; ++r) {
4974     /* TODO Map from coarse to fine cells */
4975     ierr = DMPlexGetTransitiveClosure(dmf, point*numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints);CHKERRQ(ierr);
4976     /* Compress out points not in the section */
4977     ierr = PetscSectionGetChart(fsection, &pStart, &pEnd);CHKERRQ(ierr);
4978     for (p = 0; p < numFPoints*2; p += 2) {
4979       if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) {
4980         ierr = PetscSectionGetDof(fsection, fpoints[p], &dof);CHKERRQ(ierr);
4981         if (!dof) continue;
4982         for (s = 0; s < q; ++s) if (fpoints[p] == ftotpoints[s*2]) break;
4983         if (s < q) continue;
4984         ftotpoints[q*2]   = fpoints[p];
4985         ftotpoints[q*2+1] = fpoints[p+1];
4986         ++q;
4987       }
4988     }
4989     ierr = DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints);CHKERRQ(ierr);
4990   }
4991   numFPoints = q;
4992   for (p = 0, numFIndices = 0; p < numFPoints*2; p += 2) {
4993     PetscInt fdof;
4994 
4995     ierr = PetscSectionGetDof(fsection, ftotpoints[p], &dof);CHKERRQ(ierr);
4996     if (!dof) continue;
4997     for (f = 0; f < numFields; ++f) {
4998       ierr           = PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof);CHKERRQ(ierr);
4999       foffsets[f+1] += fdof;
5000     }
5001     numFIndices += dof;
5002   }
5003   for (f = 1; f < numFields; ++f) foffsets[f+1] += foffsets[f];
5004 
5005   if (numFields && foffsets[numFields] != numFIndices) SETERRQ2(PetscObjectComm((PetscObject)dmf), PETSC_ERR_PLIB, "Invalid size for closure %d should be %d", foffsets[numFields], numFIndices);
5006   if (numFields && coffsets[numFields] != numCIndices) SETERRQ2(PetscObjectComm((PetscObject)dmc), PETSC_ERR_PLIB, "Invalid size for closure %d should be %d", coffsets[numFields], numCIndices);
5007   ierr = DMGetWorkArray(dmf, numFIndices, PETSC_INT, &findices);CHKERRQ(ierr);
5008   ierr = DMGetWorkArray(dmc, numCIndices, PETSC_INT, &cindices);CHKERRQ(ierr);
5009   if (numFields) {
5010     for (p = 0; p < numFPoints*2; p += 2) {
5011       PetscInt o = ftotpoints[p+1];
5012       ierr = PetscSectionGetOffset(globalFSection, ftotpoints[p], &globalOff);CHKERRQ(ierr);
5013       indicesPointFields_private(fsection, ftotpoints[p], globalOff < 0 ? -(globalOff+1) : globalOff, foffsets, PETSC_FALSE, o, findices);
5014     }
5015     for (p = 0; p < numCPoints*2; p += 2) {
5016       PetscInt o = cpoints[p+1];
5017       ierr = PetscSectionGetOffset(globalCSection, cpoints[p], &globalOff);CHKERRQ(ierr);
5018       indicesPointFields_private(csection, cpoints[p], globalOff < 0 ? -(globalOff+1) : globalOff, coffsets, PETSC_FALSE, o, cindices);
5019     }
5020   } else {
5021     for (p = 0, off = 0; p < numFPoints*2; p += 2) {
5022       PetscInt o = ftotpoints[p+1];
5023       ierr = PetscSectionGetOffset(globalFSection, ftotpoints[p], &globalOff);CHKERRQ(ierr);
5024       indicesPoint_private(fsection, ftotpoints[p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, o, findices);
5025     }
5026     for (p = 0, off = 0; p < numCPoints*2; p += 2) {
5027       PetscInt o = cpoints[p+1];
5028       ierr = PetscSectionGetOffset(globalCSection, cpoints[p], &globalOff);CHKERRQ(ierr);
5029       indicesPoint_private(csection, cpoints[p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, o, cindices);
5030     }
5031   }
5032   if (mesh->printSetValues) {ierr = DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numFIndices, findices, numCIndices, cindices, values);CHKERRQ(ierr);}
5033   ierr = MatSetValues(A, numFIndices, findices, numCIndices, cindices, values, mode);
5034   if (ierr) {
5035     PetscMPIInt    rank;
5036     PetscErrorCode ierr2;
5037 
5038     ierr2 = MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank);CHKERRQ(ierr2);
5039     ierr2 = (*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank);CHKERRQ(ierr2);
5040     ierr2 = DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numFIndices, findices, numCIndices, cindices, values);CHKERRQ(ierr2);
5041     ierr2 = DMRestoreWorkArray(dmf, numFIndices, PETSC_INT, &findices);CHKERRQ(ierr2);
5042     ierr2 = DMRestoreWorkArray(dmc, numCIndices, PETSC_INT, &cindices);CHKERRQ(ierr2);
5043     CHKERRQ(ierr);
5044   }
5045   ierr = DMRestoreWorkArray(dmf, numCPoints*2*4, PETSC_INT, &ftotpoints);CHKERRQ(ierr);
5046   ierr = DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints);CHKERRQ(ierr);
5047   ierr = DMRestoreWorkArray(dmf, numFIndices, PETSC_INT, &findices);CHKERRQ(ierr);
5048   ierr = DMRestoreWorkArray(dmc, numCIndices, PETSC_INT, &cindices);CHKERRQ(ierr);
5049   PetscFunctionReturn(0);
5050 }
5051 
5052 #undef __FUNCT__
5053 #define __FUNCT__ "DMPlexMatGetClosureIndicesRefined"
5054 PetscErrorCode DMPlexMatGetClosureIndicesRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, PetscInt point, PetscInt cindices[], PetscInt findices[])
5055 {
5056   PetscInt      *fpoints = NULL, *ftotpoints = NULL;
5057   PetscInt      *cpoints = NULL;
5058   PetscInt       foffsets[32], coffsets[32];
5059   CellRefiner    cellRefiner;
5060   PetscInt       numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f;
5061   PetscErrorCode ierr;
5062 
5063   PetscFunctionBegin;
5064   PetscValidHeaderSpecific(dmf, DM_CLASSID, 1);
5065   PetscValidHeaderSpecific(dmc, DM_CLASSID, 4);
5066   if (!fsection) {ierr = DMGetDefaultSection(dmf, &fsection);CHKERRQ(ierr);}
5067   PetscValidHeaderSpecific(fsection, PETSC_SECTION_CLASSID, 2);
5068   if (!csection) {ierr = DMGetDefaultSection(dmc, &csection);CHKERRQ(ierr);}
5069   PetscValidHeaderSpecific(csection, PETSC_SECTION_CLASSID, 5);
5070   if (!globalFSection) {ierr = DMGetDefaultGlobalSection(dmf, &globalFSection);CHKERRQ(ierr);}
5071   PetscValidHeaderSpecific(globalFSection, PETSC_SECTION_CLASSID, 3);
5072   if (!globalCSection) {ierr = DMGetDefaultGlobalSection(dmc, &globalCSection);CHKERRQ(ierr);}
5073   PetscValidHeaderSpecific(globalCSection, PETSC_SECTION_CLASSID, 6);
5074   ierr = PetscSectionGetNumFields(fsection, &numFields);CHKERRQ(ierr);
5075   if (numFields > 31) SETERRQ1(PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
5076   ierr = PetscMemzero(foffsets, 32 * sizeof(PetscInt));CHKERRQ(ierr);
5077   ierr = PetscMemzero(coffsets, 32 * sizeof(PetscInt));CHKERRQ(ierr);
5078   /* Column indices */
5079   ierr = DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints);CHKERRQ(ierr);
5080   maxFPoints = numCPoints;
5081   /* Compress out points not in the section */
5082   /*   TODO: Squeeze out points with 0 dof as well */
5083   ierr = PetscSectionGetChart(csection, &pStart, &pEnd);CHKERRQ(ierr);
5084   for (p = 0, q = 0; p < numCPoints*2; p += 2) {
5085     if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) {
5086       cpoints[q*2]   = cpoints[p];
5087       cpoints[q*2+1] = cpoints[p+1];
5088       ++q;
5089     }
5090   }
5091   numCPoints = q;
5092   for (p = 0, numCIndices = 0; p < numCPoints*2; p += 2) {
5093     PetscInt fdof;
5094 
5095     ierr = PetscSectionGetDof(csection, cpoints[p], &dof);CHKERRQ(ierr);
5096     if (!dof) continue;
5097     for (f = 0; f < numFields; ++f) {
5098       ierr           = PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof);CHKERRQ(ierr);
5099       coffsets[f+1] += fdof;
5100     }
5101     numCIndices += dof;
5102   }
5103   for (f = 1; f < numFields; ++f) coffsets[f+1] += coffsets[f];
5104   /* Row indices */
5105   ierr = DMPlexGetCellRefiner_Internal(dmc, &cellRefiner);CHKERRQ(ierr);
5106   ierr = CellRefinerGetAffineTransforms_Internal(cellRefiner, &numSubcells, NULL, NULL, NULL);CHKERRQ(ierr);
5107   ierr = DMGetWorkArray(dmf, maxFPoints*2*numSubcells, PETSC_INT, &ftotpoints);CHKERRQ(ierr);
5108   for (r = 0, q = 0; r < numSubcells; ++r) {
5109     /* TODO Map from coarse to fine cells */
5110     ierr = DMPlexGetTransitiveClosure(dmf, point*numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints);CHKERRQ(ierr);
5111     /* Compress out points not in the section */
5112     ierr = PetscSectionGetChart(fsection, &pStart, &pEnd);CHKERRQ(ierr);
5113     for (p = 0; p < numFPoints*2; p += 2) {
5114       if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) {
5115         ierr = PetscSectionGetDof(fsection, fpoints[p], &dof);CHKERRQ(ierr);
5116         if (!dof) continue;
5117         for (s = 0; s < q; ++s) if (fpoints[p] == ftotpoints[s*2]) break;
5118         if (s < q) continue;
5119         ftotpoints[q*2]   = fpoints[p];
5120         ftotpoints[q*2+1] = fpoints[p+1];
5121         ++q;
5122       }
5123     }
5124     ierr = DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints);CHKERRQ(ierr);
5125   }
5126   numFPoints = q;
5127   for (p = 0, numFIndices = 0; p < numFPoints*2; p += 2) {
5128     PetscInt fdof;
5129 
5130     ierr = PetscSectionGetDof(fsection, ftotpoints[p], &dof);CHKERRQ(ierr);
5131     if (!dof) continue;
5132     for (f = 0; f < numFields; ++f) {
5133       ierr           = PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof);CHKERRQ(ierr);
5134       foffsets[f+1] += fdof;
5135     }
5136     numFIndices += dof;
5137   }
5138   for (f = 1; f < numFields; ++f) foffsets[f+1] += foffsets[f];
5139 
5140   if (numFields && foffsets[numFields] != numFIndices) SETERRQ2(PetscObjectComm((PetscObject)dmf), PETSC_ERR_PLIB, "Invalid size for closure %d should be %d", foffsets[numFields], numFIndices);
5141   if (numFields && coffsets[numFields] != numCIndices) SETERRQ2(PetscObjectComm((PetscObject)dmc), PETSC_ERR_PLIB, "Invalid size for closure %d should be %d", coffsets[numFields], numCIndices);
5142   if (numFields) {
5143     for (p = 0; p < numFPoints*2; p += 2) {
5144       PetscInt o = ftotpoints[p+1];
5145       ierr = PetscSectionGetOffset(globalFSection, ftotpoints[p], &globalOff);CHKERRQ(ierr);
5146       indicesPointFields_private(fsection, ftotpoints[p], globalOff < 0 ? -(globalOff+1) : globalOff, foffsets, PETSC_FALSE, o, findices);
5147     }
5148     for (p = 0; p < numCPoints*2; p += 2) {
5149       PetscInt o = cpoints[p+1];
5150       ierr = PetscSectionGetOffset(globalCSection, cpoints[p], &globalOff);CHKERRQ(ierr);
5151       indicesPointFields_private(csection, cpoints[p], globalOff < 0 ? -(globalOff+1) : globalOff, coffsets, PETSC_FALSE, o, cindices);
5152     }
5153   } else {
5154     for (p = 0, off = 0; p < numFPoints*2; p += 2) {
5155       PetscInt o = ftotpoints[p+1];
5156       ierr = PetscSectionGetOffset(globalFSection, ftotpoints[p], &globalOff);CHKERRQ(ierr);
5157       indicesPoint_private(fsection, ftotpoints[p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, o, findices);
5158     }
5159     for (p = 0, off = 0; p < numCPoints*2; p += 2) {
5160       PetscInt o = cpoints[p+1];
5161       ierr = PetscSectionGetOffset(globalCSection, cpoints[p], &globalOff);CHKERRQ(ierr);
5162       indicesPoint_private(csection, cpoints[p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, o, cindices);
5163     }
5164   }
5165   ierr = DMRestoreWorkArray(dmf, numCPoints*2*4, PETSC_INT, &ftotpoints);CHKERRQ(ierr);
5166   ierr = DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints);CHKERRQ(ierr);
5167   PetscFunctionReturn(0);
5168 }
5169 
5170 #undef __FUNCT__
5171 #define __FUNCT__ "DMPlexGetHybridBounds"
5172 /*@
5173   DMPlexGetHybridBounds - Get the first mesh point of each dimension which is a hybrid
5174 
5175   Input Parameter:
5176 . dm - The DMPlex object
5177 
5178   Output Parameters:
5179 + cMax - The first hybrid cell
5180 . fMax - The first hybrid face
5181 . eMax - The first hybrid edge
5182 - vMax - The first hybrid vertex
5183 
5184   Level: developer
5185 
5186 .seealso DMPlexCreateHybridMesh(), DMPlexSetHybridBounds()
5187 @*/
5188 PetscErrorCode DMPlexGetHybridBounds(DM dm, PetscInt *cMax, PetscInt *fMax, PetscInt *eMax, PetscInt *vMax)
5189 {
5190   DM_Plex       *mesh = (DM_Plex*) dm->data;
5191   PetscInt       dim;
5192   PetscErrorCode ierr;
5193 
5194   PetscFunctionBegin;
5195   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5196   ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr);
5197   if (cMax) *cMax = mesh->hybridPointMax[dim];
5198   if (fMax) *fMax = mesh->hybridPointMax[dim-1];
5199   if (eMax) *eMax = mesh->hybridPointMax[1];
5200   if (vMax) *vMax = mesh->hybridPointMax[0];
5201   PetscFunctionReturn(0);
5202 }
5203 
5204 #undef __FUNCT__
5205 #define __FUNCT__ "DMPlexSetHybridBounds"
5206 /*@
5207   DMPlexSetHybridBounds - Set the first mesh point of each dimension which is a hybrid
5208 
5209   Input Parameters:
5210 . dm   - The DMPlex object
5211 . cMax - The first hybrid cell
5212 . fMax - The first hybrid face
5213 . eMax - The first hybrid edge
5214 - vMax - The first hybrid vertex
5215 
5216   Level: developer
5217 
5218 .seealso DMPlexCreateHybridMesh(), DMPlexGetHybridBounds()
5219 @*/
5220 PetscErrorCode DMPlexSetHybridBounds(DM dm, PetscInt cMax, PetscInt fMax, PetscInt eMax, PetscInt vMax)
5221 {
5222   DM_Plex       *mesh = (DM_Plex*) dm->data;
5223   PetscInt       dim;
5224   PetscErrorCode ierr;
5225 
5226   PetscFunctionBegin;
5227   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5228   ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr);
5229   if (cMax >= 0) mesh->hybridPointMax[dim]   = cMax;
5230   if (fMax >= 0) mesh->hybridPointMax[dim-1] = fMax;
5231   if (eMax >= 0) mesh->hybridPointMax[1]     = eMax;
5232   if (vMax >= 0) mesh->hybridPointMax[0]     = vMax;
5233   PetscFunctionReturn(0);
5234 }
5235 
5236 #undef __FUNCT__
5237 #define __FUNCT__ "DMPlexGetVTKCellHeight"
5238 PetscErrorCode DMPlexGetVTKCellHeight(DM dm, PetscInt *cellHeight)
5239 {
5240   DM_Plex *mesh = (DM_Plex*) dm->data;
5241 
5242   PetscFunctionBegin;
5243   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5244   PetscValidPointer(cellHeight, 2);
5245   *cellHeight = mesh->vtkCellHeight;
5246   PetscFunctionReturn(0);
5247 }
5248 
5249 #undef __FUNCT__
5250 #define __FUNCT__ "DMPlexSetVTKCellHeight"
5251 PetscErrorCode DMPlexSetVTKCellHeight(DM dm, PetscInt cellHeight)
5252 {
5253   DM_Plex *mesh = (DM_Plex*) dm->data;
5254 
5255   PetscFunctionBegin;
5256   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5257   mesh->vtkCellHeight = cellHeight;
5258   PetscFunctionReturn(0);
5259 }
5260 
5261 #undef __FUNCT__
5262 #define __FUNCT__ "DMPlexCreateNumbering_Private"
5263 /* We can easily have a form that takes an IS instead */
5264 static PetscErrorCode DMPlexCreateNumbering_Private(DM dm, PetscInt pStart, PetscInt pEnd, PetscInt shift, PetscInt *globalSize, PetscSF sf, IS *numbering)
5265 {
5266   PetscSection   section, globalSection;
5267   PetscInt      *numbers, p;
5268   PetscErrorCode ierr;
5269 
5270   PetscFunctionBegin;
5271   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)dm), &section);CHKERRQ(ierr);
5272   ierr = PetscSectionSetChart(section, pStart, pEnd);CHKERRQ(ierr);
5273   for (p = pStart; p < pEnd; ++p) {
5274     ierr = PetscSectionSetDof(section, p, 1);CHKERRQ(ierr);
5275   }
5276   ierr = PetscSectionSetUp(section);CHKERRQ(ierr);
5277   ierr = PetscSectionCreateGlobalSection(section, sf, PETSC_FALSE, PETSC_FALSE, &globalSection);CHKERRQ(ierr);
5278   ierr = PetscMalloc1(pEnd - pStart, &numbers);CHKERRQ(ierr);
5279   for (p = pStart; p < pEnd; ++p) {
5280     ierr = PetscSectionGetOffset(globalSection, p, &numbers[p-pStart]);CHKERRQ(ierr);
5281     if (numbers[p-pStart] < 0) numbers[p-pStart] -= shift;
5282     else                       numbers[p-pStart] += shift;
5283   }
5284   ierr = ISCreateGeneral(PetscObjectComm((PetscObject) dm), pEnd - pStart, numbers, PETSC_OWN_POINTER, numbering);CHKERRQ(ierr);
5285   if (globalSize) {
5286     PetscLayout layout;
5287     ierr = PetscSectionGetPointLayout(PetscObjectComm((PetscObject) dm), globalSection, &layout);CHKERRQ(ierr);
5288     ierr = PetscLayoutGetSize(layout, globalSize);CHKERRQ(ierr);
5289     ierr = PetscLayoutDestroy(&layout);CHKERRQ(ierr);
5290   }
5291   ierr = PetscSectionDestroy(&section);CHKERRQ(ierr);
5292   ierr = PetscSectionDestroy(&globalSection);CHKERRQ(ierr);
5293   PetscFunctionReturn(0);
5294 }
5295 
5296 #undef __FUNCT__
5297 #define __FUNCT__ "DMPlexGetCellNumbering"
5298 PetscErrorCode DMPlexGetCellNumbering(DM dm, IS *globalCellNumbers)
5299 {
5300   DM_Plex       *mesh = (DM_Plex*) dm->data;
5301   PetscInt       cellHeight, cStart, cEnd, cMax;
5302   PetscErrorCode ierr;
5303 
5304   PetscFunctionBegin;
5305   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5306   if (!mesh->globalCellNumbers) {
5307     ierr = DMPlexGetVTKCellHeight(dm, &cellHeight);CHKERRQ(ierr);
5308     ierr = DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd);CHKERRQ(ierr);
5309     ierr = DMPlexGetHybridBounds(dm, &cMax, NULL, NULL, NULL);CHKERRQ(ierr);
5310     if (cMax >= 0) cEnd = PetscMin(cEnd, cMax);
5311     ierr = DMPlexCreateNumbering_Private(dm, cStart, cEnd, 0, NULL, dm->sf, &mesh->globalCellNumbers);CHKERRQ(ierr);
5312   }
5313   *globalCellNumbers = mesh->globalCellNumbers;
5314   PetscFunctionReturn(0);
5315 }
5316 
5317 #undef __FUNCT__
5318 #define __FUNCT__ "DMPlexGetVertexNumbering"
5319 PetscErrorCode DMPlexGetVertexNumbering(DM dm, IS *globalVertexNumbers)
5320 {
5321   DM_Plex       *mesh = (DM_Plex*) dm->data;
5322   PetscInt       vStart, vEnd, vMax;
5323   PetscErrorCode ierr;
5324 
5325   PetscFunctionBegin;
5326   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5327   if (!mesh->globalVertexNumbers) {
5328     ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
5329     ierr = DMPlexGetHybridBounds(dm, NULL, NULL, NULL, &vMax);CHKERRQ(ierr);
5330     if (vMax >= 0) vEnd = PetscMin(vEnd, vMax);
5331     ierr = DMPlexCreateNumbering_Private(dm, vStart, vEnd, 0, NULL, dm->sf, &mesh->globalVertexNumbers);CHKERRQ(ierr);
5332   }
5333   *globalVertexNumbers = mesh->globalVertexNumbers;
5334   PetscFunctionReturn(0);
5335 }
5336 
5337 #undef __FUNCT__
5338 #define __FUNCT__ "DMPlexCreatePointNumbering"
5339 PetscErrorCode DMPlexCreatePointNumbering(DM dm, IS *globalPointNumbers)
5340 {
5341   IS             nums[4];
5342   PetscInt       depths[4];
5343   PetscInt       depth, d, shift = 0;
5344   PetscErrorCode ierr;
5345 
5346   PetscFunctionBegin;
5347   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5348   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
5349   /* For unstratified meshes use dim instead of depth */
5350   if (depth < 0) {ierr = DMGetDimension(dm, &depth);CHKERRQ(ierr);}
5351   depths[0] = depth; depths[1] = 0;
5352   for (d = 2; d <= depth; ++d) depths[d] = depth-d+1;
5353   for (d = 0; d <= depth; ++d) {
5354     PetscInt pStart, pEnd, gsize;
5355 
5356     ierr = DMPlexGetDepthStratum(dm, depths[d], &pStart, &pEnd);CHKERRQ(ierr);
5357     ierr = DMPlexCreateNumbering_Private(dm, pStart, pEnd, shift, &gsize, dm->sf, &nums[d]);CHKERRQ(ierr);
5358     shift += gsize;
5359   }
5360   ierr = ISConcatenate(PetscObjectComm((PetscObject) dm), depth+1, nums, globalPointNumbers);CHKERRQ(ierr);
5361   for (d = 0; d <= depth; ++d) {ierr = ISDestroy(&nums[d]);CHKERRQ(ierr);}
5362   PetscFunctionReturn(0);
5363 }
5364 
5365 
5366 #undef __FUNCT__
5367 #define __FUNCT__ "PetscSectionCreateGlobalSectionLabel"
5368 /*@C
5369   PetscSectionCreateGlobalSectionLabel - Create a section describing the global field layout using
5370   the local section and an SF describing the section point overlap.
5371 
5372   Input Parameters:
5373   + s - The PetscSection for the local field layout
5374   . sf - The SF describing parallel layout of the section points
5375   . includeConstraints - By default this is PETSC_FALSE, meaning that the global field vector will not possess constrained dofs
5376   . label - The label specifying the points
5377   - labelValue - The label stratum specifying the points
5378 
5379   Output Parameter:
5380   . gsection - The PetscSection for the global field layout
5381 
5382   Note: This gives negative sizes and offsets to points not owned by this process
5383 
5384   Level: developer
5385 
5386 .seealso: PetscSectionCreate()
5387 @*/
5388 PetscErrorCode PetscSectionCreateGlobalSectionLabel(PetscSection s, PetscSF sf, PetscBool includeConstraints, DMLabel label, PetscInt labelValue, PetscSection *gsection)
5389 {
5390   PetscInt      *neg = NULL, *tmpOff = NULL;
5391   PetscInt       pStart, pEnd, p, dof, cdof, off, globalOff = 0, nroots;
5392   PetscErrorCode ierr;
5393 
5394   PetscFunctionBegin;
5395   ierr = PetscSectionCreate(PetscObjectComm((PetscObject) s), gsection);CHKERRQ(ierr);
5396   ierr = PetscSectionGetChart(s, &pStart, &pEnd);CHKERRQ(ierr);
5397   ierr = PetscSectionSetChart(*gsection, pStart, pEnd);CHKERRQ(ierr);
5398   ierr = PetscSFGetGraph(sf, &nroots, NULL, NULL, NULL);CHKERRQ(ierr);
5399   if (nroots >= 0) {
5400     if (nroots < pEnd-pStart) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "PetscSF nroots %d < %d section size", nroots, pEnd-pStart);
5401     ierr = PetscCalloc1(nroots, &neg);CHKERRQ(ierr);
5402     if (nroots > pEnd-pStart) {
5403       ierr = PetscCalloc1(nroots, &tmpOff);CHKERRQ(ierr);
5404     } else {
5405       tmpOff = &(*gsection)->atlasDof[-pStart];
5406     }
5407   }
5408   /* Mark ghost points with negative dof */
5409   for (p = pStart; p < pEnd; ++p) {
5410     PetscInt value;
5411 
5412     ierr = DMLabelGetValue(label, p, &value);CHKERRQ(ierr);
5413     if (value != labelValue) continue;
5414     ierr = PetscSectionGetDof(s, p, &dof);CHKERRQ(ierr);
5415     ierr = PetscSectionSetDof(*gsection, p, dof);CHKERRQ(ierr);
5416     ierr = PetscSectionGetConstraintDof(s, p, &cdof);CHKERRQ(ierr);
5417     if (!includeConstraints && cdof > 0) {ierr = PetscSectionSetConstraintDof(*gsection, p, cdof);CHKERRQ(ierr);}
5418     if (neg) neg[p] = -(dof+1);
5419   }
5420   ierr = PetscSectionSetUpBC(*gsection);CHKERRQ(ierr);
5421   if (nroots >= 0) {
5422     ierr = PetscSFBcastBegin(sf, MPIU_INT, neg, tmpOff);CHKERRQ(ierr);
5423     ierr = PetscSFBcastEnd(sf, MPIU_INT, neg, tmpOff);CHKERRQ(ierr);
5424     if (nroots > pEnd-pStart) {
5425       for (p = pStart; p < pEnd; ++p) {if (tmpOff[p] < 0) (*gsection)->atlasDof[p-pStart] = tmpOff[p];}
5426     }
5427   }
5428   /* Calculate new sizes, get proccess offset, and calculate point offsets */
5429   for (p = 0, off = 0; p < pEnd-pStart; ++p) {
5430     cdof = (!includeConstraints && s->bc) ? s->bc->atlasDof[p] : 0;
5431     (*gsection)->atlasOff[p] = off;
5432     off += (*gsection)->atlasDof[p] > 0 ? (*gsection)->atlasDof[p]-cdof : 0;
5433   }
5434   ierr       = MPI_Scan(&off, &globalOff, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject) s));CHKERRQ(ierr);
5435   globalOff -= off;
5436   for (p = 0, off = 0; p < pEnd-pStart; ++p) {
5437     (*gsection)->atlasOff[p] += globalOff;
5438     if (neg) neg[p] = -((*gsection)->atlasOff[p]+1);
5439   }
5440   /* Put in negative offsets for ghost points */
5441   if (nroots >= 0) {
5442     ierr = PetscSFBcastBegin(sf, MPIU_INT, neg, tmpOff);CHKERRQ(ierr);
5443     ierr = PetscSFBcastEnd(sf, MPIU_INT, neg, tmpOff);CHKERRQ(ierr);
5444     if (nroots > pEnd-pStart) {
5445       for (p = pStart; p < pEnd; ++p) {if (tmpOff[p] < 0) (*gsection)->atlasOff[p-pStart] = tmpOff[p];}
5446     }
5447   }
5448   if (nroots >= 0 && nroots > pEnd-pStart) {ierr = PetscFree(tmpOff);CHKERRQ(ierr);}
5449   ierr = PetscFree(neg);CHKERRQ(ierr);
5450   PetscFunctionReturn(0);
5451 }
5452 
5453 #undef __FUNCT__
5454 #define __FUNCT__ "DMPlexCheckSymmetry"
5455 /*@
5456   DMPlexCheckSymmetry - Check that the adjacency information in the mesh is symmetric.
5457 
5458   Input Parameters:
5459   + dm - The DMPlex object
5460 
5461   Note: This is a useful diagnostic when creating meshes programmatically.
5462 
5463   Level: developer
5464 
5465 .seealso: DMCreate(), DMCheckSkeleton(), DMCheckFaces()
5466 @*/
5467 PetscErrorCode DMPlexCheckSymmetry(DM dm)
5468 {
5469   PetscSection    coneSection, supportSection;
5470   const PetscInt *cone, *support;
5471   PetscInt        coneSize, c, supportSize, s;
5472   PetscInt        pStart, pEnd, p, csize, ssize;
5473   PetscErrorCode  ierr;
5474 
5475   PetscFunctionBegin;
5476   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5477   ierr = DMPlexGetConeSection(dm, &coneSection);CHKERRQ(ierr);
5478   ierr = DMPlexGetSupportSection(dm, &supportSection);CHKERRQ(ierr);
5479   /* Check that point p is found in the support of its cone points, and vice versa */
5480   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
5481   for (p = pStart; p < pEnd; ++p) {
5482     ierr = DMPlexGetConeSize(dm, p, &coneSize);CHKERRQ(ierr);
5483     ierr = DMPlexGetCone(dm, p, &cone);CHKERRQ(ierr);
5484     for (c = 0; c < coneSize; ++c) {
5485       PetscBool dup = PETSC_FALSE;
5486       PetscInt  d;
5487       for (d = c-1; d >= 0; --d) {
5488         if (cone[c] == cone[d]) {dup = PETSC_TRUE; break;}
5489       }
5490       ierr = DMPlexGetSupportSize(dm, cone[c], &supportSize);CHKERRQ(ierr);
5491       ierr = DMPlexGetSupport(dm, cone[c], &support);CHKERRQ(ierr);
5492       for (s = 0; s < supportSize; ++s) {
5493         if (support[s] == p) break;
5494       }
5495       if ((s >= supportSize) || (dup && (support[s+1] != p))) {
5496         ierr = PetscPrintf(PETSC_COMM_SELF, "p: %d cone: ", p);CHKERRQ(ierr);
5497         for (s = 0; s < coneSize; ++s) {
5498           ierr = PetscPrintf(PETSC_COMM_SELF, "%d, ", cone[s]);CHKERRQ(ierr);
5499         }
5500         ierr = PetscPrintf(PETSC_COMM_SELF, "\n");CHKERRQ(ierr);
5501         ierr = PetscPrintf(PETSC_COMM_SELF, "p: %d support: ", cone[c]);CHKERRQ(ierr);
5502         for (s = 0; s < supportSize; ++s) {
5503           ierr = PetscPrintf(PETSC_COMM_SELF, "%d, ", support[s]);CHKERRQ(ierr);
5504         }
5505         ierr = PetscPrintf(PETSC_COMM_SELF, "\n");CHKERRQ(ierr);
5506         if (dup) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d not repeatedly found in support of repeated cone point %d", p, cone[c]);
5507         else SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d not found in support of cone point %d", p, cone[c]);
5508       }
5509     }
5510     ierr = DMPlexGetSupportSize(dm, p, &supportSize);CHKERRQ(ierr);
5511     ierr = DMPlexGetSupport(dm, p, &support);CHKERRQ(ierr);
5512     for (s = 0; s < supportSize; ++s) {
5513       ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
5514       ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
5515       for (c = 0; c < coneSize; ++c) {
5516         if (cone[c] == p) break;
5517       }
5518       if (c >= coneSize) {
5519         ierr = PetscPrintf(PETSC_COMM_SELF, "p: %d support: ", p);CHKERRQ(ierr);
5520         for (c = 0; c < supportSize; ++c) {
5521           ierr = PetscPrintf(PETSC_COMM_SELF, "%d, ", support[c]);CHKERRQ(ierr);
5522         }
5523         ierr = PetscPrintf(PETSC_COMM_SELF, "\n");CHKERRQ(ierr);
5524         ierr = PetscPrintf(PETSC_COMM_SELF, "p: %d cone: ", support[s]);CHKERRQ(ierr);
5525         for (c = 0; c < coneSize; ++c) {
5526           ierr = PetscPrintf(PETSC_COMM_SELF, "%d, ", cone[c]);CHKERRQ(ierr);
5527         }
5528         ierr = PetscPrintf(PETSC_COMM_SELF, "\n");CHKERRQ(ierr);
5529         SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d not found in cone of support point %d", p, support[s]);
5530       }
5531     }
5532   }
5533   ierr = PetscSectionGetStorageSize(coneSection, &csize);CHKERRQ(ierr);
5534   ierr = PetscSectionGetStorageSize(supportSection, &ssize);CHKERRQ(ierr);
5535   if (csize != ssize) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Total cone size %d != Total support size %d", csize, ssize);
5536   PetscFunctionReturn(0);
5537 }
5538 
5539 #undef __FUNCT__
5540 #define __FUNCT__ "DMPlexCheckSkeleton"
5541 /*@
5542   DMPlexCheckSkeleton - Check that each cell has the correct number of vertices
5543 
5544   Input Parameters:
5545 + dm - The DMPlex object
5546 . isSimplex - Are the cells simplices or tensor products
5547 - cellHeight - Normally 0
5548 
5549   Note: This is a useful diagnostic when creating meshes programmatically.
5550 
5551   Level: developer
5552 
5553 .seealso: DMCreate(), DMCheckSymmetry(), DMCheckFaces()
5554 @*/
5555 PetscErrorCode DMPlexCheckSkeleton(DM dm, PetscBool isSimplex, PetscInt cellHeight)
5556 {
5557   PetscInt       dim, numCorners, numHybridCorners, vStart, vEnd, cStart, cEnd, cMax, c;
5558   PetscErrorCode ierr;
5559 
5560   PetscFunctionBegin;
5561   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5562   ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr);
5563   switch (dim) {
5564   case 1: numCorners = isSimplex ? 2 : 2; numHybridCorners = isSimplex ? 2 : 2; break;
5565   case 2: numCorners = isSimplex ? 3 : 4; numHybridCorners = isSimplex ? 4 : 4; break;
5566   case 3: numCorners = isSimplex ? 4 : 8; numHybridCorners = isSimplex ? 6 : 8; break;
5567   default:
5568     SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_OUTOFRANGE, "Cannot handle meshes of dimension %d", dim);
5569   }
5570   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
5571   ierr = DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd);CHKERRQ(ierr);
5572   ierr = DMPlexGetHybridBounds(dm, &cMax, NULL, NULL, NULL);CHKERRQ(ierr);
5573   cMax = cMax >= 0 ? cMax : cEnd;
5574   for (c = cStart; c < cMax; ++c) {
5575     PetscInt *closure = NULL, closureSize, cl, coneSize = 0;
5576 
5577     ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
5578     for (cl = 0; cl < closureSize*2; cl += 2) {
5579       const PetscInt p = closure[cl];
5580       if ((p >= vStart) && (p < vEnd)) ++coneSize;
5581     }
5582     ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
5583     if (coneSize != numCorners) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cell %d has  %d vertices != %d", c, coneSize, numCorners);
5584   }
5585   for (c = cMax; c < cEnd; ++c) {
5586     PetscInt *closure = NULL, closureSize, cl, coneSize = 0;
5587 
5588     ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
5589     for (cl = 0; cl < closureSize*2; cl += 2) {
5590       const PetscInt p = closure[cl];
5591       if ((p >= vStart) && (p < vEnd)) ++coneSize;
5592     }
5593     ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
5594     if (coneSize > numHybridCorners) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Hybrid cell %d has  %d vertices > %d", c, coneSize, numHybridCorners);
5595   }
5596   PetscFunctionReturn(0);
5597 }
5598 
5599 #undef __FUNCT__
5600 #define __FUNCT__ "DMPlexCheckFaces"
5601 /*@
5602   DMPlexCheckFaces - Check that the faces of each cell give a vertex order this is consistent with what we expect from the cell type
5603 
5604   Input Parameters:
5605 + dm - The DMPlex object
5606 . isSimplex - Are the cells simplices or tensor products
5607 - cellHeight - Normally 0
5608 
5609   Note: This is a useful diagnostic when creating meshes programmatically.
5610 
5611   Level: developer
5612 
5613 .seealso: DMCreate(), DMCheckSymmetry(), DMCheckSkeleton()
5614 @*/
5615 PetscErrorCode DMPlexCheckFaces(DM dm, PetscBool isSimplex, PetscInt cellHeight)
5616 {
5617   PetscInt       pMax[4];
5618   PetscInt       dim, vStart, vEnd, cStart, cEnd, c, h;
5619   PetscErrorCode ierr;
5620 
5621   PetscFunctionBegin;
5622   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5623   ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr);
5624   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
5625   ierr = DMPlexGetHybridBounds(dm, &pMax[dim], &pMax[dim-1], &pMax[1], &pMax[0]);CHKERRQ(ierr);
5626   for (h = cellHeight; h < dim; ++h) {
5627     ierr = DMPlexGetHeightStratum(dm, h, &cStart, &cEnd);CHKERRQ(ierr);
5628     for (c = cStart; c < cEnd; ++c) {
5629       const PetscInt *cone, *ornt, *faces;
5630       PetscInt        numFaces, faceSize, coneSize,f;
5631       PetscInt       *closure = NULL, closureSize, cl, numCorners = 0;
5632 
5633       if (pMax[dim-h] >= 0 && c >= pMax[dim-h]) continue;
5634       ierr = DMPlexGetConeSize(dm, c, &coneSize);CHKERRQ(ierr);
5635       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
5636       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
5637       ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
5638       for (cl = 0; cl < closureSize*2; cl += 2) {
5639         const PetscInt p = closure[cl];
5640         if ((p >= vStart) && (p < vEnd)) closure[numCorners++] = p;
5641       }
5642       ierr = DMPlexGetRawFaces_Internal(dm, dim-h, numCorners, closure, &numFaces, &faceSize, &faces);CHKERRQ(ierr);
5643       if (coneSize != numFaces) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cell %d has %d faces but should have %d", c, coneSize, numFaces);
5644       for (f = 0; f < numFaces; ++f) {
5645         PetscInt *fclosure = NULL, fclosureSize, cl, fnumCorners = 0, v;
5646 
5647         ierr = DMPlexGetTransitiveClosure_Internal(dm, cone[f], ornt[f], PETSC_TRUE, &fclosureSize, &fclosure);CHKERRQ(ierr);
5648         for (cl = 0; cl < fclosureSize*2; cl += 2) {
5649           const PetscInt p = fclosure[cl];
5650           if ((p >= vStart) && (p < vEnd)) fclosure[fnumCorners++] = p;
5651         }
5652         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);
5653         for (v = 0; v < fnumCorners; ++v) {
5654           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]);
5655         }
5656         ierr = DMPlexRestoreTransitiveClosure(dm, cone[f], PETSC_TRUE, &fclosureSize, &fclosure);CHKERRQ(ierr);
5657       }
5658       ierr = DMPlexRestoreFaces_Internal(dm, dim, c, &numFaces, &faceSize, &faces);CHKERRQ(ierr);
5659       ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
5660     }
5661   }
5662   PetscFunctionReturn(0);
5663 }
5664 
5665 #undef __FUNCT__
5666 #define __FUNCT__ "DMCreateInterpolation_Plex"
5667 /* Pointwise interpolation
5668      Just code FEM for now
5669      u^f = I u^c
5670      sum_k u^f_k phi^f_k = I sum_j u^c_j phi^c_j
5671      u^f_i = sum_j psi^f_i I phi^c_j u^c_j
5672      I_{ij} = psi^f_i phi^c_j
5673 */
5674 PetscErrorCode DMCreateInterpolation_Plex(DM dmCoarse, DM dmFine, Mat *interpolation, Vec *scaling)
5675 {
5676   PetscSection   gsc, gsf;
5677   PetscInt       m, n;
5678   void          *ctx;
5679   DM             cdm;
5680   PetscBool      regular;
5681   PetscErrorCode ierr;
5682 
5683   PetscFunctionBegin;
5684   ierr = DMGetDefaultGlobalSection(dmFine, &gsf);CHKERRQ(ierr);
5685   ierr = PetscSectionGetConstrainedStorageSize(gsf, &m);CHKERRQ(ierr);
5686   ierr = DMGetDefaultGlobalSection(dmCoarse, &gsc);CHKERRQ(ierr);
5687   ierr = PetscSectionGetConstrainedStorageSize(gsc, &n);CHKERRQ(ierr);
5688 
5689   ierr = MatCreate(PetscObjectComm((PetscObject) dmCoarse), interpolation);CHKERRQ(ierr);
5690   ierr = MatSetSizes(*interpolation, m, n, PETSC_DETERMINE, PETSC_DETERMINE);CHKERRQ(ierr);
5691   ierr = MatSetType(*interpolation, dmCoarse->mattype);CHKERRQ(ierr);
5692   ierr = DMGetApplicationContext(dmFine, &ctx);CHKERRQ(ierr);
5693 
5694   ierr = DMPlexGetCoarseDM(dmFine, &cdm);CHKERRQ(ierr);
5695   ierr = DMPlexGetRegularRefinement(dmFine, &regular);CHKERRQ(ierr);
5696   if (regular && cdm == dmCoarse) {ierr = DMPlexComputeInterpolatorNested(dmCoarse, dmFine, *interpolation, ctx);CHKERRQ(ierr);}
5697   else                            {ierr = DMPlexComputeInterpolatorGeneral(dmCoarse, dmFine, *interpolation, ctx);CHKERRQ(ierr);}
5698   ierr = MatViewFromOptions(*interpolation, NULL, "-interp_mat_view");CHKERRQ(ierr);
5699   /* Use naive scaling */
5700   ierr = DMCreateInterpolationScale(dmCoarse, dmFine, *interpolation, scaling);CHKERRQ(ierr);
5701   PetscFunctionReturn(0);
5702 }
5703 
5704 #undef __FUNCT__
5705 #define __FUNCT__ "DMCreateInjection_Plex"
5706 PetscErrorCode DMCreateInjection_Plex(DM dmCoarse, DM dmFine, Mat *mat)
5707 {
5708   PetscErrorCode ierr;
5709   VecScatter     ctx;
5710 
5711   PetscFunctionBegin;
5712   ierr = DMPlexComputeInjectorFEM(dmCoarse, dmFine, &ctx, NULL);CHKERRQ(ierr);
5713   ierr = MatCreateScatter(PetscObjectComm((PetscObject)ctx), ctx, mat);CHKERRQ(ierr);
5714   ierr = VecScatterDestroy(&ctx);CHKERRQ(ierr);
5715   PetscFunctionReturn(0);
5716 }
5717 
5718 #undef __FUNCT__
5719 #define __FUNCT__ "DMCreateDefaultSection_Plex"
5720 PetscErrorCode DMCreateDefaultSection_Plex(DM dm)
5721 {
5722   PetscSection   section;
5723   IS            *bcPoints, *bcComps;
5724   PetscBool     *isFE;
5725   PetscInt      *bcFields, *numComp, *numDof;
5726   PetscInt       depth, dim, numBd, numBC = 0, numFields, bd, bc = 0, f;
5727   PetscInt       cStart, cEnd, cEndInterior;
5728   PetscErrorCode ierr;
5729 
5730   PetscFunctionBegin;
5731   ierr = DMGetNumFields(dm, &numFields);CHKERRQ(ierr);
5732   /* FE and FV boundary conditions are handled slightly differently */
5733   ierr = PetscMalloc1(numFields, &isFE);CHKERRQ(ierr);
5734   for (f = 0; f < numFields; ++f) {
5735     PetscObject  obj;
5736     PetscClassId id;
5737 
5738     ierr = DMGetField(dm, f, &obj);CHKERRQ(ierr);
5739     ierr = PetscObjectGetClassId(obj, &id);CHKERRQ(ierr);
5740     if (id == PETSCFE_CLASSID)      {isFE[f] = PETSC_TRUE;}
5741     else if (id == PETSCFV_CLASSID) {isFE[f] = PETSC_FALSE;}
5742     else SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %d", f);
5743   }
5744   /* Allocate boundary point storage for FEM boundaries */
5745   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
5746   ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr);
5747   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
5748   ierr = DMPlexGetHybridBounds(dm, &cEndInterior, NULL, NULL, NULL);CHKERRQ(ierr);
5749   ierr = DMPlexGetNumBoundary(dm, &numBd);CHKERRQ(ierr);
5750   for (bd = 0; bd < numBd; ++bd) {
5751     PetscInt  field;
5752     PetscBool isEssential;
5753 
5754     ierr = DMPlexGetBoundary(dm, bd, &isEssential, NULL, NULL, &field, NULL, NULL, NULL, NULL, NULL, NULL);CHKERRQ(ierr);
5755     if (isFE[field] && isEssential) ++numBC;
5756   }
5757   /* Add ghost cell boundaries for FVM */
5758   for (f = 0; f < numFields; ++f) if (!isFE[f] && cEndInterior >= 0) ++numBC;
5759   ierr = PetscCalloc3(numBC,&bcFields,numBC,&bcPoints,numBC,&bcComps);CHKERRQ(ierr);
5760   /* Constrain ghost cells for FV */
5761   for (f = 0; f < numFields; ++f) {
5762     PetscInt *newidx, c;
5763 
5764     if (isFE[f] || cEndInterior < 0) continue;
5765     ierr = PetscMalloc1(cEnd-cEndInterior,&newidx);CHKERRQ(ierr);
5766     for (c = cEndInterior; c < cEnd; ++c) newidx[c-cEndInterior] = c;
5767     bcFields[bc] = f;
5768     ierr = ISCreateGeneral(PetscObjectComm((PetscObject) dm), cEnd-cEndInterior, newidx, PETSC_OWN_POINTER, &bcPoints[bc++]);CHKERRQ(ierr);
5769   }
5770   /* Handle FEM Dirichlet boundaries */
5771   for (bd = 0; bd < numBd; ++bd) {
5772     const char     *bdLabel;
5773     DMLabel         label;
5774     const PetscInt *comps;
5775     const PetscInt *values;
5776     PetscInt        bd2, field, numComps, numValues;
5777     PetscBool       isEssential, duplicate = PETSC_FALSE;
5778 
5779     ierr = DMPlexGetBoundary(dm, bd, &isEssential, NULL, &bdLabel, &field, &numComps, &comps, NULL, &numValues, &values, NULL);CHKERRQ(ierr);
5780     if (!isFE[field]) continue;
5781     ierr = DMPlexGetLabel(dm, bdLabel, &label);CHKERRQ(ierr);
5782     /* Only want to modify label once */
5783     for (bd2 = 0; bd2 < bd; ++bd2) {
5784       const char *bdname;
5785       ierr = DMPlexGetBoundary(dm, bd2, NULL, NULL, &bdname, NULL, NULL, NULL, NULL, NULL, NULL, NULL);CHKERRQ(ierr);
5786       ierr = PetscStrcmp(bdname, bdLabel, &duplicate);CHKERRQ(ierr);
5787       if (duplicate) break;
5788     }
5789     if (!duplicate && (isFE[field])) {
5790       ierr = DMPlexLabelComplete(dm, label);CHKERRQ(ierr);
5791       ierr = DMPlexLabelAddCells(dm, label);CHKERRQ(ierr);
5792     }
5793     /* Filter out cells, if you actually want to constrain cells you need to do things by hand right now */
5794     if (isEssential) {
5795       PetscInt       *newidx;
5796       PetscInt        n, newn = 0, p, v;
5797 
5798       bcFields[bc] = field;
5799       if (numComps) {ierr = ISCreateGeneral(PetscObjectComm((PetscObject) dm), numComps, comps, PETSC_COPY_VALUES, &bcComps[bc]);CHKERRQ(ierr);}
5800       for (v = 0; v < numValues; ++v) {
5801         IS              tmp;
5802         const PetscInt *idx;
5803 
5804         ierr = DMPlexGetStratumIS(dm, bdLabel, values[v], &tmp);CHKERRQ(ierr);
5805         if (!tmp) continue;
5806         ierr = ISGetLocalSize(tmp, &n);CHKERRQ(ierr);
5807         ierr = ISGetIndices(tmp, &idx);CHKERRQ(ierr);
5808         if (isFE[field]) {
5809           for (p = 0; p < n; ++p) if ((idx[p] < cStart) || (idx[p] >= cEnd)) ++newn;
5810         } else {
5811           for (p = 0; p < n; ++p) if ((idx[p] >= cStart) || (idx[p] < cEnd)) ++newn;
5812         }
5813         ierr = ISRestoreIndices(tmp, &idx);CHKERRQ(ierr);
5814         ierr = ISDestroy(&tmp);CHKERRQ(ierr);
5815       }
5816       ierr = PetscMalloc1(newn,&newidx);CHKERRQ(ierr);
5817       newn = 0;
5818       for (v = 0; v < numValues; ++v) {
5819         IS              tmp;
5820         const PetscInt *idx;
5821 
5822         ierr = DMPlexGetStratumIS(dm, bdLabel, values[v], &tmp);CHKERRQ(ierr);
5823         if (!tmp) continue;
5824         ierr = ISGetLocalSize(tmp, &n);CHKERRQ(ierr);
5825         ierr = ISGetIndices(tmp, &idx);CHKERRQ(ierr);
5826         if (isFE[field]) {
5827           for (p = 0; p < n; ++p) if ((idx[p] < cStart) || (idx[p] >= cEnd)) newidx[newn++] = idx[p];
5828         } else {
5829           for (p = 0; p < n; ++p) if ((idx[p] >= cStart) || (idx[p] < cEnd)) newidx[newn++] = idx[p];
5830         }
5831         ierr = ISRestoreIndices(tmp, &idx);CHKERRQ(ierr);
5832         ierr = ISDestroy(&tmp);CHKERRQ(ierr);
5833       }
5834       ierr = ISCreateGeneral(PetscObjectComm((PetscObject) dm), newn, newidx, PETSC_OWN_POINTER, &bcPoints[bc++]);CHKERRQ(ierr);
5835     }
5836   }
5837   /* Handle discretization */
5838   ierr = PetscCalloc2(numFields,&numComp,numFields*(dim+1),&numDof);CHKERRQ(ierr);
5839   for (f = 0; f < numFields; ++f) {
5840     PetscObject obj;
5841 
5842     ierr = DMGetField(dm, f, &obj);CHKERRQ(ierr);
5843     if (isFE[f]) {
5844       PetscFE         fe = (PetscFE) obj;
5845       const PetscInt *numFieldDof;
5846       PetscInt        d;
5847 
5848       ierr = PetscFEGetNumComponents(fe, &numComp[f]);CHKERRQ(ierr);
5849       ierr = PetscFEGetNumDof(fe, &numFieldDof);CHKERRQ(ierr);
5850       for (d = 0; d < dim+1; ++d) numDof[f*(dim+1)+d] = numFieldDof[d];
5851     } else {
5852       PetscFV fv = (PetscFV) obj;
5853 
5854       ierr = PetscFVGetNumComponents(fv, &numComp[f]);CHKERRQ(ierr);
5855       numDof[f*(dim+1)+dim] = numComp[f];
5856     }
5857   }
5858   for (f = 0; f < numFields; ++f) {
5859     PetscInt d;
5860     for (d = 1; d < dim; ++d) {
5861       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.");
5862     }
5863   }
5864   ierr = DMPlexCreateSection(dm, dim, numFields, numComp, numDof, numBC, bcFields, bcComps, bcPoints, NULL, &section);CHKERRQ(ierr);
5865   for (f = 0; f < numFields; ++f) {
5866     PetscFE     fe;
5867     const char *name;
5868 
5869     ierr = DMGetField(dm, f, (PetscObject *) &fe);CHKERRQ(ierr);
5870     ierr = PetscObjectGetName((PetscObject) fe, &name);CHKERRQ(ierr);
5871     ierr = PetscSectionSetFieldName(section, f, name);CHKERRQ(ierr);
5872   }
5873   ierr = DMSetDefaultSection(dm, section);CHKERRQ(ierr);
5874   ierr = PetscSectionDestroy(&section);CHKERRQ(ierr);
5875   for (bc = 0; bc < numBC; ++bc) {ierr = ISDestroy(&bcPoints[bc]);CHKERRQ(ierr);ierr = ISDestroy(&bcComps[bc]);CHKERRQ(ierr);}
5876   ierr = PetscFree3(bcFields,bcPoints,bcComps);CHKERRQ(ierr);
5877   ierr = PetscFree2(numComp,numDof);CHKERRQ(ierr);
5878   ierr = PetscFree(isFE);CHKERRQ(ierr);
5879   PetscFunctionReturn(0);
5880 }
5881 
5882 #undef __FUNCT__
5883 #define __FUNCT__ "DMPlexGetCoarseDM"
5884 /*@
5885   DMPlexGetCoarseDM - Get the coarse mesh from which this was obtained by refinement
5886 
5887   Input Parameter:
5888 . dm - The DMPlex object
5889 
5890   Output Parameter:
5891 . cdm - The coarse DM
5892 
5893   Level: intermediate
5894 
5895 .seealso: DMPlexSetCoarseDM()
5896 @*/
5897 PetscErrorCode DMPlexGetCoarseDM(DM dm, DM *cdm)
5898 {
5899   PetscFunctionBegin;
5900   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5901   PetscValidPointer(cdm, 2);
5902   *cdm = ((DM_Plex *) dm->data)->coarseMesh;
5903   PetscFunctionReturn(0);
5904 }
5905 
5906 #undef __FUNCT__
5907 #define __FUNCT__ "DMPlexSetCoarseDM"
5908 /*@
5909   DMPlexSetCoarseDM - Set the coarse mesh from which this was obtained by refinement
5910 
5911   Input Parameters:
5912 + dm - The DMPlex object
5913 - cdm - The coarse DM
5914 
5915   Level: intermediate
5916 
5917 .seealso: DMPlexGetCoarseDM()
5918 @*/
5919 PetscErrorCode DMPlexSetCoarseDM(DM dm, DM cdm)
5920 {
5921   DM_Plex       *mesh;
5922   PetscErrorCode ierr;
5923 
5924   PetscFunctionBegin;
5925   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5926   if (cdm) PetscValidHeaderSpecific(cdm, DM_CLASSID, 2);
5927   mesh = (DM_Plex *) dm->data;
5928   ierr = DMDestroy(&mesh->coarseMesh);CHKERRQ(ierr);
5929   mesh->coarseMesh = cdm;
5930   ierr = PetscObjectReference((PetscObject) mesh->coarseMesh);CHKERRQ(ierr);
5931   PetscFunctionReturn(0);
5932 }
5933 
5934 #undef __FUNCT__
5935 #define __FUNCT__ "DMPlexGetRegularRefinement"
5936 /*@
5937   DMPlexGetRegularRefinement - Get the flag indicating that this mesh was obtained by regular refinement from its coarse mesh
5938 
5939   Input Parameter:
5940 . dm - The DMPlex object
5941 
5942   Output Parameter:
5943 . regular - The flag
5944 
5945   Level: intermediate
5946 
5947 .seealso: DMPlexSetRegularRefinement()
5948 @*/
5949 PetscErrorCode DMPlexGetRegularRefinement(DM dm, PetscBool *regular)
5950 {
5951   PetscFunctionBegin;
5952   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5953   PetscValidPointer(regular, 2);
5954   *regular = ((DM_Plex *) dm->data)->regularRefinement;
5955   PetscFunctionReturn(0);
5956 }
5957 
5958 #undef __FUNCT__
5959 #define __FUNCT__ "DMPlexSetRegularRefinement"
5960 /*@
5961   DMPlexSetRegularRefinement - Set the flag indicating that this mesh was obtained by regular refinement from its coarse mesh
5962 
5963   Input Parameters:
5964 + dm - The DMPlex object
5965 - regular - The flag
5966 
5967   Level: intermediate
5968 
5969 .seealso: DMPlexGetRegularRefinement()
5970 @*/
5971 PetscErrorCode DMPlexSetRegularRefinement(DM dm, PetscBool regular)
5972 {
5973   PetscFunctionBegin;
5974   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5975   ((DM_Plex *) dm->data)->regularRefinement = regular;
5976   PetscFunctionReturn(0);
5977 }
5978 
5979 /* anchors */
5980 #undef __FUNCT__
5981 #define __FUNCT__ "DMPlexGetAnchors"
5982 /*@
5983   DMPlexGetAnchors - Get the layout of the anchor (point-to-point) constraints.  Typically, the user will not have to
5984   call DMPlexGetAnchors() directly: if there are anchors, then DMPlexGetAnchors() is called during DMGetConstraints().
5985 
5986   not collective
5987 
5988   Input Parameters:
5989 . dm - The DMPlex object
5990 
5991   Output Parameters:
5992 + anchorSection - If not NULL, set to the section describing which points anchor the constrained points.
5993 - anchorIS - If not NULL, set to the list of anchors indexed by anchorSection
5994 
5995 
5996   Level: intermediate
5997 
5998 .seealso: DMPlexSetAnchors(), DMGetConstraints(), DMSetConstraints()
5999 @*/
6000 PetscErrorCode DMPlexGetAnchors(DM dm, PetscSection *anchorSection, IS *anchorIS)
6001 {
6002   DM_Plex *plex = (DM_Plex *)dm->data;
6003   PetscErrorCode ierr;
6004 
6005   PetscFunctionBegin;
6006   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6007   if (!plex->anchorSection && !plex->anchorIS && plex->createanchors) {ierr = (*plex->createanchors)(dm);CHKERRQ(ierr);}
6008   if (anchorSection) *anchorSection = plex->anchorSection;
6009   if (anchorIS) *anchorIS = plex->anchorIS;
6010   PetscFunctionReturn(0);
6011 }
6012 
6013 #undef __FUNCT__
6014 #define __FUNCT__ "DMPlexSetAnchors"
6015 /*@
6016   DMPlexSetAnchors - Set the layout of the local anchor (point-to-point) constraints.  Unlike boundary conditions,
6017   when a point's degrees of freedom in a section are constrained to an outside value, the anchor constraints set a
6018   point's degrees of freedom to be a linear combination of other points' degrees of freedom.
6019 
6020   After specifying the layout of constraints with DMPlexSetAnchors(), one specifies the constraints by calling
6021   DMGetConstraints() and filling in the entries in the constraint matrix.
6022 
6023   collective on dm
6024 
6025   Input Parameters:
6026 + dm - The DMPlex object
6027 . 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).
6028 - anchorIS - The list of all anchor points.  Must have a local communicator (PETSC_COMM_SELF or derivative).
6029 
6030   The reference counts of anchorSection and anchorIS are incremented.
6031 
6032   Level: intermediate
6033 
6034 .seealso: DMPlexGetAnchors(), DMGetConstraints(), DMSetConstraints()
6035 @*/
6036 PetscErrorCode DMPlexSetAnchors(DM dm, PetscSection anchorSection, IS anchorIS)
6037 {
6038   DM_Plex        *plex = (DM_Plex *)dm->data;
6039   PetscMPIInt    result;
6040   PetscErrorCode ierr;
6041 
6042   PetscFunctionBegin;
6043   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6044   if (anchorSection) {
6045     PetscValidHeaderSpecific(anchorSection,PETSC_SECTION_CLASSID,2);
6046     ierr = MPI_Comm_compare(PETSC_COMM_SELF,PetscObjectComm((PetscObject)anchorSection),&result);CHKERRQ(ierr);
6047     if (result != MPI_CONGRUENT) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_NOTSAMECOMM,"anchor section must have local communicator");
6048   }
6049   if (anchorIS) {
6050     PetscValidHeaderSpecific(anchorIS,IS_CLASSID,3);
6051     ierr = MPI_Comm_compare(PETSC_COMM_SELF,PetscObjectComm((PetscObject)anchorIS),&result);CHKERRQ(ierr);
6052     if (result != MPI_CONGRUENT) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_NOTSAMECOMM,"anchor IS must have local communicator");
6053   }
6054 
6055   ierr = PetscObjectReference((PetscObject)anchorSection);CHKERRQ(ierr);
6056   ierr = PetscSectionDestroy(&plex->anchorSection);CHKERRQ(ierr);
6057   plex->anchorSection = anchorSection;
6058 
6059   ierr = PetscObjectReference((PetscObject)anchorIS);CHKERRQ(ierr);
6060   ierr = ISDestroy(&plex->anchorIS);CHKERRQ(ierr);
6061   plex->anchorIS = anchorIS;
6062 
6063 #if defined(PETSC_USE_DEBUG)
6064   if (anchorIS && anchorSection) {
6065     PetscInt size, a, pStart, pEnd;
6066     const PetscInt *anchors;
6067 
6068     ierr = PetscSectionGetChart(anchorSection,&pStart,&pEnd);CHKERRQ(ierr);
6069     ierr = ISGetLocalSize(anchorIS,&size);CHKERRQ(ierr);
6070     ierr = ISGetIndices(anchorIS,&anchors);CHKERRQ(ierr);
6071     for (a = 0; a < size; a++) {
6072       PetscInt p;
6073 
6074       p = anchors[a];
6075       if (p >= pStart && p < pEnd) {
6076         PetscInt dof;
6077 
6078         ierr = PetscSectionGetDof(anchorSection,p,&dof);CHKERRQ(ierr);
6079         if (dof) {
6080           PetscErrorCode ierr2;
6081 
6082           ierr2 = ISRestoreIndices(anchorIS,&anchors);CHKERRQ(ierr2);
6083           SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Point %d cannot be constrained and an anchor",p);
6084         }
6085       }
6086     }
6087     ierr = ISRestoreIndices(anchorIS,&anchors);CHKERRQ(ierr);
6088   }
6089 #endif
6090   /* reset the generic constraints */
6091   ierr = DMSetDefaultConstraints(dm,NULL,NULL);CHKERRQ(ierr);
6092   PetscFunctionReturn(0);
6093 }
6094 
6095 #undef __FUNCT__
6096 #define __FUNCT__ "DMPlexCreateConstraintSection_Anchors"
6097 static PetscErrorCode DMPlexCreateConstraintSection_Anchors(DM dm, PetscSection section, PetscSection *cSec)
6098 {
6099   PetscSection anchorSection;
6100   PetscInt pStart, pEnd, sStart, sEnd, p, dof, numFields, f;
6101   PetscErrorCode ierr;
6102 
6103   PetscFunctionBegin;
6104   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6105   ierr = DMPlexGetAnchors(dm,&anchorSection,NULL);CHKERRQ(ierr);
6106   ierr = PetscSectionCreate(PETSC_COMM_SELF,cSec);CHKERRQ(ierr);
6107   ierr = PetscSectionGetNumFields(section,&numFields);CHKERRQ(ierr);
6108   if (numFields) {
6109     ierr = PetscSectionSetNumFields(*cSec,numFields);CHKERRQ(ierr);
6110   }
6111   ierr = PetscSectionGetChart(anchorSection,&pStart,&pEnd);CHKERRQ(ierr);
6112   ierr = PetscSectionGetChart(section,&sStart,&sEnd);CHKERRQ(ierr);
6113   pStart = PetscMax(pStart,sStart);
6114   pEnd   = PetscMin(pEnd,sEnd);
6115   pEnd   = PetscMax(pStart,pEnd);
6116   ierr = PetscSectionSetChart(*cSec,pStart,pEnd);CHKERRQ(ierr);
6117   for (p = pStart; p < pEnd; p++) {
6118     ierr = PetscSectionGetDof(anchorSection,p,&dof);CHKERRQ(ierr);
6119     if (dof) {
6120       ierr = PetscSectionGetDof(section,p,&dof);CHKERRQ(ierr);
6121       ierr = PetscSectionSetDof(*cSec,p,dof);CHKERRQ(ierr);
6122       for (f = 0; f < numFields; f++) {
6123         ierr = PetscSectionGetFieldDof(section,p,f,&dof);CHKERRQ(ierr);
6124         ierr = PetscSectionSetFieldDof(*cSec,p,f,dof);CHKERRQ(ierr);
6125       }
6126     }
6127   }
6128   ierr = PetscSectionSetUp(*cSec);CHKERRQ(ierr);
6129   PetscFunctionReturn(0);
6130 }
6131 
6132 #undef __FUNCT__
6133 #define __FUNCT__ "DMPlexCreateConstraintMatrix_Anchors"
6134 static PetscErrorCode DMPlexCreateConstraintMatrix_Anchors(DM dm, PetscSection section, PetscSection cSec, Mat *cMat)
6135 {
6136   PetscSection aSec;
6137   PetscInt pStart, pEnd, p, dof, aDof, aOff, off, nnz, annz, m, n, q, a, offset, *i, *j;
6138   const PetscInt *anchors;
6139   PetscInt numFields, f;
6140   IS aIS;
6141   PetscErrorCode ierr;
6142 
6143   PetscFunctionBegin;
6144   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6145   ierr = PetscSectionGetStorageSize(cSec, &m);CHKERRQ(ierr);
6146   ierr = PetscSectionGetStorageSize(section, &n);CHKERRQ(ierr);
6147   ierr = MatCreate(PETSC_COMM_SELF,cMat);CHKERRQ(ierr);
6148   ierr = MatSetSizes(*cMat,m,n,m,n);CHKERRQ(ierr);
6149   ierr = MatSetType(*cMat,MATSEQAIJ);CHKERRQ(ierr);
6150   ierr = DMPlexGetAnchors(dm,&aSec,&aIS);CHKERRQ(ierr);
6151   ierr = ISGetIndices(aIS,&anchors);CHKERRQ(ierr);
6152   /* cSec will be a subset of aSec and section */
6153   ierr = PetscSectionGetChart(cSec,&pStart,&pEnd);CHKERRQ(ierr);
6154   ierr = PetscMalloc1(m+1,&i);CHKERRQ(ierr);
6155   i[0] = 0;
6156   ierr = PetscSectionGetNumFields(section,&numFields);CHKERRQ(ierr);
6157   for (p = pStart; p < pEnd; p++) {
6158     ierr = PetscSectionGetDof(aSec,p,&dof);CHKERRQ(ierr);
6159     if (!dof) continue;
6160     ierr = PetscSectionGetOffset(aSec,p,&off);CHKERRQ(ierr);
6161     if (numFields) {
6162       for (f = 0; f < numFields; f++) {
6163         annz = 0;
6164         for (q = 0; q < dof; q++) {
6165           a = anchors[off + q];
6166           ierr = PetscSectionGetFieldDof(section,a,f,&aDof);CHKERRQ(ierr);
6167           annz += aDof;
6168         }
6169         ierr = PetscSectionGetFieldDof(cSec,p,f,&dof);CHKERRQ(ierr);
6170         ierr = PetscSectionGetFieldOffset(cSec,p,f,&off);CHKERRQ(ierr);
6171         for (q = 0; q < dof; q++) {
6172           i[off + q + 1] = i[off + q] + annz;
6173         }
6174       }
6175     }
6176     else {
6177       annz = 0;
6178       for (q = 0; q < dof; q++) {
6179         a = anchors[off + q];
6180         ierr = PetscSectionGetDof(section,a,&aDof);CHKERRQ(ierr);
6181         annz += aDof;
6182       }
6183       ierr = PetscSectionGetDof(cSec,p,&dof);CHKERRQ(ierr);
6184       ierr = PetscSectionGetOffset(cSec,p,&off);CHKERRQ(ierr);
6185       for (q = 0; q < dof; q++) {
6186         i[off + q + 1] = i[off + q] + annz;
6187       }
6188     }
6189   }
6190   nnz = i[m];
6191   ierr = PetscMalloc1(nnz,&j);CHKERRQ(ierr);
6192   offset = 0;
6193   for (p = pStart; p < pEnd; p++) {
6194     if (numFields) {
6195       for (f = 0; f < numFields; f++) {
6196         ierr = PetscSectionGetFieldDof(cSec,p,f,&dof);CHKERRQ(ierr);
6197         for (q = 0; q < dof; q++) {
6198           PetscInt rDof, rOff, r;
6199           ierr = PetscSectionGetDof(aSec,p,&rDof);CHKERRQ(ierr);
6200           ierr = PetscSectionGetOffset(aSec,p,&rOff);CHKERRQ(ierr);
6201           for (r = 0; r < rDof; r++) {
6202             PetscInt s;
6203 
6204             a = anchors[rOff + r];
6205             ierr = PetscSectionGetFieldDof(section,a,f,&aDof);CHKERRQ(ierr);
6206             ierr = PetscSectionGetFieldOffset(section,a,f,&aOff);CHKERRQ(ierr);
6207             for (s = 0; s < aDof; s++) {
6208               j[offset++] = aOff + s;
6209             }
6210           }
6211         }
6212       }
6213     }
6214     else {
6215       ierr = PetscSectionGetDof(cSec,p,&dof);CHKERRQ(ierr);
6216       for (q = 0; q < dof; q++) {
6217         PetscInt rDof, rOff, r;
6218         ierr = PetscSectionGetDof(aSec,p,&rDof);CHKERRQ(ierr);
6219         ierr = PetscSectionGetOffset(aSec,p,&rOff);CHKERRQ(ierr);
6220         for (r = 0; r < rDof; r++) {
6221           PetscInt s;
6222 
6223           a = anchors[rOff + r];
6224           ierr = PetscSectionGetDof(section,a,&aDof);CHKERRQ(ierr);
6225           ierr = PetscSectionGetOffset(section,a,&aOff);CHKERRQ(ierr);
6226           for (s = 0; s < aDof; s++) {
6227             j[offset++] = aOff + s;
6228           }
6229         }
6230       }
6231     }
6232   }
6233   ierr = MatSeqAIJSetPreallocationCSR(*cMat,i,j,NULL);CHKERRQ(ierr);
6234   ierr = PetscFree(i);CHKERRQ(ierr);
6235   ierr = PetscFree(j);CHKERRQ(ierr);
6236   ierr = ISRestoreIndices(aIS,&anchors);CHKERRQ(ierr);
6237   PetscFunctionReturn(0);
6238 }
6239 
6240 #undef __FUNCT__
6241 #define __FUNCT__ "DMCreateDefaultConstraints_Plex"
6242 PetscErrorCode DMCreateDefaultConstraints_Plex(DM dm)
6243 {
6244   DM_Plex        *plex = (DM_Plex *)dm->data;
6245   PetscSection   anchorSection, section, cSec;
6246   Mat            cMat;
6247   PetscErrorCode ierr;
6248 
6249   PetscFunctionBegin;
6250   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6251   ierr = DMPlexGetAnchors(dm,&anchorSection,NULL);CHKERRQ(ierr);
6252   if (anchorSection) {
6253     PetscDS  ds;
6254     PetscInt nf;
6255 
6256     ierr = DMGetDefaultSection(dm,&section);CHKERRQ(ierr);
6257     ierr = DMPlexCreateConstraintSection_Anchors(dm,section,&cSec);CHKERRQ(ierr);
6258     ierr = DMPlexCreateConstraintMatrix_Anchors(dm,section,cSec,&cMat);CHKERRQ(ierr);
6259     ierr = DMGetDS(dm,&ds);CHKERRQ(ierr);
6260     ierr = PetscDSGetNumFields(ds,&nf);CHKERRQ(ierr);
6261     if (nf && plex->computeanchormatrix) {ierr = (*plex->computeanchormatrix)(dm,section,cSec,cMat);CHKERRQ(ierr);}
6262     ierr = DMSetDefaultConstraints(dm,cSec,cMat);CHKERRQ(ierr);
6263     ierr = PetscSectionDestroy(&cSec);CHKERRQ(ierr);
6264     ierr = MatDestroy(&cMat);CHKERRQ(ierr);
6265   }
6266   PetscFunctionReturn(0);
6267 }
6268