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