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