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