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