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