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