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