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