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