xref: /petsc/src/dm/impls/plex/plex.c (revision 02c9f0b548ed2228330a66acd2df0a92dd2a8bb1)
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(), 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()
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()
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()
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   DMPlexGetCellTypeLabel - Get the DMLabel recording the polytope type of each cell
3841 
3842   Not Collective
3843 
3844   Input Parameter:
3845 . dm - The DMPlex object
3846 
3847   Output Parameter:
3848 . celltypeLabel - The DMLabel recording cell polytope type
3849 
3850   Level: developer
3851 
3852 .seealso: DMPlexGetCellType(), DMPlexGetDepthLabel(), DMPlexGetDepth()
3853 @*/
3854 PetscErrorCode DMPlexGetCellTypeLabel(DM dm, DMLabel *celltypeLabel)
3855 {
3856   PetscErrorCode ierr;
3857 
3858   PetscFunctionBegin;
3859   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3860   PetscValidPointer(celltypeLabel, 2);
3861   if (!dm->celltypeLabel) {ierr = DMPlexComputeCellTypes(dm);CHKERRQ(ierr);}
3862   *celltypeLabel = dm->celltypeLabel;
3863   PetscFunctionReturn(0);
3864 }
3865 
3866 /*@
3867   DMPlexGetCellType - Get the polytope type of a given cell
3868 
3869   Not Collective
3870 
3871   Input Parameter:
3872 + dm   - The DMPlex object
3873 - cell - The cell
3874 
3875   Output Parameter:
3876 . celltype - The polytope type of the cell
3877 
3878   Level: intermediate
3879 
3880 .seealso: DMPlexGetCellTypeLabel(), DMPlexGetDepthLabel(), DMPlexGetDepth()
3881 @*/
3882 PetscErrorCode DMPlexGetCellType(DM dm, PetscInt cell, DMPolytopeType *celltype)
3883 {
3884   DMLabel        label;
3885   PetscInt       ct;
3886   PetscErrorCode ierr;
3887 
3888   PetscFunctionBegin;
3889   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3890   PetscValidPointer(celltype, 3);
3891   ierr = DMPlexGetCellTypeLabel(dm, &label);CHKERRQ(ierr);
3892   ierr = DMLabelGetValue(label, cell, &ct);CHKERRQ(ierr);
3893   *celltype = (DMPolytopeType) ct;
3894   PetscFunctionReturn(0);
3895 }
3896 
3897 PetscErrorCode DMCreateCoordinateDM_Plex(DM dm, DM *cdm)
3898 {
3899   PetscSection   section, s;
3900   Mat            m;
3901   PetscInt       maxHeight;
3902   PetscErrorCode ierr;
3903 
3904   PetscFunctionBegin;
3905   ierr = DMClone(dm, cdm);CHKERRQ(ierr);
3906   ierr = DMPlexGetMaxProjectionHeight(dm, &maxHeight);CHKERRQ(ierr);
3907   ierr = DMPlexSetMaxProjectionHeight(*cdm, maxHeight);CHKERRQ(ierr);
3908   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)dm), &section);CHKERRQ(ierr);
3909   ierr = DMSetLocalSection(*cdm, section);CHKERRQ(ierr);
3910   ierr = PetscSectionDestroy(&section);CHKERRQ(ierr);
3911   ierr = PetscSectionCreate(PETSC_COMM_SELF, &s);CHKERRQ(ierr);
3912   ierr = MatCreate(PETSC_COMM_SELF, &m);CHKERRQ(ierr);
3913   ierr = DMSetDefaultConstraints(*cdm, s, m);CHKERRQ(ierr);
3914   ierr = PetscSectionDestroy(&s);CHKERRQ(ierr);
3915   ierr = MatDestroy(&m);CHKERRQ(ierr);
3916 
3917   ierr = DMSetNumFields(*cdm, 1);CHKERRQ(ierr);
3918   ierr = DMCreateDS(*cdm);CHKERRQ(ierr);
3919   PetscFunctionReturn(0);
3920 }
3921 
3922 PetscErrorCode DMCreateCoordinateField_Plex(DM dm, DMField *field)
3923 {
3924   Vec            coordsLocal;
3925   DM             coordsDM;
3926   PetscErrorCode ierr;
3927 
3928   PetscFunctionBegin;
3929   *field = NULL;
3930   ierr = DMGetCoordinatesLocal(dm,&coordsLocal);CHKERRQ(ierr);
3931   ierr = DMGetCoordinateDM(dm,&coordsDM);CHKERRQ(ierr);
3932   if (coordsLocal && coordsDM) {
3933     ierr = DMFieldCreateDS(coordsDM, 0, coordsLocal, field);CHKERRQ(ierr);
3934   }
3935   PetscFunctionReturn(0);
3936 }
3937 
3938 /*@C
3939   DMPlexGetConeSection - Return a section which describes the layout of cone data
3940 
3941   Not Collective
3942 
3943   Input Parameters:
3944 . dm        - The DMPlex object
3945 
3946   Output Parameter:
3947 . section - The PetscSection object
3948 
3949   Level: developer
3950 
3951 .seealso: DMPlexGetSupportSection(), DMPlexGetCones(), DMPlexGetConeOrientations()
3952 @*/
3953 PetscErrorCode DMPlexGetConeSection(DM dm, PetscSection *section)
3954 {
3955   DM_Plex *mesh = (DM_Plex*) dm->data;
3956 
3957   PetscFunctionBegin;
3958   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3959   if (section) *section = mesh->coneSection;
3960   PetscFunctionReturn(0);
3961 }
3962 
3963 /*@C
3964   DMPlexGetSupportSection - Return a section which describes the layout of support data
3965 
3966   Not Collective
3967 
3968   Input Parameters:
3969 . dm        - The DMPlex object
3970 
3971   Output Parameter:
3972 . section - The PetscSection object
3973 
3974   Level: developer
3975 
3976 .seealso: DMPlexGetConeSection()
3977 @*/
3978 PetscErrorCode DMPlexGetSupportSection(DM dm, PetscSection *section)
3979 {
3980   DM_Plex *mesh = (DM_Plex*) dm->data;
3981 
3982   PetscFunctionBegin;
3983   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3984   if (section) *section = mesh->supportSection;
3985   PetscFunctionReturn(0);
3986 }
3987 
3988 /*@C
3989   DMPlexGetCones - Return cone data
3990 
3991   Not Collective
3992 
3993   Input Parameters:
3994 . dm        - The DMPlex object
3995 
3996   Output Parameter:
3997 . cones - The cone for each point
3998 
3999   Level: developer
4000 
4001 .seealso: DMPlexGetConeSection()
4002 @*/
4003 PetscErrorCode DMPlexGetCones(DM dm, PetscInt *cones[])
4004 {
4005   DM_Plex *mesh = (DM_Plex*) dm->data;
4006 
4007   PetscFunctionBegin;
4008   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4009   if (cones) *cones = mesh->cones;
4010   PetscFunctionReturn(0);
4011 }
4012 
4013 /*@C
4014   DMPlexGetConeOrientations - Return cone orientation data
4015 
4016   Not Collective
4017 
4018   Input Parameters:
4019 . dm        - The DMPlex object
4020 
4021   Output Parameter:
4022 . coneOrientations - The cone orientation for each point
4023 
4024   Level: developer
4025 
4026 .seealso: DMPlexGetConeSection()
4027 @*/
4028 PetscErrorCode DMPlexGetConeOrientations(DM dm, PetscInt *coneOrientations[])
4029 {
4030   DM_Plex *mesh = (DM_Plex*) dm->data;
4031 
4032   PetscFunctionBegin;
4033   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4034   if (coneOrientations) *coneOrientations = mesh->coneOrientations;
4035   PetscFunctionReturn(0);
4036 }
4037 
4038 /******************************** FEM Support **********************************/
4039 
4040 /*
4041  Returns number of components and tensor degree for the field.  For interpolated meshes, line should be a point
4042  representing a line in the section.
4043 */
4044 static PetscErrorCode PetscSectionFieldGetTensorDegree_Private(PetscSection section,PetscInt field,PetscInt line,PetscBool vertexchart,PetscInt *Nc,PetscInt *k)
4045 {
4046   PetscErrorCode ierr;
4047 
4048   PetscFunctionBeginHot;
4049   ierr = PetscSectionGetFieldComponents(section, field, Nc);CHKERRQ(ierr);
4050   if (line < 0) {
4051     *k = 0;
4052     *Nc = 0;
4053   } else if (vertexchart) {            /* If we only have a vertex chart, we must have degree k=1 */
4054     *k = 1;
4055   } else {                      /* Assume the full interpolated mesh is in the chart; lines in particular */
4056     /* An order k SEM disc has k-1 dofs on an edge */
4057     ierr = PetscSectionGetFieldDof(section, line, field, k);CHKERRQ(ierr);
4058     *k = *k / *Nc + 1;
4059   }
4060   PetscFunctionReturn(0);
4061 }
4062 
4063 /*@
4064 
4065   DMPlexSetClosurePermutationTensor - Create a permutation from the default (BFS) point ordering in the closure, to a
4066   lexicographic ordering over the tensor product cell (i.e., line, quad, hex, etc.), and set this permutation in the
4067   section provided (or the section of the DM).
4068 
4069   Input Parameters:
4070 + dm      - The DM
4071 . point   - Either a cell (highest dim point) or an edge (dim 1 point), or PETSC_DETERMINE
4072 - section - The PetscSection to reorder, or NULL for the default section
4073 
4074   Note: The point is used to determine the number of dofs/field on an edge. For SEM, this is related to the polynomial
4075   degree of the basis.
4076 
4077   Example:
4078   A typical interpolated single-quad mesh might order points as
4079 .vb
4080   [c0, v1, v2, v3, v4, e5, e6, e7, e8]
4081 
4082   v4 -- e6 -- v3
4083   |           |
4084   e7    c0    e8
4085   |           |
4086   v1 -- e5 -- v2
4087 .ve
4088 
4089   (There is no significance to the ordering described here.)  The default section for a Q3 quad might typically assign
4090   dofs in the order of points, e.g.,
4091 .vb
4092     c0 -> [0,1,2,3]
4093     v1 -> [4]
4094     ...
4095     e5 -> [8, 9]
4096 .ve
4097 
4098   which corresponds to the dofs
4099 .vb
4100     6   10  11  7
4101     13  2   3   15
4102     12  0   1   14
4103     4   8   9   5
4104 .ve
4105 
4106   The closure in BFS ordering works through height strata (cells, edges, vertices) to produce the ordering
4107 .vb
4108   0 1 2 3 8 9 14 15 11 10 13 12 4 5 7 6
4109 .ve
4110 
4111   After calling DMPlexSetClosurePermutationTensor(), the closure will be ordered lexicographically,
4112 .vb
4113    4 8 9 5 12 0 1 14 13 2 3 15 6 10 11 7
4114 .ve
4115 
4116   Level: developer
4117 
4118 .seealso: DMGetLocalSection(), PetscSectionSetClosurePermutation(), DMSetGlobalSection()
4119 @*/
4120 PetscErrorCode DMPlexSetClosurePermutationTensor(DM dm, PetscInt point, PetscSection section)
4121 {
4122   DMLabel        label;
4123   PetscInt      *perm;
4124   PetscInt       dim, depth = -1, eStart = -1, k, Nf, f, Nc, c, i, j, size = 0, offset = 0, foffset = 0;
4125   PetscBool      vertexchart;
4126   PetscErrorCode ierr;
4127 
4128   PetscFunctionBegin;
4129   ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr);
4130   if (dim < 1) PetscFunctionReturn(0);
4131   if (point < 0) {
4132     PetscInt sStart,sEnd;
4133 
4134     ierr = DMPlexGetDepthStratum(dm, 1, &sStart, &sEnd);CHKERRQ(ierr);
4135     point = sEnd-sStart ? sStart : point;
4136   }
4137   ierr = DMPlexGetDepthLabel(dm, &label);CHKERRQ(ierr);
4138   if (point >= 0) { ierr = DMLabelGetValue(label, point, &depth);CHKERRQ(ierr); }
4139   if (!section) {ierr = DMGetLocalSection(dm, &section);CHKERRQ(ierr);}
4140   if (depth == 1) {eStart = point;}
4141   else if  (depth == dim) {
4142     const PetscInt *cone;
4143 
4144     ierr = DMPlexGetCone(dm, point, &cone);CHKERRQ(ierr);
4145     if (dim == 2) eStart = cone[0];
4146     else if (dim == 3) {
4147       const PetscInt *cone2;
4148       ierr = DMPlexGetCone(dm, cone[0], &cone2);CHKERRQ(ierr);
4149       eStart = cone2[0];
4150     } 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);
4151   } 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);
4152   {                             /* Determine whether the chart covers all points or just vertices. */
4153     PetscInt pStart,pEnd,cStart,cEnd;
4154     ierr = DMPlexGetDepthStratum(dm,0,&pStart,&pEnd);CHKERRQ(ierr);
4155     ierr = PetscSectionGetChart(section,&cStart,&cEnd);CHKERRQ(ierr);
4156     if (pStart == cStart && pEnd == cEnd) vertexchart = PETSC_TRUE; /* Just vertices */
4157     else vertexchart = PETSC_FALSE;                                 /* Assume all interpolated points are in chart */
4158   }
4159   ierr = PetscSectionGetNumFields(section, &Nf);CHKERRQ(ierr);
4160   for (f = 0; f < Nf; ++f) {
4161     ierr = PetscSectionFieldGetTensorDegree_Private(section,f,eStart,vertexchart,&Nc,&k);CHKERRQ(ierr);
4162     size += PetscPowInt(k+1, dim)*Nc;
4163   }
4164   ierr = PetscMalloc1(size, &perm);CHKERRQ(ierr);
4165   for (f = 0; f < Nf; ++f) {
4166     switch (dim) {
4167     case 1:
4168       ierr = PetscSectionFieldGetTensorDegree_Private(section,f,eStart,vertexchart,&Nc,&k);CHKERRQ(ierr);
4169       /*
4170         Original ordering is [ edge of length k-1; vtx0; vtx1 ]
4171         We want              [ vtx0; edge of length k-1; vtx1 ]
4172       */
4173       for (c=0; c<Nc; c++,offset++) perm[offset] = (k-1)*Nc + c + foffset;
4174       for (i=0; i<k-1; i++) for (c=0; c<Nc; c++,offset++) perm[offset] = i*Nc + c + foffset;
4175       for (c=0; c<Nc; c++,offset++) perm[offset] = k*Nc + c + foffset;
4176       foffset = offset;
4177       break;
4178     case 2:
4179       /* The original quad closure is oriented clockwise, {f, e_b, e_r, e_t, e_l, v_lb, v_rb, v_tr, v_tl} */
4180       ierr = PetscSectionFieldGetTensorDegree_Private(section,f,eStart,vertexchart,&Nc,&k);CHKERRQ(ierr);
4181       /* The SEM order is
4182 
4183          v_lb, {e_b}, v_rb,
4184          e^{(k-1)-i}_l, {f^{i*(k-1)}}, e^i_r,
4185          v_lt, reverse {e_t}, v_rt
4186       */
4187       {
4188         const PetscInt of   = 0;
4189         const PetscInt oeb  = of   + PetscSqr(k-1);
4190         const PetscInt oer  = oeb  + (k-1);
4191         const PetscInt oet  = oer  + (k-1);
4192         const PetscInt oel  = oet  + (k-1);
4193         const PetscInt ovlb = oel  + (k-1);
4194         const PetscInt ovrb = ovlb + 1;
4195         const PetscInt ovrt = ovrb + 1;
4196         const PetscInt ovlt = ovrt + 1;
4197         PetscInt       o;
4198 
4199         /* bottom */
4200         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlb*Nc + c + foffset;
4201         for (o = oeb; o < oer; ++o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
4202         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrb*Nc + c + foffset;
4203         /* middle */
4204         for (i = 0; i < k-1; ++i) {
4205           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oel+(k-2)-i)*Nc + c + foffset;
4206           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;
4207           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oer+i)*Nc + c + foffset;
4208         }
4209         /* top */
4210         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlt*Nc + c + foffset;
4211         for (o = oel-1; o >= oet; --o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
4212         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrt*Nc + c + foffset;
4213         foffset = offset;
4214       }
4215       break;
4216     case 3:
4217       /* The original hex closure is
4218 
4219          {c,
4220           f_b, f_t, f_f, f_b, f_r, f_l,
4221           e_bl, e_bb, e_br, e_bf,  e_tf, e_tr, e_tb, e_tl,  e_rf, e_lf, e_lb, e_rb,
4222           v_blf, v_blb, v_brb, v_brf, v_tlf, v_trf, v_trb, v_tlb}
4223       */
4224       ierr = PetscSectionFieldGetTensorDegree_Private(section,f,eStart,vertexchart,&Nc,&k);CHKERRQ(ierr);
4225       /* The SEM order is
4226          Bottom Slice
4227          v_blf, {e^{(k-1)-n}_bf}, v_brf,
4228          e^{i}_bl, f^{n*(k-1)+(k-1)-i}_b, e^{(k-1)-i}_br,
4229          v_blb, {e_bb}, v_brb,
4230 
4231          Middle Slice (j)
4232          {e^{(k-1)-j}_lf}, {f^{j*(k-1)+n}_f}, e^j_rf,
4233          f^{i*(k-1)+j}_l, {c^{(j*(k-1) + i)*(k-1)+n}_t}, f^{j*(k-1)+i}_r,
4234          e^j_lb, {f^{j*(k-1)+(k-1)-n}_b}, e^{(k-1)-j}_rb,
4235 
4236          Top Slice
4237          v_tlf, {e_tf}, v_trf,
4238          e^{(k-1)-i}_tl, {f^{i*(k-1)}_t}, e^{i}_tr,
4239          v_tlb, {e^{(k-1)-n}_tb}, v_trb,
4240       */
4241       {
4242         const PetscInt oc    = 0;
4243         const PetscInt ofb   = oc    + PetscSqr(k-1)*(k-1);
4244         const PetscInt oft   = ofb   + PetscSqr(k-1);
4245         const PetscInt off   = oft   + PetscSqr(k-1);
4246         const PetscInt ofk   = off   + PetscSqr(k-1);
4247         const PetscInt ofr   = ofk   + PetscSqr(k-1);
4248         const PetscInt ofl   = ofr   + PetscSqr(k-1);
4249         const PetscInt oebl  = ofl   + PetscSqr(k-1);
4250         const PetscInt oebb  = oebl  + (k-1);
4251         const PetscInt oebr  = oebb  + (k-1);
4252         const PetscInt oebf  = oebr  + (k-1);
4253         const PetscInt oetf  = oebf  + (k-1);
4254         const PetscInt oetr  = oetf  + (k-1);
4255         const PetscInt oetb  = oetr  + (k-1);
4256         const PetscInt oetl  = oetb  + (k-1);
4257         const PetscInt oerf  = oetl  + (k-1);
4258         const PetscInt oelf  = oerf  + (k-1);
4259         const PetscInt oelb  = oelf  + (k-1);
4260         const PetscInt oerb  = oelb  + (k-1);
4261         const PetscInt ovblf = oerb  + (k-1);
4262         const PetscInt ovblb = ovblf + 1;
4263         const PetscInt ovbrb = ovblb + 1;
4264         const PetscInt ovbrf = ovbrb + 1;
4265         const PetscInt ovtlf = ovbrf + 1;
4266         const PetscInt ovtrf = ovtlf + 1;
4267         const PetscInt ovtrb = ovtrf + 1;
4268         const PetscInt ovtlb = ovtrb + 1;
4269         PetscInt       o, n;
4270 
4271         /* Bottom Slice */
4272         /*   bottom */
4273         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblf*Nc + c + foffset;
4274         for (o = oetf-1; o >= oebf; --o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
4275         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrf*Nc + c + foffset;
4276         /*   middle */
4277         for (i = 0; i < k-1; ++i) {
4278           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebl+i)*Nc + c + foffset;
4279           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;}
4280           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebr+(k-2)-i)*Nc + c + foffset;
4281         }
4282         /*   top */
4283         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblb*Nc + c + foffset;
4284         for (o = oebb; o < oebr; ++o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
4285         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrb*Nc + c + foffset;
4286 
4287         /* Middle Slice */
4288         for (j = 0; j < k-1; ++j) {
4289           /*   bottom */
4290           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelf+(k-2)-j)*Nc + c + foffset;
4291           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;
4292           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerf+j)*Nc + c + foffset;
4293           /*   middle */
4294           for (i = 0; i < k-1; ++i) {
4295             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofl+i*(k-1)+j)*Nc + c + foffset;
4296             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;
4297             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofr+j*(k-1)+i)*Nc + c + foffset;
4298           }
4299           /*   top */
4300           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelb+j)*Nc + c + foffset;
4301           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;
4302           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerb+(k-2)-j)*Nc + c + foffset;
4303         }
4304 
4305         /* Top Slice */
4306         /*   bottom */
4307         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlf*Nc + c + foffset;
4308         for (o = oetf; o < oetr; ++o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
4309         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrf*Nc + c + foffset;
4310         /*   middle */
4311         for (i = 0; i < k-1; ++i) {
4312           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetl+(k-2)-i)*Nc + c + foffset;
4313           for (n = 0; n < k-1; ++n) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oft+i*(k-1)+n)*Nc + c + foffset;
4314           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetr+i)*Nc + c + foffset;
4315         }
4316         /*   top */
4317         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlb*Nc + c + foffset;
4318         for (o = oetl-1; o >= oetb; --o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
4319         for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrb*Nc + c + foffset;
4320 
4321         foffset = offset;
4322       }
4323       break;
4324     default: SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_OUTOFRANGE, "No spectral ordering for dimension %D", dim);
4325     }
4326   }
4327   if (offset != size) SETERRQ2(PetscObjectComm((PetscObject) dm), PETSC_ERR_PLIB, "Number of permutation entries %D != %D", offset, size);
4328   /* Check permutation */
4329   {
4330     PetscInt *check;
4331 
4332     ierr = PetscMalloc1(size, &check);CHKERRQ(ierr);
4333     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]);}
4334     for (i = 0; i < size; ++i) check[perm[i]] = i;
4335     for (i = 0; i < size; ++i) {if (check[i] < 0) SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_PLIB, "Missing permutation index %D", i);}
4336     ierr = PetscFree(check);CHKERRQ(ierr);
4337   }
4338   ierr = PetscSectionSetClosurePermutation_Internal(section, (PetscObject) dm, size, PETSC_OWN_POINTER, perm);CHKERRQ(ierr);
4339   PetscFunctionReturn(0);
4340 }
4341 
4342 PetscErrorCode DMPlexGetPointDualSpaceFEM(DM dm, PetscInt point, PetscInt field, PetscDualSpace *dspace)
4343 {
4344   PetscDS        prob;
4345   PetscInt       depth, Nf, h;
4346   DMLabel        label;
4347   PetscErrorCode ierr;
4348 
4349   PetscFunctionBeginHot;
4350   ierr = DMGetDS(dm, &prob);CHKERRQ(ierr);
4351   Nf      = prob->Nf;
4352   label   = dm->depthLabel;
4353   *dspace = NULL;
4354   if (field < Nf) {
4355     PetscObject disc = prob->disc[field];
4356 
4357     if (disc->classid == PETSCFE_CLASSID) {
4358       PetscDualSpace dsp;
4359 
4360       ierr = PetscFEGetDualSpace((PetscFE)disc,&dsp);CHKERRQ(ierr);
4361       ierr = DMLabelGetNumValues(label,&depth);CHKERRQ(ierr);
4362       ierr = DMLabelGetValue(label,point,&h);CHKERRQ(ierr);
4363       h    = depth - 1 - h;
4364       if (h) {
4365         ierr = PetscDualSpaceGetHeightSubspace(dsp,h,dspace);CHKERRQ(ierr);
4366       } else {
4367         *dspace = dsp;
4368       }
4369     }
4370   }
4371   PetscFunctionReturn(0);
4372 }
4373 
4374 
4375 PETSC_STATIC_INLINE PetscErrorCode DMPlexVecGetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[])
4376 {
4377   PetscScalar    *array, *vArray;
4378   const PetscInt *cone, *coneO;
4379   PetscInt        pStart, pEnd, p, numPoints, size = 0, offset = 0;
4380   PetscErrorCode  ierr;
4381 
4382   PetscFunctionBeginHot;
4383   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
4384   ierr = DMPlexGetConeSize(dm, point, &numPoints);CHKERRQ(ierr);
4385   ierr = DMPlexGetCone(dm, point, &cone);CHKERRQ(ierr);
4386   ierr = DMPlexGetConeOrientation(dm, point, &coneO);CHKERRQ(ierr);
4387   if (!values || !*values) {
4388     if ((point >= pStart) && (point < pEnd)) {
4389       PetscInt dof;
4390 
4391       ierr = PetscSectionGetDof(section, point, &dof);CHKERRQ(ierr);
4392       size += dof;
4393     }
4394     for (p = 0; p < numPoints; ++p) {
4395       const PetscInt cp = cone[p];
4396       PetscInt       dof;
4397 
4398       if ((cp < pStart) || (cp >= pEnd)) continue;
4399       ierr = PetscSectionGetDof(section, cp, &dof);CHKERRQ(ierr);
4400       size += dof;
4401     }
4402     if (!values) {
4403       if (csize) *csize = size;
4404       PetscFunctionReturn(0);
4405     }
4406     ierr = DMGetWorkArray(dm, size, MPIU_SCALAR, &array);CHKERRQ(ierr);
4407   } else {
4408     array = *values;
4409   }
4410   size = 0;
4411   ierr = VecGetArray(v, &vArray);CHKERRQ(ierr);
4412   if ((point >= pStart) && (point < pEnd)) {
4413     PetscInt     dof, off, d;
4414     PetscScalar *varr;
4415 
4416     ierr = PetscSectionGetDof(section, point, &dof);CHKERRQ(ierr);
4417     ierr = PetscSectionGetOffset(section, point, &off);CHKERRQ(ierr);
4418     varr = &vArray[off];
4419     for (d = 0; d < dof; ++d, ++offset) {
4420       array[offset] = varr[d];
4421     }
4422     size += dof;
4423   }
4424   for (p = 0; p < numPoints; ++p) {
4425     const PetscInt cp = cone[p];
4426     PetscInt       o  = coneO[p];
4427     PetscInt       dof, off, d;
4428     PetscScalar   *varr;
4429 
4430     if ((cp < pStart) || (cp >= pEnd)) continue;
4431     ierr = PetscSectionGetDof(section, cp, &dof);CHKERRQ(ierr);
4432     ierr = PetscSectionGetOffset(section, cp, &off);CHKERRQ(ierr);
4433     varr = &vArray[off];
4434     if (o >= 0) {
4435       for (d = 0; d < dof; ++d, ++offset) {
4436         array[offset] = varr[d];
4437       }
4438     } else {
4439       for (d = dof-1; d >= 0; --d, ++offset) {
4440         array[offset] = varr[d];
4441       }
4442     }
4443     size += dof;
4444   }
4445   ierr = VecRestoreArray(v, &vArray);CHKERRQ(ierr);
4446   if (!*values) {
4447     if (csize) *csize = size;
4448     *values = array;
4449   } else {
4450     if (size > *csize) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %D < actual size %D", *csize, size);
4451     *csize = size;
4452   }
4453   PetscFunctionReturn(0);
4454 }
4455 
4456 PetscErrorCode DMPlexGetCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp)
4457 {
4458   const PetscInt *cla;
4459   PetscInt       np, *pts = NULL;
4460   PetscErrorCode ierr;
4461 
4462   PetscFunctionBeginHot;
4463   ierr = PetscSectionGetClosureIndex(section, (PetscObject) dm, clSec, clPoints);CHKERRQ(ierr);
4464   if (!*clPoints) {
4465     PetscInt pStart, pEnd, p, q;
4466 
4467     ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
4468     ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &np, &pts);CHKERRQ(ierr);
4469     /* Compress out points not in the section */
4470     for (p = 0, q = 0; p < np; p++) {
4471       PetscInt r = pts[2*p];
4472       if ((r >= pStart) && (r < pEnd)) {
4473         pts[q*2]   = r;
4474         pts[q*2+1] = pts[2*p+1];
4475         ++q;
4476       }
4477     }
4478     np = q;
4479     cla = NULL;
4480   } else {
4481     PetscInt dof, off;
4482 
4483     ierr = PetscSectionGetDof(*clSec, point, &dof);CHKERRQ(ierr);
4484     ierr = PetscSectionGetOffset(*clSec, point, &off);CHKERRQ(ierr);
4485     ierr = ISGetIndices(*clPoints, &cla);CHKERRQ(ierr);
4486     np   = dof/2;
4487     pts  = (PetscInt *) &cla[off];
4488   }
4489   *numPoints = np;
4490   *points    = pts;
4491   *clp       = cla;
4492 
4493   PetscFunctionReturn(0);
4494 }
4495 
4496 PetscErrorCode DMPlexRestoreCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp)
4497 {
4498   PetscErrorCode ierr;
4499 
4500   PetscFunctionBeginHot;
4501   if (!*clPoints) {
4502     ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, numPoints, points);CHKERRQ(ierr);
4503   } else {
4504     ierr = ISRestoreIndices(*clPoints, clp);CHKERRQ(ierr);
4505   }
4506   *numPoints = 0;
4507   *points    = NULL;
4508   *clSec     = NULL;
4509   *clPoints  = NULL;
4510   *clp       = NULL;
4511   PetscFunctionReturn(0);
4512 }
4513 
4514 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[])
4515 {
4516   PetscInt          offset = 0, p;
4517   const PetscInt    **perms = NULL;
4518   const PetscScalar **flips = NULL;
4519   PetscErrorCode    ierr;
4520 
4521   PetscFunctionBeginHot;
4522   *size = 0;
4523   ierr = PetscSectionGetPointSyms(section,numPoints,points,&perms,&flips);CHKERRQ(ierr);
4524   for (p = 0; p < numPoints; p++) {
4525     const PetscInt    point = points[2*p];
4526     const PetscInt    *perm = perms ? perms[p] : NULL;
4527     const PetscScalar *flip = flips ? flips[p] : NULL;
4528     PetscInt          dof, off, d;
4529     const PetscScalar *varr;
4530 
4531     ierr = PetscSectionGetDof(section, point, &dof);CHKERRQ(ierr);
4532     ierr = PetscSectionGetOffset(section, point, &off);CHKERRQ(ierr);
4533     varr = &vArray[off];
4534     if (clperm) {
4535       if (perm) {
4536         for (d = 0; d < dof; d++) array[clperm[offset + perm[d]]]  = varr[d];
4537       } else {
4538         for (d = 0; d < dof; d++) array[clperm[offset +      d ]]  = varr[d];
4539       }
4540       if (flip) {
4541         for (d = 0; d < dof; d++) array[clperm[offset +      d ]] *= flip[d];
4542       }
4543     } else {
4544       if (perm) {
4545         for (d = 0; d < dof; d++) array[offset + perm[d]]  = varr[d];
4546       } else {
4547         for (d = 0; d < dof; d++) array[offset +      d ]  = varr[d];
4548       }
4549       if (flip) {
4550         for (d = 0; d < dof; d++) array[offset +      d ] *= flip[d];
4551       }
4552     }
4553     offset += dof;
4554   }
4555   ierr = PetscSectionRestorePointSyms(section,numPoints,points,&perms,&flips);CHKERRQ(ierr);
4556   *size = offset;
4557   PetscFunctionReturn(0);
4558 }
4559 
4560 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[])
4561 {
4562   PetscInt          offset = 0, f;
4563   PetscErrorCode    ierr;
4564 
4565   PetscFunctionBeginHot;
4566   *size = 0;
4567   for (f = 0; f < numFields; ++f) {
4568     PetscInt          p;
4569     const PetscInt    **perms = NULL;
4570     const PetscScalar **flips = NULL;
4571 
4572     ierr = PetscSectionGetFieldPointSyms(section,f,numPoints,points,&perms,&flips);CHKERRQ(ierr);
4573     for (p = 0; p < numPoints; p++) {
4574       const PetscInt    point = points[2*p];
4575       PetscInt          fdof, foff, b;
4576       const PetscScalar *varr;
4577       const PetscInt    *perm = perms ? perms[p] : NULL;
4578       const PetscScalar *flip = flips ? flips[p] : NULL;
4579 
4580       ierr = PetscSectionGetFieldDof(section, point, f, &fdof);CHKERRQ(ierr);
4581       ierr = PetscSectionGetFieldOffset(section, point, f, &foff);CHKERRQ(ierr);
4582       varr = &vArray[foff];
4583       if (clperm) {
4584         if (perm) {for (b = 0; b < fdof; b++) {array[clperm[offset + perm[b]]]  = varr[b];}}
4585         else      {for (b = 0; b < fdof; b++) {array[clperm[offset +      b ]]  = varr[b];}}
4586         if (flip) {for (b = 0; b < fdof; b++) {array[clperm[offset +      b ]] *= flip[b];}}
4587       } else {
4588         if (perm) {for (b = 0; b < fdof; b++) {array[offset + perm[b]]  = varr[b];}}
4589         else      {for (b = 0; b < fdof; b++) {array[offset +      b ]  = varr[b];}}
4590         if (flip) {for (b = 0; b < fdof; b++) {array[offset +      b ] *= flip[b];}}
4591       }
4592       offset += fdof;
4593     }
4594     ierr = PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms,&flips);CHKERRQ(ierr);
4595   }
4596   *size = offset;
4597   PetscFunctionReturn(0);
4598 }
4599 
4600 /*@C
4601   DMPlexVecGetClosure - Get an array of the values on the closure of 'point'
4602 
4603   Not collective
4604 
4605   Input Parameters:
4606 + dm - The DM
4607 . section - The section describing the layout in v, or NULL to use the default section
4608 . v - The local vector
4609 . point - The point in the DM
4610 . csize - The size of the input values array, or NULL
4611 - values - An array to use for the values, or NULL to have it allocated automatically
4612 
4613   Output Parameters:
4614 + csize - The number of values in the closure
4615 - values - The array of values. If the user provided NULL, it is a borrowed array and should not be freed
4616 
4617 $ Note that DMPlexVecGetClosure/DMPlexVecRestoreClosure only allocates the values array if it set to NULL in the
4618 $ calling function. This is because DMPlexVecGetClosure() is typically called in the inner loop of a Vec or Mat
4619 $ assembly function, and a user may already have allocated storage for this operation.
4620 $
4621 $ A typical use could be
4622 $
4623 $  values = NULL;
4624 $  ierr = DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values);CHKERRQ(ierr);
4625 $  for (cl = 0; cl < clSize; ++cl) {
4626 $    <Compute on closure>
4627 $  }
4628 $  ierr = DMPlexVecRestoreClosure(dm, NULL, v, p, &clSize, &values);CHKERRQ(ierr);
4629 $
4630 $ or
4631 $
4632 $  PetscMalloc1(clMaxSize, &values);
4633 $  for (p = pStart; p < pEnd; ++p) {
4634 $    clSize = clMaxSize;
4635 $    ierr = DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values);CHKERRQ(ierr);
4636 $    for (cl = 0; cl < clSize; ++cl) {
4637 $      <Compute on closure>
4638 $    }
4639 $  }
4640 $  PetscFree(values);
4641 
4642   Fortran Notes:
4643   Since it returns an array, this routine is only available in Fortran 90, and you must
4644   include petsc.h90 in your code.
4645 
4646   The csize argument is not present in the Fortran 90 binding since it is internal to the array.
4647 
4648   Level: intermediate
4649 
4650 .seealso DMPlexVecRestoreClosure(), DMPlexVecSetClosure(), DMPlexMatSetClosure()
4651 @*/
4652 PetscErrorCode DMPlexVecGetClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[])
4653 {
4654   PetscSection       clSection;
4655   IS                 clPoints;
4656   PetscScalar       *array;
4657   const PetscScalar *vArray;
4658   PetscInt          *points = NULL;
4659   const PetscInt    *clp, *perm;
4660   PetscInt           depth, numFields, numPoints, size;
4661   PetscErrorCode     ierr;
4662 
4663   PetscFunctionBeginHot;
4664   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4665   if (!section) {ierr = DMGetLocalSection(dm, &section);CHKERRQ(ierr);}
4666   PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2);
4667   PetscValidHeaderSpecific(v, VEC_CLASSID, 3);
4668   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
4669   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
4670   if (depth == 1 && numFields < 2) {
4671     ierr = DMPlexVecGetClosure_Depth1_Static(dm, section, v, point, csize, values);CHKERRQ(ierr);
4672     PetscFunctionReturn(0);
4673   }
4674   /* Get points */
4675   ierr = DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);CHKERRQ(ierr);
4676   ierr = PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject) dm, NULL, &perm);CHKERRQ(ierr);
4677   /* Get array */
4678   if (!values || !*values) {
4679     PetscInt asize = 0, dof, p;
4680 
4681     for (p = 0; p < numPoints*2; p += 2) {
4682       ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
4683       asize += dof;
4684     }
4685     if (!values) {
4686       ierr = DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);CHKERRQ(ierr);
4687       if (csize) *csize = asize;
4688       PetscFunctionReturn(0);
4689     }
4690     ierr = DMGetWorkArray(dm, asize, MPIU_SCALAR, &array);CHKERRQ(ierr);
4691   } else {
4692     array = *values;
4693   }
4694   ierr = VecGetArrayRead(v, &vArray);CHKERRQ(ierr);
4695   /* Get values */
4696   if (numFields > 0) {ierr = DMPlexVecGetClosure_Fields_Static(dm, section, numPoints, points, numFields, perm, vArray, &size, array);CHKERRQ(ierr);}
4697   else               {ierr = DMPlexVecGetClosure_Static(dm, section, numPoints, points, perm, vArray, &size, array);CHKERRQ(ierr);}
4698   /* Cleanup points */
4699   ierr = DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);CHKERRQ(ierr);
4700   /* Cleanup array */
4701   ierr = VecRestoreArrayRead(v, &vArray);CHKERRQ(ierr);
4702   if (!*values) {
4703     if (csize) *csize = size;
4704     *values = array;
4705   } else {
4706     if (size > *csize) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %D < actual size %D", *csize, size);
4707     *csize = size;
4708   }
4709   PetscFunctionReturn(0);
4710 }
4711 
4712 /*@C
4713   DMPlexVecRestoreClosure - Restore the array of the values on the closure of 'point'
4714 
4715   Not collective
4716 
4717   Input Parameters:
4718 + dm - The DM
4719 . section - The section describing the layout in v, or NULL to use the default section
4720 . v - The local vector
4721 . point - The point in the DM
4722 . csize - The number of values in the closure, or NULL
4723 - values - The array of values, which is a borrowed array and should not be freed
4724 
4725   Note that the array values are discarded and not copied back into v. In order to copy values back to v, use DMPlexVecSetClosure()
4726 
4727   Fortran Notes:
4728   Since it returns an array, this routine is only available in Fortran 90, and you must
4729   include petsc.h90 in your code.
4730 
4731   The csize argument is not present in the Fortran 90 binding since it is internal to the array.
4732 
4733   Level: intermediate
4734 
4735 .seealso DMPlexVecGetClosure(), DMPlexVecSetClosure(), DMPlexMatSetClosure()
4736 @*/
4737 PetscErrorCode DMPlexVecRestoreClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[])
4738 {
4739   PetscInt       size = 0;
4740   PetscErrorCode ierr;
4741 
4742   PetscFunctionBegin;
4743   /* Should work without recalculating size */
4744   ierr = DMRestoreWorkArray(dm, size, MPIU_SCALAR, (void*) values);CHKERRQ(ierr);
4745   *values = NULL;
4746   PetscFunctionReturn(0);
4747 }
4748 
4749 PETSC_STATIC_INLINE void add   (PetscScalar *x, PetscScalar y) {*x += y;}
4750 PETSC_STATIC_INLINE void insert(PetscScalar *x, PetscScalar y) {*x  = y;}
4751 
4752 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[])
4753 {
4754   PetscInt        cdof;   /* The number of constraints on this point */
4755   const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
4756   PetscScalar    *a;
4757   PetscInt        off, cind = 0, k;
4758   PetscErrorCode  ierr;
4759 
4760   PetscFunctionBegin;
4761   ierr = PetscSectionGetConstraintDof(section, point, &cdof);CHKERRQ(ierr);
4762   ierr = PetscSectionGetOffset(section, point, &off);CHKERRQ(ierr);
4763   a    = &array[off];
4764   if (!cdof || setBC) {
4765     if (clperm) {
4766       if (perm) {for (k = 0; k < dof; ++k) {fuse(&a[k], values[clperm[offset+perm[k]]] * (flip ? flip[perm[k]] : 1.));}}
4767       else      {for (k = 0; k < dof; ++k) {fuse(&a[k], values[clperm[offset+     k ]] * (flip ? flip[     k ] : 1.));}}
4768     } else {
4769       if (perm) {for (k = 0; k < dof; ++k) {fuse(&a[k], values[offset+perm[k]] * (flip ? flip[perm[k]] : 1.));}}
4770       else      {for (k = 0; k < dof; ++k) {fuse(&a[k], values[offset+     k ] * (flip ? flip[     k ] : 1.));}}
4771     }
4772   } else {
4773     ierr = PetscSectionGetConstraintIndices(section, point, &cdofs);CHKERRQ(ierr);
4774     if (clperm) {
4775       if (perm) {for (k = 0; k < dof; ++k) {
4776           if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
4777           fuse(&a[k], values[clperm[offset+perm[k]]] * (flip ? flip[perm[k]] : 1.));
4778         }
4779       } else {
4780         for (k = 0; k < dof; ++k) {
4781           if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
4782           fuse(&a[k], values[clperm[offset+     k ]] * (flip ? flip[     k ] : 1.));
4783         }
4784       }
4785     } else {
4786       if (perm) {
4787         for (k = 0; k < dof; ++k) {
4788           if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
4789           fuse(&a[k], values[offset+perm[k]] * (flip ? flip[perm[k]] : 1.));
4790         }
4791       } else {
4792         for (k = 0; k < dof; ++k) {
4793           if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
4794           fuse(&a[k], values[offset+     k ] * (flip ? flip[     k ] : 1.));
4795         }
4796       }
4797     }
4798   }
4799   PetscFunctionReturn(0);
4800 }
4801 
4802 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[])
4803 {
4804   PetscInt        cdof;   /* The number of constraints on this point */
4805   const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
4806   PetscScalar    *a;
4807   PetscInt        off, cind = 0, k;
4808   PetscErrorCode  ierr;
4809 
4810   PetscFunctionBegin;
4811   ierr = PetscSectionGetConstraintDof(section, point, &cdof);CHKERRQ(ierr);
4812   ierr = PetscSectionGetOffset(section, point, &off);CHKERRQ(ierr);
4813   a    = &array[off];
4814   if (cdof) {
4815     ierr = PetscSectionGetConstraintIndices(section, point, &cdofs);CHKERRQ(ierr);
4816     if (clperm) {
4817       if (perm) {
4818         for (k = 0; k < dof; ++k) {
4819           if ((cind < cdof) && (k == cdofs[cind])) {
4820             fuse(&a[k], values[clperm[offset+perm[k]]] * (flip ? flip[perm[k]] : 1.));
4821             cind++;
4822           }
4823         }
4824       } else {
4825         for (k = 0; k < dof; ++k) {
4826           if ((cind < cdof) && (k == cdofs[cind])) {
4827             fuse(&a[k], values[clperm[offset+     k ]] * (flip ? flip[     k ] : 1.));
4828             cind++;
4829           }
4830         }
4831       }
4832     } else {
4833       if (perm) {
4834         for (k = 0; k < dof; ++k) {
4835           if ((cind < cdof) && (k == cdofs[cind])) {
4836             fuse(&a[k], values[offset+perm[k]] * (flip ? flip[perm[k]] : 1.));
4837             cind++;
4838           }
4839         }
4840       } else {
4841         for (k = 0; k < dof; ++k) {
4842           if ((cind < cdof) && (k == cdofs[cind])) {
4843             fuse(&a[k], values[offset+     k ] * (flip ? flip[     k ] : 1.));
4844             cind++;
4845           }
4846         }
4847       }
4848     }
4849   }
4850   PetscFunctionReturn(0);
4851 }
4852 
4853 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[])
4854 {
4855   PetscScalar    *a;
4856   PetscInt        fdof, foff, fcdof, foffset = *offset;
4857   const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
4858   PetscInt        cind = 0, b;
4859   PetscErrorCode  ierr;
4860 
4861   PetscFunctionBegin;
4862   ierr = PetscSectionGetFieldDof(section, point, f, &fdof);CHKERRQ(ierr);
4863   ierr = PetscSectionGetFieldConstraintDof(section, point, f, &fcdof);CHKERRQ(ierr);
4864   ierr = PetscSectionGetFieldOffset(section, point, f, &foff);CHKERRQ(ierr);
4865   a    = &array[foff];
4866   if (!fcdof || setBC) {
4867     if (clperm) {
4868       if (perm) {for (b = 0; b < fdof; b++) {fuse(&a[b], values[clperm[foffset+perm[b]]] * (flip ? flip[perm[b]] : 1.));}}
4869       else      {for (b = 0; b < fdof; b++) {fuse(&a[b], values[clperm[foffset+     b ]] * (flip ? flip[     b ] : 1.));}}
4870     } else {
4871       if (perm) {for (b = 0; b < fdof; b++) {fuse(&a[b], values[foffset+perm[b]] * (flip ? flip[perm[b]] : 1.));}}
4872       else      {for (b = 0; b < fdof; b++) {fuse(&a[b], values[foffset+     b ] * (flip ? flip[     b ] : 1.));}}
4873     }
4874   } else {
4875     ierr = PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);CHKERRQ(ierr);
4876     if (clperm) {
4877       if (perm) {
4878         for (b = 0; b < fdof; b++) {
4879           if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; continue;}
4880           fuse(&a[b], values[clperm[foffset+perm[b]]] * (flip ? flip[perm[b]] : 1.));
4881         }
4882       } else {
4883         for (b = 0; b < fdof; b++) {
4884           if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; continue;}
4885           fuse(&a[b], values[clperm[foffset+     b ]] * (flip ? flip[     b ] : 1.));
4886         }
4887       }
4888     } else {
4889       if (perm) {
4890         for (b = 0; b < fdof; b++) {
4891           if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; continue;}
4892           fuse(&a[b], values[foffset+perm[b]] * (flip ? flip[perm[b]] : 1.));
4893         }
4894       } else {
4895         for (b = 0; b < fdof; b++) {
4896           if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; continue;}
4897           fuse(&a[b], values[foffset+     b ] * (flip ? flip[     b ] : 1.));
4898         }
4899       }
4900     }
4901   }
4902   *offset += fdof;
4903   PetscFunctionReturn(0);
4904 }
4905 
4906 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[])
4907 {
4908   PetscScalar    *a;
4909   PetscInt        fdof, foff, fcdof, foffset = *offset;
4910   const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
4911   PetscInt        cind = 0, ncind = 0, b;
4912   PetscBool       ncSet, fcSet;
4913   PetscErrorCode  ierr;
4914 
4915   PetscFunctionBegin;
4916   ierr = PetscSectionGetFieldDof(section, point, f, &fdof);CHKERRQ(ierr);
4917   ierr = PetscSectionGetFieldConstraintDof(section, point, f, &fcdof);CHKERRQ(ierr);
4918   ierr = PetscSectionGetFieldOffset(section, point, f, &foff);CHKERRQ(ierr);
4919   a    = &array[foff];
4920   if (fcdof) {
4921     /* We just override fcdof and fcdofs with Ncc and comps */
4922     ierr = PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);CHKERRQ(ierr);
4923     if (clperm) {
4924       if (perm) {
4925         if (comps) {
4926           for (b = 0; b < fdof; b++) {
4927             ncSet = fcSet = PETSC_FALSE;
4928             if ((ncind < Ncc)  && (b == comps[ncind])) {++ncind; ncSet = PETSC_TRUE;}
4929             if ((cind < fcdof) && (b == fcdofs[cind])) {++cind;  fcSet = PETSC_TRUE;}
4930             if (ncSet && fcSet) {fuse(&a[b], values[clperm[foffset+perm[b]]] * (flip ? flip[perm[b]] : 1.));}
4931           }
4932         } else {
4933           for (b = 0; b < fdof; b++) {
4934             if ((cind < fcdof) && (b == fcdofs[cind])) {
4935               fuse(&a[b], values[clperm[foffset+perm[b]]] * (flip ? flip[perm[b]] : 1.));
4936               ++cind;
4937             }
4938           }
4939         }
4940       } else {
4941         if (comps) {
4942           for (b = 0; b < fdof; b++) {
4943             ncSet = fcSet = PETSC_FALSE;
4944             if ((ncind < Ncc)  && (b == comps[ncind])) {++ncind; ncSet = PETSC_TRUE;}
4945             if ((cind < fcdof) && (b == fcdofs[cind])) {++cind;  fcSet = PETSC_TRUE;}
4946             if (ncSet && fcSet) {fuse(&a[b], values[clperm[foffset+     b ]] * (flip ? flip[     b ] : 1.));}
4947           }
4948         } else {
4949           for (b = 0; b < fdof; b++) {
4950             if ((cind < fcdof) && (b == fcdofs[cind])) {
4951               fuse(&a[b], values[clperm[foffset+     b ]] * (flip ? flip[     b ] : 1.));
4952               ++cind;
4953             }
4954           }
4955         }
4956       }
4957     } else {
4958       if (perm) {
4959         if (comps) {
4960           for (b = 0; b < fdof; b++) {
4961             ncSet = fcSet = PETSC_FALSE;
4962             if ((ncind < Ncc)  && (b == comps[ncind])) {++ncind; ncSet = PETSC_TRUE;}
4963             if ((cind < fcdof) && (b == fcdofs[cind])) {++cind;  fcSet = PETSC_TRUE;}
4964             if (ncSet && fcSet) {fuse(&a[b], values[foffset+perm[b]] * (flip ? flip[perm[b]] : 1.));}
4965           }
4966         } else {
4967           for (b = 0; b < fdof; b++) {
4968             if ((cind < fcdof) && (b == fcdofs[cind])) {
4969               fuse(&a[b], values[foffset+perm[b]] * (flip ? flip[perm[b]] : 1.));
4970               ++cind;
4971             }
4972           }
4973         }
4974       } else {
4975         if (comps) {
4976           for (b = 0; b < fdof; b++) {
4977             ncSet = fcSet = PETSC_FALSE;
4978             if ((ncind < Ncc)  && (b == comps[ncind])) {++ncind; ncSet = PETSC_TRUE;}
4979             if ((cind < fcdof) && (b == fcdofs[cind])) {++cind;  fcSet = PETSC_TRUE;}
4980             if (ncSet && fcSet) {fuse(&a[b], values[foffset+     b ] * (flip ? flip[     b ] : 1.));}
4981           }
4982         } else {
4983           for (b = 0; b < fdof; b++) {
4984             if ((cind < fcdof) && (b == fcdofs[cind])) {
4985               fuse(&a[b], values[foffset+     b ] * (flip ? flip[     b ] : 1.));
4986               ++cind;
4987             }
4988           }
4989         }
4990       }
4991     }
4992   }
4993   *offset += fdof;
4994   PetscFunctionReturn(0);
4995 }
4996 
4997 PETSC_STATIC_INLINE PetscErrorCode DMPlexVecSetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode)
4998 {
4999   PetscScalar    *array;
5000   const PetscInt *cone, *coneO;
5001   PetscInt        pStart, pEnd, p, numPoints, off, dof;
5002   PetscErrorCode  ierr;
5003 
5004   PetscFunctionBeginHot;
5005   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
5006   ierr = DMPlexGetConeSize(dm, point, &numPoints);CHKERRQ(ierr);
5007   ierr = DMPlexGetCone(dm, point, &cone);CHKERRQ(ierr);
5008   ierr = DMPlexGetConeOrientation(dm, point, &coneO);CHKERRQ(ierr);
5009   ierr = VecGetArray(v, &array);CHKERRQ(ierr);
5010   for (p = 0, off = 0; p <= numPoints; ++p, off += dof) {
5011     const PetscInt cp = !p ? point : cone[p-1];
5012     const PetscInt o  = !p ? 0     : coneO[p-1];
5013 
5014     if ((cp < pStart) || (cp >= pEnd)) {dof = 0; continue;}
5015     ierr = PetscSectionGetDof(section, cp, &dof);CHKERRQ(ierr);
5016     /* ADD_VALUES */
5017     {
5018       const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
5019       PetscScalar    *a;
5020       PetscInt        cdof, coff, cind = 0, k;
5021 
5022       ierr = PetscSectionGetConstraintDof(section, cp, &cdof);CHKERRQ(ierr);
5023       ierr = PetscSectionGetOffset(section, cp, &coff);CHKERRQ(ierr);
5024       a    = &array[coff];
5025       if (!cdof) {
5026         if (o >= 0) {
5027           for (k = 0; k < dof; ++k) {
5028             a[k] += values[off+k];
5029           }
5030         } else {
5031           for (k = 0; k < dof; ++k) {
5032             a[k] += values[off+dof-k-1];
5033           }
5034         }
5035       } else {
5036         ierr = PetscSectionGetConstraintIndices(section, cp, &cdofs);CHKERRQ(ierr);
5037         if (o >= 0) {
5038           for (k = 0; k < dof; ++k) {
5039             if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
5040             a[k] += values[off+k];
5041           }
5042         } else {
5043           for (k = 0; k < dof; ++k) {
5044             if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
5045             a[k] += values[off+dof-k-1];
5046           }
5047         }
5048       }
5049     }
5050   }
5051   ierr = VecRestoreArray(v, &array);CHKERRQ(ierr);
5052   PetscFunctionReturn(0);
5053 }
5054 
5055 /*@C
5056   DMPlexVecSetClosure - Set an array of the values on the closure of 'point'
5057 
5058   Not collective
5059 
5060   Input Parameters:
5061 + dm - The DM
5062 . section - The section describing the layout in v, or NULL to use the default section
5063 . v - The local vector
5064 . point - The point in the DM
5065 . values - The array of values
5066 - mode - The insert mode. One of INSERT_ALL_VALUES, ADD_ALL_VALUES, INSERT_VALUES, ADD_VALUES, INSERT_BC_VALUES, and ADD_BC_VALUES,
5067          where INSERT_ALL_VALUES and ADD_ALL_VALUES also overwrite boundary conditions.
5068 
5069   Fortran Notes:
5070   This routine is only available in Fortran 90, and you must include petsc.h90 in your code.
5071 
5072   Level: intermediate
5073 
5074 .seealso DMPlexVecGetClosure(), DMPlexMatSetClosure()
5075 @*/
5076 PetscErrorCode DMPlexVecSetClosure(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode)
5077 {
5078   PetscSection    clSection;
5079   IS              clPoints;
5080   PetscScalar    *array;
5081   PetscInt       *points = NULL;
5082   const PetscInt *clp, *clperm;
5083   PetscInt        depth, numFields, numPoints, p;
5084   PetscErrorCode  ierr;
5085 
5086   PetscFunctionBeginHot;
5087   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5088   if (!section) {ierr = DMGetLocalSection(dm, &section);CHKERRQ(ierr);}
5089   PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2);
5090   PetscValidHeaderSpecific(v, VEC_CLASSID, 3);
5091   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
5092   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
5093   if (depth == 1 && numFields < 2 && mode == ADD_VALUES) {
5094     ierr = DMPlexVecSetClosure_Depth1_Static(dm, section, v, point, values, mode);CHKERRQ(ierr);
5095     PetscFunctionReturn(0);
5096   }
5097   /* Get points */
5098   ierr = PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject) dm, NULL, &clperm);CHKERRQ(ierr);
5099   ierr = DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);CHKERRQ(ierr);
5100   /* Get array */
5101   ierr = VecGetArray(v, &array);CHKERRQ(ierr);
5102   /* Get values */
5103   if (numFields > 0) {
5104     PetscInt offset = 0, f;
5105     for (f = 0; f < numFields; ++f) {
5106       const PetscInt    **perms = NULL;
5107       const PetscScalar **flips = NULL;
5108 
5109       ierr = PetscSectionGetFieldPointSyms(section,f,numPoints,points,&perms,&flips);CHKERRQ(ierr);
5110       switch (mode) {
5111       case INSERT_VALUES:
5112         for (p = 0; p < numPoints; p++) {
5113           const PetscInt    point = points[2*p];
5114           const PetscInt    *perm = perms ? perms[p] : NULL;
5115           const PetscScalar *flip = flips ? flips[p] : NULL;
5116           updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, clperm, values, &offset, array);
5117         } break;
5118       case INSERT_ALL_VALUES:
5119         for (p = 0; p < numPoints; p++) {
5120           const PetscInt    point = points[2*p];
5121           const PetscInt    *perm = perms ? perms[p] : NULL;
5122           const PetscScalar *flip = flips ? flips[p] : NULL;
5123           updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, clperm, values, &offset, array);
5124         } break;
5125       case INSERT_BC_VALUES:
5126         for (p = 0; p < numPoints; p++) {
5127           const PetscInt    point = points[2*p];
5128           const PetscInt    *perm = perms ? perms[p] : NULL;
5129           const PetscScalar *flip = flips ? flips[p] : NULL;
5130           updatePointFieldsBC_private(section, point, perm, flip, f, -1, NULL, insert, clperm, values, &offset, array);
5131         } break;
5132       case ADD_VALUES:
5133         for (p = 0; p < numPoints; p++) {
5134           const PetscInt    point = points[2*p];
5135           const PetscInt    *perm = perms ? perms[p] : NULL;
5136           const PetscScalar *flip = flips ? flips[p] : NULL;
5137           updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, clperm, values, &offset, array);
5138         } break;
5139       case ADD_ALL_VALUES:
5140         for (p = 0; p < numPoints; p++) {
5141           const PetscInt    point = points[2*p];
5142           const PetscInt    *perm = perms ? perms[p] : NULL;
5143           const PetscScalar *flip = flips ? flips[p] : NULL;
5144           updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, clperm, values, &offset, array);
5145         } break;
5146       case ADD_BC_VALUES:
5147         for (p = 0; p < numPoints; p++) {
5148           const PetscInt    point = points[2*p];
5149           const PetscInt    *perm = perms ? perms[p] : NULL;
5150           const PetscScalar *flip = flips ? flips[p] : NULL;
5151           updatePointFieldsBC_private(section, point, perm, flip, f, -1, NULL, add, clperm, values, &offset, array);
5152         } break;
5153       default:
5154         SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode);
5155       }
5156       ierr = PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms,&flips);CHKERRQ(ierr);
5157     }
5158   } else {
5159     PetscInt dof, off;
5160     const PetscInt    **perms = NULL;
5161     const PetscScalar **flips = NULL;
5162 
5163     ierr = PetscSectionGetPointSyms(section,numPoints,points,&perms,&flips);CHKERRQ(ierr);
5164     switch (mode) {
5165     case INSERT_VALUES:
5166       for (p = 0, off = 0; p < numPoints; p++, off += dof) {
5167         const PetscInt    point = points[2*p];
5168         const PetscInt    *perm = perms ? perms[p] : NULL;
5169         const PetscScalar *flip = flips ? flips[p] : NULL;
5170         ierr = PetscSectionGetDof(section, point, &dof);CHKERRQ(ierr);
5171         updatePoint_private(section, point, dof, insert, PETSC_FALSE, perm, flip, clperm, values, off, array);
5172       } break;
5173     case INSERT_ALL_VALUES:
5174       for (p = 0, off = 0; p < numPoints; p++, off += dof) {
5175         const PetscInt    point = points[2*p];
5176         const PetscInt    *perm = perms ? perms[p] : NULL;
5177         const PetscScalar *flip = flips ? flips[p] : NULL;
5178         ierr = PetscSectionGetDof(section, point, &dof);CHKERRQ(ierr);
5179         updatePoint_private(section, point, dof, insert, PETSC_TRUE,  perm, flip, clperm, values, off, array);
5180       } break;
5181     case INSERT_BC_VALUES:
5182       for (p = 0, off = 0; p < numPoints; p++, off += dof) {
5183         const PetscInt    point = points[2*p];
5184         const PetscInt    *perm = perms ? perms[p] : NULL;
5185         const PetscScalar *flip = flips ? flips[p] : NULL;
5186         ierr = PetscSectionGetDof(section, point, &dof);CHKERRQ(ierr);
5187         updatePointBC_private(section, point, dof, insert,  perm, flip, clperm, values, off, array);
5188       } break;
5189     case ADD_VALUES:
5190       for (p = 0, off = 0; p < numPoints; p++, off += dof) {
5191         const PetscInt    point = points[2*p];
5192         const PetscInt    *perm = perms ? perms[p] : NULL;
5193         const PetscScalar *flip = flips ? flips[p] : NULL;
5194         ierr = PetscSectionGetDof(section, point, &dof);CHKERRQ(ierr);
5195         updatePoint_private(section, point, dof, add,    PETSC_FALSE, perm, flip, clperm, values, off, array);
5196       } break;
5197     case ADD_ALL_VALUES:
5198       for (p = 0, off = 0; p < numPoints; p++, off += dof) {
5199         const PetscInt    point = points[2*p];
5200         const PetscInt    *perm = perms ? perms[p] : NULL;
5201         const PetscScalar *flip = flips ? flips[p] : NULL;
5202         ierr = PetscSectionGetDof(section, point, &dof);CHKERRQ(ierr);
5203         updatePoint_private(section, point, dof, add,    PETSC_TRUE,  perm, flip, clperm, values, off, array);
5204       } break;
5205     case ADD_BC_VALUES:
5206       for (p = 0, off = 0; p < numPoints; p++, off += dof) {
5207         const PetscInt    point = points[2*p];
5208         const PetscInt    *perm = perms ? perms[p] : NULL;
5209         const PetscScalar *flip = flips ? flips[p] : NULL;
5210         ierr = PetscSectionGetDof(section, point, &dof);CHKERRQ(ierr);
5211         updatePointBC_private(section, point, dof, add,  perm, flip, clperm, values, off, array);
5212       } break;
5213     default:
5214       SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode);
5215     }
5216     ierr = PetscSectionRestorePointSyms(section,numPoints,points,&perms,&flips);CHKERRQ(ierr);
5217   }
5218   /* Cleanup points */
5219   ierr = DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);CHKERRQ(ierr);
5220   /* Cleanup array */
5221   ierr = VecRestoreArray(v, &array);CHKERRQ(ierr);
5222   PetscFunctionReturn(0);
5223 }
5224 
5225 PetscErrorCode DMPlexVecSetFieldClosure_Internal(DM dm, PetscSection section, Vec v, PetscBool fieldActive[], PetscInt point, PetscInt Ncc, const PetscInt comps[], const PetscScalar values[], InsertMode mode)
5226 {
5227   PetscSection      clSection;
5228   IS                clPoints;
5229   PetscScalar       *array;
5230   PetscInt          *points = NULL;
5231   const PetscInt    *clp, *clperm;
5232   PetscInt          numFields, numPoints, p;
5233   PetscInt          offset = 0, f;
5234   PetscErrorCode    ierr;
5235 
5236   PetscFunctionBeginHot;
5237   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5238   if (!section) {ierr = DMGetLocalSection(dm, &section);CHKERRQ(ierr);}
5239   PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2);
5240   PetscValidHeaderSpecific(v, VEC_CLASSID, 3);
5241   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
5242   /* Get points */
5243   ierr = PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject) dm, NULL, &clperm);CHKERRQ(ierr);
5244   ierr = DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);CHKERRQ(ierr);
5245   /* Get array */
5246   ierr = VecGetArray(v, &array);CHKERRQ(ierr);
5247   /* Get values */
5248   for (f = 0; f < numFields; ++f) {
5249     const PetscInt    **perms = NULL;
5250     const PetscScalar **flips = NULL;
5251 
5252     if (!fieldActive[f]) {
5253       for (p = 0; p < numPoints*2; p += 2) {
5254         PetscInt fdof;
5255         ierr = PetscSectionGetFieldDof(section, points[p], f, &fdof);CHKERRQ(ierr);
5256         offset += fdof;
5257       }
5258       continue;
5259     }
5260     ierr = PetscSectionGetFieldPointSyms(section,f,numPoints,points,&perms,&flips);CHKERRQ(ierr);
5261     switch (mode) {
5262     case INSERT_VALUES:
5263       for (p = 0; p < numPoints; p++) {
5264         const PetscInt    point = points[2*p];
5265         const PetscInt    *perm = perms ? perms[p] : NULL;
5266         const PetscScalar *flip = flips ? flips[p] : NULL;
5267         updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, clperm, values, &offset, array);
5268       } break;
5269     case INSERT_ALL_VALUES:
5270       for (p = 0; p < numPoints; p++) {
5271         const PetscInt    point = points[2*p];
5272         const PetscInt    *perm = perms ? perms[p] : NULL;
5273         const PetscScalar *flip = flips ? flips[p] : NULL;
5274         updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, clperm, values, &offset, array);
5275         } break;
5276     case INSERT_BC_VALUES:
5277       for (p = 0; p < numPoints; p++) {
5278         const PetscInt    point = points[2*p];
5279         const PetscInt    *perm = perms ? perms[p] : NULL;
5280         const PetscScalar *flip = flips ? flips[p] : NULL;
5281         updatePointFieldsBC_private(section, point, perm, flip, f, Ncc, comps, insert, clperm, values, &offset, array);
5282       } break;
5283     case ADD_VALUES:
5284       for (p = 0; p < numPoints; p++) {
5285         const PetscInt    point = points[2*p];
5286         const PetscInt    *perm = perms ? perms[p] : NULL;
5287         const PetscScalar *flip = flips ? flips[p] : NULL;
5288         updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, clperm, values, &offset, array);
5289       } break;
5290     case ADD_ALL_VALUES:
5291       for (p = 0; p < numPoints; p++) {
5292         const PetscInt    point = points[2*p];
5293         const PetscInt    *perm = perms ? perms[p] : NULL;
5294         const PetscScalar *flip = flips ? flips[p] : NULL;
5295         updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, clperm, values, &offset, array);
5296       } break;
5297     default:
5298       SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode);
5299     }
5300     ierr = PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms,&flips);CHKERRQ(ierr);
5301   }
5302   /* Cleanup points */
5303   ierr = DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);CHKERRQ(ierr);
5304   /* Cleanup array */
5305   ierr = VecRestoreArray(v, &array);CHKERRQ(ierr);
5306   PetscFunctionReturn(0);
5307 }
5308 
5309 static PetscErrorCode DMPlexPrintMatSetValues(PetscViewer viewer, Mat A, PetscInt point, PetscInt numRIndices, const PetscInt rindices[], PetscInt numCIndices, const PetscInt cindices[], const PetscScalar values[])
5310 {
5311   PetscMPIInt    rank;
5312   PetscInt       i, j;
5313   PetscErrorCode ierr;
5314 
5315   PetscFunctionBegin;
5316   ierr = MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank);CHKERRQ(ierr);
5317   ierr = PetscViewerASCIIPrintf(viewer, "[%d]mat for point %D\n", rank, point);CHKERRQ(ierr);
5318   for (i = 0; i < numRIndices; i++) {ierr = PetscViewerASCIIPrintf(viewer, "[%d]mat row indices[%D] = %D\n", rank, i, rindices[i]);CHKERRQ(ierr);}
5319   for (i = 0; i < numCIndices; i++) {ierr = PetscViewerASCIIPrintf(viewer, "[%d]mat col indices[%D] = %D\n", rank, i, cindices[i]);CHKERRQ(ierr);}
5320   numCIndices = numCIndices ? numCIndices : numRIndices;
5321   for (i = 0; i < numRIndices; i++) {
5322     ierr = PetscViewerASCIIPrintf(viewer, "[%d]", rank);CHKERRQ(ierr);
5323     for (j = 0; j < numCIndices; j++) {
5324 #if defined(PETSC_USE_COMPLEX)
5325       ierr = PetscViewerASCIIPrintf(viewer, " (%g,%g)", (double)PetscRealPart(values[i*numCIndices+j]), (double)PetscImaginaryPart(values[i*numCIndices+j]));CHKERRQ(ierr);
5326 #else
5327       ierr = PetscViewerASCIIPrintf(viewer, " %g", (double)values[i*numCIndices+j]);CHKERRQ(ierr);
5328 #endif
5329     }
5330     ierr = PetscViewerASCIIPrintf(viewer, "\n");CHKERRQ(ierr);
5331   }
5332   PetscFunctionReturn(0);
5333 }
5334 
5335 /*
5336   DMPlexGetIndicesPoint_Internal - Add the indices for dofs on a point to an index array
5337 
5338   Input Parameters:
5339 + section - The section for this data layout
5340 . point   - The point contributing dofs with these indices
5341 . off     - The global offset of this point
5342 . loff    - The local offset of each field
5343 . setBC   - The flag determining whether to include indices of bounsary values
5344 . perm    - A permutation of the dofs on this point, or NULL
5345 - indperm - A permutation of the entire indices array, or NULL
5346 
5347   Output Parameter:
5348 . indices - Indices for dofs on this point
5349 
5350   Level: developer
5351 
5352   Note: The indices could be local or global, depending on the value of 'off'.
5353 */
5354 PetscErrorCode DMPlexGetIndicesPoint_Internal(PetscSection section, PetscInt point, PetscInt off, PetscInt *loff, PetscBool setBC, const PetscInt perm[], const PetscInt indperm[], PetscInt indices[])
5355 {
5356   PetscInt        dof;   /* The number of unknowns on this point */
5357   PetscInt        cdof;  /* The number of constraints on this point */
5358   const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
5359   PetscInt        cind = 0, k;
5360   PetscErrorCode  ierr;
5361 
5362   PetscFunctionBegin;
5363   ierr = PetscSectionGetDof(section, point, &dof);CHKERRQ(ierr);
5364   ierr = PetscSectionGetConstraintDof(section, point, &cdof);CHKERRQ(ierr);
5365   if (!cdof || setBC) {
5366     for (k = 0; k < dof; ++k) {
5367       const PetscInt preind = perm ? *loff+perm[k] : *loff+k;
5368       const PetscInt ind    = indperm ? indperm[preind] : preind;
5369 
5370       indices[ind] = off + k;
5371     }
5372   } else {
5373     ierr = PetscSectionGetConstraintIndices(section, point, &cdofs);CHKERRQ(ierr);
5374     for (k = 0; k < dof; ++k) {
5375       const PetscInt preind = perm ? *loff+perm[k] : *loff+k;
5376       const PetscInt ind    = indperm ? indperm[preind] : preind;
5377 
5378       if ((cind < cdof) && (k == cdofs[cind])) {
5379         /* Insert check for returning constrained indices */
5380         indices[ind] = -(off+k+1);
5381         ++cind;
5382       } else {
5383         indices[ind] = off+k-cind;
5384       }
5385     }
5386   }
5387   *loff += dof;
5388   PetscFunctionReturn(0);
5389 }
5390 
5391 /*
5392   This version only believes the point offset from the globalSection
5393 
5394  . off - The global offset of this point
5395 */
5396 PetscErrorCode DMPlexGetIndicesPointFields_Internal(PetscSection section, PetscInt point, PetscInt off, PetscInt foffs[], PetscBool setBC, const PetscInt ***perms, PetscInt permsoff, const PetscInt indperm[], PetscInt indices[])
5397 {
5398   PetscInt       numFields, foff, f;
5399   PetscErrorCode ierr;
5400 
5401   PetscFunctionBegin;
5402   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
5403   for (f = 0, foff = 0; f < numFields; ++f) {
5404     PetscInt        fdof, cfdof;
5405     const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
5406     PetscInt        cind = 0, b;
5407     const PetscInt  *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL;
5408 
5409     ierr = PetscSectionGetFieldDof(section, point, f, &fdof);CHKERRQ(ierr);
5410     ierr = PetscSectionGetFieldConstraintDof(section, point, f, &cfdof);CHKERRQ(ierr);
5411     if (!cfdof || setBC) {
5412       for (b = 0; b < fdof; ++b) {
5413         const PetscInt preind = perm ? foffs[f]+perm[b] : foffs[f]+b;
5414         const PetscInt ind    = indperm ? indperm[preind] : preind;
5415 
5416         indices[ind] = off+foff+b;
5417       }
5418     } else {
5419       ierr = PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);CHKERRQ(ierr);
5420       for (b = 0; b < fdof; ++b) {
5421         const PetscInt preind = perm ? foffs[f]+perm[b] : foffs[f]+b;
5422         const PetscInt ind    = indperm ? indperm[preind] : preind;
5423 
5424         if ((cind < cfdof) && (b == fcdofs[cind])) {
5425           indices[ind] = -(off+foff+b+1);
5426           ++cind;
5427         } else {
5428           indices[ind] = off+foff+b-cind;
5429         }
5430       }
5431     }
5432     foff     += (setBC ? fdof : (fdof - cfdof));
5433     foffs[f] += fdof;
5434   }
5435   PetscFunctionReturn(0);
5436 }
5437 
5438 /*
5439   This version believes the globalSection offsets for each field, rather than just the point offset
5440 
5441  . foffs - The offset into 'indices' for each field, since it is segregated by field
5442 */
5443 PetscErrorCode DMPlexGetIndicesPointFieldsSplit_Internal(PetscSection section, PetscSection globalSection, PetscInt point, PetscInt foffs[], PetscBool setBC, const PetscInt ***perms, PetscInt permsoff, const PetscInt indperm[], PetscInt indices[])
5444 {
5445   PetscInt       numFields, foff, f;
5446   PetscErrorCode ierr;
5447 
5448   PetscFunctionBegin;
5449   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
5450   for (f = 0; f < numFields; ++f) {
5451     PetscInt        fdof, cfdof;
5452     const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
5453     PetscInt        cind = 0, b;
5454     const PetscInt  *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL;
5455 
5456     ierr = PetscSectionGetFieldDof(section, point, f, &fdof);CHKERRQ(ierr);
5457     ierr = PetscSectionGetFieldConstraintDof(section, point, f, &cfdof);CHKERRQ(ierr);
5458     ierr = PetscSectionGetFieldOffset(globalSection, point, f, &foff);CHKERRQ(ierr);
5459     if (!cfdof || setBC) {
5460       for (b = 0; b < fdof; ++b) {
5461         const PetscInt preind = perm ? foffs[f]+perm[b] : foffs[f]+b;
5462         const PetscInt ind    = indperm ? indperm[preind] : preind;
5463 
5464         indices[ind] = foff+b;
5465       }
5466     } else {
5467       ierr = PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);CHKERRQ(ierr);
5468       for (b = 0; b < fdof; ++b) {
5469         const PetscInt preind = perm ? foffs[f]+perm[b] : foffs[f]+b;
5470         const PetscInt ind    = indperm ? indperm[preind] : preind;
5471 
5472         if ((cind < cfdof) && (b == fcdofs[cind])) {
5473           indices[ind] = -(foff+b+1);
5474           ++cind;
5475         } else {
5476           indices[ind] = foff+b-cind;
5477         }
5478       }
5479     }
5480     foffs[f] += fdof;
5481   }
5482   PetscFunctionReturn(0);
5483 }
5484 
5485 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)
5486 {
5487   Mat             cMat;
5488   PetscSection    aSec, cSec;
5489   IS              aIS;
5490   PetscInt        aStart = -1, aEnd = -1;
5491   const PetscInt  *anchors;
5492   PetscInt        numFields, f, p, q, newP = 0;
5493   PetscInt        newNumPoints = 0, newNumIndices = 0;
5494   PetscInt        *newPoints, *indices, *newIndices;
5495   PetscInt        maxAnchor, maxDof;
5496   PetscInt        newOffsets[32];
5497   PetscInt        *pointMatOffsets[32];
5498   PetscInt        *newPointOffsets[32];
5499   PetscScalar     *pointMat[32];
5500   PetscScalar     *newValues=NULL,*tmpValues;
5501   PetscBool       anyConstrained = PETSC_FALSE;
5502   PetscErrorCode  ierr;
5503 
5504   PetscFunctionBegin;
5505   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5506   PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2);
5507   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
5508 
5509   ierr = DMPlexGetAnchors(dm,&aSec,&aIS);CHKERRQ(ierr);
5510   /* if there are point-to-point constraints */
5511   if (aSec) {
5512     ierr = PetscArrayzero(newOffsets, 32);CHKERRQ(ierr);
5513     ierr = ISGetIndices(aIS,&anchors);CHKERRQ(ierr);
5514     ierr = PetscSectionGetChart(aSec,&aStart,&aEnd);CHKERRQ(ierr);
5515     /* figure out how many points are going to be in the new element matrix
5516      * (we allow double counting, because it's all just going to be summed
5517      * into the global matrix anyway) */
5518     for (p = 0; p < 2*numPoints; p+=2) {
5519       PetscInt b    = points[p];
5520       PetscInt bDof = 0, bSecDof;
5521 
5522       ierr = PetscSectionGetDof(section,b,&bSecDof);CHKERRQ(ierr);
5523       if (!bSecDof) {
5524         continue;
5525       }
5526       if (b >= aStart && b < aEnd) {
5527         ierr = PetscSectionGetDof(aSec,b,&bDof);CHKERRQ(ierr);
5528       }
5529       if (bDof) {
5530         /* this point is constrained */
5531         /* it is going to be replaced by its anchors */
5532         PetscInt bOff, q;
5533 
5534         anyConstrained = PETSC_TRUE;
5535         newNumPoints  += bDof;
5536         ierr = PetscSectionGetOffset(aSec,b,&bOff);CHKERRQ(ierr);
5537         for (q = 0; q < bDof; q++) {
5538           PetscInt a = anchors[bOff + q];
5539           PetscInt aDof;
5540 
5541           ierr           = PetscSectionGetDof(section,a,&aDof);CHKERRQ(ierr);
5542           newNumIndices += aDof;
5543           for (f = 0; f < numFields; ++f) {
5544             PetscInt fDof;
5545 
5546             ierr             = PetscSectionGetFieldDof(section, a, f, &fDof);CHKERRQ(ierr);
5547             newOffsets[f+1] += fDof;
5548           }
5549         }
5550       }
5551       else {
5552         /* this point is not constrained */
5553         newNumPoints++;
5554         newNumIndices += bSecDof;
5555         for (f = 0; f < numFields; ++f) {
5556           PetscInt fDof;
5557 
5558           ierr = PetscSectionGetFieldDof(section, b, f, &fDof);CHKERRQ(ierr);
5559           newOffsets[f+1] += fDof;
5560         }
5561       }
5562     }
5563   }
5564   if (!anyConstrained) {
5565     if (outNumPoints)  *outNumPoints  = 0;
5566     if (outNumIndices) *outNumIndices = 0;
5567     if (outPoints)     *outPoints     = NULL;
5568     if (outValues)     *outValues     = NULL;
5569     if (aSec) {ierr = ISRestoreIndices(aIS,&anchors);CHKERRQ(ierr);}
5570     PetscFunctionReturn(0);
5571   }
5572 
5573   if (outNumPoints)  *outNumPoints  = newNumPoints;
5574   if (outNumIndices) *outNumIndices = newNumIndices;
5575 
5576   for (f = 0; f < numFields; ++f) newOffsets[f+1] += newOffsets[f];
5577 
5578   if (!outPoints && !outValues) {
5579     if (offsets) {
5580       for (f = 0; f <= numFields; f++) {
5581         offsets[f] = newOffsets[f];
5582       }
5583     }
5584     if (aSec) {ierr = ISRestoreIndices(aIS,&anchors);CHKERRQ(ierr);}
5585     PetscFunctionReturn(0);
5586   }
5587 
5588   if (numFields && newOffsets[numFields] != newNumIndices) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid size for closure %D should be %D", newOffsets[numFields], newNumIndices);
5589 
5590   ierr = DMGetDefaultConstraints(dm, &cSec, &cMat);CHKERRQ(ierr);
5591 
5592   /* workspaces */
5593   if (numFields) {
5594     for (f = 0; f < numFields; f++) {
5595       ierr = DMGetWorkArray(dm,numPoints+1,MPIU_INT,&pointMatOffsets[f]);CHKERRQ(ierr);
5596       ierr = DMGetWorkArray(dm,numPoints+1,MPIU_INT,&newPointOffsets[f]);CHKERRQ(ierr);
5597     }
5598   }
5599   else {
5600     ierr = DMGetWorkArray(dm,numPoints+1,MPIU_INT,&pointMatOffsets[0]);CHKERRQ(ierr);
5601     ierr = DMGetWorkArray(dm,numPoints,MPIU_INT,&newPointOffsets[0]);CHKERRQ(ierr);
5602   }
5603 
5604   /* get workspaces for the point-to-point matrices */
5605   if (numFields) {
5606     PetscInt totalOffset, totalMatOffset;
5607 
5608     for (p = 0; p < numPoints; p++) {
5609       PetscInt b    = points[2*p];
5610       PetscInt bDof = 0, bSecDof;
5611 
5612       ierr = PetscSectionGetDof(section,b,&bSecDof);CHKERRQ(ierr);
5613       if (!bSecDof) {
5614         for (f = 0; f < numFields; f++) {
5615           newPointOffsets[f][p + 1] = 0;
5616           pointMatOffsets[f][p + 1] = 0;
5617         }
5618         continue;
5619       }
5620       if (b >= aStart && b < aEnd) {
5621         ierr = PetscSectionGetDof(aSec, b, &bDof);CHKERRQ(ierr);
5622       }
5623       if (bDof) {
5624         for (f = 0; f < numFields; f++) {
5625           PetscInt fDof, q, bOff, allFDof = 0;
5626 
5627           ierr = PetscSectionGetFieldDof(section, b, f, &fDof);CHKERRQ(ierr);
5628           ierr = PetscSectionGetOffset(aSec, b, &bOff);CHKERRQ(ierr);
5629           for (q = 0; q < bDof; q++) {
5630             PetscInt a = anchors[bOff + q];
5631             PetscInt aFDof;
5632 
5633             ierr     = PetscSectionGetFieldDof(section, a, f, &aFDof);CHKERRQ(ierr);
5634             allFDof += aFDof;
5635           }
5636           newPointOffsets[f][p+1] = allFDof;
5637           pointMatOffsets[f][p+1] = fDof * allFDof;
5638         }
5639       }
5640       else {
5641         for (f = 0; f < numFields; f++) {
5642           PetscInt fDof;
5643 
5644           ierr = PetscSectionGetFieldDof(section, b, f, &fDof);CHKERRQ(ierr);
5645           newPointOffsets[f][p+1] = fDof;
5646           pointMatOffsets[f][p+1] = 0;
5647         }
5648       }
5649     }
5650     for (f = 0, totalOffset = 0, totalMatOffset = 0; f < numFields; f++) {
5651       newPointOffsets[f][0] = totalOffset;
5652       pointMatOffsets[f][0] = totalMatOffset;
5653       for (p = 0; p < numPoints; p++) {
5654         newPointOffsets[f][p+1] += newPointOffsets[f][p];
5655         pointMatOffsets[f][p+1] += pointMatOffsets[f][p];
5656       }
5657       totalOffset    = newPointOffsets[f][numPoints];
5658       totalMatOffset = pointMatOffsets[f][numPoints];
5659       ierr = DMGetWorkArray(dm,pointMatOffsets[f][numPoints],MPIU_SCALAR,&pointMat[f]);CHKERRQ(ierr);
5660     }
5661   }
5662   else {
5663     for (p = 0; p < numPoints; p++) {
5664       PetscInt b    = points[2*p];
5665       PetscInt bDof = 0, bSecDof;
5666 
5667       ierr = PetscSectionGetDof(section,b,&bSecDof);CHKERRQ(ierr);
5668       if (!bSecDof) {
5669         newPointOffsets[0][p + 1] = 0;
5670         pointMatOffsets[0][p + 1] = 0;
5671         continue;
5672       }
5673       if (b >= aStart && b < aEnd) {
5674         ierr = PetscSectionGetDof(aSec, b, &bDof);CHKERRQ(ierr);
5675       }
5676       if (bDof) {
5677         PetscInt bOff, q, allDof = 0;
5678 
5679         ierr = PetscSectionGetOffset(aSec, b, &bOff);CHKERRQ(ierr);
5680         for (q = 0; q < bDof; q++) {
5681           PetscInt a = anchors[bOff + q], aDof;
5682 
5683           ierr    = PetscSectionGetDof(section, a, &aDof);CHKERRQ(ierr);
5684           allDof += aDof;
5685         }
5686         newPointOffsets[0][p+1] = allDof;
5687         pointMatOffsets[0][p+1] = bSecDof * allDof;
5688       }
5689       else {
5690         newPointOffsets[0][p+1] = bSecDof;
5691         pointMatOffsets[0][p+1] = 0;
5692       }
5693     }
5694     newPointOffsets[0][0] = 0;
5695     pointMatOffsets[0][0] = 0;
5696     for (p = 0; p < numPoints; p++) {
5697       newPointOffsets[0][p+1] += newPointOffsets[0][p];
5698       pointMatOffsets[0][p+1] += pointMatOffsets[0][p];
5699     }
5700     ierr = DMGetWorkArray(dm,pointMatOffsets[0][numPoints],MPIU_SCALAR,&pointMat[0]);CHKERRQ(ierr);
5701   }
5702 
5703   /* output arrays */
5704   ierr = DMGetWorkArray(dm,2*newNumPoints,MPIU_INT,&newPoints);CHKERRQ(ierr);
5705 
5706   /* get the point-to-point matrices; construct newPoints */
5707   ierr = PetscSectionGetMaxDof(aSec, &maxAnchor);CHKERRQ(ierr);
5708   ierr = PetscSectionGetMaxDof(section, &maxDof);CHKERRQ(ierr);
5709   ierr = DMGetWorkArray(dm,maxDof,MPIU_INT,&indices);CHKERRQ(ierr);
5710   ierr = DMGetWorkArray(dm,maxAnchor*maxDof,MPIU_INT,&newIndices);CHKERRQ(ierr);
5711   if (numFields) {
5712     for (p = 0, newP = 0; p < numPoints; p++) {
5713       PetscInt b    = points[2*p];
5714       PetscInt o    = points[2*p+1];
5715       PetscInt bDof = 0, bSecDof;
5716 
5717       ierr = PetscSectionGetDof(section, b, &bSecDof);CHKERRQ(ierr);
5718       if (!bSecDof) {
5719         continue;
5720       }
5721       if (b >= aStart && b < aEnd) {
5722         ierr = PetscSectionGetDof(aSec, b, &bDof);CHKERRQ(ierr);
5723       }
5724       if (bDof) {
5725         PetscInt fStart[32], fEnd[32], fAnchorStart[32], fAnchorEnd[32], bOff, q;
5726 
5727         fStart[0] = 0;
5728         fEnd[0]   = 0;
5729         for (f = 0; f < numFields; f++) {
5730           PetscInt fDof;
5731 
5732           ierr        = PetscSectionGetFieldDof(cSec, b, f, &fDof);CHKERRQ(ierr);
5733           fStart[f+1] = fStart[f] + fDof;
5734           fEnd[f+1]   = fStart[f+1];
5735         }
5736         ierr = PetscSectionGetOffset(cSec, b, &bOff);CHKERRQ(ierr);
5737         ierr = DMPlexGetIndicesPointFields_Internal(cSec, b, bOff, fEnd, PETSC_TRUE, perms, p, NULL, indices);CHKERRQ(ierr);
5738 
5739         fAnchorStart[0] = 0;
5740         fAnchorEnd[0]   = 0;
5741         for (f = 0; f < numFields; f++) {
5742           PetscInt fDof = newPointOffsets[f][p + 1] - newPointOffsets[f][p];
5743 
5744           fAnchorStart[f+1] = fAnchorStart[f] + fDof;
5745           fAnchorEnd[f+1]   = fAnchorStart[f + 1];
5746         }
5747         ierr = PetscSectionGetOffset(aSec, b, &bOff);CHKERRQ(ierr);
5748         for (q = 0; q < bDof; q++) {
5749           PetscInt a = anchors[bOff + q], aOff;
5750 
5751           /* we take the orientation of ap into account in the order that we constructed the indices above: the newly added points have no orientation */
5752           newPoints[2*(newP + q)]     = a;
5753           newPoints[2*(newP + q) + 1] = 0;
5754           ierr = PetscSectionGetOffset(section, a, &aOff);CHKERRQ(ierr);
5755           ierr = DMPlexGetIndicesPointFields_Internal(section, a, aOff, fAnchorEnd, PETSC_TRUE, NULL, -1, NULL, newIndices);CHKERRQ(ierr);
5756         }
5757         newP += bDof;
5758 
5759         if (outValues) {
5760           /* get the point-to-point submatrix */
5761           for (f = 0; f < numFields; f++) {
5762             ierr = MatGetValues(cMat,fEnd[f]-fStart[f],indices + fStart[f],fAnchorEnd[f] - fAnchorStart[f],newIndices + fAnchorStart[f],pointMat[f] + pointMatOffsets[f][p]);CHKERRQ(ierr);
5763           }
5764         }
5765       }
5766       else {
5767         newPoints[2 * newP]     = b;
5768         newPoints[2 * newP + 1] = o;
5769         newP++;
5770       }
5771     }
5772   } else {
5773     for (p = 0; p < numPoints; p++) {
5774       PetscInt b    = points[2*p];
5775       PetscInt o    = points[2*p+1];
5776       PetscInt bDof = 0, bSecDof;
5777 
5778       ierr = PetscSectionGetDof(section, b, &bSecDof);CHKERRQ(ierr);
5779       if (!bSecDof) {
5780         continue;
5781       }
5782       if (b >= aStart && b < aEnd) {
5783         ierr = PetscSectionGetDof(aSec, b, &bDof);CHKERRQ(ierr);
5784       }
5785       if (bDof) {
5786         PetscInt bEnd = 0, bAnchorEnd = 0, bOff;
5787 
5788         ierr = PetscSectionGetOffset(cSec, b, &bOff);CHKERRQ(ierr);
5789         ierr = DMPlexGetIndicesPoint_Internal(cSec, b, bOff, &bEnd, PETSC_TRUE, (perms && perms[0]) ? perms[0][p] : NULL, NULL, indices);CHKERRQ(ierr);
5790 
5791         ierr = PetscSectionGetOffset (aSec, b, &bOff);CHKERRQ(ierr);
5792         for (q = 0; q < bDof; q++) {
5793           PetscInt a = anchors[bOff + q], aOff;
5794 
5795           /* we take the orientation of ap into account in the order that we constructed the indices above: the newly added points have no orientation */
5796 
5797           newPoints[2*(newP + q)]     = a;
5798           newPoints[2*(newP + q) + 1] = 0;
5799           ierr = PetscSectionGetOffset(section, a, &aOff);CHKERRQ(ierr);
5800           ierr = DMPlexGetIndicesPoint_Internal(section, a, aOff, &bAnchorEnd, PETSC_TRUE, NULL, NULL, newIndices);CHKERRQ(ierr);
5801         }
5802         newP += bDof;
5803 
5804         /* get the point-to-point submatrix */
5805         if (outValues) {
5806           ierr = MatGetValues(cMat,bEnd,indices,bAnchorEnd,newIndices,pointMat[0] + pointMatOffsets[0][p]);CHKERRQ(ierr);
5807         }
5808       }
5809       else {
5810         newPoints[2 * newP]     = b;
5811         newPoints[2 * newP + 1] = o;
5812         newP++;
5813       }
5814     }
5815   }
5816 
5817   if (outValues) {
5818     ierr = DMGetWorkArray(dm,newNumIndices*numIndices,MPIU_SCALAR,&tmpValues);CHKERRQ(ierr);
5819     ierr = PetscArrayzero(tmpValues,newNumIndices*numIndices);CHKERRQ(ierr);
5820     /* multiply constraints on the right */
5821     if (numFields) {
5822       for (f = 0; f < numFields; f++) {
5823         PetscInt oldOff = offsets[f];
5824 
5825         for (p = 0; p < numPoints; p++) {
5826           PetscInt cStart = newPointOffsets[f][p];
5827           PetscInt b      = points[2 * p];
5828           PetscInt c, r, k;
5829           PetscInt dof;
5830 
5831           ierr = PetscSectionGetFieldDof(section,b,f,&dof);CHKERRQ(ierr);
5832           if (!dof) {
5833             continue;
5834           }
5835           if (pointMatOffsets[f][p] < pointMatOffsets[f][p + 1]) {
5836             PetscInt nCols         = newPointOffsets[f][p+1]-cStart;
5837             const PetscScalar *mat = pointMat[f] + pointMatOffsets[f][p];
5838 
5839             for (r = 0; r < numIndices; r++) {
5840               for (c = 0; c < nCols; c++) {
5841                 for (k = 0; k < dof; k++) {
5842                   tmpValues[r * newNumIndices + cStart + c] += values[r * numIndices + oldOff + k] * mat[k * nCols + c];
5843                 }
5844               }
5845             }
5846           }
5847           else {
5848             /* copy this column as is */
5849             for (r = 0; r < numIndices; r++) {
5850               for (c = 0; c < dof; c++) {
5851                 tmpValues[r * newNumIndices + cStart + c] = values[r * numIndices + oldOff + c];
5852               }
5853             }
5854           }
5855           oldOff += dof;
5856         }
5857       }
5858     }
5859     else {
5860       PetscInt oldOff = 0;
5861       for (p = 0; p < numPoints; p++) {
5862         PetscInt cStart = newPointOffsets[0][p];
5863         PetscInt b      = points[2 * p];
5864         PetscInt c, r, k;
5865         PetscInt dof;
5866 
5867         ierr = PetscSectionGetDof(section,b,&dof);CHKERRQ(ierr);
5868         if (!dof) {
5869           continue;
5870         }
5871         if (pointMatOffsets[0][p] < pointMatOffsets[0][p + 1]) {
5872           PetscInt nCols         = newPointOffsets[0][p+1]-cStart;
5873           const PetscScalar *mat = pointMat[0] + pointMatOffsets[0][p];
5874 
5875           for (r = 0; r < numIndices; r++) {
5876             for (c = 0; c < nCols; c++) {
5877               for (k = 0; k < dof; k++) {
5878                 tmpValues[r * newNumIndices + cStart + c] += mat[k * nCols + c] * values[r * numIndices + oldOff + k];
5879               }
5880             }
5881           }
5882         }
5883         else {
5884           /* copy this column as is */
5885           for (r = 0; r < numIndices; r++) {
5886             for (c = 0; c < dof; c++) {
5887               tmpValues[r * newNumIndices + cStart + c] = values[r * numIndices + oldOff + c];
5888             }
5889           }
5890         }
5891         oldOff += dof;
5892       }
5893     }
5894 
5895     if (multiplyLeft) {
5896       ierr = DMGetWorkArray(dm,newNumIndices*newNumIndices,MPIU_SCALAR,&newValues);CHKERRQ(ierr);
5897       ierr = PetscArrayzero(newValues,newNumIndices*newNumIndices);CHKERRQ(ierr);
5898       /* multiply constraints transpose on the left */
5899       if (numFields) {
5900         for (f = 0; f < numFields; f++) {
5901           PetscInt oldOff = offsets[f];
5902 
5903           for (p = 0; p < numPoints; p++) {
5904             PetscInt rStart = newPointOffsets[f][p];
5905             PetscInt b      = points[2 * p];
5906             PetscInt c, r, k;
5907             PetscInt dof;
5908 
5909             ierr = PetscSectionGetFieldDof(section,b,f,&dof);CHKERRQ(ierr);
5910             if (pointMatOffsets[f][p] < pointMatOffsets[f][p + 1]) {
5911               PetscInt nRows                        = newPointOffsets[f][p+1]-rStart;
5912               const PetscScalar *PETSC_RESTRICT mat = pointMat[f] + pointMatOffsets[f][p];
5913 
5914               for (r = 0; r < nRows; r++) {
5915                 for (c = 0; c < newNumIndices; c++) {
5916                   for (k = 0; k < dof; k++) {
5917                     newValues[(rStart + r) * newNumIndices + c] += mat[k * nRows + r] * tmpValues[(oldOff + k) * newNumIndices + c];
5918                   }
5919                 }
5920               }
5921             }
5922             else {
5923               /* copy this row as is */
5924               for (r = 0; r < dof; r++) {
5925                 for (c = 0; c < newNumIndices; c++) {
5926                   newValues[(rStart + r) * newNumIndices + c] = tmpValues[(oldOff + r) * newNumIndices + c];
5927                 }
5928               }
5929             }
5930             oldOff += dof;
5931           }
5932         }
5933       }
5934       else {
5935         PetscInt oldOff = 0;
5936 
5937         for (p = 0; p < numPoints; p++) {
5938           PetscInt rStart = newPointOffsets[0][p];
5939           PetscInt b      = points[2 * p];
5940           PetscInt c, r, k;
5941           PetscInt dof;
5942 
5943           ierr = PetscSectionGetDof(section,b,&dof);CHKERRQ(ierr);
5944           if (pointMatOffsets[0][p] < pointMatOffsets[0][p + 1]) {
5945             PetscInt nRows                        = newPointOffsets[0][p+1]-rStart;
5946             const PetscScalar *PETSC_RESTRICT mat = pointMat[0] + pointMatOffsets[0][p];
5947 
5948             for (r = 0; r < nRows; r++) {
5949               for (c = 0; c < newNumIndices; c++) {
5950                 for (k = 0; k < dof; k++) {
5951                   newValues[(rStart + r) * newNumIndices + c] += mat[k * nRows + r] * tmpValues[(oldOff + k) * newNumIndices + c];
5952                 }
5953               }
5954             }
5955           }
5956           else {
5957             /* copy this row as is */
5958             for (r = 0; r < dof; r++) {
5959               for (c = 0; c < newNumIndices; c++) {
5960                 newValues[(rStart + r) * newNumIndices + c] = tmpValues[(oldOff + r) * newNumIndices + c];
5961               }
5962             }
5963           }
5964           oldOff += dof;
5965         }
5966       }
5967 
5968       ierr = DMRestoreWorkArray(dm,newNumIndices*numIndices,MPIU_SCALAR,&tmpValues);CHKERRQ(ierr);
5969     }
5970     else {
5971       newValues = tmpValues;
5972     }
5973   }
5974 
5975   /* clean up */
5976   ierr = DMRestoreWorkArray(dm,maxDof,MPIU_INT,&indices);CHKERRQ(ierr);
5977   ierr = DMRestoreWorkArray(dm,maxAnchor*maxDof,MPIU_INT,&newIndices);CHKERRQ(ierr);
5978 
5979   if (numFields) {
5980     for (f = 0; f < numFields; f++) {
5981       ierr = DMRestoreWorkArray(dm,pointMatOffsets[f][numPoints],MPIU_SCALAR,&pointMat[f]);CHKERRQ(ierr);
5982       ierr = DMRestoreWorkArray(dm,numPoints+1,MPIU_INT,&pointMatOffsets[f]);CHKERRQ(ierr);
5983       ierr = DMRestoreWorkArray(dm,numPoints+1,MPIU_INT,&newPointOffsets[f]);CHKERRQ(ierr);
5984     }
5985   }
5986   else {
5987     ierr = DMRestoreWorkArray(dm,pointMatOffsets[0][numPoints],MPIU_SCALAR,&pointMat[0]);CHKERRQ(ierr);
5988     ierr = DMRestoreWorkArray(dm,numPoints+1,MPIU_INT,&pointMatOffsets[0]);CHKERRQ(ierr);
5989     ierr = DMRestoreWorkArray(dm,numPoints+1,MPIU_INT,&newPointOffsets[0]);CHKERRQ(ierr);
5990   }
5991   ierr = ISRestoreIndices(aIS,&anchors);CHKERRQ(ierr);
5992 
5993   /* output */
5994   if (outPoints) {
5995     *outPoints = newPoints;
5996   }
5997   else {
5998     ierr = DMRestoreWorkArray(dm,2*newNumPoints,MPIU_INT,&newPoints);CHKERRQ(ierr);
5999   }
6000   if (outValues) {
6001     *outValues = newValues;
6002   }
6003   for (f = 0; f <= numFields; f++) {
6004     offsets[f] = newOffsets[f];
6005   }
6006   PetscFunctionReturn(0);
6007 }
6008 
6009 /*@C
6010   DMPlexGetClosureIndices - Get the global indices for all local points in the closure of the given point
6011 
6012   Not collective
6013 
6014   Input Parameters:
6015 + dm - The DM
6016 . section - The section describing the local layout
6017 . globalSection - The section describing the parallel layout
6018 - point - The mesh point
6019 
6020   Output parameters:
6021 + numIndices - The number of indices
6022 . indices - The indices
6023 - outOffsets - Field offset if not NULL
6024 
6025   Note: Must call DMPlexRestoreClosureIndices() to free allocated memory
6026 
6027   Level: advanced
6028 
6029 .seealso DMPlexRestoreClosureIndices(), DMPlexVecGetClosure(), DMPlexMatSetClosure()
6030 @*/
6031 PetscErrorCode DMPlexGetClosureIndices(DM dm, PetscSection section, PetscSection globalSection, PetscInt point, PetscInt *numIndices, PetscInt **indices, PetscInt *outOffsets)
6032 {
6033   PetscSection    clSection;
6034   IS              clPoints;
6035   const PetscInt *clp, *clperm;
6036   const PetscInt  **perms[32] = {NULL};
6037   PetscInt       *points = NULL, *pointsNew;
6038   PetscInt        numPoints, numPointsNew;
6039   PetscInt        offsets[32];
6040   PetscInt        Nf, Nind, NindNew, off, globalOff, f, p;
6041   PetscErrorCode  ierr;
6042 
6043   PetscFunctionBegin;
6044   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6045   PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2);
6046   PetscValidHeaderSpecific(globalSection, PETSC_SECTION_CLASSID, 3);
6047   if (numIndices) PetscValidPointer(numIndices, 4);
6048   PetscValidPointer(indices, 5);
6049   ierr = PetscSectionGetNumFields(section, &Nf);CHKERRQ(ierr);
6050   if (Nf > 31) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", Nf);
6051   ierr = PetscArrayzero(offsets, 32);CHKERRQ(ierr);
6052   /* Get points in closure */
6053   ierr = DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);CHKERRQ(ierr);
6054   ierr = PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject) dm, NULL, &clperm);CHKERRQ(ierr);
6055   /* Get number of indices and indices per field */
6056   for (p = 0, Nind = 0; p < numPoints*2; p += 2) {
6057     PetscInt dof, fdof;
6058 
6059     ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
6060     for (f = 0; f < Nf; ++f) {
6061       ierr = PetscSectionGetFieldDof(section, points[p], f, &fdof);CHKERRQ(ierr);
6062       offsets[f+1] += fdof;
6063     }
6064     Nind += dof;
6065   }
6066   for (f = 1; f < Nf; ++f) offsets[f+1] += offsets[f];
6067   if (Nf && offsets[Nf] != Nind) SETERRQ2(PetscObjectComm((PetscObject) dm), PETSC_ERR_PLIB, "Invalid size for closure %D should be %D", offsets[Nf], Nind);
6068   if (!Nf) offsets[1] = Nind;
6069   /* Get dual space symmetries */
6070   for (f = 0; f < PetscMax(1,Nf); f++) {
6071     if (Nf) {ierr = PetscSectionGetFieldPointSyms(section,f,numPoints,points,&perms[f],NULL);CHKERRQ(ierr);}
6072     else    {ierr = PetscSectionGetPointSyms(section,numPoints,points,&perms[f],NULL);CHKERRQ(ierr);}
6073   }
6074   /* Correct for hanging node constraints */
6075   {
6076     ierr = DMPlexAnchorsModifyMat(dm, section, numPoints, Nind, points, perms, NULL, &numPointsNew, &NindNew, &pointsNew, NULL, offsets, PETSC_TRUE);CHKERRQ(ierr);
6077     if (numPointsNew) {
6078       for (f = 0; f < PetscMax(1,Nf); f++) {
6079         if (Nf) {ierr = PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms[f],NULL);CHKERRQ(ierr);}
6080         else    {ierr = PetscSectionRestorePointSyms(section,numPoints,points,&perms[f],NULL);CHKERRQ(ierr);}
6081       }
6082       for (f = 0; f < PetscMax(1,Nf); f++) {
6083         if (Nf) {ierr = PetscSectionGetFieldPointSyms(section,f,numPointsNew,pointsNew,&perms[f],NULL);CHKERRQ(ierr);}
6084         else    {ierr = PetscSectionGetPointSyms(section,numPointsNew,pointsNew,&perms[f],NULL);CHKERRQ(ierr);}
6085       }
6086       ierr = DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);CHKERRQ(ierr);
6087       numPoints = numPointsNew;
6088       Nind      = NindNew;
6089       points    = pointsNew;
6090     }
6091   }
6092   /* Calculate indices */
6093   ierr = DMGetWorkArray(dm, Nind, MPIU_INT, indices);CHKERRQ(ierr);
6094   if (Nf) {
6095     if (outOffsets) {
6096       PetscInt f;
6097 
6098       for (f = 0; f <= Nf; f++) {
6099         outOffsets[f] = offsets[f];
6100       }
6101     }
6102     for (p = 0; p < numPoints; p++) {
6103       ierr = PetscSectionGetOffset(globalSection, points[2*p], &globalOff);CHKERRQ(ierr);
6104       ierr = DMPlexGetIndicesPointFields_Internal(section, points[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, offsets, PETSC_FALSE, perms, p, clperm, *indices);CHKERRQ(ierr);
6105     }
6106   } else {
6107     for (p = 0, off = 0; p < numPoints; p++) {
6108       const PetscInt *perm = perms[0] ? perms[0][p] : NULL;
6109 
6110       ierr = PetscSectionGetOffset(globalSection, points[2*p], &globalOff);CHKERRQ(ierr);
6111       ierr = DMPlexGetIndicesPoint_Internal(section, points[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, clperm, *indices);CHKERRQ(ierr);
6112     }
6113   }
6114   /* Cleanup points */
6115   for (f = 0; f < PetscMax(1,Nf); f++) {
6116     if (Nf) {ierr = PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms[f],NULL);CHKERRQ(ierr);}
6117     else    {ierr = PetscSectionRestorePointSyms(section,numPoints,points,&perms[f],NULL);CHKERRQ(ierr);}
6118   }
6119   if (numPointsNew) {
6120     ierr = DMRestoreWorkArray(dm, 2*numPointsNew, MPIU_INT, &pointsNew);CHKERRQ(ierr);
6121   } else {
6122     ierr = DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);CHKERRQ(ierr);
6123   }
6124   if (numIndices) *numIndices = Nind;
6125   PetscFunctionReturn(0);
6126 }
6127 
6128 /*@C
6129   DMPlexRestoreClosureIndices - Restore the indices in a vector v for all points in the closure of the given point
6130 
6131   Not collective
6132 
6133   Input Parameters:
6134 + dm - The DM
6135 . section - The section describing the layout in v, or NULL to use the default section
6136 . globalSection - The section describing the parallel layout in v, or NULL to use the default section
6137 . point - The mesh point
6138 . numIndices - The number of indices
6139 . indices - The indices
6140 - outOffsets - Field offset if not NULL
6141 
6142   Level: advanced
6143 
6144 .seealso DMPlexGetClosureIndices(), DMPlexVecGetClosure(), DMPlexMatSetClosure()
6145 @*/
6146 PetscErrorCode DMPlexRestoreClosureIndices(DM dm, PetscSection section, PetscSection globalSection, PetscInt point, PetscInt *numIndices, PetscInt **indices,PetscInt *outOffsets)
6147 {
6148   PetscErrorCode ierr;
6149 
6150   PetscFunctionBegin;
6151   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6152   PetscValidPointer(indices, 5);
6153   ierr = DMRestoreWorkArray(dm, 0, MPIU_INT, indices);CHKERRQ(ierr);
6154   PetscFunctionReturn(0);
6155 }
6156 
6157 /*@C
6158   DMPlexMatSetClosure - Set an array of the values on the closure of 'point'
6159 
6160   Not collective
6161 
6162   Input Parameters:
6163 + dm - The DM
6164 . section - The section describing the layout in v, or NULL to use the default section
6165 . globalSection - The section describing the layout in v, or NULL to use the default global section
6166 . A - The matrix
6167 . point - The point in the DM
6168 . values - The array of values
6169 - mode - The insert mode, where INSERT_ALL_VALUES and ADD_ALL_VALUES also overwrite boundary conditions
6170 
6171   Fortran Notes:
6172   This routine is only available in Fortran 90, and you must include petsc.h90 in your code.
6173 
6174   Level: intermediate
6175 
6176 .seealso DMPlexVecGetClosure(), DMPlexVecSetClosure()
6177 @*/
6178 PetscErrorCode DMPlexMatSetClosure(DM dm, PetscSection section, PetscSection globalSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode)
6179 {
6180   DM_Plex            *mesh   = (DM_Plex*) dm->data;
6181   PetscSection        clSection;
6182   IS                  clPoints;
6183   PetscInt           *points = NULL, *newPoints;
6184   const PetscInt     *clp, *clperm;
6185   PetscInt           *indices;
6186   PetscInt            offsets[32];
6187   const PetscInt    **perms[32] = {NULL};
6188   const PetscScalar **flips[32] = {NULL};
6189   PetscInt            numFields, numPoints, newNumPoints, numIndices, newNumIndices, dof, off, globalOff, p, f;
6190   PetscScalar        *valCopy = NULL;
6191   PetscScalar        *newValues;
6192   PetscErrorCode      ierr;
6193 
6194   PetscFunctionBegin;
6195   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6196   if (!section) {ierr = DMGetLocalSection(dm, &section);CHKERRQ(ierr);}
6197   PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2);
6198   if (!globalSection) {ierr = DMGetGlobalSection(dm, &globalSection);CHKERRQ(ierr);}
6199   PetscValidHeaderSpecific(globalSection, PETSC_SECTION_CLASSID, 3);
6200   PetscValidHeaderSpecific(A, MAT_CLASSID, 4);
6201   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
6202   if (numFields > 31) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
6203   ierr = PetscArrayzero(offsets, 32);CHKERRQ(ierr);
6204   ierr = PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject) dm, NULL, &clperm);CHKERRQ(ierr);
6205   ierr = DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);CHKERRQ(ierr);
6206   for (p = 0, numIndices = 0; p < numPoints*2; p += 2) {
6207     PetscInt fdof;
6208 
6209     ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
6210     for (f = 0; f < numFields; ++f) {
6211       ierr          = PetscSectionGetFieldDof(section, points[p], f, &fdof);CHKERRQ(ierr);
6212       offsets[f+1] += fdof;
6213     }
6214     numIndices += dof;
6215   }
6216   for (f = 1; f < numFields; ++f) offsets[f+1] += offsets[f];
6217 
6218   if (numFields && offsets[numFields] != numIndices) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid size for closure %D should be %D", offsets[numFields], numIndices);
6219   /* Get symmetries */
6220   for (f = 0; f < PetscMax(1,numFields); f++) {
6221     if (numFields) {ierr = PetscSectionGetFieldPointSyms(section,f,numPoints,points,&perms[f],&flips[f]);CHKERRQ(ierr);}
6222     else           {ierr = PetscSectionGetPointSyms(section,numPoints,points,&perms[f],&flips[f]);CHKERRQ(ierr);}
6223     if (values && flips[f]) { /* may need to apply sign changes to the element matrix */
6224       PetscInt foffset = offsets[f];
6225 
6226       for (p = 0; p < numPoints; p++) {
6227         PetscInt point          = points[2*p], fdof;
6228         const PetscScalar *flip = flips[f] ? flips[f][p] : NULL;
6229 
6230         if (!numFields) {
6231           ierr = PetscSectionGetDof(section,point,&fdof);CHKERRQ(ierr);
6232         } else {
6233           ierr = PetscSectionGetFieldDof(section,point,f,&fdof);CHKERRQ(ierr);
6234         }
6235         if (flip) {
6236           PetscInt i, j, k;
6237 
6238           if (!valCopy) {
6239             ierr = DMGetWorkArray(dm,numIndices*numIndices,MPIU_SCALAR,&valCopy);CHKERRQ(ierr);
6240             for (j = 0; j < numIndices * numIndices; j++) valCopy[j] = values[j];
6241             values = valCopy;
6242           }
6243           for (i = 0; i < fdof; i++) {
6244             PetscScalar fval = flip[i];
6245 
6246             for (k = 0; k < numIndices; k++) {
6247               valCopy[numIndices * (foffset + i) + k] *= fval;
6248               valCopy[numIndices * k + (foffset + i)] *= fval;
6249             }
6250           }
6251         }
6252         foffset += fdof;
6253       }
6254     }
6255   }
6256   ierr = DMPlexAnchorsModifyMat(dm,section,numPoints,numIndices,points,perms,values,&newNumPoints,&newNumIndices,&newPoints,&newValues,offsets,PETSC_TRUE);CHKERRQ(ierr);
6257   if (newNumPoints) {
6258     if (valCopy) {
6259       ierr = DMRestoreWorkArray(dm,numIndices*numIndices,MPIU_SCALAR,&valCopy);CHKERRQ(ierr);
6260     }
6261     for (f = 0; f < PetscMax(1,numFields); f++) {
6262       if (numFields) {ierr = PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms[f],&flips[f]);CHKERRQ(ierr);}
6263       else           {ierr = PetscSectionRestorePointSyms(section,numPoints,points,&perms[f],&flips[f]);CHKERRQ(ierr);}
6264     }
6265     for (f = 0; f < PetscMax(1,numFields); f++) {
6266       if (numFields) {ierr = PetscSectionGetFieldPointSyms(section,f,newNumPoints,newPoints,&perms[f],&flips[f]);CHKERRQ(ierr);}
6267       else           {ierr = PetscSectionGetPointSyms(section,newNumPoints,newPoints,&perms[f],&flips[f]);CHKERRQ(ierr);}
6268     }
6269     ierr = DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);CHKERRQ(ierr);
6270     numPoints  = newNumPoints;
6271     numIndices = newNumIndices;
6272     points     = newPoints;
6273     values     = newValues;
6274   }
6275   ierr = DMGetWorkArray(dm, numIndices, MPIU_INT, &indices);CHKERRQ(ierr);
6276   if (numFields) {
6277     PetscBool useFieldOffsets;
6278 
6279     ierr = PetscSectionGetUseFieldOffsets(globalSection, &useFieldOffsets);CHKERRQ(ierr);
6280     if (useFieldOffsets) {
6281       for (p = 0; p < numPoints; p++) {
6282         DMPlexGetIndicesPointFieldsSplit_Internal(section, globalSection, points[2*p], offsets, PETSC_FALSE, perms, p, clperm, indices);
6283       }
6284     } else {
6285       for (p = 0; p < numPoints; p++) {
6286         ierr = PetscSectionGetOffset(globalSection, points[2*p], &globalOff);CHKERRQ(ierr);
6287         DMPlexGetIndicesPointFields_Internal(section, points[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, offsets, PETSC_FALSE, perms, p, clperm, indices);
6288       }
6289     }
6290   } else {
6291     for (p = 0, off = 0; p < numPoints; p++) {
6292       const PetscInt *perm = perms[0] ? perms[0][p] : NULL;
6293       ierr = PetscSectionGetOffset(globalSection, points[2*p], &globalOff);CHKERRQ(ierr);
6294       DMPlexGetIndicesPoint_Internal(section, points[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, clperm, indices);
6295     }
6296   }
6297   if (mesh->printSetValues) {ierr = DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndices, indices, 0, NULL, values);CHKERRQ(ierr);}
6298   ierr = MatSetValues(A, numIndices, indices, numIndices, indices, values, mode);
6299   if (mesh->printFEM > 1) {
6300     PetscInt i;
6301     ierr = PetscPrintf(PETSC_COMM_SELF, "  Indices:");CHKERRQ(ierr);
6302     for (i = 0; i < numIndices; ++i) {ierr = PetscPrintf(PETSC_COMM_SELF, " %D", indices[i]);CHKERRQ(ierr);}
6303     ierr = PetscPrintf(PETSC_COMM_SELF, "\n");CHKERRQ(ierr);
6304   }
6305   if (ierr) {
6306     PetscMPIInt    rank;
6307     PetscErrorCode ierr2;
6308 
6309     ierr2 = MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank);CHKERRQ(ierr2);
6310     ierr2 = (*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank);CHKERRQ(ierr2);
6311     ierr2 = DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndices, indices, 0, NULL, values);CHKERRQ(ierr2);
6312     ierr2 = DMRestoreWorkArray(dm, numIndices, MPIU_INT, &indices);CHKERRQ(ierr2);
6313     CHKERRQ(ierr);
6314   }
6315   for (f = 0; f < PetscMax(1,numFields); f++) {
6316     if (numFields) {ierr = PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms[f],&flips[f]);CHKERRQ(ierr);}
6317     else           {ierr = PetscSectionRestorePointSyms(section,numPoints,points,&perms[f],&flips[f]);CHKERRQ(ierr);}
6318   }
6319   if (newNumPoints) {
6320     ierr = DMRestoreWorkArray(dm,newNumIndices*newNumIndices,MPIU_SCALAR,&newValues);CHKERRQ(ierr);
6321     ierr = DMRestoreWorkArray(dm,2*newNumPoints,MPIU_INT,&newPoints);CHKERRQ(ierr);
6322   }
6323   else {
6324     if (valCopy) {
6325       ierr = DMRestoreWorkArray(dm,numIndices*numIndices,MPIU_SCALAR,&valCopy);CHKERRQ(ierr);
6326     }
6327     ierr = DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);CHKERRQ(ierr);
6328   }
6329   ierr = DMRestoreWorkArray(dm, numIndices, MPIU_INT, &indices);CHKERRQ(ierr);
6330   PetscFunctionReturn(0);
6331 }
6332 
6333 PetscErrorCode DMPlexMatSetClosureRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode)
6334 {
6335   DM_Plex        *mesh   = (DM_Plex*) dmf->data;
6336   PetscInt       *fpoints = NULL, *ftotpoints = NULL;
6337   PetscInt       *cpoints = NULL;
6338   PetscInt       *findices, *cindices;
6339   const PetscInt *fclperm = NULL, *cclperm = NULL; /* Closure permutations cannot work here */
6340   PetscInt        foffsets[32], coffsets[32];
6341   CellRefiner     cellRefiner;
6342   PetscInt        numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f;
6343   PetscErrorCode  ierr;
6344 
6345   PetscFunctionBegin;
6346   PetscValidHeaderSpecific(dmf, DM_CLASSID, 1);
6347   PetscValidHeaderSpecific(dmc, DM_CLASSID, 4);
6348   if (!fsection) {ierr = DMGetLocalSection(dmf, &fsection);CHKERRQ(ierr);}
6349   PetscValidHeaderSpecific(fsection, PETSC_SECTION_CLASSID, 2);
6350   if (!csection) {ierr = DMGetLocalSection(dmc, &csection);CHKERRQ(ierr);}
6351   PetscValidHeaderSpecific(csection, PETSC_SECTION_CLASSID, 5);
6352   if (!globalFSection) {ierr = DMGetGlobalSection(dmf, &globalFSection);CHKERRQ(ierr);}
6353   PetscValidHeaderSpecific(globalFSection, PETSC_SECTION_CLASSID, 3);
6354   if (!globalCSection) {ierr = DMGetGlobalSection(dmc, &globalCSection);CHKERRQ(ierr);}
6355   PetscValidHeaderSpecific(globalCSection, PETSC_SECTION_CLASSID, 6);
6356   PetscValidHeaderSpecific(A, MAT_CLASSID, 7);
6357   ierr = PetscSectionGetNumFields(fsection, &numFields);CHKERRQ(ierr);
6358   if (numFields > 31) SETERRQ1(PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
6359   ierr = PetscArrayzero(foffsets, 32);CHKERRQ(ierr);
6360   ierr = PetscArrayzero(coffsets, 32);CHKERRQ(ierr);
6361   /* Column indices */
6362   ierr = DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints);CHKERRQ(ierr);
6363   maxFPoints = numCPoints;
6364   /* Compress out points not in the section */
6365   /*   TODO: Squeeze out points with 0 dof as well */
6366   ierr = PetscSectionGetChart(csection, &pStart, &pEnd);CHKERRQ(ierr);
6367   for (p = 0, q = 0; p < numCPoints*2; p += 2) {
6368     if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) {
6369       cpoints[q*2]   = cpoints[p];
6370       cpoints[q*2+1] = cpoints[p+1];
6371       ++q;
6372     }
6373   }
6374   numCPoints = q;
6375   for (p = 0, numCIndices = 0; p < numCPoints*2; p += 2) {
6376     PetscInt fdof;
6377 
6378     ierr = PetscSectionGetDof(csection, cpoints[p], &dof);CHKERRQ(ierr);
6379     if (!dof) continue;
6380     for (f = 0; f < numFields; ++f) {
6381       ierr           = PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof);CHKERRQ(ierr);
6382       coffsets[f+1] += fdof;
6383     }
6384     numCIndices += dof;
6385   }
6386   for (f = 1; f < numFields; ++f) coffsets[f+1] += coffsets[f];
6387   /* Row indices */
6388   ierr = DMPlexGetCellRefiner_Internal(dmc, &cellRefiner);CHKERRQ(ierr);
6389   ierr = CellRefinerGetAffineTransforms_Internal(cellRefiner, &numSubcells, NULL, NULL, NULL);CHKERRQ(ierr);
6390   ierr = DMGetWorkArray(dmf, maxFPoints*2*numSubcells, MPIU_INT, &ftotpoints);CHKERRQ(ierr);
6391   for (r = 0, q = 0; r < numSubcells; ++r) {
6392     /* TODO Map from coarse to fine cells */
6393     ierr = DMPlexGetTransitiveClosure(dmf, point*numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints);CHKERRQ(ierr);
6394     /* Compress out points not in the section */
6395     ierr = PetscSectionGetChart(fsection, &pStart, &pEnd);CHKERRQ(ierr);
6396     for (p = 0; p < numFPoints*2; p += 2) {
6397       if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) {
6398         ierr = PetscSectionGetDof(fsection, fpoints[p], &dof);CHKERRQ(ierr);
6399         if (!dof) continue;
6400         for (s = 0; s < q; ++s) if (fpoints[p] == ftotpoints[s*2]) break;
6401         if (s < q) continue;
6402         ftotpoints[q*2]   = fpoints[p];
6403         ftotpoints[q*2+1] = fpoints[p+1];
6404         ++q;
6405       }
6406     }
6407     ierr = DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints);CHKERRQ(ierr);
6408   }
6409   numFPoints = q;
6410   for (p = 0, numFIndices = 0; p < numFPoints*2; p += 2) {
6411     PetscInt fdof;
6412 
6413     ierr = PetscSectionGetDof(fsection, ftotpoints[p], &dof);CHKERRQ(ierr);
6414     if (!dof) continue;
6415     for (f = 0; f < numFields; ++f) {
6416       ierr           = PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof);CHKERRQ(ierr);
6417       foffsets[f+1] += fdof;
6418     }
6419     numFIndices += dof;
6420   }
6421   for (f = 1; f < numFields; ++f) foffsets[f+1] += foffsets[f];
6422 
6423   if (numFields && foffsets[numFields] != numFIndices) SETERRQ2(PetscObjectComm((PetscObject)dmf), PETSC_ERR_PLIB, "Invalid size for closure %D should be %D", foffsets[numFields], numFIndices);
6424   if (numFields && coffsets[numFields] != numCIndices) SETERRQ2(PetscObjectComm((PetscObject)dmc), PETSC_ERR_PLIB, "Invalid size for closure %D should be %D", coffsets[numFields], numCIndices);
6425   ierr = DMGetWorkArray(dmf, numFIndices, MPIU_INT, &findices);CHKERRQ(ierr);
6426   ierr = DMGetWorkArray(dmc, numCIndices, MPIU_INT, &cindices);CHKERRQ(ierr);
6427   if (numFields) {
6428     const PetscInt **permsF[32] = {NULL};
6429     const PetscInt **permsC[32] = {NULL};
6430 
6431     for (f = 0; f < numFields; f++) {
6432       ierr = PetscSectionGetFieldPointSyms(fsection,f,numFPoints,ftotpoints,&permsF[f],NULL);CHKERRQ(ierr);
6433       ierr = PetscSectionGetFieldPointSyms(csection,f,numCPoints,cpoints,&permsC[f],NULL);CHKERRQ(ierr);
6434     }
6435     for (p = 0; p < numFPoints; p++) {
6436       ierr = PetscSectionGetOffset(globalFSection, ftotpoints[2*p], &globalOff);CHKERRQ(ierr);
6437       ierr = DMPlexGetIndicesPointFields_Internal(fsection, ftotpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, foffsets, PETSC_FALSE, permsF, p, fclperm, findices);CHKERRQ(ierr);
6438     }
6439     for (p = 0; p < numCPoints; p++) {
6440       ierr = PetscSectionGetOffset(globalCSection, cpoints[2*p], &globalOff);CHKERRQ(ierr);
6441       ierr = DMPlexGetIndicesPointFields_Internal(csection, cpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cclperm, cindices);CHKERRQ(ierr);
6442     }
6443     for (f = 0; f < numFields; f++) {
6444       ierr = PetscSectionRestoreFieldPointSyms(fsection,f,numFPoints,ftotpoints,&permsF[f],NULL);CHKERRQ(ierr);
6445       ierr = PetscSectionRestoreFieldPointSyms(csection,f,numCPoints,cpoints,&permsC[f],NULL);CHKERRQ(ierr);
6446     }
6447   } else {
6448     const PetscInt **permsF = NULL;
6449     const PetscInt **permsC = NULL;
6450 
6451     ierr = PetscSectionGetPointSyms(fsection,numFPoints,ftotpoints,&permsF,NULL);CHKERRQ(ierr);
6452     ierr = PetscSectionGetPointSyms(csection,numCPoints,cpoints,&permsC,NULL);CHKERRQ(ierr);
6453     for (p = 0, off = 0; p < numFPoints; p++) {
6454       const PetscInt *perm = permsF ? permsF[p] : NULL;
6455 
6456       ierr = PetscSectionGetOffset(globalFSection, ftotpoints[2*p], &globalOff);CHKERRQ(ierr);
6457       ierr = DMPlexGetIndicesPoint_Internal(fsection, ftotpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, fclperm, findices);CHKERRQ(ierr);
6458     }
6459     for (p = 0, off = 0; p < numCPoints; p++) {
6460       const PetscInt *perm = permsC ? permsC[p] : NULL;
6461 
6462       ierr = PetscSectionGetOffset(globalCSection, cpoints[2*p], &globalOff);CHKERRQ(ierr);
6463       ierr = DMPlexGetIndicesPoint_Internal(csection, cpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, cclperm, cindices);CHKERRQ(ierr);
6464     }
6465     ierr = PetscSectionRestorePointSyms(fsection,numFPoints,ftotpoints,&permsF,NULL);CHKERRQ(ierr);
6466     ierr = PetscSectionRestorePointSyms(csection,numCPoints,cpoints,&permsC,NULL);CHKERRQ(ierr);
6467   }
6468   if (mesh->printSetValues) {ierr = DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numFIndices, findices, numCIndices, cindices, values);CHKERRQ(ierr);}
6469   /* TODO: flips */
6470   ierr = MatSetValues(A, numFIndices, findices, numCIndices, cindices, values, mode);
6471   if (ierr) {
6472     PetscMPIInt    rank;
6473     PetscErrorCode ierr2;
6474 
6475     ierr2 = MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank);CHKERRQ(ierr2);
6476     ierr2 = (*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank);CHKERRQ(ierr2);
6477     ierr2 = DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numFIndices, findices, numCIndices, cindices, values);CHKERRQ(ierr2);
6478     ierr2 = DMRestoreWorkArray(dmf, numFIndices, MPIU_INT, &findices);CHKERRQ(ierr2);
6479     ierr2 = DMRestoreWorkArray(dmc, numCIndices, MPIU_INT, &cindices);CHKERRQ(ierr2);
6480     CHKERRQ(ierr);
6481   }
6482   ierr = DMRestoreWorkArray(dmf, numCPoints*2*4, MPIU_INT, &ftotpoints);CHKERRQ(ierr);
6483   ierr = DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints);CHKERRQ(ierr);
6484   ierr = DMRestoreWorkArray(dmf, numFIndices, MPIU_INT, &findices);CHKERRQ(ierr);
6485   ierr = DMRestoreWorkArray(dmc, numCIndices, MPIU_INT, &cindices);CHKERRQ(ierr);
6486   PetscFunctionReturn(0);
6487 }
6488 
6489 PetscErrorCode DMPlexMatGetClosureIndicesRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, PetscInt point, PetscInt cindices[], PetscInt findices[])
6490 {
6491   PetscInt      *fpoints = NULL, *ftotpoints = NULL;
6492   PetscInt      *cpoints = NULL;
6493   PetscInt       foffsets[32], coffsets[32];
6494   const PetscInt *fclperm = NULL, *cclperm = NULL; /* Closure permutations cannot work here */
6495   CellRefiner    cellRefiner;
6496   PetscInt       numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f;
6497   PetscErrorCode ierr;
6498 
6499   PetscFunctionBegin;
6500   PetscValidHeaderSpecific(dmf, DM_CLASSID, 1);
6501   PetscValidHeaderSpecific(dmc, DM_CLASSID, 4);
6502   if (!fsection) {ierr = DMGetLocalSection(dmf, &fsection);CHKERRQ(ierr);}
6503   PetscValidHeaderSpecific(fsection, PETSC_SECTION_CLASSID, 2);
6504   if (!csection) {ierr = DMGetLocalSection(dmc, &csection);CHKERRQ(ierr);}
6505   PetscValidHeaderSpecific(csection, PETSC_SECTION_CLASSID, 5);
6506   if (!globalFSection) {ierr = DMGetGlobalSection(dmf, &globalFSection);CHKERRQ(ierr);}
6507   PetscValidHeaderSpecific(globalFSection, PETSC_SECTION_CLASSID, 3);
6508   if (!globalCSection) {ierr = DMGetGlobalSection(dmc, &globalCSection);CHKERRQ(ierr);}
6509   PetscValidHeaderSpecific(globalCSection, PETSC_SECTION_CLASSID, 6);
6510   ierr = PetscSectionGetNumFields(fsection, &numFields);CHKERRQ(ierr);
6511   if (numFields > 31) SETERRQ1(PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
6512   ierr = PetscArrayzero(foffsets, 32);CHKERRQ(ierr);
6513   ierr = PetscArrayzero(coffsets, 32);CHKERRQ(ierr);
6514   /* Column indices */
6515   ierr = DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints);CHKERRQ(ierr);
6516   maxFPoints = numCPoints;
6517   /* Compress out points not in the section */
6518   /*   TODO: Squeeze out points with 0 dof as well */
6519   ierr = PetscSectionGetChart(csection, &pStart, &pEnd);CHKERRQ(ierr);
6520   for (p = 0, q = 0; p < numCPoints*2; p += 2) {
6521     if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) {
6522       cpoints[q*2]   = cpoints[p];
6523       cpoints[q*2+1] = cpoints[p+1];
6524       ++q;
6525     }
6526   }
6527   numCPoints = q;
6528   for (p = 0, numCIndices = 0; p < numCPoints*2; p += 2) {
6529     PetscInt fdof;
6530 
6531     ierr = PetscSectionGetDof(csection, cpoints[p], &dof);CHKERRQ(ierr);
6532     if (!dof) continue;
6533     for (f = 0; f < numFields; ++f) {
6534       ierr           = PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof);CHKERRQ(ierr);
6535       coffsets[f+1] += fdof;
6536     }
6537     numCIndices += dof;
6538   }
6539   for (f = 1; f < numFields; ++f) coffsets[f+1] += coffsets[f];
6540   /* Row indices */
6541   ierr = DMPlexGetCellRefiner_Internal(dmc, &cellRefiner);CHKERRQ(ierr);
6542   ierr = CellRefinerGetAffineTransforms_Internal(cellRefiner, &numSubcells, NULL, NULL, NULL);CHKERRQ(ierr);
6543   ierr = DMGetWorkArray(dmf, maxFPoints*2*numSubcells, MPIU_INT, &ftotpoints);CHKERRQ(ierr);
6544   for (r = 0, q = 0; r < numSubcells; ++r) {
6545     /* TODO Map from coarse to fine cells */
6546     ierr = DMPlexGetTransitiveClosure(dmf, point*numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints);CHKERRQ(ierr);
6547     /* Compress out points not in the section */
6548     ierr = PetscSectionGetChart(fsection, &pStart, &pEnd);CHKERRQ(ierr);
6549     for (p = 0; p < numFPoints*2; p += 2) {
6550       if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) {
6551         ierr = PetscSectionGetDof(fsection, fpoints[p], &dof);CHKERRQ(ierr);
6552         if (!dof) continue;
6553         for (s = 0; s < q; ++s) if (fpoints[p] == ftotpoints[s*2]) break;
6554         if (s < q) continue;
6555         ftotpoints[q*2]   = fpoints[p];
6556         ftotpoints[q*2+1] = fpoints[p+1];
6557         ++q;
6558       }
6559     }
6560     ierr = DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints);CHKERRQ(ierr);
6561   }
6562   numFPoints = q;
6563   for (p = 0, numFIndices = 0; p < numFPoints*2; p += 2) {
6564     PetscInt fdof;
6565 
6566     ierr = PetscSectionGetDof(fsection, ftotpoints[p], &dof);CHKERRQ(ierr);
6567     if (!dof) continue;
6568     for (f = 0; f < numFields; ++f) {
6569       ierr           = PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof);CHKERRQ(ierr);
6570       foffsets[f+1] += fdof;
6571     }
6572     numFIndices += dof;
6573   }
6574   for (f = 1; f < numFields; ++f) foffsets[f+1] += foffsets[f];
6575 
6576   if (numFields && foffsets[numFields] != numFIndices) SETERRQ2(PetscObjectComm((PetscObject)dmf), PETSC_ERR_PLIB, "Invalid size for closure %D should be %D", foffsets[numFields], numFIndices);
6577   if (numFields && coffsets[numFields] != numCIndices) SETERRQ2(PetscObjectComm((PetscObject)dmc), PETSC_ERR_PLIB, "Invalid size for closure %D should be %D", coffsets[numFields], numCIndices);
6578   if (numFields) {
6579     const PetscInt **permsF[32] = {NULL};
6580     const PetscInt **permsC[32] = {NULL};
6581 
6582     for (f = 0; f < numFields; f++) {
6583       ierr = PetscSectionGetFieldPointSyms(fsection,f,numFPoints,ftotpoints,&permsF[f],NULL);CHKERRQ(ierr);
6584       ierr = PetscSectionGetFieldPointSyms(csection,f,numCPoints,cpoints,&permsC[f],NULL);CHKERRQ(ierr);
6585     }
6586     for (p = 0; p < numFPoints; p++) {
6587       ierr = PetscSectionGetOffset(globalFSection, ftotpoints[2*p], &globalOff);CHKERRQ(ierr);
6588       DMPlexGetIndicesPointFields_Internal(fsection, ftotpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, foffsets, PETSC_FALSE, permsF, p, fclperm, findices);
6589     }
6590     for (p = 0; p < numCPoints; p++) {
6591       ierr = PetscSectionGetOffset(globalCSection, cpoints[2*p], &globalOff);CHKERRQ(ierr);
6592       DMPlexGetIndicesPointFields_Internal(csection, cpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cclperm, cindices);
6593     }
6594     for (f = 0; f < numFields; f++) {
6595       ierr = PetscSectionRestoreFieldPointSyms(fsection,f,numFPoints,ftotpoints,&permsF[f],NULL);CHKERRQ(ierr);
6596       ierr = PetscSectionRestoreFieldPointSyms(csection,f,numCPoints,cpoints,&permsC[f],NULL);CHKERRQ(ierr);
6597     }
6598   } else {
6599     const PetscInt **permsF = NULL;
6600     const PetscInt **permsC = NULL;
6601 
6602     ierr = PetscSectionGetPointSyms(fsection,numFPoints,ftotpoints,&permsF,NULL);CHKERRQ(ierr);
6603     ierr = PetscSectionGetPointSyms(csection,numCPoints,cpoints,&permsC,NULL);CHKERRQ(ierr);
6604     for (p = 0, off = 0; p < numFPoints; p++) {
6605       const PetscInt *perm = permsF ? permsF[p] : NULL;
6606 
6607       ierr = PetscSectionGetOffset(globalFSection, ftotpoints[2*p], &globalOff);CHKERRQ(ierr);
6608       DMPlexGetIndicesPoint_Internal(fsection, ftotpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, fclperm, findices);
6609     }
6610     for (p = 0, off = 0; p < numCPoints; p++) {
6611       const PetscInt *perm = permsC ? permsC[p] : NULL;
6612 
6613       ierr = PetscSectionGetOffset(globalCSection, cpoints[2*p], &globalOff);CHKERRQ(ierr);
6614       DMPlexGetIndicesPoint_Internal(csection, cpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, cclperm, cindices);
6615     }
6616     ierr = PetscSectionRestorePointSyms(fsection,numFPoints,ftotpoints,&permsF,NULL);CHKERRQ(ierr);
6617     ierr = PetscSectionRestorePointSyms(csection,numCPoints,cpoints,&permsC,NULL);CHKERRQ(ierr);
6618   }
6619   ierr = DMRestoreWorkArray(dmf, numCPoints*2*4, MPIU_INT, &ftotpoints);CHKERRQ(ierr);
6620   ierr = DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints);CHKERRQ(ierr);
6621   PetscFunctionReturn(0);
6622 }
6623 
6624 /*@
6625   DMPlexGetHybridBounds - Get the first mesh point of each dimension which is a hybrid
6626 
6627   Input Parameter:
6628 . dm - The DMPlex object
6629 
6630   Output Parameters:
6631 + cMax - The first hybrid cell
6632 . fMax - The first hybrid face
6633 . eMax - The first hybrid edge
6634 - vMax - The first hybrid vertex
6635 
6636   Level: developer
6637 
6638 .seealso DMPlexCreateHybridMesh(), DMPlexSetHybridBounds()
6639 @*/
6640 PetscErrorCode DMPlexGetHybridBounds(DM dm, PetscInt *cMax, PetscInt *fMax, PetscInt *eMax, PetscInt *vMax)
6641 {
6642   DM_Plex       *mesh = (DM_Plex*) dm->data;
6643   PetscInt       dim;
6644   PetscErrorCode ierr;
6645 
6646   PetscFunctionBegin;
6647   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6648   ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr);
6649   if (dim < 0) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "DM dimension not yet set");
6650   if (cMax) *cMax = mesh->hybridPointMax[dim];
6651   if (fMax) *fMax = mesh->hybridPointMax[PetscMax(dim-1,0)];
6652   if (eMax) *eMax = mesh->hybridPointMax[1];
6653   if (vMax) *vMax = mesh->hybridPointMax[0];
6654   PetscFunctionReturn(0);
6655 }
6656 
6657 static PetscErrorCode DMPlexCreateDimStratum(DM dm, DMLabel depthLabel, DMLabel dimLabel, PetscInt d, PetscInt dMax)
6658 {
6659   IS             is, his;
6660   PetscInt       first = 0, stride;
6661   PetscBool      isStride;
6662   PetscErrorCode ierr;
6663 
6664   PetscFunctionBegin;
6665   ierr = DMLabelGetStratumIS(depthLabel, d, &is);CHKERRQ(ierr);
6666   ierr = PetscObjectTypeCompare((PetscObject) is, ISSTRIDE, &isStride);CHKERRQ(ierr);
6667   if (isStride) {ierr = ISStrideGetInfo(is, &first, &stride);CHKERRQ(ierr);}
6668   if (is && (!isStride || stride != 1)) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "DM is not stratified: depth %D IS is not contiguous", d);
6669   ierr = ISCreateStride(PETSC_COMM_SELF, (dMax - first), first, 1, &his);CHKERRQ(ierr);
6670   ierr = DMLabelSetStratumIS(dimLabel, d, his);CHKERRQ(ierr);
6671   ierr = ISDestroy(&his);CHKERRQ(ierr);
6672   ierr = ISDestroy(&is);CHKERRQ(ierr);
6673   PetscFunctionReturn(0);
6674 }
6675 
6676 /*@
6677   DMPlexSetHybridBounds - Set the first mesh point of each dimension which is a hybrid
6678 
6679   Input Parameters:
6680 + dm   - The DMPlex object
6681 . cMax - The first hybrid cell
6682 . fMax - The first hybrid face
6683 . eMax - The first hybrid edge
6684 - vMax - The first hybrid vertex
6685 
6686   Level: developer
6687 
6688 .seealso DMPlexCreateHybridMesh(), DMPlexGetHybridBounds()
6689 @*/
6690 PetscErrorCode DMPlexSetHybridBounds(DM dm, PetscInt cMax, PetscInt fMax, PetscInt eMax, PetscInt vMax)
6691 {
6692   DM_Plex       *mesh = (DM_Plex*) dm->data;
6693   PetscInt       dim;
6694   PetscErrorCode ierr;
6695 
6696   PetscFunctionBegin;
6697   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6698   ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr);
6699   if (dim < 0) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "DM dimension not yet set");
6700   if (cMax >= 0) mesh->hybridPointMax[dim]               = cMax;
6701   if (fMax >= 0) mesh->hybridPointMax[PetscMax(dim-1,0)] = fMax;
6702   if (eMax >= 0) mesh->hybridPointMax[1]                 = eMax;
6703   if (vMax >= 0) mesh->hybridPointMax[0]                 = vMax;
6704   PetscFunctionReturn(0);
6705 }
6706 
6707 /*@C
6708   DMPlexGetVTKCellHeight - Returns the height in the DAG used to determine which points are cells (normally 0)
6709 
6710   Input Parameter:
6711 . dm   - The DMPlex object
6712 
6713   Output Parameter:
6714 . cellHeight - The height of a cell
6715 
6716   Level: developer
6717 
6718 .seealso DMPlexSetVTKCellHeight()
6719 @*/
6720 PetscErrorCode DMPlexGetVTKCellHeight(DM dm, PetscInt *cellHeight)
6721 {
6722   DM_Plex *mesh = (DM_Plex*) dm->data;
6723 
6724   PetscFunctionBegin;
6725   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6726   PetscValidPointer(cellHeight, 2);
6727   *cellHeight = mesh->vtkCellHeight;
6728   PetscFunctionReturn(0);
6729 }
6730 
6731 /*@C
6732   DMPlexSetVTKCellHeight - Sets the height in the DAG used to determine which points are cells (normally 0)
6733 
6734   Input Parameters:
6735 + dm   - The DMPlex object
6736 - cellHeight - The height of a cell
6737 
6738   Level: developer
6739 
6740 .seealso DMPlexGetVTKCellHeight()
6741 @*/
6742 PetscErrorCode DMPlexSetVTKCellHeight(DM dm, PetscInt cellHeight)
6743 {
6744   DM_Plex *mesh = (DM_Plex*) dm->data;
6745 
6746   PetscFunctionBegin;
6747   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6748   mesh->vtkCellHeight = cellHeight;
6749   PetscFunctionReturn(0);
6750 }
6751 
6752 /*@
6753   DMPlexGetGhostCellStratum - Get the range of cells which are used to enforce FV boundary conditions
6754 
6755   Input Parameter:
6756 . dm - The DMPlex object
6757 
6758   Output Parameters:
6759 + gcStart - The first ghost cell, or NULL
6760 - gcEnd   - The upper bound on ghost cells, or NULL
6761 
6762   Level: advanced
6763 
6764 .seealso DMPlexConstructGhostCells(), DMPlexSetGhostCellStratum(), DMPlexGetHybridBounds()
6765 @*/
6766 PetscErrorCode DMPlexGetGhostCellStratum(DM dm, PetscInt *gcStart, PetscInt *gcEnd)
6767 {
6768   DM_Plex       *mesh = (DM_Plex*) dm->data;
6769   PetscInt       dim;
6770   PetscErrorCode ierr;
6771 
6772   PetscFunctionBegin;
6773   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6774   ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr);
6775   if (dim < 0) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "DM dimension not yet set");
6776   if (gcStart) {PetscValidIntPointer(gcStart, 2); *gcStart = mesh->ghostCellStart;}
6777   if (gcEnd)   {
6778     PetscValidIntPointer(gcEnd, 3);
6779     if (mesh->ghostCellStart >= 0) {ierr = DMPlexGetHeightStratum(dm, 0, NULL, gcEnd);CHKERRQ(ierr);}
6780     else                           {*gcEnd = -1;}
6781   }
6782   PetscFunctionReturn(0);
6783 }
6784 
6785 /*@
6786   DMPlexSetGhostCellStratum - Set the range of cells which are used to enforce FV boundary conditions
6787 
6788   Input Parameters:
6789 + dm      - The DMPlex object
6790 . gcStart - The first ghost cell, or PETSC_DETERMINE
6791 - gcEnd   - The upper bound on ghost cells, or PETSC_DETERMINE
6792 
6793   Level: advanced
6794 
6795   Note: This is not usually called directly by a user.
6796 
6797 .seealso DMPlexConstructGhostCells(), DMPlexGetGhostCellStratum(), DMPlexSetHybridBounds()
6798 @*/
6799 PetscErrorCode DMPlexSetGhostCellStratum(DM dm, PetscInt gcStart, PetscInt gcEnd)
6800 {
6801   DM_Plex       *mesh = (DM_Plex*) dm->data;
6802   PetscInt       dim;
6803   PetscErrorCode ierr;
6804 
6805   PetscFunctionBegin;
6806   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6807   ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr);
6808   if (dim < 0) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "DM dimension not yet set");
6809   mesh->ghostCellStart = gcStart;
6810   if (gcEnd >= 0) {
6811     PetscInt cEnd;
6812     ierr = DMPlexGetHeightStratum(dm, 0, NULL, &cEnd);CHKERRQ(ierr);
6813     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);
6814   }
6815   PetscFunctionReturn(0);
6816 }
6817 
6818 /*@
6819   DMPlexGetInteriorCellStratum - Get the range of cells which are neither hybrid nor ghost FV cells
6820 
6821   Input Parameter:
6822 . dm - The DMPlex object
6823 
6824   Output Parameters:
6825 + cStartInterior - The first ghost cell
6826 - cEndInterior   - The upper bound on ghost cells
6827 
6828   Level: developer
6829 
6830 .seealso DMPlexConstructGhostCells(), DMPlexSetGhostCellStratum(), DMPlexGetHybridBounds()
6831 @*/
6832 PetscErrorCode DMPlexGetInteriorCellStratum(DM dm, PetscInt *cStartInterior, PetscInt *cEndInterior)
6833 {
6834   PetscInt       gcEnd, cMax;
6835   PetscErrorCode ierr;
6836 
6837   PetscFunctionBegin;
6838   ierr = DMPlexGetHeightStratum(dm, 0, cStartInterior, cEndInterior);CHKERRQ(ierr);
6839   ierr = DMPlexGetGhostCellStratum(dm, &gcEnd, NULL);CHKERRQ(ierr);
6840   *cEndInterior = gcEnd < 0 ? *cEndInterior : gcEnd;
6841   ierr = DMPlexGetHybridBounds(dm, &cMax, NULL, NULL, NULL);CHKERRQ(ierr);
6842   *cEndInterior = cMax  < 0 ? *cEndInterior : cMax;
6843   PetscFunctionReturn(0);
6844 }
6845 
6846 /* We can easily have a form that takes an IS instead */
6847 PetscErrorCode DMPlexCreateNumbering_Plex(DM dm, PetscInt pStart, PetscInt pEnd, PetscInt shift, PetscInt *globalSize, PetscSF sf, IS *numbering)
6848 {
6849   PetscSection   section, globalSection;
6850   PetscInt      *numbers, p;
6851   PetscErrorCode ierr;
6852 
6853   PetscFunctionBegin;
6854   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)dm), &section);CHKERRQ(ierr);
6855   ierr = PetscSectionSetChart(section, pStart, pEnd);CHKERRQ(ierr);
6856   for (p = pStart; p < pEnd; ++p) {
6857     ierr = PetscSectionSetDof(section, p, 1);CHKERRQ(ierr);
6858   }
6859   ierr = PetscSectionSetUp(section);CHKERRQ(ierr);
6860   ierr = PetscSectionCreateGlobalSection(section, sf, PETSC_FALSE, PETSC_FALSE, &globalSection);CHKERRQ(ierr);
6861   ierr = PetscMalloc1(pEnd - pStart, &numbers);CHKERRQ(ierr);
6862   for (p = pStart; p < pEnd; ++p) {
6863     ierr = PetscSectionGetOffset(globalSection, p, &numbers[p-pStart]);CHKERRQ(ierr);
6864     if (numbers[p-pStart] < 0) numbers[p-pStart] -= shift;
6865     else                       numbers[p-pStart] += shift;
6866   }
6867   ierr = ISCreateGeneral(PetscObjectComm((PetscObject) dm), pEnd - pStart, numbers, PETSC_OWN_POINTER, numbering);CHKERRQ(ierr);
6868   if (globalSize) {
6869     PetscLayout layout;
6870     ierr = PetscSectionGetPointLayout(PetscObjectComm((PetscObject) dm), globalSection, &layout);CHKERRQ(ierr);
6871     ierr = PetscLayoutGetSize(layout, globalSize);CHKERRQ(ierr);
6872     ierr = PetscLayoutDestroy(&layout);CHKERRQ(ierr);
6873   }
6874   ierr = PetscSectionDestroy(&section);CHKERRQ(ierr);
6875   ierr = PetscSectionDestroy(&globalSection);CHKERRQ(ierr);
6876   PetscFunctionReturn(0);
6877 }
6878 
6879 PetscErrorCode DMPlexCreateCellNumbering_Internal(DM dm, PetscBool includeHybrid, IS *globalCellNumbers)
6880 {
6881   PetscInt       cellHeight, cStart, cEnd, cMax;
6882   PetscErrorCode ierr;
6883 
6884   PetscFunctionBegin;
6885   ierr = DMPlexGetVTKCellHeight(dm, &cellHeight);CHKERRQ(ierr);
6886   ierr = DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd);CHKERRQ(ierr);
6887   ierr = DMPlexGetHybridBounds(dm, &cMax, NULL, NULL, NULL);CHKERRQ(ierr);
6888   if (cMax >= 0 && !includeHybrid) cEnd = PetscMin(cEnd, cMax);
6889   ierr = DMPlexCreateNumbering_Plex(dm, cStart, cEnd, 0, NULL, dm->sf, globalCellNumbers);CHKERRQ(ierr);
6890   PetscFunctionReturn(0);
6891 }
6892 
6893 /*@
6894   DMPlexGetCellNumbering - Get a global cell numbering for all cells on this process
6895 
6896   Input Parameter:
6897 . dm   - The DMPlex object
6898 
6899   Output Parameter:
6900 . globalCellNumbers - Global cell numbers for all cells on this process
6901 
6902   Level: developer
6903 
6904 .seealso DMPlexGetVertexNumbering()
6905 @*/
6906 PetscErrorCode DMPlexGetCellNumbering(DM dm, IS *globalCellNumbers)
6907 {
6908   DM_Plex       *mesh = (DM_Plex*) dm->data;
6909   PetscErrorCode ierr;
6910 
6911   PetscFunctionBegin;
6912   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6913   if (!mesh->globalCellNumbers) {ierr = DMPlexCreateCellNumbering_Internal(dm, PETSC_FALSE, &mesh->globalCellNumbers);CHKERRQ(ierr);}
6914   *globalCellNumbers = mesh->globalCellNumbers;
6915   PetscFunctionReturn(0);
6916 }
6917 
6918 PetscErrorCode DMPlexCreateVertexNumbering_Internal(DM dm, PetscBool includeHybrid, IS *globalVertexNumbers)
6919 {
6920   PetscInt       vStart, vEnd, vMax;
6921   PetscErrorCode ierr;
6922 
6923   PetscFunctionBegin;
6924   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6925   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
6926   ierr = DMPlexGetHybridBounds(dm, NULL, NULL, NULL, &vMax);CHKERRQ(ierr);
6927   if (vMax >= 0 && !includeHybrid) vEnd = PetscMin(vEnd, vMax);
6928   ierr = DMPlexCreateNumbering_Plex(dm, vStart, vEnd, 0, NULL, dm->sf, globalVertexNumbers);CHKERRQ(ierr);
6929   PetscFunctionReturn(0);
6930 }
6931 
6932 /*@
6933   DMPlexGetVertexNumbering - Get a global vertex numbering for all vertices on this process
6934 
6935   Input Parameter:
6936 . dm   - The DMPlex object
6937 
6938   Output Parameter:
6939 . globalVertexNumbers - Global vertex numbers for all vertices on this process
6940 
6941   Level: developer
6942 
6943 .seealso DMPlexGetCellNumbering()
6944 @*/
6945 PetscErrorCode DMPlexGetVertexNumbering(DM dm, IS *globalVertexNumbers)
6946 {
6947   DM_Plex       *mesh = (DM_Plex*) dm->data;
6948   PetscErrorCode ierr;
6949 
6950   PetscFunctionBegin;
6951   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6952   if (!mesh->globalVertexNumbers) {ierr = DMPlexCreateVertexNumbering_Internal(dm, PETSC_FALSE, &mesh->globalVertexNumbers);CHKERRQ(ierr);}
6953   *globalVertexNumbers = mesh->globalVertexNumbers;
6954   PetscFunctionReturn(0);
6955 }
6956 
6957 /*@
6958   DMPlexCreatePointNumbering - Create a global numbering for all points on this process
6959 
6960   Input Parameter:
6961 . dm   - The DMPlex object
6962 
6963   Output Parameter:
6964 . globalPointNumbers - Global numbers for all points on this process
6965 
6966   Level: developer
6967 
6968 .seealso DMPlexGetCellNumbering()
6969 @*/
6970 PetscErrorCode DMPlexCreatePointNumbering(DM dm, IS *globalPointNumbers)
6971 {
6972   IS             nums[4];
6973   PetscInt       depths[4], gdepths[4], starts[4];
6974   PetscInt       depth, d, shift = 0;
6975   PetscErrorCode ierr;
6976 
6977   PetscFunctionBegin;
6978   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6979   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
6980   /* For unstratified meshes use dim instead of depth */
6981   if (depth < 0) {ierr = DMGetDimension(dm, &depth);CHKERRQ(ierr);}
6982   for (d = 0; d <= depth; ++d) {
6983     PetscInt end;
6984 
6985     depths[d] = depth-d;
6986     ierr = DMPlexGetDepthStratum(dm, depths[d], &starts[d], &end);CHKERRQ(ierr);
6987     if (!(starts[d]-end)) { starts[d] = depths[d] = -1; }
6988   }
6989   ierr = PetscSortIntWithArray(depth+1, starts, depths);CHKERRQ(ierr);
6990   ierr = MPIU_Allreduce(depths, gdepths, depth+1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject) dm));CHKERRQ(ierr);
6991   for (d = 0; d <= depth; ++d) {
6992     if (starts[d] >= 0 && depths[d] != gdepths[d]) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Expected depth %D, found %D",depths[d],gdepths[d]);
6993   }
6994   for (d = 0; d <= depth; ++d) {
6995     PetscInt pStart, pEnd, gsize;
6996 
6997     ierr = DMPlexGetDepthStratum(dm, gdepths[d], &pStart, &pEnd);CHKERRQ(ierr);
6998     ierr = DMPlexCreateNumbering_Plex(dm, pStart, pEnd, shift, &gsize, dm->sf, &nums[d]);CHKERRQ(ierr);
6999     shift += gsize;
7000   }
7001   ierr = ISConcatenate(PetscObjectComm((PetscObject) dm), depth+1, nums, globalPointNumbers);CHKERRQ(ierr);
7002   for (d = 0; d <= depth; ++d) {ierr = ISDestroy(&nums[d]);CHKERRQ(ierr);}
7003   PetscFunctionReturn(0);
7004 }
7005 
7006 
7007 /*@
7008   DMPlexCreateRankField - Create a cell field whose value is the rank of the owner
7009 
7010   Input Parameter:
7011 . dm - The DMPlex object
7012 
7013   Output Parameter:
7014 . ranks - The rank field
7015 
7016   Options Database Keys:
7017 . -dm_partition_view - Adds the rank field into the DM output from -dm_view using the same viewer
7018 
7019   Level: intermediate
7020 
7021 .seealso: DMView()
7022 @*/
7023 PetscErrorCode DMPlexCreateRankField(DM dm, Vec *ranks)
7024 {
7025   DM             rdm;
7026   PetscFE        fe;
7027   PetscScalar   *r;
7028   PetscMPIInt    rank;
7029   PetscInt       dim, cStart, cEnd, c;
7030   PetscErrorCode ierr;
7031 
7032   PetscFunctionBeginUser;
7033   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7034   PetscValidPointer(ranks, 2);
7035   ierr = MPI_Comm_rank(PetscObjectComm((PetscObject) dm), &rank);CHKERRQ(ierr);
7036   ierr = DMClone(dm, &rdm);CHKERRQ(ierr);
7037   ierr = DMGetDimension(rdm, &dim);CHKERRQ(ierr);
7038   ierr = PetscFECreateDefault(PetscObjectComm((PetscObject) rdm), dim, 1, PETSC_TRUE, "PETSc___rank_", -1, &fe);CHKERRQ(ierr);
7039   ierr = PetscObjectSetName((PetscObject) fe, "rank");CHKERRQ(ierr);
7040   ierr = DMSetField(rdm, 0, NULL, (PetscObject) fe);CHKERRQ(ierr);
7041   ierr = PetscFEDestroy(&fe);CHKERRQ(ierr);
7042   ierr = DMCreateDS(rdm);CHKERRQ(ierr);
7043   ierr = DMPlexGetHeightStratum(rdm, 0, &cStart, &cEnd);CHKERRQ(ierr);
7044   ierr = DMCreateGlobalVector(rdm, ranks);CHKERRQ(ierr);
7045   ierr = PetscObjectSetName((PetscObject) *ranks, "partition");CHKERRQ(ierr);
7046   ierr = VecGetArray(*ranks, &r);CHKERRQ(ierr);
7047   for (c = cStart; c < cEnd; ++c) {
7048     PetscScalar *lr;
7049 
7050     ierr = DMPlexPointGlobalRef(rdm, c, r, &lr);CHKERRQ(ierr);
7051     *lr = rank;
7052   }
7053   ierr = VecRestoreArray(*ranks, &r);CHKERRQ(ierr);
7054   ierr = DMDestroy(&rdm);CHKERRQ(ierr);
7055   PetscFunctionReturn(0);
7056 }
7057 
7058 /*@
7059   DMPlexCreateLabelField - Create a cell field whose value is the label value for that cell
7060 
7061   Input Parameters:
7062 + dm    - The DMPlex
7063 - label - The DMLabel
7064 
7065   Output Parameter:
7066 . val - The label value field
7067 
7068   Options Database Keys:
7069 . -dm_label_view - Adds the label value field into the DM output from -dm_view using the same viewer
7070 
7071   Level: intermediate
7072 
7073 .seealso: DMView()
7074 @*/
7075 PetscErrorCode DMPlexCreateLabelField(DM dm, DMLabel label, Vec *val)
7076 {
7077   DM             rdm;
7078   PetscFE        fe;
7079   PetscScalar   *v;
7080   PetscInt       dim, cStart, cEnd, c;
7081   PetscErrorCode ierr;
7082 
7083   PetscFunctionBeginUser;
7084   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7085   PetscValidPointer(label, 2);
7086   PetscValidPointer(val, 3);
7087   ierr = DMClone(dm, &rdm);CHKERRQ(ierr);
7088   ierr = DMGetDimension(rdm, &dim);CHKERRQ(ierr);
7089   ierr = PetscFECreateDefault(PetscObjectComm((PetscObject) rdm), dim, 1, PETSC_TRUE, "PETSc___label_value_", -1, &fe);CHKERRQ(ierr);
7090   ierr = PetscObjectSetName((PetscObject) fe, "label_value");CHKERRQ(ierr);
7091   ierr = DMSetField(rdm, 0, NULL, (PetscObject) fe);CHKERRQ(ierr);
7092   ierr = PetscFEDestroy(&fe);CHKERRQ(ierr);
7093   ierr = DMCreateDS(rdm);CHKERRQ(ierr);
7094   ierr = DMPlexGetHeightStratum(rdm, 0, &cStart, &cEnd);CHKERRQ(ierr);
7095   ierr = DMCreateGlobalVector(rdm, val);CHKERRQ(ierr);
7096   ierr = PetscObjectSetName((PetscObject) *val, "label_value");CHKERRQ(ierr);
7097   ierr = VecGetArray(*val, &v);CHKERRQ(ierr);
7098   for (c = cStart; c < cEnd; ++c) {
7099     PetscScalar *lv;
7100     PetscInt     cval;
7101 
7102     ierr = DMPlexPointGlobalRef(rdm, c, v, &lv);CHKERRQ(ierr);
7103     ierr = DMLabelGetValue(label, c, &cval);CHKERRQ(ierr);
7104     *lv = cval;
7105   }
7106   ierr = VecRestoreArray(*val, &v);CHKERRQ(ierr);
7107   ierr = DMDestroy(&rdm);CHKERRQ(ierr);
7108   PetscFunctionReturn(0);
7109 }
7110 
7111 /*@
7112   DMPlexCheckSymmetry - Check that the adjacency information in the mesh is symmetric.
7113 
7114   Input Parameter:
7115 . dm - The DMPlex object
7116 
7117   Notes:
7118   This is a useful diagnostic when creating meshes programmatically.
7119 
7120   For the complete list of DMPlexCheck* functions, see DMSetFromOptions().
7121 
7122   Level: developer
7123 
7124 .seealso: DMCreate(), DMSetFromOptions()
7125 @*/
7126 PetscErrorCode DMPlexCheckSymmetry(DM dm)
7127 {
7128   PetscSection    coneSection, supportSection;
7129   const PetscInt *cone, *support;
7130   PetscInt        coneSize, c, supportSize, s;
7131   PetscInt        pStart, pEnd, p, pp, csize, ssize;
7132   PetscBool       storagecheck = PETSC_TRUE;
7133   PetscErrorCode  ierr;
7134 
7135   PetscFunctionBegin;
7136   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7137   ierr = DMPlexGetConeSection(dm, &coneSection);CHKERRQ(ierr);
7138   ierr = DMPlexGetSupportSection(dm, &supportSection);CHKERRQ(ierr);
7139   /* Check that point p is found in the support of its cone points, and vice versa */
7140   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
7141   for (p = pStart; p < pEnd; ++p) {
7142     ierr = DMPlexGetConeSize(dm, p, &coneSize);CHKERRQ(ierr);
7143     ierr = DMPlexGetCone(dm, p, &cone);CHKERRQ(ierr);
7144     for (c = 0; c < coneSize; ++c) {
7145       PetscBool dup = PETSC_FALSE;
7146       PetscInt  d;
7147       for (d = c-1; d >= 0; --d) {
7148         if (cone[c] == cone[d]) {dup = PETSC_TRUE; break;}
7149       }
7150       ierr = DMPlexGetSupportSize(dm, cone[c], &supportSize);CHKERRQ(ierr);
7151       ierr = DMPlexGetSupport(dm, cone[c], &support);CHKERRQ(ierr);
7152       for (s = 0; s < supportSize; ++s) {
7153         if (support[s] == p) break;
7154       }
7155       if ((s >= supportSize) || (dup && (support[s+1] != p))) {
7156         ierr = PetscPrintf(PETSC_COMM_SELF, "p: %D cone: ", p);CHKERRQ(ierr);
7157         for (s = 0; s < coneSize; ++s) {
7158           ierr = PetscPrintf(PETSC_COMM_SELF, "%D, ", cone[s]);CHKERRQ(ierr);
7159         }
7160         ierr = PetscPrintf(PETSC_COMM_SELF, "\n");CHKERRQ(ierr);
7161         ierr = PetscPrintf(PETSC_COMM_SELF, "p: %D support: ", cone[c]);CHKERRQ(ierr);
7162         for (s = 0; s < supportSize; ++s) {
7163           ierr = PetscPrintf(PETSC_COMM_SELF, "%D, ", support[s]);CHKERRQ(ierr);
7164         }
7165         ierr = PetscPrintf(PETSC_COMM_SELF, "\n");CHKERRQ(ierr);
7166         if (dup) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D not repeatedly found in support of repeated cone point %D", p, cone[c]);
7167         else SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D not found in support of cone point %D", p, cone[c]);
7168       }
7169     }
7170     ierr = DMPlexGetTreeParent(dm, p, &pp, NULL);CHKERRQ(ierr);
7171     if (p != pp) { storagecheck = PETSC_FALSE; continue; }
7172     ierr = DMPlexGetSupportSize(dm, p, &supportSize);CHKERRQ(ierr);
7173     ierr = DMPlexGetSupport(dm, p, &support);CHKERRQ(ierr);
7174     for (s = 0; s < supportSize; ++s) {
7175       ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
7176       ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
7177       for (c = 0; c < coneSize; ++c) {
7178         ierr = DMPlexGetTreeParent(dm, cone[c], &pp, NULL);CHKERRQ(ierr);
7179         if (cone[c] != pp) { c = 0; break; }
7180         if (cone[c] == p) break;
7181       }
7182       if (c >= coneSize) {
7183         ierr = PetscPrintf(PETSC_COMM_SELF, "p: %D support: ", p);CHKERRQ(ierr);
7184         for (c = 0; c < supportSize; ++c) {
7185           ierr = PetscPrintf(PETSC_COMM_SELF, "%D, ", support[c]);CHKERRQ(ierr);
7186         }
7187         ierr = PetscPrintf(PETSC_COMM_SELF, "\n");CHKERRQ(ierr);
7188         ierr = PetscPrintf(PETSC_COMM_SELF, "p: %D cone: ", support[s]);CHKERRQ(ierr);
7189         for (c = 0; c < coneSize; ++c) {
7190           ierr = PetscPrintf(PETSC_COMM_SELF, "%D, ", cone[c]);CHKERRQ(ierr);
7191         }
7192         ierr = PetscPrintf(PETSC_COMM_SELF, "\n");CHKERRQ(ierr);
7193         SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D not found in cone of support point %D", p, support[s]);
7194       }
7195     }
7196   }
7197   if (storagecheck) {
7198     ierr = PetscSectionGetStorageSize(coneSection, &csize);CHKERRQ(ierr);
7199     ierr = PetscSectionGetStorageSize(supportSection, &ssize);CHKERRQ(ierr);
7200     if (csize != ssize) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Total cone size %D != Total support size %D", csize, ssize);
7201   }
7202   PetscFunctionReturn(0);
7203 }
7204 
7205 /*@
7206   DMPlexCheckSkeleton - Check that each cell has the correct number of vertices
7207 
7208   Input Parameters:
7209 + dm - The DMPlex object
7210 - cellHeight - Normally 0
7211 
7212   Notes:
7213   This is a useful diagnostic when creating meshes programmatically.
7214   Currently applicable only to homogeneous simplex or tensor meshes.
7215 
7216   For the complete list of DMPlexCheck* functions, see DMSetFromOptions().
7217 
7218   Level: developer
7219 
7220 .seealso: DMCreate(), DMSetFromOptions()
7221 @*/
7222 PetscErrorCode DMPlexCheckSkeleton(DM dm, PetscInt cellHeight)
7223 {
7224   PetscInt       dim, numCorners, numHybridCorners, vStart, vEnd, cStart, cEnd, cMax, c;
7225   PetscBool      isSimplex = PETSC_FALSE;
7226   PetscErrorCode ierr;
7227 
7228   PetscFunctionBegin;
7229   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7230   ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr);
7231   ierr = DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd);CHKERRQ(ierr);
7232   if (cStart < cEnd) {
7233     ierr = DMPlexGetConeSize(dm, cStart, &c);CHKERRQ(ierr);
7234     isSimplex = c == dim+1 ? PETSC_TRUE : PETSC_FALSE;
7235   }
7236   switch (dim) {
7237   case 1: numCorners = isSimplex ? 2 : 2; numHybridCorners = isSimplex ? 2 : 2; break;
7238   case 2: numCorners = isSimplex ? 3 : 4; numHybridCorners = isSimplex ? 4 : 4; break;
7239   case 3: numCorners = isSimplex ? 4 : 8; numHybridCorners = isSimplex ? 6 : 8; break;
7240   default:
7241     SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_OUTOFRANGE, "Cannot handle meshes of dimension %D", dim);
7242   }
7243   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
7244   ierr = DMPlexGetHybridBounds(dm, &cMax, NULL, NULL, NULL);CHKERRQ(ierr);
7245   cMax = cMax >= 0 ? cMax : cEnd;
7246   for (c = cStart; c < cMax; ++c) {
7247     PetscInt *closure = NULL, closureSize, cl, coneSize = 0;
7248 
7249     ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
7250     for (cl = 0; cl < closureSize*2; cl += 2) {
7251       const PetscInt p = closure[cl];
7252       if ((p >= vStart) && (p < vEnd)) ++coneSize;
7253     }
7254     ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
7255     if (coneSize != numCorners) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cell %D has  %D vertices != %D", c, coneSize, numCorners);
7256   }
7257   for (c = cMax; c < cEnd; ++c) {
7258     PetscInt *closure = NULL, closureSize, cl, coneSize = 0;
7259 
7260     ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
7261     for (cl = 0; cl < closureSize*2; cl += 2) {
7262       const PetscInt p = closure[cl];
7263       if ((p >= vStart) && (p < vEnd)) ++coneSize;
7264     }
7265     ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
7266     if (coneSize > numHybridCorners) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Hybrid cell %D has  %D vertices > %D", c, coneSize, numHybridCorners);
7267   }
7268   PetscFunctionReturn(0);
7269 }
7270 
7271 /*@
7272   DMPlexCheckFaces - Check that the faces of each cell give a vertex order this is consistent with what we expect from the cell type
7273 
7274   Not Collective
7275 
7276   Input Parameters:
7277 + dm - The DMPlex object
7278 - cellHeight - Normally 0
7279 
7280   Notes:
7281   This is a useful diagnostic when creating meshes programmatically.
7282   This routine is only relevant for meshes that are fully interpolated across all ranks.
7283   It will error out if a partially interpolated mesh is given on some rank.
7284   It will do nothing for locally uninterpolated mesh (as there is nothing to check).
7285 
7286   For the complete list of DMPlexCheck* functions, see DMSetFromOptions().
7287 
7288   Level: developer
7289 
7290 .seealso: DMCreate(), DMPlexGetVTKCellHeight(), DMSetFromOptions()
7291 @*/
7292 PetscErrorCode DMPlexCheckFaces(DM dm, PetscInt cellHeight)
7293 {
7294   PetscInt       pMax[4];
7295   PetscInt       dim, depth, vStart, vEnd, cStart, cEnd, c, h;
7296   PetscErrorCode ierr;
7297   DMPlexInterpolatedFlag interpEnum;
7298 
7299   PetscFunctionBegin;
7300   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7301   ierr = DMPlexIsInterpolated(dm, &interpEnum);CHKERRQ(ierr);
7302   if (interpEnum == DMPLEX_INTERPOLATED_NONE) PetscFunctionReturn(0);
7303   if (interpEnum == DMPLEX_INTERPOLATED_PARTIAL) {
7304     PetscMPIInt	rank;
7305     MPI_Comm	comm;
7306 
7307     ierr = PetscObjectGetComm((PetscObject) dm, &comm);CHKERRQ(ierr);
7308     ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
7309     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_SUP, "Mesh is only partially interpolated on rank %d, this is currently not supported", rank);
7310   }
7311 
7312   ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr);
7313   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
7314   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
7315   ierr = DMPlexGetHybridBounds(dm, &pMax[dim], &pMax[dim-1], &pMax[1], &pMax[0]);CHKERRQ(ierr);
7316   for (h = cellHeight; h < PetscMin(depth, dim); ++h) {
7317     ierr = DMPlexGetHeightStratum(dm, h, &cStart, &cEnd);CHKERRQ(ierr);
7318     for (c = cStart; c < cEnd; ++c) {
7319       const PetscInt *cone, *ornt, *faces;
7320       DMPolytopeType  ct;
7321       PetscInt        numFaces, faceSize, coneSize,f;
7322       PetscInt       *closure = NULL, closureSize, cl, numCorners = 0;
7323 
7324       if (pMax[dim-h] >= 0 && c >= pMax[dim-h]) continue;
7325       ierr = DMPlexGetCellType(dm, c, &ct);CHKERRQ(ierr);
7326       ierr = DMPlexGetConeSize(dm, c, &coneSize);CHKERRQ(ierr);
7327       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
7328       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
7329       ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
7330       for (cl = 0; cl < closureSize*2; cl += 2) {
7331         const PetscInt p = closure[cl];
7332         if ((p >= vStart) && (p < vEnd)) closure[numCorners++] = p;
7333       }
7334       ierr = DMPlexGetRawFaces_Internal(dm, ct, closure, &numFaces, &faceSize, &faces);CHKERRQ(ierr);
7335       if (coneSize != numFaces) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cell %D has %D faces but should have %D", c, coneSize, numFaces);
7336       for (f = 0; f < numFaces; ++f) {
7337         PetscInt *fclosure = NULL, fclosureSize, cl, fnumCorners = 0, v;
7338 
7339         ierr = DMPlexGetTransitiveClosure_Internal(dm, cone[f], ornt[f], PETSC_TRUE, &fclosureSize, &fclosure);CHKERRQ(ierr);
7340         for (cl = 0; cl < fclosureSize*2; cl += 2) {
7341           const PetscInt p = fclosure[cl];
7342           if ((p >= vStart) && (p < vEnd)) fclosure[fnumCorners++] = p;
7343         }
7344         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);
7345         for (v = 0; v < fnumCorners; ++v) {
7346           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]);
7347         }
7348         ierr = DMPlexRestoreTransitiveClosure(dm, cone[f], PETSC_TRUE, &fclosureSize, &fclosure);CHKERRQ(ierr);
7349       }
7350       ierr = DMPlexRestoreFaces_Internal(dm, ct, &numFaces, &faceSize, &faces);CHKERRQ(ierr);
7351       ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
7352     }
7353   }
7354   PetscFunctionReturn(0);
7355 }
7356 
7357 /*@
7358   DMPlexCheckGeometry - Check the geometry of mesh cells
7359 
7360   Input Parameter:
7361 . dm - The DMPlex object
7362 
7363   Notes:
7364   This is a useful diagnostic when creating meshes programmatically.
7365 
7366   For the complete list of DMPlexCheck* functions, see DMSetFromOptions().
7367 
7368   Level: developer
7369 
7370 .seealso: DMCreate(), DMSetFromOptions()
7371 @*/
7372 PetscErrorCode DMPlexCheckGeometry(DM dm)
7373 {
7374   PetscReal      detJ, J[9], refVol = 1.0;
7375   PetscReal      vol;
7376   PetscInt       dim, depth, d, cStart, cEnd, c, cMax;
7377   PetscErrorCode ierr;
7378 
7379   PetscFunctionBegin;
7380   ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr);
7381   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
7382   for (d = 0; d < dim; ++d) refVol *= 2.0;
7383   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
7384   ierr = DMPlexGetHybridBounds(dm, &cMax, NULL, NULL, NULL);CHKERRQ(ierr);
7385   cMax = cMax < 0 ? cEnd : cMax;
7386   for (c = cStart; c < cMax; ++c) {
7387     ierr = DMPlexComputeCellGeometryFEM(dm, c, NULL, NULL, J, NULL, &detJ);CHKERRQ(ierr);
7388     if (detJ <= 0.0) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Mesh cell %D is inverted, |J| = %g", c, (double) detJ);
7389     ierr = PetscInfo2(dm, "Cell %D FEM Volume %g\n", c, (double) detJ*refVol);CHKERRQ(ierr);
7390     if (depth > 1) {
7391       ierr = DMPlexComputeCellGeometryFVM(dm, c, &vol, NULL, NULL);CHKERRQ(ierr);
7392       if (vol <= 0.0) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Mesh cell %d is inverted, vol = %g", c, (double) vol);
7393       ierr = PetscInfo2(dm, "Cell %D FVM Volume %g\n", c, (double) vol);CHKERRQ(ierr);
7394     }
7395   }
7396   PetscFunctionReturn(0);
7397 }
7398 
7399 /*@
7400   DMPlexCheckPointSF - Check that several necessary conditions are met for the point SF of this plex.
7401 
7402   Input Parameters:
7403 . dm - The DMPlex object
7404 
7405   Notes:
7406   This is mainly intended for debugging/testing purposes.
7407   It currently checks only meshes with no partition overlapping.
7408 
7409   For the complete list of DMPlexCheck* functions, see DMSetFromOptions().
7410 
7411   Level: developer
7412 
7413 .seealso: DMGetPointSF(), DMSetFromOptions()
7414 @*/
7415 PetscErrorCode DMPlexCheckPointSF(DM dm)
7416 {
7417   PetscSF         pointSF;
7418   PetscInt        cellHeight, cStart, cEnd, l, nleaves, nroots, overlap;
7419   const PetscInt *locals, *rootdegree;
7420   PetscBool       distributed;
7421   PetscErrorCode  ierr;
7422 
7423   PetscFunctionBegin;
7424   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7425   ierr = DMGetPointSF(dm, &pointSF);CHKERRQ(ierr);
7426   ierr = DMPlexIsDistributed(dm, &distributed);CHKERRQ(ierr);
7427   if (!distributed) PetscFunctionReturn(0);
7428   ierr = DMPlexGetOverlap(dm, &overlap);CHKERRQ(ierr);
7429   if (overlap) {
7430     ierr = PetscPrintf(PetscObjectComm((PetscObject)dm), "Warning: DMPlexCheckPointSF() is currently not implemented for meshes with partition overlapping");
7431     PetscFunctionReturn(0);
7432   }
7433   if (!pointSF) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "This DMPlex is distributed but does not have PointSF attached");
7434   ierr = PetscSFGetGraph(pointSF, &nroots, &nleaves, &locals, NULL);CHKERRQ(ierr);
7435   if (nroots < 0) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "This DMPlex is distributed but its PointSF has no graph set");
7436   ierr = PetscSFComputeDegreeBegin(pointSF, &rootdegree);CHKERRQ(ierr);
7437   ierr = PetscSFComputeDegreeEnd(pointSF, &rootdegree);CHKERRQ(ierr);
7438 
7439   /* 1) check there are no faces in 2D, cells in 3D, in interface */
7440   ierr = DMPlexGetVTKCellHeight(dm, &cellHeight);CHKERRQ(ierr);
7441   ierr = DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd);CHKERRQ(ierr);
7442   for (l = 0; l < nleaves; ++l) {
7443     const PetscInt point = locals[l];
7444 
7445     if (point >= cStart && point < cEnd) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point SF contains %D which is a cell", point);
7446   }
7447 
7448   /* 2) if some point is in interface, then all its cone points must be also in interface (either as leaves or roots) */
7449   for (l = 0; l < nleaves; ++l) {
7450     const PetscInt  point = locals[l];
7451     const PetscInt *cone;
7452     PetscInt        coneSize, c, idx;
7453 
7454     ierr = DMPlexGetConeSize(dm, point, &coneSize);CHKERRQ(ierr);
7455     ierr = DMPlexGetCone(dm, point, &cone);CHKERRQ(ierr);
7456     for (c = 0; c < coneSize; ++c) {
7457       if (!rootdegree[cone[c]]) {
7458         ierr = PetscFindInt(cone[c], nleaves, locals, &idx);CHKERRQ(ierr);
7459         if (idx < 0) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point SF contains %D but not %D from its cone", point, cone[c]);
7460       }
7461     }
7462   }
7463   PetscFunctionReturn(0);
7464 }
7465 
7466 typedef struct cell_stats
7467 {
7468   PetscReal min, max, sum, squaresum;
7469   PetscInt  count;
7470 } cell_stats_t;
7471 
7472 static void MPIAPI cell_stats_reduce(void *a, void *b, int * len, MPI_Datatype *datatype)
7473 {
7474   PetscInt i, N = *len;
7475 
7476   for (i = 0; i < N; i++) {
7477     cell_stats_t *A = (cell_stats_t *) a;
7478     cell_stats_t *B = (cell_stats_t *) b;
7479 
7480     B->min = PetscMin(A->min,B->min);
7481     B->max = PetscMax(A->max,B->max);
7482     B->sum += A->sum;
7483     B->squaresum += A->squaresum;
7484     B->count += A->count;
7485   }
7486 }
7487 
7488 /*@
7489   DMPlexCheckCellShape - Checks the Jacobian of the mapping from reference to real cells and computes some minimal statistics.
7490 
7491   Collective on dm
7492 
7493   Input Parameters:
7494 + dm        - The DMPlex object
7495 . output    - If true, statistics will be displayed on stdout
7496 - condLimit - Display all cells above this condition number, or PETSC_DETERMINE for no cell output
7497 
7498   Notes:
7499   This is mainly intended for debugging/testing purposes.
7500 
7501   For the complete list of DMPlexCheck* functions, see DMSetFromOptions().
7502 
7503   Level: developer
7504 
7505 .seealso: DMSetFromOptions()
7506 @*/
7507 PetscErrorCode DMPlexCheckCellShape(DM dm, PetscBool output, PetscReal condLimit)
7508 {
7509   DM             dmCoarse;
7510   cell_stats_t   stats, globalStats;
7511   MPI_Comm       comm = PetscObjectComm((PetscObject)dm);
7512   PetscReal      *J, *invJ, min = 0, max = 0, mean = 0, stdev = 0;
7513   PetscReal      limit = condLimit > 0 ? condLimit : PETSC_MAX_REAL;
7514   PetscInt       cdim, cStart, cEnd, cMax, c, eStart, eEnd, count = 0;
7515   PetscMPIInt    rank,size;
7516   PetscErrorCode ierr;
7517 
7518   PetscFunctionBegin;
7519   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7520   stats.min   = PETSC_MAX_REAL;
7521   stats.max   = PETSC_MIN_REAL;
7522   stats.sum   = stats.squaresum = 0.;
7523   stats.count = 0;
7524 
7525   ierr = MPI_Comm_size(comm, &size);CHKERRQ(ierr);
7526   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
7527   ierr = DMGetCoordinateDim(dm,&cdim);CHKERRQ(ierr);
7528   ierr = PetscMalloc2(PetscSqr(cdim), &J, PetscSqr(cdim), &invJ);CHKERRQ(ierr);
7529   ierr = DMPlexGetHeightStratum(dm,0,&cStart,&cEnd);CHKERRQ(ierr);
7530   ierr = DMPlexGetDepthStratum(dm,1,&eStart,&eEnd);CHKERRQ(ierr);
7531   ierr = DMPlexGetHybridBounds(dm,&cMax,NULL,NULL,NULL);CHKERRQ(ierr);
7532   cMax = cMax < 0 ? cEnd : cMax;
7533   for (c = cStart; c < cMax; c++) {
7534     PetscInt  i;
7535     PetscReal frobJ = 0., frobInvJ = 0., cond2, cond, detJ;
7536 
7537     ierr = DMPlexComputeCellGeometryAffineFEM(dm,c,NULL,J,invJ,&detJ);CHKERRQ(ierr);
7538     if (detJ < 0.0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Mesh cell %D is inverted", c);
7539     for (i = 0; i < PetscSqr(cdim); ++i) {
7540       frobJ    += J[i] * J[i];
7541       frobInvJ += invJ[i] * invJ[i];
7542     }
7543     cond2 = frobJ * frobInvJ;
7544     cond  = PetscSqrtReal(cond2);
7545 
7546     stats.min        = PetscMin(stats.min,cond);
7547     stats.max        = PetscMax(stats.max,cond);
7548     stats.sum       += cond;
7549     stats.squaresum += cond2;
7550     stats.count++;
7551     if (output && cond > limit) {
7552       PetscSection coordSection;
7553       Vec          coordsLocal;
7554       PetscScalar *coords = NULL;
7555       PetscInt     Nv, d, clSize, cl, *closure = NULL;
7556 
7557       ierr = DMGetCoordinatesLocal(dm, &coordsLocal);CHKERRQ(ierr);
7558       ierr = DMGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
7559       ierr = DMPlexVecGetClosure(dm, coordSection, coordsLocal, c, &Nv, &coords);CHKERRQ(ierr);
7560       ierr = PetscSynchronizedPrintf(comm, "[%d] Cell %D cond %g\n", rank, c, (double) cond);CHKERRQ(ierr);
7561       for (i = 0; i < Nv/cdim; ++i) {
7562         ierr = PetscSynchronizedPrintf(comm, "  Vertex %D: (", i);CHKERRQ(ierr);
7563         for (d = 0; d < cdim; ++d) {
7564           if (d > 0) {ierr = PetscSynchronizedPrintf(comm, ", ");CHKERRQ(ierr);}
7565           ierr = PetscSynchronizedPrintf(comm, "%g", (double) PetscRealPart(coords[i*cdim+d]));CHKERRQ(ierr);
7566         }
7567         ierr = PetscSynchronizedPrintf(comm, ")\n");CHKERRQ(ierr);
7568       }
7569       ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &clSize, &closure);CHKERRQ(ierr);
7570       for (cl = 0; cl < clSize*2; cl += 2) {
7571         const PetscInt edge = closure[cl];
7572 
7573         if ((edge >= eStart) && (edge < eEnd)) {
7574           PetscReal len;
7575 
7576           ierr = DMPlexComputeCellGeometryFVM(dm, edge, &len, NULL, NULL);CHKERRQ(ierr);
7577           ierr = PetscSynchronizedPrintf(comm, "  Edge %D: length %g\n", edge, (double) len);CHKERRQ(ierr);
7578         }
7579       }
7580       ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &clSize, &closure);CHKERRQ(ierr);
7581       ierr = DMPlexVecRestoreClosure(dm, coordSection, coordsLocal, c, &Nv, &coords);CHKERRQ(ierr);
7582     }
7583   }
7584   if (output) {ierr = PetscSynchronizedFlush(comm, NULL);CHKERRQ(ierr);}
7585 
7586   if (size > 1) {
7587     PetscMPIInt   blockLengths[2] = {4,1};
7588     MPI_Aint      blockOffsets[2] = {offsetof(cell_stats_t,min),offsetof(cell_stats_t,count)};
7589     MPI_Datatype  blockTypes[2]   = {MPIU_REAL,MPIU_INT}, statType;
7590     MPI_Op        statReduce;
7591 
7592     ierr = MPI_Type_create_struct(2,blockLengths,blockOffsets,blockTypes,&statType);CHKERRQ(ierr);
7593     ierr = MPI_Type_commit(&statType);CHKERRQ(ierr);
7594     ierr = MPI_Op_create(cell_stats_reduce, PETSC_TRUE, &statReduce);CHKERRQ(ierr);
7595     ierr = MPI_Reduce(&stats,&globalStats,1,statType,statReduce,0,comm);CHKERRQ(ierr);
7596     ierr = MPI_Op_free(&statReduce);CHKERRQ(ierr);
7597     ierr = MPI_Type_free(&statType);CHKERRQ(ierr);
7598   } else {
7599     ierr = PetscArraycpy(&globalStats,&stats,1);CHKERRQ(ierr);
7600   }
7601   if (!rank) {
7602     count = globalStats.count;
7603     min   = globalStats.min;
7604     max   = globalStats.max;
7605     mean  = globalStats.sum / globalStats.count;
7606     stdev = globalStats.count > 1 ? PetscSqrtReal(PetscMax((globalStats.squaresum - globalStats.count * mean * mean) / (globalStats.count - 1),0)) : 0.0;
7607   }
7608 
7609   if (output) {
7610     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);
7611   }
7612   ierr = PetscFree2(J,invJ);CHKERRQ(ierr);
7613 
7614   ierr = DMGetCoarseDM(dm,&dmCoarse);CHKERRQ(ierr);
7615   if (dmCoarse) {
7616     PetscBool isplex;
7617 
7618     ierr = PetscObjectTypeCompare((PetscObject)dmCoarse,DMPLEX,&isplex);CHKERRQ(ierr);
7619     if (isplex) {
7620       ierr = DMPlexCheckCellShape(dmCoarse,output,condLimit);CHKERRQ(ierr);
7621     }
7622   }
7623   PetscFunctionReturn(0);
7624 }
7625 
7626 /* Pointwise interpolation
7627      Just code FEM for now
7628      u^f = I u^c
7629      sum_k u^f_k phi^f_k = I sum_j u^c_j phi^c_j
7630      u^f_i = sum_j psi^f_i I phi^c_j u^c_j
7631      I_{ij} = psi^f_i phi^c_j
7632 */
7633 PetscErrorCode DMCreateInterpolation_Plex(DM dmCoarse, DM dmFine, Mat *interpolation, Vec *scaling)
7634 {
7635   PetscSection   gsc, gsf;
7636   PetscInt       m, n;
7637   void          *ctx;
7638   DM             cdm;
7639   PetscBool      regular, ismatis;
7640   PetscErrorCode ierr;
7641 
7642   PetscFunctionBegin;
7643   ierr = DMGetGlobalSection(dmFine, &gsf);CHKERRQ(ierr);
7644   ierr = PetscSectionGetConstrainedStorageSize(gsf, &m);CHKERRQ(ierr);
7645   ierr = DMGetGlobalSection(dmCoarse, &gsc);CHKERRQ(ierr);
7646   ierr = PetscSectionGetConstrainedStorageSize(gsc, &n);CHKERRQ(ierr);
7647 
7648   ierr = PetscStrcmp(dmCoarse->mattype, MATIS, &ismatis);CHKERRQ(ierr);
7649   ierr = MatCreate(PetscObjectComm((PetscObject) dmCoarse), interpolation);CHKERRQ(ierr);
7650   ierr = MatSetSizes(*interpolation, m, n, PETSC_DETERMINE, PETSC_DETERMINE);CHKERRQ(ierr);
7651   ierr = MatSetType(*interpolation, ismatis ? MATAIJ : dmCoarse->mattype);CHKERRQ(ierr);
7652   ierr = DMGetApplicationContext(dmFine, &ctx);CHKERRQ(ierr);
7653 
7654   ierr = DMGetCoarseDM(dmFine, &cdm);CHKERRQ(ierr);
7655   ierr = DMPlexGetRegularRefinement(dmFine, &regular);CHKERRQ(ierr);
7656   if (regular && cdm == dmCoarse) {ierr = DMPlexComputeInterpolatorNested(dmCoarse, dmFine, *interpolation, ctx);CHKERRQ(ierr);}
7657   else                            {ierr = DMPlexComputeInterpolatorGeneral(dmCoarse, dmFine, *interpolation, ctx);CHKERRQ(ierr);}
7658   ierr = MatViewFromOptions(*interpolation, NULL, "-interp_mat_view");CHKERRQ(ierr);
7659   if (scaling) {
7660     /* Use naive scaling */
7661     ierr = DMCreateInterpolationScale(dmCoarse, dmFine, *interpolation, scaling);CHKERRQ(ierr);
7662   }
7663   PetscFunctionReturn(0);
7664 }
7665 
7666 PetscErrorCode DMCreateInjection_Plex(DM dmCoarse, DM dmFine, Mat *mat)
7667 {
7668   PetscErrorCode ierr;
7669   VecScatter     ctx;
7670 
7671   PetscFunctionBegin;
7672   ierr = DMPlexComputeInjectorFEM(dmCoarse, dmFine, &ctx, NULL);CHKERRQ(ierr);
7673   ierr = MatCreateScatter(PetscObjectComm((PetscObject)ctx), ctx, mat);CHKERRQ(ierr);
7674   ierr = VecScatterDestroy(&ctx);CHKERRQ(ierr);
7675   PetscFunctionReturn(0);
7676 }
7677 
7678 PetscErrorCode DMCreateMassMatrix_Plex(DM dmCoarse, DM dmFine, Mat *mass)
7679 {
7680   PetscSection   gsc, gsf;
7681   PetscInt       m, n;
7682   void          *ctx;
7683   DM             cdm;
7684   PetscBool      regular;
7685   PetscErrorCode ierr;
7686 
7687   PetscFunctionBegin;
7688   ierr = DMGetGlobalSection(dmFine, &gsf);CHKERRQ(ierr);
7689   ierr = PetscSectionGetConstrainedStorageSize(gsf, &m);CHKERRQ(ierr);
7690   ierr = DMGetGlobalSection(dmCoarse, &gsc);CHKERRQ(ierr);
7691   ierr = PetscSectionGetConstrainedStorageSize(gsc, &n);CHKERRQ(ierr);
7692 
7693   ierr = MatCreate(PetscObjectComm((PetscObject) dmCoarse), mass);CHKERRQ(ierr);
7694   ierr = MatSetSizes(*mass, m, n, PETSC_DETERMINE, PETSC_DETERMINE);CHKERRQ(ierr);
7695   ierr = MatSetType(*mass, dmCoarse->mattype);CHKERRQ(ierr);
7696   ierr = DMGetApplicationContext(dmFine, &ctx);CHKERRQ(ierr);
7697 
7698   ierr = DMGetCoarseDM(dmFine, &cdm);CHKERRQ(ierr);
7699   ierr = DMPlexGetRegularRefinement(dmFine, &regular);CHKERRQ(ierr);
7700   if (regular && cdm == dmCoarse) {ierr = DMPlexComputeMassMatrixNested(dmCoarse, dmFine, *mass, ctx);CHKERRQ(ierr);}
7701   else                            {ierr = DMPlexComputeMassMatrixGeneral(dmCoarse, dmFine, *mass, ctx);CHKERRQ(ierr);}
7702   ierr = MatViewFromOptions(*mass, NULL, "-mass_mat_view");CHKERRQ(ierr);
7703   PetscFunctionReturn(0);
7704 }
7705 
7706 /*@
7707   DMPlexGetRegularRefinement - Get the flag indicating that this mesh was obtained by regular refinement from its coarse mesh
7708 
7709   Input Parameter:
7710 . dm - The DMPlex object
7711 
7712   Output Parameter:
7713 . regular - The flag
7714 
7715   Level: intermediate
7716 
7717 .seealso: DMPlexSetRegularRefinement()
7718 @*/
7719 PetscErrorCode DMPlexGetRegularRefinement(DM dm, PetscBool *regular)
7720 {
7721   PetscFunctionBegin;
7722   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7723   PetscValidPointer(regular, 2);
7724   *regular = ((DM_Plex *) dm->data)->regularRefinement;
7725   PetscFunctionReturn(0);
7726 }
7727 
7728 /*@
7729   DMPlexSetRegularRefinement - Set the flag indicating that this mesh was obtained by regular refinement from its coarse mesh
7730 
7731   Input Parameters:
7732 + dm - The DMPlex object
7733 - regular - The flag
7734 
7735   Level: intermediate
7736 
7737 .seealso: DMPlexGetRegularRefinement()
7738 @*/
7739 PetscErrorCode DMPlexSetRegularRefinement(DM dm, PetscBool regular)
7740 {
7741   PetscFunctionBegin;
7742   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7743   ((DM_Plex *) dm->data)->regularRefinement = regular;
7744   PetscFunctionReturn(0);
7745 }
7746 
7747 /* anchors */
7748 /*@
7749   DMPlexGetAnchors - Get the layout of the anchor (point-to-point) constraints.  Typically, the user will not have to
7750   call DMPlexGetAnchors() directly: if there are anchors, then DMPlexGetAnchors() is called during DMGetConstraints().
7751 
7752   not collective
7753 
7754   Input Parameters:
7755 . dm - The DMPlex object
7756 
7757   Output Parameters:
7758 + anchorSection - If not NULL, set to the section describing which points anchor the constrained points.
7759 - anchorIS - If not NULL, set to the list of anchors indexed by anchorSection
7760 
7761 
7762   Level: intermediate
7763 
7764 .seealso: DMPlexSetAnchors(), DMGetConstraints(), DMSetConstraints()
7765 @*/
7766 PetscErrorCode DMPlexGetAnchors(DM dm, PetscSection *anchorSection, IS *anchorIS)
7767 {
7768   DM_Plex *plex = (DM_Plex *)dm->data;
7769   PetscErrorCode ierr;
7770 
7771   PetscFunctionBegin;
7772   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7773   if (!plex->anchorSection && !plex->anchorIS && plex->createanchors) {ierr = (*plex->createanchors)(dm);CHKERRQ(ierr);}
7774   if (anchorSection) *anchorSection = plex->anchorSection;
7775   if (anchorIS) *anchorIS = plex->anchorIS;
7776   PetscFunctionReturn(0);
7777 }
7778 
7779 /*@
7780   DMPlexSetAnchors - Set the layout of the local anchor (point-to-point) constraints.  Unlike boundary conditions,
7781   when a point's degrees of freedom in a section are constrained to an outside value, the anchor constraints set a
7782   point's degrees of freedom to be a linear combination of other points' degrees of freedom.
7783 
7784   After specifying the layout of constraints with DMPlexSetAnchors(), one specifies the constraints by calling
7785   DMGetConstraints() and filling in the entries in the constraint matrix.
7786 
7787   collective on dm
7788 
7789   Input Parameters:
7790 + dm - The DMPlex object
7791 . 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).
7792 - anchorIS - The list of all anchor points.  Must have a local communicator (PETSC_COMM_SELF or derivative).
7793 
7794   The reference counts of anchorSection and anchorIS are incremented.
7795 
7796   Level: intermediate
7797 
7798 .seealso: DMPlexGetAnchors(), DMGetConstraints(), DMSetConstraints()
7799 @*/
7800 PetscErrorCode DMPlexSetAnchors(DM dm, PetscSection anchorSection, IS anchorIS)
7801 {
7802   DM_Plex        *plex = (DM_Plex *)dm->data;
7803   PetscMPIInt    result;
7804   PetscErrorCode ierr;
7805 
7806   PetscFunctionBegin;
7807   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7808   if (anchorSection) {
7809     PetscValidHeaderSpecific(anchorSection,PETSC_SECTION_CLASSID,2);
7810     ierr = MPI_Comm_compare(PETSC_COMM_SELF,PetscObjectComm((PetscObject)anchorSection),&result);CHKERRQ(ierr);
7811     if (result != MPI_CONGRUENT && result != MPI_IDENT) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_NOTSAMECOMM,"anchor section must have local communicator");
7812   }
7813   if (anchorIS) {
7814     PetscValidHeaderSpecific(anchorIS,IS_CLASSID,3);
7815     ierr = MPI_Comm_compare(PETSC_COMM_SELF,PetscObjectComm((PetscObject)anchorIS),&result);CHKERRQ(ierr);
7816     if (result != MPI_CONGRUENT && result != MPI_IDENT) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_NOTSAMECOMM,"anchor IS must have local communicator");
7817   }
7818 
7819   ierr = PetscObjectReference((PetscObject)anchorSection);CHKERRQ(ierr);
7820   ierr = PetscSectionDestroy(&plex->anchorSection);CHKERRQ(ierr);
7821   plex->anchorSection = anchorSection;
7822 
7823   ierr = PetscObjectReference((PetscObject)anchorIS);CHKERRQ(ierr);
7824   ierr = ISDestroy(&plex->anchorIS);CHKERRQ(ierr);
7825   plex->anchorIS = anchorIS;
7826 
7827 #if defined(PETSC_USE_DEBUG)
7828   if (anchorIS && anchorSection) {
7829     PetscInt size, a, pStart, pEnd;
7830     const PetscInt *anchors;
7831 
7832     ierr = PetscSectionGetChart(anchorSection,&pStart,&pEnd);CHKERRQ(ierr);
7833     ierr = ISGetLocalSize(anchorIS,&size);CHKERRQ(ierr);
7834     ierr = ISGetIndices(anchorIS,&anchors);CHKERRQ(ierr);
7835     for (a = 0; a < size; a++) {
7836       PetscInt p;
7837 
7838       p = anchors[a];
7839       if (p >= pStart && p < pEnd) {
7840         PetscInt dof;
7841 
7842         ierr = PetscSectionGetDof(anchorSection,p,&dof);CHKERRQ(ierr);
7843         if (dof) {
7844           PetscErrorCode ierr2;
7845 
7846           ierr2 = ISRestoreIndices(anchorIS,&anchors);CHKERRQ(ierr2);
7847           SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Point %D cannot be constrained and an anchor",p);
7848         }
7849       }
7850     }
7851     ierr = ISRestoreIndices(anchorIS,&anchors);CHKERRQ(ierr);
7852   }
7853 #endif
7854   /* reset the generic constraints */
7855   ierr = DMSetDefaultConstraints(dm,NULL,NULL);CHKERRQ(ierr);
7856   PetscFunctionReturn(0);
7857 }
7858 
7859 static PetscErrorCode DMPlexCreateConstraintSection_Anchors(DM dm, PetscSection section, PetscSection *cSec)
7860 {
7861   PetscSection anchorSection;
7862   PetscInt pStart, pEnd, sStart, sEnd, p, dof, numFields, f;
7863   PetscErrorCode ierr;
7864 
7865   PetscFunctionBegin;
7866   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7867   ierr = DMPlexGetAnchors(dm,&anchorSection,NULL);CHKERRQ(ierr);
7868   ierr = PetscSectionCreate(PETSC_COMM_SELF,cSec);CHKERRQ(ierr);
7869   ierr = PetscSectionGetNumFields(section,&numFields);CHKERRQ(ierr);
7870   if (numFields) {
7871     PetscInt f;
7872     ierr = PetscSectionSetNumFields(*cSec,numFields);CHKERRQ(ierr);
7873 
7874     for (f = 0; f < numFields; f++) {
7875       PetscInt numComp;
7876 
7877       ierr = PetscSectionGetFieldComponents(section,f,&numComp);CHKERRQ(ierr);
7878       ierr = PetscSectionSetFieldComponents(*cSec,f,numComp);CHKERRQ(ierr);
7879     }
7880   }
7881   ierr = PetscSectionGetChart(anchorSection,&pStart,&pEnd);CHKERRQ(ierr);
7882   ierr = PetscSectionGetChart(section,&sStart,&sEnd);CHKERRQ(ierr);
7883   pStart = PetscMax(pStart,sStart);
7884   pEnd   = PetscMin(pEnd,sEnd);
7885   pEnd   = PetscMax(pStart,pEnd);
7886   ierr = PetscSectionSetChart(*cSec,pStart,pEnd);CHKERRQ(ierr);
7887   for (p = pStart; p < pEnd; p++) {
7888     ierr = PetscSectionGetDof(anchorSection,p,&dof);CHKERRQ(ierr);
7889     if (dof) {
7890       ierr = PetscSectionGetDof(section,p,&dof);CHKERRQ(ierr);
7891       ierr = PetscSectionSetDof(*cSec,p,dof);CHKERRQ(ierr);
7892       for (f = 0; f < numFields; f++) {
7893         ierr = PetscSectionGetFieldDof(section,p,f,&dof);CHKERRQ(ierr);
7894         ierr = PetscSectionSetFieldDof(*cSec,p,f,dof);CHKERRQ(ierr);
7895       }
7896     }
7897   }
7898   ierr = PetscSectionSetUp(*cSec);CHKERRQ(ierr);
7899   PetscFunctionReturn(0);
7900 }
7901 
7902 static PetscErrorCode DMPlexCreateConstraintMatrix_Anchors(DM dm, PetscSection section, PetscSection cSec, Mat *cMat)
7903 {
7904   PetscSection aSec;
7905   PetscInt pStart, pEnd, p, dof, aDof, aOff, off, nnz, annz, m, n, q, a, offset, *i, *j;
7906   const PetscInt *anchors;
7907   PetscInt numFields, f;
7908   IS aIS;
7909   PetscErrorCode ierr;
7910 
7911   PetscFunctionBegin;
7912   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7913   ierr = PetscSectionGetStorageSize(cSec, &m);CHKERRQ(ierr);
7914   ierr = PetscSectionGetStorageSize(section, &n);CHKERRQ(ierr);
7915   ierr = MatCreate(PETSC_COMM_SELF,cMat);CHKERRQ(ierr);
7916   ierr = MatSetSizes(*cMat,m,n,m,n);CHKERRQ(ierr);
7917   ierr = MatSetType(*cMat,MATSEQAIJ);CHKERRQ(ierr);
7918   ierr = DMPlexGetAnchors(dm,&aSec,&aIS);CHKERRQ(ierr);
7919   ierr = ISGetIndices(aIS,&anchors);CHKERRQ(ierr);
7920   /* cSec will be a subset of aSec and section */
7921   ierr = PetscSectionGetChart(cSec,&pStart,&pEnd);CHKERRQ(ierr);
7922   ierr = PetscMalloc1(m+1,&i);CHKERRQ(ierr);
7923   i[0] = 0;
7924   ierr = PetscSectionGetNumFields(section,&numFields);CHKERRQ(ierr);
7925   for (p = pStart; p < pEnd; p++) {
7926     PetscInt rDof, rOff, r;
7927 
7928     ierr = PetscSectionGetDof(aSec,p,&rDof);CHKERRQ(ierr);
7929     if (!rDof) continue;
7930     ierr = PetscSectionGetOffset(aSec,p,&rOff);CHKERRQ(ierr);
7931     if (numFields) {
7932       for (f = 0; f < numFields; f++) {
7933         annz = 0;
7934         for (r = 0; r < rDof; r++) {
7935           a = anchors[rOff + r];
7936           ierr = PetscSectionGetFieldDof(section,a,f,&aDof);CHKERRQ(ierr);
7937           annz += aDof;
7938         }
7939         ierr = PetscSectionGetFieldDof(cSec,p,f,&dof);CHKERRQ(ierr);
7940         ierr = PetscSectionGetFieldOffset(cSec,p,f,&off);CHKERRQ(ierr);
7941         for (q = 0; q < dof; q++) {
7942           i[off + q + 1] = i[off + q] + annz;
7943         }
7944       }
7945     }
7946     else {
7947       annz = 0;
7948       for (q = 0; q < dof; q++) {
7949         a = anchors[off + q];
7950         ierr = PetscSectionGetDof(section,a,&aDof);CHKERRQ(ierr);
7951         annz += aDof;
7952       }
7953       ierr = PetscSectionGetDof(cSec,p,&dof);CHKERRQ(ierr);
7954       ierr = PetscSectionGetOffset(cSec,p,&off);CHKERRQ(ierr);
7955       for (q = 0; q < dof; q++) {
7956         i[off + q + 1] = i[off + q] + annz;
7957       }
7958     }
7959   }
7960   nnz = i[m];
7961   ierr = PetscMalloc1(nnz,&j);CHKERRQ(ierr);
7962   offset = 0;
7963   for (p = pStart; p < pEnd; p++) {
7964     if (numFields) {
7965       for (f = 0; f < numFields; f++) {
7966         ierr = PetscSectionGetFieldDof(cSec,p,f,&dof);CHKERRQ(ierr);
7967         for (q = 0; q < dof; q++) {
7968           PetscInt rDof, rOff, r;
7969           ierr = PetscSectionGetDof(aSec,p,&rDof);CHKERRQ(ierr);
7970           ierr = PetscSectionGetOffset(aSec,p,&rOff);CHKERRQ(ierr);
7971           for (r = 0; r < rDof; r++) {
7972             PetscInt s;
7973 
7974             a = anchors[rOff + r];
7975             ierr = PetscSectionGetFieldDof(section,a,f,&aDof);CHKERRQ(ierr);
7976             ierr = PetscSectionGetFieldOffset(section,a,f,&aOff);CHKERRQ(ierr);
7977             for (s = 0; s < aDof; s++) {
7978               j[offset++] = aOff + s;
7979             }
7980           }
7981         }
7982       }
7983     }
7984     else {
7985       ierr = PetscSectionGetDof(cSec,p,&dof);CHKERRQ(ierr);
7986       for (q = 0; q < dof; q++) {
7987         PetscInt rDof, rOff, r;
7988         ierr = PetscSectionGetDof(aSec,p,&rDof);CHKERRQ(ierr);
7989         ierr = PetscSectionGetOffset(aSec,p,&rOff);CHKERRQ(ierr);
7990         for (r = 0; r < rDof; r++) {
7991           PetscInt s;
7992 
7993           a = anchors[rOff + r];
7994           ierr = PetscSectionGetDof(section,a,&aDof);CHKERRQ(ierr);
7995           ierr = PetscSectionGetOffset(section,a,&aOff);CHKERRQ(ierr);
7996           for (s = 0; s < aDof; s++) {
7997             j[offset++] = aOff + s;
7998           }
7999         }
8000       }
8001     }
8002   }
8003   ierr = MatSeqAIJSetPreallocationCSR(*cMat,i,j,NULL);CHKERRQ(ierr);
8004   ierr = PetscFree(i);CHKERRQ(ierr);
8005   ierr = PetscFree(j);CHKERRQ(ierr);
8006   ierr = ISRestoreIndices(aIS,&anchors);CHKERRQ(ierr);
8007   PetscFunctionReturn(0);
8008 }
8009 
8010 PetscErrorCode DMCreateDefaultConstraints_Plex(DM dm)
8011 {
8012   DM_Plex        *plex = (DM_Plex *)dm->data;
8013   PetscSection   anchorSection, section, cSec;
8014   Mat            cMat;
8015   PetscErrorCode ierr;
8016 
8017   PetscFunctionBegin;
8018   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8019   ierr = DMPlexGetAnchors(dm,&anchorSection,NULL);CHKERRQ(ierr);
8020   if (anchorSection) {
8021     PetscInt Nf;
8022 
8023     ierr = DMGetLocalSection(dm,&section);CHKERRQ(ierr);
8024     ierr = DMPlexCreateConstraintSection_Anchors(dm,section,&cSec);CHKERRQ(ierr);
8025     ierr = DMPlexCreateConstraintMatrix_Anchors(dm,section,cSec,&cMat);CHKERRQ(ierr);
8026     ierr = DMGetNumFields(dm,&Nf);CHKERRQ(ierr);
8027     if (Nf && plex->computeanchormatrix) {ierr = (*plex->computeanchormatrix)(dm,section,cSec,cMat);CHKERRQ(ierr);}
8028     ierr = DMSetDefaultConstraints(dm,cSec,cMat);CHKERRQ(ierr);
8029     ierr = PetscSectionDestroy(&cSec);CHKERRQ(ierr);
8030     ierr = MatDestroy(&cMat);CHKERRQ(ierr);
8031   }
8032   PetscFunctionReturn(0);
8033 }
8034 
8035 PetscErrorCode DMCreateSubDomainDM_Plex(DM dm, DMLabel label, PetscInt value, IS *is, DM *subdm)
8036 {
8037   IS             subis;
8038   PetscSection   section, subsection;
8039   PetscErrorCode ierr;
8040 
8041   PetscFunctionBegin;
8042   ierr = DMGetLocalSection(dm, &section);CHKERRQ(ierr);
8043   if (!section) SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "Must set default section for DM before splitting subdomain");
8044   if (!subdm)   SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "Must set output subDM for splitting subdomain");
8045   /* Create subdomain */
8046   ierr = DMPlexFilter(dm, label, value, subdm);CHKERRQ(ierr);
8047   /* Create submodel */
8048   ierr = DMPlexCreateSubpointIS(*subdm, &subis);CHKERRQ(ierr);
8049   ierr = PetscSectionCreateSubmeshSection(section, subis, &subsection);CHKERRQ(ierr);
8050   ierr = ISDestroy(&subis);CHKERRQ(ierr);
8051   ierr = DMSetLocalSection(*subdm, subsection);CHKERRQ(ierr);
8052   ierr = PetscSectionDestroy(&subsection);CHKERRQ(ierr);
8053   ierr = DMCopyDisc(dm, *subdm);CHKERRQ(ierr);
8054   /* Create map from submodel to global model */
8055   if (is) {
8056     PetscSection    sectionGlobal, subsectionGlobal;
8057     IS              spIS;
8058     const PetscInt *spmap;
8059     PetscInt       *subIndices;
8060     PetscInt        subSize = 0, subOff = 0, pStart, pEnd, p;
8061     PetscInt        Nf, f, bs = -1, bsLocal[2], bsMinMax[2];
8062 
8063     ierr = DMPlexCreateSubpointIS(*subdm, &spIS);CHKERRQ(ierr);
8064     ierr = ISGetIndices(spIS, &spmap);CHKERRQ(ierr);
8065     ierr = PetscSectionGetNumFields(section, &Nf);CHKERRQ(ierr);
8066     ierr = DMGetGlobalSection(dm, &sectionGlobal);CHKERRQ(ierr);
8067     ierr = DMGetGlobalSection(*subdm, &subsectionGlobal);CHKERRQ(ierr);
8068     ierr = PetscSectionGetChart(subsection, &pStart, &pEnd);CHKERRQ(ierr);
8069     for (p = pStart; p < pEnd; ++p) {
8070       PetscInt gdof, pSubSize  = 0;
8071 
8072       ierr = PetscSectionGetDof(sectionGlobal, p, &gdof);CHKERRQ(ierr);
8073       if (gdof > 0) {
8074         for (f = 0; f < Nf; ++f) {
8075           PetscInt fdof, fcdof;
8076 
8077           ierr     = PetscSectionGetFieldDof(subsection, p, f, &fdof);CHKERRQ(ierr);
8078           ierr     = PetscSectionGetFieldConstraintDof(subsection, p, f, &fcdof);CHKERRQ(ierr);
8079           pSubSize += fdof-fcdof;
8080         }
8081         subSize += pSubSize;
8082         if (pSubSize) {
8083           if (bs < 0) {
8084             bs = pSubSize;
8085           } else if (bs != pSubSize) {
8086             /* Layout does not admit a pointwise block size */
8087             bs = 1;
8088           }
8089         }
8090       }
8091     }
8092     /* Must have same blocksize on all procs (some might have no points) */
8093     bsLocal[0] = bs < 0 ? PETSC_MAX_INT : bs; bsLocal[1] = bs;
8094     ierr = PetscGlobalMinMaxInt(PetscObjectComm((PetscObject) dm), bsLocal, bsMinMax);CHKERRQ(ierr);
8095     if (bsMinMax[0] != bsMinMax[1]) {bs = 1;}
8096     else                            {bs = bsMinMax[0];}
8097     ierr = PetscMalloc1(subSize, &subIndices);CHKERRQ(ierr);
8098     for (p = pStart; p < pEnd; ++p) {
8099       PetscInt gdof, goff;
8100 
8101       ierr = PetscSectionGetDof(subsectionGlobal, p, &gdof);CHKERRQ(ierr);
8102       if (gdof > 0) {
8103         const PetscInt point = spmap[p];
8104 
8105         ierr = PetscSectionGetOffset(sectionGlobal, point, &goff);CHKERRQ(ierr);
8106         for (f = 0; f < Nf; ++f) {
8107           PetscInt fdof, fcdof, fc, f2, poff = 0;
8108 
8109           /* Can get rid of this loop by storing field information in the global section */
8110           for (f2 = 0; f2 < f; ++f2) {
8111             ierr  = PetscSectionGetFieldDof(section, p, f2, &fdof);CHKERRQ(ierr);
8112             ierr  = PetscSectionGetFieldConstraintDof(section, p, f2, &fcdof);CHKERRQ(ierr);
8113             poff += fdof-fcdof;
8114           }
8115           ierr = PetscSectionGetFieldDof(section, p, f, &fdof);CHKERRQ(ierr);
8116           ierr = PetscSectionGetFieldConstraintDof(section, p, f, &fcdof);CHKERRQ(ierr);
8117           for (fc = 0; fc < fdof-fcdof; ++fc, ++subOff) {
8118             subIndices[subOff] = goff+poff+fc;
8119           }
8120         }
8121       }
8122     }
8123     ierr = ISRestoreIndices(spIS, &spmap);CHKERRQ(ierr);
8124     ierr = ISDestroy(&spIS);CHKERRQ(ierr);
8125     ierr = ISCreateGeneral(PetscObjectComm((PetscObject)dm), subSize, subIndices, PETSC_OWN_POINTER, is);CHKERRQ(ierr);
8126     if (bs > 1) {
8127       /* We need to check that the block size does not come from non-contiguous fields */
8128       PetscInt i, j, set = 1;
8129       for (i = 0; i < subSize; i += bs) {
8130         for (j = 0; j < bs; ++j) {
8131           if (subIndices[i+j] != subIndices[i]+j) {set = 0; break;}
8132         }
8133       }
8134       if (set) {ierr = ISSetBlockSize(*is, bs);CHKERRQ(ierr);}
8135     }
8136     /* Attach nullspace */
8137     for (f = 0; f < Nf; ++f) {
8138       (*subdm)->nullspaceConstructors[f] = dm->nullspaceConstructors[f];
8139       if ((*subdm)->nullspaceConstructors[f]) break;
8140     }
8141     if (f < Nf) {
8142       MatNullSpace nullSpace;
8143 
8144       ierr = (*(*subdm)->nullspaceConstructors[f])(*subdm, f, &nullSpace);CHKERRQ(ierr);
8145       ierr = PetscObjectCompose((PetscObject) *is, "nullspace", (PetscObject) nullSpace);CHKERRQ(ierr);
8146       ierr = MatNullSpaceDestroy(&nullSpace);CHKERRQ(ierr);
8147     }
8148   }
8149   PetscFunctionReturn(0);
8150 }
8151 
8152 /*@
8153   DMPlexMonitorThroughput - Report the cell throughput of FE integration
8154 
8155   Input Parameter:
8156 - dm - The DM
8157 
8158   Level: developer
8159 
8160   Options Database Keys:
8161 . -dm_plex_monitor_throughput - Activate the monitor
8162 
8163 .seealso: DMSetFromOptions(), DMPlexCreate()
8164 @*/
8165 PetscErrorCode DMPlexMonitorThroughput(DM dm, void *dummy)
8166 {
8167   PetscStageLog      stageLog;
8168   PetscLogEvent      event;
8169   PetscLogStage      stage;
8170   PetscEventPerfInfo eventInfo;
8171   PetscReal          cellRate, flopRate;
8172   PetscInt           cStart, cEnd, Nf, N;
8173   const char        *name;
8174   PetscErrorCode     ierr;
8175 
8176   PetscFunctionBegin;
8177   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8178 #if defined(PETSC_USE_LOG)
8179   ierr = PetscObjectGetName((PetscObject) dm, &name);CHKERRQ(ierr);
8180   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
8181   ierr = DMGetNumFields(dm, &Nf);CHKERRQ(ierr);
8182   ierr = PetscLogGetStageLog(&stageLog);CHKERRQ(ierr);
8183   ierr = PetscStageLogGetCurrent(stageLog, &stage);CHKERRQ(ierr);
8184   ierr = PetscLogEventGetId("DMPlexResidualFE", &event);CHKERRQ(ierr);
8185   ierr = PetscLogEventGetPerfInfo(stage, event, &eventInfo);CHKERRQ(ierr);
8186   N        = (cEnd - cStart)*Nf*eventInfo.count;
8187   flopRate = eventInfo.flops/eventInfo.time;
8188   cellRate = N/eventInfo.time;
8189   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);
8190 #else
8191   SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Plex Throughput Monitor is not supported if logging is turned off. Reconfigure using --with-log.");
8192 #endif
8193   PetscFunctionReturn(0);
8194 }
8195