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