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