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