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