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