xref: /petsc/src/dm/impls/plex/plex.c (revision 647d62bacb8391928cd2e1fd4b5c8cb238cecf4c)
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 PETSC_STATIC_INLINE PetscErrorCode DMPlexVecGetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[])
4670 {
4671   PetscScalar    *array, *vArray;
4672   const PetscInt *cone, *coneO;
4673   PetscInt        pStart, pEnd, p, numPoints, size = 0, offset = 0;
4674   PetscErrorCode  ierr;
4675 
4676   PetscFunctionBeginHot;
4677   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
4678   ierr = DMPlexGetConeSize(dm, point, &numPoints);CHKERRQ(ierr);
4679   ierr = DMPlexGetCone(dm, point, &cone);CHKERRQ(ierr);
4680   ierr = DMPlexGetConeOrientation(dm, point, &coneO);CHKERRQ(ierr);
4681   if (!values || !*values) {
4682     if ((point >= pStart) && (point < pEnd)) {
4683       PetscInt dof;
4684 
4685       ierr = PetscSectionGetDof(section, point, &dof);CHKERRQ(ierr);
4686       size += dof;
4687     }
4688     for (p = 0; p < numPoints; ++p) {
4689       const PetscInt cp = cone[p];
4690       PetscInt       dof;
4691 
4692       if ((cp < pStart) || (cp >= pEnd)) continue;
4693       ierr = PetscSectionGetDof(section, cp, &dof);CHKERRQ(ierr);
4694       size += dof;
4695     }
4696     if (!values) {
4697       if (csize) *csize = size;
4698       PetscFunctionReturn(0);
4699     }
4700     ierr = DMGetWorkArray(dm, size, MPIU_SCALAR, &array);CHKERRQ(ierr);
4701   } else {
4702     array = *values;
4703   }
4704   size = 0;
4705   ierr = VecGetArray(v, &vArray);CHKERRQ(ierr);
4706   if ((point >= pStart) && (point < pEnd)) {
4707     PetscInt     dof, off, d;
4708     PetscScalar *varr;
4709 
4710     ierr = PetscSectionGetDof(section, point, &dof);CHKERRQ(ierr);
4711     ierr = PetscSectionGetOffset(section, point, &off);CHKERRQ(ierr);
4712     varr = &vArray[off];
4713     for (d = 0; d < dof; ++d, ++offset) {
4714       array[offset] = varr[d];
4715     }
4716     size += dof;
4717   }
4718   for (p = 0; p < numPoints; ++p) {
4719     const PetscInt cp = cone[p];
4720     PetscInt       o  = coneO[p];
4721     PetscInt       dof, off, d;
4722     PetscScalar   *varr;
4723 
4724     if ((cp < pStart) || (cp >= pEnd)) continue;
4725     ierr = PetscSectionGetDof(section, cp, &dof);CHKERRQ(ierr);
4726     ierr = PetscSectionGetOffset(section, cp, &off);CHKERRQ(ierr);
4727     varr = &vArray[off];
4728     if (o >= 0) {
4729       for (d = 0; d < dof; ++d, ++offset) {
4730         array[offset] = varr[d];
4731       }
4732     } else {
4733       for (d = dof-1; d >= 0; --d, ++offset) {
4734         array[offset] = varr[d];
4735       }
4736     }
4737     size += dof;
4738   }
4739   ierr = VecRestoreArray(v, &vArray);CHKERRQ(ierr);
4740   if (!*values) {
4741     if (csize) *csize = size;
4742     *values = array;
4743   } else {
4744     if (size > *csize) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %D < actual size %D", *csize, size);
4745     *csize = size;
4746   }
4747   PetscFunctionReturn(0);
4748 }
4749 
4750 /* Compress out points not in the section */
4751 PETSC_STATIC_INLINE PetscErrorCode CompressPoints_Private(PetscSection section, PetscInt *numPoints, PetscInt points[])
4752 {
4753   const PetscInt np = *numPoints;
4754   PetscInt       pStart, pEnd, p, q;
4755   PetscErrorCode ierr;
4756 
4757   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
4758   for (p = 0, q = 0; p < np; ++p) {
4759     const PetscInt r = points[p*2];
4760     if ((r >= pStart) && (r < pEnd)) {
4761       points[q*2]   = r;
4762       points[q*2+1] = points[p*2+1];
4763       ++q;
4764     }
4765   }
4766   *numPoints = q;
4767   return 0;
4768 }
4769 
4770 static PetscErrorCode DMPlexTransitiveClosure_Hybrid_Internal(DM dm, PetscInt point, PetscInt np, PetscInt *numPoints, PetscInt **points)
4771 {
4772   const PetscInt *cone, *ornt;
4773   PetscInt       *pts,  *closure = NULL;
4774   PetscInt        dim, coneSize, c, d, clSize, cl;
4775   PetscErrorCode  ierr;
4776 
4777   PetscFunctionBeginHot;
4778   ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr);
4779   ierr = DMPlexGetConeSize(dm, point, &coneSize);CHKERRQ(ierr);
4780   ierr = DMPlexGetCone(dm, point, &cone);CHKERRQ(ierr);
4781   ierr = DMPlexGetConeOrientation(dm, point, &ornt);CHKERRQ(ierr);
4782   ierr = DMPlexGetTransitiveClosure(dm, cone[0], PETSC_TRUE, &clSize, &closure);CHKERRQ(ierr);
4783   ierr = DMGetWorkArray(dm, np*2, MPIU_INT, &pts);CHKERRQ(ierr);
4784   c    = 0;
4785   pts[c*2+0] = point;
4786   pts[c*2+1] = 0;
4787   ++c;
4788   for (cl = 0; cl < clSize*2; cl += 2, ++c) {pts[c*2+0] = closure[cl]; pts[c*2+1] = closure[cl+1];}
4789   ierr = DMPlexGetTransitiveClosure(dm, cone[1], PETSC_TRUE, &clSize, &closure);CHKERRQ(ierr);
4790   for (cl = 0; cl < clSize*2; cl += 2, ++c) {pts[c*2+0] = closure[cl]; pts[c*2+1] = closure[cl+1];}
4791   ierr = DMPlexRestoreTransitiveClosure(dm, cone[0], PETSC_TRUE, &clSize, &closure);CHKERRQ(ierr);
4792   if (dim >= 2) {
4793     for (d = 2; d < coneSize; ++d, ++c) {pts[c*2+0] = cone[d]; pts[c*2+1] = ornt[d];}
4794   }
4795   if (dim >= 3) {
4796     for (d = 2; d < coneSize; ++d) {
4797       const PetscInt  fpoint = cone[d];
4798       const PetscInt *fcone;
4799       PetscInt        fconeSize, fc, i;
4800 
4801       ierr = DMPlexGetConeSize(dm, fpoint, &fconeSize);CHKERRQ(ierr);
4802       ierr = DMPlexGetCone(dm, fpoint, &fcone);CHKERRQ(ierr);
4803       for (fc = 0; fc < fconeSize; ++fc) {
4804         for (i = 0; i < c; ++i) if (pts[i*2] == fcone[fc]) break;
4805         if (i == c) {pts[c*2+0] = fcone[fc]; pts[c*2+1] = 0; ++c;}
4806       }
4807     }
4808   }
4809   if (c != np) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid closure for hybrid point %D, size %D != %D", point, c, np);
4810   *numPoints = np;
4811   *points    = pts;
4812   PetscFunctionReturn(0);
4813 }
4814 
4815 /* Compressed closure does not apply closure permutation */
4816 PetscErrorCode DMPlexGetCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp)
4817 {
4818   const PetscInt *cla = NULL;
4819   PetscInt       np, *pts = NULL;
4820   PetscErrorCode ierr;
4821 
4822   PetscFunctionBeginHot;
4823   ierr = PetscSectionGetClosureIndex(section, (PetscObject) dm, clSec, clPoints);CHKERRQ(ierr);
4824   if (*clPoints) {
4825     PetscInt dof, off;
4826 
4827     ierr = PetscSectionGetDof(*clSec, point, &dof);CHKERRQ(ierr);
4828     ierr = PetscSectionGetOffset(*clSec, point, &off);CHKERRQ(ierr);
4829     ierr = ISGetIndices(*clPoints, &cla);CHKERRQ(ierr);
4830     np   = dof/2;
4831     pts  = (PetscInt *) &cla[off];
4832   } else {
4833     DMPolytopeType ct;
4834 
4835     /* Do not make the label if it does not exist */
4836     if (!dm->celltypeLabel) {ct = DM_POLYTOPE_POINT;}
4837     else                    {ierr = DMPlexGetCellType(dm, point, &ct);CHKERRQ(ierr);}
4838     switch (ct) {
4839       case DM_POLYTOPE_SEG_PRISM_TENSOR:
4840         ierr = DMPlexTransitiveClosure_Hybrid_Internal(dm, point, 9, &np, &pts);CHKERRQ(ierr);
4841         break;
4842       case DM_POLYTOPE_TRI_PRISM_TENSOR:
4843         ierr = DMPlexTransitiveClosure_Hybrid_Internal(dm, point, 21, &np, &pts);CHKERRQ(ierr);
4844         break;
4845       case DM_POLYTOPE_QUAD_PRISM_TENSOR:
4846         ierr = DMPlexTransitiveClosure_Hybrid_Internal(dm, point, 27, &np, &pts);CHKERRQ(ierr);
4847         break;
4848       default:
4849         ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &np, &pts);CHKERRQ(ierr);
4850     }
4851     ierr = CompressPoints_Private(section, &np, pts);CHKERRQ(ierr);
4852   }
4853   *numPoints = np;
4854   *points    = pts;
4855   *clp       = cla;
4856   PetscFunctionReturn(0);
4857 }
4858 
4859 PetscErrorCode DMPlexRestoreCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp)
4860 {
4861   PetscErrorCode ierr;
4862 
4863   PetscFunctionBeginHot;
4864   if (!*clPoints) {
4865     ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, numPoints, points);CHKERRQ(ierr);
4866   } else {
4867     ierr = ISRestoreIndices(*clPoints, clp);CHKERRQ(ierr);
4868   }
4869   *numPoints = 0;
4870   *points    = NULL;
4871   *clSec     = NULL;
4872   *clPoints  = NULL;
4873   *clp       = NULL;
4874   PetscFunctionReturn(0);
4875 }
4876 
4877 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[])
4878 {
4879   PetscInt          offset = 0, p;
4880   const PetscInt    **perms = NULL;
4881   const PetscScalar **flips = NULL;
4882   PetscErrorCode    ierr;
4883 
4884   PetscFunctionBeginHot;
4885   *size = 0;
4886   ierr = PetscSectionGetPointSyms(section,numPoints,points,&perms,&flips);CHKERRQ(ierr);
4887   for (p = 0; p < numPoints; p++) {
4888     const PetscInt    point = points[2*p];
4889     const PetscInt    *perm = perms ? perms[p] : NULL;
4890     const PetscScalar *flip = flips ? flips[p] : NULL;
4891     PetscInt          dof, off, d;
4892     const PetscScalar *varr;
4893 
4894     ierr = PetscSectionGetDof(section, point, &dof);CHKERRQ(ierr);
4895     ierr = PetscSectionGetOffset(section, point, &off);CHKERRQ(ierr);
4896     varr = &vArray[off];
4897     if (clperm) {
4898       if (perm) {
4899         for (d = 0; d < dof; d++) array[clperm[offset + perm[d]]]  = varr[d];
4900       } else {
4901         for (d = 0; d < dof; d++) array[clperm[offset +      d ]]  = varr[d];
4902       }
4903       if (flip) {
4904         for (d = 0; d < dof; d++) array[clperm[offset +      d ]] *= flip[d];
4905       }
4906     } else {
4907       if (perm) {
4908         for (d = 0; d < dof; d++) array[offset + perm[d]]  = varr[d];
4909       } else {
4910         for (d = 0; d < dof; d++) array[offset +      d ]  = varr[d];
4911       }
4912       if (flip) {
4913         for (d = 0; d < dof; d++) array[offset +      d ] *= flip[d];
4914       }
4915     }
4916     offset += dof;
4917   }
4918   ierr = PetscSectionRestorePointSyms(section,numPoints,points,&perms,&flips);CHKERRQ(ierr);
4919   *size = offset;
4920   PetscFunctionReturn(0);
4921 }
4922 
4923 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[])
4924 {
4925   PetscInt          offset = 0, f;
4926   PetscErrorCode    ierr;
4927 
4928   PetscFunctionBeginHot;
4929   *size = 0;
4930   for (f = 0; f < numFields; ++f) {
4931     PetscInt          p;
4932     const PetscInt    **perms = NULL;
4933     const PetscScalar **flips = NULL;
4934 
4935     ierr = PetscSectionGetFieldPointSyms(section,f,numPoints,points,&perms,&flips);CHKERRQ(ierr);
4936     for (p = 0; p < numPoints; p++) {
4937       const PetscInt    point = points[2*p];
4938       PetscInt          fdof, foff, b;
4939       const PetscScalar *varr;
4940       const PetscInt    *perm = perms ? perms[p] : NULL;
4941       const PetscScalar *flip = flips ? flips[p] : NULL;
4942 
4943       ierr = PetscSectionGetFieldDof(section, point, f, &fdof);CHKERRQ(ierr);
4944       ierr = PetscSectionGetFieldOffset(section, point, f, &foff);CHKERRQ(ierr);
4945       varr = &vArray[foff];
4946       if (clperm) {
4947         if (perm) {for (b = 0; b < fdof; b++) {array[clperm[offset + perm[b]]]  = varr[b];}}
4948         else      {for (b = 0; b < fdof; b++) {array[clperm[offset +      b ]]  = varr[b];}}
4949         if (flip) {for (b = 0; b < fdof; b++) {array[clperm[offset +      b ]] *= flip[b];}}
4950       } else {
4951         if (perm) {for (b = 0; b < fdof; b++) {array[offset + perm[b]]  = varr[b];}}
4952         else      {for (b = 0; b < fdof; b++) {array[offset +      b ]  = varr[b];}}
4953         if (flip) {for (b = 0; b < fdof; b++) {array[offset +      b ] *= flip[b];}}
4954       }
4955       offset += fdof;
4956     }
4957     ierr = PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms,&flips);CHKERRQ(ierr);
4958   }
4959   *size = offset;
4960   PetscFunctionReturn(0);
4961 }
4962 
4963 /*@C
4964   DMPlexVecGetClosure - Get an array of the values on the closure of 'point'
4965 
4966   Not collective
4967 
4968   Input Parameters:
4969 + dm - The DM
4970 . section - The section describing the layout in v, or NULL to use the default section
4971 . v - The local vector
4972 . point - The point in the DM
4973 . csize - The size of the input values array, or NULL
4974 - values - An array to use for the values, or NULL to have it allocated automatically
4975 
4976   Output Parameters:
4977 + csize - The number of values in the closure
4978 - values - The array of values. If the user provided NULL, it is a borrowed array and should not be freed
4979 
4980 $ Note that DMPlexVecGetClosure/DMPlexVecRestoreClosure only allocates the values array if it set to NULL in the
4981 $ calling function. This is because DMPlexVecGetClosure() is typically called in the inner loop of a Vec or Mat
4982 $ assembly function, and a user may already have allocated storage for this operation.
4983 $
4984 $ A typical use could be
4985 $
4986 $  values = NULL;
4987 $  ierr = DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values);CHKERRQ(ierr);
4988 $  for (cl = 0; cl < clSize; ++cl) {
4989 $    <Compute on closure>
4990 $  }
4991 $  ierr = DMPlexVecRestoreClosure(dm, NULL, v, p, &clSize, &values);CHKERRQ(ierr);
4992 $
4993 $ or
4994 $
4995 $  PetscMalloc1(clMaxSize, &values);
4996 $  for (p = pStart; p < pEnd; ++p) {
4997 $    clSize = clMaxSize;
4998 $    ierr = DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values);CHKERRQ(ierr);
4999 $    for (cl = 0; cl < clSize; ++cl) {
5000 $      <Compute on closure>
5001 $    }
5002 $  }
5003 $  PetscFree(values);
5004 
5005   Fortran Notes:
5006   Since it returns an array, this routine is only available in Fortran 90, and you must
5007   include petsc.h90 in your code.
5008 
5009   The csize argument is not present in the Fortran 90 binding since it is internal to the array.
5010 
5011   Level: intermediate
5012 
5013 .seealso DMPlexVecRestoreClosure(), DMPlexVecSetClosure(), DMPlexMatSetClosure()
5014 @*/
5015 PetscErrorCode DMPlexVecGetClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[])
5016 {
5017   PetscSection       clSection;
5018   IS                 clPoints;
5019   PetscInt          *points = NULL;
5020   const PetscInt    *clp, *perm;
5021   PetscInt           depth, numFields, numPoints, asize;
5022   PetscErrorCode     ierr;
5023 
5024   PetscFunctionBeginHot;
5025   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5026   if (!section) {ierr = DMGetLocalSection(dm, &section);CHKERRQ(ierr);}
5027   PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2);
5028   PetscValidHeaderSpecific(v, VEC_CLASSID, 3);
5029   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
5030   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
5031   if (depth == 1 && numFields < 2) {
5032     ierr = DMPlexVecGetClosure_Depth1_Static(dm, section, v, point, csize, values);CHKERRQ(ierr);
5033     PetscFunctionReturn(0);
5034   }
5035   /* Get points */
5036   ierr = DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);CHKERRQ(ierr);
5037   /* Get sizes */
5038   asize = 0;
5039   for (PetscInt p = 0; p < numPoints*2; p += 2) {
5040     PetscInt dof;
5041     ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
5042     asize += dof;
5043   }
5044   if (values) {
5045     const PetscScalar *vArray;
5046     PetscInt          size;
5047 
5048     if (*values) {
5049       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);
5050     } else {ierr = DMGetWorkArray(dm, asize, MPIU_SCALAR, values);CHKERRQ(ierr);}
5051     ierr = PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject) dm, depth, asize, &perm);CHKERRQ(ierr);
5052     ierr = VecGetArrayRead(v, &vArray);CHKERRQ(ierr);
5053     /* Get values */
5054     if (numFields > 0) {ierr = DMPlexVecGetClosure_Fields_Static(dm, section, numPoints, points, numFields, perm, vArray, &size, *values);CHKERRQ(ierr);}
5055     else               {ierr = DMPlexVecGetClosure_Static(dm, section, numPoints, points, perm, vArray, &size, *values);CHKERRQ(ierr);}
5056     if (PetscUnlikely(asize != size)) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Section size %D does not match Vec closure size %D", asize, size);
5057     /* Cleanup array */
5058     ierr = VecRestoreArrayRead(v, &vArray);CHKERRQ(ierr);
5059   }
5060   if (csize) *csize = asize;
5061   /* Cleanup points */
5062   ierr = DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);CHKERRQ(ierr);
5063   PetscFunctionReturn(0);
5064 }
5065 
5066 PetscErrorCode DMPlexVecGetClosureAtDepth_Internal(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt depth, PetscInt *csize, PetscScalar *values[])
5067 {
5068   DMLabel            depthLabel;
5069   PetscSection       clSection;
5070   IS                 clPoints;
5071   PetscScalar       *array;
5072   const PetscScalar *vArray;
5073   PetscInt          *points = NULL;
5074   const PetscInt    *clp, *perm = NULL;
5075   PetscInt           mdepth, numFields, numPoints, Np = 0, p, clsize, size;
5076   PetscErrorCode     ierr;
5077 
5078   PetscFunctionBeginHot;
5079   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5080   if (!section) {ierr = DMGetLocalSection(dm, &section);CHKERRQ(ierr);}
5081   PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2);
5082   PetscValidHeaderSpecific(v, VEC_CLASSID, 3);
5083   ierr = DMPlexGetDepth(dm, &mdepth);CHKERRQ(ierr);
5084   ierr = DMPlexGetDepthLabel(dm, &depthLabel);CHKERRQ(ierr);
5085   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
5086   if (mdepth == 1 && numFields < 2) {
5087     ierr = DMPlexVecGetClosure_Depth1_Static(dm, section, v, point, csize, values);CHKERRQ(ierr);
5088     PetscFunctionReturn(0);
5089   }
5090   /* Get points */
5091   ierr = DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);CHKERRQ(ierr);
5092   for (clsize=0,p=0; p<Np; p++) {
5093     PetscInt dof;
5094     ierr = PetscSectionGetDof(section, points[2*p], &dof);CHKERRQ(ierr);
5095     clsize += dof;
5096   }
5097   ierr = PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject) dm, depth, clsize, &perm);CHKERRQ(ierr);
5098   /* Filter points */
5099   for (p = 0; p < numPoints*2; p += 2) {
5100     PetscInt dep;
5101 
5102     ierr = DMLabelGetValue(depthLabel, points[p], &dep);CHKERRQ(ierr);
5103     if (dep != depth) continue;
5104     points[Np*2+0] = points[p];
5105     points[Np*2+1] = points[p+1];
5106     ++Np;
5107   }
5108   /* Get array */
5109   if (!values || !*values) {
5110     PetscInt asize = 0, dof;
5111 
5112     for (p = 0; p < Np*2; p += 2) {
5113       ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
5114       asize += dof;
5115     }
5116     if (!values) {
5117       ierr = DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);CHKERRQ(ierr);
5118       if (csize) *csize = asize;
5119       PetscFunctionReturn(0);
5120     }
5121     ierr = DMGetWorkArray(dm, asize, MPIU_SCALAR, &array);CHKERRQ(ierr);
5122   } else {
5123     array = *values;
5124   }
5125   ierr = VecGetArrayRead(v, &vArray);CHKERRQ(ierr);
5126   /* Get values */
5127   if (numFields > 0) {ierr = DMPlexVecGetClosure_Fields_Static(dm, section, Np, points, numFields, perm, vArray, &size, array);CHKERRQ(ierr);}
5128   else               {ierr = DMPlexVecGetClosure_Static(dm, section, Np, points, perm, vArray, &size, array);CHKERRQ(ierr);}
5129   /* Cleanup points */
5130   ierr = DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);CHKERRQ(ierr);
5131   /* Cleanup array */
5132   ierr = VecRestoreArrayRead(v, &vArray);CHKERRQ(ierr);
5133   if (!*values) {
5134     if (csize) *csize = size;
5135     *values = array;
5136   } else {
5137     if (size > *csize) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %D < actual size %D", *csize, size);
5138     *csize = size;
5139   }
5140   PetscFunctionReturn(0);
5141 }
5142 
5143 /*@C
5144   DMPlexVecRestoreClosure - Restore the array of the values on the closure of 'point'
5145 
5146   Not collective
5147 
5148   Input Parameters:
5149 + dm - The DM
5150 . section - The section describing the layout in v, or NULL to use the default section
5151 . v - The local vector
5152 . point - The point in the DM
5153 . csize - The number of values in the closure, or NULL
5154 - values - The array of values, which is a borrowed array and should not be freed
5155 
5156   Note that the array values are discarded and not copied back into v. In order to copy values back to v, use DMPlexVecSetClosure()
5157 
5158   Fortran Notes:
5159   Since it returns an array, this routine is only available in Fortran 90, and you must
5160   include petsc.h90 in your code.
5161 
5162   The csize argument is not present in the Fortran 90 binding since it is internal to the array.
5163 
5164   Level: intermediate
5165 
5166 .seealso DMPlexVecGetClosure(), DMPlexVecSetClosure(), DMPlexMatSetClosure()
5167 @*/
5168 PetscErrorCode DMPlexVecRestoreClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[])
5169 {
5170   PetscInt       size = 0;
5171   PetscErrorCode ierr;
5172 
5173   PetscFunctionBegin;
5174   /* Should work without recalculating size */
5175   ierr = DMRestoreWorkArray(dm, size, MPIU_SCALAR, (void*) values);CHKERRQ(ierr);
5176   *values = NULL;
5177   PetscFunctionReturn(0);
5178 }
5179 
5180 PETSC_STATIC_INLINE void add   (PetscScalar *x, PetscScalar y) {*x += y;}
5181 PETSC_STATIC_INLINE void insert(PetscScalar *x, PetscScalar y) {*x  = y;}
5182 
5183 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[])
5184 {
5185   PetscInt        cdof;   /* The number of constraints on this point */
5186   const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
5187   PetscScalar    *a;
5188   PetscInt        off, cind = 0, k;
5189   PetscErrorCode  ierr;
5190 
5191   PetscFunctionBegin;
5192   ierr = PetscSectionGetConstraintDof(section, point, &cdof);CHKERRQ(ierr);
5193   ierr = PetscSectionGetOffset(section, point, &off);CHKERRQ(ierr);
5194   a    = &array[off];
5195   if (!cdof || setBC) {
5196     if (clperm) {
5197       if (perm) {for (k = 0; k < dof; ++k) {fuse(&a[k], values[clperm[offset+perm[k]]] * (flip ? flip[perm[k]] : 1.));}}
5198       else      {for (k = 0; k < dof; ++k) {fuse(&a[k], values[clperm[offset+     k ]] * (flip ? flip[     k ] : 1.));}}
5199     } else {
5200       if (perm) {for (k = 0; k < dof; ++k) {fuse(&a[k], values[offset+perm[k]] * (flip ? flip[perm[k]] : 1.));}}
5201       else      {for (k = 0; k < dof; ++k) {fuse(&a[k], values[offset+     k ] * (flip ? flip[     k ] : 1.));}}
5202     }
5203   } else {
5204     ierr = PetscSectionGetConstraintIndices(section, point, &cdofs);CHKERRQ(ierr);
5205     if (clperm) {
5206       if (perm) {for (k = 0; k < dof; ++k) {
5207           if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
5208           fuse(&a[k], values[clperm[offset+perm[k]]] * (flip ? flip[perm[k]] : 1.));
5209         }
5210       } else {
5211         for (k = 0; k < dof; ++k) {
5212           if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
5213           fuse(&a[k], values[clperm[offset+     k ]] * (flip ? flip[     k ] : 1.));
5214         }
5215       }
5216     } else {
5217       if (perm) {
5218         for (k = 0; k < dof; ++k) {
5219           if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
5220           fuse(&a[k], values[offset+perm[k]] * (flip ? flip[perm[k]] : 1.));
5221         }
5222       } else {
5223         for (k = 0; k < dof; ++k) {
5224           if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
5225           fuse(&a[k], values[offset+     k ] * (flip ? flip[     k ] : 1.));
5226         }
5227       }
5228     }
5229   }
5230   PetscFunctionReturn(0);
5231 }
5232 
5233 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[])
5234 {
5235   PetscInt        cdof;   /* The number of constraints on this point */
5236   const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
5237   PetscScalar    *a;
5238   PetscInt        off, cind = 0, k;
5239   PetscErrorCode  ierr;
5240 
5241   PetscFunctionBegin;
5242   ierr = PetscSectionGetConstraintDof(section, point, &cdof);CHKERRQ(ierr);
5243   ierr = PetscSectionGetOffset(section, point, &off);CHKERRQ(ierr);
5244   a    = &array[off];
5245   if (cdof) {
5246     ierr = PetscSectionGetConstraintIndices(section, point, &cdofs);CHKERRQ(ierr);
5247     if (clperm) {
5248       if (perm) {
5249         for (k = 0; k < dof; ++k) {
5250           if ((cind < cdof) && (k == cdofs[cind])) {
5251             fuse(&a[k], values[clperm[offset+perm[k]]] * (flip ? flip[perm[k]] : 1.));
5252             cind++;
5253           }
5254         }
5255       } else {
5256         for (k = 0; k < dof; ++k) {
5257           if ((cind < cdof) && (k == cdofs[cind])) {
5258             fuse(&a[k], values[clperm[offset+     k ]] * (flip ? flip[     k ] : 1.));
5259             cind++;
5260           }
5261         }
5262       }
5263     } else {
5264       if (perm) {
5265         for (k = 0; k < dof; ++k) {
5266           if ((cind < cdof) && (k == cdofs[cind])) {
5267             fuse(&a[k], values[offset+perm[k]] * (flip ? flip[perm[k]] : 1.));
5268             cind++;
5269           }
5270         }
5271       } else {
5272         for (k = 0; k < dof; ++k) {
5273           if ((cind < cdof) && (k == cdofs[cind])) {
5274             fuse(&a[k], values[offset+     k ] * (flip ? flip[     k ] : 1.));
5275             cind++;
5276           }
5277         }
5278       }
5279     }
5280   }
5281   PetscFunctionReturn(0);
5282 }
5283 
5284 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[])
5285 {
5286   PetscScalar    *a;
5287   PetscInt        fdof, foff, fcdof, foffset = *offset;
5288   const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
5289   PetscInt        cind = 0, b;
5290   PetscErrorCode  ierr;
5291 
5292   PetscFunctionBegin;
5293   ierr = PetscSectionGetFieldDof(section, point, f, &fdof);CHKERRQ(ierr);
5294   ierr = PetscSectionGetFieldConstraintDof(section, point, f, &fcdof);CHKERRQ(ierr);
5295   ierr = PetscSectionGetFieldOffset(section, point, f, &foff);CHKERRQ(ierr);
5296   a    = &array[foff];
5297   if (!fcdof || setBC) {
5298     if (clperm) {
5299       if (perm) {for (b = 0; b < fdof; b++) {fuse(&a[b], values[clperm[foffset+perm[b]]] * (flip ? flip[perm[b]] : 1.));}}
5300       else      {for (b = 0; b < fdof; b++) {fuse(&a[b], values[clperm[foffset+     b ]] * (flip ? flip[     b ] : 1.));}}
5301     } else {
5302       if (perm) {for (b = 0; b < fdof; b++) {fuse(&a[b], values[foffset+perm[b]] * (flip ? flip[perm[b]] : 1.));}}
5303       else      {for (b = 0; b < fdof; b++) {fuse(&a[b], values[foffset+     b ] * (flip ? flip[     b ] : 1.));}}
5304     }
5305   } else {
5306     ierr = PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);CHKERRQ(ierr);
5307     if (clperm) {
5308       if (perm) {
5309         for (b = 0; b < fdof; b++) {
5310           if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; continue;}
5311           fuse(&a[b], values[clperm[foffset+perm[b]]] * (flip ? flip[perm[b]] : 1.));
5312         }
5313       } else {
5314         for (b = 0; b < fdof; b++) {
5315           if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; continue;}
5316           fuse(&a[b], values[clperm[foffset+     b ]] * (flip ? flip[     b ] : 1.));
5317         }
5318       }
5319     } else {
5320       if (perm) {
5321         for (b = 0; b < fdof; b++) {
5322           if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; continue;}
5323           fuse(&a[b], values[foffset+perm[b]] * (flip ? flip[perm[b]] : 1.));
5324         }
5325       } else {
5326         for (b = 0; b < fdof; b++) {
5327           if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; continue;}
5328           fuse(&a[b], values[foffset+     b ] * (flip ? flip[     b ] : 1.));
5329         }
5330       }
5331     }
5332   }
5333   *offset += fdof;
5334   PetscFunctionReturn(0);
5335 }
5336 
5337 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[])
5338 {
5339   PetscScalar    *a;
5340   PetscInt        fdof, foff, fcdof, foffset = *offset;
5341   const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
5342   PetscInt        Nc, cind = 0, ncind = 0, b;
5343   PetscBool       ncSet, fcSet;
5344   PetscErrorCode  ierr;
5345 
5346   PetscFunctionBegin;
5347   ierr = PetscSectionGetFieldComponents(section, f, &Nc);CHKERRQ(ierr);
5348   ierr = PetscSectionGetFieldDof(section, point, f, &fdof);CHKERRQ(ierr);
5349   ierr = PetscSectionGetFieldConstraintDof(section, point, f, &fcdof);CHKERRQ(ierr);
5350   ierr = PetscSectionGetFieldOffset(section, point, f, &foff);CHKERRQ(ierr);
5351   a    = &array[foff];
5352   if (fcdof) {
5353     /* We just override fcdof and fcdofs with Ncc and comps */
5354     ierr = PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);CHKERRQ(ierr);
5355     if (clperm) {
5356       if (perm) {
5357         if (comps) {
5358           for (b = 0; b < fdof; b++) {
5359             ncSet = fcSet = PETSC_FALSE;
5360             if (b%Nc == comps[ncind]) {ncind = (ncind+1)%Ncc; ncSet = PETSC_TRUE;}
5361             if ((cind < fcdof) && (b == fcdofs[cind])) {++cind;  fcSet = PETSC_TRUE;}
5362             if (ncSet && fcSet) {fuse(&a[b], values[clperm[foffset+perm[b]]] * (flip ? flip[perm[b]] : 1.));}
5363           }
5364         } else {
5365           for (b = 0; b < fdof; b++) {
5366             if ((cind < fcdof) && (b == fcdofs[cind])) {
5367               fuse(&a[b], values[clperm[foffset+perm[b]]] * (flip ? flip[perm[b]] : 1.));
5368               ++cind;
5369             }
5370           }
5371         }
5372       } else {
5373         if (comps) {
5374           for (b = 0; b < fdof; b++) {
5375             ncSet = fcSet = PETSC_FALSE;
5376             if (b%Nc == comps[ncind]) {ncind = (ncind+1)%Ncc; ncSet = PETSC_TRUE;}
5377             if ((cind < fcdof) && (b == fcdofs[cind])) {++cind;  fcSet = PETSC_TRUE;}
5378             if (ncSet && fcSet) {fuse(&a[b], values[clperm[foffset+     b ]] * (flip ? flip[     b ] : 1.));}
5379           }
5380         } else {
5381           for (b = 0; b < fdof; b++) {
5382             if ((cind < fcdof) && (b == fcdofs[cind])) {
5383               fuse(&a[b], values[clperm[foffset+     b ]] * (flip ? flip[     b ] : 1.));
5384               ++cind;
5385             }
5386           }
5387         }
5388       }
5389     } else {
5390       if (perm) {
5391         if (comps) {
5392           for (b = 0; b < fdof; b++) {
5393             ncSet = fcSet = PETSC_FALSE;
5394             if (b%Nc == comps[ncind]) {ncind = (ncind+1)%Ncc; ncSet = PETSC_TRUE;}
5395             if ((cind < fcdof) && (b == fcdofs[cind])) {++cind;  fcSet = PETSC_TRUE;}
5396             if (ncSet && fcSet) {fuse(&a[b], values[foffset+perm[b]] * (flip ? flip[perm[b]] : 1.));}
5397           }
5398         } else {
5399           for (b = 0; b < fdof; b++) {
5400             if ((cind < fcdof) && (b == fcdofs[cind])) {
5401               fuse(&a[b], values[foffset+perm[b]] * (flip ? flip[perm[b]] : 1.));
5402               ++cind;
5403             }
5404           }
5405         }
5406       } else {
5407         if (comps) {
5408           for (b = 0; b < fdof; b++) {
5409             ncSet = fcSet = PETSC_FALSE;
5410             if (b%Nc == comps[ncind]) {ncind = (ncind+1)%Ncc; ncSet = PETSC_TRUE;}
5411             if ((cind < fcdof) && (b == fcdofs[cind])) {++cind;  fcSet = PETSC_TRUE;}
5412             if (ncSet && fcSet) {fuse(&a[b], values[foffset+     b ] * (flip ? flip[     b ] : 1.));}
5413           }
5414         } else {
5415           for (b = 0; b < fdof; b++) {
5416             if ((cind < fcdof) && (b == fcdofs[cind])) {
5417               fuse(&a[b], values[foffset+     b ] * (flip ? flip[     b ] : 1.));
5418               ++cind;
5419             }
5420           }
5421         }
5422       }
5423     }
5424   }
5425   *offset += fdof;
5426   PetscFunctionReturn(0);
5427 }
5428 
5429 PETSC_STATIC_INLINE PetscErrorCode DMPlexVecSetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode)
5430 {
5431   PetscScalar    *array;
5432   const PetscInt *cone, *coneO;
5433   PetscInt        pStart, pEnd, p, numPoints, off, dof;
5434   PetscErrorCode  ierr;
5435 
5436   PetscFunctionBeginHot;
5437   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
5438   ierr = DMPlexGetConeSize(dm, point, &numPoints);CHKERRQ(ierr);
5439   ierr = DMPlexGetCone(dm, point, &cone);CHKERRQ(ierr);
5440   ierr = DMPlexGetConeOrientation(dm, point, &coneO);CHKERRQ(ierr);
5441   ierr = VecGetArray(v, &array);CHKERRQ(ierr);
5442   for (p = 0, off = 0; p <= numPoints; ++p, off += dof) {
5443     const PetscInt cp = !p ? point : cone[p-1];
5444     const PetscInt o  = !p ? 0     : coneO[p-1];
5445 
5446     if ((cp < pStart) || (cp >= pEnd)) {dof = 0; continue;}
5447     ierr = PetscSectionGetDof(section, cp, &dof);CHKERRQ(ierr);
5448     /* ADD_VALUES */
5449     {
5450       const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
5451       PetscScalar    *a;
5452       PetscInt        cdof, coff, cind = 0, k;
5453 
5454       ierr = PetscSectionGetConstraintDof(section, cp, &cdof);CHKERRQ(ierr);
5455       ierr = PetscSectionGetOffset(section, cp, &coff);CHKERRQ(ierr);
5456       a    = &array[coff];
5457       if (!cdof) {
5458         if (o >= 0) {
5459           for (k = 0; k < dof; ++k) {
5460             a[k] += values[off+k];
5461           }
5462         } else {
5463           for (k = 0; k < dof; ++k) {
5464             a[k] += values[off+dof-k-1];
5465           }
5466         }
5467       } else {
5468         ierr = PetscSectionGetConstraintIndices(section, cp, &cdofs);CHKERRQ(ierr);
5469         if (o >= 0) {
5470           for (k = 0; k < dof; ++k) {
5471             if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
5472             a[k] += values[off+k];
5473           }
5474         } else {
5475           for (k = 0; k < dof; ++k) {
5476             if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
5477             a[k] += values[off+dof-k-1];
5478           }
5479         }
5480       }
5481     }
5482   }
5483   ierr = VecRestoreArray(v, &array);CHKERRQ(ierr);
5484   PetscFunctionReturn(0);
5485 }
5486 
5487 /*@C
5488   DMPlexVecSetClosure - Set an array of the values on the closure of 'point'
5489 
5490   Not collective
5491 
5492   Input Parameters:
5493 + dm - The DM
5494 . section - The section describing the layout in v, or NULL to use the default section
5495 . v - The local vector
5496 . point - The point in the DM
5497 . values - The array of values
5498 - mode - The insert mode. One of INSERT_ALL_VALUES, ADD_ALL_VALUES, INSERT_VALUES, ADD_VALUES, INSERT_BC_VALUES, and ADD_BC_VALUES,
5499          where INSERT_ALL_VALUES and ADD_ALL_VALUES also overwrite boundary conditions.
5500 
5501   Fortran Notes:
5502   This routine is only available in Fortran 90, and you must include petsc.h90 in your code.
5503 
5504   Level: intermediate
5505 
5506 .seealso DMPlexVecGetClosure(), DMPlexMatSetClosure()
5507 @*/
5508 PetscErrorCode DMPlexVecSetClosure(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode)
5509 {
5510   PetscSection    clSection;
5511   IS              clPoints;
5512   PetscScalar    *array;
5513   PetscInt       *points = NULL;
5514   const PetscInt *clp, *clperm = NULL;
5515   PetscInt        depth, numFields, numPoints, p, clsize;
5516   PetscErrorCode  ierr;
5517 
5518   PetscFunctionBeginHot;
5519   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5520   if (!section) {ierr = DMGetLocalSection(dm, &section);CHKERRQ(ierr);}
5521   PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2);
5522   PetscValidHeaderSpecific(v, VEC_CLASSID, 3);
5523   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
5524   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
5525   if (depth == 1 && numFields < 2 && mode == ADD_VALUES) {
5526     ierr = DMPlexVecSetClosure_Depth1_Static(dm, section, v, point, values, mode);CHKERRQ(ierr);
5527     PetscFunctionReturn(0);
5528   }
5529   /* Get points */
5530   ierr = DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);CHKERRQ(ierr);
5531   for (clsize=0,p=0; p<numPoints; p++) {
5532     PetscInt dof;
5533     ierr = PetscSectionGetDof(section, points[2*p], &dof);CHKERRQ(ierr);
5534     clsize += dof;
5535   }
5536   ierr = PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject) dm, depth, clsize, &clperm);CHKERRQ(ierr);
5537   /* Get array */
5538   ierr = VecGetArray(v, &array);CHKERRQ(ierr);
5539   /* Get values */
5540   if (numFields > 0) {
5541     PetscInt offset = 0, f;
5542     for (f = 0; f < numFields; ++f) {
5543       const PetscInt    **perms = NULL;
5544       const PetscScalar **flips = NULL;
5545 
5546       ierr = PetscSectionGetFieldPointSyms(section,f,numPoints,points,&perms,&flips);CHKERRQ(ierr);
5547       switch (mode) {
5548       case INSERT_VALUES:
5549         for (p = 0; p < numPoints; p++) {
5550           const PetscInt    point = points[2*p];
5551           const PetscInt    *perm = perms ? perms[p] : NULL;
5552           const PetscScalar *flip = flips ? flips[p] : NULL;
5553           updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, clperm, values, &offset, array);
5554         } break;
5555       case INSERT_ALL_VALUES:
5556         for (p = 0; p < numPoints; p++) {
5557           const PetscInt    point = points[2*p];
5558           const PetscInt    *perm = perms ? perms[p] : NULL;
5559           const PetscScalar *flip = flips ? flips[p] : NULL;
5560           updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, clperm, values, &offset, array);
5561         } break;
5562       case INSERT_BC_VALUES:
5563         for (p = 0; p < numPoints; p++) {
5564           const PetscInt    point = points[2*p];
5565           const PetscInt    *perm = perms ? perms[p] : NULL;
5566           const PetscScalar *flip = flips ? flips[p] : NULL;
5567           updatePointFieldsBC_private(section, point, perm, flip, f, -1, NULL, insert, clperm, values, &offset, array);
5568         } break;
5569       case ADD_VALUES:
5570         for (p = 0; p < numPoints; p++) {
5571           const PetscInt    point = points[2*p];
5572           const PetscInt    *perm = perms ? perms[p] : NULL;
5573           const PetscScalar *flip = flips ? flips[p] : NULL;
5574           updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, clperm, values, &offset, array);
5575         } break;
5576       case ADD_ALL_VALUES:
5577         for (p = 0; p < numPoints; p++) {
5578           const PetscInt    point = points[2*p];
5579           const PetscInt    *perm = perms ? perms[p] : NULL;
5580           const PetscScalar *flip = flips ? flips[p] : NULL;
5581           updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, clperm, values, &offset, array);
5582         } break;
5583       case ADD_BC_VALUES:
5584         for (p = 0; p < numPoints; p++) {
5585           const PetscInt    point = points[2*p];
5586           const PetscInt    *perm = perms ? perms[p] : NULL;
5587           const PetscScalar *flip = flips ? flips[p] : NULL;
5588           updatePointFieldsBC_private(section, point, perm, flip, f, -1, NULL, add, clperm, values, &offset, array);
5589         } break;
5590       default:
5591         SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode);
5592       }
5593       ierr = PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms,&flips);CHKERRQ(ierr);
5594     }
5595   } else {
5596     PetscInt dof, off;
5597     const PetscInt    **perms = NULL;
5598     const PetscScalar **flips = NULL;
5599 
5600     ierr = PetscSectionGetPointSyms(section,numPoints,points,&perms,&flips);CHKERRQ(ierr);
5601     switch (mode) {
5602     case INSERT_VALUES:
5603       for (p = 0, off = 0; p < numPoints; p++, off += dof) {
5604         const PetscInt    point = points[2*p];
5605         const PetscInt    *perm = perms ? perms[p] : NULL;
5606         const PetscScalar *flip = flips ? flips[p] : NULL;
5607         ierr = PetscSectionGetDof(section, point, &dof);CHKERRQ(ierr);
5608         updatePoint_private(section, point, dof, insert, PETSC_FALSE, perm, flip, clperm, values, off, array);
5609       } break;
5610     case INSERT_ALL_VALUES:
5611       for (p = 0, off = 0; p < numPoints; p++, off += dof) {
5612         const PetscInt    point = points[2*p];
5613         const PetscInt    *perm = perms ? perms[p] : NULL;
5614         const PetscScalar *flip = flips ? flips[p] : NULL;
5615         ierr = PetscSectionGetDof(section, point, &dof);CHKERRQ(ierr);
5616         updatePoint_private(section, point, dof, insert, PETSC_TRUE,  perm, flip, clperm, values, off, array);
5617       } break;
5618     case INSERT_BC_VALUES:
5619       for (p = 0, off = 0; p < numPoints; p++, off += dof) {
5620         const PetscInt    point = points[2*p];
5621         const PetscInt    *perm = perms ? perms[p] : NULL;
5622         const PetscScalar *flip = flips ? flips[p] : NULL;
5623         ierr = PetscSectionGetDof(section, point, &dof);CHKERRQ(ierr);
5624         updatePointBC_private(section, point, dof, insert,  perm, flip, clperm, values, off, array);
5625       } break;
5626     case ADD_VALUES:
5627       for (p = 0, off = 0; p < numPoints; p++, off += dof) {
5628         const PetscInt    point = points[2*p];
5629         const PetscInt    *perm = perms ? perms[p] : NULL;
5630         const PetscScalar *flip = flips ? flips[p] : NULL;
5631         ierr = PetscSectionGetDof(section, point, &dof);CHKERRQ(ierr);
5632         updatePoint_private(section, point, dof, add,    PETSC_FALSE, perm, flip, clperm, values, off, array);
5633       } break;
5634     case ADD_ALL_VALUES:
5635       for (p = 0, off = 0; p < numPoints; p++, off += dof) {
5636         const PetscInt    point = points[2*p];
5637         const PetscInt    *perm = perms ? perms[p] : NULL;
5638         const PetscScalar *flip = flips ? flips[p] : NULL;
5639         ierr = PetscSectionGetDof(section, point, &dof);CHKERRQ(ierr);
5640         updatePoint_private(section, point, dof, add,    PETSC_TRUE,  perm, flip, clperm, values, off, array);
5641       } break;
5642     case ADD_BC_VALUES:
5643       for (p = 0, off = 0; p < numPoints; p++, off += dof) {
5644         const PetscInt    point = points[2*p];
5645         const PetscInt    *perm = perms ? perms[p] : NULL;
5646         const PetscScalar *flip = flips ? flips[p] : NULL;
5647         ierr = PetscSectionGetDof(section, point, &dof);CHKERRQ(ierr);
5648         updatePointBC_private(section, point, dof, add,  perm, flip, clperm, values, off, array);
5649       } break;
5650     default:
5651       SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode);
5652     }
5653     ierr = PetscSectionRestorePointSyms(section,numPoints,points,&perms,&flips);CHKERRQ(ierr);
5654   }
5655   /* Cleanup points */
5656   ierr = DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);CHKERRQ(ierr);
5657   /* Cleanup array */
5658   ierr = VecRestoreArray(v, &array);CHKERRQ(ierr);
5659   PetscFunctionReturn(0);
5660 }
5661 
5662 /* Check whether the given point is in the label. If not, update the offset to skip this point */
5663 PETSC_STATIC_INLINE PetscErrorCode CheckPoint_Private(DMLabel label, PetscInt labelId, PetscSection section, PetscInt point, PetscInt f, PetscInt *offset)
5664 {
5665   PetscFunctionBegin;
5666   if (label) {
5667     PetscInt       val, fdof;
5668     PetscErrorCode ierr;
5669 
5670     /* There is a problem with this:
5671          Suppose we have two label values, defining surfaces, interecting along a line in 3D. When we add cells to the label, the cells that
5672        touch both surfaces must pick a label value. Thus we miss setting values for the surface with that other value intersecting that cell.
5673        Thus I am only going to check val != -1, not val != labelId
5674     */
5675     ierr = DMLabelGetValue(label, point, &val);CHKERRQ(ierr);
5676     if (val < 0) {
5677       ierr = PetscSectionGetFieldDof(section, point, f, &fdof);CHKERRQ(ierr);
5678       *offset += fdof;
5679       PetscFunctionReturn(1);
5680     }
5681   }
5682   PetscFunctionReturn(0);
5683 }
5684 
5685 /* Unlike DMPlexVecSetClosure(), this uses plex-native closure permutation, not a user-specified permutation such as DMPlexSetClosurePermutationTensor(). */
5686 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)
5687 {
5688   PetscSection      clSection;
5689   IS                clPoints;
5690   PetscScalar       *array;
5691   PetscInt          *points = NULL;
5692   const PetscInt    *clp;
5693   PetscInt          numFields, numPoints, p;
5694   PetscInt          offset = 0, f;
5695   PetscErrorCode    ierr;
5696 
5697   PetscFunctionBeginHot;
5698   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5699   if (!section) {ierr = DMGetLocalSection(dm, &section);CHKERRQ(ierr);}
5700   PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2);
5701   PetscValidHeaderSpecific(v, VEC_CLASSID, 3);
5702   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
5703   /* Get points */
5704   ierr = DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);CHKERRQ(ierr);
5705   /* Get array */
5706   ierr = VecGetArray(v, &array);CHKERRQ(ierr);
5707   /* Get values */
5708   for (f = 0; f < numFields; ++f) {
5709     const PetscInt    **perms = NULL;
5710     const PetscScalar **flips = NULL;
5711 
5712     if (!fieldActive[f]) {
5713       for (p = 0; p < numPoints*2; p += 2) {
5714         PetscInt fdof;
5715         ierr = PetscSectionGetFieldDof(section, points[p], f, &fdof);CHKERRQ(ierr);
5716         offset += fdof;
5717       }
5718       continue;
5719     }
5720     ierr = PetscSectionGetFieldPointSyms(section,f,numPoints,points,&perms,&flips);CHKERRQ(ierr);
5721     switch (mode) {
5722     case INSERT_VALUES:
5723       for (p = 0; p < numPoints; p++) {
5724         const PetscInt    point = points[2*p];
5725         const PetscInt    *perm = perms ? perms[p] : NULL;
5726         const PetscScalar *flip = flips ? flips[p] : NULL;
5727         ierr = CheckPoint_Private(label, labelId, section, point, f, &offset); if (ierr) continue;
5728         updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, NULL, values, &offset, array);
5729       } break;
5730     case INSERT_ALL_VALUES:
5731       for (p = 0; p < numPoints; p++) {
5732         const PetscInt    point = points[2*p];
5733         const PetscInt    *perm = perms ? perms[p] : NULL;
5734         const PetscScalar *flip = flips ? flips[p] : NULL;
5735         ierr = CheckPoint_Private(label, labelId, section, point, f, &offset); if (ierr) continue;
5736         updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, NULL, values, &offset, array);
5737       } break;
5738     case INSERT_BC_VALUES:
5739       for (p = 0; p < numPoints; p++) {
5740         const PetscInt    point = points[2*p];
5741         const PetscInt    *perm = perms ? perms[p] : NULL;
5742         const PetscScalar *flip = flips ? flips[p] : NULL;
5743         ierr = CheckPoint_Private(label, labelId, section, point, f, &offset); if (ierr) continue;
5744         updatePointFieldsBC_private(section, point, perm, flip, f, Ncc, comps, insert, NULL, values, &offset, array);
5745       } break;
5746     case ADD_VALUES:
5747       for (p = 0; p < numPoints; p++) {
5748         const PetscInt    point = points[2*p];
5749         const PetscInt    *perm = perms ? perms[p] : NULL;
5750         const PetscScalar *flip = flips ? flips[p] : NULL;
5751         ierr = CheckPoint_Private(label, labelId, section, point, f, &offset); if (ierr) continue;
5752         updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, NULL, values, &offset, array);
5753       } break;
5754     case ADD_ALL_VALUES:
5755       for (p = 0; p < numPoints; p++) {
5756         const PetscInt    point = points[2*p];
5757         const PetscInt    *perm = perms ? perms[p] : NULL;
5758         const PetscScalar *flip = flips ? flips[p] : NULL;
5759         ierr = CheckPoint_Private(label, labelId, section, point, f, &offset); if (ierr) continue;
5760         updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, NULL, values, &offset, array);
5761       } break;
5762     default:
5763       SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode);
5764     }
5765     ierr = PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms,&flips);CHKERRQ(ierr);
5766   }
5767   /* Cleanup points */
5768   ierr = DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);CHKERRQ(ierr);
5769   /* Cleanup array */
5770   ierr = VecRestoreArray(v, &array);CHKERRQ(ierr);
5771   PetscFunctionReturn(0);
5772 }
5773 
5774 static PetscErrorCode DMPlexPrintMatSetValues(PetscViewer viewer, Mat A, PetscInt point, PetscInt numRIndices, const PetscInt rindices[], PetscInt numCIndices, const PetscInt cindices[], const PetscScalar values[])
5775 {
5776   PetscMPIInt    rank;
5777   PetscInt       i, j;
5778   PetscErrorCode ierr;
5779 
5780   PetscFunctionBegin;
5781   ierr = MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank);CHKERRMPI(ierr);
5782   ierr = PetscViewerASCIIPrintf(viewer, "[%d]mat for point %D\n", rank, point);CHKERRQ(ierr);
5783   for (i = 0; i < numRIndices; i++) {ierr = PetscViewerASCIIPrintf(viewer, "[%d]mat row indices[%D] = %D\n", rank, i, rindices[i]);CHKERRQ(ierr);}
5784   for (i = 0; i < numCIndices; i++) {ierr = PetscViewerASCIIPrintf(viewer, "[%d]mat col indices[%D] = %D\n", rank, i, cindices[i]);CHKERRQ(ierr);}
5785   numCIndices = numCIndices ? numCIndices : numRIndices;
5786   if (!values) PetscFunctionReturn(0);
5787   for (i = 0; i < numRIndices; i++) {
5788     ierr = PetscViewerASCIIPrintf(viewer, "[%d]", rank);CHKERRQ(ierr);
5789     for (j = 0; j < numCIndices; j++) {
5790 #if defined(PETSC_USE_COMPLEX)
5791       ierr = PetscViewerASCIIPrintf(viewer, " (%g,%g)", (double)PetscRealPart(values[i*numCIndices+j]), (double)PetscImaginaryPart(values[i*numCIndices+j]));CHKERRQ(ierr);
5792 #else
5793       ierr = PetscViewerASCIIPrintf(viewer, " %g", (double)values[i*numCIndices+j]);CHKERRQ(ierr);
5794 #endif
5795     }
5796     ierr = PetscViewerASCIIPrintf(viewer, "\n");CHKERRQ(ierr);
5797   }
5798   PetscFunctionReturn(0);
5799 }
5800 
5801 /*
5802   DMPlexGetIndicesPoint_Internal - Add the indices for dofs on a point to an index array
5803 
5804   Input Parameters:
5805 + section - The section for this data layout
5806 . islocal - Is the section (and thus indices being requested) local or global?
5807 . point   - The point contributing dofs with these indices
5808 . off     - The global offset of this point
5809 . loff    - The local offset of each field
5810 . setBC   - The flag determining whether to include indices of bounsary values
5811 . perm    - A permutation of the dofs on this point, or NULL
5812 - indperm - A permutation of the entire indices array, or NULL
5813 
5814   Output Parameter:
5815 . indices - Indices for dofs on this point
5816 
5817   Level: developer
5818 
5819   Note: The indices could be local or global, depending on the value of 'off'.
5820 */
5821 PetscErrorCode DMPlexGetIndicesPoint_Internal(PetscSection section, PetscBool islocal,PetscInt point, PetscInt off, PetscInt *loff, PetscBool setBC, const PetscInt perm[], const PetscInt indperm[], PetscInt indices[])
5822 {
5823   PetscInt        dof;   /* The number of unknowns on this point */
5824   PetscInt        cdof;  /* The number of constraints on this point */
5825   const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
5826   PetscInt        cind = 0, k;
5827   PetscErrorCode  ierr;
5828 
5829   PetscFunctionBegin;
5830   if (!islocal && setBC) SETERRQ(PetscObjectComm((PetscObject)section),PETSC_ERR_ARG_INCOMP,"setBC incompatible with global indices; use a local section or disable setBC");
5831   ierr = PetscSectionGetDof(section, point, &dof);CHKERRQ(ierr);
5832   ierr = PetscSectionGetConstraintDof(section, point, &cdof);CHKERRQ(ierr);
5833   if (!cdof || setBC) {
5834     for (k = 0; k < dof; ++k) {
5835       const PetscInt preind = perm ? *loff+perm[k] : *loff+k;
5836       const PetscInt ind    = indperm ? indperm[preind] : preind;
5837 
5838       indices[ind] = off + k;
5839     }
5840   } else {
5841     ierr = PetscSectionGetConstraintIndices(section, point, &cdofs);CHKERRQ(ierr);
5842     for (k = 0; k < dof; ++k) {
5843       const PetscInt preind = perm ? *loff+perm[k] : *loff+k;
5844       const PetscInt ind    = indperm ? indperm[preind] : preind;
5845 
5846       if ((cind < cdof) && (k == cdofs[cind])) {
5847         /* Insert check for returning constrained indices */
5848         indices[ind] = -(off+k+1);
5849         ++cind;
5850       } else {
5851         indices[ind] = off + k - (islocal ? 0 : cind);
5852       }
5853     }
5854   }
5855   *loff += dof;
5856   PetscFunctionReturn(0);
5857 }
5858 
5859 /*
5860  DMPlexGetIndicesPointFields_Internal - gets section indices for a point in its canonical ordering.
5861 
5862  Input Parameters:
5863 + section - a section (global or local)
5864 - islocal - PETSC_TRUE if requesting local indices (i.e., section is local); PETSC_FALSE for global
5865 . point - point within section
5866 . off - The offset of this point in the (local or global) indexed space - should match islocal and (usually) the section
5867 . foffs - array of length numFields containing the offset in canonical point ordering (the location in indices) of each field
5868 . setBC - identify constrained (boundary condition) points via involution.
5869 . perms - perms[f][permsoff][:] is a permutation of dofs within each field
5870 . permsoff - offset
5871 - indperm - index permutation
5872 
5873  Output Parameter:
5874 . foffs - each entry is incremented by the number of (unconstrained if setBC=FALSE) dofs in that field
5875 . indices - array to hold indices (as defined by section) of each dof associated with point
5876 
5877  Notes:
5878  If section is local and setBC=true, there is no distinction between constrained and unconstrained dofs.
5879  If section is local and setBC=false, the indices for constrained points are the involution -(i+1) of their position
5880  in the local vector.
5881 
5882  If section is global and setBC=false, the indices for constrained points are negative (and their value is not
5883  significant).  It is invalid to call with a global section and setBC=true.
5884 
5885  Developer Note:
5886  The section is only used for field layout, so islocal is technically a statement about the offset (off).  At some point
5887  in the future, global sections may have fields set, in which case we could pass the global section and obtain the
5888  offset could be obtained from the section instead of passing it explicitly as we do now.
5889 
5890  Example:
5891  Suppose a point contains one field with three components, and for which the unconstrained indices are {10, 11, 12}.
5892  When the middle component is constrained, we get the array {10, -12, 12} for (islocal=TRUE, setBC=FALSE).
5893  Note that -12 is the involution of 11, so the user can involute negative indices to recover local indices.
5894  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.
5895 
5896  Level: developer
5897 */
5898 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[])
5899 {
5900   PetscInt       numFields, foff, f;
5901   PetscErrorCode ierr;
5902 
5903   PetscFunctionBegin;
5904   if (!islocal && setBC) SETERRQ(PetscObjectComm((PetscObject)section),PETSC_ERR_ARG_INCOMP,"setBC incompatible with global indices; use a local section or disable setBC");
5905   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
5906   for (f = 0, foff = 0; f < numFields; ++f) {
5907     PetscInt        fdof, cfdof;
5908     const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
5909     PetscInt        cind = 0, b;
5910     const PetscInt  *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL;
5911 
5912     ierr = PetscSectionGetFieldDof(section, point, f, &fdof);CHKERRQ(ierr);
5913     ierr = PetscSectionGetFieldConstraintDof(section, point, f, &cfdof);CHKERRQ(ierr);
5914     if (!cfdof || setBC) {
5915       for (b = 0; b < fdof; ++b) {
5916         const PetscInt preind = perm ? foffs[f]+perm[b] : foffs[f]+b;
5917         const PetscInt ind    = indperm ? indperm[preind] : preind;
5918 
5919         indices[ind] = off+foff+b;
5920       }
5921     } else {
5922       ierr = PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);CHKERRQ(ierr);
5923       for (b = 0; b < fdof; ++b) {
5924         const PetscInt preind = perm ? foffs[f]+perm[b] : foffs[f]+b;
5925         const PetscInt ind    = indperm ? indperm[preind] : preind;
5926 
5927         if ((cind < cfdof) && (b == fcdofs[cind])) {
5928           indices[ind] = -(off+foff+b+1);
5929           ++cind;
5930         } else {
5931           indices[ind] = off + foff + b - (islocal ? 0 : cind);
5932         }
5933       }
5934     }
5935     foff     += (setBC || islocal ? fdof : (fdof - cfdof));
5936     foffs[f] += fdof;
5937   }
5938   PetscFunctionReturn(0);
5939 }
5940 
5941 /*
5942   This version believes the globalSection offsets for each field, rather than just the point offset
5943 
5944  . foffs - The offset into 'indices' for each field, since it is segregated by field
5945 
5946  Notes:
5947  The semantics of this function relate to that of setBC=FALSE in DMPlexGetIndicesPointFields_Internal.
5948  Since this function uses global indices, setBC=TRUE would be invalid, so no such argument exists.
5949 */
5950 static PetscErrorCode DMPlexGetIndicesPointFieldsSplit_Internal(PetscSection section, PetscSection globalSection, PetscInt point, PetscInt foffs[], const PetscInt ***perms, PetscInt permsoff, const PetscInt indperm[], PetscInt indices[])
5951 {
5952   PetscInt       numFields, foff, f;
5953   PetscErrorCode ierr;
5954 
5955   PetscFunctionBegin;
5956   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
5957   for (f = 0; f < numFields; ++f) {
5958     PetscInt        fdof, cfdof;
5959     const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
5960     PetscInt        cind = 0, b;
5961     const PetscInt  *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL;
5962 
5963     ierr = PetscSectionGetFieldDof(section, point, f, &fdof);CHKERRQ(ierr);
5964     ierr = PetscSectionGetFieldConstraintDof(section, point, f, &cfdof);CHKERRQ(ierr);
5965     ierr = PetscSectionGetFieldOffset(globalSection, point, f, &foff);CHKERRQ(ierr);
5966     if (!cfdof) {
5967       for (b = 0; b < fdof; ++b) {
5968         const PetscInt preind = perm ? foffs[f]+perm[b] : foffs[f]+b;
5969         const PetscInt ind    = indperm ? indperm[preind] : preind;
5970 
5971         indices[ind] = foff+b;
5972       }
5973     } else {
5974       ierr = PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);CHKERRQ(ierr);
5975       for (b = 0; b < fdof; ++b) {
5976         const PetscInt preind = perm ? foffs[f]+perm[b] : foffs[f]+b;
5977         const PetscInt ind    = indperm ? indperm[preind] : preind;
5978 
5979         if ((cind < cfdof) && (b == fcdofs[cind])) {
5980           indices[ind] = -(foff+b+1);
5981           ++cind;
5982         } else {
5983           indices[ind] = foff+b-cind;
5984         }
5985       }
5986     }
5987     foffs[f] += fdof;
5988   }
5989   PetscFunctionReturn(0);
5990 }
5991 
5992 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)
5993 {
5994   Mat             cMat;
5995   PetscSection    aSec, cSec;
5996   IS              aIS;
5997   PetscInt        aStart = -1, aEnd = -1;
5998   const PetscInt  *anchors;
5999   PetscInt        numFields, f, p, q, newP = 0;
6000   PetscInt        newNumPoints = 0, newNumIndices = 0;
6001   PetscInt        *newPoints, *indices, *newIndices;
6002   PetscInt        maxAnchor, maxDof;
6003   PetscInt        newOffsets[32];
6004   PetscInt        *pointMatOffsets[32];
6005   PetscInt        *newPointOffsets[32];
6006   PetscScalar     *pointMat[32];
6007   PetscScalar     *newValues=NULL,*tmpValues;
6008   PetscBool       anyConstrained = PETSC_FALSE;
6009   PetscErrorCode  ierr;
6010 
6011   PetscFunctionBegin;
6012   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6013   PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2);
6014   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
6015 
6016   ierr = DMPlexGetAnchors(dm,&aSec,&aIS);CHKERRQ(ierr);
6017   /* if there are point-to-point constraints */
6018   if (aSec) {
6019     ierr = PetscArrayzero(newOffsets, 32);CHKERRQ(ierr);
6020     ierr = ISGetIndices(aIS,&anchors);CHKERRQ(ierr);
6021     ierr = PetscSectionGetChart(aSec,&aStart,&aEnd);CHKERRQ(ierr);
6022     /* figure out how many points are going to be in the new element matrix
6023      * (we allow double counting, because it's all just going to be summed
6024      * into the global matrix anyway) */
6025     for (p = 0; p < 2*numPoints; p+=2) {
6026       PetscInt b    = points[p];
6027       PetscInt bDof = 0, bSecDof;
6028 
6029       ierr = PetscSectionGetDof(section,b,&bSecDof);CHKERRQ(ierr);
6030       if (!bSecDof) {
6031         continue;
6032       }
6033       if (b >= aStart && b < aEnd) {
6034         ierr = PetscSectionGetDof(aSec,b,&bDof);CHKERRQ(ierr);
6035       }
6036       if (bDof) {
6037         /* this point is constrained */
6038         /* it is going to be replaced by its anchors */
6039         PetscInt bOff, q;
6040 
6041         anyConstrained = PETSC_TRUE;
6042         newNumPoints  += bDof;
6043         ierr = PetscSectionGetOffset(aSec,b,&bOff);CHKERRQ(ierr);
6044         for (q = 0; q < bDof; q++) {
6045           PetscInt a = anchors[bOff + q];
6046           PetscInt aDof;
6047 
6048           ierr           = PetscSectionGetDof(section,a,&aDof);CHKERRQ(ierr);
6049           newNumIndices += aDof;
6050           for (f = 0; f < numFields; ++f) {
6051             PetscInt fDof;
6052 
6053             ierr             = PetscSectionGetFieldDof(section, a, f, &fDof);CHKERRQ(ierr);
6054             newOffsets[f+1] += fDof;
6055           }
6056         }
6057       }
6058       else {
6059         /* this point is not constrained */
6060         newNumPoints++;
6061         newNumIndices += bSecDof;
6062         for (f = 0; f < numFields; ++f) {
6063           PetscInt fDof;
6064 
6065           ierr = PetscSectionGetFieldDof(section, b, f, &fDof);CHKERRQ(ierr);
6066           newOffsets[f+1] += fDof;
6067         }
6068       }
6069     }
6070   }
6071   if (!anyConstrained) {
6072     if (outNumPoints)  *outNumPoints  = 0;
6073     if (outNumIndices) *outNumIndices = 0;
6074     if (outPoints)     *outPoints     = NULL;
6075     if (outValues)     *outValues     = NULL;
6076     if (aSec) {ierr = ISRestoreIndices(aIS,&anchors);CHKERRQ(ierr);}
6077     PetscFunctionReturn(0);
6078   }
6079 
6080   if (outNumPoints)  *outNumPoints  = newNumPoints;
6081   if (outNumIndices) *outNumIndices = newNumIndices;
6082 
6083   for (f = 0; f < numFields; ++f) newOffsets[f+1] += newOffsets[f];
6084 
6085   if (!outPoints && !outValues) {
6086     if (offsets) {
6087       for (f = 0; f <= numFields; f++) {
6088         offsets[f] = newOffsets[f];
6089       }
6090     }
6091     if (aSec) {ierr = ISRestoreIndices(aIS,&anchors);CHKERRQ(ierr);}
6092     PetscFunctionReturn(0);
6093   }
6094 
6095   if (numFields && newOffsets[numFields] != newNumIndices) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid size for closure %D should be %D", newOffsets[numFields], newNumIndices);
6096 
6097   ierr = DMGetDefaultConstraints(dm, &cSec, &cMat);CHKERRQ(ierr);
6098 
6099   /* workspaces */
6100   if (numFields) {
6101     for (f = 0; f < numFields; f++) {
6102       ierr = DMGetWorkArray(dm,numPoints+1,MPIU_INT,&pointMatOffsets[f]);CHKERRQ(ierr);
6103       ierr = DMGetWorkArray(dm,numPoints+1,MPIU_INT,&newPointOffsets[f]);CHKERRQ(ierr);
6104     }
6105   }
6106   else {
6107     ierr = DMGetWorkArray(dm,numPoints+1,MPIU_INT,&pointMatOffsets[0]);CHKERRQ(ierr);
6108     ierr = DMGetWorkArray(dm,numPoints,MPIU_INT,&newPointOffsets[0]);CHKERRQ(ierr);
6109   }
6110 
6111   /* get workspaces for the point-to-point matrices */
6112   if (numFields) {
6113     PetscInt totalOffset, totalMatOffset;
6114 
6115     for (p = 0; p < numPoints; p++) {
6116       PetscInt b    = points[2*p];
6117       PetscInt bDof = 0, bSecDof;
6118 
6119       ierr = PetscSectionGetDof(section,b,&bSecDof);CHKERRQ(ierr);
6120       if (!bSecDof) {
6121         for (f = 0; f < numFields; f++) {
6122           newPointOffsets[f][p + 1] = 0;
6123           pointMatOffsets[f][p + 1] = 0;
6124         }
6125         continue;
6126       }
6127       if (b >= aStart && b < aEnd) {
6128         ierr = PetscSectionGetDof(aSec, b, &bDof);CHKERRQ(ierr);
6129       }
6130       if (bDof) {
6131         for (f = 0; f < numFields; f++) {
6132           PetscInt fDof, q, bOff, allFDof = 0;
6133 
6134           ierr = PetscSectionGetFieldDof(section, b, f, &fDof);CHKERRQ(ierr);
6135           ierr = PetscSectionGetOffset(aSec, b, &bOff);CHKERRQ(ierr);
6136           for (q = 0; q < bDof; q++) {
6137             PetscInt a = anchors[bOff + q];
6138             PetscInt aFDof;
6139 
6140             ierr     = PetscSectionGetFieldDof(section, a, f, &aFDof);CHKERRQ(ierr);
6141             allFDof += aFDof;
6142           }
6143           newPointOffsets[f][p+1] = allFDof;
6144           pointMatOffsets[f][p+1] = fDof * allFDof;
6145         }
6146       }
6147       else {
6148         for (f = 0; f < numFields; f++) {
6149           PetscInt fDof;
6150 
6151           ierr = PetscSectionGetFieldDof(section, b, f, &fDof);CHKERRQ(ierr);
6152           newPointOffsets[f][p+1] = fDof;
6153           pointMatOffsets[f][p+1] = 0;
6154         }
6155       }
6156     }
6157     for (f = 0, totalOffset = 0, totalMatOffset = 0; f < numFields; f++) {
6158       newPointOffsets[f][0] = totalOffset;
6159       pointMatOffsets[f][0] = totalMatOffset;
6160       for (p = 0; p < numPoints; p++) {
6161         newPointOffsets[f][p+1] += newPointOffsets[f][p];
6162         pointMatOffsets[f][p+1] += pointMatOffsets[f][p];
6163       }
6164       totalOffset    = newPointOffsets[f][numPoints];
6165       totalMatOffset = pointMatOffsets[f][numPoints];
6166       ierr = DMGetWorkArray(dm,pointMatOffsets[f][numPoints],MPIU_SCALAR,&pointMat[f]);CHKERRQ(ierr);
6167     }
6168   }
6169   else {
6170     for (p = 0; p < numPoints; p++) {
6171       PetscInt b    = points[2*p];
6172       PetscInt bDof = 0, bSecDof;
6173 
6174       ierr = PetscSectionGetDof(section,b,&bSecDof);CHKERRQ(ierr);
6175       if (!bSecDof) {
6176         newPointOffsets[0][p + 1] = 0;
6177         pointMatOffsets[0][p + 1] = 0;
6178         continue;
6179       }
6180       if (b >= aStart && b < aEnd) {
6181         ierr = PetscSectionGetDof(aSec, b, &bDof);CHKERRQ(ierr);
6182       }
6183       if (bDof) {
6184         PetscInt bOff, q, allDof = 0;
6185 
6186         ierr = PetscSectionGetOffset(aSec, b, &bOff);CHKERRQ(ierr);
6187         for (q = 0; q < bDof; q++) {
6188           PetscInt a = anchors[bOff + q], aDof;
6189 
6190           ierr    = PetscSectionGetDof(section, a, &aDof);CHKERRQ(ierr);
6191           allDof += aDof;
6192         }
6193         newPointOffsets[0][p+1] = allDof;
6194         pointMatOffsets[0][p+1] = bSecDof * allDof;
6195       }
6196       else {
6197         newPointOffsets[0][p+1] = bSecDof;
6198         pointMatOffsets[0][p+1] = 0;
6199       }
6200     }
6201     newPointOffsets[0][0] = 0;
6202     pointMatOffsets[0][0] = 0;
6203     for (p = 0; p < numPoints; p++) {
6204       newPointOffsets[0][p+1] += newPointOffsets[0][p];
6205       pointMatOffsets[0][p+1] += pointMatOffsets[0][p];
6206     }
6207     ierr = DMGetWorkArray(dm,pointMatOffsets[0][numPoints],MPIU_SCALAR,&pointMat[0]);CHKERRQ(ierr);
6208   }
6209 
6210   /* output arrays */
6211   ierr = DMGetWorkArray(dm,2*newNumPoints,MPIU_INT,&newPoints);CHKERRQ(ierr);
6212 
6213   /* get the point-to-point matrices; construct newPoints */
6214   ierr = PetscSectionGetMaxDof(aSec, &maxAnchor);CHKERRQ(ierr);
6215   ierr = PetscSectionGetMaxDof(section, &maxDof);CHKERRQ(ierr);
6216   ierr = DMGetWorkArray(dm,maxDof,MPIU_INT,&indices);CHKERRQ(ierr);
6217   ierr = DMGetWorkArray(dm,maxAnchor*maxDof,MPIU_INT,&newIndices);CHKERRQ(ierr);
6218   if (numFields) {
6219     for (p = 0, newP = 0; p < numPoints; p++) {
6220       PetscInt b    = points[2*p];
6221       PetscInt o    = points[2*p+1];
6222       PetscInt bDof = 0, bSecDof;
6223 
6224       ierr = PetscSectionGetDof(section, b, &bSecDof);CHKERRQ(ierr);
6225       if (!bSecDof) {
6226         continue;
6227       }
6228       if (b >= aStart && b < aEnd) {
6229         ierr = PetscSectionGetDof(aSec, b, &bDof);CHKERRQ(ierr);
6230       }
6231       if (bDof) {
6232         PetscInt fStart[32], fEnd[32], fAnchorStart[32], fAnchorEnd[32], bOff, q;
6233 
6234         fStart[0] = 0;
6235         fEnd[0]   = 0;
6236         for (f = 0; f < numFields; f++) {
6237           PetscInt fDof;
6238 
6239           ierr        = PetscSectionGetFieldDof(cSec, b, f, &fDof);CHKERRQ(ierr);
6240           fStart[f+1] = fStart[f] + fDof;
6241           fEnd[f+1]   = fStart[f+1];
6242         }
6243         ierr = PetscSectionGetOffset(cSec, b, &bOff);CHKERRQ(ierr);
6244         ierr = DMPlexGetIndicesPointFields_Internal(cSec, PETSC_TRUE, b, bOff, fEnd, PETSC_TRUE, perms, p, NULL, indices);CHKERRQ(ierr);
6245 
6246         fAnchorStart[0] = 0;
6247         fAnchorEnd[0]   = 0;
6248         for (f = 0; f < numFields; f++) {
6249           PetscInt fDof = newPointOffsets[f][p + 1] - newPointOffsets[f][p];
6250 
6251           fAnchorStart[f+1] = fAnchorStart[f] + fDof;
6252           fAnchorEnd[f+1]   = fAnchorStart[f + 1];
6253         }
6254         ierr = PetscSectionGetOffset(aSec, b, &bOff);CHKERRQ(ierr);
6255         for (q = 0; q < bDof; q++) {
6256           PetscInt a = anchors[bOff + q], aOff;
6257 
6258           /* we take the orientation of ap into account in the order that we constructed the indices above: the newly added points have no orientation */
6259           newPoints[2*(newP + q)]     = a;
6260           newPoints[2*(newP + q) + 1] = 0;
6261           ierr = PetscSectionGetOffset(section, a, &aOff);CHKERRQ(ierr);
6262           ierr = DMPlexGetIndicesPointFields_Internal(section, PETSC_TRUE, a, aOff, fAnchorEnd, PETSC_TRUE, NULL, -1, NULL, newIndices);CHKERRQ(ierr);
6263         }
6264         newP += bDof;
6265 
6266         if (outValues) {
6267           /* get the point-to-point submatrix */
6268           for (f = 0; f < numFields; f++) {
6269             ierr = MatGetValues(cMat,fEnd[f]-fStart[f],indices + fStart[f],fAnchorEnd[f] - fAnchorStart[f],newIndices + fAnchorStart[f],pointMat[f] + pointMatOffsets[f][p]);CHKERRQ(ierr);
6270           }
6271         }
6272       }
6273       else {
6274         newPoints[2 * newP]     = b;
6275         newPoints[2 * newP + 1] = o;
6276         newP++;
6277       }
6278     }
6279   } else {
6280     for (p = 0; p < numPoints; p++) {
6281       PetscInt b    = points[2*p];
6282       PetscInt o    = points[2*p+1];
6283       PetscInt bDof = 0, bSecDof;
6284 
6285       ierr = PetscSectionGetDof(section, b, &bSecDof);CHKERRQ(ierr);
6286       if (!bSecDof) {
6287         continue;
6288       }
6289       if (b >= aStart && b < aEnd) {
6290         ierr = PetscSectionGetDof(aSec, b, &bDof);CHKERRQ(ierr);
6291       }
6292       if (bDof) {
6293         PetscInt bEnd = 0, bAnchorEnd = 0, bOff;
6294 
6295         ierr = PetscSectionGetOffset(cSec, b, &bOff);CHKERRQ(ierr);
6296         ierr = DMPlexGetIndicesPoint_Internal(cSec, PETSC_TRUE, b, bOff, &bEnd, PETSC_TRUE, (perms && perms[0]) ? perms[0][p] : NULL, NULL, indices);CHKERRQ(ierr);
6297 
6298         ierr = PetscSectionGetOffset (aSec, b, &bOff);CHKERRQ(ierr);
6299         for (q = 0; q < bDof; q++) {
6300           PetscInt a = anchors[bOff + q], aOff;
6301 
6302           /* we take the orientation of ap into account in the order that we constructed the indices above: the newly added points have no orientation */
6303 
6304           newPoints[2*(newP + q)]     = a;
6305           newPoints[2*(newP + q) + 1] = 0;
6306           ierr = PetscSectionGetOffset(section, a, &aOff);CHKERRQ(ierr);
6307           ierr = DMPlexGetIndicesPoint_Internal(section, PETSC_TRUE, a, aOff, &bAnchorEnd, PETSC_TRUE, NULL, NULL, newIndices);CHKERRQ(ierr);
6308         }
6309         newP += bDof;
6310 
6311         /* get the point-to-point submatrix */
6312         if (outValues) {
6313           ierr = MatGetValues(cMat,bEnd,indices,bAnchorEnd,newIndices,pointMat[0] + pointMatOffsets[0][p]);CHKERRQ(ierr);
6314         }
6315       }
6316       else {
6317         newPoints[2 * newP]     = b;
6318         newPoints[2 * newP + 1] = o;
6319         newP++;
6320       }
6321     }
6322   }
6323 
6324   if (outValues) {
6325     ierr = DMGetWorkArray(dm,newNumIndices*numIndices,MPIU_SCALAR,&tmpValues);CHKERRQ(ierr);
6326     ierr = PetscArrayzero(tmpValues,newNumIndices*numIndices);CHKERRQ(ierr);
6327     /* multiply constraints on the right */
6328     if (numFields) {
6329       for (f = 0; f < numFields; f++) {
6330         PetscInt oldOff = offsets[f];
6331 
6332         for (p = 0; p < numPoints; p++) {
6333           PetscInt cStart = newPointOffsets[f][p];
6334           PetscInt b      = points[2 * p];
6335           PetscInt c, r, k;
6336           PetscInt dof;
6337 
6338           ierr = PetscSectionGetFieldDof(section,b,f,&dof);CHKERRQ(ierr);
6339           if (!dof) {
6340             continue;
6341           }
6342           if (pointMatOffsets[f][p] < pointMatOffsets[f][p + 1]) {
6343             PetscInt nCols         = newPointOffsets[f][p+1]-cStart;
6344             const PetscScalar *mat = pointMat[f] + pointMatOffsets[f][p];
6345 
6346             for (r = 0; r < numIndices; r++) {
6347               for (c = 0; c < nCols; c++) {
6348                 for (k = 0; k < dof; k++) {
6349                   tmpValues[r * newNumIndices + cStart + c] += values[r * numIndices + oldOff + k] * mat[k * nCols + c];
6350                 }
6351               }
6352             }
6353           }
6354           else {
6355             /* copy this column as is */
6356             for (r = 0; r < numIndices; r++) {
6357               for (c = 0; c < dof; c++) {
6358                 tmpValues[r * newNumIndices + cStart + c] = values[r * numIndices + oldOff + c];
6359               }
6360             }
6361           }
6362           oldOff += dof;
6363         }
6364       }
6365     }
6366     else {
6367       PetscInt oldOff = 0;
6368       for (p = 0; p < numPoints; p++) {
6369         PetscInt cStart = newPointOffsets[0][p];
6370         PetscInt b      = points[2 * p];
6371         PetscInt c, r, k;
6372         PetscInt dof;
6373 
6374         ierr = PetscSectionGetDof(section,b,&dof);CHKERRQ(ierr);
6375         if (!dof) {
6376           continue;
6377         }
6378         if (pointMatOffsets[0][p] < pointMatOffsets[0][p + 1]) {
6379           PetscInt nCols         = newPointOffsets[0][p+1]-cStart;
6380           const PetscScalar *mat = pointMat[0] + pointMatOffsets[0][p];
6381 
6382           for (r = 0; r < numIndices; r++) {
6383             for (c = 0; c < nCols; c++) {
6384               for (k = 0; k < dof; k++) {
6385                 tmpValues[r * newNumIndices + cStart + c] += mat[k * nCols + c] * values[r * numIndices + oldOff + k];
6386               }
6387             }
6388           }
6389         }
6390         else {
6391           /* copy this column as is */
6392           for (r = 0; r < numIndices; r++) {
6393             for (c = 0; c < dof; c++) {
6394               tmpValues[r * newNumIndices + cStart + c] = values[r * numIndices + oldOff + c];
6395             }
6396           }
6397         }
6398         oldOff += dof;
6399       }
6400     }
6401 
6402     if (multiplyLeft) {
6403       ierr = DMGetWorkArray(dm,newNumIndices*newNumIndices,MPIU_SCALAR,&newValues);CHKERRQ(ierr);
6404       ierr = PetscArrayzero(newValues,newNumIndices*newNumIndices);CHKERRQ(ierr);
6405       /* multiply constraints transpose on the left */
6406       if (numFields) {
6407         for (f = 0; f < numFields; f++) {
6408           PetscInt oldOff = offsets[f];
6409 
6410           for (p = 0; p < numPoints; p++) {
6411             PetscInt rStart = newPointOffsets[f][p];
6412             PetscInt b      = points[2 * p];
6413             PetscInt c, r, k;
6414             PetscInt dof;
6415 
6416             ierr = PetscSectionGetFieldDof(section,b,f,&dof);CHKERRQ(ierr);
6417             if (pointMatOffsets[f][p] < pointMatOffsets[f][p + 1]) {
6418               PetscInt nRows                        = newPointOffsets[f][p+1]-rStart;
6419               const PetscScalar *PETSC_RESTRICT mat = pointMat[f] + pointMatOffsets[f][p];
6420 
6421               for (r = 0; r < nRows; r++) {
6422                 for (c = 0; c < newNumIndices; c++) {
6423                   for (k = 0; k < dof; k++) {
6424                     newValues[(rStart + r) * newNumIndices + c] += mat[k * nRows + r] * tmpValues[(oldOff + k) * newNumIndices + c];
6425                   }
6426                 }
6427               }
6428             }
6429             else {
6430               /* copy this row as is */
6431               for (r = 0; r < dof; r++) {
6432                 for (c = 0; c < newNumIndices; c++) {
6433                   newValues[(rStart + r) * newNumIndices + c] = tmpValues[(oldOff + r) * newNumIndices + c];
6434                 }
6435               }
6436             }
6437             oldOff += dof;
6438           }
6439         }
6440       }
6441       else {
6442         PetscInt oldOff = 0;
6443 
6444         for (p = 0; p < numPoints; p++) {
6445           PetscInt rStart = newPointOffsets[0][p];
6446           PetscInt b      = points[2 * p];
6447           PetscInt c, r, k;
6448           PetscInt dof;
6449 
6450           ierr = PetscSectionGetDof(section,b,&dof);CHKERRQ(ierr);
6451           if (pointMatOffsets[0][p] < pointMatOffsets[0][p + 1]) {
6452             PetscInt nRows                        = newPointOffsets[0][p+1]-rStart;
6453             const PetscScalar *PETSC_RESTRICT mat = pointMat[0] + pointMatOffsets[0][p];
6454 
6455             for (r = 0; r < nRows; r++) {
6456               for (c = 0; c < newNumIndices; c++) {
6457                 for (k = 0; k < dof; k++) {
6458                   newValues[(rStart + r) * newNumIndices + c] += mat[k * nRows + r] * tmpValues[(oldOff + k) * newNumIndices + c];
6459                 }
6460               }
6461             }
6462           }
6463           else {
6464             /* copy this row as is */
6465             for (r = 0; r < dof; r++) {
6466               for (c = 0; c < newNumIndices; c++) {
6467                 newValues[(rStart + r) * newNumIndices + c] = tmpValues[(oldOff + r) * newNumIndices + c];
6468               }
6469             }
6470           }
6471           oldOff += dof;
6472         }
6473       }
6474 
6475       ierr = DMRestoreWorkArray(dm,newNumIndices*numIndices,MPIU_SCALAR,&tmpValues);CHKERRQ(ierr);
6476     }
6477     else {
6478       newValues = tmpValues;
6479     }
6480   }
6481 
6482   /* clean up */
6483   ierr = DMRestoreWorkArray(dm,maxDof,MPIU_INT,&indices);CHKERRQ(ierr);
6484   ierr = DMRestoreWorkArray(dm,maxAnchor*maxDof,MPIU_INT,&newIndices);CHKERRQ(ierr);
6485 
6486   if (numFields) {
6487     for (f = 0; f < numFields; f++) {
6488       ierr = DMRestoreWorkArray(dm,pointMatOffsets[f][numPoints],MPIU_SCALAR,&pointMat[f]);CHKERRQ(ierr);
6489       ierr = DMRestoreWorkArray(dm,numPoints+1,MPIU_INT,&pointMatOffsets[f]);CHKERRQ(ierr);
6490       ierr = DMRestoreWorkArray(dm,numPoints+1,MPIU_INT,&newPointOffsets[f]);CHKERRQ(ierr);
6491     }
6492   }
6493   else {
6494     ierr = DMRestoreWorkArray(dm,pointMatOffsets[0][numPoints],MPIU_SCALAR,&pointMat[0]);CHKERRQ(ierr);
6495     ierr = DMRestoreWorkArray(dm,numPoints+1,MPIU_INT,&pointMatOffsets[0]);CHKERRQ(ierr);
6496     ierr = DMRestoreWorkArray(dm,numPoints+1,MPIU_INT,&newPointOffsets[0]);CHKERRQ(ierr);
6497   }
6498   ierr = ISRestoreIndices(aIS,&anchors);CHKERRQ(ierr);
6499 
6500   /* output */
6501   if (outPoints) {
6502     *outPoints = newPoints;
6503   }
6504   else {
6505     ierr = DMRestoreWorkArray(dm,2*newNumPoints,MPIU_INT,&newPoints);CHKERRQ(ierr);
6506   }
6507   if (outValues) {
6508     *outValues = newValues;
6509   }
6510   for (f = 0; f <= numFields; f++) {
6511     offsets[f] = newOffsets[f];
6512   }
6513   PetscFunctionReturn(0);
6514 }
6515 
6516 /*@C
6517   DMPlexGetClosureIndices - Gets the global dof indices associated with the closure of the given point within the provided sections.
6518 
6519   Not collective
6520 
6521   Input Parameters:
6522 + dm         - The DM
6523 . section    - The PetscSection describing the points (a local section)
6524 . idxSection - The PetscSection from which to obtain indices (may be local or global)
6525 . point      - The point defining the closure
6526 - useClPerm  - Use the closure point permutation if available
6527 
6528   Output Parameters:
6529 + numIndices - The number of dof indices in the closure of point with the input sections
6530 . indices    - The dof indices
6531 . outOffsets - Array to write the field offsets into, or NULL
6532 - values     - The input values, which may be modified if sign flips are induced by the point symmetries, or NULL
6533 
6534   Notes:
6535   Must call DMPlexRestoreClosureIndices() to free allocated memory
6536 
6537   If idxSection is global, any constrained dofs (see DMAddBoundary(), for example) will get negative indices.  The value
6538   of those indices is not significant.  If idxSection is local, the constrained dofs will yield the involution -(idx+1)
6539   of their index in a local vector.  A caller who does not wish to distinguish those points may recover the nonnegative
6540   indices via involution, -(-(idx+1)+1)==idx.  Local indices are provided when idxSection == section, otherwise global
6541   indices (with the above semantics) are implied.
6542 
6543   Level: advanced
6544 
6545 .seealso DMPlexRestoreClosureIndices(), DMPlexVecGetClosure(), DMPlexMatSetClosure(), DMGetLocalSection(), DMGetGlobalSection()
6546 @*/
6547 PetscErrorCode DMPlexGetClosureIndices(DM dm, PetscSection section, PetscSection idxSection, PetscInt point, PetscBool useClPerm,
6548                                        PetscInt *numIndices, PetscInt *indices[], PetscInt outOffsets[], PetscScalar *values[])
6549 {
6550   /* Closure ordering */
6551   PetscSection        clSection;
6552   IS                  clPoints;
6553   const PetscInt     *clp;
6554   PetscInt           *points;
6555   const PetscInt     *clperm = NULL;
6556   /* Dof permutation and sign flips */
6557   const PetscInt    **perms[32] = {NULL};
6558   const PetscScalar **flips[32] = {NULL};
6559   PetscScalar        *valCopy   = NULL;
6560   /* Hanging node constraints */
6561   PetscInt           *pointsC = NULL;
6562   PetscScalar        *valuesC = NULL;
6563   PetscInt            NclC, NiC;
6564 
6565   PetscInt           *idx;
6566   PetscInt            Nf, Ncl, Ni = 0, offsets[32], p, f;
6567   PetscBool           isLocal = (section == idxSection) ? PETSC_TRUE : PETSC_FALSE;
6568   PetscErrorCode      ierr;
6569 
6570   PetscFunctionBeginHot;
6571   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6572   PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2);
6573   PetscValidHeaderSpecific(idxSection, PETSC_SECTION_CLASSID, 3);
6574   if (numIndices) PetscValidPointer(numIndices, 6);
6575   if (indices)    PetscValidPointer(indices, 7);
6576   if (outOffsets) PetscValidPointer(outOffsets, 8);
6577   if (values)     PetscValidPointer(values, 9);
6578   ierr = PetscSectionGetNumFields(section, &Nf);CHKERRQ(ierr);
6579   if (Nf > 31) SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", Nf);
6580   ierr = PetscArrayzero(offsets, 32);CHKERRQ(ierr);
6581   /* 1) Get points in closure */
6582   ierr = DMPlexGetCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp);CHKERRQ(ierr);
6583   if (useClPerm) {
6584     PetscInt depth, clsize;
6585     ierr = DMPlexGetPointDepth(dm, point, &depth);CHKERRQ(ierr);
6586     for (clsize=0,p=0; p<Ncl; p++) {
6587       PetscInt dof;
6588       ierr = PetscSectionGetDof(section, points[2*p], &dof);CHKERRQ(ierr);
6589       clsize += dof;
6590     }
6591     ierr = PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject) dm, depth, clsize, &clperm);CHKERRQ(ierr);
6592   }
6593   /* 2) Get number of indices on these points and field offsets from section */
6594   for (p = 0; p < Ncl*2; p += 2) {
6595     PetscInt dof, fdof;
6596 
6597     ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
6598     for (f = 0; f < Nf; ++f) {
6599       ierr = PetscSectionGetFieldDof(section, points[p], f, &fdof);CHKERRQ(ierr);
6600       offsets[f+1] += fdof;
6601     }
6602     Ni += dof;
6603   }
6604   for (f = 1; f < Nf; ++f) offsets[f+1] += offsets[f];
6605   if (Nf && offsets[Nf] != Ni) SETERRQ2(PetscObjectComm((PetscObject) dm), PETSC_ERR_PLIB, "Invalid size for closure %D should be %D", offsets[Nf], Ni);
6606   /* 3) Get symmetries and sign flips. Apply sign flips to values if passed in (only works for square values matrix) */
6607   for (f = 0; f < PetscMax(1, Nf); ++f) {
6608     if (Nf) {ierr = PetscSectionGetFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f]);CHKERRQ(ierr);}
6609     else    {ierr = PetscSectionGetPointSyms(section, Ncl, points, &perms[f], &flips[f]);CHKERRQ(ierr);}
6610     /* may need to apply sign changes to the element matrix */
6611     if (values && flips[f]) {
6612       PetscInt foffset = offsets[f];
6613 
6614       for (p = 0; p < Ncl; ++p) {
6615         PetscInt           pnt  = points[2*p], fdof;
6616         const PetscScalar *flip = flips[f] ? flips[f][p] : NULL;
6617 
6618         if (!Nf) {ierr = PetscSectionGetDof(section, pnt, &fdof);CHKERRQ(ierr);}
6619         else     {ierr = PetscSectionGetFieldDof(section, pnt, f, &fdof);CHKERRQ(ierr);}
6620         if (flip) {
6621           PetscInt i, j, k;
6622 
6623           if (!valCopy) {
6624             ierr = DMGetWorkArray(dm, Ni*Ni, MPIU_SCALAR, &valCopy);CHKERRQ(ierr);
6625             for (j = 0; j < Ni * Ni; ++j) valCopy[j] = (*values)[j];
6626             *values = valCopy;
6627           }
6628           for (i = 0; i < fdof; ++i) {
6629             PetscScalar fval = flip[i];
6630 
6631             for (k = 0; k < Ni; ++k) {
6632               valCopy[Ni * (foffset + i) + k] *= fval;
6633               valCopy[Ni * k + (foffset + i)] *= fval;
6634             }
6635           }
6636         }
6637         foffset += fdof;
6638       }
6639     }
6640   }
6641   /* 4) Apply hanging node constraints. Get new symmetries and replace all storage with constrained storage */
6642   ierr = DMPlexAnchorsModifyMat(dm, section, Ncl, Ni, points, perms, values ? *values : NULL, &NclC, &NiC, &pointsC, values ? &valuesC : NULL, offsets, PETSC_TRUE);CHKERRQ(ierr);
6643   if (NclC) {
6644     if (valCopy) {ierr = DMRestoreWorkArray(dm, Ni*Ni, MPIU_SCALAR, &valCopy);CHKERRQ(ierr);}
6645     for (f = 0; f < PetscMax(1, Nf); ++f) {
6646       if (Nf) {ierr = PetscSectionRestoreFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f]);CHKERRQ(ierr);}
6647       else    {ierr = PetscSectionRestorePointSyms(section, Ncl, points, &perms[f], &flips[f]);CHKERRQ(ierr);}
6648     }
6649     for (f = 0; f < PetscMax(1, Nf); ++f) {
6650       if (Nf) {ierr = PetscSectionGetFieldPointSyms(section, f, NclC, pointsC, &perms[f], &flips[f]);CHKERRQ(ierr);}
6651       else    {ierr = PetscSectionGetPointSyms(section, NclC, pointsC, &perms[f], &flips[f]);CHKERRQ(ierr);}
6652     }
6653     ierr = DMPlexRestoreCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp);CHKERRQ(ierr);
6654     Ncl     = NclC;
6655     Ni      = NiC;
6656     points  = pointsC;
6657     if (values) *values = valuesC;
6658   }
6659   /* 5) Calculate indices */
6660   ierr = DMGetWorkArray(dm, Ni, MPIU_INT, &idx);CHKERRQ(ierr);
6661   if (Nf) {
6662     PetscInt  idxOff;
6663     PetscBool useFieldOffsets;
6664 
6665     if (outOffsets) {for (f = 0; f <= Nf; f++) outOffsets[f] = offsets[f];}
6666     ierr = PetscSectionGetUseFieldOffsets(idxSection, &useFieldOffsets);CHKERRQ(ierr);
6667     if (useFieldOffsets) {
6668       for (p = 0; p < Ncl; ++p) {
6669         const PetscInt pnt = points[p*2];
6670 
6671         ierr = DMPlexGetIndicesPointFieldsSplit_Internal(section, idxSection, pnt, offsets, perms, p, clperm, idx);CHKERRQ(ierr);
6672       }
6673     } else {
6674       for (p = 0; p < Ncl; ++p) {
6675         const PetscInt pnt = points[p*2];
6676 
6677         ierr = PetscSectionGetOffset(idxSection, pnt, &idxOff);CHKERRQ(ierr);
6678         /* Note that we pass a local section even though we're using global offsets.  This is because global sections do
6679          * not (at the time of this writing) have fields set. They probably should, in which case we would pass the
6680          * global section. */
6681         ierr = DMPlexGetIndicesPointFields_Internal(section, isLocal, pnt, idxOff < 0 ? -(idxOff+1) : idxOff, offsets, PETSC_FALSE, perms, p, clperm, idx);CHKERRQ(ierr);
6682       }
6683     }
6684   } else {
6685     PetscInt off = 0, idxOff;
6686 
6687     for (p = 0; p < Ncl; ++p) {
6688       const PetscInt  pnt  = points[p*2];
6689       const PetscInt *perm = perms[0] ? perms[0][p] : NULL;
6690 
6691       ierr = PetscSectionGetOffset(idxSection, pnt, &idxOff);CHKERRQ(ierr);
6692       /* Note that we pass a local section even though we're using global offsets.  This is because global sections do
6693        * not (at the time of this writing) have fields set. They probably should, in which case we would pass the global section. */
6694       ierr = DMPlexGetIndicesPoint_Internal(section, isLocal, pnt, idxOff < 0 ? -(idxOff+1) : idxOff, &off, PETSC_FALSE, perm, clperm, idx);CHKERRQ(ierr);
6695     }
6696   }
6697   /* 6) Cleanup */
6698   for (f = 0; f < PetscMax(1, Nf); ++f) {
6699     if (Nf) {ierr = PetscSectionRestoreFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f]);CHKERRQ(ierr);}
6700     else    {ierr = PetscSectionRestorePointSyms(section, Ncl, points, &perms[f], &flips[f]);CHKERRQ(ierr);}
6701   }
6702   if (NclC) {
6703     ierr = DMRestoreWorkArray(dm, NclC*2, MPIU_INT, &pointsC);CHKERRQ(ierr);
6704   } else {
6705     ierr = DMPlexRestoreCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp);CHKERRQ(ierr);
6706   }
6707 
6708   if (numIndices) *numIndices = Ni;
6709   if (indices)    *indices    = idx;
6710   PetscFunctionReturn(0);
6711 }
6712 
6713 /*@C
6714   DMPlexRestoreClosureIndices - Restores the global dof indices associated with the closure of the given point within the provided sections.
6715 
6716   Not collective
6717 
6718   Input Parameters:
6719 + dm         - The DM
6720 . section    - The PetscSection describing the points (a local section)
6721 . idxSection - The PetscSection from which to obtain indices (may be local or global)
6722 . point      - The point defining the closure
6723 - useClPerm  - Use the closure point permutation if available
6724 
6725   Output Parameters:
6726 + numIndices - The number of dof indices in the closure of point with the input sections
6727 . indices    - The dof indices
6728 . outOffsets - Array to write the field offsets into, or NULL
6729 - values     - The input values, which may be modified if sign flips are induced by the point symmetries, or NULL
6730 
6731   Notes:
6732   If values were modified, the user is responsible for calling DMRestoreWorkArray(dm, 0, MPIU_SCALAR, &values).
6733 
6734   If idxSection is global, any constrained dofs (see DMAddBoundary(), for example) will get negative indices.  The value
6735   of those indices is not significant.  If idxSection is local, the constrained dofs will yield the involution -(idx+1)
6736   of their index in a local vector.  A caller who does not wish to distinguish those points may recover the nonnegative
6737   indices via involution, -(-(idx+1)+1)==idx.  Local indices are provided when idxSection == section, otherwise global
6738   indices (with the above semantics) are implied.
6739 
6740   Level: advanced
6741 
6742 .seealso DMPlexGetClosureIndices(), DMPlexVecGetClosure(), DMPlexMatSetClosure(), DMGetLocalSection(), DMGetGlobalSection()
6743 @*/
6744 PetscErrorCode DMPlexRestoreClosureIndices(DM dm, PetscSection section, PetscSection idxSection, PetscInt point, PetscBool useClPerm,
6745                                            PetscInt *numIndices, PetscInt *indices[], PetscInt outOffsets[], PetscScalar *values[])
6746 {
6747   PetscErrorCode ierr;
6748 
6749   PetscFunctionBegin;
6750   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6751   PetscValidPointer(indices, 7);
6752   ierr = DMRestoreWorkArray(dm, 0, MPIU_INT, indices);CHKERRQ(ierr);
6753   PetscFunctionReturn(0);
6754 }
6755 
6756 /*@C
6757   DMPlexMatSetClosure - Set an array of the values on the closure of 'point'
6758 
6759   Not collective
6760 
6761   Input Parameters:
6762 + dm - The DM
6763 . section - The section describing the layout in v, or NULL to use the default section
6764 . globalSection - The section describing the layout in v, or NULL to use the default global section
6765 . A - The matrix
6766 . point - The point in the DM
6767 . values - The array of values
6768 - mode - The insert mode, where INSERT_ALL_VALUES and ADD_ALL_VALUES also overwrite boundary conditions
6769 
6770   Fortran Notes:
6771   This routine is only available in Fortran 90, and you must include petsc.h90 in your code.
6772 
6773   Level: intermediate
6774 
6775 .seealso DMPlexMatSetClosureGeneral(), DMPlexVecGetClosure(), DMPlexVecSetClosure()
6776 @*/
6777 PetscErrorCode DMPlexMatSetClosure(DM dm, PetscSection section, PetscSection globalSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode)
6778 {
6779   DM_Plex           *mesh = (DM_Plex*) dm->data;
6780   PetscInt          *indices;
6781   PetscInt           numIndices;
6782   const PetscScalar *valuesOrig = values;
6783   PetscErrorCode     ierr;
6784 
6785   PetscFunctionBegin;
6786   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6787   if (!section) {ierr = DMGetLocalSection(dm, &section);CHKERRQ(ierr);}
6788   PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2);
6789   if (!globalSection) {ierr = DMGetGlobalSection(dm, &globalSection);CHKERRQ(ierr);}
6790   PetscValidHeaderSpecific(globalSection, PETSC_SECTION_CLASSID, 3);
6791   PetscValidHeaderSpecific(A, MAT_CLASSID, 4);
6792 
6793   ierr = DMPlexGetClosureIndices(dm, section, globalSection, point, PETSC_TRUE, &numIndices, &indices, NULL, (PetscScalar **) &values);CHKERRQ(ierr);
6794 
6795   if (mesh->printSetValues) {ierr = DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndices, indices, 0, NULL, values);CHKERRQ(ierr);}
6796   ierr = MatSetValues(A, numIndices, indices, numIndices, indices, values, mode);
6797   if (ierr) {
6798     PetscMPIInt    rank;
6799     PetscErrorCode ierr2;
6800 
6801     ierr2 = MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank);CHKERRMPI(ierr2);
6802     ierr2 = (*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank);CHKERRQ(ierr2);
6803     ierr2 = DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndices, indices, 0, NULL, values);CHKERRQ(ierr2);
6804     ierr2 = DMPlexRestoreClosureIndices(dm, section, globalSection, point, PETSC_TRUE, &numIndices, &indices, NULL, (PetscScalar **) &values);CHKERRQ(ierr2);
6805     if (values != valuesOrig) {ierr2 = DMRestoreWorkArray(dm, 0, MPIU_SCALAR, &values);CHKERRQ(ierr2);}
6806     CHKERRQ(ierr);
6807   }
6808   if (mesh->printFEM > 1) {
6809     PetscInt i;
6810     ierr = PetscPrintf(PETSC_COMM_SELF, "  Indices:");CHKERRQ(ierr);
6811     for (i = 0; i < numIndices; ++i) {ierr = PetscPrintf(PETSC_COMM_SELF, " %D", indices[i]);CHKERRQ(ierr);}
6812     ierr = PetscPrintf(PETSC_COMM_SELF, "\n");CHKERRQ(ierr);
6813   }
6814 
6815   ierr = DMPlexRestoreClosureIndices(dm, section, globalSection, point, PETSC_TRUE, &numIndices, &indices, NULL, (PetscScalar **) &values);CHKERRQ(ierr);
6816   if (values != valuesOrig) {ierr = DMRestoreWorkArray(dm, 0, MPIU_SCALAR, &values);CHKERRQ(ierr);}
6817   PetscFunctionReturn(0);
6818 }
6819 
6820 /*@C
6821   DMPlexMatSetClosure - Set an array of the values on the closure of 'point' using a different row and column section
6822 
6823   Not collective
6824 
6825   Input Parameters:
6826 + dmRow - The DM for the row fields
6827 . sectionRow - The section describing the layout, or NULL to use the default section in dmRow
6828 . globalSectionRow - The section describing the layout, or NULL to use the default global section in dmRow
6829 . dmCol - The DM for the column fields
6830 . sectionCol - The section describing the layout, or NULL to use the default section in dmCol
6831 . globalSectionCol - The section describing the layout, or NULL to use the default global section in dmCol
6832 . A - The matrix
6833 . point - The point in the DMs
6834 . values - The array of values
6835 - mode - The insert mode, where INSERT_ALL_VALUES and ADD_ALL_VALUES also overwrite boundary conditions
6836 
6837   Level: intermediate
6838 
6839 .seealso DMPlexMatSetClosure(), DMPlexVecGetClosure(), DMPlexVecSetClosure()
6840 @*/
6841 PetscErrorCode DMPlexMatSetClosureGeneral(DM dmRow, PetscSection sectionRow, PetscSection globalSectionRow, DM dmCol, PetscSection sectionCol, PetscSection globalSectionCol, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode)
6842 {
6843   DM_Plex           *mesh = (DM_Plex*) dmRow->data;
6844   PetscInt          *indicesRow, *indicesCol;
6845   PetscInt           numIndicesRow, numIndicesCol;
6846   const PetscScalar *valuesOrig = values;
6847   PetscErrorCode     ierr;
6848 
6849   PetscFunctionBegin;
6850   PetscValidHeaderSpecific(dmRow, DM_CLASSID, 1);
6851   if (!sectionRow) {ierr = DMGetLocalSection(dmRow, &sectionRow);CHKERRQ(ierr);}
6852   PetscValidHeaderSpecific(sectionRow, PETSC_SECTION_CLASSID, 2);
6853   if (!globalSectionRow) {ierr = DMGetGlobalSection(dmRow, &globalSectionRow);CHKERRQ(ierr);}
6854   PetscValidHeaderSpecific(globalSectionRow, PETSC_SECTION_CLASSID, 3);
6855   PetscValidHeaderSpecific(dmCol, DM_CLASSID, 4);
6856   if (!sectionCol) {ierr = DMGetLocalSection(dmCol, &sectionCol);CHKERRQ(ierr);}
6857   PetscValidHeaderSpecific(sectionCol, PETSC_SECTION_CLASSID, 5);
6858   if (!globalSectionCol) {ierr = DMGetGlobalSection(dmCol, &globalSectionCol);CHKERRQ(ierr);}
6859   PetscValidHeaderSpecific(globalSectionCol, PETSC_SECTION_CLASSID, 6);
6860   PetscValidHeaderSpecific(A, MAT_CLASSID, 7);
6861 
6862   ierr = DMPlexGetClosureIndices(dmRow, sectionRow, globalSectionRow, point, PETSC_TRUE, &numIndicesRow, &indicesRow, NULL, (PetscScalar **) &values);CHKERRQ(ierr);
6863   ierr = DMPlexGetClosureIndices(dmCol, sectionCol, globalSectionCol, point, PETSC_TRUE, &numIndicesCol, &indicesCol, NULL, (PetscScalar **) &values);CHKERRQ(ierr);
6864 
6865   if (mesh->printSetValues) {ierr = DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndicesRow, indicesRow, numIndicesCol, indicesCol, values);CHKERRQ(ierr);}
6866   ierr = MatSetValues(A, numIndicesRow, indicesRow, numIndicesCol, indicesCol, values, mode);
6867   if (ierr) {
6868     PetscMPIInt    rank;
6869     PetscErrorCode ierr2;
6870 
6871     ierr2 = MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank);CHKERRMPI(ierr2);
6872     ierr2 = (*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank);CHKERRQ(ierr2);
6873     ierr2 = DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndicesRow, indicesRow, numIndicesCol, indicesCol, values);CHKERRQ(ierr2);
6874     ierr2 = DMPlexRestoreClosureIndices(dmRow, sectionRow, globalSectionRow, point, PETSC_TRUE, &numIndicesRow, &indicesRow, NULL, (PetscScalar **) &values);CHKERRQ(ierr2);
6875     ierr2 = DMPlexRestoreClosureIndices(dmCol, sectionCol, globalSectionCol, point, PETSC_TRUE, &numIndicesCol, &indicesRow, NULL, (PetscScalar **) &values);CHKERRQ(ierr2);
6876     if (values != valuesOrig) {ierr2 = DMRestoreWorkArray(dmRow, 0, MPIU_SCALAR, &values);CHKERRQ(ierr2);}
6877     CHKERRQ(ierr);
6878   }
6879 
6880   ierr = DMPlexRestoreClosureIndices(dmRow, sectionRow, globalSectionRow, point, PETSC_TRUE, &numIndicesRow, &indicesRow, NULL, (PetscScalar **) &values);CHKERRQ(ierr);
6881   ierr = DMPlexRestoreClosureIndices(dmCol, sectionCol, globalSectionCol, point, PETSC_TRUE, &numIndicesCol, &indicesCol, NULL, (PetscScalar **) &values);CHKERRQ(ierr);
6882   if (values != valuesOrig) {ierr = DMRestoreWorkArray(dmRow, 0, MPIU_SCALAR, &values);CHKERRQ(ierr);}
6883   PetscFunctionReturn(0);
6884 }
6885 
6886 PetscErrorCode DMPlexMatSetClosureRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode)
6887 {
6888   DM_Plex        *mesh   = (DM_Plex*) dmf->data;
6889   PetscInt       *fpoints = NULL, *ftotpoints = NULL;
6890   PetscInt       *cpoints = NULL;
6891   PetscInt       *findices, *cindices;
6892   const PetscInt *fclperm = NULL, *cclperm = NULL; /* Closure permutations cannot work here */
6893   PetscInt        foffsets[32], coffsets[32];
6894   DMPolytopeType  ct;
6895   PetscInt        numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f;
6896   PetscErrorCode  ierr;
6897 
6898   PetscFunctionBegin;
6899   PetscValidHeaderSpecific(dmf, DM_CLASSID, 1);
6900   PetscValidHeaderSpecific(dmc, DM_CLASSID, 4);
6901   if (!fsection) {ierr = DMGetLocalSection(dmf, &fsection);CHKERRQ(ierr);}
6902   PetscValidHeaderSpecific(fsection, PETSC_SECTION_CLASSID, 2);
6903   if (!csection) {ierr = DMGetLocalSection(dmc, &csection);CHKERRQ(ierr);}
6904   PetscValidHeaderSpecific(csection, PETSC_SECTION_CLASSID, 5);
6905   if (!globalFSection) {ierr = DMGetGlobalSection(dmf, &globalFSection);CHKERRQ(ierr);}
6906   PetscValidHeaderSpecific(globalFSection, PETSC_SECTION_CLASSID, 3);
6907   if (!globalCSection) {ierr = DMGetGlobalSection(dmc, &globalCSection);CHKERRQ(ierr);}
6908   PetscValidHeaderSpecific(globalCSection, PETSC_SECTION_CLASSID, 6);
6909   PetscValidHeaderSpecific(A, MAT_CLASSID, 7);
6910   ierr = PetscSectionGetNumFields(fsection, &numFields);CHKERRQ(ierr);
6911   if (numFields > 31) SETERRQ1(PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
6912   ierr = PetscArrayzero(foffsets, 32);CHKERRQ(ierr);
6913   ierr = PetscArrayzero(coffsets, 32);CHKERRQ(ierr);
6914   /* Column indices */
6915   ierr = DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints);CHKERRQ(ierr);
6916   maxFPoints = numCPoints;
6917   /* Compress out points not in the section */
6918   /*   TODO: Squeeze out points with 0 dof as well */
6919   ierr = PetscSectionGetChart(csection, &pStart, &pEnd);CHKERRQ(ierr);
6920   for (p = 0, q = 0; p < numCPoints*2; p += 2) {
6921     if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) {
6922       cpoints[q*2]   = cpoints[p];
6923       cpoints[q*2+1] = cpoints[p+1];
6924       ++q;
6925     }
6926   }
6927   numCPoints = q;
6928   for (p = 0, numCIndices = 0; p < numCPoints*2; p += 2) {
6929     PetscInt fdof;
6930 
6931     ierr = PetscSectionGetDof(csection, cpoints[p], &dof);CHKERRQ(ierr);
6932     if (!dof) continue;
6933     for (f = 0; f < numFields; ++f) {
6934       ierr           = PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof);CHKERRQ(ierr);
6935       coffsets[f+1] += fdof;
6936     }
6937     numCIndices += dof;
6938   }
6939   for (f = 1; f < numFields; ++f) coffsets[f+1] += coffsets[f];
6940   /* Row indices */
6941   ierr = DMPlexGetCellType(dmc, point, &ct);CHKERRQ(ierr);
6942   {
6943     DMPlexCellRefiner cr;
6944     ierr = DMPlexCellRefinerCreate(dmc, &cr);CHKERRQ(ierr);
6945     ierr = DMPlexCellRefinerGetAffineTransforms(cr, ct, &numSubcells, NULL, NULL, NULL);CHKERRQ(ierr);
6946     ierr = DMPlexCellRefinerDestroy(&cr);CHKERRQ(ierr);
6947   }
6948   ierr = DMGetWorkArray(dmf, maxFPoints*2*numSubcells, MPIU_INT, &ftotpoints);CHKERRQ(ierr);
6949   for (r = 0, q = 0; r < numSubcells; ++r) {
6950     /* TODO Map from coarse to fine cells */
6951     ierr = DMPlexGetTransitiveClosure(dmf, point*numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints);CHKERRQ(ierr);
6952     /* Compress out points not in the section */
6953     ierr = PetscSectionGetChart(fsection, &pStart, &pEnd);CHKERRQ(ierr);
6954     for (p = 0; p < numFPoints*2; p += 2) {
6955       if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) {
6956         ierr = PetscSectionGetDof(fsection, fpoints[p], &dof);CHKERRQ(ierr);
6957         if (!dof) continue;
6958         for (s = 0; s < q; ++s) if (fpoints[p] == ftotpoints[s*2]) break;
6959         if (s < q) continue;
6960         ftotpoints[q*2]   = fpoints[p];
6961         ftotpoints[q*2+1] = fpoints[p+1];
6962         ++q;
6963       }
6964     }
6965     ierr = DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints);CHKERRQ(ierr);
6966   }
6967   numFPoints = q;
6968   for (p = 0, numFIndices = 0; p < numFPoints*2; p += 2) {
6969     PetscInt fdof;
6970 
6971     ierr = PetscSectionGetDof(fsection, ftotpoints[p], &dof);CHKERRQ(ierr);
6972     if (!dof) continue;
6973     for (f = 0; f < numFields; ++f) {
6974       ierr           = PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof);CHKERRQ(ierr);
6975       foffsets[f+1] += fdof;
6976     }
6977     numFIndices += dof;
6978   }
6979   for (f = 1; f < numFields; ++f) foffsets[f+1] += foffsets[f];
6980 
6981   if (numFields && foffsets[numFields] != numFIndices) SETERRQ2(PetscObjectComm((PetscObject)dmf), PETSC_ERR_PLIB, "Invalid size for closure %D should be %D", foffsets[numFields], numFIndices);
6982   if (numFields && coffsets[numFields] != numCIndices) SETERRQ2(PetscObjectComm((PetscObject)dmc), PETSC_ERR_PLIB, "Invalid size for closure %D should be %D", coffsets[numFields], numCIndices);
6983   ierr = DMGetWorkArray(dmf, numFIndices, MPIU_INT, &findices);CHKERRQ(ierr);
6984   ierr = DMGetWorkArray(dmc, numCIndices, MPIU_INT, &cindices);CHKERRQ(ierr);
6985   if (numFields) {
6986     const PetscInt **permsF[32] = {NULL};
6987     const PetscInt **permsC[32] = {NULL};
6988 
6989     for (f = 0; f < numFields; f++) {
6990       ierr = PetscSectionGetFieldPointSyms(fsection,f,numFPoints,ftotpoints,&permsF[f],NULL);CHKERRQ(ierr);
6991       ierr = PetscSectionGetFieldPointSyms(csection,f,numCPoints,cpoints,&permsC[f],NULL);CHKERRQ(ierr);
6992     }
6993     for (p = 0; p < numFPoints; p++) {
6994       ierr = PetscSectionGetOffset(globalFSection, ftotpoints[2*p], &globalOff);CHKERRQ(ierr);
6995       ierr = DMPlexGetIndicesPointFields_Internal(fsection, PETSC_FALSE, ftotpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, foffsets, PETSC_FALSE, permsF, p, fclperm, findices);CHKERRQ(ierr);
6996     }
6997     for (p = 0; p < numCPoints; p++) {
6998       ierr = PetscSectionGetOffset(globalCSection, cpoints[2*p], &globalOff);CHKERRQ(ierr);
6999       ierr = DMPlexGetIndicesPointFields_Internal(csection, PETSC_FALSE, cpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cclperm, cindices);CHKERRQ(ierr);
7000     }
7001     for (f = 0; f < numFields; f++) {
7002       ierr = PetscSectionRestoreFieldPointSyms(fsection,f,numFPoints,ftotpoints,&permsF[f],NULL);CHKERRQ(ierr);
7003       ierr = PetscSectionRestoreFieldPointSyms(csection,f,numCPoints,cpoints,&permsC[f],NULL);CHKERRQ(ierr);
7004     }
7005   } else {
7006     const PetscInt **permsF = NULL;
7007     const PetscInt **permsC = NULL;
7008 
7009     ierr = PetscSectionGetPointSyms(fsection,numFPoints,ftotpoints,&permsF,NULL);CHKERRQ(ierr);
7010     ierr = PetscSectionGetPointSyms(csection,numCPoints,cpoints,&permsC,NULL);CHKERRQ(ierr);
7011     for (p = 0, off = 0; p < numFPoints; p++) {
7012       const PetscInt *perm = permsF ? permsF[p] : NULL;
7013 
7014       ierr = PetscSectionGetOffset(globalFSection, ftotpoints[2*p], &globalOff);CHKERRQ(ierr);
7015       ierr = DMPlexGetIndicesPoint_Internal(fsection, PETSC_FALSE, ftotpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, fclperm, findices);CHKERRQ(ierr);
7016     }
7017     for (p = 0, off = 0; p < numCPoints; p++) {
7018       const PetscInt *perm = permsC ? permsC[p] : NULL;
7019 
7020       ierr = PetscSectionGetOffset(globalCSection, cpoints[2*p], &globalOff);CHKERRQ(ierr);
7021       ierr = DMPlexGetIndicesPoint_Internal(csection, PETSC_FALSE, cpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, cclperm, cindices);CHKERRQ(ierr);
7022     }
7023     ierr = PetscSectionRestorePointSyms(fsection,numFPoints,ftotpoints,&permsF,NULL);CHKERRQ(ierr);
7024     ierr = PetscSectionRestorePointSyms(csection,numCPoints,cpoints,&permsC,NULL);CHKERRQ(ierr);
7025   }
7026   if (mesh->printSetValues) {ierr = DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numFIndices, findices, numCIndices, cindices, values);CHKERRQ(ierr);}
7027   /* TODO: flips */
7028   ierr = MatSetValues(A, numFIndices, findices, numCIndices, cindices, values, mode);
7029   if (ierr) {
7030     PetscMPIInt    rank;
7031     PetscErrorCode ierr2;
7032 
7033     ierr2 = MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank);CHKERRMPI(ierr2);
7034     ierr2 = (*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank);CHKERRQ(ierr2);
7035     ierr2 = DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numFIndices, findices, numCIndices, cindices, values);CHKERRQ(ierr2);
7036     ierr2 = DMRestoreWorkArray(dmf, numFIndices, MPIU_INT, &findices);CHKERRQ(ierr2);
7037     ierr2 = DMRestoreWorkArray(dmc, numCIndices, MPIU_INT, &cindices);CHKERRQ(ierr2);
7038     CHKERRQ(ierr);
7039   }
7040   ierr = DMRestoreWorkArray(dmf, numCPoints*2*4, MPIU_INT, &ftotpoints);CHKERRQ(ierr);
7041   ierr = DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints);CHKERRQ(ierr);
7042   ierr = DMRestoreWorkArray(dmf, numFIndices, MPIU_INT, &findices);CHKERRQ(ierr);
7043   ierr = DMRestoreWorkArray(dmc, numCIndices, MPIU_INT, &cindices);CHKERRQ(ierr);
7044   PetscFunctionReturn(0);
7045 }
7046 
7047 PetscErrorCode DMPlexMatGetClosureIndicesRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, PetscInt point, PetscInt cindices[], PetscInt findices[])
7048 {
7049   PetscInt      *fpoints = NULL, *ftotpoints = NULL;
7050   PetscInt      *cpoints = NULL;
7051   PetscInt       foffsets[32], coffsets[32];
7052   const PetscInt *fclperm = NULL, *cclperm = NULL; /* Closure permutations cannot work here */
7053   DMPolytopeType ct;
7054   PetscInt       numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f;
7055   PetscErrorCode ierr;
7056 
7057   PetscFunctionBegin;
7058   PetscValidHeaderSpecific(dmf, DM_CLASSID, 1);
7059   PetscValidHeaderSpecific(dmc, DM_CLASSID, 4);
7060   if (!fsection) {ierr = DMGetLocalSection(dmf, &fsection);CHKERRQ(ierr);}
7061   PetscValidHeaderSpecific(fsection, PETSC_SECTION_CLASSID, 2);
7062   if (!csection) {ierr = DMGetLocalSection(dmc, &csection);CHKERRQ(ierr);}
7063   PetscValidHeaderSpecific(csection, PETSC_SECTION_CLASSID, 5);
7064   if (!globalFSection) {ierr = DMGetGlobalSection(dmf, &globalFSection);CHKERRQ(ierr);}
7065   PetscValidHeaderSpecific(globalFSection, PETSC_SECTION_CLASSID, 3);
7066   if (!globalCSection) {ierr = DMGetGlobalSection(dmc, &globalCSection);CHKERRQ(ierr);}
7067   PetscValidHeaderSpecific(globalCSection, PETSC_SECTION_CLASSID, 6);
7068   ierr = PetscSectionGetNumFields(fsection, &numFields);CHKERRQ(ierr);
7069   if (numFields > 31) SETERRQ1(PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
7070   ierr = PetscArrayzero(foffsets, 32);CHKERRQ(ierr);
7071   ierr = PetscArrayzero(coffsets, 32);CHKERRQ(ierr);
7072   /* Column indices */
7073   ierr = DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints);CHKERRQ(ierr);
7074   maxFPoints = numCPoints;
7075   /* Compress out points not in the section */
7076   /*   TODO: Squeeze out points with 0 dof as well */
7077   ierr = PetscSectionGetChart(csection, &pStart, &pEnd);CHKERRQ(ierr);
7078   for (p = 0, q = 0; p < numCPoints*2; p += 2) {
7079     if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) {
7080       cpoints[q*2]   = cpoints[p];
7081       cpoints[q*2+1] = cpoints[p+1];
7082       ++q;
7083     }
7084   }
7085   numCPoints = q;
7086   for (p = 0, numCIndices = 0; p < numCPoints*2; p += 2) {
7087     PetscInt fdof;
7088 
7089     ierr = PetscSectionGetDof(csection, cpoints[p], &dof);CHKERRQ(ierr);
7090     if (!dof) continue;
7091     for (f = 0; f < numFields; ++f) {
7092       ierr           = PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof);CHKERRQ(ierr);
7093       coffsets[f+1] += fdof;
7094     }
7095     numCIndices += dof;
7096   }
7097   for (f = 1; f < numFields; ++f) coffsets[f+1] += coffsets[f];
7098   /* Row indices */
7099   ierr = DMPlexGetCellType(dmc, point, &ct);CHKERRQ(ierr);
7100   {
7101     DMPlexCellRefiner cr;
7102     ierr = DMPlexCellRefinerCreate(dmc, &cr);CHKERRQ(ierr);
7103     ierr = DMPlexCellRefinerGetAffineTransforms(cr, ct, &numSubcells, NULL, NULL, NULL);CHKERRQ(ierr);
7104     ierr = DMPlexCellRefinerDestroy(&cr);CHKERRQ(ierr);
7105   }
7106   ierr = DMGetWorkArray(dmf, maxFPoints*2*numSubcells, MPIU_INT, &ftotpoints);CHKERRQ(ierr);
7107   for (r = 0, q = 0; r < numSubcells; ++r) {
7108     /* TODO Map from coarse to fine cells */
7109     ierr = DMPlexGetTransitiveClosure(dmf, point*numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints);CHKERRQ(ierr);
7110     /* Compress out points not in the section */
7111     ierr = PetscSectionGetChart(fsection, &pStart, &pEnd);CHKERRQ(ierr);
7112     for (p = 0; p < numFPoints*2; p += 2) {
7113       if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) {
7114         ierr = PetscSectionGetDof(fsection, fpoints[p], &dof);CHKERRQ(ierr);
7115         if (!dof) continue;
7116         for (s = 0; s < q; ++s) if (fpoints[p] == ftotpoints[s*2]) break;
7117         if (s < q) continue;
7118         ftotpoints[q*2]   = fpoints[p];
7119         ftotpoints[q*2+1] = fpoints[p+1];
7120         ++q;
7121       }
7122     }
7123     ierr = DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints);CHKERRQ(ierr);
7124   }
7125   numFPoints = q;
7126   for (p = 0, numFIndices = 0; p < numFPoints*2; p += 2) {
7127     PetscInt fdof;
7128 
7129     ierr = PetscSectionGetDof(fsection, ftotpoints[p], &dof);CHKERRQ(ierr);
7130     if (!dof) continue;
7131     for (f = 0; f < numFields; ++f) {
7132       ierr           = PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof);CHKERRQ(ierr);
7133       foffsets[f+1] += fdof;
7134     }
7135     numFIndices += dof;
7136   }
7137   for (f = 1; f < numFields; ++f) foffsets[f+1] += foffsets[f];
7138 
7139   if (numFields && foffsets[numFields] != numFIndices) SETERRQ2(PetscObjectComm((PetscObject)dmf), PETSC_ERR_PLIB, "Invalid size for closure %D should be %D", foffsets[numFields], numFIndices);
7140   if (numFields && coffsets[numFields] != numCIndices) SETERRQ2(PetscObjectComm((PetscObject)dmc), PETSC_ERR_PLIB, "Invalid size for closure %D should be %D", coffsets[numFields], numCIndices);
7141   if (numFields) {
7142     const PetscInt **permsF[32] = {NULL};
7143     const PetscInt **permsC[32] = {NULL};
7144 
7145     for (f = 0; f < numFields; f++) {
7146       ierr = PetscSectionGetFieldPointSyms(fsection,f,numFPoints,ftotpoints,&permsF[f],NULL);CHKERRQ(ierr);
7147       ierr = PetscSectionGetFieldPointSyms(csection,f,numCPoints,cpoints,&permsC[f],NULL);CHKERRQ(ierr);
7148     }
7149     for (p = 0; p < numFPoints; p++) {
7150       ierr = PetscSectionGetOffset(globalFSection, ftotpoints[2*p], &globalOff);CHKERRQ(ierr);
7151       ierr = DMPlexGetIndicesPointFields_Internal(fsection, PETSC_FALSE, ftotpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, foffsets, PETSC_FALSE, permsF, p, fclperm, findices);CHKERRQ(ierr);
7152     }
7153     for (p = 0; p < numCPoints; p++) {
7154       ierr = PetscSectionGetOffset(globalCSection, cpoints[2*p], &globalOff);CHKERRQ(ierr);
7155       ierr = DMPlexGetIndicesPointFields_Internal(csection, PETSC_FALSE, cpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cclperm, cindices);CHKERRQ(ierr);
7156     }
7157     for (f = 0; f < numFields; f++) {
7158       ierr = PetscSectionRestoreFieldPointSyms(fsection,f,numFPoints,ftotpoints,&permsF[f],NULL);CHKERRQ(ierr);
7159       ierr = PetscSectionRestoreFieldPointSyms(csection,f,numCPoints,cpoints,&permsC[f],NULL);CHKERRQ(ierr);
7160     }
7161   } else {
7162     const PetscInt **permsF = NULL;
7163     const PetscInt **permsC = NULL;
7164 
7165     ierr = PetscSectionGetPointSyms(fsection,numFPoints,ftotpoints,&permsF,NULL);CHKERRQ(ierr);
7166     ierr = PetscSectionGetPointSyms(csection,numCPoints,cpoints,&permsC,NULL);CHKERRQ(ierr);
7167     for (p = 0, off = 0; p < numFPoints; p++) {
7168       const PetscInt *perm = permsF ? permsF[p] : NULL;
7169 
7170       ierr = PetscSectionGetOffset(globalFSection, ftotpoints[2*p], &globalOff);CHKERRQ(ierr);
7171       ierr = DMPlexGetIndicesPoint_Internal(fsection, PETSC_FALSE, ftotpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, fclperm, findices);CHKERRQ(ierr);
7172     }
7173     for (p = 0, off = 0; p < numCPoints; p++) {
7174       const PetscInt *perm = permsC ? permsC[p] : NULL;
7175 
7176       ierr = PetscSectionGetOffset(globalCSection, cpoints[2*p], &globalOff);CHKERRQ(ierr);
7177       ierr = DMPlexGetIndicesPoint_Internal(csection, PETSC_FALSE, cpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, cclperm, cindices);CHKERRQ(ierr);
7178     }
7179     ierr = PetscSectionRestorePointSyms(fsection,numFPoints,ftotpoints,&permsF,NULL);CHKERRQ(ierr);
7180     ierr = PetscSectionRestorePointSyms(csection,numCPoints,cpoints,&permsC,NULL);CHKERRQ(ierr);
7181   }
7182   ierr = DMRestoreWorkArray(dmf, numCPoints*2*4, MPIU_INT, &ftotpoints);CHKERRQ(ierr);
7183   ierr = DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints);CHKERRQ(ierr);
7184   PetscFunctionReturn(0);
7185 }
7186 
7187 /*@C
7188   DMPlexGetVTKCellHeight - Returns the height in the DAG used to determine which points are cells (normally 0)
7189 
7190   Input Parameter:
7191 . dm   - The DMPlex object
7192 
7193   Output Parameter:
7194 . cellHeight - The height of a cell
7195 
7196   Level: developer
7197 
7198 .seealso DMPlexSetVTKCellHeight()
7199 @*/
7200 PetscErrorCode DMPlexGetVTKCellHeight(DM dm, PetscInt *cellHeight)
7201 {
7202   DM_Plex *mesh = (DM_Plex*) dm->data;
7203 
7204   PetscFunctionBegin;
7205   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7206   PetscValidPointer(cellHeight, 2);
7207   *cellHeight = mesh->vtkCellHeight;
7208   PetscFunctionReturn(0);
7209 }
7210 
7211 /*@C
7212   DMPlexSetVTKCellHeight - Sets the height in the DAG used to determine which points are cells (normally 0)
7213 
7214   Input Parameters:
7215 + dm   - The DMPlex object
7216 - cellHeight - The height of a cell
7217 
7218   Level: developer
7219 
7220 .seealso DMPlexGetVTKCellHeight()
7221 @*/
7222 PetscErrorCode DMPlexSetVTKCellHeight(DM dm, PetscInt cellHeight)
7223 {
7224   DM_Plex *mesh = (DM_Plex*) dm->data;
7225 
7226   PetscFunctionBegin;
7227   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7228   mesh->vtkCellHeight = cellHeight;
7229   PetscFunctionReturn(0);
7230 }
7231 
7232 /*@
7233   DMPlexGetGhostCellStratum - Get the range of cells which are used to enforce FV boundary conditions
7234 
7235   Input Parameter:
7236 . dm - The DMPlex object
7237 
7238   Output Parameters:
7239 + gcStart - The first ghost cell, or NULL
7240 - gcEnd   - The upper bound on ghost cells, or NULL
7241 
7242   Level: advanced
7243 
7244 .seealso DMPlexConstructGhostCells(), DMPlexGetGhostCellStratum()
7245 @*/
7246 PetscErrorCode DMPlexGetGhostCellStratum(DM dm, PetscInt *gcStart, PetscInt *gcEnd)
7247 {
7248   DMLabel        ctLabel;
7249   PetscErrorCode ierr;
7250 
7251   PetscFunctionBegin;
7252   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7253   ierr = DMPlexGetCellTypeLabel(dm, &ctLabel);CHKERRQ(ierr);
7254   ierr = DMLabelGetStratumBounds(ctLabel, DM_POLYTOPE_FV_GHOST, gcStart, gcEnd);CHKERRQ(ierr);
7255   PetscFunctionReturn(0);
7256 }
7257 
7258 /* We can easily have a form that takes an IS instead */
7259 PetscErrorCode DMPlexCreateNumbering_Plex(DM dm, PetscInt pStart, PetscInt pEnd, PetscInt shift, PetscInt *globalSize, PetscSF sf, IS *numbering)
7260 {
7261   PetscSection   section, globalSection;
7262   PetscInt      *numbers, p;
7263   PetscErrorCode ierr;
7264 
7265   PetscFunctionBegin;
7266   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)dm), &section);CHKERRQ(ierr);
7267   ierr = PetscSectionSetChart(section, pStart, pEnd);CHKERRQ(ierr);
7268   for (p = pStart; p < pEnd; ++p) {
7269     ierr = PetscSectionSetDof(section, p, 1);CHKERRQ(ierr);
7270   }
7271   ierr = PetscSectionSetUp(section);CHKERRQ(ierr);
7272   ierr = PetscSectionCreateGlobalSection(section, sf, PETSC_FALSE, PETSC_FALSE, &globalSection);CHKERRQ(ierr);
7273   ierr = PetscMalloc1(pEnd - pStart, &numbers);CHKERRQ(ierr);
7274   for (p = pStart; p < pEnd; ++p) {
7275     ierr = PetscSectionGetOffset(globalSection, p, &numbers[p-pStart]);CHKERRQ(ierr);
7276     if (numbers[p-pStart] < 0) numbers[p-pStart] -= shift;
7277     else                       numbers[p-pStart] += shift;
7278   }
7279   ierr = ISCreateGeneral(PetscObjectComm((PetscObject) dm), pEnd - pStart, numbers, PETSC_OWN_POINTER, numbering);CHKERRQ(ierr);
7280   if (globalSize) {
7281     PetscLayout layout;
7282     ierr = PetscSectionGetPointLayout(PetscObjectComm((PetscObject) dm), globalSection, &layout);CHKERRQ(ierr);
7283     ierr = PetscLayoutGetSize(layout, globalSize);CHKERRQ(ierr);
7284     ierr = PetscLayoutDestroy(&layout);CHKERRQ(ierr);
7285   }
7286   ierr = PetscSectionDestroy(&section);CHKERRQ(ierr);
7287   ierr = PetscSectionDestroy(&globalSection);CHKERRQ(ierr);
7288   PetscFunctionReturn(0);
7289 }
7290 
7291 PetscErrorCode DMPlexCreateCellNumbering_Internal(DM dm, PetscBool includeHybrid, IS *globalCellNumbers)
7292 {
7293   PetscInt       cellHeight, cStart, cEnd;
7294   PetscErrorCode ierr;
7295 
7296   PetscFunctionBegin;
7297   ierr = DMPlexGetVTKCellHeight(dm, &cellHeight);CHKERRQ(ierr);
7298   if (includeHybrid) {ierr = DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd);CHKERRQ(ierr);}
7299   else               {ierr = DMPlexGetSimplexOrBoxCells(dm, cellHeight, &cStart, &cEnd);CHKERRQ(ierr);}
7300   ierr = DMPlexCreateNumbering_Plex(dm, cStart, cEnd, 0, NULL, dm->sf, globalCellNumbers);CHKERRQ(ierr);
7301   PetscFunctionReturn(0);
7302 }
7303 
7304 /*@
7305   DMPlexGetCellNumbering - Get a global cell numbering for all cells on this process
7306 
7307   Input Parameter:
7308 . dm   - The DMPlex object
7309 
7310   Output Parameter:
7311 . globalCellNumbers - Global cell numbers for all cells on this process
7312 
7313   Level: developer
7314 
7315 .seealso DMPlexGetVertexNumbering()
7316 @*/
7317 PetscErrorCode DMPlexGetCellNumbering(DM dm, IS *globalCellNumbers)
7318 {
7319   DM_Plex       *mesh = (DM_Plex*) dm->data;
7320   PetscErrorCode ierr;
7321 
7322   PetscFunctionBegin;
7323   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7324   if (!mesh->globalCellNumbers) {ierr = DMPlexCreateCellNumbering_Internal(dm, PETSC_FALSE, &mesh->globalCellNumbers);CHKERRQ(ierr);}
7325   *globalCellNumbers = mesh->globalCellNumbers;
7326   PetscFunctionReturn(0);
7327 }
7328 
7329 PetscErrorCode DMPlexCreateVertexNumbering_Internal(DM dm, PetscBool includeHybrid, IS *globalVertexNumbers)
7330 {
7331   PetscInt       vStart, vEnd;
7332   PetscErrorCode ierr;
7333 
7334   PetscFunctionBegin;
7335   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7336   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
7337   ierr = DMPlexCreateNumbering_Plex(dm, vStart, vEnd, 0, NULL, dm->sf, globalVertexNumbers);CHKERRQ(ierr);
7338   PetscFunctionReturn(0);
7339 }
7340 
7341 /*@
7342   DMPlexGetVertexNumbering - Get a global vertex numbering for all vertices on this process
7343 
7344   Input Parameter:
7345 . dm   - The DMPlex object
7346 
7347   Output Parameter:
7348 . globalVertexNumbers - Global vertex numbers for all vertices on this process
7349 
7350   Level: developer
7351 
7352 .seealso DMPlexGetCellNumbering()
7353 @*/
7354 PetscErrorCode DMPlexGetVertexNumbering(DM dm, IS *globalVertexNumbers)
7355 {
7356   DM_Plex       *mesh = (DM_Plex*) dm->data;
7357   PetscErrorCode ierr;
7358 
7359   PetscFunctionBegin;
7360   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7361   if (!mesh->globalVertexNumbers) {ierr = DMPlexCreateVertexNumbering_Internal(dm, PETSC_FALSE, &mesh->globalVertexNumbers);CHKERRQ(ierr);}
7362   *globalVertexNumbers = mesh->globalVertexNumbers;
7363   PetscFunctionReturn(0);
7364 }
7365 
7366 /*@
7367   DMPlexCreatePointNumbering - Create a global numbering for all points on this process
7368 
7369   Input Parameter:
7370 . dm   - The DMPlex object
7371 
7372   Output Parameter:
7373 . globalPointNumbers - Global numbers for all points on this process
7374 
7375   Level: developer
7376 
7377 .seealso DMPlexGetCellNumbering()
7378 @*/
7379 PetscErrorCode DMPlexCreatePointNumbering(DM dm, IS *globalPointNumbers)
7380 {
7381   IS             nums[4];
7382   PetscInt       depths[4], gdepths[4], starts[4];
7383   PetscInt       depth, d, shift = 0;
7384   PetscErrorCode ierr;
7385 
7386   PetscFunctionBegin;
7387   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7388   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
7389   /* For unstratified meshes use dim instead of depth */
7390   if (depth < 0) {ierr = DMGetDimension(dm, &depth);CHKERRQ(ierr);}
7391   for (d = 0; d <= depth; ++d) {
7392     PetscInt end;
7393 
7394     depths[d] = depth-d;
7395     ierr = DMPlexGetDepthStratum(dm, depths[d], &starts[d], &end);CHKERRQ(ierr);
7396     if (!(starts[d]-end)) { starts[d] = depths[d] = -1; }
7397   }
7398   ierr = PetscSortIntWithArray(depth+1, starts, depths);CHKERRQ(ierr);
7399   ierr = MPIU_Allreduce(depths, gdepths, depth+1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject) dm));CHKERRMPI(ierr);
7400   for (d = 0; d <= depth; ++d) {
7401     if (starts[d] >= 0 && depths[d] != gdepths[d]) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Expected depth %D, found %D",depths[d],gdepths[d]);
7402   }
7403   for (d = 0; d <= depth; ++d) {
7404     PetscInt pStart, pEnd, gsize;
7405 
7406     ierr = DMPlexGetDepthStratum(dm, gdepths[d], &pStart, &pEnd);CHKERRQ(ierr);
7407     ierr = DMPlexCreateNumbering_Plex(dm, pStart, pEnd, shift, &gsize, dm->sf, &nums[d]);CHKERRQ(ierr);
7408     shift += gsize;
7409   }
7410   ierr = ISConcatenate(PetscObjectComm((PetscObject) dm), depth+1, nums, globalPointNumbers);CHKERRQ(ierr);
7411   for (d = 0; d <= depth; ++d) {ierr = ISDestroy(&nums[d]);CHKERRQ(ierr);}
7412   PetscFunctionReturn(0);
7413 }
7414 
7415 /*@
7416   DMPlexCreateRankField - Create a cell field whose value is the rank of the owner
7417 
7418   Input Parameter:
7419 . dm - The DMPlex object
7420 
7421   Output Parameter:
7422 . ranks - The rank field
7423 
7424   Options Database Keys:
7425 . -dm_partition_view - Adds the rank field into the DM output from -dm_view using the same viewer
7426 
7427   Level: intermediate
7428 
7429 .seealso: DMView()
7430 @*/
7431 PetscErrorCode DMPlexCreateRankField(DM dm, Vec *ranks)
7432 {
7433   DM             rdm;
7434   PetscFE        fe;
7435   PetscScalar   *r;
7436   PetscMPIInt    rank;
7437   DMPolytopeType ct;
7438   PetscInt       dim, cStart, cEnd, c;
7439   PetscBool      simplex;
7440   PetscErrorCode ierr;
7441 
7442   PetscFunctionBeginUser;
7443   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7444   PetscValidPointer(ranks, 2);
7445   ierr = MPI_Comm_rank(PetscObjectComm((PetscObject) dm), &rank);CHKERRMPI(ierr);
7446   ierr = DMClone(dm, &rdm);CHKERRQ(ierr);
7447   ierr = DMGetDimension(rdm, &dim);CHKERRQ(ierr);
7448   ierr = DMPlexGetHeightStratum(rdm, 0, &cStart, &cEnd);CHKERRQ(ierr);
7449   ierr = DMPlexGetCellType(dm, cStart, &ct);CHKERRQ(ierr);
7450   simplex = DMPolytopeTypeGetNumVertices(ct) == DMPolytopeTypeGetDim(ct)+1 ? PETSC_TRUE : PETSC_FALSE;
7451   ierr = PetscFECreateDefault(PETSC_COMM_SELF, dim, 1, simplex, "PETSc___rank_", -1, &fe);CHKERRQ(ierr);
7452   ierr = PetscObjectSetName((PetscObject) fe, "rank");CHKERRQ(ierr);
7453   ierr = DMSetField(rdm, 0, NULL, (PetscObject) fe);CHKERRQ(ierr);
7454   ierr = PetscFEDestroy(&fe);CHKERRQ(ierr);
7455   ierr = DMCreateDS(rdm);CHKERRQ(ierr);
7456   ierr = DMCreateGlobalVector(rdm, ranks);CHKERRQ(ierr);
7457   ierr = PetscObjectSetName((PetscObject) *ranks, "partition");CHKERRQ(ierr);
7458   ierr = VecGetArray(*ranks, &r);CHKERRQ(ierr);
7459   for (c = cStart; c < cEnd; ++c) {
7460     PetscScalar *lr;
7461 
7462     ierr = DMPlexPointGlobalRef(rdm, c, r, &lr);CHKERRQ(ierr);
7463     if (lr) *lr = rank;
7464   }
7465   ierr = VecRestoreArray(*ranks, &r);CHKERRQ(ierr);
7466   ierr = DMDestroy(&rdm);CHKERRQ(ierr);
7467   PetscFunctionReturn(0);
7468 }
7469 
7470 /*@
7471   DMPlexCreateLabelField - Create a cell field whose value is the label value for that cell
7472 
7473   Input Parameters:
7474 + dm    - The DMPlex
7475 - label - The DMLabel
7476 
7477   Output Parameter:
7478 . val - The label value field
7479 
7480   Options Database Keys:
7481 . -dm_label_view - Adds the label value field into the DM output from -dm_view using the same viewer
7482 
7483   Level: intermediate
7484 
7485 .seealso: DMView()
7486 @*/
7487 PetscErrorCode DMPlexCreateLabelField(DM dm, DMLabel label, Vec *val)
7488 {
7489   DM             rdm;
7490   PetscFE        fe;
7491   PetscScalar   *v;
7492   PetscInt       dim, cStart, cEnd, c;
7493   PetscErrorCode ierr;
7494 
7495   PetscFunctionBeginUser;
7496   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7497   PetscValidPointer(label, 2);
7498   PetscValidPointer(val, 3);
7499   ierr = DMClone(dm, &rdm);CHKERRQ(ierr);
7500   ierr = DMGetDimension(rdm, &dim);CHKERRQ(ierr);
7501   ierr = PetscFECreateDefault(PetscObjectComm((PetscObject) rdm), dim, 1, PETSC_TRUE, "PETSc___label_value_", -1, &fe);CHKERRQ(ierr);
7502   ierr = PetscObjectSetName((PetscObject) fe, "label_value");CHKERRQ(ierr);
7503   ierr = DMSetField(rdm, 0, NULL, (PetscObject) fe);CHKERRQ(ierr);
7504   ierr = PetscFEDestroy(&fe);CHKERRQ(ierr);
7505   ierr = DMCreateDS(rdm);CHKERRQ(ierr);
7506   ierr = DMPlexGetHeightStratum(rdm, 0, &cStart, &cEnd);CHKERRQ(ierr);
7507   ierr = DMCreateGlobalVector(rdm, val);CHKERRQ(ierr);
7508   ierr = PetscObjectSetName((PetscObject) *val, "label_value");CHKERRQ(ierr);
7509   ierr = VecGetArray(*val, &v);CHKERRQ(ierr);
7510   for (c = cStart; c < cEnd; ++c) {
7511     PetscScalar *lv;
7512     PetscInt     cval;
7513 
7514     ierr = DMPlexPointGlobalRef(rdm, c, v, &lv);CHKERRQ(ierr);
7515     ierr = DMLabelGetValue(label, c, &cval);CHKERRQ(ierr);
7516     *lv = cval;
7517   }
7518   ierr = VecRestoreArray(*val, &v);CHKERRQ(ierr);
7519   ierr = DMDestroy(&rdm);CHKERRQ(ierr);
7520   PetscFunctionReturn(0);
7521 }
7522 
7523 /*@
7524   DMPlexCheckSymmetry - Check that the adjacency information in the mesh is symmetric.
7525 
7526   Input Parameter:
7527 . dm - The DMPlex object
7528 
7529   Notes:
7530   This is a useful diagnostic when creating meshes programmatically.
7531 
7532   For the complete list of DMPlexCheck* functions, see DMSetFromOptions().
7533 
7534   Level: developer
7535 
7536 .seealso: DMCreate(), DMSetFromOptions()
7537 @*/
7538 PetscErrorCode DMPlexCheckSymmetry(DM dm)
7539 {
7540   PetscSection    coneSection, supportSection;
7541   const PetscInt *cone, *support;
7542   PetscInt        coneSize, c, supportSize, s;
7543   PetscInt        pStart, pEnd, p, pp, csize, ssize;
7544   PetscBool       storagecheck = PETSC_TRUE;
7545   PetscErrorCode  ierr;
7546 
7547   PetscFunctionBegin;
7548   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7549   ierr = DMViewFromOptions(dm, NULL, "-sym_dm_view");CHKERRQ(ierr);
7550   ierr = DMPlexGetConeSection(dm, &coneSection);CHKERRQ(ierr);
7551   ierr = DMPlexGetSupportSection(dm, &supportSection);CHKERRQ(ierr);
7552   /* Check that point p is found in the support of its cone points, and vice versa */
7553   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
7554   for (p = pStart; p < pEnd; ++p) {
7555     ierr = DMPlexGetConeSize(dm, p, &coneSize);CHKERRQ(ierr);
7556     ierr = DMPlexGetCone(dm, p, &cone);CHKERRQ(ierr);
7557     for (c = 0; c < coneSize; ++c) {
7558       PetscBool dup = PETSC_FALSE;
7559       PetscInt  d;
7560       for (d = c-1; d >= 0; --d) {
7561         if (cone[c] == cone[d]) {dup = PETSC_TRUE; break;}
7562       }
7563       ierr = DMPlexGetSupportSize(dm, cone[c], &supportSize);CHKERRQ(ierr);
7564       ierr = DMPlexGetSupport(dm, cone[c], &support);CHKERRQ(ierr);
7565       for (s = 0; s < supportSize; ++s) {
7566         if (support[s] == p) break;
7567       }
7568       if ((s >= supportSize) || (dup && (support[s+1] != p))) {
7569         ierr = PetscPrintf(PETSC_COMM_SELF, "p: %D cone: ", p);CHKERRQ(ierr);
7570         for (s = 0; s < coneSize; ++s) {
7571           ierr = PetscPrintf(PETSC_COMM_SELF, "%D, ", cone[s]);CHKERRQ(ierr);
7572         }
7573         ierr = PetscPrintf(PETSC_COMM_SELF, "\n");CHKERRQ(ierr);
7574         ierr = PetscPrintf(PETSC_COMM_SELF, "p: %D support: ", cone[c]);CHKERRQ(ierr);
7575         for (s = 0; s < supportSize; ++s) {
7576           ierr = PetscPrintf(PETSC_COMM_SELF, "%D, ", support[s]);CHKERRQ(ierr);
7577         }
7578         ierr = PetscPrintf(PETSC_COMM_SELF, "\n");CHKERRQ(ierr);
7579         if (dup) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D not repeatedly found in support of repeated cone point %D", p, cone[c]);
7580         else SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D not found in support of cone point %D", p, cone[c]);
7581       }
7582     }
7583     ierr = DMPlexGetTreeParent(dm, p, &pp, NULL);CHKERRQ(ierr);
7584     if (p != pp) { storagecheck = PETSC_FALSE; continue; }
7585     ierr = DMPlexGetSupportSize(dm, p, &supportSize);CHKERRQ(ierr);
7586     ierr = DMPlexGetSupport(dm, p, &support);CHKERRQ(ierr);
7587     for (s = 0; s < supportSize; ++s) {
7588       ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
7589       ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
7590       for (c = 0; c < coneSize; ++c) {
7591         ierr = DMPlexGetTreeParent(dm, cone[c], &pp, NULL);CHKERRQ(ierr);
7592         if (cone[c] != pp) { c = 0; break; }
7593         if (cone[c] == p) break;
7594       }
7595       if (c >= coneSize) {
7596         ierr = PetscPrintf(PETSC_COMM_SELF, "p: %D support: ", p);CHKERRQ(ierr);
7597         for (c = 0; c < supportSize; ++c) {
7598           ierr = PetscPrintf(PETSC_COMM_SELF, "%D, ", support[c]);CHKERRQ(ierr);
7599         }
7600         ierr = PetscPrintf(PETSC_COMM_SELF, "\n");CHKERRQ(ierr);
7601         ierr = PetscPrintf(PETSC_COMM_SELF, "p: %D cone: ", support[s]);CHKERRQ(ierr);
7602         for (c = 0; c < coneSize; ++c) {
7603           ierr = PetscPrintf(PETSC_COMM_SELF, "%D, ", cone[c]);CHKERRQ(ierr);
7604         }
7605         ierr = PetscPrintf(PETSC_COMM_SELF, "\n");CHKERRQ(ierr);
7606         SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D not found in cone of support point %D", p, support[s]);
7607       }
7608     }
7609   }
7610   if (storagecheck) {
7611     ierr = PetscSectionGetStorageSize(coneSection, &csize);CHKERRQ(ierr);
7612     ierr = PetscSectionGetStorageSize(supportSection, &ssize);CHKERRQ(ierr);
7613     if (csize != ssize) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Total cone size %D != Total support size %D", csize, ssize);
7614   }
7615   PetscFunctionReturn(0);
7616 }
7617 
7618 /*
7619   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.
7620 */
7621 static PetscErrorCode DMPlexCellUnsplitVertices_Private(DM dm, PetscInt c, DMPolytopeType ct, PetscInt *unsplit)
7622 {
7623   DMPolytopeType  cct;
7624   PetscInt        ptpoints[4];
7625   const PetscInt *cone, *ccone, *ptcone;
7626   PetscInt        coneSize, cp, cconeSize, ccp, npt = 0, pt;
7627   PetscErrorCode  ierr;
7628 
7629   PetscFunctionBegin;
7630   *unsplit = 0;
7631   switch (ct) {
7632     case DM_POLYTOPE_SEG_PRISM_TENSOR:
7633       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
7634       ierr = DMPlexGetConeSize(dm, c, &coneSize);CHKERRQ(ierr);
7635       for (cp = 0; cp < coneSize; ++cp) {
7636         ierr = DMPlexGetCellType(dm, cone[cp], &cct);CHKERRQ(ierr);
7637         if (cct == DM_POLYTOPE_POINT_PRISM_TENSOR) ptpoints[npt++] = cone[cp];
7638       }
7639       break;
7640     case DM_POLYTOPE_TRI_PRISM_TENSOR:
7641     case DM_POLYTOPE_QUAD_PRISM_TENSOR:
7642       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
7643       ierr = DMPlexGetConeSize(dm, c, &coneSize);CHKERRQ(ierr);
7644       for (cp = 0; cp < coneSize; ++cp) {
7645         ierr = DMPlexGetCone(dm, cone[cp], &ccone);CHKERRQ(ierr);
7646         ierr = DMPlexGetConeSize(dm, cone[cp], &cconeSize);CHKERRQ(ierr);
7647         for (ccp = 0; ccp < cconeSize; ++ccp) {
7648           ierr = DMPlexGetCellType(dm, ccone[ccp], &cct);CHKERRQ(ierr);
7649           if (cct == DM_POLYTOPE_POINT_PRISM_TENSOR) {
7650             PetscInt p;
7651             for (p = 0; p < npt; ++p) if (ptpoints[p] == ccone[ccp]) break;
7652             if (p == npt) ptpoints[npt++] = ccone[ccp];
7653           }
7654         }
7655       }
7656       break;
7657     default: break;
7658   }
7659   for (pt = 0; pt < npt; ++pt) {
7660     ierr = DMPlexGetCone(dm, ptpoints[pt], &ptcone);CHKERRQ(ierr);
7661     if (ptcone[0] == ptcone[1]) ++(*unsplit);
7662   }
7663   PetscFunctionReturn(0);
7664 }
7665 
7666 /*@
7667   DMPlexCheckSkeleton - Check that each cell has the correct number of vertices
7668 
7669   Input Parameters:
7670 + dm - The DMPlex object
7671 - cellHeight - Normally 0
7672 
7673   Notes:
7674   This is a useful diagnostic when creating meshes programmatically.
7675   Currently applicable only to homogeneous simplex or tensor meshes.
7676 
7677   For the complete list of DMPlexCheck* functions, see DMSetFromOptions().
7678 
7679   Level: developer
7680 
7681 .seealso: DMCreate(), DMSetFromOptions()
7682 @*/
7683 PetscErrorCode DMPlexCheckSkeleton(DM dm, PetscInt cellHeight)
7684 {
7685   DMPlexInterpolatedFlag interp;
7686   DMPolytopeType         ct;
7687   PetscInt               vStart, vEnd, cStart, cEnd, c;
7688   PetscErrorCode         ierr;
7689 
7690   PetscFunctionBegin;
7691   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7692   ierr = DMPlexIsInterpolated(dm, &interp);CHKERRQ(ierr);
7693   ierr = DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd);CHKERRQ(ierr);
7694   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
7695   for (c = cStart; c < cEnd; ++c) {
7696     PetscInt *closure = NULL;
7697     PetscInt  coneSize, closureSize, cl, Nv = 0;
7698 
7699     ierr = DMPlexGetCellType(dm, c, &ct);CHKERRQ(ierr);
7700     if ((PetscInt) ct < 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cell %D has no cell type", c);
7701     if (ct == DM_POLYTOPE_UNKNOWN) continue;
7702     if (interp == DMPLEX_INTERPOLATED_FULL) {
7703       ierr = DMPlexGetConeSize(dm, c, &coneSize);CHKERRQ(ierr);
7704       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));
7705     }
7706     ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
7707     for (cl = 0; cl < closureSize*2; cl += 2) {
7708       const PetscInt p = closure[cl];
7709       if ((p >= vStart) && (p < vEnd)) ++Nv;
7710     }
7711     ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
7712     /* Special Case: Tensor faces with identified vertices */
7713     if (Nv < DMPolytopeTypeGetNumVertices(ct)) {
7714       PetscInt unsplit;
7715 
7716       ierr = DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit);CHKERRQ(ierr);
7717       if (Nv + unsplit == DMPolytopeTypeGetNumVertices(ct)) continue;
7718     }
7719     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));
7720   }
7721   PetscFunctionReturn(0);
7722 }
7723 
7724 /*@
7725   DMPlexCheckFaces - Check that the faces of each cell give a vertex order this is consistent with what we expect from the cell type
7726 
7727   Not Collective
7728 
7729   Input Parameters:
7730 + dm - The DMPlex object
7731 - cellHeight - Normally 0
7732 
7733   Notes:
7734   This is a useful diagnostic when creating meshes programmatically.
7735   This routine is only relevant for meshes that are fully interpolated across all ranks.
7736   It will error out if a partially interpolated mesh is given on some rank.
7737   It will do nothing for locally uninterpolated mesh (as there is nothing to check).
7738 
7739   For the complete list of DMPlexCheck* functions, see DMSetFromOptions().
7740 
7741   Level: developer
7742 
7743 .seealso: DMCreate(), DMPlexGetVTKCellHeight(), DMSetFromOptions()
7744 @*/
7745 PetscErrorCode DMPlexCheckFaces(DM dm, PetscInt cellHeight)
7746 {
7747   PetscInt       dim, depth, vStart, vEnd, cStart, cEnd, c, h;
7748   PetscErrorCode ierr;
7749   DMPlexInterpolatedFlag interpEnum;
7750 
7751   PetscFunctionBegin;
7752   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7753   ierr = DMPlexIsInterpolated(dm, &interpEnum);CHKERRQ(ierr);
7754   if (interpEnum == DMPLEX_INTERPOLATED_NONE) PetscFunctionReturn(0);
7755   if (interpEnum == DMPLEX_INTERPOLATED_PARTIAL) {
7756     PetscMPIInt rank;
7757     MPI_Comm    comm;
7758 
7759     ierr = PetscObjectGetComm((PetscObject) dm, &comm);CHKERRQ(ierr);
7760     ierr = MPI_Comm_rank(comm, &rank);CHKERRMPI(ierr);
7761     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_SUP, "Mesh is only partially interpolated on rank %d, this is currently not supported", rank);
7762   }
7763 
7764   ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr);
7765   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
7766   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
7767   for (h = cellHeight; h < PetscMin(depth, dim); ++h) {
7768     ierr = DMPlexGetHeightStratum(dm, h, &cStart, &cEnd);CHKERRQ(ierr);
7769     for (c = cStart; c < cEnd; ++c) {
7770       const PetscInt      *cone, *ornt, *faceSizes, *faces;
7771       const DMPolytopeType *faceTypes;
7772       DMPolytopeType        ct;
7773       PetscInt              numFaces, coneSize, f;
7774       PetscInt             *closure = NULL, closureSize, cl, numCorners = 0, fOff = 0, unsplit;
7775 
7776       ierr = DMPlexGetCellType(dm, c, &ct);CHKERRQ(ierr);
7777       ierr = DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit);CHKERRQ(ierr);
7778       if (unsplit) continue;
7779       ierr = DMPlexGetConeSize(dm, c, &coneSize);CHKERRQ(ierr);
7780       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
7781       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
7782       ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
7783       for (cl = 0; cl < closureSize*2; cl += 2) {
7784         const PetscInt p = closure[cl];
7785         if ((p >= vStart) && (p < vEnd)) closure[numCorners++] = p;
7786       }
7787       ierr = DMPlexGetRawFaces_Internal(dm, ct, closure, &numFaces, &faceTypes, &faceSizes, &faces);CHKERRQ(ierr);
7788       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);
7789       for (f = 0; f < numFaces; ++f) {
7790         DMPolytopeType fct;
7791         PetscInt       *fclosure = NULL, fclosureSize, cl, fnumCorners = 0, v;
7792 
7793         ierr = DMPlexGetCellType(dm, cone[f], &fct);CHKERRQ(ierr);
7794         ierr = DMPlexGetTransitiveClosure_Internal(dm, cone[f], ornt[f], PETSC_TRUE, &fclosureSize, &fclosure);CHKERRQ(ierr);
7795         for (cl = 0; cl < fclosureSize*2; cl += 2) {
7796           const PetscInt p = fclosure[cl];
7797           if ((p >= vStart) && (p < vEnd)) fclosure[fnumCorners++] = p;
7798         }
7799         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]);
7800         for (v = 0; v < fnumCorners; ++v) {
7801           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]);
7802         }
7803         ierr = DMPlexRestoreTransitiveClosure(dm, cone[f], PETSC_TRUE, &fclosureSize, &fclosure);CHKERRQ(ierr);
7804         fOff += faceSizes[f];
7805       }
7806       ierr = DMPlexRestoreRawFaces_Internal(dm, ct, closure, &numFaces, &faceTypes, &faceSizes, &faces);CHKERRQ(ierr);
7807       ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
7808     }
7809   }
7810   PetscFunctionReturn(0);
7811 }
7812 
7813 /*@
7814   DMPlexCheckGeometry - Check the geometry of mesh cells
7815 
7816   Input Parameter:
7817 . dm - The DMPlex object
7818 
7819   Notes:
7820   This is a useful diagnostic when creating meshes programmatically.
7821 
7822   For the complete list of DMPlexCheck* functions, see DMSetFromOptions().
7823 
7824   Level: developer
7825 
7826 .seealso: DMCreate(), DMSetFromOptions()
7827 @*/
7828 PetscErrorCode DMPlexCheckGeometry(DM dm)
7829 {
7830   Vec            coordinates;
7831   PetscReal      detJ, J[9], refVol = 1.0;
7832   PetscReal      vol;
7833   PetscBool      periodic;
7834   PetscInt       dim, depth, dE, d, cStart, cEnd, c;
7835   PetscErrorCode ierr;
7836 
7837   PetscFunctionBegin;
7838   ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr);
7839   ierr = DMGetCoordinateDim(dm, &dE);CHKERRQ(ierr);
7840   if (dim != dE) PetscFunctionReturn(0);
7841   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
7842   ierr = DMGetPeriodicity(dm, &periodic, NULL, NULL, NULL);CHKERRQ(ierr);
7843   for (d = 0; d < dim; ++d) refVol *= 2.0;
7844   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
7845   /* Make sure local coordinates are created, because that step is collective */
7846   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
7847   for (c = cStart; c < cEnd; ++c) {
7848     DMPolytopeType ct;
7849     PetscInt       unsplit;
7850     PetscBool      ignoreZeroVol = PETSC_FALSE;
7851 
7852     ierr = DMPlexGetCellType(dm, c, &ct);CHKERRQ(ierr);
7853     switch (ct) {
7854       case DM_POLYTOPE_SEG_PRISM_TENSOR:
7855       case DM_POLYTOPE_TRI_PRISM_TENSOR:
7856       case DM_POLYTOPE_QUAD_PRISM_TENSOR:
7857         ignoreZeroVol = PETSC_TRUE; break;
7858       default: break;
7859     }
7860     switch (ct) {
7861       case DM_POLYTOPE_TRI_PRISM:
7862       case DM_POLYTOPE_TRI_PRISM_TENSOR:
7863       case DM_POLYTOPE_QUAD_PRISM_TENSOR:
7864       case DM_POLYTOPE_PYRAMID:
7865         continue;
7866       default: break;
7867     }
7868     ierr = DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit);CHKERRQ(ierr);
7869     if (unsplit) continue;
7870     ierr = DMPlexComputeCellGeometryFEM(dm, c, NULL, NULL, J, NULL, &detJ);CHKERRQ(ierr);
7871     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);
7872     ierr = PetscInfo2(dm, "Cell %D FEM Volume %g\n", c, (double) detJ*refVol);CHKERRQ(ierr);
7873     if (depth > 1 && !periodic) {
7874       ierr = DMPlexComputeCellGeometryFVM(dm, c, &vol, NULL, NULL);CHKERRQ(ierr);
7875       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);
7876       ierr = PetscInfo2(dm, "Cell %D FVM Volume %g\n", c, (double) vol);CHKERRQ(ierr);
7877     }
7878   }
7879   PetscFunctionReturn(0);
7880 }
7881 
7882 /*@
7883   DMPlexCheckPointSF - Check that several necessary conditions are met for the point SF of this plex.
7884 
7885   Input Parameters:
7886 . dm - The DMPlex object
7887 
7888   Notes:
7889   This is mainly intended for debugging/testing purposes.
7890   It currently checks only meshes with no partition overlapping.
7891 
7892   For the complete list of DMPlexCheck* functions, see DMSetFromOptions().
7893 
7894   Level: developer
7895 
7896 .seealso: DMGetPointSF(), DMSetFromOptions()
7897 @*/
7898 PetscErrorCode DMPlexCheckPointSF(DM dm)
7899 {
7900   PetscSF         pointSF;
7901   PetscInt        cellHeight, cStart, cEnd, l, nleaves, nroots, overlap;
7902   const PetscInt *locals, *rootdegree;
7903   PetscBool       distributed;
7904   PetscErrorCode  ierr;
7905 
7906   PetscFunctionBegin;
7907   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7908   ierr = DMGetPointSF(dm, &pointSF);CHKERRQ(ierr);
7909   ierr = DMPlexIsDistributed(dm, &distributed);CHKERRQ(ierr);
7910   if (!distributed) PetscFunctionReturn(0);
7911   ierr = DMPlexGetOverlap(dm, &overlap);CHKERRQ(ierr);
7912   if (overlap) {
7913     ierr = PetscPrintf(PetscObjectComm((PetscObject)dm), "Warning: DMPlexCheckPointSF() is currently not implemented for meshes with partition overlapping");
7914     PetscFunctionReturn(0);
7915   }
7916   if (!pointSF) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "This DMPlex is distributed but does not have PointSF attached");
7917   ierr = PetscSFGetGraph(pointSF, &nroots, &nleaves, &locals, NULL);CHKERRQ(ierr);
7918   if (nroots < 0) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "This DMPlex is distributed but its PointSF has no graph set");
7919   ierr = PetscSFComputeDegreeBegin(pointSF, &rootdegree);CHKERRQ(ierr);
7920   ierr = PetscSFComputeDegreeEnd(pointSF, &rootdegree);CHKERRQ(ierr);
7921 
7922   /* 1) check there are no faces in 2D, cells in 3D, in interface */
7923   ierr = DMPlexGetVTKCellHeight(dm, &cellHeight);CHKERRQ(ierr);
7924   ierr = DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd);CHKERRQ(ierr);
7925   for (l = 0; l < nleaves; ++l) {
7926     const PetscInt point = locals[l];
7927 
7928     if (point >= cStart && point < cEnd) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point SF contains %D which is a cell", point);
7929   }
7930 
7931   /* 2) if some point is in interface, then all its cone points must be also in interface (either as leaves or roots) */
7932   for (l = 0; l < nleaves; ++l) {
7933     const PetscInt  point = locals[l];
7934     const PetscInt *cone;
7935     PetscInt        coneSize, c, idx;
7936 
7937     ierr = DMPlexGetConeSize(dm, point, &coneSize);CHKERRQ(ierr);
7938     ierr = DMPlexGetCone(dm, point, &cone);CHKERRQ(ierr);
7939     for (c = 0; c < coneSize; ++c) {
7940       if (!rootdegree[cone[c]]) {
7941         ierr = PetscFindInt(cone[c], nleaves, locals, &idx);CHKERRQ(ierr);
7942         if (idx < 0) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point SF contains %D but not %D from its cone", point, cone[c]);
7943       }
7944     }
7945   }
7946   PetscFunctionReturn(0);
7947 }
7948 
7949 typedef struct cell_stats
7950 {
7951   PetscReal min, max, sum, squaresum;
7952   PetscInt  count;
7953 } cell_stats_t;
7954 
7955 static void MPIAPI cell_stats_reduce(void *a, void *b, int * len, MPI_Datatype *datatype)
7956 {
7957   PetscInt i, N = *len;
7958 
7959   for (i = 0; i < N; i++) {
7960     cell_stats_t *A = (cell_stats_t *) a;
7961     cell_stats_t *B = (cell_stats_t *) b;
7962 
7963     B->min = PetscMin(A->min,B->min);
7964     B->max = PetscMax(A->max,B->max);
7965     B->sum += A->sum;
7966     B->squaresum += A->squaresum;
7967     B->count += A->count;
7968   }
7969 }
7970 
7971 /*@
7972   DMPlexCheckCellShape - Checks the Jacobian of the mapping from reference to real cells and computes some minimal statistics.
7973 
7974   Collective on dm
7975 
7976   Input Parameters:
7977 + dm        - The DMPlex object
7978 . output    - If true, statistics will be displayed on stdout
7979 - condLimit - Display all cells above this condition number, or PETSC_DETERMINE for no cell output
7980 
7981   Notes:
7982   This is mainly intended for debugging/testing purposes.
7983 
7984   For the complete list of DMPlexCheck* functions, see DMSetFromOptions().
7985 
7986   Level: developer
7987 
7988 .seealso: DMSetFromOptions(), DMPlexComputeOrthogonalQuality()
7989 @*/
7990 PetscErrorCode DMPlexCheckCellShape(DM dm, PetscBool output, PetscReal condLimit)
7991 {
7992   DM             dmCoarse;
7993   cell_stats_t   stats, globalStats;
7994   MPI_Comm       comm = PetscObjectComm((PetscObject)dm);
7995   PetscReal      *J, *invJ, min = 0, max = 0, mean = 0, stdev = 0;
7996   PetscReal      limit = condLimit > 0 ? condLimit : PETSC_MAX_REAL;
7997   PetscInt       cdim, cStart, cEnd, c, eStart, eEnd, count = 0;
7998   PetscMPIInt    rank,size;
7999   PetscErrorCode ierr;
8000 
8001   PetscFunctionBegin;
8002   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8003   stats.min   = PETSC_MAX_REAL;
8004   stats.max   = PETSC_MIN_REAL;
8005   stats.sum   = stats.squaresum = 0.;
8006   stats.count = 0;
8007 
8008   ierr = MPI_Comm_size(comm, &size);CHKERRMPI(ierr);
8009   ierr = MPI_Comm_rank(comm, &rank);CHKERRMPI(ierr);
8010   ierr = DMGetCoordinateDim(dm,&cdim);CHKERRQ(ierr);
8011   ierr = PetscMalloc2(PetscSqr(cdim), &J, PetscSqr(cdim), &invJ);CHKERRQ(ierr);
8012   ierr = DMPlexGetSimplexOrBoxCells(dm,0,&cStart,&cEnd);CHKERRQ(ierr);
8013   ierr = DMPlexGetDepthStratum(dm,1,&eStart,&eEnd);CHKERRQ(ierr);
8014   for (c = cStart; c < cEnd; c++) {
8015     PetscInt  i;
8016     PetscReal frobJ = 0., frobInvJ = 0., cond2, cond, detJ;
8017 
8018     ierr = DMPlexComputeCellGeometryAffineFEM(dm,c,NULL,J,invJ,&detJ);CHKERRQ(ierr);
8019     if (detJ < 0.0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Mesh cell %D is inverted", c);
8020     for (i = 0; i < PetscSqr(cdim); ++i) {
8021       frobJ    += J[i] * J[i];
8022       frobInvJ += invJ[i] * invJ[i];
8023     }
8024     cond2 = frobJ * frobInvJ;
8025     cond  = PetscSqrtReal(cond2);
8026 
8027     stats.min        = PetscMin(stats.min,cond);
8028     stats.max        = PetscMax(stats.max,cond);
8029     stats.sum       += cond;
8030     stats.squaresum += cond2;
8031     stats.count++;
8032     if (output && cond > limit) {
8033       PetscSection coordSection;
8034       Vec          coordsLocal;
8035       PetscScalar *coords = NULL;
8036       PetscInt     Nv, d, clSize, cl, *closure = NULL;
8037 
8038       ierr = DMGetCoordinatesLocal(dm, &coordsLocal);CHKERRQ(ierr);
8039       ierr = DMGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
8040       ierr = DMPlexVecGetClosure(dm, coordSection, coordsLocal, c, &Nv, &coords);CHKERRQ(ierr);
8041       ierr = PetscSynchronizedPrintf(comm, "[%d] Cell %D cond %g\n", rank, c, (double) cond);CHKERRQ(ierr);
8042       for (i = 0; i < Nv/cdim; ++i) {
8043         ierr = PetscSynchronizedPrintf(comm, "  Vertex %D: (", i);CHKERRQ(ierr);
8044         for (d = 0; d < cdim; ++d) {
8045           if (d > 0) {ierr = PetscSynchronizedPrintf(comm, ", ");CHKERRQ(ierr);}
8046           ierr = PetscSynchronizedPrintf(comm, "%g", (double) PetscRealPart(coords[i*cdim+d]));CHKERRQ(ierr);
8047         }
8048         ierr = PetscSynchronizedPrintf(comm, ")\n");CHKERRQ(ierr);
8049       }
8050       ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &clSize, &closure);CHKERRQ(ierr);
8051       for (cl = 0; cl < clSize*2; cl += 2) {
8052         const PetscInt edge = closure[cl];
8053 
8054         if ((edge >= eStart) && (edge < eEnd)) {
8055           PetscReal len;
8056 
8057           ierr = DMPlexComputeCellGeometryFVM(dm, edge, &len, NULL, NULL);CHKERRQ(ierr);
8058           ierr = PetscSynchronizedPrintf(comm, "  Edge %D: length %g\n", edge, (double) len);CHKERRQ(ierr);
8059         }
8060       }
8061       ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &clSize, &closure);CHKERRQ(ierr);
8062       ierr = DMPlexVecRestoreClosure(dm, coordSection, coordsLocal, c, &Nv, &coords);CHKERRQ(ierr);
8063     }
8064   }
8065   if (output) {ierr = PetscSynchronizedFlush(comm, NULL);CHKERRQ(ierr);}
8066 
8067   if (size > 1) {
8068     PetscMPIInt   blockLengths[2] = {4,1};
8069     MPI_Aint      blockOffsets[2] = {offsetof(cell_stats_t,min),offsetof(cell_stats_t,count)};
8070     MPI_Datatype  blockTypes[2]   = {MPIU_REAL,MPIU_INT}, statType;
8071     MPI_Op        statReduce;
8072 
8073     ierr = MPI_Type_create_struct(2,blockLengths,blockOffsets,blockTypes,&statType);CHKERRMPI(ierr);
8074     ierr = MPI_Type_commit(&statType);CHKERRMPI(ierr);
8075     ierr = MPI_Op_create(cell_stats_reduce, PETSC_TRUE, &statReduce);CHKERRMPI(ierr);
8076     ierr = MPI_Reduce(&stats,&globalStats,1,statType,statReduce,0,comm);CHKERRMPI(ierr);
8077     ierr = MPI_Op_free(&statReduce);CHKERRMPI(ierr);
8078     ierr = MPI_Type_free(&statType);CHKERRMPI(ierr);
8079   } else {
8080     ierr = PetscArraycpy(&globalStats,&stats,1);CHKERRQ(ierr);
8081   }
8082   if (!rank) {
8083     count = globalStats.count;
8084     min   = globalStats.min;
8085     max   = globalStats.max;
8086     mean  = globalStats.sum / globalStats.count;
8087     stdev = globalStats.count > 1 ? PetscSqrtReal(PetscMax((globalStats.squaresum - globalStats.count * mean * mean) / (globalStats.count - 1),0)) : 0.0;
8088   }
8089 
8090   if (output) {
8091     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);
8092   }
8093   ierr = PetscFree2(J,invJ);CHKERRQ(ierr);
8094 
8095   ierr = DMGetCoarseDM(dm,&dmCoarse);CHKERRQ(ierr);
8096   if (dmCoarse) {
8097     PetscBool isplex;
8098 
8099     ierr = PetscObjectTypeCompare((PetscObject)dmCoarse,DMPLEX,&isplex);CHKERRQ(ierr);
8100     if (isplex) {
8101       ierr = DMPlexCheckCellShape(dmCoarse,output,condLimit);CHKERRQ(ierr);
8102     }
8103   }
8104   PetscFunctionReturn(0);
8105 }
8106 
8107 /*@
8108   DMPlexComputeOrthogonalQuality - Compute cell-wise orthogonal quality mesh statistic. Optionally tags all cells with
8109   orthogonal quality below given tolerance.
8110 
8111   Collective on dm
8112 
8113   Input Parameters:
8114 + dm   - The DMPlex object
8115 . fv   - Optional PetscFV object for pre-computed cell/face centroid information
8116 - atol - [0, 1] Absolute tolerance for tagging cells.
8117 
8118   Output Parameters:
8119 + OrthQual      - Vec containing orthogonal quality per cell
8120 - OrthQualLabel - DMLabel tagging cells below atol with DM_ADAPT_REFINE
8121 
8122   Options Database Keys:
8123 + -dm_plex_orthogonal_quality_label_view - view OrthQualLabel if label is requested. Currently only PETSCVIEWERASCII is
8124 supported.
8125 - -dm_plex_orthogonal_quality_vec_view - view OrthQual vector.
8126 
8127   Notes:
8128   Orthogonal quality is given by the following formula:
8129 
8130   \min \left[ \frac{A_i \cdot f_i}{\|A_i\| \|f_i\|} , \frac{A_i \cdot c_i}{\|A_i\| \|c_i\|} \right]
8131 
8132   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
8133   is the vector from the current cells centroid to the centroid of its i'th neighbor (which shares a face with the
8134   current cell). This computes the vector similarity between each cell face and its corresponding neighbor centroid by
8135   calculating the cosine of the angle between these vectors.
8136 
8137   Orthogonal quality ranges from 1 (best) to 0 (worst).
8138 
8139   This routine is mainly useful for FVM, however is not restricted to only FVM. The PetscFV object is optionally used to check for
8140   pre-computed FVM cell data, but if it is not passed in then this data will be computed.
8141 
8142   Cells are tagged if they have an orthogonal quality less than or equal to the absolute tolerance.
8143 
8144   Level: intermediate
8145 
8146 .seealso: DMPlexCheckCellShape(), DMCreateLabel()
8147 @*/
8148 PetscErrorCode DMPlexComputeOrthogonalQuality(DM dm, PetscFV fv, PetscReal atol, Vec *OrthQual, DMLabel *OrthQualLabel)
8149 {
8150   PetscInt                nc, cellHeight, cStart, cEnd, cell, cellIter = 0;
8151   PetscInt                *idx;
8152   PetscScalar             *oqVals;
8153   const PetscScalar       *cellGeomArr, *faceGeomArr;
8154   PetscReal               *ci, *fi, *Ai;
8155   MPI_Comm                comm;
8156   Vec                     cellgeom, facegeom;
8157   DM                      dmFace, dmCell;
8158   IS                      glob;
8159   ISLocalToGlobalMapping  ltog;
8160   PetscViewer             vwr;
8161   PetscErrorCode          ierr;
8162 
8163   PetscFunctionBegin;
8164   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8165   if (fv) {PetscValidHeaderSpecific(fv, PETSCFV_CLASSID, 2);}
8166   PetscValidPointer(OrthQual, 4);
8167   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);
8168   ierr = PetscObjectGetComm((PetscObject) dm, &comm);CHKERRQ(ierr);
8169   ierr = DMGetDimension(dm, &nc);CHKERRQ(ierr);
8170   if (nc < 2) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "DM must have dimension >= 2 (current %D)", nc);
8171   {
8172     DMPlexInterpolatedFlag interpFlag;
8173 
8174     ierr = DMPlexIsInterpolated(dm, &interpFlag);CHKERRQ(ierr);
8175     if (interpFlag != DMPLEX_INTERPOLATED_FULL) {
8176       PetscMPIInt rank;
8177 
8178       ierr = MPI_Comm_rank(comm, &rank);CHKERRMPI(ierr);
8179       SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "DM must be fully interpolated, DM on rank %d is not fully interpolated", rank);
8180     }
8181   }
8182   if (OrthQualLabel) {
8183     PetscValidPointer(OrthQualLabel, 5);
8184     ierr = DMCreateLabel(dm, "Orthogonal_Quality");CHKERRQ(ierr);
8185     ierr = DMGetLabel(dm, "Orthogonal_Quality", OrthQualLabel);CHKERRQ(ierr);
8186   } else {*OrthQualLabel = NULL;}
8187   ierr = DMPlexGetVTKCellHeight(dm, &cellHeight);CHKERRQ(ierr);
8188   ierr = DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd);CHKERRQ(ierr);
8189   ierr = DMPlexCreateCellNumbering_Internal(dm, PETSC_TRUE, &glob);CHKERRQ(ierr);
8190   ierr = ISLocalToGlobalMappingCreateIS(glob, &ltog);CHKERRQ(ierr);
8191   ierr = ISLocalToGlobalMappingSetType(ltog, ISLOCALTOGLOBALMAPPINGHASH);CHKERRQ(ierr);
8192   ierr = VecCreate(comm, OrthQual);CHKERRQ(ierr);
8193   ierr = VecSetType(*OrthQual, VECSTANDARD);CHKERRQ(ierr);
8194   ierr = VecSetSizes(*OrthQual, cEnd-cStart, PETSC_DETERMINE);CHKERRQ(ierr);
8195   ierr = VecSetLocalToGlobalMapping(*OrthQual, ltog);CHKERRQ(ierr);
8196   ierr = VecSetUp(*OrthQual);CHKERRQ(ierr);
8197   ierr = ISDestroy(&glob);CHKERRQ(ierr);
8198   ierr = ISLocalToGlobalMappingDestroy(&ltog);CHKERRQ(ierr);
8199   ierr = DMPlexGetDataFVM(dm, fv, &cellgeom, &facegeom, NULL);CHKERRQ(ierr);
8200   ierr = VecGetArrayRead(cellgeom, &cellGeomArr);CHKERRQ(ierr);
8201   ierr = VecGetArrayRead(facegeom, &faceGeomArr);CHKERRQ(ierr);
8202   ierr = VecGetDM(cellgeom, &dmCell);CHKERRQ(ierr);
8203   ierr = VecGetDM(facegeom, &dmFace);CHKERRQ(ierr);
8204   ierr = PetscMalloc5(cEnd-cStart, &idx, cEnd-cStart, &oqVals, nc, &ci, nc, &fi, nc, &Ai);CHKERRQ(ierr);
8205   for (cell = cStart; cell < cEnd; cellIter++,cell++) {
8206     PetscInt           cellneigh, cellneighiter = 0, adjSize = PETSC_DETERMINE;
8207     PetscInt           cellarr[2], *adj = NULL;
8208     PetscScalar        *cArr, *fArr;
8209     PetscReal          minvalc = 1.0, minvalf = 1.0;
8210     PetscFVCellGeom    *cg;
8211 
8212     idx[cellIter] = cell-cStart;
8213     cellarr[0] = cell;
8214     /* Make indexing into cellGeom easier */
8215     ierr = DMPlexPointLocalRead(dmCell, cell, cellGeomArr, &cg);CHKERRQ(ierr);
8216     ierr = DMPlexGetAdjacency_Internal(dm, cell, PETSC_TRUE, PETSC_FALSE, PETSC_FALSE, &adjSize, &adj);CHKERRQ(ierr);
8217     /* Technically 1 too big, but easier than fiddling with empty adjacency array */
8218     ierr = PetscCalloc2(adjSize, &cArr, adjSize, &fArr);CHKERRQ(ierr);
8219     for (cellneigh = 0; cellneigh < adjSize; cellneighiter++,cellneigh++) {
8220       PetscInt         i;
8221       const PetscInt   neigh = adj[cellneigh];
8222       PetscReal        normci = 0, normfi = 0, normai = 0;
8223       PetscFVCellGeom  *cgneigh;
8224       PetscFVFaceGeom  *fg;
8225 
8226       /* Don't count ourselves in the neighbor list */
8227       if (neigh == cell) continue;
8228       ierr = DMPlexPointLocalRead(dmCell, neigh, cellGeomArr, &cgneigh);CHKERRQ(ierr);
8229       cellarr[1] = neigh;
8230       {
8231         PetscInt       numcovpts;
8232         const PetscInt *covpts;
8233 
8234         ierr = DMPlexGetMeet(dm, 2, cellarr, &numcovpts, &covpts);CHKERRQ(ierr);
8235         ierr = DMPlexPointLocalRead(dmFace, covpts[0], faceGeomArr, &fg);CHKERRQ(ierr);
8236         ierr = DMPlexRestoreMeet(dm, 2, cellarr, &numcovpts, &covpts);CHKERRQ(ierr);
8237       }
8238 
8239       /* Compute c_i, f_i and their norms */
8240       for (i = 0; i < nc; i++) {
8241         ci[i] = cgneigh->centroid[i] - cg->centroid[i];
8242         fi[i] = fg->centroid[i] - cg->centroid[i];
8243         Ai[i] = fg->normal[i];
8244         normci += PetscPowReal(ci[i], 2);
8245         normfi += PetscPowReal(fi[i], 2);
8246         normai += PetscPowReal(Ai[i], 2);
8247       }
8248       normci = PetscSqrtReal(normci);
8249       normfi = PetscSqrtReal(normfi);
8250       normai = PetscSqrtReal(normai);
8251 
8252       /* Normalize and compute for each face-cell-normal pair */
8253       for (i = 0; i < nc; i++) {
8254         ci[i] = ci[i]/normci;
8255         fi[i] = fi[i]/normfi;
8256         Ai[i] = Ai[i]/normai;
8257         /* PetscAbs because I don't know if normals are guaranteed to point out */
8258         cArr[cellneighiter] += PetscAbs(Ai[i]*ci[i]);
8259         fArr[cellneighiter] += PetscAbs(Ai[i]*fi[i]);
8260       }
8261       if (PetscRealPart(cArr[cellneighiter]) < minvalc) {
8262         minvalc = PetscRealPart(cArr[cellneighiter]);
8263       }
8264       if (PetscRealPart(fArr[cellneighiter]) < minvalf) {
8265         minvalf = PetscRealPart(fArr[cellneighiter]);
8266       }
8267     }
8268     ierr = PetscFree(adj);CHKERRQ(ierr);
8269     ierr = PetscFree2(cArr, fArr);CHKERRQ(ierr);
8270     /* Defer to cell if they're equal */
8271     oqVals[cellIter] = PetscMin(minvalf, minvalc);
8272     if (OrthQualLabel) {
8273       if (PetscRealPart(oqVals[cellIter]) <= atol) {ierr = DMLabelSetValue(*OrthQualLabel, cell, DM_ADAPT_REFINE);CHKERRQ(ierr);}
8274     }
8275   }
8276   ierr = VecSetValuesLocal(*OrthQual, cEnd-cStart, idx, oqVals, INSERT_VALUES);CHKERRQ(ierr);
8277   ierr = VecAssemblyBegin(*OrthQual);CHKERRQ(ierr);
8278   ierr = VecAssemblyEnd(*OrthQual);CHKERRQ(ierr);
8279   ierr = VecRestoreArrayRead(cellgeom, &cellGeomArr);CHKERRQ(ierr);
8280   ierr = VecRestoreArrayRead(facegeom, &faceGeomArr);CHKERRQ(ierr);
8281   ierr = PetscOptionsGetViewer(comm, NULL, NULL, "-dm_plex_orthogonal_quality_label_view", &vwr, NULL, NULL);CHKERRQ(ierr);
8282   if (OrthQualLabel) {
8283     if (vwr) {ierr = DMLabelView(*OrthQualLabel, vwr);CHKERRQ(ierr);}
8284   }
8285   ierr = PetscFree5(idx, oqVals, ci, fi, Ai);CHKERRQ(ierr);
8286   ierr = PetscViewerDestroy(&vwr);CHKERRQ(ierr);
8287   ierr = VecViewFromOptions(*OrthQual, NULL, "-dm_plex_orthogonal_quality_vec_view");CHKERRQ(ierr);
8288   PetscFunctionReturn(0);
8289 }
8290 
8291 /* this is here insead of DMGetOutputDM because output DM still has constraints in the local indices that affect
8292  * interpolator construction */
8293 static PetscErrorCode DMGetFullDM(DM dm, DM *odm)
8294 {
8295   PetscSection   section, newSection, gsection;
8296   PetscSF        sf;
8297   PetscBool      hasConstraints, ghasConstraints;
8298   PetscErrorCode ierr;
8299 
8300   PetscFunctionBegin;
8301   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
8302   PetscValidPointer(odm,2);
8303   ierr = DMGetLocalSection(dm, &section);CHKERRQ(ierr);
8304   ierr = PetscSectionHasConstraints(section, &hasConstraints);CHKERRQ(ierr);
8305   ierr = MPI_Allreduce(&hasConstraints, &ghasConstraints, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject) dm));CHKERRMPI(ierr);
8306   if (!ghasConstraints) {
8307     ierr = PetscObjectReference((PetscObject)dm);CHKERRQ(ierr);
8308     *odm = dm;
8309     PetscFunctionReturn(0);
8310   }
8311   ierr = DMClone(dm, odm);CHKERRQ(ierr);
8312   ierr = DMCopyFields(dm, *odm);CHKERRQ(ierr);
8313   ierr = DMGetLocalSection(*odm, &newSection);CHKERRQ(ierr);
8314   ierr = DMGetPointSF(*odm, &sf);CHKERRQ(ierr);
8315   ierr = PetscSectionCreateGlobalSection(newSection, sf, PETSC_TRUE, PETSC_FALSE, &gsection);CHKERRQ(ierr);
8316   ierr = DMSetGlobalSection(*odm, gsection);CHKERRQ(ierr);
8317   ierr = PetscSectionDestroy(&gsection);CHKERRQ(ierr);
8318   PetscFunctionReturn(0);
8319 }
8320 
8321 static PetscErrorCode DMCreateAffineInterpolationCorrection_Plex(DM dmc, DM dmf, Vec *shift)
8322 {
8323   DM             dmco, dmfo;
8324   Mat            interpo;
8325   Vec            rscale;
8326   Vec            cglobalo, clocal;
8327   Vec            fglobal, fglobalo, flocal;
8328   PetscBool      regular;
8329   PetscErrorCode ierr;
8330 
8331   PetscFunctionBegin;
8332   ierr = DMGetFullDM(dmc, &dmco);CHKERRQ(ierr);
8333   ierr = DMGetFullDM(dmf, &dmfo);CHKERRQ(ierr);
8334   ierr = DMSetCoarseDM(dmfo, dmco);CHKERRQ(ierr);
8335   ierr = DMPlexGetRegularRefinement(dmf, &regular);CHKERRQ(ierr);
8336   ierr = DMPlexSetRegularRefinement(dmfo, regular);CHKERRQ(ierr);
8337   ierr = DMCreateInterpolation(dmco, dmfo, &interpo, &rscale);CHKERRQ(ierr);
8338   ierr = DMCreateGlobalVector(dmco, &cglobalo);CHKERRQ(ierr);
8339   ierr = DMCreateLocalVector(dmc, &clocal);CHKERRQ(ierr);
8340   ierr = VecSet(cglobalo, 0.);CHKERRQ(ierr);
8341   ierr = VecSet(clocal, 0.);CHKERRQ(ierr);
8342   ierr = DMCreateGlobalVector(dmf, &fglobal);CHKERRQ(ierr);
8343   ierr = DMCreateGlobalVector(dmfo, &fglobalo);CHKERRQ(ierr);
8344   ierr = DMCreateLocalVector(dmf, &flocal);CHKERRQ(ierr);
8345   ierr = VecSet(fglobal, 0.);CHKERRQ(ierr);
8346   ierr = VecSet(fglobalo, 0.);CHKERRQ(ierr);
8347   ierr = VecSet(flocal, 0.);CHKERRQ(ierr);
8348   ierr = DMPlexInsertBoundaryValues(dmc, PETSC_TRUE, clocal, 0., NULL, NULL, NULL);CHKERRQ(ierr);
8349   ierr = DMLocalToGlobalBegin(dmco, clocal, INSERT_VALUES, cglobalo);CHKERRQ(ierr);
8350   ierr = DMLocalToGlobalEnd(dmco, clocal, INSERT_VALUES, cglobalo);CHKERRQ(ierr);
8351   ierr = MatMult(interpo, cglobalo, fglobalo);CHKERRQ(ierr);
8352   ierr = DMGlobalToLocalBegin(dmfo, fglobalo, INSERT_VALUES, flocal);CHKERRQ(ierr);
8353   ierr = DMGlobalToLocalEnd(dmfo, fglobalo, INSERT_VALUES, flocal);CHKERRQ(ierr);
8354   ierr = DMLocalToGlobalBegin(dmf, flocal, INSERT_VALUES, fglobal);CHKERRQ(ierr);
8355   ierr = DMLocalToGlobalEnd(dmf, flocal, INSERT_VALUES, fglobal);CHKERRQ(ierr);
8356   *shift = fglobal;
8357   ierr = VecDestroy(&flocal);CHKERRQ(ierr);
8358   ierr = VecDestroy(&fglobalo);CHKERRQ(ierr);
8359   ierr = VecDestroy(&clocal);CHKERRQ(ierr);
8360   ierr = VecDestroy(&cglobalo);CHKERRQ(ierr);
8361   ierr = VecDestroy(&rscale);CHKERRQ(ierr);
8362   ierr = MatDestroy(&interpo);CHKERRQ(ierr);
8363   ierr = DMDestroy(&dmfo);CHKERRQ(ierr);
8364   ierr = DMDestroy(&dmco);CHKERRQ(ierr);
8365   PetscFunctionReturn(0);
8366 }
8367 
8368 PETSC_INTERN PetscErrorCode DMInterpolateSolution_Plex(DM coarse, DM fine, Mat interp, Vec coarseSol, Vec fineSol)
8369 {
8370   PetscObject    shifto;
8371   Vec            shift;
8372 
8373   PetscErrorCode ierr;
8374 
8375   PetscFunctionBegin;
8376   if (!interp) {
8377     Vec rscale;
8378 
8379     ierr = DMCreateInterpolation(coarse, fine, &interp, &rscale);CHKERRQ(ierr);
8380     ierr = VecDestroy(&rscale);CHKERRQ(ierr);
8381   } else {
8382     ierr = PetscObjectReference((PetscObject)interp);CHKERRQ(ierr);
8383   }
8384   ierr = PetscObjectQuery((PetscObject)interp, "_DMInterpolateSolution_Plex_Vec", &shifto);CHKERRQ(ierr);
8385   if (!shifto) {
8386     ierr = DMCreateAffineInterpolationCorrection_Plex(coarse, fine, &shift);CHKERRQ(ierr);
8387     ierr = PetscObjectCompose((PetscObject)interp, "_DMInterpolateSolution_Plex_Vec", (PetscObject) shift);CHKERRQ(ierr);
8388     shifto = (PetscObject) shift;
8389     ierr = VecDestroy(&shift);CHKERRQ(ierr);
8390   }
8391   shift = (Vec) shifto;
8392   ierr = MatInterpolate(interp, coarseSol, fineSol);CHKERRQ(ierr);
8393   ierr = VecAXPY(fineSol, 1.0, shift);CHKERRQ(ierr);
8394   ierr = MatDestroy(&interp);CHKERRQ(ierr);
8395   PetscFunctionReturn(0);
8396 }
8397 
8398 /* Pointwise interpolation
8399      Just code FEM for now
8400      u^f = I u^c
8401      sum_k u^f_k phi^f_k = I sum_j u^c_j phi^c_j
8402      u^f_i = sum_j psi^f_i I phi^c_j u^c_j
8403      I_{ij} = psi^f_i phi^c_j
8404 */
8405 PetscErrorCode DMCreateInterpolation_Plex(DM dmCoarse, DM dmFine, Mat *interpolation, Vec *scaling)
8406 {
8407   PetscSection   gsc, gsf;
8408   PetscInt       m, n;
8409   void          *ctx;
8410   DM             cdm;
8411   PetscBool      regular, ismatis, isRefined = dmCoarse->data == dmFine->data ? PETSC_FALSE : PETSC_TRUE;
8412   PetscErrorCode ierr;
8413 
8414   PetscFunctionBegin;
8415   ierr = DMGetGlobalSection(dmFine, &gsf);CHKERRQ(ierr);
8416   ierr = PetscSectionGetConstrainedStorageSize(gsf, &m);CHKERRQ(ierr);
8417   ierr = DMGetGlobalSection(dmCoarse, &gsc);CHKERRQ(ierr);
8418   ierr = PetscSectionGetConstrainedStorageSize(gsc, &n);CHKERRQ(ierr);
8419 
8420   ierr = PetscStrcmp(dmCoarse->mattype, MATIS, &ismatis);CHKERRQ(ierr);
8421   ierr = MatCreate(PetscObjectComm((PetscObject) dmCoarse), interpolation);CHKERRQ(ierr);
8422   ierr = MatSetSizes(*interpolation, m, n, PETSC_DETERMINE, PETSC_DETERMINE);CHKERRQ(ierr);
8423   ierr = MatSetType(*interpolation, ismatis ? MATAIJ : dmCoarse->mattype);CHKERRQ(ierr);
8424   ierr = DMGetApplicationContext(dmFine, &ctx);CHKERRQ(ierr);
8425 
8426   ierr = DMGetCoarseDM(dmFine, &cdm);CHKERRQ(ierr);
8427   ierr = DMPlexGetRegularRefinement(dmFine, &regular);CHKERRQ(ierr);
8428   if (!isRefined || (regular && cdm == dmCoarse)) {ierr = DMPlexComputeInterpolatorNested(dmCoarse, dmFine, isRefined, *interpolation, ctx);CHKERRQ(ierr);}
8429   else                                            {ierr = DMPlexComputeInterpolatorGeneral(dmCoarse, dmFine, *interpolation, ctx);CHKERRQ(ierr);}
8430   ierr = MatViewFromOptions(*interpolation, NULL, "-interp_mat_view");CHKERRQ(ierr);
8431   if (scaling) {
8432     /* Use naive scaling */
8433     ierr = DMCreateInterpolationScale(dmCoarse, dmFine, *interpolation, scaling);CHKERRQ(ierr);
8434   }
8435   PetscFunctionReturn(0);
8436 }
8437 
8438 PetscErrorCode DMCreateInjection_Plex(DM dmCoarse, DM dmFine, Mat *mat)
8439 {
8440   PetscErrorCode ierr;
8441   VecScatter     ctx;
8442 
8443   PetscFunctionBegin;
8444   ierr = DMPlexComputeInjectorFEM(dmCoarse, dmFine, &ctx, NULL);CHKERRQ(ierr);
8445   ierr = MatCreateScatter(PetscObjectComm((PetscObject)ctx), ctx, mat);CHKERRQ(ierr);
8446   ierr = VecScatterDestroy(&ctx);CHKERRQ(ierr);
8447   PetscFunctionReturn(0);
8448 }
8449 
8450 static void g0_identity_private(PetscInt dim, PetscInt Nf, PetscInt NfAux,
8451                                 const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
8452                                 const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
8453                                 PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g0[])
8454 {
8455   g0[0] = 1.0;
8456 }
8457 
8458 PetscErrorCode DMCreateMassMatrix_Plex(DM dmCoarse, DM dmFine, Mat *mass)
8459 {
8460   PetscSection   gsc, gsf;
8461   PetscInt       m, n;
8462   void          *ctx;
8463   DM             cdm;
8464   PetscBool      regular;
8465   PetscErrorCode ierr;
8466 
8467   PetscFunctionBegin;
8468   if (dmFine == dmCoarse) {
8469     DM       dmc;
8470     PetscDS  ds;
8471     Vec      u;
8472     IS       cellIS;
8473     PetscFormKey key;
8474     PetscInt depth;
8475 
8476     ierr = DMClone(dmFine, &dmc);CHKERRQ(ierr);
8477     ierr = DMCopyDisc(dmFine, dmc);CHKERRQ(ierr);
8478     ierr = DMGetDS(dmc, &ds);CHKERRQ(ierr);
8479     ierr = PetscDSSetJacobian(ds, 0, 0, g0_identity_private, NULL, NULL, NULL);CHKERRQ(ierr);
8480     ierr = DMCreateMatrix(dmc, mass);CHKERRQ(ierr);
8481     ierr = DMGetGlobalVector(dmc, &u);CHKERRQ(ierr);
8482     ierr = DMPlexGetDepth(dmc, &depth);CHKERRQ(ierr);
8483     ierr = DMGetStratumIS(dmc, "depth", depth, &cellIS);CHKERRQ(ierr);
8484     ierr = MatZeroEntries(*mass);CHKERRQ(ierr);
8485     key.label = NULL;
8486     key.value = 0;
8487     key.field = 0;
8488     key.part  = 0;
8489     ierr = DMPlexComputeJacobian_Internal(dmc, key, cellIS, 0.0, 0.0, u, NULL, *mass, *mass, NULL);CHKERRQ(ierr);
8490     ierr = ISDestroy(&cellIS);CHKERRQ(ierr);
8491     ierr = DMRestoreGlobalVector(dmc, &u);CHKERRQ(ierr);
8492     ierr = DMDestroy(&dmc);CHKERRQ(ierr);
8493   } else {
8494     ierr = DMGetGlobalSection(dmFine, &gsf);CHKERRQ(ierr);
8495     ierr = PetscSectionGetConstrainedStorageSize(gsf, &m);CHKERRQ(ierr);
8496     ierr = DMGetGlobalSection(dmCoarse, &gsc);CHKERRQ(ierr);
8497     ierr = PetscSectionGetConstrainedStorageSize(gsc, &n);CHKERRQ(ierr);
8498 
8499     ierr = MatCreate(PetscObjectComm((PetscObject) dmCoarse), mass);CHKERRQ(ierr);
8500     ierr = MatSetSizes(*mass, m, n, PETSC_DETERMINE, PETSC_DETERMINE);CHKERRQ(ierr);
8501     ierr = MatSetType(*mass, dmCoarse->mattype);CHKERRQ(ierr);
8502     ierr = DMGetApplicationContext(dmFine, &ctx);CHKERRQ(ierr);
8503 
8504     ierr = DMGetCoarseDM(dmFine, &cdm);CHKERRQ(ierr);
8505     ierr = DMPlexGetRegularRefinement(dmFine, &regular);CHKERRQ(ierr);
8506     if (regular && cdm == dmCoarse) {ierr = DMPlexComputeMassMatrixNested(dmCoarse, dmFine, *mass, ctx);CHKERRQ(ierr);}
8507     else                            {ierr = DMPlexComputeMassMatrixGeneral(dmCoarse, dmFine, *mass, ctx);CHKERRQ(ierr);}
8508   }
8509   ierr = MatViewFromOptions(*mass, NULL, "-mass_mat_view");CHKERRQ(ierr);
8510   PetscFunctionReturn(0);
8511 }
8512 
8513 /*@
8514   DMPlexGetRegularRefinement - Get the flag indicating that this mesh was obtained by regular refinement from its coarse mesh
8515 
8516   Input Parameter:
8517 . dm - The DMPlex object
8518 
8519   Output Parameter:
8520 . regular - The flag
8521 
8522   Level: intermediate
8523 
8524 .seealso: DMPlexSetRegularRefinement()
8525 @*/
8526 PetscErrorCode DMPlexGetRegularRefinement(DM dm, PetscBool *regular)
8527 {
8528   PetscFunctionBegin;
8529   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8530   PetscValidPointer(regular, 2);
8531   *regular = ((DM_Plex *) dm->data)->regularRefinement;
8532   PetscFunctionReturn(0);
8533 }
8534 
8535 /*@
8536   DMPlexSetRegularRefinement - Set the flag indicating that this mesh was obtained by regular refinement from its coarse mesh
8537 
8538   Input Parameters:
8539 + dm - The DMPlex object
8540 - regular - The flag
8541 
8542   Level: intermediate
8543 
8544 .seealso: DMPlexGetRegularRefinement()
8545 @*/
8546 PetscErrorCode DMPlexSetRegularRefinement(DM dm, PetscBool regular)
8547 {
8548   PetscFunctionBegin;
8549   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8550   ((DM_Plex *) dm->data)->regularRefinement = regular;
8551   PetscFunctionReturn(0);
8552 }
8553 
8554 /*@
8555   DMPlexGetCellRefinerType - Get the strategy for refining a cell
8556 
8557   Input Parameter:
8558 . dm - The DMPlex object
8559 
8560   Output Parameter:
8561 . cr - The strategy number
8562 
8563   Level: intermediate
8564 
8565 .seealso: DMPlexSetCellRefinerType(), DMPlexSetRegularRefinement()
8566 @*/
8567 PetscErrorCode DMPlexGetCellRefinerType(DM dm, DMPlexCellRefinerType *cr)
8568 {
8569   PetscFunctionBegin;
8570   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8571   PetscValidPointer(cr, 2);
8572   *cr = ((DM_Plex *) dm->data)->cellRefiner;
8573   PetscFunctionReturn(0);
8574 }
8575 
8576 /*@
8577   DMPlexSetCellRefinerType - Set the strategy for refining a cell
8578 
8579   Input Parameters:
8580 + dm - The DMPlex object
8581 - cr - The strategy number
8582 
8583   Level: intermediate
8584 
8585 .seealso: DMPlexGetCellRefinerType(), DMPlexGetRegularRefinement()
8586 @*/
8587 PetscErrorCode DMPlexSetCellRefinerType(DM dm, DMPlexCellRefinerType cr)
8588 {
8589   PetscFunctionBegin;
8590   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8591   ((DM_Plex *) dm->data)->cellRefiner = cr;
8592   PetscFunctionReturn(0);
8593 }
8594 
8595 /* anchors */
8596 /*@
8597   DMPlexGetAnchors - Get the layout of the anchor (point-to-point) constraints.  Typically, the user will not have to
8598   call DMPlexGetAnchors() directly: if there are anchors, then DMPlexGetAnchors() is called during DMGetConstraints().
8599 
8600   not collective
8601 
8602   Input Parameters:
8603 . dm - The DMPlex object
8604 
8605   Output Parameters:
8606 + anchorSection - If not NULL, set to the section describing which points anchor the constrained points.
8607 - anchorIS - If not NULL, set to the list of anchors indexed by anchorSection
8608 
8609   Level: intermediate
8610 
8611 .seealso: DMPlexSetAnchors(), DMGetConstraints(), DMSetConstraints()
8612 @*/
8613 PetscErrorCode DMPlexGetAnchors(DM dm, PetscSection *anchorSection, IS *anchorIS)
8614 {
8615   DM_Plex *plex = (DM_Plex *)dm->data;
8616   PetscErrorCode ierr;
8617 
8618   PetscFunctionBegin;
8619   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8620   if (!plex->anchorSection && !plex->anchorIS && plex->createanchors) {ierr = (*plex->createanchors)(dm);CHKERRQ(ierr);}
8621   if (anchorSection) *anchorSection = plex->anchorSection;
8622   if (anchorIS) *anchorIS = plex->anchorIS;
8623   PetscFunctionReturn(0);
8624 }
8625 
8626 /*@
8627   DMPlexSetAnchors - Set the layout of the local anchor (point-to-point) constraints.  Unlike boundary conditions,
8628   when a point's degrees of freedom in a section are constrained to an outside value, the anchor constraints set a
8629   point's degrees of freedom to be a linear combination of other points' degrees of freedom.
8630 
8631   After specifying the layout of constraints with DMPlexSetAnchors(), one specifies the constraints by calling
8632   DMGetConstraints() and filling in the entries in the constraint matrix.
8633 
8634   collective on dm
8635 
8636   Input Parameters:
8637 + dm - The DMPlex object
8638 . 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).
8639 - anchorIS - The list of all anchor points.  Must have a local communicator (PETSC_COMM_SELF or derivative).
8640 
8641   The reference counts of anchorSection and anchorIS are incremented.
8642 
8643   Level: intermediate
8644 
8645 .seealso: DMPlexGetAnchors(), DMGetConstraints(), DMSetConstraints()
8646 @*/
8647 PetscErrorCode DMPlexSetAnchors(DM dm, PetscSection anchorSection, IS anchorIS)
8648 {
8649   DM_Plex        *plex = (DM_Plex *)dm->data;
8650   PetscMPIInt    result;
8651   PetscErrorCode ierr;
8652 
8653   PetscFunctionBegin;
8654   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8655   if (anchorSection) {
8656     PetscValidHeaderSpecific(anchorSection,PETSC_SECTION_CLASSID,2);
8657     ierr = MPI_Comm_compare(PETSC_COMM_SELF,PetscObjectComm((PetscObject)anchorSection),&result);CHKERRMPI(ierr);
8658     if (result != MPI_CONGRUENT && result != MPI_IDENT) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_NOTSAMECOMM,"anchor section must have local communicator");
8659   }
8660   if (anchorIS) {
8661     PetscValidHeaderSpecific(anchorIS,IS_CLASSID,3);
8662     ierr = MPI_Comm_compare(PETSC_COMM_SELF,PetscObjectComm((PetscObject)anchorIS),&result);CHKERRMPI(ierr);
8663     if (result != MPI_CONGRUENT && result != MPI_IDENT) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_NOTSAMECOMM,"anchor IS must have local communicator");
8664   }
8665 
8666   ierr = PetscObjectReference((PetscObject)anchorSection);CHKERRQ(ierr);
8667   ierr = PetscSectionDestroy(&plex->anchorSection);CHKERRQ(ierr);
8668   plex->anchorSection = anchorSection;
8669 
8670   ierr = PetscObjectReference((PetscObject)anchorIS);CHKERRQ(ierr);
8671   ierr = ISDestroy(&plex->anchorIS);CHKERRQ(ierr);
8672   plex->anchorIS = anchorIS;
8673 
8674   if (PetscUnlikelyDebug(anchorIS && anchorSection)) {
8675     PetscInt size, a, pStart, pEnd;
8676     const PetscInt *anchors;
8677 
8678     ierr = PetscSectionGetChart(anchorSection,&pStart,&pEnd);CHKERRQ(ierr);
8679     ierr = ISGetLocalSize(anchorIS,&size);CHKERRQ(ierr);
8680     ierr = ISGetIndices(anchorIS,&anchors);CHKERRQ(ierr);
8681     for (a = 0; a < size; a++) {
8682       PetscInt p;
8683 
8684       p = anchors[a];
8685       if (p >= pStart && p < pEnd) {
8686         PetscInt dof;
8687 
8688         ierr = PetscSectionGetDof(anchorSection,p,&dof);CHKERRQ(ierr);
8689         if (dof) {
8690           PetscErrorCode ierr2;
8691 
8692           ierr2 = ISRestoreIndices(anchorIS,&anchors);CHKERRQ(ierr2);
8693           SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Point %D cannot be constrained and an anchor",p);
8694         }
8695       }
8696     }
8697     ierr = ISRestoreIndices(anchorIS,&anchors);CHKERRQ(ierr);
8698   }
8699   /* reset the generic constraints */
8700   ierr = DMSetDefaultConstraints(dm,NULL,NULL);CHKERRQ(ierr);
8701   PetscFunctionReturn(0);
8702 }
8703 
8704 static PetscErrorCode DMPlexCreateConstraintSection_Anchors(DM dm, PetscSection section, PetscSection *cSec)
8705 {
8706   PetscSection anchorSection;
8707   PetscInt pStart, pEnd, sStart, sEnd, p, dof, numFields, f;
8708   PetscErrorCode ierr;
8709 
8710   PetscFunctionBegin;
8711   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8712   ierr = DMPlexGetAnchors(dm,&anchorSection,NULL);CHKERRQ(ierr);
8713   ierr = PetscSectionCreate(PETSC_COMM_SELF,cSec);CHKERRQ(ierr);
8714   ierr = PetscSectionGetNumFields(section,&numFields);CHKERRQ(ierr);
8715   if (numFields) {
8716     PetscInt f;
8717     ierr = PetscSectionSetNumFields(*cSec,numFields);CHKERRQ(ierr);
8718 
8719     for (f = 0; f < numFields; f++) {
8720       PetscInt numComp;
8721 
8722       ierr = PetscSectionGetFieldComponents(section,f,&numComp);CHKERRQ(ierr);
8723       ierr = PetscSectionSetFieldComponents(*cSec,f,numComp);CHKERRQ(ierr);
8724     }
8725   }
8726   ierr = PetscSectionGetChart(anchorSection,&pStart,&pEnd);CHKERRQ(ierr);
8727   ierr = PetscSectionGetChart(section,&sStart,&sEnd);CHKERRQ(ierr);
8728   pStart = PetscMax(pStart,sStart);
8729   pEnd   = PetscMin(pEnd,sEnd);
8730   pEnd   = PetscMax(pStart,pEnd);
8731   ierr = PetscSectionSetChart(*cSec,pStart,pEnd);CHKERRQ(ierr);
8732   for (p = pStart; p < pEnd; p++) {
8733     ierr = PetscSectionGetDof(anchorSection,p,&dof);CHKERRQ(ierr);
8734     if (dof) {
8735       ierr = PetscSectionGetDof(section,p,&dof);CHKERRQ(ierr);
8736       ierr = PetscSectionSetDof(*cSec,p,dof);CHKERRQ(ierr);
8737       for (f = 0; f < numFields; f++) {
8738         ierr = PetscSectionGetFieldDof(section,p,f,&dof);CHKERRQ(ierr);
8739         ierr = PetscSectionSetFieldDof(*cSec,p,f,dof);CHKERRQ(ierr);
8740       }
8741     }
8742   }
8743   ierr = PetscSectionSetUp(*cSec);CHKERRQ(ierr);
8744   ierr = PetscObjectSetName((PetscObject) *cSec, "Constraint Section");CHKERRQ(ierr);
8745   PetscFunctionReturn(0);
8746 }
8747 
8748 static PetscErrorCode DMPlexCreateConstraintMatrix_Anchors(DM dm, PetscSection section, PetscSection cSec, Mat *cMat)
8749 {
8750   PetscSection   aSec;
8751   PetscInt       pStart, pEnd, p, sStart, sEnd, dof, aDof, aOff, off, nnz, annz, m, n, q, a, offset, *i, *j;
8752   const PetscInt *anchors;
8753   PetscInt       numFields, f;
8754   IS             aIS;
8755   PetscErrorCode ierr;
8756   MatType        mtype;
8757   PetscBool      iscuda,iskokkos;
8758 
8759   PetscFunctionBegin;
8760   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8761   ierr = PetscSectionGetStorageSize(cSec, &m);CHKERRQ(ierr);
8762   ierr = PetscSectionGetStorageSize(section, &n);CHKERRQ(ierr);
8763   ierr = MatCreate(PETSC_COMM_SELF,cMat);CHKERRQ(ierr);
8764   ierr = MatSetSizes(*cMat,m,n,m,n);CHKERRQ(ierr);
8765   ierr = PetscStrcmp(dm->mattype,MATSEQAIJCUSPARSE,&iscuda);CHKERRQ(ierr);
8766   if (!iscuda) { ierr = PetscStrcmp(dm->mattype,MATMPIAIJCUSPARSE,&iscuda);CHKERRQ(ierr); }
8767   ierr = PetscStrcmp(dm->mattype,MATSEQAIJKOKKOS,&iskokkos);CHKERRQ(ierr);
8768   if (!iskokkos) { ierr = PetscStrcmp(dm->mattype,MATMPIAIJKOKKOS,&iskokkos);CHKERRQ(ierr); }
8769   if (iscuda) mtype = MATSEQAIJCUSPARSE;
8770   else if (iskokkos) mtype = MATSEQAIJKOKKOS;
8771   else mtype = MATSEQAIJ;
8772   ierr = MatSetType(*cMat,mtype);CHKERRQ(ierr);
8773   ierr = DMPlexGetAnchors(dm,&aSec,&aIS);CHKERRQ(ierr);
8774   ierr = ISGetIndices(aIS,&anchors);CHKERRQ(ierr);
8775   /* cSec will be a subset of aSec and section */
8776   ierr = PetscSectionGetChart(cSec,&pStart,&pEnd);CHKERRQ(ierr);
8777   ierr = PetscSectionGetChart(section,&sStart,&sEnd);CHKERRQ(ierr);
8778   ierr = PetscMalloc1(m+1,&i);CHKERRQ(ierr);
8779   i[0] = 0;
8780   ierr = PetscSectionGetNumFields(section,&numFields);CHKERRQ(ierr);
8781   for (p = pStart; p < pEnd; p++) {
8782     PetscInt rDof, rOff, r;
8783 
8784     ierr = PetscSectionGetDof(aSec,p,&rDof);CHKERRQ(ierr);
8785     if (!rDof) continue;
8786     ierr = PetscSectionGetOffset(aSec,p,&rOff);CHKERRQ(ierr);
8787     if (numFields) {
8788       for (f = 0; f < numFields; f++) {
8789         annz = 0;
8790         for (r = 0; r < rDof; r++) {
8791           a = anchors[rOff + r];
8792           if (a < sStart || a >= sEnd) continue;
8793           ierr = PetscSectionGetFieldDof(section,a,f,&aDof);CHKERRQ(ierr);
8794           annz += aDof;
8795         }
8796         ierr = PetscSectionGetFieldDof(cSec,p,f,&dof);CHKERRQ(ierr);
8797         ierr = PetscSectionGetFieldOffset(cSec,p,f,&off);CHKERRQ(ierr);
8798         for (q = 0; q < dof; q++) {
8799           i[off + q + 1] = i[off + q] + annz;
8800         }
8801       }
8802     }
8803     else {
8804       annz = 0;
8805       ierr = PetscSectionGetDof(cSec,p,&dof);CHKERRQ(ierr);
8806       for (q = 0; q < dof; q++) {
8807         a = anchors[rOff + q];
8808         if (a < sStart || a >= sEnd) continue;
8809         ierr = PetscSectionGetDof(section,a,&aDof);CHKERRQ(ierr);
8810         annz += aDof;
8811       }
8812       ierr = PetscSectionGetDof(cSec,p,&dof);CHKERRQ(ierr);
8813       ierr = PetscSectionGetOffset(cSec,p,&off);CHKERRQ(ierr);
8814       for (q = 0; q < dof; q++) {
8815         i[off + q + 1] = i[off + q] + annz;
8816       }
8817     }
8818   }
8819   nnz = i[m];
8820   ierr = PetscMalloc1(nnz,&j);CHKERRQ(ierr);
8821   offset = 0;
8822   for (p = pStart; p < pEnd; p++) {
8823     if (numFields) {
8824       for (f = 0; f < numFields; f++) {
8825         ierr = PetscSectionGetFieldDof(cSec,p,f,&dof);CHKERRQ(ierr);
8826         for (q = 0; q < dof; q++) {
8827           PetscInt rDof, rOff, r;
8828           ierr = PetscSectionGetDof(aSec,p,&rDof);CHKERRQ(ierr);
8829           ierr = PetscSectionGetOffset(aSec,p,&rOff);CHKERRQ(ierr);
8830           for (r = 0; r < rDof; r++) {
8831             PetscInt s;
8832 
8833             a = anchors[rOff + r];
8834             if (a < sStart || a >= sEnd) continue;
8835             ierr = PetscSectionGetFieldDof(section,a,f,&aDof);CHKERRQ(ierr);
8836             ierr = PetscSectionGetFieldOffset(section,a,f,&aOff);CHKERRQ(ierr);
8837             for (s = 0; s < aDof; s++) {
8838               j[offset++] = aOff + s;
8839             }
8840           }
8841         }
8842       }
8843     }
8844     else {
8845       ierr = PetscSectionGetDof(cSec,p,&dof);CHKERRQ(ierr);
8846       for (q = 0; q < dof; q++) {
8847         PetscInt rDof, rOff, r;
8848         ierr = PetscSectionGetDof(aSec,p,&rDof);CHKERRQ(ierr);
8849         ierr = PetscSectionGetOffset(aSec,p,&rOff);CHKERRQ(ierr);
8850         for (r = 0; r < rDof; r++) {
8851           PetscInt s;
8852 
8853           a = anchors[rOff + r];
8854           if (a < sStart || a >= sEnd) continue;
8855           ierr = PetscSectionGetDof(section,a,&aDof);CHKERRQ(ierr);
8856           ierr = PetscSectionGetOffset(section,a,&aOff);CHKERRQ(ierr);
8857           for (s = 0; s < aDof; s++) {
8858             j[offset++] = aOff + s;
8859           }
8860         }
8861       }
8862     }
8863   }
8864   ierr = MatSeqAIJSetPreallocationCSR(*cMat,i,j,NULL);CHKERRQ(ierr);
8865   ierr = PetscFree(i);CHKERRQ(ierr);
8866   ierr = PetscFree(j);CHKERRQ(ierr);
8867   ierr = ISRestoreIndices(aIS,&anchors);CHKERRQ(ierr);
8868   PetscFunctionReturn(0);
8869 }
8870 
8871 PetscErrorCode DMCreateDefaultConstraints_Plex(DM dm)
8872 {
8873   DM_Plex        *plex = (DM_Plex *)dm->data;
8874   PetscSection   anchorSection, section, cSec;
8875   Mat            cMat;
8876   PetscErrorCode ierr;
8877 
8878   PetscFunctionBegin;
8879   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8880   ierr = DMPlexGetAnchors(dm,&anchorSection,NULL);CHKERRQ(ierr);
8881   if (anchorSection) {
8882     PetscInt Nf;
8883 
8884     ierr = DMGetLocalSection(dm,&section);CHKERRQ(ierr);
8885     ierr = DMPlexCreateConstraintSection_Anchors(dm,section,&cSec);CHKERRQ(ierr);
8886     ierr = DMPlexCreateConstraintMatrix_Anchors(dm,section,cSec,&cMat);CHKERRQ(ierr);
8887     ierr = DMGetNumFields(dm,&Nf);CHKERRQ(ierr);
8888     if (Nf && plex->computeanchormatrix) {ierr = (*plex->computeanchormatrix)(dm,section,cSec,cMat);CHKERRQ(ierr);}
8889     ierr = DMSetDefaultConstraints(dm,cSec,cMat);CHKERRQ(ierr);
8890     ierr = PetscSectionDestroy(&cSec);CHKERRQ(ierr);
8891     ierr = MatDestroy(&cMat);CHKERRQ(ierr);
8892   }
8893   PetscFunctionReturn(0);
8894 }
8895 
8896 PetscErrorCode DMCreateSubDomainDM_Plex(DM dm, DMLabel label, PetscInt value, IS *is, DM *subdm)
8897 {
8898   IS             subis;
8899   PetscSection   section, subsection;
8900   PetscErrorCode ierr;
8901 
8902   PetscFunctionBegin;
8903   ierr = DMGetLocalSection(dm, &section);CHKERRQ(ierr);
8904   if (!section) SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "Must set default section for DM before splitting subdomain");
8905   if (!subdm)   SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "Must set output subDM for splitting subdomain");
8906   /* Create subdomain */
8907   ierr = DMPlexFilter(dm, label, value, subdm);CHKERRQ(ierr);
8908   /* Create submodel */
8909   ierr = DMPlexGetSubpointIS(*subdm, &subis);CHKERRQ(ierr);
8910   ierr = PetscSectionCreateSubmeshSection(section, subis, &subsection);CHKERRQ(ierr);
8911   ierr = DMSetLocalSection(*subdm, subsection);CHKERRQ(ierr);
8912   ierr = PetscSectionDestroy(&subsection);CHKERRQ(ierr);
8913   ierr = DMCopyDisc(dm, *subdm);CHKERRQ(ierr);
8914   /* Create map from submodel to global model */
8915   if (is) {
8916     PetscSection    sectionGlobal, subsectionGlobal;
8917     IS              spIS;
8918     const PetscInt *spmap;
8919     PetscInt       *subIndices;
8920     PetscInt        subSize = 0, subOff = 0, pStart, pEnd, p;
8921     PetscInt        Nf, f, bs = -1, bsLocal[2], bsMinMax[2];
8922 
8923     ierr = DMPlexGetSubpointIS(*subdm, &spIS);CHKERRQ(ierr);
8924     ierr = ISGetIndices(spIS, &spmap);CHKERRQ(ierr);
8925     ierr = PetscSectionGetNumFields(section, &Nf);CHKERRQ(ierr);
8926     ierr = DMGetGlobalSection(dm, &sectionGlobal);CHKERRQ(ierr);
8927     ierr = DMGetGlobalSection(*subdm, &subsectionGlobal);CHKERRQ(ierr);
8928     ierr = PetscSectionGetChart(subsection, &pStart, &pEnd);CHKERRQ(ierr);
8929     for (p = pStart; p < pEnd; ++p) {
8930       PetscInt gdof, pSubSize  = 0;
8931 
8932       ierr = PetscSectionGetDof(sectionGlobal, p, &gdof);CHKERRQ(ierr);
8933       if (gdof > 0) {
8934         for (f = 0; f < Nf; ++f) {
8935           PetscInt fdof, fcdof;
8936 
8937           ierr     = PetscSectionGetFieldDof(subsection, p, f, &fdof);CHKERRQ(ierr);
8938           ierr     = PetscSectionGetFieldConstraintDof(subsection, p, f, &fcdof);CHKERRQ(ierr);
8939           pSubSize += fdof-fcdof;
8940         }
8941         subSize += pSubSize;
8942         if (pSubSize) {
8943           if (bs < 0) {
8944             bs = pSubSize;
8945           } else if (bs != pSubSize) {
8946             /* Layout does not admit a pointwise block size */
8947             bs = 1;
8948           }
8949         }
8950       }
8951     }
8952     /* Must have same blocksize on all procs (some might have no points) */
8953     bsLocal[0] = bs < 0 ? PETSC_MAX_INT : bs; bsLocal[1] = bs;
8954     ierr = PetscGlobalMinMaxInt(PetscObjectComm((PetscObject) dm), bsLocal, bsMinMax);CHKERRQ(ierr);
8955     if (bsMinMax[0] != bsMinMax[1]) {bs = 1;}
8956     else                            {bs = bsMinMax[0];}
8957     ierr = PetscMalloc1(subSize, &subIndices);CHKERRQ(ierr);
8958     for (p = pStart; p < pEnd; ++p) {
8959       PetscInt gdof, goff;
8960 
8961       ierr = PetscSectionGetDof(subsectionGlobal, p, &gdof);CHKERRQ(ierr);
8962       if (gdof > 0) {
8963         const PetscInt point = spmap[p];
8964 
8965         ierr = PetscSectionGetOffset(sectionGlobal, point, &goff);CHKERRQ(ierr);
8966         for (f = 0; f < Nf; ++f) {
8967           PetscInt fdof, fcdof, fc, f2, poff = 0;
8968 
8969           /* Can get rid of this loop by storing field information in the global section */
8970           for (f2 = 0; f2 < f; ++f2) {
8971             ierr  = PetscSectionGetFieldDof(section, p, f2, &fdof);CHKERRQ(ierr);
8972             ierr  = PetscSectionGetFieldConstraintDof(section, p, f2, &fcdof);CHKERRQ(ierr);
8973             poff += fdof-fcdof;
8974           }
8975           ierr = PetscSectionGetFieldDof(section, p, f, &fdof);CHKERRQ(ierr);
8976           ierr = PetscSectionGetFieldConstraintDof(section, p, f, &fcdof);CHKERRQ(ierr);
8977           for (fc = 0; fc < fdof-fcdof; ++fc, ++subOff) {
8978             subIndices[subOff] = goff+poff+fc;
8979           }
8980         }
8981       }
8982     }
8983     ierr = ISRestoreIndices(spIS, &spmap);CHKERRQ(ierr);
8984     ierr = ISCreateGeneral(PetscObjectComm((PetscObject)dm), subSize, subIndices, PETSC_OWN_POINTER, is);CHKERRQ(ierr);
8985     if (bs > 1) {
8986       /* We need to check that the block size does not come from non-contiguous fields */
8987       PetscInt i, j, set = 1;
8988       for (i = 0; i < subSize; i += bs) {
8989         for (j = 0; j < bs; ++j) {
8990           if (subIndices[i+j] != subIndices[i]+j) {set = 0; break;}
8991         }
8992       }
8993       if (set) {ierr = ISSetBlockSize(*is, bs);CHKERRQ(ierr);}
8994     }
8995     /* Attach nullspace */
8996     for (f = 0; f < Nf; ++f) {
8997       (*subdm)->nullspaceConstructors[f] = dm->nullspaceConstructors[f];
8998       if ((*subdm)->nullspaceConstructors[f]) break;
8999     }
9000     if (f < Nf) {
9001       MatNullSpace nullSpace;
9002       ierr = (*(*subdm)->nullspaceConstructors[f])(*subdm, f, f, &nullSpace);CHKERRQ(ierr);
9003 
9004       ierr = PetscObjectCompose((PetscObject) *is, "nullspace", (PetscObject) nullSpace);CHKERRQ(ierr);
9005       ierr = MatNullSpaceDestroy(&nullSpace);CHKERRQ(ierr);
9006     }
9007   }
9008   PetscFunctionReturn(0);
9009 }
9010 
9011 /*@
9012   DMPlexMonitorThroughput - Report the cell throughput of FE integration
9013 
9014   Input Parameter:
9015 - dm - The DM
9016 
9017   Level: developer
9018 
9019   Options Database Keys:
9020 . -dm_plex_monitor_throughput - Activate the monitor
9021 
9022 .seealso: DMSetFromOptions(), DMPlexCreate()
9023 @*/
9024 PetscErrorCode DMPlexMonitorThroughput(DM dm, void *dummy)
9025 {
9026 #if defined(PETSC_USE_LOG)
9027   PetscStageLog      stageLog;
9028   PetscLogEvent      event;
9029   PetscLogStage      stage;
9030   PetscEventPerfInfo eventInfo;
9031   PetscReal          cellRate, flopRate;
9032   PetscInt           cStart, cEnd, Nf, N;
9033   const char        *name;
9034   PetscErrorCode     ierr;
9035 #endif
9036 
9037   PetscFunctionBegin;
9038   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9039 #if defined(PETSC_USE_LOG)
9040   ierr = PetscObjectGetName((PetscObject) dm, &name);CHKERRQ(ierr);
9041   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
9042   ierr = DMGetNumFields(dm, &Nf);CHKERRQ(ierr);
9043   ierr = PetscLogGetStageLog(&stageLog);CHKERRQ(ierr);
9044   ierr = PetscStageLogGetCurrent(stageLog, &stage);CHKERRQ(ierr);
9045   ierr = PetscLogEventGetId("DMPlexResidualFE", &event);CHKERRQ(ierr);
9046   ierr = PetscLogEventGetPerfInfo(stage, event, &eventInfo);CHKERRQ(ierr);
9047   N        = (cEnd - cStart)*Nf*eventInfo.count;
9048   flopRate = eventInfo.flops/eventInfo.time;
9049   cellRate = N/eventInfo.time;
9050   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);
9051 #else
9052   SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Plex Throughput Monitor is not supported if logging is turned off. Reconfigure using --with-log.");
9053 #endif
9054   PetscFunctionReturn(0);
9055 }
9056