xref: /petsc/src/dm/impls/plex/plex.c (revision 5a84ad33814bf43cbf4616f6fbb16f87c523bdea)
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 .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexSetCone(), DMPlexSetChart()
1808 @*/
1809 PetscErrorCode DMPlexGetConeOrientation(DM dm, PetscInt p, const PetscInt *coneOrientation[])
1810 {
1811   DM_Plex       *mesh = (DM_Plex*) dm->data;
1812   PetscInt       off;
1813   PetscErrorCode ierr;
1814 
1815   PetscFunctionBegin;
1816   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1817 #if defined(PETSC_USE_DEBUG)
1818   {
1819     PetscInt dof;
1820     ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
1821     if (dof) PetscValidPointer(coneOrientation, 3);
1822   }
1823 #endif
1824   ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
1825 
1826   *coneOrientation = &mesh->coneOrientations[off];
1827   PetscFunctionReturn(0);
1828 }
1829 
1830 /*@
1831   DMPlexSetConeOrientation - Set the orientations on the in-edges for this point in the DAG
1832 
1833   Not collective
1834 
1835   Input Parameters:
1836 + mesh - The DMPlex
1837 . p - The point, which must lie in the chart set with DMPlexSetChart()
1838 - coneOrientation - An array of orientations which are on the in-edges for point p. An orientation is an
1839                     integer giving the prescription for cone traversal. If it is negative, the cone is
1840                     traversed in the opposite direction. Its value 'o', or if negative '-(o+1)', gives
1841                     the index of the cone point on which to start.
1842 
1843   Output Parameter:
1844 
1845   Note:
1846   This should be called after all calls to DMPlexSetConeSize() and DMSetUp().
1847 
1848   Level: beginner
1849 
1850 .seealso: DMPlexCreate(), DMPlexGetConeOrientation(), DMPlexSetCone(), DMPlexSetChart(), DMPlexSetConeSize(), DMSetUp()
1851 @*/
1852 PetscErrorCode DMPlexSetConeOrientation(DM dm, PetscInt p, const PetscInt coneOrientation[])
1853 {
1854   DM_Plex       *mesh = (DM_Plex*) dm->data;
1855   PetscInt       pStart, pEnd;
1856   PetscInt       dof, off, c;
1857   PetscErrorCode ierr;
1858 
1859   PetscFunctionBegin;
1860   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1861   ierr = PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);CHKERRQ(ierr);
1862   ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
1863   if (dof) PetscValidPointer(coneOrientation, 3);
1864   ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
1865   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);
1866   for (c = 0; c < dof; ++c) {
1867     PetscInt cdof, o = coneOrientation[c];
1868 
1869     ierr = PetscSectionGetDof(mesh->coneSection, mesh->cones[off+c], &cdof);CHKERRQ(ierr);
1870     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);
1871     mesh->coneOrientations[off+c] = o;
1872   }
1873   PetscFunctionReturn(0);
1874 }
1875 
1876 /*@
1877   DMPlexInsertCone - Insert a point into the in-edges for the point p in the DAG
1878 
1879   Not collective
1880 
1881   Input Parameters:
1882 + mesh - The DMPlex
1883 . p - The point, which must lie in the chart set with DMPlexSetChart()
1884 . conePos - The local index in the cone where the point should be put
1885 - conePoint - The mesh point to insert
1886 
1887   Level: beginner
1888 
1889 .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexSetChart(), DMPlexSetConeSize(), DMSetUp()
1890 @*/
1891 PetscErrorCode DMPlexInsertCone(DM dm, PetscInt p, PetscInt conePos, PetscInt conePoint)
1892 {
1893   DM_Plex       *mesh = (DM_Plex*) dm->data;
1894   PetscInt       pStart, pEnd;
1895   PetscInt       dof, off;
1896   PetscErrorCode ierr;
1897 
1898   PetscFunctionBegin;
1899   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1900   ierr = PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);CHKERRQ(ierr);
1901   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);
1902   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);
1903   ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
1904   ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
1905   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);
1906   mesh->cones[off+conePos] = conePoint;
1907   PetscFunctionReturn(0);
1908 }
1909 
1910 /*@
1911   DMPlexInsertConeOrientation - Insert a point orientation for the in-edge for the point p in the DAG
1912 
1913   Not collective
1914 
1915   Input Parameters:
1916 + mesh - The DMPlex
1917 . p - The point, which must lie in the chart set with DMPlexSetChart()
1918 . conePos - The local index in the cone where the point should be put
1919 - coneOrientation - The point orientation to insert
1920 
1921   Level: beginner
1922 
1923 .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexSetChart(), DMPlexSetConeSize(), DMSetUp()
1924 @*/
1925 PetscErrorCode DMPlexInsertConeOrientation(DM dm, PetscInt p, PetscInt conePos, PetscInt coneOrientation)
1926 {
1927   DM_Plex       *mesh = (DM_Plex*) dm->data;
1928   PetscInt       pStart, pEnd;
1929   PetscInt       dof, off;
1930   PetscErrorCode ierr;
1931 
1932   PetscFunctionBegin;
1933   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1934   ierr = PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);CHKERRQ(ierr);
1935   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);
1936   ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
1937   ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
1938   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);
1939   mesh->coneOrientations[off+conePos] = coneOrientation;
1940   PetscFunctionReturn(0);
1941 }
1942 
1943 /*@
1944   DMPlexGetSupportSize - Return the number of out-edges for this point in the DAG
1945 
1946   Not collective
1947 
1948   Input Parameters:
1949 + mesh - The DMPlex
1950 - p - The point, which must lie in the chart set with DMPlexSetChart()
1951 
1952   Output Parameter:
1953 . size - The support size for point p
1954 
1955   Level: beginner
1956 
1957 .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexSetChart(), DMPlexGetConeSize()
1958 @*/
1959 PetscErrorCode DMPlexGetSupportSize(DM dm, PetscInt p, PetscInt *size)
1960 {
1961   DM_Plex       *mesh = (DM_Plex*) dm->data;
1962   PetscErrorCode ierr;
1963 
1964   PetscFunctionBegin;
1965   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1966   PetscValidPointer(size, 3);
1967   ierr = PetscSectionGetDof(mesh->supportSection, p, size);CHKERRQ(ierr);
1968   PetscFunctionReturn(0);
1969 }
1970 
1971 /*@
1972   DMPlexSetSupportSize - Set the number of out-edges for this point in the DAG
1973 
1974   Not collective
1975 
1976   Input Parameters:
1977 + mesh - The DMPlex
1978 . p - The point, which must lie in the chart set with DMPlexSetChart()
1979 - size - The support size for point p
1980 
1981   Output Parameter:
1982 
1983   Note:
1984   This should be called after DMPlexSetChart().
1985 
1986   Level: beginner
1987 
1988 .seealso: DMPlexCreate(), DMPlexGetSupportSize(), DMPlexSetChart()
1989 @*/
1990 PetscErrorCode DMPlexSetSupportSize(DM dm, PetscInt p, PetscInt size)
1991 {
1992   DM_Plex       *mesh = (DM_Plex*) dm->data;
1993   PetscErrorCode ierr;
1994 
1995   PetscFunctionBegin;
1996   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1997   ierr = PetscSectionSetDof(mesh->supportSection, p, size);CHKERRQ(ierr);
1998 
1999   mesh->maxSupportSize = PetscMax(mesh->maxSupportSize, size);
2000   PetscFunctionReturn(0);
2001 }
2002 
2003 /*@C
2004   DMPlexGetSupport - Return the points on the out-edges for this point in the DAG
2005 
2006   Not collective
2007 
2008   Input Parameters:
2009 + mesh - The DMPlex
2010 - p - The point, which must lie in the chart set with DMPlexSetChart()
2011 
2012   Output Parameter:
2013 . support - An array of points which are on the out-edges for point p
2014 
2015   Level: beginner
2016 
2017   Fortran Notes:
2018   Since it returns an array, this routine is only available in Fortran 90, and you must
2019   include petsc.h90 in your code.
2020 
2021 .seealso: DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone()
2022 @*/
2023 PetscErrorCode DMPlexGetSupport(DM dm, PetscInt p, const PetscInt *support[])
2024 {
2025   DM_Plex       *mesh = (DM_Plex*) dm->data;
2026   PetscInt       off;
2027   PetscErrorCode ierr;
2028 
2029   PetscFunctionBegin;
2030   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2031   PetscValidPointer(support, 3);
2032   ierr     = PetscSectionGetOffset(mesh->supportSection, p, &off);CHKERRQ(ierr);
2033   *support = &mesh->supports[off];
2034   PetscFunctionReturn(0);
2035 }
2036 
2037 /*@
2038   DMPlexSetSupport - Set the points on the out-edges for this point in the DAG, that is the list of points that this point covers
2039 
2040   Not collective
2041 
2042   Input Parameters:
2043 + mesh - The DMPlex
2044 . p - The point, which must lie in the chart set with DMPlexSetChart()
2045 - support - An array of points which are on the out-edges for point p
2046 
2047   Output Parameter:
2048 
2049   Note:
2050   This should be called after all calls to DMPlexSetSupportSize() and DMSetUp().
2051 
2052   Level: beginner
2053 
2054 .seealso: DMPlexSetCone(), DMPlexSetConeSize(), DMPlexCreate(), DMPlexGetSupport(), DMPlexSetChart(), DMPlexSetSupportSize(), DMSetUp()
2055 @*/
2056 PetscErrorCode DMPlexSetSupport(DM dm, PetscInt p, const PetscInt support[])
2057 {
2058   DM_Plex       *mesh = (DM_Plex*) dm->data;
2059   PetscInt       pStart, pEnd;
2060   PetscInt       dof, off, c;
2061   PetscErrorCode ierr;
2062 
2063   PetscFunctionBegin;
2064   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2065   ierr = PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd);CHKERRQ(ierr);
2066   ierr = PetscSectionGetDof(mesh->supportSection, p, &dof);CHKERRQ(ierr);
2067   if (dof) PetscValidPointer(support, 3);
2068   ierr = PetscSectionGetOffset(mesh->supportSection, p, &off);CHKERRQ(ierr);
2069   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);
2070   for (c = 0; c < dof; ++c) {
2071     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);
2072     mesh->supports[off+c] = support[c];
2073   }
2074   PetscFunctionReturn(0);
2075 }
2076 
2077 /*@
2078   DMPlexInsertSupport - Insert a point into the out-edges for the point p in the DAG
2079 
2080   Not collective
2081 
2082   Input Parameters:
2083 + mesh - The DMPlex
2084 . p - The point, which must lie in the chart set with DMPlexSetChart()
2085 . supportPos - The local index in the cone where the point should be put
2086 - supportPoint - The mesh point to insert
2087 
2088   Level: beginner
2089 
2090 .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexSetChart(), DMPlexSetConeSize(), DMSetUp()
2091 @*/
2092 PetscErrorCode DMPlexInsertSupport(DM dm, PetscInt p, PetscInt supportPos, PetscInt supportPoint)
2093 {
2094   DM_Plex       *mesh = (DM_Plex*) dm->data;
2095   PetscInt       pStart, pEnd;
2096   PetscInt       dof, off;
2097   PetscErrorCode ierr;
2098 
2099   PetscFunctionBegin;
2100   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2101   ierr = PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd);CHKERRQ(ierr);
2102   ierr = PetscSectionGetDof(mesh->supportSection, p, &dof);CHKERRQ(ierr);
2103   ierr = PetscSectionGetOffset(mesh->supportSection, p, &off);CHKERRQ(ierr);
2104   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);
2105   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);
2106   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);
2107   mesh->supports[off+supportPos] = supportPoint;
2108   PetscFunctionReturn(0);
2109 }
2110 
2111 /*@C
2112   DMPlexGetTransitiveClosure - Return the points on the transitive closure of the in-edges or out-edges for this point in the DAG
2113 
2114   Not collective
2115 
2116   Input Parameters:
2117 + mesh - The DMPlex
2118 . p - The point, which must lie in the chart set with DMPlexSetChart()
2119 . useCone - PETSC_TRUE for in-edges,  otherwise use out-edges
2120 - points - If points is NULL on input, internal storage will be returned, otherwise the provided array is used
2121 
2122   Output Parameters:
2123 + numPoints - The number of points in the closure, so points[] is of size 2*numPoints
2124 - points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...]
2125 
2126   Note:
2127   If using internal storage (points is NULL on input), each call overwrites the last output.
2128 
2129   Fortran Notes:
2130   Since it returns an array, this routine is only available in Fortran 90, and you must
2131   include petsc.h90 in your code.
2132 
2133   The numPoints argument is not present in the Fortran 90 binding since it is internal to the array.
2134 
2135   Level: beginner
2136 
2137 .seealso: DMPlexRestoreTransitiveClosure(), DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone()
2138 @*/
2139 PetscErrorCode DMPlexGetTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[])
2140 {
2141   DM_Plex        *mesh = (DM_Plex*) dm->data;
2142   PetscInt       *closure, *fifo;
2143   const PetscInt *tmp = NULL, *tmpO = NULL;
2144   PetscInt        tmpSize, t;
2145   PetscInt        depth       = 0, maxSize;
2146   PetscInt        closureSize = 2, fifoSize = 0, fifoStart = 0;
2147   PetscErrorCode  ierr;
2148 
2149   PetscFunctionBegin;
2150   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2151   ierr    = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
2152   /* This is only 1-level */
2153   if (useCone) {
2154     ierr = DMPlexGetConeSize(dm, p, &tmpSize);CHKERRQ(ierr);
2155     ierr = DMPlexGetCone(dm, p, &tmp);CHKERRQ(ierr);
2156     ierr = DMPlexGetConeOrientation(dm, p, &tmpO);CHKERRQ(ierr);
2157   } else {
2158     ierr = DMPlexGetSupportSize(dm, p, &tmpSize);CHKERRQ(ierr);
2159     ierr = DMPlexGetSupport(dm, p, &tmp);CHKERRQ(ierr);
2160   }
2161   if (depth == 1) {
2162     if (*points) {
2163       closure = *points;
2164     } else {
2165       maxSize = 2*(PetscMax(mesh->maxConeSize, mesh->maxSupportSize)+1);
2166       ierr = DMGetWorkArray(dm, maxSize, MPIU_INT, &closure);CHKERRQ(ierr);
2167     }
2168     closure[0] = p; closure[1] = 0;
2169     for (t = 0; t < tmpSize; ++t, closureSize += 2) {
2170       closure[closureSize]   = tmp[t];
2171       closure[closureSize+1] = tmpO ? tmpO[t] : 0;
2172     }
2173     if (numPoints) *numPoints = closureSize/2;
2174     if (points)    *points    = closure;
2175     PetscFunctionReturn(0);
2176   }
2177   {
2178     PetscInt c, coneSeries, s,supportSeries;
2179 
2180     c = mesh->maxConeSize;
2181     coneSeries = (c > 1) ? ((PetscPowInt(c,depth+1)-1)/(c-1)) : depth+1;
2182     s = mesh->maxSupportSize;
2183     supportSeries = (s > 1) ? ((PetscPowInt(s,depth+1)-1)/(s-1)) : depth+1;
2184     maxSize = 2*PetscMax(coneSeries,supportSeries);
2185   }
2186   ierr    = DMGetWorkArray(dm, maxSize, MPIU_INT, &fifo);CHKERRQ(ierr);
2187   if (*points) {
2188     closure = *points;
2189   } else {
2190     ierr = DMGetWorkArray(dm, maxSize, MPIU_INT, &closure);CHKERRQ(ierr);
2191   }
2192   closure[0] = p; closure[1] = 0;
2193   for (t = 0; t < tmpSize; ++t, closureSize += 2, fifoSize += 2) {
2194     const PetscInt cp = tmp[t];
2195     const PetscInt co = tmpO ? tmpO[t] : 0;
2196 
2197     closure[closureSize]   = cp;
2198     closure[closureSize+1] = co;
2199     fifo[fifoSize]         = cp;
2200     fifo[fifoSize+1]       = co;
2201   }
2202   /* Should kick out early when depth is reached, rather than checking all vertices for empty cones */
2203   while (fifoSize - fifoStart) {
2204     const PetscInt q   = fifo[fifoStart];
2205     const PetscInt o   = fifo[fifoStart+1];
2206     const PetscInt rev = o >= 0 ? 0 : 1;
2207     const PetscInt off = rev ? -(o+1) : o;
2208 
2209     if (useCone) {
2210       ierr = DMPlexGetConeSize(dm, q, &tmpSize);CHKERRQ(ierr);
2211       ierr = DMPlexGetCone(dm, q, &tmp);CHKERRQ(ierr);
2212       ierr = DMPlexGetConeOrientation(dm, q, &tmpO);CHKERRQ(ierr);
2213     } else {
2214       ierr = DMPlexGetSupportSize(dm, q, &tmpSize);CHKERRQ(ierr);
2215       ierr = DMPlexGetSupport(dm, q, &tmp);CHKERRQ(ierr);
2216       tmpO = NULL;
2217     }
2218     for (t = 0; t < tmpSize; ++t) {
2219       const PetscInt i  = ((rev ? tmpSize-t : t) + off)%tmpSize;
2220       const PetscInt cp = tmp[i];
2221       /* Must propogate orientation: When we reverse orientation, we both reverse the direction of iteration and start at the other end of the chain. */
2222       /* HACK: It is worse to get the size here, than to change the interpretation of -(*+1)
2223        const PetscInt co = tmpO ? (rev ? -(tmpO[i]+1) : tmpO[i]) : 0; */
2224       PetscInt       co = tmpO ? tmpO[i] : 0;
2225       PetscInt       c;
2226 
2227       if (rev) {
2228         PetscInt childSize, coff;
2229         ierr = DMPlexGetConeSize(dm, cp, &childSize);CHKERRQ(ierr);
2230         coff = tmpO[i] < 0 ? -(tmpO[i]+1) : tmpO[i];
2231         co   = childSize ? -(((coff+childSize-1)%childSize)+1) : 0;
2232       }
2233       /* Check for duplicate */
2234       for (c = 0; c < closureSize; c += 2) {
2235         if (closure[c] == cp) break;
2236       }
2237       if (c == closureSize) {
2238         closure[closureSize]   = cp;
2239         closure[closureSize+1] = co;
2240         fifo[fifoSize]         = cp;
2241         fifo[fifoSize+1]       = co;
2242         closureSize           += 2;
2243         fifoSize              += 2;
2244       }
2245     }
2246     fifoStart += 2;
2247   }
2248   if (numPoints) *numPoints = closureSize/2;
2249   if (points)    *points    = closure;
2250   ierr = DMRestoreWorkArray(dm, maxSize, MPIU_INT, &fifo);CHKERRQ(ierr);
2251   PetscFunctionReturn(0);
2252 }
2253 
2254 /*@C
2255   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
2256 
2257   Not collective
2258 
2259   Input Parameters:
2260 + mesh - The DMPlex
2261 . p - The point, which must lie in the chart set with DMPlexSetChart()
2262 . orientation - The orientation of the point
2263 . useCone - PETSC_TRUE for in-edges,  otherwise use out-edges
2264 - points - If points is NULL on input, internal storage will be returned, otherwise the provided array is used
2265 
2266   Output Parameters:
2267 + numPoints - The number of points in the closure, so points[] is of size 2*numPoints
2268 - points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...]
2269 
2270   Note:
2271   If using internal storage (points is NULL on input), each call overwrites the last output.
2272 
2273   Fortran Notes:
2274   Since it returns an array, this routine is only available in Fortran 90, and you must
2275   include petsc.h90 in your code.
2276 
2277   The numPoints argument is not present in the Fortran 90 binding since it is internal to the array.
2278 
2279   Level: beginner
2280 
2281 .seealso: DMPlexRestoreTransitiveClosure(), DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone()
2282 @*/
2283 PetscErrorCode DMPlexGetTransitiveClosure_Internal(DM dm, PetscInt p, PetscInt ornt, PetscBool useCone, PetscInt *numPoints, PetscInt *points[])
2284 {
2285   DM_Plex        *mesh = (DM_Plex*) dm->data;
2286   PetscInt       *closure, *fifo;
2287   const PetscInt *tmp = NULL, *tmpO = NULL;
2288   PetscInt        tmpSize, t;
2289   PetscInt        depth       = 0, maxSize;
2290   PetscInt        closureSize = 2, fifoSize = 0, fifoStart = 0;
2291   PetscErrorCode  ierr;
2292 
2293   PetscFunctionBegin;
2294   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2295   ierr    = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
2296   /* This is only 1-level */
2297   if (useCone) {
2298     ierr = DMPlexGetConeSize(dm, p, &tmpSize);CHKERRQ(ierr);
2299     ierr = DMPlexGetCone(dm, p, &tmp);CHKERRQ(ierr);
2300     ierr = DMPlexGetConeOrientation(dm, p, &tmpO);CHKERRQ(ierr);
2301   } else {
2302     ierr = DMPlexGetSupportSize(dm, p, &tmpSize);CHKERRQ(ierr);
2303     ierr = DMPlexGetSupport(dm, p, &tmp);CHKERRQ(ierr);
2304   }
2305   if (depth == 1) {
2306     if (*points) {
2307       closure = *points;
2308     } else {
2309       maxSize = 2*(PetscMax(mesh->maxConeSize, mesh->maxSupportSize)+1);
2310       ierr = DMGetWorkArray(dm, maxSize, MPIU_INT, &closure);CHKERRQ(ierr);
2311     }
2312     closure[0] = p; closure[1] = ornt;
2313     for (t = 0; t < tmpSize; ++t, closureSize += 2) {
2314       const PetscInt i = ornt >= 0 ? (t+ornt)%tmpSize : (-(ornt+1) + tmpSize-t)%tmpSize;
2315       closure[closureSize]   = tmp[i];
2316       closure[closureSize+1] = tmpO ? tmpO[i] : 0;
2317     }
2318     if (numPoints) *numPoints = closureSize/2;
2319     if (points)    *points    = closure;
2320     PetscFunctionReturn(0);
2321   }
2322   {
2323     PetscInt c, coneSeries, s,supportSeries;
2324 
2325     c = mesh->maxConeSize;
2326     coneSeries = (c > 1) ? ((PetscPowInt(c,depth+1)-1)/(c-1)) : depth+1;
2327     s = mesh->maxSupportSize;
2328     supportSeries = (s > 1) ? ((PetscPowInt(s,depth+1)-1)/(s-1)) : depth+1;
2329     maxSize = 2*PetscMax(coneSeries,supportSeries);
2330   }
2331   ierr    = DMGetWorkArray(dm, maxSize, MPIU_INT, &fifo);CHKERRQ(ierr);
2332   if (*points) {
2333     closure = *points;
2334   } else {
2335     ierr = DMGetWorkArray(dm, maxSize, MPIU_INT, &closure);CHKERRQ(ierr);
2336   }
2337   closure[0] = p; closure[1] = ornt;
2338   for (t = 0; t < tmpSize; ++t, closureSize += 2, fifoSize += 2) {
2339     const PetscInt i  = ornt >= 0 ? (t+ornt)%tmpSize : (-(ornt+1) + tmpSize-t)%tmpSize;
2340     const PetscInt cp = tmp[i];
2341     PetscInt       co = tmpO ? tmpO[i] : 0;
2342 
2343     if (ornt < 0) {
2344       PetscInt childSize, coff;
2345       ierr = DMPlexGetConeSize(dm, cp, &childSize);CHKERRQ(ierr);
2346       coff = co < 0 ? -(tmpO[i]+1) : tmpO[i];
2347       co   = childSize ? -(((coff+childSize-1)%childSize)+1) : 0;
2348     }
2349     closure[closureSize]   = cp;
2350     closure[closureSize+1] = co;
2351     fifo[fifoSize]         = cp;
2352     fifo[fifoSize+1]       = co;
2353   }
2354   /* Should kick out early when depth is reached, rather than checking all vertices for empty cones */
2355   while (fifoSize - fifoStart) {
2356     const PetscInt q   = fifo[fifoStart];
2357     const PetscInt o   = fifo[fifoStart+1];
2358     const PetscInt rev = o >= 0 ? 0 : 1;
2359     const PetscInt off = rev ? -(o+1) : o;
2360 
2361     if (useCone) {
2362       ierr = DMPlexGetConeSize(dm, q, &tmpSize);CHKERRQ(ierr);
2363       ierr = DMPlexGetCone(dm, q, &tmp);CHKERRQ(ierr);
2364       ierr = DMPlexGetConeOrientation(dm, q, &tmpO);CHKERRQ(ierr);
2365     } else {
2366       ierr = DMPlexGetSupportSize(dm, q, &tmpSize);CHKERRQ(ierr);
2367       ierr = DMPlexGetSupport(dm, q, &tmp);CHKERRQ(ierr);
2368       tmpO = NULL;
2369     }
2370     for (t = 0; t < tmpSize; ++t) {
2371       const PetscInt i  = ((rev ? tmpSize-t : t) + off)%tmpSize;
2372       const PetscInt cp = tmp[i];
2373       /* Must propogate orientation: When we reverse orientation, we both reverse the direction of iteration and start at the other end of the chain. */
2374       /* HACK: It is worse to get the size here, than to change the interpretation of -(*+1)
2375        const PetscInt co = tmpO ? (rev ? -(tmpO[i]+1) : tmpO[i]) : 0; */
2376       PetscInt       co = tmpO ? tmpO[i] : 0;
2377       PetscInt       c;
2378 
2379       if (rev) {
2380         PetscInt childSize, coff;
2381         ierr = DMPlexGetConeSize(dm, cp, &childSize);CHKERRQ(ierr);
2382         coff = tmpO[i] < 0 ? -(tmpO[i]+1) : tmpO[i];
2383         co   = childSize ? -(((coff+childSize-1)%childSize)+1) : 0;
2384       }
2385       /* Check for duplicate */
2386       for (c = 0; c < closureSize; c += 2) {
2387         if (closure[c] == cp) break;
2388       }
2389       if (c == closureSize) {
2390         closure[closureSize]   = cp;
2391         closure[closureSize+1] = co;
2392         fifo[fifoSize]         = cp;
2393         fifo[fifoSize+1]       = co;
2394         closureSize           += 2;
2395         fifoSize              += 2;
2396       }
2397     }
2398     fifoStart += 2;
2399   }
2400   if (numPoints) *numPoints = closureSize/2;
2401   if (points)    *points    = closure;
2402   ierr = DMRestoreWorkArray(dm, maxSize, MPIU_INT, &fifo);CHKERRQ(ierr);
2403   PetscFunctionReturn(0);
2404 }
2405 
2406 /*@C
2407   DMPlexRestoreTransitiveClosure - Restore the array of points on the transitive closure of the in-edges or out-edges for this point in the DAG
2408 
2409   Not collective
2410 
2411   Input Parameters:
2412 + mesh - The DMPlex
2413 . p - The point, which must lie in the chart set with DMPlexSetChart()
2414 . useCone - PETSC_TRUE for in-edges,  otherwise use out-edges
2415 . numPoints - The number of points in the closure, so points[] is of size 2*numPoints, zeroed on exit
2416 - points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...], zeroed on exit
2417 
2418   Note:
2419   If not using internal storage (points is not NULL on input), this call is unnecessary
2420 
2421   Fortran Notes:
2422   Since it returns an array, this routine is only available in Fortran 90, and you must
2423   include petsc.h90 in your code.
2424 
2425   The numPoints argument is not present in the Fortran 90 binding since it is internal to the array.
2426 
2427   Level: beginner
2428 
2429 .seealso: DMPlexGetTransitiveClosure(), DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone()
2430 @*/
2431 PetscErrorCode DMPlexRestoreTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[])
2432 {
2433   PetscErrorCode ierr;
2434 
2435   PetscFunctionBegin;
2436   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2437   if (numPoints) PetscValidIntPointer(numPoints,4);
2438   if (points) PetscValidPointer(points,5);
2439   ierr = DMRestoreWorkArray(dm, 0, MPIU_INT, points);CHKERRQ(ierr);
2440   if (numPoints) *numPoints = 0;
2441   PetscFunctionReturn(0);
2442 }
2443 
2444 /*@
2445   DMPlexGetMaxSizes - Return the maximum number of in-edges (cone) and out-edges (support) for any point in the DAG
2446 
2447   Not collective
2448 
2449   Input Parameter:
2450 . mesh - The DMPlex
2451 
2452   Output Parameters:
2453 + maxConeSize - The maximum number of in-edges
2454 - maxSupportSize - The maximum number of out-edges
2455 
2456   Level: beginner
2457 
2458 .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexSetChart()
2459 @*/
2460 PetscErrorCode DMPlexGetMaxSizes(DM dm, PetscInt *maxConeSize, PetscInt *maxSupportSize)
2461 {
2462   DM_Plex *mesh = (DM_Plex*) dm->data;
2463 
2464   PetscFunctionBegin;
2465   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2466   if (maxConeSize)    *maxConeSize    = mesh->maxConeSize;
2467   if (maxSupportSize) *maxSupportSize = mesh->maxSupportSize;
2468   PetscFunctionReturn(0);
2469 }
2470 
2471 PetscErrorCode DMSetUp_Plex(DM dm)
2472 {
2473   DM_Plex       *mesh = (DM_Plex*) dm->data;
2474   PetscInt       size;
2475   PetscErrorCode ierr;
2476 
2477   PetscFunctionBegin;
2478   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2479   ierr = PetscSectionSetUp(mesh->coneSection);CHKERRQ(ierr);
2480   ierr = PetscSectionGetStorageSize(mesh->coneSection, &size);CHKERRQ(ierr);
2481   ierr = PetscMalloc1(size, &mesh->cones);CHKERRQ(ierr);
2482   ierr = PetscCalloc1(size, &mesh->coneOrientations);CHKERRQ(ierr);
2483   if (mesh->maxSupportSize) {
2484     ierr = PetscSectionSetUp(mesh->supportSection);CHKERRQ(ierr);
2485     ierr = PetscSectionGetStorageSize(mesh->supportSection, &size);CHKERRQ(ierr);
2486     ierr = PetscMalloc1(size, &mesh->supports);CHKERRQ(ierr);
2487   }
2488   PetscFunctionReturn(0);
2489 }
2490 
2491 PetscErrorCode DMCreateSubDM_Plex(DM dm, PetscInt numFields, const PetscInt fields[], IS *is, DM *subdm)
2492 {
2493   PetscErrorCode ierr;
2494 
2495   PetscFunctionBegin;
2496   if (subdm) {ierr = DMClone(dm, subdm);CHKERRQ(ierr);}
2497   ierr = DMCreateSectionSubDM(dm, numFields, fields, is, subdm);CHKERRQ(ierr);
2498   if (subdm) {(*subdm)->useNatural = dm->useNatural;}
2499   if (dm->useNatural && dm->sfMigration) {
2500     PetscSF        sfMigrationInv,sfNatural;
2501     PetscSection   section, sectionSeq;
2502 
2503     (*subdm)->sfMigration = dm->sfMigration;
2504     ierr = PetscObjectReference((PetscObject) dm->sfMigration);CHKERRQ(ierr);
2505     ierr = DMGetSection((*subdm), &section);CHKERRQ(ierr);CHKERRQ(ierr);
2506     ierr = PetscSFCreateInverseSF((*subdm)->sfMigration, &sfMigrationInv);CHKERRQ(ierr);
2507     ierr = PetscSectionCreate(PetscObjectComm((PetscObject) (*subdm)), &sectionSeq);CHKERRQ(ierr);
2508     ierr = PetscSFDistributeSection(sfMigrationInv, section, NULL, sectionSeq);CHKERRQ(ierr);
2509 
2510     ierr = DMPlexCreateGlobalToNaturalSF(*subdm, sectionSeq, (*subdm)->sfMigration, &sfNatural);CHKERRQ(ierr);
2511     (*subdm)->sfNatural = sfNatural;
2512     ierr = PetscSectionDestroy(&sectionSeq);CHKERRQ(ierr);
2513     ierr = PetscSFDestroy(&sfMigrationInv);CHKERRQ(ierr);
2514   }
2515   PetscFunctionReturn(0);
2516 }
2517 
2518 PetscErrorCode DMCreateSuperDM_Plex(DM dms[], PetscInt len, IS **is, DM *superdm)
2519 {
2520   PetscErrorCode ierr;
2521   PetscInt       i = 0;
2522 
2523   PetscFunctionBegin;
2524   ierr = DMClone(dms[0], superdm);CHKERRQ(ierr);
2525   ierr = DMCreateSectionSuperDM(dms, len, is, superdm);CHKERRQ(ierr);
2526   (*superdm)->useNatural = PETSC_FALSE;
2527   for (i = 0; i < len; i++){
2528     if (dms[i]->useNatural && dms[i]->sfMigration) {
2529       PetscSF        sfMigrationInv,sfNatural;
2530       PetscSection   section, sectionSeq;
2531 
2532       (*superdm)->sfMigration = dms[i]->sfMigration;
2533       ierr = PetscObjectReference((PetscObject) dms[i]->sfMigration);CHKERRQ(ierr);
2534       (*superdm)->useNatural = PETSC_TRUE;
2535       ierr = DMGetSection((*superdm), &section);CHKERRQ(ierr);
2536       ierr = PetscSFCreateInverseSF((*superdm)->sfMigration, &sfMigrationInv);CHKERRQ(ierr);
2537       ierr = PetscSectionCreate(PetscObjectComm((PetscObject) (*superdm)), &sectionSeq);CHKERRQ(ierr);
2538       ierr = PetscSFDistributeSection(sfMigrationInv, section, NULL, sectionSeq);CHKERRQ(ierr);
2539 
2540       ierr = DMPlexCreateGlobalToNaturalSF(*superdm, sectionSeq, (*superdm)->sfMigration, &sfNatural);CHKERRQ(ierr);
2541       (*superdm)->sfNatural = sfNatural;
2542       ierr = PetscSectionDestroy(&sectionSeq);CHKERRQ(ierr);
2543       ierr = PetscSFDestroy(&sfMigrationInv);CHKERRQ(ierr);
2544       break;
2545     }
2546   }
2547   PetscFunctionReturn(0);
2548 }
2549 
2550 /*@
2551   DMPlexSymmetrize - Create support (out-edge) information from cone (in-edge) information
2552 
2553   Not collective
2554 
2555   Input Parameter:
2556 . mesh - The DMPlex
2557 
2558   Output Parameter:
2559 
2560   Note:
2561   This should be called after all calls to DMPlexSetCone()
2562 
2563   Level: beginner
2564 
2565 .seealso: DMPlexCreate(), DMPlexSetChart(), DMPlexSetConeSize(), DMPlexSetCone()
2566 @*/
2567 PetscErrorCode DMPlexSymmetrize(DM dm)
2568 {
2569   DM_Plex       *mesh = (DM_Plex*) dm->data;
2570   PetscInt      *offsets;
2571   PetscInt       supportSize;
2572   PetscInt       pStart, pEnd, p;
2573   PetscErrorCode ierr;
2574 
2575   PetscFunctionBegin;
2576   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2577   if (mesh->supports) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Supports were already setup in this DMPlex");
2578   ierr = PetscLogEventBegin(DMPLEX_Symmetrize,dm,0,0,0);CHKERRQ(ierr);
2579   /* Calculate support sizes */
2580   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
2581   for (p = pStart; p < pEnd; ++p) {
2582     PetscInt dof, off, c;
2583 
2584     ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
2585     ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
2586     for (c = off; c < off+dof; ++c) {
2587       ierr = PetscSectionAddDof(mesh->supportSection, mesh->cones[c], 1);CHKERRQ(ierr);
2588     }
2589   }
2590   for (p = pStart; p < pEnd; ++p) {
2591     PetscInt dof;
2592 
2593     ierr = PetscSectionGetDof(mesh->supportSection, p, &dof);CHKERRQ(ierr);
2594 
2595     mesh->maxSupportSize = PetscMax(mesh->maxSupportSize, dof);
2596   }
2597   ierr = PetscSectionSetUp(mesh->supportSection);CHKERRQ(ierr);
2598   /* Calculate supports */
2599   ierr = PetscSectionGetStorageSize(mesh->supportSection, &supportSize);CHKERRQ(ierr);
2600   ierr = PetscMalloc1(supportSize, &mesh->supports);CHKERRQ(ierr);
2601   ierr = PetscCalloc1(pEnd - pStart, &offsets);CHKERRQ(ierr);
2602   for (p = pStart; p < pEnd; ++p) {
2603     PetscInt dof, off, c;
2604 
2605     ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
2606     ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
2607     for (c = off; c < off+dof; ++c) {
2608       const PetscInt q = mesh->cones[c];
2609       PetscInt       offS;
2610 
2611       ierr = PetscSectionGetOffset(mesh->supportSection, q, &offS);CHKERRQ(ierr);
2612 
2613       mesh->supports[offS+offsets[q]] = p;
2614       ++offsets[q];
2615     }
2616   }
2617   ierr = PetscFree(offsets);CHKERRQ(ierr);
2618   ierr = PetscLogEventEnd(DMPLEX_Symmetrize,dm,0,0,0);CHKERRQ(ierr);
2619   PetscFunctionReturn(0);
2620 }
2621 
2622 static PetscErrorCode DMPlexCreateDepthStratum(DM dm, DMLabel label, PetscInt depth, PetscInt pStart, PetscInt pEnd)
2623 {
2624   IS             stratumIS;
2625   PetscErrorCode ierr;
2626 
2627   PetscFunctionBegin;
2628   if (pStart >= pEnd) PetscFunctionReturn(0);
2629 #if defined(PETSC_USE_DEBUG)
2630   {
2631     PetscInt  qStart, qEnd, numLevels, level;
2632     PetscBool overlap = PETSC_FALSE;
2633     ierr = DMLabelGetNumValues(label, &numLevels);CHKERRQ(ierr);
2634     for (level = 0; level < numLevels; level++) {
2635       ierr = DMLabelGetStratumBounds(label, level, &qStart, &qEnd);CHKERRQ(ierr);
2636       if ((pStart >= qStart && pStart < qEnd) || (pEnd > qStart && pEnd <= qEnd)) {overlap = PETSC_TRUE; break;}
2637     }
2638     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);
2639   }
2640 #endif
2641   ierr = ISCreateStride(PETSC_COMM_SELF, pEnd-pStart, pStart, 1, &stratumIS);CHKERRQ(ierr);
2642   ierr = DMLabelSetStratumIS(label, depth, stratumIS);CHKERRQ(ierr);
2643   ierr = ISDestroy(&stratumIS);CHKERRQ(ierr);
2644   PetscFunctionReturn(0);
2645 }
2646 
2647 static PetscErrorCode DMPlexCreateDimStratum(DM,DMLabel,DMLabel,PetscInt,PetscInt);
2648 
2649 /*@
2650   DMPlexStratify - The DAG for most topologies is a graded poset (https://en.wikipedia.org/wiki/Graded_poset), and
2651   can be illustrated by a Hasse Diagram (https://en.wikipedia.org/wiki/Hasse_diagram). The strata group all points of the
2652   same grade, and this function calculates the strata. This grade can be seen as the height (or depth) of the point in
2653   the DAG.
2654 
2655   Collective on dm
2656 
2657   Input Parameter:
2658 . mesh - The DMPlex
2659 
2660   Output Parameter:
2661 
2662   Notes:
2663   Concretely, DMPlexStratify() creates a new label named "depth" containing the dimension of each element: 0 for vertices,
2664   1 for edges, and so on.  The depth label can be accessed through DMPlexGetDepthLabel() or DMPlexGetDepthStratum(), or
2665   manually via DMGetLabel().  The height is defined implicitly by height = maxDimension - depth, and can be accessed
2666   via DMPlexGetHeightStratum().  For example, cells have height 0 and faces have height 1.
2667 
2668   DMPlexStratify() should be called after all calls to DMPlexSymmetrize()
2669 
2670   Level: beginner
2671 
2672 .seealso: DMPlexCreate(), DMPlexSymmetrize()
2673 @*/
2674 PetscErrorCode DMPlexStratify(DM dm)
2675 {
2676   DM_Plex       *mesh = (DM_Plex*) dm->data;
2677   DMLabel        label;
2678   PetscInt       pStart, pEnd, p;
2679   PetscInt       numRoots = 0, numLeaves = 0;
2680   PetscInt       cMax, fMax, eMax, vMax;
2681   PetscErrorCode ierr;
2682 
2683   PetscFunctionBegin;
2684   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2685   ierr = PetscLogEventBegin(DMPLEX_Stratify,dm,0,0,0);CHKERRQ(ierr);
2686 
2687   /* Create depth label */
2688   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
2689   ierr = DMCreateLabel(dm, "depth");CHKERRQ(ierr);
2690   ierr = DMPlexGetDepthLabel(dm, &label);CHKERRQ(ierr);
2691 
2692   {
2693     /* Initialize roots and count leaves */
2694     PetscInt sMin = PETSC_MAX_INT;
2695     PetscInt sMax = PETSC_MIN_INT;
2696     PetscInt coneSize, supportSize;
2697 
2698     for (p = pStart; p < pEnd; ++p) {
2699       ierr = DMPlexGetConeSize(dm, p, &coneSize);CHKERRQ(ierr);
2700       ierr = DMPlexGetSupportSize(dm, p, &supportSize);CHKERRQ(ierr);
2701       if (!coneSize && supportSize) {
2702         sMin = PetscMin(p, sMin);
2703         sMax = PetscMax(p, sMax);
2704         ++numRoots;
2705       } else if (!supportSize && coneSize) {
2706         ++numLeaves;
2707       } else if (!supportSize && !coneSize) {
2708         /* Isolated points */
2709         sMin = PetscMin(p, sMin);
2710         sMax = PetscMax(p, sMax);
2711       }
2712     }
2713     ierr = DMPlexCreateDepthStratum(dm, label, 0, sMin, sMax+1);CHKERRQ(ierr);
2714   }
2715 
2716   if (numRoots + numLeaves == (pEnd - pStart)) {
2717     PetscInt sMin = PETSC_MAX_INT;
2718     PetscInt sMax = PETSC_MIN_INT;
2719     PetscInt coneSize, supportSize;
2720 
2721     for (p = pStart; p < pEnd; ++p) {
2722       ierr = DMPlexGetConeSize(dm, p, &coneSize);CHKERRQ(ierr);
2723       ierr = DMPlexGetSupportSize(dm, p, &supportSize);CHKERRQ(ierr);
2724       if (!supportSize && coneSize) {
2725         sMin = PetscMin(p, sMin);
2726         sMax = PetscMax(p, sMax);
2727       }
2728     }
2729     ierr = DMPlexCreateDepthStratum(dm, label, 1, sMin, sMax+1);CHKERRQ(ierr);
2730   } else {
2731     PetscInt level = 0;
2732     PetscInt qStart, qEnd, q;
2733 
2734     ierr = DMLabelGetStratumBounds(label, level, &qStart, &qEnd);CHKERRQ(ierr);
2735     while (qEnd > qStart) {
2736       PetscInt sMin = PETSC_MAX_INT;
2737       PetscInt sMax = PETSC_MIN_INT;
2738 
2739       for (q = qStart; q < qEnd; ++q) {
2740         const PetscInt *support;
2741         PetscInt        supportSize, s;
2742 
2743         ierr = DMPlexGetSupportSize(dm, q, &supportSize);CHKERRQ(ierr);
2744         ierr = DMPlexGetSupport(dm, q, &support);CHKERRQ(ierr);
2745         for (s = 0; s < supportSize; ++s) {
2746           sMin = PetscMin(support[s], sMin);
2747           sMax = PetscMax(support[s], sMax);
2748         }
2749       }
2750       ierr = DMLabelGetNumValues(label, &level);CHKERRQ(ierr);
2751       ierr = DMPlexCreateDepthStratum(dm, label, level, sMin, sMax+1);CHKERRQ(ierr);
2752       ierr = DMLabelGetStratumBounds(label, level, &qStart, &qEnd);CHKERRQ(ierr);
2753     }
2754   }
2755   { /* just in case there is an empty process */
2756     PetscInt numValues, maxValues = 0, v;
2757 
2758     ierr = DMLabelGetNumValues(label, &numValues);CHKERRQ(ierr);
2759     ierr = MPI_Allreduce(&numValues,&maxValues,1,MPIU_INT,MPI_MAX,PetscObjectComm((PetscObject)dm));CHKERRQ(ierr);
2760     for (v = numValues; v < maxValues; v++) {
2761       ierr = DMLabelAddStratum(label, v);CHKERRQ(ierr);
2762     }
2763   }
2764   ierr = PetscObjectStateGet((PetscObject) label, &mesh->depthState);CHKERRQ(ierr);
2765 
2766   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
2767   if (cMax >= 0 || fMax >= 0 || eMax >= 0 || vMax >= 0) {
2768     PetscInt dim;
2769     DMLabel  dimLabel;
2770 
2771     ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr);
2772     ierr = DMCreateLabel(dm, "dim");CHKERRQ(ierr);
2773     ierr = DMGetLabel(dm, "dim", &dimLabel);CHKERRQ(ierr);
2774     if (cMax >= 0) {ierr = DMPlexCreateDimStratum(dm, label, dimLabel, dim, cMax);CHKERRQ(ierr);}
2775     if (fMax >= 0) {ierr = DMPlexCreateDimStratum(dm, label, dimLabel, dim - 1, fMax);CHKERRQ(ierr);}
2776     if (eMax >= 0) {ierr = DMPlexCreateDimStratum(dm, label, dimLabel, 1, eMax);CHKERRQ(ierr);}
2777     if (vMax >= 0) {ierr = DMPlexCreateDimStratum(dm, label, dimLabel, 0, vMax);CHKERRQ(ierr);}
2778   }
2779   ierr = PetscLogEventEnd(DMPLEX_Stratify,dm,0,0,0);CHKERRQ(ierr);
2780   PetscFunctionReturn(0);
2781 }
2782 
2783 /*@C
2784   DMPlexGetJoin - Get an array for the join of the set of points
2785 
2786   Not Collective
2787 
2788   Input Parameters:
2789 + dm - The DMPlex object
2790 . numPoints - The number of input points for the join
2791 - points - The input points
2792 
2793   Output Parameters:
2794 + numCoveredPoints - The number of points in the join
2795 - coveredPoints - The points in the join
2796 
2797   Level: intermediate
2798 
2799   Note: Currently, this is restricted to a single level join
2800 
2801   Fortran Notes:
2802   Since it returns an array, this routine is only available in Fortran 90, and you must
2803   include petsc.h90 in your code.
2804 
2805   The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array.
2806 
2807 .seealso: DMPlexRestoreJoin(), DMPlexGetMeet()
2808 @*/
2809 PetscErrorCode DMPlexGetJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
2810 {
2811   DM_Plex       *mesh = (DM_Plex*) dm->data;
2812   PetscInt      *join[2];
2813   PetscInt       joinSize, i = 0;
2814   PetscInt       dof, off, p, c, m;
2815   PetscErrorCode ierr;
2816 
2817   PetscFunctionBegin;
2818   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2819   PetscValidIntPointer(points, 3);
2820   PetscValidIntPointer(numCoveredPoints, 4);
2821   PetscValidPointer(coveredPoints, 5);
2822   ierr = DMGetWorkArray(dm, mesh->maxSupportSize, MPIU_INT, &join[0]);CHKERRQ(ierr);
2823   ierr = DMGetWorkArray(dm, mesh->maxSupportSize, MPIU_INT, &join[1]);CHKERRQ(ierr);
2824   /* Copy in support of first point */
2825   ierr = PetscSectionGetDof(mesh->supportSection, points[0], &dof);CHKERRQ(ierr);
2826   ierr = PetscSectionGetOffset(mesh->supportSection, points[0], &off);CHKERRQ(ierr);
2827   for (joinSize = 0; joinSize < dof; ++joinSize) {
2828     join[i][joinSize] = mesh->supports[off+joinSize];
2829   }
2830   /* Check each successive support */
2831   for (p = 1; p < numPoints; ++p) {
2832     PetscInt newJoinSize = 0;
2833 
2834     ierr = PetscSectionGetDof(mesh->supportSection, points[p], &dof);CHKERRQ(ierr);
2835     ierr = PetscSectionGetOffset(mesh->supportSection, points[p], &off);CHKERRQ(ierr);
2836     for (c = 0; c < dof; ++c) {
2837       const PetscInt point = mesh->supports[off+c];
2838 
2839       for (m = 0; m < joinSize; ++m) {
2840         if (point == join[i][m]) {
2841           join[1-i][newJoinSize++] = point;
2842           break;
2843         }
2844       }
2845     }
2846     joinSize = newJoinSize;
2847     i        = 1-i;
2848   }
2849   *numCoveredPoints = joinSize;
2850   *coveredPoints    = join[i];
2851   ierr              = DMRestoreWorkArray(dm, mesh->maxSupportSize, MPIU_INT, &join[1-i]);CHKERRQ(ierr);
2852   PetscFunctionReturn(0);
2853 }
2854 
2855 /*@C
2856   DMPlexRestoreJoin - Restore an array for the join of the set of points
2857 
2858   Not Collective
2859 
2860   Input Parameters:
2861 + dm - The DMPlex object
2862 . numPoints - The number of input points for the join
2863 - points - The input points
2864 
2865   Output Parameters:
2866 + numCoveredPoints - The number of points in the join
2867 - coveredPoints - The points in the join
2868 
2869   Fortran Notes:
2870   Since it returns an array, this routine is only available in Fortran 90, and you must
2871   include petsc.h90 in your code.
2872 
2873   The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array.
2874 
2875   Level: intermediate
2876 
2877 .seealso: DMPlexGetJoin(), DMPlexGetFullJoin(), DMPlexGetMeet()
2878 @*/
2879 PetscErrorCode DMPlexRestoreJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
2880 {
2881   PetscErrorCode ierr;
2882 
2883   PetscFunctionBegin;
2884   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2885   if (points) PetscValidIntPointer(points,3);
2886   if (numCoveredPoints) PetscValidIntPointer(numCoveredPoints,4);
2887   PetscValidPointer(coveredPoints, 5);
2888   ierr = DMRestoreWorkArray(dm, 0, MPIU_INT, (void*) coveredPoints);CHKERRQ(ierr);
2889   if (numCoveredPoints) *numCoveredPoints = 0;
2890   PetscFunctionReturn(0);
2891 }
2892 
2893 /*@C
2894   DMPlexGetFullJoin - Get an array for the join of the set of points
2895 
2896   Not Collective
2897 
2898   Input Parameters:
2899 + dm - The DMPlex object
2900 . numPoints - The number of input points for the join
2901 - points - The input points
2902 
2903   Output Parameters:
2904 + numCoveredPoints - The number of points in the join
2905 - coveredPoints - The points in the join
2906 
2907   Fortran Notes:
2908   Since it returns an array, this routine is only available in Fortran 90, and you must
2909   include petsc.h90 in your code.
2910 
2911   The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array.
2912 
2913   Level: intermediate
2914 
2915 .seealso: DMPlexGetJoin(), DMPlexRestoreJoin(), DMPlexGetMeet()
2916 @*/
2917 PetscErrorCode DMPlexGetFullJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
2918 {
2919   DM_Plex       *mesh = (DM_Plex*) dm->data;
2920   PetscInt      *offsets, **closures;
2921   PetscInt      *join[2];
2922   PetscInt       depth = 0, maxSize, joinSize = 0, i = 0;
2923   PetscInt       p, d, c, m, ms;
2924   PetscErrorCode ierr;
2925 
2926   PetscFunctionBegin;
2927   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2928   PetscValidIntPointer(points, 3);
2929   PetscValidIntPointer(numCoveredPoints, 4);
2930   PetscValidPointer(coveredPoints, 5);
2931 
2932   ierr    = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
2933   ierr    = PetscCalloc1(numPoints, &closures);CHKERRQ(ierr);
2934   ierr    = DMGetWorkArray(dm, numPoints*(depth+2), MPIU_INT, &offsets);CHKERRQ(ierr);
2935   ms      = mesh->maxSupportSize;
2936   maxSize = (ms > 1) ? ((PetscPowInt(ms,depth+1)-1)/(ms-1)) : depth + 1;
2937   ierr    = DMGetWorkArray(dm, maxSize, MPIU_INT, &join[0]);CHKERRQ(ierr);
2938   ierr    = DMGetWorkArray(dm, maxSize, MPIU_INT, &join[1]);CHKERRQ(ierr);
2939 
2940   for (p = 0; p < numPoints; ++p) {
2941     PetscInt closureSize;
2942 
2943     ierr = DMPlexGetTransitiveClosure(dm, points[p], PETSC_FALSE, &closureSize, &closures[p]);CHKERRQ(ierr);
2944 
2945     offsets[p*(depth+2)+0] = 0;
2946     for (d = 0; d < depth+1; ++d) {
2947       PetscInt pStart, pEnd, i;
2948 
2949       ierr = DMPlexGetDepthStratum(dm, d, &pStart, &pEnd);CHKERRQ(ierr);
2950       for (i = offsets[p*(depth+2)+d]; i < closureSize; ++i) {
2951         if ((pStart > closures[p][i*2]) || (pEnd <= closures[p][i*2])) {
2952           offsets[p*(depth+2)+d+1] = i;
2953           break;
2954         }
2955       }
2956       if (i == closureSize) offsets[p*(depth+2)+d+1] = i;
2957     }
2958     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);
2959   }
2960   for (d = 0; d < depth+1; ++d) {
2961     PetscInt dof;
2962 
2963     /* Copy in support of first point */
2964     dof = offsets[d+1] - offsets[d];
2965     for (joinSize = 0; joinSize < dof; ++joinSize) {
2966       join[i][joinSize] = closures[0][(offsets[d]+joinSize)*2];
2967     }
2968     /* Check each successive cone */
2969     for (p = 1; p < numPoints && joinSize; ++p) {
2970       PetscInt newJoinSize = 0;
2971 
2972       dof = offsets[p*(depth+2)+d+1] - offsets[p*(depth+2)+d];
2973       for (c = 0; c < dof; ++c) {
2974         const PetscInt point = closures[p][(offsets[p*(depth+2)+d]+c)*2];
2975 
2976         for (m = 0; m < joinSize; ++m) {
2977           if (point == join[i][m]) {
2978             join[1-i][newJoinSize++] = point;
2979             break;
2980           }
2981         }
2982       }
2983       joinSize = newJoinSize;
2984       i        = 1-i;
2985     }
2986     if (joinSize) break;
2987   }
2988   *numCoveredPoints = joinSize;
2989   *coveredPoints    = join[i];
2990   for (p = 0; p < numPoints; ++p) {
2991     ierr = DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_FALSE, NULL, &closures[p]);CHKERRQ(ierr);
2992   }
2993   ierr = PetscFree(closures);CHKERRQ(ierr);
2994   ierr = DMRestoreWorkArray(dm, numPoints*(depth+2), MPIU_INT, &offsets);CHKERRQ(ierr);
2995   ierr = DMRestoreWorkArray(dm, mesh->maxSupportSize, MPIU_INT, &join[1-i]);CHKERRQ(ierr);
2996   PetscFunctionReturn(0);
2997 }
2998 
2999 /*@C
3000   DMPlexGetMeet - Get an array for the meet of the set of points
3001 
3002   Not Collective
3003 
3004   Input Parameters:
3005 + dm - The DMPlex object
3006 . numPoints - The number of input points for the meet
3007 - points - The input points
3008 
3009   Output Parameters:
3010 + numCoveredPoints - The number of points in the meet
3011 - coveredPoints - The points in the meet
3012 
3013   Level: intermediate
3014 
3015   Note: Currently, this is restricted to a single level meet
3016 
3017   Fortran Notes:
3018   Since it returns an array, this routine is only available in Fortran 90, and you must
3019   include petsc.h90 in your code.
3020 
3021   The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array.
3022 
3023 .seealso: DMPlexRestoreMeet(), DMPlexGetJoin()
3024 @*/
3025 PetscErrorCode DMPlexGetMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveringPoints, const PetscInt **coveringPoints)
3026 {
3027   DM_Plex       *mesh = (DM_Plex*) dm->data;
3028   PetscInt      *meet[2];
3029   PetscInt       meetSize, i = 0;
3030   PetscInt       dof, off, p, c, m;
3031   PetscErrorCode ierr;
3032 
3033   PetscFunctionBegin;
3034   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3035   PetscValidPointer(points, 2);
3036   PetscValidPointer(numCoveringPoints, 3);
3037   PetscValidPointer(coveringPoints, 4);
3038   ierr = DMGetWorkArray(dm, mesh->maxConeSize, MPIU_INT, &meet[0]);CHKERRQ(ierr);
3039   ierr = DMGetWorkArray(dm, mesh->maxConeSize, MPIU_INT, &meet[1]);CHKERRQ(ierr);
3040   /* Copy in cone of first point */
3041   ierr = PetscSectionGetDof(mesh->coneSection, points[0], &dof);CHKERRQ(ierr);
3042   ierr = PetscSectionGetOffset(mesh->coneSection, points[0], &off);CHKERRQ(ierr);
3043   for (meetSize = 0; meetSize < dof; ++meetSize) {
3044     meet[i][meetSize] = mesh->cones[off+meetSize];
3045   }
3046   /* Check each successive cone */
3047   for (p = 1; p < numPoints; ++p) {
3048     PetscInt newMeetSize = 0;
3049 
3050     ierr = PetscSectionGetDof(mesh->coneSection, points[p], &dof);CHKERRQ(ierr);
3051     ierr = PetscSectionGetOffset(mesh->coneSection, points[p], &off);CHKERRQ(ierr);
3052     for (c = 0; c < dof; ++c) {
3053       const PetscInt point = mesh->cones[off+c];
3054 
3055       for (m = 0; m < meetSize; ++m) {
3056         if (point == meet[i][m]) {
3057           meet[1-i][newMeetSize++] = point;
3058           break;
3059         }
3060       }
3061     }
3062     meetSize = newMeetSize;
3063     i        = 1-i;
3064   }
3065   *numCoveringPoints = meetSize;
3066   *coveringPoints    = meet[i];
3067   ierr               = DMRestoreWorkArray(dm, mesh->maxConeSize, MPIU_INT, &meet[1-i]);CHKERRQ(ierr);
3068   PetscFunctionReturn(0);
3069 }
3070 
3071 /*@C
3072   DMPlexRestoreMeet - Restore an array for the meet of the set of points
3073 
3074   Not Collective
3075 
3076   Input Parameters:
3077 + dm - The DMPlex object
3078 . numPoints - The number of input points for the meet
3079 - points - The input points
3080 
3081   Output Parameters:
3082 + numCoveredPoints - The number of points in the meet
3083 - coveredPoints - The points in the meet
3084 
3085   Level: intermediate
3086 
3087   Fortran Notes:
3088   Since it returns an array, this routine is only available in Fortran 90, and you must
3089   include petsc.h90 in your code.
3090 
3091   The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array.
3092 
3093 .seealso: DMPlexGetMeet(), DMPlexGetFullMeet(), DMPlexGetJoin()
3094 @*/
3095 PetscErrorCode DMPlexRestoreMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
3096 {
3097   PetscErrorCode ierr;
3098 
3099   PetscFunctionBegin;
3100   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3101   if (points) PetscValidIntPointer(points,3);
3102   if (numCoveredPoints) PetscValidIntPointer(numCoveredPoints,4);
3103   PetscValidPointer(coveredPoints,5);
3104   ierr = DMRestoreWorkArray(dm, 0, MPIU_INT, (void*) coveredPoints);CHKERRQ(ierr);
3105   if (numCoveredPoints) *numCoveredPoints = 0;
3106   PetscFunctionReturn(0);
3107 }
3108 
3109 /*@C
3110   DMPlexGetFullMeet - Get an array for the meet of the set of points
3111 
3112   Not Collective
3113 
3114   Input Parameters:
3115 + dm - The DMPlex object
3116 . numPoints - The number of input points for the meet
3117 - points - The input points
3118 
3119   Output Parameters:
3120 + numCoveredPoints - The number of points in the meet
3121 - coveredPoints - The points in the meet
3122 
3123   Level: intermediate
3124 
3125   Fortran Notes:
3126   Since it returns an array, this routine is only available in Fortran 90, and you must
3127   include petsc.h90 in your code.
3128 
3129   The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array.
3130 
3131 .seealso: DMPlexGetMeet(), DMPlexRestoreMeet(), DMPlexGetJoin()
3132 @*/
3133 PetscErrorCode DMPlexGetFullMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
3134 {
3135   DM_Plex       *mesh = (DM_Plex*) dm->data;
3136   PetscInt      *offsets, **closures;
3137   PetscInt      *meet[2];
3138   PetscInt       height = 0, maxSize, meetSize = 0, i = 0;
3139   PetscInt       p, h, c, m, mc;
3140   PetscErrorCode ierr;
3141 
3142   PetscFunctionBegin;
3143   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3144   PetscValidPointer(points, 2);
3145   PetscValidPointer(numCoveredPoints, 3);
3146   PetscValidPointer(coveredPoints, 4);
3147 
3148   ierr    = DMPlexGetDepth(dm, &height);CHKERRQ(ierr);
3149   ierr    = PetscMalloc1(numPoints, &closures);CHKERRQ(ierr);
3150   ierr    = DMGetWorkArray(dm, numPoints*(height+2), MPIU_INT, &offsets);CHKERRQ(ierr);
3151   mc      = mesh->maxConeSize;
3152   maxSize = (mc > 1) ? ((PetscPowInt(mc,height+1)-1)/(mc-1)) : height + 1;
3153   ierr    = DMGetWorkArray(dm, maxSize, MPIU_INT, &meet[0]);CHKERRQ(ierr);
3154   ierr    = DMGetWorkArray(dm, maxSize, MPIU_INT, &meet[1]);CHKERRQ(ierr);
3155 
3156   for (p = 0; p < numPoints; ++p) {
3157     PetscInt closureSize;
3158 
3159     ierr = DMPlexGetTransitiveClosure(dm, points[p], PETSC_TRUE, &closureSize, &closures[p]);CHKERRQ(ierr);
3160 
3161     offsets[p*(height+2)+0] = 0;
3162     for (h = 0; h < height+1; ++h) {
3163       PetscInt pStart, pEnd, i;
3164 
3165       ierr = DMPlexGetHeightStratum(dm, h, &pStart, &pEnd);CHKERRQ(ierr);
3166       for (i = offsets[p*(height+2)+h]; i < closureSize; ++i) {
3167         if ((pStart > closures[p][i*2]) || (pEnd <= closures[p][i*2])) {
3168           offsets[p*(height+2)+h+1] = i;
3169           break;
3170         }
3171       }
3172       if (i == closureSize) offsets[p*(height+2)+h+1] = i;
3173     }
3174     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);
3175   }
3176   for (h = 0; h < height+1; ++h) {
3177     PetscInt dof;
3178 
3179     /* Copy in cone of first point */
3180     dof = offsets[h+1] - offsets[h];
3181     for (meetSize = 0; meetSize < dof; ++meetSize) {
3182       meet[i][meetSize] = closures[0][(offsets[h]+meetSize)*2];
3183     }
3184     /* Check each successive cone */
3185     for (p = 1; p < numPoints && meetSize; ++p) {
3186       PetscInt newMeetSize = 0;
3187 
3188       dof = offsets[p*(height+2)+h+1] - offsets[p*(height+2)+h];
3189       for (c = 0; c < dof; ++c) {
3190         const PetscInt point = closures[p][(offsets[p*(height+2)+h]+c)*2];
3191 
3192         for (m = 0; m < meetSize; ++m) {
3193           if (point == meet[i][m]) {
3194             meet[1-i][newMeetSize++] = point;
3195             break;
3196           }
3197         }
3198       }
3199       meetSize = newMeetSize;
3200       i        = 1-i;
3201     }
3202     if (meetSize) break;
3203   }
3204   *numCoveredPoints = meetSize;
3205   *coveredPoints    = meet[i];
3206   for (p = 0; p < numPoints; ++p) {
3207     ierr = DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_TRUE, NULL, &closures[p]);CHKERRQ(ierr);
3208   }
3209   ierr = PetscFree(closures);CHKERRQ(ierr);
3210   ierr = DMRestoreWorkArray(dm, numPoints*(height+2), MPIU_INT, &offsets);CHKERRQ(ierr);
3211   ierr = DMRestoreWorkArray(dm, mesh->maxConeSize, MPIU_INT, &meet[1-i]);CHKERRQ(ierr);
3212   PetscFunctionReturn(0);
3213 }
3214 
3215 /*@C
3216   DMPlexEqual - Determine if two DMs have the same topology
3217 
3218   Not Collective
3219 
3220   Input Parameters:
3221 + dmA - A DMPlex object
3222 - dmB - A DMPlex object
3223 
3224   Output Parameters:
3225 . equal - PETSC_TRUE if the topologies are identical
3226 
3227   Level: intermediate
3228 
3229   Notes:
3230   We are not solving graph isomorphism, so we do not permutation.
3231 
3232 .seealso: DMPlexGetCone()
3233 @*/
3234 PetscErrorCode DMPlexEqual(DM dmA, DM dmB, PetscBool *equal)
3235 {
3236   PetscInt       depth, depthB, pStart, pEnd, pStartB, pEndB, p;
3237   PetscErrorCode ierr;
3238 
3239   PetscFunctionBegin;
3240   PetscValidHeaderSpecific(dmA, DM_CLASSID, 1);
3241   PetscValidHeaderSpecific(dmB, DM_CLASSID, 2);
3242   PetscValidPointer(equal, 3);
3243 
3244   *equal = PETSC_FALSE;
3245   ierr = DMPlexGetDepth(dmA, &depth);CHKERRQ(ierr);
3246   ierr = DMPlexGetDepth(dmB, &depthB);CHKERRQ(ierr);
3247   if (depth != depthB) PetscFunctionReturn(0);
3248   ierr = DMPlexGetChart(dmA, &pStart,  &pEnd);CHKERRQ(ierr);
3249   ierr = DMPlexGetChart(dmB, &pStartB, &pEndB);CHKERRQ(ierr);
3250   if ((pStart != pStartB) || (pEnd != pEndB)) PetscFunctionReturn(0);
3251   for (p = pStart; p < pEnd; ++p) {
3252     const PetscInt *cone, *coneB, *ornt, *orntB, *support, *supportB;
3253     PetscInt        coneSize, coneSizeB, c, supportSize, supportSizeB, s;
3254 
3255     ierr = DMPlexGetConeSize(dmA, p, &coneSize);CHKERRQ(ierr);
3256     ierr = DMPlexGetCone(dmA, p, &cone);CHKERRQ(ierr);
3257     ierr = DMPlexGetConeOrientation(dmA, p, &ornt);CHKERRQ(ierr);
3258     ierr = DMPlexGetConeSize(dmB, p, &coneSizeB);CHKERRQ(ierr);
3259     ierr = DMPlexGetCone(dmB, p, &coneB);CHKERRQ(ierr);
3260     ierr = DMPlexGetConeOrientation(dmB, p, &orntB);CHKERRQ(ierr);
3261     if (coneSize != coneSizeB) PetscFunctionReturn(0);
3262     for (c = 0; c < coneSize; ++c) {
3263       if (cone[c] != coneB[c]) PetscFunctionReturn(0);
3264       if (ornt[c] != orntB[c]) PetscFunctionReturn(0);
3265     }
3266     ierr = DMPlexGetSupportSize(dmA, p, &supportSize);CHKERRQ(ierr);
3267     ierr = DMPlexGetSupport(dmA, p, &support);CHKERRQ(ierr);
3268     ierr = DMPlexGetSupportSize(dmB, p, &supportSizeB);CHKERRQ(ierr);
3269     ierr = DMPlexGetSupport(dmB, p, &supportB);CHKERRQ(ierr);
3270     if (supportSize != supportSizeB) PetscFunctionReturn(0);
3271     for (s = 0; s < supportSize; ++s) {
3272       if (support[s] != supportB[s]) PetscFunctionReturn(0);
3273     }
3274   }
3275   *equal = PETSC_TRUE;
3276   PetscFunctionReturn(0);
3277 }
3278 
3279 /*@C
3280   DMPlexGetNumFaceVertices - Returns the number of vertices on a face
3281 
3282   Not Collective
3283 
3284   Input Parameters:
3285 + dm         - The DMPlex
3286 . cellDim    - The cell dimension
3287 - numCorners - The number of vertices on a cell
3288 
3289   Output Parameters:
3290 . numFaceVertices - The number of vertices on a face
3291 
3292   Level: developer
3293 
3294   Notes:
3295   Of course this can only work for a restricted set of symmetric shapes
3296 
3297 .seealso: DMPlexGetCone()
3298 @*/
3299 PetscErrorCode DMPlexGetNumFaceVertices(DM dm, PetscInt cellDim, PetscInt numCorners, PetscInt *numFaceVertices)
3300 {
3301   MPI_Comm       comm;
3302   PetscErrorCode ierr;
3303 
3304   PetscFunctionBegin;
3305   ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr);
3306   PetscValidPointer(numFaceVertices,3);
3307   switch (cellDim) {
3308   case 0:
3309     *numFaceVertices = 0;
3310     break;
3311   case 1:
3312     *numFaceVertices = 1;
3313     break;
3314   case 2:
3315     switch (numCorners) {
3316     case 3: /* triangle */
3317       *numFaceVertices = 2; /* Edge has 2 vertices */
3318       break;
3319     case 4: /* quadrilateral */
3320       *numFaceVertices = 2; /* Edge has 2 vertices */
3321       break;
3322     case 6: /* quadratic triangle, tri and quad cohesive Lagrange cells */
3323       *numFaceVertices = 3; /* Edge has 3 vertices */
3324       break;
3325     case 9: /* quadratic quadrilateral, quadratic quad cohesive Lagrange cells */
3326       *numFaceVertices = 3; /* Edge has 3 vertices */
3327       break;
3328     default:
3329       SETERRQ2(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %D for dimension %D", numCorners, cellDim);
3330     }
3331     break;
3332   case 3:
3333     switch (numCorners) {
3334     case 4: /* tetradehdron */
3335       *numFaceVertices = 3; /* Face has 3 vertices */
3336       break;
3337     case 6: /* tet cohesive cells */
3338       *numFaceVertices = 4; /* Face has 4 vertices */
3339       break;
3340     case 8: /* hexahedron */
3341       *numFaceVertices = 4; /* Face has 4 vertices */
3342       break;
3343     case 9: /* tet cohesive Lagrange cells */
3344       *numFaceVertices = 6; /* Face has 6 vertices */
3345       break;
3346     case 10: /* quadratic tetrahedron */
3347       *numFaceVertices = 6; /* Face has 6 vertices */
3348       break;
3349     case 12: /* hex cohesive Lagrange cells */
3350       *numFaceVertices = 6; /* Face has 6 vertices */
3351       break;
3352     case 18: /* quadratic tet cohesive Lagrange cells */
3353       *numFaceVertices = 6; /* Face has 6 vertices */
3354       break;
3355     case 27: /* quadratic hexahedron, quadratic hex cohesive Lagrange cells */
3356       *numFaceVertices = 9; /* Face has 9 vertices */
3357       break;
3358     default:
3359       SETERRQ2(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %D for dimension %D", numCorners, cellDim);
3360     }
3361     break;
3362   default:
3363     SETERRQ1(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid cell dimension %D", cellDim);
3364   }
3365   PetscFunctionReturn(0);
3366 }
3367 
3368 /*@
3369   DMPlexGetDepthLabel - Get the DMLabel recording the depth of each point
3370 
3371   Not Collective
3372 
3373   Input Parameter:
3374 . dm    - The DMPlex object
3375 
3376   Output Parameter:
3377 . depthLabel - The DMLabel recording point depth
3378 
3379   Level: developer
3380 
3381 .seealso: DMPlexGetDepth(), DMPlexGetHeightStratum(), DMPlexGetDepthStratum()
3382 @*/
3383 PetscErrorCode DMPlexGetDepthLabel(DM dm, DMLabel *depthLabel)
3384 {
3385   PetscErrorCode ierr;
3386 
3387   PetscFunctionBegin;
3388   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3389   PetscValidPointer(depthLabel, 2);
3390   if (!dm->depthLabel) {ierr = DMGetLabel(dm, "depth", &dm->depthLabel);CHKERRQ(ierr);}
3391   *depthLabel = dm->depthLabel;
3392   PetscFunctionReturn(0);
3393 }
3394 
3395 /*@
3396   DMPlexGetDepth - Get the depth of the DAG representing this mesh
3397 
3398   Not Collective
3399 
3400   Input Parameter:
3401 . dm    - The DMPlex object
3402 
3403   Output Parameter:
3404 . depth - The number of strata (breadth first levels) in the DAG
3405 
3406   Level: developer
3407 
3408 .seealso: DMPlexGetDepthLabel(), DMPlexGetHeightStratum(), DMPlexGetDepthStratum()
3409 @*/
3410 PetscErrorCode DMPlexGetDepth(DM dm, PetscInt *depth)
3411 {
3412   DMLabel        label;
3413   PetscInt       d = 0;
3414   PetscErrorCode ierr;
3415 
3416   PetscFunctionBegin;
3417   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3418   PetscValidPointer(depth, 2);
3419   ierr = DMPlexGetDepthLabel(dm, &label);CHKERRQ(ierr);
3420   if (label) {ierr = DMLabelGetNumValues(label, &d);CHKERRQ(ierr);}
3421   *depth = d-1;
3422   PetscFunctionReturn(0);
3423 }
3424 
3425 /*@
3426   DMPlexGetDepthStratum - Get the bounds [start, end) for all points at a certain depth.
3427 
3428   Not Collective
3429 
3430   Input Parameters:
3431 + dm           - The DMPlex object
3432 - stratumValue - The requested depth
3433 
3434   Output Parameters:
3435 + start - The first point at this depth
3436 - end   - One beyond the last point at this depth
3437 
3438   Notes:
3439   Depth indexing is related to topological dimension.  Depth stratum 0 contains the lowest topological dimension points,
3440   often "vertices".  If the mesh is "interpolated" (see DMPlexInterpolate()), then depth stratum 1 contains the next
3441   higher dimension, e.g., "edges".
3442 
3443   Level: developer
3444 
3445 .seealso: DMPlexGetHeightStratum(), DMPlexGetDepth()
3446 @*/
3447 PetscErrorCode DMPlexGetDepthStratum(DM dm, PetscInt stratumValue, PetscInt *start, PetscInt *end)
3448 {
3449   DMLabel        label;
3450   PetscInt       pStart, pEnd;
3451   PetscErrorCode ierr;
3452 
3453   PetscFunctionBegin;
3454   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3455   if (start) {PetscValidPointer(start, 3); *start = 0;}
3456   if (end)   {PetscValidPointer(end,   4); *end   = 0;}
3457   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
3458   if (pStart == pEnd) PetscFunctionReturn(0);
3459   if (stratumValue < 0) {
3460     if (start) *start = pStart;
3461     if (end)   *end   = pEnd;
3462     PetscFunctionReturn(0);
3463   }
3464   ierr = DMPlexGetDepthLabel(dm, &label);CHKERRQ(ierr);
3465   if (!label) SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "No label named depth was found");
3466   ierr = DMLabelGetStratumBounds(label, stratumValue, start, end);CHKERRQ(ierr);
3467   PetscFunctionReturn(0);
3468 }
3469 
3470 /*@
3471   DMPlexGetHeightStratum - Get the bounds [start, end) for all points at a certain height.
3472 
3473   Not Collective
3474 
3475   Input Parameters:
3476 + dm           - The DMPlex object
3477 - stratumValue - The requested height
3478 
3479   Output Parameters:
3480 + start - The first point at this height
3481 - end   - One beyond the last point at this height
3482 
3483   Notes:
3484   Height indexing is related to topological codimension.  Height stratum 0 contains the highest topological dimension
3485   points, often called "cells" or "elements".  If the mesh is "interpolated" (see DMPlexInterpolate()), then height
3486   stratum 1 contains the boundary of these "cells", often called "faces" or "facets".
3487 
3488   Level: developer
3489 
3490 .seealso: DMPlexGetDepthStratum(), DMPlexGetDepth()
3491 @*/
3492 PetscErrorCode DMPlexGetHeightStratum(DM dm, PetscInt stratumValue, PetscInt *start, PetscInt *end)
3493 {
3494   DMLabel        label;
3495   PetscInt       depth, pStart, pEnd;
3496   PetscErrorCode ierr;
3497 
3498   PetscFunctionBegin;
3499   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3500   if (start) {PetscValidPointer(start, 3); *start = 0;}
3501   if (end)   {PetscValidPointer(end,   4); *end   = 0;}
3502   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
3503   if (pStart == pEnd) PetscFunctionReturn(0);
3504   if (stratumValue < 0) {
3505     if (start) *start = pStart;
3506     if (end)   *end   = pEnd;
3507     PetscFunctionReturn(0);
3508   }
3509   ierr = DMPlexGetDepthLabel(dm, &label);CHKERRQ(ierr);
3510   if (!label) SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "No label named depth was found");
3511   ierr = DMLabelGetNumValues(label, &depth);CHKERRQ(ierr);
3512   ierr = DMLabelGetStratumBounds(label, depth-1-stratumValue, start, end);CHKERRQ(ierr);
3513   PetscFunctionReturn(0);
3514 }
3515 
3516 PetscErrorCode DMCreateCoordinateDM_Plex(DM dm, DM *cdm)
3517 {
3518   PetscSection   section, s;
3519   Mat            m;
3520   PetscInt       maxHeight;
3521   PetscErrorCode ierr;
3522 
3523   PetscFunctionBegin;
3524   ierr = DMClone(dm, cdm);CHKERRQ(ierr);
3525   ierr = DMPlexGetMaxProjectionHeight(dm, &maxHeight);CHKERRQ(ierr);
3526   ierr = DMPlexSetMaxProjectionHeight(*cdm, maxHeight);CHKERRQ(ierr);
3527   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)dm), &section);CHKERRQ(ierr);
3528   ierr = DMSetSection(*cdm, section);CHKERRQ(ierr);
3529   ierr = PetscSectionDestroy(&section);CHKERRQ(ierr);
3530   ierr = PetscSectionCreate(PETSC_COMM_SELF, &s);CHKERRQ(ierr);
3531   ierr = MatCreate(PETSC_COMM_SELF, &m);CHKERRQ(ierr);
3532   ierr = DMSetDefaultConstraints(*cdm, s, m);CHKERRQ(ierr);
3533   ierr = PetscSectionDestroy(&s);CHKERRQ(ierr);
3534   ierr = MatDestroy(&m);CHKERRQ(ierr);
3535 
3536   ierr = DMSetNumFields(*cdm, 1);CHKERRQ(ierr);
3537   ierr = DMCreateDS(*cdm);CHKERRQ(ierr);
3538   PetscFunctionReturn(0);
3539 }
3540 
3541 PetscErrorCode DMCreateCoordinateField_Plex(DM dm, DMField *field)
3542 {
3543   Vec            coordsLocal;
3544   DM             coordsDM;
3545   PetscErrorCode ierr;
3546 
3547   PetscFunctionBegin;
3548   *field = NULL;
3549   ierr = DMGetCoordinatesLocal(dm,&coordsLocal);CHKERRQ(ierr);
3550   ierr = DMGetCoordinateDM(dm,&coordsDM);CHKERRQ(ierr);
3551   if (coordsLocal && coordsDM) {
3552     ierr = DMFieldCreateDS(coordsDM, 0, coordsLocal, field);CHKERRQ(ierr);
3553   }
3554   PetscFunctionReturn(0);
3555 }
3556 
3557 /*@C
3558   DMPlexGetConeSection - Return a section which describes the layout of cone data
3559 
3560   Not Collective
3561 
3562   Input Parameters:
3563 . dm        - The DMPlex object
3564 
3565   Output Parameter:
3566 . section - The PetscSection object
3567 
3568   Level: developer
3569 
3570 .seealso: DMPlexGetSupportSection(), DMPlexGetCones(), DMPlexGetConeOrientations()
3571 @*/
3572 PetscErrorCode DMPlexGetConeSection(DM dm, PetscSection *section)
3573 {
3574   DM_Plex *mesh = (DM_Plex*) dm->data;
3575 
3576   PetscFunctionBegin;
3577   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3578   if (section) *section = mesh->coneSection;
3579   PetscFunctionReturn(0);
3580 }
3581 
3582 /*@C
3583   DMPlexGetSupportSection - Return a section which describes the layout of support data
3584 
3585   Not Collective
3586 
3587   Input Parameters:
3588 . dm        - The DMPlex object
3589 
3590   Output Parameter:
3591 . section - The PetscSection object
3592 
3593   Level: developer
3594 
3595 .seealso: DMPlexGetConeSection()
3596 @*/
3597 PetscErrorCode DMPlexGetSupportSection(DM dm, PetscSection *section)
3598 {
3599   DM_Plex *mesh = (DM_Plex*) dm->data;
3600 
3601   PetscFunctionBegin;
3602   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3603   if (section) *section = mesh->supportSection;
3604   PetscFunctionReturn(0);
3605 }
3606 
3607 /*@C
3608   DMPlexGetCones - Return cone data
3609 
3610   Not Collective
3611 
3612   Input Parameters:
3613 . dm        - The DMPlex object
3614 
3615   Output Parameter:
3616 . cones - The cone for each point
3617 
3618   Level: developer
3619 
3620 .seealso: DMPlexGetConeSection()
3621 @*/
3622 PetscErrorCode DMPlexGetCones(DM dm, PetscInt *cones[])
3623 {
3624   DM_Plex *mesh = (DM_Plex*) dm->data;
3625 
3626   PetscFunctionBegin;
3627   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3628   if (cones) *cones = mesh->cones;
3629   PetscFunctionReturn(0);
3630 }
3631 
3632 /*@C
3633   DMPlexGetConeOrientations - Return cone orientation data
3634 
3635   Not Collective
3636 
3637   Input Parameters:
3638 . dm        - The DMPlex object
3639 
3640   Output Parameter:
3641 . coneOrientations - The cone orientation for each point
3642 
3643   Level: developer
3644 
3645 .seealso: DMPlexGetConeSection()
3646 @*/
3647 PetscErrorCode DMPlexGetConeOrientations(DM dm, PetscInt *coneOrientations[])
3648 {
3649   DM_Plex *mesh = (DM_Plex*) dm->data;
3650 
3651   PetscFunctionBegin;
3652   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3653   if (coneOrientations) *coneOrientations = mesh->coneOrientations;
3654   PetscFunctionReturn(0);
3655 }
3656 
3657 /******************************** FEM Support **********************************/
3658 
3659 /*@
3660 
3661   DMPlexSetClosurePermutationTensor - Create a permutation from the default (BFS) point ordering in the closure, to a
3662   lexicographic ordering over the tensor product cell (i.e., line, quad, hex, etc.), and set this permutation in the
3663   section provided (or default section of the DM).
3664 
3665   Input Parameters:
3666 + dm      - The DM
3667 . point   - Either a cell (highest dim point) or an edge (dim 1 point), or PETSC_DETERMINE
3668 - section - The PetscSection to reorder, or NULL for the default section
3669 
3670   Note: The point is used to determine the number of dofs/field on an edge. For SEM, this is related to the polynomial
3671   degree of the basis.
3672 
3673   Example:
3674   A typical interpolated single-quad mesh might order points as
3675 .vb
3676   [c0, v1, v2, v3, v4, e5, e6, e7, e8]
3677 
3678   v4 -- e6 -- v3
3679   |           |
3680   e7    c0    e8
3681   |           |
3682   v1 -- e5 -- v2
3683 .ve
3684 
3685   (There is no significance to the ordering described here.)  The default section for a Q3 quad might typically assign
3686   dofs in the order of points, e.g.,
3687 .vb
3688     c0 -> [0,1,2,3]
3689     v1 -> [4]
3690     ...
3691     e5 -> [8, 9]
3692 .ve
3693 
3694   which corresponds to the dofs
3695 .vb
3696     6   10  11  7
3697     13  2   3   15
3698     12  0   1   14
3699     4   8   9   5
3700 .ve
3701 
3702   The closure in BFS ordering works through height strata (cells, edges, vertices) to produce the ordering
3703 .vb
3704   0 1 2 3 8 9 14 15 11 10 13 12 4 5 7 6
3705 .ve
3706 
3707   After calling DMPlexSetClosurePermutationTensor(), the closure will be ordered lexicographically,
3708 .vb
3709    4 8 9 5 12 0 1 14 13 2 3 15 6 10 11 7
3710 .ve
3711 
3712   Level: developer
3713 
3714 .seealso: DMGetSection(), PetscSectionSetClosurePermutation()
3715 @*/
3716 PetscErrorCode DMPlexSetClosurePermutationTensor(DM dm, PetscInt point, PetscSection section)
3717 {
3718   DMLabel        label;
3719   PetscInt      *perm;
3720   PetscInt       dim, depth, eStart, k, Nf, f, Nc, c, i, j, size = 0, offset = 0, foffset = 0;
3721   PetscErrorCode ierr;
3722 
3723   PetscFunctionBegin;
3724   if (point < 0) {ierr = DMPlexGetDepthStratum(dm, 1, &point, NULL);CHKERRQ(ierr);}
3725   ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr);
3726   ierr = DMPlexGetDepthLabel(dm, &label);CHKERRQ(ierr);
3727   ierr = DMLabelGetValue(label, point, &depth);CHKERRQ(ierr);
3728   if (depth == 1) {eStart = point;}
3729   else if  (depth == dim) {
3730     const PetscInt *cone;
3731 
3732     ierr = DMPlexGetCone(dm, point, &cone);CHKERRQ(ierr);
3733     if (dim == 2) eStart = cone[0];
3734     else if (dim == 3) {
3735       const PetscInt *cone2;
3736       ierr = DMPlexGetCone(dm, cone[0], &cone2);CHKERRQ(ierr);
3737       eStart = cone2[0];
3738     } 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);
3739   } 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);
3740   if (!section) {ierr = DMGetSection(dm, &section);CHKERRQ(ierr);}
3741   ierr = PetscSectionGetNumFields(section, &Nf);CHKERRQ(ierr);
3742   if (dim < 1) PetscFunctionReturn(0);
3743   for (f = 0; f < Nf; ++f) {
3744     /* An order k SEM disc has k-1 dofs on an edge */
3745     ierr = PetscSectionGetFieldDof(section, eStart, f, &k);CHKERRQ(ierr);
3746     ierr = PetscSectionGetFieldComponents(section, f, &Nc);CHKERRQ(ierr);
3747     k = k/Nc + 1;
3748     size += PetscPowInt(k+1, dim)*Nc;
3749   }
3750   ierr = PetscMalloc1(size, &perm);CHKERRQ(ierr);
3751   for (f = 0; f < Nf; ++f) {
3752     switch (dim) {
3753     case 1:
3754       ierr = PetscSectionGetFieldDof(section, eStart, f, &k);CHKERRQ(ierr);
3755       ierr = PetscSectionGetFieldComponents(section, f, &Nc);CHKERRQ(ierr);
3756       k = k/Nc + 1;
3757       /*
3758         Original ordering is [ edge of length k-1; vtx0; vtx1 ]
3759         We want              [ vtx0; edge of length k-1; vtx1 ]
3760       */
3761       for (c=0; c<Nc; c++,offset++) perm[offset] = (k-1)*Nc + c + foffset;
3762       for (i=0; i<k-1; i++) for (c=0; c<Nc; c++,offset++) perm[offset] = i*Nc + c + foffset;
3763       for (c=0; c<Nc; c++,offset++) perm[offset] = k*Nc + c + foffset;
3764       foffset = offset;
3765       break;
3766     case 2:
3767       /* The original quad closure is oriented clockwise, {f, e_b, e_r, e_t, e_l, v_lb, v_rb, v_tr, v_tl} */
3768       ierr = PetscSectionGetFieldDof(section, eStart, f, &k);CHKERRQ(ierr);
3769       ierr = PetscSectionGetFieldComponents(section, f, &Nc);CHKERRQ(ierr);
3770       k = k/Nc + 1;
3771       /* The SEM order is
3772 
3773          v_lb, {e_b}, v_rb,
3774          e^{(k-1)-i}_l, {f^{i*(k-1)}}, e^i_r,
3775          v_lt, reverse {e_t}, v_rt
3776       */
3777       {
3778         const PetscInt of   = 0;
3779         const PetscInt oeb  = of   + PetscSqr(k-1);
3780         const PetscInt oer  = oeb  + (k-1);
3781         const PetscInt oet  = oer  + (k-1);
3782         const PetscInt oel  = oet  + (k-1);
3783         const PetscInt ovlb = oel  + (k-1);
3784         const PetscInt ovrb = ovlb + 1;
3785         const PetscInt ovrt = ovrb + 1;
3786         const PetscInt ovlt = ovrt + 1;
3787         PetscInt       o;
3788 
3789         /* bottom */
3790         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlb*Nc + c + foffset;
3791         for (o = oeb; o < oer; ++o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
3792         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrb*Nc + c + foffset;
3793         /* middle */
3794         for (i = 0; i < k-1; ++i) {
3795           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oel+(k-2)-i)*Nc + c + foffset;
3796           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;
3797           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oer+i)*Nc + c + foffset;
3798         }
3799         /* top */
3800         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlt*Nc + c + foffset;
3801         for (o = oel-1; o >= oet; --o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
3802         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrt*Nc + c + foffset;
3803         foffset = offset;
3804       }
3805       break;
3806     case 3:
3807       /* The original hex closure is
3808 
3809          {c,
3810           f_b, f_t, f_f, f_b, f_r, f_l,
3811           e_bl, e_bb, e_br, e_bf,  e_tf, e_tr, e_tb, e_tl,  e_rf, e_lf, e_lb, e_rb,
3812           v_blf, v_blb, v_brb, v_brf, v_tlf, v_trf, v_trb, v_tlb}
3813       */
3814       ierr = PetscSectionGetFieldDof(section, eStart, f, &k);CHKERRQ(ierr);
3815       ierr = PetscSectionGetFieldComponents(section, f, &Nc);CHKERRQ(ierr);
3816       k = k/Nc + 1;
3817       /* The SEM order is
3818          Bottom Slice
3819          v_blf, {e^{(k-1)-n}_bf}, v_brf,
3820          e^{i}_bl, f^{n*(k-1)+(k-1)-i}_b, e^{(k-1)-i}_br,
3821          v_blb, {e_bb}, v_brb,
3822 
3823          Middle Slice (j)
3824          {e^{(k-1)-j}_lf}, {f^{j*(k-1)+n}_f}, e^j_rf,
3825          f^{i*(k-1)+j}_l, {c^{(j*(k-1) + i)*(k-1)+n}_t}, f^{j*(k-1)+i}_r,
3826          e^j_lb, {f^{j*(k-1)+(k-1)-n}_b}, e^{(k-1)-j}_rb,
3827 
3828          Top Slice
3829          v_tlf, {e_tf}, v_trf,
3830          e^{(k-1)-i}_tl, {f^{i*(k-1)}_t}, e^{i}_tr,
3831          v_tlb, {e^{(k-1)-n}_tb}, v_trb,
3832       */
3833       {
3834         const PetscInt oc    = 0;
3835         const PetscInt ofb   = oc    + PetscSqr(k-1)*(k-1);
3836         const PetscInt oft   = ofb   + PetscSqr(k-1);
3837         const PetscInt off   = oft   + PetscSqr(k-1);
3838         const PetscInt ofk   = off   + PetscSqr(k-1);
3839         const PetscInt ofr   = ofk   + PetscSqr(k-1);
3840         const PetscInt ofl   = ofr   + PetscSqr(k-1);
3841         const PetscInt oebl  = ofl   + PetscSqr(k-1);
3842         const PetscInt oebb  = oebl  + (k-1);
3843         const PetscInt oebr  = oebb  + (k-1);
3844         const PetscInt oebf  = oebr  + (k-1);
3845         const PetscInt oetf  = oebf  + (k-1);
3846         const PetscInt oetr  = oetf  + (k-1);
3847         const PetscInt oetb  = oetr  + (k-1);
3848         const PetscInt oetl  = oetb  + (k-1);
3849         const PetscInt oerf  = oetl  + (k-1);
3850         const PetscInt oelf  = oerf  + (k-1);
3851         const PetscInt oelb  = oelf  + (k-1);
3852         const PetscInt oerb  = oelb  + (k-1);
3853         const PetscInt ovblf = oerb  + (k-1);
3854         const PetscInt ovblb = ovblf + 1;
3855         const PetscInt ovbrb = ovblb + 1;
3856         const PetscInt ovbrf = ovbrb + 1;
3857         const PetscInt ovtlf = ovbrf + 1;
3858         const PetscInt ovtrf = ovtlf + 1;
3859         const PetscInt ovtrb = ovtrf + 1;
3860         const PetscInt ovtlb = ovtrb + 1;
3861         PetscInt       o, n;
3862 
3863         /* Bottom Slice */
3864         /*   bottom */
3865         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblf*Nc + c + foffset;
3866         for (o = oetf-1; o >= oebf; --o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
3867         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrf*Nc + c + foffset;
3868         /*   middle */
3869         for (i = 0; i < k-1; ++i) {
3870           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebl+i)*Nc + c + foffset;
3871           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;}
3872           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebr+(k-2)-i)*Nc + c + foffset;
3873         }
3874         /*   top */
3875         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblb*Nc + c + foffset;
3876         for (o = oebb; o < oebr; ++o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
3877         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrb*Nc + c + foffset;
3878 
3879         /* Middle Slice */
3880         for (j = 0; j < k-1; ++j) {
3881           /*   bottom */
3882           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelf+(k-2)-j)*Nc + c + foffset;
3883           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;
3884           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerf+j)*Nc + c + foffset;
3885           /*   middle */
3886           for (i = 0; i < k-1; ++i) {
3887             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofl+i*(k-1)+j)*Nc + c + foffset;
3888             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;
3889             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofr+j*(k-1)+i)*Nc + c + foffset;
3890           }
3891           /*   top */
3892           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelb+j)*Nc + c + foffset;
3893           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;
3894           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerb+(k-2)-j)*Nc + c + foffset;
3895         }
3896 
3897         /* Top Slice */
3898         /*   bottom */
3899         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlf*Nc + c + foffset;
3900         for (o = oetf; o < oetr; ++o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
3901         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrf*Nc + c + foffset;
3902         /*   middle */
3903         for (i = 0; i < k-1; ++i) {
3904           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetl+(k-2)-i)*Nc + c + foffset;
3905           for (n = 0; n < k-1; ++n) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oft+i*(k-1)+n)*Nc + c + foffset;
3906           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetr+i)*Nc + c + foffset;
3907         }
3908         /*   top */
3909         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlb*Nc + c + foffset;
3910         for (o = oetl-1; o >= oetb; --o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
3911         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrb*Nc + c + foffset;
3912 
3913         foffset = offset;
3914       }
3915       break;
3916     default: SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_OUTOFRANGE, "No spectral ordering for dimension %D", dim);
3917     }
3918   }
3919   if (offset != size) SETERRQ2(PetscObjectComm((PetscObject) dm), PETSC_ERR_PLIB, "Number of permutation entries %D != %D", offset, size);
3920   /* Check permutation */
3921   {
3922     PetscInt *check;
3923 
3924     ierr = PetscMalloc1(size, &check);CHKERRQ(ierr);
3925     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]);}
3926     for (i = 0; i < size; ++i) check[perm[i]] = i;
3927     for (i = 0; i < size; ++i) {if (check[i] < 0) SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_PLIB, "Missing permutation index %D", i);}
3928     ierr = PetscFree(check);CHKERRQ(ierr);
3929   }
3930   ierr = PetscSectionSetClosurePermutation_Internal(section, (PetscObject) dm, size, PETSC_OWN_POINTER, perm);CHKERRQ(ierr);
3931   PetscFunctionReturn(0);
3932 }
3933 
3934 PetscErrorCode DMPlexGetPointDualSpaceFEM(DM dm, PetscInt point, PetscInt field, PetscDualSpace *dspace)
3935 {
3936   PetscDS        prob;
3937   PetscInt       depth, Nf, h;
3938   DMLabel        label;
3939   PetscErrorCode ierr;
3940 
3941   PetscFunctionBeginHot;
3942   ierr = DMGetDS(dm, &prob);CHKERRQ(ierr);
3943   Nf      = prob->Nf;
3944   label   = dm->depthLabel;
3945   *dspace = NULL;
3946   if (field < Nf) {
3947     PetscObject disc = prob->disc[field];
3948 
3949     if (disc->classid == PETSCFE_CLASSID) {
3950       PetscDualSpace dsp;
3951 
3952       ierr = PetscFEGetDualSpace((PetscFE)disc,&dsp);CHKERRQ(ierr);
3953       ierr = DMLabelGetNumValues(label,&depth);CHKERRQ(ierr);
3954       ierr = DMLabelGetValue(label,point,&h);CHKERRQ(ierr);
3955       h    = depth - 1 - h;
3956       if (h) {
3957         ierr = PetscDualSpaceGetHeightSubspace(dsp,h,dspace);CHKERRQ(ierr);
3958       } else {
3959         *dspace = dsp;
3960       }
3961     }
3962   }
3963   PetscFunctionReturn(0);
3964 }
3965 
3966 
3967 PETSC_STATIC_INLINE PetscErrorCode DMPlexVecGetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[])
3968 {
3969   PetscScalar    *array, *vArray;
3970   const PetscInt *cone, *coneO;
3971   PetscInt        pStart, pEnd, p, numPoints, size = 0, offset = 0;
3972   PetscErrorCode  ierr;
3973 
3974   PetscFunctionBeginHot;
3975   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
3976   ierr = DMPlexGetConeSize(dm, point, &numPoints);CHKERRQ(ierr);
3977   ierr = DMPlexGetCone(dm, point, &cone);CHKERRQ(ierr);
3978   ierr = DMPlexGetConeOrientation(dm, point, &coneO);CHKERRQ(ierr);
3979   if (!values || !*values) {
3980     if ((point >= pStart) && (point < pEnd)) {
3981       PetscInt dof;
3982 
3983       ierr = PetscSectionGetDof(section, point, &dof);CHKERRQ(ierr);
3984       size += dof;
3985     }
3986     for (p = 0; p < numPoints; ++p) {
3987       const PetscInt cp = cone[p];
3988       PetscInt       dof;
3989 
3990       if ((cp < pStart) || (cp >= pEnd)) continue;
3991       ierr = PetscSectionGetDof(section, cp, &dof);CHKERRQ(ierr);
3992       size += dof;
3993     }
3994     if (!values) {
3995       if (csize) *csize = size;
3996       PetscFunctionReturn(0);
3997     }
3998     ierr = DMGetWorkArray(dm, size, MPIU_SCALAR, &array);CHKERRQ(ierr);
3999   } else {
4000     array = *values;
4001   }
4002   size = 0;
4003   ierr = VecGetArray(v, &vArray);CHKERRQ(ierr);
4004   if ((point >= pStart) && (point < pEnd)) {
4005     PetscInt     dof, off, d;
4006     PetscScalar *varr;
4007 
4008     ierr = PetscSectionGetDof(section, point, &dof);CHKERRQ(ierr);
4009     ierr = PetscSectionGetOffset(section, point, &off);CHKERRQ(ierr);
4010     varr = &vArray[off];
4011     for (d = 0; d < dof; ++d, ++offset) {
4012       array[offset] = varr[d];
4013     }
4014     size += dof;
4015   }
4016   for (p = 0; p < numPoints; ++p) {
4017     const PetscInt cp = cone[p];
4018     PetscInt       o  = coneO[p];
4019     PetscInt       dof, off, d;
4020     PetscScalar   *varr;
4021 
4022     if ((cp < pStart) || (cp >= pEnd)) continue;
4023     ierr = PetscSectionGetDof(section, cp, &dof);CHKERRQ(ierr);
4024     ierr = PetscSectionGetOffset(section, cp, &off);CHKERRQ(ierr);
4025     varr = &vArray[off];
4026     if (o >= 0) {
4027       for (d = 0; d < dof; ++d, ++offset) {
4028         array[offset] = varr[d];
4029       }
4030     } else {
4031       for (d = dof-1; d >= 0; --d, ++offset) {
4032         array[offset] = varr[d];
4033       }
4034     }
4035     size += dof;
4036   }
4037   ierr = VecRestoreArray(v, &vArray);CHKERRQ(ierr);
4038   if (!*values) {
4039     if (csize) *csize = size;
4040     *values = array;
4041   } else {
4042     if (size > *csize) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %D < actual size %D", *csize, size);
4043     *csize = size;
4044   }
4045   PetscFunctionReturn(0);
4046 }
4047 
4048 PetscErrorCode DMPlexGetCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp)
4049 {
4050   const PetscInt *cla;
4051   PetscInt       np, *pts = NULL;
4052   PetscErrorCode ierr;
4053 
4054   PetscFunctionBeginHot;
4055   ierr = PetscSectionGetClosureIndex(section, (PetscObject) dm, clSec, clPoints);CHKERRQ(ierr);
4056   if (!*clPoints) {
4057     PetscInt pStart, pEnd, p, q;
4058 
4059     ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
4060     ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &np, &pts);CHKERRQ(ierr);
4061     /* Compress out points not in the section */
4062     for (p = 0, q = 0; p < np; p++) {
4063       PetscInt r = pts[2*p];
4064       if ((r >= pStart) && (r < pEnd)) {
4065         pts[q*2]   = r;
4066         pts[q*2+1] = pts[2*p+1];
4067         ++q;
4068       }
4069     }
4070     np = q;
4071     cla = NULL;
4072   } else {
4073     PetscInt dof, off;
4074 
4075     ierr = PetscSectionGetDof(*clSec, point, &dof);CHKERRQ(ierr);
4076     ierr = PetscSectionGetOffset(*clSec, point, &off);CHKERRQ(ierr);
4077     ierr = ISGetIndices(*clPoints, &cla);CHKERRQ(ierr);
4078     np   = dof/2;
4079     pts  = (PetscInt *) &cla[off];
4080   }
4081   *numPoints = np;
4082   *points    = pts;
4083   *clp       = cla;
4084 
4085   PetscFunctionReturn(0);
4086 }
4087 
4088 PetscErrorCode DMPlexRestoreCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp)
4089 {
4090   PetscErrorCode ierr;
4091 
4092   PetscFunctionBeginHot;
4093   if (!*clPoints) {
4094     ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, numPoints, points);CHKERRQ(ierr);
4095   } else {
4096     ierr = ISRestoreIndices(*clPoints, clp);CHKERRQ(ierr);
4097   }
4098   *numPoints = 0;
4099   *points    = NULL;
4100   *clSec     = NULL;
4101   *clPoints  = NULL;
4102   *clp       = NULL;
4103   PetscFunctionReturn(0);
4104 }
4105 
4106 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[])
4107 {
4108   PetscInt          offset = 0, p;
4109   const PetscInt    **perms = NULL;
4110   const PetscScalar **flips = NULL;
4111   PetscErrorCode    ierr;
4112 
4113   PetscFunctionBeginHot;
4114   *size = 0;
4115   ierr = PetscSectionGetPointSyms(section,numPoints,points,&perms,&flips);CHKERRQ(ierr);
4116   for (p = 0; p < numPoints; p++) {
4117     const PetscInt    point = points[2*p];
4118     const PetscInt    *perm = perms ? perms[p] : NULL;
4119     const PetscScalar *flip = flips ? flips[p] : NULL;
4120     PetscInt          dof, off, d;
4121     const PetscScalar *varr;
4122 
4123     ierr = PetscSectionGetDof(section, point, &dof);CHKERRQ(ierr);
4124     ierr = PetscSectionGetOffset(section, point, &off);CHKERRQ(ierr);
4125     varr = &vArray[off];
4126     if (clperm) {
4127       if (perm) {
4128         for (d = 0; d < dof; d++) array[clperm[offset + perm[d]]]  = varr[d];
4129       } else {
4130         for (d = 0; d < dof; d++) array[clperm[offset +      d ]]  = varr[d];
4131       }
4132       if (flip) {
4133         for (d = 0; d < dof; d++) array[clperm[offset +      d ]] *= flip[d];
4134       }
4135     } else {
4136       if (perm) {
4137         for (d = 0; d < dof; d++) array[offset + perm[d]]  = varr[d];
4138       } else {
4139         for (d = 0; d < dof; d++) array[offset +      d ]  = varr[d];
4140       }
4141       if (flip) {
4142         for (d = 0; d < dof; d++) array[offset +      d ] *= flip[d];
4143       }
4144     }
4145     offset += dof;
4146   }
4147   ierr = PetscSectionRestorePointSyms(section,numPoints,points,&perms,&flips);CHKERRQ(ierr);
4148   *size = offset;
4149   PetscFunctionReturn(0);
4150 }
4151 
4152 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[])
4153 {
4154   PetscInt          offset = 0, f;
4155   PetscErrorCode    ierr;
4156 
4157   PetscFunctionBeginHot;
4158   *size = 0;
4159   for (f = 0; f < numFields; ++f) {
4160     PetscInt          p;
4161     const PetscInt    **perms = NULL;
4162     const PetscScalar **flips = NULL;
4163 
4164     ierr = PetscSectionGetFieldPointSyms(section,f,numPoints,points,&perms,&flips);CHKERRQ(ierr);
4165     for (p = 0; p < numPoints; p++) {
4166       const PetscInt    point = points[2*p];
4167       PetscInt          fdof, foff, b;
4168       const PetscScalar *varr;
4169       const PetscInt    *perm = perms ? perms[p] : NULL;
4170       const PetscScalar *flip = flips ? flips[p] : NULL;
4171 
4172       ierr = PetscSectionGetFieldDof(section, point, f, &fdof);CHKERRQ(ierr);
4173       ierr = PetscSectionGetFieldOffset(section, point, f, &foff);CHKERRQ(ierr);
4174       varr = &vArray[foff];
4175       if (clperm) {
4176         if (perm) {for (b = 0; b < fdof; b++) {array[clperm[offset + perm[b]]]  = varr[b];}}
4177         else      {for (b = 0; b < fdof; b++) {array[clperm[offset +      b ]]  = varr[b];}}
4178         if (flip) {for (b = 0; b < fdof; b++) {array[clperm[offset +      b ]] *= flip[b];}}
4179       } else {
4180         if (perm) {for (b = 0; b < fdof; b++) {array[offset + perm[b]]  = varr[b];}}
4181         else      {for (b = 0; b < fdof; b++) {array[offset +      b ]  = varr[b];}}
4182         if (flip) {for (b = 0; b < fdof; b++) {array[offset +      b ] *= flip[b];}}
4183       }
4184       offset += fdof;
4185     }
4186     ierr = PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms,&flips);CHKERRQ(ierr);
4187   }
4188   *size = offset;
4189   PetscFunctionReturn(0);
4190 }
4191 
4192 /*@C
4193   DMPlexVecGetClosure - Get an array of the values on the closure of 'point'
4194 
4195   Not collective
4196 
4197   Input Parameters:
4198 + dm - The DM
4199 . section - The section describing the layout in v, or NULL to use the default section
4200 . v - The local vector
4201 . point - The point in the DM
4202 . csize - The size of the input values array, or NULL
4203 - values - An array to use for the values, or NULL to have it allocated automatically
4204 
4205   Output Parameters:
4206 + csize - The number of values in the closure
4207 - values - The array of values. If the user provided NULL, it is a borrowed array and should not be freed
4208 
4209 $ Note that DMPlexVecGetClosure/DMPlexVecRestoreClosure only allocates the values array if it set to NULL in the
4210 $ calling function. This is because DMPlexVecGetClosure() is typically called in the inner loop of a Vec or Mat
4211 $ assembly function, and a user may already have allocated storage for this operation.
4212 $
4213 $ A typical use could be
4214 $
4215 $  values = NULL;
4216 $  ierr = DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values);CHKERRQ(ierr);
4217 $  for (cl = 0; cl < clSize; ++cl) {
4218 $    <Compute on closure>
4219 $  }
4220 $  ierr = DMPlexVecRestoreClosure(dm, NULL, v, p, &clSize, &values);CHKERRQ(ierr);
4221 $
4222 $ or
4223 $
4224 $  PetscMalloc1(clMaxSize, &values);
4225 $  for (p = pStart; p < pEnd; ++p) {
4226 $    clSize = clMaxSize;
4227 $    ierr = DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values);CHKERRQ(ierr);
4228 $    for (cl = 0; cl < clSize; ++cl) {
4229 $      <Compute on closure>
4230 $    }
4231 $  }
4232 $  PetscFree(values);
4233 
4234   Fortran Notes:
4235   Since it returns an array, this routine is only available in Fortran 90, and you must
4236   include petsc.h90 in your code.
4237 
4238   The csize argument is not present in the Fortran 90 binding since it is internal to the array.
4239 
4240   Level: intermediate
4241 
4242 .seealso DMPlexVecRestoreClosure(), DMPlexVecSetClosure(), DMPlexMatSetClosure()
4243 @*/
4244 PetscErrorCode DMPlexVecGetClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[])
4245 {
4246   PetscSection       clSection;
4247   IS                 clPoints;
4248   PetscScalar       *array;
4249   const PetscScalar *vArray;
4250   PetscInt          *points = NULL;
4251   const PetscInt    *clp, *perm;
4252   PetscInt           depth, numFields, numPoints, size;
4253   PetscErrorCode     ierr;
4254 
4255   PetscFunctionBeginHot;
4256   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4257   if (!section) {ierr = DMGetSection(dm, &section);CHKERRQ(ierr);}
4258   PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2);
4259   PetscValidHeaderSpecific(v, VEC_CLASSID, 3);
4260   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
4261   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
4262   if (depth == 1 && numFields < 2) {
4263     ierr = DMPlexVecGetClosure_Depth1_Static(dm, section, v, point, csize, values);CHKERRQ(ierr);
4264     PetscFunctionReturn(0);
4265   }
4266   /* Get points */
4267   ierr = DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);CHKERRQ(ierr);
4268   ierr = PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject) dm, NULL, &perm);CHKERRQ(ierr);
4269   /* Get array */
4270   if (!values || !*values) {
4271     PetscInt asize = 0, dof, p;
4272 
4273     for (p = 0; p < numPoints*2; p += 2) {
4274       ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
4275       asize += dof;
4276     }
4277     if (!values) {
4278       ierr = DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);CHKERRQ(ierr);
4279       if (csize) *csize = asize;
4280       PetscFunctionReturn(0);
4281     }
4282     ierr = DMGetWorkArray(dm, asize, MPIU_SCALAR, &array);CHKERRQ(ierr);
4283   } else {
4284     array = *values;
4285   }
4286   ierr = VecGetArrayRead(v, &vArray);CHKERRQ(ierr);
4287   /* Get values */
4288   if (numFields > 0) {ierr = DMPlexVecGetClosure_Fields_Static(dm, section, numPoints, points, numFields, perm, vArray, &size, array);CHKERRQ(ierr);}
4289   else               {ierr = DMPlexVecGetClosure_Static(dm, section, numPoints, points, perm, vArray, &size, array);CHKERRQ(ierr);}
4290   /* Cleanup points */
4291   ierr = DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);CHKERRQ(ierr);
4292   /* Cleanup array */
4293   ierr = VecRestoreArrayRead(v, &vArray);CHKERRQ(ierr);
4294   if (!*values) {
4295     if (csize) *csize = size;
4296     *values = array;
4297   } else {
4298     if (size > *csize) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %D < actual size %D", *csize, size);
4299     *csize = size;
4300   }
4301   PetscFunctionReturn(0);
4302 }
4303 
4304 /*@C
4305   DMPlexVecRestoreClosure - Restore the array of the values on the closure of 'point'
4306 
4307   Not collective
4308 
4309   Input Parameters:
4310 + dm - The DM
4311 . section - The section describing the layout in v, or NULL to use the default section
4312 . v - The local vector
4313 . point - The point in the DM
4314 . csize - The number of values in the closure, or NULL
4315 - values - The array of values, which is a borrowed array and should not be freed
4316 
4317   Note that the array values are discarded and not copied back into v. In order to copy values back to v, use DMPlexVecSetClosure()
4318 
4319   Fortran Notes:
4320   Since it returns an array, this routine is only available in Fortran 90, and you must
4321   include petsc.h90 in your code.
4322 
4323   The csize argument is not present in the Fortran 90 binding since it is internal to the array.
4324 
4325   Level: intermediate
4326 
4327 .seealso DMPlexVecGetClosure(), DMPlexVecSetClosure(), DMPlexMatSetClosure()
4328 @*/
4329 PetscErrorCode DMPlexVecRestoreClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[])
4330 {
4331   PetscInt       size = 0;
4332   PetscErrorCode ierr;
4333 
4334   PetscFunctionBegin;
4335   /* Should work without recalculating size */
4336   ierr = DMRestoreWorkArray(dm, size, MPIU_SCALAR, (void*) values);CHKERRQ(ierr);
4337   *values = NULL;
4338   PetscFunctionReturn(0);
4339 }
4340 
4341 PETSC_STATIC_INLINE void add   (PetscScalar *x, PetscScalar y) {*x += y;}
4342 PETSC_STATIC_INLINE void insert(PetscScalar *x, PetscScalar y) {*x  = y;}
4343 
4344 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[])
4345 {
4346   PetscInt        cdof;   /* The number of constraints on this point */
4347   const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
4348   PetscScalar    *a;
4349   PetscInt        off, cind = 0, k;
4350   PetscErrorCode  ierr;
4351 
4352   PetscFunctionBegin;
4353   ierr = PetscSectionGetConstraintDof(section, point, &cdof);CHKERRQ(ierr);
4354   ierr = PetscSectionGetOffset(section, point, &off);CHKERRQ(ierr);
4355   a    = &array[off];
4356   if (!cdof || setBC) {
4357     if (clperm) {
4358       if (perm) {for (k = 0; k < dof; ++k) {fuse(&a[k], values[clperm[offset+perm[k]]] * (flip ? flip[perm[k]] : 1.));}}
4359       else      {for (k = 0; k < dof; ++k) {fuse(&a[k], values[clperm[offset+     k ]] * (flip ? flip[     k ] : 1.));}}
4360     } else {
4361       if (perm) {for (k = 0; k < dof; ++k) {fuse(&a[k], values[offset+perm[k]] * (flip ? flip[perm[k]] : 1.));}}
4362       else      {for (k = 0; k < dof; ++k) {fuse(&a[k], values[offset+     k ] * (flip ? flip[     k ] : 1.));}}
4363     }
4364   } else {
4365     ierr = PetscSectionGetConstraintIndices(section, point, &cdofs);CHKERRQ(ierr);
4366     if (clperm) {
4367       if (perm) {for (k = 0; k < dof; ++k) {
4368           if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
4369           fuse(&a[k], values[clperm[offset+perm[k]]] * (flip ? flip[perm[k]] : 1.));
4370         }
4371       } else {
4372         for (k = 0; k < dof; ++k) {
4373           if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
4374           fuse(&a[k], values[clperm[offset+     k ]] * (flip ? flip[     k ] : 1.));
4375         }
4376       }
4377     } else {
4378       if (perm) {
4379         for (k = 0; k < dof; ++k) {
4380           if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
4381           fuse(&a[k], values[offset+perm[k]] * (flip ? flip[perm[k]] : 1.));
4382         }
4383       } else {
4384         for (k = 0; k < dof; ++k) {
4385           if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
4386           fuse(&a[k], values[offset+     k ] * (flip ? flip[     k ] : 1.));
4387         }
4388       }
4389     }
4390   }
4391   PetscFunctionReturn(0);
4392 }
4393 
4394 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[])
4395 {
4396   PetscInt        cdof;   /* The number of constraints on this point */
4397   const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
4398   PetscScalar    *a;
4399   PetscInt        off, cind = 0, k;
4400   PetscErrorCode  ierr;
4401 
4402   PetscFunctionBegin;
4403   ierr = PetscSectionGetConstraintDof(section, point, &cdof);CHKERRQ(ierr);
4404   ierr = PetscSectionGetOffset(section, point, &off);CHKERRQ(ierr);
4405   a    = &array[off];
4406   if (cdof) {
4407     ierr = PetscSectionGetConstraintIndices(section, point, &cdofs);CHKERRQ(ierr);
4408     if (clperm) {
4409       if (perm) {
4410         for (k = 0; k < dof; ++k) {
4411           if ((cind < cdof) && (k == cdofs[cind])) {
4412             fuse(&a[k], values[clperm[offset+perm[k]]] * (flip ? flip[perm[k]] : 1.));
4413             cind++;
4414           }
4415         }
4416       } else {
4417         for (k = 0; k < dof; ++k) {
4418           if ((cind < cdof) && (k == cdofs[cind])) {
4419             fuse(&a[k], values[clperm[offset+     k ]] * (flip ? flip[     k ] : 1.));
4420             cind++;
4421           }
4422         }
4423       }
4424     } else {
4425       if (perm) {
4426         for (k = 0; k < dof; ++k) {
4427           if ((cind < cdof) && (k == cdofs[cind])) {
4428             fuse(&a[k], values[offset+perm[k]] * (flip ? flip[perm[k]] : 1.));
4429             cind++;
4430           }
4431         }
4432       } else {
4433         for (k = 0; k < dof; ++k) {
4434           if ((cind < cdof) && (k == cdofs[cind])) {
4435             fuse(&a[k], values[offset+     k ] * (flip ? flip[     k ] : 1.));
4436             cind++;
4437           }
4438         }
4439       }
4440     }
4441   }
4442   PetscFunctionReturn(0);
4443 }
4444 
4445 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[])
4446 {
4447   PetscScalar    *a;
4448   PetscInt        fdof, foff, fcdof, foffset = *offset;
4449   const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
4450   PetscInt        cind = 0, b;
4451   PetscErrorCode  ierr;
4452 
4453   PetscFunctionBegin;
4454   ierr = PetscSectionGetFieldDof(section, point, f, &fdof);CHKERRQ(ierr);
4455   ierr = PetscSectionGetFieldConstraintDof(section, point, f, &fcdof);CHKERRQ(ierr);
4456   ierr = PetscSectionGetFieldOffset(section, point, f, &foff);CHKERRQ(ierr);
4457   a    = &array[foff];
4458   if (!fcdof || setBC) {
4459     if (clperm) {
4460       if (perm) {for (b = 0; b < fdof; b++) {fuse(&a[b], values[clperm[foffset+perm[b]]] * (flip ? flip[perm[b]] : 1.));}}
4461       else      {for (b = 0; b < fdof; b++) {fuse(&a[b], values[clperm[foffset+     b ]] * (flip ? flip[     b ] : 1.));}}
4462     } else {
4463       if (perm) {for (b = 0; b < fdof; b++) {fuse(&a[b], values[foffset+perm[b]] * (flip ? flip[perm[b]] : 1.));}}
4464       else      {for (b = 0; b < fdof; b++) {fuse(&a[b], values[foffset+     b ] * (flip ? flip[     b ] : 1.));}}
4465     }
4466   } else {
4467     ierr = PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);CHKERRQ(ierr);
4468     if (clperm) {
4469       if (perm) {
4470         for (b = 0; b < fdof; b++) {
4471           if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; continue;}
4472           fuse(&a[b], values[clperm[foffset+perm[b]]] * (flip ? flip[perm[b]] : 1.));
4473         }
4474       } else {
4475         for (b = 0; b < fdof; b++) {
4476           if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; continue;}
4477           fuse(&a[b], values[clperm[foffset+     b ]] * (flip ? flip[     b ] : 1.));
4478         }
4479       }
4480     } else {
4481       if (perm) {
4482         for (b = 0; b < fdof; b++) {
4483           if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; continue;}
4484           fuse(&a[b], values[foffset+perm[b]] * (flip ? flip[perm[b]] : 1.));
4485         }
4486       } else {
4487         for (b = 0; b < fdof; b++) {
4488           if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; continue;}
4489           fuse(&a[b], values[foffset+     b ] * (flip ? flip[     b ] : 1.));
4490         }
4491       }
4492     }
4493   }
4494   *offset += fdof;
4495   PetscFunctionReturn(0);
4496 }
4497 
4498 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[])
4499 {
4500   PetscScalar    *a;
4501   PetscInt        fdof, foff, fcdof, foffset = *offset;
4502   const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
4503   PetscInt        cind = 0, ncind = 0, b;
4504   PetscBool       ncSet, fcSet;
4505   PetscErrorCode  ierr;
4506 
4507   PetscFunctionBegin;
4508   ierr = PetscSectionGetFieldDof(section, point, f, &fdof);CHKERRQ(ierr);
4509   ierr = PetscSectionGetFieldConstraintDof(section, point, f, &fcdof);CHKERRQ(ierr);
4510   ierr = PetscSectionGetFieldOffset(section, point, f, &foff);CHKERRQ(ierr);
4511   a    = &array[foff];
4512   if (fcdof) {
4513     /* We just override fcdof and fcdofs with Ncc and comps */
4514     ierr = PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);CHKERRQ(ierr);
4515     if (clperm) {
4516       if (perm) {
4517         if (comps) {
4518           for (b = 0; b < fdof; b++) {
4519             ncSet = fcSet = PETSC_FALSE;
4520             if ((ncind < Ncc)  && (b == comps[ncind])) {++ncind; ncSet = PETSC_TRUE;}
4521             if ((cind < fcdof) && (b == fcdofs[cind])) {++cind;  fcSet = PETSC_TRUE;}
4522             if (ncSet && fcSet) {fuse(&a[b], values[clperm[foffset+perm[b]]] * (flip ? flip[perm[b]] : 1.));}
4523           }
4524         } else {
4525           for (b = 0; b < fdof; b++) {
4526             if ((cind < fcdof) && (b == fcdofs[cind])) {
4527               fuse(&a[b], values[clperm[foffset+perm[b]]] * (flip ? flip[perm[b]] : 1.));
4528               ++cind;
4529             }
4530           }
4531         }
4532       } else {
4533         if (comps) {
4534           for (b = 0; b < fdof; b++) {
4535             ncSet = fcSet = PETSC_FALSE;
4536             if ((ncind < Ncc)  && (b == comps[ncind])) {++ncind; ncSet = PETSC_TRUE;}
4537             if ((cind < fcdof) && (b == fcdofs[cind])) {++cind;  fcSet = PETSC_TRUE;}
4538             if (ncSet && fcSet) {fuse(&a[b], values[clperm[foffset+     b ]] * (flip ? flip[     b ] : 1.));}
4539           }
4540         } else {
4541           for (b = 0; b < fdof; b++) {
4542             if ((cind < fcdof) && (b == fcdofs[cind])) {
4543               fuse(&a[b], values[clperm[foffset+     b ]] * (flip ? flip[     b ] : 1.));
4544               ++cind;
4545             }
4546           }
4547         }
4548       }
4549     } else {
4550       if (perm) {
4551         if (comps) {
4552           for (b = 0; b < fdof; b++) {
4553             ncSet = fcSet = PETSC_FALSE;
4554             if ((ncind < Ncc)  && (b == comps[ncind])) {++ncind; ncSet = PETSC_TRUE;}
4555             if ((cind < fcdof) && (b == fcdofs[cind])) {++cind;  fcSet = PETSC_TRUE;}
4556             if (ncSet && fcSet) {fuse(&a[b], values[foffset+perm[b]] * (flip ? flip[perm[b]] : 1.));}
4557           }
4558         } else {
4559           for (b = 0; b < fdof; b++) {
4560             if ((cind < fcdof) && (b == fcdofs[cind])) {
4561               fuse(&a[b], values[foffset+perm[b]] * (flip ? flip[perm[b]] : 1.));
4562               ++cind;
4563             }
4564           }
4565         }
4566       } else {
4567         if (comps) {
4568           for (b = 0; b < fdof; b++) {
4569             ncSet = fcSet = PETSC_FALSE;
4570             if ((ncind < Ncc)  && (b == comps[ncind])) {++ncind; ncSet = PETSC_TRUE;}
4571             if ((cind < fcdof) && (b == fcdofs[cind])) {++cind;  fcSet = PETSC_TRUE;}
4572             if (ncSet && fcSet) {fuse(&a[b], values[foffset+     b ] * (flip ? flip[     b ] : 1.));}
4573           }
4574         } else {
4575           for (b = 0; b < fdof; b++) {
4576             if ((cind < fcdof) && (b == fcdofs[cind])) {
4577               fuse(&a[b], values[foffset+     b ] * (flip ? flip[     b ] : 1.));
4578               ++cind;
4579             }
4580           }
4581         }
4582       }
4583     }
4584   }
4585   *offset += fdof;
4586   PetscFunctionReturn(0);
4587 }
4588 
4589 PETSC_STATIC_INLINE PetscErrorCode DMPlexVecSetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode)
4590 {
4591   PetscScalar    *array;
4592   const PetscInt *cone, *coneO;
4593   PetscInt        pStart, pEnd, p, numPoints, off, dof;
4594   PetscErrorCode  ierr;
4595 
4596   PetscFunctionBeginHot;
4597   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
4598   ierr = DMPlexGetConeSize(dm, point, &numPoints);CHKERRQ(ierr);
4599   ierr = DMPlexGetCone(dm, point, &cone);CHKERRQ(ierr);
4600   ierr = DMPlexGetConeOrientation(dm, point, &coneO);CHKERRQ(ierr);
4601   ierr = VecGetArray(v, &array);CHKERRQ(ierr);
4602   for (p = 0, off = 0; p <= numPoints; ++p, off += dof) {
4603     const PetscInt cp = !p ? point : cone[p-1];
4604     const PetscInt o  = !p ? 0     : coneO[p-1];
4605 
4606     if ((cp < pStart) || (cp >= pEnd)) {dof = 0; continue;}
4607     ierr = PetscSectionGetDof(section, cp, &dof);CHKERRQ(ierr);
4608     /* ADD_VALUES */
4609     {
4610       const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
4611       PetscScalar    *a;
4612       PetscInt        cdof, coff, cind = 0, k;
4613 
4614       ierr = PetscSectionGetConstraintDof(section, cp, &cdof);CHKERRQ(ierr);
4615       ierr = PetscSectionGetOffset(section, cp, &coff);CHKERRQ(ierr);
4616       a    = &array[coff];
4617       if (!cdof) {
4618         if (o >= 0) {
4619           for (k = 0; k < dof; ++k) {
4620             a[k] += values[off+k];
4621           }
4622         } else {
4623           for (k = 0; k < dof; ++k) {
4624             a[k] += values[off+dof-k-1];
4625           }
4626         }
4627       } else {
4628         ierr = PetscSectionGetConstraintIndices(section, cp, &cdofs);CHKERRQ(ierr);
4629         if (o >= 0) {
4630           for (k = 0; k < dof; ++k) {
4631             if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
4632             a[k] += values[off+k];
4633           }
4634         } else {
4635           for (k = 0; k < dof; ++k) {
4636             if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
4637             a[k] += values[off+dof-k-1];
4638           }
4639         }
4640       }
4641     }
4642   }
4643   ierr = VecRestoreArray(v, &array);CHKERRQ(ierr);
4644   PetscFunctionReturn(0);
4645 }
4646 
4647 /*@C
4648   DMPlexVecSetClosure - Set an array of the values on the closure of 'point'
4649 
4650   Not collective
4651 
4652   Input Parameters:
4653 + dm - The DM
4654 . section - The section describing the layout in v, or NULL to use the default section
4655 . v - The local vector
4656 . point - The point in the DM
4657 . values - The array of values
4658 - mode - The insert mode. One of INSERT_ALL_VALUES, ADD_ALL_VALUES, INSERT_VALUES, ADD_VALUES, INSERT_BC_VALUES, and ADD_BC_VALUES,
4659          where INSERT_ALL_VALUES and ADD_ALL_VALUES also overwrite boundary conditions.
4660 
4661   Fortran Notes:
4662   This routine is only available in Fortran 90, and you must include petsc.h90 in your code.
4663 
4664   Level: intermediate
4665 
4666 .seealso DMPlexVecGetClosure(), DMPlexMatSetClosure()
4667 @*/
4668 PetscErrorCode DMPlexVecSetClosure(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode)
4669 {
4670   PetscSection    clSection;
4671   IS              clPoints;
4672   PetscScalar    *array;
4673   PetscInt       *points = NULL;
4674   const PetscInt *clp, *clperm;
4675   PetscInt        depth, numFields, numPoints, p;
4676   PetscErrorCode  ierr;
4677 
4678   PetscFunctionBeginHot;
4679   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4680   if (!section) {ierr = DMGetSection(dm, &section);CHKERRQ(ierr);}
4681   PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2);
4682   PetscValidHeaderSpecific(v, VEC_CLASSID, 3);
4683   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
4684   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
4685   if (depth == 1 && numFields < 2 && mode == ADD_VALUES) {
4686     ierr = DMPlexVecSetClosure_Depth1_Static(dm, section, v, point, values, mode);CHKERRQ(ierr);
4687     PetscFunctionReturn(0);
4688   }
4689   /* Get points */
4690   ierr = PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject) dm, NULL, &clperm);CHKERRQ(ierr);
4691   ierr = DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);CHKERRQ(ierr);
4692   /* Get array */
4693   ierr = VecGetArray(v, &array);CHKERRQ(ierr);
4694   /* Get values */
4695   if (numFields > 0) {
4696     PetscInt offset = 0, f;
4697     for (f = 0; f < numFields; ++f) {
4698       const PetscInt    **perms = NULL;
4699       const PetscScalar **flips = NULL;
4700 
4701       ierr = PetscSectionGetFieldPointSyms(section,f,numPoints,points,&perms,&flips);CHKERRQ(ierr);
4702       switch (mode) {
4703       case INSERT_VALUES:
4704         for (p = 0; p < numPoints; p++) {
4705           const PetscInt    point = points[2*p];
4706           const PetscInt    *perm = perms ? perms[p] : NULL;
4707           const PetscScalar *flip = flips ? flips[p] : NULL;
4708           updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, clperm, values, &offset, array);
4709         } break;
4710       case INSERT_ALL_VALUES:
4711         for (p = 0; p < numPoints; p++) {
4712           const PetscInt    point = points[2*p];
4713           const PetscInt    *perm = perms ? perms[p] : NULL;
4714           const PetscScalar *flip = flips ? flips[p] : NULL;
4715           updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, clperm, values, &offset, array);
4716         } break;
4717       case INSERT_BC_VALUES:
4718         for (p = 0; p < numPoints; p++) {
4719           const PetscInt    point = points[2*p];
4720           const PetscInt    *perm = perms ? perms[p] : NULL;
4721           const PetscScalar *flip = flips ? flips[p] : NULL;
4722           updatePointFieldsBC_private(section, point, perm, flip, f, -1, NULL, insert, clperm, values, &offset, array);
4723         } break;
4724       case ADD_VALUES:
4725         for (p = 0; p < numPoints; p++) {
4726           const PetscInt    point = points[2*p];
4727           const PetscInt    *perm = perms ? perms[p] : NULL;
4728           const PetscScalar *flip = flips ? flips[p] : NULL;
4729           updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, clperm, values, &offset, array);
4730         } break;
4731       case ADD_ALL_VALUES:
4732         for (p = 0; p < numPoints; p++) {
4733           const PetscInt    point = points[2*p];
4734           const PetscInt    *perm = perms ? perms[p] : NULL;
4735           const PetscScalar *flip = flips ? flips[p] : NULL;
4736           updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, clperm, values, &offset, array);
4737         } break;
4738       case ADD_BC_VALUES:
4739         for (p = 0; p < numPoints; p++) {
4740           const PetscInt    point = points[2*p];
4741           const PetscInt    *perm = perms ? perms[p] : NULL;
4742           const PetscScalar *flip = flips ? flips[p] : NULL;
4743           updatePointFieldsBC_private(section, point, perm, flip, f, -1, NULL, add, clperm, values, &offset, array);
4744         } break;
4745       default:
4746         SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode);
4747       }
4748       ierr = PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms,&flips);CHKERRQ(ierr);
4749     }
4750   } else {
4751     PetscInt dof, off;
4752     const PetscInt    **perms = NULL;
4753     const PetscScalar **flips = NULL;
4754 
4755     ierr = PetscSectionGetPointSyms(section,numPoints,points,&perms,&flips);CHKERRQ(ierr);
4756     switch (mode) {
4757     case INSERT_VALUES:
4758       for (p = 0, off = 0; p < numPoints; p++, off += dof) {
4759         const PetscInt    point = points[2*p];
4760         const PetscInt    *perm = perms ? perms[p] : NULL;
4761         const PetscScalar *flip = flips ? flips[p] : NULL;
4762         ierr = PetscSectionGetDof(section, point, &dof);CHKERRQ(ierr);
4763         updatePoint_private(section, point, dof, insert, PETSC_FALSE, perm, flip, clperm, values, off, array);
4764       } break;
4765     case INSERT_ALL_VALUES:
4766       for (p = 0, off = 0; p < numPoints; p++, off += dof) {
4767         const PetscInt    point = points[2*p];
4768         const PetscInt    *perm = perms ? perms[p] : NULL;
4769         const PetscScalar *flip = flips ? flips[p] : NULL;
4770         ierr = PetscSectionGetDof(section, point, &dof);CHKERRQ(ierr);
4771         updatePoint_private(section, point, dof, insert, PETSC_TRUE,  perm, flip, clperm, values, off, array);
4772       } break;
4773     case INSERT_BC_VALUES:
4774       for (p = 0, off = 0; p < numPoints; p++, off += dof) {
4775         const PetscInt    point = points[2*p];
4776         const PetscInt    *perm = perms ? perms[p] : NULL;
4777         const PetscScalar *flip = flips ? flips[p] : NULL;
4778         ierr = PetscSectionGetDof(section, point, &dof);CHKERRQ(ierr);
4779         updatePointBC_private(section, point, dof, insert,  perm, flip, clperm, values, off, array);
4780       } break;
4781     case ADD_VALUES:
4782       for (p = 0, off = 0; p < numPoints; p++, off += dof) {
4783         const PetscInt    point = points[2*p];
4784         const PetscInt    *perm = perms ? perms[p] : NULL;
4785         const PetscScalar *flip = flips ? flips[p] : NULL;
4786         ierr = PetscSectionGetDof(section, point, &dof);CHKERRQ(ierr);
4787         updatePoint_private(section, point, dof, add,    PETSC_FALSE, perm, flip, clperm, values, off, array);
4788       } break;
4789     case ADD_ALL_VALUES:
4790       for (p = 0, off = 0; p < numPoints; p++, off += dof) {
4791         const PetscInt    point = points[2*p];
4792         const PetscInt    *perm = perms ? perms[p] : NULL;
4793         const PetscScalar *flip = flips ? flips[p] : NULL;
4794         ierr = PetscSectionGetDof(section, point, &dof);CHKERRQ(ierr);
4795         updatePoint_private(section, point, dof, add,    PETSC_TRUE,  perm, flip, clperm, values, off, array);
4796       } break;
4797     case ADD_BC_VALUES:
4798       for (p = 0, off = 0; p < numPoints; p++, off += dof) {
4799         const PetscInt    point = points[2*p];
4800         const PetscInt    *perm = perms ? perms[p] : NULL;
4801         const PetscScalar *flip = flips ? flips[p] : NULL;
4802         ierr = PetscSectionGetDof(section, point, &dof);CHKERRQ(ierr);
4803         updatePointBC_private(section, point, dof, add,  perm, flip, clperm, values, off, array);
4804       } break;
4805     default:
4806       SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode);
4807     }
4808     ierr = PetscSectionRestorePointSyms(section,numPoints,points,&perms,&flips);CHKERRQ(ierr);
4809   }
4810   /* Cleanup points */
4811   ierr = DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);CHKERRQ(ierr);
4812   /* Cleanup array */
4813   ierr = VecRestoreArray(v, &array);CHKERRQ(ierr);
4814   PetscFunctionReturn(0);
4815 }
4816 
4817 PetscErrorCode DMPlexVecSetFieldClosure_Internal(DM dm, PetscSection section, Vec v, PetscBool fieldActive[], PetscInt point, PetscInt Ncc, const PetscInt comps[], const PetscScalar values[], InsertMode mode)
4818 {
4819   PetscSection      clSection;
4820   IS                clPoints;
4821   PetscScalar       *array;
4822   PetscInt          *points = NULL;
4823   const PetscInt    *clp, *clperm;
4824   PetscInt          numFields, numPoints, p;
4825   PetscInt          offset = 0, f;
4826   PetscErrorCode    ierr;
4827 
4828   PetscFunctionBeginHot;
4829   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4830   if (!section) {ierr = DMGetSection(dm, &section);CHKERRQ(ierr);}
4831   PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2);
4832   PetscValidHeaderSpecific(v, VEC_CLASSID, 3);
4833   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
4834   /* Get points */
4835   ierr = PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject) dm, NULL, &clperm);CHKERRQ(ierr);
4836   ierr = DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);CHKERRQ(ierr);
4837   /* Get array */
4838   ierr = VecGetArray(v, &array);CHKERRQ(ierr);
4839   /* Get values */
4840   for (f = 0; f < numFields; ++f) {
4841     const PetscInt    **perms = NULL;
4842     const PetscScalar **flips = NULL;
4843 
4844     if (!fieldActive[f]) {
4845       for (p = 0; p < numPoints*2; p += 2) {
4846         PetscInt fdof;
4847         ierr = PetscSectionGetFieldDof(section, points[p], f, &fdof);CHKERRQ(ierr);
4848         offset += fdof;
4849       }
4850       continue;
4851     }
4852     ierr = PetscSectionGetFieldPointSyms(section,f,numPoints,points,&perms,&flips);CHKERRQ(ierr);
4853     switch (mode) {
4854     case INSERT_VALUES:
4855       for (p = 0; p < numPoints; p++) {
4856         const PetscInt    point = points[2*p];
4857         const PetscInt    *perm = perms ? perms[p] : NULL;
4858         const PetscScalar *flip = flips ? flips[p] : NULL;
4859         updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, clperm, values, &offset, array);
4860       } break;
4861     case INSERT_ALL_VALUES:
4862       for (p = 0; p < numPoints; p++) {
4863         const PetscInt    point = points[2*p];
4864         const PetscInt    *perm = perms ? perms[p] : NULL;
4865         const PetscScalar *flip = flips ? flips[p] : NULL;
4866         updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, clperm, values, &offset, array);
4867         } break;
4868     case INSERT_BC_VALUES:
4869       for (p = 0; p < numPoints; p++) {
4870         const PetscInt    point = points[2*p];
4871         const PetscInt    *perm = perms ? perms[p] : NULL;
4872         const PetscScalar *flip = flips ? flips[p] : NULL;
4873         updatePointFieldsBC_private(section, point, perm, flip, f, Ncc, comps, insert, clperm, values, &offset, array);
4874       } break;
4875     case ADD_VALUES:
4876       for (p = 0; p < numPoints; p++) {
4877         const PetscInt    point = points[2*p];
4878         const PetscInt    *perm = perms ? perms[p] : NULL;
4879         const PetscScalar *flip = flips ? flips[p] : NULL;
4880         updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, clperm, values, &offset, array);
4881       } break;
4882     case ADD_ALL_VALUES:
4883       for (p = 0; p < numPoints; p++) {
4884         const PetscInt    point = points[2*p];
4885         const PetscInt    *perm = perms ? perms[p] : NULL;
4886         const PetscScalar *flip = flips ? flips[p] : NULL;
4887         updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, clperm, values, &offset, array);
4888       } break;
4889     default:
4890       SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode);
4891     }
4892     ierr = PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms,&flips);CHKERRQ(ierr);
4893   }
4894   /* Cleanup points */
4895   ierr = DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);CHKERRQ(ierr);
4896   /* Cleanup array */
4897   ierr = VecRestoreArray(v, &array);CHKERRQ(ierr);
4898   PetscFunctionReturn(0);
4899 }
4900 
4901 static PetscErrorCode DMPlexPrintMatSetValues(PetscViewer viewer, Mat A, PetscInt point, PetscInt numRIndices, const PetscInt rindices[], PetscInt numCIndices, const PetscInt cindices[], const PetscScalar values[])
4902 {
4903   PetscMPIInt    rank;
4904   PetscInt       i, j;
4905   PetscErrorCode ierr;
4906 
4907   PetscFunctionBegin;
4908   ierr = MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank);CHKERRQ(ierr);
4909   ierr = PetscViewerASCIIPrintf(viewer, "[%d]mat for point %D\n", rank, point);CHKERRQ(ierr);
4910   for (i = 0; i < numRIndices; i++) {ierr = PetscViewerASCIIPrintf(viewer, "[%d]mat row indices[%D] = %D\n", rank, i, rindices[i]);CHKERRQ(ierr);}
4911   for (i = 0; i < numCIndices; i++) {ierr = PetscViewerASCIIPrintf(viewer, "[%d]mat col indices[%D] = %D\n", rank, i, cindices[i]);CHKERRQ(ierr);}
4912   numCIndices = numCIndices ? numCIndices : numRIndices;
4913   for (i = 0; i < numRIndices; i++) {
4914     ierr = PetscViewerASCIIPrintf(viewer, "[%d]", rank);CHKERRQ(ierr);
4915     for (j = 0; j < numCIndices; j++) {
4916 #if defined(PETSC_USE_COMPLEX)
4917       ierr = PetscViewerASCIIPrintf(viewer, " (%g,%g)", (double)PetscRealPart(values[i*numCIndices+j]), (double)PetscImaginaryPart(values[i*numCIndices+j]));CHKERRQ(ierr);
4918 #else
4919       ierr = PetscViewerASCIIPrintf(viewer, " %g", (double)values[i*numCIndices+j]);CHKERRQ(ierr);
4920 #endif
4921     }
4922     ierr = PetscViewerASCIIPrintf(viewer, "\n");CHKERRQ(ierr);
4923   }
4924   PetscFunctionReturn(0);
4925 }
4926 
4927 /*
4928   DMPlexGetIndicesPoint_Internal - Add the indices for dofs on a point to an index array
4929 
4930   Input Parameters:
4931 + section - The section for this data layout
4932 . point   - The point contributing dofs with these indices
4933 . off     - The global offset of this point
4934 . loff    - The local offset of each field
4935 . setBC   - The flag determining whether to include indices of bounsary values
4936 . perm    - A permutation of the dofs on this point, or NULL
4937 - indperm - A permutation of the entire indices array, or NULL
4938 
4939   Output Parameter:
4940 . indices - Indices for dofs on this point
4941 
4942   Level: developer
4943 
4944   Note: The indices could be local or global, depending on the value of 'off'.
4945 */
4946 PetscErrorCode DMPlexGetIndicesPoint_Internal(PetscSection section, PetscInt point, PetscInt off, PetscInt *loff, PetscBool setBC, const PetscInt perm[], const PetscInt indperm[], PetscInt indices[])
4947 {
4948   PetscInt        dof;   /* The number of unknowns on this point */
4949   PetscInt        cdof;  /* The number of constraints on this point */
4950   const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
4951   PetscInt        cind = 0, k;
4952   PetscErrorCode  ierr;
4953 
4954   PetscFunctionBegin;
4955   ierr = PetscSectionGetDof(section, point, &dof);CHKERRQ(ierr);
4956   ierr = PetscSectionGetConstraintDof(section, point, &cdof);CHKERRQ(ierr);
4957   if (!cdof || setBC) {
4958     for (k = 0; k < dof; ++k) {
4959       const PetscInt preind = perm ? *loff+perm[k] : *loff+k;
4960       const PetscInt ind    = indperm ? indperm[preind] : preind;
4961 
4962       indices[ind] = off + k;
4963     }
4964   } else {
4965     ierr = PetscSectionGetConstraintIndices(section, point, &cdofs);CHKERRQ(ierr);
4966     for (k = 0; k < dof; ++k) {
4967       const PetscInt preind = perm ? *loff+perm[k] : *loff+k;
4968       const PetscInt ind    = indperm ? indperm[preind] : preind;
4969 
4970       if ((cind < cdof) && (k == cdofs[cind])) {
4971         /* Insert check for returning constrained indices */
4972         indices[ind] = -(off+k+1);
4973         ++cind;
4974       } else {
4975         indices[ind] = off+k-cind;
4976       }
4977     }
4978   }
4979   *loff += dof;
4980   PetscFunctionReturn(0);
4981 }
4982 
4983 /*
4984   This version only believes the point offset from the globalSection
4985 
4986  . off - The global offset of this point
4987 */
4988 PetscErrorCode DMPlexGetIndicesPointFields_Internal(PetscSection section, PetscInt point, PetscInt off, PetscInt foffs[], PetscBool setBC, const PetscInt ***perms, PetscInt permsoff, const PetscInt indperm[], PetscInt indices[])
4989 {
4990   PetscInt       numFields, foff, f;
4991   PetscErrorCode ierr;
4992 
4993   PetscFunctionBegin;
4994   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
4995   for (f = 0, foff = 0; f < numFields; ++f) {
4996     PetscInt        fdof, cfdof;
4997     const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
4998     PetscInt        cind = 0, b;
4999     const PetscInt  *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL;
5000 
5001     ierr = PetscSectionGetFieldDof(section, point, f, &fdof);CHKERRQ(ierr);
5002     ierr = PetscSectionGetFieldConstraintDof(section, point, f, &cfdof);CHKERRQ(ierr);
5003     if (!cfdof || setBC) {
5004       for (b = 0; b < fdof; ++b) {
5005         const PetscInt preind = perm ? foffs[f]+perm[b] : foffs[f]+b;
5006         const PetscInt ind    = indperm ? indperm[preind] : preind;
5007 
5008         indices[ind] = off+foff+b;
5009       }
5010     } else {
5011       ierr = PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);CHKERRQ(ierr);
5012       for (b = 0; b < fdof; ++b) {
5013         const PetscInt preind = perm ? foffs[f]+perm[b] : foffs[f]+b;
5014         const PetscInt ind    = indperm ? indperm[preind] : preind;
5015 
5016         if ((cind < cfdof) && (b == fcdofs[cind])) {
5017           indices[ind] = -(off+foff+b+1);
5018           ++cind;
5019         } else {
5020           indices[ind] = off+foff+b-cind;
5021         }
5022       }
5023     }
5024     foff     += (setBC ? fdof : (fdof - cfdof));
5025     foffs[f] += fdof;
5026   }
5027   PetscFunctionReturn(0);
5028 }
5029 
5030 /*
5031   This version believes the globalSection offsets for each field, rather than just the point offset
5032 
5033  . foffs - The offset into 'indices' for each field, since it is segregated by field
5034 */
5035 PetscErrorCode DMPlexGetIndicesPointFieldsSplit_Internal(PetscSection section, PetscSection globalSection, PetscInt point, PetscInt foffs[], PetscBool setBC, const PetscInt ***perms, PetscInt permsoff, const PetscInt indperm[], PetscInt indices[])
5036 {
5037   PetscInt       numFields, foff, f;
5038   PetscErrorCode ierr;
5039 
5040   PetscFunctionBegin;
5041   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
5042   for (f = 0; f < numFields; ++f) {
5043     PetscInt        fdof, cfdof;
5044     const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
5045     PetscInt        cind = 0, b;
5046     const PetscInt  *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL;
5047 
5048     ierr = PetscSectionGetFieldDof(section, point, f, &fdof);CHKERRQ(ierr);
5049     ierr = PetscSectionGetFieldConstraintDof(section, point, f, &cfdof);CHKERRQ(ierr);
5050     ierr = PetscSectionGetFieldOffset(globalSection, point, f, &foff);CHKERRQ(ierr);
5051     if (!cfdof || setBC) {
5052       for (b = 0; b < fdof; ++b) {
5053         const PetscInt preind = perm ? foffs[f]+perm[b] : foffs[f]+b;
5054         const PetscInt ind    = indperm ? indperm[preind] : preind;
5055 
5056         indices[ind] = foff+b;
5057       }
5058     } else {
5059       ierr = PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);CHKERRQ(ierr);
5060       for (b = 0; b < fdof; ++b) {
5061         const PetscInt preind = perm ? foffs[f]+perm[b] : foffs[f]+b;
5062         const PetscInt ind    = indperm ? indperm[preind] : preind;
5063 
5064         if ((cind < cfdof) && (b == fcdofs[cind])) {
5065           indices[ind] = -(foff+b+1);
5066           ++cind;
5067         } else {
5068           indices[ind] = foff+b-cind;
5069         }
5070       }
5071     }
5072     foffs[f] += fdof;
5073   }
5074   PetscFunctionReturn(0);
5075 }
5076 
5077 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)
5078 {
5079   Mat             cMat;
5080   PetscSection    aSec, cSec;
5081   IS              aIS;
5082   PetscInt        aStart = -1, aEnd = -1;
5083   const PetscInt  *anchors;
5084   PetscInt        numFields, f, p, q, newP = 0;
5085   PetscInt        newNumPoints = 0, newNumIndices = 0;
5086   PetscInt        *newPoints, *indices, *newIndices;
5087   PetscInt        maxAnchor, maxDof;
5088   PetscInt        newOffsets[32];
5089   PetscInt        *pointMatOffsets[32];
5090   PetscInt        *newPointOffsets[32];
5091   PetscScalar     *pointMat[32];
5092   PetscScalar     *newValues=NULL,*tmpValues;
5093   PetscBool       anyConstrained = PETSC_FALSE;
5094   PetscErrorCode  ierr;
5095 
5096   PetscFunctionBegin;
5097   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5098   PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2);
5099   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
5100 
5101   ierr = DMPlexGetAnchors(dm,&aSec,&aIS);CHKERRQ(ierr);
5102   /* if there are point-to-point constraints */
5103   if (aSec) {
5104     ierr = PetscArrayzero(newOffsets, 32);CHKERRQ(ierr);
5105     ierr = ISGetIndices(aIS,&anchors);CHKERRQ(ierr);
5106     ierr = PetscSectionGetChart(aSec,&aStart,&aEnd);CHKERRQ(ierr);
5107     /* figure out how many points are going to be in the new element matrix
5108      * (we allow double counting, because it's all just going to be summed
5109      * into the global matrix anyway) */
5110     for (p = 0; p < 2*numPoints; p+=2) {
5111       PetscInt b    = points[p];
5112       PetscInt bDof = 0, bSecDof;
5113 
5114       ierr = PetscSectionGetDof(section,b,&bSecDof);CHKERRQ(ierr);
5115       if (!bSecDof) {
5116         continue;
5117       }
5118       if (b >= aStart && b < aEnd) {
5119         ierr = PetscSectionGetDof(aSec,b,&bDof);CHKERRQ(ierr);
5120       }
5121       if (bDof) {
5122         /* this point is constrained */
5123         /* it is going to be replaced by its anchors */
5124         PetscInt bOff, q;
5125 
5126         anyConstrained = PETSC_TRUE;
5127         newNumPoints  += bDof;
5128         ierr = PetscSectionGetOffset(aSec,b,&bOff);CHKERRQ(ierr);
5129         for (q = 0; q < bDof; q++) {
5130           PetscInt a = anchors[bOff + q];
5131           PetscInt aDof;
5132 
5133           ierr           = PetscSectionGetDof(section,a,&aDof);CHKERRQ(ierr);
5134           newNumIndices += aDof;
5135           for (f = 0; f < numFields; ++f) {
5136             PetscInt fDof;
5137 
5138             ierr             = PetscSectionGetFieldDof(section, a, f, &fDof);CHKERRQ(ierr);
5139             newOffsets[f+1] += fDof;
5140           }
5141         }
5142       }
5143       else {
5144         /* this point is not constrained */
5145         newNumPoints++;
5146         newNumIndices += bSecDof;
5147         for (f = 0; f < numFields; ++f) {
5148           PetscInt fDof;
5149 
5150           ierr = PetscSectionGetFieldDof(section, b, f, &fDof);CHKERRQ(ierr);
5151           newOffsets[f+1] += fDof;
5152         }
5153       }
5154     }
5155   }
5156   if (!anyConstrained) {
5157     if (outNumPoints)  *outNumPoints  = 0;
5158     if (outNumIndices) *outNumIndices = 0;
5159     if (outPoints)     *outPoints     = NULL;
5160     if (outValues)     *outValues     = NULL;
5161     if (aSec) {ierr = ISRestoreIndices(aIS,&anchors);CHKERRQ(ierr);}
5162     PetscFunctionReturn(0);
5163   }
5164 
5165   if (outNumPoints)  *outNumPoints  = newNumPoints;
5166   if (outNumIndices) *outNumIndices = newNumIndices;
5167 
5168   for (f = 0; f < numFields; ++f) newOffsets[f+1] += newOffsets[f];
5169 
5170   if (!outPoints && !outValues) {
5171     if (offsets) {
5172       for (f = 0; f <= numFields; f++) {
5173         offsets[f] = newOffsets[f];
5174       }
5175     }
5176     if (aSec) {ierr = ISRestoreIndices(aIS,&anchors);CHKERRQ(ierr);}
5177     PetscFunctionReturn(0);
5178   }
5179 
5180   if (numFields && newOffsets[numFields] != newNumIndices) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid size for closure %D should be %D", newOffsets[numFields], newNumIndices);
5181 
5182   ierr = DMGetDefaultConstraints(dm, &cSec, &cMat);CHKERRQ(ierr);
5183 
5184   /* workspaces */
5185   if (numFields) {
5186     for (f = 0; f < numFields; f++) {
5187       ierr = DMGetWorkArray(dm,numPoints+1,MPIU_INT,&pointMatOffsets[f]);CHKERRQ(ierr);
5188       ierr = DMGetWorkArray(dm,numPoints+1,MPIU_INT,&newPointOffsets[f]);CHKERRQ(ierr);
5189     }
5190   }
5191   else {
5192     ierr = DMGetWorkArray(dm,numPoints+1,MPIU_INT,&pointMatOffsets[0]);CHKERRQ(ierr);
5193     ierr = DMGetWorkArray(dm,numPoints,MPIU_INT,&newPointOffsets[0]);CHKERRQ(ierr);
5194   }
5195 
5196   /* get workspaces for the point-to-point matrices */
5197   if (numFields) {
5198     PetscInt totalOffset, totalMatOffset;
5199 
5200     for (p = 0; p < numPoints; p++) {
5201       PetscInt b    = points[2*p];
5202       PetscInt bDof = 0, bSecDof;
5203 
5204       ierr = PetscSectionGetDof(section,b,&bSecDof);CHKERRQ(ierr);
5205       if (!bSecDof) {
5206         for (f = 0; f < numFields; f++) {
5207           newPointOffsets[f][p + 1] = 0;
5208           pointMatOffsets[f][p + 1] = 0;
5209         }
5210         continue;
5211       }
5212       if (b >= aStart && b < aEnd) {
5213         ierr = PetscSectionGetDof(aSec, b, &bDof);CHKERRQ(ierr);
5214       }
5215       if (bDof) {
5216         for (f = 0; f < numFields; f++) {
5217           PetscInt fDof, q, bOff, allFDof = 0;
5218 
5219           ierr = PetscSectionGetFieldDof(section, b, f, &fDof);CHKERRQ(ierr);
5220           ierr = PetscSectionGetOffset(aSec, b, &bOff);CHKERRQ(ierr);
5221           for (q = 0; q < bDof; q++) {
5222             PetscInt a = anchors[bOff + q];
5223             PetscInt aFDof;
5224 
5225             ierr     = PetscSectionGetFieldDof(section, a, f, &aFDof);CHKERRQ(ierr);
5226             allFDof += aFDof;
5227           }
5228           newPointOffsets[f][p+1] = allFDof;
5229           pointMatOffsets[f][p+1] = fDof * allFDof;
5230         }
5231       }
5232       else {
5233         for (f = 0; f < numFields; f++) {
5234           PetscInt fDof;
5235 
5236           ierr = PetscSectionGetFieldDof(section, b, f, &fDof);CHKERRQ(ierr);
5237           newPointOffsets[f][p+1] = fDof;
5238           pointMatOffsets[f][p+1] = 0;
5239         }
5240       }
5241     }
5242     for (f = 0, totalOffset = 0, totalMatOffset = 0; f < numFields; f++) {
5243       newPointOffsets[f][0] = totalOffset;
5244       pointMatOffsets[f][0] = totalMatOffset;
5245       for (p = 0; p < numPoints; p++) {
5246         newPointOffsets[f][p+1] += newPointOffsets[f][p];
5247         pointMatOffsets[f][p+1] += pointMatOffsets[f][p];
5248       }
5249       totalOffset    = newPointOffsets[f][numPoints];
5250       totalMatOffset = pointMatOffsets[f][numPoints];
5251       ierr = DMGetWorkArray(dm,pointMatOffsets[f][numPoints],MPIU_SCALAR,&pointMat[f]);CHKERRQ(ierr);
5252     }
5253   }
5254   else {
5255     for (p = 0; p < numPoints; p++) {
5256       PetscInt b    = points[2*p];
5257       PetscInt bDof = 0, bSecDof;
5258 
5259       ierr = PetscSectionGetDof(section,b,&bSecDof);CHKERRQ(ierr);
5260       if (!bSecDof) {
5261         newPointOffsets[0][p + 1] = 0;
5262         pointMatOffsets[0][p + 1] = 0;
5263         continue;
5264       }
5265       if (b >= aStart && b < aEnd) {
5266         ierr = PetscSectionGetDof(aSec, b, &bDof);CHKERRQ(ierr);
5267       }
5268       if (bDof) {
5269         PetscInt bOff, q, allDof = 0;
5270 
5271         ierr = PetscSectionGetOffset(aSec, b, &bOff);CHKERRQ(ierr);
5272         for (q = 0; q < bDof; q++) {
5273           PetscInt a = anchors[bOff + q], aDof;
5274 
5275           ierr    = PetscSectionGetDof(section, a, &aDof);CHKERRQ(ierr);
5276           allDof += aDof;
5277         }
5278         newPointOffsets[0][p+1] = allDof;
5279         pointMatOffsets[0][p+1] = bSecDof * allDof;
5280       }
5281       else {
5282         newPointOffsets[0][p+1] = bSecDof;
5283         pointMatOffsets[0][p+1] = 0;
5284       }
5285     }
5286     newPointOffsets[0][0] = 0;
5287     pointMatOffsets[0][0] = 0;
5288     for (p = 0; p < numPoints; p++) {
5289       newPointOffsets[0][p+1] += newPointOffsets[0][p];
5290       pointMatOffsets[0][p+1] += pointMatOffsets[0][p];
5291     }
5292     ierr = DMGetWorkArray(dm,pointMatOffsets[0][numPoints],MPIU_SCALAR,&pointMat[0]);CHKERRQ(ierr);
5293   }
5294 
5295   /* output arrays */
5296   ierr = DMGetWorkArray(dm,2*newNumPoints,MPIU_INT,&newPoints);CHKERRQ(ierr);
5297 
5298   /* get the point-to-point matrices; construct newPoints */
5299   ierr = PetscSectionGetMaxDof(aSec, &maxAnchor);CHKERRQ(ierr);
5300   ierr = PetscSectionGetMaxDof(section, &maxDof);CHKERRQ(ierr);
5301   ierr = DMGetWorkArray(dm,maxDof,MPIU_INT,&indices);CHKERRQ(ierr);
5302   ierr = DMGetWorkArray(dm,maxAnchor*maxDof,MPIU_INT,&newIndices);CHKERRQ(ierr);
5303   if (numFields) {
5304     for (p = 0, newP = 0; p < numPoints; p++) {
5305       PetscInt b    = points[2*p];
5306       PetscInt o    = points[2*p+1];
5307       PetscInt bDof = 0, bSecDof;
5308 
5309       ierr = PetscSectionGetDof(section, b, &bSecDof);CHKERRQ(ierr);
5310       if (!bSecDof) {
5311         continue;
5312       }
5313       if (b >= aStart && b < aEnd) {
5314         ierr = PetscSectionGetDof(aSec, b, &bDof);CHKERRQ(ierr);
5315       }
5316       if (bDof) {
5317         PetscInt fStart[32], fEnd[32], fAnchorStart[32], fAnchorEnd[32], bOff, q;
5318 
5319         fStart[0] = 0;
5320         fEnd[0]   = 0;
5321         for (f = 0; f < numFields; f++) {
5322           PetscInt fDof;
5323 
5324           ierr        = PetscSectionGetFieldDof(cSec, b, f, &fDof);CHKERRQ(ierr);
5325           fStart[f+1] = fStart[f] + fDof;
5326           fEnd[f+1]   = fStart[f+1];
5327         }
5328         ierr = PetscSectionGetOffset(cSec, b, &bOff);CHKERRQ(ierr);
5329         ierr = DMPlexGetIndicesPointFields_Internal(cSec, b, bOff, fEnd, PETSC_TRUE, perms, p, NULL, indices);CHKERRQ(ierr);
5330 
5331         fAnchorStart[0] = 0;
5332         fAnchorEnd[0]   = 0;
5333         for (f = 0; f < numFields; f++) {
5334           PetscInt fDof = newPointOffsets[f][p + 1] - newPointOffsets[f][p];
5335 
5336           fAnchorStart[f+1] = fAnchorStart[f] + fDof;
5337           fAnchorEnd[f+1]   = fAnchorStart[f + 1];
5338         }
5339         ierr = PetscSectionGetOffset(aSec, b, &bOff);CHKERRQ(ierr);
5340         for (q = 0; q < bDof; q++) {
5341           PetscInt a = anchors[bOff + q], aOff;
5342 
5343           /* we take the orientation of ap into account in the order that we constructed the indices above: the newly added points have no orientation */
5344           newPoints[2*(newP + q)]     = a;
5345           newPoints[2*(newP + q) + 1] = 0;
5346           ierr = PetscSectionGetOffset(section, a, &aOff);CHKERRQ(ierr);
5347           ierr = DMPlexGetIndicesPointFields_Internal(section, a, aOff, fAnchorEnd, PETSC_TRUE, NULL, -1, NULL, newIndices);CHKERRQ(ierr);
5348         }
5349         newP += bDof;
5350 
5351         if (outValues) {
5352           /* get the point-to-point submatrix */
5353           for (f = 0; f < numFields; f++) {
5354             ierr = MatGetValues(cMat,fEnd[f]-fStart[f],indices + fStart[f],fAnchorEnd[f] - fAnchorStart[f],newIndices + fAnchorStart[f],pointMat[f] + pointMatOffsets[f][p]);CHKERRQ(ierr);
5355           }
5356         }
5357       }
5358       else {
5359         newPoints[2 * newP]     = b;
5360         newPoints[2 * newP + 1] = o;
5361         newP++;
5362       }
5363     }
5364   } else {
5365     for (p = 0; p < numPoints; p++) {
5366       PetscInt b    = points[2*p];
5367       PetscInt o    = points[2*p+1];
5368       PetscInt bDof = 0, bSecDof;
5369 
5370       ierr = PetscSectionGetDof(section, b, &bSecDof);CHKERRQ(ierr);
5371       if (!bSecDof) {
5372         continue;
5373       }
5374       if (b >= aStart && b < aEnd) {
5375         ierr = PetscSectionGetDof(aSec, b, &bDof);CHKERRQ(ierr);
5376       }
5377       if (bDof) {
5378         PetscInt bEnd = 0, bAnchorEnd = 0, bOff;
5379 
5380         ierr = PetscSectionGetOffset(cSec, b, &bOff);CHKERRQ(ierr);
5381         ierr = DMPlexGetIndicesPoint_Internal(cSec, b, bOff, &bEnd, PETSC_TRUE, (perms && perms[0]) ? perms[0][p] : NULL, NULL, indices);CHKERRQ(ierr);
5382 
5383         ierr = PetscSectionGetOffset (aSec, b, &bOff);CHKERRQ(ierr);
5384         for (q = 0; q < bDof; q++) {
5385           PetscInt a = anchors[bOff + q], aOff;
5386 
5387           /* we take the orientation of ap into account in the order that we constructed the indices above: the newly added points have no orientation */
5388 
5389           newPoints[2*(newP + q)]     = a;
5390           newPoints[2*(newP + q) + 1] = 0;
5391           ierr = PetscSectionGetOffset(section, a, &aOff);CHKERRQ(ierr);
5392           ierr = DMPlexGetIndicesPoint_Internal(section, a, aOff, &bAnchorEnd, PETSC_TRUE, NULL, NULL, newIndices);CHKERRQ(ierr);
5393         }
5394         newP += bDof;
5395 
5396         /* get the point-to-point submatrix */
5397         if (outValues) {
5398           ierr = MatGetValues(cMat,bEnd,indices,bAnchorEnd,newIndices,pointMat[0] + pointMatOffsets[0][p]);CHKERRQ(ierr);
5399         }
5400       }
5401       else {
5402         newPoints[2 * newP]     = b;
5403         newPoints[2 * newP + 1] = o;
5404         newP++;
5405       }
5406     }
5407   }
5408 
5409   if (outValues) {
5410     ierr = DMGetWorkArray(dm,newNumIndices*numIndices,MPIU_SCALAR,&tmpValues);CHKERRQ(ierr);
5411     ierr = PetscArrayzero(tmpValues,newNumIndices*numIndices);CHKERRQ(ierr);
5412     /* multiply constraints on the right */
5413     if (numFields) {
5414       for (f = 0; f < numFields; f++) {
5415         PetscInt oldOff = offsets[f];
5416 
5417         for (p = 0; p < numPoints; p++) {
5418           PetscInt cStart = newPointOffsets[f][p];
5419           PetscInt b      = points[2 * p];
5420           PetscInt c, r, k;
5421           PetscInt dof;
5422 
5423           ierr = PetscSectionGetFieldDof(section,b,f,&dof);CHKERRQ(ierr);
5424           if (!dof) {
5425             continue;
5426           }
5427           if (pointMatOffsets[f][p] < pointMatOffsets[f][p + 1]) {
5428             PetscInt nCols         = newPointOffsets[f][p+1]-cStart;
5429             const PetscScalar *mat = pointMat[f] + pointMatOffsets[f][p];
5430 
5431             for (r = 0; r < numIndices; r++) {
5432               for (c = 0; c < nCols; c++) {
5433                 for (k = 0; k < dof; k++) {
5434                   tmpValues[r * newNumIndices + cStart + c] += values[r * numIndices + oldOff + k] * mat[k * nCols + c];
5435                 }
5436               }
5437             }
5438           }
5439           else {
5440             /* copy this column as is */
5441             for (r = 0; r < numIndices; r++) {
5442               for (c = 0; c < dof; c++) {
5443                 tmpValues[r * newNumIndices + cStart + c] = values[r * numIndices + oldOff + c];
5444               }
5445             }
5446           }
5447           oldOff += dof;
5448         }
5449       }
5450     }
5451     else {
5452       PetscInt oldOff = 0;
5453       for (p = 0; p < numPoints; p++) {
5454         PetscInt cStart = newPointOffsets[0][p];
5455         PetscInt b      = points[2 * p];
5456         PetscInt c, r, k;
5457         PetscInt dof;
5458 
5459         ierr = PetscSectionGetDof(section,b,&dof);CHKERRQ(ierr);
5460         if (!dof) {
5461           continue;
5462         }
5463         if (pointMatOffsets[0][p] < pointMatOffsets[0][p + 1]) {
5464           PetscInt nCols         = newPointOffsets[0][p+1]-cStart;
5465           const PetscScalar *mat = pointMat[0] + pointMatOffsets[0][p];
5466 
5467           for (r = 0; r < numIndices; r++) {
5468             for (c = 0; c < nCols; c++) {
5469               for (k = 0; k < dof; k++) {
5470                 tmpValues[r * newNumIndices + cStart + c] += mat[k * nCols + c] * values[r * numIndices + oldOff + k];
5471               }
5472             }
5473           }
5474         }
5475         else {
5476           /* copy this column as is */
5477           for (r = 0; r < numIndices; r++) {
5478             for (c = 0; c < dof; c++) {
5479               tmpValues[r * newNumIndices + cStart + c] = values[r * numIndices + oldOff + c];
5480             }
5481           }
5482         }
5483         oldOff += dof;
5484       }
5485     }
5486 
5487     if (multiplyLeft) {
5488       ierr = DMGetWorkArray(dm,newNumIndices*newNumIndices,MPIU_SCALAR,&newValues);CHKERRQ(ierr);
5489       ierr = PetscArrayzero(newValues,newNumIndices*newNumIndices);CHKERRQ(ierr);
5490       /* multiply constraints transpose on the left */
5491       if (numFields) {
5492         for (f = 0; f < numFields; f++) {
5493           PetscInt oldOff = offsets[f];
5494 
5495           for (p = 0; p < numPoints; p++) {
5496             PetscInt rStart = newPointOffsets[f][p];
5497             PetscInt b      = points[2 * p];
5498             PetscInt c, r, k;
5499             PetscInt dof;
5500 
5501             ierr = PetscSectionGetFieldDof(section,b,f,&dof);CHKERRQ(ierr);
5502             if (pointMatOffsets[f][p] < pointMatOffsets[f][p + 1]) {
5503               PetscInt nRows                        = newPointOffsets[f][p+1]-rStart;
5504               const PetscScalar *PETSC_RESTRICT mat = pointMat[f] + pointMatOffsets[f][p];
5505 
5506               for (r = 0; r < nRows; r++) {
5507                 for (c = 0; c < newNumIndices; c++) {
5508                   for (k = 0; k < dof; k++) {
5509                     newValues[(rStart + r) * newNumIndices + c] += mat[k * nRows + r] * tmpValues[(oldOff + k) * newNumIndices + c];
5510                   }
5511                 }
5512               }
5513             }
5514             else {
5515               /* copy this row as is */
5516               for (r = 0; r < dof; r++) {
5517                 for (c = 0; c < newNumIndices; c++) {
5518                   newValues[(rStart + r) * newNumIndices + c] = tmpValues[(oldOff + r) * newNumIndices + c];
5519                 }
5520               }
5521             }
5522             oldOff += dof;
5523           }
5524         }
5525       }
5526       else {
5527         PetscInt oldOff = 0;
5528 
5529         for (p = 0; p < numPoints; p++) {
5530           PetscInt rStart = newPointOffsets[0][p];
5531           PetscInt b      = points[2 * p];
5532           PetscInt c, r, k;
5533           PetscInt dof;
5534 
5535           ierr = PetscSectionGetDof(section,b,&dof);CHKERRQ(ierr);
5536           if (pointMatOffsets[0][p] < pointMatOffsets[0][p + 1]) {
5537             PetscInt nRows                        = newPointOffsets[0][p+1]-rStart;
5538             const PetscScalar *PETSC_RESTRICT mat = pointMat[0] + pointMatOffsets[0][p];
5539 
5540             for (r = 0; r < nRows; r++) {
5541               for (c = 0; c < newNumIndices; c++) {
5542                 for (k = 0; k < dof; k++) {
5543                   newValues[(rStart + r) * newNumIndices + c] += mat[k * nRows + r] * tmpValues[(oldOff + k) * newNumIndices + c];
5544                 }
5545               }
5546             }
5547           }
5548           else {
5549             /* copy this row as is */
5550             for (r = 0; r < dof; r++) {
5551               for (c = 0; c < newNumIndices; c++) {
5552                 newValues[(rStart + r) * newNumIndices + c] = tmpValues[(oldOff + r) * newNumIndices + c];
5553               }
5554             }
5555           }
5556           oldOff += dof;
5557         }
5558       }
5559 
5560       ierr = DMRestoreWorkArray(dm,newNumIndices*numIndices,MPIU_SCALAR,&tmpValues);CHKERRQ(ierr);
5561     }
5562     else {
5563       newValues = tmpValues;
5564     }
5565   }
5566 
5567   /* clean up */
5568   ierr = DMRestoreWorkArray(dm,maxDof,MPIU_INT,&indices);CHKERRQ(ierr);
5569   ierr = DMRestoreWorkArray(dm,maxAnchor*maxDof,MPIU_INT,&newIndices);CHKERRQ(ierr);
5570 
5571   if (numFields) {
5572     for (f = 0; f < numFields; f++) {
5573       ierr = DMRestoreWorkArray(dm,pointMatOffsets[f][numPoints],MPIU_SCALAR,&pointMat[f]);CHKERRQ(ierr);
5574       ierr = DMRestoreWorkArray(dm,numPoints+1,MPIU_INT,&pointMatOffsets[f]);CHKERRQ(ierr);
5575       ierr = DMRestoreWorkArray(dm,numPoints+1,MPIU_INT,&newPointOffsets[f]);CHKERRQ(ierr);
5576     }
5577   }
5578   else {
5579     ierr = DMRestoreWorkArray(dm,pointMatOffsets[0][numPoints],MPIU_SCALAR,&pointMat[0]);CHKERRQ(ierr);
5580     ierr = DMRestoreWorkArray(dm,numPoints+1,MPIU_INT,&pointMatOffsets[0]);CHKERRQ(ierr);
5581     ierr = DMRestoreWorkArray(dm,numPoints+1,MPIU_INT,&newPointOffsets[0]);CHKERRQ(ierr);
5582   }
5583   ierr = ISRestoreIndices(aIS,&anchors);CHKERRQ(ierr);
5584 
5585   /* output */
5586   if (outPoints) {
5587     *outPoints = newPoints;
5588   }
5589   else {
5590     ierr = DMRestoreWorkArray(dm,2*newNumPoints,MPIU_INT,&newPoints);CHKERRQ(ierr);
5591   }
5592   if (outValues) {
5593     *outValues = newValues;
5594   }
5595   for (f = 0; f <= numFields; f++) {
5596     offsets[f] = newOffsets[f];
5597   }
5598   PetscFunctionReturn(0);
5599 }
5600 
5601 /*@C
5602   DMPlexGetClosureIndices - Get the global indices in a vector v for all points in the closure of the given point
5603 
5604   Not collective
5605 
5606   Input Parameters:
5607 + dm - The DM
5608 . section - The section describing the layout in v, or NULL to use the default section
5609 . globalSection - The section describing the parallel layout in v, or NULL to use the default section
5610 - point - The mesh point
5611 
5612   Output parameters:
5613 + numIndices - The number of indices
5614 . indices - The indices
5615 - outOffsets - Field offset if not NULL
5616 
5617   Note: Must call DMPlexRestoreClosureIndices() to free allocated memory
5618 
5619   Level: advanced
5620 
5621 .seealso DMPlexRestoreClosureIndices(), DMPlexVecGetClosure(), DMPlexMatSetClosure()
5622 @*/
5623 PetscErrorCode DMPlexGetClosureIndices(DM dm, PetscSection section, PetscSection globalSection, PetscInt point, PetscInt *numIndices, PetscInt **indices, PetscInt *outOffsets)
5624 {
5625   PetscSection    clSection;
5626   IS              clPoints;
5627   const PetscInt *clp, *clperm;
5628   const PetscInt  **perms[32] = {NULL};
5629   PetscInt       *points = NULL, *pointsNew;
5630   PetscInt        numPoints, numPointsNew;
5631   PetscInt        offsets[32];
5632   PetscInt        Nf, Nind, NindNew, off, globalOff, f, p;
5633   PetscErrorCode  ierr;
5634 
5635   PetscFunctionBegin;
5636   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5637   PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2);
5638   PetscValidHeaderSpecific(globalSection, PETSC_SECTION_CLASSID, 3);
5639   if (numIndices) PetscValidPointer(numIndices, 4);
5640   PetscValidPointer(indices, 5);
5641   ierr = PetscSectionGetNumFields(section, &Nf);CHKERRQ(ierr);
5642   if (Nf > 31) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", Nf);
5643   ierr = PetscArrayzero(offsets, 32);CHKERRQ(ierr);
5644   /* Get points in closure */
5645   ierr = DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);CHKERRQ(ierr);
5646   ierr = PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject) dm, NULL, &clperm);CHKERRQ(ierr);
5647   /* Get number of indices and indices per field */
5648   for (p = 0, Nind = 0; p < numPoints*2; p += 2) {
5649     PetscInt dof, fdof;
5650 
5651     ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
5652     for (f = 0; f < Nf; ++f) {
5653       ierr = PetscSectionGetFieldDof(section, points[p], f, &fdof);CHKERRQ(ierr);
5654       offsets[f+1] += fdof;
5655     }
5656     Nind += dof;
5657   }
5658   for (f = 1; f < Nf; ++f) offsets[f+1] += offsets[f];
5659   if (Nf && offsets[Nf] != Nind) SETERRQ2(PetscObjectComm((PetscObject) dm), PETSC_ERR_PLIB, "Invalid size for closure %D should be %D", offsets[Nf], Nind);
5660   if (!Nf) offsets[1] = Nind;
5661   /* Get dual space symmetries */
5662   for (f = 0; f < PetscMax(1,Nf); f++) {
5663     if (Nf) {ierr = PetscSectionGetFieldPointSyms(section,f,numPoints,points,&perms[f],NULL);CHKERRQ(ierr);}
5664     else    {ierr = PetscSectionGetPointSyms(section,numPoints,points,&perms[f],NULL);CHKERRQ(ierr);}
5665   }
5666   /* Correct for hanging node constraints */
5667   {
5668     ierr = DMPlexAnchorsModifyMat(dm, section, numPoints, Nind, points, perms, NULL, &numPointsNew, &NindNew, &pointsNew, NULL, offsets, PETSC_TRUE);CHKERRQ(ierr);
5669     if (numPointsNew) {
5670       for (f = 0; f < PetscMax(1,Nf); f++) {
5671         if (Nf) {ierr = PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms[f],NULL);CHKERRQ(ierr);}
5672         else    {ierr = PetscSectionRestorePointSyms(section,numPoints,points,&perms[f],NULL);CHKERRQ(ierr);}
5673       }
5674       for (f = 0; f < PetscMax(1,Nf); f++) {
5675         if (Nf) {ierr = PetscSectionGetFieldPointSyms(section,f,numPointsNew,pointsNew,&perms[f],NULL);CHKERRQ(ierr);}
5676         else    {ierr = PetscSectionGetPointSyms(section,numPointsNew,pointsNew,&perms[f],NULL);CHKERRQ(ierr);}
5677       }
5678       ierr = DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);CHKERRQ(ierr);
5679       numPoints = numPointsNew;
5680       Nind      = NindNew;
5681       points    = pointsNew;
5682     }
5683   }
5684   /* Calculate indices */
5685   ierr = DMGetWorkArray(dm, Nind, MPIU_INT, indices);CHKERRQ(ierr);
5686   if (Nf) {
5687     if (outOffsets) {
5688       PetscInt f;
5689 
5690       for (f = 0; f <= Nf; f++) {
5691         outOffsets[f] = offsets[f];
5692       }
5693     }
5694     for (p = 0; p < numPoints; p++) {
5695       ierr = PetscSectionGetOffset(globalSection, points[2*p], &globalOff);CHKERRQ(ierr);
5696       DMPlexGetIndicesPointFields_Internal(section, points[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, offsets, PETSC_FALSE, perms, p, clperm, *indices);
5697     }
5698   } else {
5699     for (p = 0, off = 0; p < numPoints; p++) {
5700       const PetscInt *perm = perms[0] ? perms[0][p] : NULL;
5701 
5702       ierr = PetscSectionGetOffset(globalSection, points[2*p], &globalOff);CHKERRQ(ierr);
5703       DMPlexGetIndicesPoint_Internal(section, points[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, clperm, *indices);
5704     }
5705   }
5706   /* Cleanup points */
5707   for (f = 0; f < PetscMax(1,Nf); f++) {
5708     if (Nf) {ierr = PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms[f],NULL);CHKERRQ(ierr);}
5709     else    {ierr = PetscSectionRestorePointSyms(section,numPoints,points,&perms[f],NULL);CHKERRQ(ierr);}
5710   }
5711   if (numPointsNew) {
5712     ierr = DMRestoreWorkArray(dm, 2*numPointsNew, MPIU_INT, &pointsNew);CHKERRQ(ierr);
5713   } else {
5714     ierr = DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);CHKERRQ(ierr);
5715   }
5716   if (numIndices) *numIndices = Nind;
5717   PetscFunctionReturn(0);
5718 }
5719 
5720 /*@C
5721   DMPlexRestoreClosureIndices - Restore the indices in a vector v for all points in the closure of the given point
5722 
5723   Not collective
5724 
5725   Input Parameters:
5726 + dm - The DM
5727 . section - The section describing the layout in v, or NULL to use the default section
5728 . globalSection - The section describing the parallel layout in v, or NULL to use the default section
5729 . point - The mesh point
5730 . numIndices - The number of indices
5731 . indices - The indices
5732 - outOffsets - Field offset if not NULL
5733 
5734   Level: advanced
5735 
5736 .seealso DMPlexGetClosureIndices(), DMPlexVecGetClosure(), DMPlexMatSetClosure()
5737 @*/
5738 PetscErrorCode DMPlexRestoreClosureIndices(DM dm, PetscSection section, PetscSection globalSection, PetscInt point, PetscInt *numIndices, PetscInt **indices,PetscInt *outOffsets)
5739 {
5740   PetscErrorCode ierr;
5741 
5742   PetscFunctionBegin;
5743   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5744   PetscValidPointer(indices, 5);
5745   ierr = DMRestoreWorkArray(dm, 0, MPIU_INT, indices);CHKERRQ(ierr);
5746   PetscFunctionReturn(0);
5747 }
5748 
5749 /*@C
5750   DMPlexMatSetClosure - Set an array of the values on the closure of 'point'
5751 
5752   Not collective
5753 
5754   Input Parameters:
5755 + dm - The DM
5756 . section - The section describing the layout in v, or NULL to use the default section
5757 . globalSection - The section describing the layout in v, or NULL to use the default global section
5758 . A - The matrix
5759 . point - The point in the DM
5760 . values - The array of values
5761 - mode - The insert mode, where INSERT_ALL_VALUES and ADD_ALL_VALUES also overwrite boundary conditions
5762 
5763   Fortran Notes:
5764   This routine is only available in Fortran 90, and you must include petsc.h90 in your code.
5765 
5766   Level: intermediate
5767 
5768 .seealso DMPlexVecGetClosure(), DMPlexVecSetClosure()
5769 @*/
5770 PetscErrorCode DMPlexMatSetClosure(DM dm, PetscSection section, PetscSection globalSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode)
5771 {
5772   DM_Plex            *mesh   = (DM_Plex*) dm->data;
5773   PetscSection        clSection;
5774   IS                  clPoints;
5775   PetscInt           *points = NULL, *newPoints;
5776   const PetscInt     *clp, *clperm;
5777   PetscInt           *indices;
5778   PetscInt            offsets[32];
5779   const PetscInt    **perms[32] = {NULL};
5780   const PetscScalar **flips[32] = {NULL};
5781   PetscInt            numFields, numPoints, newNumPoints, numIndices, newNumIndices, dof, off, globalOff, p, f;
5782   PetscScalar        *valCopy = NULL;
5783   PetscScalar        *newValues;
5784   PetscErrorCode      ierr;
5785 
5786   PetscFunctionBegin;
5787   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5788   if (!section) {ierr = DMGetSection(dm, &section);CHKERRQ(ierr);}
5789   PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2);
5790   if (!globalSection) {ierr = DMGetGlobalSection(dm, &globalSection);CHKERRQ(ierr);}
5791   PetscValidHeaderSpecific(globalSection, PETSC_SECTION_CLASSID, 3);
5792   PetscValidHeaderSpecific(A, MAT_CLASSID, 4);
5793   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
5794   if (numFields > 31) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
5795   ierr = PetscArrayzero(offsets, 32);CHKERRQ(ierr);
5796   ierr = PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject) dm, NULL, &clperm);CHKERRQ(ierr);
5797   ierr = DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);CHKERRQ(ierr);
5798   for (p = 0, numIndices = 0; p < numPoints*2; p += 2) {
5799     PetscInt fdof;
5800 
5801     ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
5802     for (f = 0; f < numFields; ++f) {
5803       ierr          = PetscSectionGetFieldDof(section, points[p], f, &fdof);CHKERRQ(ierr);
5804       offsets[f+1] += fdof;
5805     }
5806     numIndices += dof;
5807   }
5808   for (f = 1; f < numFields; ++f) offsets[f+1] += offsets[f];
5809 
5810   if (numFields && offsets[numFields] != numIndices) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid size for closure %D should be %D", offsets[numFields], numIndices);
5811   /* Get symmetries */
5812   for (f = 0; f < PetscMax(1,numFields); f++) {
5813     if (numFields) {ierr = PetscSectionGetFieldPointSyms(section,f,numPoints,points,&perms[f],&flips[f]);CHKERRQ(ierr);}
5814     else           {ierr = PetscSectionGetPointSyms(section,numPoints,points,&perms[f],&flips[f]);CHKERRQ(ierr);}
5815     if (values && flips[f]) { /* may need to apply sign changes to the element matrix */
5816       PetscInt foffset = offsets[f];
5817 
5818       for (p = 0; p < numPoints; p++) {
5819         PetscInt point          = points[2*p], fdof;
5820         const PetscScalar *flip = flips[f] ? flips[f][p] : NULL;
5821 
5822         if (!numFields) {
5823           ierr = PetscSectionGetDof(section,point,&fdof);CHKERRQ(ierr);
5824         } else {
5825           ierr = PetscSectionGetFieldDof(section,point,f,&fdof);CHKERRQ(ierr);
5826         }
5827         if (flip) {
5828           PetscInt i, j, k;
5829 
5830           if (!valCopy) {
5831             ierr = DMGetWorkArray(dm,numIndices*numIndices,MPIU_SCALAR,&valCopy);CHKERRQ(ierr);
5832             for (j = 0; j < numIndices * numIndices; j++) valCopy[j] = values[j];
5833             values = valCopy;
5834           }
5835           for (i = 0; i < fdof; i++) {
5836             PetscScalar fval = flip[i];
5837 
5838             for (k = 0; k < numIndices; k++) {
5839               valCopy[numIndices * (foffset + i) + k] *= fval;
5840               valCopy[numIndices * k + (foffset + i)] *= fval;
5841             }
5842           }
5843         }
5844         foffset += fdof;
5845       }
5846     }
5847   }
5848   ierr = DMPlexAnchorsModifyMat(dm,section,numPoints,numIndices,points,perms,values,&newNumPoints,&newNumIndices,&newPoints,&newValues,offsets,PETSC_TRUE);CHKERRQ(ierr);
5849   if (newNumPoints) {
5850     if (valCopy) {
5851       ierr = DMRestoreWorkArray(dm,numIndices*numIndices,MPIU_SCALAR,&valCopy);CHKERRQ(ierr);
5852     }
5853     for (f = 0; f < PetscMax(1,numFields); f++) {
5854       if (numFields) {ierr = PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms[f],&flips[f]);CHKERRQ(ierr);}
5855       else           {ierr = PetscSectionRestorePointSyms(section,numPoints,points,&perms[f],&flips[f]);CHKERRQ(ierr);}
5856     }
5857     for (f = 0; f < PetscMax(1,numFields); f++) {
5858       if (numFields) {ierr = PetscSectionGetFieldPointSyms(section,f,newNumPoints,newPoints,&perms[f],&flips[f]);CHKERRQ(ierr);}
5859       else           {ierr = PetscSectionGetPointSyms(section,newNumPoints,newPoints,&perms[f],&flips[f]);CHKERRQ(ierr);}
5860     }
5861     ierr = DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);CHKERRQ(ierr);
5862     numPoints  = newNumPoints;
5863     numIndices = newNumIndices;
5864     points     = newPoints;
5865     values     = newValues;
5866   }
5867   ierr = DMGetWorkArray(dm, numIndices, MPIU_INT, &indices);CHKERRQ(ierr);
5868   if (numFields) {
5869     PetscBool useFieldOffsets;
5870 
5871     ierr = PetscSectionGetUseFieldOffsets(globalSection, &useFieldOffsets);CHKERRQ(ierr);
5872     if (useFieldOffsets) {
5873       for (p = 0; p < numPoints; p++) {
5874         DMPlexGetIndicesPointFieldsSplit_Internal(section, globalSection, points[2*p], offsets, PETSC_FALSE, perms, p, clperm, indices);
5875       }
5876     } else {
5877       for (p = 0; p < numPoints; p++) {
5878         ierr = PetscSectionGetOffset(globalSection, points[2*p], &globalOff);CHKERRQ(ierr);
5879         DMPlexGetIndicesPointFields_Internal(section, points[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, offsets, PETSC_FALSE, perms, p, clperm, indices);
5880       }
5881     }
5882   } else {
5883     for (p = 0, off = 0; p < numPoints; p++) {
5884       const PetscInt *perm = perms[0] ? perms[0][p] : NULL;
5885       ierr = PetscSectionGetOffset(globalSection, points[2*p], &globalOff);CHKERRQ(ierr);
5886       DMPlexGetIndicesPoint_Internal(section, points[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, clperm, indices);
5887     }
5888   }
5889   if (mesh->printSetValues) {ierr = DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndices, indices, 0, NULL, values);CHKERRQ(ierr);}
5890   ierr = MatSetValues(A, numIndices, indices, numIndices, indices, values, mode);
5891   if (mesh->printFEM > 1) {
5892     PetscInt i;
5893     ierr = PetscPrintf(PETSC_COMM_SELF, "  Indices:");CHKERRQ(ierr);
5894     for (i = 0; i < numIndices; ++i) {ierr = PetscPrintf(PETSC_COMM_SELF, " %D", indices[i]);CHKERRQ(ierr);}
5895     ierr = PetscPrintf(PETSC_COMM_SELF, "\n");CHKERRQ(ierr);
5896   }
5897   if (ierr) {
5898     PetscMPIInt    rank;
5899     PetscErrorCode ierr2;
5900 
5901     ierr2 = MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank);CHKERRQ(ierr2);
5902     ierr2 = (*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank);CHKERRQ(ierr2);
5903     ierr2 = DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndices, indices, 0, NULL, values);CHKERRQ(ierr2);
5904     ierr2 = DMRestoreWorkArray(dm, numIndices, MPIU_INT, &indices);CHKERRQ(ierr2);
5905     CHKERRQ(ierr);
5906   }
5907   for (f = 0; f < PetscMax(1,numFields); f++) {
5908     if (numFields) {ierr = PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms[f],&flips[f]);CHKERRQ(ierr);}
5909     else           {ierr = PetscSectionRestorePointSyms(section,numPoints,points,&perms[f],&flips[f]);CHKERRQ(ierr);}
5910   }
5911   if (newNumPoints) {
5912     ierr = DMRestoreWorkArray(dm,newNumIndices*newNumIndices,MPIU_SCALAR,&newValues);CHKERRQ(ierr);
5913     ierr = DMRestoreWorkArray(dm,2*newNumPoints,MPIU_INT,&newPoints);CHKERRQ(ierr);
5914   }
5915   else {
5916     if (valCopy) {
5917       ierr = DMRestoreWorkArray(dm,numIndices*numIndices,MPIU_SCALAR,&valCopy);CHKERRQ(ierr);
5918     }
5919     ierr = DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);CHKERRQ(ierr);
5920   }
5921   ierr = DMRestoreWorkArray(dm, numIndices, MPIU_INT, &indices);CHKERRQ(ierr);
5922   PetscFunctionReturn(0);
5923 }
5924 
5925 PetscErrorCode DMPlexMatSetClosureRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode)
5926 {
5927   DM_Plex        *mesh   = (DM_Plex*) dmf->data;
5928   PetscInt       *fpoints = NULL, *ftotpoints = NULL;
5929   PetscInt       *cpoints = NULL;
5930   PetscInt       *findices, *cindices;
5931   const PetscInt *fclperm, *cclperm;
5932   PetscInt        foffsets[32], coffsets[32];
5933   CellRefiner     cellRefiner;
5934   PetscInt        numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f;
5935   PetscErrorCode  ierr;
5936 
5937   PetscFunctionBegin;
5938   PetscValidHeaderSpecific(dmf, DM_CLASSID, 1);
5939   PetscValidHeaderSpecific(dmc, DM_CLASSID, 4);
5940   if (!fsection) {ierr = DMGetSection(dmf, &fsection);CHKERRQ(ierr);}
5941   PetscValidHeaderSpecific(fsection, PETSC_SECTION_CLASSID, 2);
5942   if (!csection) {ierr = DMGetSection(dmc, &csection);CHKERRQ(ierr);}
5943   PetscValidHeaderSpecific(csection, PETSC_SECTION_CLASSID, 5);
5944   if (!globalFSection) {ierr = DMGetGlobalSection(dmf, &globalFSection);CHKERRQ(ierr);}
5945   PetscValidHeaderSpecific(globalFSection, PETSC_SECTION_CLASSID, 3);
5946   if (!globalCSection) {ierr = DMGetGlobalSection(dmc, &globalCSection);CHKERRQ(ierr);}
5947   PetscValidHeaderSpecific(globalCSection, PETSC_SECTION_CLASSID, 6);
5948   PetscValidHeaderSpecific(A, MAT_CLASSID, 7);
5949   ierr = PetscSectionGetNumFields(fsection, &numFields);CHKERRQ(ierr);
5950   if (numFields > 31) SETERRQ1(PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
5951   ierr = PetscArrayzero(foffsets, 32);CHKERRQ(ierr);
5952   ierr = PetscArrayzero(coffsets, 32);CHKERRQ(ierr);
5953   ierr = PetscSectionGetClosureInversePermutation_Internal(fsection, (PetscObject) dmf, NULL, &fclperm);CHKERRQ(ierr);
5954   ierr = PetscSectionGetClosureInversePermutation_Internal(csection, (PetscObject) dmc, NULL, &cclperm);CHKERRQ(ierr);
5955   /* Column indices */
5956   ierr = DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints);CHKERRQ(ierr);
5957   maxFPoints = numCPoints;
5958   /* Compress out points not in the section */
5959   /*   TODO: Squeeze out points with 0 dof as well */
5960   ierr = PetscSectionGetChart(csection, &pStart, &pEnd);CHKERRQ(ierr);
5961   for (p = 0, q = 0; p < numCPoints*2; p += 2) {
5962     if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) {
5963       cpoints[q*2]   = cpoints[p];
5964       cpoints[q*2+1] = cpoints[p+1];
5965       ++q;
5966     }
5967   }
5968   numCPoints = q;
5969   for (p = 0, numCIndices = 0; p < numCPoints*2; p += 2) {
5970     PetscInt fdof;
5971 
5972     ierr = PetscSectionGetDof(csection, cpoints[p], &dof);CHKERRQ(ierr);
5973     if (!dof) continue;
5974     for (f = 0; f < numFields; ++f) {
5975       ierr           = PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof);CHKERRQ(ierr);
5976       coffsets[f+1] += fdof;
5977     }
5978     numCIndices += dof;
5979   }
5980   for (f = 1; f < numFields; ++f) coffsets[f+1] += coffsets[f];
5981   /* Row indices */
5982   ierr = DMPlexGetCellRefiner_Internal(dmc, &cellRefiner);CHKERRQ(ierr);
5983   ierr = CellRefinerGetAffineTransforms_Internal(cellRefiner, &numSubcells, NULL, NULL, NULL);CHKERRQ(ierr);
5984   ierr = DMGetWorkArray(dmf, maxFPoints*2*numSubcells, MPIU_INT, &ftotpoints);CHKERRQ(ierr);
5985   for (r = 0, q = 0; r < numSubcells; ++r) {
5986     /* TODO Map from coarse to fine cells */
5987     ierr = DMPlexGetTransitiveClosure(dmf, point*numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints);CHKERRQ(ierr);
5988     /* Compress out points not in the section */
5989     ierr = PetscSectionGetChart(fsection, &pStart, &pEnd);CHKERRQ(ierr);
5990     for (p = 0; p < numFPoints*2; p += 2) {
5991       if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) {
5992         ierr = PetscSectionGetDof(fsection, fpoints[p], &dof);CHKERRQ(ierr);
5993         if (!dof) continue;
5994         for (s = 0; s < q; ++s) if (fpoints[p] == ftotpoints[s*2]) break;
5995         if (s < q) continue;
5996         ftotpoints[q*2]   = fpoints[p];
5997         ftotpoints[q*2+1] = fpoints[p+1];
5998         ++q;
5999       }
6000     }
6001     ierr = DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints);CHKERRQ(ierr);
6002   }
6003   numFPoints = q;
6004   for (p = 0, numFIndices = 0; p < numFPoints*2; p += 2) {
6005     PetscInt fdof;
6006 
6007     ierr = PetscSectionGetDof(fsection, ftotpoints[p], &dof);CHKERRQ(ierr);
6008     if (!dof) continue;
6009     for (f = 0; f < numFields; ++f) {
6010       ierr           = PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof);CHKERRQ(ierr);
6011       foffsets[f+1] += fdof;
6012     }
6013     numFIndices += dof;
6014   }
6015   for (f = 1; f < numFields; ++f) foffsets[f+1] += foffsets[f];
6016 
6017   if (numFields && foffsets[numFields] != numFIndices) SETERRQ2(PetscObjectComm((PetscObject)dmf), PETSC_ERR_PLIB, "Invalid size for closure %D should be %D", foffsets[numFields], numFIndices);
6018   if (numFields && coffsets[numFields] != numCIndices) SETERRQ2(PetscObjectComm((PetscObject)dmc), PETSC_ERR_PLIB, "Invalid size for closure %D should be %D", coffsets[numFields], numCIndices);
6019   ierr = DMGetWorkArray(dmf, numFIndices, MPIU_INT, &findices);CHKERRQ(ierr);
6020   ierr = DMGetWorkArray(dmc, numCIndices, MPIU_INT, &cindices);CHKERRQ(ierr);
6021   if (numFields) {
6022     const PetscInt **permsF[32] = {NULL};
6023     const PetscInt **permsC[32] = {NULL};
6024 
6025     for (f = 0; f < numFields; f++) {
6026       ierr = PetscSectionGetFieldPointSyms(fsection,f,numFPoints,ftotpoints,&permsF[f],NULL);CHKERRQ(ierr);
6027       ierr = PetscSectionGetFieldPointSyms(csection,f,numCPoints,cpoints,&permsC[f],NULL);CHKERRQ(ierr);
6028     }
6029     for (p = 0; p < numFPoints; p++) {
6030       ierr = PetscSectionGetOffset(globalFSection, ftotpoints[2*p], &globalOff);CHKERRQ(ierr);
6031       ierr = DMPlexGetIndicesPointFields_Internal(fsection, ftotpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, foffsets, PETSC_FALSE, permsF, p, fclperm, findices);CHKERRQ(ierr);
6032     }
6033     for (p = 0; p < numCPoints; p++) {
6034       ierr = PetscSectionGetOffset(globalCSection, cpoints[2*p], &globalOff);CHKERRQ(ierr);
6035       ierr = DMPlexGetIndicesPointFields_Internal(csection, cpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cclperm, cindices);CHKERRQ(ierr);
6036     }
6037     for (f = 0; f < numFields; f++) {
6038       ierr = PetscSectionRestoreFieldPointSyms(fsection,f,numFPoints,ftotpoints,&permsF[f],NULL);CHKERRQ(ierr);
6039       ierr = PetscSectionRestoreFieldPointSyms(csection,f,numCPoints,cpoints,&permsC[f],NULL);CHKERRQ(ierr);
6040     }
6041   } else {
6042     const PetscInt **permsF = NULL;
6043     const PetscInt **permsC = NULL;
6044 
6045     ierr = PetscSectionGetPointSyms(fsection,numFPoints,ftotpoints,&permsF,NULL);CHKERRQ(ierr);
6046     ierr = PetscSectionGetPointSyms(csection,numCPoints,cpoints,&permsC,NULL);CHKERRQ(ierr);
6047     for (p = 0, off = 0; p < numFPoints; p++) {
6048       const PetscInt *perm = permsF ? permsF[p] : NULL;
6049 
6050       ierr = PetscSectionGetOffset(globalFSection, ftotpoints[2*p], &globalOff);CHKERRQ(ierr);
6051       ierr = DMPlexGetIndicesPoint_Internal(fsection, ftotpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, fclperm, findices);CHKERRQ(ierr);
6052     }
6053     for (p = 0, off = 0; p < numCPoints; p++) {
6054       const PetscInt *perm = permsC ? permsC[p] : NULL;
6055 
6056       ierr = PetscSectionGetOffset(globalCSection, cpoints[2*p], &globalOff);CHKERRQ(ierr);
6057       ierr = DMPlexGetIndicesPoint_Internal(csection, cpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, cclperm, cindices);CHKERRQ(ierr);
6058     }
6059     ierr = PetscSectionRestorePointSyms(fsection,numFPoints,ftotpoints,&permsF,NULL);CHKERRQ(ierr);
6060     ierr = PetscSectionRestorePointSyms(csection,numCPoints,cpoints,&permsC,NULL);CHKERRQ(ierr);
6061   }
6062   if (mesh->printSetValues) {ierr = DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numFIndices, findices, numCIndices, cindices, values);CHKERRQ(ierr);}
6063   /* TODO: flips */
6064   ierr = MatSetValues(A, numFIndices, findices, numCIndices, cindices, values, mode);
6065   if (ierr) {
6066     PetscMPIInt    rank;
6067     PetscErrorCode ierr2;
6068 
6069     ierr2 = MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank);CHKERRQ(ierr2);
6070     ierr2 = (*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank);CHKERRQ(ierr2);
6071     ierr2 = DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numFIndices, findices, numCIndices, cindices, values);CHKERRQ(ierr2);
6072     ierr2 = DMRestoreWorkArray(dmf, numFIndices, MPIU_INT, &findices);CHKERRQ(ierr2);
6073     ierr2 = DMRestoreWorkArray(dmc, numCIndices, MPIU_INT, &cindices);CHKERRQ(ierr2);
6074     CHKERRQ(ierr);
6075   }
6076   ierr = DMRestoreWorkArray(dmf, numCPoints*2*4, MPIU_INT, &ftotpoints);CHKERRQ(ierr);
6077   ierr = DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints);CHKERRQ(ierr);
6078   ierr = DMRestoreWorkArray(dmf, numFIndices, MPIU_INT, &findices);CHKERRQ(ierr);
6079   ierr = DMRestoreWorkArray(dmc, numCIndices, MPIU_INT, &cindices);CHKERRQ(ierr);
6080   PetscFunctionReturn(0);
6081 }
6082 
6083 PetscErrorCode DMPlexMatGetClosureIndicesRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, PetscInt point, PetscInt cindices[], PetscInt findices[])
6084 {
6085   PetscInt      *fpoints = NULL, *ftotpoints = NULL;
6086   PetscInt      *cpoints = NULL;
6087   PetscInt       foffsets[32], coffsets[32];
6088   const PetscInt *fclperm, *cclperm;
6089   CellRefiner    cellRefiner;
6090   PetscInt       numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f;
6091   PetscErrorCode ierr;
6092 
6093   PetscFunctionBegin;
6094   PetscValidHeaderSpecific(dmf, DM_CLASSID, 1);
6095   PetscValidHeaderSpecific(dmc, DM_CLASSID, 4);
6096   if (!fsection) {ierr = DMGetSection(dmf, &fsection);CHKERRQ(ierr);}
6097   PetscValidHeaderSpecific(fsection, PETSC_SECTION_CLASSID, 2);
6098   if (!csection) {ierr = DMGetSection(dmc, &csection);CHKERRQ(ierr);}
6099   PetscValidHeaderSpecific(csection, PETSC_SECTION_CLASSID, 5);
6100   if (!globalFSection) {ierr = DMGetGlobalSection(dmf, &globalFSection);CHKERRQ(ierr);}
6101   PetscValidHeaderSpecific(globalFSection, PETSC_SECTION_CLASSID, 3);
6102   if (!globalCSection) {ierr = DMGetGlobalSection(dmc, &globalCSection);CHKERRQ(ierr);}
6103   PetscValidHeaderSpecific(globalCSection, PETSC_SECTION_CLASSID, 6);
6104   ierr = PetscSectionGetNumFields(fsection, &numFields);CHKERRQ(ierr);
6105   if (numFields > 31) SETERRQ1(PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
6106   ierr = PetscArrayzero(foffsets, 32);CHKERRQ(ierr);
6107   ierr = PetscArrayzero(coffsets, 32);CHKERRQ(ierr);
6108   ierr = PetscSectionGetClosureInversePermutation_Internal(fsection, (PetscObject) dmf, NULL, &fclperm);CHKERRQ(ierr);
6109   ierr = PetscSectionGetClosureInversePermutation_Internal(csection, (PetscObject) dmc, NULL, &cclperm);CHKERRQ(ierr);
6110   /* Column indices */
6111   ierr = DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints);CHKERRQ(ierr);
6112   maxFPoints = numCPoints;
6113   /* Compress out points not in the section */
6114   /*   TODO: Squeeze out points with 0 dof as well */
6115   ierr = PetscSectionGetChart(csection, &pStart, &pEnd);CHKERRQ(ierr);
6116   for (p = 0, q = 0; p < numCPoints*2; p += 2) {
6117     if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) {
6118       cpoints[q*2]   = cpoints[p];
6119       cpoints[q*2+1] = cpoints[p+1];
6120       ++q;
6121     }
6122   }
6123   numCPoints = q;
6124   for (p = 0, numCIndices = 0; p < numCPoints*2; p += 2) {
6125     PetscInt fdof;
6126 
6127     ierr = PetscSectionGetDof(csection, cpoints[p], &dof);CHKERRQ(ierr);
6128     if (!dof) continue;
6129     for (f = 0; f < numFields; ++f) {
6130       ierr           = PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof);CHKERRQ(ierr);
6131       coffsets[f+1] += fdof;
6132     }
6133     numCIndices += dof;
6134   }
6135   for (f = 1; f < numFields; ++f) coffsets[f+1] += coffsets[f];
6136   /* Row indices */
6137   ierr = DMPlexGetCellRefiner_Internal(dmc, &cellRefiner);CHKERRQ(ierr);
6138   ierr = CellRefinerGetAffineTransforms_Internal(cellRefiner, &numSubcells, NULL, NULL, NULL);CHKERRQ(ierr);
6139   ierr = DMGetWorkArray(dmf, maxFPoints*2*numSubcells, MPIU_INT, &ftotpoints);CHKERRQ(ierr);
6140   for (r = 0, q = 0; r < numSubcells; ++r) {
6141     /* TODO Map from coarse to fine cells */
6142     ierr = DMPlexGetTransitiveClosure(dmf, point*numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints);CHKERRQ(ierr);
6143     /* Compress out points not in the section */
6144     ierr = PetscSectionGetChart(fsection, &pStart, &pEnd);CHKERRQ(ierr);
6145     for (p = 0; p < numFPoints*2; p += 2) {
6146       if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) {
6147         ierr = PetscSectionGetDof(fsection, fpoints[p], &dof);CHKERRQ(ierr);
6148         if (!dof) continue;
6149         for (s = 0; s < q; ++s) if (fpoints[p] == ftotpoints[s*2]) break;
6150         if (s < q) continue;
6151         ftotpoints[q*2]   = fpoints[p];
6152         ftotpoints[q*2+1] = fpoints[p+1];
6153         ++q;
6154       }
6155     }
6156     ierr = DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints);CHKERRQ(ierr);
6157   }
6158   numFPoints = q;
6159   for (p = 0, numFIndices = 0; p < numFPoints*2; p += 2) {
6160     PetscInt fdof;
6161 
6162     ierr = PetscSectionGetDof(fsection, ftotpoints[p], &dof);CHKERRQ(ierr);
6163     if (!dof) continue;
6164     for (f = 0; f < numFields; ++f) {
6165       ierr           = PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof);CHKERRQ(ierr);
6166       foffsets[f+1] += fdof;
6167     }
6168     numFIndices += dof;
6169   }
6170   for (f = 1; f < numFields; ++f) foffsets[f+1] += foffsets[f];
6171 
6172   if (numFields && foffsets[numFields] != numFIndices) SETERRQ2(PetscObjectComm((PetscObject)dmf), PETSC_ERR_PLIB, "Invalid size for closure %D should be %D", foffsets[numFields], numFIndices);
6173   if (numFields && coffsets[numFields] != numCIndices) SETERRQ2(PetscObjectComm((PetscObject)dmc), PETSC_ERR_PLIB, "Invalid size for closure %D should be %D", coffsets[numFields], numCIndices);
6174   if (numFields) {
6175     const PetscInt **permsF[32] = {NULL};
6176     const PetscInt **permsC[32] = {NULL};
6177 
6178     for (f = 0; f < numFields; f++) {
6179       ierr = PetscSectionGetFieldPointSyms(fsection,f,numFPoints,ftotpoints,&permsF[f],NULL);CHKERRQ(ierr);
6180       ierr = PetscSectionGetFieldPointSyms(csection,f,numCPoints,cpoints,&permsC[f],NULL);CHKERRQ(ierr);
6181     }
6182     for (p = 0; p < numFPoints; p++) {
6183       ierr = PetscSectionGetOffset(globalFSection, ftotpoints[2*p], &globalOff);CHKERRQ(ierr);
6184       DMPlexGetIndicesPointFields_Internal(fsection, ftotpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, foffsets, PETSC_FALSE, permsF, p, fclperm, findices);
6185     }
6186     for (p = 0; p < numCPoints; p++) {
6187       ierr = PetscSectionGetOffset(globalCSection, cpoints[2*p], &globalOff);CHKERRQ(ierr);
6188       DMPlexGetIndicesPointFields_Internal(csection, cpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cclperm, cindices);
6189     }
6190     for (f = 0; f < numFields; f++) {
6191       ierr = PetscSectionRestoreFieldPointSyms(fsection,f,numFPoints,ftotpoints,&permsF[f],NULL);CHKERRQ(ierr);
6192       ierr = PetscSectionRestoreFieldPointSyms(csection,f,numCPoints,cpoints,&permsC[f],NULL);CHKERRQ(ierr);
6193     }
6194   } else {
6195     const PetscInt **permsF = NULL;
6196     const PetscInt **permsC = NULL;
6197 
6198     ierr = PetscSectionGetPointSyms(fsection,numFPoints,ftotpoints,&permsF,NULL);CHKERRQ(ierr);
6199     ierr = PetscSectionGetPointSyms(csection,numCPoints,cpoints,&permsC,NULL);CHKERRQ(ierr);
6200     for (p = 0, off = 0; p < numFPoints; p++) {
6201       const PetscInt *perm = permsF ? permsF[p] : NULL;
6202 
6203       ierr = PetscSectionGetOffset(globalFSection, ftotpoints[2*p], &globalOff);CHKERRQ(ierr);
6204       DMPlexGetIndicesPoint_Internal(fsection, ftotpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, fclperm, findices);
6205     }
6206     for (p = 0, off = 0; p < numCPoints; p++) {
6207       const PetscInt *perm = permsC ? permsC[p] : NULL;
6208 
6209       ierr = PetscSectionGetOffset(globalCSection, cpoints[2*p], &globalOff);CHKERRQ(ierr);
6210       DMPlexGetIndicesPoint_Internal(csection, cpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, cclperm, cindices);
6211     }
6212     ierr = PetscSectionRestorePointSyms(fsection,numFPoints,ftotpoints,&permsF,NULL);CHKERRQ(ierr);
6213     ierr = PetscSectionRestorePointSyms(csection,numCPoints,cpoints,&permsC,NULL);CHKERRQ(ierr);
6214   }
6215   ierr = DMRestoreWorkArray(dmf, numCPoints*2*4, MPIU_INT, &ftotpoints);CHKERRQ(ierr);
6216   ierr = DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints);CHKERRQ(ierr);
6217   PetscFunctionReturn(0);
6218 }
6219 
6220 /*@
6221   DMPlexGetHybridBounds - Get the first mesh point of each dimension which is a hybrid
6222 
6223   Input Parameter:
6224 . dm - The DMPlex object
6225 
6226   Output Parameters:
6227 + cMax - The first hybrid cell
6228 . fMax - The first hybrid face
6229 . eMax - The first hybrid edge
6230 - vMax - The first hybrid vertex
6231 
6232   Level: developer
6233 
6234 .seealso DMPlexCreateHybridMesh(), DMPlexSetHybridBounds()
6235 @*/
6236 PetscErrorCode DMPlexGetHybridBounds(DM dm, PetscInt *cMax, PetscInt *fMax, PetscInt *eMax, PetscInt *vMax)
6237 {
6238   DM_Plex       *mesh = (DM_Plex*) dm->data;
6239   PetscInt       dim;
6240   PetscErrorCode ierr;
6241 
6242   PetscFunctionBegin;
6243   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6244   ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr);
6245   if (dim < 0) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "DM dimension not yet set");
6246   if (cMax) *cMax = mesh->hybridPointMax[dim];
6247   if (fMax) *fMax = mesh->hybridPointMax[PetscMax(dim-1,0)];
6248   if (eMax) *eMax = mesh->hybridPointMax[1];
6249   if (vMax) *vMax = mesh->hybridPointMax[0];
6250   PetscFunctionReturn(0);
6251 }
6252 
6253 static PetscErrorCode DMPlexCreateDimStratum(DM dm, DMLabel depthLabel, DMLabel dimLabel, PetscInt d, PetscInt dMax)
6254 {
6255   IS             is, his;
6256   PetscInt       first = 0, stride;
6257   PetscBool      isStride;
6258   PetscErrorCode ierr;
6259 
6260   PetscFunctionBegin;
6261   ierr = DMLabelGetStratumIS(depthLabel, d, &is);CHKERRQ(ierr);
6262   ierr = PetscObjectTypeCompare((PetscObject) is, ISSTRIDE, &isStride);CHKERRQ(ierr);
6263   if (isStride) {
6264     ierr = ISStrideGetInfo(is, &first, &stride);CHKERRQ(ierr);
6265   }
6266   if (is && (!isStride || stride != 1)) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "DM is not stratified: depth %D IS is not contiguous", d);
6267   ierr = ISCreateStride(PETSC_COMM_SELF, (dMax - first), first, 1, &his);CHKERRQ(ierr);
6268   ierr = DMLabelSetStratumIS(dimLabel, d, his);CHKERRQ(ierr);
6269   ierr = ISDestroy(&his);CHKERRQ(ierr);
6270   ierr = ISDestroy(&is);CHKERRQ(ierr);
6271   PetscFunctionReturn(0);
6272 }
6273 
6274 /*@
6275   DMPlexSetHybridBounds - Set the first mesh point of each dimension which is a hybrid
6276 
6277   Input Parameters:
6278 . dm   - The DMPlex object
6279 . cMax - The first hybrid cell
6280 . fMax - The first hybrid face
6281 . eMax - The first hybrid edge
6282 - vMax - The first hybrid vertex
6283 
6284   Level: developer
6285 
6286 .seealso DMPlexCreateHybridMesh(), DMPlexGetHybridBounds()
6287 @*/
6288 PetscErrorCode DMPlexSetHybridBounds(DM dm, PetscInt cMax, PetscInt fMax, PetscInt eMax, PetscInt vMax)
6289 {
6290   DM_Plex       *mesh = (DM_Plex*) dm->data;
6291   PetscInt       dim;
6292   PetscErrorCode ierr;
6293 
6294   PetscFunctionBegin;
6295   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6296   ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr);
6297   if (dim < 0) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "DM dimension not yet set");
6298   if (cMax >= 0) mesh->hybridPointMax[dim]               = cMax;
6299   if (fMax >= 0) mesh->hybridPointMax[PetscMax(dim-1,0)] = fMax;
6300   if (eMax >= 0) mesh->hybridPointMax[1]                 = eMax;
6301   if (vMax >= 0) mesh->hybridPointMax[0]                 = vMax;
6302   PetscFunctionReturn(0);
6303 }
6304 
6305 /*@C
6306   DMPlexGetVTKCellHeight - Returns the height in the DAG used to determine which points are cells (normally 0)
6307 
6308   Input Parameter:
6309 . dm   - The DMPlex object
6310 
6311   Output Parameter:
6312 . cellHeight - The height of a cell
6313 
6314   Level: developer
6315 
6316 .seealso DMPlexSetVTKCellHeight()
6317 @*/
6318 PetscErrorCode DMPlexGetVTKCellHeight(DM dm, PetscInt *cellHeight)
6319 {
6320   DM_Plex *mesh = (DM_Plex*) dm->data;
6321 
6322   PetscFunctionBegin;
6323   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6324   PetscValidPointer(cellHeight, 2);
6325   *cellHeight = mesh->vtkCellHeight;
6326   PetscFunctionReturn(0);
6327 }
6328 
6329 /*@C
6330   DMPlexSetVTKCellHeight - Sets the height in the DAG used to determine which points are cells (normally 0)
6331 
6332   Input Parameters:
6333 + dm   - The DMPlex object
6334 - cellHeight - The height of a cell
6335 
6336   Level: developer
6337 
6338 .seealso DMPlexGetVTKCellHeight()
6339 @*/
6340 PetscErrorCode DMPlexSetVTKCellHeight(DM dm, PetscInt cellHeight)
6341 {
6342   DM_Plex *mesh = (DM_Plex*) dm->data;
6343 
6344   PetscFunctionBegin;
6345   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6346   mesh->vtkCellHeight = cellHeight;
6347   PetscFunctionReturn(0);
6348 }
6349 
6350 /* We can easily have a form that takes an IS instead */
6351 PetscErrorCode DMPlexCreateNumbering_Internal(DM dm, PetscInt pStart, PetscInt pEnd, PetscInt shift, PetscInt *globalSize, PetscSF sf, IS *numbering)
6352 {
6353   PetscSection   section, globalSection;
6354   PetscInt      *numbers, p;
6355   PetscErrorCode ierr;
6356 
6357   PetscFunctionBegin;
6358   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)dm), &section);CHKERRQ(ierr);
6359   ierr = PetscSectionSetChart(section, pStart, pEnd);CHKERRQ(ierr);
6360   for (p = pStart; p < pEnd; ++p) {
6361     ierr = PetscSectionSetDof(section, p, 1);CHKERRQ(ierr);
6362   }
6363   ierr = PetscSectionSetUp(section);CHKERRQ(ierr);
6364   ierr = PetscSectionCreateGlobalSection(section, sf, PETSC_FALSE, PETSC_FALSE, &globalSection);CHKERRQ(ierr);
6365   ierr = PetscMalloc1(pEnd - pStart, &numbers);CHKERRQ(ierr);
6366   for (p = pStart; p < pEnd; ++p) {
6367     ierr = PetscSectionGetOffset(globalSection, p, &numbers[p-pStart]);CHKERRQ(ierr);
6368     if (numbers[p-pStart] < 0) numbers[p-pStart] -= shift;
6369     else                       numbers[p-pStart] += shift;
6370   }
6371   ierr = ISCreateGeneral(PetscObjectComm((PetscObject) dm), pEnd - pStart, numbers, PETSC_OWN_POINTER, numbering);CHKERRQ(ierr);
6372   if (globalSize) {
6373     PetscLayout layout;
6374     ierr = PetscSectionGetPointLayout(PetscObjectComm((PetscObject) dm), globalSection, &layout);CHKERRQ(ierr);
6375     ierr = PetscLayoutGetSize(layout, globalSize);CHKERRQ(ierr);
6376     ierr = PetscLayoutDestroy(&layout);CHKERRQ(ierr);
6377   }
6378   ierr = PetscSectionDestroy(&section);CHKERRQ(ierr);
6379   ierr = PetscSectionDestroy(&globalSection);CHKERRQ(ierr);
6380   PetscFunctionReturn(0);
6381 }
6382 
6383 PetscErrorCode DMPlexCreateCellNumbering_Internal(DM dm, PetscBool includeHybrid, IS *globalCellNumbers)
6384 {
6385   PetscInt       cellHeight, cStart, cEnd, cMax;
6386   PetscErrorCode ierr;
6387 
6388   PetscFunctionBegin;
6389   ierr = DMPlexGetVTKCellHeight(dm, &cellHeight);CHKERRQ(ierr);
6390   ierr = DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd);CHKERRQ(ierr);
6391   ierr = DMPlexGetHybridBounds(dm, &cMax, NULL, NULL, NULL);CHKERRQ(ierr);
6392   if (cMax >= 0 && !includeHybrid) cEnd = PetscMin(cEnd, cMax);
6393   ierr = DMPlexCreateNumbering_Internal(dm, cStart, cEnd, 0, NULL, dm->sf, globalCellNumbers);CHKERRQ(ierr);
6394   PetscFunctionReturn(0);
6395 }
6396 
6397 /*@
6398   DMPlexGetCellNumbering - Get a global cell numbering for all cells on this process
6399 
6400   Input Parameter:
6401 . dm   - The DMPlex object
6402 
6403   Output Parameter:
6404 . globalCellNumbers - Global cell numbers for all cells on this process
6405 
6406   Level: developer
6407 
6408 .seealso DMPlexGetVertexNumbering()
6409 @*/
6410 PetscErrorCode DMPlexGetCellNumbering(DM dm, IS *globalCellNumbers)
6411 {
6412   DM_Plex       *mesh = (DM_Plex*) dm->data;
6413   PetscErrorCode ierr;
6414 
6415   PetscFunctionBegin;
6416   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6417   if (!mesh->globalCellNumbers) {ierr = DMPlexCreateCellNumbering_Internal(dm, PETSC_FALSE, &mesh->globalCellNumbers);CHKERRQ(ierr);}
6418   *globalCellNumbers = mesh->globalCellNumbers;
6419   PetscFunctionReturn(0);
6420 }
6421 
6422 PetscErrorCode DMPlexCreateVertexNumbering_Internal(DM dm, PetscBool includeHybrid, IS *globalVertexNumbers)
6423 {
6424   PetscInt       vStart, vEnd, vMax;
6425   PetscErrorCode ierr;
6426 
6427   PetscFunctionBegin;
6428   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6429   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
6430   ierr = DMPlexGetHybridBounds(dm, NULL, NULL, NULL, &vMax);CHKERRQ(ierr);
6431   if (vMax >= 0 && !includeHybrid) vEnd = PetscMin(vEnd, vMax);
6432   ierr = DMPlexCreateNumbering_Internal(dm, vStart, vEnd, 0, NULL, dm->sf, globalVertexNumbers);CHKERRQ(ierr);
6433   PetscFunctionReturn(0);
6434 }
6435 
6436 /*@
6437   DMPlexGetVertexNumbering - Get a global certex numbering for all vertices on this process
6438 
6439   Input Parameter:
6440 . dm   - The DMPlex object
6441 
6442   Output Parameter:
6443 . globalVertexNumbers - Global vertex numbers for all vertices on this process
6444 
6445   Level: developer
6446 
6447 .seealso DMPlexGetCellNumbering()
6448 @*/
6449 PetscErrorCode DMPlexGetVertexNumbering(DM dm, IS *globalVertexNumbers)
6450 {
6451   DM_Plex       *mesh = (DM_Plex*) dm->data;
6452   PetscErrorCode ierr;
6453 
6454   PetscFunctionBegin;
6455   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6456   if (!mesh->globalVertexNumbers) {ierr = DMPlexCreateVertexNumbering_Internal(dm, PETSC_FALSE, &mesh->globalVertexNumbers);CHKERRQ(ierr);}
6457   *globalVertexNumbers = mesh->globalVertexNumbers;
6458   PetscFunctionReturn(0);
6459 }
6460 
6461 /*@
6462   DMPlexCreatePointNumbering - Create a global numbering for all points on this process
6463 
6464   Input Parameter:
6465 . dm   - The DMPlex object
6466 
6467   Output Parameter:
6468 . globalPointNumbers - Global numbers for all points on this process
6469 
6470   Level: developer
6471 
6472 .seealso DMPlexGetCellNumbering()
6473 @*/
6474 PetscErrorCode DMPlexCreatePointNumbering(DM dm, IS *globalPointNumbers)
6475 {
6476   IS             nums[4];
6477   PetscInt       depths[4], gdepths[4], starts[4];
6478   PetscInt       depth, d, shift = 0;
6479   PetscErrorCode ierr;
6480 
6481   PetscFunctionBegin;
6482   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6483   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
6484   /* For unstratified meshes use dim instead of depth */
6485   if (depth < 0) {ierr = DMGetDimension(dm, &depth);CHKERRQ(ierr);}
6486   for (d = 0; d <= depth; ++d) {
6487     PetscInt end;
6488 
6489     depths[d] = depth-d;
6490     ierr = DMPlexGetDepthStratum(dm, depths[d], &starts[d], &end);CHKERRQ(ierr);
6491     if (!(starts[d]-end)) { starts[d] = depths[d] = -1; }
6492   }
6493   ierr = PetscSortIntWithArray(depth+1, starts, depths);CHKERRQ(ierr);
6494   ierr = MPIU_Allreduce(depths, gdepths, depth+1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject) dm));CHKERRQ(ierr);
6495   for (d = 0; d <= depth; ++d) {
6496     if (starts[d] >= 0 && depths[d] != gdepths[d]) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Expected depth %D, found %D",depths[d],gdepths[d]);
6497   }
6498   for (d = 0; d <= depth; ++d) {
6499     PetscInt pStart, pEnd, gsize;
6500 
6501     ierr = DMPlexGetDepthStratum(dm, gdepths[d], &pStart, &pEnd);CHKERRQ(ierr);
6502     ierr = DMPlexCreateNumbering_Internal(dm, pStart, pEnd, shift, &gsize, dm->sf, &nums[d]);CHKERRQ(ierr);
6503     shift += gsize;
6504   }
6505   ierr = ISConcatenate(PetscObjectComm((PetscObject) dm), depth+1, nums, globalPointNumbers);CHKERRQ(ierr);
6506   for (d = 0; d <= depth; ++d) {ierr = ISDestroy(&nums[d]);CHKERRQ(ierr);}
6507   PetscFunctionReturn(0);
6508 }
6509 
6510 
6511 /*@
6512   DMPlexCreateRankField - Create a cell field whose value is the rank of the owner
6513 
6514   Input Parameter:
6515 . dm - The DMPlex object
6516 
6517   Output Parameter:
6518 . ranks - The rank field
6519 
6520   Options Database Keys:
6521 . -dm_partition_view - Adds the rank field into the DM output from -dm_view using the same viewer
6522 
6523   Level: intermediate
6524 
6525 .seealso: DMView()
6526 @*/
6527 PetscErrorCode DMPlexCreateRankField(DM dm, Vec *ranks)
6528 {
6529   DM             rdm;
6530   PetscFE        fe;
6531   PetscScalar   *r;
6532   PetscMPIInt    rank;
6533   PetscInt       dim, cStart, cEnd, c;
6534   PetscErrorCode ierr;
6535 
6536   PetscFunctionBeginUser;
6537   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6538   PetscValidPointer(ranks, 2);
6539   ierr = MPI_Comm_rank(PetscObjectComm((PetscObject) dm), &rank);CHKERRQ(ierr);
6540   ierr = DMClone(dm, &rdm);CHKERRQ(ierr);
6541   ierr = DMGetDimension(rdm, &dim);CHKERRQ(ierr);
6542   ierr = PetscFECreateDefault(PetscObjectComm((PetscObject) rdm), dim, 1, PETSC_TRUE, "PETSc___rank_", -1, &fe);CHKERRQ(ierr);
6543   ierr = PetscObjectSetName((PetscObject) fe, "rank");CHKERRQ(ierr);
6544   ierr = DMSetField(rdm, 0, NULL, (PetscObject) fe);CHKERRQ(ierr);
6545   ierr = PetscFEDestroy(&fe);CHKERRQ(ierr);
6546   ierr = DMCreateDS(rdm);CHKERRQ(ierr);
6547   ierr = DMPlexGetHeightStratum(rdm, 0, &cStart, &cEnd);CHKERRQ(ierr);
6548   ierr = DMCreateGlobalVector(rdm, ranks);CHKERRQ(ierr);
6549   ierr = PetscObjectSetName((PetscObject) *ranks, "partition");CHKERRQ(ierr);
6550   ierr = VecGetArray(*ranks, &r);CHKERRQ(ierr);
6551   for (c = cStart; c < cEnd; ++c) {
6552     PetscScalar *lr;
6553 
6554     ierr = DMPlexPointGlobalRef(rdm, c, r, &lr);CHKERRQ(ierr);
6555     *lr = rank;
6556   }
6557   ierr = VecRestoreArray(*ranks, &r);CHKERRQ(ierr);
6558   ierr = DMDestroy(&rdm);CHKERRQ(ierr);
6559   PetscFunctionReturn(0);
6560 }
6561 
6562 /*@
6563   DMPlexCreateLabelField - Create a cell field whose value is the label value for that cell
6564 
6565   Input Parameters:
6566 + dm    - The DMPlex
6567 - label - The DMLabel
6568 
6569   Output Parameter:
6570 . val - The label value field
6571 
6572   Options Database Keys:
6573 . -dm_label_view - Adds the label value field into the DM output from -dm_view using the same viewer
6574 
6575   Level: intermediate
6576 
6577 .seealso: DMView()
6578 @*/
6579 PetscErrorCode DMPlexCreateLabelField(DM dm, DMLabel label, Vec *val)
6580 {
6581   DM             rdm;
6582   PetscFE        fe;
6583   PetscScalar   *v;
6584   PetscInt       dim, cStart, cEnd, c;
6585   PetscErrorCode ierr;
6586 
6587   PetscFunctionBeginUser;
6588   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6589   PetscValidPointer(label, 2);
6590   PetscValidPointer(val, 3);
6591   ierr = DMClone(dm, &rdm);CHKERRQ(ierr);
6592   ierr = DMGetDimension(rdm, &dim);CHKERRQ(ierr);
6593   ierr = PetscFECreateDefault(PetscObjectComm((PetscObject) rdm), dim, 1, PETSC_TRUE, "PETSc___label_value_", -1, &fe);CHKERRQ(ierr);
6594   ierr = PetscObjectSetName((PetscObject) fe, "label_value");CHKERRQ(ierr);
6595   ierr = DMSetField(rdm, 0, NULL, (PetscObject) fe);CHKERRQ(ierr);
6596   ierr = PetscFEDestroy(&fe);CHKERRQ(ierr);
6597   ierr = DMCreateDS(rdm);CHKERRQ(ierr);
6598   ierr = DMPlexGetHeightStratum(rdm, 0, &cStart, &cEnd);CHKERRQ(ierr);
6599   ierr = DMCreateGlobalVector(rdm, val);CHKERRQ(ierr);
6600   ierr = PetscObjectSetName((PetscObject) *val, "label_value");CHKERRQ(ierr);
6601   ierr = VecGetArray(*val, &v);CHKERRQ(ierr);
6602   for (c = cStart; c < cEnd; ++c) {
6603     PetscScalar *lv;
6604     PetscInt     cval;
6605 
6606     ierr = DMPlexPointGlobalRef(rdm, c, v, &lv);CHKERRQ(ierr);
6607     ierr = DMLabelGetValue(label, c, &cval);CHKERRQ(ierr);
6608     *lv = cval;
6609   }
6610   ierr = VecRestoreArray(*val, &v);CHKERRQ(ierr);
6611   ierr = DMDestroy(&rdm);CHKERRQ(ierr);
6612   PetscFunctionReturn(0);
6613 }
6614 
6615 /*@
6616   DMPlexCheckSymmetry - Check that the adjacency information in the mesh is symmetric.
6617 
6618   Input Parameter:
6619 . dm - The DMPlex object
6620 
6621   Note: This is a useful diagnostic when creating meshes programmatically.
6622 
6623   Level: developer
6624 
6625 .seealso: DMCreate(), DMPlexCheckSkeleton(), DMPlexCheckFaces()
6626 @*/
6627 PetscErrorCode DMPlexCheckSymmetry(DM dm)
6628 {
6629   PetscSection    coneSection, supportSection;
6630   const PetscInt *cone, *support;
6631   PetscInt        coneSize, c, supportSize, s;
6632   PetscInt        pStart, pEnd, p, pp, csize, ssize;
6633   PetscBool       storagecheck = PETSC_TRUE;
6634   PetscErrorCode  ierr;
6635 
6636   PetscFunctionBegin;
6637   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6638   ierr = DMPlexGetConeSection(dm, &coneSection);CHKERRQ(ierr);
6639   ierr = DMPlexGetSupportSection(dm, &supportSection);CHKERRQ(ierr);
6640   /* Check that point p is found in the support of its cone points, and vice versa */
6641   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
6642   for (p = pStart; p < pEnd; ++p) {
6643     ierr = DMPlexGetConeSize(dm, p, &coneSize);CHKERRQ(ierr);
6644     ierr = DMPlexGetCone(dm, p, &cone);CHKERRQ(ierr);
6645     for (c = 0; c < coneSize; ++c) {
6646       PetscBool dup = PETSC_FALSE;
6647       PetscInt  d;
6648       for (d = c-1; d >= 0; --d) {
6649         if (cone[c] == cone[d]) {dup = PETSC_TRUE; break;}
6650       }
6651       ierr = DMPlexGetSupportSize(dm, cone[c], &supportSize);CHKERRQ(ierr);
6652       ierr = DMPlexGetSupport(dm, cone[c], &support);CHKERRQ(ierr);
6653       for (s = 0; s < supportSize; ++s) {
6654         if (support[s] == p) break;
6655       }
6656       if ((s >= supportSize) || (dup && (support[s+1] != p))) {
6657         ierr = PetscPrintf(PETSC_COMM_SELF, "p: %D cone: ", p);CHKERRQ(ierr);
6658         for (s = 0; s < coneSize; ++s) {
6659           ierr = PetscPrintf(PETSC_COMM_SELF, "%D, ", cone[s]);CHKERRQ(ierr);
6660         }
6661         ierr = PetscPrintf(PETSC_COMM_SELF, "\n");CHKERRQ(ierr);
6662         ierr = PetscPrintf(PETSC_COMM_SELF, "p: %D support: ", cone[c]);CHKERRQ(ierr);
6663         for (s = 0; s < supportSize; ++s) {
6664           ierr = PetscPrintf(PETSC_COMM_SELF, "%D, ", support[s]);CHKERRQ(ierr);
6665         }
6666         ierr = PetscPrintf(PETSC_COMM_SELF, "\n");CHKERRQ(ierr);
6667         if (dup) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D not repeatedly found in support of repeated cone point %D", p, cone[c]);
6668         else SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D not found in support of cone point %D", p, cone[c]);
6669       }
6670     }
6671     ierr = DMPlexGetTreeParent(dm, p, &pp, NULL);CHKERRQ(ierr);
6672     if (p != pp) { storagecheck = PETSC_FALSE; continue; }
6673     ierr = DMPlexGetSupportSize(dm, p, &supportSize);CHKERRQ(ierr);
6674     ierr = DMPlexGetSupport(dm, p, &support);CHKERRQ(ierr);
6675     for (s = 0; s < supportSize; ++s) {
6676       ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
6677       ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6678       for (c = 0; c < coneSize; ++c) {
6679         ierr = DMPlexGetTreeParent(dm, cone[c], &pp, NULL);CHKERRQ(ierr);
6680         if (cone[c] != pp) { c = 0; break; }
6681         if (cone[c] == p) break;
6682       }
6683       if (c >= coneSize) {
6684         ierr = PetscPrintf(PETSC_COMM_SELF, "p: %D support: ", p);CHKERRQ(ierr);
6685         for (c = 0; c < supportSize; ++c) {
6686           ierr = PetscPrintf(PETSC_COMM_SELF, "%D, ", support[c]);CHKERRQ(ierr);
6687         }
6688         ierr = PetscPrintf(PETSC_COMM_SELF, "\n");CHKERRQ(ierr);
6689         ierr = PetscPrintf(PETSC_COMM_SELF, "p: %D cone: ", support[s]);CHKERRQ(ierr);
6690         for (c = 0; c < coneSize; ++c) {
6691           ierr = PetscPrintf(PETSC_COMM_SELF, "%D, ", cone[c]);CHKERRQ(ierr);
6692         }
6693         ierr = PetscPrintf(PETSC_COMM_SELF, "\n");CHKERRQ(ierr);
6694         SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D not found in cone of support point %D", p, support[s]);
6695       }
6696     }
6697   }
6698   if (storagecheck) {
6699     ierr = PetscSectionGetStorageSize(coneSection, &csize);CHKERRQ(ierr);
6700     ierr = PetscSectionGetStorageSize(supportSection, &ssize);CHKERRQ(ierr);
6701     if (csize != ssize) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Total cone size %D != Total support size %D", csize, ssize);
6702   }
6703   PetscFunctionReturn(0);
6704 }
6705 
6706 /*@
6707   DMPlexCheckSkeleton - Check that each cell has the correct number of vertices
6708 
6709   Input Parameters:
6710 + dm - The DMPlex object
6711 - cellHeight - Normally 0
6712 
6713   Note: This is a useful diagnostic when creating meshes programmatically.
6714   Currently applicable only to homogeneous simplex or tensor meshes.
6715 
6716   Level: developer
6717 
6718 .seealso: DMCreate(), DMPlexCheckSymmetry(), DMPlexCheckFaces()
6719 @*/
6720 PetscErrorCode DMPlexCheckSkeleton(DM dm, PetscInt cellHeight)
6721 {
6722   PetscInt       dim, numCorners, numHybridCorners, vStart, vEnd, cStart, cEnd, cMax, c;
6723   PetscBool      isSimplex = PETSC_FALSE;
6724   PetscErrorCode ierr;
6725 
6726   PetscFunctionBegin;
6727   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6728   ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr);
6729   ierr = DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd);CHKERRQ(ierr);
6730   if (cStart < cEnd) {
6731     ierr = DMPlexGetConeSize(dm, cStart, &c);CHKERRQ(ierr);
6732     isSimplex = c == dim+1 ? PETSC_TRUE : PETSC_FALSE;
6733   }
6734   switch (dim) {
6735   case 1: numCorners = isSimplex ? 2 : 2; numHybridCorners = isSimplex ? 2 : 2; break;
6736   case 2: numCorners = isSimplex ? 3 : 4; numHybridCorners = isSimplex ? 4 : 4; break;
6737   case 3: numCorners = isSimplex ? 4 : 8; numHybridCorners = isSimplex ? 6 : 8; break;
6738   default:
6739     SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_OUTOFRANGE, "Cannot handle meshes of dimension %D", dim);
6740   }
6741   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
6742   ierr = DMPlexGetHybridBounds(dm, &cMax, NULL, NULL, NULL);CHKERRQ(ierr);
6743   cMax = cMax >= 0 ? cMax : cEnd;
6744   for (c = cStart; c < cMax; ++c) {
6745     PetscInt *closure = NULL, closureSize, cl, coneSize = 0;
6746 
6747     ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
6748     for (cl = 0; cl < closureSize*2; cl += 2) {
6749       const PetscInt p = closure[cl];
6750       if ((p >= vStart) && (p < vEnd)) ++coneSize;
6751     }
6752     ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
6753     if (coneSize != numCorners) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cell %D has  %D vertices != %D", c, coneSize, numCorners);
6754   }
6755   for (c = cMax; c < cEnd; ++c) {
6756     PetscInt *closure = NULL, closureSize, cl, coneSize = 0;
6757 
6758     ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
6759     for (cl = 0; cl < closureSize*2; cl += 2) {
6760       const PetscInt p = closure[cl];
6761       if ((p >= vStart) && (p < vEnd)) ++coneSize;
6762     }
6763     ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
6764     if (coneSize > numHybridCorners) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Hybrid cell %D has  %D vertices > %D", c, coneSize, numHybridCorners);
6765   }
6766   PetscFunctionReturn(0);
6767 }
6768 
6769 /*@
6770   DMPlexCheckFaces - Check that the faces of each cell give a vertex order this is consistent with what we expect from the cell type
6771 
6772   Input Parameters:
6773 + dm - The DMPlex object
6774 - cellHeight - Normally 0
6775 
6776   Note: This is a useful diagnostic when creating meshes programmatically.
6777 
6778   Level: developer
6779 
6780 .seealso: DMCreate(), DMPlexCheckSymmetry(), DMPlexCheckSkeleton()
6781 @*/
6782 PetscErrorCode DMPlexCheckFaces(DM dm, PetscInt cellHeight)
6783 {
6784   PetscInt       pMax[4];
6785   PetscInt       dim, depth, vStart, vEnd, cStart, cEnd, c, h;
6786   PetscErrorCode ierr;
6787 
6788   PetscFunctionBegin;
6789   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6790   ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr);
6791   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
6792   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
6793   ierr = DMPlexGetHybridBounds(dm, &pMax[dim], &pMax[dim-1], &pMax[1], &pMax[0]);CHKERRQ(ierr);
6794   for (h = cellHeight; h < PetscMin(depth, dim); ++h) {
6795     ierr = DMPlexGetHeightStratum(dm, h, &cStart, &cEnd);CHKERRQ(ierr);
6796     for (c = cStart; c < cEnd; ++c) {
6797       const PetscInt *cone, *ornt, *faces;
6798       PetscInt        numFaces, faceSize, coneSize,f;
6799       PetscInt       *closure = NULL, closureSize, cl, numCorners = 0;
6800 
6801       if (pMax[dim-h] >= 0 && c >= pMax[dim-h]) continue;
6802       ierr = DMPlexGetConeSize(dm, c, &coneSize);CHKERRQ(ierr);
6803       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
6804       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
6805       ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
6806       for (cl = 0; cl < closureSize*2; cl += 2) {
6807         const PetscInt p = closure[cl];
6808         if ((p >= vStart) && (p < vEnd)) closure[numCorners++] = p;
6809       }
6810       ierr = DMPlexGetRawFaces_Internal(dm, dim-h, numCorners, closure, &numFaces, &faceSize, &faces);CHKERRQ(ierr);
6811       if (coneSize != numFaces) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cell %D has %D faces but should have %D", c, coneSize, numFaces);
6812       for (f = 0; f < numFaces; ++f) {
6813         PetscInt *fclosure = NULL, fclosureSize, cl, fnumCorners = 0, v;
6814 
6815         ierr = DMPlexGetTransitiveClosure_Internal(dm, cone[f], ornt[f], PETSC_TRUE, &fclosureSize, &fclosure);CHKERRQ(ierr);
6816         for (cl = 0; cl < fclosureSize*2; cl += 2) {
6817           const PetscInt p = fclosure[cl];
6818           if ((p >= vStart) && (p < vEnd)) fclosure[fnumCorners++] = p;
6819         }
6820         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);
6821         for (v = 0; v < fnumCorners; ++v) {
6822           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]);
6823         }
6824         ierr = DMPlexRestoreTransitiveClosure(dm, cone[f], PETSC_TRUE, &fclosureSize, &fclosure);CHKERRQ(ierr);
6825       }
6826       ierr = DMPlexRestoreFaces_Internal(dm, dim, c, &numFaces, &faceSize, &faces);CHKERRQ(ierr);
6827       ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
6828     }
6829   }
6830   PetscFunctionReturn(0);
6831 }
6832 
6833 /*@
6834   DMPlexCheckGeometry - Check the geometry of mesh cells
6835 
6836   Input Parameter:
6837 . dm - The DMPlex object
6838 
6839   Note: This is a useful diagnostic when creating meshes programmatically.
6840 
6841   Level: developer
6842 
6843 .seealso: DMCreate(), DMCheckSymmetry(), DMCheckSkeleton(), DMCheckFaces()
6844 @*/
6845 PetscErrorCode DMPlexCheckGeometry(DM dm)
6846 {
6847   PetscReal      detJ, J[9], refVol = 1.0;
6848   PetscReal      vol;
6849   PetscInt       dim, depth, d, cStart, cEnd, c;
6850   PetscErrorCode ierr;
6851 
6852   PetscFunctionBegin;
6853   ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr);
6854   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
6855   for (d = 0; d < dim; ++d) refVol *= 2.0;
6856   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
6857   for (c = cStart; c < cEnd; ++c) {
6858     ierr = DMPlexComputeCellGeometryFEM(dm, c, NULL, NULL, J, NULL, &detJ);CHKERRQ(ierr);
6859     if (detJ <= 0.0) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Mesh cell %D is inverted, |J| = %g", c, (double) detJ);
6860     ierr = PetscInfo2(dm, "Cell %D FEM Volume %g\n", c, (double) detJ*refVol);CHKERRQ(ierr);
6861     if (depth > 1) {
6862       ierr = DMPlexComputeCellGeometryFVM(dm, c, &vol, NULL, NULL);CHKERRQ(ierr);
6863       if (vol <= 0.0) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Mesh cell %d is inverted, vol = %g", c, (double) vol);
6864       ierr = PetscInfo2(dm, "Cell %D FVM Volume %g\n", c, (double) vol);CHKERRQ(ierr);
6865     }
6866   }
6867   PetscFunctionReturn(0);
6868 }
6869 
6870 static PetscErrorCode DMPlexAreAllConePointsInArray_Private(DM dm, PetscInt p, PetscInt npoints, const PetscInt *points, PetscInt *missingPoint)
6871 {
6872   PetscInt i,l,n;
6873   const PetscInt *cone;
6874   PetscErrorCode ierr;
6875 
6876   PetscFunctionBegin;
6877   *missingPoint = -1;
6878   ierr = DMPlexGetConeSize(dm, p, &n);CHKERRQ(ierr);
6879   ierr = DMPlexGetCone(dm, p, &cone);CHKERRQ(ierr);
6880   for (i=0; i<n; i++) {
6881     ierr = PetscFindInt(cone[i], npoints, points, &l);CHKERRQ(ierr);
6882     if (l < 0) {
6883       *missingPoint = cone[i];
6884       break;
6885     }
6886   }
6887   PetscFunctionReturn(0);
6888 }
6889 
6890 /*@
6891   DMPlexCheckPointSF - Check that several sufficient conditions are met for the point SF of this plex.
6892 
6893   Input Parameters:
6894 . dm - The DMPlex object
6895 
6896   Note: This is mainly intended for debugging/testing purposes.
6897 
6898   Level: developer
6899 
6900 .seealso: DMGetPointSF(), DMPlexCheckSymmetry(), DMPlexCheckSkeleton(), DMPlexCheckFaces()
6901 @*/
6902 PetscErrorCode DMPlexCheckPointSF(DM dm)
6903 {
6904   PetscSF sf;
6905   PetscInt d,depth,i,nleaves,p,plo,phi,missingPoint;
6906   const PetscInt *locals;
6907   PetscErrorCode ierr;
6908 
6909   PetscFunctionBegin;
6910   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6911   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
6912   ierr = DMGetPointSF(dm, &sf);CHKERRQ(ierr);
6913   ierr = PetscSFGetGraph(sf, NULL, &nleaves, &locals, NULL);CHKERRQ(ierr);
6914 
6915   /* 1) check there are no faces in 2D, cells in 3D, in interface */
6916   ierr = DMPlexGetVTKCellHeight(dm, &d);CHKERRQ(ierr);
6917   ierr = DMPlexGetHeightStratum(dm, d, &plo, &phi);CHKERRQ(ierr);
6918   for (i=0; i<nleaves; i++) {
6919     p = locals[i];
6920     if (p >= plo && p < phi) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "point SF contains %d which is a cell",p);
6921   }
6922 
6923   /* 2) if some point is in interface, then all its cone points must be also in interface  */
6924   for (i=0; i<nleaves; i++) {
6925     p = locals[i];
6926     ierr = DMPlexAreAllConePointsInArray_Private(dm, p, nleaves, locals, &missingPoint);CHKERRQ(ierr);
6927     if (missingPoint >= 0) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "point SF contains %d but not %d from its cone",p,missingPoint);
6928   }
6929   PetscFunctionReturn(0);
6930 }
6931 
6932 typedef struct cell_stats
6933 {
6934   PetscReal min, max, sum, squaresum;
6935   PetscInt  count;
6936 } cell_stats_t;
6937 
6938 static void cell_stats_reduce(void *a, void *b, int * len, MPI_Datatype *datatype)
6939 {
6940   PetscInt i, N = *len;
6941 
6942   for (i = 0; i < N; i++) {
6943     cell_stats_t *A = (cell_stats_t *) a;
6944     cell_stats_t *B = (cell_stats_t *) b;
6945 
6946     B->min = PetscMin(A->min,B->min);
6947     B->max = PetscMax(A->max,B->max);
6948     B->sum += A->sum;
6949     B->squaresum += A->squaresum;
6950     B->count += A->count;
6951   }
6952 }
6953 
6954 /*@
6955   DMPlexCheckCellShape - Checks the Jacobian of the mapping and computes some minimal statistics.
6956 
6957   Input Parameters:
6958 + dm - The DMPlex object
6959 - output - If true, statistics will be displayed on stdout
6960 
6961   Note: This is mainly intended for debugging/testing purposes.
6962 
6963   Level: developer
6964 
6965 .seealso: DMPlexCheckSymmetry(), DMPlexCheckSkeleton(), DMPlexCheckFaces()
6966 @*/
6967 PetscErrorCode DMPlexCheckCellShape(DM dm, PetscBool output)
6968 {
6969   PetscMPIInt    rank,size;
6970   PetscInt       dim, c, cStart, cEnd, cMax, count = 0;
6971   cell_stats_t   stats, globalStats;
6972   PetscReal      *J, *invJ, min = 0, max = 0, mean = 0, stdev = 0;
6973   MPI_Comm       comm = PetscObjectComm((PetscObject)dm);
6974   DM             dmCoarse;
6975   PetscErrorCode ierr;
6976 
6977   PetscFunctionBegin;
6978   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6979   stats.min   = PETSC_MAX_REAL;
6980   stats.max   = PETSC_MIN_REAL;
6981   stats.sum   = stats.squaresum = 0.;
6982   stats.count = 0;
6983 
6984   ierr = DMGetCoordinateDim(dm,&dim);CHKERRQ(ierr);
6985   ierr = PetscMalloc2(dim * dim, &J, dim * dim, &invJ);CHKERRQ(ierr);
6986   ierr = DMPlexGetHeightStratum(dm,0,&cStart,&cEnd);CHKERRQ(ierr);
6987   ierr = DMPlexGetHybridBounds(dm,&cMax,NULL,NULL,NULL);CHKERRQ(ierr);
6988   cMax = cMax < 0 ? cEnd : cMax;
6989   for (c = cStart; c < cMax; c++) {
6990     PetscInt  i;
6991     PetscReal frobJ = 0., frobInvJ = 0., cond2, cond, detJ;
6992 
6993     ierr = DMPlexComputeCellGeometryAffineFEM(dm,c,NULL,J,invJ,&detJ);CHKERRQ(ierr);
6994     if (detJ < 0.0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Mesh cell %D is inverted", c);
6995     for (i = 0; i < dim * dim; i++) {
6996       frobJ    += J[i] * J[i];
6997       frobInvJ += invJ[i] * invJ[i];
6998     }
6999     cond2 = frobJ * frobInvJ;
7000     cond  = PetscSqrtReal(cond2);
7001 
7002     stats.min        = PetscMin(stats.min,cond);
7003     stats.max        = PetscMax(stats.max,cond);
7004     stats.sum       += cond;
7005     stats.squaresum += cond2;
7006     stats.count++;
7007   }
7008 
7009   ierr = MPI_Comm_size(comm,&size);CHKERRQ(ierr);
7010   if (size > 1) {
7011     PetscMPIInt   blockLengths[2] = {4,1};
7012     MPI_Aint      blockOffsets[2] = {offsetof(cell_stats_t,min),offsetof(cell_stats_t,count)};
7013     MPI_Datatype  blockTypes[2]   = {MPIU_REAL,MPIU_INT}, statType;
7014     MPI_Op        statReduce;
7015 
7016     ierr = MPI_Type_create_struct(2,blockLengths,blockOffsets,blockTypes,&statType);CHKERRQ(ierr);
7017     ierr = MPI_Type_commit(&statType);CHKERRQ(ierr);
7018     ierr = MPI_Op_create(cell_stats_reduce, PETSC_TRUE, &statReduce);CHKERRQ(ierr);
7019     ierr = MPI_Reduce(&stats,&globalStats,1,statType,statReduce,0,comm);CHKERRQ(ierr);
7020     ierr = MPI_Op_free(&statReduce);CHKERRQ(ierr);
7021     ierr = MPI_Type_free(&statType);CHKERRQ(ierr);
7022   } else {
7023     ierr = PetscArraycpy(&globalStats,&stats,1);CHKERRQ(ierr);
7024   }
7025 
7026   ierr = MPI_Comm_rank(comm,&rank);CHKERRQ(ierr);
7027   if (!rank) {
7028     count = globalStats.count;
7029     min   = globalStats.min;
7030     max   = globalStats.max;
7031     mean  = globalStats.sum / globalStats.count;
7032     stdev = globalStats.count > 1 ? PetscSqrtReal(PetscMax((globalStats.squaresum - globalStats.count * mean * mean) / (globalStats.count - 1),0)) : 0.0;
7033   }
7034 
7035   if (output) {
7036     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);
7037   }
7038   ierr = PetscFree2(J,invJ);CHKERRQ(ierr);
7039 
7040   ierr = DMGetCoarseDM(dm,&dmCoarse);CHKERRQ(ierr);
7041   if (dmCoarse) {
7042     PetscBool isplex;
7043 
7044     ierr = PetscObjectTypeCompare((PetscObject)dmCoarse,DMPLEX,&isplex);CHKERRQ(ierr);
7045     if (isplex) {
7046       ierr = DMPlexCheckCellShape(dmCoarse,output);CHKERRQ(ierr);
7047     }
7048   }
7049   PetscFunctionReturn(0);
7050 }
7051 
7052 /* Pointwise interpolation
7053      Just code FEM for now
7054      u^f = I u^c
7055      sum_k u^f_k phi^f_k = I sum_j u^c_j phi^c_j
7056      u^f_i = sum_j psi^f_i I phi^c_j u^c_j
7057      I_{ij} = psi^f_i phi^c_j
7058 */
7059 PetscErrorCode DMCreateInterpolation_Plex(DM dmCoarse, DM dmFine, Mat *interpolation, Vec *scaling)
7060 {
7061   PetscSection   gsc, gsf;
7062   PetscInt       m, n;
7063   void          *ctx;
7064   DM             cdm;
7065   PetscBool      regular, ismatis;
7066   PetscErrorCode ierr;
7067 
7068   PetscFunctionBegin;
7069   ierr = DMGetGlobalSection(dmFine, &gsf);CHKERRQ(ierr);
7070   ierr = PetscSectionGetConstrainedStorageSize(gsf, &m);CHKERRQ(ierr);
7071   ierr = DMGetGlobalSection(dmCoarse, &gsc);CHKERRQ(ierr);
7072   ierr = PetscSectionGetConstrainedStorageSize(gsc, &n);CHKERRQ(ierr);
7073 
7074   ierr = PetscStrcmp(dmCoarse->mattype, MATIS, &ismatis);CHKERRQ(ierr);
7075   ierr = MatCreate(PetscObjectComm((PetscObject) dmCoarse), interpolation);CHKERRQ(ierr);
7076   ierr = MatSetSizes(*interpolation, m, n, PETSC_DETERMINE, PETSC_DETERMINE);CHKERRQ(ierr);
7077   ierr = MatSetType(*interpolation, ismatis ? MATAIJ : dmCoarse->mattype);CHKERRQ(ierr);
7078   ierr = DMGetApplicationContext(dmFine, &ctx);CHKERRQ(ierr);
7079 
7080   ierr = DMGetCoarseDM(dmFine, &cdm);CHKERRQ(ierr);
7081   ierr = DMPlexGetRegularRefinement(dmFine, &regular);CHKERRQ(ierr);
7082   if (regular && cdm == dmCoarse) {ierr = DMPlexComputeInterpolatorNested(dmCoarse, dmFine, *interpolation, ctx);CHKERRQ(ierr);}
7083   else                            {ierr = DMPlexComputeInterpolatorGeneral(dmCoarse, dmFine, *interpolation, ctx);CHKERRQ(ierr);}
7084   ierr = MatViewFromOptions(*interpolation, NULL, "-interp_mat_view");CHKERRQ(ierr);
7085   if (scaling) {
7086     /* Use naive scaling */
7087     ierr = DMCreateInterpolationScale(dmCoarse, dmFine, *interpolation, scaling);CHKERRQ(ierr);
7088   }
7089   PetscFunctionReturn(0);
7090 }
7091 
7092 PetscErrorCode DMCreateInjection_Plex(DM dmCoarse, DM dmFine, Mat *mat)
7093 {
7094   PetscErrorCode ierr;
7095   VecScatter     ctx;
7096 
7097   PetscFunctionBegin;
7098   ierr = DMPlexComputeInjectorFEM(dmCoarse, dmFine, &ctx, NULL);CHKERRQ(ierr);
7099   ierr = MatCreateScatter(PetscObjectComm((PetscObject)ctx), ctx, mat);CHKERRQ(ierr);
7100   ierr = VecScatterDestroy(&ctx);CHKERRQ(ierr);
7101   PetscFunctionReturn(0);
7102 }
7103 
7104 PetscErrorCode DMCreateMassMatrix_Plex(DM dmCoarse, DM dmFine, Mat *mass)
7105 {
7106   PetscSection   gsc, gsf;
7107   PetscInt       m, n;
7108   void          *ctx;
7109   DM             cdm;
7110   PetscBool      regular;
7111   PetscErrorCode ierr;
7112 
7113   PetscFunctionBegin;
7114   ierr = DMGetGlobalSection(dmFine, &gsf);CHKERRQ(ierr);
7115   ierr = PetscSectionGetConstrainedStorageSize(gsf, &m);CHKERRQ(ierr);
7116   ierr = DMGetGlobalSection(dmCoarse, &gsc);CHKERRQ(ierr);
7117   ierr = PetscSectionGetConstrainedStorageSize(gsc, &n);CHKERRQ(ierr);
7118 
7119   ierr = MatCreate(PetscObjectComm((PetscObject) dmCoarse), mass);CHKERRQ(ierr);
7120   ierr = MatSetSizes(*mass, m, n, PETSC_DETERMINE, PETSC_DETERMINE);CHKERRQ(ierr);
7121   ierr = MatSetType(*mass, dmCoarse->mattype);CHKERRQ(ierr);
7122   ierr = DMGetApplicationContext(dmFine, &ctx);CHKERRQ(ierr);
7123 
7124   ierr = DMGetCoarseDM(dmFine, &cdm);CHKERRQ(ierr);
7125   ierr = DMPlexGetRegularRefinement(dmFine, &regular);CHKERRQ(ierr);
7126   if (regular && cdm == dmCoarse) {ierr = DMPlexComputeMassMatrixNested(dmCoarse, dmFine, *mass, ctx);CHKERRQ(ierr);}
7127   else                            {ierr = DMPlexComputeMassMatrixGeneral(dmCoarse, dmFine, *mass, ctx);CHKERRQ(ierr);}
7128   ierr = MatViewFromOptions(*mass, NULL, "-mass_mat_view");CHKERRQ(ierr);
7129   PetscFunctionReturn(0);
7130 }
7131 
7132 /*@
7133   DMPlexGetRegularRefinement - Get the flag indicating that this mesh was obtained by regular refinement from its coarse mesh
7134 
7135   Input Parameter:
7136 . dm - The DMPlex object
7137 
7138   Output Parameter:
7139 . regular - The flag
7140 
7141   Level: intermediate
7142 
7143 .seealso: DMPlexSetRegularRefinement()
7144 @*/
7145 PetscErrorCode DMPlexGetRegularRefinement(DM dm, PetscBool *regular)
7146 {
7147   PetscFunctionBegin;
7148   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7149   PetscValidPointer(regular, 2);
7150   *regular = ((DM_Plex *) dm->data)->regularRefinement;
7151   PetscFunctionReturn(0);
7152 }
7153 
7154 /*@
7155   DMPlexSetRegularRefinement - Set the flag indicating that this mesh was obtained by regular refinement from its coarse mesh
7156 
7157   Input Parameters:
7158 + dm - The DMPlex object
7159 - regular - The flag
7160 
7161   Level: intermediate
7162 
7163 .seealso: DMPlexGetRegularRefinement()
7164 @*/
7165 PetscErrorCode DMPlexSetRegularRefinement(DM dm, PetscBool regular)
7166 {
7167   PetscFunctionBegin;
7168   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7169   ((DM_Plex *) dm->data)->regularRefinement = regular;
7170   PetscFunctionReturn(0);
7171 }
7172 
7173 /* anchors */
7174 /*@
7175   DMPlexGetAnchors - Get the layout of the anchor (point-to-point) constraints.  Typically, the user will not have to
7176   call DMPlexGetAnchors() directly: if there are anchors, then DMPlexGetAnchors() is called during DMGetConstraints().
7177 
7178   not collective
7179 
7180   Input Parameters:
7181 . dm - The DMPlex object
7182 
7183   Output Parameters:
7184 + anchorSection - If not NULL, set to the section describing which points anchor the constrained points.
7185 - anchorIS - If not NULL, set to the list of anchors indexed by anchorSection
7186 
7187 
7188   Level: intermediate
7189 
7190 .seealso: DMPlexSetAnchors(), DMGetConstraints(), DMSetConstraints()
7191 @*/
7192 PetscErrorCode DMPlexGetAnchors(DM dm, PetscSection *anchorSection, IS *anchorIS)
7193 {
7194   DM_Plex *plex = (DM_Plex *)dm->data;
7195   PetscErrorCode ierr;
7196 
7197   PetscFunctionBegin;
7198   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7199   if (!plex->anchorSection && !plex->anchorIS && plex->createanchors) {ierr = (*plex->createanchors)(dm);CHKERRQ(ierr);}
7200   if (anchorSection) *anchorSection = plex->anchorSection;
7201   if (anchorIS) *anchorIS = plex->anchorIS;
7202   PetscFunctionReturn(0);
7203 }
7204 
7205 /*@
7206   DMPlexSetAnchors - Set the layout of the local anchor (point-to-point) constraints.  Unlike boundary conditions,
7207   when a point's degrees of freedom in a section are constrained to an outside value, the anchor constraints set a
7208   point's degrees of freedom to be a linear combination of other points' degrees of freedom.
7209 
7210   After specifying the layout of constraints with DMPlexSetAnchors(), one specifies the constraints by calling
7211   DMGetConstraints() and filling in the entries in the constraint matrix.
7212 
7213   collective on dm
7214 
7215   Input Parameters:
7216 + dm - The DMPlex object
7217 . 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).
7218 - anchorIS - The list of all anchor points.  Must have a local communicator (PETSC_COMM_SELF or derivative).
7219 
7220   The reference counts of anchorSection and anchorIS are incremented.
7221 
7222   Level: intermediate
7223 
7224 .seealso: DMPlexGetAnchors(), DMGetConstraints(), DMSetConstraints()
7225 @*/
7226 PetscErrorCode DMPlexSetAnchors(DM dm, PetscSection anchorSection, IS anchorIS)
7227 {
7228   DM_Plex        *plex = (DM_Plex *)dm->data;
7229   PetscMPIInt    result;
7230   PetscErrorCode ierr;
7231 
7232   PetscFunctionBegin;
7233   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7234   if (anchorSection) {
7235     PetscValidHeaderSpecific(anchorSection,PETSC_SECTION_CLASSID,2);
7236     ierr = MPI_Comm_compare(PETSC_COMM_SELF,PetscObjectComm((PetscObject)anchorSection),&result);CHKERRQ(ierr);
7237     if (result != MPI_CONGRUENT && result != MPI_IDENT) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_NOTSAMECOMM,"anchor section must have local communicator");
7238   }
7239   if (anchorIS) {
7240     PetscValidHeaderSpecific(anchorIS,IS_CLASSID,3);
7241     ierr = MPI_Comm_compare(PETSC_COMM_SELF,PetscObjectComm((PetscObject)anchorIS),&result);CHKERRQ(ierr);
7242     if (result != MPI_CONGRUENT && result != MPI_IDENT) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_NOTSAMECOMM,"anchor IS must have local communicator");
7243   }
7244 
7245   ierr = PetscObjectReference((PetscObject)anchorSection);CHKERRQ(ierr);
7246   ierr = PetscSectionDestroy(&plex->anchorSection);CHKERRQ(ierr);
7247   plex->anchorSection = anchorSection;
7248 
7249   ierr = PetscObjectReference((PetscObject)anchorIS);CHKERRQ(ierr);
7250   ierr = ISDestroy(&plex->anchorIS);CHKERRQ(ierr);
7251   plex->anchorIS = anchorIS;
7252 
7253 #if defined(PETSC_USE_DEBUG)
7254   if (anchorIS && anchorSection) {
7255     PetscInt size, a, pStart, pEnd;
7256     const PetscInt *anchors;
7257 
7258     ierr = PetscSectionGetChart(anchorSection,&pStart,&pEnd);CHKERRQ(ierr);
7259     ierr = ISGetLocalSize(anchorIS,&size);CHKERRQ(ierr);
7260     ierr = ISGetIndices(anchorIS,&anchors);CHKERRQ(ierr);
7261     for (a = 0; a < size; a++) {
7262       PetscInt p;
7263 
7264       p = anchors[a];
7265       if (p >= pStart && p < pEnd) {
7266         PetscInt dof;
7267 
7268         ierr = PetscSectionGetDof(anchorSection,p,&dof);CHKERRQ(ierr);
7269         if (dof) {
7270           PetscErrorCode ierr2;
7271 
7272           ierr2 = ISRestoreIndices(anchorIS,&anchors);CHKERRQ(ierr2);
7273           SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Point %D cannot be constrained and an anchor",p);
7274         }
7275       }
7276     }
7277     ierr = ISRestoreIndices(anchorIS,&anchors);CHKERRQ(ierr);
7278   }
7279 #endif
7280   /* reset the generic constraints */
7281   ierr = DMSetDefaultConstraints(dm,NULL,NULL);CHKERRQ(ierr);
7282   PetscFunctionReturn(0);
7283 }
7284 
7285 static PetscErrorCode DMPlexCreateConstraintSection_Anchors(DM dm, PetscSection section, PetscSection *cSec)
7286 {
7287   PetscSection anchorSection;
7288   PetscInt pStart, pEnd, sStart, sEnd, p, dof, numFields, f;
7289   PetscErrorCode ierr;
7290 
7291   PetscFunctionBegin;
7292   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7293   ierr = DMPlexGetAnchors(dm,&anchorSection,NULL);CHKERRQ(ierr);
7294   ierr = PetscSectionCreate(PETSC_COMM_SELF,cSec);CHKERRQ(ierr);
7295   ierr = PetscSectionGetNumFields(section,&numFields);CHKERRQ(ierr);
7296   if (numFields) {
7297     PetscInt f;
7298     ierr = PetscSectionSetNumFields(*cSec,numFields);CHKERRQ(ierr);
7299 
7300     for (f = 0; f < numFields; f++) {
7301       PetscInt numComp;
7302 
7303       ierr = PetscSectionGetFieldComponents(section,f,&numComp);CHKERRQ(ierr);
7304       ierr = PetscSectionSetFieldComponents(*cSec,f,numComp);CHKERRQ(ierr);
7305     }
7306   }
7307   ierr = PetscSectionGetChart(anchorSection,&pStart,&pEnd);CHKERRQ(ierr);
7308   ierr = PetscSectionGetChart(section,&sStart,&sEnd);CHKERRQ(ierr);
7309   pStart = PetscMax(pStart,sStart);
7310   pEnd   = PetscMin(pEnd,sEnd);
7311   pEnd   = PetscMax(pStart,pEnd);
7312   ierr = PetscSectionSetChart(*cSec,pStart,pEnd);CHKERRQ(ierr);
7313   for (p = pStart; p < pEnd; p++) {
7314     ierr = PetscSectionGetDof(anchorSection,p,&dof);CHKERRQ(ierr);
7315     if (dof) {
7316       ierr = PetscSectionGetDof(section,p,&dof);CHKERRQ(ierr);
7317       ierr = PetscSectionSetDof(*cSec,p,dof);CHKERRQ(ierr);
7318       for (f = 0; f < numFields; f++) {
7319         ierr = PetscSectionGetFieldDof(section,p,f,&dof);CHKERRQ(ierr);
7320         ierr = PetscSectionSetFieldDof(*cSec,p,f,dof);CHKERRQ(ierr);
7321       }
7322     }
7323   }
7324   ierr = PetscSectionSetUp(*cSec);CHKERRQ(ierr);
7325   PetscFunctionReturn(0);
7326 }
7327 
7328 static PetscErrorCode DMPlexCreateConstraintMatrix_Anchors(DM dm, PetscSection section, PetscSection cSec, Mat *cMat)
7329 {
7330   PetscSection aSec;
7331   PetscInt pStart, pEnd, p, dof, aDof, aOff, off, nnz, annz, m, n, q, a, offset, *i, *j;
7332   const PetscInt *anchors;
7333   PetscInt numFields, f;
7334   IS aIS;
7335   PetscErrorCode ierr;
7336 
7337   PetscFunctionBegin;
7338   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7339   ierr = PetscSectionGetStorageSize(cSec, &m);CHKERRQ(ierr);
7340   ierr = PetscSectionGetStorageSize(section, &n);CHKERRQ(ierr);
7341   ierr = MatCreate(PETSC_COMM_SELF,cMat);CHKERRQ(ierr);
7342   ierr = MatSetSizes(*cMat,m,n,m,n);CHKERRQ(ierr);
7343   ierr = MatSetType(*cMat,MATSEQAIJ);CHKERRQ(ierr);
7344   ierr = DMPlexGetAnchors(dm,&aSec,&aIS);CHKERRQ(ierr);
7345   ierr = ISGetIndices(aIS,&anchors);CHKERRQ(ierr);
7346   /* cSec will be a subset of aSec and section */
7347   ierr = PetscSectionGetChart(cSec,&pStart,&pEnd);CHKERRQ(ierr);
7348   ierr = PetscMalloc1(m+1,&i);CHKERRQ(ierr);
7349   i[0] = 0;
7350   ierr = PetscSectionGetNumFields(section,&numFields);CHKERRQ(ierr);
7351   for (p = pStart; p < pEnd; p++) {
7352     PetscInt rDof, rOff, r;
7353 
7354     ierr = PetscSectionGetDof(aSec,p,&rDof);CHKERRQ(ierr);
7355     if (!rDof) continue;
7356     ierr = PetscSectionGetOffset(aSec,p,&rOff);CHKERRQ(ierr);
7357     if (numFields) {
7358       for (f = 0; f < numFields; f++) {
7359         annz = 0;
7360         for (r = 0; r < rDof; r++) {
7361           a = anchors[rOff + r];
7362           ierr = PetscSectionGetFieldDof(section,a,f,&aDof);CHKERRQ(ierr);
7363           annz += aDof;
7364         }
7365         ierr = PetscSectionGetFieldDof(cSec,p,f,&dof);CHKERRQ(ierr);
7366         ierr = PetscSectionGetFieldOffset(cSec,p,f,&off);CHKERRQ(ierr);
7367         for (q = 0; q < dof; q++) {
7368           i[off + q + 1] = i[off + q] + annz;
7369         }
7370       }
7371     }
7372     else {
7373       annz = 0;
7374       for (q = 0; q < dof; q++) {
7375         a = anchors[off + q];
7376         ierr = PetscSectionGetDof(section,a,&aDof);CHKERRQ(ierr);
7377         annz += aDof;
7378       }
7379       ierr = PetscSectionGetDof(cSec,p,&dof);CHKERRQ(ierr);
7380       ierr = PetscSectionGetOffset(cSec,p,&off);CHKERRQ(ierr);
7381       for (q = 0; q < dof; q++) {
7382         i[off + q + 1] = i[off + q] + annz;
7383       }
7384     }
7385   }
7386   nnz = i[m];
7387   ierr = PetscMalloc1(nnz,&j);CHKERRQ(ierr);
7388   offset = 0;
7389   for (p = pStart; p < pEnd; p++) {
7390     if (numFields) {
7391       for (f = 0; f < numFields; f++) {
7392         ierr = PetscSectionGetFieldDof(cSec,p,f,&dof);CHKERRQ(ierr);
7393         for (q = 0; q < dof; q++) {
7394           PetscInt rDof, rOff, r;
7395           ierr = PetscSectionGetDof(aSec,p,&rDof);CHKERRQ(ierr);
7396           ierr = PetscSectionGetOffset(aSec,p,&rOff);CHKERRQ(ierr);
7397           for (r = 0; r < rDof; r++) {
7398             PetscInt s;
7399 
7400             a = anchors[rOff + r];
7401             ierr = PetscSectionGetFieldDof(section,a,f,&aDof);CHKERRQ(ierr);
7402             ierr = PetscSectionGetFieldOffset(section,a,f,&aOff);CHKERRQ(ierr);
7403             for (s = 0; s < aDof; s++) {
7404               j[offset++] = aOff + s;
7405             }
7406           }
7407         }
7408       }
7409     }
7410     else {
7411       ierr = PetscSectionGetDof(cSec,p,&dof);CHKERRQ(ierr);
7412       for (q = 0; q < dof; q++) {
7413         PetscInt rDof, rOff, r;
7414         ierr = PetscSectionGetDof(aSec,p,&rDof);CHKERRQ(ierr);
7415         ierr = PetscSectionGetOffset(aSec,p,&rOff);CHKERRQ(ierr);
7416         for (r = 0; r < rDof; r++) {
7417           PetscInt s;
7418 
7419           a = anchors[rOff + r];
7420           ierr = PetscSectionGetDof(section,a,&aDof);CHKERRQ(ierr);
7421           ierr = PetscSectionGetOffset(section,a,&aOff);CHKERRQ(ierr);
7422           for (s = 0; s < aDof; s++) {
7423             j[offset++] = aOff + s;
7424           }
7425         }
7426       }
7427     }
7428   }
7429   ierr = MatSeqAIJSetPreallocationCSR(*cMat,i,j,NULL);CHKERRQ(ierr);
7430   ierr = PetscFree(i);CHKERRQ(ierr);
7431   ierr = PetscFree(j);CHKERRQ(ierr);
7432   ierr = ISRestoreIndices(aIS,&anchors);CHKERRQ(ierr);
7433   PetscFunctionReturn(0);
7434 }
7435 
7436 PetscErrorCode DMCreateDefaultConstraints_Plex(DM dm)
7437 {
7438   DM_Plex        *plex = (DM_Plex *)dm->data;
7439   PetscSection   anchorSection, section, cSec;
7440   Mat            cMat;
7441   PetscErrorCode ierr;
7442 
7443   PetscFunctionBegin;
7444   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7445   ierr = DMPlexGetAnchors(dm,&anchorSection,NULL);CHKERRQ(ierr);
7446   if (anchorSection) {
7447     PetscInt Nf;
7448 
7449     ierr = DMGetSection(dm,&section);CHKERRQ(ierr);
7450     ierr = DMPlexCreateConstraintSection_Anchors(dm,section,&cSec);CHKERRQ(ierr);
7451     ierr = DMPlexCreateConstraintMatrix_Anchors(dm,section,cSec,&cMat);CHKERRQ(ierr);
7452     ierr = DMGetNumFields(dm,&Nf);CHKERRQ(ierr);
7453     if (Nf && plex->computeanchormatrix) {ierr = (*plex->computeanchormatrix)(dm,section,cSec,cMat);CHKERRQ(ierr);}
7454     ierr = DMSetDefaultConstraints(dm,cSec,cMat);CHKERRQ(ierr);
7455     ierr = PetscSectionDestroy(&cSec);CHKERRQ(ierr);
7456     ierr = MatDestroy(&cMat);CHKERRQ(ierr);
7457   }
7458   PetscFunctionReturn(0);
7459 }
7460 
7461 PetscErrorCode DMCreateSubDomainDM_Plex(DM dm, DMLabel label, PetscInt value, IS *is, DM *subdm)
7462 {
7463   IS             subis;
7464   PetscSection   section, subsection;
7465   PetscErrorCode ierr;
7466 
7467   PetscFunctionBegin;
7468   ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
7469   if (!section) SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "Must set default section for DM before splitting subdomain");
7470   if (!subdm)   SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "Must set output subDM for splitting subdomain");
7471   /* Create subdomain */
7472   ierr = DMPlexFilter(dm, label, value, subdm);CHKERRQ(ierr);
7473   /* Create submodel */
7474   ierr = DMPlexCreateSubpointIS(*subdm, &subis);CHKERRQ(ierr);
7475   ierr = PetscSectionCreateSubmeshSection(section, subis, &subsection);CHKERRQ(ierr);
7476   ierr = ISDestroy(&subis);CHKERRQ(ierr);
7477   ierr = DMSetDefaultSection(*subdm, subsection);CHKERRQ(ierr);
7478   ierr = PetscSectionDestroy(&subsection);CHKERRQ(ierr);
7479   ierr = DMCopyDisc(dm, *subdm);CHKERRQ(ierr);
7480   /* Create map from submodel to global model */
7481   if (is) {
7482     PetscSection    sectionGlobal, subsectionGlobal;
7483     IS              spIS;
7484     const PetscInt *spmap;
7485     PetscInt       *subIndices;
7486     PetscInt        subSize = 0, subOff = 0, pStart, pEnd, p;
7487     PetscInt        Nf, f, bs = -1, bsLocal[2], bsMinMax[2];
7488 
7489     ierr = DMPlexCreateSubpointIS(*subdm, &spIS);CHKERRQ(ierr);
7490     ierr = ISGetIndices(spIS, &spmap);CHKERRQ(ierr);
7491     ierr = PetscSectionGetNumFields(section, &Nf);CHKERRQ(ierr);
7492     ierr = DMGetDefaultGlobalSection(dm, &sectionGlobal);CHKERRQ(ierr);
7493     ierr = DMGetDefaultGlobalSection(*subdm, &subsectionGlobal);CHKERRQ(ierr);
7494     ierr = PetscSectionGetChart(subsection, &pStart, &pEnd);CHKERRQ(ierr);
7495     for (p = pStart; p < pEnd; ++p) {
7496       PetscInt gdof, pSubSize  = 0;
7497 
7498       ierr = PetscSectionGetDof(sectionGlobal, p, &gdof);CHKERRQ(ierr);
7499       if (gdof > 0) {
7500         for (f = 0; f < Nf; ++f) {
7501           PetscInt fdof, fcdof;
7502 
7503           ierr     = PetscSectionGetFieldDof(subsection, p, f, &fdof);CHKERRQ(ierr);
7504           ierr     = PetscSectionGetFieldConstraintDof(subsection, p, f, &fcdof);CHKERRQ(ierr);
7505           pSubSize += fdof-fcdof;
7506         }
7507         subSize += pSubSize;
7508         if (pSubSize) {
7509           if (bs < 0) {
7510             bs = pSubSize;
7511           } else if (bs != pSubSize) {
7512             /* Layout does not admit a pointwise block size */
7513             bs = 1;
7514           }
7515         }
7516       }
7517     }
7518     /* Must have same blocksize on all procs (some might have no points) */
7519     bsLocal[0] = bs < 0 ? PETSC_MAX_INT : bs; bsLocal[1] = bs;
7520     ierr = PetscGlobalMinMaxInt(PetscObjectComm((PetscObject) dm), bsLocal, bsMinMax);CHKERRQ(ierr);
7521     if (bsMinMax[0] != bsMinMax[1]) {bs = 1;}
7522     else                            {bs = bsMinMax[0];}
7523     ierr = PetscMalloc1(subSize, &subIndices);CHKERRQ(ierr);
7524     for (p = pStart; p < pEnd; ++p) {
7525       PetscInt gdof, goff;
7526 
7527       ierr = PetscSectionGetDof(subsectionGlobal, p, &gdof);CHKERRQ(ierr);
7528       if (gdof > 0) {
7529         const PetscInt point = spmap[p];
7530 
7531         ierr = PetscSectionGetOffset(sectionGlobal, point, &goff);CHKERRQ(ierr);
7532         for (f = 0; f < Nf; ++f) {
7533           PetscInt fdof, fcdof, fc, f2, poff = 0;
7534 
7535           /* Can get rid of this loop by storing field information in the global section */
7536           for (f2 = 0; f2 < f; ++f2) {
7537             ierr  = PetscSectionGetFieldDof(section, p, f2, &fdof);CHKERRQ(ierr);
7538             ierr  = PetscSectionGetFieldConstraintDof(section, p, f2, &fcdof);CHKERRQ(ierr);
7539             poff += fdof-fcdof;
7540           }
7541           ierr = PetscSectionGetFieldDof(section, p, f, &fdof);CHKERRQ(ierr);
7542           ierr = PetscSectionGetFieldConstraintDof(section, p, f, &fcdof);CHKERRQ(ierr);
7543           for (fc = 0; fc < fdof-fcdof; ++fc, ++subOff) {
7544             subIndices[subOff] = goff+poff+fc;
7545           }
7546         }
7547       }
7548     }
7549     ierr = ISRestoreIndices(spIS, &spmap);CHKERRQ(ierr);
7550     ierr = ISDestroy(&spIS);CHKERRQ(ierr);
7551     ierr = ISCreateGeneral(PetscObjectComm((PetscObject)dm), subSize, subIndices, PETSC_OWN_POINTER, is);CHKERRQ(ierr);
7552     if (bs > 1) {
7553       /* We need to check that the block size does not come from non-contiguous fields */
7554       PetscInt i, j, set = 1;
7555       for (i = 0; i < subSize; i += bs) {
7556         for (j = 0; j < bs; ++j) {
7557           if (subIndices[i+j] != subIndices[i]+j) {set = 0; break;}
7558         }
7559       }
7560       if (set) {ierr = ISSetBlockSize(*is, bs);CHKERRQ(ierr);}
7561     }
7562     /* Attach nullspace */
7563     for (f = 0; f < Nf; ++f) {
7564       (*subdm)->nullspaceConstructors[f] = dm->nullspaceConstructors[f];
7565       if ((*subdm)->nullspaceConstructors[f]) break;
7566     }
7567     if (f < Nf) {
7568       MatNullSpace nullSpace;
7569 
7570       ierr = (*(*subdm)->nullspaceConstructors[f])(*subdm, f, &nullSpace);CHKERRQ(ierr);
7571       ierr = PetscObjectCompose((PetscObject) *is, "nullspace", (PetscObject) nullSpace);CHKERRQ(ierr);
7572       ierr = MatNullSpaceDestroy(&nullSpace);CHKERRQ(ierr);
7573     }
7574   }
7575   PetscFunctionReturn(0);
7576 }
7577