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