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