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