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