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