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