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