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