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