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