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