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