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