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