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