xref: /petsc/src/dm/impls/plex/plex.c (revision 3e97647f96cfecc0467a6b8acb3ad3cbc6af9145)
1 #include <petsc/private/dmpleximpl.h>   /*I      "petscdmplex.h"   I*/
2 #include <petsc/private/isimpl.h>
3 #include <petsc/private/vecimpl.h>
4 #include <petsc/private/glvisvecimpl.h>
5 #include <petscsf.h>
6 #include <petscds.h>
7 #include <petscdraw.h>
8 #include <petscdmfield.h>
9 
10 /* Logging support */
11 PetscLogEvent DMPLEX_Interpolate, DMPLEX_Partition, DMPLEX_Distribute, DMPLEX_DistributeCones, DMPLEX_DistributeLabels, DMPLEX_DistributeSF, DMPLEX_DistributeOverlap, DMPLEX_DistributeField, DMPLEX_DistributeData, DMPLEX_Migrate, DMPLEX_InterpolateSF, DMPLEX_GlobalToNaturalBegin, DMPLEX_GlobalToNaturalEnd, DMPLEX_NaturalToGlobalBegin, DMPLEX_NaturalToGlobalEnd, DMPLEX_Stratify, DMPLEX_Symmetrize, DMPLEX_Preallocate, DMPLEX_ResidualFEM, DMPLEX_JacobianFEM, DMPLEX_InterpolatorFEM, DMPLEX_InjectorFEM, DMPLEX_IntegralFEM, DMPLEX_CreateGmsh, DMPLEX_RebalanceSharedPoints, DMPLEX_PartSelf, DMPLEX_PartLabelInvert, DMPLEX_PartLabelCreateSF, DMPLEX_PartStratSF, DMPLEX_CreatePointSF,DMPLEX_LocatePoints;
12 
13 PETSC_EXTERN PetscErrorCode VecView_MPI(Vec, PetscViewer);
14 
15 /*@
16   DMPlexIsSimplex - Is the first cell in this mesh a simplex?
17 
18   Input Parameter:
19 . dm      - The DMPlex object
20 
21   Output Parameter:
22 . simplex - Flag checking for a simplex
23 
24   Note: This just gives the first range of cells found. If the mesh has several cell types, it will only give the first.
25   If the mesh has no cells, this returns PETSC_FALSE.
26 
27   Level: intermediate
28 
29 .seealso DMPlexGetSimplexOrBoxCells(), DMPlexGetCellType(), DMPlexGetHeightStratum(), DMPolytopeTypeGetNumVertices()
30 @*/
31 PetscErrorCode DMPlexIsSimplex(DM dm, PetscBool *simplex)
32 {
33   DMPolytopeType ct;
34   PetscInt       cStart, cEnd;
35   PetscErrorCode ierr;
36 
37   PetscFunctionBegin;
38   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
39   if (cEnd <= cStart) {*simplex = PETSC_FALSE; PetscFunctionReturn(0);}
40   ierr = DMPlexGetCellType(dm, cStart, &ct);CHKERRQ(ierr);
41   *simplex = DMPolytopeTypeGetNumVertices(ct) == DMPolytopeTypeGetDim(ct)+1 ? PETSC_TRUE : PETSC_FALSE;
42   PetscFunctionReturn(0);
43 }
44 
45 /*@
46   DMPlexGetSimplexOrBoxCells - Get the range of cells which are neither prisms nor ghost FV cells
47 
48   Input Parameter:
49 + dm     - The DMPlex object
50 - height - The cell height in the Plex, 0 is the default
51 
52   Output Parameters:
53 + cStart - The first "normal" cell
54 - cEnd   - The upper bound on "normal"" cells
55 
56   Note: This just gives the first range of cells found. If the mesh has several cell types, it will only give the first.
57 
58   Level: developer
59 
60 .seealso DMPlexConstructGhostCells(), DMPlexGetGhostCellStratum()
61 @*/
62 PetscErrorCode DMPlexGetSimplexOrBoxCells(DM dm, PetscInt height, PetscInt *cStart, PetscInt *cEnd)
63 {
64   DMPolytopeType ct = DM_POLYTOPE_UNKNOWN;
65   PetscInt       cS, cE, c;
66   PetscErrorCode ierr;
67 
68   PetscFunctionBegin;
69   ierr = DMPlexGetHeightStratum(dm, PetscMax(height, 0), &cS, &cE);CHKERRQ(ierr);
70   for (c = cS; c < cE; ++c) {
71     DMPolytopeType cct;
72 
73     ierr = DMPlexGetCellType(dm, c, &cct);CHKERRQ(ierr);
74     if ((PetscInt) cct < 0) break;
75     switch (cct) {
76       case DM_POLYTOPE_POINT:
77       case DM_POLYTOPE_SEGMENT:
78       case DM_POLYTOPE_TRIANGLE:
79       case DM_POLYTOPE_QUADRILATERAL:
80       case DM_POLYTOPE_TETRAHEDRON:
81       case DM_POLYTOPE_HEXAHEDRON:
82         ct = cct;
83         break;
84       default: break;
85     }
86     if (ct != DM_POLYTOPE_UNKNOWN) break;
87   }
88   if (ct != DM_POLYTOPE_UNKNOWN) {
89     DMLabel ctLabel;
90 
91     ierr = DMPlexGetCellTypeLabel(dm, &ctLabel);CHKERRQ(ierr);
92     ierr = DMLabelGetStratumBounds(ctLabel, ct, &cS, &cE);CHKERRQ(ierr);
93   }
94   if (cStart) *cStart = cS;
95   if (cEnd)   *cEnd   = cE;
96   PetscFunctionReturn(0);
97 }
98 
99 PetscErrorCode DMPlexGetFieldType_Internal(DM dm, PetscSection section, PetscInt field, PetscInt *sStart, PetscInt *sEnd, PetscViewerVTKFieldType *ft)
100 {
101   PetscInt       cdim, pStart, pEnd, vStart, vEnd, cStart, cEnd;
102   PetscInt       vcdof[2] = {0,0}, globalvcdof[2];
103   PetscErrorCode ierr;
104 
105   PetscFunctionBegin;
106   *ft  = PETSC_VTK_INVALID;
107   ierr = DMGetCoordinateDim(dm, &cdim);CHKERRQ(ierr);
108   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
109   ierr = DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
110   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
111   if (field >= 0) {
112     if ((vStart >= pStart) && (vStart < pEnd)) {ierr = PetscSectionGetFieldDof(section, vStart, field, &vcdof[0]);CHKERRQ(ierr);}
113     if ((cStart >= pStart) && (cStart < pEnd)) {ierr = PetscSectionGetFieldDof(section, cStart, field, &vcdof[1]);CHKERRQ(ierr);}
114   } else {
115     if ((vStart >= pStart) && (vStart < pEnd)) {ierr = PetscSectionGetDof(section, vStart, &vcdof[0]);CHKERRQ(ierr);}
116     if ((cStart >= pStart) && (cStart < pEnd)) {ierr = PetscSectionGetDof(section, cStart, &vcdof[1]);CHKERRQ(ierr);}
117   }
118   ierr = MPI_Allreduce(vcdof, globalvcdof, 2, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm));CHKERRMPI(ierr);
119   if (globalvcdof[0]) {
120     *sStart = vStart;
121     *sEnd   = vEnd;
122     if (globalvcdof[0] == cdim) *ft = PETSC_VTK_POINT_VECTOR_FIELD;
123     else                        *ft = PETSC_VTK_POINT_FIELD;
124   } else if (globalvcdof[1]) {
125     *sStart = cStart;
126     *sEnd   = cEnd;
127     if (globalvcdof[1] == cdim) *ft = PETSC_VTK_CELL_VECTOR_FIELD;
128     else                        *ft = PETSC_VTK_CELL_FIELD;
129   } else {
130     if (field >= 0) {
131       const char *fieldname;
132 
133       ierr = PetscSectionGetFieldName(section, field, &fieldname);CHKERRQ(ierr);
134       ierr = PetscInfo2((PetscObject) dm, "Could not classify VTK output type of section field %D \"%s\"\n", field, fieldname);CHKERRQ(ierr);
135     } else {
136       ierr = PetscInfo((PetscObject) dm, "Could not classify VTK output type of section\"%s\"\n");CHKERRQ(ierr);
137     }
138   }
139   PetscFunctionReturn(0);
140 }
141 
142 static PetscErrorCode VecView_Plex_Local_Draw(Vec v, PetscViewer viewer)
143 {
144   DM                 dm;
145   PetscSection       s;
146   PetscDraw          draw, popup;
147   DM                 cdm;
148   PetscSection       coordSection;
149   Vec                coordinates;
150   const PetscScalar *coords, *array;
151   PetscReal          bound[4] = {PETSC_MAX_REAL, PETSC_MAX_REAL, PETSC_MIN_REAL, PETSC_MIN_REAL};
152   PetscReal          vbound[2], time;
153   PetscBool          isnull, flg;
154   PetscInt           dim, Nf, f, Nc, comp, vStart, vEnd, cStart, cEnd, c, N, level, step, w = 0;
155   const char        *name;
156   char               title[PETSC_MAX_PATH_LEN];
157   PetscErrorCode     ierr;
158 
159   PetscFunctionBegin;
160   ierr = PetscViewerDrawGetDraw(viewer, 0, &draw);CHKERRQ(ierr);
161   ierr = PetscDrawIsNull(draw, &isnull);CHKERRQ(ierr);
162   if (isnull) PetscFunctionReturn(0);
163 
164   ierr = VecGetDM(v, &dm);CHKERRQ(ierr);
165   ierr = DMGetCoordinateDim(dm, &dim);CHKERRQ(ierr);
166   if (dim != 2) SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Cannot draw meshes of dimension %D. Use PETSCVIEWERGLVIS", dim);
167   ierr = DMGetLocalSection(dm, &s);CHKERRQ(ierr);
168   ierr = PetscSectionGetNumFields(s, &Nf);CHKERRQ(ierr);
169   ierr = DMGetCoarsenLevel(dm, &level);CHKERRQ(ierr);
170   ierr = DMGetCoordinateDM(dm, &cdm);CHKERRQ(ierr);
171   ierr = DMGetLocalSection(cdm, &coordSection);CHKERRQ(ierr);
172   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
173   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
174   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
175 
176   ierr = PetscObjectGetName((PetscObject) v, &name);CHKERRQ(ierr);
177   ierr = DMGetOutputSequenceNumber(dm, &step, &time);CHKERRQ(ierr);
178 
179   ierr = VecGetLocalSize(coordinates, &N);CHKERRQ(ierr);
180   ierr = VecGetArrayRead(coordinates, &coords);CHKERRQ(ierr);
181   for (c = 0; c < N; c += dim) {
182     bound[0] = PetscMin(bound[0], PetscRealPart(coords[c]));   bound[2] = PetscMax(bound[2], PetscRealPart(coords[c]));
183     bound[1] = PetscMin(bound[1], PetscRealPart(coords[c+1])); bound[3] = PetscMax(bound[3], PetscRealPart(coords[c+1]));
184   }
185   ierr = VecRestoreArrayRead(coordinates, &coords);CHKERRQ(ierr);
186   ierr = PetscDrawClear(draw);CHKERRQ(ierr);
187 
188   /* Could implement something like DMDASelectFields() */
189   for (f = 0; f < Nf; ++f) {
190     DM   fdm = dm;
191     Vec  fv  = v;
192     IS   fis;
193     char prefix[PETSC_MAX_PATH_LEN];
194     const char *fname;
195 
196     ierr = PetscSectionGetFieldComponents(s, f, &Nc);CHKERRQ(ierr);
197     ierr = PetscSectionGetFieldName(s, f, &fname);CHKERRQ(ierr);
198 
199     if (v->hdr.prefix) {ierr = PetscStrncpy(prefix, v->hdr.prefix,sizeof(prefix));CHKERRQ(ierr);}
200     else               {prefix[0] = '\0';}
201     if (Nf > 1) {
202       ierr = DMCreateSubDM(dm, 1, &f, &fis, &fdm);CHKERRQ(ierr);
203       ierr = VecGetSubVector(v, fis, &fv);CHKERRQ(ierr);
204       ierr = PetscStrlcat(prefix, fname,sizeof(prefix));CHKERRQ(ierr);
205       ierr = PetscStrlcat(prefix, "_",sizeof(prefix));CHKERRQ(ierr);
206     }
207     for (comp = 0; comp < Nc; ++comp, ++w) {
208       PetscInt nmax = 2;
209 
210       ierr = PetscViewerDrawGetDraw(viewer, w, &draw);CHKERRQ(ierr);
211       if (Nc > 1) {ierr = PetscSNPrintf(title, sizeof(title), "%s:%s_%D Step: %D Time: %.4g", name, fname, comp, step, time);CHKERRQ(ierr);}
212       else        {ierr = PetscSNPrintf(title, sizeof(title), "%s:%s Step: %D Time: %.4g", name, fname, step, time);CHKERRQ(ierr);}
213       ierr = PetscDrawSetTitle(draw, title);CHKERRQ(ierr);
214 
215       /* TODO Get max and min only for this component */
216       ierr = PetscOptionsGetRealArray(NULL, prefix, "-vec_view_bounds", vbound, &nmax, &flg);CHKERRQ(ierr);
217       if (!flg) {
218         ierr = VecMin(fv, NULL, &vbound[0]);CHKERRQ(ierr);
219         ierr = VecMax(fv, NULL, &vbound[1]);CHKERRQ(ierr);
220         if (vbound[1] <= vbound[0]) vbound[1] = vbound[0] + 1.0;
221       }
222       ierr = PetscDrawGetPopup(draw, &popup);CHKERRQ(ierr);
223       ierr = PetscDrawScalePopup(popup, vbound[0], vbound[1]);CHKERRQ(ierr);
224       ierr = PetscDrawSetCoordinates(draw, bound[0], bound[1], bound[2], bound[3]);CHKERRQ(ierr);
225 
226       ierr = VecGetArrayRead(fv, &array);CHKERRQ(ierr);
227       for (c = cStart; c < cEnd; ++c) {
228         PetscScalar *coords = NULL, *a = NULL;
229         PetscInt     numCoords, color[4] = {-1,-1,-1,-1};
230 
231         ierr = DMPlexPointLocalRead(fdm, c, array, &a);CHKERRQ(ierr);
232         if (a) {
233           color[0] = PetscDrawRealToColor(PetscRealPart(a[comp]), vbound[0], vbound[1]);
234           color[1] = color[2] = color[3] = color[0];
235         } else {
236           PetscScalar *vals = NULL;
237           PetscInt     numVals, va;
238 
239           ierr = DMPlexVecGetClosure(fdm, NULL, fv, c, &numVals, &vals);CHKERRQ(ierr);
240           if (numVals % Nc) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "The number of components %D does not divide the number of values in the closure %D", Nc, numVals);
241           switch (numVals/Nc) {
242           case 3: /* P1 Triangle */
243           case 4: /* P1 Quadrangle */
244             for (va = 0; va < numVals/Nc; ++va) color[va] = PetscDrawRealToColor(PetscRealPart(vals[va*Nc+comp]), vbound[0], vbound[1]);
245             break;
246           case 6: /* P2 Triangle */
247           case 8: /* P2 Quadrangle */
248             for (va = 0; va < numVals/(Nc*2); ++va) color[va] = PetscDrawRealToColor(PetscRealPart(vals[va*Nc+comp + numVals/(Nc*2)]), vbound[0], vbound[1]);
249             break;
250           default: SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Number of values for cell closure %D cannot be handled", numVals/Nc);
251           }
252           ierr = DMPlexVecRestoreClosure(fdm, NULL, fv, c, &numVals, &vals);CHKERRQ(ierr);
253         }
254         ierr = DMPlexVecGetClosure(dm, coordSection, coordinates, c, &numCoords, &coords);CHKERRQ(ierr);
255         switch (numCoords) {
256         case 6:
257           ierr = PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), color[0], color[1], color[2]);CHKERRQ(ierr);
258           break;
259         case 8:
260           ierr = PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), color[0], color[1], color[2]);CHKERRQ(ierr);
261           ierr = PetscDrawTriangle(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), color[2], color[3], color[0]);CHKERRQ(ierr);
262           break;
263         default: SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells with %D coordinates", numCoords);
264         }
265         ierr = DMPlexVecRestoreClosure(dm, coordSection, coordinates, c, &numCoords, &coords);CHKERRQ(ierr);
266       }
267       ierr = VecRestoreArrayRead(fv, &array);CHKERRQ(ierr);
268       ierr = PetscDrawFlush(draw);CHKERRQ(ierr);
269       ierr = PetscDrawPause(draw);CHKERRQ(ierr);
270       ierr = PetscDrawSave(draw);CHKERRQ(ierr);
271     }
272     if (Nf > 1) {
273       ierr = VecRestoreSubVector(v, fis, &fv);CHKERRQ(ierr);
274       ierr = ISDestroy(&fis);CHKERRQ(ierr);
275       ierr = DMDestroy(&fdm);CHKERRQ(ierr);
276     }
277   }
278   PetscFunctionReturn(0);
279 }
280 
281 static PetscErrorCode VecView_Plex_Local_VTK(Vec v, PetscViewer viewer)
282 {
283   DM                      dm;
284   Vec                     locv;
285   const char              *name;
286   PetscSection            section;
287   PetscInt                pStart, pEnd;
288   PetscInt                numFields;
289   PetscViewerVTKFieldType ft;
290   PetscErrorCode          ierr;
291 
292   PetscFunctionBegin;
293   ierr = VecGetDM(v, &dm);CHKERRQ(ierr);
294   ierr = DMCreateLocalVector(dm, &locv);CHKERRQ(ierr); /* VTK viewer requires exclusive ownership of the vector */
295   ierr = PetscObjectGetName((PetscObject) v, &name);CHKERRQ(ierr);
296   ierr = PetscObjectSetName((PetscObject) locv, name);CHKERRQ(ierr);
297   ierr = VecCopy(v, locv);CHKERRQ(ierr);
298   ierr = DMGetLocalSection(dm, &section);CHKERRQ(ierr);
299   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
300   if (!numFields) {
301     ierr = DMPlexGetFieldType_Internal(dm, section, PETSC_DETERMINE, &pStart, &pEnd, &ft);CHKERRQ(ierr);
302     ierr = PetscViewerVTKAddField(viewer, (PetscObject) dm, DMPlexVTKWriteAll, PETSC_DEFAULT, ft, PETSC_TRUE,(PetscObject) locv);CHKERRQ(ierr);
303   } else {
304     PetscInt f;
305 
306     for (f = 0; f < numFields; f++) {
307       ierr = DMPlexGetFieldType_Internal(dm, section, f, &pStart, &pEnd, &ft);CHKERRQ(ierr);
308       if (ft == PETSC_VTK_INVALID) continue;
309       ierr = PetscObjectReference((PetscObject)locv);CHKERRQ(ierr);
310       ierr = PetscViewerVTKAddField(viewer, (PetscObject) dm, DMPlexVTKWriteAll, f, ft, PETSC_TRUE,(PetscObject) locv);CHKERRQ(ierr);
311     }
312     ierr = VecDestroy(&locv);CHKERRQ(ierr);
313   }
314   PetscFunctionReturn(0);
315 }
316 
317 PetscErrorCode VecView_Plex_Local(Vec v, PetscViewer viewer)
318 {
319   DM             dm;
320   PetscBool      isvtk, ishdf5, isdraw, isglvis;
321   PetscErrorCode ierr;
322 
323   PetscFunctionBegin;
324   ierr = VecGetDM(v, &dm);CHKERRQ(ierr);
325   if (!dm) SETERRQ(PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
326   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERVTK,   &isvtk);CHKERRQ(ierr);
327   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5,  &ishdf5);CHKERRQ(ierr);
328   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERDRAW,  &isdraw);CHKERRQ(ierr);
329   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERGLVIS, &isglvis);CHKERRQ(ierr);
330   if (isvtk || ishdf5 || isdraw || isglvis) {
331     PetscInt    i,numFields;
332     PetscObject fe;
333     PetscBool   fem = PETSC_FALSE;
334     Vec         locv = v;
335     const char  *name;
336     PetscInt    step;
337     PetscReal   time;
338 
339     ierr = DMGetNumFields(dm, &numFields);CHKERRQ(ierr);
340     for (i=0; i<numFields; i++) {
341       ierr = DMGetField(dm, i, NULL, &fe);CHKERRQ(ierr);
342       if (fe->classid == PETSCFE_CLASSID) { fem = PETSC_TRUE; break; }
343     }
344     if (fem) {
345       PetscObject isZero;
346 
347       ierr = DMGetLocalVector(dm, &locv);CHKERRQ(ierr);
348       ierr = PetscObjectGetName((PetscObject) v, &name);CHKERRQ(ierr);
349       ierr = PetscObjectSetName((PetscObject) locv, name);CHKERRQ(ierr);
350       ierr = PetscObjectQuery((PetscObject) v, "__Vec_bc_zero__", &isZero);CHKERRQ(ierr);
351       ierr = PetscObjectCompose((PetscObject) locv, "__Vec_bc_zero__", isZero);CHKERRQ(ierr);
352       ierr = VecCopy(v, locv);CHKERRQ(ierr);
353       ierr = DMGetOutputSequenceNumber(dm, NULL, &time);CHKERRQ(ierr);
354       ierr = DMPlexInsertBoundaryValues(dm, PETSC_TRUE, locv, time, NULL, NULL, NULL);CHKERRQ(ierr);
355     }
356     if (isvtk) {
357       ierr = VecView_Plex_Local_VTK(locv, viewer);CHKERRQ(ierr);
358     } else if (ishdf5) {
359 #if defined(PETSC_HAVE_HDF5)
360       ierr = VecView_Plex_Local_HDF5_Internal(locv, viewer);CHKERRQ(ierr);
361 #else
362       SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
363 #endif
364     } else if (isdraw) {
365       ierr = VecView_Plex_Local_Draw(locv, viewer);CHKERRQ(ierr);
366     } else if (isglvis) {
367       ierr = DMGetOutputSequenceNumber(dm, &step, NULL);CHKERRQ(ierr);
368       ierr = PetscViewerGLVisSetSnapId(viewer, step);CHKERRQ(ierr);
369       ierr = VecView_GLVis(locv, viewer);CHKERRQ(ierr);
370     }
371     if (fem) {
372       ierr = PetscObjectCompose((PetscObject) locv, "__Vec_bc_zero__", NULL);CHKERRQ(ierr);
373       ierr = DMRestoreLocalVector(dm, &locv);CHKERRQ(ierr);
374     }
375   } else {
376     PetscBool isseq;
377 
378     ierr = PetscObjectTypeCompare((PetscObject) v, VECSEQ, &isseq);CHKERRQ(ierr);
379     if (isseq) {ierr = VecView_Seq(v, viewer);CHKERRQ(ierr);}
380     else       {ierr = VecView_MPI(v, viewer);CHKERRQ(ierr);}
381   }
382   PetscFunctionReturn(0);
383 }
384 
385 PetscErrorCode VecView_Plex(Vec v, PetscViewer viewer)
386 {
387   DM             dm;
388   PetscBool      isvtk, ishdf5, isdraw, isglvis, isexodusii;
389   PetscErrorCode ierr;
390 
391   PetscFunctionBegin;
392   ierr = VecGetDM(v, &dm);CHKERRQ(ierr);
393   if (!dm) SETERRQ(PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
394   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERVTK,      &isvtk);CHKERRQ(ierr);
395   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5,     &ishdf5);CHKERRQ(ierr);
396   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERDRAW,     &isdraw);CHKERRQ(ierr);
397   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERGLVIS,    &isglvis);CHKERRQ(ierr);
398   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWEREXODUSII, &isexodusii);CHKERRQ(ierr);
399   if (isvtk || isdraw || isglvis) {
400     Vec         locv;
401     PetscObject isZero;
402     const char *name;
403 
404     ierr = DMGetLocalVector(dm, &locv);CHKERRQ(ierr);
405     ierr = PetscObjectGetName((PetscObject) v, &name);CHKERRQ(ierr);
406     ierr = PetscObjectSetName((PetscObject) locv, name);CHKERRQ(ierr);
407     ierr = DMGlobalToLocalBegin(dm, v, INSERT_VALUES, locv);CHKERRQ(ierr);
408     ierr = DMGlobalToLocalEnd(dm, v, INSERT_VALUES, locv);CHKERRQ(ierr);
409     ierr = PetscObjectQuery((PetscObject) v, "__Vec_bc_zero__", &isZero);CHKERRQ(ierr);
410     ierr = PetscObjectCompose((PetscObject) locv, "__Vec_bc_zero__", isZero);CHKERRQ(ierr);
411     ierr = VecView_Plex_Local(locv, viewer);CHKERRQ(ierr);
412     ierr = PetscObjectCompose((PetscObject) locv, "__Vec_bc_zero__", NULL);CHKERRQ(ierr);
413     ierr = DMRestoreLocalVector(dm, &locv);CHKERRQ(ierr);
414   } else if (ishdf5) {
415 #if defined(PETSC_HAVE_HDF5)
416     ierr = VecView_Plex_HDF5_Internal(v, viewer);CHKERRQ(ierr);
417 #else
418     SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
419 #endif
420   } else if (isexodusii) {
421 #if defined(PETSC_HAVE_EXODUSII)
422     ierr = VecView_PlexExodusII_Internal(v, viewer);CHKERRQ(ierr);
423 #else
424     SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "ExodusII not supported in this build.\nPlease reconfigure using --download-exodusii");
425 #endif
426   } else {
427     PetscBool isseq;
428 
429     ierr = PetscObjectTypeCompare((PetscObject) v, VECSEQ, &isseq);CHKERRQ(ierr);
430     if (isseq) {ierr = VecView_Seq(v, viewer);CHKERRQ(ierr);}
431     else       {ierr = VecView_MPI(v, viewer);CHKERRQ(ierr);}
432   }
433   PetscFunctionReturn(0);
434 }
435 
436 PetscErrorCode VecView_Plex_Native(Vec originalv, PetscViewer viewer)
437 {
438   DM                dm;
439   MPI_Comm          comm;
440   PetscViewerFormat format;
441   Vec               v;
442   PetscBool         isvtk, ishdf5;
443   PetscErrorCode    ierr;
444 
445   PetscFunctionBegin;
446   ierr = VecGetDM(originalv, &dm);CHKERRQ(ierr);
447   ierr = PetscObjectGetComm((PetscObject) originalv, &comm);CHKERRQ(ierr);
448   if (!dm) SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
449   ierr = PetscViewerGetFormat(viewer, &format);CHKERRQ(ierr);
450   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5);CHKERRQ(ierr);
451   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERVTK,  &isvtk);CHKERRQ(ierr);
452   if (format == PETSC_VIEWER_NATIVE) {
453     /* Natural ordering is the common case for DMDA, NATIVE means plain vector, for PLEX is the opposite */
454     /* this need a better fix */
455     if (dm->useNatural) {
456       if (dm->sfNatural) {
457         const char *vecname;
458         PetscInt    n, nroots;
459 
460         ierr = VecGetLocalSize(originalv, &n);CHKERRQ(ierr);
461         ierr = PetscSFGetGraph(dm->sfNatural, &nroots, NULL, NULL, NULL);CHKERRQ(ierr);
462         if (n == nroots) {
463           ierr = DMGetGlobalVector(dm, &v);CHKERRQ(ierr);
464           ierr = DMPlexGlobalToNaturalBegin(dm, originalv, v);CHKERRQ(ierr);
465           ierr = DMPlexGlobalToNaturalEnd(dm, originalv, v);CHKERRQ(ierr);
466           ierr = PetscObjectGetName((PetscObject) originalv, &vecname);CHKERRQ(ierr);
467           ierr = PetscObjectSetName((PetscObject) v, vecname);CHKERRQ(ierr);
468         } else SETERRQ(comm, PETSC_ERR_ARG_WRONG, "DM global to natural SF only handles global vectors");
469       } else SETERRQ(comm, PETSC_ERR_ARG_WRONGSTATE, "DM global to natural SF was not created");
470     } else v = originalv;
471   } else v = originalv;
472 
473   if (ishdf5) {
474 #if defined(PETSC_HAVE_HDF5)
475     ierr = VecView_Plex_HDF5_Native_Internal(v, viewer);CHKERRQ(ierr);
476 #else
477     SETERRQ(comm, PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
478 #endif
479   } else if (isvtk) {
480     SETERRQ(comm, PETSC_ERR_SUP, "VTK format does not support viewing in natural order. Please switch to HDF5.");
481   } else {
482     PetscBool isseq;
483 
484     ierr = PetscObjectTypeCompare((PetscObject) v, VECSEQ, &isseq);CHKERRQ(ierr);
485     if (isseq) {ierr = VecView_Seq(v, viewer);CHKERRQ(ierr);}
486     else       {ierr = VecView_MPI(v, viewer);CHKERRQ(ierr);}
487   }
488   if (v != originalv) {ierr = DMRestoreGlobalVector(dm, &v);CHKERRQ(ierr);}
489   PetscFunctionReturn(0);
490 }
491 
492 PetscErrorCode VecLoad_Plex_Local(Vec v, PetscViewer viewer)
493 {
494   DM             dm;
495   PetscBool      ishdf5;
496   PetscErrorCode ierr;
497 
498   PetscFunctionBegin;
499   ierr = VecGetDM(v, &dm);CHKERRQ(ierr);
500   if (!dm) SETERRQ(PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
501   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5);CHKERRQ(ierr);
502   if (ishdf5) {
503     DM          dmBC;
504     Vec         gv;
505     const char *name;
506 
507     ierr = DMGetOutputDM(dm, &dmBC);CHKERRQ(ierr);
508     ierr = DMGetGlobalVector(dmBC, &gv);CHKERRQ(ierr);
509     ierr = PetscObjectGetName((PetscObject) v, &name);CHKERRQ(ierr);
510     ierr = PetscObjectSetName((PetscObject) gv, name);CHKERRQ(ierr);
511     ierr = VecLoad_Default(gv, viewer);CHKERRQ(ierr);
512     ierr = DMGlobalToLocalBegin(dmBC, gv, INSERT_VALUES, v);CHKERRQ(ierr);
513     ierr = DMGlobalToLocalEnd(dmBC, gv, INSERT_VALUES, v);CHKERRQ(ierr);
514     ierr = DMRestoreGlobalVector(dmBC, &gv);CHKERRQ(ierr);
515   } else {
516     ierr = VecLoad_Default(v, viewer);CHKERRQ(ierr);
517   }
518   PetscFunctionReturn(0);
519 }
520 
521 PetscErrorCode VecLoad_Plex(Vec v, PetscViewer viewer)
522 {
523   DM             dm;
524   PetscBool      ishdf5,isexodusii;
525   PetscErrorCode ierr;
526 
527   PetscFunctionBegin;
528   ierr = VecGetDM(v, &dm);CHKERRQ(ierr);
529   if (!dm) SETERRQ(PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
530   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5,     &ishdf5);CHKERRQ(ierr);
531   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWEREXODUSII, &isexodusii);CHKERRQ(ierr);
532   if (ishdf5) {
533 #if defined(PETSC_HAVE_HDF5)
534     ierr = VecLoad_Plex_HDF5_Internal(v, viewer);CHKERRQ(ierr);
535 #else
536     SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
537 #endif
538   } else if (isexodusii) {
539 #if defined(PETSC_HAVE_EXODUSII)
540     ierr = VecLoad_PlexExodusII_Internal(v, viewer);CHKERRQ(ierr);
541 #else
542     SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "ExodusII not supported in this build.\nPlease reconfigure using --download-exodusii");
543 #endif
544   } else {
545     ierr = VecLoad_Default(v, viewer);CHKERRQ(ierr);
546   }
547   PetscFunctionReturn(0);
548 }
549 
550 PetscErrorCode VecLoad_Plex_Native(Vec originalv, PetscViewer viewer)
551 {
552   DM                dm;
553   PetscViewerFormat format;
554   PetscBool         ishdf5;
555   PetscErrorCode    ierr;
556 
557   PetscFunctionBegin;
558   ierr = VecGetDM(originalv, &dm);CHKERRQ(ierr);
559   if (!dm) SETERRQ(PetscObjectComm((PetscObject) originalv), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
560   ierr = PetscViewerGetFormat(viewer, &format);CHKERRQ(ierr);
561   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5);CHKERRQ(ierr);
562   if (format == PETSC_VIEWER_NATIVE) {
563     if (dm->useNatural) {
564       if (dm->sfNatural) {
565         if (ishdf5) {
566 #if defined(PETSC_HAVE_HDF5)
567           Vec         v;
568           const char *vecname;
569 
570           ierr = DMGetGlobalVector(dm, &v);CHKERRQ(ierr);
571           ierr = PetscObjectGetName((PetscObject) originalv, &vecname);CHKERRQ(ierr);
572           ierr = PetscObjectSetName((PetscObject) v, vecname);CHKERRQ(ierr);
573           ierr = VecLoad_Plex_HDF5_Native_Internal(v, viewer);CHKERRQ(ierr);
574           ierr = DMPlexNaturalToGlobalBegin(dm, v, originalv);CHKERRQ(ierr);
575           ierr = DMPlexNaturalToGlobalEnd(dm, v, originalv);CHKERRQ(ierr);
576           ierr = DMRestoreGlobalVector(dm, &v);CHKERRQ(ierr);
577 #else
578           SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
579 #endif
580         } else SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Reading in natural order is not supported for anything but HDF5.");
581       }
582     } else {
583       ierr = VecLoad_Default(originalv, viewer);CHKERRQ(ierr);
584     }
585   }
586   PetscFunctionReturn(0);
587 }
588 
589 PETSC_UNUSED static PetscErrorCode DMPlexView_Ascii_Geometry(DM dm, PetscViewer viewer)
590 {
591   PetscSection       coordSection;
592   Vec                coordinates;
593   DMLabel            depthLabel, celltypeLabel;
594   const char        *name[4];
595   const PetscScalar *a;
596   PetscInt           dim, pStart, pEnd, cStart, cEnd, c;
597   PetscErrorCode     ierr;
598 
599   PetscFunctionBegin;
600   ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr);
601   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
602   ierr = DMGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
603   ierr = DMPlexGetDepthLabel(dm, &depthLabel);CHKERRQ(ierr);
604   ierr = DMPlexGetCellTypeLabel(dm, &celltypeLabel);CHKERRQ(ierr);
605   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
606   ierr = PetscSectionGetChart(coordSection, &pStart, &pEnd);CHKERRQ(ierr);
607   ierr = VecGetArrayRead(coordinates, &a);CHKERRQ(ierr);
608   name[0]     = "vertex";
609   name[1]     = "edge";
610   name[dim-1] = "face";
611   name[dim]   = "cell";
612   for (c = cStart; c < cEnd; ++c) {
613     PetscInt *closure = NULL;
614     PetscInt  closureSize, cl, ct;
615 
616     ierr = DMLabelGetValue(celltypeLabel, c, &ct);CHKERRQ(ierr);
617     ierr = PetscViewerASCIIPrintf(viewer, "Geometry for cell %D polytope type %s:\n", c, DMPolytopeTypes[ct]);CHKERRQ(ierr);
618     ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
619     ierr = PetscViewerASCIIPushTab(viewer);CHKERRQ(ierr);
620     for (cl = 0; cl < closureSize*2; cl += 2) {
621       PetscInt point = closure[cl], depth, dof, off, d, p;
622 
623       if ((point < pStart) || (point >= pEnd)) continue;
624       ierr = PetscSectionGetDof(coordSection, point, &dof);CHKERRQ(ierr);
625       if (!dof) continue;
626       ierr = DMLabelGetValue(depthLabel, point, &depth);CHKERRQ(ierr);
627       ierr = PetscSectionGetOffset(coordSection, point, &off);CHKERRQ(ierr);
628       ierr = PetscViewerASCIIPrintf(viewer, "%s %D coords:", name[depth], point);CHKERRQ(ierr);
629       for (p = 0; p < dof/dim; ++p) {
630         ierr = PetscViewerASCIIPrintf(viewer, " (");CHKERRQ(ierr);
631         for (d = 0; d < dim; ++d) {
632           if (d > 0) {ierr = PetscViewerASCIIPrintf(viewer, ", ");CHKERRQ(ierr);}
633           ierr = PetscViewerASCIIPrintf(viewer, "%g", (double) PetscRealPart(a[off+p*dim+d]));CHKERRQ(ierr);
634         }
635         ierr = PetscViewerASCIIPrintf(viewer, ")");CHKERRQ(ierr);
636       }
637       ierr = PetscViewerASCIIPrintf(viewer, "\n");CHKERRQ(ierr);
638     }
639     ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
640     ierr = PetscViewerASCIIPopTab(viewer);CHKERRQ(ierr);
641   }
642   ierr = VecRestoreArrayRead(coordinates, &a);CHKERRQ(ierr);
643   PetscFunctionReturn(0);
644 }
645 
646 static PetscErrorCode DMPlexView_Ascii(DM dm, PetscViewer viewer)
647 {
648   DM_Plex          *mesh = (DM_Plex*) dm->data;
649   DM                cdm;
650   PetscSection      coordSection;
651   Vec               coordinates;
652   PetscViewerFormat format;
653   PetscErrorCode    ierr;
654 
655   PetscFunctionBegin;
656   ierr = DMGetCoordinateDM(dm, &cdm);CHKERRQ(ierr);
657   ierr = DMGetLocalSection(cdm, &coordSection);CHKERRQ(ierr);
658   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
659   ierr = PetscViewerGetFormat(viewer, &format);CHKERRQ(ierr);
660   if (format == PETSC_VIEWER_ASCII_INFO_DETAIL) {
661     const char *name;
662     PetscInt    dim, cellHeight, maxConeSize, maxSupportSize;
663     PetscInt    pStart, pEnd, p, numLabels, l;
664     PetscMPIInt rank, size;
665 
666     ierr = MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank);CHKERRMPI(ierr);
667     ierr = MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size);CHKERRMPI(ierr);
668     ierr = PetscObjectGetName((PetscObject) dm, &name);CHKERRQ(ierr);
669     ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
670     ierr = DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize);CHKERRQ(ierr);
671     ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr);
672     ierr = DMPlexGetVTKCellHeight(dm, &cellHeight);CHKERRQ(ierr);
673     if (name) {ierr = PetscViewerASCIIPrintf(viewer, "%s in %D dimension%s:\n", name, dim, dim == 1 ? "" : "s");CHKERRQ(ierr);}
674     else      {ierr = PetscViewerASCIIPrintf(viewer, "Mesh in %D dimension%s:\n", dim, dim == 1 ? "" : "s");CHKERRQ(ierr);}
675     if (cellHeight) {ierr = PetscViewerASCIIPrintf(viewer, "  Cells are at height %D\n", cellHeight);CHKERRQ(ierr);}
676     ierr = PetscViewerASCIIPrintf(viewer, "Supports:\n", name);CHKERRQ(ierr);
677     ierr = PetscViewerASCIIPushSynchronized(viewer);CHKERRQ(ierr);
678     ierr = PetscViewerASCIISynchronizedPrintf(viewer, "[%d] Max support size: %D\n", rank, maxSupportSize);CHKERRQ(ierr);
679     for (p = pStart; p < pEnd; ++p) {
680       PetscInt dof, off, s;
681 
682       ierr = PetscSectionGetDof(mesh->supportSection, p, &dof);CHKERRQ(ierr);
683       ierr = PetscSectionGetOffset(mesh->supportSection, p, &off);CHKERRQ(ierr);
684       for (s = off; s < off+dof; ++s) {
685         ierr = PetscViewerASCIISynchronizedPrintf(viewer, "[%d]: %D ----> %D\n", rank, p, mesh->supports[s]);CHKERRQ(ierr);
686       }
687     }
688     ierr = PetscViewerFlush(viewer);CHKERRQ(ierr);
689     ierr = PetscViewerASCIIPrintf(viewer, "Cones:\n", name);CHKERRQ(ierr);
690     ierr = PetscViewerASCIISynchronizedPrintf(viewer, "[%d] Max cone size: %D\n", rank, maxConeSize);CHKERRQ(ierr);
691     for (p = pStart; p < pEnd; ++p) {
692       PetscInt dof, off, c;
693 
694       ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
695       ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
696       for (c = off; c < off+dof; ++c) {
697         ierr = PetscViewerASCIISynchronizedPrintf(viewer, "[%d]: %D <---- %D (%D)\n", rank, p, mesh->cones[c], mesh->coneOrientations[c]);CHKERRQ(ierr);
698       }
699     }
700     ierr = PetscViewerFlush(viewer);CHKERRQ(ierr);
701     ierr = PetscViewerASCIIPopSynchronized(viewer);CHKERRQ(ierr);
702     if (coordSection && coordinates) {
703       ierr = PetscSectionVecView(coordSection, coordinates, viewer);CHKERRQ(ierr);
704     }
705     ierr = DMGetNumLabels(dm, &numLabels);CHKERRQ(ierr);
706     if (numLabels) {ierr = PetscViewerASCIIPrintf(viewer, "Labels:\n");CHKERRQ(ierr);}
707     for (l = 0; l < numLabels; ++l) {
708       DMLabel     label;
709       PetscBool   isdepth;
710       const char *name;
711 
712       ierr = DMGetLabelName(dm, l, &name);CHKERRQ(ierr);
713       ierr = PetscStrcmp(name, "depth", &isdepth);CHKERRQ(ierr);
714       if (isdepth) continue;
715       ierr = DMGetLabel(dm, name, &label);CHKERRQ(ierr);
716       ierr = DMLabelView(label, viewer);CHKERRQ(ierr);
717     }
718     if (size > 1) {
719       PetscSF sf;
720 
721       ierr = DMGetPointSF(dm, &sf);CHKERRQ(ierr);
722       ierr = PetscSFView(sf, viewer);CHKERRQ(ierr);
723     }
724     ierr = PetscViewerFlush(viewer);CHKERRQ(ierr);
725   } else if (format == PETSC_VIEWER_ASCII_LATEX) {
726     const char  *name, *color;
727     const char  *defcolors[3]  = {"gray", "orange", "green"};
728     const char  *deflcolors[4] = {"blue", "cyan", "red", "magenta"};
729     char         lname[PETSC_MAX_PATH_LEN];
730     PetscReal    scale         = 2.0;
731     PetscReal    tikzscale     = 1.0;
732     PetscBool    useNumbers    = PETSC_TRUE, useLabels, useColors;
733     double       tcoords[3];
734     PetscScalar *coords;
735     PetscInt     numLabels, l, numColors, numLColors, dim, depth, cStart, cEnd, c, vStart, vEnd, v, eStart = 0, eEnd = 0, e, p;
736     PetscMPIInt  rank, size;
737     char         **names, **colors, **lcolors;
738     PetscBool    plotEdges, flg, lflg;
739     PetscBT      wp = NULL;
740     PetscInt     pEnd, pStart;
741 
742     ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr);
743     ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
744     ierr = DMGetNumLabels(dm, &numLabels);CHKERRQ(ierr);
745     numLabels  = PetscMax(numLabels, 10);
746     numColors  = 10;
747     numLColors = 10;
748     ierr = PetscCalloc3(numLabels, &names, numColors, &colors, numLColors, &lcolors);CHKERRQ(ierr);
749     ierr = PetscOptionsGetReal(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_scale", &scale, NULL);CHKERRQ(ierr);
750     ierr = PetscOptionsGetReal(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_tikzscale", &tikzscale, NULL);CHKERRQ(ierr);
751     ierr = PetscOptionsGetBool(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_numbers", &useNumbers, NULL);CHKERRQ(ierr);
752     ierr = PetscOptionsGetStringArray(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_labels", names, &numLabels, &useLabels);CHKERRQ(ierr);
753     if (!useLabels) numLabels = 0;
754     ierr = PetscOptionsGetStringArray(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_colors", colors, &numColors, &useColors);CHKERRQ(ierr);
755     if (!useColors) {
756       numColors = 3;
757       for (c = 0; c < numColors; ++c) {ierr = PetscStrallocpy(defcolors[c], &colors[c]);CHKERRQ(ierr);}
758     }
759     ierr = PetscOptionsGetStringArray(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_lcolors", lcolors, &numLColors, &useColors);CHKERRQ(ierr);
760     if (!useColors) {
761       numLColors = 4;
762       for (c = 0; c < numLColors; ++c) {ierr = PetscStrallocpy(deflcolors[c], &lcolors[c]);CHKERRQ(ierr);}
763     }
764     ierr = PetscOptionsGetString(((PetscObject) viewer)->options, ((PetscObject) viewer)->prefix, "-dm_plex_view_label_filter", lname, sizeof(lname), &lflg);CHKERRQ(ierr);
765     plotEdges = (PetscBool)(depth > 1 && useNumbers && dim < 3);
766     ierr = PetscOptionsGetBool(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_edges", &plotEdges, &flg);CHKERRQ(ierr);
767     if (flg && plotEdges && depth < dim) SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Mesh must be interpolated");
768     if (depth < dim) plotEdges = PETSC_FALSE;
769 
770     /* filter points with labelvalue != labeldefaultvalue */
771     ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
772     if (lflg) {
773       DMLabel lbl;
774 
775       ierr = DMGetLabel(dm, lname, &lbl);CHKERRQ(ierr);
776       if (lbl) {
777         PetscInt val, defval;
778 
779         ierr = DMLabelGetDefaultValue(lbl, &defval);CHKERRQ(ierr);
780         ierr = PetscBTCreate(pEnd-pStart, &wp);CHKERRQ(ierr);
781         for (c = pStart;  c < pEnd; c++) {
782           PetscInt *closure = NULL;
783           PetscInt  closureSize;
784 
785           ierr = DMLabelGetValue(lbl, c, &val);CHKERRQ(ierr);
786           if (val == defval) continue;
787 
788           ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
789           for (p = 0; p < closureSize*2; p += 2) {
790             ierr = PetscBTSet(wp, closure[p] - pStart);CHKERRQ(ierr);
791           }
792           ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
793         }
794       }
795     }
796 
797     ierr = MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank);CHKERRMPI(ierr);
798     ierr = MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size);CHKERRMPI(ierr);
799     ierr = PetscObjectGetName((PetscObject) dm, &name);CHKERRQ(ierr);
800     ierr = PetscViewerASCIIPrintf(viewer, "\
801 \\documentclass[tikz]{standalone}\n\n\
802 \\usepackage{pgflibraryshapes}\n\
803 \\usetikzlibrary{backgrounds}\n\
804 \\usetikzlibrary{arrows}\n\
805 \\begin{document}\n");CHKERRQ(ierr);
806     if (size > 1) {
807       ierr = PetscViewerASCIIPrintf(viewer, "%s for process ", name);CHKERRQ(ierr);
808       for (p = 0; p < size; ++p) {
809         if (p > 0 && p == size-1) {
810           ierr = PetscViewerASCIIPrintf(viewer, ", and ", colors[p%numColors], p);CHKERRQ(ierr);
811         } else if (p > 0) {
812           ierr = PetscViewerASCIIPrintf(viewer, ", ", colors[p%numColors], p);CHKERRQ(ierr);
813         }
814         ierr = PetscViewerASCIIPrintf(viewer, "{\\textcolor{%s}%D}", colors[p%numColors], p);CHKERRQ(ierr);
815       }
816       ierr = PetscViewerASCIIPrintf(viewer, ".\n\n\n");CHKERRQ(ierr);
817     }
818     ierr = PetscViewerASCIIPrintf(viewer, "\\begin{tikzpicture}[scale = %g,font=\\fontsize{8}{8}\\selectfont]\n", (double) tikzscale);CHKERRQ(ierr);
819 
820     /* Plot vertices */
821     ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
822     ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
823     ierr = PetscViewerASCIIPushSynchronized(viewer);CHKERRQ(ierr);
824     for (v = vStart; v < vEnd; ++v) {
825       PetscInt  off, dof, d;
826       PetscBool isLabeled = PETSC_FALSE;
827 
828       if (wp && !PetscBTLookup(wp,v - pStart)) continue;
829       ierr = PetscSectionGetDof(coordSection, v, &dof);CHKERRQ(ierr);
830       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
831       ierr = PetscViewerASCIISynchronizedPrintf(viewer, "\\path (");CHKERRQ(ierr);
832       if (PetscUnlikely(dof > 3)) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_PLIB,"coordSection vertex %D has dof %D > 3",v,dof);
833       for (d = 0; d < dof; ++d) {
834         tcoords[d] = (double) (scale*PetscRealPart(coords[off+d]));
835         tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d];
836       }
837       /* Rotate coordinates since PGF makes z point out of the page instead of up */
838       if (dim == 3) {PetscReal tmp = tcoords[1]; tcoords[1] = tcoords[2]; tcoords[2] = -tmp;}
839       for (d = 0; d < dof; ++d) {
840         if (d > 0) {ierr = PetscViewerASCIISynchronizedPrintf(viewer, ",");CHKERRQ(ierr);}
841         ierr = PetscViewerASCIISynchronizedPrintf(viewer, "%g", (double) tcoords[d]);CHKERRQ(ierr);
842       }
843       color = colors[rank%numColors];
844       for (l = 0; l < numLabels; ++l) {
845         PetscInt val;
846         ierr = DMGetLabelValue(dm, names[l], v, &val);CHKERRQ(ierr);
847         if (val >= 0) {color = lcolors[l%numLColors]; isLabeled = PETSC_TRUE; break;}
848       }
849       if (useNumbers) {
850         ierr = PetscViewerASCIISynchronizedPrintf(viewer, ") node(%D_%d) [draw,shape=circle,color=%s] {%D};\n", v, rank, color, v);CHKERRQ(ierr);
851       } else {
852         ierr = PetscViewerASCIISynchronizedPrintf(viewer, ") node(%D_%d) [fill,inner sep=%dpt,shape=circle,color=%s] {};\n", v, rank, !isLabeled ? 1 : 2, color);CHKERRQ(ierr);
853       }
854     }
855     ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
856     ierr = PetscViewerFlush(viewer);CHKERRQ(ierr);
857     /* Plot cells */
858     ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
859     ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
860     if (dim == 3 || !useNumbers) {
861       for (e = eStart; e < eEnd; ++e) {
862         const PetscInt *cone;
863 
864         if (wp && !PetscBTLookup(wp,e - pStart)) continue;
865         color = colors[rank%numColors];
866         for (l = 0; l < numLabels; ++l) {
867           PetscInt val;
868           ierr = DMGetLabelValue(dm, names[l], e, &val);CHKERRQ(ierr);
869           if (val >= 0) {color = lcolors[l%numLColors]; break;}
870         }
871         ierr = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
872         ierr = PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] (%D_%d) -- (%D_%d);\n", color, cone[0], rank, cone[1], rank);CHKERRQ(ierr);
873       }
874     } else {
875       for (c = cStart; c < cEnd; ++c) {
876         PetscInt *closure = NULL;
877         PetscInt  closureSize, firstPoint = -1;
878 
879         if (wp && !PetscBTLookup(wp,c - pStart)) continue;
880         ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
881         ierr = PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] ", colors[rank%numColors]);CHKERRQ(ierr);
882         for (p = 0; p < closureSize*2; p += 2) {
883           const PetscInt point = closure[p];
884 
885           if ((point < vStart) || (point >= vEnd)) continue;
886           if (firstPoint >= 0) {ierr = PetscViewerASCIISynchronizedPrintf(viewer, " -- ");CHKERRQ(ierr);}
887           ierr = PetscViewerASCIISynchronizedPrintf(viewer, "(%D_%d)", point, rank);CHKERRQ(ierr);
888           if (firstPoint < 0) firstPoint = point;
889         }
890         /* Why doesn't this work? ierr = PetscViewerASCIISynchronizedPrintf(viewer, " -- cycle;\n");CHKERRQ(ierr); */
891         ierr = PetscViewerASCIISynchronizedPrintf(viewer, " -- (%D_%d);\n", firstPoint, rank);CHKERRQ(ierr);
892         ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
893       }
894     }
895     ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
896     for (c = cStart; c < cEnd; ++c) {
897       double    ccoords[3] = {0.0, 0.0, 0.0};
898       PetscBool isLabeled  = PETSC_FALSE;
899       PetscInt *closure    = NULL;
900       PetscInt  closureSize, dof, d, n = 0;
901 
902       if (wp && !PetscBTLookup(wp,c - pStart)) continue;
903       ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
904       ierr = PetscViewerASCIISynchronizedPrintf(viewer, "\\path (");CHKERRQ(ierr);
905       for (p = 0; p < closureSize*2; p += 2) {
906         const PetscInt point = closure[p];
907         PetscInt       off;
908 
909         if ((point < vStart) || (point >= vEnd)) continue;
910         ierr = PetscSectionGetDof(coordSection, point, &dof);CHKERRQ(ierr);
911         ierr = PetscSectionGetOffset(coordSection, point, &off);CHKERRQ(ierr);
912         for (d = 0; d < dof; ++d) {
913           tcoords[d] = (double) (scale*PetscRealPart(coords[off+d]));
914           tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d];
915         }
916         /* Rotate coordinates since PGF makes z point out of the page instead of up */
917         if (dof == 3) {PetscReal tmp = tcoords[1]; tcoords[1] = tcoords[2]; tcoords[2] = -tmp;}
918         for (d = 0; d < dof; ++d) {ccoords[d] += tcoords[d];}
919         ++n;
920       }
921       for (d = 0; d < dof; ++d) {ccoords[d] /= n;}
922       ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
923       for (d = 0; d < dof; ++d) {
924         if (d > 0) {ierr = PetscViewerASCIISynchronizedPrintf(viewer, ",");CHKERRQ(ierr);}
925         ierr = PetscViewerASCIISynchronizedPrintf(viewer, "%g", (double) ccoords[d]);CHKERRQ(ierr);
926       }
927       color = colors[rank%numColors];
928       for (l = 0; l < numLabels; ++l) {
929         PetscInt val;
930         ierr = DMGetLabelValue(dm, names[l], c, &val);CHKERRQ(ierr);
931         if (val >= 0) {color = lcolors[l%numLColors]; isLabeled = PETSC_TRUE; break;}
932       }
933       if (useNumbers) {
934         ierr = PetscViewerASCIISynchronizedPrintf(viewer, ") node(%D_%d) [draw,shape=circle,color=%s] {%D};\n", c, rank, color, c);CHKERRQ(ierr);
935       } else {
936         ierr = PetscViewerASCIISynchronizedPrintf(viewer, ") node(%D_%d) [fill,inner sep=%dpt,shape=circle,color=%s] {};\n", c, rank, !isLabeled ? 1 : 2, color);CHKERRQ(ierr);
937       }
938     }
939     ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
940     /* Plot edges */
941     if (plotEdges) {
942       ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
943       ierr = PetscViewerASCIIPrintf(viewer, "\\path\n");CHKERRQ(ierr);
944       for (e = eStart; e < eEnd; ++e) {
945         const PetscInt *cone;
946         PetscInt        coneSize, offA, offB, dof, d;
947 
948         if (wp && !PetscBTLookup(wp,e - pStart)) continue;
949         ierr = DMPlexGetConeSize(dm, e, &coneSize);CHKERRQ(ierr);
950         if (coneSize != 2) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Edge %D cone should have two vertices, not %D", e, coneSize);
951         ierr = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
952         ierr = PetscSectionGetDof(coordSection, cone[0], &dof);CHKERRQ(ierr);
953         ierr = PetscSectionGetOffset(coordSection, cone[0], &offA);CHKERRQ(ierr);
954         ierr = PetscSectionGetOffset(coordSection, cone[1], &offB);CHKERRQ(ierr);
955         ierr = PetscViewerASCIISynchronizedPrintf(viewer, "(");CHKERRQ(ierr);
956         for (d = 0; d < dof; ++d) {
957           tcoords[d] = (double) (0.5*scale*PetscRealPart(coords[offA+d]+coords[offB+d]));
958           tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d];
959         }
960         /* Rotate coordinates since PGF makes z point out of the page instead of up */
961         if (dim == 3) {PetscReal tmp = tcoords[1]; tcoords[1] = tcoords[2]; tcoords[2] = -tmp;}
962         for (d = 0; d < dof; ++d) {
963           if (d > 0) {ierr = PetscViewerASCIISynchronizedPrintf(viewer, ",");CHKERRQ(ierr);}
964           ierr = PetscViewerASCIISynchronizedPrintf(viewer, "%g", (double)tcoords[d]);CHKERRQ(ierr);
965         }
966         color = colors[rank%numColors];
967         for (l = 0; l < numLabels; ++l) {
968           PetscInt val;
969           ierr = DMGetLabelValue(dm, names[l], v, &val);CHKERRQ(ierr);
970           if (val >= 0) {color = lcolors[l%numLColors]; break;}
971         }
972         ierr = PetscViewerASCIISynchronizedPrintf(viewer, ") node(%D_%d) [draw,shape=circle,color=%s] {%D} --\n", e, rank, color, e);CHKERRQ(ierr);
973       }
974       ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
975       ierr = PetscViewerFlush(viewer);CHKERRQ(ierr);
976       ierr = PetscViewerASCIIPrintf(viewer, "(0,0);\n");CHKERRQ(ierr);
977     }
978     ierr = PetscViewerFlush(viewer);CHKERRQ(ierr);
979     ierr = PetscViewerASCIIPopSynchronized(viewer);CHKERRQ(ierr);
980     ierr = PetscViewerASCIIPrintf(viewer, "\\end{tikzpicture}\n");CHKERRQ(ierr);
981     ierr = PetscViewerASCIIPrintf(viewer, "\\end{document}\n", name);CHKERRQ(ierr);
982     for (l = 0; l < numLabels;  ++l) {ierr = PetscFree(names[l]);CHKERRQ(ierr);}
983     for (c = 0; c < numColors;  ++c) {ierr = PetscFree(colors[c]);CHKERRQ(ierr);}
984     for (c = 0; c < numLColors; ++c) {ierr = PetscFree(lcolors[c]);CHKERRQ(ierr);}
985     ierr = PetscFree3(names, colors, lcolors);CHKERRQ(ierr);
986     ierr = PetscBTDestroy(&wp);CHKERRQ(ierr);
987   } else if (format == PETSC_VIEWER_LOAD_BALANCE) {
988     Vec                    cown,acown;
989     VecScatter             sct;
990     ISLocalToGlobalMapping g2l;
991     IS                     gid,acis;
992     MPI_Comm               comm,ncomm = MPI_COMM_NULL;
993     MPI_Group              ggroup,ngroup;
994     PetscScalar            *array,nid;
995     const PetscInt         *idxs;
996     PetscInt               *idxs2,*start,*adjacency,*work;
997     PetscInt64             lm[3],gm[3];
998     PetscInt               i,c,cStart,cEnd,cum,numVertices,ect,ectn,cellHeight;
999     PetscMPIInt            d1,d2,rank;
1000 
1001     ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr);
1002     ierr = MPI_Comm_rank(comm,&rank);CHKERRMPI(ierr);
1003 #if defined(PETSC_HAVE_MPI_PROCESS_SHARED_MEMORY)
1004     ierr = MPI_Comm_split_type(comm,MPI_COMM_TYPE_SHARED,rank,MPI_INFO_NULL,&ncomm);CHKERRMPI(ierr);
1005 #endif
1006     if (ncomm != MPI_COMM_NULL) {
1007       ierr = MPI_Comm_group(comm,&ggroup);CHKERRMPI(ierr);
1008       ierr = MPI_Comm_group(ncomm,&ngroup);CHKERRMPI(ierr);
1009       d1   = 0;
1010       ierr = MPI_Group_translate_ranks(ngroup,1,&d1,ggroup,&d2);CHKERRMPI(ierr);
1011       nid  = d2;
1012       ierr = MPI_Group_free(&ggroup);CHKERRMPI(ierr);
1013       ierr = MPI_Group_free(&ngroup);CHKERRMPI(ierr);
1014       ierr = MPI_Comm_free(&ncomm);CHKERRMPI(ierr);
1015     } else nid = 0.0;
1016 
1017     /* Get connectivity */
1018     ierr = DMPlexGetVTKCellHeight(dm,&cellHeight);CHKERRQ(ierr);
1019     ierr = DMPlexCreatePartitionerGraph(dm,cellHeight,&numVertices,&start,&adjacency,&gid);CHKERRQ(ierr);
1020 
1021     /* filter overlapped local cells */
1022     ierr = DMPlexGetHeightStratum(dm,cellHeight,&cStart,&cEnd);CHKERRQ(ierr);
1023     ierr = ISGetIndices(gid,&idxs);CHKERRQ(ierr);
1024     ierr = ISGetLocalSize(gid,&cum);CHKERRQ(ierr);
1025     ierr = PetscMalloc1(cum,&idxs2);CHKERRQ(ierr);
1026     for (c = cStart, cum = 0; c < cEnd; c++) {
1027       if (idxs[c-cStart] < 0) continue;
1028       idxs2[cum++] = idxs[c-cStart];
1029     }
1030     ierr = ISRestoreIndices(gid,&idxs);CHKERRQ(ierr);
1031     if (numVertices != cum) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Unexpected %D != %D",numVertices,cum);
1032     ierr = ISDestroy(&gid);CHKERRQ(ierr);
1033     ierr = ISCreateGeneral(comm,numVertices,idxs2,PETSC_OWN_POINTER,&gid);CHKERRQ(ierr);
1034 
1035     /* support for node-aware cell locality */
1036     ierr = ISCreateGeneral(comm,start[numVertices],adjacency,PETSC_USE_POINTER,&acis);CHKERRQ(ierr);
1037     ierr = VecCreateSeq(PETSC_COMM_SELF,start[numVertices],&acown);CHKERRQ(ierr);
1038     ierr = VecCreateMPI(comm,numVertices,PETSC_DECIDE,&cown);CHKERRQ(ierr);
1039     ierr = VecGetArray(cown,&array);CHKERRQ(ierr);
1040     for (c = 0; c < numVertices; c++) array[c] = nid;
1041     ierr = VecRestoreArray(cown,&array);CHKERRQ(ierr);
1042     ierr = VecScatterCreate(cown,acis,acown,NULL,&sct);CHKERRQ(ierr);
1043     ierr = VecScatterBegin(sct,cown,acown,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
1044     ierr = VecScatterEnd(sct,cown,acown,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
1045     ierr = ISDestroy(&acis);CHKERRQ(ierr);
1046     ierr = VecScatterDestroy(&sct);CHKERRQ(ierr);
1047     ierr = VecDestroy(&cown);CHKERRQ(ierr);
1048 
1049     /* compute edgeCut */
1050     for (c = 0, cum = 0; c < numVertices; c++) cum = PetscMax(cum,start[c+1]-start[c]);
1051     ierr = PetscMalloc1(cum,&work);CHKERRQ(ierr);
1052     ierr = ISLocalToGlobalMappingCreateIS(gid,&g2l);CHKERRQ(ierr);
1053     ierr = ISLocalToGlobalMappingSetType(g2l,ISLOCALTOGLOBALMAPPINGHASH);CHKERRQ(ierr);
1054     ierr = ISDestroy(&gid);CHKERRQ(ierr);
1055     ierr = VecGetArray(acown,&array);CHKERRQ(ierr);
1056     for (c = 0, ect = 0, ectn = 0; c < numVertices; c++) {
1057       PetscInt totl;
1058 
1059       totl = start[c+1]-start[c];
1060       ierr = ISGlobalToLocalMappingApply(g2l,IS_GTOLM_MASK,totl,adjacency+start[c],NULL,work);CHKERRQ(ierr);
1061       for (i = 0; i < totl; i++) {
1062         if (work[i] < 0) {
1063           ect  += 1;
1064           ectn += (array[i + start[c]] != nid) ? 0 : 1;
1065         }
1066       }
1067     }
1068     ierr  = PetscFree(work);CHKERRQ(ierr);
1069     ierr  = VecRestoreArray(acown,&array);CHKERRQ(ierr);
1070     lm[0] = numVertices > 0 ?  numVertices : PETSC_MAX_INT;
1071     lm[1] = -numVertices;
1072     ierr  = MPIU_Allreduce(lm,gm,2,MPIU_INT64,MPI_MIN,comm);CHKERRMPI(ierr);
1073     ierr  = PetscViewerASCIIPrintf(viewer,"  Cell balance: %.2f (max %D, min %D",-((double)gm[1])/((double)gm[0]),-(PetscInt)gm[1],(PetscInt)gm[0]);CHKERRQ(ierr);
1074     lm[0] = ect; /* edgeCut */
1075     lm[1] = ectn; /* node-aware edgeCut */
1076     lm[2] = numVertices > 0 ? 0 : 1; /* empty processes */
1077     ierr  = MPIU_Allreduce(lm,gm,3,MPIU_INT64,MPI_SUM,comm);CHKERRMPI(ierr);
1078     ierr  = PetscViewerASCIIPrintf(viewer,", empty %D)\n",(PetscInt)gm[2]);CHKERRQ(ierr);
1079 #if defined(PETSC_HAVE_MPI_PROCESS_SHARED_MEMORY)
1080     ierr  = PetscViewerASCIIPrintf(viewer,"  Edge Cut: %D (on node %.3f)\n",(PetscInt)(gm[0]/2),gm[0] ? ((double)(gm[1]))/((double)gm[0]) : 1.);CHKERRQ(ierr);
1081 #else
1082     ierr  = PetscViewerASCIIPrintf(viewer,"  Edge Cut: %D (on node %.3f)\n",(PetscInt)(gm[0]/2),0.0);CHKERRQ(ierr);
1083 #endif
1084     ierr  = ISLocalToGlobalMappingDestroy(&g2l);CHKERRQ(ierr);
1085     ierr  = PetscFree(start);CHKERRQ(ierr);
1086     ierr  = PetscFree(adjacency);CHKERRQ(ierr);
1087     ierr  = VecDestroy(&acown);CHKERRQ(ierr);
1088   } else {
1089     const char    *name;
1090     PetscInt      *sizes, *hybsizes, *ghostsizes;
1091     PetscInt       locDepth, depth, cellHeight, dim, d;
1092     PetscInt       pStart, pEnd, p, gcStart, gcEnd, gcNum;
1093     PetscInt       numLabels, l;
1094     DMPolytopeType ct0 = DM_POLYTOPE_UNKNOWN;
1095     MPI_Comm       comm;
1096     PetscMPIInt    size, rank;
1097 
1098     ierr = PetscObjectGetComm((PetscObject) dm, &comm);CHKERRQ(ierr);
1099     ierr = MPI_Comm_size(comm, &size);CHKERRMPI(ierr);
1100     ierr = MPI_Comm_rank(comm, &rank);CHKERRMPI(ierr);
1101     ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr);
1102     ierr = DMPlexGetVTKCellHeight(dm, &cellHeight);CHKERRQ(ierr);
1103     ierr = PetscObjectGetName((PetscObject) dm, &name);CHKERRQ(ierr);
1104     if (name) {ierr = PetscViewerASCIIPrintf(viewer, "%s in %D dimension%s:\n", name, dim, dim == 1 ? "" : "s");CHKERRQ(ierr);}
1105     else      {ierr = PetscViewerASCIIPrintf(viewer, "Mesh in %D dimension%s:\n", dim, dim == 1 ? "" : "s");CHKERRQ(ierr);}
1106     if (cellHeight) {ierr = PetscViewerASCIIPrintf(viewer, "  Cells are at height %D\n", cellHeight);CHKERRQ(ierr);}
1107     ierr = DMPlexGetDepth(dm, &locDepth);CHKERRQ(ierr);
1108     ierr = MPIU_Allreduce(&locDepth, &depth, 1, MPIU_INT, MPI_MAX, comm);CHKERRMPI(ierr);
1109     ierr = DMPlexGetGhostCellStratum(dm, &gcStart, &gcEnd);CHKERRQ(ierr);
1110     gcNum = gcEnd - gcStart;
1111     ierr = PetscCalloc3(size,&sizes,size,&hybsizes,size,&ghostsizes);CHKERRQ(ierr);
1112     for (d = 0; d <= depth; d++) {
1113       PetscInt Nc[2] = {0, 0}, ict;
1114 
1115       ierr = DMPlexGetDepthStratum(dm, d, &pStart, &pEnd);CHKERRQ(ierr);
1116       if (pStart < pEnd) {ierr = DMPlexGetCellType(dm, pStart, &ct0);CHKERRQ(ierr);}
1117       ict  = ct0;
1118       ierr = MPI_Bcast(&ict, 1, MPIU_INT, 0, comm);CHKERRMPI(ierr);
1119       ct0  = (DMPolytopeType) ict;
1120       for (p = pStart; p < pEnd; ++p) {
1121         DMPolytopeType ct;
1122 
1123         ierr = DMPlexGetCellType(dm, p, &ct);CHKERRQ(ierr);
1124         if (ct == ct0) ++Nc[0];
1125         else           ++Nc[1];
1126       }
1127       ierr = MPI_Gather(&Nc[0], 1, MPIU_INT, sizes,    1, MPIU_INT, 0, comm);CHKERRMPI(ierr);
1128       ierr = MPI_Gather(&Nc[1], 1, MPIU_INT, hybsizes, 1, MPIU_INT, 0, comm);CHKERRMPI(ierr);
1129       if (d == depth) {ierr = MPI_Gather(&gcNum, 1, MPIU_INT, ghostsizes, 1, MPIU_INT, 0, comm);CHKERRMPI(ierr);}
1130       ierr = PetscViewerASCIIPrintf(viewer, "  %D-cells:", (depth == 1) && d ? dim : d);CHKERRQ(ierr);
1131       for (p = 0; p < size; ++p) {
1132         if (!rank) {
1133           ierr = PetscViewerASCIIPrintf(viewer, " %D", sizes[p]+hybsizes[p]);CHKERRQ(ierr);
1134           if (hybsizes[p]   > 0) {ierr = PetscViewerASCIIPrintf(viewer, " (%D)", hybsizes[p]);CHKERRQ(ierr);}
1135           if (ghostsizes[p] > 0) {ierr = PetscViewerASCIIPrintf(viewer, " [%D]", ghostsizes[p]);CHKERRQ(ierr);}
1136         }
1137       }
1138       ierr = PetscViewerASCIIPrintf(viewer, "\n");CHKERRQ(ierr);
1139     }
1140     ierr = PetscFree3(sizes,hybsizes,ghostsizes);CHKERRQ(ierr);
1141     {
1142       const PetscReal      *maxCell;
1143       const PetscReal      *L;
1144       const DMBoundaryType *bd;
1145       PetscBool             per, localized;
1146 
1147       ierr = DMGetPeriodicity(dm, &per, &maxCell, &L, &bd);CHKERRQ(ierr);
1148       ierr = DMGetCoordinatesLocalized(dm, &localized);CHKERRQ(ierr);
1149       if (per) {
1150         ierr = PetscViewerASCIIPrintf(viewer, "Periodic mesh (");CHKERRQ(ierr);
1151         ierr = PetscViewerASCIIUseTabs(viewer, PETSC_FALSE);CHKERRQ(ierr);
1152         for (d = 0; d < dim; ++d) {
1153           if (bd && d > 0) {ierr = PetscViewerASCIIPrintf(viewer, ", ");CHKERRQ(ierr);}
1154           if (bd)    {ierr = PetscViewerASCIIPrintf(viewer, "%s", DMBoundaryTypes[bd[d]]);CHKERRQ(ierr);}
1155         }
1156         ierr = PetscViewerASCIIPrintf(viewer, ") coordinates %s\n", localized ? "localized" : "not localized");CHKERRQ(ierr);
1157         ierr = PetscViewerASCIIUseTabs(viewer, PETSC_TRUE);CHKERRQ(ierr);
1158       }
1159     }
1160     ierr = DMGetNumLabels(dm, &numLabels);CHKERRQ(ierr);
1161     if (numLabels) {ierr = PetscViewerASCIIPrintf(viewer, "Labels:\n");CHKERRQ(ierr);}
1162     for (l = 0; l < numLabels; ++l) {
1163       DMLabel         label;
1164       const char     *name;
1165       IS              valueIS;
1166       const PetscInt *values;
1167       PetscInt        numValues, v;
1168 
1169       ierr = DMGetLabelName(dm, l, &name);CHKERRQ(ierr);
1170       ierr = DMGetLabel(dm, name, &label);CHKERRQ(ierr);
1171       ierr = DMLabelGetNumValues(label, &numValues);CHKERRQ(ierr);
1172       ierr = PetscViewerASCIIPrintf(viewer, "  %s: %D strata with value/size (", name, numValues);CHKERRQ(ierr);
1173       ierr = DMLabelGetValueIS(label, &valueIS);CHKERRQ(ierr);
1174       ierr = ISGetIndices(valueIS, &values);CHKERRQ(ierr);
1175       ierr = PetscViewerASCIIUseTabs(viewer, PETSC_FALSE);CHKERRQ(ierr);
1176       for (v = 0; v < numValues; ++v) {
1177         PetscInt size;
1178 
1179         ierr = DMLabelGetStratumSize(label, values[v], &size);CHKERRQ(ierr);
1180         if (v > 0) {ierr = PetscViewerASCIIPrintf(viewer, ", ");CHKERRQ(ierr);}
1181         ierr = PetscViewerASCIIPrintf(viewer, "%D (%D)", values[v], size);CHKERRQ(ierr);
1182       }
1183       ierr = PetscViewerASCIIPrintf(viewer, ")\n");CHKERRQ(ierr);
1184       ierr = PetscViewerASCIIUseTabs(viewer, PETSC_TRUE);CHKERRQ(ierr);
1185       ierr = ISRestoreIndices(valueIS, &values);CHKERRQ(ierr);
1186       ierr = ISDestroy(&valueIS);CHKERRQ(ierr);
1187     }
1188     /* If no fields are specified, people do not want to see adjacency */
1189     if (dm->Nf) {
1190       PetscInt f;
1191 
1192       for (f = 0; f < dm->Nf; ++f) {
1193         const char *name;
1194 
1195         ierr = PetscObjectGetName(dm->fields[f].disc, &name);CHKERRQ(ierr);
1196         if (numLabels) {ierr = PetscViewerASCIIPrintf(viewer, "Field %s:\n", name);CHKERRQ(ierr);}
1197         ierr = PetscViewerASCIIPushTab(viewer);CHKERRQ(ierr);
1198         if (dm->fields[f].label) {ierr = DMLabelView(dm->fields[f].label, viewer);CHKERRQ(ierr);}
1199         if (dm->fields[f].adjacency[0]) {
1200           if (dm->fields[f].adjacency[1]) {ierr = PetscViewerASCIIPrintf(viewer, "adjacency FVM++\n");CHKERRQ(ierr);}
1201           else                            {ierr = PetscViewerASCIIPrintf(viewer, "adjacency FVM\n");CHKERRQ(ierr);}
1202         } else {
1203           if (dm->fields[f].adjacency[1]) {ierr = PetscViewerASCIIPrintf(viewer, "adjacency FEM\n");CHKERRQ(ierr);}
1204           else                            {ierr = PetscViewerASCIIPrintf(viewer, "adjacency FUNKY\n");CHKERRQ(ierr);}
1205         }
1206         ierr = PetscViewerASCIIPopTab(viewer);CHKERRQ(ierr);
1207       }
1208     }
1209     ierr = DMGetCoarseDM(dm, &cdm);CHKERRQ(ierr);
1210     if (cdm) {
1211       ierr = PetscViewerASCIIPushTab(viewer);CHKERRQ(ierr);
1212       ierr = DMPlexView_Ascii(cdm, viewer);CHKERRQ(ierr);
1213       ierr = PetscViewerASCIIPopTab(viewer);CHKERRQ(ierr);
1214     }
1215   }
1216   PetscFunctionReturn(0);
1217 }
1218 
1219 static PetscErrorCode DMPlexDrawCell(DM dm, PetscDraw draw, PetscInt cell, const PetscScalar coords[])
1220 {
1221   DMPolytopeType ct;
1222   PetscMPIInt    rank;
1223   PetscErrorCode ierr;
1224 
1225   PetscFunctionBegin;
1226   ierr = MPI_Comm_rank(PetscObjectComm((PetscObject) dm), &rank);CHKERRMPI(ierr);
1227   ierr = DMPlexGetCellType(dm, cell, &ct);CHKERRQ(ierr);
1228   switch (ct) {
1229   case DM_POLYTOPE_TRIANGLE:
1230     ierr = PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]),
1231                              PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2,
1232                              PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2,
1233                              PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2);CHKERRQ(ierr);
1234     ierr = PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK);CHKERRQ(ierr);
1235     ierr = PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK);CHKERRQ(ierr);
1236     ierr = PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK);CHKERRQ(ierr);
1237     break;
1238   case DM_POLYTOPE_QUADRILATERAL:
1239     ierr = PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]),
1240                               PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2,
1241                               PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2,
1242                               PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2);CHKERRQ(ierr);
1243     ierr = PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[6]), PetscRealPart(coords[7]),
1244                               PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2,
1245                               PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2,
1246                               PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2);CHKERRQ(ierr);
1247     ierr = PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK);CHKERRQ(ierr);
1248     ierr = PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK);CHKERRQ(ierr);
1249     ierr = PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), PETSC_DRAW_BLACK);CHKERRQ(ierr);
1250     ierr = PetscDrawLine(draw, PetscRealPart(coords[6]), PetscRealPart(coords[7]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK);CHKERRQ(ierr);
1251     break;
1252   default: SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of type %s", DMPolytopeTypes[ct]);
1253   }
1254   PetscFunctionReturn(0);
1255 }
1256 
1257 static PetscErrorCode DMPlexDrawCellHighOrder(DM dm, PetscDraw draw, PetscInt cell, const PetscScalar coords[], PetscInt edgeDiv, PetscReal refCoords[], PetscReal edgeCoords[])
1258 {
1259   DMPolytopeType ct;
1260   PetscReal      centroid[2] = {0., 0.};
1261   PetscMPIInt    rank;
1262   PetscInt       fillColor, v, e, d;
1263   PetscErrorCode ierr;
1264 
1265   PetscFunctionBegin;
1266   ierr = MPI_Comm_rank(PetscObjectComm((PetscObject) dm), &rank);CHKERRMPI(ierr);
1267   ierr = DMPlexGetCellType(dm, cell, &ct);CHKERRQ(ierr);
1268   fillColor = PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2;
1269   switch (ct) {
1270   case DM_POLYTOPE_TRIANGLE:
1271     {
1272       PetscReal refVertices[6] = {-1., -1., 1., -1., -1., 1.};
1273 
1274       for (v = 0; v < 3; ++v) {centroid[0] += PetscRealPart(coords[v*2+0])/3.;centroid[1] += PetscRealPart(coords[v*2+1])/3.;}
1275       for (e = 0; e < 3; ++e) {
1276         refCoords[0] = refVertices[e*2+0];
1277         refCoords[1] = refVertices[e*2+1];
1278         for (d = 1; d <= edgeDiv; ++d) {
1279           refCoords[d*2+0] = refCoords[0] + (refVertices[(e+1)%3 * 2 + 0] - refCoords[0])*d/edgeDiv;
1280           refCoords[d*2+1] = refCoords[1] + (refVertices[(e+1)%3 * 2 + 1] - refCoords[1])*d/edgeDiv;
1281         }
1282         ierr = DMPlexReferenceToCoordinates(dm, cell, edgeDiv+1, refCoords, edgeCoords);CHKERRQ(ierr);
1283         for (d = 0; d < edgeDiv; ++d) {
1284           ierr = PetscDrawTriangle(draw, centroid[0], centroid[1], edgeCoords[d*2+0], edgeCoords[d*2+1], edgeCoords[(d+1)*2+0], edgeCoords[(d+1)*2+1], fillColor, fillColor, fillColor);CHKERRQ(ierr);
1285           ierr = PetscDrawLine(draw, edgeCoords[d*2+0], edgeCoords[d*2+1], edgeCoords[(d+1)*2+0], edgeCoords[(d+1)*2+1], PETSC_DRAW_BLACK);CHKERRQ(ierr);
1286         }
1287       }
1288     }
1289     break;
1290   default: SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of type %s", DMPolytopeTypes[ct]);
1291   }
1292   PetscFunctionReturn(0);
1293 }
1294 
1295 static PetscErrorCode DMPlexView_Draw(DM dm, PetscViewer viewer)
1296 {
1297   PetscDraw          draw;
1298   DM                 cdm;
1299   PetscSection       coordSection;
1300   Vec                coordinates;
1301   const PetscScalar *coords;
1302   PetscReal          xyl[2],xyr[2],bound[4] = {PETSC_MAX_REAL, PETSC_MAX_REAL, PETSC_MIN_REAL, PETSC_MIN_REAL};
1303   PetscReal         *refCoords, *edgeCoords;
1304   PetscBool          isnull, drawAffine = PETSC_TRUE;
1305   PetscInt           dim, vStart, vEnd, cStart, cEnd, c, N, edgeDiv = 4;
1306   PetscErrorCode     ierr;
1307 
1308   PetscFunctionBegin;
1309   ierr = DMGetCoordinateDim(dm, &dim);CHKERRQ(ierr);
1310   if (dim != 2) SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Cannot draw meshes of dimension %D", dim);
1311   ierr = PetscOptionsGetBool(((PetscObject) dm)->options, ((PetscObject) dm)->prefix, "-dm_view_draw_affine", &drawAffine, NULL);CHKERRQ(ierr);
1312   if (!drawAffine) {ierr = PetscMalloc2((edgeDiv+1)*dim, &refCoords, (edgeDiv+1)*dim, &edgeCoords);CHKERRQ(ierr);}
1313   ierr = DMGetCoordinateDM(dm, &cdm);CHKERRQ(ierr);
1314   ierr = DMGetLocalSection(cdm, &coordSection);CHKERRQ(ierr);
1315   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
1316   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
1317   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
1318 
1319   ierr = PetscViewerDrawGetDraw(viewer, 0, &draw);CHKERRQ(ierr);
1320   ierr = PetscDrawIsNull(draw, &isnull);CHKERRQ(ierr);
1321   if (isnull) PetscFunctionReturn(0);
1322   ierr = PetscDrawSetTitle(draw, "Mesh");CHKERRQ(ierr);
1323 
1324   ierr = VecGetLocalSize(coordinates, &N);CHKERRQ(ierr);
1325   ierr = VecGetArrayRead(coordinates, &coords);CHKERRQ(ierr);
1326   for (c = 0; c < N; c += dim) {
1327     bound[0] = PetscMin(bound[0], PetscRealPart(coords[c]));   bound[2] = PetscMax(bound[2], PetscRealPart(coords[c]));
1328     bound[1] = PetscMin(bound[1], PetscRealPart(coords[c+1])); bound[3] = PetscMax(bound[3], PetscRealPart(coords[c+1]));
1329   }
1330   ierr = VecRestoreArrayRead(coordinates, &coords);CHKERRQ(ierr);
1331   ierr = MPIU_Allreduce(&bound[0],xyl,2,MPIU_REAL,MPIU_MIN,PetscObjectComm((PetscObject)dm));CHKERRMPI(ierr);
1332   ierr = MPIU_Allreduce(&bound[2],xyr,2,MPIU_REAL,MPIU_MAX,PetscObjectComm((PetscObject)dm));CHKERRMPI(ierr);
1333   ierr = PetscDrawSetCoordinates(draw, xyl[0], xyl[1], xyr[0], xyr[1]);CHKERRQ(ierr);
1334   ierr = PetscDrawClear(draw);CHKERRQ(ierr);
1335 
1336   for (c = cStart; c < cEnd; ++c) {
1337     PetscScalar *coords = NULL;
1338     PetscInt     numCoords;
1339 
1340     ierr = DMPlexVecGetClosureAtDepth_Internal(dm, coordSection, coordinates, c, 0, &numCoords, &coords);CHKERRQ(ierr);
1341     if (drawAffine) {
1342       ierr = DMPlexDrawCell(dm, draw, c, coords);CHKERRQ(ierr);
1343     } else {
1344       ierr = DMPlexDrawCellHighOrder(dm, draw, c, coords, edgeDiv, refCoords, edgeCoords);CHKERRQ(ierr);
1345     }
1346     ierr = DMPlexVecRestoreClosure(dm, coordSection, coordinates, c, &numCoords, &coords);CHKERRQ(ierr);
1347   }
1348   if (!drawAffine) {ierr = PetscFree2(refCoords, edgeCoords);CHKERRQ(ierr);}
1349   ierr = PetscDrawFlush(draw);CHKERRQ(ierr);
1350   ierr = PetscDrawPause(draw);CHKERRQ(ierr);
1351   ierr = PetscDrawSave(draw);CHKERRQ(ierr);
1352   PetscFunctionReturn(0);
1353 }
1354 
1355 #if defined(PETSC_HAVE_EXODUSII)
1356 #include <exodusII.h>
1357 #include <petscviewerexodusii.h>
1358 #endif
1359 
1360 PetscErrorCode DMView_Plex(DM dm, PetscViewer viewer)
1361 {
1362   PetscBool      iascii, ishdf5, isvtk, isdraw, flg, isglvis, isexodus;
1363   char           name[PETSC_MAX_PATH_LEN];
1364   PetscErrorCode ierr;
1365 
1366   PetscFunctionBegin;
1367   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1368   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
1369   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERASCII,    &iascii);CHKERRQ(ierr);
1370   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERVTK,      &isvtk);CHKERRQ(ierr);
1371   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5,     &ishdf5);CHKERRQ(ierr);
1372   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERDRAW,     &isdraw);CHKERRQ(ierr);
1373   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERGLVIS,    &isglvis);CHKERRQ(ierr);
1374   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWEREXODUSII, &isexodus);CHKERRQ(ierr);
1375   if (iascii) {
1376     PetscViewerFormat format;
1377     ierr = PetscViewerGetFormat(viewer, &format);CHKERRQ(ierr);
1378     if (format == PETSC_VIEWER_ASCII_GLVIS) {
1379       ierr = DMPlexView_GLVis(dm, viewer);CHKERRQ(ierr);
1380     } else {
1381       ierr = DMPlexView_Ascii(dm, viewer);CHKERRQ(ierr);
1382     }
1383   } else if (ishdf5) {
1384 #if defined(PETSC_HAVE_HDF5)
1385     ierr = DMPlexView_HDF5_Internal(dm, viewer);CHKERRQ(ierr);
1386 #else
1387     SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
1388 #endif
1389   } else if (isvtk) {
1390     ierr = DMPlexVTKWriteAll((PetscObject) dm,viewer);CHKERRQ(ierr);
1391   } else if (isdraw) {
1392     ierr = DMPlexView_Draw(dm, viewer);CHKERRQ(ierr);
1393   } else if (isglvis) {
1394     ierr = DMPlexView_GLVis(dm, viewer);CHKERRQ(ierr);
1395 #if defined(PETSC_HAVE_EXODUSII)
1396   } else if (isexodus) {
1397 /*
1398       exodusII requires that all sets be part of exactly one cell set.
1399       If the dm does not have a "Cell Sets" label defined, we create one
1400       with ID 1, containig all cells.
1401       Note that if the Cell Sets label is defined but does not cover all cells,
1402       we may still have a problem. This should probably be checked here or in the viewer;
1403     */
1404     PetscInt numCS;
1405     ierr = DMGetLabelSize(dm,"Cell Sets",&numCS);CHKERRQ(ierr);
1406     if (!numCS) {
1407       PetscInt cStart, cEnd, c;
1408       ierr = DMCreateLabel(dm, "Cell Sets");CHKERRQ(ierr);
1409       ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
1410       for (c = cStart; c < cEnd; ++c) {ierr = DMSetLabelValue(dm, "Cell Sets", c, 1);CHKERRQ(ierr);}
1411     }
1412     ierr = DMView_PlexExodusII(dm, viewer);CHKERRQ(ierr);
1413 #endif
1414   } else {
1415     SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Viewer type %s not yet supported for DMPlex writing", ((PetscObject)viewer)->type_name);
1416   }
1417   /* Optionally view the partition */
1418   ierr = PetscOptionsHasName(((PetscObject) dm)->options, ((PetscObject) dm)->prefix, "-dm_partition_view", &flg);CHKERRQ(ierr);
1419   if (flg) {
1420     Vec ranks;
1421     ierr = DMPlexCreateRankField(dm, &ranks);CHKERRQ(ierr);
1422     ierr = VecView(ranks, viewer);CHKERRQ(ierr);
1423     ierr = VecDestroy(&ranks);CHKERRQ(ierr);
1424   }
1425   /* Optionally view a label */
1426   ierr = PetscOptionsGetString(((PetscObject) dm)->options, ((PetscObject) dm)->prefix, "-dm_label_view", name, sizeof(name), &flg);CHKERRQ(ierr);
1427   if (flg) {
1428     DMLabel label;
1429     Vec     val;
1430 
1431     ierr = DMGetLabel(dm, name, &label);CHKERRQ(ierr);
1432     if (!label) SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "Label %s provided to -dm_label_view does not exist in this DM", name);
1433     ierr = DMPlexCreateLabelField(dm, label, &val);CHKERRQ(ierr);
1434     ierr = VecView(val, viewer);CHKERRQ(ierr);
1435     ierr = VecDestroy(&val);CHKERRQ(ierr);
1436   }
1437   PetscFunctionReturn(0);
1438 }
1439 
1440 /*@
1441   DMPlexTopologyView - Saves a DMPlex topology into a file
1442 
1443   Collective on DM
1444 
1445   Input Parameters:
1446 + dm     - The DM whose topology is to be saved
1447 - viewer - The PetscViewer for saving
1448 
1449   Level: advanced
1450 
1451 .seealso: DMView(), DMPlexCoordinatesView(), DMPlexLabelsView(), DMPlexTopologyLoad()
1452 @*/
1453 PetscErrorCode DMPlexTopologyView(DM dm, PetscViewer viewer)
1454 {
1455   PetscBool      ishdf5;
1456   PetscErrorCode ierr;
1457 
1458   PetscFunctionBegin;
1459   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1460   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
1461   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5);CHKERRQ(ierr);
1462   if (ishdf5) {
1463 #if defined(PETSC_HAVE_HDF5)
1464     PetscViewerFormat format;
1465     ierr = PetscViewerGetFormat(viewer, &format);CHKERRQ(ierr);
1466     if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) {
1467       IS globalPointNumbering;
1468 
1469       ierr = DMPlexCreatePointNumbering(dm, &globalPointNumbering);CHKERRQ(ierr);
1470       ierr = DMPlexTopologyView_HDF5_Internal(dm, globalPointNumbering, viewer);CHKERRQ(ierr);
1471       ierr = ISDestroy(&globalPointNumbering);CHKERRQ(ierr);
1472     } else SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 output.", PetscViewerFormats[format]);
1473 #else
1474     SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
1475 #endif
1476   }
1477   PetscFunctionReturn(0);
1478 }
1479 
1480 /*@
1481   DMPlexCoordinatesView - Saves DMPlex coordinates into a file
1482 
1483   Collective on DM
1484 
1485   Input Parameters:
1486 + dm     - The DM whose coordinates are to be saved
1487 - viewer - The PetscViewer for saving
1488 
1489   Level: advanced
1490 
1491 .seealso: DMView(), DMPlexTopologyView(), DMPlexLabelsView(), DMPlexCoordinatesLoad()
1492 @*/
1493 PetscErrorCode DMPlexCoordinatesView(DM dm, PetscViewer viewer)
1494 {
1495   PetscBool      ishdf5;
1496   PetscErrorCode ierr;
1497 
1498   PetscFunctionBegin;
1499   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1500   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
1501   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5);CHKERRQ(ierr);
1502   if (ishdf5) {
1503 #if defined(PETSC_HAVE_HDF5)
1504     PetscViewerFormat format;
1505     ierr = PetscViewerGetFormat(viewer, &format);CHKERRQ(ierr);
1506     if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) {
1507       ierr = DMPlexCoordinatesView_HDF5_Internal(dm, viewer);CHKERRQ(ierr);
1508     } else SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]);
1509 #else
1510     SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
1511 #endif
1512   }
1513   PetscFunctionReturn(0);
1514 }
1515 
1516 /*@
1517   DMPlexLabelsView - Saves DMPlex labels into a file
1518 
1519   Collective on DM
1520 
1521   Input Parameters:
1522 + dm     - The DM whose labels are to be saved
1523 - viewer - The PetscViewer for saving
1524 
1525   Level: advanced
1526 
1527 .seealso: DMView(), DMPlexTopologyView(), DMPlexCoordinatesView(), DMPlexLabelsLoad()
1528 @*/
1529 PetscErrorCode DMPlexLabelsView(DM dm, PetscViewer viewer)
1530 {
1531   PetscBool      ishdf5;
1532   PetscErrorCode ierr;
1533 
1534   PetscFunctionBegin;
1535   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1536   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
1537   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5);CHKERRQ(ierr);
1538   if (ishdf5) {
1539 #if defined(PETSC_HAVE_HDF5)
1540     IS                globalPointNumbering;
1541     PetscViewerFormat format;
1542 
1543     ierr = PetscViewerGetFormat(viewer, &format);CHKERRQ(ierr);
1544     if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) {
1545       ierr = DMPlexCreatePointNumbering(dm, &globalPointNumbering);CHKERRQ(ierr);
1546       ierr = DMPlexLabelsView_HDF5_Internal(dm, globalPointNumbering, viewer);CHKERRQ(ierr);
1547       ierr = ISDestroy(&globalPointNumbering);CHKERRQ(ierr);
1548     } else SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]);
1549 #else
1550     SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
1551 #endif
1552   }
1553   PetscFunctionReturn(0);
1554 }
1555 
1556 /*@
1557   DMPlexSectionView - Saves a section associated with a DMPlex
1558 
1559   Collective on DM
1560 
1561   Input Parameters:
1562 + dm         - The DM that contains the topology on which the section to be saved is defined
1563 . viewer     - The PetscViewer for saving
1564 - sectiondm  - The DM that contains the section to be saved
1565 
1566   Level: advanced
1567 
1568   Notes:
1569   This function is a wrapper around PetscSectionView(); in addition to the raw section, it saves information that associates the section points to the topology (dm) points. When the topology (dm) and the section are later loaded with DMPlexTopologyLoad() and DMPlexSectionLoad(), respectively, this information is used to match section points with topology points.
1570 
1571   In general dm and sectiondm are two different objects, the former carrying the topology and the latter carrying the section, and have been given a topology name and a section name, respectively, with PetscObjectSetName(). In practice, however, they can be the same object if it carries both topology and section; in that case the name of the object is used as both the topology name and the section name.
1572 
1573 .seealso: DMView(), DMPlexTopologyView(), DMPlexCoordinatesView(), DMPlexLabelsView(), DMPlexGlobalVectorView(), DMPlexLocalVectorView(), PetscSectionView(), DMPlexSectionLoad()
1574 @*/
1575 PetscErrorCode DMPlexSectionView(DM dm, PetscViewer viewer, DM sectiondm)
1576 {
1577   PetscBool      ishdf5;
1578   PetscErrorCode ierr;
1579 
1580   PetscFunctionBegin;
1581   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1582   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
1583   PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3);
1584   ierr = PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERHDF5,&ishdf5);CHKERRQ(ierr);
1585   if (ishdf5) {
1586 #if defined(PETSC_HAVE_HDF5)
1587     ierr = DMPlexSectionView_HDF5_Internal(dm, viewer, sectiondm);CHKERRQ(ierr);
1588 #else
1589     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
1590 #endif
1591   }
1592   PetscFunctionReturn(0);
1593 }
1594 
1595 /*@
1596   DMPlexGlobalVectorView - Saves a global vector
1597 
1598   Collective on DM
1599 
1600   Input Parameters:
1601 + dm        - The DM that represents the topology
1602 . viewer    - The PetscViewer to save data with
1603 . sectiondm - The DM that contains the global section on which vec is defined
1604 - vec       - The global vector to be saved
1605 
1606   Level: advanced
1607 
1608   Notes:
1609   In general dm and sectiondm are two different objects, the former carrying the topology and the latter carrying the section, and have been given a topology name and a section name, respectively, with PetscObjectSetName(). In practice, however, they can be the same object if it carries both topology and section; in that case the name of the object is used as both the topology name and the section name.
1610 
1611   Typical calling sequence
1612 $       DMCreate(PETSC_COMM_WORLD, &dm);
1613 $       DMSetType(dm, DMPLEX);
1614 $       PetscObjectSetName((PetscObject)dm, "topologydm_name");
1615 $       DMClone(dm, &sectiondm);
1616 $       PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name");
1617 $       PetscSectionCreate(PETSC_COMM_WORLD, &section);
1618 $       DMPlexGetChart(sectiondm, &pStart, &pEnd);
1619 $       PetscSectionSetChart(section, pStart, pEnd);
1620 $       PetscSectionSetUp(section);
1621 $       DMSetLocalSection(sectiondm, section);
1622 $       PetscSectionDestroy(&section);
1623 $       DMGetGlobalVector(sectiondm, &vec);
1624 $       PetscObjectSetName((PetscObject)vec, "vec_name");
1625 $       DMPlexTopologyView(dm, viewer);
1626 $       DMPlexSectionView(dm, viewer, sectiondm);
1627 $       DMPlexGlobalVectorView(dm, viewer, sectiondm, vec);
1628 $       DMRestoreGlobalVector(sectiondm, &vec);
1629 $       DMDestroy(&sectiondm);
1630 $       DMDestroy(&dm);
1631 
1632 .seealso: DMPlexTopologyView(), DMPlexSectionView(), DMPlexLocalVectorView(), DMPlexGlobalVectorLoad(), DMPlexLocalVectorLoad()
1633 @*/
1634 PetscErrorCode DMPlexGlobalVectorView(DM dm, PetscViewer viewer, DM sectiondm, Vec vec)
1635 {
1636   PetscBool       ishdf5;
1637   PetscErrorCode  ierr;
1638 
1639   PetscFunctionBegin;
1640   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1641   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
1642   PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3);
1643   PetscValidHeaderSpecific(vec, VEC_CLASSID, 4);
1644   /* Check consistency */
1645   {
1646     PetscSection  section;
1647     PetscBool     includesConstraints;
1648     PetscInt      m, m1;
1649 
1650     ierr = VecGetLocalSize(vec, &m1);CHKERRQ(ierr);
1651     ierr = DMGetGlobalSection(sectiondm, &section);CHKERRQ(ierr);
1652     ierr = PetscSectionGetIncludesConstraints(section, &includesConstraints);CHKERRQ(ierr);
1653     if (includesConstraints) {ierr = PetscSectionGetStorageSize(section, &m);CHKERRQ(ierr);}
1654     else {ierr = PetscSectionGetConstrainedStorageSize(section, &m);CHKERRQ(ierr);}
1655     if (m1 != m) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Global vector size (%D) != global section storage size (%D)", m1, m);
1656   }
1657   ierr = PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5);CHKERRQ(ierr);
1658   if (ishdf5) {
1659 #if defined(PETSC_HAVE_HDF5)
1660     ierr = DMPlexGlobalVectorView_HDF5_Internal(dm, viewer, sectiondm, vec);CHKERRQ(ierr);
1661 #else
1662     SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
1663 #endif
1664   }
1665   PetscFunctionReturn(0);
1666 }
1667 
1668 /*@
1669   DMPlexLocalVectorView - Saves a local vector
1670 
1671   Collective on DM
1672 
1673   Input Parameters:
1674 + dm        - The DM that represents the topology
1675 . viewer    - The PetscViewer to save data with
1676 . sectiondm - The DM that contains the local section on which vec is defined; may be the same as dm
1677 - vec       - The local vector to be saved
1678 
1679   Level: advanced
1680 
1681   Notes:
1682   In general dm and sectiondm are two different objects, the former carrying the topology and the latter carrying the section, and have been given a topology name and a section name, respectively, with PetscObjectSetName(). In practice, however, they can be the same object if it carries both topology and section; in that case the name of the object is used as both the topology name and the section name.
1683 
1684   Typical calling sequence
1685 $       DMCreate(PETSC_COMM_WORLD, &dm);
1686 $       DMSetType(dm, DMPLEX);
1687 $       PetscObjectSetName((PetscObject)dm, "topologydm_name");
1688 $       DMClone(dm, &sectiondm);
1689 $       PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name");
1690 $       PetscSectionCreate(PETSC_COMM_WORLD, &section);
1691 $       DMPlexGetChart(sectiondm, &pStart, &pEnd);
1692 $       PetscSectionSetChart(section, pStart, pEnd);
1693 $       PetscSectionSetUp(section);
1694 $       DMSetLocalSection(sectiondm, section);
1695 $       DMGetLocalVector(sectiondm, &vec);
1696 $       PetscObjectSetName((PetscObject)vec, "vec_name");
1697 $       DMPlexTopologyView(dm, viewer);
1698 $       DMPlexSectionView(dm, viewer, sectiondm);
1699 $       DMPlexLocalVectorView(dm, viewer, sectiondm, vec);
1700 $       DMRestoreLocalVector(sectiondm, &vec);
1701 $       DMDestroy(&sectiondm);
1702 $       DMDestroy(&dm);
1703 
1704 .seealso: DMPlexTopologyView(), DMPlexSectionView(), DMPlexGlobalVectorView(), DMPlexGlobalVectorLoad(), DMPlexLocalVectorLoad()
1705 @*/
1706 PetscErrorCode DMPlexLocalVectorView(DM dm, PetscViewer viewer, DM sectiondm, Vec vec)
1707 {
1708   PetscBool       ishdf5;
1709   PetscErrorCode  ierr;
1710 
1711   PetscFunctionBegin;
1712   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1713   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
1714   PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3);
1715   PetscValidHeaderSpecific(vec, VEC_CLASSID, 4);
1716   /* Check consistency */
1717   {
1718     PetscSection  section;
1719     PetscBool     includesConstraints;
1720     PetscInt      m, m1;
1721 
1722     ierr = VecGetLocalSize(vec, &m1);CHKERRQ(ierr);
1723     ierr = DMGetLocalSection(sectiondm, &section);CHKERRQ(ierr);
1724     ierr = PetscSectionGetIncludesConstraints(section, &includesConstraints);CHKERRQ(ierr);
1725     if (includesConstraints) {ierr = PetscSectionGetStorageSize(section, &m);CHKERRQ(ierr);}
1726     else {ierr = PetscSectionGetConstrainedStorageSize(section, &m);CHKERRQ(ierr);}
1727     if (m1 != m) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Local vector size (%D) != local section storage size (%D)", m1, m);
1728   }
1729   ierr = PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5);CHKERRQ(ierr);
1730   if (ishdf5) {
1731 #if defined(PETSC_HAVE_HDF5)
1732     ierr = DMPlexLocalVectorView_HDF5_Internal(dm, viewer, sectiondm, vec);CHKERRQ(ierr);
1733 #else
1734     SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
1735 #endif
1736   }
1737   PetscFunctionReturn(0);
1738 }
1739 
1740 PetscErrorCode DMLoad_Plex(DM dm, PetscViewer viewer)
1741 {
1742   PetscBool      ishdf5;
1743   PetscErrorCode ierr;
1744 
1745   PetscFunctionBegin;
1746   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1747   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
1748   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5,   &ishdf5);CHKERRQ(ierr);
1749   if (ishdf5) {
1750 #if defined(PETSC_HAVE_HDF5)
1751     PetscViewerFormat format;
1752     ierr = PetscViewerGetFormat(viewer, &format);CHKERRQ(ierr);
1753     if (format == PETSC_VIEWER_HDF5_XDMF || format == PETSC_VIEWER_HDF5_VIZ) {
1754       ierr = DMPlexLoad_HDF5_Xdmf_Internal(dm, viewer);CHKERRQ(ierr);
1755     } else if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) {
1756       ierr = DMPlexLoad_HDF5_Internal(dm, viewer);CHKERRQ(ierr);
1757     } else SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]);
1758     PetscFunctionReturn(0);
1759 #else
1760     SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
1761 #endif
1762   } else SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Viewer type %s not yet supported for DMPlex loading", ((PetscObject)viewer)->type_name);
1763 }
1764 
1765 /*@
1766   DMPlexTopologyLoad - Loads a topology into a DMPlex
1767 
1768   Collective on DM
1769 
1770   Input Parameters:
1771 + dm     - The DM into which the topology is loaded
1772 - viewer - The PetscViewer for the saved topology
1773 
1774   Output Parameters:
1775 . globalToLocalPointSF - 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
1776 
1777   Level: advanced
1778 
1779 .seealso: DMLoad(), DMPlexCoordinatesLoad(), DMPlexLabelsLoad(), DMView(), PetscViewerHDF5Open(), PetscViewerPushFormat()
1780 @*/
1781 PetscErrorCode DMPlexTopologyLoad(DM dm, PetscViewer viewer, PetscSF *globalToLocalPointSF)
1782 {
1783   PetscBool      ishdf5;
1784   PetscErrorCode ierr;
1785 
1786   PetscFunctionBegin;
1787   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1788   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
1789   if (globalToLocalPointSF) PetscValidPointer(globalToLocalPointSF, 3);
1790   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5);CHKERRQ(ierr);
1791   if (ishdf5) {
1792 #if defined(PETSC_HAVE_HDF5)
1793     PetscViewerFormat format;
1794     ierr = PetscViewerGetFormat(viewer, &format);CHKERRQ(ierr);
1795     if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) {
1796       ierr = DMPlexTopologyLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF);CHKERRQ(ierr);
1797     } else SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]);
1798 #else
1799     SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
1800 #endif
1801   }
1802   PetscFunctionReturn(0);
1803 }
1804 
1805 /*@
1806   DMPlexCoordinatesLoad - Loads coordinates into a DMPlex
1807 
1808   Collective on DM
1809 
1810   Input Parameters:
1811 + dm     - The DM into which the coordinates are loaded
1812 - viewer - The PetscViewer for the saved coordinates
1813 
1814   Level: advanced
1815 
1816 .seealso: DMLoad(), DMPlexTopologyLoad(), DMPlexLabelsLoad(), DMView(), PetscViewerHDF5Open(), PetscViewerPushFormat()
1817 @*/
1818 PetscErrorCode DMPlexCoordinatesLoad(DM dm, PetscViewer viewer)
1819 {
1820   PetscBool      ishdf5;
1821   PetscErrorCode ierr;
1822 
1823   PetscFunctionBegin;
1824   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1825   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
1826   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5);CHKERRQ(ierr);
1827   if (ishdf5) {
1828 #if defined(PETSC_HAVE_HDF5)
1829     PetscViewerFormat format;
1830     ierr = PetscViewerGetFormat(viewer, &format);CHKERRQ(ierr);
1831     if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) {
1832       ierr = DMPlexCoordinatesLoad_HDF5_Internal(dm, viewer);CHKERRQ(ierr);
1833     } else SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]);
1834 #else
1835     SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
1836 #endif
1837   }
1838   PetscFunctionReturn(0);
1839 }
1840 
1841 /*@
1842   DMPlexLabelsLoad - Loads labels into a DMPlex
1843 
1844   Collective on DM
1845 
1846   Input Parameters:
1847 + dm     - The DM into which the labels are loaded
1848 - viewer - The PetscViewer for the saved labels
1849 
1850   Level: advanced
1851 
1852 .seealso: DMLoad(), DMPlexTopologyLoad(), DMPlexCoordinatesLoad(), DMView(), PetscViewerHDF5Open(), PetscViewerPushFormat()
1853 @*/
1854 PetscErrorCode DMPlexLabelsLoad(DM dm, PetscViewer viewer)
1855 {
1856   PetscBool      ishdf5;
1857   PetscErrorCode ierr;
1858 
1859   PetscFunctionBegin;
1860   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1861   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
1862   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5);CHKERRQ(ierr);
1863   if (ishdf5) {
1864 #if defined(PETSC_HAVE_HDF5)
1865     PetscViewerFormat format;
1866 
1867     ierr = PetscViewerGetFormat(viewer, &format);CHKERRQ(ierr);
1868     if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) {
1869       ierr = DMPlexLabelsLoad_HDF5_Internal(dm, viewer);CHKERRQ(ierr);
1870     } else SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]);
1871 #else
1872     SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
1873 #endif
1874   }
1875   PetscFunctionReturn(0);
1876 }
1877 
1878 /*@
1879   DMPlexSectionLoad - Loads section into a DMPlex
1880 
1881   Collective on DM
1882 
1883   Input Parameters:
1884 + dm          - The DM that represents the topology
1885 . viewer      - The PetscViewer that represents the on-disk section (sectionA)
1886 . sectiondm   - The DM into which the on-disk section (sectionA) is migrated
1887 - globalToLocalPointSF - The SF returned by DMPlexTopologyLoad() when loading dm from viewer
1888 
1889   Output Parameters
1890 + globalDofSF - The SF that migrates any on-disk Vec data associated with sectionA into a global Vec associated with the sectiondm's global section (NULL if not needed)
1891 - localDofSF  - The SF that migrates any on-disk Vec data associated with sectionA into a local Vec associated with the sectiondm's local section (NULL if not needed)
1892 
1893   Level: advanced
1894 
1895   Notes:
1896   This function is a wrapper around PetscSectionLoad(); it loads, in addition to the raw section, a list of global point numbers that associates each on-disk section point with a global point number in [0, NX), where NX is the number of topology points in dm. Noting that globalToLocalPointSF associates each topology point in dm with a global number in [0, NX), one can readily establish an association of the on-disk section points with the topology points.
1897 
1898   In general dm and sectiondm are two different objects, the former carrying the topology and the latter carrying the section, and have been given a topology name and a section name, respectively, with PetscObjectSetName(). In practice, however, they can be the same object if it carries both topology and section; in that case the name of the object is used as both the topology name and the section name.
1899 
1900   The output parameter, globalDofSF (localDofSF), can later be used with DMPlexGlobalVectorLoad() (DMPlexLocalVectorLoad()) to load on-disk vectors into global (local) vectors associated with sectiondm's global (local) section.
1901 
1902   Example using 2 processes:
1903 $  NX (number of points on dm): 4
1904 $  sectionA                   : the on-disk section
1905 $  vecA                       : a vector associated with sectionA
1906 $  sectionB                   : sectiondm's local section constructed in this function
1907 $  vecB (local)               : a vector associated with sectiondm's local section
1908 $  vecB (global)              : a vector associated with sectiondm's global section
1909 $
1910 $                                     rank 0    rank 1
1911 $  vecA (global)                  : [.0 .4 .1 | .2 .3]        <- to be loaded in DMPlexGlobalVectorLoad() or DMPlexLocalVectorLoad()
1912 $  sectionA->atlasOff             :       0 2 | 1             <- loaded in PetscSectionLoad()
1913 $  sectionA->atlasDof             :       1 3 | 1             <- loaded in PetscSectionLoad()
1914 $  sectionA's global point numbers:       0 2 | 3             <- loaded in DMPlexSectionLoad()
1915 $  [0, NX)                        :       0 1 | 2 3           <- conceptual partition used in globalToLocalPointSF
1916 $  sectionB's global point numbers:     0 1 3 | 3 2           <- associated with [0, NX) by globalToLocalPointSF
1917 $  sectionB->atlasDof             :     1 0 1 | 1 3
1918 $  sectionB->atlasOff (no perm)   :     0 1 1 | 0 1
1919 $  vecB (local)                   :   [.0 .4] | [.4 .1 .2 .3] <- to be constructed by calling DMPlexLocalVectorLoad() with localDofSF
1920 $  vecB (global)                  :    [.0 .4 | .1 .2 .3]     <- to be constructed by calling DMPlexGlobalVectorLoad() with globalDofSF
1921 $
1922 $  where "|" represents a partition of loaded data, and global point 3 is assumed to be owned by rank 0.
1923 
1924 .seealso: DMLoad(), DMPlexTopologyLoad(), DMPlexCoordinatesLoad(), DMPlexLabelsLoad(), DMPlexGlobalVectorLoad(), DMPlexLocalVectorLoad(), PetscSectionLoad(), DMPlexSectionView()
1925 @*/
1926 PetscErrorCode DMPlexSectionLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF globalToLocalPointSF, PetscSF *globalDofSF, PetscSF *localDofSF)
1927 {
1928   PetscBool      ishdf5;
1929   PetscErrorCode ierr;
1930 
1931   PetscFunctionBegin;
1932   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1933   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
1934   PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3);
1935   PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 4);
1936   if (globalDofSF) PetscValidPointer(globalDofSF, 5);
1937   if (localDofSF) PetscValidPointer(localDofSF, 6);
1938   ierr = PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERHDF5,&ishdf5);CHKERRQ(ierr);
1939   if (ishdf5) {
1940 #if defined(PETSC_HAVE_HDF5)
1941     ierr = DMPlexSectionLoad_HDF5_Internal(dm, viewer, sectiondm, globalToLocalPointSF, globalDofSF, localDofSF);CHKERRQ(ierr);
1942 #else
1943     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
1944 #endif
1945   }
1946   PetscFunctionReturn(0);
1947 }
1948 
1949 PetscErrorCode DMDestroy_Plex(DM dm)
1950 {
1951   DM_Plex       *mesh = (DM_Plex*) dm->data;
1952   PetscErrorCode ierr;
1953 
1954   PetscFunctionBegin;
1955   ierr = PetscObjectComposeFunction((PetscObject)dm,"DMSetUpGLVisViewer_C",NULL);CHKERRQ(ierr);
1956   ierr = PetscObjectComposeFunction((PetscObject)dm,"DMPlexInsertBoundaryValues_C", NULL);CHKERRQ(ierr);
1957   ierr = PetscObjectComposeFunction((PetscObject)dm,"DMCreateNeumannOverlap_C", NULL);CHKERRQ(ierr);
1958   ierr = PetscObjectComposeFunction((PetscObject)dm,"DMInterpolateSolution_C", NULL);CHKERRQ(ierr);
1959   if (--mesh->refct > 0) PetscFunctionReturn(0);
1960   ierr = PetscSectionDestroy(&mesh->coneSection);CHKERRQ(ierr);
1961   ierr = PetscFree(mesh->cones);CHKERRQ(ierr);
1962   ierr = PetscFree(mesh->coneOrientations);CHKERRQ(ierr);
1963   ierr = PetscSectionDestroy(&mesh->supportSection);CHKERRQ(ierr);
1964   ierr = PetscSectionDestroy(&mesh->subdomainSection);CHKERRQ(ierr);
1965   ierr = PetscFree(mesh->supports);CHKERRQ(ierr);
1966   ierr = PetscFree(mesh->facesTmp);CHKERRQ(ierr);
1967   ierr = PetscFree(mesh->tetgenOpts);CHKERRQ(ierr);
1968   ierr = PetscFree(mesh->triangleOpts);CHKERRQ(ierr);
1969   ierr = PetscPartitionerDestroy(&mesh->partitioner);CHKERRQ(ierr);
1970   ierr = DMLabelDestroy(&mesh->subpointMap);CHKERRQ(ierr);
1971   ierr = ISDestroy(&mesh->subpointIS);CHKERRQ(ierr);
1972   ierr = ISDestroy(&mesh->globalVertexNumbers);CHKERRQ(ierr);
1973   ierr = ISDestroy(&mesh->globalCellNumbers);CHKERRQ(ierr);
1974   ierr = PetscSectionDestroy(&mesh->anchorSection);CHKERRQ(ierr);
1975   ierr = ISDestroy(&mesh->anchorIS);CHKERRQ(ierr);
1976   ierr = PetscSectionDestroy(&mesh->parentSection);CHKERRQ(ierr);
1977   ierr = PetscFree(mesh->parents);CHKERRQ(ierr);
1978   ierr = PetscFree(mesh->childIDs);CHKERRQ(ierr);
1979   ierr = PetscSectionDestroy(&mesh->childSection);CHKERRQ(ierr);
1980   ierr = PetscFree(mesh->children);CHKERRQ(ierr);
1981   ierr = DMDestroy(&mesh->referenceTree);CHKERRQ(ierr);
1982   ierr = PetscGridHashDestroy(&mesh->lbox);CHKERRQ(ierr);
1983   ierr = PetscFree(mesh->neighbors);CHKERRQ(ierr);
1984   /* This was originally freed in DMDestroy(), but that prevents reference counting of backend objects */
1985   ierr = PetscFree(mesh);CHKERRQ(ierr);
1986   PetscFunctionReturn(0);
1987 }
1988 
1989 PetscErrorCode DMCreateMatrix_Plex(DM dm, Mat *J)
1990 {
1991   PetscSection           sectionGlobal;
1992   PetscInt               bs = -1, mbs;
1993   PetscInt               localSize;
1994   PetscBool              isShell, isBlock, isSeqBlock, isMPIBlock, isSymBlock, isSymSeqBlock, isSymMPIBlock, isMatIS;
1995   PetscErrorCode         ierr;
1996   MatType                mtype;
1997   ISLocalToGlobalMapping ltog;
1998 
1999   PetscFunctionBegin;
2000   ierr = MatInitializePackage();CHKERRQ(ierr);
2001   mtype = dm->mattype;
2002   ierr = DMGetGlobalSection(dm, &sectionGlobal);CHKERRQ(ierr);
2003   /* ierr = PetscSectionGetStorageSize(sectionGlobal, &localSize);CHKERRQ(ierr); */
2004   ierr = PetscSectionGetConstrainedStorageSize(sectionGlobal, &localSize);CHKERRQ(ierr);
2005   ierr = MatCreate(PetscObjectComm((PetscObject)dm), J);CHKERRQ(ierr);
2006   ierr = MatSetSizes(*J, localSize, localSize, PETSC_DETERMINE, PETSC_DETERMINE);CHKERRQ(ierr);
2007   ierr = MatSetType(*J, mtype);CHKERRQ(ierr);
2008   ierr = MatSetFromOptions(*J);CHKERRQ(ierr);
2009   ierr = MatGetBlockSize(*J, &mbs);CHKERRQ(ierr);
2010   if (mbs > 1) bs = mbs;
2011   ierr = PetscStrcmp(mtype, MATSHELL, &isShell);CHKERRQ(ierr);
2012   ierr = PetscStrcmp(mtype, MATBAIJ, &isBlock);CHKERRQ(ierr);
2013   ierr = PetscStrcmp(mtype, MATSEQBAIJ, &isSeqBlock);CHKERRQ(ierr);
2014   ierr = PetscStrcmp(mtype, MATMPIBAIJ, &isMPIBlock);CHKERRQ(ierr);
2015   ierr = PetscStrcmp(mtype, MATSBAIJ, &isSymBlock);CHKERRQ(ierr);
2016   ierr = PetscStrcmp(mtype, MATSEQSBAIJ, &isSymSeqBlock);CHKERRQ(ierr);
2017   ierr = PetscStrcmp(mtype, MATMPISBAIJ, &isSymMPIBlock);CHKERRQ(ierr);
2018   ierr = PetscStrcmp(mtype, MATIS, &isMatIS);CHKERRQ(ierr);
2019   if (!isShell) {
2020     PetscSection subSection;
2021     PetscBool    fillMatrix = (PetscBool)(!dm->prealloc_only && !isMatIS);
2022     PetscInt    *dnz, *onz, *dnzu, *onzu, bsLocal[2], bsMinMax[2], *ltogidx, lsize;
2023     PetscInt     pStart, pEnd, p, dof, cdof;
2024 
2025     /* Set localtoglobalmapping on the matrix for MatSetValuesLocal() to work (it also creates the local matrices in case of MATIS) */
2026     if (isMatIS) { /* need a different l2g map than the one computed by DMGetLocalToGlobalMapping */
2027       PetscSection section;
2028       PetscInt     size;
2029 
2030       ierr = DMGetLocalSection(dm, &section);CHKERRQ(ierr);
2031       ierr = PetscSectionGetStorageSize(section, &size);CHKERRQ(ierr);
2032       ierr = PetscMalloc1(size,&ltogidx);CHKERRQ(ierr);
2033       ierr = DMPlexGetSubdomainSection(dm, &subSection);CHKERRQ(ierr);
2034     } else {
2035       ierr = DMGetLocalToGlobalMapping(dm,&ltog);CHKERRQ(ierr);
2036     }
2037     ierr = PetscSectionGetChart(sectionGlobal, &pStart, &pEnd);CHKERRQ(ierr);
2038     for (p = pStart, lsize = 0; p < pEnd; ++p) {
2039       PetscInt bdof;
2040 
2041       ierr = PetscSectionGetDof(sectionGlobal, p, &dof);CHKERRQ(ierr);
2042       ierr = PetscSectionGetConstraintDof(sectionGlobal, p, &cdof);CHKERRQ(ierr);
2043       dof  = dof < 0 ? -(dof+1) : dof;
2044       bdof = cdof && (dof-cdof) ? 1 : dof;
2045       if (dof) {
2046         if (bs < 0)          {bs = bdof;}
2047         else if (bs != bdof) {bs = 1; if (!isMatIS) break;}
2048       }
2049       if (isMatIS) {
2050         PetscInt loff,c,off;
2051         ierr = PetscSectionGetOffset(subSection, p, &loff);CHKERRQ(ierr);
2052         ierr = PetscSectionGetOffset(sectionGlobal, p, &off);CHKERRQ(ierr);
2053         for (c = 0; c < dof-cdof; ++c, ++lsize) ltogidx[loff+c] = off > -1 ? off+c : -(off+1)+c;
2054       }
2055     }
2056     /* Must have same blocksize on all procs (some might have no points) */
2057     bsLocal[0] = bs < 0 ? PETSC_MAX_INT : bs; bsLocal[1] = bs;
2058     ierr = PetscGlobalMinMaxInt(PetscObjectComm((PetscObject) dm), bsLocal, bsMinMax);CHKERRQ(ierr);
2059     if (bsMinMax[0] != bsMinMax[1]) {bs = 1;}
2060     else                            {bs = bsMinMax[0];}
2061     bs = PetscMax(1,bs);
2062     if (isMatIS) { /* Must reduce indices by blocksize */
2063       PetscInt l;
2064 
2065       lsize = lsize/bs;
2066       if (bs > 1) for (l = 0; l < lsize; ++l) ltogidx[l] = ltogidx[l*bs]/bs;
2067       ierr = ISLocalToGlobalMappingCreate(PetscObjectComm((PetscObject)dm), bs, lsize, ltogidx, PETSC_OWN_POINTER, &ltog);CHKERRQ(ierr);
2068     }
2069     ierr = MatSetLocalToGlobalMapping(*J,ltog,ltog);CHKERRQ(ierr);
2070     if (isMatIS) {
2071       ierr = ISLocalToGlobalMappingDestroy(&ltog);CHKERRQ(ierr);
2072     }
2073     ierr = PetscCalloc4(localSize/bs, &dnz, localSize/bs, &onz, localSize/bs, &dnzu, localSize/bs, &onzu);CHKERRQ(ierr);
2074     ierr = DMPlexPreallocateOperator(dm, bs, dnz, onz, dnzu, onzu, *J, fillMatrix);CHKERRQ(ierr);
2075     ierr = PetscFree4(dnz, onz, dnzu, onzu);CHKERRQ(ierr);
2076   }
2077   ierr = MatSetDM(*J, dm);CHKERRQ(ierr);
2078   PetscFunctionReturn(0);
2079 }
2080 
2081 /*@
2082   DMPlexGetSubdomainSection - Returns the section associated with the subdomain
2083 
2084   Not collective
2085 
2086   Input Parameter:
2087 . mesh - The DMPlex
2088 
2089   Output Parameters:
2090 . subsection - The subdomain section
2091 
2092   Level: developer
2093 
2094 .seealso:
2095 @*/
2096 PetscErrorCode DMPlexGetSubdomainSection(DM dm, PetscSection *subsection)
2097 {
2098   DM_Plex       *mesh = (DM_Plex*) dm->data;
2099   PetscErrorCode ierr;
2100 
2101   PetscFunctionBegin;
2102   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2103   if (!mesh->subdomainSection) {
2104     PetscSection section;
2105     PetscSF      sf;
2106 
2107     ierr = PetscSFCreate(PETSC_COMM_SELF,&sf);CHKERRQ(ierr);
2108     ierr = DMGetLocalSection(dm,&section);CHKERRQ(ierr);
2109     ierr = PetscSectionCreateGlobalSection(section,sf,PETSC_FALSE,PETSC_TRUE,&mesh->subdomainSection);CHKERRQ(ierr);
2110     ierr = PetscSFDestroy(&sf);CHKERRQ(ierr);
2111   }
2112   *subsection = mesh->subdomainSection;
2113   PetscFunctionReturn(0);
2114 }
2115 
2116 /*@
2117   DMPlexGetChart - Return the interval for all mesh points [pStart, pEnd)
2118 
2119   Not collective
2120 
2121   Input Parameter:
2122 . mesh - The DMPlex
2123 
2124   Output Parameters:
2125 + pStart - The first mesh point
2126 - pEnd   - The upper bound for mesh points
2127 
2128   Level: beginner
2129 
2130 .seealso: DMPlexCreate(), DMPlexSetChart()
2131 @*/
2132 PetscErrorCode DMPlexGetChart(DM dm, PetscInt *pStart, PetscInt *pEnd)
2133 {
2134   DM_Plex       *mesh = (DM_Plex*) dm->data;
2135   PetscErrorCode ierr;
2136 
2137   PetscFunctionBegin;
2138   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2139   ierr = PetscSectionGetChart(mesh->coneSection, pStart, pEnd);CHKERRQ(ierr);
2140   PetscFunctionReturn(0);
2141 }
2142 
2143 /*@
2144   DMPlexSetChart - Set the interval for all mesh points [pStart, pEnd)
2145 
2146   Not collective
2147 
2148   Input Parameters:
2149 + mesh - The DMPlex
2150 . pStart - The first mesh point
2151 - pEnd   - The upper bound for mesh points
2152 
2153   Output Parameters:
2154 
2155   Level: beginner
2156 
2157 .seealso: DMPlexCreate(), DMPlexGetChart()
2158 @*/
2159 PetscErrorCode DMPlexSetChart(DM dm, PetscInt pStart, PetscInt pEnd)
2160 {
2161   DM_Plex       *mesh = (DM_Plex*) dm->data;
2162   PetscErrorCode ierr;
2163 
2164   PetscFunctionBegin;
2165   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2166   ierr = PetscSectionSetChart(mesh->coneSection, pStart, pEnd);CHKERRQ(ierr);
2167   ierr = PetscSectionSetChart(mesh->supportSection, pStart, pEnd);CHKERRQ(ierr);
2168   PetscFunctionReturn(0);
2169 }
2170 
2171 /*@
2172   DMPlexGetConeSize - Return the number of in-edges for this point in the DAG
2173 
2174   Not collective
2175 
2176   Input Parameters:
2177 + mesh - The DMPlex
2178 - p - The point, which must lie in the chart set with DMPlexSetChart()
2179 
2180   Output Parameter:
2181 . size - The cone size for point p
2182 
2183   Level: beginner
2184 
2185 .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexSetChart()
2186 @*/
2187 PetscErrorCode DMPlexGetConeSize(DM dm, PetscInt p, PetscInt *size)
2188 {
2189   DM_Plex       *mesh = (DM_Plex*) dm->data;
2190   PetscErrorCode ierr;
2191 
2192   PetscFunctionBegin;
2193   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2194   PetscValidPointer(size, 3);
2195   ierr = PetscSectionGetDof(mesh->coneSection, p, size);CHKERRQ(ierr);
2196   PetscFunctionReturn(0);
2197 }
2198 
2199 /*@
2200   DMPlexSetConeSize - Set the number of in-edges for this point in the DAG
2201 
2202   Not collective
2203 
2204   Input Parameters:
2205 + mesh - The DMPlex
2206 . p - The point, which must lie in the chart set with DMPlexSetChart()
2207 - size - The cone size for point p
2208 
2209   Output Parameter:
2210 
2211   Note:
2212   This should be called after DMPlexSetChart().
2213 
2214   Level: beginner
2215 
2216 .seealso: DMPlexCreate(), DMPlexGetConeSize(), DMPlexSetChart()
2217 @*/
2218 PetscErrorCode DMPlexSetConeSize(DM dm, PetscInt p, PetscInt size)
2219 {
2220   DM_Plex       *mesh = (DM_Plex*) dm->data;
2221   PetscErrorCode ierr;
2222 
2223   PetscFunctionBegin;
2224   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2225   ierr = PetscSectionSetDof(mesh->coneSection, p, size);CHKERRQ(ierr);
2226 
2227   mesh->maxConeSize = PetscMax(mesh->maxConeSize, size);
2228   PetscFunctionReturn(0);
2229 }
2230 
2231 /*@
2232   DMPlexAddConeSize - Add the given number of in-edges to this point in the DAG
2233 
2234   Not collective
2235 
2236   Input Parameters:
2237 + mesh - The DMPlex
2238 . p - The point, which must lie in the chart set with DMPlexSetChart()
2239 - size - The additional cone size for point p
2240 
2241   Output Parameter:
2242 
2243   Note:
2244   This should be called after DMPlexSetChart().
2245 
2246   Level: beginner
2247 
2248 .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexGetConeSize(), DMPlexSetChart()
2249 @*/
2250 PetscErrorCode DMPlexAddConeSize(DM dm, PetscInt p, PetscInt size)
2251 {
2252   DM_Plex       *mesh = (DM_Plex*) dm->data;
2253   PetscInt       csize;
2254   PetscErrorCode ierr;
2255 
2256   PetscFunctionBegin;
2257   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2258   ierr = PetscSectionAddDof(mesh->coneSection, p, size);CHKERRQ(ierr);
2259   ierr = PetscSectionGetDof(mesh->coneSection, p, &csize);CHKERRQ(ierr);
2260 
2261   mesh->maxConeSize = PetscMax(mesh->maxConeSize, csize);
2262   PetscFunctionReturn(0);
2263 }
2264 
2265 /*@C
2266   DMPlexGetCone - Return the points on the in-edges for this point in the DAG
2267 
2268   Not collective
2269 
2270   Input Parameters:
2271 + dm - The DMPlex
2272 - p - The point, which must lie in the chart set with DMPlexSetChart()
2273 
2274   Output Parameter:
2275 . cone - An array of points which are on the in-edges for point p
2276 
2277   Level: beginner
2278 
2279   Fortran Notes:
2280   Since it returns an array, this routine is only available in Fortran 90, and you must
2281   include petsc.h90 in your code.
2282   You must also call DMPlexRestoreCone() after you finish using the returned array.
2283   DMPlexRestoreCone() is not needed/available in C.
2284 
2285 .seealso: DMPlexGetConeSize(), DMPlexSetCone(), DMPlexGetConeTuple(), DMPlexSetChart()
2286 @*/
2287 PetscErrorCode DMPlexGetCone(DM dm, PetscInt p, const PetscInt *cone[])
2288 {
2289   DM_Plex       *mesh = (DM_Plex*) dm->data;
2290   PetscInt       off;
2291   PetscErrorCode ierr;
2292 
2293   PetscFunctionBegin;
2294   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2295   PetscValidPointer(cone, 3);
2296   ierr  = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
2297   *cone = &mesh->cones[off];
2298   PetscFunctionReturn(0);
2299 }
2300 
2301 /*@C
2302   DMPlexGetConeTuple - Return the points on the in-edges of several points in the DAG
2303 
2304   Not collective
2305 
2306   Input Parameters:
2307 + dm - The DMPlex
2308 - p - The IS of points, which must lie in the chart set with DMPlexSetChart()
2309 
2310   Output Parameter:
2311 + pConesSection - PetscSection describing the layout of pCones
2312 - pCones - An array of points which are on the in-edges for the point set p
2313 
2314   Level: intermediate
2315 
2316 .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexGetConeRecursive(), DMPlexSetChart()
2317 @*/
2318 PetscErrorCode DMPlexGetConeTuple(DM dm, IS p, PetscSection *pConesSection, IS *pCones)
2319 {
2320   PetscSection        cs, newcs;
2321   PetscInt            *cones;
2322   PetscInt            *newarr=NULL;
2323   PetscInt            n;
2324   PetscErrorCode      ierr;
2325 
2326   PetscFunctionBegin;
2327   ierr = DMPlexGetCones(dm, &cones);CHKERRQ(ierr);
2328   ierr = DMPlexGetConeSection(dm, &cs);CHKERRQ(ierr);
2329   ierr = PetscSectionExtractDofsFromArray(cs, MPIU_INT, cones, p, &newcs, pCones ? ((void**)&newarr) : NULL);CHKERRQ(ierr);
2330   if (pConesSection) *pConesSection = newcs;
2331   if (pCones) {
2332     ierr = PetscSectionGetStorageSize(newcs, &n);CHKERRQ(ierr);
2333     ierr = ISCreateGeneral(PetscObjectComm((PetscObject)p), n, newarr, PETSC_OWN_POINTER, pCones);CHKERRQ(ierr);
2334   }
2335   PetscFunctionReturn(0);
2336 }
2337 
2338 /*@
2339   DMPlexGetConeRecursiveVertices - Expand each given point into its cone points and do that recursively until we end up just with vertices.
2340 
2341   Not collective
2342 
2343   Input Parameters:
2344 + dm - The DMPlex
2345 - points - The IS of points, which must lie in the chart set with DMPlexSetChart()
2346 
2347   Output Parameter:
2348 . expandedPoints - An array of vertices recursively expanded from input points
2349 
2350   Level: advanced
2351 
2352   Notes:
2353   Like DMPlexGetConeRecursive but returns only the 0-depth IS (i.e. vertices only) and no sections.
2354   There is no corresponding Restore function, just call ISDestroy() on the returned IS to deallocate.
2355 
2356 .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexGetConeTuple(), DMPlexGetConeRecursive(), DMPlexRestoreConeRecursive(), DMPlexGetDepth()
2357 @*/
2358 PetscErrorCode DMPlexGetConeRecursiveVertices(DM dm, IS points, IS *expandedPoints)
2359 {
2360   IS                  *expandedPointsAll;
2361   PetscInt            depth;
2362   PetscErrorCode      ierr;
2363 
2364   PetscFunctionBegin;
2365   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2366   PetscValidHeaderSpecific(points, IS_CLASSID, 2);
2367   PetscValidPointer(expandedPoints, 3);
2368   ierr = DMPlexGetConeRecursive(dm, points, &depth, &expandedPointsAll, NULL);CHKERRQ(ierr);
2369   *expandedPoints = expandedPointsAll[0];
2370   ierr = PetscObjectReference((PetscObject)expandedPointsAll[0]);
2371   ierr = DMPlexRestoreConeRecursive(dm, points, &depth, &expandedPointsAll, NULL);CHKERRQ(ierr);
2372   PetscFunctionReturn(0);
2373 }
2374 
2375 /*@
2376   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).
2377 
2378   Not collective
2379 
2380   Input Parameters:
2381 + dm - The DMPlex
2382 - points - The IS of points, which must lie in the chart set with DMPlexSetChart()
2383 
2384   Output Parameter:
2385 + depth - (optional) Size of the output arrays, equal to DMPlex depth, returned by DMPlexGetDepth()
2386 . expandedPoints - (optional) An array of index sets with recursively expanded cones
2387 - sections - (optional) An array of sections which describe mappings from points to their cone points
2388 
2389   Level: advanced
2390 
2391   Notes:
2392   Like DMPlexGetConeTuple() but recursive.
2393 
2394   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.
2395   For example, for d=0 it contains only vertices, for d=1 it can contain vertices and edges, etc.
2396 
2397   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:
2398   (1) DAG points in expandedPoints[d+1] with depth d+1 to their cone points in expandedPoints[d];
2399   (2) DAG points in expandedPoints[d+1] with depth in [0,d] to the same points in expandedPoints[d].
2400 
2401 .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexGetConeTuple(), DMPlexRestoreConeRecursive(), DMPlexGetConeRecursiveVertices(), DMPlexGetDepth()
2402 @*/
2403 PetscErrorCode DMPlexGetConeRecursive(DM dm, IS points, PetscInt *depth, IS *expandedPoints[], PetscSection *sections[])
2404 {
2405   const PetscInt      *arr0=NULL, *cone=NULL;
2406   PetscInt            *arr=NULL, *newarr=NULL;
2407   PetscInt            d, depth_, i, n, newn, cn, co, start, end;
2408   IS                  *expandedPoints_;
2409   PetscSection        *sections_;
2410   PetscErrorCode      ierr;
2411 
2412   PetscFunctionBegin;
2413   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2414   PetscValidHeaderSpecific(points, IS_CLASSID, 2);
2415   if (depth) PetscValidIntPointer(depth, 3);
2416   if (expandedPoints) PetscValidPointer(expandedPoints, 4);
2417   if (sections) PetscValidPointer(sections, 5);
2418   ierr = ISGetLocalSize(points, &n);CHKERRQ(ierr);
2419   ierr = ISGetIndices(points, &arr0);CHKERRQ(ierr);
2420   ierr = DMPlexGetDepth(dm, &depth_);CHKERRQ(ierr);
2421   ierr = PetscCalloc1(depth_, &expandedPoints_);CHKERRQ(ierr);
2422   ierr = PetscCalloc1(depth_, &sections_);CHKERRQ(ierr);
2423   arr = (PetscInt*) arr0; /* this is ok because first generation of arr is not modified */
2424   for (d=depth_-1; d>=0; d--) {
2425     ierr = PetscSectionCreate(PETSC_COMM_SELF, &sections_[d]);CHKERRQ(ierr);
2426     ierr = PetscSectionSetChart(sections_[d], 0, n);CHKERRQ(ierr);
2427     for (i=0; i<n; i++) {
2428       ierr = DMPlexGetDepthStratum(dm, d+1, &start, &end);CHKERRQ(ierr);
2429       if (arr[i] >= start && arr[i] < end) {
2430         ierr = DMPlexGetConeSize(dm, arr[i], &cn);CHKERRQ(ierr);
2431         ierr = PetscSectionSetDof(sections_[d], i, cn);CHKERRQ(ierr);
2432       } else {
2433         ierr = PetscSectionSetDof(sections_[d], i, 1);CHKERRQ(ierr);
2434       }
2435     }
2436     ierr = PetscSectionSetUp(sections_[d]);CHKERRQ(ierr);
2437     ierr = PetscSectionGetStorageSize(sections_[d], &newn);CHKERRQ(ierr);
2438     ierr = PetscMalloc1(newn, &newarr);CHKERRQ(ierr);
2439     for (i=0; i<n; i++) {
2440       ierr = PetscSectionGetDof(sections_[d], i, &cn);CHKERRQ(ierr);
2441       ierr = PetscSectionGetOffset(sections_[d], i, &co);CHKERRQ(ierr);
2442       if (cn > 1) {
2443         ierr = DMPlexGetCone(dm, arr[i], &cone);CHKERRQ(ierr);
2444         ierr = PetscMemcpy(&newarr[co], cone, cn*sizeof(PetscInt));CHKERRQ(ierr);
2445       } else {
2446         newarr[co] = arr[i];
2447       }
2448     }
2449     ierr = ISCreateGeneral(PETSC_COMM_SELF, newn, newarr, PETSC_OWN_POINTER, &expandedPoints_[d]);CHKERRQ(ierr);
2450     arr = newarr;
2451     n = newn;
2452   }
2453   ierr = ISRestoreIndices(points, &arr0);CHKERRQ(ierr);
2454   *depth = depth_;
2455   if (expandedPoints) *expandedPoints = expandedPoints_;
2456   else {
2457     for (d=0; d<depth_; d++) {ierr = ISDestroy(&expandedPoints_[d]);CHKERRQ(ierr);}
2458     ierr = PetscFree(expandedPoints_);CHKERRQ(ierr);
2459   }
2460   if (sections) *sections = sections_;
2461   else {
2462     for (d=0; d<depth_; d++) {ierr = PetscSectionDestroy(&sections_[d]);CHKERRQ(ierr);}
2463     ierr = PetscFree(sections_);CHKERRQ(ierr);
2464   }
2465   PetscFunctionReturn(0);
2466 }
2467 
2468 /*@
2469   DMPlexRestoreConeRecursive - Deallocates arrays created by DMPlexGetConeRecursive
2470 
2471   Not collective
2472 
2473   Input Parameters:
2474 + dm - The DMPlex
2475 - points - The IS of points, which must lie in the chart set with DMPlexSetChart()
2476 
2477   Output Parameter:
2478 + depth - (optional) Size of the output arrays, equal to DMPlex depth, returned by DMPlexGetDepth()
2479 . expandedPoints - (optional) An array of recursively expanded cones
2480 - sections - (optional) An array of sections which describe mappings from points to their cone points
2481 
2482   Level: advanced
2483 
2484   Notes:
2485   See DMPlexGetConeRecursive() for details.
2486 
2487 .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexGetConeTuple(), DMPlexGetConeRecursive(), DMPlexGetConeRecursiveVertices(), DMPlexGetDepth()
2488 @*/
2489 PetscErrorCode DMPlexRestoreConeRecursive(DM dm, IS points, PetscInt *depth, IS *expandedPoints[], PetscSection *sections[])
2490 {
2491   PetscInt            d, depth_;
2492   PetscErrorCode      ierr;
2493 
2494   PetscFunctionBegin;
2495   ierr = DMPlexGetDepth(dm, &depth_);CHKERRQ(ierr);
2496   if (depth && *depth != depth_) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "depth changed since last call to DMPlexGetConeRecursive");
2497   if (depth) *depth = 0;
2498   if (expandedPoints) {
2499     for (d=0; d<depth_; d++) {ierr = ISDestroy(&((*expandedPoints)[d]));CHKERRQ(ierr);}
2500     ierr = PetscFree(*expandedPoints);CHKERRQ(ierr);
2501   }
2502   if (sections)  {
2503     for (d=0; d<depth_; d++) {ierr = PetscSectionDestroy(&((*sections)[d]));CHKERRQ(ierr);}
2504     ierr = PetscFree(*sections);CHKERRQ(ierr);
2505   }
2506   PetscFunctionReturn(0);
2507 }
2508 
2509 /*@
2510   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
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 - cone - An array of points which are on the in-edges for point p
2518 
2519   Output Parameter:
2520 
2521   Note:
2522   This should be called after all calls to DMPlexSetConeSize() and DMSetUp().
2523 
2524   Developer Note: Why not call this DMPlexSetCover()
2525 
2526   Level: beginner
2527 
2528 .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexSetChart(), DMPlexSetConeSize(), DMSetUp(), DMPlexSetSupport(), DMPlexSetSupportSize()
2529 @*/
2530 PetscErrorCode DMPlexSetCone(DM dm, PetscInt p, const PetscInt cone[])
2531 {
2532   DM_Plex       *mesh = (DM_Plex*) dm->data;
2533   PetscInt       pStart, pEnd;
2534   PetscInt       dof, off, c;
2535   PetscErrorCode ierr;
2536 
2537   PetscFunctionBegin;
2538   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2539   ierr = PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);CHKERRQ(ierr);
2540   ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
2541   if (dof) PetscValidPointer(cone, 3);
2542   ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
2543   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);
2544   for (c = 0; c < dof; ++c) {
2545     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);
2546     mesh->cones[off+c] = cone[c];
2547   }
2548   PetscFunctionReturn(0);
2549 }
2550 
2551 /*@C
2552   DMPlexGetConeOrientation - Return the orientations on the in-edges for this point in the DAG
2553 
2554   Not collective
2555 
2556   Input Parameters:
2557 + mesh - The DMPlex
2558 - p - The point, which must lie in the chart set with DMPlexSetChart()
2559 
2560   Output Parameter:
2561 . coneOrientation - An array of orientations which are on the in-edges for point p. An orientation is an
2562                     integer giving the prescription for cone traversal. If it is negative, the cone is
2563                     traversed in the opposite direction. Its value 'o', or if negative '-(o+1)', gives
2564                     the index of the cone point on which to start.
2565 
2566   Level: beginner
2567 
2568   Fortran Notes:
2569   Since it returns an array, this routine is only available in Fortran 90, and you must
2570   include petsc.h90 in your code.
2571   You must also call DMPlexRestoreConeOrientation() after you finish using the returned array.
2572   DMPlexRestoreConeOrientation() is not needed/available in C.
2573 
2574 .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexSetCone(), DMPlexSetChart()
2575 @*/
2576 PetscErrorCode DMPlexGetConeOrientation(DM dm, PetscInt p, const PetscInt *coneOrientation[])
2577 {
2578   DM_Plex       *mesh = (DM_Plex*) dm->data;
2579   PetscInt       off;
2580   PetscErrorCode ierr;
2581 
2582   PetscFunctionBegin;
2583   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2584   if (PetscDefined(USE_DEBUG)) {
2585     PetscInt dof;
2586     ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
2587     if (dof) PetscValidPointer(coneOrientation, 3);
2588   }
2589   ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
2590 
2591   *coneOrientation = &mesh->coneOrientations[off];
2592   PetscFunctionReturn(0);
2593 }
2594 
2595 /*@
2596   DMPlexSetConeOrientation - Set the orientations on the in-edges for this point in the DAG
2597 
2598   Not collective
2599 
2600   Input Parameters:
2601 + mesh - The DMPlex
2602 . p - The point, which must lie in the chart set with DMPlexSetChart()
2603 - coneOrientation - An array of orientations which are on the in-edges for point p. An orientation is an
2604                     integer giving the prescription for cone traversal. If it is negative, the cone is
2605                     traversed in the opposite direction. Its value 'o', or if negative '-(o+1)', gives
2606                     the index of the cone point on which to start.
2607 
2608   Output Parameter:
2609 
2610   Note:
2611   This should be called after all calls to DMPlexSetConeSize() and DMSetUp().
2612 
2613   Level: beginner
2614 
2615 .seealso: DMPlexCreate(), DMPlexGetConeOrientation(), DMPlexSetCone(), DMPlexSetChart(), DMPlexSetConeSize(), DMSetUp()
2616 @*/
2617 PetscErrorCode DMPlexSetConeOrientation(DM dm, PetscInt p, const PetscInt coneOrientation[])
2618 {
2619   DM_Plex       *mesh = (DM_Plex*) dm->data;
2620   PetscInt       pStart, pEnd;
2621   PetscInt       dof, off, c;
2622   PetscErrorCode ierr;
2623 
2624   PetscFunctionBegin;
2625   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2626   ierr = PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);CHKERRQ(ierr);
2627   ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
2628   if (dof) PetscValidPointer(coneOrientation, 3);
2629   ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
2630   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);
2631   for (c = 0; c < dof; ++c) {
2632     PetscInt cdof, o = coneOrientation[c];
2633 
2634     ierr = PetscSectionGetDof(mesh->coneSection, mesh->cones[off+c], &cdof);CHKERRQ(ierr);
2635     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);
2636     mesh->coneOrientations[off+c] = o;
2637   }
2638   PetscFunctionReturn(0);
2639 }
2640 
2641 /*@
2642   DMPlexInsertCone - Insert a point into the in-edges for the point p in the DAG
2643 
2644   Not collective
2645 
2646   Input Parameters:
2647 + mesh - The DMPlex
2648 . p - The point, which must lie in the chart set with DMPlexSetChart()
2649 . conePos - The local index in the cone where the point should be put
2650 - conePoint - The mesh point to insert
2651 
2652   Level: beginner
2653 
2654 .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexSetChart(), DMPlexSetConeSize(), DMSetUp()
2655 @*/
2656 PetscErrorCode DMPlexInsertCone(DM dm, PetscInt p, PetscInt conePos, PetscInt conePoint)
2657 {
2658   DM_Plex       *mesh = (DM_Plex*) dm->data;
2659   PetscInt       pStart, pEnd;
2660   PetscInt       dof, off;
2661   PetscErrorCode ierr;
2662 
2663   PetscFunctionBegin;
2664   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2665   ierr = PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);CHKERRQ(ierr);
2666   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);
2667   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);
2668   ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
2669   ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
2670   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);
2671   mesh->cones[off+conePos] = conePoint;
2672   PetscFunctionReturn(0);
2673 }
2674 
2675 /*@
2676   DMPlexInsertConeOrientation - Insert a point orientation for the in-edge for the point p in the DAG
2677 
2678   Not collective
2679 
2680   Input Parameters:
2681 + mesh - The DMPlex
2682 . p - The point, which must lie in the chart set with DMPlexSetChart()
2683 . conePos - The local index in the cone where the point should be put
2684 - coneOrientation - The point orientation to insert
2685 
2686   Level: beginner
2687 
2688 .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexSetChart(), DMPlexSetConeSize(), DMSetUp()
2689 @*/
2690 PetscErrorCode DMPlexInsertConeOrientation(DM dm, PetscInt p, PetscInt conePos, PetscInt coneOrientation)
2691 {
2692   DM_Plex       *mesh = (DM_Plex*) dm->data;
2693   PetscInt       pStart, pEnd;
2694   PetscInt       dof, off;
2695   PetscErrorCode ierr;
2696 
2697   PetscFunctionBegin;
2698   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2699   ierr = PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);CHKERRQ(ierr);
2700   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);
2701   ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
2702   ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
2703   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);
2704   mesh->coneOrientations[off+conePos] = coneOrientation;
2705   PetscFunctionReturn(0);
2706 }
2707 
2708 /*@
2709   DMPlexGetSupportSize - Return the number of out-edges for this point in the DAG
2710 
2711   Not collective
2712 
2713   Input Parameters:
2714 + mesh - The DMPlex
2715 - p - The point, which must lie in the chart set with DMPlexSetChart()
2716 
2717   Output Parameter:
2718 . size - The support size for point p
2719 
2720   Level: beginner
2721 
2722 .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexSetChart(), DMPlexGetConeSize()
2723 @*/
2724 PetscErrorCode DMPlexGetSupportSize(DM dm, PetscInt p, PetscInt *size)
2725 {
2726   DM_Plex       *mesh = (DM_Plex*) dm->data;
2727   PetscErrorCode ierr;
2728 
2729   PetscFunctionBegin;
2730   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2731   PetscValidPointer(size, 3);
2732   ierr = PetscSectionGetDof(mesh->supportSection, p, size);CHKERRQ(ierr);
2733   PetscFunctionReturn(0);
2734 }
2735 
2736 /*@
2737   DMPlexSetSupportSize - Set the number of out-edges for this point in the DAG
2738 
2739   Not collective
2740 
2741   Input Parameters:
2742 + mesh - The DMPlex
2743 . p - The point, which must lie in the chart set with DMPlexSetChart()
2744 - size - The support size for point p
2745 
2746   Output Parameter:
2747 
2748   Note:
2749   This should be called after DMPlexSetChart().
2750 
2751   Level: beginner
2752 
2753 .seealso: DMPlexCreate(), DMPlexGetSupportSize(), DMPlexSetChart()
2754 @*/
2755 PetscErrorCode DMPlexSetSupportSize(DM dm, PetscInt p, PetscInt size)
2756 {
2757   DM_Plex       *mesh = (DM_Plex*) dm->data;
2758   PetscErrorCode ierr;
2759 
2760   PetscFunctionBegin;
2761   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2762   ierr = PetscSectionSetDof(mesh->supportSection, p, size);CHKERRQ(ierr);
2763 
2764   mesh->maxSupportSize = PetscMax(mesh->maxSupportSize, size);
2765   PetscFunctionReturn(0);
2766 }
2767 
2768 /*@C
2769   DMPlexGetSupport - Return the points on the out-edges for this point in the DAG
2770 
2771   Not collective
2772 
2773   Input Parameters:
2774 + mesh - The DMPlex
2775 - p - The point, which must lie in the chart set with DMPlexSetChart()
2776 
2777   Output Parameter:
2778 . support - An array of points which are on the out-edges for point p
2779 
2780   Level: beginner
2781 
2782   Fortran Notes:
2783   Since it returns an array, this routine is only available in Fortran 90, and you must
2784   include petsc.h90 in your code.
2785   You must also call DMPlexRestoreSupport() after you finish using the returned array.
2786   DMPlexRestoreSupport() is not needed/available in C.
2787 
2788 .seealso: DMPlexGetSupportSize(), DMPlexSetSupport(), DMPlexGetCone(), DMPlexSetChart()
2789 @*/
2790 PetscErrorCode DMPlexGetSupport(DM dm, PetscInt p, const PetscInt *support[])
2791 {
2792   DM_Plex       *mesh = (DM_Plex*) dm->data;
2793   PetscInt       off;
2794   PetscErrorCode ierr;
2795 
2796   PetscFunctionBegin;
2797   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2798   PetscValidPointer(support, 3);
2799   ierr     = PetscSectionGetOffset(mesh->supportSection, p, &off);CHKERRQ(ierr);
2800   *support = &mesh->supports[off];
2801   PetscFunctionReturn(0);
2802 }
2803 
2804 /*@
2805   DMPlexSetSupport - Set the points on the out-edges for this point in the DAG, that is the list of points that this point covers
2806 
2807   Not collective
2808 
2809   Input Parameters:
2810 + mesh - The DMPlex
2811 . p - The point, which must lie in the chart set with DMPlexSetChart()
2812 - support - An array of points which are on the out-edges for point p
2813 
2814   Output Parameter:
2815 
2816   Note:
2817   This should be called after all calls to DMPlexSetSupportSize() and DMSetUp().
2818 
2819   Level: beginner
2820 
2821 .seealso: DMPlexSetCone(), DMPlexSetConeSize(), DMPlexCreate(), DMPlexGetSupport(), DMPlexSetChart(), DMPlexSetSupportSize(), DMSetUp()
2822 @*/
2823 PetscErrorCode DMPlexSetSupport(DM dm, PetscInt p, const PetscInt support[])
2824 {
2825   DM_Plex       *mesh = (DM_Plex*) dm->data;
2826   PetscInt       pStart, pEnd;
2827   PetscInt       dof, off, c;
2828   PetscErrorCode ierr;
2829 
2830   PetscFunctionBegin;
2831   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2832   ierr = PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd);CHKERRQ(ierr);
2833   ierr = PetscSectionGetDof(mesh->supportSection, p, &dof);CHKERRQ(ierr);
2834   if (dof) PetscValidPointer(support, 3);
2835   ierr = PetscSectionGetOffset(mesh->supportSection, p, &off);CHKERRQ(ierr);
2836   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);
2837   for (c = 0; c < dof; ++c) {
2838     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);
2839     mesh->supports[off+c] = support[c];
2840   }
2841   PetscFunctionReturn(0);
2842 }
2843 
2844 /*@
2845   DMPlexInsertSupport - Insert a point into the out-edges for the point p in the DAG
2846 
2847   Not collective
2848 
2849   Input Parameters:
2850 + mesh - The DMPlex
2851 . p - The point, which must lie in the chart set with DMPlexSetChart()
2852 . supportPos - The local index in the cone where the point should be put
2853 - supportPoint - The mesh point to insert
2854 
2855   Level: beginner
2856 
2857 .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexSetChart(), DMPlexSetConeSize(), DMSetUp()
2858 @*/
2859 PetscErrorCode DMPlexInsertSupport(DM dm, PetscInt p, PetscInt supportPos, PetscInt supportPoint)
2860 {
2861   DM_Plex       *mesh = (DM_Plex*) dm->data;
2862   PetscInt       pStart, pEnd;
2863   PetscInt       dof, off;
2864   PetscErrorCode ierr;
2865 
2866   PetscFunctionBegin;
2867   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2868   ierr = PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd);CHKERRQ(ierr);
2869   ierr = PetscSectionGetDof(mesh->supportSection, p, &dof);CHKERRQ(ierr);
2870   ierr = PetscSectionGetOffset(mesh->supportSection, p, &off);CHKERRQ(ierr);
2871   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);
2872   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);
2873   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);
2874   mesh->supports[off+supportPos] = supportPoint;
2875   PetscFunctionReturn(0);
2876 }
2877 
2878 /*@C
2879   DMPlexGetTransitiveClosure - Return the 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 - points - If points is NULL on input, internal storage will be returned, otherwise the provided array is used
2888 
2889   Output Parameters:
2890 + numPoints - The number of points in the closure, so points[] is of size 2*numPoints
2891 - points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...]
2892 
2893   Note:
2894   If using internal storage (points is NULL on input), each call overwrites the last output.
2895 
2896   Fortran Notes:
2897   Since it returns an array, this routine is only available in Fortran 90, and you must
2898   include petsc.h90 in your code.
2899 
2900   The numPoints argument is not present in the Fortran 90 binding since it is internal to the array.
2901 
2902   Level: beginner
2903 
2904 .seealso: DMPlexRestoreTransitiveClosure(), DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone()
2905 @*/
2906 PetscErrorCode DMPlexGetTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[])
2907 {
2908   DM_Plex        *mesh = (DM_Plex*) dm->data;
2909   PetscInt       *closure, *fifo;
2910   const PetscInt *tmp = NULL, *tmpO = NULL;
2911   PetscInt        tmpSize, t;
2912   PetscInt        depth       = 0, maxSize;
2913   PetscInt        closureSize = 2, fifoSize = 0, fifoStart = 0;
2914   PetscErrorCode  ierr;
2915 
2916   PetscFunctionBegin;
2917   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2918   ierr    = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
2919   /* This is only 1-level */
2920   if (useCone) {
2921     ierr = DMPlexGetConeSize(dm, p, &tmpSize);CHKERRQ(ierr);
2922     ierr = DMPlexGetCone(dm, p, &tmp);CHKERRQ(ierr);
2923     ierr = DMPlexGetConeOrientation(dm, p, &tmpO);CHKERRQ(ierr);
2924   } else {
2925     ierr = DMPlexGetSupportSize(dm, p, &tmpSize);CHKERRQ(ierr);
2926     ierr = DMPlexGetSupport(dm, p, &tmp);CHKERRQ(ierr);
2927   }
2928   if (depth == 1) {
2929     if (*points) {
2930       closure = *points;
2931     } else {
2932       maxSize = 2*(PetscMax(mesh->maxConeSize, mesh->maxSupportSize)+1);
2933       ierr = DMGetWorkArray(dm, maxSize, MPIU_INT, &closure);CHKERRQ(ierr);
2934     }
2935     closure[0] = p; closure[1] = 0;
2936     for (t = 0; t < tmpSize; ++t, closureSize += 2) {
2937       closure[closureSize]   = tmp[t];
2938       closure[closureSize+1] = tmpO ? tmpO[t] : 0;
2939     }
2940     if (numPoints) *numPoints = closureSize/2;
2941     if (points)    *points    = closure;
2942     PetscFunctionReturn(0);
2943   }
2944   {
2945     PetscInt c, coneSeries, s,supportSeries;
2946 
2947     c = mesh->maxConeSize;
2948     coneSeries = (c > 1) ? ((PetscPowInt(c,depth+1)-1)/(c-1)) : depth+1;
2949     s = mesh->maxSupportSize;
2950     supportSeries = (s > 1) ? ((PetscPowInt(s,depth+1)-1)/(s-1)) : depth+1;
2951     maxSize = 2*PetscMax(coneSeries,supportSeries);
2952   }
2953   ierr    = DMGetWorkArray(dm, maxSize, MPIU_INT, &fifo);CHKERRQ(ierr);
2954   if (*points) {
2955     closure = *points;
2956   } else {
2957     ierr = DMGetWorkArray(dm, maxSize, MPIU_INT, &closure);CHKERRQ(ierr);
2958   }
2959   closure[0] = p; closure[1] = 0;
2960   for (t = 0; t < tmpSize; ++t, closureSize += 2, fifoSize += 2) {
2961     const PetscInt cp = tmp[t];
2962     const PetscInt co = tmpO ? tmpO[t] : 0;
2963 
2964     closure[closureSize]   = cp;
2965     closure[closureSize+1] = co;
2966     fifo[fifoSize]         = cp;
2967     fifo[fifoSize+1]       = co;
2968   }
2969   /* Should kick out early when depth is reached, rather than checking all vertices for empty cones */
2970   while (fifoSize - fifoStart) {
2971     const PetscInt q   = fifo[fifoStart];
2972     const PetscInt o   = fifo[fifoStart+1];
2973     const PetscInt rev = o >= 0 ? 0 : 1;
2974     const PetscInt off = rev ? -(o+1) : o;
2975 
2976     if (useCone) {
2977       ierr = DMPlexGetConeSize(dm, q, &tmpSize);CHKERRQ(ierr);
2978       ierr = DMPlexGetCone(dm, q, &tmp);CHKERRQ(ierr);
2979       ierr = DMPlexGetConeOrientation(dm, q, &tmpO);CHKERRQ(ierr);
2980     } else {
2981       ierr = DMPlexGetSupportSize(dm, q, &tmpSize);CHKERRQ(ierr);
2982       ierr = DMPlexGetSupport(dm, q, &tmp);CHKERRQ(ierr);
2983       tmpO = NULL;
2984     }
2985     for (t = 0; t < tmpSize; ++t) {
2986       const PetscInt i  = ((rev ? tmpSize-t : t) + off)%tmpSize;
2987       const PetscInt cp = tmp[i];
2988       /* Must propogate orientation: When we reverse orientation, we both reverse the direction of iteration and start at the other end of the chain. */
2989       /* HACK: It is worse to get the size here, than to change the interpretation of -(*+1)
2990        const PetscInt co = tmpO ? (rev ? -(tmpO[i]+1) : tmpO[i]) : 0; */
2991       PetscInt       co = tmpO ? tmpO[i] : 0;
2992       PetscInt       c;
2993 
2994       if (rev) {
2995         PetscInt childSize, coff;
2996         ierr = DMPlexGetConeSize(dm, cp, &childSize);CHKERRQ(ierr);
2997         coff = tmpO[i] < 0 ? -(tmpO[i]+1) : tmpO[i];
2998         co   = childSize ? -(((coff+childSize-1)%childSize)+1) : 0;
2999       }
3000       /* Check for duplicate */
3001       for (c = 0; c < closureSize; c += 2) {
3002         if (closure[c] == cp) break;
3003       }
3004       if (c == closureSize) {
3005         closure[closureSize]   = cp;
3006         closure[closureSize+1] = co;
3007         fifo[fifoSize]         = cp;
3008         fifo[fifoSize+1]       = co;
3009         closureSize           += 2;
3010         fifoSize              += 2;
3011       }
3012     }
3013     fifoStart += 2;
3014   }
3015   if (numPoints) *numPoints = closureSize/2;
3016   if (points)    *points    = closure;
3017   ierr = DMRestoreWorkArray(dm, maxSize, MPIU_INT, &fifo);CHKERRQ(ierr);
3018   PetscFunctionReturn(0);
3019 }
3020 
3021 /*@C
3022   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
3023 
3024   Not collective
3025 
3026   Input Parameters:
3027 + mesh - The DMPlex
3028 . p - The point, which must lie in the chart set with DMPlexSetChart()
3029 . orientation - The orientation of the point
3030 . useCone - PETSC_TRUE for in-edges,  otherwise use out-edges
3031 - points - If points is NULL on input, internal storage will be returned, otherwise the provided array is used
3032 
3033   Output Parameters:
3034 + numPoints - The number of points in the closure, so points[] is of size 2*numPoints
3035 - points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...]
3036 
3037   Note:
3038   If using internal storage (points is NULL on input), each call overwrites the last output.
3039 
3040   Fortran Notes:
3041   Since it returns an array, this routine is only available in Fortran 90, and you must
3042   include petsc.h90 in your code.
3043 
3044   The numPoints argument is not present in the Fortran 90 binding since it is internal to the array.
3045 
3046   Level: beginner
3047 
3048 .seealso: DMPlexRestoreTransitiveClosure(), DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone()
3049 @*/
3050 PetscErrorCode DMPlexGetTransitiveClosure_Internal(DM dm, PetscInt p, PetscInt ornt, PetscBool useCone, PetscInt *numPoints, PetscInt *points[])
3051 {
3052   DM_Plex        *mesh = (DM_Plex*) dm->data;
3053   PetscInt       *closure, *fifo;
3054   const PetscInt *tmp = NULL, *tmpO = NULL;
3055   PetscInt        tmpSize, t;
3056   PetscInt        depth       = 0, maxSize;
3057   PetscInt        closureSize = 2, fifoSize = 0, fifoStart = 0;
3058   PetscErrorCode  ierr;
3059 
3060   PetscFunctionBegin;
3061   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3062   ierr    = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3063   /* This is only 1-level */
3064   if (useCone) {
3065     ierr = DMPlexGetConeSize(dm, p, &tmpSize);CHKERRQ(ierr);
3066     ierr = DMPlexGetCone(dm, p, &tmp);CHKERRQ(ierr);
3067     ierr = DMPlexGetConeOrientation(dm, p, &tmpO);CHKERRQ(ierr);
3068   } else {
3069     ierr = DMPlexGetSupportSize(dm, p, &tmpSize);CHKERRQ(ierr);
3070     ierr = DMPlexGetSupport(dm, p, &tmp);CHKERRQ(ierr);
3071   }
3072   if (depth == 1) {
3073     if (*points) {
3074       closure = *points;
3075     } else {
3076       maxSize = 2*(PetscMax(mesh->maxConeSize, mesh->maxSupportSize)+1);
3077       ierr = DMGetWorkArray(dm, maxSize, MPIU_INT, &closure);CHKERRQ(ierr);
3078     }
3079     closure[0] = p; closure[1] = ornt;
3080     for (t = 0; t < tmpSize; ++t, closureSize += 2) {
3081       const PetscInt i = ornt >= 0 ? (t+ornt)%tmpSize : (-(ornt+1) + tmpSize-t)%tmpSize;
3082       closure[closureSize]   = tmp[i];
3083       closure[closureSize+1] = tmpO ? tmpO[i] : 0;
3084     }
3085     if (numPoints) *numPoints = closureSize/2;
3086     if (points)    *points    = closure;
3087     PetscFunctionReturn(0);
3088   }
3089   {
3090     PetscInt c, coneSeries, s,supportSeries;
3091 
3092     c = mesh->maxConeSize;
3093     coneSeries = (c > 1) ? ((PetscPowInt(c,depth+1)-1)/(c-1)) : depth+1;
3094     s = mesh->maxSupportSize;
3095     supportSeries = (s > 1) ? ((PetscPowInt(s,depth+1)-1)/(s-1)) : depth+1;
3096     maxSize = 2*PetscMax(coneSeries,supportSeries);
3097   }
3098   ierr    = DMGetWorkArray(dm, maxSize, MPIU_INT, &fifo);CHKERRQ(ierr);
3099   if (*points) {
3100     closure = *points;
3101   } else {
3102     ierr = DMGetWorkArray(dm, maxSize, MPIU_INT, &closure);CHKERRQ(ierr);
3103   }
3104   closure[0] = p; closure[1] = ornt;
3105   for (t = 0; t < tmpSize; ++t, closureSize += 2, fifoSize += 2) {
3106     const PetscInt i  = ornt >= 0 ? (t+ornt)%tmpSize : (-(ornt+1) + tmpSize-t)%tmpSize;
3107     const PetscInt cp = tmp[i];
3108     PetscInt       co = tmpO ? tmpO[i] : 0;
3109 
3110     if (ornt < 0) {
3111       PetscInt childSize, coff;
3112       ierr = DMPlexGetConeSize(dm, cp, &childSize);CHKERRQ(ierr);
3113       coff = co < 0 ? -(tmpO[i]+1) : tmpO[i];
3114       co   = childSize ? -(((coff+childSize-1)%childSize)+1) : 0;
3115     }
3116     closure[closureSize]   = cp;
3117     closure[closureSize+1] = co;
3118     fifo[fifoSize]         = cp;
3119     fifo[fifoSize+1]       = co;
3120   }
3121   /* Should kick out early when depth is reached, rather than checking all vertices for empty cones */
3122   while (fifoSize - fifoStart) {
3123     const PetscInt q   = fifo[fifoStart];
3124     const PetscInt o   = fifo[fifoStart+1];
3125     const PetscInt rev = o >= 0 ? 0 : 1;
3126     const PetscInt off = rev ? -(o+1) : o;
3127 
3128     if (useCone) {
3129       ierr = DMPlexGetConeSize(dm, q, &tmpSize);CHKERRQ(ierr);
3130       ierr = DMPlexGetCone(dm, q, &tmp);CHKERRQ(ierr);
3131       ierr = DMPlexGetConeOrientation(dm, q, &tmpO);CHKERRQ(ierr);
3132     } else {
3133       ierr = DMPlexGetSupportSize(dm, q, &tmpSize);CHKERRQ(ierr);
3134       ierr = DMPlexGetSupport(dm, q, &tmp);CHKERRQ(ierr);
3135       tmpO = NULL;
3136     }
3137     for (t = 0; t < tmpSize; ++t) {
3138       const PetscInt i  = ((rev ? tmpSize-t : t) + off)%tmpSize;
3139       const PetscInt cp = tmp[i];
3140       /* Must propogate orientation: When we reverse orientation, we both reverse the direction of iteration and start at the other end of the chain. */
3141       /* HACK: It is worse to get the size here, than to change the interpretation of -(*+1)
3142        const PetscInt co = tmpO ? (rev ? -(tmpO[i]+1) : tmpO[i]) : 0; */
3143       PetscInt       co = tmpO ? tmpO[i] : 0;
3144       PetscInt       c;
3145 
3146       if (rev) {
3147         PetscInt childSize, coff;
3148         ierr = DMPlexGetConeSize(dm, cp, &childSize);CHKERRQ(ierr);
3149         coff = tmpO[i] < 0 ? -(tmpO[i]+1) : tmpO[i];
3150         co   = childSize ? -(((coff+childSize-1)%childSize)+1) : 0;
3151       }
3152       /* Check for duplicate */
3153       for (c = 0; c < closureSize; c += 2) {
3154         if (closure[c] == cp) break;
3155       }
3156       if (c == closureSize) {
3157         closure[closureSize]   = cp;
3158         closure[closureSize+1] = co;
3159         fifo[fifoSize]         = cp;
3160         fifo[fifoSize+1]       = co;
3161         closureSize           += 2;
3162         fifoSize              += 2;
3163       }
3164     }
3165     fifoStart += 2;
3166   }
3167   if (numPoints) *numPoints = closureSize/2;
3168   if (points)    *points    = closure;
3169   ierr = DMRestoreWorkArray(dm, maxSize, MPIU_INT, &fifo);CHKERRQ(ierr);
3170   PetscFunctionReturn(0);
3171 }
3172 
3173 /*@C
3174   DMPlexRestoreTransitiveClosure - Restore the array of points on the transitive closure of the in-edges or out-edges for this point in the DAG
3175 
3176   Not collective
3177 
3178   Input Parameters:
3179 + mesh - The DMPlex
3180 . p - The point, which must lie in the chart set with DMPlexSetChart()
3181 . useCone - PETSC_TRUE for in-edges,  otherwise use out-edges
3182 . numPoints - The number of points in the closure, so points[] is of size 2*numPoints, zeroed on exit
3183 - points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...], zeroed on exit
3184 
3185   Note:
3186   If not using internal storage (points is not NULL on input), this call is unnecessary
3187 
3188   Fortran Notes:
3189   Since it returns an array, this routine is only available in Fortran 90, and you must
3190   include petsc.h90 in your code.
3191 
3192   The numPoints argument is not present in the Fortran 90 binding since it is internal to the array.
3193 
3194   Level: beginner
3195 
3196 .seealso: DMPlexGetTransitiveClosure(), DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone()
3197 @*/
3198 PetscErrorCode DMPlexRestoreTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[])
3199 {
3200   PetscErrorCode ierr;
3201 
3202   PetscFunctionBegin;
3203   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3204   if (numPoints) PetscValidIntPointer(numPoints,4);
3205   if (points) PetscValidPointer(points,5);
3206   ierr = DMRestoreWorkArray(dm, 0, MPIU_INT, points);CHKERRQ(ierr);
3207   if (numPoints) *numPoints = 0;
3208   PetscFunctionReturn(0);
3209 }
3210 
3211 /*@
3212   DMPlexGetMaxSizes - Return the maximum number of in-edges (cone) and out-edges (support) for any point in the DAG
3213 
3214   Not collective
3215 
3216   Input Parameter:
3217 . mesh - The DMPlex
3218 
3219   Output Parameters:
3220 + maxConeSize - The maximum number of in-edges
3221 - maxSupportSize - The maximum number of out-edges
3222 
3223   Level: beginner
3224 
3225 .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexSetChart()
3226 @*/
3227 PetscErrorCode DMPlexGetMaxSizes(DM dm, PetscInt *maxConeSize, PetscInt *maxSupportSize)
3228 {
3229   DM_Plex *mesh = (DM_Plex*) dm->data;
3230 
3231   PetscFunctionBegin;
3232   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3233   if (maxConeSize)    *maxConeSize    = mesh->maxConeSize;
3234   if (maxSupportSize) *maxSupportSize = mesh->maxSupportSize;
3235   PetscFunctionReturn(0);
3236 }
3237 
3238 PetscErrorCode DMSetUp_Plex(DM dm)
3239 {
3240   DM_Plex       *mesh = (DM_Plex*) dm->data;
3241   PetscInt       size;
3242   PetscErrorCode ierr;
3243 
3244   PetscFunctionBegin;
3245   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3246   ierr = PetscSectionSetUp(mesh->coneSection);CHKERRQ(ierr);
3247   ierr = PetscSectionGetStorageSize(mesh->coneSection, &size);CHKERRQ(ierr);
3248   ierr = PetscMalloc1(size, &mesh->cones);CHKERRQ(ierr);
3249   ierr = PetscCalloc1(size, &mesh->coneOrientations);CHKERRQ(ierr);
3250   ierr = PetscLogObjectMemory((PetscObject) dm, size*2*sizeof(PetscInt));CHKERRQ(ierr);
3251   if (mesh->maxSupportSize) {
3252     ierr = PetscSectionSetUp(mesh->supportSection);CHKERRQ(ierr);
3253     ierr = PetscSectionGetStorageSize(mesh->supportSection, &size);CHKERRQ(ierr);
3254     ierr = PetscMalloc1(size, &mesh->supports);CHKERRQ(ierr);
3255     ierr = PetscLogObjectMemory((PetscObject) dm, size*sizeof(PetscInt));CHKERRQ(ierr);
3256   }
3257   PetscFunctionReturn(0);
3258 }
3259 
3260 PetscErrorCode DMCreateSubDM_Plex(DM dm, PetscInt numFields, const PetscInt fields[], IS *is, DM *subdm)
3261 {
3262   PetscErrorCode ierr;
3263 
3264   PetscFunctionBegin;
3265   if (subdm) {ierr = DMClone(dm, subdm);CHKERRQ(ierr);}
3266   ierr = DMCreateSectionSubDM(dm, numFields, fields, is, subdm);CHKERRQ(ierr);
3267   if (subdm) {(*subdm)->useNatural = dm->useNatural;}
3268   if (dm->useNatural && dm->sfMigration) {
3269     PetscSF        sfMigrationInv,sfNatural;
3270     PetscSection   section, sectionSeq;
3271 
3272     (*subdm)->sfMigration = dm->sfMigration;
3273     ierr = PetscObjectReference((PetscObject) dm->sfMigration);CHKERRQ(ierr);
3274     ierr = DMGetLocalSection((*subdm), &section);CHKERRQ(ierr);
3275     ierr = PetscSFCreateInverseSF((*subdm)->sfMigration, &sfMigrationInv);CHKERRQ(ierr);
3276     ierr = PetscSectionCreate(PetscObjectComm((PetscObject) (*subdm)), &sectionSeq);CHKERRQ(ierr);
3277     ierr = PetscSFDistributeSection(sfMigrationInv, section, NULL, sectionSeq);CHKERRQ(ierr);
3278 
3279     ierr = DMPlexCreateGlobalToNaturalSF(*subdm, sectionSeq, (*subdm)->sfMigration, &sfNatural);CHKERRQ(ierr);
3280     (*subdm)->sfNatural = sfNatural;
3281     ierr = PetscSectionDestroy(&sectionSeq);CHKERRQ(ierr);
3282     ierr = PetscSFDestroy(&sfMigrationInv);CHKERRQ(ierr);
3283   }
3284   PetscFunctionReturn(0);
3285 }
3286 
3287 PetscErrorCode DMCreateSuperDM_Plex(DM dms[], PetscInt len, IS **is, DM *superdm)
3288 {
3289   PetscErrorCode ierr;
3290   PetscInt       i = 0;
3291 
3292   PetscFunctionBegin;
3293   ierr = DMClone(dms[0], superdm);CHKERRQ(ierr);
3294   ierr = DMCreateSectionSuperDM(dms, len, is, superdm);CHKERRQ(ierr);
3295   (*superdm)->useNatural = PETSC_FALSE;
3296   for (i = 0; i < len; i++) {
3297     if (dms[i]->useNatural && dms[i]->sfMigration) {
3298       PetscSF        sfMigrationInv,sfNatural;
3299       PetscSection   section, sectionSeq;
3300 
3301       (*superdm)->sfMigration = dms[i]->sfMigration;
3302       ierr = PetscObjectReference((PetscObject) dms[i]->sfMigration);CHKERRQ(ierr);
3303       (*superdm)->useNatural = PETSC_TRUE;
3304       ierr = DMGetLocalSection((*superdm), &section);CHKERRQ(ierr);
3305       ierr = PetscSFCreateInverseSF((*superdm)->sfMigration, &sfMigrationInv);CHKERRQ(ierr);
3306       ierr = PetscSectionCreate(PetscObjectComm((PetscObject) (*superdm)), &sectionSeq);CHKERRQ(ierr);
3307       ierr = PetscSFDistributeSection(sfMigrationInv, section, NULL, sectionSeq);CHKERRQ(ierr);
3308 
3309       ierr = DMPlexCreateGlobalToNaturalSF(*superdm, sectionSeq, (*superdm)->sfMigration, &sfNatural);CHKERRQ(ierr);
3310       (*superdm)->sfNatural = sfNatural;
3311       ierr = PetscSectionDestroy(&sectionSeq);CHKERRQ(ierr);
3312       ierr = PetscSFDestroy(&sfMigrationInv);CHKERRQ(ierr);
3313       break;
3314     }
3315   }
3316   PetscFunctionReturn(0);
3317 }
3318 
3319 /*@
3320   DMPlexSymmetrize - Create support (out-edge) information from cone (in-edge) information
3321 
3322   Not collective
3323 
3324   Input Parameter:
3325 . mesh - The DMPlex
3326 
3327   Output Parameter:
3328 
3329   Note:
3330   This should be called after all calls to DMPlexSetCone()
3331 
3332   Level: beginner
3333 
3334 .seealso: DMPlexCreate(), DMPlexSetChart(), DMPlexSetConeSize(), DMPlexSetCone()
3335 @*/
3336 PetscErrorCode DMPlexSymmetrize(DM dm)
3337 {
3338   DM_Plex       *mesh = (DM_Plex*) dm->data;
3339   PetscInt      *offsets;
3340   PetscInt       supportSize;
3341   PetscInt       pStart, pEnd, p;
3342   PetscErrorCode ierr;
3343 
3344   PetscFunctionBegin;
3345   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3346   if (mesh->supports) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Supports were already setup in this DMPlex");
3347   ierr = PetscLogEventBegin(DMPLEX_Symmetrize,dm,0,0,0);CHKERRQ(ierr);
3348   /* Calculate support sizes */
3349   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
3350   for (p = pStart; p < pEnd; ++p) {
3351     PetscInt dof, off, c;
3352 
3353     ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
3354     ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
3355     for (c = off; c < off+dof; ++c) {
3356       ierr = PetscSectionAddDof(mesh->supportSection, mesh->cones[c], 1);CHKERRQ(ierr);
3357     }
3358   }
3359   for (p = pStart; p < pEnd; ++p) {
3360     PetscInt dof;
3361 
3362     ierr = PetscSectionGetDof(mesh->supportSection, p, &dof);CHKERRQ(ierr);
3363 
3364     mesh->maxSupportSize = PetscMax(mesh->maxSupportSize, dof);
3365   }
3366   ierr = PetscSectionSetUp(mesh->supportSection);CHKERRQ(ierr);
3367   /* Calculate supports */
3368   ierr = PetscSectionGetStorageSize(mesh->supportSection, &supportSize);CHKERRQ(ierr);
3369   ierr = PetscMalloc1(supportSize, &mesh->supports);CHKERRQ(ierr);
3370   ierr = PetscCalloc1(pEnd - pStart, &offsets);CHKERRQ(ierr);
3371   for (p = pStart; p < pEnd; ++p) {
3372     PetscInt dof, off, c;
3373 
3374     ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
3375     ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
3376     for (c = off; c < off+dof; ++c) {
3377       const PetscInt q = mesh->cones[c];
3378       PetscInt       offS;
3379 
3380       ierr = PetscSectionGetOffset(mesh->supportSection, q, &offS);CHKERRQ(ierr);
3381 
3382       mesh->supports[offS+offsets[q]] = p;
3383       ++offsets[q];
3384     }
3385   }
3386   ierr = PetscFree(offsets);CHKERRQ(ierr);
3387   ierr = PetscLogEventEnd(DMPLEX_Symmetrize,dm,0,0,0);CHKERRQ(ierr);
3388   PetscFunctionReturn(0);
3389 }
3390 
3391 static PetscErrorCode DMPlexCreateDepthStratum(DM dm, DMLabel label, PetscInt depth, PetscInt pStart, PetscInt pEnd)
3392 {
3393   IS             stratumIS;
3394   PetscErrorCode ierr;
3395 
3396   PetscFunctionBegin;
3397   if (pStart >= pEnd) PetscFunctionReturn(0);
3398   if (PetscDefined(USE_DEBUG)) {
3399     PetscInt  qStart, qEnd, numLevels, level;
3400     PetscBool overlap = PETSC_FALSE;
3401     ierr = DMLabelGetNumValues(label, &numLevels);CHKERRQ(ierr);
3402     for (level = 0; level < numLevels; level++) {
3403       ierr = DMLabelGetStratumBounds(label, level, &qStart, &qEnd);CHKERRQ(ierr);
3404       if ((pStart >= qStart && pStart < qEnd) || (pEnd > qStart && pEnd <= qEnd)) {overlap = PETSC_TRUE; break;}
3405     }
3406     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);
3407   }
3408   ierr = ISCreateStride(PETSC_COMM_SELF, pEnd-pStart, pStart, 1, &stratumIS);CHKERRQ(ierr);
3409   ierr = DMLabelSetStratumIS(label, depth, stratumIS);CHKERRQ(ierr);
3410   ierr = ISDestroy(&stratumIS);CHKERRQ(ierr);
3411   PetscFunctionReturn(0);
3412 }
3413 
3414 /*@
3415   DMPlexStratify - The DAG for most topologies is a graded poset (https://en.wikipedia.org/wiki/Graded_poset), and
3416   can be illustrated by a Hasse Diagram (https://en.wikipedia.org/wiki/Hasse_diagram). The strata group all points of the
3417   same grade, and this function calculates the strata. This grade can be seen as the height (or depth) of the point in
3418   the DAG.
3419 
3420   Collective on dm
3421 
3422   Input Parameter:
3423 . mesh - The DMPlex
3424 
3425   Output Parameter:
3426 
3427   Notes:
3428   Concretely, DMPlexStratify() creates a new label named "depth" containing the depth in the DAG of each point. For cell-vertex
3429   meshes, vertices are depth 0 and cells are depth 1. For fully interpolated meshes, depth 0 for vertices, 1 for edges, and so on
3430   until cells have depth equal to the dimension of the mesh. The depth label can be accessed through DMPlexGetDepthLabel() or DMPlexGetDepthStratum(), or
3431   manually via DMGetLabel().  The height is defined implicitly by height = maxDimension - depth, and can be accessed
3432   via DMPlexGetHeightStratum().  For example, cells have height 0 and faces have height 1.
3433 
3434   The depth of a point is calculated by executing a breadth-first search (BFS) on the DAG. This could produce surprising results
3435   if run on a partially interpolated mesh, meaning one that had some edges and faces, but not others. For example, suppose that
3436   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
3437   to interpolate only that one (e0), so that
3438 $  cone(c0) = {e0, v2}
3439 $  cone(e0) = {v0, v1}
3440   If DMPlexStratify() is run on this mesh, it will give depths
3441 $  depth 0 = {v0, v1, v2}
3442 $  depth 1 = {e0, c0}
3443   where the triangle has been given depth 1, instead of 2, because it is reachable from vertex v2.
3444 
3445   DMPlexStratify() should be called after all calls to DMPlexSymmetrize()
3446 
3447   Level: beginner
3448 
3449 .seealso: DMPlexCreate(), DMPlexSymmetrize(), DMPlexComputeCellTypes()
3450 @*/
3451 PetscErrorCode DMPlexStratify(DM dm)
3452 {
3453   DM_Plex       *mesh = (DM_Plex*) dm->data;
3454   DMLabel        label;
3455   PetscInt       pStart, pEnd, p;
3456   PetscInt       numRoots = 0, numLeaves = 0;
3457   PetscErrorCode ierr;
3458 
3459   PetscFunctionBegin;
3460   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3461   ierr = PetscLogEventBegin(DMPLEX_Stratify,dm,0,0,0);CHKERRQ(ierr);
3462 
3463   /* Create depth label */
3464   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
3465   ierr = DMCreateLabel(dm, "depth");CHKERRQ(ierr);
3466   ierr = DMPlexGetDepthLabel(dm, &label);CHKERRQ(ierr);
3467 
3468   {
3469     /* Initialize roots and count leaves */
3470     PetscInt sMin = PETSC_MAX_INT;
3471     PetscInt sMax = PETSC_MIN_INT;
3472     PetscInt coneSize, supportSize;
3473 
3474     for (p = pStart; p < pEnd; ++p) {
3475       ierr = DMPlexGetConeSize(dm, p, &coneSize);CHKERRQ(ierr);
3476       ierr = DMPlexGetSupportSize(dm, p, &supportSize);CHKERRQ(ierr);
3477       if (!coneSize && supportSize) {
3478         sMin = PetscMin(p, sMin);
3479         sMax = PetscMax(p, sMax);
3480         ++numRoots;
3481       } else if (!supportSize && coneSize) {
3482         ++numLeaves;
3483       } else if (!supportSize && !coneSize) {
3484         /* Isolated points */
3485         sMin = PetscMin(p, sMin);
3486         sMax = PetscMax(p, sMax);
3487       }
3488     }
3489     ierr = DMPlexCreateDepthStratum(dm, label, 0, sMin, sMax+1);CHKERRQ(ierr);
3490   }
3491 
3492   if (numRoots + numLeaves == (pEnd - pStart)) {
3493     PetscInt sMin = PETSC_MAX_INT;
3494     PetscInt sMax = PETSC_MIN_INT;
3495     PetscInt coneSize, supportSize;
3496 
3497     for (p = pStart; p < pEnd; ++p) {
3498       ierr = DMPlexGetConeSize(dm, p, &coneSize);CHKERRQ(ierr);
3499       ierr = DMPlexGetSupportSize(dm, p, &supportSize);CHKERRQ(ierr);
3500       if (!supportSize && coneSize) {
3501         sMin = PetscMin(p, sMin);
3502         sMax = PetscMax(p, sMax);
3503       }
3504     }
3505     ierr = DMPlexCreateDepthStratum(dm, label, 1, sMin, sMax+1);CHKERRQ(ierr);
3506   } else {
3507     PetscInt level = 0;
3508     PetscInt qStart, qEnd, q;
3509 
3510     ierr = DMLabelGetStratumBounds(label, level, &qStart, &qEnd);CHKERRQ(ierr);
3511     while (qEnd > qStart) {
3512       PetscInt sMin = PETSC_MAX_INT;
3513       PetscInt sMax = PETSC_MIN_INT;
3514 
3515       for (q = qStart; q < qEnd; ++q) {
3516         const PetscInt *support;
3517         PetscInt        supportSize, s;
3518 
3519         ierr = DMPlexGetSupportSize(dm, q, &supportSize);CHKERRQ(ierr);
3520         ierr = DMPlexGetSupport(dm, q, &support);CHKERRQ(ierr);
3521         for (s = 0; s < supportSize; ++s) {
3522           sMin = PetscMin(support[s], sMin);
3523           sMax = PetscMax(support[s], sMax);
3524         }
3525       }
3526       ierr = DMLabelGetNumValues(label, &level);CHKERRQ(ierr);
3527       ierr = DMPlexCreateDepthStratum(dm, label, level, sMin, sMax+1);CHKERRQ(ierr);
3528       ierr = DMLabelGetStratumBounds(label, level, &qStart, &qEnd);CHKERRQ(ierr);
3529     }
3530   }
3531   { /* just in case there is an empty process */
3532     PetscInt numValues, maxValues = 0, v;
3533 
3534     ierr = DMLabelGetNumValues(label, &numValues);CHKERRQ(ierr);
3535     ierr = MPI_Allreduce(&numValues,&maxValues,1,MPIU_INT,MPI_MAX,PetscObjectComm((PetscObject)dm));CHKERRMPI(ierr);
3536     for (v = numValues; v < maxValues; v++) {
3537       ierr = DMLabelAddStratum(label, v);CHKERRQ(ierr);
3538     }
3539   }
3540   ierr = PetscObjectStateGet((PetscObject) label, &mesh->depthState);CHKERRQ(ierr);
3541   ierr = PetscLogEventEnd(DMPLEX_Stratify,dm,0,0,0);CHKERRQ(ierr);
3542   PetscFunctionReturn(0);
3543 }
3544 
3545 PetscErrorCode DMPlexComputeCellType_Internal(DM dm, PetscInt p, PetscInt pdepth, DMPolytopeType *pt)
3546 {
3547   DMPolytopeType ct = DM_POLYTOPE_UNKNOWN;
3548   PetscInt       dim, depth, pheight, coneSize;
3549   PetscErrorCode ierr;
3550 
3551   PetscFunctionBeginHot;
3552   ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr);
3553   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3554   ierr = DMPlexGetConeSize(dm, p, &coneSize);CHKERRQ(ierr);
3555   pheight = depth - pdepth;
3556   if (depth <= 1) {
3557     switch (pdepth) {
3558       case 0: ct = DM_POLYTOPE_POINT;break;
3559       case 1:
3560         switch (coneSize) {
3561           case 2: ct = DM_POLYTOPE_SEGMENT;break;
3562           case 3: ct = DM_POLYTOPE_TRIANGLE;break;
3563           case 4:
3564           switch (dim) {
3565             case 2: ct = DM_POLYTOPE_QUADRILATERAL;break;
3566             case 3: ct = DM_POLYTOPE_TETRAHEDRON;break;
3567             default: break;
3568           }
3569           break;
3570         case 5: ct = DM_POLYTOPE_PYRAMID;break;
3571         case 6: ct = DM_POLYTOPE_TRI_PRISM_TENSOR;break;
3572         case 8: ct = DM_POLYTOPE_HEXAHEDRON;break;
3573         default: break;
3574       }
3575     }
3576   } else {
3577     if (pdepth == 0) {
3578       ct = DM_POLYTOPE_POINT;
3579     } else if (pheight == 0) {
3580       switch (dim) {
3581         case 1:
3582           switch (coneSize) {
3583             case 2: ct = DM_POLYTOPE_SEGMENT;break;
3584             default: break;
3585           }
3586           break;
3587         case 2:
3588           switch (coneSize) {
3589             case 3: ct = DM_POLYTOPE_TRIANGLE;break;
3590             case 4: ct = DM_POLYTOPE_QUADRILATERAL;break;
3591             default: break;
3592           }
3593           break;
3594         case 3:
3595           switch (coneSize) {
3596             case 4: ct = DM_POLYTOPE_TETRAHEDRON;break;
3597             case 5:
3598             {
3599               const PetscInt *cone;
3600               PetscInt        faceConeSize;
3601 
3602               ierr = DMPlexGetCone(dm, p, &cone);CHKERRQ(ierr);
3603               ierr = DMPlexGetConeSize(dm, cone[0], &faceConeSize);CHKERRQ(ierr);
3604               switch (faceConeSize) {
3605                 case 3: ct = DM_POLYTOPE_TRI_PRISM_TENSOR;break;
3606                 case 4: ct = DM_POLYTOPE_PYRAMID;break;
3607               }
3608             }
3609             break;
3610             case 6: ct = DM_POLYTOPE_HEXAHEDRON;break;
3611             default: break;
3612           }
3613           break;
3614         default: break;
3615       }
3616     } else if (pheight > 0) {
3617       switch (coneSize) {
3618         case 2: ct = DM_POLYTOPE_SEGMENT;break;
3619         case 3: ct = DM_POLYTOPE_TRIANGLE;break;
3620         case 4: ct = DM_POLYTOPE_QUADRILATERAL;break;
3621         default: break;
3622       }
3623     }
3624   }
3625   *pt = ct;
3626   PetscFunctionReturn(0);
3627 }
3628 
3629 /*@
3630   DMPlexComputeCellTypes - Infer the polytope type of every cell using its dimension and cone size.
3631 
3632   Collective on dm
3633 
3634   Input Parameter:
3635 . mesh - The DMPlex
3636 
3637   DMPlexComputeCellTypes() should be called after all calls to DMPlexSymmetrize() and DMPlexStratify()
3638 
3639   Level: developer
3640 
3641   Note: This function is normally called automatically by Plex when a cell type is requested. It creates an
3642   internal DMLabel named "celltype" which can be directly accessed using DMGetLabel(). A user may disable
3643   automatic creation by creating the label manually, using DMCreateLabel(dm, "celltype").
3644 
3645 .seealso: DMPlexCreate(), DMPlexSymmetrize(), DMPlexStratify(), DMGetLabel(), DMCreateLabel()
3646 @*/
3647 PetscErrorCode DMPlexComputeCellTypes(DM dm)
3648 {
3649   DM_Plex       *mesh;
3650   DMLabel        ctLabel;
3651   PetscInt       pStart, pEnd, p;
3652   PetscErrorCode ierr;
3653 
3654   PetscFunctionBegin;
3655   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3656   mesh = (DM_Plex *) dm->data;
3657   ierr = DMCreateLabel(dm, "celltype");CHKERRQ(ierr);
3658   ierr = DMPlexGetCellTypeLabel(dm, &ctLabel);CHKERRQ(ierr);
3659   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
3660   for (p = pStart; p < pEnd; ++p) {
3661     DMPolytopeType ct = DM_POLYTOPE_UNKNOWN;
3662     PetscInt       pdepth;
3663 
3664     ierr = DMPlexGetPointDepth(dm, p, &pdepth);CHKERRQ(ierr);
3665     ierr = DMPlexComputeCellType_Internal(dm, p, pdepth, &ct);CHKERRQ(ierr);
3666     if (ct == DM_POLYTOPE_UNKNOWN) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_SUP, "Point %D is screwed up", p);
3667     ierr = DMLabelSetValue(ctLabel, p, ct);CHKERRQ(ierr);
3668   }
3669   ierr = PetscObjectStateGet((PetscObject) ctLabel, &mesh->celltypeState);CHKERRQ(ierr);
3670   ierr = PetscObjectViewFromOptions((PetscObject) ctLabel, NULL, "-dm_plex_celltypes_view");CHKERRQ(ierr);
3671   PetscFunctionReturn(0);
3672 }
3673 
3674 /*@C
3675   DMPlexGetJoin - Get an array for the join of the set of points
3676 
3677   Not Collective
3678 
3679   Input Parameters:
3680 + dm - The DMPlex object
3681 . numPoints - The number of input points for the join
3682 - points - The input points
3683 
3684   Output Parameters:
3685 + numCoveredPoints - The number of points in the join
3686 - coveredPoints - The points in the join
3687 
3688   Level: intermediate
3689 
3690   Note: Currently, this is restricted to a single level join
3691 
3692   Fortran Notes:
3693   Since it returns an array, this routine is only available in Fortran 90, and you must
3694   include petsc.h90 in your code.
3695 
3696   The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array.
3697 
3698 .seealso: DMPlexRestoreJoin(), DMPlexGetMeet()
3699 @*/
3700 PetscErrorCode DMPlexGetJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
3701 {
3702   DM_Plex       *mesh = (DM_Plex*) dm->data;
3703   PetscInt      *join[2];
3704   PetscInt       joinSize, i = 0;
3705   PetscInt       dof, off, p, c, m;
3706   PetscErrorCode ierr;
3707 
3708   PetscFunctionBegin;
3709   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3710   PetscValidIntPointer(points, 3);
3711   PetscValidIntPointer(numCoveredPoints, 4);
3712   PetscValidPointer(coveredPoints, 5);
3713   ierr = DMGetWorkArray(dm, mesh->maxSupportSize, MPIU_INT, &join[0]);CHKERRQ(ierr);
3714   ierr = DMGetWorkArray(dm, mesh->maxSupportSize, MPIU_INT, &join[1]);CHKERRQ(ierr);
3715   /* Copy in support of first point */
3716   ierr = PetscSectionGetDof(mesh->supportSection, points[0], &dof);CHKERRQ(ierr);
3717   ierr = PetscSectionGetOffset(mesh->supportSection, points[0], &off);CHKERRQ(ierr);
3718   for (joinSize = 0; joinSize < dof; ++joinSize) {
3719     join[i][joinSize] = mesh->supports[off+joinSize];
3720   }
3721   /* Check each successive support */
3722   for (p = 1; p < numPoints; ++p) {
3723     PetscInt newJoinSize = 0;
3724 
3725     ierr = PetscSectionGetDof(mesh->supportSection, points[p], &dof);CHKERRQ(ierr);
3726     ierr = PetscSectionGetOffset(mesh->supportSection, points[p], &off);CHKERRQ(ierr);
3727     for (c = 0; c < dof; ++c) {
3728       const PetscInt point = mesh->supports[off+c];
3729 
3730       for (m = 0; m < joinSize; ++m) {
3731         if (point == join[i][m]) {
3732           join[1-i][newJoinSize++] = point;
3733           break;
3734         }
3735       }
3736     }
3737     joinSize = newJoinSize;
3738     i        = 1-i;
3739   }
3740   *numCoveredPoints = joinSize;
3741   *coveredPoints    = join[i];
3742   ierr              = DMRestoreWorkArray(dm, mesh->maxSupportSize, MPIU_INT, &join[1-i]);CHKERRQ(ierr);
3743   PetscFunctionReturn(0);
3744 }
3745 
3746 /*@C
3747   DMPlexRestoreJoin - Restore an array for the join of the set of points
3748 
3749   Not Collective
3750 
3751   Input Parameters:
3752 + dm - The DMPlex object
3753 . numPoints - The number of input points for the join
3754 - points - The input points
3755 
3756   Output Parameters:
3757 + numCoveredPoints - The number of points in the join
3758 - coveredPoints - The points in the join
3759 
3760   Fortran Notes:
3761   Since it returns an array, this routine is only available in Fortran 90, and you must
3762   include petsc.h90 in your code.
3763 
3764   The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array.
3765 
3766   Level: intermediate
3767 
3768 .seealso: DMPlexGetJoin(), DMPlexGetFullJoin(), DMPlexGetMeet()
3769 @*/
3770 PetscErrorCode DMPlexRestoreJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
3771 {
3772   PetscErrorCode ierr;
3773 
3774   PetscFunctionBegin;
3775   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3776   if (points) PetscValidIntPointer(points,3);
3777   if (numCoveredPoints) PetscValidIntPointer(numCoveredPoints,4);
3778   PetscValidPointer(coveredPoints, 5);
3779   ierr = DMRestoreWorkArray(dm, 0, MPIU_INT, (void*) coveredPoints);CHKERRQ(ierr);
3780   if (numCoveredPoints) *numCoveredPoints = 0;
3781   PetscFunctionReturn(0);
3782 }
3783 
3784 /*@C
3785   DMPlexGetFullJoin - Get an array for the join of the set of points
3786 
3787   Not Collective
3788 
3789   Input Parameters:
3790 + dm - The DMPlex object
3791 . numPoints - The number of input points for the join
3792 - points - The input points
3793 
3794   Output Parameters:
3795 + numCoveredPoints - The number of points in the join
3796 - coveredPoints - The points in the join
3797 
3798   Fortran Notes:
3799   Since it returns an array, this routine is only available in Fortran 90, and you must
3800   include petsc.h90 in your code.
3801 
3802   The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array.
3803 
3804   Level: intermediate
3805 
3806 .seealso: DMPlexGetJoin(), DMPlexRestoreJoin(), DMPlexGetMeet()
3807 @*/
3808 PetscErrorCode DMPlexGetFullJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
3809 {
3810   DM_Plex       *mesh = (DM_Plex*) dm->data;
3811   PetscInt      *offsets, **closures;
3812   PetscInt      *join[2];
3813   PetscInt       depth = 0, maxSize, joinSize = 0, i = 0;
3814   PetscInt       p, d, c, m, ms;
3815   PetscErrorCode ierr;
3816 
3817   PetscFunctionBegin;
3818   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3819   PetscValidIntPointer(points, 3);
3820   PetscValidIntPointer(numCoveredPoints, 4);
3821   PetscValidPointer(coveredPoints, 5);
3822 
3823   ierr    = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3824   ierr    = PetscCalloc1(numPoints, &closures);CHKERRQ(ierr);
3825   ierr    = DMGetWorkArray(dm, numPoints*(depth+2), MPIU_INT, &offsets);CHKERRQ(ierr);
3826   ms      = mesh->maxSupportSize;
3827   maxSize = (ms > 1) ? ((PetscPowInt(ms,depth+1)-1)/(ms-1)) : depth + 1;
3828   ierr    = DMGetWorkArray(dm, maxSize, MPIU_INT, &join[0]);CHKERRQ(ierr);
3829   ierr    = DMGetWorkArray(dm, maxSize, MPIU_INT, &join[1]);CHKERRQ(ierr);
3830 
3831   for (p = 0; p < numPoints; ++p) {
3832     PetscInt closureSize;
3833 
3834     ierr = DMPlexGetTransitiveClosure(dm, points[p], PETSC_FALSE, &closureSize, &closures[p]);CHKERRQ(ierr);
3835 
3836     offsets[p*(depth+2)+0] = 0;
3837     for (d = 0; d < depth+1; ++d) {
3838       PetscInt pStart, pEnd, i;
3839 
3840       ierr = DMPlexGetDepthStratum(dm, d, &pStart, &pEnd);CHKERRQ(ierr);
3841       for (i = offsets[p*(depth+2)+d]; i < closureSize; ++i) {
3842         if ((pStart > closures[p][i*2]) || (pEnd <= closures[p][i*2])) {
3843           offsets[p*(depth+2)+d+1] = i;
3844           break;
3845         }
3846       }
3847       if (i == closureSize) offsets[p*(depth+2)+d+1] = i;
3848     }
3849     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);
3850   }
3851   for (d = 0; d < depth+1; ++d) {
3852     PetscInt dof;
3853 
3854     /* Copy in support of first point */
3855     dof = offsets[d+1] - offsets[d];
3856     for (joinSize = 0; joinSize < dof; ++joinSize) {
3857       join[i][joinSize] = closures[0][(offsets[d]+joinSize)*2];
3858     }
3859     /* Check each successive cone */
3860     for (p = 1; p < numPoints && joinSize; ++p) {
3861       PetscInt newJoinSize = 0;
3862 
3863       dof = offsets[p*(depth+2)+d+1] - offsets[p*(depth+2)+d];
3864       for (c = 0; c < dof; ++c) {
3865         const PetscInt point = closures[p][(offsets[p*(depth+2)+d]+c)*2];
3866 
3867         for (m = 0; m < joinSize; ++m) {
3868           if (point == join[i][m]) {
3869             join[1-i][newJoinSize++] = point;
3870             break;
3871           }
3872         }
3873       }
3874       joinSize = newJoinSize;
3875       i        = 1-i;
3876     }
3877     if (joinSize) break;
3878   }
3879   *numCoveredPoints = joinSize;
3880   *coveredPoints    = join[i];
3881   for (p = 0; p < numPoints; ++p) {
3882     ierr = DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_FALSE, NULL, &closures[p]);CHKERRQ(ierr);
3883   }
3884   ierr = PetscFree(closures);CHKERRQ(ierr);
3885   ierr = DMRestoreWorkArray(dm, numPoints*(depth+2), MPIU_INT, &offsets);CHKERRQ(ierr);
3886   ierr = DMRestoreWorkArray(dm, mesh->maxSupportSize, MPIU_INT, &join[1-i]);CHKERRQ(ierr);
3887   PetscFunctionReturn(0);
3888 }
3889 
3890 /*@C
3891   DMPlexGetMeet - Get an array for the meet of the set of points
3892 
3893   Not Collective
3894 
3895   Input Parameters:
3896 + dm - The DMPlex object
3897 . numPoints - The number of input points for the meet
3898 - points - The input points
3899 
3900   Output Parameters:
3901 + numCoveredPoints - The number of points in the meet
3902 - coveredPoints - The points in the meet
3903 
3904   Level: intermediate
3905 
3906   Note: Currently, this is restricted to a single level meet
3907 
3908   Fortran Notes:
3909   Since it returns an array, this routine is only available in Fortran 90, and you must
3910   include petsc.h90 in your code.
3911 
3912   The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array.
3913 
3914 .seealso: DMPlexRestoreMeet(), DMPlexGetJoin()
3915 @*/
3916 PetscErrorCode DMPlexGetMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveringPoints, const PetscInt **coveringPoints)
3917 {
3918   DM_Plex       *mesh = (DM_Plex*) dm->data;
3919   PetscInt      *meet[2];
3920   PetscInt       meetSize, i = 0;
3921   PetscInt       dof, off, p, c, m;
3922   PetscErrorCode ierr;
3923 
3924   PetscFunctionBegin;
3925   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3926   PetscValidPointer(points, 3);
3927   PetscValidPointer(numCoveringPoints, 4);
3928   PetscValidPointer(coveringPoints, 5);
3929   ierr = DMGetWorkArray(dm, mesh->maxConeSize, MPIU_INT, &meet[0]);CHKERRQ(ierr);
3930   ierr = DMGetWorkArray(dm, mesh->maxConeSize, MPIU_INT, &meet[1]);CHKERRQ(ierr);
3931   /* Copy in cone of first point */
3932   ierr = PetscSectionGetDof(mesh->coneSection, points[0], &dof);CHKERRQ(ierr);
3933   ierr = PetscSectionGetOffset(mesh->coneSection, points[0], &off);CHKERRQ(ierr);
3934   for (meetSize = 0; meetSize < dof; ++meetSize) {
3935     meet[i][meetSize] = mesh->cones[off+meetSize];
3936   }
3937   /* Check each successive cone */
3938   for (p = 1; p < numPoints; ++p) {
3939     PetscInt newMeetSize = 0;
3940 
3941     ierr = PetscSectionGetDof(mesh->coneSection, points[p], &dof);CHKERRQ(ierr);
3942     ierr = PetscSectionGetOffset(mesh->coneSection, points[p], &off);CHKERRQ(ierr);
3943     for (c = 0; c < dof; ++c) {
3944       const PetscInt point = mesh->cones[off+c];
3945 
3946       for (m = 0; m < meetSize; ++m) {
3947         if (point == meet[i][m]) {
3948           meet[1-i][newMeetSize++] = point;
3949           break;
3950         }
3951       }
3952     }
3953     meetSize = newMeetSize;
3954     i        = 1-i;
3955   }
3956   *numCoveringPoints = meetSize;
3957   *coveringPoints    = meet[i];
3958   ierr               = DMRestoreWorkArray(dm, mesh->maxConeSize, MPIU_INT, &meet[1-i]);CHKERRQ(ierr);
3959   PetscFunctionReturn(0);
3960 }
3961 
3962 /*@C
3963   DMPlexRestoreMeet - Restore an array for the meet of the set of points
3964 
3965   Not Collective
3966 
3967   Input Parameters:
3968 + dm - The DMPlex object
3969 . numPoints - The number of input points for the meet
3970 - points - The input points
3971 
3972   Output Parameters:
3973 + numCoveredPoints - The number of points in the meet
3974 - coveredPoints - The points in the meet
3975 
3976   Level: intermediate
3977 
3978   Fortran Notes:
3979   Since it returns an array, this routine is only available in Fortran 90, and you must
3980   include petsc.h90 in your code.
3981 
3982   The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array.
3983 
3984 .seealso: DMPlexGetMeet(), DMPlexGetFullMeet(), DMPlexGetJoin()
3985 @*/
3986 PetscErrorCode DMPlexRestoreMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
3987 {
3988   PetscErrorCode ierr;
3989 
3990   PetscFunctionBegin;
3991   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3992   if (points) PetscValidIntPointer(points,3);
3993   if (numCoveredPoints) PetscValidIntPointer(numCoveredPoints,4);
3994   PetscValidPointer(coveredPoints,5);
3995   ierr = DMRestoreWorkArray(dm, 0, MPIU_INT, (void*) coveredPoints);CHKERRQ(ierr);
3996   if (numCoveredPoints) *numCoveredPoints = 0;
3997   PetscFunctionReturn(0);
3998 }
3999 
4000 /*@C
4001   DMPlexGetFullMeet - Get an array for the meet of the set of points
4002 
4003   Not Collective
4004 
4005   Input Parameters:
4006 + dm - The DMPlex object
4007 . numPoints - The number of input points for the meet
4008 - points - The input points
4009 
4010   Output Parameters:
4011 + numCoveredPoints - The number of points in the meet
4012 - coveredPoints - The points in the meet
4013 
4014   Level: intermediate
4015 
4016   Fortran Notes:
4017   Since it returns an array, this routine is only available in Fortran 90, and you must
4018   include petsc.h90 in your code.
4019 
4020   The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array.
4021 
4022 .seealso: DMPlexGetMeet(), DMPlexRestoreMeet(), DMPlexGetJoin()
4023 @*/
4024 PetscErrorCode DMPlexGetFullMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
4025 {
4026   DM_Plex       *mesh = (DM_Plex*) dm->data;
4027   PetscInt      *offsets, **closures;
4028   PetscInt      *meet[2];
4029   PetscInt       height = 0, maxSize, meetSize = 0, i = 0;
4030   PetscInt       p, h, c, m, mc;
4031   PetscErrorCode ierr;
4032 
4033   PetscFunctionBegin;
4034   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4035   PetscValidPointer(points, 3);
4036   PetscValidPointer(numCoveredPoints, 4);
4037   PetscValidPointer(coveredPoints, 5);
4038 
4039   ierr    = DMPlexGetDepth(dm, &height);CHKERRQ(ierr);
4040   ierr    = PetscMalloc1(numPoints, &closures);CHKERRQ(ierr);
4041   ierr    = DMGetWorkArray(dm, numPoints*(height+2), MPIU_INT, &offsets);CHKERRQ(ierr);
4042   mc      = mesh->maxConeSize;
4043   maxSize = (mc > 1) ? ((PetscPowInt(mc,height+1)-1)/(mc-1)) : height + 1;
4044   ierr    = DMGetWorkArray(dm, maxSize, MPIU_INT, &meet[0]);CHKERRQ(ierr);
4045   ierr    = DMGetWorkArray(dm, maxSize, MPIU_INT, &meet[1]);CHKERRQ(ierr);
4046 
4047   for (p = 0; p < numPoints; ++p) {
4048     PetscInt closureSize;
4049 
4050     ierr = DMPlexGetTransitiveClosure(dm, points[p], PETSC_TRUE, &closureSize, &closures[p]);CHKERRQ(ierr);
4051 
4052     offsets[p*(height+2)+0] = 0;
4053     for (h = 0; h < height+1; ++h) {
4054       PetscInt pStart, pEnd, i;
4055 
4056       ierr = DMPlexGetHeightStratum(dm, h, &pStart, &pEnd);CHKERRQ(ierr);
4057       for (i = offsets[p*(height+2)+h]; i < closureSize; ++i) {
4058         if ((pStart > closures[p][i*2]) || (pEnd <= closures[p][i*2])) {
4059           offsets[p*(height+2)+h+1] = i;
4060           break;
4061         }
4062       }
4063       if (i == closureSize) offsets[p*(height+2)+h+1] = i;
4064     }
4065     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);
4066   }
4067   for (h = 0; h < height+1; ++h) {
4068     PetscInt dof;
4069 
4070     /* Copy in cone of first point */
4071     dof = offsets[h+1] - offsets[h];
4072     for (meetSize = 0; meetSize < dof; ++meetSize) {
4073       meet[i][meetSize] = closures[0][(offsets[h]+meetSize)*2];
4074     }
4075     /* Check each successive cone */
4076     for (p = 1; p < numPoints && meetSize; ++p) {
4077       PetscInt newMeetSize = 0;
4078 
4079       dof = offsets[p*(height+2)+h+1] - offsets[p*(height+2)+h];
4080       for (c = 0; c < dof; ++c) {
4081         const PetscInt point = closures[p][(offsets[p*(height+2)+h]+c)*2];
4082 
4083         for (m = 0; m < meetSize; ++m) {
4084           if (point == meet[i][m]) {
4085             meet[1-i][newMeetSize++] = point;
4086             break;
4087           }
4088         }
4089       }
4090       meetSize = newMeetSize;
4091       i        = 1-i;
4092     }
4093     if (meetSize) break;
4094   }
4095   *numCoveredPoints = meetSize;
4096   *coveredPoints    = meet[i];
4097   for (p = 0; p < numPoints; ++p) {
4098     ierr = DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_TRUE, NULL, &closures[p]);CHKERRQ(ierr);
4099   }
4100   ierr = PetscFree(closures);CHKERRQ(ierr);
4101   ierr = DMRestoreWorkArray(dm, numPoints*(height+2), MPIU_INT, &offsets);CHKERRQ(ierr);
4102   ierr = DMRestoreWorkArray(dm, mesh->maxConeSize, MPIU_INT, &meet[1-i]);CHKERRQ(ierr);
4103   PetscFunctionReturn(0);
4104 }
4105 
4106 /*@C
4107   DMPlexEqual - Determine if two DMs have the same topology
4108 
4109   Not Collective
4110 
4111   Input Parameters:
4112 + dmA - A DMPlex object
4113 - dmB - A DMPlex object
4114 
4115   Output Parameters:
4116 . equal - PETSC_TRUE if the topologies are identical
4117 
4118   Level: intermediate
4119 
4120   Notes:
4121   We are not solving graph isomorphism, so we do not permutation.
4122 
4123 .seealso: DMPlexGetCone()
4124 @*/
4125 PetscErrorCode DMPlexEqual(DM dmA, DM dmB, PetscBool *equal)
4126 {
4127   PetscInt       depth, depthB, pStart, pEnd, pStartB, pEndB, p;
4128   PetscErrorCode ierr;
4129 
4130   PetscFunctionBegin;
4131   PetscValidHeaderSpecific(dmA, DM_CLASSID, 1);
4132   PetscValidHeaderSpecific(dmB, DM_CLASSID, 2);
4133   PetscValidPointer(equal, 3);
4134 
4135   *equal = PETSC_FALSE;
4136   ierr = DMPlexGetDepth(dmA, &depth);CHKERRQ(ierr);
4137   ierr = DMPlexGetDepth(dmB, &depthB);CHKERRQ(ierr);
4138   if (depth != depthB) PetscFunctionReturn(0);
4139   ierr = DMPlexGetChart(dmA, &pStart,  &pEnd);CHKERRQ(ierr);
4140   ierr = DMPlexGetChart(dmB, &pStartB, &pEndB);CHKERRQ(ierr);
4141   if ((pStart != pStartB) || (pEnd != pEndB)) PetscFunctionReturn(0);
4142   for (p = pStart; p < pEnd; ++p) {
4143     const PetscInt *cone, *coneB, *ornt, *orntB, *support, *supportB;
4144     PetscInt        coneSize, coneSizeB, c, supportSize, supportSizeB, s;
4145 
4146     ierr = DMPlexGetConeSize(dmA, p, &coneSize);CHKERRQ(ierr);
4147     ierr = DMPlexGetCone(dmA, p, &cone);CHKERRQ(ierr);
4148     ierr = DMPlexGetConeOrientation(dmA, p, &ornt);CHKERRQ(ierr);
4149     ierr = DMPlexGetConeSize(dmB, p, &coneSizeB);CHKERRQ(ierr);
4150     ierr = DMPlexGetCone(dmB, p, &coneB);CHKERRQ(ierr);
4151     ierr = DMPlexGetConeOrientation(dmB, p, &orntB);CHKERRQ(ierr);
4152     if (coneSize != coneSizeB) PetscFunctionReturn(0);
4153     for (c = 0; c < coneSize; ++c) {
4154       if (cone[c] != coneB[c]) PetscFunctionReturn(0);
4155       if (ornt[c] != orntB[c]) PetscFunctionReturn(0);
4156     }
4157     ierr = DMPlexGetSupportSize(dmA, p, &supportSize);CHKERRQ(ierr);
4158     ierr = DMPlexGetSupport(dmA, p, &support);CHKERRQ(ierr);
4159     ierr = DMPlexGetSupportSize(dmB, p, &supportSizeB);CHKERRQ(ierr);
4160     ierr = DMPlexGetSupport(dmB, p, &supportB);CHKERRQ(ierr);
4161     if (supportSize != supportSizeB) PetscFunctionReturn(0);
4162     for (s = 0; s < supportSize; ++s) {
4163       if (support[s] != supportB[s]) PetscFunctionReturn(0);
4164     }
4165   }
4166   *equal = PETSC_TRUE;
4167   PetscFunctionReturn(0);
4168 }
4169 
4170 /*@C
4171   DMPlexGetNumFaceVertices - Returns the number of vertices on a face
4172 
4173   Not Collective
4174 
4175   Input Parameters:
4176 + dm         - The DMPlex
4177 . cellDim    - The cell dimension
4178 - numCorners - The number of vertices on a cell
4179 
4180   Output Parameters:
4181 . numFaceVertices - The number of vertices on a face
4182 
4183   Level: developer
4184 
4185   Notes:
4186   Of course this can only work for a restricted set of symmetric shapes
4187 
4188 .seealso: DMPlexGetCone()
4189 @*/
4190 PetscErrorCode DMPlexGetNumFaceVertices(DM dm, PetscInt cellDim, PetscInt numCorners, PetscInt *numFaceVertices)
4191 {
4192   MPI_Comm       comm;
4193   PetscErrorCode ierr;
4194 
4195   PetscFunctionBegin;
4196   ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr);
4197   PetscValidPointer(numFaceVertices,4);
4198   switch (cellDim) {
4199   case 0:
4200     *numFaceVertices = 0;
4201     break;
4202   case 1:
4203     *numFaceVertices = 1;
4204     break;
4205   case 2:
4206     switch (numCorners) {
4207     case 3: /* triangle */
4208       *numFaceVertices = 2; /* Edge has 2 vertices */
4209       break;
4210     case 4: /* quadrilateral */
4211       *numFaceVertices = 2; /* Edge has 2 vertices */
4212       break;
4213     case 6: /* quadratic triangle, tri and quad cohesive Lagrange cells */
4214       *numFaceVertices = 3; /* Edge has 3 vertices */
4215       break;
4216     case 9: /* quadratic quadrilateral, quadratic quad cohesive Lagrange cells */
4217       *numFaceVertices = 3; /* Edge has 3 vertices */
4218       break;
4219     default:
4220       SETERRQ2(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %D for dimension %D", numCorners, cellDim);
4221     }
4222     break;
4223   case 3:
4224     switch (numCorners) {
4225     case 4: /* tetradehdron */
4226       *numFaceVertices = 3; /* Face has 3 vertices */
4227       break;
4228     case 6: /* tet cohesive cells */
4229       *numFaceVertices = 4; /* Face has 4 vertices */
4230       break;
4231     case 8: /* hexahedron */
4232       *numFaceVertices = 4; /* Face has 4 vertices */
4233       break;
4234     case 9: /* tet cohesive Lagrange cells */
4235       *numFaceVertices = 6; /* Face has 6 vertices */
4236       break;
4237     case 10: /* quadratic tetrahedron */
4238       *numFaceVertices = 6; /* Face has 6 vertices */
4239       break;
4240     case 12: /* hex cohesive Lagrange cells */
4241       *numFaceVertices = 6; /* Face has 6 vertices */
4242       break;
4243     case 18: /* quadratic tet cohesive Lagrange cells */
4244       *numFaceVertices = 6; /* Face has 6 vertices */
4245       break;
4246     case 27: /* quadratic hexahedron, quadratic hex cohesive Lagrange cells */
4247       *numFaceVertices = 9; /* Face has 9 vertices */
4248       break;
4249     default:
4250       SETERRQ2(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %D for dimension %D", numCorners, cellDim);
4251     }
4252     break;
4253   default:
4254     SETERRQ1(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid cell dimension %D", cellDim);
4255   }
4256   PetscFunctionReturn(0);
4257 }
4258 
4259 /*@
4260   DMPlexGetDepthLabel - Get the DMLabel recording the depth of each point
4261 
4262   Not Collective
4263 
4264   Input Parameter:
4265 . dm    - The DMPlex object
4266 
4267   Output Parameter:
4268 . depthLabel - The DMLabel recording point depth
4269 
4270   Level: developer
4271 
4272 .seealso: DMPlexGetDepth(), DMPlexGetHeightStratum(), DMPlexGetDepthStratum(), DMPlexGetPointDepth(),
4273 @*/
4274 PetscErrorCode DMPlexGetDepthLabel(DM dm, DMLabel *depthLabel)
4275 {
4276   PetscFunctionBegin;
4277   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4278   PetscValidPointer(depthLabel, 2);
4279   *depthLabel = dm->depthLabel;
4280   PetscFunctionReturn(0);
4281 }
4282 
4283 /*@
4284   DMPlexGetDepth - Get the depth of the DAG representing this mesh
4285 
4286   Not Collective
4287 
4288   Input Parameter:
4289 . dm    - The DMPlex object
4290 
4291   Output Parameter:
4292 . depth - The number of strata (breadth first levels) in the DAG
4293 
4294   Level: developer
4295 
4296   Notes:
4297   This returns maximum of point depths over all points, i.e. maximum value of the label returned by DMPlexGetDepthLabel().
4298   The point depth is described more in detail in DMPlexGetDepthStratum().
4299   An empty mesh gives -1.
4300 
4301 .seealso: DMPlexGetDepthLabel(), DMPlexGetDepthStratum(), DMPlexGetPointDepth(), DMPlexSymmetrize()
4302 @*/
4303 PetscErrorCode DMPlexGetDepth(DM dm, PetscInt *depth)
4304 {
4305   DMLabel        label;
4306   PetscInt       d = 0;
4307   PetscErrorCode ierr;
4308 
4309   PetscFunctionBegin;
4310   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4311   PetscValidPointer(depth, 2);
4312   ierr = DMPlexGetDepthLabel(dm, &label);CHKERRQ(ierr);
4313   if (label) {ierr = DMLabelGetNumValues(label, &d);CHKERRQ(ierr);}
4314   *depth = d-1;
4315   PetscFunctionReturn(0);
4316 }
4317 
4318 /*@
4319   DMPlexGetDepthStratum - Get the bounds [start, end) for all points at a certain depth.
4320 
4321   Not Collective
4322 
4323   Input Parameters:
4324 + dm           - The DMPlex object
4325 - stratumValue - The requested depth
4326 
4327   Output Parameters:
4328 + start - The first point at this depth
4329 - end   - One beyond the last point at this depth
4330 
4331   Notes:
4332   Depth indexing is related to topological dimension.  Depth stratum 0 contains the lowest topological dimension points,
4333   often "vertices".  If the mesh is "interpolated" (see DMPlexInterpolate()), then depth stratum 1 contains the next
4334   higher dimension, e.g., "edges".
4335 
4336   Level: developer
4337 
4338 .seealso: DMPlexGetHeightStratum(), DMPlexGetDepth(), DMPlexGetDepthLabel(), DMPlexGetPointDepth(), DMPlexSymmetrize(), DMPlexInterpolate()
4339 @*/
4340 PetscErrorCode DMPlexGetDepthStratum(DM dm, PetscInt stratumValue, PetscInt *start, PetscInt *end)
4341 {
4342   DMLabel        label;
4343   PetscInt       pStart, pEnd;
4344   PetscErrorCode ierr;
4345 
4346   PetscFunctionBegin;
4347   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4348   if (start) {PetscValidPointer(start, 3); *start = 0;}
4349   if (end)   {PetscValidPointer(end,   4); *end   = 0;}
4350   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
4351   if (pStart == pEnd) PetscFunctionReturn(0);
4352   if (stratumValue < 0) {
4353     if (start) *start = pStart;
4354     if (end)   *end   = pEnd;
4355     PetscFunctionReturn(0);
4356   }
4357   ierr = DMPlexGetDepthLabel(dm, &label);CHKERRQ(ierr);
4358   if (!label) SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "No label named depth was found");
4359   ierr = DMLabelGetStratumBounds(label, stratumValue, start, end);CHKERRQ(ierr);
4360   PetscFunctionReturn(0);
4361 }
4362 
4363 /*@
4364   DMPlexGetHeightStratum - Get the bounds [start, end) for all points at a certain height.
4365 
4366   Not Collective
4367 
4368   Input Parameters:
4369 + dm           - The DMPlex object
4370 - stratumValue - The requested height
4371 
4372   Output Parameters:
4373 + start - The first point at this height
4374 - end   - One beyond the last point at this height
4375 
4376   Notes:
4377   Height indexing is related to topological codimension.  Height stratum 0 contains the highest topological dimension
4378   points, often called "cells" or "elements".  If the mesh is "interpolated" (see DMPlexInterpolate()), then height
4379   stratum 1 contains the boundary of these "cells", often called "faces" or "facets".
4380 
4381   Level: developer
4382 
4383 .seealso: DMPlexGetDepthStratum(), DMPlexGetDepth(), DMPlexGetPointHeight()
4384 @*/
4385 PetscErrorCode DMPlexGetHeightStratum(DM dm, PetscInt stratumValue, PetscInt *start, PetscInt *end)
4386 {
4387   DMLabel        label;
4388   PetscInt       depth, pStart, pEnd;
4389   PetscErrorCode ierr;
4390 
4391   PetscFunctionBegin;
4392   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4393   if (start) {PetscValidPointer(start, 3); *start = 0;}
4394   if (end)   {PetscValidPointer(end,   4); *end   = 0;}
4395   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
4396   if (pStart == pEnd) PetscFunctionReturn(0);
4397   if (stratumValue < 0) {
4398     if (start) *start = pStart;
4399     if (end)   *end   = pEnd;
4400     PetscFunctionReturn(0);
4401   }
4402   ierr = DMPlexGetDepthLabel(dm, &label);CHKERRQ(ierr);
4403   if (!label) SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "No label named depth was found");
4404   ierr = DMLabelGetNumValues(label, &depth);CHKERRQ(ierr);
4405   ierr = DMLabelGetStratumBounds(label, depth-1-stratumValue, start, end);CHKERRQ(ierr);
4406   PetscFunctionReturn(0);
4407 }
4408 
4409 /*@
4410   DMPlexGetPointDepth - Get the depth of a given point
4411 
4412   Not Collective
4413 
4414   Input Parameter:
4415 + dm    - The DMPlex object
4416 - point - The point
4417 
4418   Output Parameter:
4419 . depth - The depth of the point
4420 
4421   Level: intermediate
4422 
4423 .seealso: DMPlexGetCellType(), DMPlexGetDepthLabel(), DMPlexGetDepth(), DMPlexGetPointHeight()
4424 @*/
4425 PetscErrorCode DMPlexGetPointDepth(DM dm, PetscInt point, PetscInt *depth)
4426 {
4427   PetscErrorCode ierr;
4428 
4429   PetscFunctionBegin;
4430   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4431   PetscValidIntPointer(depth, 3);
4432   ierr = DMLabelGetValue(dm->depthLabel, point, depth);CHKERRQ(ierr);
4433   PetscFunctionReturn(0);
4434 }
4435 
4436 /*@
4437   DMPlexGetPointHeight - Get the height of a given point
4438 
4439   Not Collective
4440 
4441   Input Parameter:
4442 + dm    - The DMPlex object
4443 - point - The point
4444 
4445   Output Parameter:
4446 . height - The height of the point
4447 
4448   Level: intermediate
4449 
4450 .seealso: DMPlexGetCellType(), DMPlexGetDepthLabel(), DMPlexGetDepth(), DMPlexGetPointDepth()
4451 @*/
4452 PetscErrorCode DMPlexGetPointHeight(DM dm, PetscInt point, PetscInt *height)
4453 {
4454   PetscInt       n, pDepth;
4455   PetscErrorCode ierr;
4456 
4457   PetscFunctionBegin;
4458   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4459   PetscValidIntPointer(height, 3);
4460   ierr = DMLabelGetNumValues(dm->depthLabel, &n);CHKERRQ(ierr);
4461   ierr = DMLabelGetValue(dm->depthLabel, point, &pDepth);CHKERRQ(ierr);
4462   *height = n - 1 - pDepth;  /* DAG depth is n-1 */
4463   PetscFunctionReturn(0);
4464 }
4465 
4466 /*@
4467   DMPlexGetCellTypeLabel - Get the DMLabel recording the polytope type of each cell
4468 
4469   Not Collective
4470 
4471   Input Parameter:
4472 . dm - The DMPlex object
4473 
4474   Output Parameter:
4475 . celltypeLabel - The DMLabel recording cell polytope type
4476 
4477   Note: This function will trigger automatica computation of cell types. This can be disabled by calling
4478   DMCreateLabel(dm, "celltype") beforehand.
4479 
4480   Level: developer
4481 
4482 .seealso: DMPlexGetCellType(), DMPlexGetDepthLabel(), DMCreateLabel()
4483 @*/
4484 PetscErrorCode DMPlexGetCellTypeLabel(DM dm, DMLabel *celltypeLabel)
4485 {
4486   PetscErrorCode ierr;
4487 
4488   PetscFunctionBegin;
4489   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4490   PetscValidPointer(celltypeLabel, 2);
4491   if (!dm->celltypeLabel) {ierr = DMPlexComputeCellTypes(dm);CHKERRQ(ierr);}
4492   *celltypeLabel = dm->celltypeLabel;
4493   PetscFunctionReturn(0);
4494 }
4495 
4496 /*@
4497   DMPlexGetCellType - Get the polytope type of a given cell
4498 
4499   Not Collective
4500 
4501   Input Parameter:
4502 + dm   - The DMPlex object
4503 - cell - The cell
4504 
4505   Output Parameter:
4506 . celltype - The polytope type of the cell
4507 
4508   Level: intermediate
4509 
4510 .seealso: DMPlexGetCellTypeLabel(), DMPlexGetDepthLabel(), DMPlexGetDepth()
4511 @*/
4512 PetscErrorCode DMPlexGetCellType(DM dm, PetscInt cell, DMPolytopeType *celltype)
4513 {
4514   DMLabel        label;
4515   PetscInt       ct;
4516   PetscErrorCode ierr;
4517 
4518   PetscFunctionBegin;
4519   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4520   PetscValidPointer(celltype, 3);
4521   ierr = DMPlexGetCellTypeLabel(dm, &label);CHKERRQ(ierr);
4522   ierr = DMLabelGetValue(label, cell, &ct);CHKERRQ(ierr);
4523   if (ct < 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Cell %D has not been assigned a cell type", cell);
4524   *celltype = (DMPolytopeType) ct;
4525   PetscFunctionReturn(0);
4526 }
4527 
4528 /*@
4529   DMPlexSetCellType - Set the polytope type of a given cell
4530 
4531   Not Collective
4532 
4533   Input Parameters:
4534 + dm   - The DMPlex object
4535 . cell - The cell
4536 - celltype - The polytope type of the cell
4537 
4538   Note: By default, cell types will be automatically computed using DMPlexComputeCellTypes() before this function
4539   is executed. This function will override the computed type. However, if automatic classification will not succeed
4540   and a user wants to manually specify all types, the classification must be disabled by calling
4541   DMCreaateLabel(dm, "celltype") before getting or setting any cell types.
4542 
4543   Level: advanced
4544 
4545 .seealso: DMPlexGetCellTypeLabel(), DMPlexGetDepthLabel(), DMPlexGetDepth(), DMPlexComputeCellTypes(), DMCreateLabel()
4546 @*/
4547 PetscErrorCode DMPlexSetCellType(DM dm, PetscInt cell, DMPolytopeType celltype)
4548 {
4549   DMLabel        label;
4550   PetscErrorCode ierr;
4551 
4552   PetscFunctionBegin;
4553   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4554   ierr = DMPlexGetCellTypeLabel(dm, &label);CHKERRQ(ierr);
4555   ierr = DMLabelSetValue(label, cell, celltype);CHKERRQ(ierr);
4556   PetscFunctionReturn(0);
4557 }
4558 
4559 PetscErrorCode DMCreateCoordinateDM_Plex(DM dm, DM *cdm)
4560 {
4561   PetscSection   section, s;
4562   Mat            m;
4563   PetscInt       maxHeight;
4564   PetscErrorCode ierr;
4565 
4566   PetscFunctionBegin;
4567   ierr = DMClone(dm, cdm);CHKERRQ(ierr);
4568   ierr = DMPlexGetMaxProjectionHeight(dm, &maxHeight);CHKERRQ(ierr);
4569   ierr = DMPlexSetMaxProjectionHeight(*cdm, maxHeight);CHKERRQ(ierr);
4570   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)dm), &section);CHKERRQ(ierr);
4571   ierr = DMSetLocalSection(*cdm, section);CHKERRQ(ierr);
4572   ierr = PetscSectionDestroy(&section);CHKERRQ(ierr);
4573   ierr = PetscSectionCreate(PETSC_COMM_SELF, &s);CHKERRQ(ierr);
4574   ierr = MatCreate(PETSC_COMM_SELF, &m);CHKERRQ(ierr);
4575   ierr = DMSetDefaultConstraints(*cdm, s, m);CHKERRQ(ierr);
4576   ierr = PetscSectionDestroy(&s);CHKERRQ(ierr);
4577   ierr = MatDestroy(&m);CHKERRQ(ierr);
4578 
4579   ierr = DMSetNumFields(*cdm, 1);CHKERRQ(ierr);
4580   ierr = DMCreateDS(*cdm);CHKERRQ(ierr);
4581   PetscFunctionReturn(0);
4582 }
4583 
4584 PetscErrorCode DMCreateCoordinateField_Plex(DM dm, DMField *field)
4585 {
4586   Vec            coordsLocal;
4587   DM             coordsDM;
4588   PetscErrorCode ierr;
4589 
4590   PetscFunctionBegin;
4591   *field = NULL;
4592   ierr = DMGetCoordinatesLocal(dm,&coordsLocal);CHKERRQ(ierr);
4593   ierr = DMGetCoordinateDM(dm,&coordsDM);CHKERRQ(ierr);
4594   if (coordsLocal && coordsDM) {
4595     ierr = DMFieldCreateDS(coordsDM, 0, coordsLocal, field);CHKERRQ(ierr);
4596   }
4597   PetscFunctionReturn(0);
4598 }
4599 
4600 /*@C
4601   DMPlexGetConeSection - Return a section which describes the layout of cone data
4602 
4603   Not Collective
4604 
4605   Input Parameters:
4606 . dm        - The DMPlex object
4607 
4608   Output Parameter:
4609 . section - The PetscSection object
4610 
4611   Level: developer
4612 
4613 .seealso: DMPlexGetSupportSection(), DMPlexGetCones(), DMPlexGetConeOrientations()
4614 @*/
4615 PetscErrorCode DMPlexGetConeSection(DM dm, PetscSection *section)
4616 {
4617   DM_Plex *mesh = (DM_Plex*) dm->data;
4618 
4619   PetscFunctionBegin;
4620   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4621   if (section) *section = mesh->coneSection;
4622   PetscFunctionReturn(0);
4623 }
4624 
4625 /*@C
4626   DMPlexGetSupportSection - Return a section which describes the layout of support data
4627 
4628   Not Collective
4629 
4630   Input Parameters:
4631 . dm        - The DMPlex object
4632 
4633   Output Parameter:
4634 . section - The PetscSection object
4635 
4636   Level: developer
4637 
4638 .seealso: DMPlexGetConeSection()
4639 @*/
4640 PetscErrorCode DMPlexGetSupportSection(DM dm, PetscSection *section)
4641 {
4642   DM_Plex *mesh = (DM_Plex*) dm->data;
4643 
4644   PetscFunctionBegin;
4645   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4646   if (section) *section = mesh->supportSection;
4647   PetscFunctionReturn(0);
4648 }
4649 
4650 /*@C
4651   DMPlexGetCones - Return cone data
4652 
4653   Not Collective
4654 
4655   Input Parameters:
4656 . dm        - The DMPlex object
4657 
4658   Output Parameter:
4659 . cones - The cone for each point
4660 
4661   Level: developer
4662 
4663 .seealso: DMPlexGetConeSection()
4664 @*/
4665 PetscErrorCode DMPlexGetCones(DM dm, PetscInt *cones[])
4666 {
4667   DM_Plex *mesh = (DM_Plex*) dm->data;
4668 
4669   PetscFunctionBegin;
4670   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4671   if (cones) *cones = mesh->cones;
4672   PetscFunctionReturn(0);
4673 }
4674 
4675 /*@C
4676   DMPlexGetConeOrientations - Return cone orientation data
4677 
4678   Not Collective
4679 
4680   Input Parameters:
4681 . dm        - The DMPlex object
4682 
4683   Output Parameter:
4684 . coneOrientations - The cone orientation for each point
4685 
4686   Level: developer
4687 
4688 .seealso: DMPlexGetConeSection()
4689 @*/
4690 PetscErrorCode DMPlexGetConeOrientations(DM dm, PetscInt *coneOrientations[])
4691 {
4692   DM_Plex *mesh = (DM_Plex*) dm->data;
4693 
4694   PetscFunctionBegin;
4695   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4696   if (coneOrientations) *coneOrientations = mesh->coneOrientations;
4697   PetscFunctionReturn(0);
4698 }
4699 
4700 /******************************** FEM Support **********************************/
4701 
4702 /*
4703  Returns number of components and tensor degree for the field.  For interpolated meshes, line should be a point
4704  representing a line in the section.
4705 */
4706 static PetscErrorCode PetscSectionFieldGetTensorDegree_Private(PetscSection section,PetscInt field,PetscInt line,PetscBool vertexchart,PetscInt *Nc,PetscInt *k)
4707 {
4708   PetscErrorCode ierr;
4709 
4710   PetscFunctionBeginHot;
4711   ierr = PetscSectionGetFieldComponents(section, field, Nc);CHKERRQ(ierr);
4712   if (line < 0) {
4713     *k = 0;
4714     *Nc = 0;
4715   } else if (vertexchart) {            /* If we only have a vertex chart, we must have degree k=1 */
4716     *k = 1;
4717   } else {                      /* Assume the full interpolated mesh is in the chart; lines in particular */
4718     /* An order k SEM disc has k-1 dofs on an edge */
4719     ierr = PetscSectionGetFieldDof(section, line, field, k);CHKERRQ(ierr);
4720     *k = *k / *Nc + 1;
4721   }
4722   PetscFunctionReturn(0);
4723 }
4724 
4725 /*@
4726 
4727   DMPlexSetClosurePermutationTensor - Create a permutation from the default (BFS) point ordering in the closure, to a
4728   lexicographic ordering over the tensor product cell (i.e., line, quad, hex, etc.), and set this permutation in the
4729   section provided (or the section of the DM).
4730 
4731   Input Parameters:
4732 + dm      - The DM
4733 . point   - Either a cell (highest dim point) or an edge (dim 1 point), or PETSC_DETERMINE
4734 - section - The PetscSection to reorder, or NULL for the default section
4735 
4736   Note: The point is used to determine the number of dofs/field on an edge. For SEM, this is related to the polynomial
4737   degree of the basis.
4738 
4739   Example:
4740   A typical interpolated single-quad mesh might order points as
4741 .vb
4742   [c0, v1, v2, v3, v4, e5, e6, e7, e8]
4743 
4744   v4 -- e6 -- v3
4745   |           |
4746   e7    c0    e8
4747   |           |
4748   v1 -- e5 -- v2
4749 .ve
4750 
4751   (There is no significance to the ordering described here.)  The default section for a Q3 quad might typically assign
4752   dofs in the order of points, e.g.,
4753 .vb
4754     c0 -> [0,1,2,3]
4755     v1 -> [4]
4756     ...
4757     e5 -> [8, 9]
4758 .ve
4759 
4760   which corresponds to the dofs
4761 .vb
4762     6   10  11  7
4763     13  2   3   15
4764     12  0   1   14
4765     4   8   9   5
4766 .ve
4767 
4768   The closure in BFS ordering works through height strata (cells, edges, vertices) to produce the ordering
4769 .vb
4770   0 1 2 3 8 9 14 15 11 10 13 12 4 5 7 6
4771 .ve
4772 
4773   After calling DMPlexSetClosurePermutationTensor(), the closure will be ordered lexicographically,
4774 .vb
4775    4 8 9 5 12 0 1 14 13 2 3 15 6 10 11 7
4776 .ve
4777 
4778   Level: developer
4779 
4780 .seealso: DMGetLocalSection(), PetscSectionSetClosurePermutation(), DMSetGlobalSection()
4781 @*/
4782 PetscErrorCode DMPlexSetClosurePermutationTensor(DM dm, PetscInt point, PetscSection section)
4783 {
4784   DMLabel        label;
4785   PetscInt       dim, depth = -1, eStart = -1, Nf;
4786   PetscBool      vertexchart;
4787   PetscErrorCode ierr;
4788 
4789   PetscFunctionBegin;
4790   ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr);
4791   if (dim < 1) PetscFunctionReturn(0);
4792   if (point < 0) {
4793     PetscInt sStart,sEnd;
4794 
4795     ierr = DMPlexGetDepthStratum(dm, 1, &sStart, &sEnd);CHKERRQ(ierr);
4796     point = sEnd-sStart ? sStart : point;
4797   }
4798   ierr = DMPlexGetDepthLabel(dm, &label);CHKERRQ(ierr);
4799   if (point >= 0) { ierr = DMLabelGetValue(label, point, &depth);CHKERRQ(ierr); }
4800   if (!section) {ierr = DMGetLocalSection(dm, &section);CHKERRQ(ierr);}
4801   if (depth == 1) {eStart = point;}
4802   else if  (depth == dim) {
4803     const PetscInt *cone;
4804 
4805     ierr = DMPlexGetCone(dm, point, &cone);CHKERRQ(ierr);
4806     if (dim == 2) eStart = cone[0];
4807     else if (dim == 3) {
4808       const PetscInt *cone2;
4809       ierr = DMPlexGetCone(dm, cone[0], &cone2);CHKERRQ(ierr);
4810       eStart = cone2[0];
4811     } 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);
4812   } 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);
4813   {                             /* Determine whether the chart covers all points or just vertices. */
4814     PetscInt pStart,pEnd,cStart,cEnd;
4815     ierr = DMPlexGetDepthStratum(dm,0,&pStart,&pEnd);CHKERRQ(ierr);
4816     ierr = PetscSectionGetChart(section,&cStart,&cEnd);CHKERRQ(ierr);
4817     if (pStart == cStart && pEnd == cEnd) vertexchart = PETSC_TRUE; /* Just vertices */
4818     else vertexchart = PETSC_FALSE;                                 /* Assume all interpolated points are in chart */
4819   }
4820   ierr = PetscSectionGetNumFields(section, &Nf);CHKERRQ(ierr);
4821   for (PetscInt d=1; d<=dim; d++) {
4822     PetscInt k, f, Nc, c, i, j, size = 0, offset = 0, foffset = 0;
4823     PetscInt *perm;
4824 
4825     for (f = 0; f < Nf; ++f) {
4826       ierr = PetscSectionFieldGetTensorDegree_Private(section,f,eStart,vertexchart,&Nc,&k);CHKERRQ(ierr);
4827       size += PetscPowInt(k+1, d)*Nc;
4828     }
4829     ierr = PetscMalloc1(size, &perm);CHKERRQ(ierr);
4830     for (f = 0; f < Nf; ++f) {
4831       switch (d) {
4832       case 1:
4833         ierr = PetscSectionFieldGetTensorDegree_Private(section,f,eStart,vertexchart,&Nc,&k);CHKERRQ(ierr);
4834         /*
4835          Original ordering is [ edge of length k-1; vtx0; vtx1 ]
4836          We want              [ vtx0; edge of length k-1; vtx1 ]
4837          */
4838         for (c=0; c<Nc; c++,offset++) perm[offset] = (k-1)*Nc + c + foffset;
4839         for (i=0; i<k-1; i++) for (c=0; c<Nc; c++,offset++) perm[offset] = i*Nc + c + foffset;
4840         for (c=0; c<Nc; c++,offset++) perm[offset] = k*Nc + c + foffset;
4841         foffset = offset;
4842         break;
4843       case 2:
4844         /* The original quad closure is oriented clockwise, {f, e_b, e_r, e_t, e_l, v_lb, v_rb, v_tr, v_tl} */
4845         ierr = PetscSectionFieldGetTensorDegree_Private(section,f,eStart,vertexchart,&Nc,&k);CHKERRQ(ierr);
4846         /* The SEM order is
4847 
4848          v_lb, {e_b}, v_rb,
4849          e^{(k-1)-i}_l, {f^{i*(k-1)}}, e^i_r,
4850          v_lt, reverse {e_t}, v_rt
4851          */
4852         {
4853           const PetscInt of   = 0;
4854           const PetscInt oeb  = of   + PetscSqr(k-1);
4855           const PetscInt oer  = oeb  + (k-1);
4856           const PetscInt oet  = oer  + (k-1);
4857           const PetscInt oel  = oet  + (k-1);
4858           const PetscInt ovlb = oel  + (k-1);
4859           const PetscInt ovrb = ovlb + 1;
4860           const PetscInt ovrt = ovrb + 1;
4861           const PetscInt ovlt = ovrt + 1;
4862           PetscInt       o;
4863 
4864           /* bottom */
4865           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlb*Nc + c + foffset;
4866           for (o = oeb; o < oer; ++o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
4867           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrb*Nc + c + foffset;
4868           /* middle */
4869           for (i = 0; i < k-1; ++i) {
4870             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oel+(k-2)-i)*Nc + c + foffset;
4871             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;
4872             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oer+i)*Nc + c + foffset;
4873           }
4874           /* top */
4875           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlt*Nc + c + foffset;
4876           for (o = oel-1; o >= oet; --o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
4877           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrt*Nc + c + foffset;
4878           foffset = offset;
4879         }
4880         break;
4881       case 3:
4882         /* The original hex closure is
4883 
4884          {c,
4885          f_b, f_t, f_f, f_b, f_r, f_l,
4886          e_bl, e_bb, e_br, e_bf,  e_tf, e_tr, e_tb, e_tl,  e_rf, e_lf, e_lb, e_rb,
4887          v_blf, v_blb, v_brb, v_brf, v_tlf, v_trf, v_trb, v_tlb}
4888          */
4889         ierr = PetscSectionFieldGetTensorDegree_Private(section,f,eStart,vertexchart,&Nc,&k);CHKERRQ(ierr);
4890         /* The SEM order is
4891          Bottom Slice
4892          v_blf, {e^{(k-1)-n}_bf}, v_brf,
4893          e^{i}_bl, f^{n*(k-1)+(k-1)-i}_b, e^{(k-1)-i}_br,
4894          v_blb, {e_bb}, v_brb,
4895 
4896          Middle Slice (j)
4897          {e^{(k-1)-j}_lf}, {f^{j*(k-1)+n}_f}, e^j_rf,
4898          f^{i*(k-1)+j}_l, {c^{(j*(k-1) + i)*(k-1)+n}_t}, f^{j*(k-1)+i}_r,
4899          e^j_lb, {f^{j*(k-1)+(k-1)-n}_b}, e^{(k-1)-j}_rb,
4900 
4901          Top Slice
4902          v_tlf, {e_tf}, v_trf,
4903          e^{(k-1)-i}_tl, {f^{i*(k-1)}_t}, e^{i}_tr,
4904          v_tlb, {e^{(k-1)-n}_tb}, v_trb,
4905          */
4906         {
4907           const PetscInt oc    = 0;
4908           const PetscInt ofb   = oc    + PetscSqr(k-1)*(k-1);
4909           const PetscInt oft   = ofb   + PetscSqr(k-1);
4910           const PetscInt off   = oft   + PetscSqr(k-1);
4911           const PetscInt ofk   = off   + PetscSqr(k-1);
4912           const PetscInt ofr   = ofk   + PetscSqr(k-1);
4913           const PetscInt ofl   = ofr   + PetscSqr(k-1);
4914           const PetscInt oebl  = ofl   + PetscSqr(k-1);
4915           const PetscInt oebb  = oebl  + (k-1);
4916           const PetscInt oebr  = oebb  + (k-1);
4917           const PetscInt oebf  = oebr  + (k-1);
4918           const PetscInt oetf  = oebf  + (k-1);
4919           const PetscInt oetr  = oetf  + (k-1);
4920           const PetscInt oetb  = oetr  + (k-1);
4921           const PetscInt oetl  = oetb  + (k-1);
4922           const PetscInt oerf  = oetl  + (k-1);
4923           const PetscInt oelf  = oerf  + (k-1);
4924           const PetscInt oelb  = oelf  + (k-1);
4925           const PetscInt oerb  = oelb  + (k-1);
4926           const PetscInt ovblf = oerb  + (k-1);
4927           const PetscInt ovblb = ovblf + 1;
4928           const PetscInt ovbrb = ovblb + 1;
4929           const PetscInt ovbrf = ovbrb + 1;
4930           const PetscInt ovtlf = ovbrf + 1;
4931           const PetscInt ovtrf = ovtlf + 1;
4932           const PetscInt ovtrb = ovtrf + 1;
4933           const PetscInt ovtlb = ovtrb + 1;
4934           PetscInt       o, n;
4935 
4936           /* Bottom Slice */
4937           /*   bottom */
4938           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblf*Nc + c + foffset;
4939           for (o = oetf-1; o >= oebf; --o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
4940           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrf*Nc + c + foffset;
4941           /*   middle */
4942           for (i = 0; i < k-1; ++i) {
4943             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebl+i)*Nc + c + foffset;
4944             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;}
4945             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebr+(k-2)-i)*Nc + c + foffset;
4946           }
4947           /*   top */
4948           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblb*Nc + c + foffset;
4949           for (o = oebb; o < oebr; ++o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
4950           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrb*Nc + c + foffset;
4951 
4952           /* Middle Slice */
4953           for (j = 0; j < k-1; ++j) {
4954             /*   bottom */
4955             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelf+(k-2)-j)*Nc + c + foffset;
4956             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;
4957             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerf+j)*Nc + c + foffset;
4958             /*   middle */
4959             for (i = 0; i < k-1; ++i) {
4960               for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofl+i*(k-1)+j)*Nc + c + foffset;
4961               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;
4962               for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofr+j*(k-1)+i)*Nc + c + foffset;
4963             }
4964             /*   top */
4965             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelb+j)*Nc + c + foffset;
4966             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;
4967             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerb+(k-2)-j)*Nc + c + foffset;
4968           }
4969 
4970           /* Top Slice */
4971           /*   bottom */
4972           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlf*Nc + c + foffset;
4973           for (o = oetf; o < oetr; ++o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
4974           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrf*Nc + c + foffset;
4975           /*   middle */
4976           for (i = 0; i < k-1; ++i) {
4977             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetl+(k-2)-i)*Nc + c + foffset;
4978             for (n = 0; n < k-1; ++n) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oft+i*(k-1)+n)*Nc + c + foffset;
4979             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetr+i)*Nc + c + foffset;
4980           }
4981           /*   top */
4982           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlb*Nc + c + foffset;
4983           for (o = oetl-1; o >= oetb; --o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
4984           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrb*Nc + c + foffset;
4985 
4986           foffset = offset;
4987         }
4988         break;
4989       default: SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_OUTOFRANGE, "No spectral ordering for dimension %D", d);
4990       }
4991     }
4992     if (offset != size) SETERRQ2(PetscObjectComm((PetscObject) dm), PETSC_ERR_PLIB, "Number of permutation entries %D != %D", offset, size);
4993     /* Check permutation */
4994     {
4995       PetscInt *check;
4996 
4997       ierr = PetscMalloc1(size, &check);CHKERRQ(ierr);
4998       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]);}
4999       for (i = 0; i < size; ++i) check[perm[i]] = i;
5000       for (i = 0; i < size; ++i) {if (check[i] < 0) SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_PLIB, "Missing permutation index %D", i);}
5001       ierr = PetscFree(check);CHKERRQ(ierr);
5002     }
5003     ierr = PetscSectionSetClosurePermutation_Internal(section, (PetscObject) dm, d, size, PETSC_OWN_POINTER, perm);CHKERRQ(ierr);
5004   }
5005   PetscFunctionReturn(0);
5006 }
5007 
5008 PetscErrorCode DMPlexGetPointDualSpaceFEM(DM dm, PetscInt point, PetscInt field, PetscDualSpace *dspace)
5009 {
5010   PetscDS        prob;
5011   PetscInt       depth, Nf, h;
5012   DMLabel        label;
5013   PetscErrorCode ierr;
5014 
5015   PetscFunctionBeginHot;
5016   ierr = DMGetDS(dm, &prob);CHKERRQ(ierr);
5017   Nf      = prob->Nf;
5018   label   = dm->depthLabel;
5019   *dspace = NULL;
5020   if (field < Nf) {
5021     PetscObject disc = prob->disc[field];
5022 
5023     if (disc->classid == PETSCFE_CLASSID) {
5024       PetscDualSpace dsp;
5025 
5026       ierr = PetscFEGetDualSpace((PetscFE)disc,&dsp);CHKERRQ(ierr);
5027       ierr = DMLabelGetNumValues(label,&depth);CHKERRQ(ierr);
5028       ierr = DMLabelGetValue(label,point,&h);CHKERRQ(ierr);
5029       h    = depth - 1 - h;
5030       if (h) {
5031         ierr = PetscDualSpaceGetHeightSubspace(dsp,h,dspace);CHKERRQ(ierr);
5032       } else {
5033         *dspace = dsp;
5034       }
5035     }
5036   }
5037   PetscFunctionReturn(0);
5038 }
5039 
5040 PETSC_STATIC_INLINE PetscErrorCode DMPlexVecGetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[])
5041 {
5042   PetscScalar    *array, *vArray;
5043   const PetscInt *cone, *coneO;
5044   PetscInt        pStart, pEnd, p, numPoints, size = 0, offset = 0;
5045   PetscErrorCode  ierr;
5046 
5047   PetscFunctionBeginHot;
5048   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
5049   ierr = DMPlexGetConeSize(dm, point, &numPoints);CHKERRQ(ierr);
5050   ierr = DMPlexGetCone(dm, point, &cone);CHKERRQ(ierr);
5051   ierr = DMPlexGetConeOrientation(dm, point, &coneO);CHKERRQ(ierr);
5052   if (!values || !*values) {
5053     if ((point >= pStart) && (point < pEnd)) {
5054       PetscInt dof;
5055 
5056       ierr = PetscSectionGetDof(section, point, &dof);CHKERRQ(ierr);
5057       size += dof;
5058     }
5059     for (p = 0; p < numPoints; ++p) {
5060       const PetscInt cp = cone[p];
5061       PetscInt       dof;
5062 
5063       if ((cp < pStart) || (cp >= pEnd)) continue;
5064       ierr = PetscSectionGetDof(section, cp, &dof);CHKERRQ(ierr);
5065       size += dof;
5066     }
5067     if (!values) {
5068       if (csize) *csize = size;
5069       PetscFunctionReturn(0);
5070     }
5071     ierr = DMGetWorkArray(dm, size, MPIU_SCALAR, &array);CHKERRQ(ierr);
5072   } else {
5073     array = *values;
5074   }
5075   size = 0;
5076   ierr = VecGetArray(v, &vArray);CHKERRQ(ierr);
5077   if ((point >= pStart) && (point < pEnd)) {
5078     PetscInt     dof, off, d;
5079     PetscScalar *varr;
5080 
5081     ierr = PetscSectionGetDof(section, point, &dof);CHKERRQ(ierr);
5082     ierr = PetscSectionGetOffset(section, point, &off);CHKERRQ(ierr);
5083     varr = &vArray[off];
5084     for (d = 0; d < dof; ++d, ++offset) {
5085       array[offset] = varr[d];
5086     }
5087     size += dof;
5088   }
5089   for (p = 0; p < numPoints; ++p) {
5090     const PetscInt cp = cone[p];
5091     PetscInt       o  = coneO[p];
5092     PetscInt       dof, off, d;
5093     PetscScalar   *varr;
5094 
5095     if ((cp < pStart) || (cp >= pEnd)) continue;
5096     ierr = PetscSectionGetDof(section, cp, &dof);CHKERRQ(ierr);
5097     ierr = PetscSectionGetOffset(section, cp, &off);CHKERRQ(ierr);
5098     varr = &vArray[off];
5099     if (o >= 0) {
5100       for (d = 0; d < dof; ++d, ++offset) {
5101         array[offset] = varr[d];
5102       }
5103     } else {
5104       for (d = dof-1; d >= 0; --d, ++offset) {
5105         array[offset] = varr[d];
5106       }
5107     }
5108     size += dof;
5109   }
5110   ierr = VecRestoreArray(v, &vArray);CHKERRQ(ierr);
5111   if (!*values) {
5112     if (csize) *csize = size;
5113     *values = array;
5114   } else {
5115     if (size > *csize) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %D < actual size %D", *csize, size);
5116     *csize = size;
5117   }
5118   PetscFunctionReturn(0);
5119 }
5120 
5121 /* Compress out points not in the section */
5122 PETSC_STATIC_INLINE PetscErrorCode CompressPoints_Private(PetscSection section, PetscInt *numPoints, PetscInt points[])
5123 {
5124   const PetscInt np = *numPoints;
5125   PetscInt       pStart, pEnd, p, q;
5126   PetscErrorCode ierr;
5127 
5128   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
5129   for (p = 0, q = 0; p < np; ++p) {
5130     const PetscInt r = points[p*2];
5131     if ((r >= pStart) && (r < pEnd)) {
5132       points[q*2]   = r;
5133       points[q*2+1] = points[p*2+1];
5134       ++q;
5135     }
5136   }
5137   *numPoints = q;
5138   return 0;
5139 }
5140 
5141 static PetscErrorCode DMPlexTransitiveClosure_Hybrid_Internal(DM dm, PetscInt point, PetscInt np, PetscInt *numPoints, PetscInt **points)
5142 {
5143   const PetscInt *cone, *ornt;
5144   PetscInt       *pts,  *closure = NULL;
5145   PetscInt        dim, coneSize, c, d, clSize, cl;
5146   PetscErrorCode  ierr;
5147 
5148   PetscFunctionBeginHot;
5149   ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr);
5150   ierr = DMPlexGetConeSize(dm, point, &coneSize);CHKERRQ(ierr);
5151   ierr = DMPlexGetCone(dm, point, &cone);CHKERRQ(ierr);
5152   ierr = DMPlexGetConeOrientation(dm, point, &ornt);CHKERRQ(ierr);
5153   ierr = DMPlexGetTransitiveClosure(dm, cone[0], PETSC_TRUE, &clSize, &closure);CHKERRQ(ierr);
5154   ierr = DMGetWorkArray(dm, np*2, MPIU_INT, &pts);CHKERRQ(ierr);
5155   c    = 0;
5156   pts[c*2+0] = point;
5157   pts[c*2+1] = 0;
5158   ++c;
5159   for (cl = 0; cl < clSize*2; cl += 2, ++c) {pts[c*2+0] = closure[cl]; pts[c*2+1] = closure[cl+1];}
5160   ierr = DMPlexGetTransitiveClosure(dm, cone[1], PETSC_TRUE, &clSize, &closure);CHKERRQ(ierr);
5161   for (cl = 0; cl < clSize*2; cl += 2, ++c) {pts[c*2+0] = closure[cl]; pts[c*2+1] = closure[cl+1];}
5162   ierr = DMPlexRestoreTransitiveClosure(dm, cone[0], PETSC_TRUE, &clSize, &closure);CHKERRQ(ierr);
5163   if (dim >= 2) {
5164     for (d = 2; d < coneSize; ++d, ++c) {pts[c*2+0] = cone[d]; pts[c*2+1] = ornt[d];}
5165   }
5166   if (dim >= 3) {
5167     for (d = 2; d < coneSize; ++d) {
5168       const PetscInt  fpoint = cone[d];
5169       const PetscInt *fcone;
5170       PetscInt        fconeSize, fc, i;
5171 
5172       ierr = DMPlexGetConeSize(dm, fpoint, &fconeSize);CHKERRQ(ierr);
5173       ierr = DMPlexGetCone(dm, fpoint, &fcone);CHKERRQ(ierr);
5174       for (fc = 0; fc < fconeSize; ++fc) {
5175         for (i = 0; i < c; ++i) if (pts[i*2] == fcone[fc]) break;
5176         if (i == c) {pts[c*2+0] = fcone[fc]; pts[c*2+1] = 0; ++c;}
5177       }
5178     }
5179   }
5180   if (c != np) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid closure for hybrid point %D, size %D != %D", point, c, np);
5181   *numPoints = np;
5182   *points    = pts;
5183   PetscFunctionReturn(0);
5184 }
5185 
5186 /* Compressed closure does not apply closure permutation */
5187 PetscErrorCode DMPlexGetCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp)
5188 {
5189   const PetscInt *cla = NULL;
5190   PetscInt       np, *pts = NULL;
5191   PetscErrorCode ierr;
5192 
5193   PetscFunctionBeginHot;
5194   ierr = PetscSectionGetClosureIndex(section, (PetscObject) dm, clSec, clPoints);CHKERRQ(ierr);
5195   if (*clPoints) {
5196     PetscInt dof, off;
5197 
5198     ierr = PetscSectionGetDof(*clSec, point, &dof);CHKERRQ(ierr);
5199     ierr = PetscSectionGetOffset(*clSec, point, &off);CHKERRQ(ierr);
5200     ierr = ISGetIndices(*clPoints, &cla);CHKERRQ(ierr);
5201     np   = dof/2;
5202     pts  = (PetscInt *) &cla[off];
5203   } else {
5204     DMPolytopeType ct;
5205 
5206     /* Do not make the label if it does not exist */
5207     if (!dm->celltypeLabel) {ct = DM_POLYTOPE_POINT;}
5208     else                    {ierr = DMPlexGetCellType(dm, point, &ct);CHKERRQ(ierr);}
5209     switch (ct) {
5210       case DM_POLYTOPE_SEG_PRISM_TENSOR:
5211         ierr = DMPlexTransitiveClosure_Hybrid_Internal(dm, point, 9, &np, &pts);CHKERRQ(ierr);
5212         break;
5213       case DM_POLYTOPE_TRI_PRISM_TENSOR:
5214         ierr = DMPlexTransitiveClosure_Hybrid_Internal(dm, point, 21, &np, &pts);CHKERRQ(ierr);
5215         break;
5216       case DM_POLYTOPE_QUAD_PRISM_TENSOR:
5217         ierr = DMPlexTransitiveClosure_Hybrid_Internal(dm, point, 27, &np, &pts);CHKERRQ(ierr);
5218         break;
5219       default:
5220         ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &np, &pts);CHKERRQ(ierr);
5221     }
5222     ierr = CompressPoints_Private(section, &np, pts);CHKERRQ(ierr);
5223   }
5224   *numPoints = np;
5225   *points    = pts;
5226   *clp       = cla;
5227   PetscFunctionReturn(0);
5228 }
5229 
5230 PetscErrorCode DMPlexRestoreCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp)
5231 {
5232   PetscErrorCode ierr;
5233 
5234   PetscFunctionBeginHot;
5235   if (!*clPoints) {
5236     ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, numPoints, points);CHKERRQ(ierr);
5237   } else {
5238     ierr = ISRestoreIndices(*clPoints, clp);CHKERRQ(ierr);
5239   }
5240   *numPoints = 0;
5241   *points    = NULL;
5242   *clSec     = NULL;
5243   *clPoints  = NULL;
5244   *clp       = NULL;
5245   PetscFunctionReturn(0);
5246 }
5247 
5248 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[])
5249 {
5250   PetscInt          offset = 0, p;
5251   const PetscInt    **perms = NULL;
5252   const PetscScalar **flips = NULL;
5253   PetscErrorCode    ierr;
5254 
5255   PetscFunctionBeginHot;
5256   *size = 0;
5257   ierr = PetscSectionGetPointSyms(section,numPoints,points,&perms,&flips);CHKERRQ(ierr);
5258   for (p = 0; p < numPoints; p++) {
5259     const PetscInt    point = points[2*p];
5260     const PetscInt    *perm = perms ? perms[p] : NULL;
5261     const PetscScalar *flip = flips ? flips[p] : NULL;
5262     PetscInt          dof, off, d;
5263     const PetscScalar *varr;
5264 
5265     ierr = PetscSectionGetDof(section, point, &dof);CHKERRQ(ierr);
5266     ierr = PetscSectionGetOffset(section, point, &off);CHKERRQ(ierr);
5267     varr = &vArray[off];
5268     if (clperm) {
5269       if (perm) {
5270         for (d = 0; d < dof; d++) array[clperm[offset + perm[d]]]  = varr[d];
5271       } else {
5272         for (d = 0; d < dof; d++) array[clperm[offset +      d ]]  = varr[d];
5273       }
5274       if (flip) {
5275         for (d = 0; d < dof; d++) array[clperm[offset +      d ]] *= flip[d];
5276       }
5277     } else {
5278       if (perm) {
5279         for (d = 0; d < dof; d++) array[offset + perm[d]]  = varr[d];
5280       } else {
5281         for (d = 0; d < dof; d++) array[offset +      d ]  = varr[d];
5282       }
5283       if (flip) {
5284         for (d = 0; d < dof; d++) array[offset +      d ] *= flip[d];
5285       }
5286     }
5287     offset += dof;
5288   }
5289   ierr = PetscSectionRestorePointSyms(section,numPoints,points,&perms,&flips);CHKERRQ(ierr);
5290   *size = offset;
5291   PetscFunctionReturn(0);
5292 }
5293 
5294 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[])
5295 {
5296   PetscInt          offset = 0, f;
5297   PetscErrorCode    ierr;
5298 
5299   PetscFunctionBeginHot;
5300   *size = 0;
5301   for (f = 0; f < numFields; ++f) {
5302     PetscInt          p;
5303     const PetscInt    **perms = NULL;
5304     const PetscScalar **flips = NULL;
5305 
5306     ierr = PetscSectionGetFieldPointSyms(section,f,numPoints,points,&perms,&flips);CHKERRQ(ierr);
5307     for (p = 0; p < numPoints; p++) {
5308       const PetscInt    point = points[2*p];
5309       PetscInt          fdof, foff, b;
5310       const PetscScalar *varr;
5311       const PetscInt    *perm = perms ? perms[p] : NULL;
5312       const PetscScalar *flip = flips ? flips[p] : NULL;
5313 
5314       ierr = PetscSectionGetFieldDof(section, point, f, &fdof);CHKERRQ(ierr);
5315       ierr = PetscSectionGetFieldOffset(section, point, f, &foff);CHKERRQ(ierr);
5316       varr = &vArray[foff];
5317       if (clperm) {
5318         if (perm) {for (b = 0; b < fdof; b++) {array[clperm[offset + perm[b]]]  = varr[b];}}
5319         else      {for (b = 0; b < fdof; b++) {array[clperm[offset +      b ]]  = varr[b];}}
5320         if (flip) {for (b = 0; b < fdof; b++) {array[clperm[offset +      b ]] *= flip[b];}}
5321       } else {
5322         if (perm) {for (b = 0; b < fdof; b++) {array[offset + perm[b]]  = varr[b];}}
5323         else      {for (b = 0; b < fdof; b++) {array[offset +      b ]  = varr[b];}}
5324         if (flip) {for (b = 0; b < fdof; b++) {array[offset +      b ] *= flip[b];}}
5325       }
5326       offset += fdof;
5327     }
5328     ierr = PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms,&flips);CHKERRQ(ierr);
5329   }
5330   *size = offset;
5331   PetscFunctionReturn(0);
5332 }
5333 
5334 /*@C
5335   DMPlexVecGetClosure - Get an array of the values on the closure of 'point'
5336 
5337   Not collective
5338 
5339   Input Parameters:
5340 + dm - The DM
5341 . section - The section describing the layout in v, or NULL to use the default section
5342 . v - The local vector
5343 . point - The point in the DM
5344 . csize - The size of the input values array, or NULL
5345 - values - An array to use for the values, or NULL to have it allocated automatically
5346 
5347   Output Parameters:
5348 + csize - The number of values in the closure
5349 - values - The array of values. If the user provided NULL, it is a borrowed array and should not be freed
5350 
5351 $ Note that DMPlexVecGetClosure/DMPlexVecRestoreClosure only allocates the values array if it set to NULL in the
5352 $ calling function. This is because DMPlexVecGetClosure() is typically called in the inner loop of a Vec or Mat
5353 $ assembly function, and a user may already have allocated storage for this operation.
5354 $
5355 $ A typical use could be
5356 $
5357 $  values = NULL;
5358 $  ierr = DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values);CHKERRQ(ierr);
5359 $  for (cl = 0; cl < clSize; ++cl) {
5360 $    <Compute on closure>
5361 $  }
5362 $  ierr = DMPlexVecRestoreClosure(dm, NULL, v, p, &clSize, &values);CHKERRQ(ierr);
5363 $
5364 $ or
5365 $
5366 $  PetscMalloc1(clMaxSize, &values);
5367 $  for (p = pStart; p < pEnd; ++p) {
5368 $    clSize = clMaxSize;
5369 $    ierr = DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values);CHKERRQ(ierr);
5370 $    for (cl = 0; cl < clSize; ++cl) {
5371 $      <Compute on closure>
5372 $    }
5373 $  }
5374 $  PetscFree(values);
5375 
5376   Fortran Notes:
5377   Since it returns an array, this routine is only available in Fortran 90, and you must
5378   include petsc.h90 in your code.
5379 
5380   The csize argument is not present in the Fortran 90 binding since it is internal to the array.
5381 
5382   Level: intermediate
5383 
5384 .seealso DMPlexVecRestoreClosure(), DMPlexVecSetClosure(), DMPlexMatSetClosure()
5385 @*/
5386 PetscErrorCode DMPlexVecGetClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[])
5387 {
5388   PetscSection       clSection;
5389   IS                 clPoints;
5390   PetscInt          *points = NULL;
5391   const PetscInt    *clp, *perm;
5392   PetscInt           depth, numFields, numPoints, asize;
5393   PetscErrorCode     ierr;
5394 
5395   PetscFunctionBeginHot;
5396   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5397   if (!section) {ierr = DMGetLocalSection(dm, &section);CHKERRQ(ierr);}
5398   PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2);
5399   PetscValidHeaderSpecific(v, VEC_CLASSID, 3);
5400   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
5401   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
5402   if (depth == 1 && numFields < 2) {
5403     ierr = DMPlexVecGetClosure_Depth1_Static(dm, section, v, point, csize, values);CHKERRQ(ierr);
5404     PetscFunctionReturn(0);
5405   }
5406   /* Get points */
5407   ierr = DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);CHKERRQ(ierr);
5408   /* Get sizes */
5409   asize = 0;
5410   for (PetscInt p = 0; p < numPoints*2; p += 2) {
5411     PetscInt dof;
5412     ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
5413     asize += dof;
5414   }
5415   if (values) {
5416     const PetscScalar *vArray;
5417     PetscInt          size;
5418 
5419     if (*values) {
5420       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);
5421     } else {ierr = DMGetWorkArray(dm, asize, MPIU_SCALAR, values);CHKERRQ(ierr);}
5422     ierr = PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject) dm, depth, asize, &perm);CHKERRQ(ierr);
5423     ierr = VecGetArrayRead(v, &vArray);CHKERRQ(ierr);
5424     /* Get values */
5425     if (numFields > 0) {ierr = DMPlexVecGetClosure_Fields_Static(dm, section, numPoints, points, numFields, perm, vArray, &size, *values);CHKERRQ(ierr);}
5426     else               {ierr = DMPlexVecGetClosure_Static(dm, section, numPoints, points, perm, vArray, &size, *values);CHKERRQ(ierr);}
5427     if (PetscUnlikely(asize != size)) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Section size %D does not match Vec closure size %D", asize, size);
5428     /* Cleanup array */
5429     ierr = VecRestoreArrayRead(v, &vArray);CHKERRQ(ierr);
5430   }
5431   if (csize) *csize = asize;
5432   /* Cleanup points */
5433   ierr = DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);CHKERRQ(ierr);
5434   PetscFunctionReturn(0);
5435 }
5436 
5437 PetscErrorCode DMPlexVecGetClosureAtDepth_Internal(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt depth, PetscInt *csize, PetscScalar *values[])
5438 {
5439   DMLabel            depthLabel;
5440   PetscSection       clSection;
5441   IS                 clPoints;
5442   PetscScalar       *array;
5443   const PetscScalar *vArray;
5444   PetscInt          *points = NULL;
5445   const PetscInt    *clp, *perm = NULL;
5446   PetscInt           mdepth, numFields, numPoints, Np = 0, p, clsize, size;
5447   PetscErrorCode     ierr;
5448 
5449   PetscFunctionBeginHot;
5450   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5451   if (!section) {ierr = DMGetLocalSection(dm, &section);CHKERRQ(ierr);}
5452   PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2);
5453   PetscValidHeaderSpecific(v, VEC_CLASSID, 3);
5454   ierr = DMPlexGetDepth(dm, &mdepth);CHKERRQ(ierr);
5455   ierr = DMPlexGetDepthLabel(dm, &depthLabel);CHKERRQ(ierr);
5456   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
5457   if (mdepth == 1 && numFields < 2) {
5458     ierr = DMPlexVecGetClosure_Depth1_Static(dm, section, v, point, csize, values);CHKERRQ(ierr);
5459     PetscFunctionReturn(0);
5460   }
5461   /* Get points */
5462   ierr = DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);CHKERRQ(ierr);
5463   for (clsize=0,p=0; p<Np; p++) {
5464     PetscInt dof;
5465     ierr = PetscSectionGetDof(section, points[2*p], &dof);CHKERRQ(ierr);
5466     clsize += dof;
5467   }
5468   ierr = PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject) dm, depth, clsize, &perm);CHKERRQ(ierr);
5469   /* Filter points */
5470   for (p = 0; p < numPoints*2; p += 2) {
5471     PetscInt dep;
5472 
5473     ierr = DMLabelGetValue(depthLabel, points[p], &dep);CHKERRQ(ierr);
5474     if (dep != depth) continue;
5475     points[Np*2+0] = points[p];
5476     points[Np*2+1] = points[p+1];
5477     ++Np;
5478   }
5479   /* Get array */
5480   if (!values || !*values) {
5481     PetscInt asize = 0, dof;
5482 
5483     for (p = 0; p < Np*2; p += 2) {
5484       ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
5485       asize += dof;
5486     }
5487     if (!values) {
5488       ierr = DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);CHKERRQ(ierr);
5489       if (csize) *csize = asize;
5490       PetscFunctionReturn(0);
5491     }
5492     ierr = DMGetWorkArray(dm, asize, MPIU_SCALAR, &array);CHKERRQ(ierr);
5493   } else {
5494     array = *values;
5495   }
5496   ierr = VecGetArrayRead(v, &vArray);CHKERRQ(ierr);
5497   /* Get values */
5498   if (numFields > 0) {ierr = DMPlexVecGetClosure_Fields_Static(dm, section, Np, points, numFields, perm, vArray, &size, array);CHKERRQ(ierr);}
5499   else               {ierr = DMPlexVecGetClosure_Static(dm, section, Np, points, perm, vArray, &size, array);CHKERRQ(ierr);}
5500   /* Cleanup points */
5501   ierr = DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);CHKERRQ(ierr);
5502   /* Cleanup array */
5503   ierr = VecRestoreArrayRead(v, &vArray);CHKERRQ(ierr);
5504   if (!*values) {
5505     if (csize) *csize = size;
5506     *values = array;
5507   } else {
5508     if (size > *csize) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %D < actual size %D", *csize, size);
5509     *csize = size;
5510   }
5511   PetscFunctionReturn(0);
5512 }
5513 
5514 /*@C
5515   DMPlexVecRestoreClosure - Restore the array of the values on the closure of 'point'
5516 
5517   Not collective
5518 
5519   Input Parameters:
5520 + dm - The DM
5521 . section - The section describing the layout in v, or NULL to use the default section
5522 . v - The local vector
5523 . point - The point in the DM
5524 . csize - The number of values in the closure, or NULL
5525 - values - The array of values, which is a borrowed array and should not be freed
5526 
5527   Note that the array values are discarded and not copied back into v. In order to copy values back to v, use DMPlexVecSetClosure()
5528 
5529   Fortran Notes:
5530   Since it returns an array, this routine is only available in Fortran 90, and you must
5531   include petsc.h90 in your code.
5532 
5533   The csize argument is not present in the Fortran 90 binding since it is internal to the array.
5534 
5535   Level: intermediate
5536 
5537 .seealso DMPlexVecGetClosure(), DMPlexVecSetClosure(), DMPlexMatSetClosure()
5538 @*/
5539 PetscErrorCode DMPlexVecRestoreClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[])
5540 {
5541   PetscInt       size = 0;
5542   PetscErrorCode ierr;
5543 
5544   PetscFunctionBegin;
5545   /* Should work without recalculating size */
5546   ierr = DMRestoreWorkArray(dm, size, MPIU_SCALAR, (void*) values);CHKERRQ(ierr);
5547   *values = NULL;
5548   PetscFunctionReturn(0);
5549 }
5550 
5551 PETSC_STATIC_INLINE void add   (PetscScalar *x, PetscScalar y) {*x += y;}
5552 PETSC_STATIC_INLINE void insert(PetscScalar *x, PetscScalar y) {*x  = y;}
5553 
5554 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[])
5555 {
5556   PetscInt        cdof;   /* The number of constraints on this point */
5557   const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
5558   PetscScalar    *a;
5559   PetscInt        off, cind = 0, k;
5560   PetscErrorCode  ierr;
5561 
5562   PetscFunctionBegin;
5563   ierr = PetscSectionGetConstraintDof(section, point, &cdof);CHKERRQ(ierr);
5564   ierr = PetscSectionGetOffset(section, point, &off);CHKERRQ(ierr);
5565   a    = &array[off];
5566   if (!cdof || setBC) {
5567     if (clperm) {
5568       if (perm) {for (k = 0; k < dof; ++k) {fuse(&a[k], values[clperm[offset+perm[k]]] * (flip ? flip[perm[k]] : 1.));}}
5569       else      {for (k = 0; k < dof; ++k) {fuse(&a[k], values[clperm[offset+     k ]] * (flip ? flip[     k ] : 1.));}}
5570     } else {
5571       if (perm) {for (k = 0; k < dof; ++k) {fuse(&a[k], values[offset+perm[k]] * (flip ? flip[perm[k]] : 1.));}}
5572       else      {for (k = 0; k < dof; ++k) {fuse(&a[k], values[offset+     k ] * (flip ? flip[     k ] : 1.));}}
5573     }
5574   } else {
5575     ierr = PetscSectionGetConstraintIndices(section, point, &cdofs);CHKERRQ(ierr);
5576     if (clperm) {
5577       if (perm) {for (k = 0; k < dof; ++k) {
5578           if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
5579           fuse(&a[k], values[clperm[offset+perm[k]]] * (flip ? flip[perm[k]] : 1.));
5580         }
5581       } else {
5582         for (k = 0; k < dof; ++k) {
5583           if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
5584           fuse(&a[k], values[clperm[offset+     k ]] * (flip ? flip[     k ] : 1.));
5585         }
5586       }
5587     } else {
5588       if (perm) {
5589         for (k = 0; k < dof; ++k) {
5590           if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
5591           fuse(&a[k], values[offset+perm[k]] * (flip ? flip[perm[k]] : 1.));
5592         }
5593       } else {
5594         for (k = 0; k < dof; ++k) {
5595           if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
5596           fuse(&a[k], values[offset+     k ] * (flip ? flip[     k ] : 1.));
5597         }
5598       }
5599     }
5600   }
5601   PetscFunctionReturn(0);
5602 }
5603 
5604 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[])
5605 {
5606   PetscInt        cdof;   /* The number of constraints on this point */
5607   const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
5608   PetscScalar    *a;
5609   PetscInt        off, cind = 0, k;
5610   PetscErrorCode  ierr;
5611 
5612   PetscFunctionBegin;
5613   ierr = PetscSectionGetConstraintDof(section, point, &cdof);CHKERRQ(ierr);
5614   ierr = PetscSectionGetOffset(section, point, &off);CHKERRQ(ierr);
5615   a    = &array[off];
5616   if (cdof) {
5617     ierr = PetscSectionGetConstraintIndices(section, point, &cdofs);CHKERRQ(ierr);
5618     if (clperm) {
5619       if (perm) {
5620         for (k = 0; k < dof; ++k) {
5621           if ((cind < cdof) && (k == cdofs[cind])) {
5622             fuse(&a[k], values[clperm[offset+perm[k]]] * (flip ? flip[perm[k]] : 1.));
5623             cind++;
5624           }
5625         }
5626       } else {
5627         for (k = 0; k < dof; ++k) {
5628           if ((cind < cdof) && (k == cdofs[cind])) {
5629             fuse(&a[k], values[clperm[offset+     k ]] * (flip ? flip[     k ] : 1.));
5630             cind++;
5631           }
5632         }
5633       }
5634     } else {
5635       if (perm) {
5636         for (k = 0; k < dof; ++k) {
5637           if ((cind < cdof) && (k == cdofs[cind])) {
5638             fuse(&a[k], values[offset+perm[k]] * (flip ? flip[perm[k]] : 1.));
5639             cind++;
5640           }
5641         }
5642       } else {
5643         for (k = 0; k < dof; ++k) {
5644           if ((cind < cdof) && (k == cdofs[cind])) {
5645             fuse(&a[k], values[offset+     k ] * (flip ? flip[     k ] : 1.));
5646             cind++;
5647           }
5648         }
5649       }
5650     }
5651   }
5652   PetscFunctionReturn(0);
5653 }
5654 
5655 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[])
5656 {
5657   PetscScalar    *a;
5658   PetscInt        fdof, foff, fcdof, foffset = *offset;
5659   const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
5660   PetscInt        cind = 0, b;
5661   PetscErrorCode  ierr;
5662 
5663   PetscFunctionBegin;
5664   ierr = PetscSectionGetFieldDof(section, point, f, &fdof);CHKERRQ(ierr);
5665   ierr = PetscSectionGetFieldConstraintDof(section, point, f, &fcdof);CHKERRQ(ierr);
5666   ierr = PetscSectionGetFieldOffset(section, point, f, &foff);CHKERRQ(ierr);
5667   a    = &array[foff];
5668   if (!fcdof || setBC) {
5669     if (clperm) {
5670       if (perm) {for (b = 0; b < fdof; b++) {fuse(&a[b], values[clperm[foffset+perm[b]]] * (flip ? flip[perm[b]] : 1.));}}
5671       else      {for (b = 0; b < fdof; b++) {fuse(&a[b], values[clperm[foffset+     b ]] * (flip ? flip[     b ] : 1.));}}
5672     } else {
5673       if (perm) {for (b = 0; b < fdof; b++) {fuse(&a[b], values[foffset+perm[b]] * (flip ? flip[perm[b]] : 1.));}}
5674       else      {for (b = 0; b < fdof; b++) {fuse(&a[b], values[foffset+     b ] * (flip ? flip[     b ] : 1.));}}
5675     }
5676   } else {
5677     ierr = PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);CHKERRQ(ierr);
5678     if (clperm) {
5679       if (perm) {
5680         for (b = 0; b < fdof; b++) {
5681           if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; continue;}
5682           fuse(&a[b], values[clperm[foffset+perm[b]]] * (flip ? flip[perm[b]] : 1.));
5683         }
5684       } else {
5685         for (b = 0; b < fdof; b++) {
5686           if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; continue;}
5687           fuse(&a[b], values[clperm[foffset+     b ]] * (flip ? flip[     b ] : 1.));
5688         }
5689       }
5690     } else {
5691       if (perm) {
5692         for (b = 0; b < fdof; b++) {
5693           if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; continue;}
5694           fuse(&a[b], values[foffset+perm[b]] * (flip ? flip[perm[b]] : 1.));
5695         }
5696       } else {
5697         for (b = 0; b < fdof; b++) {
5698           if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; continue;}
5699           fuse(&a[b], values[foffset+     b ] * (flip ? flip[     b ] : 1.));
5700         }
5701       }
5702     }
5703   }
5704   *offset += fdof;
5705   PetscFunctionReturn(0);
5706 }
5707 
5708 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[])
5709 {
5710   PetscScalar    *a;
5711   PetscInt        fdof, foff, fcdof, foffset = *offset;
5712   const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
5713   PetscInt        Nc, cind = 0, ncind = 0, b;
5714   PetscBool       ncSet, fcSet;
5715   PetscErrorCode  ierr;
5716 
5717   PetscFunctionBegin;
5718   ierr = PetscSectionGetFieldComponents(section, f, &Nc);CHKERRQ(ierr);
5719   ierr = PetscSectionGetFieldDof(section, point, f, &fdof);CHKERRQ(ierr);
5720   ierr = PetscSectionGetFieldConstraintDof(section, point, f, &fcdof);CHKERRQ(ierr);
5721   ierr = PetscSectionGetFieldOffset(section, point, f, &foff);CHKERRQ(ierr);
5722   a    = &array[foff];
5723   if (fcdof) {
5724     /* We just override fcdof and fcdofs with Ncc and comps */
5725     ierr = PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);CHKERRQ(ierr);
5726     if (clperm) {
5727       if (perm) {
5728         if (comps) {
5729           for (b = 0; b < fdof; b++) {
5730             ncSet = fcSet = PETSC_FALSE;
5731             if (b%Nc == comps[ncind]) {ncind = (ncind+1)%Ncc; ncSet = PETSC_TRUE;}
5732             if ((cind < fcdof) && (b == fcdofs[cind])) {++cind;  fcSet = PETSC_TRUE;}
5733             if (ncSet && fcSet) {fuse(&a[b], values[clperm[foffset+perm[b]]] * (flip ? flip[perm[b]] : 1.));}
5734           }
5735         } else {
5736           for (b = 0; b < fdof; b++) {
5737             if ((cind < fcdof) && (b == fcdofs[cind])) {
5738               fuse(&a[b], values[clperm[foffset+perm[b]]] * (flip ? flip[perm[b]] : 1.));
5739               ++cind;
5740             }
5741           }
5742         }
5743       } else {
5744         if (comps) {
5745           for (b = 0; b < fdof; b++) {
5746             ncSet = fcSet = PETSC_FALSE;
5747             if (b%Nc == comps[ncind]) {ncind = (ncind+1)%Ncc; ncSet = PETSC_TRUE;}
5748             if ((cind < fcdof) && (b == fcdofs[cind])) {++cind;  fcSet = PETSC_TRUE;}
5749             if (ncSet && fcSet) {fuse(&a[b], values[clperm[foffset+     b ]] * (flip ? flip[     b ] : 1.));}
5750           }
5751         } else {
5752           for (b = 0; b < fdof; b++) {
5753             if ((cind < fcdof) && (b == fcdofs[cind])) {
5754               fuse(&a[b], values[clperm[foffset+     b ]] * (flip ? flip[     b ] : 1.));
5755               ++cind;
5756             }
5757           }
5758         }
5759       }
5760     } else {
5761       if (perm) {
5762         if (comps) {
5763           for (b = 0; b < fdof; b++) {
5764             ncSet = fcSet = PETSC_FALSE;
5765             if (b%Nc == comps[ncind]) {ncind = (ncind+1)%Ncc; ncSet = PETSC_TRUE;}
5766             if ((cind < fcdof) && (b == fcdofs[cind])) {++cind;  fcSet = PETSC_TRUE;}
5767             if (ncSet && fcSet) {fuse(&a[b], values[foffset+perm[b]] * (flip ? flip[perm[b]] : 1.));}
5768           }
5769         } else {
5770           for (b = 0; b < fdof; b++) {
5771             if ((cind < fcdof) && (b == fcdofs[cind])) {
5772               fuse(&a[b], values[foffset+perm[b]] * (flip ? flip[perm[b]] : 1.));
5773               ++cind;
5774             }
5775           }
5776         }
5777       } else {
5778         if (comps) {
5779           for (b = 0; b < fdof; b++) {
5780             ncSet = fcSet = PETSC_FALSE;
5781             if (b%Nc == comps[ncind]) {ncind = (ncind+1)%Ncc; ncSet = PETSC_TRUE;}
5782             if ((cind < fcdof) && (b == fcdofs[cind])) {++cind;  fcSet = PETSC_TRUE;}
5783             if (ncSet && fcSet) {fuse(&a[b], values[foffset+     b ] * (flip ? flip[     b ] : 1.));}
5784           }
5785         } else {
5786           for (b = 0; b < fdof; b++) {
5787             if ((cind < fcdof) && (b == fcdofs[cind])) {
5788               fuse(&a[b], values[foffset+     b ] * (flip ? flip[     b ] : 1.));
5789               ++cind;
5790             }
5791           }
5792         }
5793       }
5794     }
5795   }
5796   *offset += fdof;
5797   PetscFunctionReturn(0);
5798 }
5799 
5800 PETSC_STATIC_INLINE PetscErrorCode DMPlexVecSetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode)
5801 {
5802   PetscScalar    *array;
5803   const PetscInt *cone, *coneO;
5804   PetscInt        pStart, pEnd, p, numPoints, off, dof;
5805   PetscErrorCode  ierr;
5806 
5807   PetscFunctionBeginHot;
5808   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
5809   ierr = DMPlexGetConeSize(dm, point, &numPoints);CHKERRQ(ierr);
5810   ierr = DMPlexGetCone(dm, point, &cone);CHKERRQ(ierr);
5811   ierr = DMPlexGetConeOrientation(dm, point, &coneO);CHKERRQ(ierr);
5812   ierr = VecGetArray(v, &array);CHKERRQ(ierr);
5813   for (p = 0, off = 0; p <= numPoints; ++p, off += dof) {
5814     const PetscInt cp = !p ? point : cone[p-1];
5815     const PetscInt o  = !p ? 0     : coneO[p-1];
5816 
5817     if ((cp < pStart) || (cp >= pEnd)) {dof = 0; continue;}
5818     ierr = PetscSectionGetDof(section, cp, &dof);CHKERRQ(ierr);
5819     /* ADD_VALUES */
5820     {
5821       const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
5822       PetscScalar    *a;
5823       PetscInt        cdof, coff, cind = 0, k;
5824 
5825       ierr = PetscSectionGetConstraintDof(section, cp, &cdof);CHKERRQ(ierr);
5826       ierr = PetscSectionGetOffset(section, cp, &coff);CHKERRQ(ierr);
5827       a    = &array[coff];
5828       if (!cdof) {
5829         if (o >= 0) {
5830           for (k = 0; k < dof; ++k) {
5831             a[k] += values[off+k];
5832           }
5833         } else {
5834           for (k = 0; k < dof; ++k) {
5835             a[k] += values[off+dof-k-1];
5836           }
5837         }
5838       } else {
5839         ierr = PetscSectionGetConstraintIndices(section, cp, &cdofs);CHKERRQ(ierr);
5840         if (o >= 0) {
5841           for (k = 0; k < dof; ++k) {
5842             if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
5843             a[k] += values[off+k];
5844           }
5845         } else {
5846           for (k = 0; k < dof; ++k) {
5847             if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
5848             a[k] += values[off+dof-k-1];
5849           }
5850         }
5851       }
5852     }
5853   }
5854   ierr = VecRestoreArray(v, &array);CHKERRQ(ierr);
5855   PetscFunctionReturn(0);
5856 }
5857 
5858 /*@C
5859   DMPlexVecSetClosure - Set an array of the values on the closure of 'point'
5860 
5861   Not collective
5862 
5863   Input Parameters:
5864 + dm - The DM
5865 . section - The section describing the layout in v, or NULL to use the default section
5866 . v - The local vector
5867 . point - The point in the DM
5868 . values - The array of values
5869 - mode - The insert mode. One of INSERT_ALL_VALUES, ADD_ALL_VALUES, INSERT_VALUES, ADD_VALUES, INSERT_BC_VALUES, and ADD_BC_VALUES,
5870          where INSERT_ALL_VALUES and ADD_ALL_VALUES also overwrite boundary conditions.
5871 
5872   Fortran Notes:
5873   This routine is only available in Fortran 90, and you must include petsc.h90 in your code.
5874 
5875   Level: intermediate
5876 
5877 .seealso DMPlexVecGetClosure(), DMPlexMatSetClosure()
5878 @*/
5879 PetscErrorCode DMPlexVecSetClosure(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode)
5880 {
5881   PetscSection    clSection;
5882   IS              clPoints;
5883   PetscScalar    *array;
5884   PetscInt       *points = NULL;
5885   const PetscInt *clp, *clperm = NULL;
5886   PetscInt        depth, numFields, numPoints, p, clsize;
5887   PetscErrorCode  ierr;
5888 
5889   PetscFunctionBeginHot;
5890   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5891   if (!section) {ierr = DMGetLocalSection(dm, &section);CHKERRQ(ierr);}
5892   PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2);
5893   PetscValidHeaderSpecific(v, VEC_CLASSID, 3);
5894   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
5895   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
5896   if (depth == 1 && numFields < 2 && mode == ADD_VALUES) {
5897     ierr = DMPlexVecSetClosure_Depth1_Static(dm, section, v, point, values, mode);CHKERRQ(ierr);
5898     PetscFunctionReturn(0);
5899   }
5900   /* Get points */
5901   ierr = DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);CHKERRQ(ierr);
5902   for (clsize=0,p=0; p<numPoints; p++) {
5903     PetscInt dof;
5904     ierr = PetscSectionGetDof(section, points[2*p], &dof);CHKERRQ(ierr);
5905     clsize += dof;
5906   }
5907   ierr = PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject) dm, depth, clsize, &clperm);CHKERRQ(ierr);
5908   /* Get array */
5909   ierr = VecGetArray(v, &array);CHKERRQ(ierr);
5910   /* Get values */
5911   if (numFields > 0) {
5912     PetscInt offset = 0, f;
5913     for (f = 0; f < numFields; ++f) {
5914       const PetscInt    **perms = NULL;
5915       const PetscScalar **flips = NULL;
5916 
5917       ierr = PetscSectionGetFieldPointSyms(section,f,numPoints,points,&perms,&flips);CHKERRQ(ierr);
5918       switch (mode) {
5919       case INSERT_VALUES:
5920         for (p = 0; p < numPoints; p++) {
5921           const PetscInt    point = points[2*p];
5922           const PetscInt    *perm = perms ? perms[p] : NULL;
5923           const PetscScalar *flip = flips ? flips[p] : NULL;
5924           updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, clperm, values, &offset, array);
5925         } break;
5926       case INSERT_ALL_VALUES:
5927         for (p = 0; p < numPoints; p++) {
5928           const PetscInt    point = points[2*p];
5929           const PetscInt    *perm = perms ? perms[p] : NULL;
5930           const PetscScalar *flip = flips ? flips[p] : NULL;
5931           updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, clperm, values, &offset, array);
5932         } break;
5933       case INSERT_BC_VALUES:
5934         for (p = 0; p < numPoints; p++) {
5935           const PetscInt    point = points[2*p];
5936           const PetscInt    *perm = perms ? perms[p] : NULL;
5937           const PetscScalar *flip = flips ? flips[p] : NULL;
5938           updatePointFieldsBC_private(section, point, perm, flip, f, -1, NULL, insert, clperm, values, &offset, array);
5939         } break;
5940       case ADD_VALUES:
5941         for (p = 0; p < numPoints; p++) {
5942           const PetscInt    point = points[2*p];
5943           const PetscInt    *perm = perms ? perms[p] : NULL;
5944           const PetscScalar *flip = flips ? flips[p] : NULL;
5945           updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, clperm, values, &offset, array);
5946         } break;
5947       case ADD_ALL_VALUES:
5948         for (p = 0; p < numPoints; p++) {
5949           const PetscInt    point = points[2*p];
5950           const PetscInt    *perm = perms ? perms[p] : NULL;
5951           const PetscScalar *flip = flips ? flips[p] : NULL;
5952           updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, clperm, values, &offset, array);
5953         } break;
5954       case ADD_BC_VALUES:
5955         for (p = 0; p < numPoints; p++) {
5956           const PetscInt    point = points[2*p];
5957           const PetscInt    *perm = perms ? perms[p] : NULL;
5958           const PetscScalar *flip = flips ? flips[p] : NULL;
5959           updatePointFieldsBC_private(section, point, perm, flip, f, -1, NULL, add, clperm, values, &offset, array);
5960         } break;
5961       default:
5962         SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode);
5963       }
5964       ierr = PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms,&flips);CHKERRQ(ierr);
5965     }
5966   } else {
5967     PetscInt dof, off;
5968     const PetscInt    **perms = NULL;
5969     const PetscScalar **flips = NULL;
5970 
5971     ierr = PetscSectionGetPointSyms(section,numPoints,points,&perms,&flips);CHKERRQ(ierr);
5972     switch (mode) {
5973     case INSERT_VALUES:
5974       for (p = 0, off = 0; p < numPoints; p++, off += dof) {
5975         const PetscInt    point = points[2*p];
5976         const PetscInt    *perm = perms ? perms[p] : NULL;
5977         const PetscScalar *flip = flips ? flips[p] : NULL;
5978         ierr = PetscSectionGetDof(section, point, &dof);CHKERRQ(ierr);
5979         updatePoint_private(section, point, dof, insert, PETSC_FALSE, perm, flip, clperm, values, off, array);
5980       } break;
5981     case INSERT_ALL_VALUES:
5982       for (p = 0, off = 0; p < numPoints; p++, off += dof) {
5983         const PetscInt    point = points[2*p];
5984         const PetscInt    *perm = perms ? perms[p] : NULL;
5985         const PetscScalar *flip = flips ? flips[p] : NULL;
5986         ierr = PetscSectionGetDof(section, point, &dof);CHKERRQ(ierr);
5987         updatePoint_private(section, point, dof, insert, PETSC_TRUE,  perm, flip, clperm, values, off, array);
5988       } break;
5989     case INSERT_BC_VALUES:
5990       for (p = 0, off = 0; p < numPoints; p++, off += dof) {
5991         const PetscInt    point = points[2*p];
5992         const PetscInt    *perm = perms ? perms[p] : NULL;
5993         const PetscScalar *flip = flips ? flips[p] : NULL;
5994         ierr = PetscSectionGetDof(section, point, &dof);CHKERRQ(ierr);
5995         updatePointBC_private(section, point, dof, insert,  perm, flip, clperm, values, off, array);
5996       } break;
5997     case ADD_VALUES:
5998       for (p = 0, off = 0; p < numPoints; p++, off += dof) {
5999         const PetscInt    point = points[2*p];
6000         const PetscInt    *perm = perms ? perms[p] : NULL;
6001         const PetscScalar *flip = flips ? flips[p] : NULL;
6002         ierr = PetscSectionGetDof(section, point, &dof);CHKERRQ(ierr);
6003         updatePoint_private(section, point, dof, add,    PETSC_FALSE, perm, flip, clperm, values, off, array);
6004       } break;
6005     case ADD_ALL_VALUES:
6006       for (p = 0, off = 0; p < numPoints; p++, off += dof) {
6007         const PetscInt    point = points[2*p];
6008         const PetscInt    *perm = perms ? perms[p] : NULL;
6009         const PetscScalar *flip = flips ? flips[p] : NULL;
6010         ierr = PetscSectionGetDof(section, point, &dof);CHKERRQ(ierr);
6011         updatePoint_private(section, point, dof, add,    PETSC_TRUE,  perm, flip, clperm, values, off, array);
6012       } break;
6013     case ADD_BC_VALUES:
6014       for (p = 0, off = 0; p < numPoints; p++, off += dof) {
6015         const PetscInt    point = points[2*p];
6016         const PetscInt    *perm = perms ? perms[p] : NULL;
6017         const PetscScalar *flip = flips ? flips[p] : NULL;
6018         ierr = PetscSectionGetDof(section, point, &dof);CHKERRQ(ierr);
6019         updatePointBC_private(section, point, dof, add,  perm, flip, clperm, values, off, array);
6020       } break;
6021     default:
6022       SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode);
6023     }
6024     ierr = PetscSectionRestorePointSyms(section,numPoints,points,&perms,&flips);CHKERRQ(ierr);
6025   }
6026   /* Cleanup points */
6027   ierr = DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);CHKERRQ(ierr);
6028   /* Cleanup array */
6029   ierr = VecRestoreArray(v, &array);CHKERRQ(ierr);
6030   PetscFunctionReturn(0);
6031 }
6032 
6033 /* Check whether the given point is in the label. If not, update the offset to skip this point */
6034 PETSC_STATIC_INLINE PetscErrorCode CheckPoint_Private(DMLabel label, PetscInt labelId, PetscSection section, PetscInt point, PetscInt f, PetscInt *offset)
6035 {
6036   PetscFunctionBegin;
6037   if (label) {
6038     PetscInt       val, fdof;
6039     PetscErrorCode ierr;
6040 
6041     /* There is a problem with this:
6042          Suppose we have two label values, defining surfaces, interecting along a line in 3D. When we add cells to the label, the cells that
6043        touch both surfaces must pick a label value. Thus we miss setting values for the surface with that other value intersecting that cell.
6044        Thus I am only going to check val != -1, not val != labelId
6045     */
6046     ierr = DMLabelGetValue(label, point, &val);CHKERRQ(ierr);
6047     if (val < 0) {
6048       ierr = PetscSectionGetFieldDof(section, point, f, &fdof);CHKERRQ(ierr);
6049       *offset += fdof;
6050       PetscFunctionReturn(1);
6051     }
6052   }
6053   PetscFunctionReturn(0);
6054 }
6055 
6056 /* Unlike DMPlexVecSetClosure(), this uses plex-native closure permutation, not a user-specified permutation such as DMPlexSetClosurePermutationTensor(). */
6057 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)
6058 {
6059   PetscSection      clSection;
6060   IS                clPoints;
6061   PetscScalar       *array;
6062   PetscInt          *points = NULL;
6063   const PetscInt    *clp;
6064   PetscInt          numFields, numPoints, p;
6065   PetscInt          offset = 0, f;
6066   PetscErrorCode    ierr;
6067 
6068   PetscFunctionBeginHot;
6069   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6070   if (!section) {ierr = DMGetLocalSection(dm, &section);CHKERRQ(ierr);}
6071   PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2);
6072   PetscValidHeaderSpecific(v, VEC_CLASSID, 3);
6073   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
6074   /* Get points */
6075   ierr = DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);CHKERRQ(ierr);
6076   /* Get array */
6077   ierr = VecGetArray(v, &array);CHKERRQ(ierr);
6078   /* Get values */
6079   for (f = 0; f < numFields; ++f) {
6080     const PetscInt    **perms = NULL;
6081     const PetscScalar **flips = NULL;
6082 
6083     if (!fieldActive[f]) {
6084       for (p = 0; p < numPoints*2; p += 2) {
6085         PetscInt fdof;
6086         ierr = PetscSectionGetFieldDof(section, points[p], f, &fdof);CHKERRQ(ierr);
6087         offset += fdof;
6088       }
6089       continue;
6090     }
6091     ierr = PetscSectionGetFieldPointSyms(section,f,numPoints,points,&perms,&flips);CHKERRQ(ierr);
6092     switch (mode) {
6093     case INSERT_VALUES:
6094       for (p = 0; p < numPoints; p++) {
6095         const PetscInt    point = points[2*p];
6096         const PetscInt    *perm = perms ? perms[p] : NULL;
6097         const PetscScalar *flip = flips ? flips[p] : NULL;
6098         ierr = CheckPoint_Private(label, labelId, section, point, f, &offset); if (ierr) continue;
6099         updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, NULL, values, &offset, array);
6100       } break;
6101     case INSERT_ALL_VALUES:
6102       for (p = 0; p < numPoints; p++) {
6103         const PetscInt    point = points[2*p];
6104         const PetscInt    *perm = perms ? perms[p] : NULL;
6105         const PetscScalar *flip = flips ? flips[p] : NULL;
6106         ierr = CheckPoint_Private(label, labelId, section, point, f, &offset); if (ierr) continue;
6107         updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, NULL, values, &offset, array);
6108       } break;
6109     case INSERT_BC_VALUES:
6110       for (p = 0; p < numPoints; p++) {
6111         const PetscInt    point = points[2*p];
6112         const PetscInt    *perm = perms ? perms[p] : NULL;
6113         const PetscScalar *flip = flips ? flips[p] : NULL;
6114         ierr = CheckPoint_Private(label, labelId, section, point, f, &offset); if (ierr) continue;
6115         updatePointFieldsBC_private(section, point, perm, flip, f, Ncc, comps, insert, NULL, values, &offset, array);
6116       } break;
6117     case ADD_VALUES:
6118       for (p = 0; p < numPoints; p++) {
6119         const PetscInt    point = points[2*p];
6120         const PetscInt    *perm = perms ? perms[p] : NULL;
6121         const PetscScalar *flip = flips ? flips[p] : NULL;
6122         ierr = CheckPoint_Private(label, labelId, section, point, f, &offset); if (ierr) continue;
6123         updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, NULL, values, &offset, array);
6124       } break;
6125     case ADD_ALL_VALUES:
6126       for (p = 0; p < numPoints; p++) {
6127         const PetscInt    point = points[2*p];
6128         const PetscInt    *perm = perms ? perms[p] : NULL;
6129         const PetscScalar *flip = flips ? flips[p] : NULL;
6130         ierr = CheckPoint_Private(label, labelId, section, point, f, &offset); if (ierr) continue;
6131         updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, NULL, values, &offset, array);
6132       } break;
6133     default:
6134       SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode);
6135     }
6136     ierr = PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms,&flips);CHKERRQ(ierr);
6137   }
6138   /* Cleanup points */
6139   ierr = DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);CHKERRQ(ierr);
6140   /* Cleanup array */
6141   ierr = VecRestoreArray(v, &array);CHKERRQ(ierr);
6142   PetscFunctionReturn(0);
6143 }
6144 
6145 static PetscErrorCode DMPlexPrintMatSetValues(PetscViewer viewer, Mat A, PetscInt point, PetscInt numRIndices, const PetscInt rindices[], PetscInt numCIndices, const PetscInt cindices[], const PetscScalar values[])
6146 {
6147   PetscMPIInt    rank;
6148   PetscInt       i, j;
6149   PetscErrorCode ierr;
6150 
6151   PetscFunctionBegin;
6152   ierr = MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank);CHKERRMPI(ierr);
6153   ierr = PetscViewerASCIIPrintf(viewer, "[%d]mat for point %D\n", rank, point);CHKERRQ(ierr);
6154   for (i = 0; i < numRIndices; i++) {ierr = PetscViewerASCIIPrintf(viewer, "[%d]mat row indices[%D] = %D\n", rank, i, rindices[i]);CHKERRQ(ierr);}
6155   for (i = 0; i < numCIndices; i++) {ierr = PetscViewerASCIIPrintf(viewer, "[%d]mat col indices[%D] = %D\n", rank, i, cindices[i]);CHKERRQ(ierr);}
6156   numCIndices = numCIndices ? numCIndices : numRIndices;
6157   if (!values) PetscFunctionReturn(0);
6158   for (i = 0; i < numRIndices; i++) {
6159     ierr = PetscViewerASCIIPrintf(viewer, "[%d]", rank);CHKERRQ(ierr);
6160     for (j = 0; j < numCIndices; j++) {
6161 #if defined(PETSC_USE_COMPLEX)
6162       ierr = PetscViewerASCIIPrintf(viewer, " (%g,%g)", (double)PetscRealPart(values[i*numCIndices+j]), (double)PetscImaginaryPart(values[i*numCIndices+j]));CHKERRQ(ierr);
6163 #else
6164       ierr = PetscViewerASCIIPrintf(viewer, " %g", (double)values[i*numCIndices+j]);CHKERRQ(ierr);
6165 #endif
6166     }
6167     ierr = PetscViewerASCIIPrintf(viewer, "\n");CHKERRQ(ierr);
6168   }
6169   PetscFunctionReturn(0);
6170 }
6171 
6172 /*
6173   DMPlexGetIndicesPoint_Internal - Add the indices for dofs on a point to an index array
6174 
6175   Input Parameters:
6176 + section - The section for this data layout
6177 . islocal - Is the section (and thus indices being requested) local or global?
6178 . point   - The point contributing dofs with these indices
6179 . off     - The global offset of this point
6180 . loff    - The local offset of each field
6181 . setBC   - The flag determining whether to include indices of bounsary values
6182 . perm    - A permutation of the dofs on this point, or NULL
6183 - indperm - A permutation of the entire indices array, or NULL
6184 
6185   Output Parameter:
6186 . indices - Indices for dofs on this point
6187 
6188   Level: developer
6189 
6190   Note: The indices could be local or global, depending on the value of 'off'.
6191 */
6192 PetscErrorCode DMPlexGetIndicesPoint_Internal(PetscSection section, PetscBool islocal,PetscInt point, PetscInt off, PetscInt *loff, PetscBool setBC, const PetscInt perm[], const PetscInt indperm[], PetscInt indices[])
6193 {
6194   PetscInt        dof;   /* The number of unknowns on this point */
6195   PetscInt        cdof;  /* The number of constraints on this point */
6196   const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
6197   PetscInt        cind = 0, k;
6198   PetscErrorCode  ierr;
6199 
6200   PetscFunctionBegin;
6201   if (!islocal && setBC) SETERRQ(PetscObjectComm((PetscObject)section),PETSC_ERR_ARG_INCOMP,"setBC incompatible with global indices; use a local section or disable setBC");
6202   ierr = PetscSectionGetDof(section, point, &dof);CHKERRQ(ierr);
6203   ierr = PetscSectionGetConstraintDof(section, point, &cdof);CHKERRQ(ierr);
6204   if (!cdof || setBC) {
6205     for (k = 0; k < dof; ++k) {
6206       const PetscInt preind = perm ? *loff+perm[k] : *loff+k;
6207       const PetscInt ind    = indperm ? indperm[preind] : preind;
6208 
6209       indices[ind] = off + k;
6210     }
6211   } else {
6212     ierr = PetscSectionGetConstraintIndices(section, point, &cdofs);CHKERRQ(ierr);
6213     for (k = 0; k < dof; ++k) {
6214       const PetscInt preind = perm ? *loff+perm[k] : *loff+k;
6215       const PetscInt ind    = indperm ? indperm[preind] : preind;
6216 
6217       if ((cind < cdof) && (k == cdofs[cind])) {
6218         /* Insert check for returning constrained indices */
6219         indices[ind] = -(off+k+1);
6220         ++cind;
6221       } else {
6222         indices[ind] = off + k - (islocal ? 0 : cind);
6223       }
6224     }
6225   }
6226   *loff += dof;
6227   PetscFunctionReturn(0);
6228 }
6229 
6230 /*
6231  DMPlexGetIndicesPointFields_Internal - gets section indices for a point in its canonical ordering.
6232 
6233  Input Parameters:
6234 + section - a section (global or local)
6235 - islocal - PETSC_TRUE if requesting local indices (i.e., section is local); PETSC_FALSE for global
6236 . point - point within section
6237 . off - The offset of this point in the (local or global) indexed space - should match islocal and (usually) the section
6238 . foffs - array of length numFields containing the offset in canonical point ordering (the location in indices) of each field
6239 . setBC - identify constrained (boundary condition) points via involution.
6240 . perms - perms[f][permsoff][:] is a permutation of dofs within each field
6241 . permsoff - offset
6242 - indperm - index permutation
6243 
6244  Output Parameter:
6245 . foffs - each entry is incremented by the number of (unconstrained if setBC=FALSE) dofs in that field
6246 . indices - array to hold indices (as defined by section) of each dof associated with point
6247 
6248  Notes:
6249  If section is local and setBC=true, there is no distinction between constrained and unconstrained dofs.
6250  If section is local and setBC=false, the indices for constrained points are the involution -(i+1) of their position
6251  in the local vector.
6252 
6253  If section is global and setBC=false, the indices for constrained points are negative (and their value is not
6254  significant).  It is invalid to call with a global section and setBC=true.
6255 
6256  Developer Note:
6257  The section is only used for field layout, so islocal is technically a statement about the offset (off).  At some point
6258  in the future, global sections may have fields set, in which case we could pass the global section and obtain the
6259  offset could be obtained from the section instead of passing it explicitly as we do now.
6260 
6261  Example:
6262  Suppose a point contains one field with three components, and for which the unconstrained indices are {10, 11, 12}.
6263  When the middle component is constrained, we get the array {10, -12, 12} for (islocal=TRUE, setBC=FALSE).
6264  Note that -12 is the involution of 11, so the user can involute negative indices to recover local indices.
6265  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.
6266 
6267  Level: developer
6268 */
6269 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[])
6270 {
6271   PetscInt       numFields, foff, f;
6272   PetscErrorCode ierr;
6273 
6274   PetscFunctionBegin;
6275   if (!islocal && setBC) SETERRQ(PetscObjectComm((PetscObject)section),PETSC_ERR_ARG_INCOMP,"setBC incompatible with global indices; use a local section or disable setBC");
6276   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
6277   for (f = 0, foff = 0; f < numFields; ++f) {
6278     PetscInt        fdof, cfdof;
6279     const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
6280     PetscInt        cind = 0, b;
6281     const PetscInt  *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL;
6282 
6283     ierr = PetscSectionGetFieldDof(section, point, f, &fdof);CHKERRQ(ierr);
6284     ierr = PetscSectionGetFieldConstraintDof(section, point, f, &cfdof);CHKERRQ(ierr);
6285     if (!cfdof || setBC) {
6286       for (b = 0; b < fdof; ++b) {
6287         const PetscInt preind = perm ? foffs[f]+perm[b] : foffs[f]+b;
6288         const PetscInt ind    = indperm ? indperm[preind] : preind;
6289 
6290         indices[ind] = off+foff+b;
6291       }
6292     } else {
6293       ierr = PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);CHKERRQ(ierr);
6294       for (b = 0; b < fdof; ++b) {
6295         const PetscInt preind = perm ? foffs[f]+perm[b] : foffs[f]+b;
6296         const PetscInt ind    = indperm ? indperm[preind] : preind;
6297 
6298         if ((cind < cfdof) && (b == fcdofs[cind])) {
6299           indices[ind] = -(off+foff+b+1);
6300           ++cind;
6301         } else {
6302           indices[ind] = off + foff + b - (islocal ? 0 : cind);
6303         }
6304       }
6305     }
6306     foff     += (setBC || islocal ? fdof : (fdof - cfdof));
6307     foffs[f] += fdof;
6308   }
6309   PetscFunctionReturn(0);
6310 }
6311 
6312 /*
6313   This version believes the globalSection offsets for each field, rather than just the point offset
6314 
6315  . foffs - The offset into 'indices' for each field, since it is segregated by field
6316 
6317  Notes:
6318  The semantics of this function relate to that of setBC=FALSE in DMPlexGetIndicesPointFields_Internal.
6319  Since this function uses global indices, setBC=TRUE would be invalid, so no such argument exists.
6320 */
6321 static PetscErrorCode DMPlexGetIndicesPointFieldsSplit_Internal(PetscSection section, PetscSection globalSection, PetscInt point, PetscInt foffs[], const PetscInt ***perms, PetscInt permsoff, const PetscInt indperm[], PetscInt indices[])
6322 {
6323   PetscInt       numFields, foff, f;
6324   PetscErrorCode ierr;
6325 
6326   PetscFunctionBegin;
6327   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
6328   for (f = 0; f < numFields; ++f) {
6329     PetscInt        fdof, cfdof;
6330     const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
6331     PetscInt        cind = 0, b;
6332     const PetscInt  *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL;
6333 
6334     ierr = PetscSectionGetFieldDof(section, point, f, &fdof);CHKERRQ(ierr);
6335     ierr = PetscSectionGetFieldConstraintDof(section, point, f, &cfdof);CHKERRQ(ierr);
6336     ierr = PetscSectionGetFieldOffset(globalSection, point, f, &foff);CHKERRQ(ierr);
6337     if (!cfdof) {
6338       for (b = 0; b < fdof; ++b) {
6339         const PetscInt preind = perm ? foffs[f]+perm[b] : foffs[f]+b;
6340         const PetscInt ind    = indperm ? indperm[preind] : preind;
6341 
6342         indices[ind] = foff+b;
6343       }
6344     } else {
6345       ierr = PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);CHKERRQ(ierr);
6346       for (b = 0; b < fdof; ++b) {
6347         const PetscInt preind = perm ? foffs[f]+perm[b] : foffs[f]+b;
6348         const PetscInt ind    = indperm ? indperm[preind] : preind;
6349 
6350         if ((cind < cfdof) && (b == fcdofs[cind])) {
6351           indices[ind] = -(foff+b+1);
6352           ++cind;
6353         } else {
6354           indices[ind] = foff+b-cind;
6355         }
6356       }
6357     }
6358     foffs[f] += fdof;
6359   }
6360   PetscFunctionReturn(0);
6361 }
6362 
6363 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)
6364 {
6365   Mat             cMat;
6366   PetscSection    aSec, cSec;
6367   IS              aIS;
6368   PetscInt        aStart = -1, aEnd = -1;
6369   const PetscInt  *anchors;
6370   PetscInt        numFields, f, p, q, newP = 0;
6371   PetscInt        newNumPoints = 0, newNumIndices = 0;
6372   PetscInt        *newPoints, *indices, *newIndices;
6373   PetscInt        maxAnchor, maxDof;
6374   PetscInt        newOffsets[32];
6375   PetscInt        *pointMatOffsets[32];
6376   PetscInt        *newPointOffsets[32];
6377   PetscScalar     *pointMat[32];
6378   PetscScalar     *newValues=NULL,*tmpValues;
6379   PetscBool       anyConstrained = PETSC_FALSE;
6380   PetscErrorCode  ierr;
6381 
6382   PetscFunctionBegin;
6383   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6384   PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2);
6385   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
6386 
6387   ierr = DMPlexGetAnchors(dm,&aSec,&aIS);CHKERRQ(ierr);
6388   /* if there are point-to-point constraints */
6389   if (aSec) {
6390     ierr = PetscArrayzero(newOffsets, 32);CHKERRQ(ierr);
6391     ierr = ISGetIndices(aIS,&anchors);CHKERRQ(ierr);
6392     ierr = PetscSectionGetChart(aSec,&aStart,&aEnd);CHKERRQ(ierr);
6393     /* figure out how many points are going to be in the new element matrix
6394      * (we allow double counting, because it's all just going to be summed
6395      * into the global matrix anyway) */
6396     for (p = 0; p < 2*numPoints; p+=2) {
6397       PetscInt b    = points[p];
6398       PetscInt bDof = 0, bSecDof;
6399 
6400       ierr = PetscSectionGetDof(section,b,&bSecDof);CHKERRQ(ierr);
6401       if (!bSecDof) {
6402         continue;
6403       }
6404       if (b >= aStart && b < aEnd) {
6405         ierr = PetscSectionGetDof(aSec,b,&bDof);CHKERRQ(ierr);
6406       }
6407       if (bDof) {
6408         /* this point is constrained */
6409         /* it is going to be replaced by its anchors */
6410         PetscInt bOff, q;
6411 
6412         anyConstrained = PETSC_TRUE;
6413         newNumPoints  += bDof;
6414         ierr = PetscSectionGetOffset(aSec,b,&bOff);CHKERRQ(ierr);
6415         for (q = 0; q < bDof; q++) {
6416           PetscInt a = anchors[bOff + q];
6417           PetscInt aDof;
6418 
6419           ierr           = PetscSectionGetDof(section,a,&aDof);CHKERRQ(ierr);
6420           newNumIndices += aDof;
6421           for (f = 0; f < numFields; ++f) {
6422             PetscInt fDof;
6423 
6424             ierr             = PetscSectionGetFieldDof(section, a, f, &fDof);CHKERRQ(ierr);
6425             newOffsets[f+1] += fDof;
6426           }
6427         }
6428       }
6429       else {
6430         /* this point is not constrained */
6431         newNumPoints++;
6432         newNumIndices += bSecDof;
6433         for (f = 0; f < numFields; ++f) {
6434           PetscInt fDof;
6435 
6436           ierr = PetscSectionGetFieldDof(section, b, f, &fDof);CHKERRQ(ierr);
6437           newOffsets[f+1] += fDof;
6438         }
6439       }
6440     }
6441   }
6442   if (!anyConstrained) {
6443     if (outNumPoints)  *outNumPoints  = 0;
6444     if (outNumIndices) *outNumIndices = 0;
6445     if (outPoints)     *outPoints     = NULL;
6446     if (outValues)     *outValues     = NULL;
6447     if (aSec) {ierr = ISRestoreIndices(aIS,&anchors);CHKERRQ(ierr);}
6448     PetscFunctionReturn(0);
6449   }
6450 
6451   if (outNumPoints)  *outNumPoints  = newNumPoints;
6452   if (outNumIndices) *outNumIndices = newNumIndices;
6453 
6454   for (f = 0; f < numFields; ++f) newOffsets[f+1] += newOffsets[f];
6455 
6456   if (!outPoints && !outValues) {
6457     if (offsets) {
6458       for (f = 0; f <= numFields; f++) {
6459         offsets[f] = newOffsets[f];
6460       }
6461     }
6462     if (aSec) {ierr = ISRestoreIndices(aIS,&anchors);CHKERRQ(ierr);}
6463     PetscFunctionReturn(0);
6464   }
6465 
6466   if (numFields && newOffsets[numFields] != newNumIndices) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid size for closure %D should be %D", newOffsets[numFields], newNumIndices);
6467 
6468   ierr = DMGetDefaultConstraints(dm, &cSec, &cMat);CHKERRQ(ierr);
6469 
6470   /* workspaces */
6471   if (numFields) {
6472     for (f = 0; f < numFields; f++) {
6473       ierr = DMGetWorkArray(dm,numPoints+1,MPIU_INT,&pointMatOffsets[f]);CHKERRQ(ierr);
6474       ierr = DMGetWorkArray(dm,numPoints+1,MPIU_INT,&newPointOffsets[f]);CHKERRQ(ierr);
6475     }
6476   }
6477   else {
6478     ierr = DMGetWorkArray(dm,numPoints+1,MPIU_INT,&pointMatOffsets[0]);CHKERRQ(ierr);
6479     ierr = DMGetWorkArray(dm,numPoints,MPIU_INT,&newPointOffsets[0]);CHKERRQ(ierr);
6480   }
6481 
6482   /* get workspaces for the point-to-point matrices */
6483   if (numFields) {
6484     PetscInt totalOffset, totalMatOffset;
6485 
6486     for (p = 0; p < numPoints; p++) {
6487       PetscInt b    = points[2*p];
6488       PetscInt bDof = 0, bSecDof;
6489 
6490       ierr = PetscSectionGetDof(section,b,&bSecDof);CHKERRQ(ierr);
6491       if (!bSecDof) {
6492         for (f = 0; f < numFields; f++) {
6493           newPointOffsets[f][p + 1] = 0;
6494           pointMatOffsets[f][p + 1] = 0;
6495         }
6496         continue;
6497       }
6498       if (b >= aStart && b < aEnd) {
6499         ierr = PetscSectionGetDof(aSec, b, &bDof);CHKERRQ(ierr);
6500       }
6501       if (bDof) {
6502         for (f = 0; f < numFields; f++) {
6503           PetscInt fDof, q, bOff, allFDof = 0;
6504 
6505           ierr = PetscSectionGetFieldDof(section, b, f, &fDof);CHKERRQ(ierr);
6506           ierr = PetscSectionGetOffset(aSec, b, &bOff);CHKERRQ(ierr);
6507           for (q = 0; q < bDof; q++) {
6508             PetscInt a = anchors[bOff + q];
6509             PetscInt aFDof;
6510 
6511             ierr     = PetscSectionGetFieldDof(section, a, f, &aFDof);CHKERRQ(ierr);
6512             allFDof += aFDof;
6513           }
6514           newPointOffsets[f][p+1] = allFDof;
6515           pointMatOffsets[f][p+1] = fDof * allFDof;
6516         }
6517       }
6518       else {
6519         for (f = 0; f < numFields; f++) {
6520           PetscInt fDof;
6521 
6522           ierr = PetscSectionGetFieldDof(section, b, f, &fDof);CHKERRQ(ierr);
6523           newPointOffsets[f][p+1] = fDof;
6524           pointMatOffsets[f][p+1] = 0;
6525         }
6526       }
6527     }
6528     for (f = 0, totalOffset = 0, totalMatOffset = 0; f < numFields; f++) {
6529       newPointOffsets[f][0] = totalOffset;
6530       pointMatOffsets[f][0] = totalMatOffset;
6531       for (p = 0; p < numPoints; p++) {
6532         newPointOffsets[f][p+1] += newPointOffsets[f][p];
6533         pointMatOffsets[f][p+1] += pointMatOffsets[f][p];
6534       }
6535       totalOffset    = newPointOffsets[f][numPoints];
6536       totalMatOffset = pointMatOffsets[f][numPoints];
6537       ierr = DMGetWorkArray(dm,pointMatOffsets[f][numPoints],MPIU_SCALAR,&pointMat[f]);CHKERRQ(ierr);
6538     }
6539   }
6540   else {
6541     for (p = 0; p < numPoints; p++) {
6542       PetscInt b    = points[2*p];
6543       PetscInt bDof = 0, bSecDof;
6544 
6545       ierr = PetscSectionGetDof(section,b,&bSecDof);CHKERRQ(ierr);
6546       if (!bSecDof) {
6547         newPointOffsets[0][p + 1] = 0;
6548         pointMatOffsets[0][p + 1] = 0;
6549         continue;
6550       }
6551       if (b >= aStart && b < aEnd) {
6552         ierr = PetscSectionGetDof(aSec, b, &bDof);CHKERRQ(ierr);
6553       }
6554       if (bDof) {
6555         PetscInt bOff, q, allDof = 0;
6556 
6557         ierr = PetscSectionGetOffset(aSec, b, &bOff);CHKERRQ(ierr);
6558         for (q = 0; q < bDof; q++) {
6559           PetscInt a = anchors[bOff + q], aDof;
6560 
6561           ierr    = PetscSectionGetDof(section, a, &aDof);CHKERRQ(ierr);
6562           allDof += aDof;
6563         }
6564         newPointOffsets[0][p+1] = allDof;
6565         pointMatOffsets[0][p+1] = bSecDof * allDof;
6566       }
6567       else {
6568         newPointOffsets[0][p+1] = bSecDof;
6569         pointMatOffsets[0][p+1] = 0;
6570       }
6571     }
6572     newPointOffsets[0][0] = 0;
6573     pointMatOffsets[0][0] = 0;
6574     for (p = 0; p < numPoints; p++) {
6575       newPointOffsets[0][p+1] += newPointOffsets[0][p];
6576       pointMatOffsets[0][p+1] += pointMatOffsets[0][p];
6577     }
6578     ierr = DMGetWorkArray(dm,pointMatOffsets[0][numPoints],MPIU_SCALAR,&pointMat[0]);CHKERRQ(ierr);
6579   }
6580 
6581   /* output arrays */
6582   ierr = DMGetWorkArray(dm,2*newNumPoints,MPIU_INT,&newPoints);CHKERRQ(ierr);
6583 
6584   /* get the point-to-point matrices; construct newPoints */
6585   ierr = PetscSectionGetMaxDof(aSec, &maxAnchor);CHKERRQ(ierr);
6586   ierr = PetscSectionGetMaxDof(section, &maxDof);CHKERRQ(ierr);
6587   ierr = DMGetWorkArray(dm,maxDof,MPIU_INT,&indices);CHKERRQ(ierr);
6588   ierr = DMGetWorkArray(dm,maxAnchor*maxDof,MPIU_INT,&newIndices);CHKERRQ(ierr);
6589   if (numFields) {
6590     for (p = 0, newP = 0; p < numPoints; p++) {
6591       PetscInt b    = points[2*p];
6592       PetscInt o    = points[2*p+1];
6593       PetscInt bDof = 0, bSecDof;
6594 
6595       ierr = PetscSectionGetDof(section, b, &bSecDof);CHKERRQ(ierr);
6596       if (!bSecDof) {
6597         continue;
6598       }
6599       if (b >= aStart && b < aEnd) {
6600         ierr = PetscSectionGetDof(aSec, b, &bDof);CHKERRQ(ierr);
6601       }
6602       if (bDof) {
6603         PetscInt fStart[32], fEnd[32], fAnchorStart[32], fAnchorEnd[32], bOff, q;
6604 
6605         fStart[0] = 0;
6606         fEnd[0]   = 0;
6607         for (f = 0; f < numFields; f++) {
6608           PetscInt fDof;
6609 
6610           ierr        = PetscSectionGetFieldDof(cSec, b, f, &fDof);CHKERRQ(ierr);
6611           fStart[f+1] = fStart[f] + fDof;
6612           fEnd[f+1]   = fStart[f+1];
6613         }
6614         ierr = PetscSectionGetOffset(cSec, b, &bOff);CHKERRQ(ierr);
6615         ierr = DMPlexGetIndicesPointFields_Internal(cSec, PETSC_TRUE, b, bOff, fEnd, PETSC_TRUE, perms, p, NULL, indices);CHKERRQ(ierr);
6616 
6617         fAnchorStart[0] = 0;
6618         fAnchorEnd[0]   = 0;
6619         for (f = 0; f < numFields; f++) {
6620           PetscInt fDof = newPointOffsets[f][p + 1] - newPointOffsets[f][p];
6621 
6622           fAnchorStart[f+1] = fAnchorStart[f] + fDof;
6623           fAnchorEnd[f+1]   = fAnchorStart[f + 1];
6624         }
6625         ierr = PetscSectionGetOffset(aSec, b, &bOff);CHKERRQ(ierr);
6626         for (q = 0; q < bDof; q++) {
6627           PetscInt a = anchors[bOff + q], aOff;
6628 
6629           /* we take the orientation of ap into account in the order that we constructed the indices above: the newly added points have no orientation */
6630           newPoints[2*(newP + q)]     = a;
6631           newPoints[2*(newP + q) + 1] = 0;
6632           ierr = PetscSectionGetOffset(section, a, &aOff);CHKERRQ(ierr);
6633           ierr = DMPlexGetIndicesPointFields_Internal(section, PETSC_TRUE, a, aOff, fAnchorEnd, PETSC_TRUE, NULL, -1, NULL, newIndices);CHKERRQ(ierr);
6634         }
6635         newP += bDof;
6636 
6637         if (outValues) {
6638           /* get the point-to-point submatrix */
6639           for (f = 0; f < numFields; f++) {
6640             ierr = MatGetValues(cMat,fEnd[f]-fStart[f],indices + fStart[f],fAnchorEnd[f] - fAnchorStart[f],newIndices + fAnchorStart[f],pointMat[f] + pointMatOffsets[f][p]);CHKERRQ(ierr);
6641           }
6642         }
6643       }
6644       else {
6645         newPoints[2 * newP]     = b;
6646         newPoints[2 * newP + 1] = o;
6647         newP++;
6648       }
6649     }
6650   } else {
6651     for (p = 0; p < numPoints; p++) {
6652       PetscInt b    = points[2*p];
6653       PetscInt o    = points[2*p+1];
6654       PetscInt bDof = 0, bSecDof;
6655 
6656       ierr = PetscSectionGetDof(section, b, &bSecDof);CHKERRQ(ierr);
6657       if (!bSecDof) {
6658         continue;
6659       }
6660       if (b >= aStart && b < aEnd) {
6661         ierr = PetscSectionGetDof(aSec, b, &bDof);CHKERRQ(ierr);
6662       }
6663       if (bDof) {
6664         PetscInt bEnd = 0, bAnchorEnd = 0, bOff;
6665 
6666         ierr = PetscSectionGetOffset(cSec, b, &bOff);CHKERRQ(ierr);
6667         ierr = DMPlexGetIndicesPoint_Internal(cSec, PETSC_TRUE, b, bOff, &bEnd, PETSC_TRUE, (perms && perms[0]) ? perms[0][p] : NULL, NULL, indices);CHKERRQ(ierr);
6668 
6669         ierr = PetscSectionGetOffset (aSec, b, &bOff);CHKERRQ(ierr);
6670         for (q = 0; q < bDof; q++) {
6671           PetscInt a = anchors[bOff + q], aOff;
6672 
6673           /* we take the orientation of ap into account in the order that we constructed the indices above: the newly added points have no orientation */
6674 
6675           newPoints[2*(newP + q)]     = a;
6676           newPoints[2*(newP + q) + 1] = 0;
6677           ierr = PetscSectionGetOffset(section, a, &aOff);CHKERRQ(ierr);
6678           ierr = DMPlexGetIndicesPoint_Internal(section, PETSC_TRUE, a, aOff, &bAnchorEnd, PETSC_TRUE, NULL, NULL, newIndices);CHKERRQ(ierr);
6679         }
6680         newP += bDof;
6681 
6682         /* get the point-to-point submatrix */
6683         if (outValues) {
6684           ierr = MatGetValues(cMat,bEnd,indices,bAnchorEnd,newIndices,pointMat[0] + pointMatOffsets[0][p]);CHKERRQ(ierr);
6685         }
6686       }
6687       else {
6688         newPoints[2 * newP]     = b;
6689         newPoints[2 * newP + 1] = o;
6690         newP++;
6691       }
6692     }
6693   }
6694 
6695   if (outValues) {
6696     ierr = DMGetWorkArray(dm,newNumIndices*numIndices,MPIU_SCALAR,&tmpValues);CHKERRQ(ierr);
6697     ierr = PetscArrayzero(tmpValues,newNumIndices*numIndices);CHKERRQ(ierr);
6698     /* multiply constraints on the right */
6699     if (numFields) {
6700       for (f = 0; f < numFields; f++) {
6701         PetscInt oldOff = offsets[f];
6702 
6703         for (p = 0; p < numPoints; p++) {
6704           PetscInt cStart = newPointOffsets[f][p];
6705           PetscInt b      = points[2 * p];
6706           PetscInt c, r, k;
6707           PetscInt dof;
6708 
6709           ierr = PetscSectionGetFieldDof(section,b,f,&dof);CHKERRQ(ierr);
6710           if (!dof) {
6711             continue;
6712           }
6713           if (pointMatOffsets[f][p] < pointMatOffsets[f][p + 1]) {
6714             PetscInt nCols         = newPointOffsets[f][p+1]-cStart;
6715             const PetscScalar *mat = pointMat[f] + pointMatOffsets[f][p];
6716 
6717             for (r = 0; r < numIndices; r++) {
6718               for (c = 0; c < nCols; c++) {
6719                 for (k = 0; k < dof; k++) {
6720                   tmpValues[r * newNumIndices + cStart + c] += values[r * numIndices + oldOff + k] * mat[k * nCols + c];
6721                 }
6722               }
6723             }
6724           }
6725           else {
6726             /* copy this column as is */
6727             for (r = 0; r < numIndices; r++) {
6728               for (c = 0; c < dof; c++) {
6729                 tmpValues[r * newNumIndices + cStart + c] = values[r * numIndices + oldOff + c];
6730               }
6731             }
6732           }
6733           oldOff += dof;
6734         }
6735       }
6736     }
6737     else {
6738       PetscInt oldOff = 0;
6739       for (p = 0; p < numPoints; p++) {
6740         PetscInt cStart = newPointOffsets[0][p];
6741         PetscInt b      = points[2 * p];
6742         PetscInt c, r, k;
6743         PetscInt dof;
6744 
6745         ierr = PetscSectionGetDof(section,b,&dof);CHKERRQ(ierr);
6746         if (!dof) {
6747           continue;
6748         }
6749         if (pointMatOffsets[0][p] < pointMatOffsets[0][p + 1]) {
6750           PetscInt nCols         = newPointOffsets[0][p+1]-cStart;
6751           const PetscScalar *mat = pointMat[0] + pointMatOffsets[0][p];
6752 
6753           for (r = 0; r < numIndices; r++) {
6754             for (c = 0; c < nCols; c++) {
6755               for (k = 0; k < dof; k++) {
6756                 tmpValues[r * newNumIndices + cStart + c] += mat[k * nCols + c] * values[r * numIndices + oldOff + k];
6757               }
6758             }
6759           }
6760         }
6761         else {
6762           /* copy this column as is */
6763           for (r = 0; r < numIndices; r++) {
6764             for (c = 0; c < dof; c++) {
6765               tmpValues[r * newNumIndices + cStart + c] = values[r * numIndices + oldOff + c];
6766             }
6767           }
6768         }
6769         oldOff += dof;
6770       }
6771     }
6772 
6773     if (multiplyLeft) {
6774       ierr = DMGetWorkArray(dm,newNumIndices*newNumIndices,MPIU_SCALAR,&newValues);CHKERRQ(ierr);
6775       ierr = PetscArrayzero(newValues,newNumIndices*newNumIndices);CHKERRQ(ierr);
6776       /* multiply constraints transpose on the left */
6777       if (numFields) {
6778         for (f = 0; f < numFields; f++) {
6779           PetscInt oldOff = offsets[f];
6780 
6781           for (p = 0; p < numPoints; p++) {
6782             PetscInt rStart = newPointOffsets[f][p];
6783             PetscInt b      = points[2 * p];
6784             PetscInt c, r, k;
6785             PetscInt dof;
6786 
6787             ierr = PetscSectionGetFieldDof(section,b,f,&dof);CHKERRQ(ierr);
6788             if (pointMatOffsets[f][p] < pointMatOffsets[f][p + 1]) {
6789               PetscInt nRows                        = newPointOffsets[f][p+1]-rStart;
6790               const PetscScalar *PETSC_RESTRICT mat = pointMat[f] + pointMatOffsets[f][p];
6791 
6792               for (r = 0; r < nRows; r++) {
6793                 for (c = 0; c < newNumIndices; c++) {
6794                   for (k = 0; k < dof; k++) {
6795                     newValues[(rStart + r) * newNumIndices + c] += mat[k * nRows + r] * tmpValues[(oldOff + k) * newNumIndices + c];
6796                   }
6797                 }
6798               }
6799             }
6800             else {
6801               /* copy this row as is */
6802               for (r = 0; r < dof; r++) {
6803                 for (c = 0; c < newNumIndices; c++) {
6804                   newValues[(rStart + r) * newNumIndices + c] = tmpValues[(oldOff + r) * newNumIndices + c];
6805                 }
6806               }
6807             }
6808             oldOff += dof;
6809           }
6810         }
6811       }
6812       else {
6813         PetscInt oldOff = 0;
6814 
6815         for (p = 0; p < numPoints; p++) {
6816           PetscInt rStart = newPointOffsets[0][p];
6817           PetscInt b      = points[2 * p];
6818           PetscInt c, r, k;
6819           PetscInt dof;
6820 
6821           ierr = PetscSectionGetDof(section,b,&dof);CHKERRQ(ierr);
6822           if (pointMatOffsets[0][p] < pointMatOffsets[0][p + 1]) {
6823             PetscInt nRows                        = newPointOffsets[0][p+1]-rStart;
6824             const PetscScalar *PETSC_RESTRICT mat = pointMat[0] + pointMatOffsets[0][p];
6825 
6826             for (r = 0; r < nRows; r++) {
6827               for (c = 0; c < newNumIndices; c++) {
6828                 for (k = 0; k < dof; k++) {
6829                   newValues[(rStart + r) * newNumIndices + c] += mat[k * nRows + r] * tmpValues[(oldOff + k) * newNumIndices + c];
6830                 }
6831               }
6832             }
6833           }
6834           else {
6835             /* copy this row as is */
6836             for (r = 0; r < dof; r++) {
6837               for (c = 0; c < newNumIndices; c++) {
6838                 newValues[(rStart + r) * newNumIndices + c] = tmpValues[(oldOff + r) * newNumIndices + c];
6839               }
6840             }
6841           }
6842           oldOff += dof;
6843         }
6844       }
6845 
6846       ierr = DMRestoreWorkArray(dm,newNumIndices*numIndices,MPIU_SCALAR,&tmpValues);CHKERRQ(ierr);
6847     }
6848     else {
6849       newValues = tmpValues;
6850     }
6851   }
6852 
6853   /* clean up */
6854   ierr = DMRestoreWorkArray(dm,maxDof,MPIU_INT,&indices);CHKERRQ(ierr);
6855   ierr = DMRestoreWorkArray(dm,maxAnchor*maxDof,MPIU_INT,&newIndices);CHKERRQ(ierr);
6856 
6857   if (numFields) {
6858     for (f = 0; f < numFields; f++) {
6859       ierr = DMRestoreWorkArray(dm,pointMatOffsets[f][numPoints],MPIU_SCALAR,&pointMat[f]);CHKERRQ(ierr);
6860       ierr = DMRestoreWorkArray(dm,numPoints+1,MPIU_INT,&pointMatOffsets[f]);CHKERRQ(ierr);
6861       ierr = DMRestoreWorkArray(dm,numPoints+1,MPIU_INT,&newPointOffsets[f]);CHKERRQ(ierr);
6862     }
6863   }
6864   else {
6865     ierr = DMRestoreWorkArray(dm,pointMatOffsets[0][numPoints],MPIU_SCALAR,&pointMat[0]);CHKERRQ(ierr);
6866     ierr = DMRestoreWorkArray(dm,numPoints+1,MPIU_INT,&pointMatOffsets[0]);CHKERRQ(ierr);
6867     ierr = DMRestoreWorkArray(dm,numPoints+1,MPIU_INT,&newPointOffsets[0]);CHKERRQ(ierr);
6868   }
6869   ierr = ISRestoreIndices(aIS,&anchors);CHKERRQ(ierr);
6870 
6871   /* output */
6872   if (outPoints) {
6873     *outPoints = newPoints;
6874   }
6875   else {
6876     ierr = DMRestoreWorkArray(dm,2*newNumPoints,MPIU_INT,&newPoints);CHKERRQ(ierr);
6877   }
6878   if (outValues) {
6879     *outValues = newValues;
6880   }
6881   for (f = 0; f <= numFields; f++) {
6882     offsets[f] = newOffsets[f];
6883   }
6884   PetscFunctionReturn(0);
6885 }
6886 
6887 /*@C
6888   DMPlexGetClosureIndices - Gets the global dof indices associated with the closure of the given point within the provided sections.
6889 
6890   Not collective
6891 
6892   Input Parameters:
6893 + dm         - The DM
6894 . section    - The PetscSection describing the points (a local section)
6895 . idxSection - The PetscSection from which to obtain indices (may be local or global)
6896 . point      - The point defining the closure
6897 - useClPerm  - Use the closure point permutation if available
6898 
6899   Output Parameters:
6900 + numIndices - The number of dof indices in the closure of point with the input sections
6901 . indices    - The dof indices
6902 . outOffsets - Array to write the field offsets into, or NULL
6903 - values     - The input values, which may be modified if sign flips are induced by the point symmetries, or NULL
6904 
6905   Notes:
6906   Must call DMPlexRestoreClosureIndices() to free allocated memory
6907 
6908   If idxSection is global, any constrained dofs (see DMAddBoundary(), for example) will get negative indices.  The value
6909   of those indices is not significant.  If idxSection is local, the constrained dofs will yield the involution -(idx+1)
6910   of their index in a local vector.  A caller who does not wish to distinguish those points may recover the nonnegative
6911   indices via involution, -(-(idx+1)+1)==idx.  Local indices are provided when idxSection == section, otherwise global
6912   indices (with the above semantics) are implied.
6913 
6914   Level: advanced
6915 
6916 .seealso DMPlexRestoreClosureIndices(), DMPlexVecGetClosure(), DMPlexMatSetClosure(), DMGetLocalSection(), DMGetGlobalSection()
6917 @*/
6918 PetscErrorCode DMPlexGetClosureIndices(DM dm, PetscSection section, PetscSection idxSection, PetscInt point, PetscBool useClPerm,
6919                                        PetscInt *numIndices, PetscInt *indices[], PetscInt outOffsets[], PetscScalar *values[])
6920 {
6921   /* Closure ordering */
6922   PetscSection        clSection;
6923   IS                  clPoints;
6924   const PetscInt     *clp;
6925   PetscInt           *points;
6926   const PetscInt     *clperm = NULL;
6927   /* Dof permutation and sign flips */
6928   const PetscInt    **perms[32] = {NULL};
6929   const PetscScalar **flips[32] = {NULL};
6930   PetscScalar        *valCopy   = NULL;
6931   /* Hanging node constraints */
6932   PetscInt           *pointsC = NULL;
6933   PetscScalar        *valuesC = NULL;
6934   PetscInt            NclC, NiC;
6935 
6936   PetscInt           *idx;
6937   PetscInt            Nf, Ncl, Ni = 0, offsets[32], p, f;
6938   PetscBool           isLocal = (section == idxSection) ? PETSC_TRUE : PETSC_FALSE;
6939   PetscErrorCode      ierr;
6940 
6941   PetscFunctionBeginHot;
6942   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6943   PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2);
6944   PetscValidHeaderSpecific(idxSection, PETSC_SECTION_CLASSID, 3);
6945   if (numIndices) PetscValidPointer(numIndices, 6);
6946   if (indices)    PetscValidPointer(indices, 7);
6947   if (outOffsets) PetscValidPointer(outOffsets, 8);
6948   if (values)     PetscValidPointer(values, 9);
6949   ierr = PetscSectionGetNumFields(section, &Nf);CHKERRQ(ierr);
6950   if (Nf > 31) SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", Nf);
6951   ierr = PetscArrayzero(offsets, 32);CHKERRQ(ierr);
6952   /* 1) Get points in closure */
6953   ierr = DMPlexGetCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp);CHKERRQ(ierr);
6954   if (useClPerm) {
6955     PetscInt depth, clsize;
6956     ierr = DMPlexGetPointDepth(dm, point, &depth);CHKERRQ(ierr);
6957     for (clsize=0,p=0; p<Ncl; p++) {
6958       PetscInt dof;
6959       ierr = PetscSectionGetDof(section, points[2*p], &dof);CHKERRQ(ierr);
6960       clsize += dof;
6961     }
6962     ierr = PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject) dm, depth, clsize, &clperm);CHKERRQ(ierr);
6963   }
6964   /* 2) Get number of indices on these points and field offsets from section */
6965   for (p = 0; p < Ncl*2; p += 2) {
6966     PetscInt dof, fdof;
6967 
6968     ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
6969     for (f = 0; f < Nf; ++f) {
6970       ierr = PetscSectionGetFieldDof(section, points[p], f, &fdof);CHKERRQ(ierr);
6971       offsets[f+1] += fdof;
6972     }
6973     Ni += dof;
6974   }
6975   for (f = 1; f < Nf; ++f) offsets[f+1] += offsets[f];
6976   if (Nf && offsets[Nf] != Ni) SETERRQ2(PetscObjectComm((PetscObject) dm), PETSC_ERR_PLIB, "Invalid size for closure %D should be %D", offsets[Nf], Ni);
6977   /* 3) Get symmetries and sign flips. Apply sign flips to values if passed in (only works for square values matrix) */
6978   for (f = 0; f < PetscMax(1, Nf); ++f) {
6979     if (Nf) {ierr = PetscSectionGetFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f]);CHKERRQ(ierr);}
6980     else    {ierr = PetscSectionGetPointSyms(section, Ncl, points, &perms[f], &flips[f]);CHKERRQ(ierr);}
6981     /* may need to apply sign changes to the element matrix */
6982     if (values && flips[f]) {
6983       PetscInt foffset = offsets[f];
6984 
6985       for (p = 0; p < Ncl; ++p) {
6986         PetscInt           pnt  = points[2*p], fdof;
6987         const PetscScalar *flip = flips[f] ? flips[f][p] : NULL;
6988 
6989         if (!Nf) {ierr = PetscSectionGetDof(section, pnt, &fdof);CHKERRQ(ierr);}
6990         else     {ierr = PetscSectionGetFieldDof(section, pnt, f, &fdof);CHKERRQ(ierr);}
6991         if (flip) {
6992           PetscInt i, j, k;
6993 
6994           if (!valCopy) {
6995             ierr = DMGetWorkArray(dm, Ni*Ni, MPIU_SCALAR, &valCopy);CHKERRQ(ierr);
6996             for (j = 0; j < Ni * Ni; ++j) valCopy[j] = (*values)[j];
6997             *values = valCopy;
6998           }
6999           for (i = 0; i < fdof; ++i) {
7000             PetscScalar fval = flip[i];
7001 
7002             for (k = 0; k < Ni; ++k) {
7003               valCopy[Ni * (foffset + i) + k] *= fval;
7004               valCopy[Ni * k + (foffset + i)] *= fval;
7005             }
7006           }
7007         }
7008         foffset += fdof;
7009       }
7010     }
7011   }
7012   /* 4) Apply hanging node constraints. Get new symmetries and replace all storage with constrained storage */
7013   ierr = DMPlexAnchorsModifyMat(dm, section, Ncl, Ni, points, perms, values ? *values : NULL, &NclC, &NiC, &pointsC, values ? &valuesC : NULL, offsets, PETSC_TRUE);CHKERRQ(ierr);
7014   if (NclC) {
7015     if (valCopy) {ierr = DMRestoreWorkArray(dm, Ni*Ni, MPIU_SCALAR, &valCopy);CHKERRQ(ierr);}
7016     for (f = 0; f < PetscMax(1, Nf); ++f) {
7017       if (Nf) {ierr = PetscSectionRestoreFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f]);CHKERRQ(ierr);}
7018       else    {ierr = PetscSectionRestorePointSyms(section, Ncl, points, &perms[f], &flips[f]);CHKERRQ(ierr);}
7019     }
7020     for (f = 0; f < PetscMax(1, Nf); ++f) {
7021       if (Nf) {ierr = PetscSectionGetFieldPointSyms(section, f, NclC, pointsC, &perms[f], &flips[f]);CHKERRQ(ierr);}
7022       else    {ierr = PetscSectionGetPointSyms(section, NclC, pointsC, &perms[f], &flips[f]);CHKERRQ(ierr);}
7023     }
7024     ierr = DMPlexRestoreCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp);CHKERRQ(ierr);
7025     Ncl     = NclC;
7026     Ni      = NiC;
7027     points  = pointsC;
7028     if (values) *values = valuesC;
7029   }
7030   /* 5) Calculate indices */
7031   ierr = DMGetWorkArray(dm, Ni, MPIU_INT, &idx);CHKERRQ(ierr);
7032   if (Nf) {
7033     PetscInt  idxOff;
7034     PetscBool useFieldOffsets;
7035 
7036     if (outOffsets) {for (f = 0; f <= Nf; f++) outOffsets[f] = offsets[f];}
7037     ierr = PetscSectionGetUseFieldOffsets(idxSection, &useFieldOffsets);CHKERRQ(ierr);
7038     if (useFieldOffsets) {
7039       for (p = 0; p < Ncl; ++p) {
7040         const PetscInt pnt = points[p*2];
7041 
7042         ierr = DMPlexGetIndicesPointFieldsSplit_Internal(section, idxSection, pnt, offsets, perms, p, clperm, idx);CHKERRQ(ierr);
7043       }
7044     } else {
7045       for (p = 0; p < Ncl; ++p) {
7046         const PetscInt pnt = points[p*2];
7047 
7048         ierr = PetscSectionGetOffset(idxSection, pnt, &idxOff);CHKERRQ(ierr);
7049         /* Note that we pass a local section even though we're using global offsets.  This is because global sections do
7050          * not (at the time of this writing) have fields set. They probably should, in which case we would pass the
7051          * global section. */
7052         ierr = DMPlexGetIndicesPointFields_Internal(section, isLocal, pnt, idxOff < 0 ? -(idxOff+1) : idxOff, offsets, PETSC_FALSE, perms, p, clperm, idx);CHKERRQ(ierr);
7053       }
7054     }
7055   } else {
7056     PetscInt off = 0, idxOff;
7057 
7058     for (p = 0; p < Ncl; ++p) {
7059       const PetscInt  pnt  = points[p*2];
7060       const PetscInt *perm = perms[0] ? perms[0][p] : NULL;
7061 
7062       ierr = PetscSectionGetOffset(idxSection, pnt, &idxOff);CHKERRQ(ierr);
7063       /* Note that we pass a local section even though we're using global offsets.  This is because global sections do
7064        * not (at the time of this writing) have fields set. They probably should, in which case we would pass the global section. */
7065       ierr = DMPlexGetIndicesPoint_Internal(section, isLocal, pnt, idxOff < 0 ? -(idxOff+1) : idxOff, &off, PETSC_FALSE, perm, clperm, idx);CHKERRQ(ierr);
7066     }
7067   }
7068   /* 6) Cleanup */
7069   for (f = 0; f < PetscMax(1, Nf); ++f) {
7070     if (Nf) {ierr = PetscSectionRestoreFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f]);CHKERRQ(ierr);}
7071     else    {ierr = PetscSectionRestorePointSyms(section, Ncl, points, &perms[f], &flips[f]);CHKERRQ(ierr);}
7072   }
7073   if (NclC) {
7074     ierr = DMRestoreWorkArray(dm, NclC*2, MPIU_INT, &pointsC);CHKERRQ(ierr);
7075   } else {
7076     ierr = DMPlexRestoreCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp);CHKERRQ(ierr);
7077   }
7078 
7079   if (numIndices) *numIndices = Ni;
7080   if (indices)    *indices    = idx;
7081   PetscFunctionReturn(0);
7082 }
7083 
7084 /*@C
7085   DMPlexRestoreClosureIndices - Restores the global dof indices associated with the closure of the given point within the provided sections.
7086 
7087   Not collective
7088 
7089   Input Parameters:
7090 + dm         - The DM
7091 . section    - The PetscSection describing the points (a local section)
7092 . idxSection - The PetscSection from which to obtain indices (may be local or global)
7093 . point      - The point defining the closure
7094 - useClPerm  - Use the closure point permutation if available
7095 
7096   Output Parameters:
7097 + numIndices - The number of dof indices in the closure of point with the input sections
7098 . indices    - The dof indices
7099 . outOffsets - Array to write the field offsets into, or NULL
7100 - values     - The input values, which may be modified if sign flips are induced by the point symmetries, or NULL
7101 
7102   Notes:
7103   If values were modified, the user is responsible for calling DMRestoreWorkArray(dm, 0, MPIU_SCALAR, &values).
7104 
7105   If idxSection is global, any constrained dofs (see DMAddBoundary(), for example) will get negative indices.  The value
7106   of those indices is not significant.  If idxSection is local, the constrained dofs will yield the involution -(idx+1)
7107   of their index in a local vector.  A caller who does not wish to distinguish those points may recover the nonnegative
7108   indices via involution, -(-(idx+1)+1)==idx.  Local indices are provided when idxSection == section, otherwise global
7109   indices (with the above semantics) are implied.
7110 
7111   Level: advanced
7112 
7113 .seealso DMPlexGetClosureIndices(), DMPlexVecGetClosure(), DMPlexMatSetClosure(), DMGetLocalSection(), DMGetGlobalSection()
7114 @*/
7115 PetscErrorCode DMPlexRestoreClosureIndices(DM dm, PetscSection section, PetscSection idxSection, PetscInt point, PetscBool useClPerm,
7116                                            PetscInt *numIndices, PetscInt *indices[], PetscInt outOffsets[], PetscScalar *values[])
7117 {
7118   PetscErrorCode ierr;
7119 
7120   PetscFunctionBegin;
7121   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7122   PetscValidPointer(indices, 7);
7123   ierr = DMRestoreWorkArray(dm, 0, MPIU_INT, indices);CHKERRQ(ierr);
7124   PetscFunctionReturn(0);
7125 }
7126 
7127 /*@C
7128   DMPlexMatSetClosure - Set an array of the values on the closure of 'point'
7129 
7130   Not collective
7131 
7132   Input Parameters:
7133 + dm - The DM
7134 . section - The section describing the layout in v, or NULL to use the default section
7135 . globalSection - The section describing the layout in v, or NULL to use the default global section
7136 . A - The matrix
7137 . point - The point in the DM
7138 . values - The array of values
7139 - mode - The insert mode, where INSERT_ALL_VALUES and ADD_ALL_VALUES also overwrite boundary conditions
7140 
7141   Fortran Notes:
7142   This routine is only available in Fortran 90, and you must include petsc.h90 in your code.
7143 
7144   Level: intermediate
7145 
7146 .seealso DMPlexMatSetClosureGeneral(), DMPlexVecGetClosure(), DMPlexVecSetClosure()
7147 @*/
7148 PetscErrorCode DMPlexMatSetClosure(DM dm, PetscSection section, PetscSection globalSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode)
7149 {
7150   DM_Plex           *mesh = (DM_Plex*) dm->data;
7151   PetscInt          *indices;
7152   PetscInt           numIndices;
7153   const PetscScalar *valuesOrig = values;
7154   PetscErrorCode     ierr;
7155 
7156   PetscFunctionBegin;
7157   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7158   if (!section) {ierr = DMGetLocalSection(dm, &section);CHKERRQ(ierr);}
7159   PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2);
7160   if (!globalSection) {ierr = DMGetGlobalSection(dm, &globalSection);CHKERRQ(ierr);}
7161   PetscValidHeaderSpecific(globalSection, PETSC_SECTION_CLASSID, 3);
7162   PetscValidHeaderSpecific(A, MAT_CLASSID, 4);
7163 
7164   ierr = DMPlexGetClosureIndices(dm, section, globalSection, point, PETSC_TRUE, &numIndices, &indices, NULL, (PetscScalar **) &values);CHKERRQ(ierr);
7165 
7166   if (mesh->printSetValues) {ierr = DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndices, indices, 0, NULL, values);CHKERRQ(ierr);}
7167   ierr = MatSetValues(A, numIndices, indices, numIndices, indices, values, mode);
7168   if (ierr) {
7169     PetscMPIInt    rank;
7170     PetscErrorCode ierr2;
7171 
7172     ierr2 = MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank);CHKERRMPI(ierr2);
7173     ierr2 = (*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank);CHKERRQ(ierr2);
7174     ierr2 = DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndices, indices, 0, NULL, values);CHKERRQ(ierr2);
7175     ierr2 = DMPlexRestoreClosureIndices(dm, section, globalSection, point, PETSC_TRUE, &numIndices, &indices, NULL, (PetscScalar **) &values);CHKERRQ(ierr2);
7176     if (values != valuesOrig) {ierr2 = DMRestoreWorkArray(dm, 0, MPIU_SCALAR, &values);CHKERRQ(ierr2);}
7177     CHKERRQ(ierr);
7178   }
7179   if (mesh->printFEM > 1) {
7180     PetscInt i;
7181     ierr = PetscPrintf(PETSC_COMM_SELF, "  Indices:");CHKERRQ(ierr);
7182     for (i = 0; i < numIndices; ++i) {ierr = PetscPrintf(PETSC_COMM_SELF, " %D", indices[i]);CHKERRQ(ierr);}
7183     ierr = PetscPrintf(PETSC_COMM_SELF, "\n");CHKERRQ(ierr);
7184   }
7185 
7186   ierr = DMPlexRestoreClosureIndices(dm, section, globalSection, point, PETSC_TRUE, &numIndices, &indices, NULL, (PetscScalar **) &values);CHKERRQ(ierr);
7187   if (values != valuesOrig) {ierr = DMRestoreWorkArray(dm, 0, MPIU_SCALAR, &values);CHKERRQ(ierr);}
7188   PetscFunctionReturn(0);
7189 }
7190 
7191 /*@C
7192   DMPlexMatSetClosure - Set an array of the values on the closure of 'point' using a different row and column section
7193 
7194   Not collective
7195 
7196   Input Parameters:
7197 + dmRow - The DM for the row fields
7198 . sectionRow - The section describing the layout, or NULL to use the default section in dmRow
7199 . globalSectionRow - The section describing the layout, or NULL to use the default global section in dmRow
7200 . dmCol - The DM for the column fields
7201 . sectionCol - The section describing the layout, or NULL to use the default section in dmCol
7202 . globalSectionCol - The section describing the layout, or NULL to use the default global section in dmCol
7203 . A - The matrix
7204 . point - The point in the DMs
7205 . values - The array of values
7206 - mode - The insert mode, where INSERT_ALL_VALUES and ADD_ALL_VALUES also overwrite boundary conditions
7207 
7208   Level: intermediate
7209 
7210 .seealso DMPlexMatSetClosure(), DMPlexVecGetClosure(), DMPlexVecSetClosure()
7211 @*/
7212 PetscErrorCode DMPlexMatSetClosureGeneral(DM dmRow, PetscSection sectionRow, PetscSection globalSectionRow, DM dmCol, PetscSection sectionCol, PetscSection globalSectionCol, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode)
7213 {
7214   DM_Plex           *mesh = (DM_Plex*) dmRow->data;
7215   PetscInt          *indicesRow, *indicesCol;
7216   PetscInt           numIndicesRow, numIndicesCol;
7217   const PetscScalar *valuesOrig = values;
7218   PetscErrorCode     ierr;
7219 
7220   PetscFunctionBegin;
7221   PetscValidHeaderSpecific(dmRow, DM_CLASSID, 1);
7222   if (!sectionRow) {ierr = DMGetLocalSection(dmRow, &sectionRow);CHKERRQ(ierr);}
7223   PetscValidHeaderSpecific(sectionRow, PETSC_SECTION_CLASSID, 2);
7224   if (!globalSectionRow) {ierr = DMGetGlobalSection(dmRow, &globalSectionRow);CHKERRQ(ierr);}
7225   PetscValidHeaderSpecific(globalSectionRow, PETSC_SECTION_CLASSID, 3);
7226   PetscValidHeaderSpecific(dmCol, DM_CLASSID, 4);
7227   if (!sectionCol) {ierr = DMGetLocalSection(dmCol, &sectionCol);CHKERRQ(ierr);}
7228   PetscValidHeaderSpecific(sectionCol, PETSC_SECTION_CLASSID, 5);
7229   if (!globalSectionCol) {ierr = DMGetGlobalSection(dmCol, &globalSectionCol);CHKERRQ(ierr);}
7230   PetscValidHeaderSpecific(globalSectionCol, PETSC_SECTION_CLASSID, 6);
7231   PetscValidHeaderSpecific(A, MAT_CLASSID, 7);
7232 
7233   ierr = DMPlexGetClosureIndices(dmRow, sectionRow, globalSectionRow, point, PETSC_TRUE, &numIndicesRow, &indicesRow, NULL, (PetscScalar **) &values);CHKERRQ(ierr);
7234   ierr = DMPlexGetClosureIndices(dmCol, sectionCol, globalSectionCol, point, PETSC_TRUE, &numIndicesCol, &indicesCol, NULL, (PetscScalar **) &values);CHKERRQ(ierr);
7235 
7236   if (mesh->printSetValues) {ierr = DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndicesRow, indicesRow, numIndicesCol, indicesCol, values);CHKERRQ(ierr);}
7237   ierr = MatSetValues(A, numIndicesRow, indicesRow, numIndicesCol, indicesCol, values, mode);
7238   if (ierr) {
7239     PetscMPIInt    rank;
7240     PetscErrorCode ierr2;
7241 
7242     ierr2 = MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank);CHKERRMPI(ierr2);
7243     ierr2 = (*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank);CHKERRQ(ierr2);
7244     ierr2 = DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndicesRow, indicesRow, numIndicesCol, indicesCol, values);CHKERRQ(ierr2);
7245     ierr2 = DMPlexRestoreClosureIndices(dmRow, sectionRow, globalSectionRow, point, PETSC_TRUE, &numIndicesRow, &indicesRow, NULL, (PetscScalar **) &values);CHKERRQ(ierr2);
7246     ierr2 = DMPlexRestoreClosureIndices(dmCol, sectionCol, globalSectionCol, point, PETSC_TRUE, &numIndicesCol, &indicesRow, NULL, (PetscScalar **) &values);CHKERRQ(ierr2);
7247     if (values != valuesOrig) {ierr2 = DMRestoreWorkArray(dmRow, 0, MPIU_SCALAR, &values);CHKERRQ(ierr2);}
7248     CHKERRQ(ierr);
7249   }
7250 
7251   ierr = DMPlexRestoreClosureIndices(dmRow, sectionRow, globalSectionRow, point, PETSC_TRUE, &numIndicesRow, &indicesRow, NULL, (PetscScalar **) &values);CHKERRQ(ierr);
7252   ierr = DMPlexRestoreClosureIndices(dmCol, sectionCol, globalSectionCol, point, PETSC_TRUE, &numIndicesCol, &indicesCol, NULL, (PetscScalar **) &values);CHKERRQ(ierr);
7253   if (values != valuesOrig) {ierr = DMRestoreWorkArray(dmRow, 0, MPIU_SCALAR, &values);CHKERRQ(ierr);}
7254   PetscFunctionReturn(0);
7255 }
7256 
7257 PetscErrorCode DMPlexMatSetClosureRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode)
7258 {
7259   DM_Plex        *mesh   = (DM_Plex*) dmf->data;
7260   PetscInt       *fpoints = NULL, *ftotpoints = NULL;
7261   PetscInt       *cpoints = NULL;
7262   PetscInt       *findices, *cindices;
7263   const PetscInt *fclperm = NULL, *cclperm = NULL; /* Closure permutations cannot work here */
7264   PetscInt        foffsets[32], coffsets[32];
7265   DMPolytopeType  ct;
7266   PetscInt        numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f;
7267   PetscErrorCode  ierr;
7268 
7269   PetscFunctionBegin;
7270   PetscValidHeaderSpecific(dmf, DM_CLASSID, 1);
7271   PetscValidHeaderSpecific(dmc, DM_CLASSID, 4);
7272   if (!fsection) {ierr = DMGetLocalSection(dmf, &fsection);CHKERRQ(ierr);}
7273   PetscValidHeaderSpecific(fsection, PETSC_SECTION_CLASSID, 2);
7274   if (!csection) {ierr = DMGetLocalSection(dmc, &csection);CHKERRQ(ierr);}
7275   PetscValidHeaderSpecific(csection, PETSC_SECTION_CLASSID, 5);
7276   if (!globalFSection) {ierr = DMGetGlobalSection(dmf, &globalFSection);CHKERRQ(ierr);}
7277   PetscValidHeaderSpecific(globalFSection, PETSC_SECTION_CLASSID, 3);
7278   if (!globalCSection) {ierr = DMGetGlobalSection(dmc, &globalCSection);CHKERRQ(ierr);}
7279   PetscValidHeaderSpecific(globalCSection, PETSC_SECTION_CLASSID, 6);
7280   PetscValidHeaderSpecific(A, MAT_CLASSID, 7);
7281   ierr = PetscSectionGetNumFields(fsection, &numFields);CHKERRQ(ierr);
7282   if (numFields > 31) SETERRQ1(PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
7283   ierr = PetscArrayzero(foffsets, 32);CHKERRQ(ierr);
7284   ierr = PetscArrayzero(coffsets, 32);CHKERRQ(ierr);
7285   /* Column indices */
7286   ierr = DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints);CHKERRQ(ierr);
7287   maxFPoints = numCPoints;
7288   /* Compress out points not in the section */
7289   /*   TODO: Squeeze out points with 0 dof as well */
7290   ierr = PetscSectionGetChart(csection, &pStart, &pEnd);CHKERRQ(ierr);
7291   for (p = 0, q = 0; p < numCPoints*2; p += 2) {
7292     if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) {
7293       cpoints[q*2]   = cpoints[p];
7294       cpoints[q*2+1] = cpoints[p+1];
7295       ++q;
7296     }
7297   }
7298   numCPoints = q;
7299   for (p = 0, numCIndices = 0; p < numCPoints*2; p += 2) {
7300     PetscInt fdof;
7301 
7302     ierr = PetscSectionGetDof(csection, cpoints[p], &dof);CHKERRQ(ierr);
7303     if (!dof) continue;
7304     for (f = 0; f < numFields; ++f) {
7305       ierr           = PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof);CHKERRQ(ierr);
7306       coffsets[f+1] += fdof;
7307     }
7308     numCIndices += dof;
7309   }
7310   for (f = 1; f < numFields; ++f) coffsets[f+1] += coffsets[f];
7311   /* Row indices */
7312   ierr = DMPlexGetCellType(dmc, point, &ct);CHKERRQ(ierr);
7313   {
7314     DMPlexCellRefiner cr;
7315     ierr = DMPlexCellRefinerCreate(dmc, &cr);CHKERRQ(ierr);
7316     ierr = DMPlexCellRefinerGetAffineTransforms(cr, ct, &numSubcells, NULL, NULL, NULL);CHKERRQ(ierr);
7317     ierr = DMPlexCellRefinerDestroy(&cr);CHKERRQ(ierr);
7318   }
7319   ierr = DMGetWorkArray(dmf, maxFPoints*2*numSubcells, MPIU_INT, &ftotpoints);CHKERRQ(ierr);
7320   for (r = 0, q = 0; r < numSubcells; ++r) {
7321     /* TODO Map from coarse to fine cells */
7322     ierr = DMPlexGetTransitiveClosure(dmf, point*numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints);CHKERRQ(ierr);
7323     /* Compress out points not in the section */
7324     ierr = PetscSectionGetChart(fsection, &pStart, &pEnd);CHKERRQ(ierr);
7325     for (p = 0; p < numFPoints*2; p += 2) {
7326       if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) {
7327         ierr = PetscSectionGetDof(fsection, fpoints[p], &dof);CHKERRQ(ierr);
7328         if (!dof) continue;
7329         for (s = 0; s < q; ++s) if (fpoints[p] == ftotpoints[s*2]) break;
7330         if (s < q) continue;
7331         ftotpoints[q*2]   = fpoints[p];
7332         ftotpoints[q*2+1] = fpoints[p+1];
7333         ++q;
7334       }
7335     }
7336     ierr = DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints);CHKERRQ(ierr);
7337   }
7338   numFPoints = q;
7339   for (p = 0, numFIndices = 0; p < numFPoints*2; p += 2) {
7340     PetscInt fdof;
7341 
7342     ierr = PetscSectionGetDof(fsection, ftotpoints[p], &dof);CHKERRQ(ierr);
7343     if (!dof) continue;
7344     for (f = 0; f < numFields; ++f) {
7345       ierr           = PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof);CHKERRQ(ierr);
7346       foffsets[f+1] += fdof;
7347     }
7348     numFIndices += dof;
7349   }
7350   for (f = 1; f < numFields; ++f) foffsets[f+1] += foffsets[f];
7351 
7352   if (numFields && foffsets[numFields] != numFIndices) SETERRQ2(PetscObjectComm((PetscObject)dmf), PETSC_ERR_PLIB, "Invalid size for closure %D should be %D", foffsets[numFields], numFIndices);
7353   if (numFields && coffsets[numFields] != numCIndices) SETERRQ2(PetscObjectComm((PetscObject)dmc), PETSC_ERR_PLIB, "Invalid size for closure %D should be %D", coffsets[numFields], numCIndices);
7354   ierr = DMGetWorkArray(dmf, numFIndices, MPIU_INT, &findices);CHKERRQ(ierr);
7355   ierr = DMGetWorkArray(dmc, numCIndices, MPIU_INT, &cindices);CHKERRQ(ierr);
7356   if (numFields) {
7357     const PetscInt **permsF[32] = {NULL};
7358     const PetscInt **permsC[32] = {NULL};
7359 
7360     for (f = 0; f < numFields; f++) {
7361       ierr = PetscSectionGetFieldPointSyms(fsection,f,numFPoints,ftotpoints,&permsF[f],NULL);CHKERRQ(ierr);
7362       ierr = PetscSectionGetFieldPointSyms(csection,f,numCPoints,cpoints,&permsC[f],NULL);CHKERRQ(ierr);
7363     }
7364     for (p = 0; p < numFPoints; p++) {
7365       ierr = PetscSectionGetOffset(globalFSection, ftotpoints[2*p], &globalOff);CHKERRQ(ierr);
7366       ierr = DMPlexGetIndicesPointFields_Internal(fsection, PETSC_FALSE, ftotpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, foffsets, PETSC_FALSE, permsF, p, fclperm, findices);CHKERRQ(ierr);
7367     }
7368     for (p = 0; p < numCPoints; p++) {
7369       ierr = PetscSectionGetOffset(globalCSection, cpoints[2*p], &globalOff);CHKERRQ(ierr);
7370       ierr = DMPlexGetIndicesPointFields_Internal(csection, PETSC_FALSE, cpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cclperm, cindices);CHKERRQ(ierr);
7371     }
7372     for (f = 0; f < numFields; f++) {
7373       ierr = PetscSectionRestoreFieldPointSyms(fsection,f,numFPoints,ftotpoints,&permsF[f],NULL);CHKERRQ(ierr);
7374       ierr = PetscSectionRestoreFieldPointSyms(csection,f,numCPoints,cpoints,&permsC[f],NULL);CHKERRQ(ierr);
7375     }
7376   } else {
7377     const PetscInt **permsF = NULL;
7378     const PetscInt **permsC = NULL;
7379 
7380     ierr = PetscSectionGetPointSyms(fsection,numFPoints,ftotpoints,&permsF,NULL);CHKERRQ(ierr);
7381     ierr = PetscSectionGetPointSyms(csection,numCPoints,cpoints,&permsC,NULL);CHKERRQ(ierr);
7382     for (p = 0, off = 0; p < numFPoints; p++) {
7383       const PetscInt *perm = permsF ? permsF[p] : NULL;
7384 
7385       ierr = PetscSectionGetOffset(globalFSection, ftotpoints[2*p], &globalOff);CHKERRQ(ierr);
7386       ierr = DMPlexGetIndicesPoint_Internal(fsection, PETSC_FALSE, ftotpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, fclperm, findices);CHKERRQ(ierr);
7387     }
7388     for (p = 0, off = 0; p < numCPoints; p++) {
7389       const PetscInt *perm = permsC ? permsC[p] : NULL;
7390 
7391       ierr = PetscSectionGetOffset(globalCSection, cpoints[2*p], &globalOff);CHKERRQ(ierr);
7392       ierr = DMPlexGetIndicesPoint_Internal(csection, PETSC_FALSE, cpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, cclperm, cindices);CHKERRQ(ierr);
7393     }
7394     ierr = PetscSectionRestorePointSyms(fsection,numFPoints,ftotpoints,&permsF,NULL);CHKERRQ(ierr);
7395     ierr = PetscSectionRestorePointSyms(csection,numCPoints,cpoints,&permsC,NULL);CHKERRQ(ierr);
7396   }
7397   if (mesh->printSetValues) {ierr = DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numFIndices, findices, numCIndices, cindices, values);CHKERRQ(ierr);}
7398   /* TODO: flips */
7399   ierr = MatSetValues(A, numFIndices, findices, numCIndices, cindices, values, mode);
7400   if (ierr) {
7401     PetscMPIInt    rank;
7402     PetscErrorCode ierr2;
7403 
7404     ierr2 = MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank);CHKERRMPI(ierr2);
7405     ierr2 = (*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank);CHKERRQ(ierr2);
7406     ierr2 = DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numFIndices, findices, numCIndices, cindices, values);CHKERRQ(ierr2);
7407     ierr2 = DMRestoreWorkArray(dmf, numFIndices, MPIU_INT, &findices);CHKERRQ(ierr2);
7408     ierr2 = DMRestoreWorkArray(dmc, numCIndices, MPIU_INT, &cindices);CHKERRQ(ierr2);
7409     CHKERRQ(ierr);
7410   }
7411   ierr = DMRestoreWorkArray(dmf, numCPoints*2*4, MPIU_INT, &ftotpoints);CHKERRQ(ierr);
7412   ierr = DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints);CHKERRQ(ierr);
7413   ierr = DMRestoreWorkArray(dmf, numFIndices, MPIU_INT, &findices);CHKERRQ(ierr);
7414   ierr = DMRestoreWorkArray(dmc, numCIndices, MPIU_INT, &cindices);CHKERRQ(ierr);
7415   PetscFunctionReturn(0);
7416 }
7417 
7418 PetscErrorCode DMPlexMatGetClosureIndicesRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, PetscInt point, PetscInt cindices[], PetscInt findices[])
7419 {
7420   PetscInt      *fpoints = NULL, *ftotpoints = NULL;
7421   PetscInt      *cpoints = NULL;
7422   PetscInt       foffsets[32], coffsets[32];
7423   const PetscInt *fclperm = NULL, *cclperm = NULL; /* Closure permutations cannot work here */
7424   DMPolytopeType ct;
7425   PetscInt       numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f;
7426   PetscErrorCode ierr;
7427 
7428   PetscFunctionBegin;
7429   PetscValidHeaderSpecific(dmf, DM_CLASSID, 1);
7430   PetscValidHeaderSpecific(dmc, DM_CLASSID, 4);
7431   if (!fsection) {ierr = DMGetLocalSection(dmf, &fsection);CHKERRQ(ierr);}
7432   PetscValidHeaderSpecific(fsection, PETSC_SECTION_CLASSID, 2);
7433   if (!csection) {ierr = DMGetLocalSection(dmc, &csection);CHKERRQ(ierr);}
7434   PetscValidHeaderSpecific(csection, PETSC_SECTION_CLASSID, 5);
7435   if (!globalFSection) {ierr = DMGetGlobalSection(dmf, &globalFSection);CHKERRQ(ierr);}
7436   PetscValidHeaderSpecific(globalFSection, PETSC_SECTION_CLASSID, 3);
7437   if (!globalCSection) {ierr = DMGetGlobalSection(dmc, &globalCSection);CHKERRQ(ierr);}
7438   PetscValidHeaderSpecific(globalCSection, PETSC_SECTION_CLASSID, 6);
7439   ierr = PetscSectionGetNumFields(fsection, &numFields);CHKERRQ(ierr);
7440   if (numFields > 31) SETERRQ1(PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
7441   ierr = PetscArrayzero(foffsets, 32);CHKERRQ(ierr);
7442   ierr = PetscArrayzero(coffsets, 32);CHKERRQ(ierr);
7443   /* Column indices */
7444   ierr = DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints);CHKERRQ(ierr);
7445   maxFPoints = numCPoints;
7446   /* Compress out points not in the section */
7447   /*   TODO: Squeeze out points with 0 dof as well */
7448   ierr = PetscSectionGetChart(csection, &pStart, &pEnd);CHKERRQ(ierr);
7449   for (p = 0, q = 0; p < numCPoints*2; p += 2) {
7450     if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) {
7451       cpoints[q*2]   = cpoints[p];
7452       cpoints[q*2+1] = cpoints[p+1];
7453       ++q;
7454     }
7455   }
7456   numCPoints = q;
7457   for (p = 0, numCIndices = 0; p < numCPoints*2; p += 2) {
7458     PetscInt fdof;
7459 
7460     ierr = PetscSectionGetDof(csection, cpoints[p], &dof);CHKERRQ(ierr);
7461     if (!dof) continue;
7462     for (f = 0; f < numFields; ++f) {
7463       ierr           = PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof);CHKERRQ(ierr);
7464       coffsets[f+1] += fdof;
7465     }
7466     numCIndices += dof;
7467   }
7468   for (f = 1; f < numFields; ++f) coffsets[f+1] += coffsets[f];
7469   /* Row indices */
7470   ierr = DMPlexGetCellType(dmc, point, &ct);CHKERRQ(ierr);
7471   {
7472     DMPlexCellRefiner cr;
7473     ierr = DMPlexCellRefinerCreate(dmc, &cr);CHKERRQ(ierr);
7474     ierr = DMPlexCellRefinerGetAffineTransforms(cr, ct, &numSubcells, NULL, NULL, NULL);CHKERRQ(ierr);
7475     ierr = DMPlexCellRefinerDestroy(&cr);CHKERRQ(ierr);
7476   }
7477   ierr = DMGetWorkArray(dmf, maxFPoints*2*numSubcells, MPIU_INT, &ftotpoints);CHKERRQ(ierr);
7478   for (r = 0, q = 0; r < numSubcells; ++r) {
7479     /* TODO Map from coarse to fine cells */
7480     ierr = DMPlexGetTransitiveClosure(dmf, point*numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints);CHKERRQ(ierr);
7481     /* Compress out points not in the section */
7482     ierr = PetscSectionGetChart(fsection, &pStart, &pEnd);CHKERRQ(ierr);
7483     for (p = 0; p < numFPoints*2; p += 2) {
7484       if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) {
7485         ierr = PetscSectionGetDof(fsection, fpoints[p], &dof);CHKERRQ(ierr);
7486         if (!dof) continue;
7487         for (s = 0; s < q; ++s) if (fpoints[p] == ftotpoints[s*2]) break;
7488         if (s < q) continue;
7489         ftotpoints[q*2]   = fpoints[p];
7490         ftotpoints[q*2+1] = fpoints[p+1];
7491         ++q;
7492       }
7493     }
7494     ierr = DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints);CHKERRQ(ierr);
7495   }
7496   numFPoints = q;
7497   for (p = 0, numFIndices = 0; p < numFPoints*2; p += 2) {
7498     PetscInt fdof;
7499 
7500     ierr = PetscSectionGetDof(fsection, ftotpoints[p], &dof);CHKERRQ(ierr);
7501     if (!dof) continue;
7502     for (f = 0; f < numFields; ++f) {
7503       ierr           = PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof);CHKERRQ(ierr);
7504       foffsets[f+1] += fdof;
7505     }
7506     numFIndices += dof;
7507   }
7508   for (f = 1; f < numFields; ++f) foffsets[f+1] += foffsets[f];
7509 
7510   if (numFields && foffsets[numFields] != numFIndices) SETERRQ2(PetscObjectComm((PetscObject)dmf), PETSC_ERR_PLIB, "Invalid size for closure %D should be %D", foffsets[numFields], numFIndices);
7511   if (numFields && coffsets[numFields] != numCIndices) SETERRQ2(PetscObjectComm((PetscObject)dmc), PETSC_ERR_PLIB, "Invalid size for closure %D should be %D", coffsets[numFields], numCIndices);
7512   if (numFields) {
7513     const PetscInt **permsF[32] = {NULL};
7514     const PetscInt **permsC[32] = {NULL};
7515 
7516     for (f = 0; f < numFields; f++) {
7517       ierr = PetscSectionGetFieldPointSyms(fsection,f,numFPoints,ftotpoints,&permsF[f],NULL);CHKERRQ(ierr);
7518       ierr = PetscSectionGetFieldPointSyms(csection,f,numCPoints,cpoints,&permsC[f],NULL);CHKERRQ(ierr);
7519     }
7520     for (p = 0; p < numFPoints; p++) {
7521       ierr = PetscSectionGetOffset(globalFSection, ftotpoints[2*p], &globalOff);CHKERRQ(ierr);
7522       ierr = DMPlexGetIndicesPointFields_Internal(fsection, PETSC_FALSE, ftotpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, foffsets, PETSC_FALSE, permsF, p, fclperm, findices);CHKERRQ(ierr);
7523     }
7524     for (p = 0; p < numCPoints; p++) {
7525       ierr = PetscSectionGetOffset(globalCSection, cpoints[2*p], &globalOff);CHKERRQ(ierr);
7526       ierr = DMPlexGetIndicesPointFields_Internal(csection, PETSC_FALSE, cpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cclperm, cindices);CHKERRQ(ierr);
7527     }
7528     for (f = 0; f < numFields; f++) {
7529       ierr = PetscSectionRestoreFieldPointSyms(fsection,f,numFPoints,ftotpoints,&permsF[f],NULL);CHKERRQ(ierr);
7530       ierr = PetscSectionRestoreFieldPointSyms(csection,f,numCPoints,cpoints,&permsC[f],NULL);CHKERRQ(ierr);
7531     }
7532   } else {
7533     const PetscInt **permsF = NULL;
7534     const PetscInt **permsC = NULL;
7535 
7536     ierr = PetscSectionGetPointSyms(fsection,numFPoints,ftotpoints,&permsF,NULL);CHKERRQ(ierr);
7537     ierr = PetscSectionGetPointSyms(csection,numCPoints,cpoints,&permsC,NULL);CHKERRQ(ierr);
7538     for (p = 0, off = 0; p < numFPoints; p++) {
7539       const PetscInt *perm = permsF ? permsF[p] : NULL;
7540 
7541       ierr = PetscSectionGetOffset(globalFSection, ftotpoints[2*p], &globalOff);CHKERRQ(ierr);
7542       ierr = DMPlexGetIndicesPoint_Internal(fsection, PETSC_FALSE, ftotpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, fclperm, findices);CHKERRQ(ierr);
7543     }
7544     for (p = 0, off = 0; p < numCPoints; p++) {
7545       const PetscInt *perm = permsC ? permsC[p] : NULL;
7546 
7547       ierr = PetscSectionGetOffset(globalCSection, cpoints[2*p], &globalOff);CHKERRQ(ierr);
7548       ierr = DMPlexGetIndicesPoint_Internal(csection, PETSC_FALSE, cpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, cclperm, cindices);CHKERRQ(ierr);
7549     }
7550     ierr = PetscSectionRestorePointSyms(fsection,numFPoints,ftotpoints,&permsF,NULL);CHKERRQ(ierr);
7551     ierr = PetscSectionRestorePointSyms(csection,numCPoints,cpoints,&permsC,NULL);CHKERRQ(ierr);
7552   }
7553   ierr = DMRestoreWorkArray(dmf, numCPoints*2*4, MPIU_INT, &ftotpoints);CHKERRQ(ierr);
7554   ierr = DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints);CHKERRQ(ierr);
7555   PetscFunctionReturn(0);
7556 }
7557 
7558 /*@C
7559   DMPlexGetVTKCellHeight - Returns the height in the DAG used to determine which points are cells (normally 0)
7560 
7561   Input Parameter:
7562 . dm   - The DMPlex object
7563 
7564   Output Parameter:
7565 . cellHeight - The height of a cell
7566 
7567   Level: developer
7568 
7569 .seealso DMPlexSetVTKCellHeight()
7570 @*/
7571 PetscErrorCode DMPlexGetVTKCellHeight(DM dm, PetscInt *cellHeight)
7572 {
7573   DM_Plex *mesh = (DM_Plex*) dm->data;
7574 
7575   PetscFunctionBegin;
7576   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7577   PetscValidPointer(cellHeight, 2);
7578   *cellHeight = mesh->vtkCellHeight;
7579   PetscFunctionReturn(0);
7580 }
7581 
7582 /*@C
7583   DMPlexSetVTKCellHeight - Sets the height in the DAG used to determine which points are cells (normally 0)
7584 
7585   Input Parameters:
7586 + dm   - The DMPlex object
7587 - cellHeight - The height of a cell
7588 
7589   Level: developer
7590 
7591 .seealso DMPlexGetVTKCellHeight()
7592 @*/
7593 PetscErrorCode DMPlexSetVTKCellHeight(DM dm, PetscInt cellHeight)
7594 {
7595   DM_Plex *mesh = (DM_Plex*) dm->data;
7596 
7597   PetscFunctionBegin;
7598   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7599   mesh->vtkCellHeight = cellHeight;
7600   PetscFunctionReturn(0);
7601 }
7602 
7603 /*@
7604   DMPlexGetGhostCellStratum - Get the range of cells which are used to enforce FV boundary conditions
7605 
7606   Input Parameter:
7607 . dm - The DMPlex object
7608 
7609   Output Parameters:
7610 + gcStart - The first ghost cell, or NULL
7611 - gcEnd   - The upper bound on ghost cells, or NULL
7612 
7613   Level: advanced
7614 
7615 .seealso DMPlexConstructGhostCells(), DMPlexGetGhostCellStratum()
7616 @*/
7617 PetscErrorCode DMPlexGetGhostCellStratum(DM dm, PetscInt *gcStart, PetscInt *gcEnd)
7618 {
7619   DMLabel        ctLabel;
7620   PetscErrorCode ierr;
7621 
7622   PetscFunctionBegin;
7623   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7624   ierr = DMPlexGetCellTypeLabel(dm, &ctLabel);CHKERRQ(ierr);
7625   ierr = DMLabelGetStratumBounds(ctLabel, DM_POLYTOPE_FV_GHOST, gcStart, gcEnd);CHKERRQ(ierr);
7626   PetscFunctionReturn(0);
7627 }
7628 
7629 /* We can easily have a form that takes an IS instead */
7630 PetscErrorCode DMPlexCreateNumbering_Plex(DM dm, PetscInt pStart, PetscInt pEnd, PetscInt shift, PetscInt *globalSize, PetscSF sf, IS *numbering)
7631 {
7632   PetscSection   section, globalSection;
7633   PetscInt      *numbers, p;
7634   PetscErrorCode ierr;
7635 
7636   PetscFunctionBegin;
7637   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)dm), &section);CHKERRQ(ierr);
7638   ierr = PetscSectionSetChart(section, pStart, pEnd);CHKERRQ(ierr);
7639   for (p = pStart; p < pEnd; ++p) {
7640     ierr = PetscSectionSetDof(section, p, 1);CHKERRQ(ierr);
7641   }
7642   ierr = PetscSectionSetUp(section);CHKERRQ(ierr);
7643   ierr = PetscSectionCreateGlobalSection(section, sf, PETSC_FALSE, PETSC_FALSE, &globalSection);CHKERRQ(ierr);
7644   ierr = PetscMalloc1(pEnd - pStart, &numbers);CHKERRQ(ierr);
7645   for (p = pStart; p < pEnd; ++p) {
7646     ierr = PetscSectionGetOffset(globalSection, p, &numbers[p-pStart]);CHKERRQ(ierr);
7647     if (numbers[p-pStart] < 0) numbers[p-pStart] -= shift;
7648     else                       numbers[p-pStart] += shift;
7649   }
7650   ierr = ISCreateGeneral(PetscObjectComm((PetscObject) dm), pEnd - pStart, numbers, PETSC_OWN_POINTER, numbering);CHKERRQ(ierr);
7651   if (globalSize) {
7652     PetscLayout layout;
7653     ierr = PetscSectionGetPointLayout(PetscObjectComm((PetscObject) dm), globalSection, &layout);CHKERRQ(ierr);
7654     ierr = PetscLayoutGetSize(layout, globalSize);CHKERRQ(ierr);
7655     ierr = PetscLayoutDestroy(&layout);CHKERRQ(ierr);
7656   }
7657   ierr = PetscSectionDestroy(&section);CHKERRQ(ierr);
7658   ierr = PetscSectionDestroy(&globalSection);CHKERRQ(ierr);
7659   PetscFunctionReturn(0);
7660 }
7661 
7662 PetscErrorCode DMPlexCreateCellNumbering_Internal(DM dm, PetscBool includeHybrid, IS *globalCellNumbers)
7663 {
7664   PetscInt       cellHeight, cStart, cEnd;
7665   PetscErrorCode ierr;
7666 
7667   PetscFunctionBegin;
7668   ierr = DMPlexGetVTKCellHeight(dm, &cellHeight);CHKERRQ(ierr);
7669   if (includeHybrid) {ierr = DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd);CHKERRQ(ierr);}
7670   else               {ierr = DMPlexGetSimplexOrBoxCells(dm, cellHeight, &cStart, &cEnd);CHKERRQ(ierr);}
7671   ierr = DMPlexCreateNumbering_Plex(dm, cStart, cEnd, 0, NULL, dm->sf, globalCellNumbers);CHKERRQ(ierr);
7672   PetscFunctionReturn(0);
7673 }
7674 
7675 /*@
7676   DMPlexGetCellNumbering - Get a global cell numbering for all cells on this process
7677 
7678   Input Parameter:
7679 . dm   - The DMPlex object
7680 
7681   Output Parameter:
7682 . globalCellNumbers - Global cell numbers for all cells on this process
7683 
7684   Level: developer
7685 
7686 .seealso DMPlexGetVertexNumbering()
7687 @*/
7688 PetscErrorCode DMPlexGetCellNumbering(DM dm, IS *globalCellNumbers)
7689 {
7690   DM_Plex       *mesh = (DM_Plex*) dm->data;
7691   PetscErrorCode ierr;
7692 
7693   PetscFunctionBegin;
7694   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7695   if (!mesh->globalCellNumbers) {ierr = DMPlexCreateCellNumbering_Internal(dm, PETSC_FALSE, &mesh->globalCellNumbers);CHKERRQ(ierr);}
7696   *globalCellNumbers = mesh->globalCellNumbers;
7697   PetscFunctionReturn(0);
7698 }
7699 
7700 PetscErrorCode DMPlexCreateVertexNumbering_Internal(DM dm, PetscBool includeHybrid, IS *globalVertexNumbers)
7701 {
7702   PetscInt       vStart, vEnd;
7703   PetscErrorCode ierr;
7704 
7705   PetscFunctionBegin;
7706   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7707   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
7708   ierr = DMPlexCreateNumbering_Plex(dm, vStart, vEnd, 0, NULL, dm->sf, globalVertexNumbers);CHKERRQ(ierr);
7709   PetscFunctionReturn(0);
7710 }
7711 
7712 /*@
7713   DMPlexGetVertexNumbering - Get a global vertex numbering for all vertices on this process
7714 
7715   Input Parameter:
7716 . dm   - The DMPlex object
7717 
7718   Output Parameter:
7719 . globalVertexNumbers - Global vertex numbers for all vertices on this process
7720 
7721   Level: developer
7722 
7723 .seealso DMPlexGetCellNumbering()
7724 @*/
7725 PetscErrorCode DMPlexGetVertexNumbering(DM dm, IS *globalVertexNumbers)
7726 {
7727   DM_Plex       *mesh = (DM_Plex*) dm->data;
7728   PetscErrorCode ierr;
7729 
7730   PetscFunctionBegin;
7731   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7732   if (!mesh->globalVertexNumbers) {ierr = DMPlexCreateVertexNumbering_Internal(dm, PETSC_FALSE, &mesh->globalVertexNumbers);CHKERRQ(ierr);}
7733   *globalVertexNumbers = mesh->globalVertexNumbers;
7734   PetscFunctionReturn(0);
7735 }
7736 
7737 /*@
7738   DMPlexCreatePointNumbering - Create a global numbering for all points on this process
7739 
7740   Input Parameter:
7741 . dm   - The DMPlex object
7742 
7743   Output Parameter:
7744 . globalPointNumbers - Global numbers for all points on this process
7745 
7746   Level: developer
7747 
7748 .seealso DMPlexGetCellNumbering()
7749 @*/
7750 PetscErrorCode DMPlexCreatePointNumbering(DM dm, IS *globalPointNumbers)
7751 {
7752   IS             nums[4];
7753   PetscInt       depths[4], gdepths[4], starts[4];
7754   PetscInt       depth, d, shift = 0;
7755   PetscErrorCode ierr;
7756 
7757   PetscFunctionBegin;
7758   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7759   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
7760   /* For unstratified meshes use dim instead of depth */
7761   if (depth < 0) {ierr = DMGetDimension(dm, &depth);CHKERRQ(ierr);}
7762   for (d = 0; d <= depth; ++d) {
7763     PetscInt end;
7764 
7765     depths[d] = depth-d;
7766     ierr = DMPlexGetDepthStratum(dm, depths[d], &starts[d], &end);CHKERRQ(ierr);
7767     if (!(starts[d]-end)) { starts[d] = depths[d] = -1; }
7768   }
7769   ierr = PetscSortIntWithArray(depth+1, starts, depths);CHKERRQ(ierr);
7770   ierr = MPIU_Allreduce(depths, gdepths, depth+1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject) dm));CHKERRMPI(ierr);
7771   for (d = 0; d <= depth; ++d) {
7772     if (starts[d] >= 0 && depths[d] != gdepths[d]) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Expected depth %D, found %D",depths[d],gdepths[d]);
7773   }
7774   for (d = 0; d <= depth; ++d) {
7775     PetscInt pStart, pEnd, gsize;
7776 
7777     ierr = DMPlexGetDepthStratum(dm, gdepths[d], &pStart, &pEnd);CHKERRQ(ierr);
7778     ierr = DMPlexCreateNumbering_Plex(dm, pStart, pEnd, shift, &gsize, dm->sf, &nums[d]);CHKERRQ(ierr);
7779     shift += gsize;
7780   }
7781   ierr = ISConcatenate(PetscObjectComm((PetscObject) dm), depth+1, nums, globalPointNumbers);CHKERRQ(ierr);
7782   for (d = 0; d <= depth; ++d) {ierr = ISDestroy(&nums[d]);CHKERRQ(ierr);}
7783   PetscFunctionReturn(0);
7784 }
7785 
7786 /*@
7787   DMPlexCreateRankField - Create a cell field whose value is the rank of the owner
7788 
7789   Input Parameter:
7790 . dm - The DMPlex object
7791 
7792   Output Parameter:
7793 . ranks - The rank field
7794 
7795   Options Database Keys:
7796 . -dm_partition_view - Adds the rank field into the DM output from -dm_view using the same viewer
7797 
7798   Level: intermediate
7799 
7800 .seealso: DMView()
7801 @*/
7802 PetscErrorCode DMPlexCreateRankField(DM dm, Vec *ranks)
7803 {
7804   DM             rdm;
7805   PetscFE        fe;
7806   PetscScalar   *r;
7807   PetscMPIInt    rank;
7808   DMPolytopeType ct;
7809   PetscInt       dim, cStart, cEnd, c;
7810   PetscBool      simplex;
7811   PetscErrorCode ierr;
7812 
7813   PetscFunctionBeginUser;
7814   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7815   PetscValidPointer(ranks, 2);
7816   ierr = MPI_Comm_rank(PetscObjectComm((PetscObject) dm), &rank);CHKERRMPI(ierr);
7817   ierr = DMClone(dm, &rdm);CHKERRQ(ierr);
7818   ierr = DMGetDimension(rdm, &dim);CHKERRQ(ierr);
7819   ierr = DMPlexGetHeightStratum(rdm, 0, &cStart, &cEnd);CHKERRQ(ierr);
7820   ierr = DMPlexGetCellType(dm, cStart, &ct);CHKERRQ(ierr);
7821   simplex = DMPolytopeTypeGetNumVertices(ct) == DMPolytopeTypeGetDim(ct)+1 ? PETSC_TRUE : PETSC_FALSE;
7822   ierr = PetscFECreateDefault(PETSC_COMM_SELF, dim, 1, simplex, "PETSc___rank_", -1, &fe);CHKERRQ(ierr);
7823   ierr = PetscObjectSetName((PetscObject) fe, "rank");CHKERRQ(ierr);
7824   ierr = DMSetField(rdm, 0, NULL, (PetscObject) fe);CHKERRQ(ierr);
7825   ierr = PetscFEDestroy(&fe);CHKERRQ(ierr);
7826   ierr = DMCreateDS(rdm);CHKERRQ(ierr);
7827   ierr = DMCreateGlobalVector(rdm, ranks);CHKERRQ(ierr);
7828   ierr = PetscObjectSetName((PetscObject) *ranks, "partition");CHKERRQ(ierr);
7829   ierr = VecGetArray(*ranks, &r);CHKERRQ(ierr);
7830   for (c = cStart; c < cEnd; ++c) {
7831     PetscScalar *lr;
7832 
7833     ierr = DMPlexPointGlobalRef(rdm, c, r, &lr);CHKERRQ(ierr);
7834     if (lr) *lr = rank;
7835   }
7836   ierr = VecRestoreArray(*ranks, &r);CHKERRQ(ierr);
7837   ierr = DMDestroy(&rdm);CHKERRQ(ierr);
7838   PetscFunctionReturn(0);
7839 }
7840 
7841 /*@
7842   DMPlexCreateLabelField - Create a cell field whose value is the label value for that cell
7843 
7844   Input Parameters:
7845 + dm    - The DMPlex
7846 - label - The DMLabel
7847 
7848   Output Parameter:
7849 . val - The label value field
7850 
7851   Options Database Keys:
7852 . -dm_label_view - Adds the label value field into the DM output from -dm_view using the same viewer
7853 
7854   Level: intermediate
7855 
7856 .seealso: DMView()
7857 @*/
7858 PetscErrorCode DMPlexCreateLabelField(DM dm, DMLabel label, Vec *val)
7859 {
7860   DM             rdm;
7861   PetscFE        fe;
7862   PetscScalar   *v;
7863   PetscInt       dim, cStart, cEnd, c;
7864   PetscErrorCode ierr;
7865 
7866   PetscFunctionBeginUser;
7867   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7868   PetscValidPointer(label, 2);
7869   PetscValidPointer(val, 3);
7870   ierr = DMClone(dm, &rdm);CHKERRQ(ierr);
7871   ierr = DMGetDimension(rdm, &dim);CHKERRQ(ierr);
7872   ierr = PetscFECreateDefault(PetscObjectComm((PetscObject) rdm), dim, 1, PETSC_TRUE, "PETSc___label_value_", -1, &fe);CHKERRQ(ierr);
7873   ierr = PetscObjectSetName((PetscObject) fe, "label_value");CHKERRQ(ierr);
7874   ierr = DMSetField(rdm, 0, NULL, (PetscObject) fe);CHKERRQ(ierr);
7875   ierr = PetscFEDestroy(&fe);CHKERRQ(ierr);
7876   ierr = DMCreateDS(rdm);CHKERRQ(ierr);
7877   ierr = DMPlexGetHeightStratum(rdm, 0, &cStart, &cEnd);CHKERRQ(ierr);
7878   ierr = DMCreateGlobalVector(rdm, val);CHKERRQ(ierr);
7879   ierr = PetscObjectSetName((PetscObject) *val, "label_value");CHKERRQ(ierr);
7880   ierr = VecGetArray(*val, &v);CHKERRQ(ierr);
7881   for (c = cStart; c < cEnd; ++c) {
7882     PetscScalar *lv;
7883     PetscInt     cval;
7884 
7885     ierr = DMPlexPointGlobalRef(rdm, c, v, &lv);CHKERRQ(ierr);
7886     ierr = DMLabelGetValue(label, c, &cval);CHKERRQ(ierr);
7887     *lv = cval;
7888   }
7889   ierr = VecRestoreArray(*val, &v);CHKERRQ(ierr);
7890   ierr = DMDestroy(&rdm);CHKERRQ(ierr);
7891   PetscFunctionReturn(0);
7892 }
7893 
7894 /*@
7895   DMPlexCheckSymmetry - Check that the adjacency information in the mesh is symmetric.
7896 
7897   Input Parameter:
7898 . dm - The DMPlex object
7899 
7900   Notes:
7901   This is a useful diagnostic when creating meshes programmatically.
7902 
7903   For the complete list of DMPlexCheck* functions, see DMSetFromOptions().
7904 
7905   Level: developer
7906 
7907 .seealso: DMCreate(), DMSetFromOptions()
7908 @*/
7909 PetscErrorCode DMPlexCheckSymmetry(DM dm)
7910 {
7911   PetscSection    coneSection, supportSection;
7912   const PetscInt *cone, *support;
7913   PetscInt        coneSize, c, supportSize, s;
7914   PetscInt        pStart, pEnd, p, pp, csize, ssize;
7915   PetscBool       storagecheck = PETSC_TRUE;
7916   PetscErrorCode  ierr;
7917 
7918   PetscFunctionBegin;
7919   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7920   ierr = DMViewFromOptions(dm, NULL, "-sym_dm_view");CHKERRQ(ierr);
7921   ierr = DMPlexGetConeSection(dm, &coneSection);CHKERRQ(ierr);
7922   ierr = DMPlexGetSupportSection(dm, &supportSection);CHKERRQ(ierr);
7923   /* Check that point p is found in the support of its cone points, and vice versa */
7924   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
7925   for (p = pStart; p < pEnd; ++p) {
7926     ierr = DMPlexGetConeSize(dm, p, &coneSize);CHKERRQ(ierr);
7927     ierr = DMPlexGetCone(dm, p, &cone);CHKERRQ(ierr);
7928     for (c = 0; c < coneSize; ++c) {
7929       PetscBool dup = PETSC_FALSE;
7930       PetscInt  d;
7931       for (d = c-1; d >= 0; --d) {
7932         if (cone[c] == cone[d]) {dup = PETSC_TRUE; break;}
7933       }
7934       ierr = DMPlexGetSupportSize(dm, cone[c], &supportSize);CHKERRQ(ierr);
7935       ierr = DMPlexGetSupport(dm, cone[c], &support);CHKERRQ(ierr);
7936       for (s = 0; s < supportSize; ++s) {
7937         if (support[s] == p) break;
7938       }
7939       if ((s >= supportSize) || (dup && (support[s+1] != p))) {
7940         ierr = PetscPrintf(PETSC_COMM_SELF, "p: %D cone: ", p);CHKERRQ(ierr);
7941         for (s = 0; s < coneSize; ++s) {
7942           ierr = PetscPrintf(PETSC_COMM_SELF, "%D, ", cone[s]);CHKERRQ(ierr);
7943         }
7944         ierr = PetscPrintf(PETSC_COMM_SELF, "\n");CHKERRQ(ierr);
7945         ierr = PetscPrintf(PETSC_COMM_SELF, "p: %D support: ", cone[c]);CHKERRQ(ierr);
7946         for (s = 0; s < supportSize; ++s) {
7947           ierr = PetscPrintf(PETSC_COMM_SELF, "%D, ", support[s]);CHKERRQ(ierr);
7948         }
7949         ierr = PetscPrintf(PETSC_COMM_SELF, "\n");CHKERRQ(ierr);
7950         if (dup) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D not repeatedly found in support of repeated cone point %D", p, cone[c]);
7951         else SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D not found in support of cone point %D", p, cone[c]);
7952       }
7953     }
7954     ierr = DMPlexGetTreeParent(dm, p, &pp, NULL);CHKERRQ(ierr);
7955     if (p != pp) { storagecheck = PETSC_FALSE; continue; }
7956     ierr = DMPlexGetSupportSize(dm, p, &supportSize);CHKERRQ(ierr);
7957     ierr = DMPlexGetSupport(dm, p, &support);CHKERRQ(ierr);
7958     for (s = 0; s < supportSize; ++s) {
7959       ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
7960       ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
7961       for (c = 0; c < coneSize; ++c) {
7962         ierr = DMPlexGetTreeParent(dm, cone[c], &pp, NULL);CHKERRQ(ierr);
7963         if (cone[c] != pp) { c = 0; break; }
7964         if (cone[c] == p) break;
7965       }
7966       if (c >= coneSize) {
7967         ierr = PetscPrintf(PETSC_COMM_SELF, "p: %D support: ", p);CHKERRQ(ierr);
7968         for (c = 0; c < supportSize; ++c) {
7969           ierr = PetscPrintf(PETSC_COMM_SELF, "%D, ", support[c]);CHKERRQ(ierr);
7970         }
7971         ierr = PetscPrintf(PETSC_COMM_SELF, "\n");CHKERRQ(ierr);
7972         ierr = PetscPrintf(PETSC_COMM_SELF, "p: %D cone: ", support[s]);CHKERRQ(ierr);
7973         for (c = 0; c < coneSize; ++c) {
7974           ierr = PetscPrintf(PETSC_COMM_SELF, "%D, ", cone[c]);CHKERRQ(ierr);
7975         }
7976         ierr = PetscPrintf(PETSC_COMM_SELF, "\n");CHKERRQ(ierr);
7977         SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D not found in cone of support point %D", p, support[s]);
7978       }
7979     }
7980   }
7981   if (storagecheck) {
7982     ierr = PetscSectionGetStorageSize(coneSection, &csize);CHKERRQ(ierr);
7983     ierr = PetscSectionGetStorageSize(supportSection, &ssize);CHKERRQ(ierr);
7984     if (csize != ssize) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Total cone size %D != Total support size %D", csize, ssize);
7985   }
7986   PetscFunctionReturn(0);
7987 }
7988 
7989 /*
7990   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.
7991 */
7992 static PetscErrorCode DMPlexCellUnsplitVertices_Private(DM dm, PetscInt c, DMPolytopeType ct, PetscInt *unsplit)
7993 {
7994   DMPolytopeType  cct;
7995   PetscInt        ptpoints[4];
7996   const PetscInt *cone, *ccone, *ptcone;
7997   PetscInt        coneSize, cp, cconeSize, ccp, npt = 0, pt;
7998   PetscErrorCode  ierr;
7999 
8000   PetscFunctionBegin;
8001   *unsplit = 0;
8002   switch (ct) {
8003     case DM_POLYTOPE_SEG_PRISM_TENSOR:
8004       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
8005       ierr = DMPlexGetConeSize(dm, c, &coneSize);CHKERRQ(ierr);
8006       for (cp = 0; cp < coneSize; ++cp) {
8007         ierr = DMPlexGetCellType(dm, cone[cp], &cct);CHKERRQ(ierr);
8008         if (cct == DM_POLYTOPE_POINT_PRISM_TENSOR) ptpoints[npt++] = cone[cp];
8009       }
8010       break;
8011     case DM_POLYTOPE_TRI_PRISM_TENSOR:
8012     case DM_POLYTOPE_QUAD_PRISM_TENSOR:
8013       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
8014       ierr = DMPlexGetConeSize(dm, c, &coneSize);CHKERRQ(ierr);
8015       for (cp = 0; cp < coneSize; ++cp) {
8016         ierr = DMPlexGetCone(dm, cone[cp], &ccone);CHKERRQ(ierr);
8017         ierr = DMPlexGetConeSize(dm, cone[cp], &cconeSize);CHKERRQ(ierr);
8018         for (ccp = 0; ccp < cconeSize; ++ccp) {
8019           ierr = DMPlexGetCellType(dm, ccone[ccp], &cct);CHKERRQ(ierr);
8020           if (cct == DM_POLYTOPE_POINT_PRISM_TENSOR) {
8021             PetscInt p;
8022             for (p = 0; p < npt; ++p) if (ptpoints[p] == ccone[ccp]) break;
8023             if (p == npt) ptpoints[npt++] = ccone[ccp];
8024           }
8025         }
8026       }
8027       break;
8028     default: break;
8029   }
8030   for (pt = 0; pt < npt; ++pt) {
8031     ierr = DMPlexGetCone(dm, ptpoints[pt], &ptcone);CHKERRQ(ierr);
8032     if (ptcone[0] == ptcone[1]) ++(*unsplit);
8033   }
8034   PetscFunctionReturn(0);
8035 }
8036 
8037 /*@
8038   DMPlexCheckSkeleton - Check that each cell has the correct number of vertices
8039 
8040   Input Parameters:
8041 + dm - The DMPlex object
8042 - cellHeight - Normally 0
8043 
8044   Notes:
8045   This is a useful diagnostic when creating meshes programmatically.
8046   Currently applicable only to homogeneous simplex or tensor meshes.
8047 
8048   For the complete list of DMPlexCheck* functions, see DMSetFromOptions().
8049 
8050   Level: developer
8051 
8052 .seealso: DMCreate(), DMSetFromOptions()
8053 @*/
8054 PetscErrorCode DMPlexCheckSkeleton(DM dm, PetscInt cellHeight)
8055 {
8056   DMPlexInterpolatedFlag interp;
8057   DMPolytopeType         ct;
8058   PetscInt               vStart, vEnd, cStart, cEnd, c;
8059   PetscErrorCode         ierr;
8060 
8061   PetscFunctionBegin;
8062   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8063   ierr = DMPlexIsInterpolated(dm, &interp);CHKERRQ(ierr);
8064   ierr = DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd);CHKERRQ(ierr);
8065   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
8066   for (c = cStart; c < cEnd; ++c) {
8067     PetscInt *closure = NULL;
8068     PetscInt  coneSize, closureSize, cl, Nv = 0;
8069 
8070     ierr = DMPlexGetCellType(dm, c, &ct);CHKERRQ(ierr);
8071     if ((PetscInt) ct < 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cell %D has no cell type", c);
8072     if (ct == DM_POLYTOPE_UNKNOWN) continue;
8073     if (interp == DMPLEX_INTERPOLATED_FULL) {
8074       ierr = DMPlexGetConeSize(dm, c, &coneSize);CHKERRQ(ierr);
8075       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));
8076     }
8077     ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
8078     for (cl = 0; cl < closureSize*2; cl += 2) {
8079       const PetscInt p = closure[cl];
8080       if ((p >= vStart) && (p < vEnd)) ++Nv;
8081     }
8082     ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
8083     /* Special Case: Tensor faces with identified vertices */
8084     if (Nv < DMPolytopeTypeGetNumVertices(ct)) {
8085       PetscInt unsplit;
8086 
8087       ierr = DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit);CHKERRQ(ierr);
8088       if (Nv + unsplit == DMPolytopeTypeGetNumVertices(ct)) continue;
8089     }
8090     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));
8091   }
8092   PetscFunctionReturn(0);
8093 }
8094 
8095 /*@
8096   DMPlexCheckFaces - Check that the faces of each cell give a vertex order this is consistent with what we expect from the cell type
8097 
8098   Not Collective
8099 
8100   Input Parameters:
8101 + dm - The DMPlex object
8102 - cellHeight - Normally 0
8103 
8104   Notes:
8105   This is a useful diagnostic when creating meshes programmatically.
8106   This routine is only relevant for meshes that are fully interpolated across all ranks.
8107   It will error out if a partially interpolated mesh is given on some rank.
8108   It will do nothing for locally uninterpolated mesh (as there is nothing to check).
8109 
8110   For the complete list of DMPlexCheck* functions, see DMSetFromOptions().
8111 
8112   Level: developer
8113 
8114 .seealso: DMCreate(), DMPlexGetVTKCellHeight(), DMSetFromOptions()
8115 @*/
8116 PetscErrorCode DMPlexCheckFaces(DM dm, PetscInt cellHeight)
8117 {
8118   PetscInt       dim, depth, vStart, vEnd, cStart, cEnd, c, h;
8119   PetscErrorCode ierr;
8120   DMPlexInterpolatedFlag interpEnum;
8121 
8122   PetscFunctionBegin;
8123   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8124   ierr = DMPlexIsInterpolated(dm, &interpEnum);CHKERRQ(ierr);
8125   if (interpEnum == DMPLEX_INTERPOLATED_NONE) PetscFunctionReturn(0);
8126   if (interpEnum == DMPLEX_INTERPOLATED_PARTIAL) {
8127     PetscMPIInt rank;
8128     MPI_Comm    comm;
8129 
8130     ierr = PetscObjectGetComm((PetscObject) dm, &comm);CHKERRQ(ierr);
8131     ierr = MPI_Comm_rank(comm, &rank);CHKERRMPI(ierr);
8132     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_SUP, "Mesh is only partially interpolated on rank %d, this is currently not supported", rank);
8133   }
8134 
8135   ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr);
8136   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
8137   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
8138   for (h = cellHeight; h < PetscMin(depth, dim); ++h) {
8139     ierr = DMPlexGetHeightStratum(dm, h, &cStart, &cEnd);CHKERRQ(ierr);
8140     for (c = cStart; c < cEnd; ++c) {
8141       const PetscInt      *cone, *ornt, *faceSizes, *faces;
8142       const DMPolytopeType *faceTypes;
8143       DMPolytopeType        ct;
8144       PetscInt              numFaces, coneSize, f;
8145       PetscInt             *closure = NULL, closureSize, cl, numCorners = 0, fOff = 0, unsplit;
8146 
8147       ierr = DMPlexGetCellType(dm, c, &ct);CHKERRQ(ierr);
8148       ierr = DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit);CHKERRQ(ierr);
8149       if (unsplit) continue;
8150       ierr = DMPlexGetConeSize(dm, c, &coneSize);CHKERRQ(ierr);
8151       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
8152       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
8153       ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
8154       for (cl = 0; cl < closureSize*2; cl += 2) {
8155         const PetscInt p = closure[cl];
8156         if ((p >= vStart) && (p < vEnd)) closure[numCorners++] = p;
8157       }
8158       ierr = DMPlexGetRawFaces_Internal(dm, ct, closure, &numFaces, &faceTypes, &faceSizes, &faces);CHKERRQ(ierr);
8159       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);
8160       for (f = 0; f < numFaces; ++f) {
8161         DMPolytopeType fct;
8162         PetscInt       *fclosure = NULL, fclosureSize, cl, fnumCorners = 0, v;
8163 
8164         ierr = DMPlexGetCellType(dm, cone[f], &fct);CHKERRQ(ierr);
8165         ierr = DMPlexGetTransitiveClosure_Internal(dm, cone[f], ornt[f], PETSC_TRUE, &fclosureSize, &fclosure);CHKERRQ(ierr);
8166         for (cl = 0; cl < fclosureSize*2; cl += 2) {
8167           const PetscInt p = fclosure[cl];
8168           if ((p >= vStart) && (p < vEnd)) fclosure[fnumCorners++] = p;
8169         }
8170         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]);
8171         for (v = 0; v < fnumCorners; ++v) {
8172           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]);
8173         }
8174         ierr = DMPlexRestoreTransitiveClosure(dm, cone[f], PETSC_TRUE, &fclosureSize, &fclosure);CHKERRQ(ierr);
8175         fOff += faceSizes[f];
8176       }
8177       ierr = DMPlexRestoreRawFaces_Internal(dm, ct, closure, &numFaces, &faceTypes, &faceSizes, &faces);CHKERRQ(ierr);
8178       ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
8179     }
8180   }
8181   PetscFunctionReturn(0);
8182 }
8183 
8184 /*@
8185   DMPlexCheckGeometry - Check the geometry of mesh cells
8186 
8187   Input Parameter:
8188 . dm - The DMPlex object
8189 
8190   Notes:
8191   This is a useful diagnostic when creating meshes programmatically.
8192 
8193   For the complete list of DMPlexCheck* functions, see DMSetFromOptions().
8194 
8195   Level: developer
8196 
8197 .seealso: DMCreate(), DMSetFromOptions()
8198 @*/
8199 PetscErrorCode DMPlexCheckGeometry(DM dm)
8200 {
8201   Vec            coordinates;
8202   PetscReal      detJ, J[9], refVol = 1.0;
8203   PetscReal      vol;
8204   PetscBool      periodic;
8205   PetscInt       dim, depth, dE, d, cStart, cEnd, c;
8206   PetscErrorCode ierr;
8207 
8208   PetscFunctionBegin;
8209   ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr);
8210   ierr = DMGetCoordinateDim(dm, &dE);CHKERRQ(ierr);
8211   if (dim != dE) PetscFunctionReturn(0);
8212   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
8213   ierr = DMGetPeriodicity(dm, &periodic, NULL, NULL, NULL);CHKERRQ(ierr);
8214   for (d = 0; d < dim; ++d) refVol *= 2.0;
8215   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
8216   /* Make sure local coordinates are created, because that step is collective */
8217   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
8218   for (c = cStart; c < cEnd; ++c) {
8219     DMPolytopeType ct;
8220     PetscInt       unsplit;
8221     PetscBool      ignoreZeroVol = PETSC_FALSE;
8222 
8223     ierr = DMPlexGetCellType(dm, c, &ct);CHKERRQ(ierr);
8224     switch (ct) {
8225       case DM_POLYTOPE_SEG_PRISM_TENSOR:
8226       case DM_POLYTOPE_TRI_PRISM_TENSOR:
8227       case DM_POLYTOPE_QUAD_PRISM_TENSOR:
8228         ignoreZeroVol = PETSC_TRUE; break;
8229       default: break;
8230     }
8231     switch (ct) {
8232       case DM_POLYTOPE_TRI_PRISM:
8233       case DM_POLYTOPE_TRI_PRISM_TENSOR:
8234       case DM_POLYTOPE_QUAD_PRISM_TENSOR:
8235       case DM_POLYTOPE_PYRAMID:
8236         continue;
8237       default: break;
8238     }
8239     ierr = DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit);CHKERRQ(ierr);
8240     if (unsplit) continue;
8241     ierr = DMPlexComputeCellGeometryFEM(dm, c, NULL, NULL, J, NULL, &detJ);CHKERRQ(ierr);
8242     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);
8243     ierr = PetscInfo2(dm, "Cell %D FEM Volume %g\n", c, (double) detJ*refVol);CHKERRQ(ierr);
8244     if (depth > 1 && !periodic) {
8245       ierr = DMPlexComputeCellGeometryFVM(dm, c, &vol, NULL, NULL);CHKERRQ(ierr);
8246       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);
8247       ierr = PetscInfo2(dm, "Cell %D FVM Volume %g\n", c, (double) vol);CHKERRQ(ierr);
8248     }
8249   }
8250   PetscFunctionReturn(0);
8251 }
8252 
8253 /*@
8254   DMPlexCheckPointSF - Check that several necessary conditions are met for the point SF of this plex.
8255 
8256   Input Parameters:
8257 . dm - The DMPlex object
8258 
8259   Notes:
8260   This is mainly intended for debugging/testing purposes.
8261   It currently checks only meshes with no partition overlapping.
8262 
8263   For the complete list of DMPlexCheck* functions, see DMSetFromOptions().
8264 
8265   Level: developer
8266 
8267 .seealso: DMGetPointSF(), DMSetFromOptions()
8268 @*/
8269 PetscErrorCode DMPlexCheckPointSF(DM dm)
8270 {
8271   PetscSF         pointSF;
8272   PetscInt        cellHeight, cStart, cEnd, l, nleaves, nroots, overlap;
8273   const PetscInt *locals, *rootdegree;
8274   PetscBool       distributed;
8275   PetscErrorCode  ierr;
8276 
8277   PetscFunctionBegin;
8278   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8279   ierr = DMGetPointSF(dm, &pointSF);CHKERRQ(ierr);
8280   ierr = DMPlexIsDistributed(dm, &distributed);CHKERRQ(ierr);
8281   if (!distributed) PetscFunctionReturn(0);
8282   ierr = DMPlexGetOverlap(dm, &overlap);CHKERRQ(ierr);
8283   if (overlap) {
8284     ierr = PetscPrintf(PetscObjectComm((PetscObject)dm), "Warning: DMPlexCheckPointSF() is currently not implemented for meshes with partition overlapping");
8285     PetscFunctionReturn(0);
8286   }
8287   if (!pointSF) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "This DMPlex is distributed but does not have PointSF attached");
8288   ierr = PetscSFGetGraph(pointSF, &nroots, &nleaves, &locals, NULL);CHKERRQ(ierr);
8289   if (nroots < 0) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "This DMPlex is distributed but its PointSF has no graph set");
8290   ierr = PetscSFComputeDegreeBegin(pointSF, &rootdegree);CHKERRQ(ierr);
8291   ierr = PetscSFComputeDegreeEnd(pointSF, &rootdegree);CHKERRQ(ierr);
8292 
8293   /* 1) check there are no faces in 2D, cells in 3D, in interface */
8294   ierr = DMPlexGetVTKCellHeight(dm, &cellHeight);CHKERRQ(ierr);
8295   ierr = DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd);CHKERRQ(ierr);
8296   for (l = 0; l < nleaves; ++l) {
8297     const PetscInt point = locals[l];
8298 
8299     if (point >= cStart && point < cEnd) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point SF contains %D which is a cell", point);
8300   }
8301 
8302   /* 2) if some point is in interface, then all its cone points must be also in interface (either as leaves or roots) */
8303   for (l = 0; l < nleaves; ++l) {
8304     const PetscInt  point = locals[l];
8305     const PetscInt *cone;
8306     PetscInt        coneSize, c, idx;
8307 
8308     ierr = DMPlexGetConeSize(dm, point, &coneSize);CHKERRQ(ierr);
8309     ierr = DMPlexGetCone(dm, point, &cone);CHKERRQ(ierr);
8310     for (c = 0; c < coneSize; ++c) {
8311       if (!rootdegree[cone[c]]) {
8312         ierr = PetscFindInt(cone[c], nleaves, locals, &idx);CHKERRQ(ierr);
8313         if (idx < 0) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point SF contains %D but not %D from its cone", point, cone[c]);
8314       }
8315     }
8316   }
8317   PetscFunctionReturn(0);
8318 }
8319 
8320 typedef struct cell_stats
8321 {
8322   PetscReal min, max, sum, squaresum;
8323   PetscInt  count;
8324 } cell_stats_t;
8325 
8326 static void MPIAPI cell_stats_reduce(void *a, void *b, int * len, MPI_Datatype *datatype)
8327 {
8328   PetscInt i, N = *len;
8329 
8330   for (i = 0; i < N; i++) {
8331     cell_stats_t *A = (cell_stats_t *) a;
8332     cell_stats_t *B = (cell_stats_t *) b;
8333 
8334     B->min = PetscMin(A->min,B->min);
8335     B->max = PetscMax(A->max,B->max);
8336     B->sum += A->sum;
8337     B->squaresum += A->squaresum;
8338     B->count += A->count;
8339   }
8340 }
8341 
8342 /*@
8343   DMPlexCheckCellShape - Checks the Jacobian of the mapping from reference to real cells and computes some minimal statistics.
8344 
8345   Collective on dm
8346 
8347   Input Parameters:
8348 + dm        - The DMPlex object
8349 . output    - If true, statistics will be displayed on stdout
8350 - condLimit - Display all cells above this condition number, or PETSC_DETERMINE for no cell output
8351 
8352   Notes:
8353   This is mainly intended for debugging/testing purposes.
8354 
8355   For the complete list of DMPlexCheck* functions, see DMSetFromOptions().
8356 
8357   Level: developer
8358 
8359 .seealso: DMSetFromOptions(), DMPlexComputeOrthogonalQuality()
8360 @*/
8361 PetscErrorCode DMPlexCheckCellShape(DM dm, PetscBool output, PetscReal condLimit)
8362 {
8363   DM             dmCoarse;
8364   cell_stats_t   stats, globalStats;
8365   MPI_Comm       comm = PetscObjectComm((PetscObject)dm);
8366   PetscReal      *J, *invJ, min = 0, max = 0, mean = 0, stdev = 0;
8367   PetscReal      limit = condLimit > 0 ? condLimit : PETSC_MAX_REAL;
8368   PetscInt       cdim, cStart, cEnd, c, eStart, eEnd, count = 0;
8369   PetscMPIInt    rank,size;
8370   PetscErrorCode ierr;
8371 
8372   PetscFunctionBegin;
8373   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8374   stats.min   = PETSC_MAX_REAL;
8375   stats.max   = PETSC_MIN_REAL;
8376   stats.sum   = stats.squaresum = 0.;
8377   stats.count = 0;
8378 
8379   ierr = MPI_Comm_size(comm, &size);CHKERRMPI(ierr);
8380   ierr = MPI_Comm_rank(comm, &rank);CHKERRMPI(ierr);
8381   ierr = DMGetCoordinateDim(dm,&cdim);CHKERRQ(ierr);
8382   ierr = PetscMalloc2(PetscSqr(cdim), &J, PetscSqr(cdim), &invJ);CHKERRQ(ierr);
8383   ierr = DMPlexGetSimplexOrBoxCells(dm,0,&cStart,&cEnd);CHKERRQ(ierr);
8384   ierr = DMPlexGetDepthStratum(dm,1,&eStart,&eEnd);CHKERRQ(ierr);
8385   for (c = cStart; c < cEnd; c++) {
8386     PetscInt  i;
8387     PetscReal frobJ = 0., frobInvJ = 0., cond2, cond, detJ;
8388 
8389     ierr = DMPlexComputeCellGeometryAffineFEM(dm,c,NULL,J,invJ,&detJ);CHKERRQ(ierr);
8390     if (detJ < 0.0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Mesh cell %D is inverted", c);
8391     for (i = 0; i < PetscSqr(cdim); ++i) {
8392       frobJ    += J[i] * J[i];
8393       frobInvJ += invJ[i] * invJ[i];
8394     }
8395     cond2 = frobJ * frobInvJ;
8396     cond  = PetscSqrtReal(cond2);
8397 
8398     stats.min        = PetscMin(stats.min,cond);
8399     stats.max        = PetscMax(stats.max,cond);
8400     stats.sum       += cond;
8401     stats.squaresum += cond2;
8402     stats.count++;
8403     if (output && cond > limit) {
8404       PetscSection coordSection;
8405       Vec          coordsLocal;
8406       PetscScalar *coords = NULL;
8407       PetscInt     Nv, d, clSize, cl, *closure = NULL;
8408 
8409       ierr = DMGetCoordinatesLocal(dm, &coordsLocal);CHKERRQ(ierr);
8410       ierr = DMGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
8411       ierr = DMPlexVecGetClosure(dm, coordSection, coordsLocal, c, &Nv, &coords);CHKERRQ(ierr);
8412       ierr = PetscSynchronizedPrintf(comm, "[%d] Cell %D cond %g\n", rank, c, (double) cond);CHKERRQ(ierr);
8413       for (i = 0; i < Nv/cdim; ++i) {
8414         ierr = PetscSynchronizedPrintf(comm, "  Vertex %D: (", i);CHKERRQ(ierr);
8415         for (d = 0; d < cdim; ++d) {
8416           if (d > 0) {ierr = PetscSynchronizedPrintf(comm, ", ");CHKERRQ(ierr);}
8417           ierr = PetscSynchronizedPrintf(comm, "%g", (double) PetscRealPart(coords[i*cdim+d]));CHKERRQ(ierr);
8418         }
8419         ierr = PetscSynchronizedPrintf(comm, ")\n");CHKERRQ(ierr);
8420       }
8421       ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &clSize, &closure);CHKERRQ(ierr);
8422       for (cl = 0; cl < clSize*2; cl += 2) {
8423         const PetscInt edge = closure[cl];
8424 
8425         if ((edge >= eStart) && (edge < eEnd)) {
8426           PetscReal len;
8427 
8428           ierr = DMPlexComputeCellGeometryFVM(dm, edge, &len, NULL, NULL);CHKERRQ(ierr);
8429           ierr = PetscSynchronizedPrintf(comm, "  Edge %D: length %g\n", edge, (double) len);CHKERRQ(ierr);
8430         }
8431       }
8432       ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &clSize, &closure);CHKERRQ(ierr);
8433       ierr = DMPlexVecRestoreClosure(dm, coordSection, coordsLocal, c, &Nv, &coords);CHKERRQ(ierr);
8434     }
8435   }
8436   if (output) {ierr = PetscSynchronizedFlush(comm, NULL);CHKERRQ(ierr);}
8437 
8438   if (size > 1) {
8439     PetscMPIInt   blockLengths[2] = {4,1};
8440     MPI_Aint      blockOffsets[2] = {offsetof(cell_stats_t,min),offsetof(cell_stats_t,count)};
8441     MPI_Datatype  blockTypes[2]   = {MPIU_REAL,MPIU_INT}, statType;
8442     MPI_Op        statReduce;
8443 
8444     ierr = MPI_Type_create_struct(2,blockLengths,blockOffsets,blockTypes,&statType);CHKERRMPI(ierr);
8445     ierr = MPI_Type_commit(&statType);CHKERRMPI(ierr);
8446     ierr = MPI_Op_create(cell_stats_reduce, PETSC_TRUE, &statReduce);CHKERRMPI(ierr);
8447     ierr = MPI_Reduce(&stats,&globalStats,1,statType,statReduce,0,comm);CHKERRMPI(ierr);
8448     ierr = MPI_Op_free(&statReduce);CHKERRMPI(ierr);
8449     ierr = MPI_Type_free(&statType);CHKERRMPI(ierr);
8450   } else {
8451     ierr = PetscArraycpy(&globalStats,&stats,1);CHKERRQ(ierr);
8452   }
8453   if (!rank) {
8454     count = globalStats.count;
8455     min   = globalStats.min;
8456     max   = globalStats.max;
8457     mean  = globalStats.sum / globalStats.count;
8458     stdev = globalStats.count > 1 ? PetscSqrtReal(PetscMax((globalStats.squaresum - globalStats.count * mean * mean) / (globalStats.count - 1),0)) : 0.0;
8459   }
8460 
8461   if (output) {
8462     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);
8463   }
8464   ierr = PetscFree2(J,invJ);CHKERRQ(ierr);
8465 
8466   ierr = DMGetCoarseDM(dm,&dmCoarse);CHKERRQ(ierr);
8467   if (dmCoarse) {
8468     PetscBool isplex;
8469 
8470     ierr = PetscObjectTypeCompare((PetscObject)dmCoarse,DMPLEX,&isplex);CHKERRQ(ierr);
8471     if (isplex) {
8472       ierr = DMPlexCheckCellShape(dmCoarse,output,condLimit);CHKERRQ(ierr);
8473     }
8474   }
8475   PetscFunctionReturn(0);
8476 }
8477 
8478 /*@
8479   DMPlexComputeOrthogonalQuality - Compute cell-wise orthogonal quality mesh statistic. Optionally tags all cells with
8480   orthogonal quality below given tolerance.
8481 
8482   Collective on dm
8483 
8484   Input Parameters:
8485 + dm   - The DMPlex object
8486 . fv   - Optional PetscFV object for pre-computed cell/face centroid information
8487 - atol - [0, 1] Absolute tolerance for tagging cells.
8488 
8489   Output Parameters:
8490 + OrthQual      - Vec containing orthogonal quality per cell
8491 - OrthQualLabel - DMLabel tagging cells below atol with DM_ADAPT_REFINE
8492 
8493   Options Database Keys:
8494 + -dm_plex_orthogonal_quality_label_view - view OrthQualLabel if label is requested. Currently only PETSCVIEWERASCII is
8495 supported.
8496 - -dm_plex_orthogonal_quality_vec_view - view OrthQual vector.
8497 
8498   Notes:
8499   Orthogonal quality is given by the following formula:
8500 
8501   \min \left[ \frac{A_i \cdot f_i}{\|A_i\| \|f_i\|} , \frac{A_i \cdot c_i}{\|A_i\| \|c_i\|} \right]
8502 
8503   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
8504   is the vector from the current cells centroid to the centroid of its i'th neighbor (which shares a face with the
8505   current cell). This computes the vector similarity between each cell face and its corresponding neighbor centroid by
8506   calculating the cosine of the angle between these vectors.
8507 
8508   Orthogonal quality ranges from 1 (best) to 0 (worst).
8509 
8510   This routine is mainly useful for FVM, however is not restricted to only FVM. The PetscFV object is optionally used to check for
8511   pre-computed FVM cell data, but if it is not passed in then this data will be computed.
8512 
8513   Cells are tagged if they have an orthogonal quality less than or equal to the absolute tolerance.
8514 
8515   Level: intermediate
8516 
8517 .seealso: DMPlexCheckCellShape(), DMCreateLabel()
8518 @*/
8519 PetscErrorCode DMPlexComputeOrthogonalQuality(DM dm, PetscFV fv, PetscReal atol, Vec *OrthQual, DMLabel *OrthQualLabel)
8520 {
8521   PetscInt                nc, cellHeight, cStart, cEnd, cell, cellIter = 0;
8522   PetscInt                *idx;
8523   PetscScalar             *oqVals;
8524   const PetscScalar       *cellGeomArr, *faceGeomArr;
8525   PetscReal               *ci, *fi, *Ai;
8526   MPI_Comm                comm;
8527   Vec                     cellgeom, facegeom;
8528   DM                      dmFace, dmCell;
8529   IS                      glob;
8530   ISLocalToGlobalMapping  ltog;
8531   PetscViewer             vwr;
8532   PetscErrorCode          ierr;
8533 
8534   PetscFunctionBegin;
8535   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8536   if (fv) {PetscValidHeaderSpecific(fv, PETSCFV_CLASSID, 2);}
8537   PetscValidPointer(OrthQual, 4);
8538   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);
8539   ierr = PetscObjectGetComm((PetscObject) dm, &comm);CHKERRQ(ierr);
8540   ierr = DMGetDimension(dm, &nc);CHKERRQ(ierr);
8541   if (nc < 2) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "DM must have dimension >= 2 (current %D)", nc);
8542   {
8543     DMPlexInterpolatedFlag interpFlag;
8544 
8545     ierr = DMPlexIsInterpolated(dm, &interpFlag);CHKERRQ(ierr);
8546     if (interpFlag != DMPLEX_INTERPOLATED_FULL) {
8547       PetscMPIInt rank;
8548 
8549       ierr = MPI_Comm_rank(comm, &rank);CHKERRMPI(ierr);
8550       SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "DM must be fully interpolated, DM on rank %d is not fully interpolated", rank);
8551     }
8552   }
8553   if (OrthQualLabel) {
8554     PetscValidPointer(OrthQualLabel, 5);
8555     ierr = DMCreateLabel(dm, "Orthogonal_Quality");CHKERRQ(ierr);
8556     ierr = DMGetLabel(dm, "Orthogonal_Quality", OrthQualLabel);CHKERRQ(ierr);
8557   } else {*OrthQualLabel = NULL;}
8558   ierr = DMPlexGetVTKCellHeight(dm, &cellHeight);CHKERRQ(ierr);
8559   ierr = DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd);CHKERRQ(ierr);
8560   ierr = DMPlexCreateCellNumbering_Internal(dm, PETSC_TRUE, &glob);CHKERRQ(ierr);
8561   ierr = ISLocalToGlobalMappingCreateIS(glob, &ltog);CHKERRQ(ierr);
8562   ierr = ISLocalToGlobalMappingSetType(ltog, ISLOCALTOGLOBALMAPPINGHASH);CHKERRQ(ierr);
8563   ierr = VecCreate(comm, OrthQual);CHKERRQ(ierr);
8564   ierr = VecSetType(*OrthQual, VECSTANDARD);CHKERRQ(ierr);
8565   ierr = VecSetSizes(*OrthQual, cEnd-cStart, PETSC_DETERMINE);CHKERRQ(ierr);
8566   ierr = VecSetLocalToGlobalMapping(*OrthQual, ltog);CHKERRQ(ierr);
8567   ierr = VecSetUp(*OrthQual);CHKERRQ(ierr);
8568   ierr = ISDestroy(&glob);CHKERRQ(ierr);
8569   ierr = ISLocalToGlobalMappingDestroy(&ltog);CHKERRQ(ierr);
8570   ierr = DMPlexGetDataFVM(dm, fv, &cellgeom, &facegeom, NULL);CHKERRQ(ierr);
8571   ierr = VecGetArrayRead(cellgeom, &cellGeomArr);CHKERRQ(ierr);
8572   ierr = VecGetArrayRead(facegeom, &faceGeomArr);CHKERRQ(ierr);
8573   ierr = VecGetDM(cellgeom, &dmCell);CHKERRQ(ierr);
8574   ierr = VecGetDM(facegeom, &dmFace);CHKERRQ(ierr);
8575   ierr = PetscMalloc5(cEnd-cStart, &idx, cEnd-cStart, &oqVals, nc, &ci, nc, &fi, nc, &Ai);CHKERRQ(ierr);
8576   for (cell = cStart; cell < cEnd; cellIter++,cell++) {
8577     PetscInt           cellneigh, cellneighiter = 0, adjSize = PETSC_DETERMINE;
8578     PetscInt           cellarr[2], *adj = NULL;
8579     PetscScalar        *cArr, *fArr;
8580     PetscReal          minvalc = 1.0, minvalf = 1.0;
8581     PetscFVCellGeom    *cg;
8582 
8583     idx[cellIter] = cell-cStart;
8584     cellarr[0] = cell;
8585     /* Make indexing into cellGeom easier */
8586     ierr = DMPlexPointLocalRead(dmCell, cell, cellGeomArr, &cg);CHKERRQ(ierr);
8587     ierr = DMPlexGetAdjacency_Internal(dm, cell, PETSC_TRUE, PETSC_FALSE, PETSC_FALSE, &adjSize, &adj);CHKERRQ(ierr);
8588     /* Technically 1 too big, but easier than fiddling with empty adjacency array */
8589     ierr = PetscCalloc2(adjSize, &cArr, adjSize, &fArr);CHKERRQ(ierr);
8590     for (cellneigh = 0; cellneigh < adjSize; cellneighiter++,cellneigh++) {
8591       PetscInt         i;
8592       const PetscInt   neigh = adj[cellneigh];
8593       PetscReal        normci = 0, normfi = 0, normai = 0;
8594       PetscFVCellGeom  *cgneigh;
8595       PetscFVFaceGeom  *fg;
8596 
8597       /* Don't count ourselves in the neighbor list */
8598       if (neigh == cell) continue;
8599       ierr = DMPlexPointLocalRead(dmCell, neigh, cellGeomArr, &cgneigh);CHKERRQ(ierr);
8600       cellarr[1] = neigh;
8601       {
8602         PetscInt       numcovpts;
8603         const PetscInt *covpts;
8604 
8605         ierr = DMPlexGetMeet(dm, 2, cellarr, &numcovpts, &covpts);CHKERRQ(ierr);
8606         ierr = DMPlexPointLocalRead(dmFace, covpts[0], faceGeomArr, &fg);CHKERRQ(ierr);
8607         ierr = DMPlexRestoreMeet(dm, 2, cellarr, &numcovpts, &covpts);CHKERRQ(ierr);
8608       }
8609 
8610       /* Compute c_i, f_i and their norms */
8611       for (i = 0; i < nc; i++) {
8612         ci[i] = cgneigh->centroid[i] - cg->centroid[i];
8613         fi[i] = fg->centroid[i] - cg->centroid[i];
8614         Ai[i] = fg->normal[i];
8615         normci += PetscPowReal(ci[i], 2);
8616         normfi += PetscPowReal(fi[i], 2);
8617         normai += PetscPowReal(Ai[i], 2);
8618       }
8619       normci = PetscSqrtReal(normci);
8620       normfi = PetscSqrtReal(normfi);
8621       normai = PetscSqrtReal(normai);
8622 
8623       /* Normalize and compute for each face-cell-normal pair */
8624       for (i = 0; i < nc; i++) {
8625         ci[i] = ci[i]/normci;
8626         fi[i] = fi[i]/normfi;
8627         Ai[i] = Ai[i]/normai;
8628         /* PetscAbs because I don't know if normals are guaranteed to point out */
8629         cArr[cellneighiter] += PetscAbs(Ai[i]*ci[i]);
8630         fArr[cellneighiter] += PetscAbs(Ai[i]*fi[i]);
8631       }
8632       if (PetscRealPart(cArr[cellneighiter]) < minvalc) {
8633         minvalc = PetscRealPart(cArr[cellneighiter]);
8634       }
8635       if (PetscRealPart(fArr[cellneighiter]) < minvalf) {
8636         minvalf = PetscRealPart(fArr[cellneighiter]);
8637       }
8638     }
8639     ierr = PetscFree(adj);CHKERRQ(ierr);
8640     ierr = PetscFree2(cArr, fArr);CHKERRQ(ierr);
8641     /* Defer to cell if they're equal */
8642     oqVals[cellIter] = PetscMin(minvalf, minvalc);
8643     if (OrthQualLabel) {
8644       if (PetscRealPart(oqVals[cellIter]) <= atol) {ierr = DMLabelSetValue(*OrthQualLabel, cell, DM_ADAPT_REFINE);CHKERRQ(ierr);}
8645     }
8646   }
8647   ierr = VecSetValuesLocal(*OrthQual, cEnd-cStart, idx, oqVals, INSERT_VALUES);CHKERRQ(ierr);
8648   ierr = VecAssemblyBegin(*OrthQual);CHKERRQ(ierr);
8649   ierr = VecAssemblyEnd(*OrthQual);CHKERRQ(ierr);
8650   ierr = VecRestoreArrayRead(cellgeom, &cellGeomArr);CHKERRQ(ierr);
8651   ierr = VecRestoreArrayRead(facegeom, &faceGeomArr);CHKERRQ(ierr);
8652   ierr = PetscOptionsGetViewer(comm, NULL, NULL, "-dm_plex_orthogonal_quality_label_view", &vwr, NULL, NULL);CHKERRQ(ierr);
8653   if (OrthQualLabel) {
8654     if (vwr) {ierr = DMLabelView(*OrthQualLabel, vwr);CHKERRQ(ierr);}
8655   }
8656   ierr = PetscFree5(idx, oqVals, ci, fi, Ai);CHKERRQ(ierr);
8657   ierr = PetscViewerDestroy(&vwr);CHKERRQ(ierr);
8658   ierr = VecViewFromOptions(*OrthQual, NULL, "-dm_plex_orthogonal_quality_vec_view");CHKERRQ(ierr);
8659   PetscFunctionReturn(0);
8660 }
8661 
8662 /* this is here insead of DMGetOutputDM because output DM still has constraints in the local indices that affect
8663  * interpolator construction */
8664 static PetscErrorCode DMGetFullDM(DM dm, DM *odm)
8665 {
8666   PetscSection   section, newSection, gsection;
8667   PetscSF        sf;
8668   PetscBool      hasConstraints, ghasConstraints;
8669   PetscErrorCode ierr;
8670 
8671   PetscFunctionBegin;
8672   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
8673   PetscValidPointer(odm,2);
8674   ierr = DMGetLocalSection(dm, &section);CHKERRQ(ierr);
8675   ierr = PetscSectionHasConstraints(section, &hasConstraints);CHKERRQ(ierr);
8676   ierr = MPI_Allreduce(&hasConstraints, &ghasConstraints, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject) dm));CHKERRMPI(ierr);
8677   if (!ghasConstraints) {
8678     ierr = PetscObjectReference((PetscObject)dm);CHKERRQ(ierr);
8679     *odm = dm;
8680     PetscFunctionReturn(0);
8681   }
8682   ierr = DMClone(dm, odm);CHKERRQ(ierr);
8683   ierr = DMCopyFields(dm, *odm);CHKERRQ(ierr);
8684   ierr = DMGetLocalSection(*odm, &newSection);CHKERRQ(ierr);
8685   ierr = DMGetPointSF(*odm, &sf);CHKERRQ(ierr);
8686   ierr = PetscSectionCreateGlobalSection(newSection, sf, PETSC_TRUE, PETSC_FALSE, &gsection);CHKERRQ(ierr);
8687   ierr = DMSetGlobalSection(*odm, gsection);CHKERRQ(ierr);
8688   ierr = PetscSectionDestroy(&gsection);CHKERRQ(ierr);
8689   PetscFunctionReturn(0);
8690 }
8691 
8692 static PetscErrorCode DMCreateAffineInterpolationCorrection_Plex(DM dmc, DM dmf, Vec *shift)
8693 {
8694   DM             dmco, dmfo;
8695   Mat            interpo;
8696   Vec            rscale;
8697   Vec            cglobalo, clocal;
8698   Vec            fglobal, fglobalo, flocal;
8699   PetscBool      regular;
8700   PetscErrorCode ierr;
8701 
8702   PetscFunctionBegin;
8703   ierr = DMGetFullDM(dmc, &dmco);CHKERRQ(ierr);
8704   ierr = DMGetFullDM(dmf, &dmfo);CHKERRQ(ierr);
8705   ierr = DMSetCoarseDM(dmfo, dmco);CHKERRQ(ierr);
8706   ierr = DMPlexGetRegularRefinement(dmf, &regular);CHKERRQ(ierr);
8707   ierr = DMPlexSetRegularRefinement(dmfo, regular);CHKERRQ(ierr);
8708   ierr = DMCreateInterpolation(dmco, dmfo, &interpo, &rscale);CHKERRQ(ierr);
8709   ierr = DMCreateGlobalVector(dmco, &cglobalo);CHKERRQ(ierr);
8710   ierr = DMCreateLocalVector(dmc, &clocal);CHKERRQ(ierr);
8711   ierr = VecSet(cglobalo, 0.);CHKERRQ(ierr);
8712   ierr = VecSet(clocal, 0.);CHKERRQ(ierr);
8713   ierr = DMCreateGlobalVector(dmf, &fglobal);CHKERRQ(ierr);
8714   ierr = DMCreateGlobalVector(dmfo, &fglobalo);CHKERRQ(ierr);
8715   ierr = DMCreateLocalVector(dmf, &flocal);CHKERRQ(ierr);
8716   ierr = VecSet(fglobal, 0.);CHKERRQ(ierr);
8717   ierr = VecSet(fglobalo, 0.);CHKERRQ(ierr);
8718   ierr = VecSet(flocal, 0.);CHKERRQ(ierr);
8719   ierr = DMPlexInsertBoundaryValues(dmc, PETSC_TRUE, clocal, 0., NULL, NULL, NULL);CHKERRQ(ierr);
8720   ierr = DMLocalToGlobalBegin(dmco, clocal, INSERT_VALUES, cglobalo);CHKERRQ(ierr);
8721   ierr = DMLocalToGlobalEnd(dmco, clocal, INSERT_VALUES, cglobalo);CHKERRQ(ierr);
8722   ierr = MatMult(interpo, cglobalo, fglobalo);CHKERRQ(ierr);
8723   ierr = DMGlobalToLocalBegin(dmfo, fglobalo, INSERT_VALUES, flocal);CHKERRQ(ierr);
8724   ierr = DMGlobalToLocalEnd(dmfo, fglobalo, INSERT_VALUES, flocal);CHKERRQ(ierr);
8725   ierr = DMLocalToGlobalBegin(dmf, flocal, INSERT_VALUES, fglobal);CHKERRQ(ierr);
8726   ierr = DMLocalToGlobalEnd(dmf, flocal, INSERT_VALUES, fglobal);CHKERRQ(ierr);
8727   *shift = fglobal;
8728   ierr = VecDestroy(&flocal);CHKERRQ(ierr);
8729   ierr = VecDestroy(&fglobalo);CHKERRQ(ierr);
8730   ierr = VecDestroy(&clocal);CHKERRQ(ierr);
8731   ierr = VecDestroy(&cglobalo);CHKERRQ(ierr);
8732   ierr = VecDestroy(&rscale);CHKERRQ(ierr);
8733   ierr = MatDestroy(&interpo);CHKERRQ(ierr);
8734   ierr = DMDestroy(&dmfo);CHKERRQ(ierr);
8735   ierr = DMDestroy(&dmco);CHKERRQ(ierr);
8736   PetscFunctionReturn(0);
8737 }
8738 
8739 PETSC_INTERN PetscErrorCode DMInterpolateSolution_Plex(DM coarse, DM fine, Mat interp, Vec coarseSol, Vec fineSol)
8740 {
8741   PetscObject    shifto;
8742   Vec            shift;
8743 
8744   PetscErrorCode ierr;
8745 
8746   PetscFunctionBegin;
8747   if (!interp) {
8748     Vec rscale;
8749 
8750     ierr = DMCreateInterpolation(coarse, fine, &interp, &rscale);CHKERRQ(ierr);
8751     ierr = VecDestroy(&rscale);CHKERRQ(ierr);
8752   } else {
8753     ierr = PetscObjectReference((PetscObject)interp);CHKERRQ(ierr);
8754   }
8755   ierr = PetscObjectQuery((PetscObject)interp, "_DMInterpolateSolution_Plex_Vec", &shifto);CHKERRQ(ierr);
8756   if (!shifto) {
8757     ierr = DMCreateAffineInterpolationCorrection_Plex(coarse, fine, &shift);CHKERRQ(ierr);
8758     ierr = PetscObjectCompose((PetscObject)interp, "_DMInterpolateSolution_Plex_Vec", (PetscObject) shift);CHKERRQ(ierr);
8759     shifto = (PetscObject) shift;
8760     ierr = VecDestroy(&shift);CHKERRQ(ierr);
8761   }
8762   shift = (Vec) shifto;
8763   ierr = MatInterpolate(interp, coarseSol, fineSol);CHKERRQ(ierr);
8764   ierr = VecAXPY(fineSol, 1.0, shift);CHKERRQ(ierr);
8765   ierr = MatDestroy(&interp);CHKERRQ(ierr);
8766   PetscFunctionReturn(0);
8767 }
8768 
8769 /* Pointwise interpolation
8770      Just code FEM for now
8771      u^f = I u^c
8772      sum_k u^f_k phi^f_k = I sum_j u^c_j phi^c_j
8773      u^f_i = sum_j psi^f_i I phi^c_j u^c_j
8774      I_{ij} = psi^f_i phi^c_j
8775 */
8776 PetscErrorCode DMCreateInterpolation_Plex(DM dmCoarse, DM dmFine, Mat *interpolation, Vec *scaling)
8777 {
8778   PetscSection   gsc, gsf;
8779   PetscInt       m, n;
8780   void          *ctx;
8781   DM             cdm;
8782   PetscBool      regular, ismatis, isRefined = dmCoarse->data == dmFine->data ? PETSC_FALSE : PETSC_TRUE;
8783   PetscErrorCode ierr;
8784 
8785   PetscFunctionBegin;
8786   ierr = DMGetGlobalSection(dmFine, &gsf);CHKERRQ(ierr);
8787   ierr = PetscSectionGetConstrainedStorageSize(gsf, &m);CHKERRQ(ierr);
8788   ierr = DMGetGlobalSection(dmCoarse, &gsc);CHKERRQ(ierr);
8789   ierr = PetscSectionGetConstrainedStorageSize(gsc, &n);CHKERRQ(ierr);
8790 
8791   ierr = PetscStrcmp(dmCoarse->mattype, MATIS, &ismatis);CHKERRQ(ierr);
8792   ierr = MatCreate(PetscObjectComm((PetscObject) dmCoarse), interpolation);CHKERRQ(ierr);
8793   ierr = MatSetSizes(*interpolation, m, n, PETSC_DETERMINE, PETSC_DETERMINE);CHKERRQ(ierr);
8794   ierr = MatSetType(*interpolation, ismatis ? MATAIJ : dmCoarse->mattype);CHKERRQ(ierr);
8795   ierr = DMGetApplicationContext(dmFine, &ctx);CHKERRQ(ierr);
8796 
8797   ierr = DMGetCoarseDM(dmFine, &cdm);CHKERRQ(ierr);
8798   ierr = DMPlexGetRegularRefinement(dmFine, &regular);CHKERRQ(ierr);
8799   if (!isRefined || (regular && cdm == dmCoarse)) {ierr = DMPlexComputeInterpolatorNested(dmCoarse, dmFine, isRefined, *interpolation, ctx);CHKERRQ(ierr);}
8800   else                                            {ierr = DMPlexComputeInterpolatorGeneral(dmCoarse, dmFine, *interpolation, ctx);CHKERRQ(ierr);}
8801   ierr = MatViewFromOptions(*interpolation, NULL, "-interp_mat_view");CHKERRQ(ierr);
8802   if (scaling) {
8803     /* Use naive scaling */
8804     ierr = DMCreateInterpolationScale(dmCoarse, dmFine, *interpolation, scaling);CHKERRQ(ierr);
8805   }
8806   PetscFunctionReturn(0);
8807 }
8808 
8809 PetscErrorCode DMCreateInjection_Plex(DM dmCoarse, DM dmFine, Mat *mat)
8810 {
8811   PetscErrorCode ierr;
8812   VecScatter     ctx;
8813 
8814   PetscFunctionBegin;
8815   ierr = DMPlexComputeInjectorFEM(dmCoarse, dmFine, &ctx, NULL);CHKERRQ(ierr);
8816   ierr = MatCreateScatter(PetscObjectComm((PetscObject)ctx), ctx, mat);CHKERRQ(ierr);
8817   ierr = VecScatterDestroy(&ctx);CHKERRQ(ierr);
8818   PetscFunctionReturn(0);
8819 }
8820 
8821 static void g0_identity_private(PetscInt dim, PetscInt Nf, PetscInt NfAux,
8822                                 const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
8823                                 const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
8824                                 PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g0[])
8825 {
8826   g0[0] = 1.0;
8827 }
8828 
8829 PetscErrorCode DMCreateMassMatrix_Plex(DM dmCoarse, DM dmFine, Mat *mass)
8830 {
8831   PetscSection   gsc, gsf;
8832   PetscInt       m, n;
8833   void          *ctx;
8834   DM             cdm;
8835   PetscBool      regular;
8836   PetscErrorCode ierr;
8837 
8838   PetscFunctionBegin;
8839   if (dmFine == dmCoarse) {
8840     DM       dmc;
8841     PetscDS  ds;
8842     Vec      u;
8843     IS       cellIS;
8844     PetscFormKey key;
8845     PetscInt depth;
8846 
8847     ierr = DMClone(dmFine, &dmc);CHKERRQ(ierr);
8848     ierr = DMCopyDisc(dmFine, dmc);CHKERRQ(ierr);
8849     ierr = DMGetDS(dmc, &ds);CHKERRQ(ierr);
8850     ierr = PetscDSSetJacobian(ds, 0, 0, g0_identity_private, NULL, NULL, NULL);CHKERRQ(ierr);
8851     ierr = DMCreateMatrix(dmc, mass);CHKERRQ(ierr);
8852     ierr = DMGetGlobalVector(dmc, &u);CHKERRQ(ierr);
8853     ierr = DMPlexGetDepth(dmc, &depth);CHKERRQ(ierr);
8854     ierr = DMGetStratumIS(dmc, "depth", depth, &cellIS);CHKERRQ(ierr);
8855     ierr = MatZeroEntries(*mass);CHKERRQ(ierr);
8856     key.label = NULL;
8857     key.value = 0;
8858     key.field = 0;
8859     key.part  = 0;
8860     ierr = DMPlexComputeJacobian_Internal(dmc, key, cellIS, 0.0, 0.0, u, NULL, *mass, *mass, NULL);CHKERRQ(ierr);
8861     ierr = ISDestroy(&cellIS);CHKERRQ(ierr);
8862     ierr = DMRestoreGlobalVector(dmc, &u);CHKERRQ(ierr);
8863     ierr = DMDestroy(&dmc);CHKERRQ(ierr);
8864   } else {
8865     ierr = DMGetGlobalSection(dmFine, &gsf);CHKERRQ(ierr);
8866     ierr = PetscSectionGetConstrainedStorageSize(gsf, &m);CHKERRQ(ierr);
8867     ierr = DMGetGlobalSection(dmCoarse, &gsc);CHKERRQ(ierr);
8868     ierr = PetscSectionGetConstrainedStorageSize(gsc, &n);CHKERRQ(ierr);
8869 
8870     ierr = MatCreate(PetscObjectComm((PetscObject) dmCoarse), mass);CHKERRQ(ierr);
8871     ierr = MatSetSizes(*mass, m, n, PETSC_DETERMINE, PETSC_DETERMINE);CHKERRQ(ierr);
8872     ierr = MatSetType(*mass, dmCoarse->mattype);CHKERRQ(ierr);
8873     ierr = DMGetApplicationContext(dmFine, &ctx);CHKERRQ(ierr);
8874 
8875     ierr = DMGetCoarseDM(dmFine, &cdm);CHKERRQ(ierr);
8876     ierr = DMPlexGetRegularRefinement(dmFine, &regular);CHKERRQ(ierr);
8877     if (regular && cdm == dmCoarse) {ierr = DMPlexComputeMassMatrixNested(dmCoarse, dmFine, *mass, ctx);CHKERRQ(ierr);}
8878     else                            {ierr = DMPlexComputeMassMatrixGeneral(dmCoarse, dmFine, *mass, ctx);CHKERRQ(ierr);}
8879   }
8880   ierr = MatViewFromOptions(*mass, NULL, "-mass_mat_view");CHKERRQ(ierr);
8881   PetscFunctionReturn(0);
8882 }
8883 
8884 /*@
8885   DMPlexGetRegularRefinement - Get the flag indicating that this mesh was obtained by regular refinement from its coarse mesh
8886 
8887   Input Parameter:
8888 . dm - The DMPlex object
8889 
8890   Output Parameter:
8891 . regular - The flag
8892 
8893   Level: intermediate
8894 
8895 .seealso: DMPlexSetRegularRefinement()
8896 @*/
8897 PetscErrorCode DMPlexGetRegularRefinement(DM dm, PetscBool *regular)
8898 {
8899   PetscFunctionBegin;
8900   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8901   PetscValidPointer(regular, 2);
8902   *regular = ((DM_Plex *) dm->data)->regularRefinement;
8903   PetscFunctionReturn(0);
8904 }
8905 
8906 /*@
8907   DMPlexSetRegularRefinement - Set the flag indicating that this mesh was obtained by regular refinement from its coarse mesh
8908 
8909   Input Parameters:
8910 + dm - The DMPlex object
8911 - regular - The flag
8912 
8913   Level: intermediate
8914 
8915 .seealso: DMPlexGetRegularRefinement()
8916 @*/
8917 PetscErrorCode DMPlexSetRegularRefinement(DM dm, PetscBool regular)
8918 {
8919   PetscFunctionBegin;
8920   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8921   ((DM_Plex *) dm->data)->regularRefinement = regular;
8922   PetscFunctionReturn(0);
8923 }
8924 
8925 /*@
8926   DMPlexGetCellRefinerType - Get the strategy for refining a cell
8927 
8928   Input Parameter:
8929 . dm - The DMPlex object
8930 
8931   Output Parameter:
8932 . cr - The strategy number
8933 
8934   Level: intermediate
8935 
8936 .seealso: DMPlexSetCellRefinerType(), DMPlexSetRegularRefinement()
8937 @*/
8938 PetscErrorCode DMPlexGetCellRefinerType(DM dm, DMPlexCellRefinerType *cr)
8939 {
8940   PetscFunctionBegin;
8941   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8942   PetscValidPointer(cr, 2);
8943   *cr = ((DM_Plex *) dm->data)->cellRefiner;
8944   PetscFunctionReturn(0);
8945 }
8946 
8947 /*@
8948   DMPlexSetCellRefinerType - Set the strategy for refining a cell
8949 
8950   Input Parameters:
8951 + dm - The DMPlex object
8952 - cr - The strategy number
8953 
8954   Level: intermediate
8955 
8956 .seealso: DMPlexGetCellRefinerType(), DMPlexGetRegularRefinement()
8957 @*/
8958 PetscErrorCode DMPlexSetCellRefinerType(DM dm, DMPlexCellRefinerType cr)
8959 {
8960   PetscFunctionBegin;
8961   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8962   ((DM_Plex *) dm->data)->cellRefiner = cr;
8963   PetscFunctionReturn(0);
8964 }
8965 
8966 /* anchors */
8967 /*@
8968   DMPlexGetAnchors - Get the layout of the anchor (point-to-point) constraints.  Typically, the user will not have to
8969   call DMPlexGetAnchors() directly: if there are anchors, then DMPlexGetAnchors() is called during DMGetConstraints().
8970 
8971   not collective
8972 
8973   Input Parameters:
8974 . dm - The DMPlex object
8975 
8976   Output Parameters:
8977 + anchorSection - If not NULL, set to the section describing which points anchor the constrained points.
8978 - anchorIS - If not NULL, set to the list of anchors indexed by anchorSection
8979 
8980   Level: intermediate
8981 
8982 .seealso: DMPlexSetAnchors(), DMGetConstraints(), DMSetConstraints()
8983 @*/
8984 PetscErrorCode DMPlexGetAnchors(DM dm, PetscSection *anchorSection, IS *anchorIS)
8985 {
8986   DM_Plex *plex = (DM_Plex *)dm->data;
8987   PetscErrorCode ierr;
8988 
8989   PetscFunctionBegin;
8990   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8991   if (!plex->anchorSection && !plex->anchorIS && plex->createanchors) {ierr = (*plex->createanchors)(dm);CHKERRQ(ierr);}
8992   if (anchorSection) *anchorSection = plex->anchorSection;
8993   if (anchorIS) *anchorIS = plex->anchorIS;
8994   PetscFunctionReturn(0);
8995 }
8996 
8997 /*@
8998   DMPlexSetAnchors - Set the layout of the local anchor (point-to-point) constraints.  Unlike boundary conditions,
8999   when a point's degrees of freedom in a section are constrained to an outside value, the anchor constraints set a
9000   point's degrees of freedom to be a linear combination of other points' degrees of freedom.
9001 
9002   After specifying the layout of constraints with DMPlexSetAnchors(), one specifies the constraints by calling
9003   DMGetConstraints() and filling in the entries in the constraint matrix.
9004 
9005   collective on dm
9006 
9007   Input Parameters:
9008 + dm - The DMPlex object
9009 . 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).
9010 - anchorIS - The list of all anchor points.  Must have a local communicator (PETSC_COMM_SELF or derivative).
9011 
9012   The reference counts of anchorSection and anchorIS are incremented.
9013 
9014   Level: intermediate
9015 
9016 .seealso: DMPlexGetAnchors(), DMGetConstraints(), DMSetConstraints()
9017 @*/
9018 PetscErrorCode DMPlexSetAnchors(DM dm, PetscSection anchorSection, IS anchorIS)
9019 {
9020   DM_Plex        *plex = (DM_Plex *)dm->data;
9021   PetscMPIInt    result;
9022   PetscErrorCode ierr;
9023 
9024   PetscFunctionBegin;
9025   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9026   if (anchorSection) {
9027     PetscValidHeaderSpecific(anchorSection,PETSC_SECTION_CLASSID,2);
9028     ierr = MPI_Comm_compare(PETSC_COMM_SELF,PetscObjectComm((PetscObject)anchorSection),&result);CHKERRMPI(ierr);
9029     if (result != MPI_CONGRUENT && result != MPI_IDENT) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_NOTSAMECOMM,"anchor section must have local communicator");
9030   }
9031   if (anchorIS) {
9032     PetscValidHeaderSpecific(anchorIS,IS_CLASSID,3);
9033     ierr = MPI_Comm_compare(PETSC_COMM_SELF,PetscObjectComm((PetscObject)anchorIS),&result);CHKERRMPI(ierr);
9034     if (result != MPI_CONGRUENT && result != MPI_IDENT) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_NOTSAMECOMM,"anchor IS must have local communicator");
9035   }
9036 
9037   ierr = PetscObjectReference((PetscObject)anchorSection);CHKERRQ(ierr);
9038   ierr = PetscSectionDestroy(&plex->anchorSection);CHKERRQ(ierr);
9039   plex->anchorSection = anchorSection;
9040 
9041   ierr = PetscObjectReference((PetscObject)anchorIS);CHKERRQ(ierr);
9042   ierr = ISDestroy(&plex->anchorIS);CHKERRQ(ierr);
9043   plex->anchorIS = anchorIS;
9044 
9045   if (PetscUnlikelyDebug(anchorIS && anchorSection)) {
9046     PetscInt size, a, pStart, pEnd;
9047     const PetscInt *anchors;
9048 
9049     ierr = PetscSectionGetChart(anchorSection,&pStart,&pEnd);CHKERRQ(ierr);
9050     ierr = ISGetLocalSize(anchorIS,&size);CHKERRQ(ierr);
9051     ierr = ISGetIndices(anchorIS,&anchors);CHKERRQ(ierr);
9052     for (a = 0; a < size; a++) {
9053       PetscInt p;
9054 
9055       p = anchors[a];
9056       if (p >= pStart && p < pEnd) {
9057         PetscInt dof;
9058 
9059         ierr = PetscSectionGetDof(anchorSection,p,&dof);CHKERRQ(ierr);
9060         if (dof) {
9061           PetscErrorCode ierr2;
9062 
9063           ierr2 = ISRestoreIndices(anchorIS,&anchors);CHKERRQ(ierr2);
9064           SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Point %D cannot be constrained and an anchor",p);
9065         }
9066       }
9067     }
9068     ierr = ISRestoreIndices(anchorIS,&anchors);CHKERRQ(ierr);
9069   }
9070   /* reset the generic constraints */
9071   ierr = DMSetDefaultConstraints(dm,NULL,NULL);CHKERRQ(ierr);
9072   PetscFunctionReturn(0);
9073 }
9074 
9075 static PetscErrorCode DMPlexCreateConstraintSection_Anchors(DM dm, PetscSection section, PetscSection *cSec)
9076 {
9077   PetscSection anchorSection;
9078   PetscInt pStart, pEnd, sStart, sEnd, p, dof, numFields, f;
9079   PetscErrorCode ierr;
9080 
9081   PetscFunctionBegin;
9082   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9083   ierr = DMPlexGetAnchors(dm,&anchorSection,NULL);CHKERRQ(ierr);
9084   ierr = PetscSectionCreate(PETSC_COMM_SELF,cSec);CHKERRQ(ierr);
9085   ierr = PetscSectionGetNumFields(section,&numFields);CHKERRQ(ierr);
9086   if (numFields) {
9087     PetscInt f;
9088     ierr = PetscSectionSetNumFields(*cSec,numFields);CHKERRQ(ierr);
9089 
9090     for (f = 0; f < numFields; f++) {
9091       PetscInt numComp;
9092 
9093       ierr = PetscSectionGetFieldComponents(section,f,&numComp);CHKERRQ(ierr);
9094       ierr = PetscSectionSetFieldComponents(*cSec,f,numComp);CHKERRQ(ierr);
9095     }
9096   }
9097   ierr = PetscSectionGetChart(anchorSection,&pStart,&pEnd);CHKERRQ(ierr);
9098   ierr = PetscSectionGetChart(section,&sStart,&sEnd);CHKERRQ(ierr);
9099   pStart = PetscMax(pStart,sStart);
9100   pEnd   = PetscMin(pEnd,sEnd);
9101   pEnd   = PetscMax(pStart,pEnd);
9102   ierr = PetscSectionSetChart(*cSec,pStart,pEnd);CHKERRQ(ierr);
9103   for (p = pStart; p < pEnd; p++) {
9104     ierr = PetscSectionGetDof(anchorSection,p,&dof);CHKERRQ(ierr);
9105     if (dof) {
9106       ierr = PetscSectionGetDof(section,p,&dof);CHKERRQ(ierr);
9107       ierr = PetscSectionSetDof(*cSec,p,dof);CHKERRQ(ierr);
9108       for (f = 0; f < numFields; f++) {
9109         ierr = PetscSectionGetFieldDof(section,p,f,&dof);CHKERRQ(ierr);
9110         ierr = PetscSectionSetFieldDof(*cSec,p,f,dof);CHKERRQ(ierr);
9111       }
9112     }
9113   }
9114   ierr = PetscSectionSetUp(*cSec);CHKERRQ(ierr);
9115   ierr = PetscObjectSetName((PetscObject) *cSec, "Constraint Section");CHKERRQ(ierr);
9116   PetscFunctionReturn(0);
9117 }
9118 
9119 static PetscErrorCode DMPlexCreateConstraintMatrix_Anchors(DM dm, PetscSection section, PetscSection cSec, Mat *cMat)
9120 {
9121   PetscSection   aSec;
9122   PetscInt       pStart, pEnd, p, sStart, sEnd, dof, aDof, aOff, off, nnz, annz, m, n, q, a, offset, *i, *j;
9123   const PetscInt *anchors;
9124   PetscInt       numFields, f;
9125   IS             aIS;
9126   PetscErrorCode ierr;
9127   MatType        mtype;
9128   PetscBool      iscuda,iskokkos;
9129 
9130   PetscFunctionBegin;
9131   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9132   ierr = PetscSectionGetStorageSize(cSec, &m);CHKERRQ(ierr);
9133   ierr = PetscSectionGetStorageSize(section, &n);CHKERRQ(ierr);
9134   ierr = MatCreate(PETSC_COMM_SELF,cMat);CHKERRQ(ierr);
9135   ierr = MatSetSizes(*cMat,m,n,m,n);CHKERRQ(ierr);
9136   ierr = PetscStrcmp(dm->mattype,MATSEQAIJCUSPARSE,&iscuda);CHKERRQ(ierr);
9137   if (!iscuda) { ierr = PetscStrcmp(dm->mattype,MATMPIAIJCUSPARSE,&iscuda);CHKERRQ(ierr); }
9138   ierr = PetscStrcmp(dm->mattype,MATSEQAIJKOKKOS,&iskokkos);CHKERRQ(ierr);
9139   if (!iskokkos) { ierr = PetscStrcmp(dm->mattype,MATMPIAIJKOKKOS,&iskokkos);CHKERRQ(ierr); }
9140   if (iscuda) mtype = MATSEQAIJCUSPARSE;
9141   else if (iskokkos) mtype = MATSEQAIJKOKKOS;
9142   else mtype = MATSEQAIJ;
9143   ierr = MatSetType(*cMat,mtype);CHKERRQ(ierr);
9144   ierr = DMPlexGetAnchors(dm,&aSec,&aIS);CHKERRQ(ierr);
9145   ierr = ISGetIndices(aIS,&anchors);CHKERRQ(ierr);
9146   /* cSec will be a subset of aSec and section */
9147   ierr = PetscSectionGetChart(cSec,&pStart,&pEnd);CHKERRQ(ierr);
9148   ierr = PetscSectionGetChart(section,&sStart,&sEnd);CHKERRQ(ierr);
9149   ierr = PetscMalloc1(m+1,&i);CHKERRQ(ierr);
9150   i[0] = 0;
9151   ierr = PetscSectionGetNumFields(section,&numFields);CHKERRQ(ierr);
9152   for (p = pStart; p < pEnd; p++) {
9153     PetscInt rDof, rOff, r;
9154 
9155     ierr = PetscSectionGetDof(aSec,p,&rDof);CHKERRQ(ierr);
9156     if (!rDof) continue;
9157     ierr = PetscSectionGetOffset(aSec,p,&rOff);CHKERRQ(ierr);
9158     if (numFields) {
9159       for (f = 0; f < numFields; f++) {
9160         annz = 0;
9161         for (r = 0; r < rDof; r++) {
9162           a = anchors[rOff + r];
9163           if (a < sStart || a >= sEnd) continue;
9164           ierr = PetscSectionGetFieldDof(section,a,f,&aDof);CHKERRQ(ierr);
9165           annz += aDof;
9166         }
9167         ierr = PetscSectionGetFieldDof(cSec,p,f,&dof);CHKERRQ(ierr);
9168         ierr = PetscSectionGetFieldOffset(cSec,p,f,&off);CHKERRQ(ierr);
9169         for (q = 0; q < dof; q++) {
9170           i[off + q + 1] = i[off + q] + annz;
9171         }
9172       }
9173     }
9174     else {
9175       annz = 0;
9176       ierr = PetscSectionGetDof(cSec,p,&dof);CHKERRQ(ierr);
9177       for (q = 0; q < dof; q++) {
9178         a = anchors[rOff + q];
9179         if (a < sStart || a >= sEnd) continue;
9180         ierr = PetscSectionGetDof(section,a,&aDof);CHKERRQ(ierr);
9181         annz += aDof;
9182       }
9183       ierr = PetscSectionGetDof(cSec,p,&dof);CHKERRQ(ierr);
9184       ierr = PetscSectionGetOffset(cSec,p,&off);CHKERRQ(ierr);
9185       for (q = 0; q < dof; q++) {
9186         i[off + q + 1] = i[off + q] + annz;
9187       }
9188     }
9189   }
9190   nnz = i[m];
9191   ierr = PetscMalloc1(nnz,&j);CHKERRQ(ierr);
9192   offset = 0;
9193   for (p = pStart; p < pEnd; p++) {
9194     if (numFields) {
9195       for (f = 0; f < numFields; f++) {
9196         ierr = PetscSectionGetFieldDof(cSec,p,f,&dof);CHKERRQ(ierr);
9197         for (q = 0; q < dof; q++) {
9198           PetscInt rDof, rOff, r;
9199           ierr = PetscSectionGetDof(aSec,p,&rDof);CHKERRQ(ierr);
9200           ierr = PetscSectionGetOffset(aSec,p,&rOff);CHKERRQ(ierr);
9201           for (r = 0; r < rDof; r++) {
9202             PetscInt s;
9203 
9204             a = anchors[rOff + r];
9205             if (a < sStart || a >= sEnd) continue;
9206             ierr = PetscSectionGetFieldDof(section,a,f,&aDof);CHKERRQ(ierr);
9207             ierr = PetscSectionGetFieldOffset(section,a,f,&aOff);CHKERRQ(ierr);
9208             for (s = 0; s < aDof; s++) {
9209               j[offset++] = aOff + s;
9210             }
9211           }
9212         }
9213       }
9214     }
9215     else {
9216       ierr = PetscSectionGetDof(cSec,p,&dof);CHKERRQ(ierr);
9217       for (q = 0; q < dof; q++) {
9218         PetscInt rDof, rOff, r;
9219         ierr = PetscSectionGetDof(aSec,p,&rDof);CHKERRQ(ierr);
9220         ierr = PetscSectionGetOffset(aSec,p,&rOff);CHKERRQ(ierr);
9221         for (r = 0; r < rDof; r++) {
9222           PetscInt s;
9223 
9224           a = anchors[rOff + r];
9225           if (a < sStart || a >= sEnd) continue;
9226           ierr = PetscSectionGetDof(section,a,&aDof);CHKERRQ(ierr);
9227           ierr = PetscSectionGetOffset(section,a,&aOff);CHKERRQ(ierr);
9228           for (s = 0; s < aDof; s++) {
9229             j[offset++] = aOff + s;
9230           }
9231         }
9232       }
9233     }
9234   }
9235   ierr = MatSeqAIJSetPreallocationCSR(*cMat,i,j,NULL);CHKERRQ(ierr);
9236   ierr = PetscFree(i);CHKERRQ(ierr);
9237   ierr = PetscFree(j);CHKERRQ(ierr);
9238   ierr = ISRestoreIndices(aIS,&anchors);CHKERRQ(ierr);
9239   PetscFunctionReturn(0);
9240 }
9241 
9242 PetscErrorCode DMCreateDefaultConstraints_Plex(DM dm)
9243 {
9244   DM_Plex        *plex = (DM_Plex *)dm->data;
9245   PetscSection   anchorSection, section, cSec;
9246   Mat            cMat;
9247   PetscErrorCode ierr;
9248 
9249   PetscFunctionBegin;
9250   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9251   ierr = DMPlexGetAnchors(dm,&anchorSection,NULL);CHKERRQ(ierr);
9252   if (anchorSection) {
9253     PetscInt Nf;
9254 
9255     ierr = DMGetLocalSection(dm,&section);CHKERRQ(ierr);
9256     ierr = DMPlexCreateConstraintSection_Anchors(dm,section,&cSec);CHKERRQ(ierr);
9257     ierr = DMPlexCreateConstraintMatrix_Anchors(dm,section,cSec,&cMat);CHKERRQ(ierr);
9258     ierr = DMGetNumFields(dm,&Nf);CHKERRQ(ierr);
9259     if (Nf && plex->computeanchormatrix) {ierr = (*plex->computeanchormatrix)(dm,section,cSec,cMat);CHKERRQ(ierr);}
9260     ierr = DMSetDefaultConstraints(dm,cSec,cMat);CHKERRQ(ierr);
9261     ierr = PetscSectionDestroy(&cSec);CHKERRQ(ierr);
9262     ierr = MatDestroy(&cMat);CHKERRQ(ierr);
9263   }
9264   PetscFunctionReturn(0);
9265 }
9266 
9267 PetscErrorCode DMCreateSubDomainDM_Plex(DM dm, DMLabel label, PetscInt value, IS *is, DM *subdm)
9268 {
9269   IS             subis;
9270   PetscSection   section, subsection;
9271   PetscErrorCode ierr;
9272 
9273   PetscFunctionBegin;
9274   ierr = DMGetLocalSection(dm, &section);CHKERRQ(ierr);
9275   if (!section) SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "Must set default section for DM before splitting subdomain");
9276   if (!subdm)   SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "Must set output subDM for splitting subdomain");
9277   /* Create subdomain */
9278   ierr = DMPlexFilter(dm, label, value, subdm);CHKERRQ(ierr);
9279   /* Create submodel */
9280   ierr = DMPlexGetSubpointIS(*subdm, &subis);CHKERRQ(ierr);
9281   ierr = PetscSectionCreateSubmeshSection(section, subis, &subsection);CHKERRQ(ierr);
9282   ierr = DMSetLocalSection(*subdm, subsection);CHKERRQ(ierr);
9283   ierr = PetscSectionDestroy(&subsection);CHKERRQ(ierr);
9284   ierr = DMCopyDisc(dm, *subdm);CHKERRQ(ierr);
9285   /* Create map from submodel to global model */
9286   if (is) {
9287     PetscSection    sectionGlobal, subsectionGlobal;
9288     IS              spIS;
9289     const PetscInt *spmap;
9290     PetscInt       *subIndices;
9291     PetscInt        subSize = 0, subOff = 0, pStart, pEnd, p;
9292     PetscInt        Nf, f, bs = -1, bsLocal[2], bsMinMax[2];
9293 
9294     ierr = DMPlexGetSubpointIS(*subdm, &spIS);CHKERRQ(ierr);
9295     ierr = ISGetIndices(spIS, &spmap);CHKERRQ(ierr);
9296     ierr = PetscSectionGetNumFields(section, &Nf);CHKERRQ(ierr);
9297     ierr = DMGetGlobalSection(dm, &sectionGlobal);CHKERRQ(ierr);
9298     ierr = DMGetGlobalSection(*subdm, &subsectionGlobal);CHKERRQ(ierr);
9299     ierr = PetscSectionGetChart(subsection, &pStart, &pEnd);CHKERRQ(ierr);
9300     for (p = pStart; p < pEnd; ++p) {
9301       PetscInt gdof, pSubSize  = 0;
9302 
9303       ierr = PetscSectionGetDof(sectionGlobal, p, &gdof);CHKERRQ(ierr);
9304       if (gdof > 0) {
9305         for (f = 0; f < Nf; ++f) {
9306           PetscInt fdof, fcdof;
9307 
9308           ierr     = PetscSectionGetFieldDof(subsection, p, f, &fdof);CHKERRQ(ierr);
9309           ierr     = PetscSectionGetFieldConstraintDof(subsection, p, f, &fcdof);CHKERRQ(ierr);
9310           pSubSize += fdof-fcdof;
9311         }
9312         subSize += pSubSize;
9313         if (pSubSize) {
9314           if (bs < 0) {
9315             bs = pSubSize;
9316           } else if (bs != pSubSize) {
9317             /* Layout does not admit a pointwise block size */
9318             bs = 1;
9319           }
9320         }
9321       }
9322     }
9323     /* Must have same blocksize on all procs (some might have no points) */
9324     bsLocal[0] = bs < 0 ? PETSC_MAX_INT : bs; bsLocal[1] = bs;
9325     ierr = PetscGlobalMinMaxInt(PetscObjectComm((PetscObject) dm), bsLocal, bsMinMax);CHKERRQ(ierr);
9326     if (bsMinMax[0] != bsMinMax[1]) {bs = 1;}
9327     else                            {bs = bsMinMax[0];}
9328     ierr = PetscMalloc1(subSize, &subIndices);CHKERRQ(ierr);
9329     for (p = pStart; p < pEnd; ++p) {
9330       PetscInt gdof, goff;
9331 
9332       ierr = PetscSectionGetDof(subsectionGlobal, p, &gdof);CHKERRQ(ierr);
9333       if (gdof > 0) {
9334         const PetscInt point = spmap[p];
9335 
9336         ierr = PetscSectionGetOffset(sectionGlobal, point, &goff);CHKERRQ(ierr);
9337         for (f = 0; f < Nf; ++f) {
9338           PetscInt fdof, fcdof, fc, f2, poff = 0;
9339 
9340           /* Can get rid of this loop by storing field information in the global section */
9341           for (f2 = 0; f2 < f; ++f2) {
9342             ierr  = PetscSectionGetFieldDof(section, p, f2, &fdof);CHKERRQ(ierr);
9343             ierr  = PetscSectionGetFieldConstraintDof(section, p, f2, &fcdof);CHKERRQ(ierr);
9344             poff += fdof-fcdof;
9345           }
9346           ierr = PetscSectionGetFieldDof(section, p, f, &fdof);CHKERRQ(ierr);
9347           ierr = PetscSectionGetFieldConstraintDof(section, p, f, &fcdof);CHKERRQ(ierr);
9348           for (fc = 0; fc < fdof-fcdof; ++fc, ++subOff) {
9349             subIndices[subOff] = goff+poff+fc;
9350           }
9351         }
9352       }
9353     }
9354     ierr = ISRestoreIndices(spIS, &spmap);CHKERRQ(ierr);
9355     ierr = ISCreateGeneral(PetscObjectComm((PetscObject)dm), subSize, subIndices, PETSC_OWN_POINTER, is);CHKERRQ(ierr);
9356     if (bs > 1) {
9357       /* We need to check that the block size does not come from non-contiguous fields */
9358       PetscInt i, j, set = 1;
9359       for (i = 0; i < subSize; i += bs) {
9360         for (j = 0; j < bs; ++j) {
9361           if (subIndices[i+j] != subIndices[i]+j) {set = 0; break;}
9362         }
9363       }
9364       if (set) {ierr = ISSetBlockSize(*is, bs);CHKERRQ(ierr);}
9365     }
9366     /* Attach nullspace */
9367     for (f = 0; f < Nf; ++f) {
9368       (*subdm)->nullspaceConstructors[f] = dm->nullspaceConstructors[f];
9369       if ((*subdm)->nullspaceConstructors[f]) break;
9370     }
9371     if (f < Nf) {
9372       MatNullSpace nullSpace;
9373       ierr = (*(*subdm)->nullspaceConstructors[f])(*subdm, f, f, &nullSpace);CHKERRQ(ierr);
9374 
9375       ierr = PetscObjectCompose((PetscObject) *is, "nullspace", (PetscObject) nullSpace);CHKERRQ(ierr);
9376       ierr = MatNullSpaceDestroy(&nullSpace);CHKERRQ(ierr);
9377     }
9378   }
9379   PetscFunctionReturn(0);
9380 }
9381 
9382 /*@
9383   DMPlexMonitorThroughput - Report the cell throughput of FE integration
9384 
9385   Input Parameter:
9386 - dm - The DM
9387 
9388   Level: developer
9389 
9390   Options Database Keys:
9391 . -dm_plex_monitor_throughput - Activate the monitor
9392 
9393 .seealso: DMSetFromOptions(), DMPlexCreate()
9394 @*/
9395 PetscErrorCode DMPlexMonitorThroughput(DM dm, void *dummy)
9396 {
9397 #if defined(PETSC_USE_LOG)
9398   PetscStageLog      stageLog;
9399   PetscLogEvent      event;
9400   PetscLogStage      stage;
9401   PetscEventPerfInfo eventInfo;
9402   PetscReal          cellRate, flopRate;
9403   PetscInt           cStart, cEnd, Nf, N;
9404   const char        *name;
9405   PetscErrorCode     ierr;
9406 #endif
9407 
9408   PetscFunctionBegin;
9409   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9410 #if defined(PETSC_USE_LOG)
9411   ierr = PetscObjectGetName((PetscObject) dm, &name);CHKERRQ(ierr);
9412   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
9413   ierr = DMGetNumFields(dm, &Nf);CHKERRQ(ierr);
9414   ierr = PetscLogGetStageLog(&stageLog);CHKERRQ(ierr);
9415   ierr = PetscStageLogGetCurrent(stageLog, &stage);CHKERRQ(ierr);
9416   ierr = PetscLogEventGetId("DMPlexResidualFE", &event);CHKERRQ(ierr);
9417   ierr = PetscLogEventGetPerfInfo(stage, event, &eventInfo);CHKERRQ(ierr);
9418   N        = (cEnd - cStart)*Nf*eventInfo.count;
9419   flopRate = eventInfo.flops/eventInfo.time;
9420   cellRate = N/eventInfo.time;
9421   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);
9422 #else
9423   SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Plex Throughput Monitor is not supported if logging is turned off. Reconfigure using --with-log.");
9424 #endif
9425   PetscFunctionReturn(0);
9426 }
9427