xref: /petsc/src/dm/impls/plex/plex.c (revision 341678547508e47cff562fc13f1ac7d91217da63)
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       }
2950     }
2951   }
2952   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
2953   ierr = PetscSectionSetChart(*section, pStart, pEnd);CHKERRQ(ierr);
2954   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
2955   ierr = PetscMalloc1(depth+1,&pMax);CHKERRQ(ierr);
2956   ierr = DMPlexGetHybridBounds(dm, depth >= 0 ? &pMax[depth] : NULL, depth>1 ? &pMax[depth-1] : NULL, depth>2 ? &pMax[1] : NULL, &pMax[0]);CHKERRQ(ierr);
2957   for (dep = 0; dep <= depth; ++dep) {
2958     d    = dim == depth ? dep : (!dep ? 0 : dim);
2959     ierr = DMPlexGetDepthStratum(dm, dep, &pStart, &pEnd);CHKERRQ(ierr);
2960     pMax[dep] = pMax[dep] < 0 ? pEnd : pMax[dep];
2961     for (p = pStart; p < pEnd; ++p) {
2962       PetscInt tot = 0;
2963 
2964       for (f = 0; f < numFields; ++f) {
2965         if (isFE[f] && p >= pMax[dep]) continue;
2966         ierr = PetscSectionSetFieldDof(*section, p, f, numDof[f*(dim+1)+d]);CHKERRQ(ierr);
2967         tot += numDof[f*(dim+1)+d];
2968       }
2969       ierr = PetscSectionSetDof(*section, p, tot);CHKERRQ(ierr);
2970     }
2971   }
2972   ierr = PetscFree(pMax);CHKERRQ(ierr);
2973   ierr = PetscFree(isFE);CHKERRQ(ierr);
2974   PetscFunctionReturn(0);
2975 }
2976 
2977 #undef __FUNCT__
2978 #define __FUNCT__ "DMPlexCreateSectionBCDof"
2979 /* Set the number of dof on each point and separate by fields
2980    If bcComps is NULL or the IS is NULL, constrain every dof on the point
2981 */
2982 PetscErrorCode DMPlexCreateSectionBCDof(DM dm, PetscInt numBC, const PetscInt bcField[], const IS bcComps[], const IS bcPoints[], PetscSection section)
2983 {
2984   PetscInt       numFields;
2985   PetscInt       bc;
2986   PetscSection   aSec;
2987   PetscErrorCode ierr;
2988 
2989   PetscFunctionBegin;
2990   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
2991   for (bc = 0; bc < numBC; ++bc) {
2992     PetscInt        field = 0;
2993     const PetscInt *comp;
2994     const PetscInt *idx;
2995     PetscInt        Nc = -1, n, i;
2996 
2997     if (numFields) field = bcField[bc];
2998     if (bcComps && bcComps[bc]) {ierr = ISGetLocalSize(bcComps[bc], &Nc);CHKERRQ(ierr);}
2999     if (bcComps && bcComps[bc]) {ierr = ISGetIndices(bcComps[bc], &comp);CHKERRQ(ierr);}
3000     ierr = ISGetLocalSize(bcPoints[bc], &n);CHKERRQ(ierr);
3001     ierr = ISGetIndices(bcPoints[bc], &idx);CHKERRQ(ierr);
3002     for (i = 0; i < n; ++i) {
3003       const PetscInt p = idx[i];
3004       PetscInt       numConst;
3005 
3006       if (numFields) {
3007         ierr = PetscSectionGetFieldDof(section, p, field, &numConst);CHKERRQ(ierr);
3008       } else {
3009         ierr = PetscSectionGetDof(section, p, &numConst);CHKERRQ(ierr);
3010       }
3011       /* If Nc < 0, constrain every dof on the point */
3012       if (Nc > 0) numConst = PetscMin(numConst, Nc);
3013       if (numFields) {ierr = PetscSectionAddFieldConstraintDof(section, p, field, numConst);CHKERRQ(ierr);}
3014       ierr = PetscSectionAddConstraintDof(section, p, numConst);CHKERRQ(ierr);
3015     }
3016     ierr = ISRestoreIndices(bcPoints[bc], &idx);CHKERRQ(ierr);
3017     if (bcComps && bcComps[bc]) {ierr = ISRestoreIndices(bcComps[bc], &comp);CHKERRQ(ierr);}
3018   }
3019   ierr = DMPlexGetAnchors(dm, &aSec, NULL);CHKERRQ(ierr);
3020   if (aSec) {
3021     PetscInt aStart, aEnd, a;
3022 
3023     ierr = PetscSectionGetChart(aSec, &aStart, &aEnd);CHKERRQ(ierr);
3024     for (a = aStart; a < aEnd; a++) {
3025       PetscInt dof, f;
3026 
3027       ierr = PetscSectionGetDof(aSec, a, &dof);CHKERRQ(ierr);
3028       if (dof) {
3029         /* if there are point-to-point constraints, then all dofs are constrained */
3030         ierr = PetscSectionGetDof(section, a, &dof);CHKERRQ(ierr);
3031         ierr = PetscSectionSetConstraintDof(section, a, dof);CHKERRQ(ierr);
3032         for (f = 0; f < numFields; f++) {
3033           ierr = PetscSectionGetFieldDof(section, a, f, &dof);CHKERRQ(ierr);
3034           ierr = PetscSectionSetFieldConstraintDof(section, a, f, dof);CHKERRQ(ierr);
3035         }
3036       }
3037     }
3038   }
3039   PetscFunctionReturn(0);
3040 }
3041 
3042 #undef __FUNCT__
3043 #define __FUNCT__ "DMPlexCreateSectionBCIndicesField"
3044 /* Set the constrained field indices on each point
3045    If bcComps is NULL or the IS is NULL, constrain every dof on the point
3046 */
3047 PetscErrorCode DMPlexCreateSectionBCIndicesField(DM dm, PetscInt numBC,const PetscInt bcField[], const IS bcComps[], const IS bcPoints[], PetscSection section)
3048 {
3049   PetscSection   aSec;
3050   PetscInt      *indices;
3051   PetscInt       numFields, maxDof, pStart, pEnd, p, bc, f, d;
3052   PetscErrorCode ierr;
3053 
3054   PetscFunctionBegin;
3055   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
3056   if (!numFields) PetscFunctionReturn(0);
3057   /* Initialize all field indices to -1 */
3058   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
3059   ierr = PetscSectionGetMaxDof(section, &maxDof);CHKERRQ(ierr);
3060   ierr = PetscMalloc1(maxDof, &indices);CHKERRQ(ierr);
3061   for (d = 0; d < maxDof; ++d) indices[d] = -1;
3062   for (p = pStart; p < pEnd; ++p) for (f = 0; f < numFields; ++f) {ierr = PetscSectionSetFieldConstraintIndices(section, p, f, indices);CHKERRQ(ierr);}
3063   /* Handle BC constraints */
3064   for (bc = 0; bc < numBC; ++bc) {
3065     const PetscInt  field = bcField[bc];
3066     const PetscInt *comp, *idx;
3067     PetscInt        Nc = -1, n, i;
3068 
3069     if (bcComps && bcComps[bc]) {ierr = ISGetLocalSize(bcComps[bc], &Nc);CHKERRQ(ierr);}
3070     if (bcComps && bcComps[bc]) {ierr = ISGetIndices(bcComps[bc], &comp);CHKERRQ(ierr);}
3071     ierr = ISGetLocalSize(bcPoints[bc], &n);CHKERRQ(ierr);
3072     ierr = ISGetIndices(bcPoints[bc], &idx);CHKERRQ(ierr);
3073     for (i = 0; i < n; ++i) {
3074       const PetscInt  p = idx[i];
3075       const PetscInt *find;
3076       PetscInt        fcdof, c;
3077 
3078       ierr = PetscSectionGetFieldConstraintDof(section, p, field, &fcdof);CHKERRQ(ierr);
3079       if (Nc < 0) {
3080         for (d = 0; d < fcdof; ++d) indices[d] = d;
3081       } else {
3082         ierr = PetscSectionGetFieldConstraintIndices(section, p, field, &find);CHKERRQ(ierr);
3083         for (d = 0; d < fcdof; ++d) {if (find[d] < 0) break; indices[d] = find[d];}
3084         for (c = 0; c < Nc; ++c) indices[d+c] = comp[c];
3085         ierr = PetscSortInt(d+Nc, indices);CHKERRQ(ierr);
3086         for (c = d+Nc; c < fcdof; ++c) indices[c] = -1;
3087       }
3088       ierr = PetscSectionSetFieldConstraintIndices(section, p, field, indices);CHKERRQ(ierr);
3089     }
3090     if (bcComps && bcComps[bc]) {ierr = ISRestoreIndices(bcComps[bc], &comp);CHKERRQ(ierr);}
3091     ierr = ISRestoreIndices(bcPoints[bc], &idx);CHKERRQ(ierr);
3092   }
3093   /* Handle anchors */
3094   ierr = DMPlexGetAnchors(dm, &aSec, NULL);CHKERRQ(ierr);
3095   if (aSec) {
3096     PetscInt aStart, aEnd, a;
3097 
3098     for (d = 0; d < maxDof; ++d) indices[d] = d;
3099     ierr = PetscSectionGetChart(aSec, &aStart, &aEnd);CHKERRQ(ierr);
3100     for (a = aStart; a < aEnd; a++) {
3101       PetscInt dof, fdof, f;
3102 
3103       ierr = PetscSectionGetDof(aSec, a, &dof);CHKERRQ(ierr);
3104       if (dof) {
3105         /* if there are point-to-point constraints, then all dofs are constrained */
3106         for (f = 0; f < numFields; f++) {
3107           ierr = PetscSectionGetFieldDof(section, a, f, &fdof);CHKERRQ(ierr);
3108           ierr = PetscSectionSetFieldConstraintIndices(section, a, f, indices);CHKERRQ(ierr);
3109         }
3110       }
3111     }
3112   }
3113   ierr = PetscFree(indices);CHKERRQ(ierr);
3114   PetscFunctionReturn(0);
3115 }
3116 
3117 #undef __FUNCT__
3118 #define __FUNCT__ "DMPlexCreateSectionBCIndices"
3119 /* Set the constrained indices on each point */
3120 PetscErrorCode DMPlexCreateSectionBCIndices(DM dm, PetscSection section)
3121 {
3122   PetscInt      *indices;
3123   PetscInt       numFields, maxDof, pStart, pEnd, p, f, d;
3124   PetscErrorCode ierr;
3125 
3126   PetscFunctionBegin;
3127   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
3128   ierr = PetscSectionGetMaxDof(section, &maxDof);CHKERRQ(ierr);
3129   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
3130   ierr = PetscMalloc1(maxDof, &indices);CHKERRQ(ierr);
3131   for (d = 0; d < maxDof; ++d) indices[d] = -1;
3132   for (p = pStart; p < pEnd; ++p) {
3133     PetscInt cdof, d;
3134 
3135     ierr = PetscSectionGetConstraintDof(section, p, &cdof);CHKERRQ(ierr);
3136     if (cdof) {
3137       if (numFields) {
3138         PetscInt numConst = 0, foff = 0;
3139 
3140         for (f = 0; f < numFields; ++f) {
3141           const PetscInt *find;
3142           PetscInt        fcdof, fdof;
3143 
3144           ierr = PetscSectionGetFieldDof(section, p, f, &fdof);CHKERRQ(ierr);
3145           ierr = PetscSectionGetFieldConstraintDof(section, p, f, &fcdof);CHKERRQ(ierr);
3146           /* Change constraint numbering from field component to local dof number */
3147           ierr = PetscSectionGetFieldConstraintIndices(section, p, f, &find);CHKERRQ(ierr);
3148           for (d = 0; d < fcdof; ++d) indices[numConst+d] = find[d] + foff;
3149           numConst += fcdof;
3150           foff     += fdof;
3151         }
3152         if (cdof != numConst) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_LIB, "Total number of field constraints %D should be %D", numConst, cdof);
3153       } else {
3154         for (d = 0; d < cdof; ++d) indices[d] = d;
3155       }
3156       ierr = PetscSectionSetConstraintIndices(section, p, indices);CHKERRQ(ierr);
3157     }
3158   }
3159   ierr = PetscFree(indices);CHKERRQ(ierr);
3160   PetscFunctionReturn(0);
3161 }
3162 
3163 #undef __FUNCT__
3164 #define __FUNCT__ "DMPlexCreateSection"
3165 /*@C
3166   DMPlexCreateSection - Create a PetscSection based upon the dof layout specification provided.
3167 
3168   Not Collective
3169 
3170   Input Parameters:
3171 + dm        - The DMPlex object
3172 . dim       - The spatial dimension of the problem
3173 . numFields - The number of fields in the problem
3174 . numComp   - An array of size numFields that holds the number of components for each field
3175 . numDof    - An array of size numFields*(dim+1) which holds the number of dof for each field on a mesh piece of dimension d
3176 . numBC     - The number of boundary conditions
3177 . bcField   - An array of size numBC giving the field number for each boundry condition
3178 . bcComps   - [Optional] An array of size numBC giving an IS holding the field components to which each boundary condition applies
3179 . bcPoints  - An array of size numBC giving an IS holding the Plex points to which each boundary condition applies
3180 - perm      - Optional permutation of the chart, or NULL
3181 
3182   Output Parameter:
3183 . section - The PetscSection object
3184 
3185   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
3186   number of dof for field 0 on each edge.
3187 
3188   The chart permutation is the same one set using PetscSectionSetPermutation()
3189 
3190   Level: developer
3191 
3192   Fortran Notes:
3193   A Fortran 90 version is available as DMPlexCreateSectionF90()
3194 
3195 .keywords: mesh, elements
3196 .seealso: DMPlexCreate(), PetscSectionCreate(), PetscSectionSetPermutation()
3197 @*/
3198 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)
3199 {
3200   PetscSection   aSec;
3201   PetscErrorCode ierr;
3202 
3203   PetscFunctionBegin;
3204   ierr = DMPlexCreateSectionInitial(dm, dim, numFields, numComp, numDof, section);CHKERRQ(ierr);
3205   ierr = DMPlexCreateSectionBCDof(dm, numBC, bcField, bcComps, bcPoints, *section);CHKERRQ(ierr);
3206   if (perm) {ierr = PetscSectionSetPermutation(*section, perm);CHKERRQ(ierr);}
3207   ierr = PetscSectionSetUp(*section);CHKERRQ(ierr);
3208   ierr = DMPlexGetAnchors(dm,&aSec,NULL);CHKERRQ(ierr);
3209   if (numBC || aSec) {
3210     ierr = DMPlexCreateSectionBCIndicesField(dm, numBC, bcField, bcComps, bcPoints, *section);CHKERRQ(ierr);
3211     ierr = DMPlexCreateSectionBCIndices(dm, *section);CHKERRQ(ierr);
3212   }
3213   ierr = PetscSectionViewFromOptions(*section,NULL,"-section_view");CHKERRQ(ierr);
3214   PetscFunctionReturn(0);
3215 }
3216 
3217 #undef __FUNCT__
3218 #define __FUNCT__ "DMCreateCoordinateDM_Plex"
3219 PetscErrorCode DMCreateCoordinateDM_Plex(DM dm, DM *cdm)
3220 {
3221   PetscSection   section, s;
3222   Mat            m;
3223   PetscInt       maxHeight;
3224   PetscErrorCode ierr;
3225 
3226   PetscFunctionBegin;
3227   ierr = DMClone(dm, cdm);CHKERRQ(ierr);
3228   ierr = DMPlexGetMaxProjectionHeight(dm, &maxHeight);CHKERRQ(ierr);
3229   ierr = DMPlexSetMaxProjectionHeight(*cdm, maxHeight);CHKERRQ(ierr);
3230   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)dm), &section);CHKERRQ(ierr);
3231   ierr = DMSetDefaultSection(*cdm, section);CHKERRQ(ierr);
3232   ierr = PetscSectionDestroy(&section);CHKERRQ(ierr);
3233   ierr = PetscSectionCreate(PETSC_COMM_SELF, &s);CHKERRQ(ierr);
3234   ierr = MatCreate(PETSC_COMM_SELF, &m);CHKERRQ(ierr);
3235   ierr = DMSetDefaultConstraints(*cdm, s, m);CHKERRQ(ierr);
3236   ierr = PetscSectionDestroy(&s);CHKERRQ(ierr);
3237   ierr = MatDestroy(&m);CHKERRQ(ierr);
3238   PetscFunctionReturn(0);
3239 }
3240 
3241 #undef __FUNCT__
3242 #define __FUNCT__ "DMPlexGetConeSection"
3243 PetscErrorCode DMPlexGetConeSection(DM dm, PetscSection *section)
3244 {
3245   DM_Plex *mesh = (DM_Plex*) dm->data;
3246 
3247   PetscFunctionBegin;
3248   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3249   if (section) *section = mesh->coneSection;
3250   PetscFunctionReturn(0);
3251 }
3252 
3253 #undef __FUNCT__
3254 #define __FUNCT__ "DMPlexGetSupportSection"
3255 PetscErrorCode DMPlexGetSupportSection(DM dm, PetscSection *section)
3256 {
3257   DM_Plex *mesh = (DM_Plex*) dm->data;
3258 
3259   PetscFunctionBegin;
3260   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3261   if (section) *section = mesh->supportSection;
3262   PetscFunctionReturn(0);
3263 }
3264 
3265 #undef __FUNCT__
3266 #define __FUNCT__ "DMPlexGetCones"
3267 PetscErrorCode DMPlexGetCones(DM dm, PetscInt *cones[])
3268 {
3269   DM_Plex *mesh = (DM_Plex*) dm->data;
3270 
3271   PetscFunctionBegin;
3272   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3273   if (cones) *cones = mesh->cones;
3274   PetscFunctionReturn(0);
3275 }
3276 
3277 #undef __FUNCT__
3278 #define __FUNCT__ "DMPlexGetConeOrientations"
3279 PetscErrorCode DMPlexGetConeOrientations(DM dm, PetscInt *coneOrientations[])
3280 {
3281   DM_Plex *mesh = (DM_Plex*) dm->data;
3282 
3283   PetscFunctionBegin;
3284   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3285   if (coneOrientations) *coneOrientations = mesh->coneOrientations;
3286   PetscFunctionReturn(0);
3287 }
3288 
3289 /******************************** FEM Support **********************************/
3290 
3291 #undef __FUNCT__
3292 #define __FUNCT__ "DMPlexCreateSpectralClosurePermutation"
3293 PetscErrorCode DMPlexCreateSpectralClosurePermutation(DM dm, PetscSection section)
3294 {
3295   PetscInt      *perm;
3296   PetscInt       dim, eStart, k, Nf, f, Nc, c, i, size = 0, offset = 0, foffset = 0;
3297   PetscErrorCode ierr;
3298 
3299   PetscFunctionBegin;
3300   if (!section) {ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);}
3301   ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr);
3302   ierr = PetscSectionGetNumFields(section, &Nf);CHKERRQ(ierr);
3303   if (dim != 2) SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Can only do quads now");
3304   for (f = 0; f < Nf; ++f) {
3305     /* An order k SEM disc has k-1 dofs on an edge */
3306     ierr = DMPlexGetDepthStratum(dm, 1, &eStart, NULL);CHKERRQ(ierr);
3307     ierr = PetscSectionGetFieldDof(section, eStart, f, &k);CHKERRQ(ierr);
3308     ierr = PetscSectionGetFieldComponents(section, f, &Nc);CHKERRQ(ierr);
3309     k = k/Nc + 1;
3310     size += PetscSqr(k+1)*Nc;
3311   }
3312   ierr = PetscMalloc1(size, &perm);CHKERRQ(ierr);
3313   for (f = 0; f < Nf; ++f) {
3314     /* The original quad closure is oriented clockwise, {f, e_b, e_r, e_t, e_l, v_lb, v_rb, v_tr, v_tl} */
3315     ierr = DMPlexGetDepthStratum(dm, 1, &eStart, NULL);CHKERRQ(ierr);
3316     ierr = PetscSectionGetFieldDof(section, eStart, f, &k);CHKERRQ(ierr);
3317     ierr = PetscSectionGetFieldComponents(section, f, &Nc);CHKERRQ(ierr);
3318     k = k/Nc + 1;
3319     /* The SEM order is
3320 
3321        v_lb, {e_b}, v_rb,
3322        e^{(k-1)-i}_l, {f^{((k-1)-i)*(k-1)}}, e^i_r,
3323        v_lt, reverse {e_t}, v_rt
3324     */
3325     {
3326       const PetscInt of   = 0;
3327       const PetscInt oeb  = of   + PetscSqr(k-1);
3328       const PetscInt oer  = oeb  + (k-1);
3329       const PetscInt oet  = oer  + (k-1);
3330       const PetscInt oel  = oet  + (k-1);
3331       const PetscInt ovlb = oel  + (k-1);
3332       const PetscInt ovrb = ovlb + 1;
3333       const PetscInt ovrt = ovrb + 1;
3334       const PetscInt ovlt = ovrt + 1;
3335       PetscInt       o;
3336 
3337       /* bottom */
3338       for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlb*Nc + c + foffset;
3339       for (o = oeb; o < oer; ++o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
3340       for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrb*Nc + c + foffset;
3341       /* middle */
3342       for (i = 0; i < k-1; ++i) {
3343         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oel+(k-2)-i)*Nc + c + foffset;
3344         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;
3345         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oer+i)*Nc + c + foffset;
3346       }
3347       /* top */
3348       for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlt*Nc + c + foffset;
3349       for (o = oel-1; o >= oet; --o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
3350       for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrt*Nc + c + foffset;
3351       foffset = offset;
3352     }
3353   }
3354   /* Check permutation */
3355   {
3356     PetscInt *check;
3357 
3358     ierr = PetscMalloc1(size, &check);CHKERRQ(ierr);
3359     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]);}
3360     for (i = 0; i < size; ++i) check[perm[i]] = i;
3361     for (i = 0; i < size; ++i) {if (check[i] < 0) SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_PLIB, "Missing permutation index %D", i);}
3362     ierr = PetscFree(check);CHKERRQ(ierr);
3363   }
3364   ierr = PetscSectionSetClosurePermutation_Internal(section, (PetscObject) dm, size, PETSC_OWN_POINTER, perm);CHKERRQ(ierr);
3365   PetscFunctionReturn(0);
3366 }
3367 
3368 #undef __FUNCT__
3369 #define __FUNCT__ "DMPlexVecGetClosure_Depth1_Static"
3370 PETSC_STATIC_INLINE PetscErrorCode DMPlexVecGetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[])
3371 {
3372   PetscScalar    *array, *vArray;
3373   const PetscInt *cone, *coneO;
3374   PetscInt        pStart, pEnd, p, numPoints, size = 0, offset = 0;
3375   PetscErrorCode  ierr;
3376 
3377   PetscFunctionBeginHot;
3378   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
3379   ierr = DMPlexGetConeSize(dm, point, &numPoints);CHKERRQ(ierr);
3380   ierr = DMPlexGetCone(dm, point, &cone);CHKERRQ(ierr);
3381   ierr = DMPlexGetConeOrientation(dm, point, &coneO);CHKERRQ(ierr);
3382   if (!values || !*values) {
3383     if ((point >= pStart) && (point < pEnd)) {
3384       PetscInt dof;
3385 
3386       ierr = PetscSectionGetDof(section, point, &dof);CHKERRQ(ierr);
3387       size += dof;
3388     }
3389     for (p = 0; p < numPoints; ++p) {
3390       const PetscInt cp = cone[p];
3391       PetscInt       dof;
3392 
3393       if ((cp < pStart) || (cp >= pEnd)) continue;
3394       ierr = PetscSectionGetDof(section, cp, &dof);CHKERRQ(ierr);
3395       size += dof;
3396     }
3397     if (!values) {
3398       if (csize) *csize = size;
3399       PetscFunctionReturn(0);
3400     }
3401     ierr = DMGetWorkArray(dm, size, PETSC_SCALAR, &array);CHKERRQ(ierr);
3402   } else {
3403     array = *values;
3404   }
3405   size = 0;
3406   ierr = VecGetArray(v, &vArray);CHKERRQ(ierr);
3407   if ((point >= pStart) && (point < pEnd)) {
3408     PetscInt     dof, off, d;
3409     PetscScalar *varr;
3410 
3411     ierr = PetscSectionGetDof(section, point, &dof);CHKERRQ(ierr);
3412     ierr = PetscSectionGetOffset(section, point, &off);CHKERRQ(ierr);
3413     varr = &vArray[off];
3414     for (d = 0; d < dof; ++d, ++offset) {
3415       array[offset] = varr[d];
3416     }
3417     size += dof;
3418   }
3419   for (p = 0; p < numPoints; ++p) {
3420     const PetscInt cp = cone[p];
3421     PetscInt       o  = coneO[p];
3422     PetscInt       dof, off, d;
3423     PetscScalar   *varr;
3424 
3425     if ((cp < pStart) || (cp >= pEnd)) continue;
3426     ierr = PetscSectionGetDof(section, cp, &dof);CHKERRQ(ierr);
3427     ierr = PetscSectionGetOffset(section, cp, &off);CHKERRQ(ierr);
3428     varr = &vArray[off];
3429     if (o >= 0) {
3430       for (d = 0; d < dof; ++d, ++offset) {
3431         array[offset] = varr[d];
3432       }
3433     } else {
3434       for (d = dof-1; d >= 0; --d, ++offset) {
3435         array[offset] = varr[d];
3436       }
3437     }
3438     size += dof;
3439   }
3440   ierr = VecRestoreArray(v, &vArray);CHKERRQ(ierr);
3441   if (!*values) {
3442     if (csize) *csize = size;
3443     *values = array;
3444   } else {
3445     if (size > *csize) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %d < actual size %d", *csize, size);
3446     *csize = size;
3447   }
3448   PetscFunctionReturn(0);
3449 }
3450 
3451 #undef __FUNCT__
3452 #define __FUNCT__ "DMPlexVecGetClosure_Static"
3453 PETSC_STATIC_INLINE PetscErrorCode DMPlexVecGetClosure_Static(PetscSection section, PetscInt numPoints, const PetscInt points[], const PetscInt perm[], const PetscScalar vArray[], PetscInt *size, PetscScalar array[])
3454 {
3455   PetscInt       offset = 0, p;
3456   PetscErrorCode ierr;
3457 
3458   PetscFunctionBeginHot;
3459   *size = 0;
3460   for (p = 0; p < numPoints*2; p += 2) {
3461     const PetscInt point = points[p];
3462     const PetscInt o     = points[p+1];
3463     PetscInt       dof, off, d;
3464     const PetscScalar *varr;
3465 
3466     ierr = PetscSectionGetDof(section, point, &dof);CHKERRQ(ierr);
3467     ierr = PetscSectionGetOffset(section, point, &off);CHKERRQ(ierr);
3468     varr = &vArray[off];
3469     if (o >= 0) {
3470       for (d = 0; d < dof; ++d, ++offset)    array[perm ? perm[offset] : offset] = varr[d];
3471     } else {
3472       for (d = dof-1; d >= 0; --d, ++offset) array[perm ? perm[offset] : offset] = varr[d];
3473     }
3474   }
3475   *size = offset;
3476   PetscFunctionReturn(0);
3477 }
3478 
3479 #undef __FUNCT__
3480 #define __FUNCT__ "DMPlexVecGetClosure_Fields_Static"
3481 PETSC_STATIC_INLINE PetscErrorCode DMPlexVecGetClosure_Fields_Static(PetscSection section, PetscInt numPoints, const PetscInt points[], PetscInt numFields, const PetscInt perm[], const PetscScalar vArray[], PetscInt *size, PetscScalar array[])
3482 {
3483   PetscInt       offset = 0, f;
3484   PetscErrorCode ierr;
3485 
3486   PetscFunctionBeginHot;
3487   *size = 0;
3488   for (f = 0; f < numFields; ++f) {
3489     PetscInt fcomp, p;
3490 
3491     ierr = PetscSectionGetFieldComponents(section, f, &fcomp);CHKERRQ(ierr);
3492     for (p = 0; p < numPoints*2; p += 2) {
3493       const PetscInt point = points[p];
3494       const PetscInt o     = points[p+1];
3495       PetscInt       fdof, foff, d, c;
3496       const PetscScalar *varr;
3497 
3498       ierr = PetscSectionGetFieldDof(section, point, f, &fdof);CHKERRQ(ierr);
3499       ierr = PetscSectionGetFieldOffset(section, point, f, &foff);CHKERRQ(ierr);
3500       varr = &vArray[foff];
3501       if (o >= 0) {
3502         for (d = 0; d < fdof; ++d, ++offset) array[perm ? perm[offset] : offset] = varr[d];
3503       } else {
3504         for (d = fdof/fcomp-1; d >= 0; --d) {
3505           for (c = 0; c < fcomp; ++c, ++offset) {
3506             array[perm ? perm[offset] : offset] = varr[d*fcomp+c];
3507           }
3508         }
3509       }
3510     }
3511   }
3512   *size = offset;
3513   PetscFunctionReturn(0);
3514 }
3515 
3516 #undef __FUNCT__
3517 #define __FUNCT__ "DMPlexVecGetClosure"
3518 /*@C
3519   DMPlexVecGetClosure - Get an array of the values on the closure of 'point'
3520 
3521   Not collective
3522 
3523   Input Parameters:
3524 + dm - The DM
3525 . section - The section describing the layout in v, or NULL to use the default section
3526 . v - The local vector
3527 - point - The sieve point in the DM
3528 
3529   Output Parameters:
3530 + csize - The number of values in the closure, or NULL
3531 - values - The array of values, which is a borrowed array and should not be freed
3532 
3533   Fortran Notes:
3534   Since it returns an array, this routine is only available in Fortran 90, and you must
3535   include petsc.h90 in your code.
3536 
3537   The csize argument is not present in the Fortran 90 binding since it is internal to the array.
3538 
3539   Level: intermediate
3540 
3541 .seealso DMPlexVecRestoreClosure(), DMPlexVecSetClosure(), DMPlexMatSetClosure()
3542 @*/
3543 PetscErrorCode DMPlexVecGetClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[])
3544 {
3545   PetscSection    clSection;
3546   IS              clPoints;
3547   PetscScalar    *array, *vArray;
3548   PetscInt       *points = NULL;
3549   const PetscInt *clp, *perm;
3550   PetscInt        depth, numFields, numPoints, size;
3551   PetscErrorCode  ierr;
3552 
3553   PetscFunctionBeginHot;
3554   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3555   if (!section) {ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);}
3556   PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2);
3557   PetscValidHeaderSpecific(v, VEC_CLASSID, 3);
3558   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3559   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
3560   if (depth == 1 && numFields < 2) {
3561     ierr = DMPlexVecGetClosure_Depth1_Static(dm, section, v, point, csize, values);CHKERRQ(ierr);
3562     PetscFunctionReturn(0);
3563   }
3564   /* Get points */
3565   ierr = PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject) dm, NULL, &perm);CHKERRQ(ierr);
3566   ierr = PetscSectionGetClosureIndex(section, (PetscObject) dm, &clSection, &clPoints);CHKERRQ(ierr);
3567   if (!clPoints) {
3568     PetscInt pStart, pEnd, p, q;
3569 
3570     ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
3571     ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
3572     /* Compress out points not in the section */
3573     for (p = 0, q = 0; p < numPoints*2; p += 2) {
3574       if ((points[p] >= pStart) && (points[p] < pEnd)) {
3575         points[q*2]   = points[p];
3576         points[q*2+1] = points[p+1];
3577         ++q;
3578       }
3579     }
3580     numPoints = q;
3581   } else {
3582     PetscInt dof, off;
3583 
3584     ierr = PetscSectionGetDof(clSection, point, &dof);CHKERRQ(ierr);
3585     ierr = PetscSectionGetOffset(clSection, point, &off);CHKERRQ(ierr);
3586     ierr = ISGetIndices(clPoints, &clp);CHKERRQ(ierr);
3587     numPoints = dof/2;
3588     points    = (PetscInt *) &clp[off];
3589   }
3590   /* Get array */
3591   if (!values || !*values) {
3592     PetscInt asize = 0, dof, p;
3593 
3594     for (p = 0; p < numPoints*2; p += 2) {
3595       ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
3596       asize += dof;
3597     }
3598     if (!values) {
3599       if (!clPoints) {ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);}
3600       else           {ierr = ISRestoreIndices(clPoints, &clp);CHKERRQ(ierr);}
3601       if (csize) *csize = asize;
3602       PetscFunctionReturn(0);
3603     }
3604     ierr = DMGetWorkArray(dm, asize, PETSC_SCALAR, &array);CHKERRQ(ierr);
3605   } else {
3606     array = *values;
3607   }
3608   ierr = VecGetArray(v, &vArray);CHKERRQ(ierr);
3609   /* Get values */
3610   if (numFields > 0) {ierr = DMPlexVecGetClosure_Fields_Static(section, numPoints, points, numFields, perm, vArray, &size, array);CHKERRQ(ierr);}
3611   else               {ierr = DMPlexVecGetClosure_Static(section, numPoints, points, perm, vArray, &size, array);CHKERRQ(ierr);}
3612   /* Cleanup points */
3613   if (!clPoints) {ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);}
3614   else           {ierr = ISRestoreIndices(clPoints, &clp);CHKERRQ(ierr);}
3615   /* Cleanup array */
3616   ierr = VecRestoreArray(v, &vArray);CHKERRQ(ierr);
3617   if (!*values) {
3618     if (csize) *csize = size;
3619     *values = array;
3620   } else {
3621     if (size > *csize) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %D < actual size %D", *csize, size);
3622     *csize = size;
3623   }
3624   PetscFunctionReturn(0);
3625 }
3626 
3627 #undef __FUNCT__
3628 #define __FUNCT__ "DMPlexVecRestoreClosure"
3629 /*@C
3630   DMPlexVecRestoreClosure - Restore the array of the values on the closure of 'point'
3631 
3632   Not collective
3633 
3634   Input Parameters:
3635 + dm - The DM
3636 . section - The section describing the layout in v, or NULL to use the default section
3637 . v - The local vector
3638 . point - The sieve point in the DM
3639 . csize - The number of values in the closure, or NULL
3640 - values - The array of values, which is a borrowed array and should not be freed
3641 
3642   Fortran Notes:
3643   Since it returns an array, this routine is only available in Fortran 90, and you must
3644   include petsc.h90 in your code.
3645 
3646   The csize argument is not present in the Fortran 90 binding since it is internal to the array.
3647 
3648   Level: intermediate
3649 
3650 .seealso DMPlexVecGetClosure(), DMPlexVecSetClosure(), DMPlexMatSetClosure()
3651 @*/
3652 PetscErrorCode DMPlexVecRestoreClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[])
3653 {
3654   PetscInt       size = 0;
3655   PetscErrorCode ierr;
3656 
3657   PetscFunctionBegin;
3658   /* Should work without recalculating size */
3659   ierr = DMRestoreWorkArray(dm, size, PETSC_SCALAR, (void*) values);CHKERRQ(ierr);
3660   PetscFunctionReturn(0);
3661 }
3662 
3663 PETSC_STATIC_INLINE void add   (PetscScalar *x, PetscScalar y) {*x += y;}
3664 PETSC_STATIC_INLINE void insert(PetscScalar *x, PetscScalar y) {*x  = y;}
3665 
3666 #undef __FUNCT__
3667 #define __FUNCT__ "updatePoint_private"
3668 PETSC_STATIC_INLINE PetscErrorCode updatePoint_private(PetscSection section, PetscInt point, PetscInt dof, void (*fuse)(PetscScalar*, PetscScalar), PetscBool setBC, PetscInt orientation, const PetscInt perm[], const PetscScalar values[], PetscInt offset, PetscScalar array[])
3669 {
3670   PetscInt        cdof;   /* The number of constraints on this point */
3671   const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
3672   PetscScalar    *a;
3673   PetscInt        off, cind = 0, k;
3674   PetscErrorCode  ierr;
3675 
3676   PetscFunctionBegin;
3677   ierr = PetscSectionGetConstraintDof(section, point, &cdof);CHKERRQ(ierr);
3678   ierr = PetscSectionGetOffset(section, point, &off);CHKERRQ(ierr);
3679   a    = &array[off];
3680   if (!cdof || setBC) {
3681     if (orientation >= 0) {
3682       for (k = 0; k < dof; ++k) {
3683         fuse(&a[k], values[perm ? perm[offset+k] : offset+k]);
3684       }
3685     } else {
3686       for (k = 0; k < dof; ++k) {
3687         fuse(&a[k], values[perm ? perm[offset+dof-k-1] : offset+dof-k-1]);
3688       }
3689     }
3690   } else {
3691     ierr = PetscSectionGetConstraintIndices(section, point, &cdofs);CHKERRQ(ierr);
3692     if (orientation >= 0) {
3693       for (k = 0; k < dof; ++k) {
3694         if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
3695         fuse(&a[k], values[perm ? perm[offset+k] : offset+k]);
3696       }
3697     } else {
3698       for (k = 0; k < dof; ++k) {
3699         if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
3700         fuse(&a[k], values[perm ? perm[offset+dof-k-1] : offset+dof-k-1]);
3701       }
3702     }
3703   }
3704   PetscFunctionReturn(0);
3705 }
3706 
3707 #undef __FUNCT__
3708 #define __FUNCT__ "updatePointBC_private"
3709 PETSC_STATIC_INLINE PetscErrorCode updatePointBC_private(PetscSection section, PetscInt point, PetscInt dof, void (*fuse)(PetscScalar*, PetscScalar), PetscInt orientation, const PetscInt perm[], const PetscScalar values[], PetscInt offset, PetscScalar array[])
3710 {
3711   PetscInt        cdof;   /* The number of constraints on this point */
3712   const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
3713   PetscScalar    *a;
3714   PetscInt        off, cind = 0, k;
3715   PetscErrorCode  ierr;
3716 
3717   PetscFunctionBegin;
3718   ierr = PetscSectionGetConstraintDof(section, point, &cdof);CHKERRQ(ierr);
3719   ierr = PetscSectionGetOffset(section, point, &off);CHKERRQ(ierr);
3720   a    = &array[off];
3721   if (cdof) {
3722     ierr = PetscSectionGetConstraintIndices(section, point, &cdofs);CHKERRQ(ierr);
3723     if (orientation >= 0) {
3724       for (k = 0; k < dof; ++k) {
3725         if ((cind < cdof) && (k == cdofs[cind])) {
3726           fuse(&a[k], values[perm ? perm[offset+k] : offset+k]);
3727           ++cind;
3728         }
3729       }
3730     } else {
3731       for (k = 0; k < dof; ++k) {
3732         if ((cind < cdof) && (k == cdofs[cind])) {
3733           fuse(&a[k], values[perm ? perm[offset+dof-k-1] : offset+dof-k-1]);
3734           ++cind;
3735         }
3736       }
3737     }
3738   }
3739   PetscFunctionReturn(0);
3740 }
3741 
3742 #undef __FUNCT__
3743 #define __FUNCT__ "updatePointFields_private"
3744 PETSC_STATIC_INLINE PetscErrorCode updatePointFields_private(PetscSection section, PetscInt point, PetscInt o, PetscInt f, PetscInt fcomp, void (*fuse)(PetscScalar*, PetscScalar), PetscBool setBC, const PetscInt perm[], const PetscScalar values[], PetscInt *offset, PetscScalar array[])
3745 {
3746   PetscScalar    *a;
3747   PetscInt        fdof, foff, fcdof, foffset = *offset;
3748   const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
3749   PetscInt        cind = 0, k, c;
3750   PetscErrorCode  ierr;
3751 
3752   PetscFunctionBegin;
3753   ierr = PetscSectionGetFieldDof(section, point, f, &fdof);CHKERRQ(ierr);
3754   ierr = PetscSectionGetFieldConstraintDof(section, point, f, &fcdof);CHKERRQ(ierr);
3755   ierr = PetscSectionGetFieldOffset(section, point, f, &foff);CHKERRQ(ierr);
3756   a    = &array[foff];
3757   if (!fcdof || setBC) {
3758     if (o >= 0) {
3759       for (k = 0; k < fdof; ++k) fuse(&a[k], values[perm ? perm[foffset+k] : foffset+k]);
3760     } else {
3761       for (k = fdof/fcomp-1; k >= 0; --k) {
3762         for (c = 0; c < fcomp; ++c) {
3763           fuse(&a[(fdof/fcomp-1-k)*fcomp+c], values[perm ? perm[foffset+k*fcomp+c] : foffset+k*fcomp+c]);
3764         }
3765       }
3766     }
3767   } else {
3768     ierr = PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);CHKERRQ(ierr);
3769     if (o >= 0) {
3770       for (k = 0; k < fdof; ++k) {
3771         if ((cind < fcdof) && (k == fcdofs[cind])) {++cind; continue;}
3772         fuse(&a[k], values[perm ? perm[foffset+k] : foffset+k]);
3773       }
3774     } else {
3775       for (k = fdof/fcomp-1; k >= 0; --k) {
3776         for (c = 0; c < fcomp; ++c) {
3777           if ((cind < fcdof) && (k*fcomp+c == fcdofs[cind])) {++cind; continue;}
3778           fuse(&a[(fdof/fcomp-1-k)*fcomp+c], values[perm ? perm[foffset+k*fcomp+c] : foffset+k*fcomp+c]);
3779         }
3780       }
3781     }
3782   }
3783   *offset += fdof;
3784   PetscFunctionReturn(0);
3785 }
3786 
3787 #undef __FUNCT__
3788 #define __FUNCT__ "updatePointFieldsBC_private"
3789 PETSC_STATIC_INLINE PetscErrorCode updatePointFieldsBC_private(PetscSection section, PetscInt point, PetscInt o, PetscInt f, PetscInt fcomp, void (*fuse)(PetscScalar*, PetscScalar), const PetscInt perm[], const PetscScalar values[], PetscInt *offset, PetscScalar array[])
3790 {
3791   PetscScalar    *a;
3792   PetscInt        fdof, foff, fcdof, foffset = *offset;
3793   const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
3794   PetscInt        cind = 0, k, c;
3795   PetscErrorCode  ierr;
3796 
3797   PetscFunctionBegin;
3798   ierr = PetscSectionGetFieldDof(section, point, f, &fdof);CHKERRQ(ierr);
3799   ierr = PetscSectionGetFieldConstraintDof(section, point, f, &fcdof);CHKERRQ(ierr);
3800   ierr = PetscSectionGetFieldOffset(section, point, f, &foff);CHKERRQ(ierr);
3801   a    = &array[foff];
3802   if (fcdof) {
3803     ierr = PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);CHKERRQ(ierr);
3804     if (o >= 0) {
3805       for (k = 0; k < fdof; ++k) {
3806         if ((cind < fcdof) && (k == fcdofs[cind])) {
3807           fuse(&a[k], values[perm ? perm[foffset+k] : foffset+k]);
3808           ++cind;
3809         }
3810       }
3811     } else {
3812       for (k = fdof/fcomp-1; k >= 0; --k) {
3813         for (c = 0; c < fcomp; ++c) {
3814           if ((cind < fcdof) && (k*fcomp+c == fcdofs[cind])) {
3815             fuse(&a[(fdof/fcomp-1-k)*fcomp+c], values[perm ? perm[foffset+k*fcomp+c] : foffset+k*fcomp+c]);
3816             ++cind;
3817           }
3818         }
3819       }
3820     }
3821   }
3822   *offset += fdof;
3823   PetscFunctionReturn(0);
3824 }
3825 
3826 #undef __FUNCT__
3827 #define __FUNCT__ "DMPlexVecSetClosure_Depth1_Static"
3828 PETSC_STATIC_INLINE PetscErrorCode DMPlexVecSetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode)
3829 {
3830   PetscScalar    *array;
3831   const PetscInt *cone, *coneO;
3832   PetscInt        pStart, pEnd, p, numPoints, off, dof;
3833   PetscErrorCode  ierr;
3834 
3835   PetscFunctionBeginHot;
3836   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
3837   ierr = DMPlexGetConeSize(dm, point, &numPoints);CHKERRQ(ierr);
3838   ierr = DMPlexGetCone(dm, point, &cone);CHKERRQ(ierr);
3839   ierr = DMPlexGetConeOrientation(dm, point, &coneO);CHKERRQ(ierr);
3840   ierr = VecGetArray(v, &array);CHKERRQ(ierr);
3841   for (p = 0, off = 0; p <= numPoints; ++p, off += dof) {
3842     const PetscInt cp = !p ? point : cone[p-1];
3843     const PetscInt o  = !p ? 0     : coneO[p-1];
3844 
3845     if ((cp < pStart) || (cp >= pEnd)) {dof = 0; continue;}
3846     ierr = PetscSectionGetDof(section, cp, &dof);CHKERRQ(ierr);
3847     /* ADD_VALUES */
3848     {
3849       const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
3850       PetscScalar    *a;
3851       PetscInt        cdof, coff, cind = 0, k;
3852 
3853       ierr = PetscSectionGetConstraintDof(section, cp, &cdof);CHKERRQ(ierr);
3854       ierr = PetscSectionGetOffset(section, cp, &coff);CHKERRQ(ierr);
3855       a    = &array[coff];
3856       if (!cdof) {
3857         if (o >= 0) {
3858           for (k = 0; k < dof; ++k) {
3859             a[k] += values[off+k];
3860           }
3861         } else {
3862           for (k = 0; k < dof; ++k) {
3863             a[k] += values[off+dof-k-1];
3864           }
3865         }
3866       } else {
3867         ierr = PetscSectionGetConstraintIndices(section, cp, &cdofs);CHKERRQ(ierr);
3868         if (o >= 0) {
3869           for (k = 0; k < dof; ++k) {
3870             if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
3871             a[k] += values[off+k];
3872           }
3873         } else {
3874           for (k = 0; k < dof; ++k) {
3875             if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
3876             a[k] += values[off+dof-k-1];
3877           }
3878         }
3879       }
3880     }
3881   }
3882   ierr = VecRestoreArray(v, &array);CHKERRQ(ierr);
3883   PetscFunctionReturn(0);
3884 }
3885 
3886 #undef __FUNCT__
3887 #define __FUNCT__ "DMPlexVecSetClosure"
3888 /*@C
3889   DMPlexVecSetClosure - Set an array of the values on the closure of 'point'
3890 
3891   Not collective
3892 
3893   Input Parameters:
3894 + dm - The DM
3895 . section - The section describing the layout in v, or NULL to use the default section
3896 . v - The local vector
3897 . point - The sieve point in the DM
3898 . values - The array of values
3899 - mode - The insert mode, where INSERT_ALL_VALUES and ADD_ALL_VALUES also overwrite boundary conditions
3900 
3901   Fortran Notes:
3902   This routine is only available in Fortran 90, and you must include petsc.h90 in your code.
3903 
3904   Level: intermediate
3905 
3906 .seealso DMPlexVecGetClosure(), DMPlexMatSetClosure()
3907 @*/
3908 PetscErrorCode DMPlexVecSetClosure(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode)
3909 {
3910   PetscSection    clSection;
3911   IS              clPoints;
3912   PetscScalar    *array;
3913   PetscInt       *points = NULL;
3914   const PetscInt *clp, *perm;
3915   PetscInt        depth, numFields, numPoints, p;
3916   PetscErrorCode  ierr;
3917 
3918   PetscFunctionBeginHot;
3919   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3920   if (!section) {ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);}
3921   PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2);
3922   PetscValidHeaderSpecific(v, VEC_CLASSID, 3);
3923   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3924   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
3925   if (depth == 1 && numFields < 2 && mode == ADD_VALUES) {
3926     ierr = DMPlexVecSetClosure_Depth1_Static(dm, section, v, point, values, mode);CHKERRQ(ierr);
3927     PetscFunctionReturn(0);
3928   }
3929   /* Get points */
3930   ierr = PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject) dm, NULL, &perm);CHKERRQ(ierr);
3931   ierr = PetscSectionGetClosureIndex(section, (PetscObject) dm, &clSection, &clPoints);CHKERRQ(ierr);
3932   if (!clPoints) {
3933     PetscInt pStart, pEnd, q;
3934 
3935     ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
3936     ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
3937     /* Compress out points not in the section */
3938     for (p = 0, q = 0; p < numPoints*2; p += 2) {
3939       if ((points[p] >= pStart) && (points[p] < pEnd)) {
3940         points[q*2]   = points[p];
3941         points[q*2+1] = points[p+1];
3942         ++q;
3943       }
3944     }
3945     numPoints = q;
3946   } else {
3947     PetscInt dof, off;
3948 
3949     ierr = PetscSectionGetDof(clSection, point, &dof);CHKERRQ(ierr);
3950     ierr = PetscSectionGetOffset(clSection, point, &off);CHKERRQ(ierr);
3951     ierr = ISGetIndices(clPoints, &clp);CHKERRQ(ierr);
3952     numPoints = dof/2;
3953     points    = (PetscInt *) &clp[off];
3954   }
3955   /* Get array */
3956   ierr = VecGetArray(v, &array);CHKERRQ(ierr);
3957   /* Get values */
3958   if (numFields > 0) {
3959     PetscInt offset = 0, fcomp, f;
3960     for (f = 0; f < numFields; ++f) {
3961       ierr = PetscSectionGetFieldComponents(section, f, &fcomp);CHKERRQ(ierr);
3962       switch (mode) {
3963       case INSERT_VALUES:
3964         for (p = 0; p < numPoints*2; p += 2) {
3965           const PetscInt point = points[p];
3966           const PetscInt o     = points[p+1];
3967           updatePointFields_private(section, point, o, f, fcomp, insert, PETSC_FALSE, perm, values, &offset, array);
3968         } break;
3969       case INSERT_ALL_VALUES:
3970         for (p = 0; p < numPoints*2; p += 2) {
3971           const PetscInt point = points[p];
3972           const PetscInt o     = points[p+1];
3973           updatePointFields_private(section, point, o, f, fcomp, insert, PETSC_TRUE, perm, values, &offset, array);
3974         } break;
3975       case INSERT_BC_VALUES:
3976         for (p = 0; p < numPoints*2; p += 2) {
3977           const PetscInt point = points[p];
3978           const PetscInt o     = points[p+1];
3979           updatePointFieldsBC_private(section, point, o, f, fcomp, insert, perm, values, &offset, array);
3980         } break;
3981       case ADD_VALUES:
3982         for (p = 0; p < numPoints*2; p += 2) {
3983           const PetscInt point = points[p];
3984           const PetscInt o     = points[p+1];
3985           updatePointFields_private(section, point, o, f, fcomp, add, PETSC_FALSE, perm, values, &offset, array);
3986         } break;
3987       case ADD_ALL_VALUES:
3988         for (p = 0; p < numPoints*2; p += 2) {
3989           const PetscInt point = points[p];
3990           const PetscInt o     = points[p+1];
3991           updatePointFields_private(section, point, o, f, fcomp, add, PETSC_TRUE, perm, values, &offset, array);
3992         } break;
3993       case ADD_BC_VALUES:
3994         for (p = 0; p < numPoints*2; p += 2) {
3995           const PetscInt point = points[p];
3996           const PetscInt o     = points[p+1];
3997           updatePointFieldsBC_private(section, point, o, f, fcomp, add, perm, values, &offset, array);
3998         } break;
3999       default:
4000         SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode);
4001       }
4002     }
4003   } else {
4004     PetscInt dof, off;
4005 
4006     switch (mode) {
4007     case INSERT_VALUES:
4008       for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) {
4009         PetscInt o = points[p+1];
4010         ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
4011         updatePoint_private(section, points[p], dof, insert, PETSC_FALSE, o, perm, values, off, array);
4012       } break;
4013     case INSERT_ALL_VALUES:
4014       for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) {
4015         PetscInt o = points[p+1];
4016         ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
4017         updatePoint_private(section, points[p], dof, insert, PETSC_TRUE,  o, perm, values, off, array);
4018       } break;
4019     case INSERT_BC_VALUES:
4020       for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) {
4021         PetscInt o = points[p+1];
4022         ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
4023         updatePointBC_private(section, points[p], dof, insert,  o, perm, values, off, array);
4024       } break;
4025     case ADD_VALUES:
4026       for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) {
4027         PetscInt o = points[p+1];
4028         ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
4029         updatePoint_private(section, points[p], dof, add,    PETSC_FALSE, o, perm, values, off, array);
4030       } break;
4031     case ADD_ALL_VALUES:
4032       for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) {
4033         PetscInt o = points[p+1];
4034         ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
4035         updatePoint_private(section, points[p], dof, add,    PETSC_TRUE,  o, perm, values, off, array);
4036       } break;
4037     case ADD_BC_VALUES:
4038       for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) {
4039         PetscInt o = points[p+1];
4040         ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
4041         updatePointBC_private(section, points[p], dof, add,  o, perm, values, off, array);
4042       } break;
4043     default:
4044       SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode);
4045     }
4046   }
4047   /* Cleanup points */
4048   if (!clPoints) {ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);}
4049   else           {ierr = ISRestoreIndices(clPoints, &clp);CHKERRQ(ierr);}
4050   /* Cleanup array */
4051   ierr = VecRestoreArray(v, &array);CHKERRQ(ierr);
4052   PetscFunctionReturn(0);
4053 }
4054 
4055 #undef __FUNCT__
4056 #define __FUNCT__ "DMPlexVecSetFieldClosure_Internal"
4057 PetscErrorCode DMPlexVecSetFieldClosure_Internal(DM dm, PetscSection section, Vec v, PetscBool fieldActive[], PetscInt point, const PetscScalar values[], InsertMode mode)
4058 {
4059   PetscSection    clSection;
4060   IS              clPoints;
4061   PetscScalar    *array;
4062   PetscInt       *points = NULL;
4063   const PetscInt *clp, *perm;
4064   PetscInt        numFields, numPoints, p;
4065   PetscInt        offset = 0, fcomp, f;
4066   PetscErrorCode  ierr;
4067 
4068   PetscFunctionBeginHot;
4069   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4070   if (!section) {ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);}
4071   PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2);
4072   PetscValidHeaderSpecific(v, VEC_CLASSID, 3);
4073   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
4074   /* Get points */
4075   ierr = PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject) dm, NULL, &perm);CHKERRQ(ierr);
4076   ierr = PetscSectionGetClosureIndex(section, (PetscObject) dm, &clSection, &clPoints);CHKERRQ(ierr);
4077   if (!clPoints) {
4078     PetscInt pStart, pEnd, q;
4079 
4080     ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
4081     ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
4082     /* Compress out points not in the section */
4083     for (p = 0, q = 0; p < numPoints*2; p += 2) {
4084       if ((points[p] >= pStart) && (points[p] < pEnd)) {
4085         points[q*2]   = points[p];
4086         points[q*2+1] = points[p+1];
4087         ++q;
4088       }
4089     }
4090     numPoints = q;
4091   } else {
4092     PetscInt dof, off;
4093 
4094     ierr = PetscSectionGetDof(clSection, point, &dof);CHKERRQ(ierr);
4095     ierr = PetscSectionGetOffset(clSection, point, &off);CHKERRQ(ierr);
4096     ierr = ISGetIndices(clPoints, &clp);CHKERRQ(ierr);
4097     numPoints = dof/2;
4098     points    = (PetscInt *) &clp[off];
4099   }
4100   /* Get array */
4101   ierr = VecGetArray(v, &array);CHKERRQ(ierr);
4102   /* Get values */
4103   for (f = 0; f < numFields; ++f) {
4104     ierr = PetscSectionGetFieldComponents(section, f, &fcomp);CHKERRQ(ierr);
4105     if (!fieldActive[f]) {
4106       for (p = 0; p < numPoints*2; p += 2) {
4107         PetscInt fdof;
4108         ierr = PetscSectionGetFieldDof(section, points[p], f, &fdof);CHKERRQ(ierr);
4109         offset += fdof;
4110       }
4111       continue;
4112     }
4113     switch (mode) {
4114     case INSERT_VALUES:
4115       for (p = 0; p < numPoints*2; p += 2) {
4116         const PetscInt point = points[p];
4117         const PetscInt o     = points[p+1];
4118         updatePointFields_private(section, point, o, f, fcomp, insert, PETSC_FALSE, perm, values, &offset, array);
4119       } break;
4120     case INSERT_ALL_VALUES:
4121       for (p = 0; p < numPoints*2; p += 2) {
4122         const PetscInt point = points[p];
4123         const PetscInt o     = points[p+1];
4124         updatePointFields_private(section, point, o, f, fcomp, insert, PETSC_TRUE, perm, values, &offset, array);
4125         } break;
4126     case INSERT_BC_VALUES:
4127       for (p = 0; p < numPoints*2; p += 2) {
4128         const PetscInt point = points[p];
4129         const PetscInt o     = points[p+1];
4130         updatePointFieldsBC_private(section, point, o, f, fcomp, insert, perm, values, &offset, array);
4131       } break;
4132     case ADD_VALUES:
4133       for (p = 0; p < numPoints*2; p += 2) {
4134         const PetscInt point = points[p];
4135         const PetscInt o     = points[p+1];
4136         updatePointFields_private(section, point, o, f, fcomp, add, PETSC_FALSE, perm, values, &offset, array);
4137       } break;
4138     case ADD_ALL_VALUES:
4139       for (p = 0; p < numPoints*2; p += 2) {
4140         const PetscInt point = points[p];
4141         const PetscInt o     = points[p+1];
4142         updatePointFields_private(section, point, o, f, fcomp, add, PETSC_TRUE, perm, values, &offset, array);
4143       } break;
4144     default:
4145       SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode);
4146     }
4147   }
4148   /* Cleanup points */
4149   if (!clPoints) {ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);}
4150   else           {ierr = ISRestoreIndices(clPoints, &clp);CHKERRQ(ierr);}
4151   /* Cleanup array */
4152   ierr = VecRestoreArray(v, &array);CHKERRQ(ierr);
4153   PetscFunctionReturn(0);
4154 }
4155 
4156 #undef __FUNCT__
4157 #define __FUNCT__ "DMPlexPrintMatSetValues"
4158 PetscErrorCode DMPlexPrintMatSetValues(PetscViewer viewer, Mat A, PetscInt point, PetscInt numRIndices, const PetscInt rindices[], PetscInt numCIndices, const PetscInt cindices[], const PetscScalar values[])
4159 {
4160   PetscMPIInt    rank;
4161   PetscInt       i, j;
4162   PetscErrorCode ierr;
4163 
4164   PetscFunctionBegin;
4165   ierr = MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank);CHKERRQ(ierr);
4166   ierr = PetscViewerASCIIPrintf(viewer, "[%d]mat for sieve point %D\n", rank, point);CHKERRQ(ierr);
4167   for (i = 0; i < numRIndices; i++) {ierr = PetscViewerASCIIPrintf(viewer, "[%d]mat row indices[%D] = %D\n", rank, i, rindices[i]);CHKERRQ(ierr);}
4168   for (i = 0; i < numCIndices; i++) {ierr = PetscViewerASCIIPrintf(viewer, "[%d]mat col indices[%D] = %D\n", rank, i, cindices[i]);CHKERRQ(ierr);}
4169   numCIndices = numCIndices ? numCIndices : numRIndices;
4170   for (i = 0; i < numRIndices; i++) {
4171     ierr = PetscViewerASCIIPrintf(viewer, "[%d]", rank);CHKERRQ(ierr);
4172     for (j = 0; j < numCIndices; j++) {
4173 #if defined(PETSC_USE_COMPLEX)
4174       ierr = PetscViewerASCIIPrintf(viewer, " (%g,%g)", (double)PetscRealPart(values[i*numCIndices+j]), (double)PetscImaginaryPart(values[i*numCIndices+j]));CHKERRQ(ierr);
4175 #else
4176       ierr = PetscViewerASCIIPrintf(viewer, " %g", (double)values[i*numCIndices+j]);CHKERRQ(ierr);
4177 #endif
4178     }
4179     ierr = PetscViewerASCIIPrintf(viewer, "\n");CHKERRQ(ierr);
4180   }
4181   PetscFunctionReturn(0);
4182 }
4183 
4184 #undef __FUNCT__
4185 #define __FUNCT__ "DMPlexGetIndicesPoint_Internal"
4186 /* . off - The global offset of this point */
4187 PetscErrorCode DMPlexGetIndicesPoint_Internal(PetscSection section, PetscInt point, PetscInt off, PetscInt *loff, PetscBool setBC, PetscInt orientation, PetscInt indices[])
4188 {
4189   PetscInt        dof;    /* The number of unknowns on this point */
4190   PetscInt        cdof;   /* The number of constraints on this point */
4191   const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
4192   PetscInt        cind = 0, k;
4193   PetscErrorCode  ierr;
4194 
4195   PetscFunctionBegin;
4196   ierr = PetscSectionGetDof(section, point, &dof);CHKERRQ(ierr);
4197   ierr = PetscSectionGetConstraintDof(section, point, &cdof);CHKERRQ(ierr);
4198   if (!cdof || setBC) {
4199     if (orientation >= 0) {
4200       for (k = 0; k < dof; ++k) indices[*loff+k] = off+k;
4201     } else {
4202       for (k = 0; k < dof; ++k) indices[*loff+dof-k-1] = off+k;
4203     }
4204   } else {
4205     ierr = PetscSectionGetConstraintIndices(section, point, &cdofs);CHKERRQ(ierr);
4206     if (orientation >= 0) {
4207       for (k = 0; k < dof; ++k) {
4208         if ((cind < cdof) && (k == cdofs[cind])) {
4209           /* Insert check for returning constrained indices */
4210           indices[*loff+k] = -(off+k+1);
4211           ++cind;
4212         } else {
4213           indices[*loff+k] = off+k-cind;
4214         }
4215       }
4216     } else {
4217       for (k = 0; k < dof; ++k) {
4218         if ((cind < cdof) && (k == cdofs[cind])) {
4219           /* Insert check for returning constrained indices */
4220           indices[*loff+dof-k-1] = -(off+k+1);
4221           ++cind;
4222         } else {
4223           indices[*loff+dof-k-1] = off+k-cind;
4224         }
4225       }
4226     }
4227   }
4228   *loff += dof;
4229   PetscFunctionReturn(0);
4230 }
4231 
4232 #undef __FUNCT__
4233 #define __FUNCT__ "DMPlexGetIndicesPointFields_Internal"
4234 /* . off - The global offset of this point */
4235 PetscErrorCode DMPlexGetIndicesPointFields_Internal(PetscSection section, PetscInt point, PetscInt off, PetscInt foffs[], PetscBool setBC, PetscInt orientation, PetscInt indices[])
4236 {
4237   PetscInt       numFields, foff, f;
4238   PetscErrorCode ierr;
4239 
4240   PetscFunctionBegin;
4241   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
4242   for (f = 0, foff = 0; f < numFields; ++f) {
4243     PetscInt        fdof, fcomp, cfdof;
4244     const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
4245     PetscInt        cind = 0, k, c;
4246 
4247     ierr = PetscSectionGetFieldComponents(section, f, &fcomp);CHKERRQ(ierr);
4248     ierr = PetscSectionGetFieldDof(section, point, f, &fdof);CHKERRQ(ierr);
4249     ierr = PetscSectionGetFieldConstraintDof(section, point, f, &cfdof);CHKERRQ(ierr);
4250     if (!cfdof || setBC) {
4251       if (orientation >= 0) {
4252         for (k = 0; k < fdof; ++k) indices[foffs[f]+k] = off+foff+k;
4253       } else {
4254         for (k = fdof/fcomp-1; k >= 0; --k) {
4255           for (c = 0; c < fcomp; ++c) {
4256             indices[foffs[f]+k*fcomp+c] = off+foff+(fdof/fcomp-1-k)*fcomp+c;
4257           }
4258         }
4259       }
4260     } else {
4261       ierr = PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);CHKERRQ(ierr);
4262       if (orientation >= 0) {
4263         for (k = 0; k < fdof; ++k) {
4264           if ((cind < cfdof) && (k == fcdofs[cind])) {
4265             indices[foffs[f]+k] = -(off+foff+k+1);
4266             ++cind;
4267           } else {
4268             indices[foffs[f]+k] = off+foff+k-cind;
4269           }
4270         }
4271       } else {
4272         for (k = fdof/fcomp-1; k >= 0; --k) {
4273           for (c = 0; c < fcomp; ++c) {
4274             if ((cind < cfdof) && ((fdof/fcomp-1-k)*fcomp+c == fcdofs[cind])) {
4275               indices[foffs[f]+k*fcomp+c] = -(off+foff+(fdof/fcomp-1-k)*fcomp+c+1);
4276               ++cind;
4277             } else {
4278               indices[foffs[f]+k*fcomp+c] = off+foff+(fdof/fcomp-1-k)*fcomp+c-cind;
4279             }
4280           }
4281         }
4282       }
4283     }
4284     foff     += (setBC ? fdof : (fdof - cfdof));
4285     foffs[f] += fdof;
4286   }
4287   PetscFunctionReturn(0);
4288 }
4289 
4290 #undef __FUNCT__
4291 #define __FUNCT__ "DMPlexAnchorsModifyMat"
4292 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)
4293 {
4294   Mat             cMat;
4295   PetscSection    aSec, cSec;
4296   IS              aIS;
4297   PetscInt        aStart = -1, aEnd = -1;
4298   const PetscInt  *anchors;
4299   PetscInt        numFields, f, p, q, newP = 0;
4300   PetscInt        newNumPoints = 0, newNumIndices = 0;
4301   PetscInt        *newPoints, *indices, *newIndices;
4302   PetscInt        maxAnchor, maxDof;
4303   PetscInt        newOffsets[32];
4304   PetscInt        *pointMatOffsets[32];
4305   PetscInt        *newPointOffsets[32];
4306   PetscScalar     *pointMat[32];
4307   PetscScalar     *newValues=NULL,*tmpValues;
4308   PetscBool       anyConstrained = PETSC_FALSE;
4309   PetscErrorCode  ierr;
4310 
4311   PetscFunctionBegin;
4312   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4313   PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2);
4314   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
4315 
4316   ierr = DMPlexGetAnchors(dm,&aSec,&aIS);CHKERRQ(ierr);
4317   /* if there are point-to-point constraints */
4318   if (aSec) {
4319     ierr = PetscMemzero(newOffsets, 32 * sizeof(PetscInt));CHKERRQ(ierr);
4320     ierr = ISGetIndices(aIS,&anchors);CHKERRQ(ierr);
4321     ierr = PetscSectionGetChart(aSec,&aStart,&aEnd);CHKERRQ(ierr);
4322     /* figure out how many points are going to be in the new element matrix
4323      * (we allow double counting, because it's all just going to be summed
4324      * into the global matrix anyway) */
4325     for (p = 0; p < 2*numPoints; p+=2) {
4326       PetscInt b    = points[p];
4327       PetscInt bDof = 0, bSecDof;
4328 
4329       ierr = PetscSectionGetDof(section,b,&bSecDof);CHKERRQ(ierr);
4330       if (!bSecDof) {
4331         continue;
4332       }
4333       if (b >= aStart && b < aEnd) {
4334         ierr = PetscSectionGetDof(aSec,b,&bDof);CHKERRQ(ierr);
4335       }
4336       if (bDof) {
4337         /* this point is constrained */
4338         /* it is going to be replaced by its anchors */
4339         PetscInt bOff, q;
4340 
4341         anyConstrained = PETSC_TRUE;
4342         newNumPoints  += bDof;
4343         ierr = PetscSectionGetOffset(aSec,b,&bOff);CHKERRQ(ierr);
4344         for (q = 0; q < bDof; q++) {
4345           PetscInt a = anchors[bOff + q];
4346           PetscInt aDof;
4347 
4348           ierr           = PetscSectionGetDof(section,a,&aDof);CHKERRQ(ierr);
4349           newNumIndices += aDof;
4350           for (f = 0; f < numFields; ++f) {
4351             PetscInt fDof;
4352 
4353             ierr             = PetscSectionGetFieldDof(section, a, f, &fDof);CHKERRQ(ierr);
4354             newOffsets[f+1] += fDof;
4355           }
4356         }
4357       }
4358       else {
4359         /* this point is not constrained */
4360         newNumPoints++;
4361         newNumIndices += bSecDof;
4362         for (f = 0; f < numFields; ++f) {
4363           PetscInt fDof;
4364 
4365           ierr = PetscSectionGetFieldDof(section, b, f, &fDof);CHKERRQ(ierr);
4366           newOffsets[f+1] += fDof;
4367         }
4368       }
4369     }
4370   }
4371   if (!anyConstrained) {
4372     if (outNumPoints)  *outNumPoints  = 0;
4373     if (outNumIndices) *outNumIndices = 0;
4374     if (outPoints)     *outPoints     = NULL;
4375     if (outValues)     *outValues     = NULL;
4376     if (aSec) {ierr = ISRestoreIndices(aIS,&anchors);CHKERRQ(ierr);}
4377     PetscFunctionReturn(0);
4378   }
4379 
4380   if (outNumPoints)  *outNumPoints  = newNumPoints;
4381   if (outNumIndices) *outNumIndices = newNumIndices;
4382 
4383   for (f = 0; f < numFields; ++f) newOffsets[f+1] += newOffsets[f];
4384 
4385   if (!outPoints && !outValues) {
4386     if (offsets) {
4387       for (f = 0; f <= numFields; f++) {
4388         offsets[f] = newOffsets[f];
4389       }
4390     }
4391     if (aSec) {ierr = ISRestoreIndices(aIS,&anchors);CHKERRQ(ierr);}
4392     PetscFunctionReturn(0);
4393   }
4394 
4395   if (numFields && newOffsets[numFields] != newNumIndices) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid size for closure %D should be %D", newOffsets[numFields], newNumIndices);
4396 
4397   ierr = DMGetDefaultConstraints(dm, &cSec, &cMat);CHKERRQ(ierr);
4398 
4399   /* workspaces */
4400   if (numFields) {
4401     for (f = 0; f < numFields; f++) {
4402       ierr = DMGetWorkArray(dm,numPoints+1,PETSC_INT,&pointMatOffsets[f]);CHKERRQ(ierr);
4403       ierr = DMGetWorkArray(dm,numPoints+1,PETSC_INT,&newPointOffsets[f]);CHKERRQ(ierr);
4404     }
4405   }
4406   else {
4407     ierr = DMGetWorkArray(dm,numPoints+1,PETSC_INT,&pointMatOffsets[0]);CHKERRQ(ierr);
4408     ierr = DMGetWorkArray(dm,numPoints,PETSC_INT,&newPointOffsets[0]);CHKERRQ(ierr);
4409   }
4410 
4411   /* get workspaces for the point-to-point matrices */
4412   if (numFields) {
4413     PetscInt totalOffset, totalMatOffset;
4414 
4415     for (p = 0; p < numPoints; p++) {
4416       PetscInt b    = points[2*p];
4417       PetscInt bDof = 0, bSecDof;
4418 
4419       ierr = PetscSectionGetDof(section,b,&bSecDof);CHKERRQ(ierr);
4420       if (!bSecDof) {
4421         for (f = 0; f < numFields; f++) {
4422           newPointOffsets[f][p + 1] = 0;
4423           pointMatOffsets[f][p + 1] = 0;
4424         }
4425         continue;
4426       }
4427       if (b >= aStart && b < aEnd) {
4428         ierr = PetscSectionGetDof(aSec, b, &bDof);CHKERRQ(ierr);
4429       }
4430       if (bDof) {
4431         for (f = 0; f < numFields; f++) {
4432           PetscInt fDof, q, bOff, allFDof = 0;
4433 
4434           ierr = PetscSectionGetFieldDof(section, b, f, &fDof);CHKERRQ(ierr);
4435           ierr = PetscSectionGetOffset(aSec, b, &bOff);CHKERRQ(ierr);
4436           for (q = 0; q < bDof; q++) {
4437             PetscInt a = anchors[bOff + q];
4438             PetscInt aFDof;
4439 
4440             ierr     = PetscSectionGetFieldDof(section, a, f, &aFDof);CHKERRQ(ierr);
4441             allFDof += aFDof;
4442           }
4443           newPointOffsets[f][p+1] = allFDof;
4444           pointMatOffsets[f][p+1] = fDof * allFDof;
4445         }
4446       }
4447       else {
4448         for (f = 0; f < numFields; f++) {
4449           PetscInt fDof;
4450 
4451           ierr = PetscSectionGetFieldDof(section, b, f, &fDof);CHKERRQ(ierr);
4452           newPointOffsets[f][p+1] = fDof;
4453           pointMatOffsets[f][p+1] = 0;
4454         }
4455       }
4456     }
4457     for (f = 0, totalOffset = 0, totalMatOffset = 0; f < numFields; f++) {
4458       newPointOffsets[f][0] = totalOffset;
4459       pointMatOffsets[f][0] = totalMatOffset;
4460       for (p = 0; p < numPoints; p++) {
4461         newPointOffsets[f][p+1] += newPointOffsets[f][p];
4462         pointMatOffsets[f][p+1] += pointMatOffsets[f][p];
4463       }
4464       totalOffset    = newPointOffsets[f][numPoints];
4465       totalMatOffset = pointMatOffsets[f][numPoints];
4466       ierr = DMGetWorkArray(dm,pointMatOffsets[f][numPoints],PETSC_SCALAR,&pointMat[f]);CHKERRQ(ierr);
4467     }
4468   }
4469   else {
4470     for (p = 0; p < numPoints; p++) {
4471       PetscInt b    = points[2*p];
4472       PetscInt bDof = 0, bSecDof;
4473 
4474       ierr = PetscSectionGetDof(section,b,&bSecDof);CHKERRQ(ierr);
4475       if (!bSecDof) {
4476         newPointOffsets[0][p + 1] = 0;
4477         pointMatOffsets[0][p + 1] = 0;
4478         continue;
4479       }
4480       if (b >= aStart && b < aEnd) {
4481         ierr = PetscSectionGetDof(aSec, b, &bDof);CHKERRQ(ierr);
4482       }
4483       if (bDof) {
4484         PetscInt bOff, q, allDof = 0;
4485 
4486         ierr = PetscSectionGetOffset(aSec, b, &bOff);CHKERRQ(ierr);
4487         for (q = 0; q < bDof; q++) {
4488           PetscInt a = anchors[bOff + q], aDof;
4489 
4490           ierr    = PetscSectionGetDof(section, a, &aDof);CHKERRQ(ierr);
4491           allDof += aDof;
4492         }
4493         newPointOffsets[0][p+1] = allDof;
4494         pointMatOffsets[0][p+1] = bSecDof * allDof;
4495       }
4496       else {
4497         newPointOffsets[0][p+1] = bSecDof;
4498         pointMatOffsets[0][p+1] = 0;
4499       }
4500     }
4501     newPointOffsets[0][0] = 0;
4502     pointMatOffsets[0][0] = 0;
4503     for (p = 0; p < numPoints; p++) {
4504       newPointOffsets[0][p+1] += newPointOffsets[0][p];
4505       pointMatOffsets[0][p+1] += pointMatOffsets[0][p];
4506     }
4507     ierr = DMGetWorkArray(dm,pointMatOffsets[0][numPoints],PETSC_SCALAR,&pointMat[0]);CHKERRQ(ierr);
4508   }
4509 
4510   /* output arrays */
4511   ierr = DMGetWorkArray(dm,2*newNumPoints,PETSC_INT,&newPoints);CHKERRQ(ierr);
4512 
4513   /* get the point-to-point matrices; construct newPoints */
4514   ierr = PetscSectionGetMaxDof(aSec, &maxAnchor);CHKERRQ(ierr);
4515   ierr = PetscSectionGetMaxDof(section, &maxDof);CHKERRQ(ierr);
4516   ierr = DMGetWorkArray(dm,maxDof,PETSC_INT,&indices);CHKERRQ(ierr);
4517   ierr = DMGetWorkArray(dm,maxAnchor*maxDof,PETSC_INT,&newIndices);CHKERRQ(ierr);
4518   if (numFields) {
4519     for (p = 0, newP = 0; p < numPoints; p++) {
4520       PetscInt b    = points[2*p];
4521       PetscInt o    = points[2*p+1];
4522       PetscInt bDof = 0, bSecDof;
4523 
4524       ierr = PetscSectionGetDof(section, b, &bSecDof);CHKERRQ(ierr);
4525       if (!bSecDof) {
4526         continue;
4527       }
4528       if (b >= aStart && b < aEnd) {
4529         ierr = PetscSectionGetDof(aSec, b, &bDof);CHKERRQ(ierr);
4530       }
4531       if (bDof) {
4532         PetscInt fStart[32], fEnd[32], fAnchorStart[32], fAnchorEnd[32], bOff, q;
4533 
4534         fStart[0] = 0;
4535         fEnd[0]   = 0;
4536         for (f = 0; f < numFields; f++) {
4537           PetscInt fDof;
4538 
4539           ierr        = PetscSectionGetFieldDof(cSec, b, f, &fDof);CHKERRQ(ierr);
4540           fStart[f+1] = fStart[f] + fDof;
4541           fEnd[f+1]   = fStart[f+1];
4542         }
4543         ierr = PetscSectionGetOffset(cSec, b, &bOff);CHKERRQ(ierr);
4544         ierr = DMPlexGetIndicesPointFields_Internal(cSec, b, bOff, fEnd, PETSC_TRUE, o, indices);CHKERRQ(ierr);
4545 
4546         fAnchorStart[0] = 0;
4547         fAnchorEnd[0]   = 0;
4548         for (f = 0; f < numFields; f++) {
4549           PetscInt fDof = newPointOffsets[f][p + 1] - newPointOffsets[f][p];
4550 
4551           fAnchorStart[f+1] = fAnchorStart[f] + fDof;
4552           fAnchorEnd[f+1]   = fAnchorStart[f + 1];
4553         }
4554         ierr = PetscSectionGetOffset(aSec, b, &bOff);CHKERRQ(ierr);
4555         for (q = 0; q < bDof; q++) {
4556           PetscInt a = anchors[bOff + q], aOff;
4557 
4558           /* we take the orientation of ap into account in the order that we constructed the indices above: the newly added points have no orientation */
4559           newPoints[2*(newP + q)]     = a;
4560           newPoints[2*(newP + q) + 1] = 0;
4561           ierr = PetscSectionGetOffset(section, a, &aOff);CHKERRQ(ierr);
4562           ierr = DMPlexGetIndicesPointFields_Internal(section, a, aOff, fAnchorEnd, PETSC_TRUE, 0, newIndices);CHKERRQ(ierr);
4563         }
4564         newP += bDof;
4565 
4566         if (outValues) {
4567           /* get the point-to-point submatrix */
4568           for (f = 0; f < numFields; f++) {
4569             ierr = MatGetValues(cMat,fEnd[f]-fStart[f],indices + fStart[f],fAnchorEnd[f] - fAnchorStart[f],newIndices + fAnchorStart[f],pointMat[f] + pointMatOffsets[f][p]);CHKERRQ(ierr);
4570           }
4571         }
4572       }
4573       else {
4574         newPoints[2 * newP]     = b;
4575         newPoints[2 * newP + 1] = o;
4576         newP++;
4577       }
4578     }
4579   } else {
4580     for (p = 0; p < numPoints; p++) {
4581       PetscInt b    = points[2*p];
4582       PetscInt o    = points[2*p+1];
4583       PetscInt bDof = 0, bSecDof;
4584 
4585       ierr = PetscSectionGetDof(section, b, &bSecDof);CHKERRQ(ierr);
4586       if (!bSecDof) {
4587         continue;
4588       }
4589       if (b >= aStart && b < aEnd) {
4590         ierr = PetscSectionGetDof(aSec, b, &bDof);CHKERRQ(ierr);
4591       }
4592       if (bDof) {
4593         PetscInt bEnd = 0, bAnchorEnd = 0, bOff;
4594 
4595         ierr = PetscSectionGetOffset(cSec, b, &bOff);CHKERRQ(ierr);
4596         ierr = DMPlexGetIndicesPoint_Internal(cSec, b, bOff, &bEnd, PETSC_TRUE, o, indices);CHKERRQ(ierr);
4597 
4598         ierr = PetscSectionGetOffset (aSec, b, &bOff);CHKERRQ(ierr);
4599         for (q = 0; q < bDof; q++) {
4600           PetscInt a = anchors[bOff + q], aOff;
4601 
4602           /* we take the orientation of ap into account in the order that we constructed the indices above: the newly added points have no orientation */
4603 
4604           newPoints[2*(newP + q)]     = a;
4605           newPoints[2*(newP + q) + 1] = 0;
4606           ierr = PetscSectionGetOffset(section, a, &aOff);CHKERRQ(ierr);
4607           ierr = DMPlexGetIndicesPoint_Internal(section, a, aOff, &bAnchorEnd, PETSC_TRUE, 0, newIndices);CHKERRQ(ierr);
4608         }
4609         newP += bDof;
4610 
4611         /* get the point-to-point submatrix */
4612         if (outValues) {
4613           ierr = MatGetValues(cMat,bEnd,indices,bAnchorEnd,newIndices,pointMat[0] + pointMatOffsets[0][p]);CHKERRQ(ierr);
4614         }
4615       }
4616       else {
4617         newPoints[2 * newP]     = b;
4618         newPoints[2 * newP + 1] = o;
4619         newP++;
4620       }
4621     }
4622   }
4623 
4624   if (outValues) {
4625     ierr = DMGetWorkArray(dm,newNumIndices*numIndices,PETSC_SCALAR,&tmpValues);CHKERRQ(ierr);
4626     ierr = PetscMemzero(tmpValues,newNumIndices*numIndices*sizeof(*tmpValues));CHKERRQ(ierr);
4627     /* multiply constraints on the right */
4628     if (numFields) {
4629       for (f = 0; f < numFields; f++) {
4630         PetscInt oldOff = offsets[f];
4631 
4632         for (p = 0; p < numPoints; p++) {
4633           PetscInt cStart = newPointOffsets[f][p];
4634           PetscInt b      = points[2 * p];
4635           PetscInt c, r, k;
4636           PetscInt dof;
4637 
4638           ierr = PetscSectionGetFieldDof(section,b,f,&dof);CHKERRQ(ierr);
4639           if (!dof) {
4640             continue;
4641           }
4642           if (pointMatOffsets[f][p] < pointMatOffsets[f][p + 1]) {
4643             PetscInt nCols         = newPointOffsets[f][p+1]-cStart;
4644             const PetscScalar *mat = pointMat[f] + pointMatOffsets[f][p];
4645 
4646             for (r = 0; r < numIndices; r++) {
4647               for (c = 0; c < nCols; c++) {
4648                 for (k = 0; k < dof; k++) {
4649                   tmpValues[r * newNumIndices + cStart + c] += mat[k * nCols + c] * values[r * numIndices + oldOff + k];
4650                 }
4651               }
4652             }
4653           }
4654           else {
4655             /* copy this column as is */
4656             for (r = 0; r < numIndices; r++) {
4657               for (c = 0; c < dof; c++) {
4658                 tmpValues[r * newNumIndices + cStart + c] = values[r * numIndices + oldOff + c];
4659               }
4660             }
4661           }
4662           oldOff += dof;
4663         }
4664       }
4665     }
4666     else {
4667       PetscInt oldOff = 0;
4668       for (p = 0; p < numPoints; p++) {
4669         PetscInt cStart = newPointOffsets[0][p];
4670         PetscInt b      = points[2 * p];
4671         PetscInt c, r, k;
4672         PetscInt dof;
4673 
4674         ierr = PetscSectionGetDof(section,b,&dof);CHKERRQ(ierr);
4675         if (!dof) {
4676           continue;
4677         }
4678         if (pointMatOffsets[0][p] < pointMatOffsets[0][p + 1]) {
4679           PetscInt nCols         = newPointOffsets[0][p+1]-cStart;
4680           const PetscScalar *mat = pointMat[0] + pointMatOffsets[0][p];
4681 
4682           for (r = 0; r < numIndices; r++) {
4683             for (c = 0; c < nCols; c++) {
4684               for (k = 0; k < dof; k++) {
4685                 tmpValues[r * newNumIndices + cStart + c] += mat[k * nCols + c] * values[r * numIndices + oldOff + k];
4686               }
4687             }
4688           }
4689         }
4690         else {
4691           /* copy this column as is */
4692           for (r = 0; r < numIndices; r++) {
4693             for (c = 0; c < dof; c++) {
4694               tmpValues[r * newNumIndices + cStart + c] = values[r * numIndices + oldOff + c];
4695             }
4696           }
4697         }
4698         oldOff += dof;
4699       }
4700     }
4701 
4702     if (multiplyLeft) {
4703       ierr = DMGetWorkArray(dm,newNumIndices*newNumIndices,PETSC_SCALAR,&newValues);CHKERRQ(ierr);
4704       ierr = PetscMemzero(newValues,newNumIndices*newNumIndices*sizeof(*newValues));CHKERRQ(ierr);
4705       /* multiply constraints transpose on the left */
4706       if (numFields) {
4707         for (f = 0; f < numFields; f++) {
4708           PetscInt oldOff = offsets[f];
4709 
4710           for (p = 0; p < numPoints; p++) {
4711             PetscInt rStart = newPointOffsets[f][p];
4712             PetscInt b      = points[2 * p];
4713             PetscInt c, r, k;
4714             PetscInt dof;
4715 
4716             ierr = PetscSectionGetFieldDof(section,b,f,&dof);CHKERRQ(ierr);
4717             if (pointMatOffsets[f][p] < pointMatOffsets[f][p + 1]) {
4718               PetscInt nRows                        = newPointOffsets[f][p+1]-rStart;
4719               const PetscScalar *PETSC_RESTRICT mat = pointMat[f] + pointMatOffsets[f][p];
4720 
4721               for (r = 0; r < nRows; r++) {
4722                 for (c = 0; c < newNumIndices; c++) {
4723                   for (k = 0; k < dof; k++) {
4724                     newValues[(rStart + r) * newNumIndices + c] += mat[k * nRows + r] * tmpValues[(oldOff + k) * newNumIndices + c];
4725                   }
4726                 }
4727               }
4728             }
4729             else {
4730               /* copy this row as is */
4731               for (r = 0; r < dof; r++) {
4732                 for (c = 0; c < newNumIndices; c++) {
4733                   newValues[(rStart + r) * newNumIndices + c] = tmpValues[(oldOff + r) * newNumIndices + c];
4734                 }
4735               }
4736             }
4737             oldOff += dof;
4738           }
4739         }
4740       }
4741       else {
4742         PetscInt oldOff = 0;
4743 
4744         for (p = 0; p < numPoints; p++) {
4745           PetscInt rStart = newPointOffsets[0][p];
4746           PetscInt b      = points[2 * p];
4747           PetscInt c, r, k;
4748           PetscInt dof;
4749 
4750           ierr = PetscSectionGetDof(section,b,&dof);CHKERRQ(ierr);
4751           if (pointMatOffsets[0][p] < pointMatOffsets[0][p + 1]) {
4752             PetscInt nRows                        = newPointOffsets[0][p+1]-rStart;
4753             const PetscScalar *PETSC_RESTRICT mat = pointMat[0] + pointMatOffsets[0][p];
4754 
4755             for (r = 0; r < nRows; r++) {
4756               for (c = 0; c < newNumIndices; c++) {
4757                 for (k = 0; k < dof; k++) {
4758                   newValues[(rStart + r) * newNumIndices + c] += mat[k * nRows + r] * tmpValues[(oldOff + k) * newNumIndices + c];
4759                 }
4760               }
4761             }
4762           }
4763           else {
4764             /* copy this row as is */
4765             for (r = 0; r < dof; r++) {
4766               for (c = 0; c < newNumIndices; c++) {
4767                 newValues[(rStart + r) * newNumIndices + c] = tmpValues[(oldOff + r) * newNumIndices + c];
4768               }
4769             }
4770           }
4771           oldOff += dof;
4772         }
4773       }
4774 
4775       ierr = DMRestoreWorkArray(dm,newNumIndices*numIndices,PETSC_SCALAR,&tmpValues);CHKERRQ(ierr);
4776     }
4777     else {
4778       newValues = tmpValues;
4779     }
4780   }
4781 
4782   /* clean up */
4783   ierr = DMRestoreWorkArray(dm,maxDof,PETSC_INT,&indices);CHKERRQ(ierr);
4784   ierr = DMRestoreWorkArray(dm,maxAnchor*maxDof,PETSC_INT,&newIndices);CHKERRQ(ierr);
4785 
4786   if (numFields) {
4787     for (f = 0; f < numFields; f++) {
4788       ierr = DMRestoreWorkArray(dm,pointMatOffsets[f][numPoints],PETSC_SCALAR,&pointMat[f]);CHKERRQ(ierr);
4789       ierr = DMRestoreWorkArray(dm,numPoints+1,PETSC_INT,&pointMatOffsets[f]);CHKERRQ(ierr);
4790       ierr = DMRestoreWorkArray(dm,numPoints+1,PETSC_INT,&newPointOffsets[f]);CHKERRQ(ierr);
4791     }
4792   }
4793   else {
4794     ierr = DMRestoreWorkArray(dm,pointMatOffsets[0][numPoints],PETSC_SCALAR,&pointMat[0]);CHKERRQ(ierr);
4795     ierr = DMRestoreWorkArray(dm,numPoints+1,PETSC_INT,&pointMatOffsets[0]);CHKERRQ(ierr);
4796     ierr = DMRestoreWorkArray(dm,numPoints+1,PETSC_INT,&newPointOffsets[0]);CHKERRQ(ierr);
4797   }
4798   ierr = ISRestoreIndices(aIS,&anchors);CHKERRQ(ierr);
4799 
4800   /* output */
4801   if (outPoints) {
4802     *outPoints = newPoints;
4803   }
4804   else {
4805     ierr = DMRestoreWorkArray(dm,2*newNumPoints,PETSC_INT,&newPoints);CHKERRQ(ierr);
4806   }
4807   if (outValues) {
4808     *outValues = newValues;
4809   }
4810   for (f = 0; f <= numFields; f++) {
4811     offsets[f] = newOffsets[f];
4812   }
4813   PetscFunctionReturn(0);
4814 }
4815 
4816 #undef __FUNCT__
4817 #define __FUNCT__ "DMPlexGetClosureIndices"
4818 PetscErrorCode DMPlexGetClosureIndices(DM dm, PetscSection section, PetscSection globalSection, PetscInt point, PetscInt *numIndices, PetscInt **indices, PetscInt *outOffsets)
4819 {
4820   PetscSection    clSection;
4821   IS              clPoints;
4822   const PetscInt *clp;
4823   PetscInt       *points = NULL, *pointsNew;
4824   PetscInt        numPoints, numPointsNew;
4825   PetscInt        offsets[32];
4826   PetscInt        Nf, Nind, NindNew, off, globalOff, f, p;
4827   PetscErrorCode  ierr;
4828 
4829   PetscFunctionBegin;
4830   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4831   PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2);
4832   PetscValidHeaderSpecific(globalSection, PETSC_SECTION_CLASSID, 3);
4833   if (numIndices) PetscValidPointer(numIndices, 4);
4834   PetscValidPointer(indices, 5);
4835   ierr = PetscSectionGetNumFields(section, &Nf);CHKERRQ(ierr);
4836   if (Nf > 31) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", Nf);
4837   ierr = PetscMemzero(offsets, 32 * sizeof(PetscInt));CHKERRQ(ierr);
4838   /* Get points in closure */
4839   ierr = PetscSectionGetClosureIndex(section, (PetscObject) dm, &clSection, &clPoints);CHKERRQ(ierr);
4840   if (!clPoints) {
4841     PetscInt pStart, pEnd, q;
4842 
4843     ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
4844     /* Compress out points not in the section */
4845     ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
4846     for (p = 0, q = 0; p < numPoints*2; p += 2) {
4847       if ((points[p] >= pStart) && (points[p] < pEnd)) {
4848         points[q*2]   = points[p];
4849         points[q*2+1] = points[p+1];
4850         ++q;
4851       }
4852     }
4853     numPoints = q;
4854   } else {
4855     PetscInt dof, off;
4856 
4857     ierr = PetscSectionGetDof(clSection, point, &dof);CHKERRQ(ierr);
4858     numPoints = dof/2;
4859     ierr = PetscSectionGetOffset(clSection, point, &off);CHKERRQ(ierr);
4860     ierr = ISGetIndices(clPoints, &clp);CHKERRQ(ierr);
4861     points = (PetscInt *) &clp[off];
4862   }
4863   /* Get number of indices and indices per field */
4864   for (p = 0, Nind = 0; p < numPoints*2; p += 2) {
4865     PetscInt dof, fdof;
4866 
4867     ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
4868     for (f = 0; f < Nf; ++f) {
4869       ierr = PetscSectionGetFieldDof(section, points[p], f, &fdof);CHKERRQ(ierr);
4870       offsets[f+1] += fdof;
4871     }
4872     Nind += dof;
4873   }
4874   for (f = 1; f < Nf; ++f) offsets[f+1] += offsets[f];
4875   if (Nf && offsets[Nf] != Nind) SETERRQ2(PetscObjectComm((PetscObject) dm), PETSC_ERR_PLIB, "Invalid size for closure %d should be %d", offsets[Nf], Nind);
4876   /* Correct for hanging node constraints */
4877   {
4878     ierr = DMPlexAnchorsModifyMat(dm, section, numPoints, Nind, points, NULL, &numPointsNew, &NindNew, &pointsNew, NULL, offsets, PETSC_TRUE);CHKERRQ(ierr);
4879     if (numPointsNew) {
4880       if (!clPoints) {ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);}
4881       else           {ierr = ISRestoreIndices(clPoints, &clp);CHKERRQ(ierr);}
4882       numPoints = numPointsNew;
4883       Nind      = NindNew;
4884       points    = pointsNew;
4885     }
4886   }
4887   /* Calculate indices */
4888   ierr = DMGetWorkArray(dm, Nind, PETSC_INT, indices);CHKERRQ(ierr);
4889   if (Nf) {
4890     if (outOffsets) {
4891       PetscInt f;
4892 
4893       for (f = 0; f <= Nf; f++) {
4894         outOffsets[f] = offsets[f];
4895       }
4896     }
4897     for (p = 0; p < numPoints*2; p += 2) {
4898       PetscInt o = points[p+1];
4899       ierr = PetscSectionGetOffset(globalSection, points[p], &globalOff);CHKERRQ(ierr);
4900       DMPlexGetIndicesPointFields_Internal(section, points[p], globalOff < 0 ? -(globalOff+1) : globalOff, offsets, PETSC_FALSE, o, *indices);
4901     }
4902   } else {
4903     for (p = 0, off = 0; p < numPoints*2; p += 2) {
4904       PetscInt o = points[p+1];
4905       ierr = PetscSectionGetOffset(globalSection, points[p], &globalOff);CHKERRQ(ierr);
4906       DMPlexGetIndicesPoint_Internal(section, points[p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, o, *indices);
4907     }
4908   }
4909   /* Cleanup points */
4910   if (numPointsNew) {
4911     ierr = DMRestoreWorkArray(dm, 2*numPointsNew, PETSC_INT, &pointsNew);CHKERRQ(ierr);
4912   } else {
4913     if (!clPoints) {ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);}
4914     else           {ierr = ISRestoreIndices(clPoints, &clp);CHKERRQ(ierr);}
4915   }
4916   if (numIndices) *numIndices = Nind;
4917   PetscFunctionReturn(0);
4918 }
4919 
4920 #undef __FUNCT__
4921 #define __FUNCT__ "DMPlexRestoreClosureIndices"
4922 PetscErrorCode DMPlexRestoreClosureIndices(DM dm, PetscSection section, PetscSection globalSection, PetscInt point, PetscInt *numIndices, PetscInt **indices,PetscInt *outOffsets)
4923 {
4924   PetscErrorCode ierr;
4925 
4926   PetscFunctionBegin;
4927   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4928   PetscValidPointer(indices, 5);
4929   ierr = DMRestoreWorkArray(dm, 0, PETSC_INT, indices);CHKERRQ(ierr);
4930   PetscFunctionReturn(0);
4931 }
4932 
4933 #undef __FUNCT__
4934 #define __FUNCT__ "DMPlexMatSetClosure"
4935 /*@C
4936   DMPlexMatSetClosure - Set an array of the values on the closure of 'point'
4937 
4938   Not collective
4939 
4940   Input Parameters:
4941 + dm - The DM
4942 . section - The section describing the layout in v, or NULL to use the default section
4943 . globalSection - The section describing the layout in v, or NULL to use the default global section
4944 . A - The matrix
4945 . point - The sieve point in the DM
4946 . values - The array of values
4947 - mode - The insert mode, where INSERT_ALL_VALUES and ADD_ALL_VALUES also overwrite boundary conditions
4948 
4949   Fortran Notes:
4950   This routine is only available in Fortran 90, and you must include petsc.h90 in your code.
4951 
4952   Level: intermediate
4953 
4954 .seealso DMPlexVecGetClosure(), DMPlexVecSetClosure()
4955 @*/
4956 PetscErrorCode DMPlexMatSetClosure(DM dm, PetscSection section, PetscSection globalSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode)
4957 {
4958   DM_Plex        *mesh   = (DM_Plex*) dm->data;
4959   PetscSection    clSection;
4960   IS              clPoints;
4961   PetscInt       *points = NULL, *newPoints;
4962   const PetscInt *clp;
4963   PetscInt       *indices;
4964   PetscInt        offsets[32];
4965   PetscInt        numFields, numPoints, newNumPoints, numIndices, newNumIndices, dof, off, globalOff, pStart, pEnd, p, q, f;
4966   PetscScalar    *newValues;
4967   PetscErrorCode  ierr;
4968 
4969   PetscFunctionBegin;
4970   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4971   if (!section) {ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);}
4972   PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2);
4973   if (!globalSection) {ierr = DMGetDefaultGlobalSection(dm, &globalSection);CHKERRQ(ierr);}
4974   PetscValidHeaderSpecific(globalSection, PETSC_SECTION_CLASSID, 3);
4975   PetscValidHeaderSpecific(A, MAT_CLASSID, 4);
4976   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
4977   if (numFields > 31) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
4978   ierr = PetscMemzero(offsets, 32 * sizeof(PetscInt));CHKERRQ(ierr);
4979   ierr = PetscSectionGetClosureIndex(section, (PetscObject) dm, &clSection, &clPoints);CHKERRQ(ierr);
4980   if (!clPoints) {
4981     ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
4982     /* Compress out points not in the section */
4983     ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
4984     for (p = 0, q = 0; p < numPoints*2; p += 2) {
4985       if ((points[p] >= pStart) && (points[p] < pEnd)) {
4986         points[q*2]   = points[p];
4987         points[q*2+1] = points[p+1];
4988         ++q;
4989       }
4990     }
4991     numPoints = q;
4992   } else {
4993     PetscInt dof, off;
4994 
4995     ierr = PetscSectionGetDof(clSection, point, &dof);CHKERRQ(ierr);
4996     numPoints = dof/2;
4997     ierr = PetscSectionGetOffset(clSection, point, &off);CHKERRQ(ierr);
4998     ierr = ISGetIndices(clPoints, &clp);CHKERRQ(ierr);
4999     points = (PetscInt *) &clp[off];
5000   }
5001   for (p = 0, numIndices = 0; p < numPoints*2; p += 2) {
5002     PetscInt fdof;
5003 
5004     ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
5005     for (f = 0; f < numFields; ++f) {
5006       ierr          = PetscSectionGetFieldDof(section, points[p], f, &fdof);CHKERRQ(ierr);
5007       offsets[f+1] += fdof;
5008     }
5009     numIndices += dof;
5010   }
5011   for (f = 1; f < numFields; ++f) offsets[f+1] += offsets[f];
5012 
5013   if (numFields && offsets[numFields] != numIndices) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid size for closure %d should be %d", offsets[numFields], numIndices);
5014   ierr = DMPlexAnchorsModifyMat(dm,section,numPoints,numIndices,points,values,&newNumPoints,&newNumIndices,&newPoints,&newValues,offsets,PETSC_TRUE);CHKERRQ(ierr);
5015   if (newNumPoints) {
5016     if (!clPoints) {
5017       ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
5018     } else {
5019       ierr = ISRestoreIndices(clPoints, &clp);CHKERRQ(ierr);
5020     }
5021     numPoints  = newNumPoints;
5022     numIndices = newNumIndices;
5023     points     = newPoints;
5024     values     = newValues;
5025   }
5026   ierr = DMGetWorkArray(dm, numIndices, PETSC_INT, &indices);CHKERRQ(ierr);
5027   if (numFields) {
5028     for (p = 0; p < numPoints*2; p += 2) {
5029       PetscInt o = points[p+1];
5030       ierr = PetscSectionGetOffset(globalSection, points[p], &globalOff);CHKERRQ(ierr);
5031       DMPlexGetIndicesPointFields_Internal(section, points[p], globalOff < 0 ? -(globalOff+1) : globalOff, offsets, PETSC_FALSE, o, indices);
5032     }
5033   } else {
5034     for (p = 0, off = 0; p < numPoints*2; p += 2) {
5035       PetscInt o = points[p+1];
5036       ierr = PetscSectionGetOffset(globalSection, points[p], &globalOff);CHKERRQ(ierr);
5037       DMPlexGetIndicesPoint_Internal(section, points[p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, o, indices);
5038     }
5039   }
5040   if (mesh->printSetValues) {ierr = DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndices, indices, 0, NULL, values);CHKERRQ(ierr);}
5041   ierr = MatSetValues(A, numIndices, indices, numIndices, indices, values, mode);
5042   if (mesh->printFEM > 1) {
5043     PetscInt i;
5044     ierr = PetscPrintf(PETSC_COMM_SELF, "  Indices:");CHKERRQ(ierr);
5045     for (i = 0; i < numIndices; ++i) {ierr = PetscPrintf(PETSC_COMM_SELF, " %d", indices[i]);CHKERRQ(ierr);}
5046     ierr = PetscPrintf(PETSC_COMM_SELF, "\n");CHKERRQ(ierr);
5047   }
5048   if (ierr) {
5049     PetscMPIInt    rank;
5050     PetscErrorCode ierr2;
5051 
5052     ierr2 = MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank);CHKERRQ(ierr2);
5053     ierr2 = (*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank);CHKERRQ(ierr2);
5054     ierr2 = DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndices, indices, 0, NULL, values);CHKERRQ(ierr2);
5055     ierr2 = DMRestoreWorkArray(dm, numIndices, PETSC_INT, &indices);CHKERRQ(ierr2);
5056     CHKERRQ(ierr);
5057   }
5058   if (newNumPoints) {
5059     ierr = DMRestoreWorkArray(dm,newNumIndices*newNumIndices,PETSC_SCALAR,&newValues);CHKERRQ(ierr);
5060     ierr = DMRestoreWorkArray(dm,2*newNumPoints,PETSC_INT,&newPoints);CHKERRQ(ierr);
5061   }
5062   else {
5063     if (!clPoints) {
5064       ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
5065     } else {
5066       ierr = ISRestoreIndices(clPoints, &clp);CHKERRQ(ierr);
5067     }
5068   }
5069   ierr = DMRestoreWorkArray(dm, numIndices, PETSC_INT, &indices);CHKERRQ(ierr);
5070   PetscFunctionReturn(0);
5071 }
5072 
5073 #undef __FUNCT__
5074 #define __FUNCT__ "DMPlexMatSetClosureRefined"
5075 PetscErrorCode DMPlexMatSetClosureRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode)
5076 {
5077   DM_Plex        *mesh   = (DM_Plex*) dmf->data;
5078   PetscInt       *fpoints = NULL, *ftotpoints = NULL;
5079   PetscInt       *cpoints = NULL;
5080   PetscInt       *findices, *cindices;
5081   PetscInt        foffsets[32], coffsets[32];
5082   CellRefiner     cellRefiner;
5083   PetscInt        numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f;
5084   PetscErrorCode  ierr;
5085 
5086   PetscFunctionBegin;
5087   PetscValidHeaderSpecific(dmf, DM_CLASSID, 1);
5088   PetscValidHeaderSpecific(dmc, DM_CLASSID, 4);
5089   if (!fsection) {ierr = DMGetDefaultSection(dmf, &fsection);CHKERRQ(ierr);}
5090   PetscValidHeaderSpecific(fsection, PETSC_SECTION_CLASSID, 2);
5091   if (!csection) {ierr = DMGetDefaultSection(dmc, &csection);CHKERRQ(ierr);}
5092   PetscValidHeaderSpecific(csection, PETSC_SECTION_CLASSID, 5);
5093   if (!globalFSection) {ierr = DMGetDefaultGlobalSection(dmf, &globalFSection);CHKERRQ(ierr);}
5094   PetscValidHeaderSpecific(globalFSection, PETSC_SECTION_CLASSID, 3);
5095   if (!globalCSection) {ierr = DMGetDefaultGlobalSection(dmc, &globalCSection);CHKERRQ(ierr);}
5096   PetscValidHeaderSpecific(globalCSection, PETSC_SECTION_CLASSID, 6);
5097   PetscValidHeaderSpecific(A, MAT_CLASSID, 7);
5098   ierr = PetscSectionGetNumFields(fsection, &numFields);CHKERRQ(ierr);
5099   if (numFields > 31) SETERRQ1(PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
5100   ierr = PetscMemzero(foffsets, 32 * sizeof(PetscInt));CHKERRQ(ierr);
5101   ierr = PetscMemzero(coffsets, 32 * sizeof(PetscInt));CHKERRQ(ierr);
5102   /* Column indices */
5103   ierr = DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints);CHKERRQ(ierr);
5104   maxFPoints = numCPoints;
5105   /* Compress out points not in the section */
5106   /*   TODO: Squeeze out points with 0 dof as well */
5107   ierr = PetscSectionGetChart(csection, &pStart, &pEnd);CHKERRQ(ierr);
5108   for (p = 0, q = 0; p < numCPoints*2; p += 2) {
5109     if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) {
5110       cpoints[q*2]   = cpoints[p];
5111       cpoints[q*2+1] = cpoints[p+1];
5112       ++q;
5113     }
5114   }
5115   numCPoints = q;
5116   for (p = 0, numCIndices = 0; p < numCPoints*2; p += 2) {
5117     PetscInt fdof;
5118 
5119     ierr = PetscSectionGetDof(csection, cpoints[p], &dof);CHKERRQ(ierr);
5120     if (!dof) continue;
5121     for (f = 0; f < numFields; ++f) {
5122       ierr           = PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof);CHKERRQ(ierr);
5123       coffsets[f+1] += fdof;
5124     }
5125     numCIndices += dof;
5126   }
5127   for (f = 1; f < numFields; ++f) coffsets[f+1] += coffsets[f];
5128   /* Row indices */
5129   ierr = DMPlexGetCellRefiner_Internal(dmc, &cellRefiner);CHKERRQ(ierr);
5130   ierr = CellRefinerGetAffineTransforms_Internal(cellRefiner, &numSubcells, NULL, NULL, NULL);CHKERRQ(ierr);
5131   ierr = DMGetWorkArray(dmf, maxFPoints*2*numSubcells, PETSC_INT, &ftotpoints);CHKERRQ(ierr);
5132   for (r = 0, q = 0; r < numSubcells; ++r) {
5133     /* TODO Map from coarse to fine cells */
5134     ierr = DMPlexGetTransitiveClosure(dmf, point*numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints);CHKERRQ(ierr);
5135     /* Compress out points not in the section */
5136     ierr = PetscSectionGetChart(fsection, &pStart, &pEnd);CHKERRQ(ierr);
5137     for (p = 0; p < numFPoints*2; p += 2) {
5138       if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) {
5139         ierr = PetscSectionGetDof(fsection, fpoints[p], &dof);CHKERRQ(ierr);
5140         if (!dof) continue;
5141         for (s = 0; s < q; ++s) if (fpoints[p] == ftotpoints[s*2]) break;
5142         if (s < q) continue;
5143         ftotpoints[q*2]   = fpoints[p];
5144         ftotpoints[q*2+1] = fpoints[p+1];
5145         ++q;
5146       }
5147     }
5148     ierr = DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints);CHKERRQ(ierr);
5149   }
5150   numFPoints = q;
5151   for (p = 0, numFIndices = 0; p < numFPoints*2; p += 2) {
5152     PetscInt fdof;
5153 
5154     ierr = PetscSectionGetDof(fsection, ftotpoints[p], &dof);CHKERRQ(ierr);
5155     if (!dof) continue;
5156     for (f = 0; f < numFields; ++f) {
5157       ierr           = PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof);CHKERRQ(ierr);
5158       foffsets[f+1] += fdof;
5159     }
5160     numFIndices += dof;
5161   }
5162   for (f = 1; f < numFields; ++f) foffsets[f+1] += foffsets[f];
5163 
5164   if (numFields && foffsets[numFields] != numFIndices) SETERRQ2(PetscObjectComm((PetscObject)dmf), PETSC_ERR_PLIB, "Invalid size for closure %d should be %d", foffsets[numFields], numFIndices);
5165   if (numFields && coffsets[numFields] != numCIndices) SETERRQ2(PetscObjectComm((PetscObject)dmc), PETSC_ERR_PLIB, "Invalid size for closure %d should be %d", coffsets[numFields], numCIndices);
5166   ierr = DMGetWorkArray(dmf, numFIndices, PETSC_INT, &findices);CHKERRQ(ierr);
5167   ierr = DMGetWorkArray(dmc, numCIndices, PETSC_INT, &cindices);CHKERRQ(ierr);
5168   if (numFields) {
5169     for (p = 0; p < numFPoints*2; p += 2) {
5170       PetscInt o = ftotpoints[p+1];
5171       ierr = PetscSectionGetOffset(globalFSection, ftotpoints[p], &globalOff);CHKERRQ(ierr);
5172       DMPlexGetIndicesPointFields_Internal(fsection, ftotpoints[p], globalOff < 0 ? -(globalOff+1) : globalOff, foffsets, PETSC_FALSE, o, findices);
5173     }
5174     for (p = 0; p < numCPoints*2; p += 2) {
5175       PetscInt o = cpoints[p+1];
5176       ierr = PetscSectionGetOffset(globalCSection, cpoints[p], &globalOff);CHKERRQ(ierr);
5177       DMPlexGetIndicesPointFields_Internal(csection, cpoints[p], globalOff < 0 ? -(globalOff+1) : globalOff, coffsets, PETSC_FALSE, o, cindices);
5178     }
5179   } else {
5180     for (p = 0, off = 0; p < numFPoints*2; p += 2) {
5181       PetscInt o = ftotpoints[p+1];
5182       ierr = PetscSectionGetOffset(globalFSection, ftotpoints[p], &globalOff);CHKERRQ(ierr);
5183       DMPlexGetIndicesPoint_Internal(fsection, ftotpoints[p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, o, findices);
5184     }
5185     for (p = 0, off = 0; p < numCPoints*2; p += 2) {
5186       PetscInt o = cpoints[p+1];
5187       ierr = PetscSectionGetOffset(globalCSection, cpoints[p], &globalOff);CHKERRQ(ierr);
5188       DMPlexGetIndicesPoint_Internal(csection, cpoints[p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, o, cindices);
5189     }
5190   }
5191   if (mesh->printSetValues) {ierr = DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numFIndices, findices, numCIndices, cindices, values);CHKERRQ(ierr);}
5192   ierr = MatSetValues(A, numFIndices, findices, numCIndices, cindices, values, mode);
5193   if (ierr) {
5194     PetscMPIInt    rank;
5195     PetscErrorCode ierr2;
5196 
5197     ierr2 = MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank);CHKERRQ(ierr2);
5198     ierr2 = (*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank);CHKERRQ(ierr2);
5199     ierr2 = DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numFIndices, findices, numCIndices, cindices, values);CHKERRQ(ierr2);
5200     ierr2 = DMRestoreWorkArray(dmf, numFIndices, PETSC_INT, &findices);CHKERRQ(ierr2);
5201     ierr2 = DMRestoreWorkArray(dmc, numCIndices, PETSC_INT, &cindices);CHKERRQ(ierr2);
5202     CHKERRQ(ierr);
5203   }
5204   ierr = DMRestoreWorkArray(dmf, numCPoints*2*4, PETSC_INT, &ftotpoints);CHKERRQ(ierr);
5205   ierr = DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints);CHKERRQ(ierr);
5206   ierr = DMRestoreWorkArray(dmf, numFIndices, PETSC_INT, &findices);CHKERRQ(ierr);
5207   ierr = DMRestoreWorkArray(dmc, numCIndices, PETSC_INT, &cindices);CHKERRQ(ierr);
5208   PetscFunctionReturn(0);
5209 }
5210 
5211 #undef __FUNCT__
5212 #define __FUNCT__ "DMPlexMatGetClosureIndicesRefined"
5213 PetscErrorCode DMPlexMatGetClosureIndicesRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, PetscInt point, PetscInt cindices[], PetscInt findices[])
5214 {
5215   PetscInt      *fpoints = NULL, *ftotpoints = NULL;
5216   PetscInt      *cpoints = NULL;
5217   PetscInt       foffsets[32], coffsets[32];
5218   CellRefiner    cellRefiner;
5219   PetscInt       numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f;
5220   PetscErrorCode ierr;
5221 
5222   PetscFunctionBegin;
5223   PetscValidHeaderSpecific(dmf, DM_CLASSID, 1);
5224   PetscValidHeaderSpecific(dmc, DM_CLASSID, 4);
5225   if (!fsection) {ierr = DMGetDefaultSection(dmf, &fsection);CHKERRQ(ierr);}
5226   PetscValidHeaderSpecific(fsection, PETSC_SECTION_CLASSID, 2);
5227   if (!csection) {ierr = DMGetDefaultSection(dmc, &csection);CHKERRQ(ierr);}
5228   PetscValidHeaderSpecific(csection, PETSC_SECTION_CLASSID, 5);
5229   if (!globalFSection) {ierr = DMGetDefaultGlobalSection(dmf, &globalFSection);CHKERRQ(ierr);}
5230   PetscValidHeaderSpecific(globalFSection, PETSC_SECTION_CLASSID, 3);
5231   if (!globalCSection) {ierr = DMGetDefaultGlobalSection(dmc, &globalCSection);CHKERRQ(ierr);}
5232   PetscValidHeaderSpecific(globalCSection, PETSC_SECTION_CLASSID, 6);
5233   ierr = PetscSectionGetNumFields(fsection, &numFields);CHKERRQ(ierr);
5234   if (numFields > 31) SETERRQ1(PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
5235   ierr = PetscMemzero(foffsets, 32 * sizeof(PetscInt));CHKERRQ(ierr);
5236   ierr = PetscMemzero(coffsets, 32 * sizeof(PetscInt));CHKERRQ(ierr);
5237   /* Column indices */
5238   ierr = DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints);CHKERRQ(ierr);
5239   maxFPoints = numCPoints;
5240   /* Compress out points not in the section */
5241   /*   TODO: Squeeze out points with 0 dof as well */
5242   ierr = PetscSectionGetChart(csection, &pStart, &pEnd);CHKERRQ(ierr);
5243   for (p = 0, q = 0; p < numCPoints*2; p += 2) {
5244     if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) {
5245       cpoints[q*2]   = cpoints[p];
5246       cpoints[q*2+1] = cpoints[p+1];
5247       ++q;
5248     }
5249   }
5250   numCPoints = q;
5251   for (p = 0, numCIndices = 0; p < numCPoints*2; p += 2) {
5252     PetscInt fdof;
5253 
5254     ierr = PetscSectionGetDof(csection, cpoints[p], &dof);CHKERRQ(ierr);
5255     if (!dof) continue;
5256     for (f = 0; f < numFields; ++f) {
5257       ierr           = PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof);CHKERRQ(ierr);
5258       coffsets[f+1] += fdof;
5259     }
5260     numCIndices += dof;
5261   }
5262   for (f = 1; f < numFields; ++f) coffsets[f+1] += coffsets[f];
5263   /* Row indices */
5264   ierr = DMPlexGetCellRefiner_Internal(dmc, &cellRefiner);CHKERRQ(ierr);
5265   ierr = CellRefinerGetAffineTransforms_Internal(cellRefiner, &numSubcells, NULL, NULL, NULL);CHKERRQ(ierr);
5266   ierr = DMGetWorkArray(dmf, maxFPoints*2*numSubcells, PETSC_INT, &ftotpoints);CHKERRQ(ierr);
5267   for (r = 0, q = 0; r < numSubcells; ++r) {
5268     /* TODO Map from coarse to fine cells */
5269     ierr = DMPlexGetTransitiveClosure(dmf, point*numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints);CHKERRQ(ierr);
5270     /* Compress out points not in the section */
5271     ierr = PetscSectionGetChart(fsection, &pStart, &pEnd);CHKERRQ(ierr);
5272     for (p = 0; p < numFPoints*2; p += 2) {
5273       if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) {
5274         ierr = PetscSectionGetDof(fsection, fpoints[p], &dof);CHKERRQ(ierr);
5275         if (!dof) continue;
5276         for (s = 0; s < q; ++s) if (fpoints[p] == ftotpoints[s*2]) break;
5277         if (s < q) continue;
5278         ftotpoints[q*2]   = fpoints[p];
5279         ftotpoints[q*2+1] = fpoints[p+1];
5280         ++q;
5281       }
5282     }
5283     ierr = DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints);CHKERRQ(ierr);
5284   }
5285   numFPoints = q;
5286   for (p = 0, numFIndices = 0; p < numFPoints*2; p += 2) {
5287     PetscInt fdof;
5288 
5289     ierr = PetscSectionGetDof(fsection, ftotpoints[p], &dof);CHKERRQ(ierr);
5290     if (!dof) continue;
5291     for (f = 0; f < numFields; ++f) {
5292       ierr           = PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof);CHKERRQ(ierr);
5293       foffsets[f+1] += fdof;
5294     }
5295     numFIndices += dof;
5296   }
5297   for (f = 1; f < numFields; ++f) foffsets[f+1] += foffsets[f];
5298 
5299   if (numFields && foffsets[numFields] != numFIndices) SETERRQ2(PetscObjectComm((PetscObject)dmf), PETSC_ERR_PLIB, "Invalid size for closure %d should be %d", foffsets[numFields], numFIndices);
5300   if (numFields && coffsets[numFields] != numCIndices) SETERRQ2(PetscObjectComm((PetscObject)dmc), PETSC_ERR_PLIB, "Invalid size for closure %d should be %d", coffsets[numFields], numCIndices);
5301   if (numFields) {
5302     for (p = 0; p < numFPoints*2; p += 2) {
5303       PetscInt o = ftotpoints[p+1];
5304       ierr = PetscSectionGetOffset(globalFSection, ftotpoints[p], &globalOff);CHKERRQ(ierr);
5305       DMPlexGetIndicesPointFields_Internal(fsection, ftotpoints[p], globalOff < 0 ? -(globalOff+1) : globalOff, foffsets, PETSC_FALSE, o, findices);
5306     }
5307     for (p = 0; p < numCPoints*2; p += 2) {
5308       PetscInt o = cpoints[p+1];
5309       ierr = PetscSectionGetOffset(globalCSection, cpoints[p], &globalOff);CHKERRQ(ierr);
5310       DMPlexGetIndicesPointFields_Internal(csection, cpoints[p], globalOff < 0 ? -(globalOff+1) : globalOff, coffsets, PETSC_FALSE, o, cindices);
5311     }
5312   } else {
5313     for (p = 0, off = 0; p < numFPoints*2; p += 2) {
5314       PetscInt o = ftotpoints[p+1];
5315       ierr = PetscSectionGetOffset(globalFSection, ftotpoints[p], &globalOff);CHKERRQ(ierr);
5316       DMPlexGetIndicesPoint_Internal(fsection, ftotpoints[p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, o, findices);
5317     }
5318     for (p = 0, off = 0; p < numCPoints*2; p += 2) {
5319       PetscInt o = cpoints[p+1];
5320       ierr = PetscSectionGetOffset(globalCSection, cpoints[p], &globalOff);CHKERRQ(ierr);
5321       DMPlexGetIndicesPoint_Internal(csection, cpoints[p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, o, cindices);
5322     }
5323   }
5324   ierr = DMRestoreWorkArray(dmf, numCPoints*2*4, PETSC_INT, &ftotpoints);CHKERRQ(ierr);
5325   ierr = DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints);CHKERRQ(ierr);
5326   PetscFunctionReturn(0);
5327 }
5328 
5329 #undef __FUNCT__
5330 #define __FUNCT__ "DMPlexGetHybridBounds"
5331 /*@
5332   DMPlexGetHybridBounds - Get the first mesh point of each dimension which is a hybrid
5333 
5334   Input Parameter:
5335 . dm - The DMPlex object
5336 
5337   Output Parameters:
5338 + cMax - The first hybrid cell
5339 . fMax - The first hybrid face
5340 . eMax - The first hybrid edge
5341 - vMax - The first hybrid vertex
5342 
5343   Level: developer
5344 
5345 .seealso DMPlexCreateHybridMesh(), DMPlexSetHybridBounds()
5346 @*/
5347 PetscErrorCode DMPlexGetHybridBounds(DM dm, PetscInt *cMax, PetscInt *fMax, PetscInt *eMax, PetscInt *vMax)
5348 {
5349   DM_Plex       *mesh = (DM_Plex*) dm->data;
5350   PetscInt       dim;
5351   PetscErrorCode ierr;
5352 
5353   PetscFunctionBegin;
5354   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5355   ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr);
5356   if (cMax) *cMax = mesh->hybridPointMax[dim];
5357   if (fMax) *fMax = mesh->hybridPointMax[dim-1];
5358   if (eMax) *eMax = mesh->hybridPointMax[1];
5359   if (vMax) *vMax = mesh->hybridPointMax[0];
5360   PetscFunctionReturn(0);
5361 }
5362 
5363 #undef __FUNCT__
5364 #define __FUNCT__ "DMPlexSetHybridBounds"
5365 /*@
5366   DMPlexSetHybridBounds - Set the first mesh point of each dimension which is a hybrid
5367 
5368   Input Parameters:
5369 . dm   - The DMPlex object
5370 . cMax - The first hybrid cell
5371 . fMax - The first hybrid face
5372 . eMax - The first hybrid edge
5373 - vMax - The first hybrid vertex
5374 
5375   Level: developer
5376 
5377 .seealso DMPlexCreateHybridMesh(), DMPlexGetHybridBounds()
5378 @*/
5379 PetscErrorCode DMPlexSetHybridBounds(DM dm, PetscInt cMax, PetscInt fMax, PetscInt eMax, PetscInt vMax)
5380 {
5381   DM_Plex       *mesh = (DM_Plex*) dm->data;
5382   PetscInt       dim;
5383   PetscErrorCode ierr;
5384 
5385   PetscFunctionBegin;
5386   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5387   ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr);
5388   if (cMax >= 0) mesh->hybridPointMax[dim]   = cMax;
5389   if (fMax >= 0) mesh->hybridPointMax[dim-1] = fMax;
5390   if (eMax >= 0) mesh->hybridPointMax[1]     = eMax;
5391   if (vMax >= 0) mesh->hybridPointMax[0]     = vMax;
5392   PetscFunctionReturn(0);
5393 }
5394 
5395 #undef __FUNCT__
5396 #define __FUNCT__ "DMPlexGetVTKCellHeight"
5397 PetscErrorCode DMPlexGetVTKCellHeight(DM dm, PetscInt *cellHeight)
5398 {
5399   DM_Plex *mesh = (DM_Plex*) dm->data;
5400 
5401   PetscFunctionBegin;
5402   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5403   PetscValidPointer(cellHeight, 2);
5404   *cellHeight = mesh->vtkCellHeight;
5405   PetscFunctionReturn(0);
5406 }
5407 
5408 #undef __FUNCT__
5409 #define __FUNCT__ "DMPlexSetVTKCellHeight"
5410 PetscErrorCode DMPlexSetVTKCellHeight(DM dm, PetscInt cellHeight)
5411 {
5412   DM_Plex *mesh = (DM_Plex*) dm->data;
5413 
5414   PetscFunctionBegin;
5415   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5416   mesh->vtkCellHeight = cellHeight;
5417   PetscFunctionReturn(0);
5418 }
5419 
5420 #undef __FUNCT__
5421 #define __FUNCT__ "DMPlexCreateNumbering_Private"
5422 /* We can easily have a form that takes an IS instead */
5423 static PetscErrorCode DMPlexCreateNumbering_Private(DM dm, PetscInt pStart, PetscInt pEnd, PetscInt shift, PetscInt *globalSize, PetscSF sf, IS *numbering)
5424 {
5425   PetscSection   section, globalSection;
5426   PetscInt      *numbers, p;
5427   PetscErrorCode ierr;
5428 
5429   PetscFunctionBegin;
5430   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)dm), &section);CHKERRQ(ierr);
5431   ierr = PetscSectionSetChart(section, pStart, pEnd);CHKERRQ(ierr);
5432   for (p = pStart; p < pEnd; ++p) {
5433     ierr = PetscSectionSetDof(section, p, 1);CHKERRQ(ierr);
5434   }
5435   ierr = PetscSectionSetUp(section);CHKERRQ(ierr);
5436   ierr = PetscSectionCreateGlobalSection(section, sf, PETSC_FALSE, PETSC_FALSE, &globalSection);CHKERRQ(ierr);
5437   ierr = PetscMalloc1(pEnd - pStart, &numbers);CHKERRQ(ierr);
5438   for (p = pStart; p < pEnd; ++p) {
5439     ierr = PetscSectionGetOffset(globalSection, p, &numbers[p-pStart]);CHKERRQ(ierr);
5440     if (numbers[p-pStart] < 0) numbers[p-pStart] -= shift;
5441     else                       numbers[p-pStart] += shift;
5442   }
5443   ierr = ISCreateGeneral(PetscObjectComm((PetscObject) dm), pEnd - pStart, numbers, PETSC_OWN_POINTER, numbering);CHKERRQ(ierr);
5444   if (globalSize) {
5445     PetscLayout layout;
5446     ierr = PetscSectionGetPointLayout(PetscObjectComm((PetscObject) dm), globalSection, &layout);CHKERRQ(ierr);
5447     ierr = PetscLayoutGetSize(layout, globalSize);CHKERRQ(ierr);
5448     ierr = PetscLayoutDestroy(&layout);CHKERRQ(ierr);
5449   }
5450   ierr = PetscSectionDestroy(&section);CHKERRQ(ierr);
5451   ierr = PetscSectionDestroy(&globalSection);CHKERRQ(ierr);
5452   PetscFunctionReturn(0);
5453 }
5454 
5455 #undef __FUNCT__
5456 #define __FUNCT__ "DMPlexCreateCellNumbering_Internal"
5457 PetscErrorCode DMPlexCreateCellNumbering_Internal(DM dm, PetscBool includeHybrid, IS *globalCellNumbers)
5458 {
5459   PetscInt       cellHeight, cStart, cEnd, cMax;
5460   PetscErrorCode ierr;
5461 
5462   PetscFunctionBegin;
5463   ierr = DMPlexGetVTKCellHeight(dm, &cellHeight);CHKERRQ(ierr);
5464   ierr = DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd);CHKERRQ(ierr);
5465   ierr = DMPlexGetHybridBounds(dm, &cMax, NULL, NULL, NULL);CHKERRQ(ierr);
5466   if (cMax >= 0 && !includeHybrid) cEnd = PetscMin(cEnd, cMax);
5467   ierr = DMPlexCreateNumbering_Private(dm, cStart, cEnd, 0, NULL, dm->sf, globalCellNumbers);CHKERRQ(ierr);
5468   PetscFunctionReturn(0);
5469 }
5470 
5471 #undef __FUNCT__
5472 #define __FUNCT__ "DMPlexGetCellNumbering"
5473 PetscErrorCode DMPlexGetCellNumbering(DM dm, IS *globalCellNumbers)
5474 {
5475   DM_Plex       *mesh = (DM_Plex*) dm->data;
5476   PetscErrorCode ierr;
5477 
5478   PetscFunctionBegin;
5479   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5480   if (!mesh->globalCellNumbers) {ierr = DMPlexCreateCellNumbering_Internal(dm, PETSC_FALSE, &mesh->globalCellNumbers);CHKERRQ(ierr);}
5481   *globalCellNumbers = mesh->globalCellNumbers;
5482   PetscFunctionReturn(0);
5483 }
5484 
5485 #undef __FUNCT__
5486 #define __FUNCT__ "DMPlexCreateVertexNumbering_Internal"
5487 PetscErrorCode DMPlexCreateVertexNumbering_Internal(DM dm, PetscBool includeHybrid, IS *globalVertexNumbers)
5488 {
5489   PetscInt       vStart, vEnd, vMax;
5490   PetscErrorCode ierr;
5491 
5492   PetscFunctionBegin;
5493   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5494   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
5495   ierr = DMPlexGetHybridBounds(dm, NULL, NULL, NULL, &vMax);CHKERRQ(ierr);
5496   if (vMax >= 0 && !includeHybrid) vEnd = PetscMin(vEnd, vMax);
5497   ierr = DMPlexCreateNumbering_Private(dm, vStart, vEnd, 0, NULL, dm->sf, globalVertexNumbers);CHKERRQ(ierr);
5498   PetscFunctionReturn(0);
5499 }
5500 
5501 #undef __FUNCT__
5502 #define __FUNCT__ "DMPlexGetVertexNumbering"
5503 PetscErrorCode DMPlexGetVertexNumbering(DM dm, IS *globalVertexNumbers)
5504 {
5505   DM_Plex       *mesh = (DM_Plex*) dm->data;
5506   PetscErrorCode ierr;
5507 
5508   PetscFunctionBegin;
5509   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5510   if (!mesh->globalVertexNumbers) {ierr = DMPlexCreateVertexNumbering_Internal(dm, PETSC_FALSE, &mesh->globalVertexNumbers);CHKERRQ(ierr);}
5511   *globalVertexNumbers = mesh->globalVertexNumbers;
5512   PetscFunctionReturn(0);
5513 }
5514 
5515 #undef __FUNCT__
5516 #define __FUNCT__ "DMPlexCreatePointNumbering"
5517 PetscErrorCode DMPlexCreatePointNumbering(DM dm, IS *globalPointNumbers)
5518 {
5519   IS             nums[4];
5520   PetscInt       depths[4];
5521   PetscInt       depth, d, shift = 0;
5522   PetscErrorCode ierr;
5523 
5524   PetscFunctionBegin;
5525   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5526   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
5527   /* For unstratified meshes use dim instead of depth */
5528   if (depth < 0) {ierr = DMGetDimension(dm, &depth);CHKERRQ(ierr);}
5529   depths[0] = depth; depths[1] = 0;
5530   for (d = 2; d <= depth; ++d) depths[d] = depth-d+1;
5531   for (d = 0; d <= depth; ++d) {
5532     PetscInt pStart, pEnd, gsize;
5533 
5534     ierr = DMPlexGetDepthStratum(dm, depths[d], &pStart, &pEnd);CHKERRQ(ierr);
5535     ierr = DMPlexCreateNumbering_Private(dm, pStart, pEnd, shift, &gsize, dm->sf, &nums[d]);CHKERRQ(ierr);
5536     shift += gsize;
5537   }
5538   ierr = ISConcatenate(PetscObjectComm((PetscObject) dm), depth+1, nums, globalPointNumbers);CHKERRQ(ierr);
5539   for (d = 0; d <= depth; ++d) {ierr = ISDestroy(&nums[d]);CHKERRQ(ierr);}
5540   PetscFunctionReturn(0);
5541 }
5542 
5543 #undef __FUNCT__
5544 #define __FUNCT__ "DMPlexCheckSymmetry"
5545 /*@
5546   DMPlexCheckSymmetry - Check that the adjacency information in the mesh is symmetric.
5547 
5548   Input Parameters:
5549   + dm - The DMPlex object
5550 
5551   Note: This is a useful diagnostic when creating meshes programmatically.
5552 
5553   Level: developer
5554 
5555 .seealso: DMCreate(), DMCheckSkeleton(), DMCheckFaces()
5556 @*/
5557 PetscErrorCode DMPlexCheckSymmetry(DM dm)
5558 {
5559   PetscSection    coneSection, supportSection;
5560   const PetscInt *cone, *support;
5561   PetscInt        coneSize, c, supportSize, s;
5562   PetscInt        pStart, pEnd, p, csize, ssize;
5563   PetscErrorCode  ierr;
5564 
5565   PetscFunctionBegin;
5566   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5567   ierr = DMPlexGetConeSection(dm, &coneSection);CHKERRQ(ierr);
5568   ierr = DMPlexGetSupportSection(dm, &supportSection);CHKERRQ(ierr);
5569   /* Check that point p is found in the support of its cone points, and vice versa */
5570   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
5571   for (p = pStart; p < pEnd; ++p) {
5572     ierr = DMPlexGetConeSize(dm, p, &coneSize);CHKERRQ(ierr);
5573     ierr = DMPlexGetCone(dm, p, &cone);CHKERRQ(ierr);
5574     for (c = 0; c < coneSize; ++c) {
5575       PetscBool dup = PETSC_FALSE;
5576       PetscInt  d;
5577       for (d = c-1; d >= 0; --d) {
5578         if (cone[c] == cone[d]) {dup = PETSC_TRUE; break;}
5579       }
5580       ierr = DMPlexGetSupportSize(dm, cone[c], &supportSize);CHKERRQ(ierr);
5581       ierr = DMPlexGetSupport(dm, cone[c], &support);CHKERRQ(ierr);
5582       for (s = 0; s < supportSize; ++s) {
5583         if (support[s] == p) break;
5584       }
5585       if ((s >= supportSize) || (dup && (support[s+1] != p))) {
5586         ierr = PetscPrintf(PETSC_COMM_SELF, "p: %d cone: ", p);CHKERRQ(ierr);
5587         for (s = 0; s < coneSize; ++s) {
5588           ierr = PetscPrintf(PETSC_COMM_SELF, "%d, ", cone[s]);CHKERRQ(ierr);
5589         }
5590         ierr = PetscPrintf(PETSC_COMM_SELF, "\n");CHKERRQ(ierr);
5591         ierr = PetscPrintf(PETSC_COMM_SELF, "p: %d support: ", cone[c]);CHKERRQ(ierr);
5592         for (s = 0; s < supportSize; ++s) {
5593           ierr = PetscPrintf(PETSC_COMM_SELF, "%d, ", support[s]);CHKERRQ(ierr);
5594         }
5595         ierr = PetscPrintf(PETSC_COMM_SELF, "\n");CHKERRQ(ierr);
5596         if (dup) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d not repeatedly found in support of repeated cone point %d", p, cone[c]);
5597         else SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d not found in support of cone point %d", p, cone[c]);
5598       }
5599     }
5600     ierr = DMPlexGetSupportSize(dm, p, &supportSize);CHKERRQ(ierr);
5601     ierr = DMPlexGetSupport(dm, p, &support);CHKERRQ(ierr);
5602     for (s = 0; s < supportSize; ++s) {
5603       ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
5604       ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
5605       for (c = 0; c < coneSize; ++c) {
5606         if (cone[c] == p) break;
5607       }
5608       if (c >= coneSize) {
5609         ierr = PetscPrintf(PETSC_COMM_SELF, "p: %d support: ", p);CHKERRQ(ierr);
5610         for (c = 0; c < supportSize; ++c) {
5611           ierr = PetscPrintf(PETSC_COMM_SELF, "%d, ", support[c]);CHKERRQ(ierr);
5612         }
5613         ierr = PetscPrintf(PETSC_COMM_SELF, "\n");CHKERRQ(ierr);
5614         ierr = PetscPrintf(PETSC_COMM_SELF, "p: %d cone: ", support[s]);CHKERRQ(ierr);
5615         for (c = 0; c < coneSize; ++c) {
5616           ierr = PetscPrintf(PETSC_COMM_SELF, "%d, ", cone[c]);CHKERRQ(ierr);
5617         }
5618         ierr = PetscPrintf(PETSC_COMM_SELF, "\n");CHKERRQ(ierr);
5619         SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d not found in cone of support point %d", p, support[s]);
5620       }
5621     }
5622   }
5623   ierr = PetscSectionGetStorageSize(coneSection, &csize);CHKERRQ(ierr);
5624   ierr = PetscSectionGetStorageSize(supportSection, &ssize);CHKERRQ(ierr);
5625   if (csize != ssize) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Total cone size %d != Total support size %d", csize, ssize);
5626   PetscFunctionReturn(0);
5627 }
5628 
5629 #undef __FUNCT__
5630 #define __FUNCT__ "DMPlexCheckSkeleton"
5631 /*@
5632   DMPlexCheckSkeleton - Check that each cell has the correct number of vertices
5633 
5634   Input Parameters:
5635 + dm - The DMPlex object
5636 . isSimplex - Are the cells simplices or tensor products
5637 - cellHeight - Normally 0
5638 
5639   Note: This is a useful diagnostic when creating meshes programmatically.
5640 
5641   Level: developer
5642 
5643 .seealso: DMCreate(), DMCheckSymmetry(), DMCheckFaces()
5644 @*/
5645 PetscErrorCode DMPlexCheckSkeleton(DM dm, PetscBool isSimplex, PetscInt cellHeight)
5646 {
5647   PetscInt       dim, numCorners, numHybridCorners, vStart, vEnd, cStart, cEnd, cMax, c;
5648   PetscErrorCode ierr;
5649 
5650   PetscFunctionBegin;
5651   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5652   ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr);
5653   switch (dim) {
5654   case 1: numCorners = isSimplex ? 2 : 2; numHybridCorners = isSimplex ? 2 : 2; break;
5655   case 2: numCorners = isSimplex ? 3 : 4; numHybridCorners = isSimplex ? 4 : 4; break;
5656   case 3: numCorners = isSimplex ? 4 : 8; numHybridCorners = isSimplex ? 6 : 8; break;
5657   default:
5658     SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_OUTOFRANGE, "Cannot handle meshes of dimension %d", dim);
5659   }
5660   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
5661   ierr = DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd);CHKERRQ(ierr);
5662   ierr = DMPlexGetHybridBounds(dm, &cMax, NULL, NULL, NULL);CHKERRQ(ierr);
5663   cMax = cMax >= 0 ? cMax : cEnd;
5664   for (c = cStart; c < cMax; ++c) {
5665     PetscInt *closure = NULL, closureSize, cl, coneSize = 0;
5666 
5667     ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
5668     for (cl = 0; cl < closureSize*2; cl += 2) {
5669       const PetscInt p = closure[cl];
5670       if ((p >= vStart) && (p < vEnd)) ++coneSize;
5671     }
5672     ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
5673     if (coneSize != numCorners) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cell %d has  %d vertices != %d", c, coneSize, numCorners);
5674   }
5675   for (c = cMax; c < cEnd; ++c) {
5676     PetscInt *closure = NULL, closureSize, cl, coneSize = 0;
5677 
5678     ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
5679     for (cl = 0; cl < closureSize*2; cl += 2) {
5680       const PetscInt p = closure[cl];
5681       if ((p >= vStart) && (p < vEnd)) ++coneSize;
5682     }
5683     ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
5684     if (coneSize > numHybridCorners) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Hybrid cell %d has  %d vertices > %d", c, coneSize, numHybridCorners);
5685   }
5686   PetscFunctionReturn(0);
5687 }
5688 
5689 #undef __FUNCT__
5690 #define __FUNCT__ "DMPlexCheckFaces"
5691 /*@
5692   DMPlexCheckFaces - Check that the faces of each cell give a vertex order this is consistent with what we expect from the cell type
5693 
5694   Input Parameters:
5695 + dm - The DMPlex object
5696 . isSimplex - Are the cells simplices or tensor products
5697 - cellHeight - Normally 0
5698 
5699   Note: This is a useful diagnostic when creating meshes programmatically.
5700 
5701   Level: developer
5702 
5703 .seealso: DMCreate(), DMCheckSymmetry(), DMCheckSkeleton()
5704 @*/
5705 PetscErrorCode DMPlexCheckFaces(DM dm, PetscBool isSimplex, PetscInt cellHeight)
5706 {
5707   PetscInt       pMax[4];
5708   PetscInt       dim, vStart, vEnd, cStart, cEnd, c, h;
5709   PetscErrorCode ierr;
5710 
5711   PetscFunctionBegin;
5712   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5713   ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr);
5714   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
5715   ierr = DMPlexGetHybridBounds(dm, &pMax[dim], &pMax[dim-1], &pMax[1], &pMax[0]);CHKERRQ(ierr);
5716   for (h = cellHeight; h < dim; ++h) {
5717     ierr = DMPlexGetHeightStratum(dm, h, &cStart, &cEnd);CHKERRQ(ierr);
5718     for (c = cStart; c < cEnd; ++c) {
5719       const PetscInt *cone, *ornt, *faces;
5720       PetscInt        numFaces, faceSize, coneSize,f;
5721       PetscInt       *closure = NULL, closureSize, cl, numCorners = 0;
5722 
5723       if (pMax[dim-h] >= 0 && c >= pMax[dim-h]) continue;
5724       ierr = DMPlexGetConeSize(dm, c, &coneSize);CHKERRQ(ierr);
5725       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
5726       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
5727       ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
5728       for (cl = 0; cl < closureSize*2; cl += 2) {
5729         const PetscInt p = closure[cl];
5730         if ((p >= vStart) && (p < vEnd)) closure[numCorners++] = p;
5731       }
5732       ierr = DMPlexGetRawFaces_Internal(dm, dim-h, numCorners, closure, &numFaces, &faceSize, &faces);CHKERRQ(ierr);
5733       if (coneSize != numFaces) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cell %d has %d faces but should have %d", c, coneSize, numFaces);
5734       for (f = 0; f < numFaces; ++f) {
5735         PetscInt *fclosure = NULL, fclosureSize, cl, fnumCorners = 0, v;
5736 
5737         ierr = DMPlexGetTransitiveClosure_Internal(dm, cone[f], ornt[f], PETSC_TRUE, &fclosureSize, &fclosure);CHKERRQ(ierr);
5738         for (cl = 0; cl < fclosureSize*2; cl += 2) {
5739           const PetscInt p = fclosure[cl];
5740           if ((p >= vStart) && (p < vEnd)) fclosure[fnumCorners++] = p;
5741         }
5742         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);
5743         for (v = 0; v < fnumCorners; ++v) {
5744           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]);
5745         }
5746         ierr = DMPlexRestoreTransitiveClosure(dm, cone[f], PETSC_TRUE, &fclosureSize, &fclosure);CHKERRQ(ierr);
5747       }
5748       ierr = DMPlexRestoreFaces_Internal(dm, dim, c, &numFaces, &faceSize, &faces);CHKERRQ(ierr);
5749       ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
5750     }
5751   }
5752   PetscFunctionReturn(0);
5753 }
5754 
5755 #undef __FUNCT__
5756 #define __FUNCT__ "DMCreateInterpolation_Plex"
5757 /* Pointwise interpolation
5758      Just code FEM for now
5759      u^f = I u^c
5760      sum_k u^f_k phi^f_k = I sum_j u^c_j phi^c_j
5761      u^f_i = sum_j psi^f_i I phi^c_j u^c_j
5762      I_{ij} = psi^f_i phi^c_j
5763 */
5764 PetscErrorCode DMCreateInterpolation_Plex(DM dmCoarse, DM dmFine, Mat *interpolation, Vec *scaling)
5765 {
5766   PetscSection   gsc, gsf;
5767   PetscInt       m, n;
5768   void          *ctx;
5769   DM             cdm;
5770   PetscBool      regular;
5771   PetscErrorCode ierr;
5772 
5773   PetscFunctionBegin;
5774   ierr = DMGetDefaultGlobalSection(dmFine, &gsf);CHKERRQ(ierr);
5775   ierr = PetscSectionGetConstrainedStorageSize(gsf, &m);CHKERRQ(ierr);
5776   ierr = DMGetDefaultGlobalSection(dmCoarse, &gsc);CHKERRQ(ierr);
5777   ierr = PetscSectionGetConstrainedStorageSize(gsc, &n);CHKERRQ(ierr);
5778 
5779   ierr = MatCreate(PetscObjectComm((PetscObject) dmCoarse), interpolation);CHKERRQ(ierr);
5780   ierr = MatSetSizes(*interpolation, m, n, PETSC_DETERMINE, PETSC_DETERMINE);CHKERRQ(ierr);
5781   ierr = MatSetType(*interpolation, dmCoarse->mattype);CHKERRQ(ierr);
5782   ierr = DMGetApplicationContext(dmFine, &ctx);CHKERRQ(ierr);
5783 
5784   ierr = DMGetCoarseDM(dmFine, &cdm);CHKERRQ(ierr);
5785   ierr = DMPlexGetRegularRefinement(dmFine, &regular);CHKERRQ(ierr);
5786   if (regular && cdm == dmCoarse) {ierr = DMPlexComputeInterpolatorNested(dmCoarse, dmFine, *interpolation, ctx);CHKERRQ(ierr);}
5787   else                            {ierr = DMPlexComputeInterpolatorGeneral(dmCoarse, dmFine, *interpolation, ctx);CHKERRQ(ierr);}
5788   ierr = MatViewFromOptions(*interpolation, NULL, "-interp_mat_view");CHKERRQ(ierr);
5789   /* Use naive scaling */
5790   ierr = DMCreateInterpolationScale(dmCoarse, dmFine, *interpolation, scaling);CHKERRQ(ierr);
5791   PetscFunctionReturn(0);
5792 }
5793 
5794 #undef __FUNCT__
5795 #define __FUNCT__ "DMCreateInjection_Plex"
5796 PetscErrorCode DMCreateInjection_Plex(DM dmCoarse, DM dmFine, Mat *mat)
5797 {
5798   PetscErrorCode ierr;
5799   VecScatter     ctx;
5800 
5801   PetscFunctionBegin;
5802   ierr = DMPlexComputeInjectorFEM(dmCoarse, dmFine, &ctx, NULL);CHKERRQ(ierr);
5803   ierr = MatCreateScatter(PetscObjectComm((PetscObject)ctx), ctx, mat);CHKERRQ(ierr);
5804   ierr = VecScatterDestroy(&ctx);CHKERRQ(ierr);
5805   PetscFunctionReturn(0);
5806 }
5807 
5808 #undef __FUNCT__
5809 #define __FUNCT__ "DMCreateDefaultSection_Plex"
5810 PetscErrorCode DMCreateDefaultSection_Plex(DM dm)
5811 {
5812   PetscSection   section;
5813   IS            *bcPoints, *bcComps;
5814   PetscBool     *isFE;
5815   PetscInt      *bcFields, *numComp, *numDof;
5816   PetscInt       depth, dim, numBd, numBC = 0, numFields, bd, bc = 0, f;
5817   PetscInt       cStart, cEnd, cEndInterior;
5818   PetscErrorCode ierr;
5819 
5820   PetscFunctionBegin;
5821   ierr = DMGetNumFields(dm, &numFields);CHKERRQ(ierr);
5822   if (!numFields) PetscFunctionReturn(0);
5823   /* FE and FV boundary conditions are handled slightly differently */
5824   ierr = PetscMalloc1(numFields, &isFE);CHKERRQ(ierr);
5825   for (f = 0; f < numFields; ++f) {
5826     PetscObject  obj;
5827     PetscClassId id;
5828 
5829     ierr = DMGetField(dm, f, &obj);CHKERRQ(ierr);
5830     ierr = PetscObjectGetClassId(obj, &id);CHKERRQ(ierr);
5831     if (id == PETSCFE_CLASSID)      {isFE[f] = PETSC_TRUE;}
5832     else if (id == PETSCFV_CLASSID) {isFE[f] = PETSC_FALSE;}
5833     else SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %d", f);
5834   }
5835   /* Allocate boundary point storage for FEM boundaries */
5836   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
5837   ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr);
5838   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
5839   ierr = DMPlexGetHybridBounds(dm, &cEndInterior, NULL, NULL, NULL);CHKERRQ(ierr);
5840   ierr = PetscDSGetNumBoundary(dm->prob, &numBd);CHKERRQ(ierr);
5841   for (bd = 0; bd < numBd; ++bd) {
5842     PetscInt    field;
5843     PetscBool   isEssential;
5844     const char  *labelName;
5845     DMLabel     label;
5846 
5847     ierr = PetscDSGetBoundary(dm->prob, bd, &isEssential, NULL, &labelName, &field, NULL, NULL, NULL, NULL, NULL, NULL);CHKERRQ(ierr);
5848     ierr = DMGetLabel(dm,labelName,&label);CHKERRQ(ierr);
5849     if (label && isFE[field] && isEssential) ++numBC;
5850   }
5851   /* Add ghost cell boundaries for FVM */
5852   for (f = 0; f < numFields; ++f) if (!isFE[f] && cEndInterior >= 0) ++numBC;
5853   ierr = PetscCalloc3(numBC,&bcFields,numBC,&bcPoints,numBC,&bcComps);CHKERRQ(ierr);
5854   /* Constrain ghost cells for FV */
5855   for (f = 0; f < numFields; ++f) {
5856     PetscInt *newidx, c;
5857 
5858     if (isFE[f] || cEndInterior < 0) continue;
5859     ierr = PetscMalloc1(cEnd-cEndInterior,&newidx);CHKERRQ(ierr);
5860     for (c = cEndInterior; c < cEnd; ++c) newidx[c-cEndInterior] = c;
5861     bcFields[bc] = f;
5862     ierr = ISCreateGeneral(PetscObjectComm((PetscObject) dm), cEnd-cEndInterior, newidx, PETSC_OWN_POINTER, &bcPoints[bc++]);CHKERRQ(ierr);
5863   }
5864   /* Handle FEM Dirichlet boundaries */
5865   for (bd = 0; bd < numBd; ++bd) {
5866     const char     *bdLabel;
5867     DMLabel         label;
5868     const PetscInt *comps;
5869     const PetscInt *values;
5870     PetscInt        bd2, field, numComps, numValues;
5871     PetscBool       isEssential, duplicate = PETSC_FALSE;
5872 
5873     ierr = PetscDSGetBoundary(dm->prob, bd, &isEssential, NULL, &bdLabel, &field, &numComps, &comps, NULL, &numValues, &values, NULL);CHKERRQ(ierr);
5874     ierr = DMGetLabel(dm, bdLabel, &label);CHKERRQ(ierr);
5875     if (!isFE[field] || !label) continue;
5876     /* Only want to modify label once */
5877     for (bd2 = 0; bd2 < bd; ++bd2) {
5878       const char *bdname;
5879       ierr = PetscDSGetBoundary(dm->prob, bd2, NULL, NULL, &bdname, NULL, NULL, NULL, NULL, NULL, NULL, NULL);CHKERRQ(ierr);
5880       ierr = PetscStrcmp(bdname, bdLabel, &duplicate);CHKERRQ(ierr);
5881       if (duplicate) break;
5882     }
5883     if (!duplicate && (isFE[field])) {
5884       /* don't complete cells, which are just present to give orientation to the boundary */
5885       ierr = DMPlexLabelComplete(dm, label);CHKERRQ(ierr);
5886     }
5887     /* Filter out cells, if you actually want to constrain cells you need to do things by hand right now */
5888     if (isEssential) {
5889       PetscInt       *newidx;
5890       PetscInt        n, newn = 0, p, v;
5891 
5892       bcFields[bc] = field;
5893       if (numComps) {ierr = ISCreateGeneral(PetscObjectComm((PetscObject) dm), numComps, comps, PETSC_COPY_VALUES, &bcComps[bc]);CHKERRQ(ierr);}
5894       for (v = 0; v < numValues; ++v) {
5895         IS              tmp;
5896         const PetscInt *idx;
5897 
5898         ierr = DMGetStratumIS(dm, bdLabel, values[v], &tmp);CHKERRQ(ierr);
5899         if (!tmp) continue;
5900         ierr = ISGetLocalSize(tmp, &n);CHKERRQ(ierr);
5901         ierr = ISGetIndices(tmp, &idx);CHKERRQ(ierr);
5902         if (isFE[field]) {
5903           for (p = 0; p < n; ++p) if ((idx[p] < cStart) || (idx[p] >= cEnd)) ++newn;
5904         } else {
5905           for (p = 0; p < n; ++p) if ((idx[p] >= cStart) || (idx[p] < cEnd)) ++newn;
5906         }
5907         ierr = ISRestoreIndices(tmp, &idx);CHKERRQ(ierr);
5908         ierr = ISDestroy(&tmp);CHKERRQ(ierr);
5909       }
5910       ierr = PetscMalloc1(newn,&newidx);CHKERRQ(ierr);
5911       newn = 0;
5912       for (v = 0; v < numValues; ++v) {
5913         IS              tmp;
5914         const PetscInt *idx;
5915 
5916         ierr = DMGetStratumIS(dm, bdLabel, values[v], &tmp);CHKERRQ(ierr);
5917         if (!tmp) continue;
5918         ierr = ISGetLocalSize(tmp, &n);CHKERRQ(ierr);
5919         ierr = ISGetIndices(tmp, &idx);CHKERRQ(ierr);
5920         if (isFE[field]) {
5921           for (p = 0; p < n; ++p) if ((idx[p] < cStart) || (idx[p] >= cEnd)) newidx[newn++] = idx[p];
5922         } else {
5923           for (p = 0; p < n; ++p) if ((idx[p] >= cStart) || (idx[p] < cEnd)) newidx[newn++] = idx[p];
5924         }
5925         ierr = ISRestoreIndices(tmp, &idx);CHKERRQ(ierr);
5926         ierr = ISDestroy(&tmp);CHKERRQ(ierr);
5927       }
5928       ierr = ISCreateGeneral(PetscObjectComm((PetscObject) dm), newn, newidx, PETSC_OWN_POINTER, &bcPoints[bc++]);CHKERRQ(ierr);
5929     }
5930   }
5931   /* Handle discretization */
5932   ierr = PetscCalloc2(numFields,&numComp,numFields*(dim+1),&numDof);CHKERRQ(ierr);
5933   for (f = 0; f < numFields; ++f) {
5934     PetscObject obj;
5935 
5936     ierr = DMGetField(dm, f, &obj);CHKERRQ(ierr);
5937     if (isFE[f]) {
5938       PetscFE         fe = (PetscFE) obj;
5939       const PetscInt *numFieldDof;
5940       PetscInt        d;
5941 
5942       ierr = PetscFEGetNumComponents(fe, &numComp[f]);CHKERRQ(ierr);
5943       ierr = PetscFEGetNumDof(fe, &numFieldDof);CHKERRQ(ierr);
5944       for (d = 0; d < dim+1; ++d) numDof[f*(dim+1)+d] = numFieldDof[d];
5945     } else {
5946       PetscFV fv = (PetscFV) obj;
5947 
5948       ierr = PetscFVGetNumComponents(fv, &numComp[f]);CHKERRQ(ierr);
5949       numDof[f*(dim+1)+dim] = numComp[f];
5950     }
5951   }
5952   for (f = 0; f < numFields; ++f) {
5953     PetscInt d;
5954     for (d = 1; d < dim; ++d) {
5955       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.");
5956     }
5957   }
5958   ierr = DMPlexCreateSection(dm, dim, numFields, numComp, numDof, numBC, bcFields, bcComps, bcPoints, NULL, &section);CHKERRQ(ierr);
5959   for (f = 0; f < numFields; ++f) {
5960     PetscFE     fe;
5961     const char *name;
5962 
5963     ierr = DMGetField(dm, f, (PetscObject *) &fe);CHKERRQ(ierr);
5964     ierr = PetscObjectGetName((PetscObject) fe, &name);CHKERRQ(ierr);
5965     ierr = PetscSectionSetFieldName(section, f, name);CHKERRQ(ierr);
5966   }
5967   ierr = DMSetDefaultSection(dm, section);CHKERRQ(ierr);
5968   ierr = PetscSectionDestroy(&section);CHKERRQ(ierr);
5969   for (bc = 0; bc < numBC; ++bc) {ierr = ISDestroy(&bcPoints[bc]);CHKERRQ(ierr);ierr = ISDestroy(&bcComps[bc]);CHKERRQ(ierr);}
5970   ierr = PetscFree3(bcFields,bcPoints,bcComps);CHKERRQ(ierr);
5971   ierr = PetscFree2(numComp,numDof);CHKERRQ(ierr);
5972   ierr = PetscFree(isFE);CHKERRQ(ierr);
5973   PetscFunctionReturn(0);
5974 }
5975 
5976 #undef __FUNCT__
5977 #define __FUNCT__ "DMPlexGetRegularRefinement"
5978 /*@
5979   DMPlexGetRegularRefinement - Get the flag indicating that this mesh was obtained by regular refinement from its coarse mesh
5980 
5981   Input Parameter:
5982 . dm - The DMPlex object
5983 
5984   Output Parameter:
5985 . regular - The flag
5986 
5987   Level: intermediate
5988 
5989 .seealso: DMPlexSetRegularRefinement()
5990 @*/
5991 PetscErrorCode DMPlexGetRegularRefinement(DM dm, PetscBool *regular)
5992 {
5993   PetscFunctionBegin;
5994   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5995   PetscValidPointer(regular, 2);
5996   *regular = ((DM_Plex *) dm->data)->regularRefinement;
5997   PetscFunctionReturn(0);
5998 }
5999 
6000 #undef __FUNCT__
6001 #define __FUNCT__ "DMPlexSetRegularRefinement"
6002 /*@
6003   DMPlexSetRegularRefinement - Set the flag indicating that this mesh was obtained by regular refinement from its coarse mesh
6004 
6005   Input Parameters:
6006 + dm - The DMPlex object
6007 - regular - The flag
6008 
6009   Level: intermediate
6010 
6011 .seealso: DMPlexGetRegularRefinement()
6012 @*/
6013 PetscErrorCode DMPlexSetRegularRefinement(DM dm, PetscBool regular)
6014 {
6015   PetscFunctionBegin;
6016   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6017   ((DM_Plex *) dm->data)->regularRefinement = regular;
6018   PetscFunctionReturn(0);
6019 }
6020 
6021 /* anchors */
6022 #undef __FUNCT__
6023 #define __FUNCT__ "DMPlexGetAnchors"
6024 /*@
6025   DMPlexGetAnchors - Get the layout of the anchor (point-to-point) constraints.  Typically, the user will not have to
6026   call DMPlexGetAnchors() directly: if there are anchors, then DMPlexGetAnchors() is called during DMGetConstraints().
6027 
6028   not collective
6029 
6030   Input Parameters:
6031 . dm - The DMPlex object
6032 
6033   Output Parameters:
6034 + anchorSection - If not NULL, set to the section describing which points anchor the constrained points.
6035 - anchorIS - If not NULL, set to the list of anchors indexed by anchorSection
6036 
6037 
6038   Level: intermediate
6039 
6040 .seealso: DMPlexSetAnchors(), DMGetConstraints(), DMSetConstraints()
6041 @*/
6042 PetscErrorCode DMPlexGetAnchors(DM dm, PetscSection *anchorSection, IS *anchorIS)
6043 {
6044   DM_Plex *plex = (DM_Plex *)dm->data;
6045   PetscErrorCode ierr;
6046 
6047   PetscFunctionBegin;
6048   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6049   if (!plex->anchorSection && !plex->anchorIS && plex->createanchors) {ierr = (*plex->createanchors)(dm);CHKERRQ(ierr);}
6050   if (anchorSection) *anchorSection = plex->anchorSection;
6051   if (anchorIS) *anchorIS = plex->anchorIS;
6052   PetscFunctionReturn(0);
6053 }
6054 
6055 #undef __FUNCT__
6056 #define __FUNCT__ "DMPlexSetAnchors"
6057 /*@
6058   DMPlexSetAnchors - Set the layout of the local anchor (point-to-point) constraints.  Unlike boundary conditions,
6059   when a point's degrees of freedom in a section are constrained to an outside value, the anchor constraints set a
6060   point's degrees of freedom to be a linear combination of other points' degrees of freedom.
6061 
6062   After specifying the layout of constraints with DMPlexSetAnchors(), one specifies the constraints by calling
6063   DMGetConstraints() and filling in the entries in the constraint matrix.
6064 
6065   collective on dm
6066 
6067   Input Parameters:
6068 + dm - The DMPlex object
6069 . 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).
6070 - anchorIS - The list of all anchor points.  Must have a local communicator (PETSC_COMM_SELF or derivative).
6071 
6072   The reference counts of anchorSection and anchorIS are incremented.
6073 
6074   Level: intermediate
6075 
6076 .seealso: DMPlexGetAnchors(), DMGetConstraints(), DMSetConstraints()
6077 @*/
6078 PetscErrorCode DMPlexSetAnchors(DM dm, PetscSection anchorSection, IS anchorIS)
6079 {
6080   DM_Plex        *plex = (DM_Plex *)dm->data;
6081   PetscMPIInt    result;
6082   PetscErrorCode ierr;
6083 
6084   PetscFunctionBegin;
6085   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6086   if (anchorSection) {
6087     PetscValidHeaderSpecific(anchorSection,PETSC_SECTION_CLASSID,2);
6088     ierr = MPI_Comm_compare(PETSC_COMM_SELF,PetscObjectComm((PetscObject)anchorSection),&result);CHKERRQ(ierr);
6089     if (result != MPI_CONGRUENT) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_NOTSAMECOMM,"anchor section must have local communicator");
6090   }
6091   if (anchorIS) {
6092     PetscValidHeaderSpecific(anchorIS,IS_CLASSID,3);
6093     ierr = MPI_Comm_compare(PETSC_COMM_SELF,PetscObjectComm((PetscObject)anchorIS),&result);CHKERRQ(ierr);
6094     if (result != MPI_CONGRUENT) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_NOTSAMECOMM,"anchor IS must have local communicator");
6095   }
6096 
6097   ierr = PetscObjectReference((PetscObject)anchorSection);CHKERRQ(ierr);
6098   ierr = PetscSectionDestroy(&plex->anchorSection);CHKERRQ(ierr);
6099   plex->anchorSection = anchorSection;
6100 
6101   ierr = PetscObjectReference((PetscObject)anchorIS);CHKERRQ(ierr);
6102   ierr = ISDestroy(&plex->anchorIS);CHKERRQ(ierr);
6103   plex->anchorIS = anchorIS;
6104 
6105 #if defined(PETSC_USE_DEBUG)
6106   if (anchorIS && anchorSection) {
6107     PetscInt size, a, pStart, pEnd;
6108     const PetscInt *anchors;
6109 
6110     ierr = PetscSectionGetChart(anchorSection,&pStart,&pEnd);CHKERRQ(ierr);
6111     ierr = ISGetLocalSize(anchorIS,&size);CHKERRQ(ierr);
6112     ierr = ISGetIndices(anchorIS,&anchors);CHKERRQ(ierr);
6113     for (a = 0; a < size; a++) {
6114       PetscInt p;
6115 
6116       p = anchors[a];
6117       if (p >= pStart && p < pEnd) {
6118         PetscInt dof;
6119 
6120         ierr = PetscSectionGetDof(anchorSection,p,&dof);CHKERRQ(ierr);
6121         if (dof) {
6122           PetscErrorCode ierr2;
6123 
6124           ierr2 = ISRestoreIndices(anchorIS,&anchors);CHKERRQ(ierr2);
6125           SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Point %d cannot be constrained and an anchor",p);
6126         }
6127       }
6128     }
6129     ierr = ISRestoreIndices(anchorIS,&anchors);CHKERRQ(ierr);
6130   }
6131 #endif
6132   /* reset the generic constraints */
6133   ierr = DMSetDefaultConstraints(dm,NULL,NULL);CHKERRQ(ierr);
6134   PetscFunctionReturn(0);
6135 }
6136 
6137 #undef __FUNCT__
6138 #define __FUNCT__ "DMPlexCreateConstraintSection_Anchors"
6139 static PetscErrorCode DMPlexCreateConstraintSection_Anchors(DM dm, PetscSection section, PetscSection *cSec)
6140 {
6141   PetscSection anchorSection;
6142   PetscInt pStart, pEnd, sStart, sEnd, p, dof, numFields, f;
6143   PetscErrorCode ierr;
6144 
6145   PetscFunctionBegin;
6146   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6147   ierr = DMPlexGetAnchors(dm,&anchorSection,NULL);CHKERRQ(ierr);
6148   ierr = PetscSectionCreate(PETSC_COMM_SELF,cSec);CHKERRQ(ierr);
6149   ierr = PetscSectionGetNumFields(section,&numFields);CHKERRQ(ierr);
6150   if (numFields) {
6151     PetscInt f;
6152     ierr = PetscSectionSetNumFields(*cSec,numFields);CHKERRQ(ierr);
6153 
6154     for (f = 0; f < numFields; f++) {
6155       PetscInt numComp;
6156 
6157       ierr = PetscSectionGetFieldComponents(section,f,&numComp);CHKERRQ(ierr);
6158       ierr = PetscSectionSetFieldComponents(*cSec,f,numComp);CHKERRQ(ierr);
6159     }
6160   }
6161   ierr = PetscSectionGetChart(anchorSection,&pStart,&pEnd);CHKERRQ(ierr);
6162   ierr = PetscSectionGetChart(section,&sStart,&sEnd);CHKERRQ(ierr);
6163   pStart = PetscMax(pStart,sStart);
6164   pEnd   = PetscMin(pEnd,sEnd);
6165   pEnd   = PetscMax(pStart,pEnd);
6166   ierr = PetscSectionSetChart(*cSec,pStart,pEnd);CHKERRQ(ierr);
6167   for (p = pStart; p < pEnd; p++) {
6168     ierr = PetscSectionGetDof(anchorSection,p,&dof);CHKERRQ(ierr);
6169     if (dof) {
6170       ierr = PetscSectionGetDof(section,p,&dof);CHKERRQ(ierr);
6171       ierr = PetscSectionSetDof(*cSec,p,dof);CHKERRQ(ierr);
6172       for (f = 0; f < numFields; f++) {
6173         ierr = PetscSectionGetFieldDof(section,p,f,&dof);CHKERRQ(ierr);
6174         ierr = PetscSectionSetFieldDof(*cSec,p,f,dof);CHKERRQ(ierr);
6175       }
6176     }
6177   }
6178   ierr = PetscSectionSetUp(*cSec);CHKERRQ(ierr);
6179   PetscFunctionReturn(0);
6180 }
6181 
6182 #undef __FUNCT__
6183 #define __FUNCT__ "DMPlexCreateConstraintMatrix_Anchors"
6184 static PetscErrorCode DMPlexCreateConstraintMatrix_Anchors(DM dm, PetscSection section, PetscSection cSec, Mat *cMat)
6185 {
6186   PetscSection aSec;
6187   PetscInt pStart, pEnd, p, dof, aDof, aOff, off, nnz, annz, m, n, q, a, offset, *i, *j;
6188   const PetscInt *anchors;
6189   PetscInt numFields, f;
6190   IS aIS;
6191   PetscErrorCode ierr;
6192 
6193   PetscFunctionBegin;
6194   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6195   ierr = PetscSectionGetStorageSize(cSec, &m);CHKERRQ(ierr);
6196   ierr = PetscSectionGetStorageSize(section, &n);CHKERRQ(ierr);
6197   ierr = MatCreate(PETSC_COMM_SELF,cMat);CHKERRQ(ierr);
6198   ierr = MatSetSizes(*cMat,m,n,m,n);CHKERRQ(ierr);
6199   ierr = MatSetType(*cMat,MATSEQAIJ);CHKERRQ(ierr);
6200   ierr = DMPlexGetAnchors(dm,&aSec,&aIS);CHKERRQ(ierr);
6201   ierr = ISGetIndices(aIS,&anchors);CHKERRQ(ierr);
6202   /* cSec will be a subset of aSec and section */
6203   ierr = PetscSectionGetChart(cSec,&pStart,&pEnd);CHKERRQ(ierr);
6204   ierr = PetscMalloc1(m+1,&i);CHKERRQ(ierr);
6205   i[0] = 0;
6206   ierr = PetscSectionGetNumFields(section,&numFields);CHKERRQ(ierr);
6207   for (p = pStart; p < pEnd; p++) {
6208     PetscInt rDof, rOff, r;
6209 
6210     ierr = PetscSectionGetDof(aSec,p,&rDof);CHKERRQ(ierr);
6211     if (!rDof) continue;
6212     ierr = PetscSectionGetOffset(aSec,p,&rOff);CHKERRQ(ierr);
6213     if (numFields) {
6214       for (f = 0; f < numFields; f++) {
6215         annz = 0;
6216         for (r = 0; r < rDof; r++) {
6217           a = anchors[rOff + r];
6218           ierr = PetscSectionGetFieldDof(section,a,f,&aDof);CHKERRQ(ierr);
6219           annz += aDof;
6220         }
6221         ierr = PetscSectionGetFieldDof(cSec,p,f,&dof);CHKERRQ(ierr);
6222         ierr = PetscSectionGetFieldOffset(cSec,p,f,&off);CHKERRQ(ierr);
6223         for (q = 0; q < dof; q++) {
6224           i[off + q + 1] = i[off + q] + annz;
6225         }
6226       }
6227     }
6228     else {
6229       annz = 0;
6230       for (q = 0; q < dof; q++) {
6231         a = anchors[off + q];
6232         ierr = PetscSectionGetDof(section,a,&aDof);CHKERRQ(ierr);
6233         annz += aDof;
6234       }
6235       ierr = PetscSectionGetDof(cSec,p,&dof);CHKERRQ(ierr);
6236       ierr = PetscSectionGetOffset(cSec,p,&off);CHKERRQ(ierr);
6237       for (q = 0; q < dof; q++) {
6238         i[off + q + 1] = i[off + q] + annz;
6239       }
6240     }
6241   }
6242   nnz = i[m];
6243   ierr = PetscMalloc1(nnz,&j);CHKERRQ(ierr);
6244   offset = 0;
6245   for (p = pStart; p < pEnd; p++) {
6246     if (numFields) {
6247       for (f = 0; f < numFields; f++) {
6248         ierr = PetscSectionGetFieldDof(cSec,p,f,&dof);CHKERRQ(ierr);
6249         for (q = 0; q < dof; q++) {
6250           PetscInt rDof, rOff, r;
6251           ierr = PetscSectionGetDof(aSec,p,&rDof);CHKERRQ(ierr);
6252           ierr = PetscSectionGetOffset(aSec,p,&rOff);CHKERRQ(ierr);
6253           for (r = 0; r < rDof; r++) {
6254             PetscInt s;
6255 
6256             a = anchors[rOff + r];
6257             ierr = PetscSectionGetFieldDof(section,a,f,&aDof);CHKERRQ(ierr);
6258             ierr = PetscSectionGetFieldOffset(section,a,f,&aOff);CHKERRQ(ierr);
6259             for (s = 0; s < aDof; s++) {
6260               j[offset++] = aOff + s;
6261             }
6262           }
6263         }
6264       }
6265     }
6266     else {
6267       ierr = PetscSectionGetDof(cSec,p,&dof);CHKERRQ(ierr);
6268       for (q = 0; q < dof; q++) {
6269         PetscInt rDof, rOff, r;
6270         ierr = PetscSectionGetDof(aSec,p,&rDof);CHKERRQ(ierr);
6271         ierr = PetscSectionGetOffset(aSec,p,&rOff);CHKERRQ(ierr);
6272         for (r = 0; r < rDof; r++) {
6273           PetscInt s;
6274 
6275           a = anchors[rOff + r];
6276           ierr = PetscSectionGetDof(section,a,&aDof);CHKERRQ(ierr);
6277           ierr = PetscSectionGetOffset(section,a,&aOff);CHKERRQ(ierr);
6278           for (s = 0; s < aDof; s++) {
6279             j[offset++] = aOff + s;
6280           }
6281         }
6282       }
6283     }
6284   }
6285   ierr = MatSeqAIJSetPreallocationCSR(*cMat,i,j,NULL);CHKERRQ(ierr);
6286   ierr = PetscFree(i);CHKERRQ(ierr);
6287   ierr = PetscFree(j);CHKERRQ(ierr);
6288   ierr = ISRestoreIndices(aIS,&anchors);CHKERRQ(ierr);
6289   PetscFunctionReturn(0);
6290 }
6291 
6292 #undef __FUNCT__
6293 #define __FUNCT__ "DMCreateDefaultConstraints_Plex"
6294 PetscErrorCode DMCreateDefaultConstraints_Plex(DM dm)
6295 {
6296   DM_Plex        *plex = (DM_Plex *)dm->data;
6297   PetscSection   anchorSection, section, cSec;
6298   Mat            cMat;
6299   PetscErrorCode ierr;
6300 
6301   PetscFunctionBegin;
6302   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6303   ierr = DMPlexGetAnchors(dm,&anchorSection,NULL);CHKERRQ(ierr);
6304   if (anchorSection) {
6305     PetscDS  ds;
6306     PetscInt nf;
6307 
6308     ierr = DMGetDefaultSection(dm,&section);CHKERRQ(ierr);
6309     ierr = DMPlexCreateConstraintSection_Anchors(dm,section,&cSec);CHKERRQ(ierr);
6310     ierr = DMPlexCreateConstraintMatrix_Anchors(dm,section,cSec,&cMat);CHKERRQ(ierr);
6311     ierr = DMGetDS(dm,&ds);CHKERRQ(ierr);
6312     ierr = PetscDSGetNumFields(ds,&nf);CHKERRQ(ierr);
6313     if (nf && plex->computeanchormatrix) {ierr = (*plex->computeanchormatrix)(dm,section,cSec,cMat);CHKERRQ(ierr);}
6314     ierr = DMSetDefaultConstraints(dm,cSec,cMat);CHKERRQ(ierr);
6315     ierr = PetscSectionDestroy(&cSec);CHKERRQ(ierr);
6316     ierr = MatDestroy(&cMat);CHKERRQ(ierr);
6317   }
6318   PetscFunctionReturn(0);
6319 }
6320