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