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