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