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