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