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