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