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