xref: /petsc/src/dm/impls/plex/plex.c (revision 817da375e672db5c7e13659b00b476f4f84762da)
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 #include <petscdmplextransform.h>
10 
11 /* Logging support */
12 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,DMPLEX_TopologyView,DMPLEX_LabelsView,DMPLEX_CoordinatesView,DMPLEX_SectionView,DMPLEX_GlobalVectorView,DMPLEX_LocalVectorView,DMPLEX_TopologyLoad,DMPLEX_LabelsLoad,DMPLEX_CoordinatesLoad,DMPLEX_SectionLoad,DMPLEX_GlobalVectorLoad,DMPLEX_LocalVectorLoad;
13 
14 PETSC_EXTERN PetscErrorCode VecView_MPI(Vec, PetscViewer);
15 
16 /*@
17   DMPlexIsSimplex - Is the first cell in this mesh a simplex?
18 
19   Input Parameter:
20 . dm      - The DMPlex object
21 
22   Output Parameter:
23 . simplex - Flag checking for a simplex
24 
25   Note: This just gives the first range of cells found. If the mesh has several cell types, it will only give the first.
26   If the mesh has no cells, this returns PETSC_FALSE.
27 
28   Level: intermediate
29 
30 .seealso DMPlexGetSimplexOrBoxCells(), DMPlexGetCellType(), DMPlexGetHeightStratum(), DMPolytopeTypeGetNumVertices()
31 @*/
32 PetscErrorCode DMPlexIsSimplex(DM dm, PetscBool *simplex)
33 {
34   DMPolytopeType ct;
35   PetscInt       cStart, cEnd;
36   PetscErrorCode ierr;
37 
38   PetscFunctionBegin;
39   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
40   if (cEnd <= cStart) {*simplex = PETSC_FALSE; PetscFunctionReturn(0);}
41   ierr = DMPlexGetCellType(dm, cStart, &ct);CHKERRQ(ierr);
42   *simplex = DMPolytopeTypeGetNumVertices(ct) == DMPolytopeTypeGetDim(ct)+1 ? PETSC_TRUE : PETSC_FALSE;
43   PetscFunctionReturn(0);
44 }
45 
46 /*@
47   DMPlexGetSimplexOrBoxCells - Get the range of cells which are neither prisms nor ghost FV cells
48 
49   Input Parameters:
50 + dm     - The DMPlex object
51 - height - The cell height in the Plex, 0 is the default
52 
53   Output Parameters:
54 + cStart - The first "normal" cell
55 - cEnd   - The upper bound on "normal"" cells
56 
57   Note: This just gives the first range of cells found. If the mesh has several cell types, it will only give the first.
58 
59   Level: developer
60 
61 .seealso DMPlexConstructGhostCells(), DMPlexGetGhostCellStratum()
62 @*/
63 PetscErrorCode DMPlexGetSimplexOrBoxCells(DM dm, PetscInt height, PetscInt *cStart, PetscInt *cEnd)
64 {
65   DMPolytopeType ct = DM_POLYTOPE_UNKNOWN;
66   PetscInt       cS, cE, c;
67   PetscErrorCode ierr;
68 
69   PetscFunctionBegin;
70   ierr = DMPlexGetHeightStratum(dm, PetscMax(height, 0), &cS, &cE);CHKERRQ(ierr);
71   for (c = cS; c < cE; ++c) {
72     DMPolytopeType cct;
73 
74     ierr = DMPlexGetCellType(dm, c, &cct);CHKERRQ(ierr);
75     if ((PetscInt) cct < 0) break;
76     switch (cct) {
77       case DM_POLYTOPE_POINT:
78       case DM_POLYTOPE_SEGMENT:
79       case DM_POLYTOPE_TRIANGLE:
80       case DM_POLYTOPE_QUADRILATERAL:
81       case DM_POLYTOPE_TETRAHEDRON:
82       case DM_POLYTOPE_HEXAHEDRON:
83         ct = cct;
84         break;
85       default: break;
86     }
87     if (ct != DM_POLYTOPE_UNKNOWN) break;
88   }
89   if (ct != DM_POLYTOPE_UNKNOWN) {
90     DMLabel ctLabel;
91 
92     ierr = DMPlexGetCellTypeLabel(dm, &ctLabel);CHKERRQ(ierr);
93     ierr = DMLabelGetStratumBounds(ctLabel, ct, &cS, &cE);CHKERRQ(ierr);
94   }
95   if (cStart) *cStart = cS;
96   if (cEnd)   *cEnd   = cE;
97   PetscFunctionReturn(0);
98 }
99 
100 PetscErrorCode DMPlexGetFieldType_Internal(DM dm, PetscSection section, PetscInt field, PetscInt *sStart, PetscInt *sEnd, PetscViewerVTKFieldType *ft)
101 {
102   PetscInt       cdim, pStart, pEnd, vStart, vEnd, cStart, cEnd;
103   PetscInt       vcdof[2] = {0,0}, globalvcdof[2];
104   PetscErrorCode ierr;
105 
106   PetscFunctionBegin;
107   *ft  = PETSC_VTK_INVALID;
108   ierr = DMGetCoordinateDim(dm, &cdim);CHKERRQ(ierr);
109   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
110   ierr = DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
111   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
112   if (field >= 0) {
113     if ((vStart >= pStart) && (vStart < pEnd)) {ierr = PetscSectionGetFieldDof(section, vStart, field, &vcdof[0]);CHKERRQ(ierr);}
114     if ((cStart >= pStart) && (cStart < pEnd)) {ierr = PetscSectionGetFieldDof(section, cStart, field, &vcdof[1]);CHKERRQ(ierr);}
115   } else {
116     if ((vStart >= pStart) && (vStart < pEnd)) {ierr = PetscSectionGetDof(section, vStart, &vcdof[0]);CHKERRQ(ierr);}
117     if ((cStart >= pStart) && (cStart < pEnd)) {ierr = PetscSectionGetDof(section, cStart, &vcdof[1]);CHKERRQ(ierr);}
118   }
119   ierr = MPI_Allreduce(vcdof, globalvcdof, 2, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm));CHKERRMPI(ierr);
120   if (globalvcdof[0]) {
121     *sStart = vStart;
122     *sEnd   = vEnd;
123     if (globalvcdof[0] == cdim) *ft = PETSC_VTK_POINT_VECTOR_FIELD;
124     else                        *ft = PETSC_VTK_POINT_FIELD;
125   } else if (globalvcdof[1]) {
126     *sStart = cStart;
127     *sEnd   = cEnd;
128     if (globalvcdof[1] == cdim) *ft = PETSC_VTK_CELL_VECTOR_FIELD;
129     else                        *ft = PETSC_VTK_CELL_FIELD;
130   } else {
131     if (field >= 0) {
132       const char *fieldname;
133 
134       ierr = PetscSectionGetFieldName(section, field, &fieldname);CHKERRQ(ierr);
135       ierr = PetscInfo((PetscObject) dm, "Could not classify VTK output type of section field %D \"%s\"\n", field, fieldname);CHKERRQ(ierr);
136     } else {
137       ierr = PetscInfo((PetscObject) dm, "Could not classify VTK output type of section\"%s\"\n");CHKERRQ(ierr);
138     }
139   }
140   PetscFunctionReturn(0);
141 }
142 
143 static PetscErrorCode VecView_Plex_Local_Draw(Vec v, PetscViewer viewer)
144 {
145   DM                 dm;
146   PetscSection       s;
147   PetscDraw          draw, popup;
148   DM                 cdm;
149   PetscSection       coordSection;
150   Vec                coordinates;
151   const PetscScalar *coords, *array;
152   PetscReal          bound[4] = {PETSC_MAX_REAL, PETSC_MAX_REAL, PETSC_MIN_REAL, PETSC_MIN_REAL};
153   PetscReal          vbound[2], time;
154   PetscBool          isnull, flg;
155   PetscInt           dim, Nf, f, Nc, comp, vStart, vEnd, cStart, cEnd, c, N, level, step, w = 0;
156   const char        *name;
157   char               title[PETSC_MAX_PATH_LEN];
158   PetscErrorCode     ierr;
159 
160   PetscFunctionBegin;
161   ierr = PetscViewerDrawGetDraw(viewer, 0, &draw);CHKERRQ(ierr);
162   ierr = PetscDrawIsNull(draw, &isnull);CHKERRQ(ierr);
163   if (isnull) PetscFunctionReturn(0);
164 
165   ierr = VecGetDM(v, &dm);CHKERRQ(ierr);
166   ierr = DMGetCoordinateDim(dm, &dim);CHKERRQ(ierr);
167   PetscCheckFalse(dim != 2,PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Cannot draw meshes of dimension %D. Use PETSCVIEWERGLVIS", dim);
168   ierr = DMGetLocalSection(dm, &s);CHKERRQ(ierr);
169   ierr = PetscSectionGetNumFields(s, &Nf);CHKERRQ(ierr);
170   ierr = DMGetCoarsenLevel(dm, &level);CHKERRQ(ierr);
171   ierr = DMGetCoordinateDM(dm, &cdm);CHKERRQ(ierr);
172   ierr = DMGetLocalSection(cdm, &coordSection);CHKERRQ(ierr);
173   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
174   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
175   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
176 
177   ierr = PetscObjectGetName((PetscObject) v, &name);CHKERRQ(ierr);
178   ierr = DMGetOutputSequenceNumber(dm, &step, &time);CHKERRQ(ierr);
179 
180   ierr = VecGetLocalSize(coordinates, &N);CHKERRQ(ierr);
181   ierr = VecGetArrayRead(coordinates, &coords);CHKERRQ(ierr);
182   for (c = 0; c < N; c += dim) {
183     bound[0] = PetscMin(bound[0], PetscRealPart(coords[c]));   bound[2] = PetscMax(bound[2], PetscRealPart(coords[c]));
184     bound[1] = PetscMin(bound[1], PetscRealPart(coords[c+1])); bound[3] = PetscMax(bound[3], PetscRealPart(coords[c+1]));
185   }
186   ierr = VecRestoreArrayRead(coordinates, &coords);CHKERRQ(ierr);
187   ierr = PetscDrawClear(draw);CHKERRQ(ierr);
188 
189   /* Could implement something like DMDASelectFields() */
190   for (f = 0; f < Nf; ++f) {
191     DM   fdm = dm;
192     Vec  fv  = v;
193     IS   fis;
194     char prefix[PETSC_MAX_PATH_LEN];
195     const char *fname;
196 
197     ierr = PetscSectionGetFieldComponents(s, f, &Nc);CHKERRQ(ierr);
198     ierr = PetscSectionGetFieldName(s, f, &fname);CHKERRQ(ierr);
199 
200     if (v->hdr.prefix) {ierr = PetscStrncpy(prefix, v->hdr.prefix,sizeof(prefix));CHKERRQ(ierr);}
201     else               {prefix[0] = '\0';}
202     if (Nf > 1) {
203       ierr = DMCreateSubDM(dm, 1, &f, &fis, &fdm);CHKERRQ(ierr);
204       ierr = VecGetSubVector(v, fis, &fv);CHKERRQ(ierr);
205       ierr = PetscStrlcat(prefix, fname,sizeof(prefix));CHKERRQ(ierr);
206       ierr = PetscStrlcat(prefix, "_",sizeof(prefix));CHKERRQ(ierr);
207     }
208     for (comp = 0; comp < Nc; ++comp, ++w) {
209       PetscInt nmax = 2;
210 
211       ierr = PetscViewerDrawGetDraw(viewer, w, &draw);CHKERRQ(ierr);
212       if (Nc > 1) {ierr = PetscSNPrintf(title, sizeof(title), "%s:%s_%D Step: %D Time: %.4g", name, fname, comp, step, time);CHKERRQ(ierr);}
213       else        {ierr = PetscSNPrintf(title, sizeof(title), "%s:%s Step: %D Time: %.4g", name, fname, step, time);CHKERRQ(ierr);}
214       ierr = PetscDrawSetTitle(draw, title);CHKERRQ(ierr);
215 
216       /* TODO Get max and min only for this component */
217       ierr = PetscOptionsGetRealArray(NULL, prefix, "-vec_view_bounds", vbound, &nmax, &flg);CHKERRQ(ierr);
218       if (!flg) {
219         ierr = VecMin(fv, NULL, &vbound[0]);CHKERRQ(ierr);
220         ierr = VecMax(fv, NULL, &vbound[1]);CHKERRQ(ierr);
221         if (vbound[1] <= vbound[0]) vbound[1] = vbound[0] + 1.0;
222       }
223       ierr = PetscDrawGetPopup(draw, &popup);CHKERRQ(ierr);
224       ierr = PetscDrawScalePopup(popup, vbound[0], vbound[1]);CHKERRQ(ierr);
225       ierr = PetscDrawSetCoordinates(draw, bound[0], bound[1], bound[2], bound[3]);CHKERRQ(ierr);
226 
227       ierr = VecGetArrayRead(fv, &array);CHKERRQ(ierr);
228       for (c = cStart; c < cEnd; ++c) {
229         PetscScalar *coords = NULL, *a = NULL;
230         PetscInt     numCoords, color[4] = {-1,-1,-1,-1};
231 
232         ierr = DMPlexPointLocalRead(fdm, c, array, &a);CHKERRQ(ierr);
233         if (a) {
234           color[0] = PetscDrawRealToColor(PetscRealPart(a[comp]), vbound[0], vbound[1]);
235           color[1] = color[2] = color[3] = color[0];
236         } else {
237           PetscScalar *vals = NULL;
238           PetscInt     numVals, va;
239 
240           ierr = DMPlexVecGetClosure(fdm, NULL, fv, c, &numVals, &vals);CHKERRQ(ierr);
241           PetscCheckFalse(numVals % Nc,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);
242           switch (numVals/Nc) {
243           case 3: /* P1 Triangle */
244           case 4: /* P1 Quadrangle */
245             for (va = 0; va < numVals/Nc; ++va) color[va] = PetscDrawRealToColor(PetscRealPart(vals[va*Nc+comp]), vbound[0], vbound[1]);
246             break;
247           case 6: /* P2 Triangle */
248           case 8: /* P2 Quadrangle */
249             for (va = 0; va < numVals/(Nc*2); ++va) color[va] = PetscDrawRealToColor(PetscRealPart(vals[va*Nc+comp + numVals/(Nc*2)]), vbound[0], vbound[1]);
250             break;
251           default: SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Number of values for cell closure %D cannot be handled", numVals/Nc);
252           }
253           ierr = DMPlexVecRestoreClosure(fdm, NULL, fv, c, &numVals, &vals);CHKERRQ(ierr);
254         }
255         ierr = DMPlexVecGetClosure(dm, coordSection, coordinates, c, &numCoords, &coords);CHKERRQ(ierr);
256         switch (numCoords) {
257         case 6:
258         case 12: /* Localized triangle */
259           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);
260           break;
261         case 8:
262         case 16: /* Localized quadrilateral */
263           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);
264           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);
265           break;
266         default: SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells with %D coordinates", numCoords);
267         }
268         ierr = DMPlexVecRestoreClosure(dm, coordSection, coordinates, c, &numCoords, &coords);CHKERRQ(ierr);
269       }
270       ierr = VecRestoreArrayRead(fv, &array);CHKERRQ(ierr);
271       ierr = PetscDrawFlush(draw);CHKERRQ(ierr);
272       ierr = PetscDrawPause(draw);CHKERRQ(ierr);
273       ierr = PetscDrawSave(draw);CHKERRQ(ierr);
274     }
275     if (Nf > 1) {
276       ierr = VecRestoreSubVector(v, fis, &fv);CHKERRQ(ierr);
277       ierr = ISDestroy(&fis);CHKERRQ(ierr);
278       ierr = DMDestroy(&fdm);CHKERRQ(ierr);
279     }
280   }
281   PetscFunctionReturn(0);
282 }
283 
284 static PetscErrorCode VecView_Plex_Local_VTK(Vec v, PetscViewer viewer)
285 {
286   DM                      dm;
287   Vec                     locv;
288   const char              *name;
289   PetscSection            section;
290   PetscInt                pStart, pEnd;
291   PetscInt                numFields;
292   PetscViewerVTKFieldType ft;
293   PetscErrorCode          ierr;
294 
295   PetscFunctionBegin;
296   ierr = VecGetDM(v, &dm);CHKERRQ(ierr);
297   ierr = DMCreateLocalVector(dm, &locv);CHKERRQ(ierr); /* VTK viewer requires exclusive ownership of the vector */
298   ierr = PetscObjectGetName((PetscObject) v, &name);CHKERRQ(ierr);
299   ierr = PetscObjectSetName((PetscObject) locv, name);CHKERRQ(ierr);
300   ierr = VecCopy(v, locv);CHKERRQ(ierr);
301   ierr = DMGetLocalSection(dm, &section);CHKERRQ(ierr);
302   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
303   if (!numFields) {
304     ierr = DMPlexGetFieldType_Internal(dm, section, PETSC_DETERMINE, &pStart, &pEnd, &ft);CHKERRQ(ierr);
305     ierr = PetscViewerVTKAddField(viewer, (PetscObject) dm, DMPlexVTKWriteAll, PETSC_DEFAULT, ft, PETSC_TRUE,(PetscObject) locv);CHKERRQ(ierr);
306   } else {
307     PetscInt f;
308 
309     for (f = 0; f < numFields; f++) {
310       ierr = DMPlexGetFieldType_Internal(dm, section, f, &pStart, &pEnd, &ft);CHKERRQ(ierr);
311       if (ft == PETSC_VTK_INVALID) continue;
312       ierr = PetscObjectReference((PetscObject)locv);CHKERRQ(ierr);
313       ierr = PetscViewerVTKAddField(viewer, (PetscObject) dm, DMPlexVTKWriteAll, f, ft, PETSC_TRUE,(PetscObject) locv);CHKERRQ(ierr);
314     }
315     ierr = VecDestroy(&locv);CHKERRQ(ierr);
316   }
317   PetscFunctionReturn(0);
318 }
319 
320 PetscErrorCode VecView_Plex_Local(Vec v, PetscViewer viewer)
321 {
322   DM             dm;
323   PetscBool      isvtk, ishdf5, isdraw, isglvis;
324   PetscErrorCode ierr;
325 
326   PetscFunctionBegin;
327   ierr = VecGetDM(v, &dm);CHKERRQ(ierr);
328   PetscCheckFalse(!dm,PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
329   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERVTK,   &isvtk);CHKERRQ(ierr);
330   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5,  &ishdf5);CHKERRQ(ierr);
331   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERDRAW,  &isdraw);CHKERRQ(ierr);
332   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERGLVIS, &isglvis);CHKERRQ(ierr);
333   if (isvtk || ishdf5 || isdraw || isglvis) {
334     PetscInt    i,numFields;
335     PetscObject fe;
336     PetscBool   fem = PETSC_FALSE;
337     Vec         locv = v;
338     const char  *name;
339     PetscInt    step;
340     PetscReal   time;
341 
342     ierr = DMGetNumFields(dm, &numFields);CHKERRQ(ierr);
343     for (i=0; i<numFields; i++) {
344       ierr = DMGetField(dm, i, NULL, &fe);CHKERRQ(ierr);
345       if (fe->classid == PETSCFE_CLASSID) { fem = PETSC_TRUE; break; }
346     }
347     if (fem) {
348       PetscObject isZero;
349 
350       ierr = DMGetLocalVector(dm, &locv);CHKERRQ(ierr);
351       ierr = PetscObjectGetName((PetscObject) v, &name);CHKERRQ(ierr);
352       ierr = PetscObjectSetName((PetscObject) locv, name);CHKERRQ(ierr);
353       ierr = PetscObjectQuery((PetscObject) v, "__Vec_bc_zero__", &isZero);CHKERRQ(ierr);
354       ierr = PetscObjectCompose((PetscObject) locv, "__Vec_bc_zero__", isZero);CHKERRQ(ierr);
355       ierr = VecCopy(v, locv);CHKERRQ(ierr);
356       ierr = DMGetOutputSequenceNumber(dm, NULL, &time);CHKERRQ(ierr);
357       ierr = DMPlexInsertBoundaryValues(dm, PETSC_TRUE, locv, time, NULL, NULL, NULL);CHKERRQ(ierr);
358     }
359     if (isvtk) {
360       ierr = VecView_Plex_Local_VTK(locv, viewer);CHKERRQ(ierr);
361     } else if (ishdf5) {
362 #if defined(PETSC_HAVE_HDF5)
363       ierr = VecView_Plex_Local_HDF5_Internal(locv, viewer);CHKERRQ(ierr);
364 #else
365       SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
366 #endif
367     } else if (isdraw) {
368       ierr = VecView_Plex_Local_Draw(locv, viewer);CHKERRQ(ierr);
369     } else if (isglvis) {
370       ierr = DMGetOutputSequenceNumber(dm, &step, NULL);CHKERRQ(ierr);
371       ierr = PetscViewerGLVisSetSnapId(viewer, step);CHKERRQ(ierr);
372       ierr = VecView_GLVis(locv, viewer);CHKERRQ(ierr);
373     }
374     if (fem) {
375       ierr = PetscObjectCompose((PetscObject) locv, "__Vec_bc_zero__", NULL);CHKERRQ(ierr);
376       ierr = DMRestoreLocalVector(dm, &locv);CHKERRQ(ierr);
377     }
378   } else {
379     PetscBool isseq;
380 
381     ierr = PetscObjectTypeCompare((PetscObject) v, VECSEQ, &isseq);CHKERRQ(ierr);
382     if (isseq) {ierr = VecView_Seq(v, viewer);CHKERRQ(ierr);}
383     else       {ierr = VecView_MPI(v, viewer);CHKERRQ(ierr);}
384   }
385   PetscFunctionReturn(0);
386 }
387 
388 PetscErrorCode VecView_Plex(Vec v, PetscViewer viewer)
389 {
390   DM             dm;
391   PetscBool      isvtk, ishdf5, isdraw, isglvis, isexodusii;
392   PetscErrorCode ierr;
393 
394   PetscFunctionBegin;
395   ierr = VecGetDM(v, &dm);CHKERRQ(ierr);
396   PetscCheckFalse(!dm,PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
397   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERVTK,      &isvtk);CHKERRQ(ierr);
398   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5,     &ishdf5);CHKERRQ(ierr);
399   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERDRAW,     &isdraw);CHKERRQ(ierr);
400   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERGLVIS,    &isglvis);CHKERRQ(ierr);
401   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWEREXODUSII, &isexodusii);CHKERRQ(ierr);
402   if (isvtk || isdraw || isglvis) {
403     Vec         locv;
404     PetscObject isZero;
405     const char *name;
406 
407     ierr = DMGetLocalVector(dm, &locv);CHKERRQ(ierr);
408     ierr = PetscObjectGetName((PetscObject) v, &name);CHKERRQ(ierr);
409     ierr = PetscObjectSetName((PetscObject) locv, name);CHKERRQ(ierr);
410     ierr = DMGlobalToLocalBegin(dm, v, INSERT_VALUES, locv);CHKERRQ(ierr);
411     ierr = DMGlobalToLocalEnd(dm, v, INSERT_VALUES, locv);CHKERRQ(ierr);
412     ierr = PetscObjectQuery((PetscObject) v, "__Vec_bc_zero__", &isZero);CHKERRQ(ierr);
413     ierr = PetscObjectCompose((PetscObject) locv, "__Vec_bc_zero__", isZero);CHKERRQ(ierr);
414     ierr = VecView_Plex_Local(locv, viewer);CHKERRQ(ierr);
415     ierr = PetscObjectCompose((PetscObject) locv, "__Vec_bc_zero__", NULL);CHKERRQ(ierr);
416     ierr = DMRestoreLocalVector(dm, &locv);CHKERRQ(ierr);
417   } else if (ishdf5) {
418 #if defined(PETSC_HAVE_HDF5)
419     ierr = VecView_Plex_HDF5_Internal(v, viewer);CHKERRQ(ierr);
420 #else
421     SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
422 #endif
423   } else if (isexodusii) {
424 #if defined(PETSC_HAVE_EXODUSII)
425     ierr = VecView_PlexExodusII_Internal(v, viewer);CHKERRQ(ierr);
426 #else
427     SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "ExodusII not supported in this build.\nPlease reconfigure using --download-exodusii");
428 #endif
429   } else {
430     PetscBool isseq;
431 
432     ierr = PetscObjectTypeCompare((PetscObject) v, VECSEQ, &isseq);CHKERRQ(ierr);
433     if (isseq) {ierr = VecView_Seq(v, viewer);CHKERRQ(ierr);}
434     else       {ierr = VecView_MPI(v, viewer);CHKERRQ(ierr);}
435   }
436   PetscFunctionReturn(0);
437 }
438 
439 PetscErrorCode VecView_Plex_Native(Vec originalv, PetscViewer viewer)
440 {
441   DM                dm;
442   MPI_Comm          comm;
443   PetscViewerFormat format;
444   Vec               v;
445   PetscBool         isvtk, ishdf5;
446   PetscErrorCode    ierr;
447 
448   PetscFunctionBegin;
449   ierr = VecGetDM(originalv, &dm);CHKERRQ(ierr);
450   ierr = PetscObjectGetComm((PetscObject) originalv, &comm);CHKERRQ(ierr);
451   PetscCheckFalse(!dm,comm, PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
452   ierr = PetscViewerGetFormat(viewer, &format);CHKERRQ(ierr);
453   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5);CHKERRQ(ierr);
454   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERVTK,  &isvtk);CHKERRQ(ierr);
455   if (format == PETSC_VIEWER_NATIVE) {
456     /* Natural ordering is the common case for DMDA, NATIVE means plain vector, for PLEX is the opposite */
457     /* this need a better fix */
458     if (dm->useNatural) {
459       if (dm->sfNatural) {
460         const char *vecname;
461         PetscInt    n, nroots;
462 
463         ierr = VecGetLocalSize(originalv, &n);CHKERRQ(ierr);
464         ierr = PetscSFGetGraph(dm->sfNatural, &nroots, NULL, NULL, NULL);CHKERRQ(ierr);
465         if (n == nroots) {
466           ierr = DMGetGlobalVector(dm, &v);CHKERRQ(ierr);
467           ierr = DMPlexGlobalToNaturalBegin(dm, originalv, v);CHKERRQ(ierr);
468           ierr = DMPlexGlobalToNaturalEnd(dm, originalv, v);CHKERRQ(ierr);
469           ierr = PetscObjectGetName((PetscObject) originalv, &vecname);CHKERRQ(ierr);
470           ierr = PetscObjectSetName((PetscObject) v, vecname);CHKERRQ(ierr);
471         } else SETERRQ(comm, PETSC_ERR_ARG_WRONG, "DM global to natural SF only handles global vectors");
472       } else SETERRQ(comm, PETSC_ERR_ARG_WRONGSTATE, "DM global to natural SF was not created");
473     } else v = originalv;
474   } else v = originalv;
475 
476   if (ishdf5) {
477 #if defined(PETSC_HAVE_HDF5)
478     ierr = VecView_Plex_HDF5_Native_Internal(v, viewer);CHKERRQ(ierr);
479 #else
480     SETERRQ(comm, PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
481 #endif
482   } else if (isvtk) {
483     SETERRQ(comm, PETSC_ERR_SUP, "VTK format does not support viewing in natural order. Please switch to HDF5.");
484   } else {
485     PetscBool isseq;
486 
487     ierr = PetscObjectTypeCompare((PetscObject) v, VECSEQ, &isseq);CHKERRQ(ierr);
488     if (isseq) {ierr = VecView_Seq(v, viewer);CHKERRQ(ierr);}
489     else       {ierr = VecView_MPI(v, viewer);CHKERRQ(ierr);}
490   }
491   if (v != originalv) {ierr = DMRestoreGlobalVector(dm, &v);CHKERRQ(ierr);}
492   PetscFunctionReturn(0);
493 }
494 
495 PetscErrorCode VecLoad_Plex_Local(Vec v, PetscViewer viewer)
496 {
497   DM             dm;
498   PetscBool      ishdf5;
499   PetscErrorCode ierr;
500 
501   PetscFunctionBegin;
502   ierr = VecGetDM(v, &dm);CHKERRQ(ierr);
503   PetscCheckFalse(!dm,PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
504   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5);CHKERRQ(ierr);
505   if (ishdf5) {
506     DM          dmBC;
507     Vec         gv;
508     const char *name;
509 
510     ierr = DMGetOutputDM(dm, &dmBC);CHKERRQ(ierr);
511     ierr = DMGetGlobalVector(dmBC, &gv);CHKERRQ(ierr);
512     ierr = PetscObjectGetName((PetscObject) v, &name);CHKERRQ(ierr);
513     ierr = PetscObjectSetName((PetscObject) gv, name);CHKERRQ(ierr);
514     ierr = VecLoad_Default(gv, viewer);CHKERRQ(ierr);
515     ierr = DMGlobalToLocalBegin(dmBC, gv, INSERT_VALUES, v);CHKERRQ(ierr);
516     ierr = DMGlobalToLocalEnd(dmBC, gv, INSERT_VALUES, v);CHKERRQ(ierr);
517     ierr = DMRestoreGlobalVector(dmBC, &gv);CHKERRQ(ierr);
518   } else {
519     ierr = VecLoad_Default(v, viewer);CHKERRQ(ierr);
520   }
521   PetscFunctionReturn(0);
522 }
523 
524 PetscErrorCode VecLoad_Plex(Vec v, PetscViewer viewer)
525 {
526   DM             dm;
527   PetscBool      ishdf5,isexodusii;
528   PetscErrorCode ierr;
529 
530   PetscFunctionBegin;
531   ierr = VecGetDM(v, &dm);CHKERRQ(ierr);
532   PetscCheckFalse(!dm,PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
533   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5,     &ishdf5);CHKERRQ(ierr);
534   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWEREXODUSII, &isexodusii);CHKERRQ(ierr);
535   if (ishdf5) {
536 #if defined(PETSC_HAVE_HDF5)
537     ierr = VecLoad_Plex_HDF5_Internal(v, viewer);CHKERRQ(ierr);
538 #else
539     SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
540 #endif
541   } else if (isexodusii) {
542 #if defined(PETSC_HAVE_EXODUSII)
543     ierr = VecLoad_PlexExodusII_Internal(v, viewer);CHKERRQ(ierr);
544 #else
545     SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "ExodusII not supported in this build.\nPlease reconfigure using --download-exodusii");
546 #endif
547   } else {
548     ierr = VecLoad_Default(v, viewer);CHKERRQ(ierr);
549   }
550   PetscFunctionReturn(0);
551 }
552 
553 PetscErrorCode VecLoad_Plex_Native(Vec originalv, PetscViewer viewer)
554 {
555   DM                dm;
556   PetscViewerFormat format;
557   PetscBool         ishdf5;
558   PetscErrorCode    ierr;
559 
560   PetscFunctionBegin;
561   ierr = VecGetDM(originalv, &dm);CHKERRQ(ierr);
562   PetscCheckFalse(!dm,PetscObjectComm((PetscObject) originalv), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
563   ierr = PetscViewerGetFormat(viewer, &format);CHKERRQ(ierr);
564   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5);CHKERRQ(ierr);
565   if (format == PETSC_VIEWER_NATIVE) {
566     if (dm->useNatural) {
567       if (dm->sfNatural) {
568         if (ishdf5) {
569 #if defined(PETSC_HAVE_HDF5)
570           Vec         v;
571           const char *vecname;
572 
573           ierr = DMGetGlobalVector(dm, &v);CHKERRQ(ierr);
574           ierr = PetscObjectGetName((PetscObject) originalv, &vecname);CHKERRQ(ierr);
575           ierr = PetscObjectSetName((PetscObject) v, vecname);CHKERRQ(ierr);
576           ierr = VecLoad_Plex_HDF5_Native_Internal(v, viewer);CHKERRQ(ierr);
577           ierr = DMPlexNaturalToGlobalBegin(dm, v, originalv);CHKERRQ(ierr);
578           ierr = DMPlexNaturalToGlobalEnd(dm, v, originalv);CHKERRQ(ierr);
579           ierr = DMRestoreGlobalVector(dm, &v);CHKERRQ(ierr);
580 #else
581           SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
582 #endif
583         } else SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Reading in natural order is not supported for anything but HDF5.");
584       }
585     } else {
586       ierr = VecLoad_Default(originalv, viewer);CHKERRQ(ierr);
587     }
588   }
589   PetscFunctionReturn(0);
590 }
591 
592 PETSC_UNUSED static PetscErrorCode DMPlexView_Ascii_Geometry(DM dm, PetscViewer viewer)
593 {
594   PetscSection       coordSection;
595   Vec                coordinates;
596   DMLabel            depthLabel, celltypeLabel;
597   const char        *name[4];
598   const PetscScalar *a;
599   PetscInt           dim, pStart, pEnd, cStart, cEnd, c;
600   PetscErrorCode     ierr;
601 
602   PetscFunctionBegin;
603   ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr);
604   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
605   ierr = DMGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
606   ierr = DMPlexGetDepthLabel(dm, &depthLabel);CHKERRQ(ierr);
607   ierr = DMPlexGetCellTypeLabel(dm, &celltypeLabel);CHKERRQ(ierr);
608   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
609   ierr = PetscSectionGetChart(coordSection, &pStart, &pEnd);CHKERRQ(ierr);
610   ierr = VecGetArrayRead(coordinates, &a);CHKERRQ(ierr);
611   name[0]     = "vertex";
612   name[1]     = "edge";
613   name[dim-1] = "face";
614   name[dim]   = "cell";
615   for (c = cStart; c < cEnd; ++c) {
616     PetscInt *closure = NULL;
617     PetscInt  closureSize, cl, ct;
618 
619     ierr = DMLabelGetValue(celltypeLabel, c, &ct);CHKERRQ(ierr);
620     ierr = PetscViewerASCIIPrintf(viewer, "Geometry for cell %D polytope type %s:\n", c, DMPolytopeTypes[ct]);CHKERRQ(ierr);
621     ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
622     ierr = PetscViewerASCIIPushTab(viewer);CHKERRQ(ierr);
623     for (cl = 0; cl < closureSize*2; cl += 2) {
624       PetscInt point = closure[cl], depth, dof, off, d, p;
625 
626       if ((point < pStart) || (point >= pEnd)) continue;
627       ierr = PetscSectionGetDof(coordSection, point, &dof);CHKERRQ(ierr);
628       if (!dof) continue;
629       ierr = DMLabelGetValue(depthLabel, point, &depth);CHKERRQ(ierr);
630       ierr = PetscSectionGetOffset(coordSection, point, &off);CHKERRQ(ierr);
631       ierr = PetscViewerASCIIPrintf(viewer, "%s %D coords:", name[depth], point);CHKERRQ(ierr);
632       for (p = 0; p < dof/dim; ++p) {
633         ierr = PetscViewerASCIIPrintf(viewer, " (");CHKERRQ(ierr);
634         for (d = 0; d < dim; ++d) {
635           if (d > 0) {ierr = PetscViewerASCIIPrintf(viewer, ", ");CHKERRQ(ierr);}
636           ierr = PetscViewerASCIIPrintf(viewer, "%g", (double) PetscRealPart(a[off+p*dim+d]));CHKERRQ(ierr);
637         }
638         ierr = PetscViewerASCIIPrintf(viewer, ")");CHKERRQ(ierr);
639       }
640       ierr = PetscViewerASCIIPrintf(viewer, "\n");CHKERRQ(ierr);
641     }
642     ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
643     ierr = PetscViewerASCIIPopTab(viewer);CHKERRQ(ierr);
644   }
645   ierr = VecRestoreArrayRead(coordinates, &a);CHKERRQ(ierr);
646   PetscFunctionReturn(0);
647 }
648 
649 typedef enum {CS_CARTESIAN, CS_POLAR, CS_CYLINDRICAL, CS_SPHERICAL} CoordSystem;
650 const char *CoordSystems[] = {"cartesian", "polar", "cylindrical", "spherical", "CoordSystem", "CS_", NULL};
651 
652 static PetscErrorCode DMPlexView_Ascii_Coordinates(PetscViewer viewer, CoordSystem cs, PetscInt dim, const PetscScalar x[])
653 {
654   PetscInt       i;
655   PetscErrorCode ierr;
656 
657   PetscFunctionBegin;
658   if (dim > 3) {
659     for (i = 0; i < dim; ++i) {ierr = PetscViewerASCIISynchronizedPrintf(viewer, " %g", (double) PetscRealPart(x[i]));CHKERRQ(ierr);}
660   } else {
661     PetscReal coords[3], trcoords[3];
662 
663     for (i = 0; i < dim; ++i) coords[i] = PetscRealPart(x[i]);
664     switch (cs) {
665       case CS_CARTESIAN: for (i = 0; i < dim; ++i) trcoords[i] = coords[i];break;
666       case CS_POLAR:
667         PetscCheckFalse(dim != 2,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Polar coordinates are for 2 dimension, not %D", dim);
668         trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1]));
669         trcoords[1] = PetscAtan2Real(coords[1], coords[0]);
670         break;
671       case CS_CYLINDRICAL:
672         PetscCheckFalse(dim != 3,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cylindrical coordinates are for 3 dimension, not %D", dim);
673         trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1]));
674         trcoords[1] = PetscAtan2Real(coords[1], coords[0]);
675         trcoords[2] = coords[2];
676         break;
677       case CS_SPHERICAL:
678         PetscCheckFalse(dim != 3,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Spherical coordinates are for 3 dimension, not %D", dim);
679         trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1]) + PetscSqr(coords[2]));
680         trcoords[1] = PetscAtan2Real(PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1])), coords[2]);
681         trcoords[2] = PetscAtan2Real(coords[1], coords[0]);
682         break;
683     }
684     for (i = 0; i < dim; ++i) {ierr = PetscViewerASCIISynchronizedPrintf(viewer, " %g", (double) trcoords[i]);CHKERRQ(ierr);}
685   }
686   PetscFunctionReturn(0);
687 }
688 
689 static PetscErrorCode DMPlexView_Ascii(DM dm, PetscViewer viewer)
690 {
691   DM_Plex          *mesh = (DM_Plex*) dm->data;
692   DM                cdm;
693   PetscSection      coordSection;
694   Vec               coordinates;
695   PetscViewerFormat format;
696   PetscErrorCode    ierr;
697 
698   PetscFunctionBegin;
699   ierr = DMGetCoordinateDM(dm, &cdm);CHKERRQ(ierr);
700   ierr = DMGetLocalSection(cdm, &coordSection);CHKERRQ(ierr);
701   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
702   ierr = PetscViewerGetFormat(viewer, &format);CHKERRQ(ierr);
703   if (format == PETSC_VIEWER_ASCII_INFO_DETAIL) {
704     const char *name;
705     PetscInt    dim, cellHeight, maxConeSize, maxSupportSize;
706     PetscInt    pStart, pEnd, p, numLabels, l;
707     PetscMPIInt rank, size;
708 
709     ierr = MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank);CHKERRMPI(ierr);
710     ierr = MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size);CHKERRMPI(ierr);
711     ierr = PetscObjectGetName((PetscObject) dm, &name);CHKERRQ(ierr);
712     ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
713     ierr = DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize);CHKERRQ(ierr);
714     ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr);
715     ierr = DMPlexGetVTKCellHeight(dm, &cellHeight);CHKERRQ(ierr);
716     if (name) {ierr = PetscViewerASCIIPrintf(viewer, "%s in %D dimension%s:\n", name, dim, dim == 1 ? "" : "s");CHKERRQ(ierr);}
717     else      {ierr = PetscViewerASCIIPrintf(viewer, "Mesh in %D dimension%s:\n", dim, dim == 1 ? "" : "s");CHKERRQ(ierr);}
718     if (cellHeight) {ierr = PetscViewerASCIIPrintf(viewer, "  Cells are at height %D\n", cellHeight);CHKERRQ(ierr);}
719     ierr = PetscViewerASCIIPrintf(viewer, "Supports:\n", name);CHKERRQ(ierr);
720     ierr = PetscViewerASCIIPushSynchronized(viewer);CHKERRQ(ierr);
721     ierr = PetscViewerASCIISynchronizedPrintf(viewer, "[%d] Max support size: %D\n", rank, maxSupportSize);CHKERRQ(ierr);
722     for (p = pStart; p < pEnd; ++p) {
723       PetscInt dof, off, s;
724 
725       ierr = PetscSectionGetDof(mesh->supportSection, p, &dof);CHKERRQ(ierr);
726       ierr = PetscSectionGetOffset(mesh->supportSection, p, &off);CHKERRQ(ierr);
727       for (s = off; s < off+dof; ++s) {
728         ierr = PetscViewerASCIISynchronizedPrintf(viewer, "[%d]: %D ----> %D\n", rank, p, mesh->supports[s]);CHKERRQ(ierr);
729       }
730     }
731     ierr = PetscViewerFlush(viewer);CHKERRQ(ierr);
732     ierr = PetscViewerASCIIPrintf(viewer, "Cones:\n", name);CHKERRQ(ierr);
733     ierr = PetscViewerASCIISynchronizedPrintf(viewer, "[%d] Max cone size: %D\n", rank, maxConeSize);CHKERRQ(ierr);
734     for (p = pStart; p < pEnd; ++p) {
735       PetscInt dof, off, c;
736 
737       ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
738       ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
739       for (c = off; c < off+dof; ++c) {
740         ierr = PetscViewerASCIISynchronizedPrintf(viewer, "[%d]: %D <---- %D (%D)\n", rank, p, mesh->cones[c], mesh->coneOrientations[c]);CHKERRQ(ierr);
741       }
742     }
743     ierr = PetscViewerFlush(viewer);CHKERRQ(ierr);
744     ierr = PetscViewerASCIIPopSynchronized(viewer);CHKERRQ(ierr);
745     if (coordSection && coordinates) {
746       CoordSystem        cs = CS_CARTESIAN;
747       const PetscScalar *array;
748       PetscInt           Nf, Nc, pStart, pEnd, p;
749       PetscMPIInt        rank;
750       const char        *name;
751 
752       ierr = PetscOptionsGetEnum(((PetscObject) viewer)->options, ((PetscObject) viewer)->prefix, "-dm_plex_view_coord_system", CoordSystems, (PetscEnum *) &cs, NULL);CHKERRQ(ierr);
753       ierr = MPI_Comm_rank(PetscObjectComm((PetscObject)viewer), &rank);CHKERRMPI(ierr);
754       ierr = PetscSectionGetNumFields(coordSection, &Nf);CHKERRQ(ierr);
755       PetscCheckFalse(Nf != 1,PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Coordinate section should have 1 field, not %D", Nf);
756       ierr = PetscSectionGetFieldComponents(coordSection, 0, &Nc);CHKERRQ(ierr);
757       ierr = PetscSectionGetChart(coordSection, &pStart, &pEnd);CHKERRQ(ierr);
758       ierr = PetscObjectGetName((PetscObject) coordinates, &name);CHKERRQ(ierr);
759       ierr = PetscViewerASCIIPrintf(viewer, "%s with %D fields\n", name, Nf);CHKERRQ(ierr);
760       ierr = PetscViewerASCIIPrintf(viewer, "  field 0 with %D components\n", Nc);CHKERRQ(ierr);
761       if (cs != CS_CARTESIAN) {ierr = PetscViewerASCIIPrintf(viewer, "  output coordinate system: %s\n", CoordSystems[cs]);CHKERRQ(ierr);}
762 
763       ierr = VecGetArrayRead(coordinates, &array);CHKERRQ(ierr);
764       ierr = PetscViewerASCIIPushSynchronized(viewer);CHKERRQ(ierr);
765       ierr = PetscViewerASCIISynchronizedPrintf(viewer, "Process %d:\n", rank);CHKERRQ(ierr);
766       for (p = pStart; p < pEnd; ++p) {
767         PetscInt dof, off;
768 
769         ierr = PetscSectionGetDof(coordSection, p, &dof);CHKERRQ(ierr);
770         ierr = PetscSectionGetOffset(coordSection, p, &off);CHKERRQ(ierr);
771         ierr = PetscViewerASCIISynchronizedPrintf(viewer, "  (%4D) dim %2D offset %3D", p, dof, off);CHKERRQ(ierr);
772         ierr = DMPlexView_Ascii_Coordinates(viewer, cs, dof, &array[off]);CHKERRQ(ierr);
773         ierr = PetscViewerASCIISynchronizedPrintf(viewer, "\n");CHKERRQ(ierr);
774       }
775       ierr = PetscViewerFlush(viewer);CHKERRQ(ierr);
776       ierr = PetscViewerASCIIPopSynchronized(viewer);CHKERRQ(ierr);
777       ierr = VecRestoreArrayRead(coordinates, &array);CHKERRQ(ierr);
778     }
779     ierr = DMGetNumLabels(dm, &numLabels);CHKERRQ(ierr);
780     if (numLabels) {ierr = PetscViewerASCIIPrintf(viewer, "Labels:\n");CHKERRQ(ierr);}
781     for (l = 0; l < numLabels; ++l) {
782       DMLabel     label;
783       PetscBool   isdepth;
784       const char *name;
785 
786       ierr = DMGetLabelName(dm, l, &name);CHKERRQ(ierr);
787       ierr = PetscStrcmp(name, "depth", &isdepth);CHKERRQ(ierr);
788       if (isdepth) continue;
789       ierr = DMGetLabel(dm, name, &label);CHKERRQ(ierr);
790       ierr = DMLabelView(label, viewer);CHKERRQ(ierr);
791     }
792     if (size > 1) {
793       PetscSF sf;
794 
795       ierr = DMGetPointSF(dm, &sf);CHKERRQ(ierr);
796       ierr = PetscSFView(sf, viewer);CHKERRQ(ierr);
797     }
798     ierr = PetscViewerFlush(viewer);CHKERRQ(ierr);
799   } else if (format == PETSC_VIEWER_ASCII_LATEX) {
800     const char  *name, *color;
801     const char  *defcolors[3]  = {"gray", "orange", "green"};
802     const char  *deflcolors[4] = {"blue", "cyan", "red", "magenta"};
803     char         lname[PETSC_MAX_PATH_LEN];
804     PetscReal    scale         = 2.0;
805     PetscReal    tikzscale     = 1.0;
806     PetscBool    useNumbers    = PETSC_TRUE, drawNumbers[4], drawColors[4], useLabels, useColors, plotEdges, drawHasse = PETSC_FALSE;
807     double       tcoords[3];
808     PetscScalar *coords;
809     PetscInt     numLabels, l, numColors, numLColors, dim, d, depth, cStart, cEnd, c, vStart, vEnd, v, eStart = 0, eEnd = 0, e, p, n;
810     PetscMPIInt  rank, size;
811     char         **names, **colors, **lcolors;
812     PetscBool    flg, lflg;
813     PetscBT      wp = NULL;
814     PetscInt     pEnd, pStart;
815 
816     ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr);
817     ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
818     ierr = DMGetNumLabels(dm, &numLabels);CHKERRQ(ierr);
819     numLabels  = PetscMax(numLabels, 10);
820     numColors  = 10;
821     numLColors = 10;
822     ierr = PetscCalloc3(numLabels, &names, numColors, &colors, numLColors, &lcolors);CHKERRQ(ierr);
823     ierr = PetscOptionsGetReal(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_scale", &scale, NULL);CHKERRQ(ierr);
824     ierr = PetscOptionsGetReal(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_tikzscale", &tikzscale, NULL);CHKERRQ(ierr);
825     ierr = PetscOptionsGetBool(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_numbers", &useNumbers, NULL);CHKERRQ(ierr);
826     for (d = 0; d < 4; ++d) drawNumbers[d] = useNumbers;
827     for (d = 0; d < 4; ++d) drawColors[d]  = PETSC_TRUE;
828     n = 4;
829     ierr = PetscOptionsGetBoolArray(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_numbers_depth", drawNumbers, &n, &flg);CHKERRQ(ierr);
830     PetscCheckFalse(flg && n != dim+1,PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Number of flags %D != %D dim+1", n, dim+1);
831     ierr = PetscOptionsGetBoolArray(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_colors_depth", drawColors, &n, &flg);CHKERRQ(ierr);
832     PetscCheckFalse(flg && n != dim+1,PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Number of flags %D != %D dim+1", n, dim+1);
833     ierr = PetscOptionsGetStringArray(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_labels", names, &numLabels, &useLabels);CHKERRQ(ierr);
834     if (!useLabels) numLabels = 0;
835     ierr = PetscOptionsGetStringArray(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_colors", colors, &numColors, &useColors);CHKERRQ(ierr);
836     if (!useColors) {
837       numColors = 3;
838       for (c = 0; c < numColors; ++c) {ierr = PetscStrallocpy(defcolors[c], &colors[c]);CHKERRQ(ierr);}
839     }
840     ierr = PetscOptionsGetStringArray(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_lcolors", lcolors, &numLColors, &useColors);CHKERRQ(ierr);
841     if (!useColors) {
842       numLColors = 4;
843       for (c = 0; c < numLColors; ++c) {ierr = PetscStrallocpy(deflcolors[c], &lcolors[c]);CHKERRQ(ierr);}
844     }
845     ierr = PetscOptionsGetString(((PetscObject) viewer)->options, ((PetscObject) viewer)->prefix, "-dm_plex_view_label_filter", lname, sizeof(lname), &lflg);CHKERRQ(ierr);
846     plotEdges = (PetscBool)(depth > 1 && drawNumbers[1] && dim < 3);
847     ierr = PetscOptionsGetBool(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_edges", &plotEdges, &flg);CHKERRQ(ierr);
848     PetscCheckFalse(flg && plotEdges && depth < dim,PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Mesh must be interpolated");
849     if (depth < dim) plotEdges = PETSC_FALSE;
850     ierr = PetscOptionsGetBool(((PetscObject) viewer)->options, ((PetscObject) viewer)->prefix, "-dm_plex_view_hasse", &drawHasse, NULL);CHKERRQ(ierr);
851 
852     /* filter points with labelvalue != labeldefaultvalue */
853     ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
854     ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
855     ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
856     ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
857     if (lflg) {
858       DMLabel lbl;
859 
860       ierr = DMGetLabel(dm, lname, &lbl);CHKERRQ(ierr);
861       if (lbl) {
862         PetscInt val, defval;
863 
864         ierr = DMLabelGetDefaultValue(lbl, &defval);CHKERRQ(ierr);
865         ierr = PetscBTCreate(pEnd-pStart, &wp);CHKERRQ(ierr);
866         for (c = pStart;  c < pEnd; c++) {
867           PetscInt *closure = NULL;
868           PetscInt  closureSize;
869 
870           ierr = DMLabelGetValue(lbl, c, &val);CHKERRQ(ierr);
871           if (val == defval) continue;
872 
873           ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
874           for (p = 0; p < closureSize*2; p += 2) {
875             ierr = PetscBTSet(wp, closure[p] - pStart);CHKERRQ(ierr);
876           }
877           ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
878         }
879       }
880     }
881 
882     ierr = MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank);CHKERRMPI(ierr);
883     ierr = MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size);CHKERRMPI(ierr);
884     ierr = PetscObjectGetName((PetscObject) dm, &name);CHKERRQ(ierr);
885     ierr = PetscViewerASCIIPrintf(viewer, "\
886 \\documentclass[tikz]{standalone}\n\n\
887 \\usepackage{pgflibraryshapes}\n\
888 \\usetikzlibrary{backgrounds}\n\
889 \\usetikzlibrary{arrows}\n\
890 \\begin{document}\n");CHKERRQ(ierr);
891     if (size > 1) {
892       ierr = PetscViewerASCIIPrintf(viewer, "%s for process ", name);CHKERRQ(ierr);
893       for (p = 0; p < size; ++p) {
894         if (p > 0 && p == size-1) {
895           ierr = PetscViewerASCIIPrintf(viewer, ", and ", colors[p%numColors], p);CHKERRQ(ierr);
896         } else if (p > 0) {
897           ierr = PetscViewerASCIIPrintf(viewer, ", ", colors[p%numColors], p);CHKERRQ(ierr);
898         }
899         ierr = PetscViewerASCIIPrintf(viewer, "{\\textcolor{%s}%D}", colors[p%numColors], p);CHKERRQ(ierr);
900       }
901       ierr = PetscViewerASCIIPrintf(viewer, ".\n\n\n");CHKERRQ(ierr);
902     }
903     if (drawHasse) {
904       PetscInt maxStratum = PetscMax(vEnd-vStart, PetscMax(eEnd-eStart, cEnd-cStart));
905 
906       ierr = PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vStart}{%D}\n", vStart);CHKERRQ(ierr);
907       ierr = PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vEnd}{%D}\n", vEnd-1);CHKERRQ(ierr);
908       ierr = PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numVertices}{%D}\n", vEnd-vStart);CHKERRQ(ierr);
909       ierr = PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vShift}{%.2f}\n", 3 + (maxStratum-(vEnd-vStart))/2.);CHKERRQ(ierr);
910       ierr = PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eStart}{%D}\n", eStart);CHKERRQ(ierr);
911       ierr = PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eEnd}{%D}\n", eEnd-1);CHKERRQ(ierr);
912       ierr = PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eShift}{%.2f}\n", 3 + (maxStratum-(eEnd-eStart))/2.);CHKERRQ(ierr);
913       ierr = PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numEdges}{%D}\n", eEnd-eStart);CHKERRQ(ierr);
914       ierr = PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cStart}{%D}\n", cStart);CHKERRQ(ierr);
915       ierr = PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cEnd}{%D}\n", cEnd-1);CHKERRQ(ierr);
916       ierr = PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numCells}{%D}\n", cEnd-cStart);CHKERRQ(ierr);
917       ierr = PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cShift}{%.2f}\n", 3 + (maxStratum-(cEnd-cStart))/2.);CHKERRQ(ierr);
918     }
919     ierr = PetscViewerASCIIPrintf(viewer, "\\begin{tikzpicture}[scale = %g,font=\\fontsize{8}{8}\\selectfont]\n", (double) tikzscale);CHKERRQ(ierr);
920 
921     /* Plot vertices */
922     ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
923     ierr = PetscViewerASCIIPushSynchronized(viewer);CHKERRQ(ierr);
924     for (v = vStart; v < vEnd; ++v) {
925       PetscInt  off, dof, d;
926       PetscBool isLabeled = PETSC_FALSE;
927 
928       if (wp && !PetscBTLookup(wp,v - pStart)) continue;
929       ierr = PetscSectionGetDof(coordSection, v, &dof);CHKERRQ(ierr);
930       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
931       ierr = PetscViewerASCIISynchronizedPrintf(viewer, "\\path (");CHKERRQ(ierr);
932       PetscCheckFalse(dof > 3,PETSC_COMM_SELF,PETSC_ERR_PLIB,"coordSection vertex %D has dof %D > 3",v,dof);
933       for (d = 0; d < dof; ++d) {
934         tcoords[d] = (double) (scale*PetscRealPart(coords[off+d]));
935         tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d];
936       }
937       /* Rotate coordinates since PGF makes z point out of the page instead of up */
938       if (dim == 3) {PetscReal tmp = tcoords[1]; tcoords[1] = tcoords[2]; tcoords[2] = -tmp;}
939       for (d = 0; d < dof; ++d) {
940         if (d > 0) {ierr = PetscViewerASCIISynchronizedPrintf(viewer, ",");CHKERRQ(ierr);}
941         ierr = PetscViewerASCIISynchronizedPrintf(viewer, "%g", (double) tcoords[d]);CHKERRQ(ierr);
942       }
943       if (drawHasse) color = colors[0%numColors];
944       else           color = colors[rank%numColors];
945       for (l = 0; l < numLabels; ++l) {
946         PetscInt val;
947         ierr = DMGetLabelValue(dm, names[l], v, &val);CHKERRQ(ierr);
948         if (val >= 0) {color = lcolors[l%numLColors]; isLabeled = PETSC_TRUE; break;}
949       }
950       if (drawNumbers[0]) {
951         ierr = PetscViewerASCIISynchronizedPrintf(viewer, ") node(%D_%d) [draw,shape=circle,color=%s] {%D};\n", v, rank, color, v);CHKERRQ(ierr);
952       } else if (drawColors[0]) {
953         ierr = PetscViewerASCIISynchronizedPrintf(viewer, ") node(%D_%d) [fill,inner sep=%dpt,shape=circle,color=%s] {};\n", v, rank, !isLabeled ? 1 : 2, color);CHKERRQ(ierr);
954       } else {
955         ierr = PetscViewerASCIISynchronizedPrintf(viewer, ") node(%D_%d) [] {};\n", v, rank);CHKERRQ(ierr);
956       }
957     }
958     ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
959     ierr = PetscViewerFlush(viewer);CHKERRQ(ierr);
960     /* Plot edges */
961     if (plotEdges) {
962       ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
963       ierr = PetscViewerASCIIPrintf(viewer, "\\path\n");CHKERRQ(ierr);
964       for (e = eStart; e < eEnd; ++e) {
965         const PetscInt *cone;
966         PetscInt        coneSize, offA, offB, dof, d;
967 
968         if (wp && !PetscBTLookup(wp,e - pStart)) continue;
969         ierr = DMPlexGetConeSize(dm, e, &coneSize);CHKERRQ(ierr);
970         PetscCheckFalse(coneSize != 2,PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Edge %D cone should have two vertices, not %D", e, coneSize);
971         ierr = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
972         ierr = PetscSectionGetDof(coordSection, cone[0], &dof);CHKERRQ(ierr);
973         ierr = PetscSectionGetOffset(coordSection, cone[0], &offA);CHKERRQ(ierr);
974         ierr = PetscSectionGetOffset(coordSection, cone[1], &offB);CHKERRQ(ierr);
975         ierr = PetscViewerASCIISynchronizedPrintf(viewer, "(");CHKERRQ(ierr);
976         for (d = 0; d < dof; ++d) {
977           tcoords[d] = (double) (0.5*scale*PetscRealPart(coords[offA+d]+coords[offB+d]));
978           tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d];
979         }
980         /* Rotate coordinates since PGF makes z point out of the page instead of up */
981         if (dim == 3) {PetscReal tmp = tcoords[1]; tcoords[1] = tcoords[2]; tcoords[2] = -tmp;}
982         for (d = 0; d < dof; ++d) {
983           if (d > 0) {ierr = PetscViewerASCIISynchronizedPrintf(viewer, ",");CHKERRQ(ierr);}
984           ierr = PetscViewerASCIISynchronizedPrintf(viewer, "%g", (double)tcoords[d]);CHKERRQ(ierr);
985         }
986         if (drawHasse) color = colors[1%numColors];
987         else           color = colors[rank%numColors];
988         for (l = 0; l < numLabels; ++l) {
989           PetscInt val;
990           ierr = DMGetLabelValue(dm, names[l], v, &val);CHKERRQ(ierr);
991           if (val >= 0) {color = lcolors[l%numLColors]; break;}
992         }
993         ierr = PetscViewerASCIISynchronizedPrintf(viewer, ") node(%D_%d) [draw,shape=circle,color=%s] {%D} --\n", e, rank, color, e);CHKERRQ(ierr);
994       }
995       ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
996       ierr = PetscViewerFlush(viewer);CHKERRQ(ierr);
997       ierr = PetscViewerASCIIPrintf(viewer, "(0,0);\n");CHKERRQ(ierr);
998     }
999     /* Plot cells */
1000     if (dim == 3 || !drawNumbers[1]) {
1001       for (e = eStart; e < eEnd; ++e) {
1002         const PetscInt *cone;
1003 
1004         if (wp && !PetscBTLookup(wp,e - pStart)) continue;
1005         color = colors[rank%numColors];
1006         for (l = 0; l < numLabels; ++l) {
1007           PetscInt val;
1008           ierr = DMGetLabelValue(dm, names[l], e, &val);CHKERRQ(ierr);
1009           if (val >= 0) {color = lcolors[l%numLColors]; break;}
1010         }
1011         ierr = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
1012         ierr = PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] (%D_%d) -- (%D_%d);\n", color, cone[0], rank, cone[1], rank);CHKERRQ(ierr);
1013       }
1014     } else {
1015        DMPolytopeType ct;
1016 
1017       /* Drawing a 2D polygon */
1018       for (c = cStart; c < cEnd; ++c) {
1019         if (wp && !PetscBTLookup(wp, c - pStart)) continue;
1020         ierr = DMPlexGetCellType(dm, c, &ct);CHKERRQ(ierr);
1021         if (ct == DM_POLYTOPE_SEG_PRISM_TENSOR ||
1022             ct == DM_POLYTOPE_TRI_PRISM_TENSOR ||
1023             ct == DM_POLYTOPE_QUAD_PRISM_TENSOR) {
1024           const PetscInt *cone;
1025           PetscInt        coneSize, e;
1026 
1027           ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
1028           ierr = DMPlexGetConeSize(dm, c, &coneSize);CHKERRQ(ierr);
1029           for (e = 0; e < coneSize; ++e) {
1030             const PetscInt *econe;
1031 
1032             ierr = DMPlexGetCone(dm, cone[e], &econe);CHKERRQ(ierr);
1033             ierr = PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] (%D_%d) -- (%D_%d) -- (%D_%d);\n", colors[rank%numColors], econe[0], rank, cone[e], rank, econe[1], rank);CHKERRQ(ierr);
1034           }
1035         } else {
1036           PetscInt *closure = NULL;
1037           PetscInt  closureSize, Nv = 0, v;
1038 
1039           ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
1040           for (p = 0; p < closureSize*2; p += 2) {
1041             const PetscInt point = closure[p];
1042 
1043             if ((point >= vStart) && (point < vEnd)) closure[Nv++] = point;
1044           }
1045           ierr = PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] ", colors[rank%numColors]);CHKERRQ(ierr);
1046           for (v = 0; v <= Nv; ++v) {
1047             const PetscInt vertex = closure[v%Nv];
1048 
1049             if (v > 0) {
1050               if (plotEdges) {
1051                 const PetscInt *edge;
1052                 PetscInt        endpoints[2], ne;
1053 
1054                 endpoints[0] = closure[v-1]; endpoints[1] = vertex;
1055                 ierr = DMPlexGetJoin(dm, 2, endpoints, &ne, &edge);CHKERRQ(ierr);
1056                 PetscCheckFalse(ne != 1,PETSC_COMM_SELF, PETSC_ERR_PLIB, "Could not find edge for vertices %D, %D", endpoints[0], endpoints[1]);
1057                 ierr = PetscViewerASCIISynchronizedPrintf(viewer, " -- (%D_%d) -- ", edge[0], rank);CHKERRQ(ierr);
1058                 ierr = DMPlexRestoreJoin(dm, 2, endpoints, &ne, &edge);CHKERRQ(ierr);
1059               } else {
1060                 ierr = PetscViewerASCIISynchronizedPrintf(viewer, " -- ");CHKERRQ(ierr);
1061               }
1062             }
1063             ierr = PetscViewerASCIISynchronizedPrintf(viewer, "(%D_%d)", vertex, rank);CHKERRQ(ierr);
1064           }
1065           ierr = PetscViewerASCIISynchronizedPrintf(viewer, ";\n");CHKERRQ(ierr);
1066           ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
1067         }
1068       }
1069     }
1070     ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
1071     for (c = cStart; c < cEnd; ++c) {
1072       double    ccoords[3] = {0.0, 0.0, 0.0};
1073       PetscBool isLabeled  = PETSC_FALSE;
1074       PetscInt *closure    = NULL;
1075       PetscInt  closureSize, dof, d, n = 0;
1076 
1077       if (wp && !PetscBTLookup(wp,c - pStart)) continue;
1078       ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
1079       ierr = PetscViewerASCIISynchronizedPrintf(viewer, "\\path (");CHKERRQ(ierr);
1080       for (p = 0; p < closureSize*2; p += 2) {
1081         const PetscInt point = closure[p];
1082         PetscInt       off;
1083 
1084         if ((point < vStart) || (point >= vEnd)) continue;
1085         ierr = PetscSectionGetDof(coordSection, point, &dof);CHKERRQ(ierr);
1086         ierr = PetscSectionGetOffset(coordSection, point, &off);CHKERRQ(ierr);
1087         for (d = 0; d < dof; ++d) {
1088           tcoords[d] = (double) (scale*PetscRealPart(coords[off+d]));
1089           tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d];
1090         }
1091         /* Rotate coordinates since PGF makes z point out of the page instead of up */
1092         if (dof == 3) {PetscReal tmp = tcoords[1]; tcoords[1] = tcoords[2]; tcoords[2] = -tmp;}
1093         for (d = 0; d < dof; ++d) {ccoords[d] += tcoords[d];}
1094         ++n;
1095       }
1096       for (d = 0; d < dof; ++d) {ccoords[d] /= n;}
1097       ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
1098       for (d = 0; d < dof; ++d) {
1099         if (d > 0) {ierr = PetscViewerASCIISynchronizedPrintf(viewer, ",");CHKERRQ(ierr);}
1100         ierr = PetscViewerASCIISynchronizedPrintf(viewer, "%g", (double) ccoords[d]);CHKERRQ(ierr);
1101       }
1102       if (drawHasse) color = colors[depth%numColors];
1103       else           color = colors[rank%numColors];
1104       for (l = 0; l < numLabels; ++l) {
1105         PetscInt val;
1106         ierr = DMGetLabelValue(dm, names[l], c, &val);CHKERRQ(ierr);
1107         if (val >= 0) {color = lcolors[l%numLColors]; isLabeled = PETSC_TRUE; break;}
1108       }
1109       if (drawNumbers[dim]) {
1110         ierr = PetscViewerASCIISynchronizedPrintf(viewer, ") node(%D_%d) [draw,shape=circle,color=%s] {%D};\n", c, rank, color, c);CHKERRQ(ierr);
1111       } else if (drawColors[dim]) {
1112         ierr = PetscViewerASCIISynchronizedPrintf(viewer, ") node(%D_%d) [fill,inner sep=%dpt,shape=circle,color=%s] {};\n", c, rank, !isLabeled ? 1 : 2, color);CHKERRQ(ierr);
1113       } else {
1114         ierr = PetscViewerASCIISynchronizedPrintf(viewer, ") node(%D_%d) [] {};\n", c, rank);CHKERRQ(ierr);
1115       }
1116     }
1117     ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
1118     if (drawHasse) {
1119       color = colors[depth%numColors];
1120       ierr = PetscViewerASCIIPrintf(viewer, "%% Cells\n");CHKERRQ(ierr);
1121       ierr = PetscViewerASCIIPrintf(viewer, "\\foreach \\c in {\\cStart,...,\\cEnd}\n");CHKERRQ(ierr);
1122       ierr = PetscViewerASCIIPrintf(viewer, "{\n");CHKERRQ(ierr);
1123       ierr = PetscViewerASCIIPrintf(viewer, "  \\node(\\c_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\cShift+\\c-\\cStart,0) {\\c};\n", rank, color);CHKERRQ(ierr);
1124       ierr = PetscViewerASCIIPrintf(viewer, "}\n");CHKERRQ(ierr);
1125 
1126       color = colors[1%numColors];
1127       ierr = PetscViewerASCIIPrintf(viewer, "%% Edges\n");CHKERRQ(ierr);
1128       ierr = PetscViewerASCIIPrintf(viewer, "\\foreach \\e in {\\eStart,...,\\eEnd}\n");CHKERRQ(ierr);
1129       ierr = PetscViewerASCIIPrintf(viewer, "{\n");CHKERRQ(ierr);
1130       ierr = PetscViewerASCIIPrintf(viewer, "  \\node(\\e_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\eShift+\\e-\\eStart,1) {\\e};\n", rank, color);CHKERRQ(ierr);
1131       ierr = PetscViewerASCIIPrintf(viewer, "}\n");CHKERRQ(ierr);
1132 
1133       color = colors[0%numColors];
1134       ierr = PetscViewerASCIIPrintf(viewer, "%% Vertices\n");CHKERRQ(ierr);
1135       ierr = PetscViewerASCIIPrintf(viewer, "\\foreach \\v in {\\vStart,...,\\vEnd}\n");CHKERRQ(ierr);
1136       ierr = PetscViewerASCIIPrintf(viewer, "{\n");CHKERRQ(ierr);
1137       ierr = PetscViewerASCIIPrintf(viewer, "  \\node(\\v_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\vShift+\\v-\\vStart,2) {\\v};\n", rank, color);CHKERRQ(ierr);
1138       ierr = PetscViewerASCIIPrintf(viewer, "}\n");CHKERRQ(ierr);
1139 
1140       for (p = pStart; p < pEnd; ++p) {
1141         const PetscInt *cone;
1142         PetscInt        coneSize, cp;
1143 
1144         ierr = DMPlexGetCone(dm, p, &cone);CHKERRQ(ierr);
1145         ierr = DMPlexGetConeSize(dm, p, &coneSize);CHKERRQ(ierr);
1146         for (cp = 0; cp < coneSize; ++cp) {
1147           ierr = PetscViewerASCIIPrintf(viewer, "\\draw[->, shorten >=1pt] (%D_%d) -- (%D_%d);\n", cone[cp], rank, p, rank);CHKERRQ(ierr);
1148         }
1149       }
1150     }
1151     ierr = PetscViewerFlush(viewer);CHKERRQ(ierr);
1152     ierr = PetscViewerASCIIPopSynchronized(viewer);CHKERRQ(ierr);
1153     ierr = PetscViewerASCIIPrintf(viewer, "\\end{tikzpicture}\n");CHKERRQ(ierr);
1154     ierr = PetscViewerASCIIPrintf(viewer, "\\end{document}\n", name);CHKERRQ(ierr);
1155     for (l = 0; l < numLabels;  ++l) {ierr = PetscFree(names[l]);CHKERRQ(ierr);}
1156     for (c = 0; c < numColors;  ++c) {ierr = PetscFree(colors[c]);CHKERRQ(ierr);}
1157     for (c = 0; c < numLColors; ++c) {ierr = PetscFree(lcolors[c]);CHKERRQ(ierr);}
1158     ierr = PetscFree3(names, colors, lcolors);CHKERRQ(ierr);
1159     ierr = PetscBTDestroy(&wp);CHKERRQ(ierr);
1160   } else if (format == PETSC_VIEWER_LOAD_BALANCE) {
1161     Vec                    cown,acown;
1162     VecScatter             sct;
1163     ISLocalToGlobalMapping g2l;
1164     IS                     gid,acis;
1165     MPI_Comm               comm,ncomm = MPI_COMM_NULL;
1166     MPI_Group              ggroup,ngroup;
1167     PetscScalar            *array,nid;
1168     const PetscInt         *idxs;
1169     PetscInt               *idxs2,*start,*adjacency,*work;
1170     PetscInt64             lm[3],gm[3];
1171     PetscInt               i,c,cStart,cEnd,cum,numVertices,ect,ectn,cellHeight;
1172     PetscMPIInt            d1,d2,rank;
1173 
1174     ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr);
1175     ierr = MPI_Comm_rank(comm,&rank);CHKERRMPI(ierr);
1176 #if defined(PETSC_HAVE_MPI_PROCESS_SHARED_MEMORY)
1177     ierr = MPI_Comm_split_type(comm,MPI_COMM_TYPE_SHARED,rank,MPI_INFO_NULL,&ncomm);CHKERRMPI(ierr);
1178 #endif
1179     if (ncomm != MPI_COMM_NULL) {
1180       ierr = MPI_Comm_group(comm,&ggroup);CHKERRMPI(ierr);
1181       ierr = MPI_Comm_group(ncomm,&ngroup);CHKERRMPI(ierr);
1182       d1   = 0;
1183       ierr = MPI_Group_translate_ranks(ngroup,1,&d1,ggroup,&d2);CHKERRMPI(ierr);
1184       nid  = d2;
1185       ierr = MPI_Group_free(&ggroup);CHKERRMPI(ierr);
1186       ierr = MPI_Group_free(&ngroup);CHKERRMPI(ierr);
1187       ierr = MPI_Comm_free(&ncomm);CHKERRMPI(ierr);
1188     } else nid = 0.0;
1189 
1190     /* Get connectivity */
1191     ierr = DMPlexGetVTKCellHeight(dm,&cellHeight);CHKERRQ(ierr);
1192     ierr = DMPlexCreatePartitionerGraph(dm,cellHeight,&numVertices,&start,&adjacency,&gid);CHKERRQ(ierr);
1193 
1194     /* filter overlapped local cells */
1195     ierr = DMPlexGetHeightStratum(dm,cellHeight,&cStart,&cEnd);CHKERRQ(ierr);
1196     ierr = ISGetIndices(gid,&idxs);CHKERRQ(ierr);
1197     ierr = ISGetLocalSize(gid,&cum);CHKERRQ(ierr);
1198     ierr = PetscMalloc1(cum,&idxs2);CHKERRQ(ierr);
1199     for (c = cStart, cum = 0; c < cEnd; c++) {
1200       if (idxs[c-cStart] < 0) continue;
1201       idxs2[cum++] = idxs[c-cStart];
1202     }
1203     ierr = ISRestoreIndices(gid,&idxs);CHKERRQ(ierr);
1204     PetscCheckFalse(numVertices != cum,PETSC_COMM_SELF,PETSC_ERR_PLIB,"Unexpected %D != %D",numVertices,cum);
1205     ierr = ISDestroy(&gid);CHKERRQ(ierr);
1206     ierr = ISCreateGeneral(comm,numVertices,idxs2,PETSC_OWN_POINTER,&gid);CHKERRQ(ierr);
1207 
1208     /* support for node-aware cell locality */
1209     ierr = ISCreateGeneral(comm,start[numVertices],adjacency,PETSC_USE_POINTER,&acis);CHKERRQ(ierr);
1210     ierr = VecCreateSeq(PETSC_COMM_SELF,start[numVertices],&acown);CHKERRQ(ierr);
1211     ierr = VecCreateMPI(comm,numVertices,PETSC_DECIDE,&cown);CHKERRQ(ierr);
1212     ierr = VecGetArray(cown,&array);CHKERRQ(ierr);
1213     for (c = 0; c < numVertices; c++) array[c] = nid;
1214     ierr = VecRestoreArray(cown,&array);CHKERRQ(ierr);
1215     ierr = VecScatterCreate(cown,acis,acown,NULL,&sct);CHKERRQ(ierr);
1216     ierr = VecScatterBegin(sct,cown,acown,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
1217     ierr = VecScatterEnd(sct,cown,acown,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
1218     ierr = ISDestroy(&acis);CHKERRQ(ierr);
1219     ierr = VecScatterDestroy(&sct);CHKERRQ(ierr);
1220     ierr = VecDestroy(&cown);CHKERRQ(ierr);
1221 
1222     /* compute edgeCut */
1223     for (c = 0, cum = 0; c < numVertices; c++) cum = PetscMax(cum,start[c+1]-start[c]);
1224     ierr = PetscMalloc1(cum,&work);CHKERRQ(ierr);
1225     ierr = ISLocalToGlobalMappingCreateIS(gid,&g2l);CHKERRQ(ierr);
1226     ierr = ISLocalToGlobalMappingSetType(g2l,ISLOCALTOGLOBALMAPPINGHASH);CHKERRQ(ierr);
1227     ierr = ISDestroy(&gid);CHKERRQ(ierr);
1228     ierr = VecGetArray(acown,&array);CHKERRQ(ierr);
1229     for (c = 0, ect = 0, ectn = 0; c < numVertices; c++) {
1230       PetscInt totl;
1231 
1232       totl = start[c+1]-start[c];
1233       ierr = ISGlobalToLocalMappingApply(g2l,IS_GTOLM_MASK,totl,adjacency+start[c],NULL,work);CHKERRQ(ierr);
1234       for (i = 0; i < totl; i++) {
1235         if (work[i] < 0) {
1236           ect  += 1;
1237           ectn += (array[i + start[c]] != nid) ? 0 : 1;
1238         }
1239       }
1240     }
1241     ierr  = PetscFree(work);CHKERRQ(ierr);
1242     ierr  = VecRestoreArray(acown,&array);CHKERRQ(ierr);
1243     lm[0] = numVertices > 0 ?  numVertices : PETSC_MAX_INT;
1244     lm[1] = -numVertices;
1245     ierr  = MPIU_Allreduce(lm,gm,2,MPIU_INT64,MPI_MIN,comm);CHKERRMPI(ierr);
1246     ierr  = PetscViewerASCIIPrintf(viewer,"  Cell balance: %.2f (max %D, min %D",-((double)gm[1])/((double)gm[0]),-(PetscInt)gm[1],(PetscInt)gm[0]);CHKERRQ(ierr);
1247     lm[0] = ect; /* edgeCut */
1248     lm[1] = ectn; /* node-aware edgeCut */
1249     lm[2] = numVertices > 0 ? 0 : 1; /* empty processes */
1250     ierr  = MPIU_Allreduce(lm,gm,3,MPIU_INT64,MPI_SUM,comm);CHKERRMPI(ierr);
1251     ierr  = PetscViewerASCIIPrintf(viewer,", empty %D)\n",(PetscInt)gm[2]);CHKERRQ(ierr);
1252 #if defined(PETSC_HAVE_MPI_PROCESS_SHARED_MEMORY)
1253     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);
1254 #else
1255     ierr  = PetscViewerASCIIPrintf(viewer,"  Edge Cut: %D (on node %.3f)\n",(PetscInt)(gm[0]/2),0.0);CHKERRQ(ierr);
1256 #endif
1257     ierr  = ISLocalToGlobalMappingDestroy(&g2l);CHKERRQ(ierr);
1258     ierr  = PetscFree(start);CHKERRQ(ierr);
1259     ierr  = PetscFree(adjacency);CHKERRQ(ierr);
1260     ierr  = VecDestroy(&acown);CHKERRQ(ierr);
1261   } else {
1262     const char    *name;
1263     PetscInt      *sizes, *hybsizes, *ghostsizes;
1264     PetscInt       locDepth, depth, cellHeight, dim, d;
1265     PetscInt       pStart, pEnd, p, gcStart, gcEnd, gcNum;
1266     PetscInt       numLabels, l, maxSize = 17;
1267     DMPolytopeType ct0 = DM_POLYTOPE_UNKNOWN;
1268     MPI_Comm       comm;
1269     PetscMPIInt    size, rank;
1270 
1271     ierr = PetscObjectGetComm((PetscObject) dm, &comm);CHKERRQ(ierr);
1272     ierr = MPI_Comm_size(comm, &size);CHKERRMPI(ierr);
1273     ierr = MPI_Comm_rank(comm, &rank);CHKERRMPI(ierr);
1274     ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr);
1275     ierr = DMPlexGetVTKCellHeight(dm, &cellHeight);CHKERRQ(ierr);
1276     ierr = PetscObjectGetName((PetscObject) dm, &name);CHKERRQ(ierr);
1277     if (name) {ierr = PetscViewerASCIIPrintf(viewer, "%s in %D dimension%s:\n", name, dim, dim == 1 ? "" : "s");CHKERRQ(ierr);}
1278     else      {ierr = PetscViewerASCIIPrintf(viewer, "Mesh in %D dimension%s:\n", dim, dim == 1 ? "" : "s");CHKERRQ(ierr);}
1279     if (cellHeight) {ierr = PetscViewerASCIIPrintf(viewer, "  Cells are at height %D\n", cellHeight);CHKERRQ(ierr);}
1280     ierr = DMPlexGetDepth(dm, &locDepth);CHKERRQ(ierr);
1281     ierr = MPIU_Allreduce(&locDepth, &depth, 1, MPIU_INT, MPI_MAX, comm);CHKERRMPI(ierr);
1282     ierr = DMPlexGetGhostCellStratum(dm, &gcStart, &gcEnd);CHKERRQ(ierr);
1283     gcNum = gcEnd - gcStart;
1284     if (size < maxSize) {ierr = PetscCalloc3(size, &sizes, size, &hybsizes, size, &ghostsizes);CHKERRQ(ierr);}
1285     else                {ierr = PetscCalloc3(3,    &sizes, 3,    &hybsizes, 3,    &ghostsizes);CHKERRQ(ierr);}
1286     for (d = 0; d <= depth; d++) {
1287       PetscInt Nc[2] = {0, 0}, ict;
1288 
1289       ierr = DMPlexGetDepthStratum(dm, d, &pStart, &pEnd);CHKERRQ(ierr);
1290       if (pStart < pEnd) {ierr = DMPlexGetCellType(dm, pStart, &ct0);CHKERRQ(ierr);}
1291       ict  = ct0;
1292       ierr = MPI_Bcast(&ict, 1, MPIU_INT, 0, comm);CHKERRMPI(ierr);
1293       ct0  = (DMPolytopeType) ict;
1294       for (p = pStart; p < pEnd; ++p) {
1295         DMPolytopeType ct;
1296 
1297         ierr = DMPlexGetCellType(dm, p, &ct);CHKERRQ(ierr);
1298         if (ct == ct0) ++Nc[0];
1299         else           ++Nc[1];
1300       }
1301       if (size < maxSize) {
1302         ierr = MPI_Gather(&Nc[0], 1, MPIU_INT, sizes,    1, MPIU_INT, 0, comm);CHKERRMPI(ierr);
1303         ierr = MPI_Gather(&Nc[1], 1, MPIU_INT, hybsizes, 1, MPIU_INT, 0, comm);CHKERRMPI(ierr);
1304         if (d == depth) {ierr = MPI_Gather(&gcNum, 1, MPIU_INT, ghostsizes, 1, MPIU_INT, 0, comm);CHKERRMPI(ierr);}
1305         ierr = PetscViewerASCIIPrintf(viewer, "  Number of %D-cells per rank:", (depth == 1) && d ? dim : d);CHKERRQ(ierr);
1306         for (p = 0; p < size; ++p) {
1307           if (rank == 0) {
1308             ierr = PetscViewerASCIIPrintf(viewer, " %D", sizes[p]+hybsizes[p]);CHKERRQ(ierr);
1309             if (hybsizes[p]   > 0) {ierr = PetscViewerASCIIPrintf(viewer, " (%D)", hybsizes[p]);CHKERRQ(ierr);}
1310             if (ghostsizes[p] > 0) {ierr = PetscViewerASCIIPrintf(viewer, " [%D]", ghostsizes[p]);CHKERRQ(ierr);}
1311           }
1312         }
1313       } else {
1314         PetscInt locMinMax[2];
1315 
1316         locMinMax[0] = Nc[0]+Nc[1]; locMinMax[1] = Nc[0]+Nc[1];
1317         ierr = PetscGlobalMinMaxInt(comm, locMinMax, sizes);CHKERRQ(ierr);
1318         locMinMax[0] = Nc[1]; locMinMax[1] = Nc[1];
1319         ierr = PetscGlobalMinMaxInt(comm, locMinMax, hybsizes);CHKERRQ(ierr);
1320         if (d == depth) {
1321           locMinMax[0] = gcNum; locMinMax[1] = gcNum;
1322           ierr = PetscGlobalMinMaxInt(comm, locMinMax, ghostsizes);CHKERRQ(ierr);
1323         }
1324         ierr = PetscViewerASCIIPrintf(viewer, "  Min/Max of %D-cells per rank:", (depth == 1) && d ? dim : d);CHKERRQ(ierr);
1325         ierr = PetscViewerASCIIPrintf(viewer, " %" PetscInt_FMT "/%" PetscInt_FMT, sizes[0], sizes[1]);CHKERRQ(ierr);
1326         if (hybsizes[0]   > 0) {ierr = PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT "/%" PetscInt_FMT ")", hybsizes[0], hybsizes[1]);CHKERRQ(ierr);}
1327         if (ghostsizes[0] > 0) {ierr = PetscViewerASCIIPrintf(viewer, " [%" PetscInt_FMT "/%" PetscInt_FMT "]", ghostsizes[0], ghostsizes[1]);CHKERRQ(ierr);}
1328       }
1329       ierr = PetscViewerASCIIPrintf(viewer, "\n");CHKERRQ(ierr);
1330     }
1331     ierr = PetscFree3(sizes, hybsizes, ghostsizes);CHKERRQ(ierr);
1332     {
1333       const PetscReal      *maxCell;
1334       const PetscReal      *L;
1335       const DMBoundaryType *bd;
1336       PetscBool             per, localized;
1337 
1338       ierr = DMGetPeriodicity(dm, &per, &maxCell, &L, &bd);CHKERRQ(ierr);
1339       ierr = DMGetCoordinatesLocalized(dm, &localized);CHKERRQ(ierr);
1340       if (per) {
1341         ierr = PetscViewerASCIIPrintf(viewer, "Periodic mesh (");CHKERRQ(ierr);
1342         ierr = PetscViewerASCIIUseTabs(viewer, PETSC_FALSE);CHKERRQ(ierr);
1343         for (d = 0; d < dim; ++d) {
1344           if (bd && d > 0) {ierr = PetscViewerASCIIPrintf(viewer, ", ");CHKERRQ(ierr);}
1345           if (bd)    {ierr = PetscViewerASCIIPrintf(viewer, "%s", DMBoundaryTypes[bd[d]]);CHKERRQ(ierr);}
1346         }
1347         ierr = PetscViewerASCIIPrintf(viewer, ") coordinates %s\n", localized ? "localized" : "not localized");CHKERRQ(ierr);
1348         ierr = PetscViewerASCIIUseTabs(viewer, PETSC_TRUE);CHKERRQ(ierr);
1349       }
1350     }
1351     ierr = DMGetNumLabels(dm, &numLabels);CHKERRQ(ierr);
1352     if (numLabels) {ierr = PetscViewerASCIIPrintf(viewer, "Labels:\n");CHKERRQ(ierr);}
1353     for (l = 0; l < numLabels; ++l) {
1354       DMLabel         label;
1355       const char     *name;
1356       IS              valueIS;
1357       const PetscInt *values;
1358       PetscInt        numValues, v;
1359 
1360       ierr = DMGetLabelName(dm, l, &name);CHKERRQ(ierr);
1361       ierr = DMGetLabel(dm, name, &label);CHKERRQ(ierr);
1362       ierr = DMLabelGetNumValues(label, &numValues);CHKERRQ(ierr);
1363       ierr = PetscViewerASCIIPrintf(viewer, "  %s: %D strata with value/size (", name, numValues);CHKERRQ(ierr);
1364       ierr = DMLabelGetValueIS(label, &valueIS);CHKERRQ(ierr);
1365       ierr = ISGetIndices(valueIS, &values);CHKERRQ(ierr);
1366       ierr = PetscViewerASCIIUseTabs(viewer, PETSC_FALSE);CHKERRQ(ierr);
1367       for (v = 0; v < numValues; ++v) {
1368         PetscInt size;
1369 
1370         ierr = DMLabelGetStratumSize(label, values[v], &size);CHKERRQ(ierr);
1371         if (v > 0) {ierr = PetscViewerASCIIPrintf(viewer, ", ");CHKERRQ(ierr);}
1372         ierr = PetscViewerASCIIPrintf(viewer, "%D (%D)", values[v], size);CHKERRQ(ierr);
1373       }
1374       ierr = PetscViewerASCIIPrintf(viewer, ")\n");CHKERRQ(ierr);
1375       ierr = PetscViewerASCIIUseTabs(viewer, PETSC_TRUE);CHKERRQ(ierr);
1376       ierr = ISRestoreIndices(valueIS, &values);CHKERRQ(ierr);
1377       ierr = ISDestroy(&valueIS);CHKERRQ(ierr);
1378     }
1379     {
1380       char    **labelNames;
1381       PetscInt  Nl = numLabels;
1382       PetscBool flg;
1383 
1384       ierr = PetscMalloc1(Nl, &labelNames);CHKERRQ(ierr);
1385       ierr = PetscOptionsGetStringArray(((PetscObject) dm)->options, ((PetscObject) dm)->prefix, "-dm_plex_view_labels", labelNames, &Nl, &flg);CHKERRQ(ierr);
1386       for (l = 0; l < Nl; ++l) {
1387         DMLabel label;
1388 
1389         ierr = DMHasLabel(dm, labelNames[l], &flg);CHKERRQ(ierr);
1390         if (flg) {
1391           ierr = DMGetLabel(dm, labelNames[l], &label);CHKERRQ(ierr);
1392           ierr = DMLabelView(label, viewer);CHKERRQ(ierr);
1393         }
1394         ierr = PetscFree(labelNames[l]);CHKERRQ(ierr);
1395       }
1396       ierr = PetscFree(labelNames);CHKERRQ(ierr);
1397     }
1398     /* If no fields are specified, people do not want to see adjacency */
1399     if (dm->Nf) {
1400       PetscInt f;
1401 
1402       for (f = 0; f < dm->Nf; ++f) {
1403         const char *name;
1404 
1405         ierr = PetscObjectGetName(dm->fields[f].disc, &name);CHKERRQ(ierr);
1406         if (numLabels) {ierr = PetscViewerASCIIPrintf(viewer, "Field %s:\n", name);CHKERRQ(ierr);}
1407         ierr = PetscViewerASCIIPushTab(viewer);CHKERRQ(ierr);
1408         if (dm->fields[f].label) {ierr = DMLabelView(dm->fields[f].label, viewer);CHKERRQ(ierr);}
1409         if (dm->fields[f].adjacency[0]) {
1410           if (dm->fields[f].adjacency[1]) {ierr = PetscViewerASCIIPrintf(viewer, "adjacency FVM++\n");CHKERRQ(ierr);}
1411           else                            {ierr = PetscViewerASCIIPrintf(viewer, "adjacency FVM\n");CHKERRQ(ierr);}
1412         } else {
1413           if (dm->fields[f].adjacency[1]) {ierr = PetscViewerASCIIPrintf(viewer, "adjacency FEM\n");CHKERRQ(ierr);}
1414           else                            {ierr = PetscViewerASCIIPrintf(viewer, "adjacency FUNKY\n");CHKERRQ(ierr);}
1415         }
1416         ierr = PetscViewerASCIIPopTab(viewer);CHKERRQ(ierr);
1417       }
1418     }
1419     ierr = DMGetCoarseDM(dm, &cdm);CHKERRQ(ierr);
1420     if (cdm) {
1421       ierr = PetscViewerASCIIPushTab(viewer);CHKERRQ(ierr);
1422       ierr = DMPlexView_Ascii(cdm, viewer);CHKERRQ(ierr);
1423       ierr = PetscViewerASCIIPopTab(viewer);CHKERRQ(ierr);
1424     }
1425   }
1426   PetscFunctionReturn(0);
1427 }
1428 
1429 static PetscErrorCode DMPlexDrawCell(DM dm, PetscDraw draw, PetscInt cell, const PetscScalar coords[])
1430 {
1431   DMPolytopeType ct;
1432   PetscMPIInt    rank;
1433   PetscInt       cdim;
1434   PetscErrorCode ierr;
1435 
1436   PetscFunctionBegin;
1437   ierr = MPI_Comm_rank(PetscObjectComm((PetscObject) dm), &rank);CHKERRMPI(ierr);
1438   ierr = DMPlexGetCellType(dm, cell, &ct);CHKERRQ(ierr);
1439   ierr = DMGetCoordinateDim(dm, &cdim);CHKERRQ(ierr);
1440   switch (ct) {
1441   case DM_POLYTOPE_SEGMENT:
1442   case DM_POLYTOPE_POINT_PRISM_TENSOR:
1443     switch (cdim) {
1444     case 1:
1445     {
1446       const PetscReal y  = 0.5;  /* TODO Put it in the middle of the viewport */
1447       const PetscReal dy = 0.05; /* TODO Make it a fraction of the total length */
1448 
1449       ierr = PetscDrawLine(draw, PetscRealPart(coords[0]), y,    PetscRealPart(coords[1]), y,    PETSC_DRAW_BLACK);CHKERRQ(ierr);
1450       ierr = PetscDrawLine(draw, PetscRealPart(coords[0]), y+dy, PetscRealPart(coords[0]), y-dy, PETSC_DRAW_BLACK);CHKERRQ(ierr);
1451       ierr = PetscDrawLine(draw, PetscRealPart(coords[1]), y+dy, PetscRealPart(coords[1]), y-dy, PETSC_DRAW_BLACK);CHKERRQ(ierr);
1452     }
1453     break;
1454     case 2:
1455     {
1456       const PetscReal dx = (PetscRealPart(coords[3]) - PetscRealPart(coords[1]));
1457       const PetscReal dy = (PetscRealPart(coords[2]) - PetscRealPart(coords[0]));
1458       const PetscReal l  = 0.1/PetscSqrtReal(dx*dx + dy*dy);
1459 
1460       ierr = PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK);CHKERRQ(ierr);
1461       ierr = PetscDrawLine(draw, PetscRealPart(coords[0])+l*dx, PetscRealPart(coords[1])+l*dy, PetscRealPart(coords[0])-l*dx, PetscRealPart(coords[1])-l*dy, PETSC_DRAW_BLACK);CHKERRQ(ierr);
1462       ierr = PetscDrawLine(draw, PetscRealPart(coords[2])+l*dx, PetscRealPart(coords[3])+l*dy, PetscRealPart(coords[2])-l*dx, PetscRealPart(coords[3])-l*dy, PETSC_DRAW_BLACK);CHKERRQ(ierr);
1463     }
1464     break;
1465     default: SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of dimension %D", cdim);
1466     }
1467     break;
1468   case DM_POLYTOPE_TRIANGLE:
1469     ierr = PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]),
1470                              PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2,
1471                              PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2,
1472                              PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2);CHKERRQ(ierr);
1473     ierr = PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK);CHKERRQ(ierr);
1474     ierr = PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK);CHKERRQ(ierr);
1475     ierr = PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK);CHKERRQ(ierr);
1476     break;
1477   case DM_POLYTOPE_QUADRILATERAL:
1478     ierr = PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]),
1479                               PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2,
1480                               PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2,
1481                               PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2);CHKERRQ(ierr);
1482     ierr = PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[6]), PetscRealPart(coords[7]),
1483                               PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2,
1484                               PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2,
1485                               PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2);CHKERRQ(ierr);
1486     ierr = PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK);CHKERRQ(ierr);
1487     ierr = PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK);CHKERRQ(ierr);
1488     ierr = PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), PETSC_DRAW_BLACK);CHKERRQ(ierr);
1489     ierr = PetscDrawLine(draw, PetscRealPart(coords[6]), PetscRealPart(coords[7]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK);CHKERRQ(ierr);
1490     break;
1491   default: SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of type %s", DMPolytopeTypes[ct]);
1492   }
1493   PetscFunctionReturn(0);
1494 }
1495 
1496 static PetscErrorCode DMPlexDrawCellHighOrder(DM dm, PetscDraw draw, PetscInt cell, const PetscScalar coords[], PetscInt edgeDiv, PetscReal refCoords[], PetscReal edgeCoords[])
1497 {
1498   DMPolytopeType ct;
1499   PetscReal      centroid[2] = {0., 0.};
1500   PetscMPIInt    rank;
1501   PetscInt       fillColor, v, e, d;
1502   PetscErrorCode ierr;
1503 
1504   PetscFunctionBegin;
1505   ierr = MPI_Comm_rank(PetscObjectComm((PetscObject) dm), &rank);CHKERRMPI(ierr);
1506   ierr = DMPlexGetCellType(dm, cell, &ct);CHKERRQ(ierr);
1507   fillColor = PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2;
1508   switch (ct) {
1509   case DM_POLYTOPE_TRIANGLE:
1510     {
1511       PetscReal refVertices[6] = {-1., -1., 1., -1., -1., 1.};
1512 
1513       for (v = 0; v < 3; ++v) {centroid[0] += PetscRealPart(coords[v*2+0])/3.;centroid[1] += PetscRealPart(coords[v*2+1])/3.;}
1514       for (e = 0; e < 3; ++e) {
1515         refCoords[0] = refVertices[e*2+0];
1516         refCoords[1] = refVertices[e*2+1];
1517         for (d = 1; d <= edgeDiv; ++d) {
1518           refCoords[d*2+0] = refCoords[0] + (refVertices[(e+1)%3 * 2 + 0] - refCoords[0])*d/edgeDiv;
1519           refCoords[d*2+1] = refCoords[1] + (refVertices[(e+1)%3 * 2 + 1] - refCoords[1])*d/edgeDiv;
1520         }
1521         ierr = DMPlexReferenceToCoordinates(dm, cell, edgeDiv+1, refCoords, edgeCoords);CHKERRQ(ierr);
1522         for (d = 0; d < edgeDiv; ++d) {
1523           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);
1524           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);
1525         }
1526       }
1527     }
1528     break;
1529   default: SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of type %s", DMPolytopeTypes[ct]);
1530   }
1531   PetscFunctionReturn(0);
1532 }
1533 
1534 static PetscErrorCode DMPlexView_Draw(DM dm, PetscViewer viewer)
1535 {
1536   PetscDraw          draw;
1537   DM                 cdm;
1538   PetscSection       coordSection;
1539   Vec                coordinates;
1540   const PetscScalar *coords;
1541   PetscReal          xyl[2],xyr[2],bound[4] = {PETSC_MAX_REAL, PETSC_MAX_REAL, PETSC_MIN_REAL, PETSC_MIN_REAL};
1542   PetscReal         *refCoords, *edgeCoords;
1543   PetscBool          isnull, drawAffine = PETSC_TRUE;
1544   PetscInt           dim, vStart, vEnd, cStart, cEnd, c, N, edgeDiv = 4;
1545   PetscErrorCode     ierr;
1546 
1547   PetscFunctionBegin;
1548   ierr = DMGetCoordinateDim(dm, &dim);CHKERRQ(ierr);
1549   PetscCheckFalse(dim > 2,PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Cannot draw meshes of dimension %D", dim);
1550   ierr = PetscOptionsGetBool(((PetscObject) dm)->options, ((PetscObject) dm)->prefix, "-dm_view_draw_affine", &drawAffine, NULL);CHKERRQ(ierr);
1551   if (!drawAffine) {ierr = PetscMalloc2((edgeDiv+1)*dim, &refCoords, (edgeDiv+1)*dim, &edgeCoords);CHKERRQ(ierr);}
1552   ierr = DMGetCoordinateDM(dm, &cdm);CHKERRQ(ierr);
1553   ierr = DMGetLocalSection(cdm, &coordSection);CHKERRQ(ierr);
1554   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
1555   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
1556   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
1557 
1558   ierr = PetscViewerDrawGetDraw(viewer, 0, &draw);CHKERRQ(ierr);
1559   ierr = PetscDrawIsNull(draw, &isnull);CHKERRQ(ierr);
1560   if (isnull) PetscFunctionReturn(0);
1561   ierr = PetscDrawSetTitle(draw, "Mesh");CHKERRQ(ierr);
1562 
1563   ierr = VecGetLocalSize(coordinates, &N);CHKERRQ(ierr);
1564   ierr = VecGetArrayRead(coordinates, &coords);CHKERRQ(ierr);
1565   for (c = 0; c < N; c += dim) {
1566     bound[0] = PetscMin(bound[0], PetscRealPart(coords[c]));   bound[2] = PetscMax(bound[2], PetscRealPart(coords[c]));
1567     bound[1] = PetscMin(bound[1], PetscRealPart(coords[c+1])); bound[3] = PetscMax(bound[3], PetscRealPart(coords[c+1]));
1568   }
1569   ierr = VecRestoreArrayRead(coordinates, &coords);CHKERRQ(ierr);
1570   ierr = MPIU_Allreduce(&bound[0],xyl,2,MPIU_REAL,MPIU_MIN,PetscObjectComm((PetscObject)dm));CHKERRMPI(ierr);
1571   ierr = MPIU_Allreduce(&bound[2],xyr,2,MPIU_REAL,MPIU_MAX,PetscObjectComm((PetscObject)dm));CHKERRMPI(ierr);
1572   ierr = PetscDrawSetCoordinates(draw, xyl[0], xyl[1], xyr[0], xyr[1]);CHKERRQ(ierr);
1573   ierr = PetscDrawClear(draw);CHKERRQ(ierr);
1574 
1575   for (c = cStart; c < cEnd; ++c) {
1576     PetscScalar *coords = NULL;
1577     PetscInt     numCoords;
1578 
1579     ierr = DMPlexVecGetClosureAtDepth_Internal(dm, coordSection, coordinates, c, 0, &numCoords, &coords);CHKERRQ(ierr);
1580     if (drawAffine) {
1581       ierr = DMPlexDrawCell(dm, draw, c, coords);CHKERRQ(ierr);
1582     } else {
1583       ierr = DMPlexDrawCellHighOrder(dm, draw, c, coords, edgeDiv, refCoords, edgeCoords);CHKERRQ(ierr);
1584     }
1585     ierr = DMPlexVecRestoreClosure(dm, coordSection, coordinates, c, &numCoords, &coords);CHKERRQ(ierr);
1586   }
1587   if (!drawAffine) {ierr = PetscFree2(refCoords, edgeCoords);CHKERRQ(ierr);}
1588   ierr = PetscDrawFlush(draw);CHKERRQ(ierr);
1589   ierr = PetscDrawPause(draw);CHKERRQ(ierr);
1590   ierr = PetscDrawSave(draw);CHKERRQ(ierr);
1591   PetscFunctionReturn(0);
1592 }
1593 
1594 #if defined(PETSC_HAVE_EXODUSII)
1595 #include <exodusII.h>
1596 #include <petscviewerexodusii.h>
1597 #endif
1598 
1599 PetscErrorCode DMView_Plex(DM dm, PetscViewer viewer)
1600 {
1601   PetscBool      iascii, ishdf5, isvtk, isdraw, flg, isglvis, isexodus;
1602   char           name[PETSC_MAX_PATH_LEN];
1603   PetscErrorCode ierr;
1604 
1605   PetscFunctionBegin;
1606   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1607   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
1608   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERASCII,    &iascii);CHKERRQ(ierr);
1609   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERVTK,      &isvtk);CHKERRQ(ierr);
1610   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5,     &ishdf5);CHKERRQ(ierr);
1611   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERDRAW,     &isdraw);CHKERRQ(ierr);
1612   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERGLVIS,    &isglvis);CHKERRQ(ierr);
1613   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWEREXODUSII, &isexodus);CHKERRQ(ierr);
1614   if (iascii) {
1615     PetscViewerFormat format;
1616     ierr = PetscViewerGetFormat(viewer, &format);CHKERRQ(ierr);
1617     if (format == PETSC_VIEWER_ASCII_GLVIS) {
1618       ierr = DMPlexView_GLVis(dm, viewer);CHKERRQ(ierr);
1619     } else {
1620       ierr = DMPlexView_Ascii(dm, viewer);CHKERRQ(ierr);
1621     }
1622   } else if (ishdf5) {
1623 #if defined(PETSC_HAVE_HDF5)
1624     ierr = DMPlexView_HDF5_Internal(dm, viewer);CHKERRQ(ierr);
1625 #else
1626     SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
1627 #endif
1628   } else if (isvtk) {
1629     ierr = DMPlexVTKWriteAll((PetscObject) dm,viewer);CHKERRQ(ierr);
1630   } else if (isdraw) {
1631     ierr = DMPlexView_Draw(dm, viewer);CHKERRQ(ierr);
1632   } else if (isglvis) {
1633     ierr = DMPlexView_GLVis(dm, viewer);CHKERRQ(ierr);
1634 #if defined(PETSC_HAVE_EXODUSII)
1635   } else if (isexodus) {
1636 /*
1637       exodusII requires that all sets be part of exactly one cell set.
1638       If the dm does not have a "Cell Sets" label defined, we create one
1639       with ID 1, containig all cells.
1640       Note that if the Cell Sets label is defined but does not cover all cells,
1641       we may still have a problem. This should probably be checked here or in the viewer;
1642     */
1643     PetscInt numCS;
1644     ierr = DMGetLabelSize(dm,"Cell Sets",&numCS);CHKERRQ(ierr);
1645     if (!numCS) {
1646       PetscInt cStart, cEnd, c;
1647       ierr = DMCreateLabel(dm, "Cell Sets");CHKERRQ(ierr);
1648       ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
1649       for (c = cStart; c < cEnd; ++c) {ierr = DMSetLabelValue(dm, "Cell Sets", c, 1);CHKERRQ(ierr);}
1650     }
1651     ierr = DMView_PlexExodusII(dm, viewer);CHKERRQ(ierr);
1652 #endif
1653   } else {
1654     SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Viewer type %s not yet supported for DMPlex writing", ((PetscObject)viewer)->type_name);
1655   }
1656   /* Optionally view the partition */
1657   ierr = PetscOptionsHasName(((PetscObject) dm)->options, ((PetscObject) dm)->prefix, "-dm_partition_view", &flg);CHKERRQ(ierr);
1658   if (flg) {
1659     Vec ranks;
1660     ierr = DMPlexCreateRankField(dm, &ranks);CHKERRQ(ierr);
1661     ierr = VecView(ranks, viewer);CHKERRQ(ierr);
1662     ierr = VecDestroy(&ranks);CHKERRQ(ierr);
1663   }
1664   /* Optionally view a label */
1665   ierr = PetscOptionsGetString(((PetscObject) dm)->options, ((PetscObject) dm)->prefix, "-dm_label_view", name, sizeof(name), &flg);CHKERRQ(ierr);
1666   if (flg) {
1667     DMLabel label;
1668     Vec     val;
1669 
1670     ierr = DMGetLabel(dm, name, &label);CHKERRQ(ierr);
1671     PetscCheckFalse(!label,PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "Label %s provided to -dm_label_view does not exist in this DM", name);
1672     ierr = DMPlexCreateLabelField(dm, label, &val);CHKERRQ(ierr);
1673     ierr = VecView(val, viewer);CHKERRQ(ierr);
1674     ierr = VecDestroy(&val);CHKERRQ(ierr);
1675   }
1676   PetscFunctionReturn(0);
1677 }
1678 
1679 /*@
1680   DMPlexTopologyView - Saves a DMPlex topology into a file
1681 
1682   Collective on DM
1683 
1684   Input Parameters:
1685 + dm     - The DM whose topology is to be saved
1686 - viewer - The PetscViewer for saving
1687 
1688   Level: advanced
1689 
1690 .seealso: DMView(), DMPlexCoordinatesView(), DMPlexLabelsView(), DMPlexTopologyLoad()
1691 @*/
1692 PetscErrorCode DMPlexTopologyView(DM dm, PetscViewer viewer)
1693 {
1694   PetscBool      ishdf5;
1695   PetscErrorCode ierr;
1696 
1697   PetscFunctionBegin;
1698   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1699   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
1700   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5);CHKERRQ(ierr);
1701   ierr = PetscLogEventBegin(DMPLEX_TopologyView,viewer,0,0,0);CHKERRQ(ierr);
1702   if (ishdf5) {
1703 #if defined(PETSC_HAVE_HDF5)
1704     PetscViewerFormat format;
1705     ierr = PetscViewerGetFormat(viewer, &format);CHKERRQ(ierr);
1706     if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) {
1707       IS globalPointNumbering;
1708 
1709       ierr = DMPlexCreatePointNumbering(dm, &globalPointNumbering);CHKERRQ(ierr);
1710       ierr = DMPlexTopologyView_HDF5_Internal(dm, globalPointNumbering, viewer);CHKERRQ(ierr);
1711       ierr = ISDestroy(&globalPointNumbering);CHKERRQ(ierr);
1712     } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 output.", PetscViewerFormats[format]);
1713 #else
1714     SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
1715 #endif
1716   }
1717   ierr = PetscLogEventEnd(DMPLEX_TopologyView,viewer,0,0,0);CHKERRQ(ierr);
1718   PetscFunctionReturn(0);
1719 }
1720 
1721 /*@
1722   DMPlexCoordinatesView - Saves DMPlex coordinates into a file
1723 
1724   Collective on DM
1725 
1726   Input Parameters:
1727 + dm     - The DM whose coordinates are to be saved
1728 - viewer - The PetscViewer for saving
1729 
1730   Level: advanced
1731 
1732 .seealso: DMView(), DMPlexTopologyView(), DMPlexLabelsView(), DMPlexCoordinatesLoad()
1733 @*/
1734 PetscErrorCode DMPlexCoordinatesView(DM dm, PetscViewer viewer)
1735 {
1736   PetscBool      ishdf5;
1737   PetscErrorCode ierr;
1738 
1739   PetscFunctionBegin;
1740   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1741   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
1742   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5);CHKERRQ(ierr);
1743   ierr = PetscLogEventBegin(DMPLEX_CoordinatesView,viewer,0,0,0);CHKERRQ(ierr);
1744   if (ishdf5) {
1745 #if defined(PETSC_HAVE_HDF5)
1746     PetscViewerFormat format;
1747     ierr = PetscViewerGetFormat(viewer, &format);CHKERRQ(ierr);
1748     if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) {
1749       ierr = DMPlexCoordinatesView_HDF5_Internal(dm, viewer);CHKERRQ(ierr);
1750     } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]);
1751 #else
1752     SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
1753 #endif
1754   }
1755   ierr = PetscLogEventEnd(DMPLEX_CoordinatesView,viewer,0,0,0);CHKERRQ(ierr);
1756   PetscFunctionReturn(0);
1757 }
1758 
1759 /*@
1760   DMPlexLabelsView - Saves DMPlex labels into a file
1761 
1762   Collective on DM
1763 
1764   Input Parameters:
1765 + dm     - The DM whose labels are to be saved
1766 - viewer - The PetscViewer for saving
1767 
1768   Level: advanced
1769 
1770 .seealso: DMView(), DMPlexTopologyView(), DMPlexCoordinatesView(), DMPlexLabelsLoad()
1771 @*/
1772 PetscErrorCode DMPlexLabelsView(DM dm, PetscViewer viewer)
1773 {
1774   PetscBool      ishdf5;
1775   PetscErrorCode ierr;
1776 
1777   PetscFunctionBegin;
1778   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1779   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
1780   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5);CHKERRQ(ierr);
1781   ierr = PetscLogEventBegin(DMPLEX_LabelsView,viewer,0,0,0);CHKERRQ(ierr);
1782   if (ishdf5) {
1783 #if defined(PETSC_HAVE_HDF5)
1784     IS                globalPointNumbering;
1785     PetscViewerFormat format;
1786 
1787     ierr = PetscViewerGetFormat(viewer, &format);CHKERRQ(ierr);
1788     if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) {
1789       ierr = DMPlexCreatePointNumbering(dm, &globalPointNumbering);CHKERRQ(ierr);
1790       ierr = DMPlexLabelsView_HDF5_Internal(dm, globalPointNumbering, viewer);CHKERRQ(ierr);
1791       ierr = ISDestroy(&globalPointNumbering);CHKERRQ(ierr);
1792     } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]);
1793 #else
1794     SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
1795 #endif
1796   }
1797   ierr = PetscLogEventEnd(DMPLEX_LabelsView,viewer,0,0,0);CHKERRQ(ierr);
1798   PetscFunctionReturn(0);
1799 }
1800 
1801 /*@
1802   DMPlexSectionView - Saves a section associated with a DMPlex
1803 
1804   Collective on DM
1805 
1806   Input Parameters:
1807 + dm         - The DM that contains the topology on which the section to be saved is defined
1808 . viewer     - The PetscViewer for saving
1809 - sectiondm  - The DM that contains the section to be saved
1810 
1811   Level: advanced
1812 
1813   Notes:
1814   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.
1815 
1816   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.
1817 
1818 .seealso: DMView(), DMPlexTopologyView(), DMPlexCoordinatesView(), DMPlexLabelsView(), DMPlexGlobalVectorView(), DMPlexLocalVectorView(), PetscSectionView(), DMPlexSectionLoad()
1819 @*/
1820 PetscErrorCode DMPlexSectionView(DM dm, PetscViewer viewer, DM sectiondm)
1821 {
1822   PetscBool      ishdf5;
1823   PetscErrorCode ierr;
1824 
1825   PetscFunctionBegin;
1826   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1827   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
1828   PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3);
1829   ierr = PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERHDF5,&ishdf5);CHKERRQ(ierr);
1830   ierr = PetscLogEventBegin(DMPLEX_SectionView,viewer,0,0,0);CHKERRQ(ierr);
1831   if (ishdf5) {
1832 #if defined(PETSC_HAVE_HDF5)
1833     ierr = DMPlexSectionView_HDF5_Internal(dm, viewer, sectiondm);CHKERRQ(ierr);
1834 #else
1835     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
1836 #endif
1837   }
1838   ierr = PetscLogEventEnd(DMPLEX_SectionView,viewer,0,0,0);CHKERRQ(ierr);
1839   PetscFunctionReturn(0);
1840 }
1841 
1842 /*@
1843   DMPlexGlobalVectorView - Saves a global vector
1844 
1845   Collective on DM
1846 
1847   Input Parameters:
1848 + dm        - The DM that represents the topology
1849 . viewer    - The PetscViewer to save data with
1850 . sectiondm - The DM that contains the global section on which vec is defined
1851 - vec       - The global vector to be saved
1852 
1853   Level: advanced
1854 
1855   Notes:
1856   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.
1857 
1858   Typical calling sequence
1859 $       DMCreate(PETSC_COMM_WORLD, &dm);
1860 $       DMSetType(dm, DMPLEX);
1861 $       PetscObjectSetName((PetscObject)dm, "topologydm_name");
1862 $       DMClone(dm, &sectiondm);
1863 $       PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name");
1864 $       PetscSectionCreate(PETSC_COMM_WORLD, &section);
1865 $       DMPlexGetChart(sectiondm, &pStart, &pEnd);
1866 $       PetscSectionSetChart(section, pStart, pEnd);
1867 $       PetscSectionSetUp(section);
1868 $       DMSetLocalSection(sectiondm, section);
1869 $       PetscSectionDestroy(&section);
1870 $       DMGetGlobalVector(sectiondm, &vec);
1871 $       PetscObjectSetName((PetscObject)vec, "vec_name");
1872 $       DMPlexTopologyView(dm, viewer);
1873 $       DMPlexSectionView(dm, viewer, sectiondm);
1874 $       DMPlexGlobalVectorView(dm, viewer, sectiondm, vec);
1875 $       DMRestoreGlobalVector(sectiondm, &vec);
1876 $       DMDestroy(&sectiondm);
1877 $       DMDestroy(&dm);
1878 
1879 .seealso: DMPlexTopologyView(), DMPlexSectionView(), DMPlexLocalVectorView(), DMPlexGlobalVectorLoad(), DMPlexLocalVectorLoad()
1880 @*/
1881 PetscErrorCode DMPlexGlobalVectorView(DM dm, PetscViewer viewer, DM sectiondm, Vec vec)
1882 {
1883   PetscBool       ishdf5;
1884   PetscErrorCode  ierr;
1885 
1886   PetscFunctionBegin;
1887   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1888   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
1889   PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3);
1890   PetscValidHeaderSpecific(vec, VEC_CLASSID, 4);
1891   /* Check consistency */
1892   {
1893     PetscSection  section;
1894     PetscBool     includesConstraints;
1895     PetscInt      m, m1;
1896 
1897     ierr = VecGetLocalSize(vec, &m1);CHKERRQ(ierr);
1898     ierr = DMGetGlobalSection(sectiondm, &section);CHKERRQ(ierr);
1899     ierr = PetscSectionGetIncludesConstraints(section, &includesConstraints);CHKERRQ(ierr);
1900     if (includesConstraints) {ierr = PetscSectionGetStorageSize(section, &m);CHKERRQ(ierr);}
1901     else {ierr = PetscSectionGetConstrainedStorageSize(section, &m);CHKERRQ(ierr);}
1902     PetscCheckFalse(m1 != m,PETSC_COMM_SELF, PETSC_ERR_PLIB, "Global vector size (%D) != global section storage size (%D)", m1, m);
1903   }
1904   ierr = PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5);CHKERRQ(ierr);
1905   ierr = PetscLogEventBegin(DMPLEX_GlobalVectorView,viewer,0,0,0);CHKERRQ(ierr);
1906   if (ishdf5) {
1907 #if defined(PETSC_HAVE_HDF5)
1908     ierr = DMPlexGlobalVectorView_HDF5_Internal(dm, viewer, sectiondm, vec);CHKERRQ(ierr);
1909 #else
1910     SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
1911 #endif
1912   }
1913   ierr = PetscLogEventEnd(DMPLEX_GlobalVectorView,viewer,0,0,0);CHKERRQ(ierr);
1914   PetscFunctionReturn(0);
1915 }
1916 
1917 /*@
1918   DMPlexLocalVectorView - Saves a local vector
1919 
1920   Collective on DM
1921 
1922   Input Parameters:
1923 + dm        - The DM that represents the topology
1924 . viewer    - The PetscViewer to save data with
1925 . sectiondm - The DM that contains the local section on which vec is defined; may be the same as dm
1926 - vec       - The local vector to be saved
1927 
1928   Level: advanced
1929 
1930   Notes:
1931   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.
1932 
1933   Typical calling sequence
1934 $       DMCreate(PETSC_COMM_WORLD, &dm);
1935 $       DMSetType(dm, DMPLEX);
1936 $       PetscObjectSetName((PetscObject)dm, "topologydm_name");
1937 $       DMClone(dm, &sectiondm);
1938 $       PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name");
1939 $       PetscSectionCreate(PETSC_COMM_WORLD, &section);
1940 $       DMPlexGetChart(sectiondm, &pStart, &pEnd);
1941 $       PetscSectionSetChart(section, pStart, pEnd);
1942 $       PetscSectionSetUp(section);
1943 $       DMSetLocalSection(sectiondm, section);
1944 $       DMGetLocalVector(sectiondm, &vec);
1945 $       PetscObjectSetName((PetscObject)vec, "vec_name");
1946 $       DMPlexTopologyView(dm, viewer);
1947 $       DMPlexSectionView(dm, viewer, sectiondm);
1948 $       DMPlexLocalVectorView(dm, viewer, sectiondm, vec);
1949 $       DMRestoreLocalVector(sectiondm, &vec);
1950 $       DMDestroy(&sectiondm);
1951 $       DMDestroy(&dm);
1952 
1953 .seealso: DMPlexTopologyView(), DMPlexSectionView(), DMPlexGlobalVectorView(), DMPlexGlobalVectorLoad(), DMPlexLocalVectorLoad()
1954 @*/
1955 PetscErrorCode DMPlexLocalVectorView(DM dm, PetscViewer viewer, DM sectiondm, Vec vec)
1956 {
1957   PetscBool       ishdf5;
1958   PetscErrorCode  ierr;
1959 
1960   PetscFunctionBegin;
1961   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1962   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
1963   PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3);
1964   PetscValidHeaderSpecific(vec, VEC_CLASSID, 4);
1965   /* Check consistency */
1966   {
1967     PetscSection  section;
1968     PetscBool     includesConstraints;
1969     PetscInt      m, m1;
1970 
1971     ierr = VecGetLocalSize(vec, &m1);CHKERRQ(ierr);
1972     ierr = DMGetLocalSection(sectiondm, &section);CHKERRQ(ierr);
1973     ierr = PetscSectionGetIncludesConstraints(section, &includesConstraints);CHKERRQ(ierr);
1974     if (includesConstraints) {ierr = PetscSectionGetStorageSize(section, &m);CHKERRQ(ierr);}
1975     else {ierr = PetscSectionGetConstrainedStorageSize(section, &m);CHKERRQ(ierr);}
1976     PetscCheckFalse(m1 != m,PETSC_COMM_SELF, PETSC_ERR_PLIB, "Local vector size (%D) != local section storage size (%D)", m1, m);
1977   }
1978   ierr = PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5);CHKERRQ(ierr);
1979   ierr = PetscLogEventBegin(DMPLEX_LocalVectorView,viewer,0,0,0);CHKERRQ(ierr);
1980   if (ishdf5) {
1981 #if defined(PETSC_HAVE_HDF5)
1982     ierr = DMPlexLocalVectorView_HDF5_Internal(dm, viewer, sectiondm, vec);CHKERRQ(ierr);
1983 #else
1984     SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
1985 #endif
1986   }
1987   ierr = PetscLogEventEnd(DMPLEX_LocalVectorView,viewer,0,0,0);CHKERRQ(ierr);
1988   PetscFunctionReturn(0);
1989 }
1990 
1991 PetscErrorCode DMLoad_Plex(DM dm, PetscViewer viewer)
1992 {
1993   PetscBool      ishdf5;
1994   PetscErrorCode ierr;
1995 
1996   PetscFunctionBegin;
1997   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1998   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
1999   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5,   &ishdf5);CHKERRQ(ierr);
2000   if (ishdf5) {
2001 #if defined(PETSC_HAVE_HDF5)
2002     PetscViewerFormat format;
2003     ierr = PetscViewerGetFormat(viewer, &format);CHKERRQ(ierr);
2004     if (format == PETSC_VIEWER_HDF5_XDMF || format == PETSC_VIEWER_HDF5_VIZ) {
2005       ierr = DMPlexLoad_HDF5_Xdmf_Internal(dm, viewer);CHKERRQ(ierr);
2006     } else if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) {
2007       ierr = DMPlexLoad_HDF5_Internal(dm, viewer);CHKERRQ(ierr);
2008     } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]);
2009     PetscFunctionReturn(0);
2010 #else
2011     SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
2012 #endif
2013   } else SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Viewer type %s not yet supported for DMPlex loading", ((PetscObject)viewer)->type_name);
2014 }
2015 
2016 /*@
2017   DMPlexTopologyLoad - Loads a topology into a DMPlex
2018 
2019   Collective on DM
2020 
2021   Input Parameters:
2022 + dm     - The DM into which the topology is loaded
2023 - viewer - The PetscViewer for the saved topology
2024 
2025   Output Parameters:
2026 . 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
2027 
2028   Level: advanced
2029 
2030 .seealso: DMLoad(), DMPlexCoordinatesLoad(), DMPlexLabelsLoad(), DMView(), PetscViewerHDF5Open(), PetscViewerPushFormat()
2031 @*/
2032 PetscErrorCode DMPlexTopologyLoad(DM dm, PetscViewer viewer, PetscSF *globalToLocalPointSF)
2033 {
2034   PetscBool      ishdf5;
2035   PetscErrorCode ierr;
2036 
2037   PetscFunctionBegin;
2038   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2039   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
2040   if (globalToLocalPointSF) PetscValidPointer(globalToLocalPointSF, 3);
2041   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5);CHKERRQ(ierr);
2042   ierr = PetscLogEventBegin(DMPLEX_TopologyLoad,viewer,0,0,0);CHKERRQ(ierr);
2043   if (ishdf5) {
2044 #if defined(PETSC_HAVE_HDF5)
2045     PetscViewerFormat format;
2046     ierr = PetscViewerGetFormat(viewer, &format);CHKERRQ(ierr);
2047     if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) {
2048       ierr = DMPlexTopologyLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF);CHKERRQ(ierr);
2049     } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]);
2050 #else
2051     SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
2052 #endif
2053   }
2054   ierr = PetscLogEventEnd(DMPLEX_TopologyLoad,viewer,0,0,0);CHKERRQ(ierr);
2055   PetscFunctionReturn(0);
2056 }
2057 
2058 /*@
2059   DMPlexCoordinatesLoad - Loads coordinates into a DMPlex
2060 
2061   Collective on DM
2062 
2063   Input Parameters:
2064 + dm     - The DM into which the coordinates are loaded
2065 . viewer - The PetscViewer for the saved coordinates
2066 - globalToLocalPointSF - The SF returned by DMPlexTopologyLoad() when loading dm from viewer
2067 
2068   Level: advanced
2069 
2070 .seealso: DMLoad(), DMPlexTopologyLoad(), DMPlexLabelsLoad(), DMView(), PetscViewerHDF5Open(), PetscViewerPushFormat()
2071 @*/
2072 PetscErrorCode DMPlexCoordinatesLoad(DM dm, PetscViewer viewer, PetscSF globalToLocalPointSF)
2073 {
2074   PetscBool      ishdf5;
2075   PetscErrorCode ierr;
2076 
2077   PetscFunctionBegin;
2078   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2079   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
2080   PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 3);
2081   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5);CHKERRQ(ierr);
2082   ierr = PetscLogEventBegin(DMPLEX_CoordinatesLoad,viewer,0,0,0);CHKERRQ(ierr);
2083   if (ishdf5) {
2084 #if defined(PETSC_HAVE_HDF5)
2085     PetscViewerFormat format;
2086     ierr = PetscViewerGetFormat(viewer, &format);CHKERRQ(ierr);
2087     if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) {
2088       ierr = DMPlexCoordinatesLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF);CHKERRQ(ierr);
2089     } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]);
2090 #else
2091     SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
2092 #endif
2093   }
2094   ierr = PetscLogEventEnd(DMPLEX_CoordinatesLoad,viewer,0,0,0);CHKERRQ(ierr);
2095   PetscFunctionReturn(0);
2096 }
2097 
2098 /*@
2099   DMPlexLabelsLoad - Loads labels into a DMPlex
2100 
2101   Collective on DM
2102 
2103   Input Parameters:
2104 + dm     - The DM into which the labels are loaded
2105 . viewer - The PetscViewer for the saved labels
2106 - globalToLocalPointSF - The SF returned by DMPlexTopologyLoad() when loading dm from viewer
2107 
2108   Level: advanced
2109 
2110   Notes:
2111   The PetscSF argument must not be NULL if the DM is distributed, otherwise an error occurs.
2112 
2113 .seealso: DMLoad(), DMPlexTopologyLoad(), DMPlexCoordinatesLoad(), DMView(), PetscViewerHDF5Open(), PetscViewerPushFormat()
2114 @*/
2115 PetscErrorCode DMPlexLabelsLoad(DM dm, PetscViewer viewer, PetscSF globalToLocalPointSF)
2116 {
2117   PetscBool      ishdf5;
2118   PetscErrorCode ierr;
2119 
2120   PetscFunctionBegin;
2121   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2122   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
2123   if (globalToLocalPointSF) PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 3);
2124   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5);CHKERRQ(ierr);
2125   ierr = PetscLogEventBegin(DMPLEX_LabelsLoad,viewer,0,0,0);CHKERRQ(ierr);
2126   if (ishdf5) {
2127 #if defined(PETSC_HAVE_HDF5)
2128     PetscViewerFormat format;
2129 
2130     ierr = PetscViewerGetFormat(viewer, &format);CHKERRQ(ierr);
2131     if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) {
2132       ierr = DMPlexLabelsLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF);CHKERRQ(ierr);
2133     } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]);
2134 #else
2135     SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
2136 #endif
2137   }
2138   ierr = PetscLogEventEnd(DMPLEX_LabelsLoad,viewer,0,0,0);CHKERRQ(ierr);
2139   PetscFunctionReturn(0);
2140 }
2141 
2142 /*@
2143   DMPlexSectionLoad - Loads section into a DMPlex
2144 
2145   Collective on DM
2146 
2147   Input Parameters:
2148 + dm          - The DM that represents the topology
2149 . viewer      - The PetscViewer that represents the on-disk section (sectionA)
2150 . sectiondm   - The DM into which the on-disk section (sectionA) is migrated
2151 - globalToLocalPointSF - The SF returned by DMPlexTopologyLoad() when loading dm from viewer
2152 
2153   Output Parameters
2154 + 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)
2155 - 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)
2156 
2157   Level: advanced
2158 
2159   Notes:
2160   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.
2161 
2162   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.
2163 
2164   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.
2165 
2166   Example using 2 processes:
2167 $  NX (number of points on dm): 4
2168 $  sectionA                   : the on-disk section
2169 $  vecA                       : a vector associated with sectionA
2170 $  sectionB                   : sectiondm's local section constructed in this function
2171 $  vecB (local)               : a vector associated with sectiondm's local section
2172 $  vecB (global)              : a vector associated with sectiondm's global section
2173 $
2174 $                                     rank 0    rank 1
2175 $  vecA (global)                  : [.0 .4 .1 | .2 .3]        <- to be loaded in DMPlexGlobalVectorLoad() or DMPlexLocalVectorLoad()
2176 $  sectionA->atlasOff             :       0 2 | 1             <- loaded in PetscSectionLoad()
2177 $  sectionA->atlasDof             :       1 3 | 1             <- loaded in PetscSectionLoad()
2178 $  sectionA's global point numbers:       0 2 | 3             <- loaded in DMPlexSectionLoad()
2179 $  [0, NX)                        :       0 1 | 2 3           <- conceptual partition used in globalToLocalPointSF
2180 $  sectionB's global point numbers:     0 1 3 | 3 2           <- associated with [0, NX) by globalToLocalPointSF
2181 $  sectionB->atlasDof             :     1 0 1 | 1 3
2182 $  sectionB->atlasOff (no perm)   :     0 1 1 | 0 1
2183 $  vecB (local)                   :   [.0 .4] | [.4 .1 .2 .3] <- to be constructed by calling DMPlexLocalVectorLoad() with localDofSF
2184 $  vecB (global)                  :    [.0 .4 | .1 .2 .3]     <- to be constructed by calling DMPlexGlobalVectorLoad() with globalDofSF
2185 $
2186 $  where "|" represents a partition of loaded data, and global point 3 is assumed to be owned by rank 0.
2187 
2188 .seealso: DMLoad(), DMPlexTopologyLoad(), DMPlexCoordinatesLoad(), DMPlexLabelsLoad(), DMPlexGlobalVectorLoad(), DMPlexLocalVectorLoad(), PetscSectionLoad(), DMPlexSectionView()
2189 @*/
2190 PetscErrorCode DMPlexSectionLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF globalToLocalPointSF, PetscSF *globalDofSF, PetscSF *localDofSF)
2191 {
2192   PetscBool      ishdf5;
2193   PetscErrorCode ierr;
2194 
2195   PetscFunctionBegin;
2196   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2197   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
2198   PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3);
2199   PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 4);
2200   if (globalDofSF) PetscValidPointer(globalDofSF, 5);
2201   if (localDofSF) PetscValidPointer(localDofSF, 6);
2202   ierr = PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERHDF5,&ishdf5);CHKERRQ(ierr);
2203   ierr = PetscLogEventBegin(DMPLEX_SectionLoad,viewer,0,0,0);CHKERRQ(ierr);
2204   if (ishdf5) {
2205 #if defined(PETSC_HAVE_HDF5)
2206     ierr = DMPlexSectionLoad_HDF5_Internal(dm, viewer, sectiondm, globalToLocalPointSF, globalDofSF, localDofSF);CHKERRQ(ierr);
2207 #else
2208     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
2209 #endif
2210   }
2211   ierr = PetscLogEventEnd(DMPLEX_SectionLoad,viewer,0,0,0);CHKERRQ(ierr);
2212   PetscFunctionReturn(0);
2213 }
2214 
2215 /*@
2216   DMPlexGlobalVectorLoad - Loads on-disk vector data into a global vector
2217 
2218   Collective on DM
2219 
2220   Input Parameters:
2221 + dm        - The DM that represents the topology
2222 . viewer    - The PetscViewer that represents the on-disk vector data
2223 . sectiondm - The DM that contains the global section on which vec is defined
2224 . sf        - The SF that migrates the on-disk vector data into vec
2225 - vec       - The global vector to set values of
2226 
2227   Level: advanced
2228 
2229   Notes:
2230   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.
2231 
2232   Typical calling sequence
2233 $       DMCreate(PETSC_COMM_WORLD, &dm);
2234 $       DMSetType(dm, DMPLEX);
2235 $       PetscObjectSetName((PetscObject)dm, "topologydm_name");
2236 $       DMPlexTopologyLoad(dm, viewer, &sfX);
2237 $       DMClone(dm, &sectiondm);
2238 $       PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name");
2239 $       DMPlexSectionLoad(dm, viewer, sectiondm, sfX, &gsf, NULL);
2240 $       DMGetGlobalVector(sectiondm, &vec);
2241 $       PetscObjectSetName((PetscObject)vec, "vec_name");
2242 $       DMPlexGlobalVectorLoad(dm, viewer, sectiondm, gsf, vec);
2243 $       DMRestoreGlobalVector(sectiondm, &vec);
2244 $       PetscSFDestroy(&gsf);
2245 $       PetscSFDestroy(&sfX);
2246 $       DMDestroy(&sectiondm);
2247 $       DMDestroy(&dm);
2248 
2249 .seealso: DMPlexTopologyLoad(), DMPlexSectionLoad(), DMPlexLocalVectorLoad(), DMPlexGlobalVectorView(), DMPlexLocalVectorView()
2250 @*/
2251 PetscErrorCode DMPlexGlobalVectorLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF sf, Vec vec)
2252 {
2253   PetscBool       ishdf5;
2254   PetscErrorCode  ierr;
2255 
2256   PetscFunctionBegin;
2257   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2258   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
2259   PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3);
2260   PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 4);
2261   PetscValidHeaderSpecific(vec, VEC_CLASSID, 5);
2262   /* Check consistency */
2263   {
2264     PetscSection  section;
2265     PetscBool     includesConstraints;
2266     PetscInt      m, m1;
2267 
2268     ierr = VecGetLocalSize(vec, &m1);CHKERRQ(ierr);
2269     ierr = DMGetGlobalSection(sectiondm, &section);CHKERRQ(ierr);
2270     ierr = PetscSectionGetIncludesConstraints(section, &includesConstraints);CHKERRQ(ierr);
2271     if (includesConstraints) {ierr = PetscSectionGetStorageSize(section, &m);CHKERRQ(ierr);}
2272     else {ierr = PetscSectionGetConstrainedStorageSize(section, &m);CHKERRQ(ierr);}
2273     PetscCheckFalse(m1 != m,PETSC_COMM_SELF, PETSC_ERR_PLIB, "Global vector size (%D) != global section storage size (%D)", m1, m);
2274   }
2275   ierr = PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERHDF5,&ishdf5);CHKERRQ(ierr);
2276   ierr = PetscLogEventBegin(DMPLEX_GlobalVectorLoad,viewer,0,0,0);CHKERRQ(ierr);
2277   if (ishdf5) {
2278 #if defined(PETSC_HAVE_HDF5)
2279     ierr = DMPlexVecLoad_HDF5_Internal(dm, viewer, sectiondm, sf, vec);CHKERRQ(ierr);
2280 #else
2281     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
2282 #endif
2283   }
2284   ierr = PetscLogEventEnd(DMPLEX_GlobalVectorLoad,viewer,0,0,0);CHKERRQ(ierr);
2285   PetscFunctionReturn(0);
2286 }
2287 
2288 /*@
2289   DMPlexLocalVectorLoad - Loads on-disk vector data into a local vector
2290 
2291   Collective on DM
2292 
2293   Input Parameters:
2294 + dm        - The DM that represents the topology
2295 . viewer    - The PetscViewer that represents the on-disk vector data
2296 . sectiondm - The DM that contains the local section on which vec is defined
2297 . sf        - The SF that migrates the on-disk vector data into vec
2298 - vec       - The local vector to set values of
2299 
2300   Level: advanced
2301 
2302   Notes:
2303   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.
2304 
2305   Typical calling sequence
2306 $       DMCreate(PETSC_COMM_WORLD, &dm);
2307 $       DMSetType(dm, DMPLEX);
2308 $       PetscObjectSetName((PetscObject)dm, "topologydm_name");
2309 $       DMPlexTopologyLoad(dm, viewer, &sfX);
2310 $       DMClone(dm, &sectiondm);
2311 $       PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name");
2312 $       DMPlexSectionLoad(dm, viewer, sectiondm, sfX, NULL, &lsf);
2313 $       DMGetLocalVector(sectiondm, &vec);
2314 $       PetscObjectSetName((PetscObject)vec, "vec_name");
2315 $       DMPlexLocalVectorLoad(dm, viewer, sectiondm, lsf, vec);
2316 $       DMRestoreLocalVector(sectiondm, &vec);
2317 $       PetscSFDestroy(&lsf);
2318 $       PetscSFDestroy(&sfX);
2319 $       DMDestroy(&sectiondm);
2320 $       DMDestroy(&dm);
2321 
2322 .seealso: DMPlexTopologyLoad(), DMPlexSectionLoad(), DMPlexGlobalVectorLoad(), DMPlexGlobalVectorView(), DMPlexLocalVectorView()
2323 @*/
2324 PetscErrorCode DMPlexLocalVectorLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF sf, Vec vec)
2325 {
2326   PetscBool       ishdf5;
2327   PetscErrorCode  ierr;
2328 
2329   PetscFunctionBegin;
2330   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2331   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
2332   PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3);
2333   PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 4);
2334   PetscValidHeaderSpecific(vec, VEC_CLASSID, 5);
2335   /* Check consistency */
2336   {
2337     PetscSection  section;
2338     PetscBool     includesConstraints;
2339     PetscInt      m, m1;
2340 
2341     ierr = VecGetLocalSize(vec, &m1);CHKERRQ(ierr);
2342     ierr = DMGetLocalSection(sectiondm, &section);CHKERRQ(ierr);
2343     ierr = PetscSectionGetIncludesConstraints(section, &includesConstraints);CHKERRQ(ierr);
2344     if (includesConstraints) {ierr = PetscSectionGetStorageSize(section, &m);CHKERRQ(ierr);}
2345     else {ierr = PetscSectionGetConstrainedStorageSize(section, &m);CHKERRQ(ierr);}
2346     PetscCheckFalse(m1 != m,PETSC_COMM_SELF, PETSC_ERR_PLIB, "Local vector size (%D) != local section storage size (%D)", m1, m);
2347   }
2348   ierr = PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERHDF5,&ishdf5);CHKERRQ(ierr);
2349   ierr = PetscLogEventBegin(DMPLEX_LocalVectorLoad,viewer,0,0,0);CHKERRQ(ierr);
2350   if (ishdf5) {
2351 #if defined(PETSC_HAVE_HDF5)
2352     ierr = DMPlexVecLoad_HDF5_Internal(dm, viewer, sectiondm, sf, vec);CHKERRQ(ierr);
2353 #else
2354     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5");
2355 #endif
2356   }
2357   ierr = PetscLogEventEnd(DMPLEX_LocalVectorLoad,viewer,0,0,0);CHKERRQ(ierr);
2358   PetscFunctionReturn(0);
2359 }
2360 
2361 PetscErrorCode DMDestroy_Plex(DM dm)
2362 {
2363   DM_Plex       *mesh = (DM_Plex*) dm->data;
2364   PetscErrorCode ierr;
2365 
2366   PetscFunctionBegin;
2367   ierr = PetscObjectComposeFunction((PetscObject)dm,"DMSetUpGLVisViewer_C",NULL);CHKERRQ(ierr);
2368   ierr = PetscObjectComposeFunction((PetscObject)dm,"DMPlexInsertBoundaryValues_C", NULL);CHKERRQ(ierr);
2369   ierr = PetscObjectComposeFunction((PetscObject)dm,"DMCreateNeumannOverlap_C", NULL);CHKERRQ(ierr);
2370   ierr = PetscObjectComposeFunction((PetscObject)dm,"DMInterpolateSolution_C", NULL);CHKERRQ(ierr);
2371   if (--mesh->refct > 0) PetscFunctionReturn(0);
2372   ierr = PetscSectionDestroy(&mesh->coneSection);CHKERRQ(ierr);
2373   ierr = PetscFree(mesh->cones);CHKERRQ(ierr);
2374   ierr = PetscFree(mesh->coneOrientations);CHKERRQ(ierr);
2375   ierr = PetscSectionDestroy(&mesh->supportSection);CHKERRQ(ierr);
2376   ierr = PetscSectionDestroy(&mesh->subdomainSection);CHKERRQ(ierr);
2377   ierr = PetscFree(mesh->supports);CHKERRQ(ierr);
2378   ierr = PetscFree(mesh->facesTmp);CHKERRQ(ierr);
2379   ierr = PetscFree(mesh->tetgenOpts);CHKERRQ(ierr);
2380   ierr = PetscFree(mesh->triangleOpts);CHKERRQ(ierr);
2381   ierr = PetscFree(mesh->transformType);CHKERRQ(ierr);
2382   ierr = PetscPartitionerDestroy(&mesh->partitioner);CHKERRQ(ierr);
2383   ierr = DMLabelDestroy(&mesh->subpointMap);CHKERRQ(ierr);
2384   ierr = ISDestroy(&mesh->subpointIS);CHKERRQ(ierr);
2385   ierr = ISDestroy(&mesh->globalVertexNumbers);CHKERRQ(ierr);
2386   ierr = ISDestroy(&mesh->globalCellNumbers);CHKERRQ(ierr);
2387   ierr = PetscSectionDestroy(&mesh->anchorSection);CHKERRQ(ierr);
2388   ierr = ISDestroy(&mesh->anchorIS);CHKERRQ(ierr);
2389   ierr = PetscSectionDestroy(&mesh->parentSection);CHKERRQ(ierr);
2390   ierr = PetscFree(mesh->parents);CHKERRQ(ierr);
2391   ierr = PetscFree(mesh->childIDs);CHKERRQ(ierr);
2392   ierr = PetscSectionDestroy(&mesh->childSection);CHKERRQ(ierr);
2393   ierr = PetscFree(mesh->children);CHKERRQ(ierr);
2394   ierr = DMDestroy(&mesh->referenceTree);CHKERRQ(ierr);
2395   ierr = PetscGridHashDestroy(&mesh->lbox);CHKERRQ(ierr);
2396   ierr = PetscFree(mesh->neighbors);CHKERRQ(ierr);
2397   if (mesh->metricCtx) { ierr = PetscFree(mesh->metricCtx);CHKERRQ(ierr); }
2398   /* This was originally freed in DMDestroy(), but that prevents reference counting of backend objects */
2399   ierr = PetscFree(mesh);CHKERRQ(ierr);
2400   PetscFunctionReturn(0);
2401 }
2402 
2403 PetscErrorCode DMCreateMatrix_Plex(DM dm, Mat *J)
2404 {
2405   PetscSection           sectionGlobal;
2406   PetscInt               bs = -1, mbs;
2407   PetscInt               localSize;
2408   PetscBool              isShell, isBlock, isSeqBlock, isMPIBlock, isSymBlock, isSymSeqBlock, isSymMPIBlock, isMatIS;
2409   PetscErrorCode         ierr;
2410   MatType                mtype;
2411   ISLocalToGlobalMapping ltog;
2412 
2413   PetscFunctionBegin;
2414   ierr = MatInitializePackage();CHKERRQ(ierr);
2415   mtype = dm->mattype;
2416   ierr = DMGetGlobalSection(dm, &sectionGlobal);CHKERRQ(ierr);
2417   /* ierr = PetscSectionGetStorageSize(sectionGlobal, &localSize);CHKERRQ(ierr); */
2418   ierr = PetscSectionGetConstrainedStorageSize(sectionGlobal, &localSize);CHKERRQ(ierr);
2419   ierr = MatCreate(PetscObjectComm((PetscObject)dm), J);CHKERRQ(ierr);
2420   ierr = MatSetSizes(*J, localSize, localSize, PETSC_DETERMINE, PETSC_DETERMINE);CHKERRQ(ierr);
2421   ierr = MatSetType(*J, mtype);CHKERRQ(ierr);
2422   ierr = MatSetFromOptions(*J);CHKERRQ(ierr);
2423   ierr = MatGetBlockSize(*J, &mbs);CHKERRQ(ierr);
2424   if (mbs > 1) bs = mbs;
2425   ierr = PetscStrcmp(mtype, MATSHELL, &isShell);CHKERRQ(ierr);
2426   ierr = PetscStrcmp(mtype, MATBAIJ, &isBlock);CHKERRQ(ierr);
2427   ierr = PetscStrcmp(mtype, MATSEQBAIJ, &isSeqBlock);CHKERRQ(ierr);
2428   ierr = PetscStrcmp(mtype, MATMPIBAIJ, &isMPIBlock);CHKERRQ(ierr);
2429   ierr = PetscStrcmp(mtype, MATSBAIJ, &isSymBlock);CHKERRQ(ierr);
2430   ierr = PetscStrcmp(mtype, MATSEQSBAIJ, &isSymSeqBlock);CHKERRQ(ierr);
2431   ierr = PetscStrcmp(mtype, MATMPISBAIJ, &isSymMPIBlock);CHKERRQ(ierr);
2432   ierr = PetscStrcmp(mtype, MATIS, &isMatIS);CHKERRQ(ierr);
2433   if (!isShell) {
2434     PetscBool fillMatrix = (PetscBool)(!dm->prealloc_only && !isMatIS);
2435     PetscInt  *dnz, *onz, *dnzu, *onzu, bsLocal[2], bsMinMax[2];
2436     PetscInt  pStart, pEnd, p, dof, cdof;
2437 
2438     ierr = DMGetLocalToGlobalMapping(dm,&ltog);CHKERRQ(ierr);
2439     ierr = PetscSectionGetChart(sectionGlobal, &pStart, &pEnd);CHKERRQ(ierr);
2440     for (p = pStart; p < pEnd; ++p) {
2441       PetscInt bdof;
2442 
2443       ierr = PetscSectionGetDof(sectionGlobal, p, &dof);CHKERRQ(ierr);
2444       ierr = PetscSectionGetConstraintDof(sectionGlobal, p, &cdof);CHKERRQ(ierr);
2445       dof  = dof < 0 ? -(dof+1) : dof;
2446       bdof = cdof && (dof-cdof) ? 1 : dof;
2447       if (dof) {
2448         if (bs < 0)          {bs = bdof;}
2449         else if (bs != bdof) {bs = 1; break;}
2450       }
2451     }
2452     /* Must have same blocksize on all procs (some might have no points) */
2453     bsLocal[0] = bs < 0 ? PETSC_MAX_INT : bs;
2454     bsLocal[1] = bs;
2455     ierr = PetscGlobalMinMaxInt(PetscObjectComm((PetscObject) dm), bsLocal, bsMinMax);CHKERRQ(ierr);
2456     if (bsMinMax[0] != bsMinMax[1]) bs = 1;
2457     else bs = bsMinMax[0];
2458     bs = PetscMax(1,bs);
2459     ierr = MatSetLocalToGlobalMapping(*J,ltog,ltog);CHKERRQ(ierr);
2460     ierr = PetscCalloc4(localSize/bs, &dnz, localSize/bs, &onz, localSize/bs, &dnzu, localSize/bs, &onzu);CHKERRQ(ierr);
2461     ierr = DMPlexPreallocateOperator(dm, bs, dnz, onz, dnzu, onzu, *J, fillMatrix);CHKERRQ(ierr);
2462     ierr = PetscFree4(dnz, onz, dnzu, onzu);CHKERRQ(ierr);
2463   }
2464   ierr = MatSetDM(*J, dm);CHKERRQ(ierr);
2465   PetscFunctionReturn(0);
2466 }
2467 
2468 /*@
2469   DMPlexGetSubdomainSection - Returns the section associated with the subdomain
2470 
2471   Not collective
2472 
2473   Input Parameter:
2474 . mesh - The DMPlex
2475 
2476   Output Parameters:
2477 . subsection - The subdomain section
2478 
2479   Level: developer
2480 
2481 .seealso:
2482 @*/
2483 PetscErrorCode DMPlexGetSubdomainSection(DM dm, PetscSection *subsection)
2484 {
2485   DM_Plex       *mesh = (DM_Plex*) dm->data;
2486   PetscErrorCode ierr;
2487 
2488   PetscFunctionBegin;
2489   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2490   if (!mesh->subdomainSection) {
2491     PetscSection section;
2492     PetscSF      sf;
2493 
2494     ierr = PetscSFCreate(PETSC_COMM_SELF,&sf);CHKERRQ(ierr);
2495     ierr = DMGetLocalSection(dm,&section);CHKERRQ(ierr);
2496     ierr = PetscSectionCreateGlobalSection(section,sf,PETSC_FALSE,PETSC_TRUE,&mesh->subdomainSection);CHKERRQ(ierr);
2497     ierr = PetscSFDestroy(&sf);CHKERRQ(ierr);
2498   }
2499   *subsection = mesh->subdomainSection;
2500   PetscFunctionReturn(0);
2501 }
2502 
2503 /*@
2504   DMPlexGetChart - Return the interval for all mesh points [pStart, pEnd)
2505 
2506   Not collective
2507 
2508   Input Parameter:
2509 . mesh - The DMPlex
2510 
2511   Output Parameters:
2512 + pStart - The first mesh point
2513 - pEnd   - The upper bound for mesh points
2514 
2515   Level: beginner
2516 
2517 .seealso: DMPlexCreate(), DMPlexSetChart()
2518 @*/
2519 PetscErrorCode DMPlexGetChart(DM dm, PetscInt *pStart, PetscInt *pEnd)
2520 {
2521   DM_Plex       *mesh = (DM_Plex*) dm->data;
2522   PetscErrorCode ierr;
2523 
2524   PetscFunctionBegin;
2525   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2526   ierr = PetscSectionGetChart(mesh->coneSection, pStart, pEnd);CHKERRQ(ierr);
2527   PetscFunctionReturn(0);
2528 }
2529 
2530 /*@
2531   DMPlexSetChart - Set the interval for all mesh points [pStart, pEnd)
2532 
2533   Not collective
2534 
2535   Input Parameters:
2536 + mesh - The DMPlex
2537 . pStart - The first mesh point
2538 - pEnd   - The upper bound for mesh points
2539 
2540   Output Parameters:
2541 
2542   Level: beginner
2543 
2544 .seealso: DMPlexCreate(), DMPlexGetChart()
2545 @*/
2546 PetscErrorCode DMPlexSetChart(DM dm, PetscInt pStart, PetscInt pEnd)
2547 {
2548   DM_Plex       *mesh = (DM_Plex*) dm->data;
2549   PetscErrorCode ierr;
2550 
2551   PetscFunctionBegin;
2552   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2553   ierr = PetscSectionSetChart(mesh->coneSection, pStart, pEnd);CHKERRQ(ierr);
2554   ierr = PetscSectionSetChart(mesh->supportSection, pStart, pEnd);CHKERRQ(ierr);
2555   PetscFunctionReturn(0);
2556 }
2557 
2558 /*@
2559   DMPlexGetConeSize - Return the number of in-edges for this point in the DAG
2560 
2561   Not collective
2562 
2563   Input Parameters:
2564 + mesh - The DMPlex
2565 - p - The point, which must lie in the chart set with DMPlexSetChart()
2566 
2567   Output Parameter:
2568 . size - The cone size for point p
2569 
2570   Level: beginner
2571 
2572 .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexSetChart()
2573 @*/
2574 PetscErrorCode DMPlexGetConeSize(DM dm, PetscInt p, PetscInt *size)
2575 {
2576   DM_Plex       *mesh = (DM_Plex*) dm->data;
2577   PetscErrorCode ierr;
2578 
2579   PetscFunctionBegin;
2580   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2581   PetscValidPointer(size, 3);
2582   ierr = PetscSectionGetDof(mesh->coneSection, p, size);CHKERRQ(ierr);
2583   PetscFunctionReturn(0);
2584 }
2585 
2586 /*@
2587   DMPlexSetConeSize - Set the number of in-edges for this point in the DAG
2588 
2589   Not collective
2590 
2591   Input Parameters:
2592 + mesh - The DMPlex
2593 . p - The point, which must lie in the chart set with DMPlexSetChart()
2594 - size - The cone size for point p
2595 
2596   Output Parameter:
2597 
2598   Note:
2599   This should be called after DMPlexSetChart().
2600 
2601   Level: beginner
2602 
2603 .seealso: DMPlexCreate(), DMPlexGetConeSize(), DMPlexSetChart()
2604 @*/
2605 PetscErrorCode DMPlexSetConeSize(DM dm, PetscInt p, PetscInt size)
2606 {
2607   DM_Plex       *mesh = (DM_Plex*) dm->data;
2608   PetscErrorCode ierr;
2609 
2610   PetscFunctionBegin;
2611   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2612   ierr = PetscSectionSetDof(mesh->coneSection, p, size);CHKERRQ(ierr);
2613 
2614   mesh->maxConeSize = PetscMax(mesh->maxConeSize, size);
2615   PetscFunctionReturn(0);
2616 }
2617 
2618 /*@
2619   DMPlexAddConeSize - Add the given number of in-edges to this point in the DAG
2620 
2621   Not collective
2622 
2623   Input Parameters:
2624 + mesh - The DMPlex
2625 . p - The point, which must lie in the chart set with DMPlexSetChart()
2626 - size - The additional cone size for point p
2627 
2628   Output Parameter:
2629 
2630   Note:
2631   This should be called after DMPlexSetChart().
2632 
2633   Level: beginner
2634 
2635 .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexGetConeSize(), DMPlexSetChart()
2636 @*/
2637 PetscErrorCode DMPlexAddConeSize(DM dm, PetscInt p, PetscInt size)
2638 {
2639   DM_Plex       *mesh = (DM_Plex*) dm->data;
2640   PetscInt       csize;
2641   PetscErrorCode ierr;
2642 
2643   PetscFunctionBegin;
2644   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2645   ierr = PetscSectionAddDof(mesh->coneSection, p, size);CHKERRQ(ierr);
2646   ierr = PetscSectionGetDof(mesh->coneSection, p, &csize);CHKERRQ(ierr);
2647 
2648   mesh->maxConeSize = PetscMax(mesh->maxConeSize, csize);
2649   PetscFunctionReturn(0);
2650 }
2651 
2652 /*@C
2653   DMPlexGetCone - Return the points on the in-edges for this point in the DAG
2654 
2655   Not collective
2656 
2657   Input Parameters:
2658 + dm - The DMPlex
2659 - p - The point, which must lie in the chart set with DMPlexSetChart()
2660 
2661   Output Parameter:
2662 . cone - An array of points which are on the in-edges for point p
2663 
2664   Level: beginner
2665 
2666   Fortran Notes:
2667   Since it returns an array, this routine is only available in Fortran 90, and you must
2668   include petsc.h90 in your code.
2669   You must also call DMPlexRestoreCone() after you finish using the returned array.
2670   DMPlexRestoreCone() is not needed/available in C.
2671 
2672 .seealso: DMPlexGetConeSize(), DMPlexSetCone(), DMPlexGetConeTuple(), DMPlexSetChart()
2673 @*/
2674 PetscErrorCode DMPlexGetCone(DM dm, PetscInt p, const PetscInt *cone[])
2675 {
2676   DM_Plex       *mesh = (DM_Plex*) dm->data;
2677   PetscInt       off;
2678   PetscErrorCode ierr;
2679 
2680   PetscFunctionBegin;
2681   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2682   PetscValidPointer(cone, 3);
2683   ierr  = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
2684   *cone = &mesh->cones[off];
2685   PetscFunctionReturn(0);
2686 }
2687 
2688 /*@C
2689   DMPlexGetConeTuple - Return the points on the in-edges of several points in the DAG
2690 
2691   Not collective
2692 
2693   Input Parameters:
2694 + dm - The DMPlex
2695 - p - The IS of points, which must lie in the chart set with DMPlexSetChart()
2696 
2697   Output Parameters:
2698 + pConesSection - PetscSection describing the layout of pCones
2699 - pCones - An array of points which are on the in-edges for the point set p
2700 
2701   Level: intermediate
2702 
2703 .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexGetConeRecursive(), DMPlexSetChart()
2704 @*/
2705 PetscErrorCode DMPlexGetConeTuple(DM dm, IS p, PetscSection *pConesSection, IS *pCones)
2706 {
2707   PetscSection        cs, newcs;
2708   PetscInt            *cones;
2709   PetscInt            *newarr=NULL;
2710   PetscInt            n;
2711   PetscErrorCode      ierr;
2712 
2713   PetscFunctionBegin;
2714   ierr = DMPlexGetCones(dm, &cones);CHKERRQ(ierr);
2715   ierr = DMPlexGetConeSection(dm, &cs);CHKERRQ(ierr);
2716   ierr = PetscSectionExtractDofsFromArray(cs, MPIU_INT, cones, p, &newcs, pCones ? ((void**)&newarr) : NULL);CHKERRQ(ierr);
2717   if (pConesSection) *pConesSection = newcs;
2718   if (pCones) {
2719     ierr = PetscSectionGetStorageSize(newcs, &n);CHKERRQ(ierr);
2720     ierr = ISCreateGeneral(PetscObjectComm((PetscObject)p), n, newarr, PETSC_OWN_POINTER, pCones);CHKERRQ(ierr);
2721   }
2722   PetscFunctionReturn(0);
2723 }
2724 
2725 /*@
2726   DMPlexGetConeRecursiveVertices - Expand each given point into its cone points and do that recursively until we end up just with vertices.
2727 
2728   Not collective
2729 
2730   Input Parameters:
2731 + dm - The DMPlex
2732 - points - The IS of points, which must lie in the chart set with DMPlexSetChart()
2733 
2734   Output Parameter:
2735 . expandedPoints - An array of vertices recursively expanded from input points
2736 
2737   Level: advanced
2738 
2739   Notes:
2740   Like DMPlexGetConeRecursive but returns only the 0-depth IS (i.e. vertices only) and no sections.
2741   There is no corresponding Restore function, just call ISDestroy() on the returned IS to deallocate.
2742 
2743 .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexGetConeTuple(), DMPlexGetConeRecursive(), DMPlexRestoreConeRecursive(), DMPlexGetDepth()
2744 @*/
2745 PetscErrorCode DMPlexGetConeRecursiveVertices(DM dm, IS points, IS *expandedPoints)
2746 {
2747   IS                  *expandedPointsAll;
2748   PetscInt            depth;
2749   PetscErrorCode      ierr;
2750 
2751   PetscFunctionBegin;
2752   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2753   PetscValidHeaderSpecific(points, IS_CLASSID, 2);
2754   PetscValidPointer(expandedPoints, 3);
2755   ierr = DMPlexGetConeRecursive(dm, points, &depth, &expandedPointsAll, NULL);CHKERRQ(ierr);
2756   *expandedPoints = expandedPointsAll[0];
2757   ierr = PetscObjectReference((PetscObject)expandedPointsAll[0]);CHKERRQ(ierr);
2758   ierr = DMPlexRestoreConeRecursive(dm, points, &depth, &expandedPointsAll, NULL);CHKERRQ(ierr);
2759   PetscFunctionReturn(0);
2760 }
2761 
2762 /*@
2763   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).
2764 
2765   Not collective
2766 
2767   Input Parameters:
2768 + dm - The DMPlex
2769 - points - The IS of points, which must lie in the chart set with DMPlexSetChart()
2770 
2771   Output Parameters:
2772 + depth - (optional) Size of the output arrays, equal to DMPlex depth, returned by DMPlexGetDepth()
2773 . expandedPoints - (optional) An array of index sets with recursively expanded cones
2774 - sections - (optional) An array of sections which describe mappings from points to their cone points
2775 
2776   Level: advanced
2777 
2778   Notes:
2779   Like DMPlexGetConeTuple() but recursive.
2780 
2781   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.
2782   For example, for d=0 it contains only vertices, for d=1 it can contain vertices and edges, etc.
2783 
2784   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:
2785   (1) DAG points in expandedPoints[d+1] with depth d+1 to their cone points in expandedPoints[d];
2786   (2) DAG points in expandedPoints[d+1] with depth in [0,d] to the same points in expandedPoints[d].
2787 
2788 .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexGetConeTuple(), DMPlexRestoreConeRecursive(), DMPlexGetConeRecursiveVertices(), DMPlexGetDepth()
2789 @*/
2790 PetscErrorCode DMPlexGetConeRecursive(DM dm, IS points, PetscInt *depth, IS *expandedPoints[], PetscSection *sections[])
2791 {
2792   const PetscInt      *arr0=NULL, *cone=NULL;
2793   PetscInt            *arr=NULL, *newarr=NULL;
2794   PetscInt            d, depth_, i, n, newn, cn, co, start, end;
2795   IS                  *expandedPoints_;
2796   PetscSection        *sections_;
2797   PetscErrorCode      ierr;
2798 
2799   PetscFunctionBegin;
2800   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2801   PetscValidHeaderSpecific(points, IS_CLASSID, 2);
2802   if (depth) PetscValidIntPointer(depth, 3);
2803   if (expandedPoints) PetscValidPointer(expandedPoints, 4);
2804   if (sections) PetscValidPointer(sections, 5);
2805   ierr = ISGetLocalSize(points, &n);CHKERRQ(ierr);
2806   ierr = ISGetIndices(points, &arr0);CHKERRQ(ierr);
2807   ierr = DMPlexGetDepth(dm, &depth_);CHKERRQ(ierr);
2808   ierr = PetscCalloc1(depth_, &expandedPoints_);CHKERRQ(ierr);
2809   ierr = PetscCalloc1(depth_, &sections_);CHKERRQ(ierr);
2810   arr = (PetscInt*) arr0; /* this is ok because first generation of arr is not modified */
2811   for (d=depth_-1; d>=0; d--) {
2812     ierr = PetscSectionCreate(PETSC_COMM_SELF, &sections_[d]);CHKERRQ(ierr);
2813     ierr = PetscSectionSetChart(sections_[d], 0, n);CHKERRQ(ierr);
2814     for (i=0; i<n; i++) {
2815       ierr = DMPlexGetDepthStratum(dm, d+1, &start, &end);CHKERRQ(ierr);
2816       if (arr[i] >= start && arr[i] < end) {
2817         ierr = DMPlexGetConeSize(dm, arr[i], &cn);CHKERRQ(ierr);
2818         ierr = PetscSectionSetDof(sections_[d], i, cn);CHKERRQ(ierr);
2819       } else {
2820         ierr = PetscSectionSetDof(sections_[d], i, 1);CHKERRQ(ierr);
2821       }
2822     }
2823     ierr = PetscSectionSetUp(sections_[d]);CHKERRQ(ierr);
2824     ierr = PetscSectionGetStorageSize(sections_[d], &newn);CHKERRQ(ierr);
2825     ierr = PetscMalloc1(newn, &newarr);CHKERRQ(ierr);
2826     for (i=0; i<n; i++) {
2827       ierr = PetscSectionGetDof(sections_[d], i, &cn);CHKERRQ(ierr);
2828       ierr = PetscSectionGetOffset(sections_[d], i, &co);CHKERRQ(ierr);
2829       if (cn > 1) {
2830         ierr = DMPlexGetCone(dm, arr[i], &cone);CHKERRQ(ierr);
2831         ierr = PetscMemcpy(&newarr[co], cone, cn*sizeof(PetscInt));CHKERRQ(ierr);
2832       } else {
2833         newarr[co] = arr[i];
2834       }
2835     }
2836     ierr = ISCreateGeneral(PETSC_COMM_SELF, newn, newarr, PETSC_OWN_POINTER, &expandedPoints_[d]);CHKERRQ(ierr);
2837     arr = newarr;
2838     n = newn;
2839   }
2840   ierr = ISRestoreIndices(points, &arr0);CHKERRQ(ierr);
2841   *depth = depth_;
2842   if (expandedPoints) *expandedPoints = expandedPoints_;
2843   else {
2844     for (d=0; d<depth_; d++) {ierr = ISDestroy(&expandedPoints_[d]);CHKERRQ(ierr);}
2845     ierr = PetscFree(expandedPoints_);CHKERRQ(ierr);
2846   }
2847   if (sections) *sections = sections_;
2848   else {
2849     for (d=0; d<depth_; d++) {ierr = PetscSectionDestroy(&sections_[d]);CHKERRQ(ierr);}
2850     ierr = PetscFree(sections_);CHKERRQ(ierr);
2851   }
2852   PetscFunctionReturn(0);
2853 }
2854 
2855 /*@
2856   DMPlexRestoreConeRecursive - Deallocates arrays created by DMPlexGetConeRecursive
2857 
2858   Not collective
2859 
2860   Input Parameters:
2861 + dm - The DMPlex
2862 - points - The IS of points, which must lie in the chart set with DMPlexSetChart()
2863 
2864   Output Parameters:
2865 + depth - (optional) Size of the output arrays, equal to DMPlex depth, returned by DMPlexGetDepth()
2866 . expandedPoints - (optional) An array of recursively expanded cones
2867 - sections - (optional) An array of sections which describe mappings from points to their cone points
2868 
2869   Level: advanced
2870 
2871   Notes:
2872   See DMPlexGetConeRecursive() for details.
2873 
2874 .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexGetConeTuple(), DMPlexGetConeRecursive(), DMPlexGetConeRecursiveVertices(), DMPlexGetDepth()
2875 @*/
2876 PetscErrorCode DMPlexRestoreConeRecursive(DM dm, IS points, PetscInt *depth, IS *expandedPoints[], PetscSection *sections[])
2877 {
2878   PetscInt            d, depth_;
2879   PetscErrorCode      ierr;
2880 
2881   PetscFunctionBegin;
2882   ierr = DMPlexGetDepth(dm, &depth_);CHKERRQ(ierr);
2883   PetscCheckFalse(depth && *depth != depth_,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "depth changed since last call to DMPlexGetConeRecursive");
2884   if (depth) *depth = 0;
2885   if (expandedPoints) {
2886     for (d=0; d<depth_; d++) {ierr = ISDestroy(&((*expandedPoints)[d]));CHKERRQ(ierr);}
2887     ierr = PetscFree(*expandedPoints);CHKERRQ(ierr);
2888   }
2889   if (sections)  {
2890     for (d=0; d<depth_; d++) {ierr = PetscSectionDestroy(&((*sections)[d]));CHKERRQ(ierr);}
2891     ierr = PetscFree(*sections);CHKERRQ(ierr);
2892   }
2893   PetscFunctionReturn(0);
2894 }
2895 
2896 /*@
2897   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
2898 
2899   Not collective
2900 
2901   Input Parameters:
2902 + mesh - The DMPlex
2903 . p - The point, which must lie in the chart set with DMPlexSetChart()
2904 - cone - An array of points which are on the in-edges for point p
2905 
2906   Output Parameter:
2907 
2908   Note:
2909   This should be called after all calls to DMPlexSetConeSize() and DMSetUp().
2910 
2911   Level: beginner
2912 
2913 .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexSetChart(), DMPlexSetConeSize(), DMSetUp(), DMPlexSetSupport(), DMPlexSetSupportSize()
2914 @*/
2915 PetscErrorCode DMPlexSetCone(DM dm, PetscInt p, const PetscInt cone[])
2916 {
2917   DM_Plex       *mesh = (DM_Plex*) dm->data;
2918   PetscInt       pStart, pEnd;
2919   PetscInt       dof, off, c;
2920   PetscErrorCode ierr;
2921 
2922   PetscFunctionBegin;
2923   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2924   ierr = PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);CHKERRQ(ierr);
2925   ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
2926   if (dof) PetscValidPointer(cone, 3);
2927   ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
2928   PetscCheckFalse((p < pStart) || (p >= pEnd),PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %D is not in the valid range [%D, %D)", p, pStart, pEnd);
2929   for (c = 0; c < dof; ++c) {
2930     PetscCheckFalse((cone[c] < pStart) || (cone[c] >= pEnd),PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cone point %D is not in the valid range [%D, %D)", cone[c], pStart, pEnd);
2931     mesh->cones[off+c] = cone[c];
2932   }
2933   PetscFunctionReturn(0);
2934 }
2935 
2936 /*@C
2937   DMPlexGetConeOrientation - Return the orientations on the in-edges for this point in the DAG
2938 
2939   Not collective
2940 
2941   Input Parameters:
2942 + mesh - The DMPlex
2943 - p - The point, which must lie in the chart set with DMPlexSetChart()
2944 
2945   Output Parameter:
2946 . coneOrientation - An array of orientations which are on the in-edges for point p. An orientation is an
2947                     integer giving the prescription for cone traversal.
2948 
2949   Level: beginner
2950 
2951   Notes:
2952   The number indexes the symmetry transformations for the cell type (see manual). Orientation 0 is always
2953   the identity transformation. Negative orientation indicates reflection so that -(o+1) is the reflection
2954   of o, however it is not necessarily the inverse. To get the inverse, use DMPolytopeTypeComposeOrientationInv()
2955   with the identity.
2956 
2957   Fortran Notes:
2958   Since it returns an array, this routine is only available in Fortran 90, and you must
2959   include petsc.h90 in your code.
2960   You must also call DMPlexRestoreConeOrientation() after you finish using the returned array.
2961   DMPlexRestoreConeOrientation() is not needed/available in C.
2962 
2963 .seealso: DMPolytopeTypeComposeOrientation(), DMPolytopeTypeComposeOrientationInv(), DMPlexCreate(), DMPlexGetCone(), DMPlexSetCone(), DMPlexSetChart()
2964 @*/
2965 PetscErrorCode DMPlexGetConeOrientation(DM dm, PetscInt p, const PetscInt *coneOrientation[])
2966 {
2967   DM_Plex       *mesh = (DM_Plex*) dm->data;
2968   PetscInt       off;
2969   PetscErrorCode ierr;
2970 
2971   PetscFunctionBegin;
2972   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2973   if (PetscDefined(USE_DEBUG)) {
2974     PetscInt dof;
2975     ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
2976     if (dof) PetscValidPointer(coneOrientation, 3);
2977   }
2978   ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
2979 
2980   *coneOrientation = &mesh->coneOrientations[off];
2981   PetscFunctionReturn(0);
2982 }
2983 
2984 /*@
2985   DMPlexSetConeOrientation - Set the orientations on the in-edges for this point in the DAG
2986 
2987   Not collective
2988 
2989   Input Parameters:
2990 + mesh - The DMPlex
2991 . p - The point, which must lie in the chart set with DMPlexSetChart()
2992 - coneOrientation - An array of orientations
2993   Output Parameter:
2994 
2995   Notes:
2996   This should be called after all calls to DMPlexSetConeSize() and DMSetUp().
2997 
2998   The meaning of coneOrientation is detailed in DMPlexGetConeOrientation().
2999 
3000   Level: beginner
3001 
3002 .seealso: DMPlexCreate(), DMPlexGetConeOrientation(), DMPlexSetCone(), DMPlexSetChart(), DMPlexSetConeSize(), DMSetUp()
3003 @*/
3004 PetscErrorCode DMPlexSetConeOrientation(DM dm, PetscInt p, const PetscInt coneOrientation[])
3005 {
3006   DM_Plex       *mesh = (DM_Plex*) dm->data;
3007   PetscInt       pStart, pEnd;
3008   PetscInt       dof, off, c;
3009   PetscErrorCode ierr;
3010 
3011   PetscFunctionBegin;
3012   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3013   ierr = PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);CHKERRQ(ierr);
3014   ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
3015   if (dof) PetscValidPointer(coneOrientation, 3);
3016   ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
3017   PetscCheckFalse((p < pStart) || (p >= pEnd),PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %D is not in the valid range [%D, %D)", p, pStart, pEnd);
3018   for (c = 0; c < dof; ++c) {
3019     PetscInt cdof, o = coneOrientation[c];
3020 
3021     ierr = PetscSectionGetDof(mesh->coneSection, mesh->cones[off+c], &cdof);CHKERRQ(ierr);
3022     PetscCheckFalse(o && ((o < -(cdof+1)) || (o >= cdof)),PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cone orientation %D is not in the valid range [%D. %D)", o, -(cdof+1), cdof);
3023     mesh->coneOrientations[off+c] = o;
3024   }
3025   PetscFunctionReturn(0);
3026 }
3027 
3028 /*@
3029   DMPlexInsertCone - Insert a point into the in-edges for the point p in the DAG
3030 
3031   Not collective
3032 
3033   Input Parameters:
3034 + mesh - The DMPlex
3035 . p - The point, which must lie in the chart set with DMPlexSetChart()
3036 . conePos - The local index in the cone where the point should be put
3037 - conePoint - The mesh point to insert
3038 
3039   Level: beginner
3040 
3041 .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexSetChart(), DMPlexSetConeSize(), DMSetUp()
3042 @*/
3043 PetscErrorCode DMPlexInsertCone(DM dm, PetscInt p, PetscInt conePos, PetscInt conePoint)
3044 {
3045   DM_Plex       *mesh = (DM_Plex*) dm->data;
3046   PetscInt       pStart, pEnd;
3047   PetscInt       dof, off;
3048   PetscErrorCode ierr;
3049 
3050   PetscFunctionBegin;
3051   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3052   ierr = PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);CHKERRQ(ierr);
3053   PetscCheckFalse((p < pStart) || (p >= pEnd),PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %D is not in the valid range [%D, %D)", p, pStart, pEnd);
3054   PetscCheckFalse((conePoint < pStart) || (conePoint >= pEnd),PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cone point %D is not in the valid range [%D, %D)", conePoint, pStart, pEnd);
3055   ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
3056   ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
3057   PetscCheckFalse((conePos < 0) || (conePos >= dof),PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cone position %D of point %D is not in the valid range [0, %D)", conePos, p, dof);
3058   mesh->cones[off+conePos] = conePoint;
3059   PetscFunctionReturn(0);
3060 }
3061 
3062 /*@
3063   DMPlexInsertConeOrientation - Insert a point orientation for the in-edge for the point p in the DAG
3064 
3065   Not collective
3066 
3067   Input Parameters:
3068 + mesh - The DMPlex
3069 . p - The point, which must lie in the chart set with DMPlexSetChart()
3070 . conePos - The local index in the cone where the point should be put
3071 - coneOrientation - The point orientation to insert
3072 
3073   Level: beginner
3074 
3075   Notes:
3076   The meaning of coneOrientation values is detailed in DMPlexGetConeOrientation().
3077 
3078 .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexSetChart(), DMPlexSetConeSize(), DMSetUp()
3079 @*/
3080 PetscErrorCode DMPlexInsertConeOrientation(DM dm, PetscInt p, PetscInt conePos, PetscInt coneOrientation)
3081 {
3082   DM_Plex       *mesh = (DM_Plex*) dm->data;
3083   PetscInt       pStart, pEnd;
3084   PetscInt       dof, off;
3085   PetscErrorCode ierr;
3086 
3087   PetscFunctionBegin;
3088   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3089   ierr = PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);CHKERRQ(ierr);
3090   PetscCheckFalse((p < pStart) || (p >= pEnd),PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %D is not in the valid range [%D, %D)", p, pStart, pEnd);
3091   ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
3092   ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
3093   PetscCheckFalse((conePos < 0) || (conePos >= dof),PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cone position %D of point %D is not in the valid range [0, %D)", conePos, p, dof);
3094   mesh->coneOrientations[off+conePos] = coneOrientation;
3095   PetscFunctionReturn(0);
3096 }
3097 
3098 /*@
3099   DMPlexGetSupportSize - Return the number of out-edges for this point in the DAG
3100 
3101   Not collective
3102 
3103   Input Parameters:
3104 + mesh - The DMPlex
3105 - p - The point, which must lie in the chart set with DMPlexSetChart()
3106 
3107   Output Parameter:
3108 . size - The support size for point p
3109 
3110   Level: beginner
3111 
3112 .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexSetChart(), DMPlexGetConeSize()
3113 @*/
3114 PetscErrorCode DMPlexGetSupportSize(DM dm, PetscInt p, PetscInt *size)
3115 {
3116   DM_Plex       *mesh = (DM_Plex*) dm->data;
3117   PetscErrorCode ierr;
3118 
3119   PetscFunctionBegin;
3120   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3121   PetscValidPointer(size, 3);
3122   ierr = PetscSectionGetDof(mesh->supportSection, p, size);CHKERRQ(ierr);
3123   PetscFunctionReturn(0);
3124 }
3125 
3126 /*@
3127   DMPlexSetSupportSize - Set the number of out-edges for this point in the DAG
3128 
3129   Not collective
3130 
3131   Input Parameters:
3132 + mesh - The DMPlex
3133 . p - The point, which must lie in the chart set with DMPlexSetChart()
3134 - size - The support size for point p
3135 
3136   Output Parameter:
3137 
3138   Note:
3139   This should be called after DMPlexSetChart().
3140 
3141   Level: beginner
3142 
3143 .seealso: DMPlexCreate(), DMPlexGetSupportSize(), DMPlexSetChart()
3144 @*/
3145 PetscErrorCode DMPlexSetSupportSize(DM dm, PetscInt p, PetscInt size)
3146 {
3147   DM_Plex       *mesh = (DM_Plex*) dm->data;
3148   PetscErrorCode ierr;
3149 
3150   PetscFunctionBegin;
3151   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3152   ierr = PetscSectionSetDof(mesh->supportSection, p, size);CHKERRQ(ierr);
3153 
3154   mesh->maxSupportSize = PetscMax(mesh->maxSupportSize, size);
3155   PetscFunctionReturn(0);
3156 }
3157 
3158 /*@C
3159   DMPlexGetSupport - Return the points on the out-edges for this point in the DAG
3160 
3161   Not collective
3162 
3163   Input Parameters:
3164 + mesh - The DMPlex
3165 - p - The point, which must lie in the chart set with DMPlexSetChart()
3166 
3167   Output Parameter:
3168 . support - An array of points which are on the out-edges for point p
3169 
3170   Level: beginner
3171 
3172   Fortran Notes:
3173   Since it returns an array, this routine is only available in Fortran 90, and you must
3174   include petsc.h90 in your code.
3175   You must also call DMPlexRestoreSupport() after you finish using the returned array.
3176   DMPlexRestoreSupport() is not needed/available in C.
3177 
3178 .seealso: DMPlexGetSupportSize(), DMPlexSetSupport(), DMPlexGetCone(), DMPlexSetChart()
3179 @*/
3180 PetscErrorCode DMPlexGetSupport(DM dm, PetscInt p, const PetscInt *support[])
3181 {
3182   DM_Plex       *mesh = (DM_Plex*) dm->data;
3183   PetscInt       off;
3184   PetscErrorCode ierr;
3185 
3186   PetscFunctionBegin;
3187   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3188   PetscValidPointer(support, 3);
3189   ierr     = PetscSectionGetOffset(mesh->supportSection, p, &off);CHKERRQ(ierr);
3190   *support = &mesh->supports[off];
3191   PetscFunctionReturn(0);
3192 }
3193 
3194 /*@
3195   DMPlexSetSupport - Set the points on the out-edges for this point in the DAG, that is the list of points that this point covers
3196 
3197   Not collective
3198 
3199   Input Parameters:
3200 + mesh - The DMPlex
3201 . p - The point, which must lie in the chart set with DMPlexSetChart()
3202 - support - An array of points which are on the out-edges for point p
3203 
3204   Output Parameter:
3205 
3206   Note:
3207   This should be called after all calls to DMPlexSetSupportSize() and DMSetUp().
3208 
3209   Level: beginner
3210 
3211 .seealso: DMPlexSetCone(), DMPlexSetConeSize(), DMPlexCreate(), DMPlexGetSupport(), DMPlexSetChart(), DMPlexSetSupportSize(), DMSetUp()
3212 @*/
3213 PetscErrorCode DMPlexSetSupport(DM dm, PetscInt p, const PetscInt support[])
3214 {
3215   DM_Plex       *mesh = (DM_Plex*) dm->data;
3216   PetscInt       pStart, pEnd;
3217   PetscInt       dof, off, c;
3218   PetscErrorCode ierr;
3219 
3220   PetscFunctionBegin;
3221   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3222   ierr = PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd);CHKERRQ(ierr);
3223   ierr = PetscSectionGetDof(mesh->supportSection, p, &dof);CHKERRQ(ierr);
3224   if (dof) PetscValidPointer(support, 3);
3225   ierr = PetscSectionGetOffset(mesh->supportSection, p, &off);CHKERRQ(ierr);
3226   PetscCheckFalse((p < pStart) || (p >= pEnd),PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %D is not in the valid range [%D, %D)", p, pStart, pEnd);
3227   for (c = 0; c < dof; ++c) {
3228     PetscCheckFalse((support[c] < pStart) || (support[c] >= pEnd),PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Support point %D is not in the valid range [%D, %D)", support[c], pStart, pEnd);
3229     mesh->supports[off+c] = support[c];
3230   }
3231   PetscFunctionReturn(0);
3232 }
3233 
3234 /*@
3235   DMPlexInsertSupport - Insert a point into the out-edges for the point p in the DAG
3236 
3237   Not collective
3238 
3239   Input Parameters:
3240 + mesh - The DMPlex
3241 . p - The point, which must lie in the chart set with DMPlexSetChart()
3242 . supportPos - The local index in the cone where the point should be put
3243 - supportPoint - The mesh point to insert
3244 
3245   Level: beginner
3246 
3247 .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexSetChart(), DMPlexSetConeSize(), DMSetUp()
3248 @*/
3249 PetscErrorCode DMPlexInsertSupport(DM dm, PetscInt p, PetscInt supportPos, PetscInt supportPoint)
3250 {
3251   DM_Plex       *mesh = (DM_Plex*) dm->data;
3252   PetscInt       pStart, pEnd;
3253   PetscInt       dof, off;
3254   PetscErrorCode ierr;
3255 
3256   PetscFunctionBegin;
3257   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3258   ierr = PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd);CHKERRQ(ierr);
3259   ierr = PetscSectionGetDof(mesh->supportSection, p, &dof);CHKERRQ(ierr);
3260   ierr = PetscSectionGetOffset(mesh->supportSection, p, &off);CHKERRQ(ierr);
3261   PetscCheckFalse((p < pStart) || (p >= pEnd),PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %D is not in the valid range [%D, %D)", p, pStart, pEnd);
3262   PetscCheckFalse((supportPoint < pStart) || (supportPoint >= pEnd),PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Support point %D is not in the valid range [%D, %D)", supportPoint, pStart, pEnd);
3263   PetscCheckFalse(supportPos >= dof,PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Support position %D of point %D is not in the valid range [0, %D)", supportPos, p, dof);
3264   mesh->supports[off+supportPos] = supportPoint;
3265   PetscFunctionReturn(0);
3266 }
3267 
3268 /* Converts an orientation o in the current numbering to the previous scheme used in Plex */
3269 PetscInt DMPolytopeConvertNewOrientation_Internal(DMPolytopeType ct, PetscInt o)
3270 {
3271   switch (ct) {
3272     case DM_POLYTOPE_SEGMENT:
3273       if (o == -1) return -2;
3274       break;
3275     case DM_POLYTOPE_TRIANGLE:
3276       if (o == -3) return -1;
3277       if (o == -2) return -3;
3278       if (o == -1) return -2;
3279       break;
3280     case DM_POLYTOPE_QUADRILATERAL:
3281       if (o == -4) return -2;
3282       if (o == -3) return -1;
3283       if (o == -2) return -4;
3284       if (o == -1) return -3;
3285       break;
3286     default: return o;
3287   }
3288   return o;
3289 }
3290 
3291 /* Converts an orientation o in the previous scheme used in Plex to the current numbering */
3292 PetscInt DMPolytopeConvertOldOrientation_Internal(DMPolytopeType ct, PetscInt o)
3293 {
3294   switch (ct) {
3295     case DM_POLYTOPE_SEGMENT:
3296       if ((o == -2) || (o == 1)) return -1;
3297       if (o == -1) return 0;
3298       break;
3299     case DM_POLYTOPE_TRIANGLE:
3300       if (o == -3) return -2;
3301       if (o == -2) return -1;
3302       if (o == -1) return -3;
3303       break;
3304     case DM_POLYTOPE_QUADRILATERAL:
3305       if (o == -4) return -2;
3306       if (o == -3) return -1;
3307       if (o == -2) return -4;
3308       if (o == -1) return -3;
3309       break;
3310     default: return o;
3311   }
3312   return o;
3313 }
3314 
3315 /* Takes in a mesh whose orientations are in the previous scheme and converts them all to the current numbering */
3316 PetscErrorCode DMPlexConvertOldOrientations_Internal(DM dm)
3317 {
3318   PetscInt       pStart, pEnd, p;
3319   PetscErrorCode ierr;
3320 
3321   PetscFunctionBegin;
3322   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
3323   for (p = pStart; p < pEnd; ++p) {
3324     const PetscInt *cone, *ornt;
3325     PetscInt        coneSize, c;
3326 
3327     ierr = DMPlexGetConeSize(dm, p, &coneSize);CHKERRQ(ierr);
3328     ierr = DMPlexGetCone(dm, p, &cone);CHKERRQ(ierr);
3329     ierr = DMPlexGetConeOrientation(dm, p, &ornt);CHKERRQ(ierr);
3330     for (c = 0; c < coneSize; ++c) {
3331       DMPolytopeType ct;
3332       const PetscInt o = ornt[c];
3333 
3334       ierr = DMPlexGetCellType(dm, cone[c], &ct);CHKERRQ(ierr);
3335       switch (ct) {
3336         case DM_POLYTOPE_SEGMENT:
3337           if ((o == -2) || (o == 1)) {ierr = DMPlexInsertConeOrientation(dm, p, c, -1);CHKERRQ(ierr);}
3338           if (o == -1) {ierr = DMPlexInsertConeOrientation(dm, p, c, 0);CHKERRQ(ierr);}
3339           break;
3340         case DM_POLYTOPE_TRIANGLE:
3341           if (o == -3) {ierr = DMPlexInsertConeOrientation(dm, p, c, -2);CHKERRQ(ierr);}
3342           if (o == -2) {ierr = DMPlexInsertConeOrientation(dm, p, c, -1);CHKERRQ(ierr);}
3343           if (o == -1) {ierr = DMPlexInsertConeOrientation(dm, p, c, -3);CHKERRQ(ierr);}
3344           break;
3345         case DM_POLYTOPE_QUADRILATERAL:
3346           if (o == -4) {ierr = DMPlexInsertConeOrientation(dm, p, c, -2);CHKERRQ(ierr);}
3347           if (o == -3) {ierr = DMPlexInsertConeOrientation(dm, p, c, -1);CHKERRQ(ierr);}
3348           if (o == -2) {ierr = DMPlexInsertConeOrientation(dm, p, c, -4);CHKERRQ(ierr);}
3349           if (o == -1) {ierr = DMPlexInsertConeOrientation(dm, p, c, -3);CHKERRQ(ierr);}
3350           break;
3351         default: break;
3352       }
3353     }
3354   }
3355   PetscFunctionReturn(0);
3356 }
3357 
3358 static PetscErrorCode DMPlexGetTransitiveClosure_Depth1_Private(DM dm, PetscInt p, PetscInt ornt, PetscBool useCone, PetscInt *numPoints, PetscInt *points[])
3359 {
3360   DMPolytopeType  ct = DM_POLYTOPE_UNKNOWN;
3361   PetscInt       *closure;
3362   const PetscInt *tmp = NULL, *tmpO = NULL;
3363   PetscInt        off = 0, tmpSize, t;
3364   PetscErrorCode  ierr;
3365 
3366   PetscFunctionBeginHot;
3367   if (ornt) {
3368     ierr = DMPlexGetCellType(dm, p, &ct);CHKERRQ(ierr);
3369     if (ct == DM_POLYTOPE_FV_GHOST || ct == DM_POLYTOPE_INTERIOR_GHOST || ct == DM_POLYTOPE_UNKNOWN) ct = DM_POLYTOPE_UNKNOWN;
3370   }
3371   if (*points) {
3372     closure = *points;
3373   } else {
3374     PetscInt maxConeSize, maxSupportSize;
3375     ierr = DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize);CHKERRQ(ierr);
3376     ierr = DMGetWorkArray(dm, 2*(PetscMax(maxConeSize, maxSupportSize)+1), MPIU_INT, &closure);CHKERRQ(ierr);
3377   }
3378   if (useCone) {
3379     ierr = DMPlexGetConeSize(dm, p, &tmpSize);CHKERRQ(ierr);
3380     ierr = DMPlexGetCone(dm, p, &tmp);CHKERRQ(ierr);
3381     ierr = DMPlexGetConeOrientation(dm, p, &tmpO);CHKERRQ(ierr);
3382   } else {
3383     ierr = DMPlexGetSupportSize(dm, p, &tmpSize);CHKERRQ(ierr);
3384     ierr = DMPlexGetSupport(dm, p, &tmp);CHKERRQ(ierr);
3385   }
3386   if (ct == DM_POLYTOPE_UNKNOWN) {
3387     closure[off++] = p;
3388     closure[off++] = 0;
3389     for (t = 0; t < tmpSize; ++t) {
3390       closure[off++] = tmp[t];
3391       closure[off++] = tmpO ? tmpO[t] : 0;
3392     }
3393   } else {
3394     const PetscInt *arr = DMPolytopeTypeGetArrangment(ct, ornt);CHKERRQ(ierr);
3395 
3396     /* We assume that cells with a valid type have faces with a valid type */
3397     closure[off++] = p;
3398     closure[off++] = ornt;
3399     for (t = 0; t < tmpSize; ++t) {
3400       DMPolytopeType ft;
3401 
3402       ierr = DMPlexGetCellType(dm, tmp[t], &ft);CHKERRQ(ierr);
3403       closure[off++] = tmp[arr[t]];
3404       closure[off++] = tmpO ? DMPolytopeTypeComposeOrientation(ft, ornt, tmpO[t]) : 0;
3405     }
3406   }
3407   if (numPoints) *numPoints = tmpSize+1;
3408   if (points)    *points    = closure;
3409   PetscFunctionReturn(0);
3410 }
3411 
3412 /* We need a special tensor verison becasue we want to allow duplicate points in the endcaps for hybrid cells */
3413 static PetscErrorCode DMPlexTransitiveClosure_Tensor_Internal(DM dm, PetscInt point, DMPolytopeType ct, PetscInt o, PetscBool useCone, PetscInt *numPoints, PetscInt **points)
3414 {
3415   const PetscInt *arr = DMPolytopeTypeGetArrangment(ct, o);
3416   const PetscInt *cone, *ornt;
3417   PetscInt       *pts,  *closure = NULL;
3418   DMPolytopeType  ft;
3419   PetscInt        maxConeSize, maxSupportSize, coneSeries, supportSeries, maxSize;
3420   PetscInt        dim, coneSize, c, d, clSize, cl;
3421   PetscErrorCode  ierr;
3422 
3423   PetscFunctionBeginHot;
3424   ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr);
3425   ierr = DMPlexGetConeSize(dm, point, &coneSize);CHKERRQ(ierr);
3426   ierr = DMPlexGetCone(dm, point, &cone);CHKERRQ(ierr);
3427   ierr = DMPlexGetConeOrientation(dm, point, &ornt);CHKERRQ(ierr);
3428   ierr = DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize);CHKERRQ(ierr);
3429   coneSeries    = (maxConeSize    > 1) ? ((PetscPowInt(maxConeSize,    dim+1)-1)/(maxConeSize-1))    : dim+1;
3430   supportSeries = (maxSupportSize > 1) ? ((PetscPowInt(maxSupportSize, dim+1)-1)/(maxSupportSize-1)) : dim+1;
3431   maxSize       = PetscMax(coneSeries, supportSeries);
3432   if (*points) {pts  = *points;}
3433   else         {ierr = DMGetWorkArray(dm, 2*maxSize, MPIU_INT, &pts);CHKERRQ(ierr);}
3434   c    = 0;
3435   pts[c++] = point;
3436   pts[c++] = o;
3437   ierr = DMPlexGetCellType(dm, cone[arr[0*2+0]], &ft);CHKERRQ(ierr);
3438   ierr = DMPlexGetTransitiveClosure_Internal(dm, cone[arr[0*2+0]], DMPolytopeTypeComposeOrientation(ft, arr[0*2+1], ornt[0]), useCone, &clSize, &closure);CHKERRQ(ierr);
3439   for (cl = 0; cl < clSize*2; cl += 2) {pts[c++] = closure[cl]; pts[c++] = closure[cl+1];}
3440   ierr = DMPlexGetTransitiveClosure_Internal(dm, cone[arr[1*2+0]], DMPolytopeTypeComposeOrientation(ft, arr[1*2+1], ornt[1]), useCone, &clSize, &closure);CHKERRQ(ierr);
3441   for (cl = 0; cl < clSize*2; cl += 2) {pts[c++] = closure[cl]; pts[c++] = closure[cl+1];}
3442   ierr = DMPlexRestoreTransitiveClosure(dm, cone[0], useCone, &clSize, &closure);CHKERRQ(ierr);
3443   for (d = 2; d < coneSize; ++d) {
3444     ierr = DMPlexGetCellType(dm, cone[arr[d*2+0]], &ft);CHKERRQ(ierr);
3445     pts[c++] = cone[arr[d*2+0]];
3446     pts[c++] = DMPolytopeTypeComposeOrientation(ft, arr[d*2+1], ornt[d]);
3447   }
3448   if (dim >= 3) {
3449     for (d = 2; d < coneSize; ++d) {
3450       const PetscInt  fpoint = cone[arr[d*2+0]];
3451       const PetscInt *fcone, *fornt;
3452       PetscInt        fconeSize, fc, i;
3453 
3454       ierr = DMPlexGetCellType(dm, fpoint, &ft);CHKERRQ(ierr);
3455       const PetscInt *farr = DMPolytopeTypeGetArrangment(ft, DMPolytopeTypeComposeOrientation(ft, arr[d*2+1], ornt[d]));
3456       ierr = DMPlexGetConeSize(dm, fpoint, &fconeSize);CHKERRQ(ierr);
3457       ierr = DMPlexGetCone(dm, fpoint, &fcone);CHKERRQ(ierr);
3458       ierr = DMPlexGetConeOrientation(dm, fpoint, &fornt);CHKERRQ(ierr);
3459       for (fc = 0; fc < fconeSize; ++fc) {
3460         const PetscInt cp = fcone[farr[fc*2+0]];
3461         const PetscInt co = farr[fc*2+1];
3462 
3463         for (i = 0; i < c; i += 2) if (pts[i] == cp) break;
3464         if (i == c) {
3465           ierr = DMPlexGetCellType(dm, cp, &ft);CHKERRQ(ierr);
3466           pts[c++] = cp;
3467           pts[c++] = DMPolytopeTypeComposeOrientation(ft, co, fornt[farr[fc*2+0]]);
3468         }
3469       }
3470     }
3471   }
3472   *numPoints = c/2;
3473   *points    = pts;
3474   PetscFunctionReturn(0);
3475 }
3476 
3477 PetscErrorCode DMPlexGetTransitiveClosure_Internal(DM dm, PetscInt p, PetscInt ornt, PetscBool useCone, PetscInt *numPoints, PetscInt *points[])
3478 {
3479   DMPolytopeType ct;
3480   PetscInt      *closure, *fifo;
3481   PetscInt       closureSize = 0, fifoStart = 0, fifoSize = 0;
3482   PetscInt       maxConeSize, maxSupportSize, coneSeries, supportSeries;
3483   PetscInt       depth, maxSize;
3484   PetscErrorCode ierr;
3485 
3486   PetscFunctionBeginHot;
3487   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3488   if (depth == 1) {
3489     ierr = DMPlexGetTransitiveClosure_Depth1_Private(dm, p, ornt, useCone, numPoints, points);CHKERRQ(ierr);
3490     PetscFunctionReturn(0);
3491   }
3492   ierr = DMPlexGetCellType(dm, p, &ct);CHKERRQ(ierr);
3493   if (ct == DM_POLYTOPE_FV_GHOST || ct == DM_POLYTOPE_INTERIOR_GHOST || ct == DM_POLYTOPE_UNKNOWN) ct = DM_POLYTOPE_UNKNOWN;
3494   if (ct == DM_POLYTOPE_SEG_PRISM_TENSOR || ct == DM_POLYTOPE_TRI_PRISM_TENSOR || ct == DM_POLYTOPE_QUAD_PRISM_TENSOR) {
3495     ierr = DMPlexTransitiveClosure_Tensor_Internal(dm, p, ct, ornt, useCone, numPoints, points);CHKERRQ(ierr);
3496     PetscFunctionReturn(0);
3497   }
3498   ierr = DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize);CHKERRQ(ierr);
3499   coneSeries    = (maxConeSize    > 1) ? ((PetscPowInt(maxConeSize,    depth+1)-1)/(maxConeSize-1))    : depth+1;
3500   supportSeries = (maxSupportSize > 1) ? ((PetscPowInt(maxSupportSize, depth+1)-1)/(maxSupportSize-1)) : depth+1;
3501   maxSize       = PetscMax(coneSeries, supportSeries);
3502   ierr = DMGetWorkArray(dm, 3*maxSize, MPIU_INT, &fifo);CHKERRQ(ierr);
3503   if (*points) {closure = *points;}
3504   else         {ierr = DMGetWorkArray(dm, 2*maxSize, MPIU_INT, &closure);CHKERRQ(ierr);}
3505   closure[closureSize++] = p;
3506   closure[closureSize++] = ornt;
3507   fifo[fifoSize++]       = p;
3508   fifo[fifoSize++]       = ornt;
3509   fifo[fifoSize++]       = ct;
3510   /* Should kick out early when depth is reached, rather than checking all vertices for empty cones */
3511   while (fifoSize - fifoStart) {
3512     const PetscInt       q    = fifo[fifoStart++];
3513     const PetscInt       o    = fifo[fifoStart++];
3514     const DMPolytopeType qt   = (DMPolytopeType) fifo[fifoStart++];
3515     const PetscInt      *qarr = DMPolytopeTypeGetArrangment(qt, o);
3516     const PetscInt      *tmp, *tmpO;
3517     PetscInt             tmpSize, t;
3518 
3519     if (PetscDefined(USE_DEBUG)) {
3520       PetscInt nO = DMPolytopeTypeGetNumArrangments(qt)/2;
3521       PetscCheckFalse(o && (o >= nO || o < -nO),PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid orientation %D not in [%D,%D) for %s %D", o, -nO, nO, DMPolytopeTypes[qt], q);
3522     }
3523     if (useCone) {
3524       ierr = DMPlexGetConeSize(dm, q, &tmpSize);CHKERRQ(ierr);
3525       ierr = DMPlexGetCone(dm, q, &tmp);CHKERRQ(ierr);
3526       ierr = DMPlexGetConeOrientation(dm, q, &tmpO);CHKERRQ(ierr);
3527     } else {
3528       ierr = DMPlexGetSupportSize(dm, q, &tmpSize);CHKERRQ(ierr);
3529       ierr = DMPlexGetSupport(dm, q, &tmp);CHKERRQ(ierr);
3530       tmpO = NULL;
3531     }
3532     for (t = 0; t < tmpSize; ++t) {
3533       const PetscInt ip = useCone && qarr ? qarr[t*2]   : t;
3534       const PetscInt io = useCone && qarr ? qarr[t*2+1] : 0;
3535       const PetscInt cp = tmp[ip];
3536       ierr = DMPlexGetCellType(dm, cp, &ct);CHKERRQ(ierr);
3537       const PetscInt co = tmpO ? DMPolytopeTypeComposeOrientation(ct, io, tmpO[ip]) : 0;
3538       PetscInt       c;
3539 
3540       /* Check for duplicate */
3541       for (c = 0; c < closureSize; c += 2) {
3542         if (closure[c] == cp) break;
3543       }
3544       if (c == closureSize) {
3545         closure[closureSize++] = cp;
3546         closure[closureSize++] = co;
3547         fifo[fifoSize++]       = cp;
3548         fifo[fifoSize++]       = co;
3549         fifo[fifoSize++]       = ct;
3550       }
3551     }
3552   }
3553   ierr = DMRestoreWorkArray(dm, 3*maxSize, MPIU_INT, &fifo);CHKERRQ(ierr);
3554   if (numPoints) *numPoints = closureSize/2;
3555   if (points)    *points    = closure;
3556   PetscFunctionReturn(0);
3557 }
3558 
3559 /*@C
3560   DMPlexGetTransitiveClosure - Return the points on the transitive closure of the in-edges or out-edges for this point in the DAG
3561 
3562   Not collective
3563 
3564   Input Parameters:
3565 + dm      - The DMPlex
3566 . p       - The mesh point
3567 - useCone - PETSC_TRUE for the closure, otherwise return the star
3568 
3569   Input/Output Parameter:
3570 . points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...];
3571            if NULL on input, internal storage will be returned, otherwise the provided array is used
3572 
3573   Output Parameter:
3574 . numPoints - The number of points in the closure, so points[] is of size 2*numPoints
3575 
3576   Note:
3577   If using internal storage (points is NULL on input), each call overwrites the last output.
3578 
3579   Fortran Notes:
3580   Since it returns an array, this routine is only available in Fortran 90, and you must include petsc.h90 in your code.
3581 
3582   The numPoints argument is not present in the Fortran 90 binding since it is internal to the array.
3583 
3584   Level: beginner
3585 
3586 .seealso: DMPlexRestoreTransitiveClosure(), DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone()
3587 @*/
3588 PetscErrorCode DMPlexGetTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[])
3589 {
3590   PetscErrorCode ierr;
3591 
3592   PetscFunctionBeginHot;
3593   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3594   if (numPoints) PetscValidIntPointer(numPoints, 4);
3595   if (points)    PetscValidPointer(points, 5);
3596   ierr = DMPlexGetTransitiveClosure_Internal(dm, p, 0, useCone, numPoints, points);CHKERRQ(ierr);
3597   PetscFunctionReturn(0);
3598 }
3599 
3600 /*@C
3601   DMPlexRestoreTransitiveClosure - Restore the array of points on the transitive closure of the in-edges or out-edges for this point in the DAG
3602 
3603   Not collective
3604 
3605   Input Parameters:
3606 + dm        - The DMPlex
3607 . p         - The mesh point
3608 . useCone   - PETSC_TRUE for the closure, otherwise return the star
3609 . numPoints - The number of points in the closure, so points[] is of size 2*numPoints
3610 - points    - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...]
3611 
3612   Note:
3613   If not using internal storage (points is not NULL on input), this call is unnecessary
3614 
3615   Fortran Notes:
3616   Since it returns an array, this routine is only available in Fortran 90, and you must include petsc.h90 in your code.
3617 
3618   The numPoints argument is not present in the Fortran 90 binding since it is internal to the array.
3619 
3620   Level: beginner
3621 
3622 .seealso: DMPlexGetTransitiveClosure(), DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone()
3623 @*/
3624 PetscErrorCode DMPlexRestoreTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[])
3625 {
3626   PetscErrorCode ierr;
3627 
3628   PetscFunctionBeginHot;
3629   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3630   if (numPoints) *numPoints = 0;
3631   ierr = DMRestoreWorkArray(dm, 0, MPIU_INT, points);CHKERRQ(ierr);
3632   PetscFunctionReturn(0);
3633 }
3634 
3635 /*@
3636   DMPlexGetMaxSizes - Return the maximum number of in-edges (cone) and out-edges (support) for any point in the DAG
3637 
3638   Not collective
3639 
3640   Input Parameter:
3641 . mesh - The DMPlex
3642 
3643   Output Parameters:
3644 + maxConeSize - The maximum number of in-edges
3645 - maxSupportSize - The maximum number of out-edges
3646 
3647   Level: beginner
3648 
3649 .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexSetChart()
3650 @*/
3651 PetscErrorCode DMPlexGetMaxSizes(DM dm, PetscInt *maxConeSize, PetscInt *maxSupportSize)
3652 {
3653   DM_Plex *mesh = (DM_Plex*) dm->data;
3654 
3655   PetscFunctionBegin;
3656   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3657   if (maxConeSize)    *maxConeSize    = mesh->maxConeSize;
3658   if (maxSupportSize) *maxSupportSize = mesh->maxSupportSize;
3659   PetscFunctionReturn(0);
3660 }
3661 
3662 PetscErrorCode DMSetUp_Plex(DM dm)
3663 {
3664   DM_Plex       *mesh = (DM_Plex*) dm->data;
3665   PetscInt       size;
3666   PetscErrorCode ierr;
3667 
3668   PetscFunctionBegin;
3669   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3670   ierr = PetscSectionSetUp(mesh->coneSection);CHKERRQ(ierr);
3671   ierr = PetscSectionGetStorageSize(mesh->coneSection, &size);CHKERRQ(ierr);
3672   ierr = PetscMalloc1(size, &mesh->cones);CHKERRQ(ierr);
3673   ierr = PetscCalloc1(size, &mesh->coneOrientations);CHKERRQ(ierr);
3674   ierr = PetscLogObjectMemory((PetscObject) dm, size*2*sizeof(PetscInt));CHKERRQ(ierr);
3675   if (mesh->maxSupportSize) {
3676     ierr = PetscSectionSetUp(mesh->supportSection);CHKERRQ(ierr);
3677     ierr = PetscSectionGetStorageSize(mesh->supportSection, &size);CHKERRQ(ierr);
3678     ierr = PetscMalloc1(size, &mesh->supports);CHKERRQ(ierr);
3679     ierr = PetscLogObjectMemory((PetscObject) dm, size*sizeof(PetscInt));CHKERRQ(ierr);
3680   }
3681   PetscFunctionReturn(0);
3682 }
3683 
3684 PetscErrorCode DMCreateSubDM_Plex(DM dm, PetscInt numFields, const PetscInt fields[], IS *is, DM *subdm)
3685 {
3686   PetscErrorCode ierr;
3687 
3688   PetscFunctionBegin;
3689   if (subdm) {ierr = DMClone(dm, subdm);CHKERRQ(ierr);}
3690   ierr = DMCreateSectionSubDM(dm, numFields, fields, is, subdm);CHKERRQ(ierr);
3691   if (subdm) {(*subdm)->useNatural = dm->useNatural;}
3692   if (dm->useNatural && dm->sfMigration) {
3693     PetscSF        sfMigrationInv,sfNatural;
3694     PetscSection   section, sectionSeq;
3695 
3696     (*subdm)->sfMigration = dm->sfMigration;
3697     ierr = PetscObjectReference((PetscObject) dm->sfMigration);CHKERRQ(ierr);
3698     ierr = DMGetLocalSection((*subdm), &section);CHKERRQ(ierr);
3699     ierr = PetscSFCreateInverseSF((*subdm)->sfMigration, &sfMigrationInv);CHKERRQ(ierr);
3700     ierr = PetscSectionCreate(PetscObjectComm((PetscObject) (*subdm)), &sectionSeq);CHKERRQ(ierr);
3701     ierr = PetscSFDistributeSection(sfMigrationInv, section, NULL, sectionSeq);CHKERRQ(ierr);
3702 
3703     ierr = DMPlexCreateGlobalToNaturalSF(*subdm, sectionSeq, (*subdm)->sfMigration, &sfNatural);CHKERRQ(ierr);
3704     (*subdm)->sfNatural = sfNatural;
3705     ierr = PetscSectionDestroy(&sectionSeq);CHKERRQ(ierr);
3706     ierr = PetscSFDestroy(&sfMigrationInv);CHKERRQ(ierr);
3707   }
3708   PetscFunctionReturn(0);
3709 }
3710 
3711 PetscErrorCode DMCreateSuperDM_Plex(DM dms[], PetscInt len, IS **is, DM *superdm)
3712 {
3713   PetscErrorCode ierr;
3714   PetscInt       i = 0;
3715 
3716   PetscFunctionBegin;
3717   ierr = DMClone(dms[0], superdm);CHKERRQ(ierr);
3718   ierr = DMCreateSectionSuperDM(dms, len, is, superdm);CHKERRQ(ierr);
3719   (*superdm)->useNatural = PETSC_FALSE;
3720   for (i = 0; i < len; i++) {
3721     if (dms[i]->useNatural && dms[i]->sfMigration) {
3722       PetscSF        sfMigrationInv,sfNatural;
3723       PetscSection   section, sectionSeq;
3724 
3725       (*superdm)->sfMigration = dms[i]->sfMigration;
3726       ierr = PetscObjectReference((PetscObject) dms[i]->sfMigration);CHKERRQ(ierr);
3727       (*superdm)->useNatural = PETSC_TRUE;
3728       ierr = DMGetLocalSection((*superdm), &section);CHKERRQ(ierr);
3729       ierr = PetscSFCreateInverseSF((*superdm)->sfMigration, &sfMigrationInv);CHKERRQ(ierr);
3730       ierr = PetscSectionCreate(PetscObjectComm((PetscObject) (*superdm)), &sectionSeq);CHKERRQ(ierr);
3731       ierr = PetscSFDistributeSection(sfMigrationInv, section, NULL, sectionSeq);CHKERRQ(ierr);
3732 
3733       ierr = DMPlexCreateGlobalToNaturalSF(*superdm, sectionSeq, (*superdm)->sfMigration, &sfNatural);CHKERRQ(ierr);
3734       (*superdm)->sfNatural = sfNatural;
3735       ierr = PetscSectionDestroy(&sectionSeq);CHKERRQ(ierr);
3736       ierr = PetscSFDestroy(&sfMigrationInv);CHKERRQ(ierr);
3737       break;
3738     }
3739   }
3740   PetscFunctionReturn(0);
3741 }
3742 
3743 /*@
3744   DMPlexSymmetrize - Create support (out-edge) information from cone (in-edge) information
3745 
3746   Not collective
3747 
3748   Input Parameter:
3749 . mesh - The DMPlex
3750 
3751   Output Parameter:
3752 
3753   Note:
3754   This should be called after all calls to DMPlexSetCone()
3755 
3756   Level: beginner
3757 
3758 .seealso: DMPlexCreate(), DMPlexSetChart(), DMPlexSetConeSize(), DMPlexSetCone()
3759 @*/
3760 PetscErrorCode DMPlexSymmetrize(DM dm)
3761 {
3762   DM_Plex       *mesh = (DM_Plex*) dm->data;
3763   PetscInt      *offsets;
3764   PetscInt       supportSize;
3765   PetscInt       pStart, pEnd, p;
3766   PetscErrorCode ierr;
3767 
3768   PetscFunctionBegin;
3769   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3770   PetscCheckFalse(mesh->supports,PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Supports were already setup in this DMPlex");
3771   ierr = PetscLogEventBegin(DMPLEX_Symmetrize,dm,0,0,0);CHKERRQ(ierr);
3772   /* Calculate support sizes */
3773   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
3774   for (p = pStart; p < pEnd; ++p) {
3775     PetscInt dof, off, c;
3776 
3777     ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
3778     ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
3779     for (c = off; c < off+dof; ++c) {
3780       ierr = PetscSectionAddDof(mesh->supportSection, mesh->cones[c], 1);CHKERRQ(ierr);
3781     }
3782   }
3783   for (p = pStart; p < pEnd; ++p) {
3784     PetscInt dof;
3785 
3786     ierr = PetscSectionGetDof(mesh->supportSection, p, &dof);CHKERRQ(ierr);
3787 
3788     mesh->maxSupportSize = PetscMax(mesh->maxSupportSize, dof);
3789   }
3790   ierr = PetscSectionSetUp(mesh->supportSection);CHKERRQ(ierr);
3791   /* Calculate supports */
3792   ierr = PetscSectionGetStorageSize(mesh->supportSection, &supportSize);CHKERRQ(ierr);
3793   ierr = PetscMalloc1(supportSize, &mesh->supports);CHKERRQ(ierr);
3794   ierr = PetscCalloc1(pEnd - pStart, &offsets);CHKERRQ(ierr);
3795   for (p = pStart; p < pEnd; ++p) {
3796     PetscInt dof, off, c;
3797 
3798     ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
3799     ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
3800     for (c = off; c < off+dof; ++c) {
3801       const PetscInt q = mesh->cones[c];
3802       PetscInt       offS;
3803 
3804       ierr = PetscSectionGetOffset(mesh->supportSection, q, &offS);CHKERRQ(ierr);
3805 
3806       mesh->supports[offS+offsets[q]] = p;
3807       ++offsets[q];
3808     }
3809   }
3810   ierr = PetscFree(offsets);CHKERRQ(ierr);
3811   ierr = PetscLogEventEnd(DMPLEX_Symmetrize,dm,0,0,0);CHKERRQ(ierr);
3812   PetscFunctionReturn(0);
3813 }
3814 
3815 static PetscErrorCode DMPlexCreateDepthStratum(DM dm, DMLabel label, PetscInt depth, PetscInt pStart, PetscInt pEnd)
3816 {
3817   IS             stratumIS;
3818   PetscErrorCode ierr;
3819 
3820   PetscFunctionBegin;
3821   if (pStart >= pEnd) PetscFunctionReturn(0);
3822   if (PetscDefined(USE_DEBUG)) {
3823     PetscInt  qStart, qEnd, numLevels, level;
3824     PetscBool overlap = PETSC_FALSE;
3825     ierr = DMLabelGetNumValues(label, &numLevels);CHKERRQ(ierr);
3826     for (level = 0; level < numLevels; level++) {
3827       ierr = DMLabelGetStratumBounds(label, level, &qStart, &qEnd);CHKERRQ(ierr);
3828       if ((pStart >= qStart && pStart < qEnd) || (pEnd > qStart && pEnd <= qEnd)) {overlap = PETSC_TRUE; break;}
3829     }
3830     PetscCheckFalse(overlap,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);
3831   }
3832   ierr = ISCreateStride(PETSC_COMM_SELF, pEnd-pStart, pStart, 1, &stratumIS);CHKERRQ(ierr);
3833   ierr = DMLabelSetStratumIS(label, depth, stratumIS);CHKERRQ(ierr);
3834   ierr = ISDestroy(&stratumIS);CHKERRQ(ierr);
3835   PetscFunctionReturn(0);
3836 }
3837 
3838 /*@
3839   DMPlexStratify - The DAG for most topologies is a graded poset (https://en.wikipedia.org/wiki/Graded_poset), and
3840   can be illustrated by a Hasse Diagram (https://en.wikipedia.org/wiki/Hasse_diagram). The strata group all points of the
3841   same grade, and this function calculates the strata. This grade can be seen as the height (or depth) of the point in
3842   the DAG.
3843 
3844   Collective on dm
3845 
3846   Input Parameter:
3847 . mesh - The DMPlex
3848 
3849   Output Parameter:
3850 
3851   Notes:
3852   Concretely, DMPlexStratify() creates a new label named "depth" containing the depth in the DAG of each point. For cell-vertex
3853   meshes, vertices are depth 0 and cells are depth 1. For fully interpolated meshes, depth 0 for vertices, 1 for edges, and so on
3854   until cells have depth equal to the dimension of the mesh. The depth label can be accessed through DMPlexGetDepthLabel() or DMPlexGetDepthStratum(), or
3855   manually via DMGetLabel().  The height is defined implicitly by height = maxDimension - depth, and can be accessed
3856   via DMPlexGetHeightStratum().  For example, cells have height 0 and faces have height 1.
3857 
3858   The depth of a point is calculated by executing a breadth-first search (BFS) on the DAG. This could produce surprising results
3859   if run on a partially interpolated mesh, meaning one that had some edges and faces, but not others. For example, suppose that
3860   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
3861   to interpolate only that one (e0), so that
3862 $  cone(c0) = {e0, v2}
3863 $  cone(e0) = {v0, v1}
3864   If DMPlexStratify() is run on this mesh, it will give depths
3865 $  depth 0 = {v0, v1, v2}
3866 $  depth 1 = {e0, c0}
3867   where the triangle has been given depth 1, instead of 2, because it is reachable from vertex v2.
3868 
3869   DMPlexStratify() should be called after all calls to DMPlexSymmetrize()
3870 
3871   Level: beginner
3872 
3873 .seealso: DMPlexCreate(), DMPlexSymmetrize(), DMPlexComputeCellTypes()
3874 @*/
3875 PetscErrorCode DMPlexStratify(DM dm)
3876 {
3877   DM_Plex       *mesh = (DM_Plex*) dm->data;
3878   DMLabel        label;
3879   PetscInt       pStart, pEnd, p;
3880   PetscInt       numRoots = 0, numLeaves = 0;
3881   PetscErrorCode ierr;
3882 
3883   PetscFunctionBegin;
3884   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3885   ierr = PetscLogEventBegin(DMPLEX_Stratify,dm,0,0,0);CHKERRQ(ierr);
3886 
3887   /* Create depth label */
3888   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
3889   ierr = DMCreateLabel(dm, "depth");CHKERRQ(ierr);
3890   ierr = DMPlexGetDepthLabel(dm, &label);CHKERRQ(ierr);
3891 
3892   {
3893     /* Initialize roots and count leaves */
3894     PetscInt sMin = PETSC_MAX_INT;
3895     PetscInt sMax = PETSC_MIN_INT;
3896     PetscInt coneSize, supportSize;
3897 
3898     for (p = pStart; p < pEnd; ++p) {
3899       ierr = DMPlexGetConeSize(dm, p, &coneSize);CHKERRQ(ierr);
3900       ierr = DMPlexGetSupportSize(dm, p, &supportSize);CHKERRQ(ierr);
3901       if (!coneSize && supportSize) {
3902         sMin = PetscMin(p, sMin);
3903         sMax = PetscMax(p, sMax);
3904         ++numRoots;
3905       } else if (!supportSize && coneSize) {
3906         ++numLeaves;
3907       } else if (!supportSize && !coneSize) {
3908         /* Isolated points */
3909         sMin = PetscMin(p, sMin);
3910         sMax = PetscMax(p, sMax);
3911       }
3912     }
3913     ierr = DMPlexCreateDepthStratum(dm, label, 0, sMin, sMax+1);CHKERRQ(ierr);
3914   }
3915 
3916   if (numRoots + numLeaves == (pEnd - pStart)) {
3917     PetscInt sMin = PETSC_MAX_INT;
3918     PetscInt sMax = PETSC_MIN_INT;
3919     PetscInt coneSize, supportSize;
3920 
3921     for (p = pStart; p < pEnd; ++p) {
3922       ierr = DMPlexGetConeSize(dm, p, &coneSize);CHKERRQ(ierr);
3923       ierr = DMPlexGetSupportSize(dm, p, &supportSize);CHKERRQ(ierr);
3924       if (!supportSize && coneSize) {
3925         sMin = PetscMin(p, sMin);
3926         sMax = PetscMax(p, sMax);
3927       }
3928     }
3929     ierr = DMPlexCreateDepthStratum(dm, label, 1, sMin, sMax+1);CHKERRQ(ierr);
3930   } else {
3931     PetscInt level = 0;
3932     PetscInt qStart, qEnd, q;
3933 
3934     ierr = DMLabelGetStratumBounds(label, level, &qStart, &qEnd);CHKERRQ(ierr);
3935     while (qEnd > qStart) {
3936       PetscInt sMin = PETSC_MAX_INT;
3937       PetscInt sMax = PETSC_MIN_INT;
3938 
3939       for (q = qStart; q < qEnd; ++q) {
3940         const PetscInt *support;
3941         PetscInt        supportSize, s;
3942 
3943         ierr = DMPlexGetSupportSize(dm, q, &supportSize);CHKERRQ(ierr);
3944         ierr = DMPlexGetSupport(dm, q, &support);CHKERRQ(ierr);
3945         for (s = 0; s < supportSize; ++s) {
3946           sMin = PetscMin(support[s], sMin);
3947           sMax = PetscMax(support[s], sMax);
3948         }
3949       }
3950       ierr = DMLabelGetNumValues(label, &level);CHKERRQ(ierr);
3951       ierr = DMPlexCreateDepthStratum(dm, label, level, sMin, sMax+1);CHKERRQ(ierr);
3952       ierr = DMLabelGetStratumBounds(label, level, &qStart, &qEnd);CHKERRQ(ierr);
3953     }
3954   }
3955   { /* just in case there is an empty process */
3956     PetscInt numValues, maxValues = 0, v;
3957 
3958     ierr = DMLabelGetNumValues(label, &numValues);CHKERRQ(ierr);
3959     ierr = MPI_Allreduce(&numValues,&maxValues,1,MPIU_INT,MPI_MAX,PetscObjectComm((PetscObject)dm));CHKERRMPI(ierr);
3960     for (v = numValues; v < maxValues; v++) {
3961       ierr = DMLabelAddStratum(label, v);CHKERRQ(ierr);
3962     }
3963   }
3964   ierr = PetscObjectStateGet((PetscObject) label, &mesh->depthState);CHKERRQ(ierr);
3965   ierr = PetscLogEventEnd(DMPLEX_Stratify,dm,0,0,0);CHKERRQ(ierr);
3966   PetscFunctionReturn(0);
3967 }
3968 
3969 PetscErrorCode DMPlexComputeCellType_Internal(DM dm, PetscInt p, PetscInt pdepth, DMPolytopeType *pt)
3970 {
3971   DMPolytopeType ct = DM_POLYTOPE_UNKNOWN;
3972   PetscInt       dim, depth, pheight, coneSize;
3973   PetscErrorCode ierr;
3974 
3975   PetscFunctionBeginHot;
3976   ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr);
3977   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3978   ierr = DMPlexGetConeSize(dm, p, &coneSize);CHKERRQ(ierr);
3979   pheight = depth - pdepth;
3980   if (depth <= 1) {
3981     switch (pdepth) {
3982       case 0: ct = DM_POLYTOPE_POINT;break;
3983       case 1:
3984         switch (coneSize) {
3985           case 2: ct = DM_POLYTOPE_SEGMENT;break;
3986           case 3: ct = DM_POLYTOPE_TRIANGLE;break;
3987           case 4:
3988           switch (dim) {
3989             case 2: ct = DM_POLYTOPE_QUADRILATERAL;break;
3990             case 3: ct = DM_POLYTOPE_TETRAHEDRON;break;
3991             default: break;
3992           }
3993           break;
3994         case 5: ct = DM_POLYTOPE_PYRAMID;break;
3995         case 6: ct = DM_POLYTOPE_TRI_PRISM_TENSOR;break;
3996         case 8: ct = DM_POLYTOPE_HEXAHEDRON;break;
3997         default: break;
3998       }
3999     }
4000   } else {
4001     if (pdepth == 0) {
4002       ct = DM_POLYTOPE_POINT;
4003     } else if (pheight == 0) {
4004       switch (dim) {
4005         case 1:
4006           switch (coneSize) {
4007             case 2: ct = DM_POLYTOPE_SEGMENT;break;
4008             default: break;
4009           }
4010           break;
4011         case 2:
4012           switch (coneSize) {
4013             case 3: ct = DM_POLYTOPE_TRIANGLE;break;
4014             case 4: ct = DM_POLYTOPE_QUADRILATERAL;break;
4015             default: break;
4016           }
4017           break;
4018         case 3:
4019           switch (coneSize) {
4020             case 4: ct = DM_POLYTOPE_TETRAHEDRON;break;
4021             case 5:
4022             {
4023               const PetscInt *cone;
4024               PetscInt        faceConeSize;
4025 
4026               ierr = DMPlexGetCone(dm, p, &cone);CHKERRQ(ierr);
4027               ierr = DMPlexGetConeSize(dm, cone[0], &faceConeSize);CHKERRQ(ierr);
4028               switch (faceConeSize) {
4029                 case 3: ct = DM_POLYTOPE_TRI_PRISM_TENSOR;break;
4030                 case 4: ct = DM_POLYTOPE_PYRAMID;break;
4031               }
4032             }
4033             break;
4034             case 6: ct = DM_POLYTOPE_HEXAHEDRON;break;
4035             default: break;
4036           }
4037           break;
4038         default: break;
4039       }
4040     } else if (pheight > 0) {
4041       switch (coneSize) {
4042         case 2: ct = DM_POLYTOPE_SEGMENT;break;
4043         case 3: ct = DM_POLYTOPE_TRIANGLE;break;
4044         case 4: ct = DM_POLYTOPE_QUADRILATERAL;break;
4045         default: break;
4046       }
4047     }
4048   }
4049   *pt = ct;
4050   PetscFunctionReturn(0);
4051 }
4052 
4053 /*@
4054   DMPlexComputeCellTypes - Infer the polytope type of every cell using its dimension and cone size.
4055 
4056   Collective on dm
4057 
4058   Input Parameter:
4059 . mesh - The DMPlex
4060 
4061   DMPlexComputeCellTypes() should be called after all calls to DMPlexSymmetrize() and DMPlexStratify()
4062 
4063   Level: developer
4064 
4065   Note: This function is normally called automatically by Plex when a cell type is requested. It creates an
4066   internal DMLabel named "celltype" which can be directly accessed using DMGetLabel(). A user may disable
4067   automatic creation by creating the label manually, using DMCreateLabel(dm, "celltype").
4068 
4069 .seealso: DMPlexCreate(), DMPlexSymmetrize(), DMPlexStratify(), DMGetLabel(), DMCreateLabel()
4070 @*/
4071 PetscErrorCode DMPlexComputeCellTypes(DM dm)
4072 {
4073   DM_Plex       *mesh;
4074   DMLabel        ctLabel;
4075   PetscInt       pStart, pEnd, p;
4076   PetscErrorCode ierr;
4077 
4078   PetscFunctionBegin;
4079   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4080   mesh = (DM_Plex *) dm->data;
4081   ierr = DMCreateLabel(dm, "celltype");CHKERRQ(ierr);
4082   ierr = DMPlexGetCellTypeLabel(dm, &ctLabel);CHKERRQ(ierr);
4083   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
4084   for (p = pStart; p < pEnd; ++p) {
4085     DMPolytopeType ct = DM_POLYTOPE_UNKNOWN;
4086     PetscInt       pdepth;
4087 
4088     ierr = DMPlexGetPointDepth(dm, p, &pdepth);CHKERRQ(ierr);
4089     ierr = DMPlexComputeCellType_Internal(dm, p, pdepth, &ct);CHKERRQ(ierr);
4090     PetscCheckFalse(ct == DM_POLYTOPE_UNKNOWN,PETSC_COMM_SELF, PETSC_ERR_SUP, "Point %D is screwed up", p);
4091     ierr = DMLabelSetValue(ctLabel, p, ct);CHKERRQ(ierr);
4092   }
4093   ierr = PetscObjectStateGet((PetscObject) ctLabel, &mesh->celltypeState);CHKERRQ(ierr);
4094   ierr = PetscObjectViewFromOptions((PetscObject) ctLabel, NULL, "-dm_plex_celltypes_view");CHKERRQ(ierr);
4095   PetscFunctionReturn(0);
4096 }
4097 
4098 /*@C
4099   DMPlexGetJoin - Get an array for the join of the set of points
4100 
4101   Not Collective
4102 
4103   Input Parameters:
4104 + dm - The DMPlex object
4105 . numPoints - The number of input points for the join
4106 - points - The input points
4107 
4108   Output Parameters:
4109 + numCoveredPoints - The number of points in the join
4110 - coveredPoints - The points in the join
4111 
4112   Level: intermediate
4113 
4114   Note: Currently, this is restricted to a single level join
4115 
4116   Fortran Notes:
4117   Since it returns an array, this routine is only available in Fortran 90, and you must
4118   include petsc.h90 in your code.
4119 
4120   The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array.
4121 
4122 .seealso: DMPlexRestoreJoin(), DMPlexGetMeet()
4123 @*/
4124 PetscErrorCode DMPlexGetJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
4125 {
4126   DM_Plex       *mesh = (DM_Plex*) dm->data;
4127   PetscInt      *join[2];
4128   PetscInt       joinSize, i = 0;
4129   PetscInt       dof, off, p, c, m;
4130   PetscErrorCode ierr;
4131 
4132   PetscFunctionBegin;
4133   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4134   PetscValidIntPointer(points, 3);
4135   PetscValidIntPointer(numCoveredPoints, 4);
4136   PetscValidPointer(coveredPoints, 5);
4137   ierr = DMGetWorkArray(dm, mesh->maxSupportSize, MPIU_INT, &join[0]);CHKERRQ(ierr);
4138   ierr = DMGetWorkArray(dm, mesh->maxSupportSize, MPIU_INT, &join[1]);CHKERRQ(ierr);
4139   /* Copy in support of first point */
4140   ierr = PetscSectionGetDof(mesh->supportSection, points[0], &dof);CHKERRQ(ierr);
4141   ierr = PetscSectionGetOffset(mesh->supportSection, points[0], &off);CHKERRQ(ierr);
4142   for (joinSize = 0; joinSize < dof; ++joinSize) {
4143     join[i][joinSize] = mesh->supports[off+joinSize];
4144   }
4145   /* Check each successive support */
4146   for (p = 1; p < numPoints; ++p) {
4147     PetscInt newJoinSize = 0;
4148 
4149     ierr = PetscSectionGetDof(mesh->supportSection, points[p], &dof);CHKERRQ(ierr);
4150     ierr = PetscSectionGetOffset(mesh->supportSection, points[p], &off);CHKERRQ(ierr);
4151     for (c = 0; c < dof; ++c) {
4152       const PetscInt point = mesh->supports[off+c];
4153 
4154       for (m = 0; m < joinSize; ++m) {
4155         if (point == join[i][m]) {
4156           join[1-i][newJoinSize++] = point;
4157           break;
4158         }
4159       }
4160     }
4161     joinSize = newJoinSize;
4162     i        = 1-i;
4163   }
4164   *numCoveredPoints = joinSize;
4165   *coveredPoints    = join[i];
4166   ierr              = DMRestoreWorkArray(dm, mesh->maxSupportSize, MPIU_INT, &join[1-i]);CHKERRQ(ierr);
4167   PetscFunctionReturn(0);
4168 }
4169 
4170 /*@C
4171   DMPlexRestoreJoin - Restore an array for the join of the set of points
4172 
4173   Not Collective
4174 
4175   Input Parameters:
4176 + dm - The DMPlex object
4177 . numPoints - The number of input points for the join
4178 - points - The input points
4179 
4180   Output Parameters:
4181 + numCoveredPoints - The number of points in the join
4182 - coveredPoints - The points in the join
4183 
4184   Fortran Notes:
4185   Since it returns an array, this routine is only available in Fortran 90, and you must
4186   include petsc.h90 in your code.
4187 
4188   The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array.
4189 
4190   Level: intermediate
4191 
4192 .seealso: DMPlexGetJoin(), DMPlexGetFullJoin(), DMPlexGetMeet()
4193 @*/
4194 PetscErrorCode DMPlexRestoreJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
4195 {
4196   PetscErrorCode ierr;
4197 
4198   PetscFunctionBegin;
4199   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4200   if (points) PetscValidIntPointer(points,3);
4201   if (numCoveredPoints) PetscValidIntPointer(numCoveredPoints,4);
4202   PetscValidPointer(coveredPoints, 5);
4203   ierr = DMRestoreWorkArray(dm, 0, MPIU_INT, (void*) coveredPoints);CHKERRQ(ierr);
4204   if (numCoveredPoints) *numCoveredPoints = 0;
4205   PetscFunctionReturn(0);
4206 }
4207 
4208 /*@C
4209   DMPlexGetFullJoin - Get an array for the join of the set of points
4210 
4211   Not Collective
4212 
4213   Input Parameters:
4214 + dm - The DMPlex object
4215 . numPoints - The number of input points for the join
4216 - points - The input points
4217 
4218   Output Parameters:
4219 + numCoveredPoints - The number of points in the join
4220 - coveredPoints - The points in the join
4221 
4222   Fortran Notes:
4223   Since it returns an array, this routine is only available in Fortran 90, and you must
4224   include petsc.h90 in your code.
4225 
4226   The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array.
4227 
4228   Level: intermediate
4229 
4230 .seealso: DMPlexGetJoin(), DMPlexRestoreJoin(), DMPlexGetMeet()
4231 @*/
4232 PetscErrorCode DMPlexGetFullJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
4233 {
4234   DM_Plex       *mesh = (DM_Plex*) dm->data;
4235   PetscInt      *offsets, **closures;
4236   PetscInt      *join[2];
4237   PetscInt       depth = 0, maxSize, joinSize = 0, i = 0;
4238   PetscInt       p, d, c, m, ms;
4239   PetscErrorCode ierr;
4240 
4241   PetscFunctionBegin;
4242   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4243   PetscValidIntPointer(points, 3);
4244   PetscValidIntPointer(numCoveredPoints, 4);
4245   PetscValidPointer(coveredPoints, 5);
4246 
4247   ierr    = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
4248   ierr    = PetscCalloc1(numPoints, &closures);CHKERRQ(ierr);
4249   ierr    = DMGetWorkArray(dm, numPoints*(depth+2), MPIU_INT, &offsets);CHKERRQ(ierr);
4250   ms      = mesh->maxSupportSize;
4251   maxSize = (ms > 1) ? ((PetscPowInt(ms,depth+1)-1)/(ms-1)) : depth + 1;
4252   ierr    = DMGetWorkArray(dm, maxSize, MPIU_INT, &join[0]);CHKERRQ(ierr);
4253   ierr    = DMGetWorkArray(dm, maxSize, MPIU_INT, &join[1]);CHKERRQ(ierr);
4254 
4255   for (p = 0; p < numPoints; ++p) {
4256     PetscInt closureSize;
4257 
4258     ierr = DMPlexGetTransitiveClosure(dm, points[p], PETSC_FALSE, &closureSize, &closures[p]);CHKERRQ(ierr);
4259 
4260     offsets[p*(depth+2)+0] = 0;
4261     for (d = 0; d < depth+1; ++d) {
4262       PetscInt pStart, pEnd, i;
4263 
4264       ierr = DMPlexGetDepthStratum(dm, d, &pStart, &pEnd);CHKERRQ(ierr);
4265       for (i = offsets[p*(depth+2)+d]; i < closureSize; ++i) {
4266         if ((pStart > closures[p][i*2]) || (pEnd <= closures[p][i*2])) {
4267           offsets[p*(depth+2)+d+1] = i;
4268           break;
4269         }
4270       }
4271       if (i == closureSize) offsets[p*(depth+2)+d+1] = i;
4272     }
4273     PetscCheckFalse(offsets[p*(depth+2)+depth+1] != closureSize,PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Total size of closure %D should be %D", offsets[p*(depth+2)+depth+1], closureSize);
4274   }
4275   for (d = 0; d < depth+1; ++d) {
4276     PetscInt dof;
4277 
4278     /* Copy in support of first point */
4279     dof = offsets[d+1] - offsets[d];
4280     for (joinSize = 0; joinSize < dof; ++joinSize) {
4281       join[i][joinSize] = closures[0][(offsets[d]+joinSize)*2];
4282     }
4283     /* Check each successive cone */
4284     for (p = 1; p < numPoints && joinSize; ++p) {
4285       PetscInt newJoinSize = 0;
4286 
4287       dof = offsets[p*(depth+2)+d+1] - offsets[p*(depth+2)+d];
4288       for (c = 0; c < dof; ++c) {
4289         const PetscInt point = closures[p][(offsets[p*(depth+2)+d]+c)*2];
4290 
4291         for (m = 0; m < joinSize; ++m) {
4292           if (point == join[i][m]) {
4293             join[1-i][newJoinSize++] = point;
4294             break;
4295           }
4296         }
4297       }
4298       joinSize = newJoinSize;
4299       i        = 1-i;
4300     }
4301     if (joinSize) break;
4302   }
4303   *numCoveredPoints = joinSize;
4304   *coveredPoints    = join[i];
4305   for (p = 0; p < numPoints; ++p) {
4306     ierr = DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_FALSE, NULL, &closures[p]);CHKERRQ(ierr);
4307   }
4308   ierr = PetscFree(closures);CHKERRQ(ierr);
4309   ierr = DMRestoreWorkArray(dm, numPoints*(depth+2), MPIU_INT, &offsets);CHKERRQ(ierr);
4310   ierr = DMRestoreWorkArray(dm, mesh->maxSupportSize, MPIU_INT, &join[1-i]);CHKERRQ(ierr);
4311   PetscFunctionReturn(0);
4312 }
4313 
4314 /*@C
4315   DMPlexGetMeet - Get an array for the meet of the set of points
4316 
4317   Not Collective
4318 
4319   Input Parameters:
4320 + dm - The DMPlex object
4321 . numPoints - The number of input points for the meet
4322 - points - The input points
4323 
4324   Output Parameters:
4325 + numCoveredPoints - The number of points in the meet
4326 - coveredPoints - The points in the meet
4327 
4328   Level: intermediate
4329 
4330   Note: Currently, this is restricted to a single level meet
4331 
4332   Fortran Notes:
4333   Since it returns an array, this routine is only available in Fortran 90, and you must
4334   include petsc.h90 in your code.
4335 
4336   The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array.
4337 
4338 .seealso: DMPlexRestoreMeet(), DMPlexGetJoin()
4339 @*/
4340 PetscErrorCode DMPlexGetMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveringPoints, const PetscInt **coveringPoints)
4341 {
4342   DM_Plex       *mesh = (DM_Plex*) dm->data;
4343   PetscInt      *meet[2];
4344   PetscInt       meetSize, i = 0;
4345   PetscInt       dof, off, p, c, m;
4346   PetscErrorCode ierr;
4347 
4348   PetscFunctionBegin;
4349   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4350   PetscValidPointer(points, 3);
4351   PetscValidPointer(numCoveringPoints, 4);
4352   PetscValidPointer(coveringPoints, 5);
4353   ierr = DMGetWorkArray(dm, mesh->maxConeSize, MPIU_INT, &meet[0]);CHKERRQ(ierr);
4354   ierr = DMGetWorkArray(dm, mesh->maxConeSize, MPIU_INT, &meet[1]);CHKERRQ(ierr);
4355   /* Copy in cone of first point */
4356   ierr = PetscSectionGetDof(mesh->coneSection, points[0], &dof);CHKERRQ(ierr);
4357   ierr = PetscSectionGetOffset(mesh->coneSection, points[0], &off);CHKERRQ(ierr);
4358   for (meetSize = 0; meetSize < dof; ++meetSize) {
4359     meet[i][meetSize] = mesh->cones[off+meetSize];
4360   }
4361   /* Check each successive cone */
4362   for (p = 1; p < numPoints; ++p) {
4363     PetscInt newMeetSize = 0;
4364 
4365     ierr = PetscSectionGetDof(mesh->coneSection, points[p], &dof);CHKERRQ(ierr);
4366     ierr = PetscSectionGetOffset(mesh->coneSection, points[p], &off);CHKERRQ(ierr);
4367     for (c = 0; c < dof; ++c) {
4368       const PetscInt point = mesh->cones[off+c];
4369 
4370       for (m = 0; m < meetSize; ++m) {
4371         if (point == meet[i][m]) {
4372           meet[1-i][newMeetSize++] = point;
4373           break;
4374         }
4375       }
4376     }
4377     meetSize = newMeetSize;
4378     i        = 1-i;
4379   }
4380   *numCoveringPoints = meetSize;
4381   *coveringPoints    = meet[i];
4382   ierr               = DMRestoreWorkArray(dm, mesh->maxConeSize, MPIU_INT, &meet[1-i]);CHKERRQ(ierr);
4383   PetscFunctionReturn(0);
4384 }
4385 
4386 /*@C
4387   DMPlexRestoreMeet - Restore an array for the meet of the set of points
4388 
4389   Not Collective
4390 
4391   Input Parameters:
4392 + dm - The DMPlex object
4393 . numPoints - The number of input points for the meet
4394 - points - The input points
4395 
4396   Output Parameters:
4397 + numCoveredPoints - The number of points in the meet
4398 - coveredPoints - The points in the meet
4399 
4400   Level: intermediate
4401 
4402   Fortran Notes:
4403   Since it returns an array, this routine is only available in Fortran 90, and you must
4404   include petsc.h90 in your code.
4405 
4406   The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array.
4407 
4408 .seealso: DMPlexGetMeet(), DMPlexGetFullMeet(), DMPlexGetJoin()
4409 @*/
4410 PetscErrorCode DMPlexRestoreMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
4411 {
4412   PetscErrorCode ierr;
4413 
4414   PetscFunctionBegin;
4415   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4416   if (points) PetscValidIntPointer(points,3);
4417   if (numCoveredPoints) PetscValidIntPointer(numCoveredPoints,4);
4418   PetscValidPointer(coveredPoints,5);
4419   ierr = DMRestoreWorkArray(dm, 0, MPIU_INT, (void*) coveredPoints);CHKERRQ(ierr);
4420   if (numCoveredPoints) *numCoveredPoints = 0;
4421   PetscFunctionReturn(0);
4422 }
4423 
4424 /*@C
4425   DMPlexGetFullMeet - Get an array for the meet of the set of points
4426 
4427   Not Collective
4428 
4429   Input Parameters:
4430 + dm - The DMPlex object
4431 . numPoints - The number of input points for the meet
4432 - points - The input points
4433 
4434   Output Parameters:
4435 + numCoveredPoints - The number of points in the meet
4436 - coveredPoints - The points in the meet
4437 
4438   Level: intermediate
4439 
4440   Fortran Notes:
4441   Since it returns an array, this routine is only available in Fortran 90, and you must
4442   include petsc.h90 in your code.
4443 
4444   The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array.
4445 
4446 .seealso: DMPlexGetMeet(), DMPlexRestoreMeet(), DMPlexGetJoin()
4447 @*/
4448 PetscErrorCode DMPlexGetFullMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
4449 {
4450   DM_Plex       *mesh = (DM_Plex*) dm->data;
4451   PetscInt      *offsets, **closures;
4452   PetscInt      *meet[2];
4453   PetscInt       height = 0, maxSize, meetSize = 0, i = 0;
4454   PetscInt       p, h, c, m, mc;
4455   PetscErrorCode ierr;
4456 
4457   PetscFunctionBegin;
4458   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4459   PetscValidPointer(points, 3);
4460   PetscValidPointer(numCoveredPoints, 4);
4461   PetscValidPointer(coveredPoints, 5);
4462 
4463   ierr    = DMPlexGetDepth(dm, &height);CHKERRQ(ierr);
4464   ierr    = PetscMalloc1(numPoints, &closures);CHKERRQ(ierr);
4465   ierr    = DMGetWorkArray(dm, numPoints*(height+2), MPIU_INT, &offsets);CHKERRQ(ierr);
4466   mc      = mesh->maxConeSize;
4467   maxSize = (mc > 1) ? ((PetscPowInt(mc,height+1)-1)/(mc-1)) : height + 1;
4468   ierr    = DMGetWorkArray(dm, maxSize, MPIU_INT, &meet[0]);CHKERRQ(ierr);
4469   ierr    = DMGetWorkArray(dm, maxSize, MPIU_INT, &meet[1]);CHKERRQ(ierr);
4470 
4471   for (p = 0; p < numPoints; ++p) {
4472     PetscInt closureSize;
4473 
4474     ierr = DMPlexGetTransitiveClosure(dm, points[p], PETSC_TRUE, &closureSize, &closures[p]);CHKERRQ(ierr);
4475 
4476     offsets[p*(height+2)+0] = 0;
4477     for (h = 0; h < height+1; ++h) {
4478       PetscInt pStart, pEnd, i;
4479 
4480       ierr = DMPlexGetHeightStratum(dm, h, &pStart, &pEnd);CHKERRQ(ierr);
4481       for (i = offsets[p*(height+2)+h]; i < closureSize; ++i) {
4482         if ((pStart > closures[p][i*2]) || (pEnd <= closures[p][i*2])) {
4483           offsets[p*(height+2)+h+1] = i;
4484           break;
4485         }
4486       }
4487       if (i == closureSize) offsets[p*(height+2)+h+1] = i;
4488     }
4489     PetscCheckFalse(offsets[p*(height+2)+height+1] != closureSize,PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Total size of closure %D should be %D", offsets[p*(height+2)+height+1], closureSize);
4490   }
4491   for (h = 0; h < height+1; ++h) {
4492     PetscInt dof;
4493 
4494     /* Copy in cone of first point */
4495     dof = offsets[h+1] - offsets[h];
4496     for (meetSize = 0; meetSize < dof; ++meetSize) {
4497       meet[i][meetSize] = closures[0][(offsets[h]+meetSize)*2];
4498     }
4499     /* Check each successive cone */
4500     for (p = 1; p < numPoints && meetSize; ++p) {
4501       PetscInt newMeetSize = 0;
4502 
4503       dof = offsets[p*(height+2)+h+1] - offsets[p*(height+2)+h];
4504       for (c = 0; c < dof; ++c) {
4505         const PetscInt point = closures[p][(offsets[p*(height+2)+h]+c)*2];
4506 
4507         for (m = 0; m < meetSize; ++m) {
4508           if (point == meet[i][m]) {
4509             meet[1-i][newMeetSize++] = point;
4510             break;
4511           }
4512         }
4513       }
4514       meetSize = newMeetSize;
4515       i        = 1-i;
4516     }
4517     if (meetSize) break;
4518   }
4519   *numCoveredPoints = meetSize;
4520   *coveredPoints    = meet[i];
4521   for (p = 0; p < numPoints; ++p) {
4522     ierr = DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_TRUE, NULL, &closures[p]);CHKERRQ(ierr);
4523   }
4524   ierr = PetscFree(closures);CHKERRQ(ierr);
4525   ierr = DMRestoreWorkArray(dm, numPoints*(height+2), MPIU_INT, &offsets);CHKERRQ(ierr);
4526   ierr = DMRestoreWorkArray(dm, mesh->maxConeSize, MPIU_INT, &meet[1-i]);CHKERRQ(ierr);
4527   PetscFunctionReturn(0);
4528 }
4529 
4530 /*@C
4531   DMPlexEqual - Determine if two DMs have the same topology
4532 
4533   Not Collective
4534 
4535   Input Parameters:
4536 + dmA - A DMPlex object
4537 - dmB - A DMPlex object
4538 
4539   Output Parameters:
4540 . equal - PETSC_TRUE if the topologies are identical
4541 
4542   Level: intermediate
4543 
4544   Notes:
4545   We are not solving graph isomorphism, so we do not permutation.
4546 
4547 .seealso: DMPlexGetCone()
4548 @*/
4549 PetscErrorCode DMPlexEqual(DM dmA, DM dmB, PetscBool *equal)
4550 {
4551   PetscInt       depth, depthB, pStart, pEnd, pStartB, pEndB, p;
4552   PetscErrorCode ierr;
4553 
4554   PetscFunctionBegin;
4555   PetscValidHeaderSpecific(dmA, DM_CLASSID, 1);
4556   PetscValidHeaderSpecific(dmB, DM_CLASSID, 2);
4557   PetscValidPointer(equal, 3);
4558 
4559   *equal = PETSC_FALSE;
4560   ierr = DMPlexGetDepth(dmA, &depth);CHKERRQ(ierr);
4561   ierr = DMPlexGetDepth(dmB, &depthB);CHKERRQ(ierr);
4562   if (depth != depthB) PetscFunctionReturn(0);
4563   ierr = DMPlexGetChart(dmA, &pStart,  &pEnd);CHKERRQ(ierr);
4564   ierr = DMPlexGetChart(dmB, &pStartB, &pEndB);CHKERRQ(ierr);
4565   if ((pStart != pStartB) || (pEnd != pEndB)) PetscFunctionReturn(0);
4566   for (p = pStart; p < pEnd; ++p) {
4567     const PetscInt *cone, *coneB, *ornt, *orntB, *support, *supportB;
4568     PetscInt        coneSize, coneSizeB, c, supportSize, supportSizeB, s;
4569 
4570     ierr = DMPlexGetConeSize(dmA, p, &coneSize);CHKERRQ(ierr);
4571     ierr = DMPlexGetCone(dmA, p, &cone);CHKERRQ(ierr);
4572     ierr = DMPlexGetConeOrientation(dmA, p, &ornt);CHKERRQ(ierr);
4573     ierr = DMPlexGetConeSize(dmB, p, &coneSizeB);CHKERRQ(ierr);
4574     ierr = DMPlexGetCone(dmB, p, &coneB);CHKERRQ(ierr);
4575     ierr = DMPlexGetConeOrientation(dmB, p, &orntB);CHKERRQ(ierr);
4576     if (coneSize != coneSizeB) PetscFunctionReturn(0);
4577     for (c = 0; c < coneSize; ++c) {
4578       if (cone[c] != coneB[c]) PetscFunctionReturn(0);
4579       if (ornt[c] != orntB[c]) PetscFunctionReturn(0);
4580     }
4581     ierr = DMPlexGetSupportSize(dmA, p, &supportSize);CHKERRQ(ierr);
4582     ierr = DMPlexGetSupport(dmA, p, &support);CHKERRQ(ierr);
4583     ierr = DMPlexGetSupportSize(dmB, p, &supportSizeB);CHKERRQ(ierr);
4584     ierr = DMPlexGetSupport(dmB, p, &supportB);CHKERRQ(ierr);
4585     if (supportSize != supportSizeB) PetscFunctionReturn(0);
4586     for (s = 0; s < supportSize; ++s) {
4587       if (support[s] != supportB[s]) PetscFunctionReturn(0);
4588     }
4589   }
4590   *equal = PETSC_TRUE;
4591   PetscFunctionReturn(0);
4592 }
4593 
4594 /*@C
4595   DMPlexGetNumFaceVertices - Returns the number of vertices on a face
4596 
4597   Not Collective
4598 
4599   Input Parameters:
4600 + dm         - The DMPlex
4601 . cellDim    - The cell dimension
4602 - numCorners - The number of vertices on a cell
4603 
4604   Output Parameters:
4605 . numFaceVertices - The number of vertices on a face
4606 
4607   Level: developer
4608 
4609   Notes:
4610   Of course this can only work for a restricted set of symmetric shapes
4611 
4612 .seealso: DMPlexGetCone()
4613 @*/
4614 PetscErrorCode DMPlexGetNumFaceVertices(DM dm, PetscInt cellDim, PetscInt numCorners, PetscInt *numFaceVertices)
4615 {
4616   MPI_Comm       comm;
4617   PetscErrorCode ierr;
4618 
4619   PetscFunctionBegin;
4620   ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr);
4621   PetscValidPointer(numFaceVertices,4);
4622   switch (cellDim) {
4623   case 0:
4624     *numFaceVertices = 0;
4625     break;
4626   case 1:
4627     *numFaceVertices = 1;
4628     break;
4629   case 2:
4630     switch (numCorners) {
4631     case 3: /* triangle */
4632       *numFaceVertices = 2; /* Edge has 2 vertices */
4633       break;
4634     case 4: /* quadrilateral */
4635       *numFaceVertices = 2; /* Edge has 2 vertices */
4636       break;
4637     case 6: /* quadratic triangle, tri and quad cohesive Lagrange cells */
4638       *numFaceVertices = 3; /* Edge has 3 vertices */
4639       break;
4640     case 9: /* quadratic quadrilateral, quadratic quad cohesive Lagrange cells */
4641       *numFaceVertices = 3; /* Edge has 3 vertices */
4642       break;
4643     default:
4644       SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %D for dimension %D", numCorners, cellDim);
4645     }
4646     break;
4647   case 3:
4648     switch (numCorners) {
4649     case 4: /* tetradehdron */
4650       *numFaceVertices = 3; /* Face has 3 vertices */
4651       break;
4652     case 6: /* tet cohesive cells */
4653       *numFaceVertices = 4; /* Face has 4 vertices */
4654       break;
4655     case 8: /* hexahedron */
4656       *numFaceVertices = 4; /* Face has 4 vertices */
4657       break;
4658     case 9: /* tet cohesive Lagrange cells */
4659       *numFaceVertices = 6; /* Face has 6 vertices */
4660       break;
4661     case 10: /* quadratic tetrahedron */
4662       *numFaceVertices = 6; /* Face has 6 vertices */
4663       break;
4664     case 12: /* hex cohesive Lagrange cells */
4665       *numFaceVertices = 6; /* Face has 6 vertices */
4666       break;
4667     case 18: /* quadratic tet cohesive Lagrange cells */
4668       *numFaceVertices = 6; /* Face has 6 vertices */
4669       break;
4670     case 27: /* quadratic hexahedron, quadratic hex cohesive Lagrange cells */
4671       *numFaceVertices = 9; /* Face has 9 vertices */
4672       break;
4673     default:
4674       SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %D for dimension %D", numCorners, cellDim);
4675     }
4676     break;
4677   default:
4678     SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid cell dimension %D", cellDim);
4679   }
4680   PetscFunctionReturn(0);
4681 }
4682 
4683 /*@
4684   DMPlexGetDepthLabel - Get the DMLabel recording the depth of each point
4685 
4686   Not Collective
4687 
4688   Input Parameter:
4689 . dm    - The DMPlex object
4690 
4691   Output Parameter:
4692 . depthLabel - The DMLabel recording point depth
4693 
4694   Level: developer
4695 
4696 .seealso: DMPlexGetDepth(), DMPlexGetHeightStratum(), DMPlexGetDepthStratum(), DMPlexGetPointDepth(),
4697 @*/
4698 PetscErrorCode DMPlexGetDepthLabel(DM dm, DMLabel *depthLabel)
4699 {
4700   PetscFunctionBegin;
4701   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4702   PetscValidPointer(depthLabel, 2);
4703   *depthLabel = dm->depthLabel;
4704   PetscFunctionReturn(0);
4705 }
4706 
4707 /*@
4708   DMPlexGetDepth - Get the depth of the DAG representing this mesh
4709 
4710   Not Collective
4711 
4712   Input Parameter:
4713 . dm    - The DMPlex object
4714 
4715   Output Parameter:
4716 . depth - The number of strata (breadth first levels) in the DAG
4717 
4718   Level: developer
4719 
4720   Notes:
4721   This returns maximum of point depths over all points, i.e. maximum value of the label returned by DMPlexGetDepthLabel().
4722   The point depth is described more in detail in DMPlexGetDepthStratum().
4723   An empty mesh gives -1.
4724 
4725 .seealso: DMPlexGetDepthLabel(), DMPlexGetDepthStratum(), DMPlexGetPointDepth(), DMPlexSymmetrize()
4726 @*/
4727 PetscErrorCode DMPlexGetDepth(DM dm, PetscInt *depth)
4728 {
4729   DMLabel        label;
4730   PetscInt       d = 0;
4731   PetscErrorCode ierr;
4732 
4733   PetscFunctionBegin;
4734   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4735   PetscValidPointer(depth, 2);
4736   ierr = DMPlexGetDepthLabel(dm, &label);CHKERRQ(ierr);
4737   if (label) {ierr = DMLabelGetNumValues(label, &d);CHKERRQ(ierr);}
4738   *depth = d-1;
4739   PetscFunctionReturn(0);
4740 }
4741 
4742 /*@
4743   DMPlexGetDepthStratum - Get the bounds [start, end) for all points at a certain depth.
4744 
4745   Not Collective
4746 
4747   Input Parameters:
4748 + dm           - The DMPlex object
4749 - stratumValue - The requested depth
4750 
4751   Output Parameters:
4752 + start - The first point at this depth
4753 - end   - One beyond the last point at this depth
4754 
4755   Notes:
4756   Depth indexing is related to topological dimension.  Depth stratum 0 contains the lowest topological dimension points,
4757   often "vertices".  If the mesh is "interpolated" (see DMPlexInterpolate()), then depth stratum 1 contains the next
4758   higher dimension, e.g., "edges".
4759 
4760   Level: developer
4761 
4762 .seealso: DMPlexGetHeightStratum(), DMPlexGetDepth(), DMPlexGetDepthLabel(), DMPlexGetPointDepth(), DMPlexSymmetrize(), DMPlexInterpolate()
4763 @*/
4764 PetscErrorCode DMPlexGetDepthStratum(DM dm, PetscInt stratumValue, PetscInt *start, PetscInt *end)
4765 {
4766   DMLabel        label;
4767   PetscInt       pStart, pEnd;
4768   PetscErrorCode ierr;
4769 
4770   PetscFunctionBegin;
4771   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4772   if (start) {PetscValidPointer(start, 3); *start = 0;}
4773   if (end)   {PetscValidPointer(end,   4); *end   = 0;}
4774   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
4775   if (pStart == pEnd) PetscFunctionReturn(0);
4776   if (stratumValue < 0) {
4777     if (start) *start = pStart;
4778     if (end)   *end   = pEnd;
4779     PetscFunctionReturn(0);
4780   }
4781   ierr = DMPlexGetDepthLabel(dm, &label);CHKERRQ(ierr);
4782   PetscCheckFalse(!label,PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "No label named depth was found");
4783   ierr = DMLabelGetStratumBounds(label, stratumValue, start, end);CHKERRQ(ierr);
4784   PetscFunctionReturn(0);
4785 }
4786 
4787 /*@
4788   DMPlexGetHeightStratum - Get the bounds [start, end) for all points at a certain height.
4789 
4790   Not Collective
4791 
4792   Input Parameters:
4793 + dm           - The DMPlex object
4794 - stratumValue - The requested height
4795 
4796   Output Parameters:
4797 + start - The first point at this height
4798 - end   - One beyond the last point at this height
4799 
4800   Notes:
4801   Height indexing is related to topological codimension.  Height stratum 0 contains the highest topological dimension
4802   points, often called "cells" or "elements".  If the mesh is "interpolated" (see DMPlexInterpolate()), then height
4803   stratum 1 contains the boundary of these "cells", often called "faces" or "facets".
4804 
4805   Level: developer
4806 
4807 .seealso: DMPlexGetDepthStratum(), DMPlexGetDepth(), DMPlexGetPointHeight()
4808 @*/
4809 PetscErrorCode DMPlexGetHeightStratum(DM dm, PetscInt stratumValue, PetscInt *start, PetscInt *end)
4810 {
4811   DMLabel        label;
4812   PetscInt       depth, pStart, pEnd;
4813   PetscErrorCode ierr;
4814 
4815   PetscFunctionBegin;
4816   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4817   if (start) {PetscValidPointer(start, 3); *start = 0;}
4818   if (end)   {PetscValidPointer(end,   4); *end   = 0;}
4819   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
4820   if (pStart == pEnd) PetscFunctionReturn(0);
4821   if (stratumValue < 0) {
4822     if (start) *start = pStart;
4823     if (end)   *end   = pEnd;
4824     PetscFunctionReturn(0);
4825   }
4826   ierr = DMPlexGetDepthLabel(dm, &label);CHKERRQ(ierr);
4827   PetscCheckFalse(!label,PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "No label named depth was found");
4828   ierr = DMLabelGetNumValues(label, &depth);CHKERRQ(ierr);
4829   ierr = DMLabelGetStratumBounds(label, depth-1-stratumValue, start, end);CHKERRQ(ierr);
4830   PetscFunctionReturn(0);
4831 }
4832 
4833 /*@
4834   DMPlexGetPointDepth - Get the depth of a given point
4835 
4836   Not Collective
4837 
4838   Input Parameters:
4839 + dm    - The DMPlex object
4840 - point - The point
4841 
4842   Output Parameter:
4843 . depth - The depth of the point
4844 
4845   Level: intermediate
4846 
4847 .seealso: DMPlexGetCellType(), DMPlexGetDepthLabel(), DMPlexGetDepth(), DMPlexGetPointHeight()
4848 @*/
4849 PetscErrorCode DMPlexGetPointDepth(DM dm, PetscInt point, PetscInt *depth)
4850 {
4851   PetscErrorCode ierr;
4852 
4853   PetscFunctionBegin;
4854   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4855   PetscValidIntPointer(depth, 3);
4856   ierr = DMLabelGetValue(dm->depthLabel, point, depth);CHKERRQ(ierr);
4857   PetscFunctionReturn(0);
4858 }
4859 
4860 /*@
4861   DMPlexGetPointHeight - Get the height of a given point
4862 
4863   Not Collective
4864 
4865   Input Parameters:
4866 + dm    - The DMPlex object
4867 - point - The point
4868 
4869   Output Parameter:
4870 . height - The height of the point
4871 
4872   Level: intermediate
4873 
4874 .seealso: DMPlexGetCellType(), DMPlexGetDepthLabel(), DMPlexGetDepth(), DMPlexGetPointDepth()
4875 @*/
4876 PetscErrorCode DMPlexGetPointHeight(DM dm, PetscInt point, PetscInt *height)
4877 {
4878   PetscInt       n, pDepth;
4879   PetscErrorCode ierr;
4880 
4881   PetscFunctionBegin;
4882   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4883   PetscValidIntPointer(height, 3);
4884   ierr = DMLabelGetNumValues(dm->depthLabel, &n);CHKERRQ(ierr);
4885   ierr = DMLabelGetValue(dm->depthLabel, point, &pDepth);CHKERRQ(ierr);
4886   *height = n - 1 - pDepth;  /* DAG depth is n-1 */
4887   PetscFunctionReturn(0);
4888 }
4889 
4890 /*@
4891   DMPlexGetCellTypeLabel - Get the DMLabel recording the polytope type of each cell
4892 
4893   Not Collective
4894 
4895   Input Parameter:
4896 . dm - The DMPlex object
4897 
4898   Output Parameter:
4899 . celltypeLabel - The DMLabel recording cell polytope type
4900 
4901   Note: This function will trigger automatica computation of cell types. This can be disabled by calling
4902   DMCreateLabel(dm, "celltype") beforehand.
4903 
4904   Level: developer
4905 
4906 .seealso: DMPlexGetCellType(), DMPlexGetDepthLabel(), DMCreateLabel()
4907 @*/
4908 PetscErrorCode DMPlexGetCellTypeLabel(DM dm, DMLabel *celltypeLabel)
4909 {
4910   PetscErrorCode ierr;
4911 
4912   PetscFunctionBegin;
4913   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4914   PetscValidPointer(celltypeLabel, 2);
4915   if (!dm->celltypeLabel) {ierr = DMPlexComputeCellTypes(dm);CHKERRQ(ierr);}
4916   *celltypeLabel = dm->celltypeLabel;
4917   PetscFunctionReturn(0);
4918 }
4919 
4920 /*@
4921   DMPlexGetCellType - Get the polytope type of a given cell
4922 
4923   Not Collective
4924 
4925   Input Parameters:
4926 + dm   - The DMPlex object
4927 - cell - The cell
4928 
4929   Output Parameter:
4930 . celltype - The polytope type of the cell
4931 
4932   Level: intermediate
4933 
4934 .seealso: DMPlexGetCellTypeLabel(), DMPlexGetDepthLabel(), DMPlexGetDepth()
4935 @*/
4936 PetscErrorCode DMPlexGetCellType(DM dm, PetscInt cell, DMPolytopeType *celltype)
4937 {
4938   DMLabel        label;
4939   PetscInt       ct;
4940   PetscErrorCode ierr;
4941 
4942   PetscFunctionBegin;
4943   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4944   PetscValidPointer(celltype, 3);
4945   ierr = DMPlexGetCellTypeLabel(dm, &label);CHKERRQ(ierr);
4946   ierr = DMLabelGetValue(label, cell, &ct);CHKERRQ(ierr);
4947   PetscCheckFalse(ct < 0,PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Cell %D has not been assigned a cell type", cell);
4948   *celltype = (DMPolytopeType) ct;
4949   PetscFunctionReturn(0);
4950 }
4951 
4952 /*@
4953   DMPlexSetCellType - Set the polytope type of a given cell
4954 
4955   Not Collective
4956 
4957   Input Parameters:
4958 + dm   - The DMPlex object
4959 . cell - The cell
4960 - celltype - The polytope type of the cell
4961 
4962   Note: By default, cell types will be automatically computed using DMPlexComputeCellTypes() before this function
4963   is executed. This function will override the computed type. However, if automatic classification will not succeed
4964   and a user wants to manually specify all types, the classification must be disabled by calling
4965   DMCreaateLabel(dm, "celltype") before getting or setting any cell types.
4966 
4967   Level: advanced
4968 
4969 .seealso: DMPlexGetCellTypeLabel(), DMPlexGetDepthLabel(), DMPlexGetDepth(), DMPlexComputeCellTypes(), DMCreateLabel()
4970 @*/
4971 PetscErrorCode DMPlexSetCellType(DM dm, PetscInt cell, DMPolytopeType celltype)
4972 {
4973   DMLabel        label;
4974   PetscErrorCode ierr;
4975 
4976   PetscFunctionBegin;
4977   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4978   ierr = DMPlexGetCellTypeLabel(dm, &label);CHKERRQ(ierr);
4979   ierr = DMLabelSetValue(label, cell, celltype);CHKERRQ(ierr);
4980   PetscFunctionReturn(0);
4981 }
4982 
4983 PetscErrorCode DMCreateCoordinateDM_Plex(DM dm, DM *cdm)
4984 {
4985   PetscSection   section, s;
4986   Mat            m;
4987   PetscInt       maxHeight;
4988   PetscErrorCode ierr;
4989 
4990   PetscFunctionBegin;
4991   ierr = DMClone(dm, cdm);CHKERRQ(ierr);
4992   ierr = DMPlexGetMaxProjectionHeight(dm, &maxHeight);CHKERRQ(ierr);
4993   ierr = DMPlexSetMaxProjectionHeight(*cdm, maxHeight);CHKERRQ(ierr);
4994   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)dm), &section);CHKERRQ(ierr);
4995   ierr = DMSetLocalSection(*cdm, section);CHKERRQ(ierr);
4996   ierr = PetscSectionDestroy(&section);CHKERRQ(ierr);
4997   ierr = PetscSectionCreate(PETSC_COMM_SELF, &s);CHKERRQ(ierr);
4998   ierr = MatCreate(PETSC_COMM_SELF, &m);CHKERRQ(ierr);
4999   ierr = DMSetDefaultConstraints(*cdm, s, m, NULL);CHKERRQ(ierr);
5000   ierr = PetscSectionDestroy(&s);CHKERRQ(ierr);
5001   ierr = MatDestroy(&m);CHKERRQ(ierr);
5002 
5003   ierr = DMSetNumFields(*cdm, 1);CHKERRQ(ierr);
5004   ierr = DMCreateDS(*cdm);CHKERRQ(ierr);
5005   PetscFunctionReturn(0);
5006 }
5007 
5008 PetscErrorCode DMCreateCoordinateField_Plex(DM dm, DMField *field)
5009 {
5010   Vec            coordsLocal;
5011   DM             coordsDM;
5012   PetscErrorCode ierr;
5013 
5014   PetscFunctionBegin;
5015   *field = NULL;
5016   ierr = DMGetCoordinatesLocal(dm,&coordsLocal);CHKERRQ(ierr);
5017   ierr = DMGetCoordinateDM(dm,&coordsDM);CHKERRQ(ierr);
5018   if (coordsLocal && coordsDM) {
5019     ierr = DMFieldCreateDS(coordsDM, 0, coordsLocal, field);CHKERRQ(ierr);
5020   }
5021   PetscFunctionReturn(0);
5022 }
5023 
5024 /*@C
5025   DMPlexGetConeSection - Return a section which describes the layout of cone data
5026 
5027   Not Collective
5028 
5029   Input Parameters:
5030 . dm        - The DMPlex object
5031 
5032   Output Parameter:
5033 . section - The PetscSection object
5034 
5035   Level: developer
5036 
5037 .seealso: DMPlexGetSupportSection(), DMPlexGetCones(), DMPlexGetConeOrientations()
5038 @*/
5039 PetscErrorCode DMPlexGetConeSection(DM dm, PetscSection *section)
5040 {
5041   DM_Plex *mesh = (DM_Plex*) dm->data;
5042 
5043   PetscFunctionBegin;
5044   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5045   if (section) *section = mesh->coneSection;
5046   PetscFunctionReturn(0);
5047 }
5048 
5049 /*@C
5050   DMPlexGetSupportSection - Return a section which describes the layout of support data
5051 
5052   Not Collective
5053 
5054   Input Parameters:
5055 . dm        - The DMPlex object
5056 
5057   Output Parameter:
5058 . section - The PetscSection object
5059 
5060   Level: developer
5061 
5062 .seealso: DMPlexGetConeSection()
5063 @*/
5064 PetscErrorCode DMPlexGetSupportSection(DM dm, PetscSection *section)
5065 {
5066   DM_Plex *mesh = (DM_Plex*) dm->data;
5067 
5068   PetscFunctionBegin;
5069   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5070   if (section) *section = mesh->supportSection;
5071   PetscFunctionReturn(0);
5072 }
5073 
5074 /*@C
5075   DMPlexGetCones - Return cone data
5076 
5077   Not Collective
5078 
5079   Input Parameters:
5080 . dm        - The DMPlex object
5081 
5082   Output Parameter:
5083 . cones - The cone for each point
5084 
5085   Level: developer
5086 
5087 .seealso: DMPlexGetConeSection()
5088 @*/
5089 PetscErrorCode DMPlexGetCones(DM dm, PetscInt *cones[])
5090 {
5091   DM_Plex *mesh = (DM_Plex*) dm->data;
5092 
5093   PetscFunctionBegin;
5094   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5095   if (cones) *cones = mesh->cones;
5096   PetscFunctionReturn(0);
5097 }
5098 
5099 /*@C
5100   DMPlexGetConeOrientations - Return cone orientation data
5101 
5102   Not Collective
5103 
5104   Input Parameters:
5105 . dm        - The DMPlex object
5106 
5107   Output Parameter:
5108 . coneOrientations - The array of cone orientations for all points
5109 
5110   Level: developer
5111 
5112   Notes:
5113   The PetscSection returned by DMPlexGetConeSection() partitions coneOrientations into cone orientations of particular points as returned by DMPlexGetConeOrientation().
5114 
5115   The meaning of coneOrientations values is detailed in DMPlexGetConeOrientation().
5116 
5117 .seealso: DMPlexGetConeSection(), DMPlexGetConeOrientation()
5118 @*/
5119 PetscErrorCode DMPlexGetConeOrientations(DM dm, PetscInt *coneOrientations[])
5120 {
5121   DM_Plex *mesh = (DM_Plex*) dm->data;
5122 
5123   PetscFunctionBegin;
5124   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5125   if (coneOrientations) *coneOrientations = mesh->coneOrientations;
5126   PetscFunctionReturn(0);
5127 }
5128 
5129 /******************************** FEM Support **********************************/
5130 
5131 /*
5132  Returns number of components and tensor degree for the field.  For interpolated meshes, line should be a point
5133  representing a line in the section.
5134 */
5135 static PetscErrorCode PetscSectionFieldGetTensorDegree_Private(PetscSection section,PetscInt field,PetscInt line,PetscBool vertexchart,PetscInt *Nc,PetscInt *k)
5136 {
5137   PetscErrorCode ierr;
5138 
5139   PetscFunctionBeginHot;
5140   ierr = PetscSectionGetFieldComponents(section, field, Nc);CHKERRQ(ierr);
5141   if (line < 0) {
5142     *k = 0;
5143     *Nc = 0;
5144   } else if (vertexchart) {            /* If we only have a vertex chart, we must have degree k=1 */
5145     *k = 1;
5146   } else {                      /* Assume the full interpolated mesh is in the chart; lines in particular */
5147     /* An order k SEM disc has k-1 dofs on an edge */
5148     ierr = PetscSectionGetFieldDof(section, line, field, k);CHKERRQ(ierr);
5149     *k = *k / *Nc + 1;
5150   }
5151   PetscFunctionReturn(0);
5152 }
5153 
5154 /*@
5155 
5156   DMPlexSetClosurePermutationTensor - Create a permutation from the default (BFS) point ordering in the closure, to a
5157   lexicographic ordering over the tensor product cell (i.e., line, quad, hex, etc.), and set this permutation in the
5158   section provided (or the section of the DM).
5159 
5160   Input Parameters:
5161 + dm      - The DM
5162 . point   - Either a cell (highest dim point) or an edge (dim 1 point), or PETSC_DETERMINE
5163 - section - The PetscSection to reorder, or NULL for the default section
5164 
5165   Note: The point is used to determine the number of dofs/field on an edge. For SEM, this is related to the polynomial
5166   degree of the basis.
5167 
5168   Example:
5169   A typical interpolated single-quad mesh might order points as
5170 .vb
5171   [c0, v1, v2, v3, v4, e5, e6, e7, e8]
5172 
5173   v4 -- e6 -- v3
5174   |           |
5175   e7    c0    e8
5176   |           |
5177   v1 -- e5 -- v2
5178 .ve
5179 
5180   (There is no significance to the ordering described here.)  The default section for a Q3 quad might typically assign
5181   dofs in the order of points, e.g.,
5182 .vb
5183     c0 -> [0,1,2,3]
5184     v1 -> [4]
5185     ...
5186     e5 -> [8, 9]
5187 .ve
5188 
5189   which corresponds to the dofs
5190 .vb
5191     6   10  11  7
5192     13  2   3   15
5193     12  0   1   14
5194     4   8   9   5
5195 .ve
5196 
5197   The closure in BFS ordering works through height strata (cells, edges, vertices) to produce the ordering
5198 .vb
5199   0 1 2 3 8 9 14 15 11 10 13 12 4 5 7 6
5200 .ve
5201 
5202   After calling DMPlexSetClosurePermutationTensor(), the closure will be ordered lexicographically,
5203 .vb
5204    4 8 9 5 12 0 1 14 13 2 3 15 6 10 11 7
5205 .ve
5206 
5207   Level: developer
5208 
5209 .seealso: DMGetLocalSection(), PetscSectionSetClosurePermutation(), DMSetGlobalSection()
5210 @*/
5211 PetscErrorCode DMPlexSetClosurePermutationTensor(DM dm, PetscInt point, PetscSection section)
5212 {
5213   DMLabel        label;
5214   PetscInt       dim, depth = -1, eStart = -1, Nf;
5215   PetscBool      vertexchart;
5216   PetscErrorCode ierr;
5217 
5218   PetscFunctionBegin;
5219   ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr);
5220   if (dim < 1) PetscFunctionReturn(0);
5221   if (point < 0) {
5222     PetscInt sStart,sEnd;
5223 
5224     ierr = DMPlexGetDepthStratum(dm, 1, &sStart, &sEnd);CHKERRQ(ierr);
5225     point = sEnd-sStart ? sStart : point;
5226   }
5227   ierr = DMPlexGetDepthLabel(dm, &label);CHKERRQ(ierr);
5228   if (point >= 0) { ierr = DMLabelGetValue(label, point, &depth);CHKERRQ(ierr); }
5229   if (!section) {ierr = DMGetLocalSection(dm, &section);CHKERRQ(ierr);}
5230   if (depth == 1) {eStart = point;}
5231   else if  (depth == dim) {
5232     const PetscInt *cone;
5233 
5234     ierr = DMPlexGetCone(dm, point, &cone);CHKERRQ(ierr);
5235     if (dim == 2) eStart = cone[0];
5236     else if (dim == 3) {
5237       const PetscInt *cone2;
5238       ierr = DMPlexGetCone(dm, cone[0], &cone2);CHKERRQ(ierr);
5239       eStart = cone2[0];
5240     } else SETERRQ(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);
5241   } else PetscCheckFalse(depth >= 0,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);
5242   {                             /* Determine whether the chart covers all points or just vertices. */
5243     PetscInt pStart,pEnd,cStart,cEnd;
5244     ierr = DMPlexGetDepthStratum(dm,0,&pStart,&pEnd);CHKERRQ(ierr);
5245     ierr = PetscSectionGetChart(section,&cStart,&cEnd);CHKERRQ(ierr);
5246     if (pStart == cStart && pEnd == cEnd) vertexchart = PETSC_TRUE;      /* Only vertices are in the chart */
5247     else if (cStart <= point && point < cEnd) vertexchart = PETSC_FALSE; /* Some interpolated points exist in the chart */
5248     else vertexchart = PETSC_TRUE;                                       /* Some interpolated points are not in chart; assume dofs only at cells and vertices */
5249   }
5250   ierr = PetscSectionGetNumFields(section, &Nf);CHKERRQ(ierr);
5251   for (PetscInt d=1; d<=dim; d++) {
5252     PetscInt k, f, Nc, c, i, j, size = 0, offset = 0, foffset = 0;
5253     PetscInt *perm;
5254 
5255     for (f = 0; f < Nf; ++f) {
5256       ierr = PetscSectionFieldGetTensorDegree_Private(section,f,eStart,vertexchart,&Nc,&k);CHKERRQ(ierr);
5257       size += PetscPowInt(k+1, d)*Nc;
5258     }
5259     ierr = PetscMalloc1(size, &perm);CHKERRQ(ierr);
5260     for (f = 0; f < Nf; ++f) {
5261       switch (d) {
5262       case 1:
5263         ierr = PetscSectionFieldGetTensorDegree_Private(section,f,eStart,vertexchart,&Nc,&k);CHKERRQ(ierr);
5264         /*
5265          Original ordering is [ edge of length k-1; vtx0; vtx1 ]
5266          We want              [ vtx0; edge of length k-1; vtx1 ]
5267          */
5268         for (c=0; c<Nc; c++,offset++) perm[offset] = (k-1)*Nc + c + foffset;
5269         for (i=0; i<k-1; i++) for (c=0; c<Nc; c++,offset++) perm[offset] = i*Nc + c + foffset;
5270         for (c=0; c<Nc; c++,offset++) perm[offset] = k*Nc + c + foffset;
5271         foffset = offset;
5272         break;
5273       case 2:
5274         /* The original quad closure is oriented clockwise, {f, e_b, e_r, e_t, e_l, v_lb, v_rb, v_tr, v_tl} */
5275         ierr = PetscSectionFieldGetTensorDegree_Private(section,f,eStart,vertexchart,&Nc,&k);CHKERRQ(ierr);
5276         /* The SEM order is
5277 
5278          v_lb, {e_b}, v_rb,
5279          e^{(k-1)-i}_l, {f^{i*(k-1)}}, e^i_r,
5280          v_lt, reverse {e_t}, v_rt
5281          */
5282         {
5283           const PetscInt of   = 0;
5284           const PetscInt oeb  = of   + PetscSqr(k-1);
5285           const PetscInt oer  = oeb  + (k-1);
5286           const PetscInt oet  = oer  + (k-1);
5287           const PetscInt oel  = oet  + (k-1);
5288           const PetscInt ovlb = oel  + (k-1);
5289           const PetscInt ovrb = ovlb + 1;
5290           const PetscInt ovrt = ovrb + 1;
5291           const PetscInt ovlt = ovrt + 1;
5292           PetscInt       o;
5293 
5294           /* bottom */
5295           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlb*Nc + c + foffset;
5296           for (o = oeb; o < oer; ++o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
5297           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrb*Nc + c + foffset;
5298           /* middle */
5299           for (i = 0; i < k-1; ++i) {
5300             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oel+(k-2)-i)*Nc + c + foffset;
5301             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;
5302             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oer+i)*Nc + c + foffset;
5303           }
5304           /* top */
5305           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlt*Nc + c + foffset;
5306           for (o = oel-1; o >= oet; --o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
5307           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrt*Nc + c + foffset;
5308           foffset = offset;
5309         }
5310         break;
5311       case 3:
5312         /* The original hex closure is
5313 
5314          {c,
5315          f_b, f_t, f_f, f_b, f_r, f_l,
5316          e_bl, e_bb, e_br, e_bf,  e_tf, e_tr, e_tb, e_tl,  e_rf, e_lf, e_lb, e_rb,
5317          v_blf, v_blb, v_brb, v_brf, v_tlf, v_trf, v_trb, v_tlb}
5318          */
5319         ierr = PetscSectionFieldGetTensorDegree_Private(section,f,eStart,vertexchart,&Nc,&k);CHKERRQ(ierr);
5320         /* The SEM order is
5321          Bottom Slice
5322          v_blf, {e^{(k-1)-n}_bf}, v_brf,
5323          e^{i}_bl, f^{n*(k-1)+(k-1)-i}_b, e^{(k-1)-i}_br,
5324          v_blb, {e_bb}, v_brb,
5325 
5326          Middle Slice (j)
5327          {e^{(k-1)-j}_lf}, {f^{j*(k-1)+n}_f}, e^j_rf,
5328          f^{i*(k-1)+j}_l, {c^{(j*(k-1) + i)*(k-1)+n}_t}, f^{j*(k-1)+i}_r,
5329          e^j_lb, {f^{j*(k-1)+(k-1)-n}_b}, e^{(k-1)-j}_rb,
5330 
5331          Top Slice
5332          v_tlf, {e_tf}, v_trf,
5333          e^{(k-1)-i}_tl, {f^{i*(k-1)}_t}, e^{i}_tr,
5334          v_tlb, {e^{(k-1)-n}_tb}, v_trb,
5335          */
5336         {
5337           const PetscInt oc    = 0;
5338           const PetscInt ofb   = oc    + PetscSqr(k-1)*(k-1);
5339           const PetscInt oft   = ofb   + PetscSqr(k-1);
5340           const PetscInt off   = oft   + PetscSqr(k-1);
5341           const PetscInt ofk   = off   + PetscSqr(k-1);
5342           const PetscInt ofr   = ofk   + PetscSqr(k-1);
5343           const PetscInt ofl   = ofr   + PetscSqr(k-1);
5344           const PetscInt oebl  = ofl   + PetscSqr(k-1);
5345           const PetscInt oebb  = oebl  + (k-1);
5346           const PetscInt oebr  = oebb  + (k-1);
5347           const PetscInt oebf  = oebr  + (k-1);
5348           const PetscInt oetf  = oebf  + (k-1);
5349           const PetscInt oetr  = oetf  + (k-1);
5350           const PetscInt oetb  = oetr  + (k-1);
5351           const PetscInt oetl  = oetb  + (k-1);
5352           const PetscInt oerf  = oetl  + (k-1);
5353           const PetscInt oelf  = oerf  + (k-1);
5354           const PetscInt oelb  = oelf  + (k-1);
5355           const PetscInt oerb  = oelb  + (k-1);
5356           const PetscInt ovblf = oerb  + (k-1);
5357           const PetscInt ovblb = ovblf + 1;
5358           const PetscInt ovbrb = ovblb + 1;
5359           const PetscInt ovbrf = ovbrb + 1;
5360           const PetscInt ovtlf = ovbrf + 1;
5361           const PetscInt ovtrf = ovtlf + 1;
5362           const PetscInt ovtrb = ovtrf + 1;
5363           const PetscInt ovtlb = ovtrb + 1;
5364           PetscInt       o, n;
5365 
5366           /* Bottom Slice */
5367           /*   bottom */
5368           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblf*Nc + c + foffset;
5369           for (o = oetf-1; o >= oebf; --o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
5370           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrf*Nc + c + foffset;
5371           /*   middle */
5372           for (i = 0; i < k-1; ++i) {
5373             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebl+i)*Nc + c + foffset;
5374             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;}
5375             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebr+(k-2)-i)*Nc + c + foffset;
5376           }
5377           /*   top */
5378           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblb*Nc + c + foffset;
5379           for (o = oebb; o < oebr; ++o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
5380           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrb*Nc + c + foffset;
5381 
5382           /* Middle Slice */
5383           for (j = 0; j < k-1; ++j) {
5384             /*   bottom */
5385             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelf+(k-2)-j)*Nc + c + foffset;
5386             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;
5387             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerf+j)*Nc + c + foffset;
5388             /*   middle */
5389             for (i = 0; i < k-1; ++i) {
5390               for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofl+i*(k-1)+j)*Nc + c + foffset;
5391               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;
5392               for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofr+j*(k-1)+i)*Nc + c + foffset;
5393             }
5394             /*   top */
5395             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelb+j)*Nc + c + foffset;
5396             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;
5397             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerb+(k-2)-j)*Nc + c + foffset;
5398           }
5399 
5400           /* Top Slice */
5401           /*   bottom */
5402           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlf*Nc + c + foffset;
5403           for (o = oetf; o < oetr; ++o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
5404           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrf*Nc + c + foffset;
5405           /*   middle */
5406           for (i = 0; i < k-1; ++i) {
5407             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetl+(k-2)-i)*Nc + c + foffset;
5408             for (n = 0; n < k-1; ++n) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oft+i*(k-1)+n)*Nc + c + foffset;
5409             for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetr+i)*Nc + c + foffset;
5410           }
5411           /*   top */
5412           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlb*Nc + c + foffset;
5413           for (o = oetl-1; o >= oetb; --o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;
5414           for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrb*Nc + c + foffset;
5415 
5416           foffset = offset;
5417         }
5418         break;
5419       default: SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_OUTOFRANGE, "No spectral ordering for dimension %D", d);
5420       }
5421     }
5422     PetscCheckFalse(offset != size,PetscObjectComm((PetscObject) dm), PETSC_ERR_PLIB, "Number of permutation entries %D != %D", offset, size);
5423     /* Check permutation */
5424     {
5425       PetscInt *check;
5426 
5427       ierr = PetscMalloc1(size, &check);CHKERRQ(ierr);
5428       for (i = 0; i < size; ++i) {check[i] = -1; PetscCheckFalse(perm[i] < 0 || perm[i] >= size,PetscObjectComm((PetscObject) dm), PETSC_ERR_PLIB, "Invalid permutation index p[%D] = %D", i, perm[i]);}
5429       for (i = 0; i < size; ++i) check[perm[i]] = i;
5430       for (i = 0; i < size; ++i) {PetscCheckFalse(check[i] < 0,PetscObjectComm((PetscObject) dm), PETSC_ERR_PLIB, "Missing permutation index %D", i);}
5431       ierr = PetscFree(check);CHKERRQ(ierr);
5432     }
5433     ierr = PetscSectionSetClosurePermutation_Internal(section, (PetscObject) dm, d, size, PETSC_OWN_POINTER, perm);CHKERRQ(ierr);
5434     if (d == dim) { // Add permutation for localized (in case this is a coordinate DM)
5435       PetscInt *loc_perm;
5436       ierr = PetscMalloc1(size*2, &loc_perm);CHKERRQ(ierr);
5437       for (PetscInt i=0; i<size; i++) {
5438         loc_perm[i] = perm[i];
5439         loc_perm[size+i] = size + perm[i];
5440       }
5441       ierr = PetscSectionSetClosurePermutation_Internal(section, (PetscObject) dm, d, size*2, PETSC_OWN_POINTER, loc_perm);CHKERRQ(ierr);
5442     }
5443   }
5444   PetscFunctionReturn(0);
5445 }
5446 
5447 PetscErrorCode DMPlexGetPointDualSpaceFEM(DM dm, PetscInt point, PetscInt field, PetscDualSpace *dspace)
5448 {
5449   PetscDS        prob;
5450   PetscInt       depth, Nf, h;
5451   DMLabel        label;
5452   PetscErrorCode ierr;
5453 
5454   PetscFunctionBeginHot;
5455   ierr = DMGetDS(dm, &prob);CHKERRQ(ierr);
5456   Nf      = prob->Nf;
5457   label   = dm->depthLabel;
5458   *dspace = NULL;
5459   if (field < Nf) {
5460     PetscObject disc = prob->disc[field];
5461 
5462     if (disc->classid == PETSCFE_CLASSID) {
5463       PetscDualSpace dsp;
5464 
5465       ierr = PetscFEGetDualSpace((PetscFE)disc,&dsp);CHKERRQ(ierr);
5466       ierr = DMLabelGetNumValues(label,&depth);CHKERRQ(ierr);
5467       ierr = DMLabelGetValue(label,point,&h);CHKERRQ(ierr);
5468       h    = depth - 1 - h;
5469       if (h) {
5470         ierr = PetscDualSpaceGetHeightSubspace(dsp,h,dspace);CHKERRQ(ierr);
5471       } else {
5472         *dspace = dsp;
5473       }
5474     }
5475   }
5476   PetscFunctionReturn(0);
5477 }
5478 
5479 static inline PetscErrorCode DMPlexVecGetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[])
5480 {
5481   PetscScalar    *array, *vArray;
5482   const PetscInt *cone, *coneO;
5483   PetscInt        pStart, pEnd, p, numPoints, size = 0, offset = 0;
5484   PetscErrorCode  ierr;
5485 
5486   PetscFunctionBeginHot;
5487   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
5488   ierr = DMPlexGetConeSize(dm, point, &numPoints);CHKERRQ(ierr);
5489   ierr = DMPlexGetCone(dm, point, &cone);CHKERRQ(ierr);
5490   ierr = DMPlexGetConeOrientation(dm, point, &coneO);CHKERRQ(ierr);
5491   if (!values || !*values) {
5492     if ((point >= pStart) && (point < pEnd)) {
5493       PetscInt dof;
5494 
5495       ierr = PetscSectionGetDof(section, point, &dof);CHKERRQ(ierr);
5496       size += dof;
5497     }
5498     for (p = 0; p < numPoints; ++p) {
5499       const PetscInt cp = cone[p];
5500       PetscInt       dof;
5501 
5502       if ((cp < pStart) || (cp >= pEnd)) continue;
5503       ierr = PetscSectionGetDof(section, cp, &dof);CHKERRQ(ierr);
5504       size += dof;
5505     }
5506     if (!values) {
5507       if (csize) *csize = size;
5508       PetscFunctionReturn(0);
5509     }
5510     ierr = DMGetWorkArray(dm, size, MPIU_SCALAR, &array);CHKERRQ(ierr);
5511   } else {
5512     array = *values;
5513   }
5514   size = 0;
5515   ierr = VecGetArray(v, &vArray);CHKERRQ(ierr);
5516   if ((point >= pStart) && (point < pEnd)) {
5517     PetscInt     dof, off, d;
5518     PetscScalar *varr;
5519 
5520     ierr = PetscSectionGetDof(section, point, &dof);CHKERRQ(ierr);
5521     ierr = PetscSectionGetOffset(section, point, &off);CHKERRQ(ierr);
5522     varr = &vArray[off];
5523     for (d = 0; d < dof; ++d, ++offset) {
5524       array[offset] = varr[d];
5525     }
5526     size += dof;
5527   }
5528   for (p = 0; p < numPoints; ++p) {
5529     const PetscInt cp = cone[p];
5530     PetscInt       o  = coneO[p];
5531     PetscInt       dof, off, d;
5532     PetscScalar   *varr;
5533 
5534     if ((cp < pStart) || (cp >= pEnd)) continue;
5535     ierr = PetscSectionGetDof(section, cp, &dof);CHKERRQ(ierr);
5536     ierr = PetscSectionGetOffset(section, cp, &off);CHKERRQ(ierr);
5537     varr = &vArray[off];
5538     if (o >= 0) {
5539       for (d = 0; d < dof; ++d, ++offset) {
5540         array[offset] = varr[d];
5541       }
5542     } else {
5543       for (d = dof-1; d >= 0; --d, ++offset) {
5544         array[offset] = varr[d];
5545       }
5546     }
5547     size += dof;
5548   }
5549   ierr = VecRestoreArray(v, &vArray);CHKERRQ(ierr);
5550   if (!*values) {
5551     if (csize) *csize = size;
5552     *values = array;
5553   } else {
5554     PetscCheckFalse(size > *csize,PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %D < actual size %D", *csize, size);
5555     *csize = size;
5556   }
5557   PetscFunctionReturn(0);
5558 }
5559 
5560 /* Compress out points not in the section */
5561 static inline PetscErrorCode CompressPoints_Private(PetscSection section, PetscInt *numPoints, PetscInt points[])
5562 {
5563   const PetscInt np = *numPoints;
5564   PetscInt       pStart, pEnd, p, q;
5565   PetscErrorCode ierr;
5566 
5567   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
5568   for (p = 0, q = 0; p < np; ++p) {
5569     const PetscInt r = points[p*2];
5570     if ((r >= pStart) && (r < pEnd)) {
5571       points[q*2]   = r;
5572       points[q*2+1] = points[p*2+1];
5573       ++q;
5574     }
5575   }
5576   *numPoints = q;
5577   return 0;
5578 }
5579 
5580 /* Compressed closure does not apply closure permutation */
5581 PetscErrorCode DMPlexGetCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp)
5582 {
5583   const PetscInt *cla = NULL;
5584   PetscInt       np, *pts = NULL;
5585   PetscErrorCode ierr;
5586 
5587   PetscFunctionBeginHot;
5588   ierr = PetscSectionGetClosureIndex(section, (PetscObject) dm, clSec, clPoints);CHKERRQ(ierr);
5589   if (*clPoints) {
5590     PetscInt dof, off;
5591 
5592     ierr = PetscSectionGetDof(*clSec, point, &dof);CHKERRQ(ierr);
5593     ierr = PetscSectionGetOffset(*clSec, point, &off);CHKERRQ(ierr);
5594     ierr = ISGetIndices(*clPoints, &cla);CHKERRQ(ierr);
5595     np   = dof/2;
5596     pts  = (PetscInt *) &cla[off];
5597   } else {
5598     ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &np, &pts);CHKERRQ(ierr);
5599     ierr = CompressPoints_Private(section, &np, pts);CHKERRQ(ierr);
5600   }
5601   *numPoints = np;
5602   *points    = pts;
5603   *clp       = cla;
5604   PetscFunctionReturn(0);
5605 }
5606 
5607 PetscErrorCode DMPlexRestoreCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp)
5608 {
5609   PetscErrorCode ierr;
5610 
5611   PetscFunctionBeginHot;
5612   if (!*clPoints) {
5613     ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, numPoints, points);CHKERRQ(ierr);
5614   } else {
5615     ierr = ISRestoreIndices(*clPoints, clp);CHKERRQ(ierr);
5616   }
5617   *numPoints = 0;
5618   *points    = NULL;
5619   *clSec     = NULL;
5620   *clPoints  = NULL;
5621   *clp       = NULL;
5622   PetscFunctionReturn(0);
5623 }
5624 
5625 static inline PetscErrorCode DMPlexVecGetClosure_Static(DM dm, PetscSection section, PetscInt numPoints, const PetscInt points[], const PetscInt clperm[], const PetscScalar vArray[], PetscInt *size, PetscScalar array[])
5626 {
5627   PetscInt          offset = 0, p;
5628   const PetscInt    **perms = NULL;
5629   const PetscScalar **flips = NULL;
5630   PetscErrorCode    ierr;
5631 
5632   PetscFunctionBeginHot;
5633   *size = 0;
5634   ierr = PetscSectionGetPointSyms(section,numPoints,points,&perms,&flips);CHKERRQ(ierr);
5635   for (p = 0; p < numPoints; p++) {
5636     const PetscInt    point = points[2*p];
5637     const PetscInt    *perm = perms ? perms[p] : NULL;
5638     const PetscScalar *flip = flips ? flips[p] : NULL;
5639     PetscInt          dof, off, d;
5640     const PetscScalar *varr;
5641 
5642     ierr = PetscSectionGetDof(section, point, &dof);CHKERRQ(ierr);
5643     ierr = PetscSectionGetOffset(section, point, &off);CHKERRQ(ierr);
5644     varr = &vArray[off];
5645     if (clperm) {
5646       if (perm) {
5647         for (d = 0; d < dof; d++) array[clperm[offset + perm[d]]]  = varr[d];
5648       } else {
5649         for (d = 0; d < dof; d++) array[clperm[offset +      d ]]  = varr[d];
5650       }
5651       if (flip) {
5652         for (d = 0; d < dof; d++) array[clperm[offset +      d ]] *= flip[d];
5653       }
5654     } else {
5655       if (perm) {
5656         for (d = 0; d < dof; d++) array[offset + perm[d]]  = varr[d];
5657       } else {
5658         for (d = 0; d < dof; d++) array[offset +      d ]  = varr[d];
5659       }
5660       if (flip) {
5661         for (d = 0; d < dof; d++) array[offset +      d ] *= flip[d];
5662       }
5663     }
5664     offset += dof;
5665   }
5666   ierr = PetscSectionRestorePointSyms(section,numPoints,points,&perms,&flips);CHKERRQ(ierr);
5667   *size = offset;
5668   PetscFunctionReturn(0);
5669 }
5670 
5671 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[])
5672 {
5673   PetscInt          offset = 0, f;
5674   PetscErrorCode    ierr;
5675 
5676   PetscFunctionBeginHot;
5677   *size = 0;
5678   for (f = 0; f < numFields; ++f) {
5679     PetscInt          p;
5680     const PetscInt    **perms = NULL;
5681     const PetscScalar **flips = NULL;
5682 
5683     ierr = PetscSectionGetFieldPointSyms(section,f,numPoints,points,&perms,&flips);CHKERRQ(ierr);
5684     for (p = 0; p < numPoints; p++) {
5685       const PetscInt    point = points[2*p];
5686       PetscInt          fdof, foff, b;
5687       const PetscScalar *varr;
5688       const PetscInt    *perm = perms ? perms[p] : NULL;
5689       const PetscScalar *flip = flips ? flips[p] : NULL;
5690 
5691       ierr = PetscSectionGetFieldDof(section, point, f, &fdof);CHKERRQ(ierr);
5692       ierr = PetscSectionGetFieldOffset(section, point, f, &foff);CHKERRQ(ierr);
5693       varr = &vArray[foff];
5694       if (clperm) {
5695         if (perm) {for (b = 0; b < fdof; b++) {array[clperm[offset + perm[b]]]  = varr[b];}}
5696         else      {for (b = 0; b < fdof; b++) {array[clperm[offset +      b ]]  = varr[b];}}
5697         if (flip) {for (b = 0; b < fdof; b++) {array[clperm[offset +      b ]] *= flip[b];}}
5698       } else {
5699         if (perm) {for (b = 0; b < fdof; b++) {array[offset + perm[b]]  = varr[b];}}
5700         else      {for (b = 0; b < fdof; b++) {array[offset +      b ]  = varr[b];}}
5701         if (flip) {for (b = 0; b < fdof; b++) {array[offset +      b ] *= flip[b];}}
5702       }
5703       offset += fdof;
5704     }
5705     ierr = PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms,&flips);CHKERRQ(ierr);
5706   }
5707   *size = offset;
5708   PetscFunctionReturn(0);
5709 }
5710 
5711 /*@C
5712   DMPlexVecGetClosure - Get an array of the values on the closure of 'point'
5713 
5714   Not collective
5715 
5716   Input Parameters:
5717 + dm - The DM
5718 . section - The section describing the layout in v, or NULL to use the default section
5719 . v - The local vector
5720 - point - The point in the DM
5721 
5722   Input/Output Parameters:
5723 + csize  - The size of the input values array, or NULL; on output the number of values in the closure
5724 - values - An array to use for the values, or NULL to have it allocated automatically;
5725            if the user provided NULL, it is a borrowed array and should not be freed
5726 
5727 $ Note that DMPlexVecGetClosure/DMPlexVecRestoreClosure only allocates the values array if it set to NULL in the
5728 $ calling function. This is because DMPlexVecGetClosure() is typically called in the inner loop of a Vec or Mat
5729 $ assembly function, and a user may already have allocated storage for this operation.
5730 $
5731 $ A typical use could be
5732 $
5733 $  values = NULL;
5734 $  ierr = DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values);CHKERRQ(ierr);
5735 $  for (cl = 0; cl < clSize; ++cl) {
5736 $    <Compute on closure>
5737 $  }
5738 $  ierr = DMPlexVecRestoreClosure(dm, NULL, v, p, &clSize, &values);CHKERRQ(ierr);
5739 $
5740 $ or
5741 $
5742 $  PetscMalloc1(clMaxSize, &values);
5743 $  for (p = pStart; p < pEnd; ++p) {
5744 $    clSize = clMaxSize;
5745 $    ierr = DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values);CHKERRQ(ierr);
5746 $    for (cl = 0; cl < clSize; ++cl) {
5747 $      <Compute on closure>
5748 $    }
5749 $  }
5750 $  PetscFree(values);
5751 
5752   Fortran Notes:
5753   Since it returns an array, this routine is only available in Fortran 90, and you must
5754   include petsc.h90 in your code.
5755 
5756   The csize argument is not present in the Fortran 90 binding since it is internal to the array.
5757 
5758   Level: intermediate
5759 
5760 .seealso DMPlexVecRestoreClosure(), DMPlexVecSetClosure(), DMPlexMatSetClosure()
5761 @*/
5762 PetscErrorCode DMPlexVecGetClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[])
5763 {
5764   PetscSection       clSection;
5765   IS                 clPoints;
5766   PetscInt          *points = NULL;
5767   const PetscInt    *clp, *perm;
5768   PetscInt           depth, numFields, numPoints, asize;
5769   PetscErrorCode     ierr;
5770 
5771   PetscFunctionBeginHot;
5772   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5773   if (!section) {ierr = DMGetLocalSection(dm, &section);CHKERRQ(ierr);}
5774   PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2);
5775   PetscValidHeaderSpecific(v, VEC_CLASSID, 3);
5776   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
5777   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
5778   if (depth == 1 && numFields < 2) {
5779     ierr = DMPlexVecGetClosure_Depth1_Static(dm, section, v, point, csize, values);CHKERRQ(ierr);
5780     PetscFunctionReturn(0);
5781   }
5782   /* Get points */
5783   ierr = DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);CHKERRQ(ierr);
5784   /* Get sizes */
5785   asize = 0;
5786   for (PetscInt p = 0; p < numPoints*2; p += 2) {
5787     PetscInt dof;
5788     ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
5789     asize += dof;
5790   }
5791   if (values) {
5792     const PetscScalar *vArray;
5793     PetscInt          size;
5794 
5795     if (*values) {
5796       PetscCheckFalse(*csize < asize,PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Provided array size %D not sufficient to hold closure size %D", *csize, asize);
5797     } else {ierr = DMGetWorkArray(dm, asize, MPIU_SCALAR, values);CHKERRQ(ierr);}
5798     ierr = PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject) dm, depth, asize, &perm);CHKERRQ(ierr);
5799     ierr = VecGetArrayRead(v, &vArray);CHKERRQ(ierr);
5800     /* Get values */
5801     if (numFields > 0) {ierr = DMPlexVecGetClosure_Fields_Static(dm, section, numPoints, points, numFields, perm, vArray, &size, *values);CHKERRQ(ierr);}
5802     else               {ierr = DMPlexVecGetClosure_Static(dm, section, numPoints, points, perm, vArray, &size, *values);CHKERRQ(ierr);}
5803     PetscCheckFalse(asize != size,PETSC_COMM_SELF, PETSC_ERR_PLIB, "Section size %D does not match Vec closure size %D", asize, size);
5804     /* Cleanup array */
5805     ierr = VecRestoreArrayRead(v, &vArray);CHKERRQ(ierr);
5806   }
5807   if (csize) *csize = asize;
5808   /* Cleanup points */
5809   ierr = DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);CHKERRQ(ierr);
5810   PetscFunctionReturn(0);
5811 }
5812 
5813 PetscErrorCode DMPlexVecGetClosureAtDepth_Internal(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt depth, PetscInt *csize, PetscScalar *values[])
5814 {
5815   DMLabel            depthLabel;
5816   PetscSection       clSection;
5817   IS                 clPoints;
5818   PetscScalar       *array;
5819   const PetscScalar *vArray;
5820   PetscInt          *points = NULL;
5821   const PetscInt    *clp, *perm = NULL;
5822   PetscInt           mdepth, numFields, numPoints, Np = 0, p, clsize, size;
5823   PetscErrorCode     ierr;
5824 
5825   PetscFunctionBeginHot;
5826   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5827   if (!section) {ierr = DMGetLocalSection(dm, &section);CHKERRQ(ierr);}
5828   PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2);
5829   PetscValidHeaderSpecific(v, VEC_CLASSID, 3);
5830   ierr = DMPlexGetDepth(dm, &mdepth);CHKERRQ(ierr);
5831   ierr = DMPlexGetDepthLabel(dm, &depthLabel);CHKERRQ(ierr);
5832   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
5833   if (mdepth == 1 && numFields < 2) {
5834     ierr = DMPlexVecGetClosure_Depth1_Static(dm, section, v, point, csize, values);CHKERRQ(ierr);
5835     PetscFunctionReturn(0);
5836   }
5837   /* Get points */
5838   ierr = DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);CHKERRQ(ierr);
5839   for (clsize=0,p=0; p<Np; p++) {
5840     PetscInt dof;
5841     ierr = PetscSectionGetDof(section, points[2*p], &dof);CHKERRQ(ierr);
5842     clsize += dof;
5843   }
5844   ierr = PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject) dm, depth, clsize, &perm);CHKERRQ(ierr);
5845   /* Filter points */
5846   for (p = 0; p < numPoints*2; p += 2) {
5847     PetscInt dep;
5848 
5849     ierr = DMLabelGetValue(depthLabel, points[p], &dep);CHKERRQ(ierr);
5850     if (dep != depth) continue;
5851     points[Np*2+0] = points[p];
5852     points[Np*2+1] = points[p+1];
5853     ++Np;
5854   }
5855   /* Get array */
5856   if (!values || !*values) {
5857     PetscInt asize = 0, dof;
5858 
5859     for (p = 0; p < Np*2; p += 2) {
5860       ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
5861       asize += dof;
5862     }
5863     if (!values) {
5864       ierr = DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);CHKERRQ(ierr);
5865       if (csize) *csize = asize;
5866       PetscFunctionReturn(0);
5867     }
5868     ierr = DMGetWorkArray(dm, asize, MPIU_SCALAR, &array);CHKERRQ(ierr);
5869   } else {
5870     array = *values;
5871   }
5872   ierr = VecGetArrayRead(v, &vArray);CHKERRQ(ierr);
5873   /* Get values */
5874   if (numFields > 0) {ierr = DMPlexVecGetClosure_Fields_Static(dm, section, Np, points, numFields, perm, vArray, &size, array);CHKERRQ(ierr);}
5875   else               {ierr = DMPlexVecGetClosure_Static(dm, section, Np, points, perm, vArray, &size, array);CHKERRQ(ierr);}
5876   /* Cleanup points */
5877   ierr = DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);CHKERRQ(ierr);
5878   /* Cleanup array */
5879   ierr = VecRestoreArrayRead(v, &vArray);CHKERRQ(ierr);
5880   if (!*values) {
5881     if (csize) *csize = size;
5882     *values = array;
5883   } else {
5884     PetscCheckFalse(size > *csize,PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %D < actual size %D", *csize, size);
5885     *csize = size;
5886   }
5887   PetscFunctionReturn(0);
5888 }
5889 
5890 /*@C
5891   DMPlexVecRestoreClosure - Restore the array of the values on the closure of 'point'
5892 
5893   Not collective
5894 
5895   Input Parameters:
5896 + dm - The DM
5897 . section - The section describing the layout in v, or NULL to use the default section
5898 . v - The local vector
5899 . point - The point in the DM
5900 . csize - The number of values in the closure, or NULL
5901 - values - The array of values, which is a borrowed array and should not be freed
5902 
5903   Note that the array values are discarded and not copied back into v. In order to copy values back to v, use DMPlexVecSetClosure()
5904 
5905   Fortran Notes:
5906   Since it returns an array, this routine is only available in Fortran 90, and you must
5907   include petsc.h90 in your code.
5908 
5909   The csize argument is not present in the Fortran 90 binding since it is internal to the array.
5910 
5911   Level: intermediate
5912 
5913 .seealso DMPlexVecGetClosure(), DMPlexVecSetClosure(), DMPlexMatSetClosure()
5914 @*/
5915 PetscErrorCode DMPlexVecRestoreClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[])
5916 {
5917   PetscInt       size = 0;
5918   PetscErrorCode ierr;
5919 
5920   PetscFunctionBegin;
5921   /* Should work without recalculating size */
5922   ierr = DMRestoreWorkArray(dm, size, MPIU_SCALAR, (void*) values);CHKERRQ(ierr);
5923   *values = NULL;
5924   PetscFunctionReturn(0);
5925 }
5926 
5927 static inline void add   (PetscScalar *x, PetscScalar y) {*x += y;}
5928 static inline void insert(PetscScalar *x, PetscScalar y) {*x  = y;}
5929 
5930 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[])
5931 {
5932   PetscInt        cdof;   /* The number of constraints on this point */
5933   const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
5934   PetscScalar    *a;
5935   PetscInt        off, cind = 0, k;
5936   PetscErrorCode  ierr;
5937 
5938   PetscFunctionBegin;
5939   ierr = PetscSectionGetConstraintDof(section, point, &cdof);CHKERRQ(ierr);
5940   ierr = PetscSectionGetOffset(section, point, &off);CHKERRQ(ierr);
5941   a    = &array[off];
5942   if (!cdof || setBC) {
5943     if (clperm) {
5944       if (perm) {for (k = 0; k < dof; ++k) {fuse(&a[k], values[clperm[offset+perm[k]]] * (flip ? flip[perm[k]] : 1.));}}
5945       else      {for (k = 0; k < dof; ++k) {fuse(&a[k], values[clperm[offset+     k ]] * (flip ? flip[     k ] : 1.));}}
5946     } else {
5947       if (perm) {for (k = 0; k < dof; ++k) {fuse(&a[k], values[offset+perm[k]] * (flip ? flip[perm[k]] : 1.));}}
5948       else      {for (k = 0; k < dof; ++k) {fuse(&a[k], values[offset+     k ] * (flip ? flip[     k ] : 1.));}}
5949     }
5950   } else {
5951     ierr = PetscSectionGetConstraintIndices(section, point, &cdofs);CHKERRQ(ierr);
5952     if (clperm) {
5953       if (perm) {for (k = 0; k < dof; ++k) {
5954           if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
5955           fuse(&a[k], values[clperm[offset+perm[k]]] * (flip ? flip[perm[k]] : 1.));
5956         }
5957       } else {
5958         for (k = 0; k < dof; ++k) {
5959           if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
5960           fuse(&a[k], values[clperm[offset+     k ]] * (flip ? flip[     k ] : 1.));
5961         }
5962       }
5963     } else {
5964       if (perm) {
5965         for (k = 0; k < dof; ++k) {
5966           if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
5967           fuse(&a[k], values[offset+perm[k]] * (flip ? flip[perm[k]] : 1.));
5968         }
5969       } else {
5970         for (k = 0; k < dof; ++k) {
5971           if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
5972           fuse(&a[k], values[offset+     k ] * (flip ? flip[     k ] : 1.));
5973         }
5974       }
5975     }
5976   }
5977   PetscFunctionReturn(0);
5978 }
5979 
5980 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[])
5981 {
5982   PetscInt        cdof;   /* The number of constraints on this point */
5983   const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
5984   PetscScalar    *a;
5985   PetscInt        off, cind = 0, k;
5986   PetscErrorCode  ierr;
5987 
5988   PetscFunctionBegin;
5989   ierr = PetscSectionGetConstraintDof(section, point, &cdof);CHKERRQ(ierr);
5990   ierr = PetscSectionGetOffset(section, point, &off);CHKERRQ(ierr);
5991   a    = &array[off];
5992   if (cdof) {
5993     ierr = PetscSectionGetConstraintIndices(section, point, &cdofs);CHKERRQ(ierr);
5994     if (clperm) {
5995       if (perm) {
5996         for (k = 0; k < dof; ++k) {
5997           if ((cind < cdof) && (k == cdofs[cind])) {
5998             fuse(&a[k], values[clperm[offset+perm[k]]] * (flip ? flip[perm[k]] : 1.));
5999             cind++;
6000           }
6001         }
6002       } else {
6003         for (k = 0; k < dof; ++k) {
6004           if ((cind < cdof) && (k == cdofs[cind])) {
6005             fuse(&a[k], values[clperm[offset+     k ]] * (flip ? flip[     k ] : 1.));
6006             cind++;
6007           }
6008         }
6009       }
6010     } else {
6011       if (perm) {
6012         for (k = 0; k < dof; ++k) {
6013           if ((cind < cdof) && (k == cdofs[cind])) {
6014             fuse(&a[k], values[offset+perm[k]] * (flip ? flip[perm[k]] : 1.));
6015             cind++;
6016           }
6017         }
6018       } else {
6019         for (k = 0; k < dof; ++k) {
6020           if ((cind < cdof) && (k == cdofs[cind])) {
6021             fuse(&a[k], values[offset+     k ] * (flip ? flip[     k ] : 1.));
6022             cind++;
6023           }
6024         }
6025       }
6026     }
6027   }
6028   PetscFunctionReturn(0);
6029 }
6030 
6031 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[])
6032 {
6033   PetscScalar    *a;
6034   PetscInt        fdof, foff, fcdof, foffset = *offset;
6035   const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
6036   PetscInt        cind = 0, b;
6037   PetscErrorCode  ierr;
6038 
6039   PetscFunctionBegin;
6040   ierr = PetscSectionGetFieldDof(section, point, f, &fdof);CHKERRQ(ierr);
6041   ierr = PetscSectionGetFieldConstraintDof(section, point, f, &fcdof);CHKERRQ(ierr);
6042   ierr = PetscSectionGetFieldOffset(section, point, f, &foff);CHKERRQ(ierr);
6043   a    = &array[foff];
6044   if (!fcdof || setBC) {
6045     if (clperm) {
6046       if (perm) {for (b = 0; b < fdof; b++) {fuse(&a[b], values[clperm[foffset+perm[b]]] * (flip ? flip[perm[b]] : 1.));}}
6047       else      {for (b = 0; b < fdof; b++) {fuse(&a[b], values[clperm[foffset+     b ]] * (flip ? flip[     b ] : 1.));}}
6048     } else {
6049       if (perm) {for (b = 0; b < fdof; b++) {fuse(&a[b], values[foffset+perm[b]] * (flip ? flip[perm[b]] : 1.));}}
6050       else      {for (b = 0; b < fdof; b++) {fuse(&a[b], values[foffset+     b ] * (flip ? flip[     b ] : 1.));}}
6051     }
6052   } else {
6053     ierr = PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);CHKERRQ(ierr);
6054     if (clperm) {
6055       if (perm) {
6056         for (b = 0; b < fdof; b++) {
6057           if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; continue;}
6058           fuse(&a[b], values[clperm[foffset+perm[b]]] * (flip ? flip[perm[b]] : 1.));
6059         }
6060       } else {
6061         for (b = 0; b < fdof; b++) {
6062           if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; continue;}
6063           fuse(&a[b], values[clperm[foffset+     b ]] * (flip ? flip[     b ] : 1.));
6064         }
6065       }
6066     } else {
6067       if (perm) {
6068         for (b = 0; b < fdof; b++) {
6069           if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; continue;}
6070           fuse(&a[b], values[foffset+perm[b]] * (flip ? flip[perm[b]] : 1.));
6071         }
6072       } else {
6073         for (b = 0; b < fdof; b++) {
6074           if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; continue;}
6075           fuse(&a[b], values[foffset+     b ] * (flip ? flip[     b ] : 1.));
6076         }
6077       }
6078     }
6079   }
6080   *offset += fdof;
6081   PetscFunctionReturn(0);
6082 }
6083 
6084 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[])
6085 {
6086   PetscScalar    *a;
6087   PetscInt        fdof, foff, fcdof, foffset = *offset;
6088   const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
6089   PetscInt        Nc, cind = 0, ncind = 0, b;
6090   PetscBool       ncSet, fcSet;
6091   PetscErrorCode  ierr;
6092 
6093   PetscFunctionBegin;
6094   ierr = PetscSectionGetFieldComponents(section, f, &Nc);CHKERRQ(ierr);
6095   ierr = PetscSectionGetFieldDof(section, point, f, &fdof);CHKERRQ(ierr);
6096   ierr = PetscSectionGetFieldConstraintDof(section, point, f, &fcdof);CHKERRQ(ierr);
6097   ierr = PetscSectionGetFieldOffset(section, point, f, &foff);CHKERRQ(ierr);
6098   a    = &array[foff];
6099   if (fcdof) {
6100     /* We just override fcdof and fcdofs with Ncc and comps */
6101     ierr = PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);CHKERRQ(ierr);
6102     if (clperm) {
6103       if (perm) {
6104         if (comps) {
6105           for (b = 0; b < fdof; b++) {
6106             ncSet = fcSet = PETSC_FALSE;
6107             if (b%Nc == comps[ncind]) {ncind = (ncind+1)%Ncc; ncSet = PETSC_TRUE;}
6108             if ((cind < fcdof) && (b == fcdofs[cind])) {++cind;  fcSet = PETSC_TRUE;}
6109             if (ncSet && fcSet) {fuse(&a[b], values[clperm[foffset+perm[b]]] * (flip ? flip[perm[b]] : 1.));}
6110           }
6111         } else {
6112           for (b = 0; b < fdof; b++) {
6113             if ((cind < fcdof) && (b == fcdofs[cind])) {
6114               fuse(&a[b], values[clperm[foffset+perm[b]]] * (flip ? flip[perm[b]] : 1.));
6115               ++cind;
6116             }
6117           }
6118         }
6119       } else {
6120         if (comps) {
6121           for (b = 0; b < fdof; b++) {
6122             ncSet = fcSet = PETSC_FALSE;
6123             if (b%Nc == comps[ncind]) {ncind = (ncind+1)%Ncc; ncSet = PETSC_TRUE;}
6124             if ((cind < fcdof) && (b == fcdofs[cind])) {++cind;  fcSet = PETSC_TRUE;}
6125             if (ncSet && fcSet) {fuse(&a[b], values[clperm[foffset+     b ]] * (flip ? flip[     b ] : 1.));}
6126           }
6127         } else {
6128           for (b = 0; b < fdof; b++) {
6129             if ((cind < fcdof) && (b == fcdofs[cind])) {
6130               fuse(&a[b], values[clperm[foffset+     b ]] * (flip ? flip[     b ] : 1.));
6131               ++cind;
6132             }
6133           }
6134         }
6135       }
6136     } else {
6137       if (perm) {
6138         if (comps) {
6139           for (b = 0; b < fdof; b++) {
6140             ncSet = fcSet = PETSC_FALSE;
6141             if (b%Nc == comps[ncind]) {ncind = (ncind+1)%Ncc; ncSet = PETSC_TRUE;}
6142             if ((cind < fcdof) && (b == fcdofs[cind])) {++cind;  fcSet = PETSC_TRUE;}
6143             if (ncSet && fcSet) {fuse(&a[b], values[foffset+perm[b]] * (flip ? flip[perm[b]] : 1.));}
6144           }
6145         } else {
6146           for (b = 0; b < fdof; b++) {
6147             if ((cind < fcdof) && (b == fcdofs[cind])) {
6148               fuse(&a[b], values[foffset+perm[b]] * (flip ? flip[perm[b]] : 1.));
6149               ++cind;
6150             }
6151           }
6152         }
6153       } else {
6154         if (comps) {
6155           for (b = 0; b < fdof; b++) {
6156             ncSet = fcSet = PETSC_FALSE;
6157             if (b%Nc == comps[ncind]) {ncind = (ncind+1)%Ncc; ncSet = PETSC_TRUE;}
6158             if ((cind < fcdof) && (b == fcdofs[cind])) {++cind;  fcSet = PETSC_TRUE;}
6159             if (ncSet && fcSet) {fuse(&a[b], values[foffset+     b ] * (flip ? flip[     b ] : 1.));}
6160           }
6161         } else {
6162           for (b = 0; b < fdof; b++) {
6163             if ((cind < fcdof) && (b == fcdofs[cind])) {
6164               fuse(&a[b], values[foffset+     b ] * (flip ? flip[     b ] : 1.));
6165               ++cind;
6166             }
6167           }
6168         }
6169       }
6170     }
6171   }
6172   *offset += fdof;
6173   PetscFunctionReturn(0);
6174 }
6175 
6176 static inline PetscErrorCode DMPlexVecSetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode)
6177 {
6178   PetscScalar    *array;
6179   const PetscInt *cone, *coneO;
6180   PetscInt        pStart, pEnd, p, numPoints, off, dof;
6181   PetscErrorCode  ierr;
6182 
6183   PetscFunctionBeginHot;
6184   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
6185   ierr = DMPlexGetConeSize(dm, point, &numPoints);CHKERRQ(ierr);
6186   ierr = DMPlexGetCone(dm, point, &cone);CHKERRQ(ierr);
6187   ierr = DMPlexGetConeOrientation(dm, point, &coneO);CHKERRQ(ierr);
6188   ierr = VecGetArray(v, &array);CHKERRQ(ierr);
6189   for (p = 0, off = 0; p <= numPoints; ++p, off += dof) {
6190     const PetscInt cp = !p ? point : cone[p-1];
6191     const PetscInt o  = !p ? 0     : coneO[p-1];
6192 
6193     if ((cp < pStart) || (cp >= pEnd)) {dof = 0; continue;}
6194     ierr = PetscSectionGetDof(section, cp, &dof);CHKERRQ(ierr);
6195     /* ADD_VALUES */
6196     {
6197       const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
6198       PetscScalar    *a;
6199       PetscInt        cdof, coff, cind = 0, k;
6200 
6201       ierr = PetscSectionGetConstraintDof(section, cp, &cdof);CHKERRQ(ierr);
6202       ierr = PetscSectionGetOffset(section, cp, &coff);CHKERRQ(ierr);
6203       a    = &array[coff];
6204       if (!cdof) {
6205         if (o >= 0) {
6206           for (k = 0; k < dof; ++k) {
6207             a[k] += values[off+k];
6208           }
6209         } else {
6210           for (k = 0; k < dof; ++k) {
6211             a[k] += values[off+dof-k-1];
6212           }
6213         }
6214       } else {
6215         ierr = PetscSectionGetConstraintIndices(section, cp, &cdofs);CHKERRQ(ierr);
6216         if (o >= 0) {
6217           for (k = 0; k < dof; ++k) {
6218             if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
6219             a[k] += values[off+k];
6220           }
6221         } else {
6222           for (k = 0; k < dof; ++k) {
6223             if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
6224             a[k] += values[off+dof-k-1];
6225           }
6226         }
6227       }
6228     }
6229   }
6230   ierr = VecRestoreArray(v, &array);CHKERRQ(ierr);
6231   PetscFunctionReturn(0);
6232 }
6233 
6234 /*@C
6235   DMPlexVecSetClosure - Set an array of the values on the closure of 'point'
6236 
6237   Not collective
6238 
6239   Input Parameters:
6240 + dm - The DM
6241 . section - The section describing the layout in v, or NULL to use the default section
6242 . v - The local vector
6243 . point - The point in the DM
6244 . values - The array of values
6245 - mode - The insert mode. One of INSERT_ALL_VALUES, ADD_ALL_VALUES, INSERT_VALUES, ADD_VALUES, INSERT_BC_VALUES, and ADD_BC_VALUES,
6246          where INSERT_ALL_VALUES and ADD_ALL_VALUES also overwrite boundary conditions.
6247 
6248   Fortran Notes:
6249   This routine is only available in Fortran 90, and you must include petsc.h90 in your code.
6250 
6251   Level: intermediate
6252 
6253 .seealso DMPlexVecGetClosure(), DMPlexMatSetClosure()
6254 @*/
6255 PetscErrorCode DMPlexVecSetClosure(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode)
6256 {
6257   PetscSection    clSection;
6258   IS              clPoints;
6259   PetscScalar    *array;
6260   PetscInt       *points = NULL;
6261   const PetscInt *clp, *clperm = NULL;
6262   PetscInt        depth, numFields, numPoints, p, clsize;
6263   PetscErrorCode  ierr;
6264 
6265   PetscFunctionBeginHot;
6266   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6267   if (!section) {ierr = DMGetLocalSection(dm, &section);CHKERRQ(ierr);}
6268   PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2);
6269   PetscValidHeaderSpecific(v, VEC_CLASSID, 3);
6270   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
6271   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
6272   if (depth == 1 && numFields < 2 && mode == ADD_VALUES) {
6273     ierr = DMPlexVecSetClosure_Depth1_Static(dm, section, v, point, values, mode);CHKERRQ(ierr);
6274     PetscFunctionReturn(0);
6275   }
6276   /* Get points */
6277   ierr = DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);CHKERRQ(ierr);
6278   for (clsize=0,p=0; p<numPoints; p++) {
6279     PetscInt dof;
6280     ierr = PetscSectionGetDof(section, points[2*p], &dof);CHKERRQ(ierr);
6281     clsize += dof;
6282   }
6283   ierr = PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject) dm, depth, clsize, &clperm);CHKERRQ(ierr);
6284   /* Get array */
6285   ierr = VecGetArray(v, &array);CHKERRQ(ierr);
6286   /* Get values */
6287   if (numFields > 0) {
6288     PetscInt offset = 0, f;
6289     for (f = 0; f < numFields; ++f) {
6290       const PetscInt    **perms = NULL;
6291       const PetscScalar **flips = NULL;
6292 
6293       ierr = PetscSectionGetFieldPointSyms(section,f,numPoints,points,&perms,&flips);CHKERRQ(ierr);
6294       switch (mode) {
6295       case INSERT_VALUES:
6296         for (p = 0; p < numPoints; p++) {
6297           const PetscInt    point = points[2*p];
6298           const PetscInt    *perm = perms ? perms[p] : NULL;
6299           const PetscScalar *flip = flips ? flips[p] : NULL;
6300           updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, clperm, values, &offset, array);
6301         } break;
6302       case INSERT_ALL_VALUES:
6303         for (p = 0; p < numPoints; p++) {
6304           const PetscInt    point = points[2*p];
6305           const PetscInt    *perm = perms ? perms[p] : NULL;
6306           const PetscScalar *flip = flips ? flips[p] : NULL;
6307           updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, clperm, values, &offset, array);
6308         } break;
6309       case INSERT_BC_VALUES:
6310         for (p = 0; p < numPoints; p++) {
6311           const PetscInt    point = points[2*p];
6312           const PetscInt    *perm = perms ? perms[p] : NULL;
6313           const PetscScalar *flip = flips ? flips[p] : NULL;
6314           updatePointFieldsBC_private(section, point, perm, flip, f, -1, NULL, insert, clperm, values, &offset, array);
6315         } break;
6316       case ADD_VALUES:
6317         for (p = 0; p < numPoints; p++) {
6318           const PetscInt    point = points[2*p];
6319           const PetscInt    *perm = perms ? perms[p] : NULL;
6320           const PetscScalar *flip = flips ? flips[p] : NULL;
6321           updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, clperm, values, &offset, array);
6322         } break;
6323       case ADD_ALL_VALUES:
6324         for (p = 0; p < numPoints; p++) {
6325           const PetscInt    point = points[2*p];
6326           const PetscInt    *perm = perms ? perms[p] : NULL;
6327           const PetscScalar *flip = flips ? flips[p] : NULL;
6328           updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, clperm, values, &offset, array);
6329         } break;
6330       case ADD_BC_VALUES:
6331         for (p = 0; p < numPoints; p++) {
6332           const PetscInt    point = points[2*p];
6333           const PetscInt    *perm = perms ? perms[p] : NULL;
6334           const PetscScalar *flip = flips ? flips[p] : NULL;
6335           updatePointFieldsBC_private(section, point, perm, flip, f, -1, NULL, add, clperm, values, &offset, array);
6336         } break;
6337       default:
6338         SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode);
6339       }
6340       ierr = PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms,&flips);CHKERRQ(ierr);
6341     }
6342   } else {
6343     PetscInt dof, off;
6344     const PetscInt    **perms = NULL;
6345     const PetscScalar **flips = NULL;
6346 
6347     ierr = PetscSectionGetPointSyms(section,numPoints,points,&perms,&flips);CHKERRQ(ierr);
6348     switch (mode) {
6349     case INSERT_VALUES:
6350       for (p = 0, off = 0; p < numPoints; p++, off += dof) {
6351         const PetscInt    point = points[2*p];
6352         const PetscInt    *perm = perms ? perms[p] : NULL;
6353         const PetscScalar *flip = flips ? flips[p] : NULL;
6354         ierr = PetscSectionGetDof(section, point, &dof);CHKERRQ(ierr);
6355         updatePoint_private(section, point, dof, insert, PETSC_FALSE, perm, flip, clperm, values, off, array);
6356       } break;
6357     case INSERT_ALL_VALUES:
6358       for (p = 0, off = 0; p < numPoints; p++, off += dof) {
6359         const PetscInt    point = points[2*p];
6360         const PetscInt    *perm = perms ? perms[p] : NULL;
6361         const PetscScalar *flip = flips ? flips[p] : NULL;
6362         ierr = PetscSectionGetDof(section, point, &dof);CHKERRQ(ierr);
6363         updatePoint_private(section, point, dof, insert, PETSC_TRUE,  perm, flip, clperm, values, off, array);
6364       } break;
6365     case INSERT_BC_VALUES:
6366       for (p = 0, off = 0; p < numPoints; p++, off += dof) {
6367         const PetscInt    point = points[2*p];
6368         const PetscInt    *perm = perms ? perms[p] : NULL;
6369         const PetscScalar *flip = flips ? flips[p] : NULL;
6370         ierr = PetscSectionGetDof(section, point, &dof);CHKERRQ(ierr);
6371         updatePointBC_private(section, point, dof, insert,  perm, flip, clperm, values, off, array);
6372       } break;
6373     case ADD_VALUES:
6374       for (p = 0, off = 0; p < numPoints; p++, off += dof) {
6375         const PetscInt    point = points[2*p];
6376         const PetscInt    *perm = perms ? perms[p] : NULL;
6377         const PetscScalar *flip = flips ? flips[p] : NULL;
6378         ierr = PetscSectionGetDof(section, point, &dof);CHKERRQ(ierr);
6379         updatePoint_private(section, point, dof, add,    PETSC_FALSE, perm, flip, clperm, values, off, array);
6380       } break;
6381     case ADD_ALL_VALUES:
6382       for (p = 0, off = 0; p < numPoints; p++, off += dof) {
6383         const PetscInt    point = points[2*p];
6384         const PetscInt    *perm = perms ? perms[p] : NULL;
6385         const PetscScalar *flip = flips ? flips[p] : NULL;
6386         ierr = PetscSectionGetDof(section, point, &dof);CHKERRQ(ierr);
6387         updatePoint_private(section, point, dof, add,    PETSC_TRUE,  perm, flip, clperm, values, off, array);
6388       } break;
6389     case ADD_BC_VALUES:
6390       for (p = 0, off = 0; p < numPoints; p++, off += dof) {
6391         const PetscInt    point = points[2*p];
6392         const PetscInt    *perm = perms ? perms[p] : NULL;
6393         const PetscScalar *flip = flips ? flips[p] : NULL;
6394         ierr = PetscSectionGetDof(section, point, &dof);CHKERRQ(ierr);
6395         updatePointBC_private(section, point, dof, add,  perm, flip, clperm, values, off, array);
6396       } break;
6397     default:
6398       SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode);
6399     }
6400     ierr = PetscSectionRestorePointSyms(section,numPoints,points,&perms,&flips);CHKERRQ(ierr);
6401   }
6402   /* Cleanup points */
6403   ierr = DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);CHKERRQ(ierr);
6404   /* Cleanup array */
6405   ierr = VecRestoreArray(v, &array);CHKERRQ(ierr);
6406   PetscFunctionReturn(0);
6407 }
6408 
6409 /* Check whether the given point is in the label. If not, update the offset to skip this point */
6410 static inline PetscErrorCode CheckPoint_Private(DMLabel label, PetscInt labelId, PetscSection section, PetscInt point, PetscInt f, PetscInt *offset)
6411 {
6412   PetscFunctionBegin;
6413   if (label) {
6414     PetscInt       val, fdof;
6415     PetscErrorCode ierr;
6416 
6417     /* There is a problem with this:
6418          Suppose we have two label values, defining surfaces, interecting along a line in 3D. When we add cells to the label, the cells that
6419        touch both surfaces must pick a label value. Thus we miss setting values for the surface with that other value intersecting that cell.
6420        Thus I am only going to check val != -1, not val != labelId
6421     */
6422     ierr = DMLabelGetValue(label, point, &val);CHKERRQ(ierr);
6423     if (val < 0) {
6424       ierr = PetscSectionGetFieldDof(section, point, f, &fdof);CHKERRQ(ierr);
6425       *offset += fdof;
6426       PetscFunctionReturn(1);
6427     }
6428   }
6429   PetscFunctionReturn(0);
6430 }
6431 
6432 /* Unlike DMPlexVecSetClosure(), this uses plex-native closure permutation, not a user-specified permutation such as DMPlexSetClosurePermutationTensor(). */
6433 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)
6434 {
6435   PetscSection      clSection;
6436   IS                clPoints;
6437   PetscScalar       *array;
6438   PetscInt          *points = NULL;
6439   const PetscInt    *clp;
6440   PetscInt          numFields, numPoints, p;
6441   PetscInt          offset = 0, f;
6442   PetscErrorCode    ierr;
6443 
6444   PetscFunctionBeginHot;
6445   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6446   if (!section) {ierr = DMGetLocalSection(dm, &section);CHKERRQ(ierr);}
6447   PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2);
6448   PetscValidHeaderSpecific(v, VEC_CLASSID, 3);
6449   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
6450   /* Get points */
6451   ierr = DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);CHKERRQ(ierr);
6452   /* Get array */
6453   ierr = VecGetArray(v, &array);CHKERRQ(ierr);
6454   /* Get values */
6455   for (f = 0; f < numFields; ++f) {
6456     const PetscInt    **perms = NULL;
6457     const PetscScalar **flips = NULL;
6458 
6459     if (!fieldActive[f]) {
6460       for (p = 0; p < numPoints*2; p += 2) {
6461         PetscInt fdof;
6462         ierr = PetscSectionGetFieldDof(section, points[p], f, &fdof);CHKERRQ(ierr);
6463         offset += fdof;
6464       }
6465       continue;
6466     }
6467     ierr = PetscSectionGetFieldPointSyms(section,f,numPoints,points,&perms,&flips);CHKERRQ(ierr);
6468     switch (mode) {
6469     case INSERT_VALUES:
6470       for (p = 0; p < numPoints; p++) {
6471         const PetscInt    point = points[2*p];
6472         const PetscInt    *perm = perms ? perms[p] : NULL;
6473         const PetscScalar *flip = flips ? flips[p] : NULL;
6474         ierr = CheckPoint_Private(label, labelId, section, point, f, &offset); if (ierr) continue;
6475         updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, NULL, values, &offset, array);
6476       } break;
6477     case INSERT_ALL_VALUES:
6478       for (p = 0; p < numPoints; p++) {
6479         const PetscInt    point = points[2*p];
6480         const PetscInt    *perm = perms ? perms[p] : NULL;
6481         const PetscScalar *flip = flips ? flips[p] : NULL;
6482         ierr = CheckPoint_Private(label, labelId, section, point, f, &offset); if (ierr) continue;
6483         updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, NULL, values, &offset, array);
6484       } break;
6485     case INSERT_BC_VALUES:
6486       for (p = 0; p < numPoints; p++) {
6487         const PetscInt    point = points[2*p];
6488         const PetscInt    *perm = perms ? perms[p] : NULL;
6489         const PetscScalar *flip = flips ? flips[p] : NULL;
6490         ierr = CheckPoint_Private(label, labelId, section, point, f, &offset); if (ierr) continue;
6491         updatePointFieldsBC_private(section, point, perm, flip, f, Ncc, comps, insert, NULL, values, &offset, array);
6492       } break;
6493     case ADD_VALUES:
6494       for (p = 0; p < numPoints; p++) {
6495         const PetscInt    point = points[2*p];
6496         const PetscInt    *perm = perms ? perms[p] : NULL;
6497         const PetscScalar *flip = flips ? flips[p] : NULL;
6498         ierr = CheckPoint_Private(label, labelId, section, point, f, &offset); if (ierr) continue;
6499         updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, NULL, values, &offset, array);
6500       } break;
6501     case ADD_ALL_VALUES:
6502       for (p = 0; p < numPoints; p++) {
6503         const PetscInt    point = points[2*p];
6504         const PetscInt    *perm = perms ? perms[p] : NULL;
6505         const PetscScalar *flip = flips ? flips[p] : NULL;
6506         ierr = CheckPoint_Private(label, labelId, section, point, f, &offset); if (ierr) continue;
6507         updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, NULL, values, &offset, array);
6508       } break;
6509     default:
6510       SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode);
6511     }
6512     ierr = PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms,&flips);CHKERRQ(ierr);
6513   }
6514   /* Cleanup points */
6515   ierr = DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);CHKERRQ(ierr);
6516   /* Cleanup array */
6517   ierr = VecRestoreArray(v, &array);CHKERRQ(ierr);
6518   PetscFunctionReturn(0);
6519 }
6520 
6521 static PetscErrorCode DMPlexPrintMatSetValues(PetscViewer viewer, Mat A, PetscInt point, PetscInt numRIndices, const PetscInt rindices[], PetscInt numCIndices, const PetscInt cindices[], const PetscScalar values[])
6522 {
6523   PetscMPIInt    rank;
6524   PetscInt       i, j;
6525   PetscErrorCode ierr;
6526 
6527   PetscFunctionBegin;
6528   ierr = MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank);CHKERRMPI(ierr);
6529   ierr = PetscViewerASCIIPrintf(viewer, "[%d]mat for point %D\n", rank, point);CHKERRQ(ierr);
6530   for (i = 0; i < numRIndices; i++) {ierr = PetscViewerASCIIPrintf(viewer, "[%d]mat row indices[%D] = %D\n", rank, i, rindices[i]);CHKERRQ(ierr);}
6531   for (i = 0; i < numCIndices; i++) {ierr = PetscViewerASCIIPrintf(viewer, "[%d]mat col indices[%D] = %D\n", rank, i, cindices[i]);CHKERRQ(ierr);}
6532   numCIndices = numCIndices ? numCIndices : numRIndices;
6533   if (!values) PetscFunctionReturn(0);
6534   for (i = 0; i < numRIndices; i++) {
6535     ierr = PetscViewerASCIIPrintf(viewer, "[%d]", rank);CHKERRQ(ierr);
6536     for (j = 0; j < numCIndices; j++) {
6537 #if defined(PETSC_USE_COMPLEX)
6538       ierr = PetscViewerASCIIPrintf(viewer, " (%g,%g)", (double)PetscRealPart(values[i*numCIndices+j]), (double)PetscImaginaryPart(values[i*numCIndices+j]));CHKERRQ(ierr);
6539 #else
6540       ierr = PetscViewerASCIIPrintf(viewer, " %g", (double)values[i*numCIndices+j]);CHKERRQ(ierr);
6541 #endif
6542     }
6543     ierr = PetscViewerASCIIPrintf(viewer, "\n");CHKERRQ(ierr);
6544   }
6545   PetscFunctionReturn(0);
6546 }
6547 
6548 /*
6549   DMPlexGetIndicesPoint_Internal - Add the indices for dofs on a point to an index array
6550 
6551   Input Parameters:
6552 + section - The section for this data layout
6553 . islocal - Is the section (and thus indices being requested) local or global?
6554 . point   - The point contributing dofs with these indices
6555 . off     - The global offset of this point
6556 . loff    - The local offset of each field
6557 . setBC   - The flag determining whether to include indices of boundary values
6558 . perm    - A permutation of the dofs on this point, or NULL
6559 - indperm - A permutation of the entire indices array, or NULL
6560 
6561   Output Parameter:
6562 . indices - Indices for dofs on this point
6563 
6564   Level: developer
6565 
6566   Note: The indices could be local or global, depending on the value of 'off'.
6567 */
6568 PetscErrorCode DMPlexGetIndicesPoint_Internal(PetscSection section, PetscBool islocal,PetscInt point, PetscInt off, PetscInt *loff, PetscBool setBC, const PetscInt perm[], const PetscInt indperm[], PetscInt indices[])
6569 {
6570   PetscInt        dof;   /* The number of unknowns on this point */
6571   PetscInt        cdof;  /* The number of constraints on this point */
6572   const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
6573   PetscInt        cind = 0, k;
6574   PetscErrorCode  ierr;
6575 
6576   PetscFunctionBegin;
6577   PetscCheckFalse(!islocal && setBC,PetscObjectComm((PetscObject)section),PETSC_ERR_ARG_INCOMP,"setBC incompatible with global indices; use a local section or disable setBC");
6578   ierr = PetscSectionGetDof(section, point, &dof);CHKERRQ(ierr);
6579   ierr = PetscSectionGetConstraintDof(section, point, &cdof);CHKERRQ(ierr);
6580   if (!cdof || setBC) {
6581     for (k = 0; k < dof; ++k) {
6582       const PetscInt preind = perm ? *loff+perm[k] : *loff+k;
6583       const PetscInt ind    = indperm ? indperm[preind] : preind;
6584 
6585       indices[ind] = off + k;
6586     }
6587   } else {
6588     ierr = PetscSectionGetConstraintIndices(section, point, &cdofs);CHKERRQ(ierr);
6589     for (k = 0; k < dof; ++k) {
6590       const PetscInt preind = perm ? *loff+perm[k] : *loff+k;
6591       const PetscInt ind    = indperm ? indperm[preind] : preind;
6592 
6593       if ((cind < cdof) && (k == cdofs[cind])) {
6594         /* Insert check for returning constrained indices */
6595         indices[ind] = -(off+k+1);
6596         ++cind;
6597       } else {
6598         indices[ind] = off + k - (islocal ? 0 : cind);
6599       }
6600     }
6601   }
6602   *loff += dof;
6603   PetscFunctionReturn(0);
6604 }
6605 
6606 /*
6607  DMPlexGetIndicesPointFields_Internal - gets section indices for a point in its canonical ordering.
6608 
6609  Input Parameters:
6610 + section - a section (global or local)
6611 - islocal - PETSC_TRUE if requesting local indices (i.e., section is local); PETSC_FALSE for global
6612 . point - point within section
6613 . off - The offset of this point in the (local or global) indexed space - should match islocal and (usually) the section
6614 . foffs - array of length numFields containing the offset in canonical point ordering (the location in indices) of each field
6615 . setBC - identify constrained (boundary condition) points via involution.
6616 . perms - perms[f][permsoff][:] is a permutation of dofs within each field
6617 . permsoff - offset
6618 - indperm - index permutation
6619 
6620  Output Parameter:
6621 . foffs - each entry is incremented by the number of (unconstrained if setBC=FALSE) dofs in that field
6622 . indices - array to hold indices (as defined by section) of each dof associated with point
6623 
6624  Notes:
6625  If section is local and setBC=true, there is no distinction between constrained and unconstrained dofs.
6626  If section is local and setBC=false, the indices for constrained points are the involution -(i+1) of their position
6627  in the local vector.
6628 
6629  If section is global and setBC=false, the indices for constrained points are negative (and their value is not
6630  significant).  It is invalid to call with a global section and setBC=true.
6631 
6632  Developer Note:
6633  The section is only used for field layout, so islocal is technically a statement about the offset (off).  At some point
6634  in the future, global sections may have fields set, in which case we could pass the global section and obtain the
6635  offset could be obtained from the section instead of passing it explicitly as we do now.
6636 
6637  Example:
6638  Suppose a point contains one field with three components, and for which the unconstrained indices are {10, 11, 12}.
6639  When the middle component is constrained, we get the array {10, -12, 12} for (islocal=TRUE, setBC=FALSE).
6640  Note that -12 is the involution of 11, so the user can involute negative indices to recover local indices.
6641  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.
6642 
6643  Level: developer
6644 */
6645 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[])
6646 {
6647   PetscInt       numFields, foff, f;
6648   PetscErrorCode ierr;
6649 
6650   PetscFunctionBegin;
6651   PetscCheckFalse(!islocal && setBC,PetscObjectComm((PetscObject)section),PETSC_ERR_ARG_INCOMP,"setBC incompatible with global indices; use a local section or disable setBC");
6652   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
6653   for (f = 0, foff = 0; f < numFields; ++f) {
6654     PetscInt        fdof, cfdof;
6655     const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
6656     PetscInt        cind = 0, b;
6657     const PetscInt  *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL;
6658 
6659     ierr = PetscSectionGetFieldDof(section, point, f, &fdof);CHKERRQ(ierr);
6660     ierr = PetscSectionGetFieldConstraintDof(section, point, f, &cfdof);CHKERRQ(ierr);
6661     if (!cfdof || setBC) {
6662       for (b = 0; b < fdof; ++b) {
6663         const PetscInt preind = perm ? foffs[f]+perm[b] : foffs[f]+b;
6664         const PetscInt ind    = indperm ? indperm[preind] : preind;
6665 
6666         indices[ind] = off+foff+b;
6667       }
6668     } else {
6669       ierr = PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);CHKERRQ(ierr);
6670       for (b = 0; b < fdof; ++b) {
6671         const PetscInt preind = perm ? foffs[f]+perm[b] : foffs[f]+b;
6672         const PetscInt ind    = indperm ? indperm[preind] : preind;
6673 
6674         if ((cind < cfdof) && (b == fcdofs[cind])) {
6675           indices[ind] = -(off+foff+b+1);
6676           ++cind;
6677         } else {
6678           indices[ind] = off + foff + b - (islocal ? 0 : cind);
6679         }
6680       }
6681     }
6682     foff     += (setBC || islocal ? fdof : (fdof - cfdof));
6683     foffs[f] += fdof;
6684   }
6685   PetscFunctionReturn(0);
6686 }
6687 
6688 /*
6689   This version believes the globalSection offsets for each field, rather than just the point offset
6690 
6691  . foffs - The offset into 'indices' for each field, since it is segregated by field
6692 
6693  Notes:
6694  The semantics of this function relate to that of setBC=FALSE in DMPlexGetIndicesPointFields_Internal.
6695  Since this function uses global indices, setBC=TRUE would be invalid, so no such argument exists.
6696 */
6697 static PetscErrorCode DMPlexGetIndicesPointFieldsSplit_Internal(PetscSection section, PetscSection globalSection, PetscInt point, PetscInt foffs[], const PetscInt ***perms, PetscInt permsoff, const PetscInt indperm[], PetscInt indices[])
6698 {
6699   PetscInt       numFields, foff, f;
6700   PetscErrorCode ierr;
6701 
6702   PetscFunctionBegin;
6703   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
6704   for (f = 0; f < numFields; ++f) {
6705     PetscInt        fdof, cfdof;
6706     const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
6707     PetscInt        cind = 0, b;
6708     const PetscInt  *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL;
6709 
6710     ierr = PetscSectionGetFieldDof(section, point, f, &fdof);CHKERRQ(ierr);
6711     ierr = PetscSectionGetFieldConstraintDof(section, point, f, &cfdof);CHKERRQ(ierr);
6712     ierr = PetscSectionGetFieldOffset(globalSection, point, f, &foff);CHKERRQ(ierr);
6713     if (!cfdof) {
6714       for (b = 0; b < fdof; ++b) {
6715         const PetscInt preind = perm ? foffs[f]+perm[b] : foffs[f]+b;
6716         const PetscInt ind    = indperm ? indperm[preind] : preind;
6717 
6718         indices[ind] = foff+b;
6719       }
6720     } else {
6721       ierr = PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);CHKERRQ(ierr);
6722       for (b = 0; b < fdof; ++b) {
6723         const PetscInt preind = perm ? foffs[f]+perm[b] : foffs[f]+b;
6724         const PetscInt ind    = indperm ? indperm[preind] : preind;
6725 
6726         if ((cind < cfdof) && (b == fcdofs[cind])) {
6727           indices[ind] = -(foff+b+1);
6728           ++cind;
6729         } else {
6730           indices[ind] = foff+b-cind;
6731         }
6732       }
6733     }
6734     foffs[f] += fdof;
6735   }
6736   PetscFunctionReturn(0);
6737 }
6738 
6739 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)
6740 {
6741   Mat             cMat;
6742   PetscSection    aSec, cSec;
6743   IS              aIS;
6744   PetscInt        aStart = -1, aEnd = -1;
6745   const PetscInt  *anchors;
6746   PetscInt        numFields, f, p, q, newP = 0;
6747   PetscInt        newNumPoints = 0, newNumIndices = 0;
6748   PetscInt        *newPoints, *indices, *newIndices;
6749   PetscInt        maxAnchor, maxDof;
6750   PetscInt        newOffsets[32];
6751   PetscInt        *pointMatOffsets[32];
6752   PetscInt        *newPointOffsets[32];
6753   PetscScalar     *pointMat[32];
6754   PetscScalar     *newValues=NULL,*tmpValues;
6755   PetscBool       anyConstrained = PETSC_FALSE;
6756   PetscErrorCode  ierr;
6757 
6758   PetscFunctionBegin;
6759   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6760   PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2);
6761   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
6762 
6763   ierr = DMPlexGetAnchors(dm,&aSec,&aIS);CHKERRQ(ierr);
6764   /* if there are point-to-point constraints */
6765   if (aSec) {
6766     ierr = PetscArrayzero(newOffsets, 32);CHKERRQ(ierr);
6767     ierr = ISGetIndices(aIS,&anchors);CHKERRQ(ierr);
6768     ierr = PetscSectionGetChart(aSec,&aStart,&aEnd);CHKERRQ(ierr);
6769     /* figure out how many points are going to be in the new element matrix
6770      * (we allow double counting, because it's all just going to be summed
6771      * into the global matrix anyway) */
6772     for (p = 0; p < 2*numPoints; p+=2) {
6773       PetscInt b    = points[p];
6774       PetscInt bDof = 0, bSecDof;
6775 
6776       ierr = PetscSectionGetDof(section,b,&bSecDof);CHKERRQ(ierr);
6777       if (!bSecDof) {
6778         continue;
6779       }
6780       if (b >= aStart && b < aEnd) {
6781         ierr = PetscSectionGetDof(aSec,b,&bDof);CHKERRQ(ierr);
6782       }
6783       if (bDof) {
6784         /* this point is constrained */
6785         /* it is going to be replaced by its anchors */
6786         PetscInt bOff, q;
6787 
6788         anyConstrained = PETSC_TRUE;
6789         newNumPoints  += bDof;
6790         ierr = PetscSectionGetOffset(aSec,b,&bOff);CHKERRQ(ierr);
6791         for (q = 0; q < bDof; q++) {
6792           PetscInt a = anchors[bOff + q];
6793           PetscInt aDof;
6794 
6795           ierr           = PetscSectionGetDof(section,a,&aDof);CHKERRQ(ierr);
6796           newNumIndices += aDof;
6797           for (f = 0; f < numFields; ++f) {
6798             PetscInt fDof;
6799 
6800             ierr             = PetscSectionGetFieldDof(section, a, f, &fDof);CHKERRQ(ierr);
6801             newOffsets[f+1] += fDof;
6802           }
6803         }
6804       }
6805       else {
6806         /* this point is not constrained */
6807         newNumPoints++;
6808         newNumIndices += bSecDof;
6809         for (f = 0; f < numFields; ++f) {
6810           PetscInt fDof;
6811 
6812           ierr = PetscSectionGetFieldDof(section, b, f, &fDof);CHKERRQ(ierr);
6813           newOffsets[f+1] += fDof;
6814         }
6815       }
6816     }
6817   }
6818   if (!anyConstrained) {
6819     if (outNumPoints)  *outNumPoints  = 0;
6820     if (outNumIndices) *outNumIndices = 0;
6821     if (outPoints)     *outPoints     = NULL;
6822     if (outValues)     *outValues     = NULL;
6823     if (aSec) {ierr = ISRestoreIndices(aIS,&anchors);CHKERRQ(ierr);}
6824     PetscFunctionReturn(0);
6825   }
6826 
6827   if (outNumPoints)  *outNumPoints  = newNumPoints;
6828   if (outNumIndices) *outNumIndices = newNumIndices;
6829 
6830   for (f = 0; f < numFields; ++f) newOffsets[f+1] += newOffsets[f];
6831 
6832   if (!outPoints && !outValues) {
6833     if (offsets) {
6834       for (f = 0; f <= numFields; f++) {
6835         offsets[f] = newOffsets[f];
6836       }
6837     }
6838     if (aSec) {ierr = ISRestoreIndices(aIS,&anchors);CHKERRQ(ierr);}
6839     PetscFunctionReturn(0);
6840   }
6841 
6842   PetscCheckFalse(numFields && newOffsets[numFields] != newNumIndices,PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid size for closure %D should be %D", newOffsets[numFields], newNumIndices);
6843 
6844   ierr = DMGetDefaultConstraints(dm, &cSec, &cMat, NULL);CHKERRQ(ierr);
6845 
6846   /* workspaces */
6847   if (numFields) {
6848     for (f = 0; f < numFields; f++) {
6849       ierr = DMGetWorkArray(dm,numPoints+1,MPIU_INT,&pointMatOffsets[f]);CHKERRQ(ierr);
6850       ierr = DMGetWorkArray(dm,numPoints+1,MPIU_INT,&newPointOffsets[f]);CHKERRQ(ierr);
6851     }
6852   }
6853   else {
6854     ierr = DMGetWorkArray(dm,numPoints+1,MPIU_INT,&pointMatOffsets[0]);CHKERRQ(ierr);
6855     ierr = DMGetWorkArray(dm,numPoints,MPIU_INT,&newPointOffsets[0]);CHKERRQ(ierr);
6856   }
6857 
6858   /* get workspaces for the point-to-point matrices */
6859   if (numFields) {
6860     PetscInt totalOffset, totalMatOffset;
6861 
6862     for (p = 0; p < numPoints; p++) {
6863       PetscInt b    = points[2*p];
6864       PetscInt bDof = 0, bSecDof;
6865 
6866       ierr = PetscSectionGetDof(section,b,&bSecDof);CHKERRQ(ierr);
6867       if (!bSecDof) {
6868         for (f = 0; f < numFields; f++) {
6869           newPointOffsets[f][p + 1] = 0;
6870           pointMatOffsets[f][p + 1] = 0;
6871         }
6872         continue;
6873       }
6874       if (b >= aStart && b < aEnd) {
6875         ierr = PetscSectionGetDof(aSec, b, &bDof);CHKERRQ(ierr);
6876       }
6877       if (bDof) {
6878         for (f = 0; f < numFields; f++) {
6879           PetscInt fDof, q, bOff, allFDof = 0;
6880 
6881           ierr = PetscSectionGetFieldDof(section, b, f, &fDof);CHKERRQ(ierr);
6882           ierr = PetscSectionGetOffset(aSec, b, &bOff);CHKERRQ(ierr);
6883           for (q = 0; q < bDof; q++) {
6884             PetscInt a = anchors[bOff + q];
6885             PetscInt aFDof;
6886 
6887             ierr     = PetscSectionGetFieldDof(section, a, f, &aFDof);CHKERRQ(ierr);
6888             allFDof += aFDof;
6889           }
6890           newPointOffsets[f][p+1] = allFDof;
6891           pointMatOffsets[f][p+1] = fDof * allFDof;
6892         }
6893       }
6894       else {
6895         for (f = 0; f < numFields; f++) {
6896           PetscInt fDof;
6897 
6898           ierr = PetscSectionGetFieldDof(section, b, f, &fDof);CHKERRQ(ierr);
6899           newPointOffsets[f][p+1] = fDof;
6900           pointMatOffsets[f][p+1] = 0;
6901         }
6902       }
6903     }
6904     for (f = 0, totalOffset = 0, totalMatOffset = 0; f < numFields; f++) {
6905       newPointOffsets[f][0] = totalOffset;
6906       pointMatOffsets[f][0] = totalMatOffset;
6907       for (p = 0; p < numPoints; p++) {
6908         newPointOffsets[f][p+1] += newPointOffsets[f][p];
6909         pointMatOffsets[f][p+1] += pointMatOffsets[f][p];
6910       }
6911       totalOffset    = newPointOffsets[f][numPoints];
6912       totalMatOffset = pointMatOffsets[f][numPoints];
6913       ierr = DMGetWorkArray(dm,pointMatOffsets[f][numPoints],MPIU_SCALAR,&pointMat[f]);CHKERRQ(ierr);
6914     }
6915   }
6916   else {
6917     for (p = 0; p < numPoints; p++) {
6918       PetscInt b    = points[2*p];
6919       PetscInt bDof = 0, bSecDof;
6920 
6921       ierr = PetscSectionGetDof(section,b,&bSecDof);CHKERRQ(ierr);
6922       if (!bSecDof) {
6923         newPointOffsets[0][p + 1] = 0;
6924         pointMatOffsets[0][p + 1] = 0;
6925         continue;
6926       }
6927       if (b >= aStart && b < aEnd) {
6928         ierr = PetscSectionGetDof(aSec, b, &bDof);CHKERRQ(ierr);
6929       }
6930       if (bDof) {
6931         PetscInt bOff, q, allDof = 0;
6932 
6933         ierr = PetscSectionGetOffset(aSec, b, &bOff);CHKERRQ(ierr);
6934         for (q = 0; q < bDof; q++) {
6935           PetscInt a = anchors[bOff + q], aDof;
6936 
6937           ierr    = PetscSectionGetDof(section, a, &aDof);CHKERRQ(ierr);
6938           allDof += aDof;
6939         }
6940         newPointOffsets[0][p+1] = allDof;
6941         pointMatOffsets[0][p+1] = bSecDof * allDof;
6942       }
6943       else {
6944         newPointOffsets[0][p+1] = bSecDof;
6945         pointMatOffsets[0][p+1] = 0;
6946       }
6947     }
6948     newPointOffsets[0][0] = 0;
6949     pointMatOffsets[0][0] = 0;
6950     for (p = 0; p < numPoints; p++) {
6951       newPointOffsets[0][p+1] += newPointOffsets[0][p];
6952       pointMatOffsets[0][p+1] += pointMatOffsets[0][p];
6953     }
6954     ierr = DMGetWorkArray(dm,pointMatOffsets[0][numPoints],MPIU_SCALAR,&pointMat[0]);CHKERRQ(ierr);
6955   }
6956 
6957   /* output arrays */
6958   ierr = DMGetWorkArray(dm,2*newNumPoints,MPIU_INT,&newPoints);CHKERRQ(ierr);
6959 
6960   /* get the point-to-point matrices; construct newPoints */
6961   ierr = PetscSectionGetMaxDof(aSec, &maxAnchor);CHKERRQ(ierr);
6962   ierr = PetscSectionGetMaxDof(section, &maxDof);CHKERRQ(ierr);
6963   ierr = DMGetWorkArray(dm,maxDof,MPIU_INT,&indices);CHKERRQ(ierr);
6964   ierr = DMGetWorkArray(dm,maxAnchor*maxDof,MPIU_INT,&newIndices);CHKERRQ(ierr);
6965   if (numFields) {
6966     for (p = 0, newP = 0; p < numPoints; p++) {
6967       PetscInt b    = points[2*p];
6968       PetscInt o    = points[2*p+1];
6969       PetscInt bDof = 0, bSecDof;
6970 
6971       ierr = PetscSectionGetDof(section, b, &bSecDof);CHKERRQ(ierr);
6972       if (!bSecDof) {
6973         continue;
6974       }
6975       if (b >= aStart && b < aEnd) {
6976         ierr = PetscSectionGetDof(aSec, b, &bDof);CHKERRQ(ierr);
6977       }
6978       if (bDof) {
6979         PetscInt fStart[32], fEnd[32], fAnchorStart[32], fAnchorEnd[32], bOff, q;
6980 
6981         fStart[0] = 0;
6982         fEnd[0]   = 0;
6983         for (f = 0; f < numFields; f++) {
6984           PetscInt fDof;
6985 
6986           ierr        = PetscSectionGetFieldDof(cSec, b, f, &fDof);CHKERRQ(ierr);
6987           fStart[f+1] = fStart[f] + fDof;
6988           fEnd[f+1]   = fStart[f+1];
6989         }
6990         ierr = PetscSectionGetOffset(cSec, b, &bOff);CHKERRQ(ierr);
6991         ierr = DMPlexGetIndicesPointFields_Internal(cSec, PETSC_TRUE, b, bOff, fEnd, PETSC_TRUE, perms, p, NULL, indices);CHKERRQ(ierr);
6992 
6993         fAnchorStart[0] = 0;
6994         fAnchorEnd[0]   = 0;
6995         for (f = 0; f < numFields; f++) {
6996           PetscInt fDof = newPointOffsets[f][p + 1] - newPointOffsets[f][p];
6997 
6998           fAnchorStart[f+1] = fAnchorStart[f] + fDof;
6999           fAnchorEnd[f+1]   = fAnchorStart[f + 1];
7000         }
7001         ierr = PetscSectionGetOffset(aSec, b, &bOff);CHKERRQ(ierr);
7002         for (q = 0; q < bDof; q++) {
7003           PetscInt a = anchors[bOff + q], aOff;
7004 
7005           /* we take the orientation of ap into account in the order that we constructed the indices above: the newly added points have no orientation */
7006           newPoints[2*(newP + q)]     = a;
7007           newPoints[2*(newP + q) + 1] = 0;
7008           ierr = PetscSectionGetOffset(section, a, &aOff);CHKERRQ(ierr);
7009           ierr = DMPlexGetIndicesPointFields_Internal(section, PETSC_TRUE, a, aOff, fAnchorEnd, PETSC_TRUE, NULL, -1, NULL, newIndices);CHKERRQ(ierr);
7010         }
7011         newP += bDof;
7012 
7013         if (outValues) {
7014           /* get the point-to-point submatrix */
7015           for (f = 0; f < numFields; f++) {
7016             ierr = MatGetValues(cMat,fEnd[f]-fStart[f],indices + fStart[f],fAnchorEnd[f] - fAnchorStart[f],newIndices + fAnchorStart[f],pointMat[f] + pointMatOffsets[f][p]);CHKERRQ(ierr);
7017           }
7018         }
7019       }
7020       else {
7021         newPoints[2 * newP]     = b;
7022         newPoints[2 * newP + 1] = o;
7023         newP++;
7024       }
7025     }
7026   } else {
7027     for (p = 0; p < numPoints; p++) {
7028       PetscInt b    = points[2*p];
7029       PetscInt o    = points[2*p+1];
7030       PetscInt bDof = 0, bSecDof;
7031 
7032       ierr = PetscSectionGetDof(section, b, &bSecDof);CHKERRQ(ierr);
7033       if (!bSecDof) {
7034         continue;
7035       }
7036       if (b >= aStart && b < aEnd) {
7037         ierr = PetscSectionGetDof(aSec, b, &bDof);CHKERRQ(ierr);
7038       }
7039       if (bDof) {
7040         PetscInt bEnd = 0, bAnchorEnd = 0, bOff;
7041 
7042         ierr = PetscSectionGetOffset(cSec, b, &bOff);CHKERRQ(ierr);
7043         ierr = DMPlexGetIndicesPoint_Internal(cSec, PETSC_TRUE, b, bOff, &bEnd, PETSC_TRUE, (perms && perms[0]) ? perms[0][p] : NULL, NULL, indices);CHKERRQ(ierr);
7044 
7045         ierr = PetscSectionGetOffset (aSec, b, &bOff);CHKERRQ(ierr);
7046         for (q = 0; q < bDof; q++) {
7047           PetscInt a = anchors[bOff + q], aOff;
7048 
7049           /* we take the orientation of ap into account in the order that we constructed the indices above: the newly added points have no orientation */
7050 
7051           newPoints[2*(newP + q)]     = a;
7052           newPoints[2*(newP + q) + 1] = 0;
7053           ierr = PetscSectionGetOffset(section, a, &aOff);CHKERRQ(ierr);
7054           ierr = DMPlexGetIndicesPoint_Internal(section, PETSC_TRUE, a, aOff, &bAnchorEnd, PETSC_TRUE, NULL, NULL, newIndices);CHKERRQ(ierr);
7055         }
7056         newP += bDof;
7057 
7058         /* get the point-to-point submatrix */
7059         if (outValues) {
7060           ierr = MatGetValues(cMat,bEnd,indices,bAnchorEnd,newIndices,pointMat[0] + pointMatOffsets[0][p]);CHKERRQ(ierr);
7061         }
7062       }
7063       else {
7064         newPoints[2 * newP]     = b;
7065         newPoints[2 * newP + 1] = o;
7066         newP++;
7067       }
7068     }
7069   }
7070 
7071   if (outValues) {
7072     ierr = DMGetWorkArray(dm,newNumIndices*numIndices,MPIU_SCALAR,&tmpValues);CHKERRQ(ierr);
7073     ierr = PetscArrayzero(tmpValues,newNumIndices*numIndices);CHKERRQ(ierr);
7074     /* multiply constraints on the right */
7075     if (numFields) {
7076       for (f = 0; f < numFields; f++) {
7077         PetscInt oldOff = offsets[f];
7078 
7079         for (p = 0; p < numPoints; p++) {
7080           PetscInt cStart = newPointOffsets[f][p];
7081           PetscInt b      = points[2 * p];
7082           PetscInt c, r, k;
7083           PetscInt dof;
7084 
7085           ierr = PetscSectionGetFieldDof(section,b,f,&dof);CHKERRQ(ierr);
7086           if (!dof) {
7087             continue;
7088           }
7089           if (pointMatOffsets[f][p] < pointMatOffsets[f][p + 1]) {
7090             PetscInt nCols         = newPointOffsets[f][p+1]-cStart;
7091             const PetscScalar *mat = pointMat[f] + pointMatOffsets[f][p];
7092 
7093             for (r = 0; r < numIndices; r++) {
7094               for (c = 0; c < nCols; c++) {
7095                 for (k = 0; k < dof; k++) {
7096                   tmpValues[r * newNumIndices + cStart + c] += values[r * numIndices + oldOff + k] * mat[k * nCols + c];
7097                 }
7098               }
7099             }
7100           }
7101           else {
7102             /* copy this column as is */
7103             for (r = 0; r < numIndices; r++) {
7104               for (c = 0; c < dof; c++) {
7105                 tmpValues[r * newNumIndices + cStart + c] = values[r * numIndices + oldOff + c];
7106               }
7107             }
7108           }
7109           oldOff += dof;
7110         }
7111       }
7112     }
7113     else {
7114       PetscInt oldOff = 0;
7115       for (p = 0; p < numPoints; p++) {
7116         PetscInt cStart = newPointOffsets[0][p];
7117         PetscInt b      = points[2 * p];
7118         PetscInt c, r, k;
7119         PetscInt dof;
7120 
7121         ierr = PetscSectionGetDof(section,b,&dof);CHKERRQ(ierr);
7122         if (!dof) {
7123           continue;
7124         }
7125         if (pointMatOffsets[0][p] < pointMatOffsets[0][p + 1]) {
7126           PetscInt nCols         = newPointOffsets[0][p+1]-cStart;
7127           const PetscScalar *mat = pointMat[0] + pointMatOffsets[0][p];
7128 
7129           for (r = 0; r < numIndices; r++) {
7130             for (c = 0; c < nCols; c++) {
7131               for (k = 0; k < dof; k++) {
7132                 tmpValues[r * newNumIndices + cStart + c] += mat[k * nCols + c] * values[r * numIndices + oldOff + k];
7133               }
7134             }
7135           }
7136         }
7137         else {
7138           /* copy this column as is */
7139           for (r = 0; r < numIndices; r++) {
7140             for (c = 0; c < dof; c++) {
7141               tmpValues[r * newNumIndices + cStart + c] = values[r * numIndices + oldOff + c];
7142             }
7143           }
7144         }
7145         oldOff += dof;
7146       }
7147     }
7148 
7149     if (multiplyLeft) {
7150       ierr = DMGetWorkArray(dm,newNumIndices*newNumIndices,MPIU_SCALAR,&newValues);CHKERRQ(ierr);
7151       ierr = PetscArrayzero(newValues,newNumIndices*newNumIndices);CHKERRQ(ierr);
7152       /* multiply constraints transpose on the left */
7153       if (numFields) {
7154         for (f = 0; f < numFields; f++) {
7155           PetscInt oldOff = offsets[f];
7156 
7157           for (p = 0; p < numPoints; p++) {
7158             PetscInt rStart = newPointOffsets[f][p];
7159             PetscInt b      = points[2 * p];
7160             PetscInt c, r, k;
7161             PetscInt dof;
7162 
7163             ierr = PetscSectionGetFieldDof(section,b,f,&dof);CHKERRQ(ierr);
7164             if (pointMatOffsets[f][p] < pointMatOffsets[f][p + 1]) {
7165               PetscInt nRows                        = newPointOffsets[f][p+1]-rStart;
7166               const PetscScalar *PETSC_RESTRICT mat = pointMat[f] + pointMatOffsets[f][p];
7167 
7168               for (r = 0; r < nRows; r++) {
7169                 for (c = 0; c < newNumIndices; c++) {
7170                   for (k = 0; k < dof; k++) {
7171                     newValues[(rStart + r) * newNumIndices + c] += mat[k * nRows + r] * tmpValues[(oldOff + k) * newNumIndices + c];
7172                   }
7173                 }
7174               }
7175             }
7176             else {
7177               /* copy this row as is */
7178               for (r = 0; r < dof; r++) {
7179                 for (c = 0; c < newNumIndices; c++) {
7180                   newValues[(rStart + r) * newNumIndices + c] = tmpValues[(oldOff + r) * newNumIndices + c];
7181                 }
7182               }
7183             }
7184             oldOff += dof;
7185           }
7186         }
7187       }
7188       else {
7189         PetscInt oldOff = 0;
7190 
7191         for (p = 0; p < numPoints; p++) {
7192           PetscInt rStart = newPointOffsets[0][p];
7193           PetscInt b      = points[2 * p];
7194           PetscInt c, r, k;
7195           PetscInt dof;
7196 
7197           ierr = PetscSectionGetDof(section,b,&dof);CHKERRQ(ierr);
7198           if (pointMatOffsets[0][p] < pointMatOffsets[0][p + 1]) {
7199             PetscInt nRows                        = newPointOffsets[0][p+1]-rStart;
7200             const PetscScalar *PETSC_RESTRICT mat = pointMat[0] + pointMatOffsets[0][p];
7201 
7202             for (r = 0; r < nRows; r++) {
7203               for (c = 0; c < newNumIndices; c++) {
7204                 for (k = 0; k < dof; k++) {
7205                   newValues[(rStart + r) * newNumIndices + c] += mat[k * nRows + r] * tmpValues[(oldOff + k) * newNumIndices + c];
7206                 }
7207               }
7208             }
7209           }
7210           else {
7211             /* copy this row as is */
7212             for (r = 0; r < dof; r++) {
7213               for (c = 0; c < newNumIndices; c++) {
7214                 newValues[(rStart + r) * newNumIndices + c] = tmpValues[(oldOff + r) * newNumIndices + c];
7215               }
7216             }
7217           }
7218           oldOff += dof;
7219         }
7220       }
7221 
7222       ierr = DMRestoreWorkArray(dm,newNumIndices*numIndices,MPIU_SCALAR,&tmpValues);CHKERRQ(ierr);
7223     }
7224     else {
7225       newValues = tmpValues;
7226     }
7227   }
7228 
7229   /* clean up */
7230   ierr = DMRestoreWorkArray(dm,maxDof,MPIU_INT,&indices);CHKERRQ(ierr);
7231   ierr = DMRestoreWorkArray(dm,maxAnchor*maxDof,MPIU_INT,&newIndices);CHKERRQ(ierr);
7232 
7233   if (numFields) {
7234     for (f = 0; f < numFields; f++) {
7235       ierr = DMRestoreWorkArray(dm,pointMatOffsets[f][numPoints],MPIU_SCALAR,&pointMat[f]);CHKERRQ(ierr);
7236       ierr = DMRestoreWorkArray(dm,numPoints+1,MPIU_INT,&pointMatOffsets[f]);CHKERRQ(ierr);
7237       ierr = DMRestoreWorkArray(dm,numPoints+1,MPIU_INT,&newPointOffsets[f]);CHKERRQ(ierr);
7238     }
7239   }
7240   else {
7241     ierr = DMRestoreWorkArray(dm,pointMatOffsets[0][numPoints],MPIU_SCALAR,&pointMat[0]);CHKERRQ(ierr);
7242     ierr = DMRestoreWorkArray(dm,numPoints+1,MPIU_INT,&pointMatOffsets[0]);CHKERRQ(ierr);
7243     ierr = DMRestoreWorkArray(dm,numPoints+1,MPIU_INT,&newPointOffsets[0]);CHKERRQ(ierr);
7244   }
7245   ierr = ISRestoreIndices(aIS,&anchors);CHKERRQ(ierr);
7246 
7247   /* output */
7248   if (outPoints) {
7249     *outPoints = newPoints;
7250   }
7251   else {
7252     ierr = DMRestoreWorkArray(dm,2*newNumPoints,MPIU_INT,&newPoints);CHKERRQ(ierr);
7253   }
7254   if (outValues) {
7255     *outValues = newValues;
7256   }
7257   for (f = 0; f <= numFields; f++) {
7258     offsets[f] = newOffsets[f];
7259   }
7260   PetscFunctionReturn(0);
7261 }
7262 
7263 /*@C
7264   DMPlexGetClosureIndices - Gets the global dof indices associated with the closure of the given point within the provided sections.
7265 
7266   Not collective
7267 
7268   Input Parameters:
7269 + dm         - The DM
7270 . section    - The PetscSection describing the points (a local section)
7271 . idxSection - The PetscSection from which to obtain indices (may be local or global)
7272 . point      - The point defining the closure
7273 - useClPerm  - Use the closure point permutation if available
7274 
7275   Output Parameters:
7276 + numIndices - The number of dof indices in the closure of point with the input sections
7277 . indices    - The dof indices
7278 . outOffsets - Array to write the field offsets into, or NULL
7279 - values     - The input values, which may be modified if sign flips are induced by the point symmetries, or NULL
7280 
7281   Notes:
7282   Must call DMPlexRestoreClosureIndices() to free allocated memory
7283 
7284   If idxSection is global, any constrained dofs (see DMAddBoundary(), for example) will get negative indices.  The value
7285   of those indices is not significant.  If idxSection is local, the constrained dofs will yield the involution -(idx+1)
7286   of their index in a local vector.  A caller who does not wish to distinguish those points may recover the nonnegative
7287   indices via involution, -(-(idx+1)+1)==idx.  Local indices are provided when idxSection == section, otherwise global
7288   indices (with the above semantics) are implied.
7289 
7290   Level: advanced
7291 
7292 .seealso DMPlexRestoreClosureIndices(), DMPlexVecGetClosure(), DMPlexMatSetClosure(), DMGetLocalSection(), DMGetGlobalSection()
7293 @*/
7294 PetscErrorCode DMPlexGetClosureIndices(DM dm, PetscSection section, PetscSection idxSection, PetscInt point, PetscBool useClPerm,
7295                                        PetscInt *numIndices, PetscInt *indices[], PetscInt outOffsets[], PetscScalar *values[])
7296 {
7297   /* Closure ordering */
7298   PetscSection        clSection;
7299   IS                  clPoints;
7300   const PetscInt     *clp;
7301   PetscInt           *points;
7302   const PetscInt     *clperm = NULL;
7303   /* Dof permutation and sign flips */
7304   const PetscInt    **perms[32] = {NULL};
7305   const PetscScalar **flips[32] = {NULL};
7306   PetscScalar        *valCopy   = NULL;
7307   /* Hanging node constraints */
7308   PetscInt           *pointsC = NULL;
7309   PetscScalar        *valuesC = NULL;
7310   PetscInt            NclC, NiC;
7311 
7312   PetscInt           *idx;
7313   PetscInt            Nf, Ncl, Ni = 0, offsets[32], p, f;
7314   PetscBool           isLocal = (section == idxSection) ? PETSC_TRUE : PETSC_FALSE;
7315   PetscErrorCode      ierr;
7316 
7317   PetscFunctionBeginHot;
7318   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7319   PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2);
7320   PetscValidHeaderSpecific(idxSection, PETSC_SECTION_CLASSID, 3);
7321   if (numIndices) PetscValidPointer(numIndices, 6);
7322   if (indices)    PetscValidPointer(indices, 7);
7323   if (outOffsets) PetscValidPointer(outOffsets, 8);
7324   if (values)     PetscValidPointer(values, 9);
7325   ierr = PetscSectionGetNumFields(section, &Nf);CHKERRQ(ierr);
7326   PetscCheckFalse(Nf > 31,PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", Nf);
7327   ierr = PetscArrayzero(offsets, 32);CHKERRQ(ierr);
7328   /* 1) Get points in closure */
7329   ierr = DMPlexGetCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp);CHKERRQ(ierr);
7330   if (useClPerm) {
7331     PetscInt depth, clsize;
7332     ierr = DMPlexGetPointDepth(dm, point, &depth);CHKERRQ(ierr);
7333     for (clsize=0,p=0; p<Ncl; p++) {
7334       PetscInt dof;
7335       ierr = PetscSectionGetDof(section, points[2*p], &dof);CHKERRQ(ierr);
7336       clsize += dof;
7337     }
7338     ierr = PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject) dm, depth, clsize, &clperm);CHKERRQ(ierr);
7339   }
7340   /* 2) Get number of indices on these points and field offsets from section */
7341   for (p = 0; p < Ncl*2; p += 2) {
7342     PetscInt dof, fdof;
7343 
7344     ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
7345     for (f = 0; f < Nf; ++f) {
7346       ierr = PetscSectionGetFieldDof(section, points[p], f, &fdof);CHKERRQ(ierr);
7347       offsets[f+1] += fdof;
7348     }
7349     Ni += dof;
7350   }
7351   for (f = 1; f < Nf; ++f) offsets[f+1] += offsets[f];
7352   PetscCheckFalse(Nf && offsets[Nf] != Ni,PetscObjectComm((PetscObject) dm), PETSC_ERR_PLIB, "Invalid size for closure %D should be %D", offsets[Nf], Ni);
7353   /* 3) Get symmetries and sign flips. Apply sign flips to values if passed in (only works for square values matrix) */
7354   for (f = 0; f < PetscMax(1, Nf); ++f) {
7355     if (Nf) {ierr = PetscSectionGetFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f]);CHKERRQ(ierr);}
7356     else    {ierr = PetscSectionGetPointSyms(section, Ncl, points, &perms[f], &flips[f]);CHKERRQ(ierr);}
7357     /* may need to apply sign changes to the element matrix */
7358     if (values && flips[f]) {
7359       PetscInt foffset = offsets[f];
7360 
7361       for (p = 0; p < Ncl; ++p) {
7362         PetscInt           pnt  = points[2*p], fdof;
7363         const PetscScalar *flip = flips[f] ? flips[f][p] : NULL;
7364 
7365         if (!Nf) {ierr = PetscSectionGetDof(section, pnt, &fdof);CHKERRQ(ierr);}
7366         else     {ierr = PetscSectionGetFieldDof(section, pnt, f, &fdof);CHKERRQ(ierr);}
7367         if (flip) {
7368           PetscInt i, j, k;
7369 
7370           if (!valCopy) {
7371             ierr = DMGetWorkArray(dm, Ni*Ni, MPIU_SCALAR, &valCopy);CHKERRQ(ierr);
7372             for (j = 0; j < Ni * Ni; ++j) valCopy[j] = (*values)[j];
7373             *values = valCopy;
7374           }
7375           for (i = 0; i < fdof; ++i) {
7376             PetscScalar fval = flip[i];
7377 
7378             for (k = 0; k < Ni; ++k) {
7379               valCopy[Ni * (foffset + i) + k] *= fval;
7380               valCopy[Ni * k + (foffset + i)] *= fval;
7381             }
7382           }
7383         }
7384         foffset += fdof;
7385       }
7386     }
7387   }
7388   /* 4) Apply hanging node constraints. Get new symmetries and replace all storage with constrained storage */
7389   ierr = DMPlexAnchorsModifyMat(dm, section, Ncl, Ni, points, perms, values ? *values : NULL, &NclC, &NiC, &pointsC, values ? &valuesC : NULL, offsets, PETSC_TRUE);CHKERRQ(ierr);
7390   if (NclC) {
7391     if (valCopy) {ierr = DMRestoreWorkArray(dm, Ni*Ni, MPIU_SCALAR, &valCopy);CHKERRQ(ierr);}
7392     for (f = 0; f < PetscMax(1, Nf); ++f) {
7393       if (Nf) {ierr = PetscSectionRestoreFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f]);CHKERRQ(ierr);}
7394       else    {ierr = PetscSectionRestorePointSyms(section, Ncl, points, &perms[f], &flips[f]);CHKERRQ(ierr);}
7395     }
7396     for (f = 0; f < PetscMax(1, Nf); ++f) {
7397       if (Nf) {ierr = PetscSectionGetFieldPointSyms(section, f, NclC, pointsC, &perms[f], &flips[f]);CHKERRQ(ierr);}
7398       else    {ierr = PetscSectionGetPointSyms(section, NclC, pointsC, &perms[f], &flips[f]);CHKERRQ(ierr);}
7399     }
7400     ierr = DMPlexRestoreCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp);CHKERRQ(ierr);
7401     Ncl     = NclC;
7402     Ni      = NiC;
7403     points  = pointsC;
7404     if (values) *values = valuesC;
7405   }
7406   /* 5) Calculate indices */
7407   ierr = DMGetWorkArray(dm, Ni, MPIU_INT, &idx);CHKERRQ(ierr);
7408   if (Nf) {
7409     PetscInt  idxOff;
7410     PetscBool useFieldOffsets;
7411 
7412     if (outOffsets) {for (f = 0; f <= Nf; f++) outOffsets[f] = offsets[f];}
7413     ierr = PetscSectionGetUseFieldOffsets(idxSection, &useFieldOffsets);CHKERRQ(ierr);
7414     if (useFieldOffsets) {
7415       for (p = 0; p < Ncl; ++p) {
7416         const PetscInt pnt = points[p*2];
7417 
7418         ierr = DMPlexGetIndicesPointFieldsSplit_Internal(section, idxSection, pnt, offsets, perms, p, clperm, idx);CHKERRQ(ierr);
7419       }
7420     } else {
7421       for (p = 0; p < Ncl; ++p) {
7422         const PetscInt pnt = points[p*2];
7423 
7424         ierr = PetscSectionGetOffset(idxSection, pnt, &idxOff);CHKERRQ(ierr);
7425         /* Note that we pass a local section even though we're using global offsets.  This is because global sections do
7426          * not (at the time of this writing) have fields set. They probably should, in which case we would pass the
7427          * global section. */
7428         ierr = DMPlexGetIndicesPointFields_Internal(section, isLocal, pnt, idxOff < 0 ? -(idxOff+1) : idxOff, offsets, PETSC_FALSE, perms, p, clperm, idx);CHKERRQ(ierr);
7429       }
7430     }
7431   } else {
7432     PetscInt off = 0, idxOff;
7433 
7434     for (p = 0; p < Ncl; ++p) {
7435       const PetscInt  pnt  = points[p*2];
7436       const PetscInt *perm = perms[0] ? perms[0][p] : NULL;
7437 
7438       ierr = PetscSectionGetOffset(idxSection, pnt, &idxOff);CHKERRQ(ierr);
7439       /* Note that we pass a local section even though we're using global offsets.  This is because global sections do
7440        * not (at the time of this writing) have fields set. They probably should, in which case we would pass the global section. */
7441       ierr = DMPlexGetIndicesPoint_Internal(section, isLocal, pnt, idxOff < 0 ? -(idxOff+1) : idxOff, &off, PETSC_FALSE, perm, clperm, idx);CHKERRQ(ierr);
7442     }
7443   }
7444   /* 6) Cleanup */
7445   for (f = 0; f < PetscMax(1, Nf); ++f) {
7446     if (Nf) {ierr = PetscSectionRestoreFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f]);CHKERRQ(ierr);}
7447     else    {ierr = PetscSectionRestorePointSyms(section, Ncl, points, &perms[f], &flips[f]);CHKERRQ(ierr);}
7448   }
7449   if (NclC) {
7450     ierr = DMRestoreWorkArray(dm, NclC*2, MPIU_INT, &pointsC);CHKERRQ(ierr);
7451   } else {
7452     ierr = DMPlexRestoreCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp);CHKERRQ(ierr);
7453   }
7454 
7455   if (numIndices) *numIndices = Ni;
7456   if (indices)    *indices    = idx;
7457   PetscFunctionReturn(0);
7458 }
7459 
7460 /*@C
7461   DMPlexRestoreClosureIndices - Restores the global dof indices associated with the closure of the given point within the provided sections.
7462 
7463   Not collective
7464 
7465   Input Parameters:
7466 + dm         - The DM
7467 . section    - The PetscSection describing the points (a local section)
7468 . idxSection - The PetscSection from which to obtain indices (may be local or global)
7469 . point      - The point defining the closure
7470 - useClPerm  - Use the closure point permutation if available
7471 
7472   Output Parameters:
7473 + numIndices - The number of dof indices in the closure of point with the input sections
7474 . indices    - The dof indices
7475 . outOffsets - Array to write the field offsets into, or NULL
7476 - values     - The input values, which may be modified if sign flips are induced by the point symmetries, or NULL
7477 
7478   Notes:
7479   If values were modified, the user is responsible for calling DMRestoreWorkArray(dm, 0, MPIU_SCALAR, &values).
7480 
7481   If idxSection is global, any constrained dofs (see DMAddBoundary(), for example) will get negative indices.  The value
7482   of those indices is not significant.  If idxSection is local, the constrained dofs will yield the involution -(idx+1)
7483   of their index in a local vector.  A caller who does not wish to distinguish those points may recover the nonnegative
7484   indices via involution, -(-(idx+1)+1)==idx.  Local indices are provided when idxSection == section, otherwise global
7485   indices (with the above semantics) are implied.
7486 
7487   Level: advanced
7488 
7489 .seealso DMPlexGetClosureIndices(), DMPlexVecGetClosure(), DMPlexMatSetClosure(), DMGetLocalSection(), DMGetGlobalSection()
7490 @*/
7491 PetscErrorCode DMPlexRestoreClosureIndices(DM dm, PetscSection section, PetscSection idxSection, PetscInt point, PetscBool useClPerm,
7492                                            PetscInt *numIndices, PetscInt *indices[], PetscInt outOffsets[], PetscScalar *values[])
7493 {
7494   PetscErrorCode ierr;
7495 
7496   PetscFunctionBegin;
7497   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7498   PetscValidPointer(indices, 7);
7499   ierr = DMRestoreWorkArray(dm, 0, MPIU_INT, indices);CHKERRQ(ierr);
7500   PetscFunctionReturn(0);
7501 }
7502 
7503 /*@C
7504   DMPlexMatSetClosure - Set an array of the values on the closure of 'point'
7505 
7506   Not collective
7507 
7508   Input Parameters:
7509 + dm - The DM
7510 . section - The section describing the layout in v, or NULL to use the default section
7511 . globalSection - The section describing the layout in v, or NULL to use the default global section
7512 . A - The matrix
7513 . point - The point in the DM
7514 . values - The array of values
7515 - mode - The insert mode, where INSERT_ALL_VALUES and ADD_ALL_VALUES also overwrite boundary conditions
7516 
7517   Fortran Notes:
7518   This routine is only available in Fortran 90, and you must include petsc.h90 in your code.
7519 
7520   Level: intermediate
7521 
7522 .seealso DMPlexMatSetClosureGeneral(), DMPlexVecGetClosure(), DMPlexVecSetClosure()
7523 @*/
7524 PetscErrorCode DMPlexMatSetClosure(DM dm, PetscSection section, PetscSection globalSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode)
7525 {
7526   DM_Plex           *mesh = (DM_Plex*) dm->data;
7527   PetscInt          *indices;
7528   PetscInt           numIndices;
7529   const PetscScalar *valuesOrig = values;
7530   PetscErrorCode     ierr;
7531 
7532   PetscFunctionBegin;
7533   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7534   if (!section) {ierr = DMGetLocalSection(dm, &section);CHKERRQ(ierr);}
7535   PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2);
7536   if (!globalSection) {ierr = DMGetGlobalSection(dm, &globalSection);CHKERRQ(ierr);}
7537   PetscValidHeaderSpecific(globalSection, PETSC_SECTION_CLASSID, 3);
7538   PetscValidHeaderSpecific(A, MAT_CLASSID, 4);
7539 
7540   ierr = DMPlexGetClosureIndices(dm, section, globalSection, point, PETSC_TRUE, &numIndices, &indices, NULL, (PetscScalar **) &values);CHKERRQ(ierr);
7541 
7542   if (mesh->printSetValues) {ierr = DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndices, indices, 0, NULL, values);CHKERRQ(ierr);}
7543   ierr = MatSetValues(A, numIndices, indices, numIndices, indices, values, mode);
7544   if (ierr) {
7545     PetscMPIInt    rank;
7546     PetscErrorCode ierr2;
7547 
7548     ierr2 = MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank);CHKERRMPI(ierr2);
7549     ierr2 = (*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank);CHKERRQ(ierr2);
7550     ierr2 = DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndices, indices, 0, NULL, values);CHKERRQ(ierr2);
7551     ierr2 = DMPlexRestoreClosureIndices(dm, section, globalSection, point, PETSC_TRUE, &numIndices, &indices, NULL, (PetscScalar **) &values);CHKERRQ(ierr2);
7552     if (values != valuesOrig) {ierr2 = DMRestoreWorkArray(dm, 0, MPIU_SCALAR, &values);CHKERRQ(ierr2);}
7553     SETERRQ(PetscObjectComm((PetscObject)dm),ierr,"Not possible to set matrix values");
7554   }
7555   if (mesh->printFEM > 1) {
7556     PetscInt i;
7557     ierr = PetscPrintf(PETSC_COMM_SELF, "  Indices:");CHKERRQ(ierr);
7558     for (i = 0; i < numIndices; ++i) {ierr = PetscPrintf(PETSC_COMM_SELF, " %D", indices[i]);CHKERRQ(ierr);}
7559     ierr = PetscPrintf(PETSC_COMM_SELF, "\n");CHKERRQ(ierr);
7560   }
7561 
7562   ierr = DMPlexRestoreClosureIndices(dm, section, globalSection, point, PETSC_TRUE, &numIndices, &indices, NULL, (PetscScalar **) &values);CHKERRQ(ierr);
7563   if (values != valuesOrig) {ierr = DMRestoreWorkArray(dm, 0, MPIU_SCALAR, &values);CHKERRQ(ierr);}
7564   PetscFunctionReturn(0);
7565 }
7566 
7567 /*@C
7568   DMPlexMatSetClosure - Set an array of the values on the closure of 'point' using a different row and column section
7569 
7570   Not collective
7571 
7572   Input Parameters:
7573 + dmRow - The DM for the row fields
7574 . sectionRow - The section describing the layout, or NULL to use the default section in dmRow
7575 . globalSectionRow - The section describing the layout, or NULL to use the default global section in dmRow
7576 . dmCol - The DM for the column fields
7577 . sectionCol - The section describing the layout, or NULL to use the default section in dmCol
7578 . globalSectionCol - The section describing the layout, or NULL to use the default global section in dmCol
7579 . A - The matrix
7580 . point - The point in the DMs
7581 . values - The array of values
7582 - mode - The insert mode, where INSERT_ALL_VALUES and ADD_ALL_VALUES also overwrite boundary conditions
7583 
7584   Level: intermediate
7585 
7586 .seealso DMPlexMatSetClosure(), DMPlexVecGetClosure(), DMPlexVecSetClosure()
7587 @*/
7588 PetscErrorCode DMPlexMatSetClosureGeneral(DM dmRow, PetscSection sectionRow, PetscSection globalSectionRow, DM dmCol, PetscSection sectionCol, PetscSection globalSectionCol, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode)
7589 {
7590   DM_Plex           *mesh = (DM_Plex*) dmRow->data;
7591   PetscInt          *indicesRow, *indicesCol;
7592   PetscInt           numIndicesRow, numIndicesCol;
7593   const PetscScalar *valuesOrig = values;
7594   PetscErrorCode     ierr;
7595 
7596   PetscFunctionBegin;
7597   PetscValidHeaderSpecific(dmRow, DM_CLASSID, 1);
7598   if (!sectionRow) {ierr = DMGetLocalSection(dmRow, &sectionRow);CHKERRQ(ierr);}
7599   PetscValidHeaderSpecific(sectionRow, PETSC_SECTION_CLASSID, 2);
7600   if (!globalSectionRow) {ierr = DMGetGlobalSection(dmRow, &globalSectionRow);CHKERRQ(ierr);}
7601   PetscValidHeaderSpecific(globalSectionRow, PETSC_SECTION_CLASSID, 3);
7602   PetscValidHeaderSpecific(dmCol, DM_CLASSID, 4);
7603   if (!sectionCol) {ierr = DMGetLocalSection(dmCol, &sectionCol);CHKERRQ(ierr);}
7604   PetscValidHeaderSpecific(sectionCol, PETSC_SECTION_CLASSID, 5);
7605   if (!globalSectionCol) {ierr = DMGetGlobalSection(dmCol, &globalSectionCol);CHKERRQ(ierr);}
7606   PetscValidHeaderSpecific(globalSectionCol, PETSC_SECTION_CLASSID, 6);
7607   PetscValidHeaderSpecific(A, MAT_CLASSID, 7);
7608 
7609   ierr = DMPlexGetClosureIndices(dmRow, sectionRow, globalSectionRow, point, PETSC_TRUE, &numIndicesRow, &indicesRow, NULL, (PetscScalar **) &values);CHKERRQ(ierr);
7610   ierr = DMPlexGetClosureIndices(dmCol, sectionCol, globalSectionCol, point, PETSC_TRUE, &numIndicesCol, &indicesCol, NULL, (PetscScalar **) &values);CHKERRQ(ierr);
7611 
7612   if (mesh->printSetValues) {ierr = DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndicesRow, indicesRow, numIndicesCol, indicesCol, values);CHKERRQ(ierr);}
7613   ierr = MatSetValues(A, numIndicesRow, indicesRow, numIndicesCol, indicesCol, values, mode);
7614   if (ierr) {
7615     PetscMPIInt    rank;
7616     PetscErrorCode ierr2;
7617 
7618     ierr2 = MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank);CHKERRMPI(ierr2);
7619     ierr2 = (*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank);CHKERRQ(ierr2);
7620     ierr2 = DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndicesRow, indicesRow, numIndicesCol, indicesCol, values);CHKERRQ(ierr2);
7621     ierr2 = DMPlexRestoreClosureIndices(dmRow, sectionRow, globalSectionRow, point, PETSC_TRUE, &numIndicesRow, &indicesRow, NULL, (PetscScalar **) &values);CHKERRQ(ierr2);
7622     ierr2 = DMPlexRestoreClosureIndices(dmCol, sectionCol, globalSectionCol, point, PETSC_TRUE, &numIndicesCol, &indicesRow, NULL, (PetscScalar **) &values);CHKERRQ(ierr2);
7623     if (values != valuesOrig) {ierr2 = DMRestoreWorkArray(dmRow, 0, MPIU_SCALAR, &values);CHKERRQ(ierr2);}
7624     CHKERRQ(ierr);
7625   }
7626 
7627   ierr = DMPlexRestoreClosureIndices(dmRow, sectionRow, globalSectionRow, point, PETSC_TRUE, &numIndicesRow, &indicesRow, NULL, (PetscScalar **) &values);CHKERRQ(ierr);
7628   ierr = DMPlexRestoreClosureIndices(dmCol, sectionCol, globalSectionCol, point, PETSC_TRUE, &numIndicesCol, &indicesCol, NULL, (PetscScalar **) &values);CHKERRQ(ierr);
7629   if (values != valuesOrig) {ierr = DMRestoreWorkArray(dmRow, 0, MPIU_SCALAR, &values);CHKERRQ(ierr);}
7630   PetscFunctionReturn(0);
7631 }
7632 
7633 PetscErrorCode DMPlexMatSetClosureRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode)
7634 {
7635   DM_Plex        *mesh   = (DM_Plex*) dmf->data;
7636   PetscInt       *fpoints = NULL, *ftotpoints = NULL;
7637   PetscInt       *cpoints = NULL;
7638   PetscInt       *findices, *cindices;
7639   const PetscInt *fclperm = NULL, *cclperm = NULL; /* Closure permutations cannot work here */
7640   PetscInt        foffsets[32], coffsets[32];
7641   DMPolytopeType  ct;
7642   PetscInt        numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f;
7643   PetscErrorCode  ierr;
7644 
7645   PetscFunctionBegin;
7646   PetscValidHeaderSpecific(dmf, DM_CLASSID, 1);
7647   PetscValidHeaderSpecific(dmc, DM_CLASSID, 4);
7648   if (!fsection) {ierr = DMGetLocalSection(dmf, &fsection);CHKERRQ(ierr);}
7649   PetscValidHeaderSpecific(fsection, PETSC_SECTION_CLASSID, 2);
7650   if (!csection) {ierr = DMGetLocalSection(dmc, &csection);CHKERRQ(ierr);}
7651   PetscValidHeaderSpecific(csection, PETSC_SECTION_CLASSID, 5);
7652   if (!globalFSection) {ierr = DMGetGlobalSection(dmf, &globalFSection);CHKERRQ(ierr);}
7653   PetscValidHeaderSpecific(globalFSection, PETSC_SECTION_CLASSID, 3);
7654   if (!globalCSection) {ierr = DMGetGlobalSection(dmc, &globalCSection);CHKERRQ(ierr);}
7655   PetscValidHeaderSpecific(globalCSection, PETSC_SECTION_CLASSID, 6);
7656   PetscValidHeaderSpecific(A, MAT_CLASSID, 7);
7657   ierr = PetscSectionGetNumFields(fsection, &numFields);CHKERRQ(ierr);
7658   PetscCheckFalse(numFields > 31,PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
7659   ierr = PetscArrayzero(foffsets, 32);CHKERRQ(ierr);
7660   ierr = PetscArrayzero(coffsets, 32);CHKERRQ(ierr);
7661   /* Column indices */
7662   ierr = DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints);CHKERRQ(ierr);
7663   maxFPoints = numCPoints;
7664   /* Compress out points not in the section */
7665   /*   TODO: Squeeze out points with 0 dof as well */
7666   ierr = PetscSectionGetChart(csection, &pStart, &pEnd);CHKERRQ(ierr);
7667   for (p = 0, q = 0; p < numCPoints*2; p += 2) {
7668     if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) {
7669       cpoints[q*2]   = cpoints[p];
7670       cpoints[q*2+1] = cpoints[p+1];
7671       ++q;
7672     }
7673   }
7674   numCPoints = q;
7675   for (p = 0, numCIndices = 0; p < numCPoints*2; p += 2) {
7676     PetscInt fdof;
7677 
7678     ierr = PetscSectionGetDof(csection, cpoints[p], &dof);CHKERRQ(ierr);
7679     if (!dof) continue;
7680     for (f = 0; f < numFields; ++f) {
7681       ierr           = PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof);CHKERRQ(ierr);
7682       coffsets[f+1] += fdof;
7683     }
7684     numCIndices += dof;
7685   }
7686   for (f = 1; f < numFields; ++f) coffsets[f+1] += coffsets[f];
7687   /* Row indices */
7688   ierr = DMPlexGetCellType(dmc, point, &ct);CHKERRQ(ierr);
7689   {
7690     DMPlexTransform tr;
7691     DMPolytopeType *rct;
7692     PetscInt       *rsize, *rcone, *rornt, Nt;
7693 
7694     ierr = DMPlexTransformCreate(PETSC_COMM_SELF, &tr);CHKERRQ(ierr);
7695     ierr = DMPlexTransformSetType(tr, DMPLEXREFINEREGULAR);CHKERRQ(ierr);
7696     ierr = DMPlexTransformCellTransform(tr, ct, point, NULL, &Nt, &rct, &rsize, &rcone, &rornt);CHKERRQ(ierr);
7697     numSubcells = rsize[Nt-1];
7698     ierr = DMPlexTransformDestroy(&tr);CHKERRQ(ierr);
7699   }
7700   ierr = DMGetWorkArray(dmf, maxFPoints*2*numSubcells, MPIU_INT, &ftotpoints);CHKERRQ(ierr);
7701   for (r = 0, q = 0; r < numSubcells; ++r) {
7702     /* TODO Map from coarse to fine cells */
7703     ierr = DMPlexGetTransitiveClosure(dmf, point*numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints);CHKERRQ(ierr);
7704     /* Compress out points not in the section */
7705     ierr = PetscSectionGetChart(fsection, &pStart, &pEnd);CHKERRQ(ierr);
7706     for (p = 0; p < numFPoints*2; p += 2) {
7707       if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) {
7708         ierr = PetscSectionGetDof(fsection, fpoints[p], &dof);CHKERRQ(ierr);
7709         if (!dof) continue;
7710         for (s = 0; s < q; ++s) if (fpoints[p] == ftotpoints[s*2]) break;
7711         if (s < q) continue;
7712         ftotpoints[q*2]   = fpoints[p];
7713         ftotpoints[q*2+1] = fpoints[p+1];
7714         ++q;
7715       }
7716     }
7717     ierr = DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints);CHKERRQ(ierr);
7718   }
7719   numFPoints = q;
7720   for (p = 0, numFIndices = 0; p < numFPoints*2; p += 2) {
7721     PetscInt fdof;
7722 
7723     ierr = PetscSectionGetDof(fsection, ftotpoints[p], &dof);CHKERRQ(ierr);
7724     if (!dof) continue;
7725     for (f = 0; f < numFields; ++f) {
7726       ierr           = PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof);CHKERRQ(ierr);
7727       foffsets[f+1] += fdof;
7728     }
7729     numFIndices += dof;
7730   }
7731   for (f = 1; f < numFields; ++f) foffsets[f+1] += foffsets[f];
7732 
7733   PetscCheckFalse(numFields && foffsets[numFields] != numFIndices,PetscObjectComm((PetscObject)dmf), PETSC_ERR_PLIB, "Invalid size for closure %D should be %D", foffsets[numFields], numFIndices);
7734   PetscCheckFalse(numFields && coffsets[numFields] != numCIndices,PetscObjectComm((PetscObject)dmc), PETSC_ERR_PLIB, "Invalid size for closure %D should be %D", coffsets[numFields], numCIndices);
7735   ierr = DMGetWorkArray(dmf, numFIndices, MPIU_INT, &findices);CHKERRQ(ierr);
7736   ierr = DMGetWorkArray(dmc, numCIndices, MPIU_INT, &cindices);CHKERRQ(ierr);
7737   if (numFields) {
7738     const PetscInt **permsF[32] = {NULL};
7739     const PetscInt **permsC[32] = {NULL};
7740 
7741     for (f = 0; f < numFields; f++) {
7742       ierr = PetscSectionGetFieldPointSyms(fsection,f,numFPoints,ftotpoints,&permsF[f],NULL);CHKERRQ(ierr);
7743       ierr = PetscSectionGetFieldPointSyms(csection,f,numCPoints,cpoints,&permsC[f],NULL);CHKERRQ(ierr);
7744     }
7745     for (p = 0; p < numFPoints; p++) {
7746       ierr = PetscSectionGetOffset(globalFSection, ftotpoints[2*p], &globalOff);CHKERRQ(ierr);
7747       ierr = DMPlexGetIndicesPointFields_Internal(fsection, PETSC_FALSE, ftotpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, foffsets, PETSC_FALSE, permsF, p, fclperm, findices);CHKERRQ(ierr);
7748     }
7749     for (p = 0; p < numCPoints; p++) {
7750       ierr = PetscSectionGetOffset(globalCSection, cpoints[2*p], &globalOff);CHKERRQ(ierr);
7751       ierr = DMPlexGetIndicesPointFields_Internal(csection, PETSC_FALSE, cpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cclperm, cindices);CHKERRQ(ierr);
7752     }
7753     for (f = 0; f < numFields; f++) {
7754       ierr = PetscSectionRestoreFieldPointSyms(fsection,f,numFPoints,ftotpoints,&permsF[f],NULL);CHKERRQ(ierr);
7755       ierr = PetscSectionRestoreFieldPointSyms(csection,f,numCPoints,cpoints,&permsC[f],NULL);CHKERRQ(ierr);
7756     }
7757   } else {
7758     const PetscInt **permsF = NULL;
7759     const PetscInt **permsC = NULL;
7760 
7761     ierr = PetscSectionGetPointSyms(fsection,numFPoints,ftotpoints,&permsF,NULL);CHKERRQ(ierr);
7762     ierr = PetscSectionGetPointSyms(csection,numCPoints,cpoints,&permsC,NULL);CHKERRQ(ierr);
7763     for (p = 0, off = 0; p < numFPoints; p++) {
7764       const PetscInt *perm = permsF ? permsF[p] : NULL;
7765 
7766       ierr = PetscSectionGetOffset(globalFSection, ftotpoints[2*p], &globalOff);CHKERRQ(ierr);
7767       ierr = DMPlexGetIndicesPoint_Internal(fsection, PETSC_FALSE, ftotpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, fclperm, findices);CHKERRQ(ierr);
7768     }
7769     for (p = 0, off = 0; p < numCPoints; p++) {
7770       const PetscInt *perm = permsC ? permsC[p] : NULL;
7771 
7772       ierr = PetscSectionGetOffset(globalCSection, cpoints[2*p], &globalOff);CHKERRQ(ierr);
7773       ierr = DMPlexGetIndicesPoint_Internal(csection, PETSC_FALSE, cpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, cclperm, cindices);CHKERRQ(ierr);
7774     }
7775     ierr = PetscSectionRestorePointSyms(fsection,numFPoints,ftotpoints,&permsF,NULL);CHKERRQ(ierr);
7776     ierr = PetscSectionRestorePointSyms(csection,numCPoints,cpoints,&permsC,NULL);CHKERRQ(ierr);
7777   }
7778   if (mesh->printSetValues) {ierr = DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numFIndices, findices, numCIndices, cindices, values);CHKERRQ(ierr);}
7779   /* TODO: flips */
7780   ierr = MatSetValues(A, numFIndices, findices, numCIndices, cindices, values, mode);
7781   if (ierr) {
7782     PetscMPIInt    rank;
7783     PetscErrorCode ierr2;
7784 
7785     ierr2 = MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank);CHKERRMPI(ierr2);
7786     ierr2 = (*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank);CHKERRQ(ierr2);
7787     ierr2 = DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numFIndices, findices, numCIndices, cindices, values);CHKERRQ(ierr2);
7788     ierr2 = DMRestoreWorkArray(dmf, numFIndices, MPIU_INT, &findices);CHKERRQ(ierr2);
7789     ierr2 = DMRestoreWorkArray(dmc, numCIndices, MPIU_INT, &cindices);CHKERRQ(ierr2);
7790     CHKERRQ(ierr);
7791   }
7792   ierr = DMRestoreWorkArray(dmf, numCPoints*2*4, MPIU_INT, &ftotpoints);CHKERRQ(ierr);
7793   ierr = DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints);CHKERRQ(ierr);
7794   ierr = DMRestoreWorkArray(dmf, numFIndices, MPIU_INT, &findices);CHKERRQ(ierr);
7795   ierr = DMRestoreWorkArray(dmc, numCIndices, MPIU_INT, &cindices);CHKERRQ(ierr);
7796   PetscFunctionReturn(0);
7797 }
7798 
7799 PetscErrorCode DMPlexMatGetClosureIndicesRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, PetscInt point, PetscInt cindices[], PetscInt findices[])
7800 {
7801   PetscInt      *fpoints = NULL, *ftotpoints = NULL;
7802   PetscInt      *cpoints = NULL;
7803   PetscInt       foffsets[32], coffsets[32];
7804   const PetscInt *fclperm = NULL, *cclperm = NULL; /* Closure permutations cannot work here */
7805   DMPolytopeType ct;
7806   PetscInt       numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f;
7807   PetscErrorCode ierr;
7808 
7809   PetscFunctionBegin;
7810   PetscValidHeaderSpecific(dmf, DM_CLASSID, 1);
7811   PetscValidHeaderSpecific(dmc, DM_CLASSID, 4);
7812   if (!fsection) {ierr = DMGetLocalSection(dmf, &fsection);CHKERRQ(ierr);}
7813   PetscValidHeaderSpecific(fsection, PETSC_SECTION_CLASSID, 2);
7814   if (!csection) {ierr = DMGetLocalSection(dmc, &csection);CHKERRQ(ierr);}
7815   PetscValidHeaderSpecific(csection, PETSC_SECTION_CLASSID, 5);
7816   if (!globalFSection) {ierr = DMGetGlobalSection(dmf, &globalFSection);CHKERRQ(ierr);}
7817   PetscValidHeaderSpecific(globalFSection, PETSC_SECTION_CLASSID, 3);
7818   if (!globalCSection) {ierr = DMGetGlobalSection(dmc, &globalCSection);CHKERRQ(ierr);}
7819   PetscValidHeaderSpecific(globalCSection, PETSC_SECTION_CLASSID, 6);
7820   ierr = PetscSectionGetNumFields(fsection, &numFields);CHKERRQ(ierr);
7821   PetscCheckFalse(numFields > 31,PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
7822   ierr = PetscArrayzero(foffsets, 32);CHKERRQ(ierr);
7823   ierr = PetscArrayzero(coffsets, 32);CHKERRQ(ierr);
7824   /* Column indices */
7825   ierr = DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints);CHKERRQ(ierr);
7826   maxFPoints = numCPoints;
7827   /* Compress out points not in the section */
7828   /*   TODO: Squeeze out points with 0 dof as well */
7829   ierr = PetscSectionGetChart(csection, &pStart, &pEnd);CHKERRQ(ierr);
7830   for (p = 0, q = 0; p < numCPoints*2; p += 2) {
7831     if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) {
7832       cpoints[q*2]   = cpoints[p];
7833       cpoints[q*2+1] = cpoints[p+1];
7834       ++q;
7835     }
7836   }
7837   numCPoints = q;
7838   for (p = 0, numCIndices = 0; p < numCPoints*2; p += 2) {
7839     PetscInt fdof;
7840 
7841     ierr = PetscSectionGetDof(csection, cpoints[p], &dof);CHKERRQ(ierr);
7842     if (!dof) continue;
7843     for (f = 0; f < numFields; ++f) {
7844       ierr           = PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof);CHKERRQ(ierr);
7845       coffsets[f+1] += fdof;
7846     }
7847     numCIndices += dof;
7848   }
7849   for (f = 1; f < numFields; ++f) coffsets[f+1] += coffsets[f];
7850   /* Row indices */
7851   ierr = DMPlexGetCellType(dmc, point, &ct);CHKERRQ(ierr);
7852   {
7853     DMPlexTransform tr;
7854     DMPolytopeType *rct;
7855     PetscInt       *rsize, *rcone, *rornt, Nt;
7856 
7857     ierr = DMPlexTransformCreate(PETSC_COMM_SELF, &tr);CHKERRQ(ierr);
7858     ierr = DMPlexTransformSetType(tr, DMPLEXREFINEREGULAR);CHKERRQ(ierr);
7859     ierr = DMPlexTransformCellTransform(tr, ct, point, NULL, &Nt, &rct, &rsize, &rcone, &rornt);CHKERRQ(ierr);
7860     numSubcells = rsize[Nt-1];
7861     ierr = DMPlexTransformDestroy(&tr);CHKERRQ(ierr);
7862   }
7863   ierr = DMGetWorkArray(dmf, maxFPoints*2*numSubcells, MPIU_INT, &ftotpoints);CHKERRQ(ierr);
7864   for (r = 0, q = 0; r < numSubcells; ++r) {
7865     /* TODO Map from coarse to fine cells */
7866     ierr = DMPlexGetTransitiveClosure(dmf, point*numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints);CHKERRQ(ierr);
7867     /* Compress out points not in the section */
7868     ierr = PetscSectionGetChart(fsection, &pStart, &pEnd);CHKERRQ(ierr);
7869     for (p = 0; p < numFPoints*2; p += 2) {
7870       if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) {
7871         ierr = PetscSectionGetDof(fsection, fpoints[p], &dof);CHKERRQ(ierr);
7872         if (!dof) continue;
7873         for (s = 0; s < q; ++s) if (fpoints[p] == ftotpoints[s*2]) break;
7874         if (s < q) continue;
7875         ftotpoints[q*2]   = fpoints[p];
7876         ftotpoints[q*2+1] = fpoints[p+1];
7877         ++q;
7878       }
7879     }
7880     ierr = DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints);CHKERRQ(ierr);
7881   }
7882   numFPoints = q;
7883   for (p = 0, numFIndices = 0; p < numFPoints*2; p += 2) {
7884     PetscInt fdof;
7885 
7886     ierr = PetscSectionGetDof(fsection, ftotpoints[p], &dof);CHKERRQ(ierr);
7887     if (!dof) continue;
7888     for (f = 0; f < numFields; ++f) {
7889       ierr           = PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof);CHKERRQ(ierr);
7890       foffsets[f+1] += fdof;
7891     }
7892     numFIndices += dof;
7893   }
7894   for (f = 1; f < numFields; ++f) foffsets[f+1] += foffsets[f];
7895 
7896   PetscCheckFalse(numFields && foffsets[numFields] != numFIndices,PetscObjectComm((PetscObject)dmf), PETSC_ERR_PLIB, "Invalid size for closure %D should be %D", foffsets[numFields], numFIndices);
7897   PetscCheckFalse(numFields && coffsets[numFields] != numCIndices,PetscObjectComm((PetscObject)dmc), PETSC_ERR_PLIB, "Invalid size for closure %D should be %D", coffsets[numFields], numCIndices);
7898   if (numFields) {
7899     const PetscInt **permsF[32] = {NULL};
7900     const PetscInt **permsC[32] = {NULL};
7901 
7902     for (f = 0; f < numFields; f++) {
7903       ierr = PetscSectionGetFieldPointSyms(fsection,f,numFPoints,ftotpoints,&permsF[f],NULL);CHKERRQ(ierr);
7904       ierr = PetscSectionGetFieldPointSyms(csection,f,numCPoints,cpoints,&permsC[f],NULL);CHKERRQ(ierr);
7905     }
7906     for (p = 0; p < numFPoints; p++) {
7907       ierr = PetscSectionGetOffset(globalFSection, ftotpoints[2*p], &globalOff);CHKERRQ(ierr);
7908       ierr = DMPlexGetIndicesPointFields_Internal(fsection, PETSC_FALSE, ftotpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, foffsets, PETSC_FALSE, permsF, p, fclperm, findices);CHKERRQ(ierr);
7909     }
7910     for (p = 0; p < numCPoints; p++) {
7911       ierr = PetscSectionGetOffset(globalCSection, cpoints[2*p], &globalOff);CHKERRQ(ierr);
7912       ierr = DMPlexGetIndicesPointFields_Internal(csection, PETSC_FALSE, cpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cclperm, cindices);CHKERRQ(ierr);
7913     }
7914     for (f = 0; f < numFields; f++) {
7915       ierr = PetscSectionRestoreFieldPointSyms(fsection,f,numFPoints,ftotpoints,&permsF[f],NULL);CHKERRQ(ierr);
7916       ierr = PetscSectionRestoreFieldPointSyms(csection,f,numCPoints,cpoints,&permsC[f],NULL);CHKERRQ(ierr);
7917     }
7918   } else {
7919     const PetscInt **permsF = NULL;
7920     const PetscInt **permsC = NULL;
7921 
7922     ierr = PetscSectionGetPointSyms(fsection,numFPoints,ftotpoints,&permsF,NULL);CHKERRQ(ierr);
7923     ierr = PetscSectionGetPointSyms(csection,numCPoints,cpoints,&permsC,NULL);CHKERRQ(ierr);
7924     for (p = 0, off = 0; p < numFPoints; p++) {
7925       const PetscInt *perm = permsF ? permsF[p] : NULL;
7926 
7927       ierr = PetscSectionGetOffset(globalFSection, ftotpoints[2*p], &globalOff);CHKERRQ(ierr);
7928       ierr = DMPlexGetIndicesPoint_Internal(fsection, PETSC_FALSE, ftotpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, fclperm, findices);CHKERRQ(ierr);
7929     }
7930     for (p = 0, off = 0; p < numCPoints; p++) {
7931       const PetscInt *perm = permsC ? permsC[p] : NULL;
7932 
7933       ierr = PetscSectionGetOffset(globalCSection, cpoints[2*p], &globalOff);CHKERRQ(ierr);
7934       ierr = DMPlexGetIndicesPoint_Internal(csection, PETSC_FALSE, cpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, cclperm, cindices);CHKERRQ(ierr);
7935     }
7936     ierr = PetscSectionRestorePointSyms(fsection,numFPoints,ftotpoints,&permsF,NULL);CHKERRQ(ierr);
7937     ierr = PetscSectionRestorePointSyms(csection,numCPoints,cpoints,&permsC,NULL);CHKERRQ(ierr);
7938   }
7939   ierr = DMRestoreWorkArray(dmf, numCPoints*2*4, MPIU_INT, &ftotpoints);CHKERRQ(ierr);
7940   ierr = DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints);CHKERRQ(ierr);
7941   PetscFunctionReturn(0);
7942 }
7943 
7944 /*@C
7945   DMPlexGetVTKCellHeight - Returns the height in the DAG used to determine which points are cells (normally 0)
7946 
7947   Input Parameter:
7948 . dm   - The DMPlex object
7949 
7950   Output Parameter:
7951 . cellHeight - The height of a cell
7952 
7953   Level: developer
7954 
7955 .seealso DMPlexSetVTKCellHeight()
7956 @*/
7957 PetscErrorCode DMPlexGetVTKCellHeight(DM dm, PetscInt *cellHeight)
7958 {
7959   DM_Plex *mesh = (DM_Plex*) dm->data;
7960 
7961   PetscFunctionBegin;
7962   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7963   PetscValidPointer(cellHeight, 2);
7964   *cellHeight = mesh->vtkCellHeight;
7965   PetscFunctionReturn(0);
7966 }
7967 
7968 /*@C
7969   DMPlexSetVTKCellHeight - Sets the height in the DAG used to determine which points are cells (normally 0)
7970 
7971   Input Parameters:
7972 + dm   - The DMPlex object
7973 - cellHeight - The height of a cell
7974 
7975   Level: developer
7976 
7977 .seealso DMPlexGetVTKCellHeight()
7978 @*/
7979 PetscErrorCode DMPlexSetVTKCellHeight(DM dm, PetscInt cellHeight)
7980 {
7981   DM_Plex *mesh = (DM_Plex*) dm->data;
7982 
7983   PetscFunctionBegin;
7984   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7985   mesh->vtkCellHeight = cellHeight;
7986   PetscFunctionReturn(0);
7987 }
7988 
7989 /*@
7990   DMPlexGetGhostCellStratum - Get the range of cells which are used to enforce FV boundary conditions
7991 
7992   Input Parameter:
7993 . dm - The DMPlex object
7994 
7995   Output Parameters:
7996 + gcStart - The first ghost cell, or NULL
7997 - gcEnd   - The upper bound on ghost cells, or NULL
7998 
7999   Level: advanced
8000 
8001 .seealso DMPlexConstructGhostCells(), DMPlexGetGhostCellStratum()
8002 @*/
8003 PetscErrorCode DMPlexGetGhostCellStratum(DM dm, PetscInt *gcStart, PetscInt *gcEnd)
8004 {
8005   DMLabel        ctLabel;
8006   PetscErrorCode ierr;
8007 
8008   PetscFunctionBegin;
8009   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8010   ierr = DMPlexGetCellTypeLabel(dm, &ctLabel);CHKERRQ(ierr);
8011   ierr = DMLabelGetStratumBounds(ctLabel, DM_POLYTOPE_FV_GHOST, gcStart, gcEnd);CHKERRQ(ierr);
8012   PetscFunctionReturn(0);
8013 }
8014 
8015 PetscErrorCode DMPlexCreateNumbering_Plex(DM dm, PetscInt pStart, PetscInt pEnd, PetscInt shift, PetscInt *globalSize, PetscSF sf, IS *numbering)
8016 {
8017   PetscSection   section, globalSection;
8018   PetscInt      *numbers, p;
8019   PetscErrorCode ierr;
8020 
8021   PetscFunctionBegin;
8022   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)dm), &section);CHKERRQ(ierr);
8023   ierr = PetscSectionSetChart(section, pStart, pEnd);CHKERRQ(ierr);
8024   for (p = pStart; p < pEnd; ++p) {
8025     ierr = PetscSectionSetDof(section, p, 1);CHKERRQ(ierr);
8026   }
8027   ierr = PetscSectionSetUp(section);CHKERRQ(ierr);
8028   ierr = PetscSectionCreateGlobalSection(section, sf, PETSC_FALSE, PETSC_FALSE, &globalSection);CHKERRQ(ierr);
8029   ierr = PetscMalloc1(pEnd - pStart, &numbers);CHKERRQ(ierr);
8030   for (p = pStart; p < pEnd; ++p) {
8031     ierr = PetscSectionGetOffset(globalSection, p, &numbers[p-pStart]);CHKERRQ(ierr);
8032     if (numbers[p-pStart] < 0) numbers[p-pStart] -= shift;
8033     else                       numbers[p-pStart] += shift;
8034   }
8035   ierr = ISCreateGeneral(PetscObjectComm((PetscObject) dm), pEnd - pStart, numbers, PETSC_OWN_POINTER, numbering);CHKERRQ(ierr);
8036   if (globalSize) {
8037     PetscLayout layout;
8038     ierr = PetscSectionGetPointLayout(PetscObjectComm((PetscObject) dm), globalSection, &layout);CHKERRQ(ierr);
8039     ierr = PetscLayoutGetSize(layout, globalSize);CHKERRQ(ierr);
8040     ierr = PetscLayoutDestroy(&layout);CHKERRQ(ierr);
8041   }
8042   ierr = PetscSectionDestroy(&section);CHKERRQ(ierr);
8043   ierr = PetscSectionDestroy(&globalSection);CHKERRQ(ierr);
8044   PetscFunctionReturn(0);
8045 }
8046 
8047 PetscErrorCode DMPlexCreateCellNumbering_Internal(DM dm, PetscBool includeHybrid, IS *globalCellNumbers)
8048 {
8049   PetscInt       cellHeight, cStart, cEnd;
8050   PetscErrorCode ierr;
8051 
8052   PetscFunctionBegin;
8053   ierr = DMPlexGetVTKCellHeight(dm, &cellHeight);CHKERRQ(ierr);
8054   if (includeHybrid) {ierr = DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd);CHKERRQ(ierr);}
8055   else               {ierr = DMPlexGetSimplexOrBoxCells(dm, cellHeight, &cStart, &cEnd);CHKERRQ(ierr);}
8056   ierr = DMPlexCreateNumbering_Plex(dm, cStart, cEnd, 0, NULL, dm->sf, globalCellNumbers);CHKERRQ(ierr);
8057   PetscFunctionReturn(0);
8058 }
8059 
8060 /*@
8061   DMPlexGetCellNumbering - Get a global cell numbering for all cells on this process
8062 
8063   Input Parameter:
8064 . dm   - The DMPlex object
8065 
8066   Output Parameter:
8067 . globalCellNumbers - Global cell numbers for all cells on this process
8068 
8069   Level: developer
8070 
8071 .seealso DMPlexGetVertexNumbering()
8072 @*/
8073 PetscErrorCode DMPlexGetCellNumbering(DM dm, IS *globalCellNumbers)
8074 {
8075   DM_Plex       *mesh = (DM_Plex*) dm->data;
8076   PetscErrorCode ierr;
8077 
8078   PetscFunctionBegin;
8079   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8080   if (!mesh->globalCellNumbers) {ierr = DMPlexCreateCellNumbering_Internal(dm, PETSC_FALSE, &mesh->globalCellNumbers);CHKERRQ(ierr);}
8081   *globalCellNumbers = mesh->globalCellNumbers;
8082   PetscFunctionReturn(0);
8083 }
8084 
8085 PetscErrorCode DMPlexCreateVertexNumbering_Internal(DM dm, PetscBool includeHybrid, IS *globalVertexNumbers)
8086 {
8087   PetscInt       vStart, vEnd;
8088   PetscErrorCode ierr;
8089 
8090   PetscFunctionBegin;
8091   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8092   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
8093   ierr = DMPlexCreateNumbering_Plex(dm, vStart, vEnd, 0, NULL, dm->sf, globalVertexNumbers);CHKERRQ(ierr);
8094   PetscFunctionReturn(0);
8095 }
8096 
8097 /*@
8098   DMPlexGetVertexNumbering - Get a global vertex numbering for all vertices on this process
8099 
8100   Input Parameter:
8101 . dm   - The DMPlex object
8102 
8103   Output Parameter:
8104 . globalVertexNumbers - Global vertex numbers for all vertices on this process
8105 
8106   Level: developer
8107 
8108 .seealso DMPlexGetCellNumbering()
8109 @*/
8110 PetscErrorCode DMPlexGetVertexNumbering(DM dm, IS *globalVertexNumbers)
8111 {
8112   DM_Plex       *mesh = (DM_Plex*) dm->data;
8113   PetscErrorCode ierr;
8114 
8115   PetscFunctionBegin;
8116   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8117   if (!mesh->globalVertexNumbers) {ierr = DMPlexCreateVertexNumbering_Internal(dm, PETSC_FALSE, &mesh->globalVertexNumbers);CHKERRQ(ierr);}
8118   *globalVertexNumbers = mesh->globalVertexNumbers;
8119   PetscFunctionReturn(0);
8120 }
8121 
8122 /*@
8123   DMPlexCreatePointNumbering - Create a global numbering for all points on this process
8124 
8125   Input Parameter:
8126 . dm   - The DMPlex object
8127 
8128   Output Parameter:
8129 . globalPointNumbers - Global numbers for all points on this process
8130 
8131   Level: developer
8132 
8133 .seealso DMPlexGetCellNumbering()
8134 @*/
8135 PetscErrorCode DMPlexCreatePointNumbering(DM dm, IS *globalPointNumbers)
8136 {
8137   IS             nums[4];
8138   PetscInt       depths[4], gdepths[4], starts[4];
8139   PetscInt       depth, d, shift = 0;
8140   PetscErrorCode ierr;
8141 
8142   PetscFunctionBegin;
8143   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8144   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
8145   /* For unstratified meshes use dim instead of depth */
8146   if (depth < 0) {ierr = DMGetDimension(dm, &depth);CHKERRQ(ierr);}
8147   for (d = 0; d <= depth; ++d) {
8148     PetscInt end;
8149 
8150     depths[d] = depth-d;
8151     ierr = DMPlexGetDepthStratum(dm, depths[d], &starts[d], &end);CHKERRQ(ierr);
8152     if (!(starts[d]-end)) { starts[d] = depths[d] = -1; }
8153   }
8154   ierr = PetscSortIntWithArray(depth+1, starts, depths);CHKERRQ(ierr);
8155   ierr = MPIU_Allreduce(depths, gdepths, depth+1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject) dm));CHKERRMPI(ierr);
8156   for (d = 0; d <= depth; ++d) {
8157     PetscCheckFalse(starts[d] >= 0 && depths[d] != gdepths[d],PETSC_COMM_SELF,PETSC_ERR_PLIB,"Expected depth %D, found %D",depths[d],gdepths[d]);
8158   }
8159   for (d = 0; d <= depth; ++d) {
8160     PetscInt pStart, pEnd, gsize;
8161 
8162     ierr = DMPlexGetDepthStratum(dm, gdepths[d], &pStart, &pEnd);CHKERRQ(ierr);
8163     ierr = DMPlexCreateNumbering_Plex(dm, pStart, pEnd, shift, &gsize, dm->sf, &nums[d]);CHKERRQ(ierr);
8164     shift += gsize;
8165   }
8166   ierr = ISConcatenate(PetscObjectComm((PetscObject) dm), depth+1, nums, globalPointNumbers);CHKERRQ(ierr);
8167   for (d = 0; d <= depth; ++d) {ierr = ISDestroy(&nums[d]);CHKERRQ(ierr);}
8168   PetscFunctionReturn(0);
8169 }
8170 
8171 /*@
8172   DMPlexCreateRankField - Create a cell field whose value is the rank of the owner
8173 
8174   Input Parameter:
8175 . dm - The DMPlex object
8176 
8177   Output Parameter:
8178 . ranks - The rank field
8179 
8180   Options Database Keys:
8181 . -dm_partition_view - Adds the rank field into the DM output from -dm_view using the same viewer
8182 
8183   Level: intermediate
8184 
8185 .seealso: DMView()
8186 @*/
8187 PetscErrorCode DMPlexCreateRankField(DM dm, Vec *ranks)
8188 {
8189   DM             rdm;
8190   PetscFE        fe;
8191   PetscScalar   *r;
8192   PetscMPIInt    rank;
8193   DMPolytopeType ct;
8194   PetscInt       dim, cStart, cEnd, c;
8195   PetscBool      simplex;
8196   PetscErrorCode ierr;
8197 
8198   PetscFunctionBeginUser;
8199   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8200   PetscValidPointer(ranks, 2);
8201   ierr = MPI_Comm_rank(PetscObjectComm((PetscObject) dm), &rank);CHKERRMPI(ierr);
8202   ierr = DMClone(dm, &rdm);CHKERRQ(ierr);
8203   ierr = DMGetDimension(rdm, &dim);CHKERRQ(ierr);
8204   ierr = DMPlexGetHeightStratum(rdm, 0, &cStart, &cEnd);CHKERRQ(ierr);
8205   ierr = DMPlexGetCellType(dm, cStart, &ct);CHKERRQ(ierr);
8206   simplex = DMPolytopeTypeGetNumVertices(ct) == DMPolytopeTypeGetDim(ct)+1 ? PETSC_TRUE : PETSC_FALSE;
8207   ierr = PetscFECreateDefault(PETSC_COMM_SELF, dim, 1, simplex, "PETSc___rank_", -1, &fe);CHKERRQ(ierr);
8208   ierr = PetscObjectSetName((PetscObject) fe, "rank");CHKERRQ(ierr);
8209   ierr = DMSetField(rdm, 0, NULL, (PetscObject) fe);CHKERRQ(ierr);
8210   ierr = PetscFEDestroy(&fe);CHKERRQ(ierr);
8211   ierr = DMCreateDS(rdm);CHKERRQ(ierr);
8212   ierr = DMCreateGlobalVector(rdm, ranks);CHKERRQ(ierr);
8213   ierr = PetscObjectSetName((PetscObject) *ranks, "partition");CHKERRQ(ierr);
8214   ierr = VecGetArray(*ranks, &r);CHKERRQ(ierr);
8215   for (c = cStart; c < cEnd; ++c) {
8216     PetscScalar *lr;
8217 
8218     ierr = DMPlexPointGlobalRef(rdm, c, r, &lr);CHKERRQ(ierr);
8219     if (lr) *lr = rank;
8220   }
8221   ierr = VecRestoreArray(*ranks, &r);CHKERRQ(ierr);
8222   ierr = DMDestroy(&rdm);CHKERRQ(ierr);
8223   PetscFunctionReturn(0);
8224 }
8225 
8226 /*@
8227   DMPlexCreateLabelField - Create a cell field whose value is the label value for that cell
8228 
8229   Input Parameters:
8230 + dm    - The DMPlex
8231 - label - The DMLabel
8232 
8233   Output Parameter:
8234 . val - The label value field
8235 
8236   Options Database Keys:
8237 . -dm_label_view - Adds the label value field into the DM output from -dm_view using the same viewer
8238 
8239   Level: intermediate
8240 
8241 .seealso: DMView()
8242 @*/
8243 PetscErrorCode DMPlexCreateLabelField(DM dm, DMLabel label, Vec *val)
8244 {
8245   DM             rdm;
8246   PetscFE        fe;
8247   PetscScalar   *v;
8248   PetscInt       dim, cStart, cEnd, c;
8249   PetscErrorCode ierr;
8250 
8251   PetscFunctionBeginUser;
8252   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8253   PetscValidPointer(label, 2);
8254   PetscValidPointer(val, 3);
8255   ierr = DMClone(dm, &rdm);CHKERRQ(ierr);
8256   ierr = DMGetDimension(rdm, &dim);CHKERRQ(ierr);
8257   ierr = PetscFECreateDefault(PetscObjectComm((PetscObject) rdm), dim, 1, PETSC_TRUE, "PETSc___label_value_", -1, &fe);CHKERRQ(ierr);
8258   ierr = PetscObjectSetName((PetscObject) fe, "label_value");CHKERRQ(ierr);
8259   ierr = DMSetField(rdm, 0, NULL, (PetscObject) fe);CHKERRQ(ierr);
8260   ierr = PetscFEDestroy(&fe);CHKERRQ(ierr);
8261   ierr = DMCreateDS(rdm);CHKERRQ(ierr);
8262   ierr = DMPlexGetHeightStratum(rdm, 0, &cStart, &cEnd);CHKERRQ(ierr);
8263   ierr = DMCreateGlobalVector(rdm, val);CHKERRQ(ierr);
8264   ierr = PetscObjectSetName((PetscObject) *val, "label_value");CHKERRQ(ierr);
8265   ierr = VecGetArray(*val, &v);CHKERRQ(ierr);
8266   for (c = cStart; c < cEnd; ++c) {
8267     PetscScalar *lv;
8268     PetscInt     cval;
8269 
8270     ierr = DMPlexPointGlobalRef(rdm, c, v, &lv);CHKERRQ(ierr);
8271     ierr = DMLabelGetValue(label, c, &cval);CHKERRQ(ierr);
8272     *lv = cval;
8273   }
8274   ierr = VecRestoreArray(*val, &v);CHKERRQ(ierr);
8275   ierr = DMDestroy(&rdm);CHKERRQ(ierr);
8276   PetscFunctionReturn(0);
8277 }
8278 
8279 /*@
8280   DMPlexCheckSymmetry - Check that the adjacency information in the mesh is symmetric.
8281 
8282   Input Parameter:
8283 . dm - The DMPlex object
8284 
8285   Notes:
8286   This is a useful diagnostic when creating meshes programmatically.
8287 
8288   For the complete list of DMPlexCheck* functions, see DMSetFromOptions().
8289 
8290   Level: developer
8291 
8292 .seealso: DMCreate(), DMSetFromOptions()
8293 @*/
8294 PetscErrorCode DMPlexCheckSymmetry(DM dm)
8295 {
8296   PetscSection    coneSection, supportSection;
8297   const PetscInt *cone, *support;
8298   PetscInt        coneSize, c, supportSize, s;
8299   PetscInt        pStart, pEnd, p, pp, csize, ssize;
8300   PetscBool       storagecheck = PETSC_TRUE;
8301   PetscErrorCode  ierr;
8302 
8303   PetscFunctionBegin;
8304   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8305   ierr = DMViewFromOptions(dm, NULL, "-sym_dm_view");CHKERRQ(ierr);
8306   ierr = DMPlexGetConeSection(dm, &coneSection);CHKERRQ(ierr);
8307   ierr = DMPlexGetSupportSection(dm, &supportSection);CHKERRQ(ierr);
8308   /* Check that point p is found in the support of its cone points, and vice versa */
8309   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
8310   for (p = pStart; p < pEnd; ++p) {
8311     ierr = DMPlexGetConeSize(dm, p, &coneSize);CHKERRQ(ierr);
8312     ierr = DMPlexGetCone(dm, p, &cone);CHKERRQ(ierr);
8313     for (c = 0; c < coneSize; ++c) {
8314       PetscBool dup = PETSC_FALSE;
8315       PetscInt  d;
8316       for (d = c-1; d >= 0; --d) {
8317         if (cone[c] == cone[d]) {dup = PETSC_TRUE; break;}
8318       }
8319       ierr = DMPlexGetSupportSize(dm, cone[c], &supportSize);CHKERRQ(ierr);
8320       ierr = DMPlexGetSupport(dm, cone[c], &support);CHKERRQ(ierr);
8321       for (s = 0; s < supportSize; ++s) {
8322         if (support[s] == p) break;
8323       }
8324       if ((s >= supportSize) || (dup && (support[s+1] != p))) {
8325         ierr = PetscPrintf(PETSC_COMM_SELF, "p: %D cone: ", p);CHKERRQ(ierr);
8326         for (s = 0; s < coneSize; ++s) {
8327           ierr = PetscPrintf(PETSC_COMM_SELF, "%D, ", cone[s]);CHKERRQ(ierr);
8328         }
8329         ierr = PetscPrintf(PETSC_COMM_SELF, "\n");CHKERRQ(ierr);
8330         ierr = PetscPrintf(PETSC_COMM_SELF, "p: %D support: ", cone[c]);CHKERRQ(ierr);
8331         for (s = 0; s < supportSize; ++s) {
8332           ierr = PetscPrintf(PETSC_COMM_SELF, "%D, ", support[s]);CHKERRQ(ierr);
8333         }
8334         ierr = PetscPrintf(PETSC_COMM_SELF, "\n");CHKERRQ(ierr);
8335         PetscCheckFalse(dup,PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D not repeatedly found in support of repeated cone point %D", p, cone[c]);
8336         else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D not found in support of cone point %D", p, cone[c]);
8337       }
8338     }
8339     ierr = DMPlexGetTreeParent(dm, p, &pp, NULL);CHKERRQ(ierr);
8340     if (p != pp) { storagecheck = PETSC_FALSE; continue; }
8341     ierr = DMPlexGetSupportSize(dm, p, &supportSize);CHKERRQ(ierr);
8342     ierr = DMPlexGetSupport(dm, p, &support);CHKERRQ(ierr);
8343     for (s = 0; s < supportSize; ++s) {
8344       ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
8345       ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
8346       for (c = 0; c < coneSize; ++c) {
8347         ierr = DMPlexGetTreeParent(dm, cone[c], &pp, NULL);CHKERRQ(ierr);
8348         if (cone[c] != pp) { c = 0; break; }
8349         if (cone[c] == p) break;
8350       }
8351       if (c >= coneSize) {
8352         ierr = PetscPrintf(PETSC_COMM_SELF, "p: %D support: ", p);CHKERRQ(ierr);
8353         for (c = 0; c < supportSize; ++c) {
8354           ierr = PetscPrintf(PETSC_COMM_SELF, "%D, ", support[c]);CHKERRQ(ierr);
8355         }
8356         ierr = PetscPrintf(PETSC_COMM_SELF, "\n");CHKERRQ(ierr);
8357         ierr = PetscPrintf(PETSC_COMM_SELF, "p: %D cone: ", support[s]);CHKERRQ(ierr);
8358         for (c = 0; c < coneSize; ++c) {
8359           ierr = PetscPrintf(PETSC_COMM_SELF, "%D, ", cone[c]);CHKERRQ(ierr);
8360         }
8361         ierr = PetscPrintf(PETSC_COMM_SELF, "\n");CHKERRQ(ierr);
8362         SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D not found in cone of support point %D", p, support[s]);
8363       }
8364     }
8365   }
8366   if (storagecheck) {
8367     ierr = PetscSectionGetStorageSize(coneSection, &csize);CHKERRQ(ierr);
8368     ierr = PetscSectionGetStorageSize(supportSection, &ssize);CHKERRQ(ierr);
8369     PetscCheckFalse(csize != ssize,PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Total cone size %D != Total support size %D", csize, ssize);
8370   }
8371   PetscFunctionReturn(0);
8372 }
8373 
8374 /*
8375   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.
8376 */
8377 static PetscErrorCode DMPlexCellUnsplitVertices_Private(DM dm, PetscInt c, DMPolytopeType ct, PetscInt *unsplit)
8378 {
8379   DMPolytopeType  cct;
8380   PetscInt        ptpoints[4];
8381   const PetscInt *cone, *ccone, *ptcone;
8382   PetscInt        coneSize, cp, cconeSize, ccp, npt = 0, pt;
8383   PetscErrorCode  ierr;
8384 
8385   PetscFunctionBegin;
8386   *unsplit = 0;
8387   switch (ct) {
8388     case DM_POLYTOPE_POINT_PRISM_TENSOR:
8389       ptpoints[npt++] = c;
8390       break;
8391     case DM_POLYTOPE_SEG_PRISM_TENSOR:
8392       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
8393       ierr = DMPlexGetConeSize(dm, c, &coneSize);CHKERRQ(ierr);
8394       for (cp = 0; cp < coneSize; ++cp) {
8395         ierr = DMPlexGetCellType(dm, cone[cp], &cct);CHKERRQ(ierr);
8396         if (cct == DM_POLYTOPE_POINT_PRISM_TENSOR) ptpoints[npt++] = cone[cp];
8397       }
8398       break;
8399     case DM_POLYTOPE_TRI_PRISM_TENSOR:
8400     case DM_POLYTOPE_QUAD_PRISM_TENSOR:
8401       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
8402       ierr = DMPlexGetConeSize(dm, c, &coneSize);CHKERRQ(ierr);
8403       for (cp = 0; cp < coneSize; ++cp) {
8404         ierr = DMPlexGetCone(dm, cone[cp], &ccone);CHKERRQ(ierr);
8405         ierr = DMPlexGetConeSize(dm, cone[cp], &cconeSize);CHKERRQ(ierr);
8406         for (ccp = 0; ccp < cconeSize; ++ccp) {
8407           ierr = DMPlexGetCellType(dm, ccone[ccp], &cct);CHKERRQ(ierr);
8408           if (cct == DM_POLYTOPE_POINT_PRISM_TENSOR) {
8409             PetscInt p;
8410             for (p = 0; p < npt; ++p) if (ptpoints[p] == ccone[ccp]) break;
8411             if (p == npt) ptpoints[npt++] = ccone[ccp];
8412           }
8413         }
8414       }
8415       break;
8416     default: break;
8417   }
8418   for (pt = 0; pt < npt; ++pt) {
8419     ierr = DMPlexGetCone(dm, ptpoints[pt], &ptcone);CHKERRQ(ierr);
8420     if (ptcone[0] == ptcone[1]) ++(*unsplit);
8421   }
8422   PetscFunctionReturn(0);
8423 }
8424 
8425 /*@
8426   DMPlexCheckSkeleton - Check that each cell has the correct number of vertices
8427 
8428   Input Parameters:
8429 + dm - The DMPlex object
8430 - cellHeight - Normally 0
8431 
8432   Notes:
8433   This is a useful diagnostic when creating meshes programmatically.
8434   Currently applicable only to homogeneous simplex or tensor meshes.
8435 
8436   For the complete list of DMPlexCheck* functions, see DMSetFromOptions().
8437 
8438   Level: developer
8439 
8440 .seealso: DMCreate(), DMSetFromOptions()
8441 @*/
8442 PetscErrorCode DMPlexCheckSkeleton(DM dm, PetscInt cellHeight)
8443 {
8444   DMPlexInterpolatedFlag interp;
8445   DMPolytopeType         ct;
8446   PetscInt               vStart, vEnd, cStart, cEnd, c;
8447   PetscErrorCode         ierr;
8448 
8449   PetscFunctionBegin;
8450   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8451   ierr = DMPlexIsInterpolated(dm, &interp);CHKERRQ(ierr);
8452   ierr = DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd);CHKERRQ(ierr);
8453   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
8454   for (c = cStart; c < cEnd; ++c) {
8455     PetscInt *closure = NULL;
8456     PetscInt  coneSize, closureSize, cl, Nv = 0;
8457 
8458     ierr = DMPlexGetCellType(dm, c, &ct);CHKERRQ(ierr);
8459     PetscCheckFalse((PetscInt) ct < 0,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cell %D has no cell type", c);
8460     if (ct == DM_POLYTOPE_UNKNOWN) continue;
8461     if (interp == DMPLEX_INTERPOLATED_FULL) {
8462       ierr = DMPlexGetConeSize(dm, c, &coneSize);CHKERRQ(ierr);
8463       PetscCheckFalse(coneSize != DMPolytopeTypeGetConeSize(ct),PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cell %D of type %s has cone size %D != %D", c, DMPolytopeTypes[ct], coneSize, DMPolytopeTypeGetConeSize(ct));
8464     }
8465     ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
8466     for (cl = 0; cl < closureSize*2; cl += 2) {
8467       const PetscInt p = closure[cl];
8468       if ((p >= vStart) && (p < vEnd)) ++Nv;
8469     }
8470     ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
8471     /* Special Case: Tensor faces with identified vertices */
8472     if (Nv < DMPolytopeTypeGetNumVertices(ct)) {
8473       PetscInt unsplit;
8474 
8475       ierr = DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit);CHKERRQ(ierr);
8476       if (Nv + unsplit == DMPolytopeTypeGetNumVertices(ct)) continue;
8477     }
8478     PetscCheckFalse(Nv != DMPolytopeTypeGetNumVertices(ct),PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cell %D of type %s has %D vertices != %D", c, DMPolytopeTypes[ct], Nv, DMPolytopeTypeGetNumVertices(ct));
8479   }
8480   PetscFunctionReturn(0);
8481 }
8482 
8483 /*@
8484   DMPlexCheckFaces - Check that the faces of each cell give a vertex order this is consistent with what we expect from the cell type
8485 
8486   Not Collective
8487 
8488   Input Parameters:
8489 + dm - The DMPlex object
8490 - cellHeight - Normally 0
8491 
8492   Notes:
8493   This is a useful diagnostic when creating meshes programmatically.
8494   This routine is only relevant for meshes that are fully interpolated across all ranks.
8495   It will error out if a partially interpolated mesh is given on some rank.
8496   It will do nothing for locally uninterpolated mesh (as there is nothing to check).
8497 
8498   For the complete list of DMPlexCheck* functions, see DMSetFromOptions().
8499 
8500   Level: developer
8501 
8502 .seealso: DMCreate(), DMPlexGetVTKCellHeight(), DMSetFromOptions()
8503 @*/
8504 PetscErrorCode DMPlexCheckFaces(DM dm, PetscInt cellHeight)
8505 {
8506   PetscInt       dim, depth, vStart, vEnd, cStart, cEnd, c, h;
8507   PetscErrorCode ierr;
8508   DMPlexInterpolatedFlag interpEnum;
8509 
8510   PetscFunctionBegin;
8511   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8512   ierr = DMPlexIsInterpolated(dm, &interpEnum);CHKERRQ(ierr);
8513   if (interpEnum == DMPLEX_INTERPOLATED_NONE) PetscFunctionReturn(0);
8514   if (interpEnum == DMPLEX_INTERPOLATED_PARTIAL) {
8515     PetscMPIInt rank;
8516     MPI_Comm    comm;
8517 
8518     ierr = PetscObjectGetComm((PetscObject) dm, &comm);CHKERRQ(ierr);
8519     ierr = MPI_Comm_rank(comm, &rank);CHKERRMPI(ierr);
8520     SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Mesh is only partially interpolated on rank %d, this is currently not supported", rank);
8521   }
8522 
8523   ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr);
8524   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
8525   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
8526   for (h = cellHeight; h < PetscMin(depth, dim); ++h) {
8527     ierr = DMPlexGetHeightStratum(dm, h, &cStart, &cEnd);CHKERRQ(ierr);
8528     for (c = cStart; c < cEnd; ++c) {
8529       const PetscInt      *cone, *ornt, *faceSizes, *faces;
8530       const DMPolytopeType *faceTypes;
8531       DMPolytopeType        ct;
8532       PetscInt              numFaces, coneSize, f;
8533       PetscInt             *closure = NULL, closureSize, cl, numCorners = 0, fOff = 0, unsplit;
8534 
8535       ierr = DMPlexGetCellType(dm, c, &ct);CHKERRQ(ierr);
8536       ierr = DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit);CHKERRQ(ierr);
8537       if (unsplit) continue;
8538       ierr = DMPlexGetConeSize(dm, c, &coneSize);CHKERRQ(ierr);
8539       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
8540       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
8541       ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
8542       for (cl = 0; cl < closureSize*2; cl += 2) {
8543         const PetscInt p = closure[cl];
8544         if ((p >= vStart) && (p < vEnd)) closure[numCorners++] = p;
8545       }
8546       ierr = DMPlexGetRawFaces_Internal(dm, ct, closure, &numFaces, &faceTypes, &faceSizes, &faces);CHKERRQ(ierr);
8547       PetscCheckFalse(coneSize != numFaces,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cell %D of type %s has %D faces but should have %D", c, DMPolytopeTypes[ct], coneSize, numFaces);
8548       for (f = 0; f < numFaces; ++f) {
8549         DMPolytopeType fct;
8550         PetscInt       *fclosure = NULL, fclosureSize, cl, fnumCorners = 0, v;
8551 
8552         ierr = DMPlexGetCellType(dm, cone[f], &fct);CHKERRQ(ierr);
8553         ierr = DMPlexGetTransitiveClosure_Internal(dm, cone[f], ornt[f], PETSC_TRUE, &fclosureSize, &fclosure);CHKERRQ(ierr);
8554         for (cl = 0; cl < fclosureSize*2; cl += 2) {
8555           const PetscInt p = fclosure[cl];
8556           if ((p >= vStart) && (p < vEnd)) fclosure[fnumCorners++] = p;
8557         }
8558         PetscCheckFalse(fnumCorners != faceSizes[f],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]);
8559         for (v = 0; v < fnumCorners; ++v) {
8560           if (fclosure[v] != faces[fOff+v]) {
8561             PetscInt v1;
8562 
8563             ierr = PetscPrintf(PETSC_COMM_SELF, "face closure:");CHKERRQ(ierr);
8564             for (v1 = 0; v1 < fnumCorners; ++v1) {ierr = PetscPrintf(PETSC_COMM_SELF, " %D", fclosure[v1]);CHKERRQ(ierr);}
8565             ierr = PetscPrintf(PETSC_COMM_SELF, "\ncell face:");CHKERRQ(ierr);
8566             for (v1 = 0; v1 < fnumCorners; ++v1) {ierr = PetscPrintf(PETSC_COMM_SELF, " %D", faces[fOff+v1]);CHKERRQ(ierr);}
8567             ierr = PetscPrintf(PETSC_COMM_SELF, "\n");CHKERRQ(ierr);
8568             SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Face %D of type %s (cone idx %d, ornt %D) of cell %D of type %s vertex %D, %D != %D", cone[f], DMPolytopeTypes[fct], f, ornt[f], c, DMPolytopeTypes[ct], v, fclosure[v], faces[fOff+v]);
8569           }
8570         }
8571         ierr = DMPlexRestoreTransitiveClosure(dm, cone[f], PETSC_TRUE, &fclosureSize, &fclosure);CHKERRQ(ierr);
8572         fOff += faceSizes[f];
8573       }
8574       ierr = DMPlexRestoreRawFaces_Internal(dm, ct, closure, &numFaces, &faceTypes, &faceSizes, &faces);CHKERRQ(ierr);
8575       ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
8576     }
8577   }
8578   PetscFunctionReturn(0);
8579 }
8580 
8581 /*@
8582   DMPlexCheckGeometry - Check the geometry of mesh cells
8583 
8584   Input Parameter:
8585 . dm - The DMPlex object
8586 
8587   Notes:
8588   This is a useful diagnostic when creating meshes programmatically.
8589 
8590   For the complete list of DMPlexCheck* functions, see DMSetFromOptions().
8591 
8592   Level: developer
8593 
8594 .seealso: DMCreate(), DMSetFromOptions()
8595 @*/
8596 PetscErrorCode DMPlexCheckGeometry(DM dm)
8597 {
8598   Vec            coordinates;
8599   PetscReal      detJ, J[9], refVol = 1.0;
8600   PetscReal      vol;
8601   PetscBool      periodic;
8602   PetscInt       dim, depth, dE, d, cStart, cEnd, c;
8603   PetscErrorCode ierr;
8604 
8605   PetscFunctionBegin;
8606   ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr);
8607   ierr = DMGetCoordinateDim(dm, &dE);CHKERRQ(ierr);
8608   if (dim != dE) PetscFunctionReturn(0);
8609   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
8610   ierr = DMGetPeriodicity(dm, &periodic, NULL, NULL, NULL);CHKERRQ(ierr);
8611   for (d = 0; d < dim; ++d) refVol *= 2.0;
8612   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
8613   /* Make sure local coordinates are created, because that step is collective */
8614   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
8615   for (c = cStart; c < cEnd; ++c) {
8616     DMPolytopeType ct;
8617     PetscInt       unsplit;
8618     PetscBool      ignoreZeroVol = PETSC_FALSE;
8619 
8620     ierr = DMPlexGetCellType(dm, c, &ct);CHKERRQ(ierr);
8621     switch (ct) {
8622       case DM_POLYTOPE_SEG_PRISM_TENSOR:
8623       case DM_POLYTOPE_TRI_PRISM_TENSOR:
8624       case DM_POLYTOPE_QUAD_PRISM_TENSOR:
8625         ignoreZeroVol = PETSC_TRUE; break;
8626       default: break;
8627     }
8628     switch (ct) {
8629       case DM_POLYTOPE_TRI_PRISM:
8630       case DM_POLYTOPE_TRI_PRISM_TENSOR:
8631       case DM_POLYTOPE_QUAD_PRISM_TENSOR:
8632       case DM_POLYTOPE_PYRAMID:
8633         continue;
8634       default: break;
8635     }
8636     ierr = DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit);CHKERRQ(ierr);
8637     if (unsplit) continue;
8638     ierr = DMPlexComputeCellGeometryFEM(dm, c, NULL, NULL, J, NULL, &detJ);CHKERRQ(ierr);
8639     PetscCheckFalse(detJ < -PETSC_SMALL || (detJ <= 0.0 && !ignoreZeroVol),PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Mesh cell %D of type %s is inverted, |J| = %g", c, DMPolytopeTypes[ct], (double) detJ);
8640     ierr = PetscInfo(dm, "Cell %D FEM Volume %g\n", c, (double) detJ*refVol);CHKERRQ(ierr);
8641     if (depth > 1 && !periodic) {
8642       ierr = DMPlexComputeCellGeometryFVM(dm, c, &vol, NULL, NULL);CHKERRQ(ierr);
8643       PetscCheckFalse(vol < -PETSC_SMALL || (vol <= 0.0 && !ignoreZeroVol),PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Mesh cell %D of type %s is inverted, vol = %g", c, DMPolytopeTypes[ct], (double) vol);
8644       ierr = PetscInfo(dm, "Cell %D FVM Volume %g\n", c, (double) vol);CHKERRQ(ierr);
8645     }
8646   }
8647   PetscFunctionReturn(0);
8648 }
8649 
8650 /*@
8651   DMPlexCheckPointSF - Check that several necessary conditions are met for the point SF of this plex.
8652 
8653   Input Parameters:
8654 . dm - The DMPlex object
8655 
8656   Notes:
8657   This is mainly intended for debugging/testing purposes.
8658   It currently checks only meshes with no partition overlapping.
8659 
8660   For the complete list of DMPlexCheck* functions, see DMSetFromOptions().
8661 
8662   Level: developer
8663 
8664 .seealso: DMGetPointSF(), DMSetFromOptions()
8665 @*/
8666 PetscErrorCode DMPlexCheckPointSF(DM dm)
8667 {
8668   PetscSF         pointSF;
8669   PetscInt        cellHeight, cStart, cEnd, l, nleaves, nroots, overlap;
8670   const PetscInt *locals, *rootdegree;
8671   PetscBool       distributed;
8672   PetscErrorCode  ierr;
8673 
8674   PetscFunctionBegin;
8675   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8676   ierr = DMGetPointSF(dm, &pointSF);CHKERRQ(ierr);
8677   ierr = DMPlexIsDistributed(dm, &distributed);CHKERRQ(ierr);
8678   if (!distributed) PetscFunctionReturn(0);
8679   ierr = DMPlexGetOverlap(dm, &overlap);CHKERRQ(ierr);
8680   if (overlap) {
8681     ierr = PetscPrintf(PetscObjectComm((PetscObject)dm), "Warning: DMPlexCheckPointSF() is currently not implemented for meshes with partition overlapping");CHKERRQ(ierr);
8682     PetscFunctionReturn(0);
8683   }
8684   PetscCheckFalse(!pointSF,PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "This DMPlex is distributed but does not have PointSF attached");
8685   ierr = PetscSFGetGraph(pointSF, &nroots, &nleaves, &locals, NULL);CHKERRQ(ierr);
8686   PetscCheckFalse(nroots < 0,PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "This DMPlex is distributed but its PointSF has no graph set");
8687   ierr = PetscSFComputeDegreeBegin(pointSF, &rootdegree);CHKERRQ(ierr);
8688   ierr = PetscSFComputeDegreeEnd(pointSF, &rootdegree);CHKERRQ(ierr);
8689 
8690   /* 1) check there are no faces in 2D, cells in 3D, in interface */
8691   ierr = DMPlexGetVTKCellHeight(dm, &cellHeight);CHKERRQ(ierr);
8692   ierr = DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd);CHKERRQ(ierr);
8693   for (l = 0; l < nleaves; ++l) {
8694     const PetscInt point = locals[l];
8695 
8696     PetscCheckFalse(point >= cStart && point < cEnd,PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point SF contains %D which is a cell", point);
8697   }
8698 
8699   /* 2) if some point is in interface, then all its cone points must be also in interface (either as leaves or roots) */
8700   for (l = 0; l < nleaves; ++l) {
8701     const PetscInt  point = locals[l];
8702     const PetscInt *cone;
8703     PetscInt        coneSize, c, idx;
8704 
8705     ierr = DMPlexGetConeSize(dm, point, &coneSize);CHKERRQ(ierr);
8706     ierr = DMPlexGetCone(dm, point, &cone);CHKERRQ(ierr);
8707     for (c = 0; c < coneSize; ++c) {
8708       if (!rootdegree[cone[c]]) {
8709         ierr = PetscFindInt(cone[c], nleaves, locals, &idx);CHKERRQ(ierr);
8710         PetscCheckFalse(idx < 0,PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point SF contains %D but not %D from its cone", point, cone[c]);
8711       }
8712     }
8713   }
8714   PetscFunctionReturn(0);
8715 }
8716 
8717 PetscErrorCode DMPlexCheckAll_Internal(DM dm, PetscInt cellHeight)
8718 {
8719   PetscErrorCode ierr;
8720 
8721   PetscFunctionBegin;
8722   ierr = DMPlexCheckSymmetry(dm);CHKERRQ(ierr);
8723   ierr = DMPlexCheckSkeleton(dm, cellHeight);CHKERRQ(ierr);
8724   ierr = DMPlexCheckFaces(dm, cellHeight);CHKERRQ(ierr);
8725   ierr = DMPlexCheckGeometry(dm);CHKERRQ(ierr);
8726   ierr = DMPlexCheckPointSF(dm);CHKERRQ(ierr);
8727   ierr = DMPlexCheckInterfaceCones(dm);CHKERRQ(ierr);
8728   PetscFunctionReturn(0);
8729 }
8730 
8731 typedef struct cell_stats
8732 {
8733   PetscReal min, max, sum, squaresum;
8734   PetscInt  count;
8735 } cell_stats_t;
8736 
8737 static void MPIAPI cell_stats_reduce(void *a, void *b, int * len, MPI_Datatype *datatype)
8738 {
8739   PetscInt i, N = *len;
8740 
8741   for (i = 0; i < N; i++) {
8742     cell_stats_t *A = (cell_stats_t *) a;
8743     cell_stats_t *B = (cell_stats_t *) b;
8744 
8745     B->min = PetscMin(A->min,B->min);
8746     B->max = PetscMax(A->max,B->max);
8747     B->sum += A->sum;
8748     B->squaresum += A->squaresum;
8749     B->count += A->count;
8750   }
8751 }
8752 
8753 /*@
8754   DMPlexCheckCellShape - Checks the Jacobian of the mapping from reference to real cells and computes some minimal statistics.
8755 
8756   Collective on dm
8757 
8758   Input Parameters:
8759 + dm        - The DMPlex object
8760 . output    - If true, statistics will be displayed on stdout
8761 - condLimit - Display all cells above this condition number, or PETSC_DETERMINE for no cell output
8762 
8763   Notes:
8764   This is mainly intended for debugging/testing purposes.
8765 
8766   For the complete list of DMPlexCheck* functions, see DMSetFromOptions().
8767 
8768   Level: developer
8769 
8770 .seealso: DMSetFromOptions(), DMPlexComputeOrthogonalQuality()
8771 @*/
8772 PetscErrorCode DMPlexCheckCellShape(DM dm, PetscBool output, PetscReal condLimit)
8773 {
8774   DM             dmCoarse;
8775   cell_stats_t   stats, globalStats;
8776   MPI_Comm       comm = PetscObjectComm((PetscObject)dm);
8777   PetscReal      *J, *invJ, min = 0, max = 0, mean = 0, stdev = 0;
8778   PetscReal      limit = condLimit > 0 ? condLimit : PETSC_MAX_REAL;
8779   PetscInt       cdim, cStart, cEnd, c, eStart, eEnd, count = 0;
8780   PetscMPIInt    rank,size;
8781   PetscErrorCode ierr;
8782 
8783   PetscFunctionBegin;
8784   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8785   stats.min   = PETSC_MAX_REAL;
8786   stats.max   = PETSC_MIN_REAL;
8787   stats.sum   = stats.squaresum = 0.;
8788   stats.count = 0;
8789 
8790   ierr = MPI_Comm_size(comm, &size);CHKERRMPI(ierr);
8791   ierr = MPI_Comm_rank(comm, &rank);CHKERRMPI(ierr);
8792   ierr = DMGetCoordinateDim(dm,&cdim);CHKERRQ(ierr);
8793   ierr = PetscMalloc2(PetscSqr(cdim), &J, PetscSqr(cdim), &invJ);CHKERRQ(ierr);
8794   ierr = DMPlexGetSimplexOrBoxCells(dm,0,&cStart,&cEnd);CHKERRQ(ierr);
8795   ierr = DMPlexGetDepthStratum(dm,1,&eStart,&eEnd);CHKERRQ(ierr);
8796   for (c = cStart; c < cEnd; c++) {
8797     PetscInt  i;
8798     PetscReal frobJ = 0., frobInvJ = 0., cond2, cond, detJ;
8799 
8800     ierr = DMPlexComputeCellGeometryAffineFEM(dm,c,NULL,J,invJ,&detJ);CHKERRQ(ierr);
8801     PetscCheckFalse(detJ < 0.0,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Mesh cell %D is inverted", c);
8802     for (i = 0; i < PetscSqr(cdim); ++i) {
8803       frobJ    += J[i] * J[i];
8804       frobInvJ += invJ[i] * invJ[i];
8805     }
8806     cond2 = frobJ * frobInvJ;
8807     cond  = PetscSqrtReal(cond2);
8808 
8809     stats.min        = PetscMin(stats.min,cond);
8810     stats.max        = PetscMax(stats.max,cond);
8811     stats.sum       += cond;
8812     stats.squaresum += cond2;
8813     stats.count++;
8814     if (output && cond > limit) {
8815       PetscSection coordSection;
8816       Vec          coordsLocal;
8817       PetscScalar *coords = NULL;
8818       PetscInt     Nv, d, clSize, cl, *closure = NULL;
8819 
8820       ierr = DMGetCoordinatesLocal(dm, &coordsLocal);CHKERRQ(ierr);
8821       ierr = DMGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
8822       ierr = DMPlexVecGetClosure(dm, coordSection, coordsLocal, c, &Nv, &coords);CHKERRQ(ierr);
8823       ierr = PetscSynchronizedPrintf(comm, "[%d] Cell %D cond %g\n", rank, c, (double) cond);CHKERRQ(ierr);
8824       for (i = 0; i < Nv/cdim; ++i) {
8825         ierr = PetscSynchronizedPrintf(comm, "  Vertex %D: (", i);CHKERRQ(ierr);
8826         for (d = 0; d < cdim; ++d) {
8827           if (d > 0) {ierr = PetscSynchronizedPrintf(comm, ", ");CHKERRQ(ierr);}
8828           ierr = PetscSynchronizedPrintf(comm, "%g", (double) PetscRealPart(coords[i*cdim+d]));CHKERRQ(ierr);
8829         }
8830         ierr = PetscSynchronizedPrintf(comm, ")\n");CHKERRQ(ierr);
8831       }
8832       ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &clSize, &closure);CHKERRQ(ierr);
8833       for (cl = 0; cl < clSize*2; cl += 2) {
8834         const PetscInt edge = closure[cl];
8835 
8836         if ((edge >= eStart) && (edge < eEnd)) {
8837           PetscReal len;
8838 
8839           ierr = DMPlexComputeCellGeometryFVM(dm, edge, &len, NULL, NULL);CHKERRQ(ierr);
8840           ierr = PetscSynchronizedPrintf(comm, "  Edge %D: length %g\n", edge, (double) len);CHKERRQ(ierr);
8841         }
8842       }
8843       ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &clSize, &closure);CHKERRQ(ierr);
8844       ierr = DMPlexVecRestoreClosure(dm, coordSection, coordsLocal, c, &Nv, &coords);CHKERRQ(ierr);
8845     }
8846   }
8847   if (output) {ierr = PetscSynchronizedFlush(comm, NULL);CHKERRQ(ierr);}
8848 
8849   if (size > 1) {
8850     PetscMPIInt   blockLengths[2] = {4,1};
8851     MPI_Aint      blockOffsets[2] = {offsetof(cell_stats_t,min),offsetof(cell_stats_t,count)};
8852     MPI_Datatype  blockTypes[2]   = {MPIU_REAL,MPIU_INT}, statType;
8853     MPI_Op        statReduce;
8854 
8855     ierr = MPI_Type_create_struct(2,blockLengths,blockOffsets,blockTypes,&statType);CHKERRMPI(ierr);
8856     ierr = MPI_Type_commit(&statType);CHKERRMPI(ierr);
8857     ierr = MPI_Op_create(cell_stats_reduce, PETSC_TRUE, &statReduce);CHKERRMPI(ierr);
8858     ierr = MPI_Reduce(&stats,&globalStats,1,statType,statReduce,0,comm);CHKERRMPI(ierr);
8859     ierr = MPI_Op_free(&statReduce);CHKERRMPI(ierr);
8860     ierr = MPI_Type_free(&statType);CHKERRMPI(ierr);
8861   } else {
8862     ierr = PetscArraycpy(&globalStats,&stats,1);CHKERRQ(ierr);
8863   }
8864   if (rank == 0) {
8865     count = globalStats.count;
8866     min   = globalStats.min;
8867     max   = globalStats.max;
8868     mean  = globalStats.sum / globalStats.count;
8869     stdev = globalStats.count > 1 ? PetscSqrtReal(PetscMax((globalStats.squaresum - globalStats.count * mean * mean) / (globalStats.count - 1),0)) : 0.0;
8870   }
8871 
8872   if (output) {
8873     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);
8874   }
8875   ierr = PetscFree2(J,invJ);CHKERRQ(ierr);
8876 
8877   ierr = DMGetCoarseDM(dm,&dmCoarse);CHKERRQ(ierr);
8878   if (dmCoarse) {
8879     PetscBool isplex;
8880 
8881     ierr = PetscObjectTypeCompare((PetscObject)dmCoarse,DMPLEX,&isplex);CHKERRQ(ierr);
8882     if (isplex) {
8883       ierr = DMPlexCheckCellShape(dmCoarse,output,condLimit);CHKERRQ(ierr);
8884     }
8885   }
8886   PetscFunctionReturn(0);
8887 }
8888 
8889 /*@
8890   DMPlexComputeOrthogonalQuality - Compute cell-wise orthogonal quality mesh statistic. Optionally tags all cells with
8891   orthogonal quality below given tolerance.
8892 
8893   Collective on dm
8894 
8895   Input Parameters:
8896 + dm   - The DMPlex object
8897 . fv   - Optional PetscFV object for pre-computed cell/face centroid information
8898 - atol - [0, 1] Absolute tolerance for tagging cells.
8899 
8900   Output Parameters:
8901 + OrthQual      - Vec containing orthogonal quality per cell
8902 - OrthQualLabel - DMLabel tagging cells below atol with DM_ADAPT_REFINE
8903 
8904   Options Database Keys:
8905 + -dm_plex_orthogonal_quality_label_view - view OrthQualLabel if label is requested. Currently only PETSCVIEWERASCII is
8906 supported.
8907 - -dm_plex_orthogonal_quality_vec_view - view OrthQual vector.
8908 
8909   Notes:
8910   Orthogonal quality is given by the following formula:
8911 
8912   \min \left[ \frac{A_i \cdot f_i}{\|A_i\| \|f_i\|} , \frac{A_i \cdot c_i}{\|A_i\| \|c_i\|} \right]
8913 
8914   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
8915   is the vector from the current cells centroid to the centroid of its i'th neighbor (which shares a face with the
8916   current cell). This computes the vector similarity between each cell face and its corresponding neighbor centroid by
8917   calculating the cosine of the angle between these vectors.
8918 
8919   Orthogonal quality ranges from 1 (best) to 0 (worst).
8920 
8921   This routine is mainly useful for FVM, however is not restricted to only FVM. The PetscFV object is optionally used to check for
8922   pre-computed FVM cell data, but if it is not passed in then this data will be computed.
8923 
8924   Cells are tagged if they have an orthogonal quality less than or equal to the absolute tolerance.
8925 
8926   Level: intermediate
8927 
8928 .seealso: DMPlexCheckCellShape(), DMCreateLabel()
8929 @*/
8930 PetscErrorCode DMPlexComputeOrthogonalQuality(DM dm, PetscFV fv, PetscReal atol, Vec *OrthQual, DMLabel *OrthQualLabel)
8931 {
8932   PetscInt                nc, cellHeight, cStart, cEnd, cell, cellIter = 0;
8933   PetscInt                *idx;
8934   PetscScalar             *oqVals;
8935   const PetscScalar       *cellGeomArr, *faceGeomArr;
8936   PetscReal               *ci, *fi, *Ai;
8937   MPI_Comm                comm;
8938   Vec                     cellgeom, facegeom;
8939   DM                      dmFace, dmCell;
8940   IS                      glob;
8941   ISLocalToGlobalMapping  ltog;
8942   PetscViewer             vwr;
8943   PetscErrorCode          ierr;
8944 
8945   PetscFunctionBegin;
8946   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8947   if (fv) {PetscValidHeaderSpecific(fv, PETSCFV_CLASSID, 2);}
8948   PetscValidPointer(OrthQual, 4);
8949   PetscCheck(atol >= 0.0 && atol <= 1.0,PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Absolute tolerance %g not in [0,1]",(double)atol);
8950   ierr = PetscObjectGetComm((PetscObject) dm, &comm);CHKERRQ(ierr);
8951   ierr = DMGetDimension(dm, &nc);CHKERRQ(ierr);
8952   PetscCheckFalse(nc < 2,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "DM must have dimension >= 2 (current %D)", nc);
8953   {
8954     DMPlexInterpolatedFlag interpFlag;
8955 
8956     ierr = DMPlexIsInterpolated(dm, &interpFlag);CHKERRQ(ierr);
8957     if (interpFlag != DMPLEX_INTERPOLATED_FULL) {
8958       PetscMPIInt rank;
8959 
8960       ierr = MPI_Comm_rank(comm, &rank);CHKERRMPI(ierr);
8961       SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "DM must be fully interpolated, DM on rank %d is not fully interpolated", rank);
8962     }
8963   }
8964   if (OrthQualLabel) {
8965     PetscValidPointer(OrthQualLabel, 5);
8966     ierr = DMCreateLabel(dm, "Orthogonal_Quality");CHKERRQ(ierr);
8967     ierr = DMGetLabel(dm, "Orthogonal_Quality", OrthQualLabel);CHKERRQ(ierr);
8968   } else {*OrthQualLabel = NULL;}
8969   ierr = DMPlexGetVTKCellHeight(dm, &cellHeight);CHKERRQ(ierr);
8970   ierr = DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd);CHKERRQ(ierr);
8971   ierr = DMPlexCreateCellNumbering_Internal(dm, PETSC_TRUE, &glob);CHKERRQ(ierr);
8972   ierr = ISLocalToGlobalMappingCreateIS(glob, &ltog);CHKERRQ(ierr);
8973   ierr = ISLocalToGlobalMappingSetType(ltog, ISLOCALTOGLOBALMAPPINGHASH);CHKERRQ(ierr);
8974   ierr = VecCreate(comm, OrthQual);CHKERRQ(ierr);
8975   ierr = VecSetType(*OrthQual, VECSTANDARD);CHKERRQ(ierr);
8976   ierr = VecSetSizes(*OrthQual, cEnd-cStart, PETSC_DETERMINE);CHKERRQ(ierr);
8977   ierr = VecSetLocalToGlobalMapping(*OrthQual, ltog);CHKERRQ(ierr);
8978   ierr = VecSetUp(*OrthQual);CHKERRQ(ierr);
8979   ierr = ISDestroy(&glob);CHKERRQ(ierr);
8980   ierr = ISLocalToGlobalMappingDestroy(&ltog);CHKERRQ(ierr);
8981   ierr = DMPlexGetDataFVM(dm, fv, &cellgeom, &facegeom, NULL);CHKERRQ(ierr);
8982   ierr = VecGetArrayRead(cellgeom, &cellGeomArr);CHKERRQ(ierr);
8983   ierr = VecGetArrayRead(facegeom, &faceGeomArr);CHKERRQ(ierr);
8984   ierr = VecGetDM(cellgeom, &dmCell);CHKERRQ(ierr);
8985   ierr = VecGetDM(facegeom, &dmFace);CHKERRQ(ierr);
8986   ierr = PetscMalloc5(cEnd-cStart, &idx, cEnd-cStart, &oqVals, nc, &ci, nc, &fi, nc, &Ai);CHKERRQ(ierr);
8987   for (cell = cStart; cell < cEnd; cellIter++,cell++) {
8988     PetscInt           cellneigh, cellneighiter = 0, adjSize = PETSC_DETERMINE;
8989     PetscInt           cellarr[2], *adj = NULL;
8990     PetscScalar        *cArr, *fArr;
8991     PetscReal          minvalc = 1.0, minvalf = 1.0;
8992     PetscFVCellGeom    *cg;
8993 
8994     idx[cellIter] = cell-cStart;
8995     cellarr[0] = cell;
8996     /* Make indexing into cellGeom easier */
8997     ierr = DMPlexPointLocalRead(dmCell, cell, cellGeomArr, &cg);CHKERRQ(ierr);
8998     ierr = DMPlexGetAdjacency_Internal(dm, cell, PETSC_TRUE, PETSC_FALSE, PETSC_FALSE, &adjSize, &adj);CHKERRQ(ierr);
8999     /* Technically 1 too big, but easier than fiddling with empty adjacency array */
9000     ierr = PetscCalloc2(adjSize, &cArr, adjSize, &fArr);CHKERRQ(ierr);
9001     for (cellneigh = 0; cellneigh < adjSize; cellneighiter++,cellneigh++) {
9002       PetscInt         i;
9003       const PetscInt   neigh = adj[cellneigh];
9004       PetscReal        normci = 0, normfi = 0, normai = 0;
9005       PetscFVCellGeom  *cgneigh;
9006       PetscFVFaceGeom  *fg;
9007 
9008       /* Don't count ourselves in the neighbor list */
9009       if (neigh == cell) continue;
9010       ierr = DMPlexPointLocalRead(dmCell, neigh, cellGeomArr, &cgneigh);CHKERRQ(ierr);
9011       cellarr[1] = neigh;
9012       {
9013         PetscInt       numcovpts;
9014         const PetscInt *covpts;
9015 
9016         ierr = DMPlexGetMeet(dm, 2, cellarr, &numcovpts, &covpts);CHKERRQ(ierr);
9017         ierr = DMPlexPointLocalRead(dmFace, covpts[0], faceGeomArr, &fg);CHKERRQ(ierr);
9018         ierr = DMPlexRestoreMeet(dm, 2, cellarr, &numcovpts, &covpts);CHKERRQ(ierr);
9019       }
9020 
9021       /* Compute c_i, f_i and their norms */
9022       for (i = 0; i < nc; i++) {
9023         ci[i] = cgneigh->centroid[i] - cg->centroid[i];
9024         fi[i] = fg->centroid[i] - cg->centroid[i];
9025         Ai[i] = fg->normal[i];
9026         normci += PetscPowReal(ci[i], 2);
9027         normfi += PetscPowReal(fi[i], 2);
9028         normai += PetscPowReal(Ai[i], 2);
9029       }
9030       normci = PetscSqrtReal(normci);
9031       normfi = PetscSqrtReal(normfi);
9032       normai = PetscSqrtReal(normai);
9033 
9034       /* Normalize and compute for each face-cell-normal pair */
9035       for (i = 0; i < nc; i++) {
9036         ci[i] = ci[i]/normci;
9037         fi[i] = fi[i]/normfi;
9038         Ai[i] = Ai[i]/normai;
9039         /* PetscAbs because I don't know if normals are guaranteed to point out */
9040         cArr[cellneighiter] += PetscAbs(Ai[i]*ci[i]);
9041         fArr[cellneighiter] += PetscAbs(Ai[i]*fi[i]);
9042       }
9043       if (PetscRealPart(cArr[cellneighiter]) < minvalc) {
9044         minvalc = PetscRealPart(cArr[cellneighiter]);
9045       }
9046       if (PetscRealPart(fArr[cellneighiter]) < minvalf) {
9047         minvalf = PetscRealPart(fArr[cellneighiter]);
9048       }
9049     }
9050     ierr = PetscFree(adj);CHKERRQ(ierr);
9051     ierr = PetscFree2(cArr, fArr);CHKERRQ(ierr);
9052     /* Defer to cell if they're equal */
9053     oqVals[cellIter] = PetscMin(minvalf, minvalc);
9054     if (OrthQualLabel) {
9055       if (PetscRealPart(oqVals[cellIter]) <= atol) {ierr = DMLabelSetValue(*OrthQualLabel, cell, DM_ADAPT_REFINE);CHKERRQ(ierr);}
9056     }
9057   }
9058   ierr = VecSetValuesLocal(*OrthQual, cEnd-cStart, idx, oqVals, INSERT_VALUES);CHKERRQ(ierr);
9059   ierr = VecAssemblyBegin(*OrthQual);CHKERRQ(ierr);
9060   ierr = VecAssemblyEnd(*OrthQual);CHKERRQ(ierr);
9061   ierr = VecRestoreArrayRead(cellgeom, &cellGeomArr);CHKERRQ(ierr);
9062   ierr = VecRestoreArrayRead(facegeom, &faceGeomArr);CHKERRQ(ierr);
9063   ierr = PetscOptionsGetViewer(comm, NULL, NULL, "-dm_plex_orthogonal_quality_label_view", &vwr, NULL, NULL);CHKERRQ(ierr);
9064   if (OrthQualLabel) {
9065     if (vwr) {ierr = DMLabelView(*OrthQualLabel, vwr);CHKERRQ(ierr);}
9066   }
9067   ierr = PetscFree5(idx, oqVals, ci, fi, Ai);CHKERRQ(ierr);
9068   ierr = PetscViewerDestroy(&vwr);CHKERRQ(ierr);
9069   ierr = VecViewFromOptions(*OrthQual, NULL, "-dm_plex_orthogonal_quality_vec_view");CHKERRQ(ierr);
9070   PetscFunctionReturn(0);
9071 }
9072 
9073 /* this is here insead of DMGetOutputDM because output DM still has constraints in the local indices that affect
9074  * interpolator construction */
9075 static PetscErrorCode DMGetFullDM(DM dm, DM *odm)
9076 {
9077   PetscSection   section, newSection, gsection;
9078   PetscSF        sf;
9079   PetscBool      hasConstraints, ghasConstraints;
9080   PetscErrorCode ierr;
9081 
9082   PetscFunctionBegin;
9083   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
9084   PetscValidPointer(odm,2);
9085   ierr = DMGetLocalSection(dm, &section);CHKERRQ(ierr);
9086   ierr = PetscSectionHasConstraints(section, &hasConstraints);CHKERRQ(ierr);
9087   ierr = MPI_Allreduce(&hasConstraints, &ghasConstraints, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject) dm));CHKERRMPI(ierr);
9088   if (!ghasConstraints) {
9089     ierr = PetscObjectReference((PetscObject)dm);CHKERRQ(ierr);
9090     *odm = dm;
9091     PetscFunctionReturn(0);
9092   }
9093   ierr = DMClone(dm, odm);CHKERRQ(ierr);
9094   ierr = DMCopyFields(dm, *odm);CHKERRQ(ierr);
9095   ierr = DMGetLocalSection(*odm, &newSection);CHKERRQ(ierr);
9096   ierr = DMGetPointSF(*odm, &sf);CHKERRQ(ierr);
9097   ierr = PetscSectionCreateGlobalSection(newSection, sf, PETSC_TRUE, PETSC_FALSE, &gsection);CHKERRQ(ierr);
9098   ierr = DMSetGlobalSection(*odm, gsection);CHKERRQ(ierr);
9099   ierr = PetscSectionDestroy(&gsection);CHKERRQ(ierr);
9100   PetscFunctionReturn(0);
9101 }
9102 
9103 static PetscErrorCode DMCreateAffineInterpolationCorrection_Plex(DM dmc, DM dmf, Vec *shift)
9104 {
9105   DM             dmco, dmfo;
9106   Mat            interpo;
9107   Vec            rscale;
9108   Vec            cglobalo, clocal;
9109   Vec            fglobal, fglobalo, flocal;
9110   PetscBool      regular;
9111   PetscErrorCode ierr;
9112 
9113   PetscFunctionBegin;
9114   ierr = DMGetFullDM(dmc, &dmco);CHKERRQ(ierr);
9115   ierr = DMGetFullDM(dmf, &dmfo);CHKERRQ(ierr);
9116   ierr = DMSetCoarseDM(dmfo, dmco);CHKERRQ(ierr);
9117   ierr = DMPlexGetRegularRefinement(dmf, &regular);CHKERRQ(ierr);
9118   ierr = DMPlexSetRegularRefinement(dmfo, regular);CHKERRQ(ierr);
9119   ierr = DMCreateInterpolation(dmco, dmfo, &interpo, &rscale);CHKERRQ(ierr);
9120   ierr = DMCreateGlobalVector(dmco, &cglobalo);CHKERRQ(ierr);
9121   ierr = DMCreateLocalVector(dmc, &clocal);CHKERRQ(ierr);
9122   ierr = VecSet(cglobalo, 0.);CHKERRQ(ierr);
9123   ierr = VecSet(clocal, 0.);CHKERRQ(ierr);
9124   ierr = DMCreateGlobalVector(dmf, &fglobal);CHKERRQ(ierr);
9125   ierr = DMCreateGlobalVector(dmfo, &fglobalo);CHKERRQ(ierr);
9126   ierr = DMCreateLocalVector(dmf, &flocal);CHKERRQ(ierr);
9127   ierr = VecSet(fglobal, 0.);CHKERRQ(ierr);
9128   ierr = VecSet(fglobalo, 0.);CHKERRQ(ierr);
9129   ierr = VecSet(flocal, 0.);CHKERRQ(ierr);
9130   ierr = DMPlexInsertBoundaryValues(dmc, PETSC_TRUE, clocal, 0., NULL, NULL, NULL);CHKERRQ(ierr);
9131   ierr = DMLocalToGlobalBegin(dmco, clocal, INSERT_VALUES, cglobalo);CHKERRQ(ierr);
9132   ierr = DMLocalToGlobalEnd(dmco, clocal, INSERT_VALUES, cglobalo);CHKERRQ(ierr);
9133   ierr = MatMult(interpo, cglobalo, fglobalo);CHKERRQ(ierr);
9134   ierr = DMGlobalToLocalBegin(dmfo, fglobalo, INSERT_VALUES, flocal);CHKERRQ(ierr);
9135   ierr = DMGlobalToLocalEnd(dmfo, fglobalo, INSERT_VALUES, flocal);CHKERRQ(ierr);
9136   ierr = DMLocalToGlobalBegin(dmf, flocal, INSERT_VALUES, fglobal);CHKERRQ(ierr);
9137   ierr = DMLocalToGlobalEnd(dmf, flocal, INSERT_VALUES, fglobal);CHKERRQ(ierr);
9138   *shift = fglobal;
9139   ierr = VecDestroy(&flocal);CHKERRQ(ierr);
9140   ierr = VecDestroy(&fglobalo);CHKERRQ(ierr);
9141   ierr = VecDestroy(&clocal);CHKERRQ(ierr);
9142   ierr = VecDestroy(&cglobalo);CHKERRQ(ierr);
9143   ierr = VecDestroy(&rscale);CHKERRQ(ierr);
9144   ierr = MatDestroy(&interpo);CHKERRQ(ierr);
9145   ierr = DMDestroy(&dmfo);CHKERRQ(ierr);
9146   ierr = DMDestroy(&dmco);CHKERRQ(ierr);
9147   PetscFunctionReturn(0);
9148 }
9149 
9150 PETSC_INTERN PetscErrorCode DMInterpolateSolution_Plex(DM coarse, DM fine, Mat interp, Vec coarseSol, Vec fineSol)
9151 {
9152   PetscObject    shifto;
9153   Vec            shift;
9154 
9155   PetscErrorCode ierr;
9156 
9157   PetscFunctionBegin;
9158   if (!interp) {
9159     Vec rscale;
9160 
9161     ierr = DMCreateInterpolation(coarse, fine, &interp, &rscale);CHKERRQ(ierr);
9162     ierr = VecDestroy(&rscale);CHKERRQ(ierr);
9163   } else {
9164     ierr = PetscObjectReference((PetscObject)interp);CHKERRQ(ierr);
9165   }
9166   ierr = PetscObjectQuery((PetscObject)interp, "_DMInterpolateSolution_Plex_Vec", &shifto);CHKERRQ(ierr);
9167   if (!shifto) {
9168     ierr = DMCreateAffineInterpolationCorrection_Plex(coarse, fine, &shift);CHKERRQ(ierr);
9169     ierr = PetscObjectCompose((PetscObject)interp, "_DMInterpolateSolution_Plex_Vec", (PetscObject) shift);CHKERRQ(ierr);
9170     shifto = (PetscObject) shift;
9171     ierr = VecDestroy(&shift);CHKERRQ(ierr);
9172   }
9173   shift = (Vec) shifto;
9174   ierr = MatInterpolate(interp, coarseSol, fineSol);CHKERRQ(ierr);
9175   ierr = VecAXPY(fineSol, 1.0, shift);CHKERRQ(ierr);
9176   ierr = MatDestroy(&interp);CHKERRQ(ierr);
9177   PetscFunctionReturn(0);
9178 }
9179 
9180 /* Pointwise interpolation
9181      Just code FEM for now
9182      u^f = I u^c
9183      sum_k u^f_k phi^f_k = I sum_j u^c_j phi^c_j
9184      u^f_i = sum_j psi^f_i I phi^c_j u^c_j
9185      I_{ij} = psi^f_i phi^c_j
9186 */
9187 PetscErrorCode DMCreateInterpolation_Plex(DM dmCoarse, DM dmFine, Mat *interpolation, Vec *scaling)
9188 {
9189   PetscSection   gsc, gsf;
9190   PetscInt       m, n;
9191   void          *ctx;
9192   DM             cdm;
9193   PetscBool      regular, ismatis, isRefined = dmCoarse->data == dmFine->data ? PETSC_FALSE : PETSC_TRUE;
9194   PetscErrorCode ierr;
9195 
9196   PetscFunctionBegin;
9197   ierr = DMGetGlobalSection(dmFine, &gsf);CHKERRQ(ierr);
9198   ierr = PetscSectionGetConstrainedStorageSize(gsf, &m);CHKERRQ(ierr);
9199   ierr = DMGetGlobalSection(dmCoarse, &gsc);CHKERRQ(ierr);
9200   ierr = PetscSectionGetConstrainedStorageSize(gsc, &n);CHKERRQ(ierr);
9201 
9202   ierr = PetscStrcmp(dmCoarse->mattype, MATIS, &ismatis);CHKERRQ(ierr);
9203   ierr = MatCreate(PetscObjectComm((PetscObject) dmCoarse), interpolation);CHKERRQ(ierr);
9204   ierr = MatSetSizes(*interpolation, m, n, PETSC_DETERMINE, PETSC_DETERMINE);CHKERRQ(ierr);
9205   ierr = MatSetType(*interpolation, ismatis ? MATAIJ : dmCoarse->mattype);CHKERRQ(ierr);
9206   ierr = DMGetApplicationContext(dmFine, &ctx);CHKERRQ(ierr);
9207 
9208   ierr = DMGetCoarseDM(dmFine, &cdm);CHKERRQ(ierr);
9209   ierr = DMPlexGetRegularRefinement(dmFine, &regular);CHKERRQ(ierr);
9210   if (!isRefined || (regular && cdm == dmCoarse)) {ierr = DMPlexComputeInterpolatorNested(dmCoarse, dmFine, isRefined, *interpolation, ctx);CHKERRQ(ierr);}
9211   else                                            {ierr = DMPlexComputeInterpolatorGeneral(dmCoarse, dmFine, *interpolation, ctx);CHKERRQ(ierr);}
9212   ierr = MatViewFromOptions(*interpolation, NULL, "-interp_mat_view");CHKERRQ(ierr);
9213   if (scaling) {
9214     /* Use naive scaling */
9215     ierr = DMCreateInterpolationScale(dmCoarse, dmFine, *interpolation, scaling);CHKERRQ(ierr);
9216   }
9217   PetscFunctionReturn(0);
9218 }
9219 
9220 PetscErrorCode DMCreateInjection_Plex(DM dmCoarse, DM dmFine, Mat *mat)
9221 {
9222   PetscErrorCode ierr;
9223   VecScatter     ctx;
9224 
9225   PetscFunctionBegin;
9226   ierr = DMPlexComputeInjectorFEM(dmCoarse, dmFine, &ctx, NULL);CHKERRQ(ierr);
9227   ierr = MatCreateScatter(PetscObjectComm((PetscObject)ctx), ctx, mat);CHKERRQ(ierr);
9228   ierr = VecScatterDestroy(&ctx);CHKERRQ(ierr);
9229   PetscFunctionReturn(0);
9230 }
9231 
9232 static void g0_identity_private(PetscInt dim, PetscInt Nf, PetscInt NfAux,
9233                                 const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
9234                                 const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
9235                                 PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g0[])
9236 {
9237   const PetscInt Nc = uOff[1] - uOff[0];
9238   PetscInt       c;
9239   for (c = 0; c < Nc; ++c) g0[c*Nc+c] = 1.0;
9240 }
9241 
9242 PetscErrorCode DMCreateMassMatrixLumped_Plex(DM dm, Vec *mass)
9243 {
9244   DM             dmc;
9245   PetscDS        ds;
9246   Vec            ones, locmass;
9247   IS             cellIS;
9248   PetscFormKey   key;
9249   PetscInt       depth;
9250   PetscErrorCode ierr;
9251 
9252   PetscFunctionBegin;
9253   ierr = DMClone(dm, &dmc);CHKERRQ(ierr);
9254   ierr = DMCopyDisc(dm, dmc);CHKERRQ(ierr);
9255   ierr = DMGetDS(dmc, &ds);CHKERRQ(ierr);
9256   ierr = PetscDSSetJacobian(ds, 0, 0, g0_identity_private, NULL, NULL, NULL);CHKERRQ(ierr);
9257   ierr = DMCreateGlobalVector(dmc, mass);CHKERRQ(ierr);
9258   ierr = DMGetLocalVector(dmc, &ones);CHKERRQ(ierr);
9259   ierr = DMGetLocalVector(dmc, &locmass);CHKERRQ(ierr);
9260   ierr = DMPlexGetDepth(dmc, &depth);CHKERRQ(ierr);
9261   ierr = DMGetStratumIS(dmc, "depth", depth, &cellIS);CHKERRQ(ierr);
9262   ierr = VecSet(locmass, 0.0);CHKERRQ(ierr);
9263   ierr = VecSet(ones, 1.0);CHKERRQ(ierr);
9264   key.label = NULL;
9265   key.value = 0;
9266   key.field = 0;
9267   key.part  = 0;
9268   ierr = DMPlexComputeJacobian_Action_Internal(dmc, key, cellIS, 0.0, 0.0, ones, NULL, ones, locmass, NULL);CHKERRQ(ierr);
9269   ierr = ISDestroy(&cellIS);CHKERRQ(ierr);
9270   ierr = VecSet(*mass, 0.0);CHKERRQ(ierr);
9271   ierr = DMLocalToGlobalBegin(dmc, locmass, ADD_VALUES, *mass);CHKERRQ(ierr);
9272   ierr = DMLocalToGlobalEnd(dmc, locmass, ADD_VALUES, *mass);CHKERRQ(ierr);
9273   ierr = DMRestoreLocalVector(dmc, &ones);CHKERRQ(ierr);
9274   ierr = DMRestoreLocalVector(dmc, &locmass);CHKERRQ(ierr);
9275   ierr = DMDestroy(&dmc);CHKERRQ(ierr);
9276   PetscFunctionReturn(0);
9277 }
9278 
9279 PetscErrorCode DMCreateMassMatrix_Plex(DM dmCoarse, DM dmFine, Mat *mass)
9280 {
9281   PetscSection   gsc, gsf;
9282   PetscInt       m, n;
9283   void          *ctx;
9284   DM             cdm;
9285   PetscBool      regular;
9286   PetscErrorCode ierr;
9287 
9288   PetscFunctionBegin;
9289   if (dmFine == dmCoarse) {
9290     DM            dmc;
9291     PetscDS       ds;
9292     PetscWeakForm wf;
9293     Vec           u;
9294     IS            cellIS;
9295     PetscFormKey  key;
9296     PetscInt      depth;
9297 
9298     ierr = DMClone(dmFine, &dmc);CHKERRQ(ierr);
9299     ierr = DMCopyDisc(dmFine, dmc);CHKERRQ(ierr);
9300     ierr = DMGetDS(dmc, &ds);CHKERRQ(ierr);
9301     ierr = PetscDSGetWeakForm(ds, &wf);CHKERRQ(ierr);
9302     ierr = PetscWeakFormClear(wf);CHKERRQ(ierr);
9303     ierr = PetscDSSetJacobian(ds, 0, 0, g0_identity_private, NULL, NULL, NULL);CHKERRQ(ierr);
9304     ierr = DMCreateMatrix(dmc, mass);CHKERRQ(ierr);
9305     ierr = DMGetGlobalVector(dmc, &u);CHKERRQ(ierr);
9306     ierr = DMPlexGetDepth(dmc, &depth);CHKERRQ(ierr);
9307     ierr = DMGetStratumIS(dmc, "depth", depth, &cellIS);CHKERRQ(ierr);
9308     ierr = MatZeroEntries(*mass);CHKERRQ(ierr);
9309     key.label = NULL;
9310     key.value = 0;
9311     key.field = 0;
9312     key.part  = 0;
9313     ierr = DMPlexComputeJacobian_Internal(dmc, key, cellIS, 0.0, 0.0, u, NULL, *mass, *mass, NULL);CHKERRQ(ierr);
9314     ierr = ISDestroy(&cellIS);CHKERRQ(ierr);
9315     ierr = DMRestoreGlobalVector(dmc, &u);CHKERRQ(ierr);
9316     ierr = DMDestroy(&dmc);CHKERRQ(ierr);
9317   } else {
9318     ierr = DMGetGlobalSection(dmFine, &gsf);CHKERRQ(ierr);
9319     ierr = PetscSectionGetConstrainedStorageSize(gsf, &m);CHKERRQ(ierr);
9320     ierr = DMGetGlobalSection(dmCoarse, &gsc);CHKERRQ(ierr);
9321     ierr = PetscSectionGetConstrainedStorageSize(gsc, &n);CHKERRQ(ierr);
9322 
9323     ierr = MatCreate(PetscObjectComm((PetscObject) dmCoarse), mass);CHKERRQ(ierr);
9324     ierr = MatSetSizes(*mass, m, n, PETSC_DETERMINE, PETSC_DETERMINE);CHKERRQ(ierr);
9325     ierr = MatSetType(*mass, dmCoarse->mattype);CHKERRQ(ierr);
9326     ierr = DMGetApplicationContext(dmFine, &ctx);CHKERRQ(ierr);
9327 
9328     ierr = DMGetCoarseDM(dmFine, &cdm);CHKERRQ(ierr);
9329     ierr = DMPlexGetRegularRefinement(dmFine, &regular);CHKERRQ(ierr);
9330     if (regular && cdm == dmCoarse) {ierr = DMPlexComputeMassMatrixNested(dmCoarse, dmFine, *mass, ctx);CHKERRQ(ierr);}
9331     else                            {ierr = DMPlexComputeMassMatrixGeneral(dmCoarse, dmFine, *mass, ctx);CHKERRQ(ierr);}
9332   }
9333   ierr = MatViewFromOptions(*mass, NULL, "-mass_mat_view");CHKERRQ(ierr);
9334   PetscFunctionReturn(0);
9335 }
9336 
9337 /*@
9338   DMPlexGetRegularRefinement - Get the flag indicating that this mesh was obtained by regular refinement from its coarse mesh
9339 
9340   Input Parameter:
9341 . dm - The DMPlex object
9342 
9343   Output Parameter:
9344 . regular - The flag
9345 
9346   Level: intermediate
9347 
9348 .seealso: DMPlexSetRegularRefinement()
9349 @*/
9350 PetscErrorCode DMPlexGetRegularRefinement(DM dm, PetscBool *regular)
9351 {
9352   PetscFunctionBegin;
9353   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9354   PetscValidPointer(regular, 2);
9355   *regular = ((DM_Plex *) dm->data)->regularRefinement;
9356   PetscFunctionReturn(0);
9357 }
9358 
9359 /*@
9360   DMPlexSetRegularRefinement - Set the flag indicating that this mesh was obtained by regular refinement from its coarse mesh
9361 
9362   Input Parameters:
9363 + dm - The DMPlex object
9364 - regular - The flag
9365 
9366   Level: intermediate
9367 
9368 .seealso: DMPlexGetRegularRefinement()
9369 @*/
9370 PetscErrorCode DMPlexSetRegularRefinement(DM dm, PetscBool regular)
9371 {
9372   PetscFunctionBegin;
9373   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9374   ((DM_Plex *) dm->data)->regularRefinement = regular;
9375   PetscFunctionReturn(0);
9376 }
9377 
9378 /* anchors */
9379 /*@
9380   DMPlexGetAnchors - Get the layout of the anchor (point-to-point) constraints.  Typically, the user will not have to
9381   call DMPlexGetAnchors() directly: if there are anchors, then DMPlexGetAnchors() is called during DMGetDefaultConstraints().
9382 
9383   not collective
9384 
9385   Input Parameter:
9386 . dm - The DMPlex object
9387 
9388   Output Parameters:
9389 + anchorSection - If not NULL, set to the section describing which points anchor the constrained points.
9390 - anchorIS - If not NULL, set to the list of anchors indexed by anchorSection
9391 
9392   Level: intermediate
9393 
9394 .seealso: DMPlexSetAnchors(), DMGetDefaultConstraints(), DMSetDefaultConstraints()
9395 @*/
9396 PetscErrorCode DMPlexGetAnchors(DM dm, PetscSection *anchorSection, IS *anchorIS)
9397 {
9398   DM_Plex *plex = (DM_Plex *)dm->data;
9399   PetscErrorCode ierr;
9400 
9401   PetscFunctionBegin;
9402   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9403   if (!plex->anchorSection && !plex->anchorIS && plex->createanchors) {ierr = (*plex->createanchors)(dm);CHKERRQ(ierr);}
9404   if (anchorSection) *anchorSection = plex->anchorSection;
9405   if (anchorIS) *anchorIS = plex->anchorIS;
9406   PetscFunctionReturn(0);
9407 }
9408 
9409 /*@
9410   DMPlexSetAnchors - Set the layout of the local anchor (point-to-point) constraints.  Unlike boundary conditions,
9411   when a point's degrees of freedom in a section are constrained to an outside value, the anchor constraints set a
9412   point's degrees of freedom to be a linear combination of other points' degrees of freedom.
9413 
9414   After specifying the layout of constraints with DMPlexSetAnchors(), one specifies the constraints by calling
9415   DMGetDefaultConstraints() and filling in the entries in the constraint matrix.
9416 
9417   collective on dm
9418 
9419   Input Parameters:
9420 + dm - The DMPlex object
9421 . 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).
9422 - anchorIS - The list of all anchor points.  Must have a local communicator (PETSC_COMM_SELF or derivative).
9423 
9424   The reference counts of anchorSection and anchorIS are incremented.
9425 
9426   Level: intermediate
9427 
9428 .seealso: DMPlexGetAnchors(), DMGetDefaultConstraints(), DMSetDefaultConstraints()
9429 @*/
9430 PetscErrorCode DMPlexSetAnchors(DM dm, PetscSection anchorSection, IS anchorIS)
9431 {
9432   DM_Plex        *plex = (DM_Plex *)dm->data;
9433   PetscMPIInt    result;
9434   PetscErrorCode ierr;
9435 
9436   PetscFunctionBegin;
9437   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9438   if (anchorSection) {
9439     PetscValidHeaderSpecific(anchorSection,PETSC_SECTION_CLASSID,2);
9440     ierr = MPI_Comm_compare(PETSC_COMM_SELF,PetscObjectComm((PetscObject)anchorSection),&result);CHKERRMPI(ierr);
9441     PetscCheckFalse(result != MPI_CONGRUENT && result != MPI_IDENT,PETSC_COMM_SELF,PETSC_ERR_ARG_NOTSAMECOMM,"anchor section must have local communicator");
9442   }
9443   if (anchorIS) {
9444     PetscValidHeaderSpecific(anchorIS,IS_CLASSID,3);
9445     ierr = MPI_Comm_compare(PETSC_COMM_SELF,PetscObjectComm((PetscObject)anchorIS),&result);CHKERRMPI(ierr);
9446     PetscCheckFalse(result != MPI_CONGRUENT && result != MPI_IDENT,PETSC_COMM_SELF,PETSC_ERR_ARG_NOTSAMECOMM,"anchor IS must have local communicator");
9447   }
9448 
9449   ierr = PetscObjectReference((PetscObject)anchorSection);CHKERRQ(ierr);
9450   ierr = PetscSectionDestroy(&plex->anchorSection);CHKERRQ(ierr);
9451   plex->anchorSection = anchorSection;
9452 
9453   ierr = PetscObjectReference((PetscObject)anchorIS);CHKERRQ(ierr);
9454   ierr = ISDestroy(&plex->anchorIS);CHKERRQ(ierr);
9455   plex->anchorIS = anchorIS;
9456 
9457   if (PetscUnlikelyDebug(anchorIS && anchorSection)) {
9458     PetscInt size, a, pStart, pEnd;
9459     const PetscInt *anchors;
9460 
9461     ierr = PetscSectionGetChart(anchorSection,&pStart,&pEnd);CHKERRQ(ierr);
9462     ierr = ISGetLocalSize(anchorIS,&size);CHKERRQ(ierr);
9463     ierr = ISGetIndices(anchorIS,&anchors);CHKERRQ(ierr);
9464     for (a = 0; a < size; a++) {
9465       PetscInt p;
9466 
9467       p = anchors[a];
9468       if (p >= pStart && p < pEnd) {
9469         PetscInt dof;
9470 
9471         ierr = PetscSectionGetDof(anchorSection,p,&dof);CHKERRQ(ierr);
9472         if (dof) {
9473           PetscErrorCode ierr2;
9474 
9475           ierr2 = ISRestoreIndices(anchorIS,&anchors);CHKERRQ(ierr2);
9476           SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Point %D cannot be constrained and an anchor",p);
9477         }
9478       }
9479     }
9480     ierr = ISRestoreIndices(anchorIS,&anchors);CHKERRQ(ierr);
9481   }
9482   /* reset the generic constraints */
9483   ierr = DMSetDefaultConstraints(dm,NULL,NULL,NULL);CHKERRQ(ierr);
9484   PetscFunctionReturn(0);
9485 }
9486 
9487 static PetscErrorCode DMPlexCreateConstraintSection_Anchors(DM dm, PetscSection section, PetscSection *cSec)
9488 {
9489   PetscSection anchorSection;
9490   PetscInt pStart, pEnd, sStart, sEnd, p, dof, numFields, f;
9491   PetscErrorCode ierr;
9492 
9493   PetscFunctionBegin;
9494   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9495   ierr = DMPlexGetAnchors(dm,&anchorSection,NULL);CHKERRQ(ierr);
9496   ierr = PetscSectionCreate(PETSC_COMM_SELF,cSec);CHKERRQ(ierr);
9497   ierr = PetscSectionGetNumFields(section,&numFields);CHKERRQ(ierr);
9498   if (numFields) {
9499     PetscInt f;
9500     ierr = PetscSectionSetNumFields(*cSec,numFields);CHKERRQ(ierr);
9501 
9502     for (f = 0; f < numFields; f++) {
9503       PetscInt numComp;
9504 
9505       ierr = PetscSectionGetFieldComponents(section,f,&numComp);CHKERRQ(ierr);
9506       ierr = PetscSectionSetFieldComponents(*cSec,f,numComp);CHKERRQ(ierr);
9507     }
9508   }
9509   ierr = PetscSectionGetChart(anchorSection,&pStart,&pEnd);CHKERRQ(ierr);
9510   ierr = PetscSectionGetChart(section,&sStart,&sEnd);CHKERRQ(ierr);
9511   pStart = PetscMax(pStart,sStart);
9512   pEnd   = PetscMin(pEnd,sEnd);
9513   pEnd   = PetscMax(pStart,pEnd);
9514   ierr = PetscSectionSetChart(*cSec,pStart,pEnd);CHKERRQ(ierr);
9515   for (p = pStart; p < pEnd; p++) {
9516     ierr = PetscSectionGetDof(anchorSection,p,&dof);CHKERRQ(ierr);
9517     if (dof) {
9518       ierr = PetscSectionGetDof(section,p,&dof);CHKERRQ(ierr);
9519       ierr = PetscSectionSetDof(*cSec,p,dof);CHKERRQ(ierr);
9520       for (f = 0; f < numFields; f++) {
9521         ierr = PetscSectionGetFieldDof(section,p,f,&dof);CHKERRQ(ierr);
9522         ierr = PetscSectionSetFieldDof(*cSec,p,f,dof);CHKERRQ(ierr);
9523       }
9524     }
9525   }
9526   ierr = PetscSectionSetUp(*cSec);CHKERRQ(ierr);
9527   ierr = PetscObjectSetName((PetscObject) *cSec, "Constraint Section");CHKERRQ(ierr);
9528   PetscFunctionReturn(0);
9529 }
9530 
9531 static PetscErrorCode DMPlexCreateConstraintMatrix_Anchors(DM dm, PetscSection section, PetscSection cSec, Mat *cMat)
9532 {
9533   PetscSection   aSec;
9534   PetscInt       pStart, pEnd, p, sStart, sEnd, dof, aDof, aOff, off, nnz, annz, m, n, q, a, offset, *i, *j;
9535   const PetscInt *anchors;
9536   PetscInt       numFields, f;
9537   IS             aIS;
9538   PetscErrorCode ierr;
9539   MatType        mtype;
9540   PetscBool      iscuda,iskokkos;
9541 
9542   PetscFunctionBegin;
9543   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9544   ierr = PetscSectionGetStorageSize(cSec, &m);CHKERRQ(ierr);
9545   ierr = PetscSectionGetStorageSize(section, &n);CHKERRQ(ierr);
9546   ierr = MatCreate(PETSC_COMM_SELF,cMat);CHKERRQ(ierr);
9547   ierr = MatSetSizes(*cMat,m,n,m,n);CHKERRQ(ierr);
9548   ierr = PetscStrcmp(dm->mattype,MATSEQAIJCUSPARSE,&iscuda);CHKERRQ(ierr);
9549   if (!iscuda) { ierr = PetscStrcmp(dm->mattype,MATMPIAIJCUSPARSE,&iscuda);CHKERRQ(ierr); }
9550   ierr = PetscStrcmp(dm->mattype,MATSEQAIJKOKKOS,&iskokkos);CHKERRQ(ierr);
9551   if (!iskokkos) { ierr = PetscStrcmp(dm->mattype,MATMPIAIJKOKKOS,&iskokkos);CHKERRQ(ierr); }
9552   if (iscuda) mtype = MATSEQAIJCUSPARSE;
9553   else if (iskokkos) mtype = MATSEQAIJKOKKOS;
9554   else mtype = MATSEQAIJ;
9555   ierr = MatSetType(*cMat,mtype);CHKERRQ(ierr);
9556   ierr = DMPlexGetAnchors(dm,&aSec,&aIS);CHKERRQ(ierr);
9557   ierr = ISGetIndices(aIS,&anchors);CHKERRQ(ierr);
9558   /* cSec will be a subset of aSec and section */
9559   ierr = PetscSectionGetChart(cSec,&pStart,&pEnd);CHKERRQ(ierr);
9560   ierr = PetscSectionGetChart(section,&sStart,&sEnd);CHKERRQ(ierr);
9561   ierr = PetscMalloc1(m+1,&i);CHKERRQ(ierr);
9562   i[0] = 0;
9563   ierr = PetscSectionGetNumFields(section,&numFields);CHKERRQ(ierr);
9564   for (p = pStart; p < pEnd; p++) {
9565     PetscInt rDof, rOff, r;
9566 
9567     ierr = PetscSectionGetDof(aSec,p,&rDof);CHKERRQ(ierr);
9568     if (!rDof) continue;
9569     ierr = PetscSectionGetOffset(aSec,p,&rOff);CHKERRQ(ierr);
9570     if (numFields) {
9571       for (f = 0; f < numFields; f++) {
9572         annz = 0;
9573         for (r = 0; r < rDof; r++) {
9574           a = anchors[rOff + r];
9575           if (a < sStart || a >= sEnd) continue;
9576           ierr = PetscSectionGetFieldDof(section,a,f,&aDof);CHKERRQ(ierr);
9577           annz += aDof;
9578         }
9579         ierr = PetscSectionGetFieldDof(cSec,p,f,&dof);CHKERRQ(ierr);
9580         ierr = PetscSectionGetFieldOffset(cSec,p,f,&off);CHKERRQ(ierr);
9581         for (q = 0; q < dof; q++) {
9582           i[off + q + 1] = i[off + q] + annz;
9583         }
9584       }
9585     } else {
9586       annz = 0;
9587       ierr = PetscSectionGetDof(cSec,p,&dof);CHKERRQ(ierr);
9588       for (q = 0; q < dof; q++) {
9589         a = anchors[rOff + q];
9590         if (a < sStart || a >= sEnd) continue;
9591         ierr = PetscSectionGetDof(section,a,&aDof);CHKERRQ(ierr);
9592         annz += aDof;
9593       }
9594       ierr = PetscSectionGetDof(cSec,p,&dof);CHKERRQ(ierr);
9595       ierr = PetscSectionGetOffset(cSec,p,&off);CHKERRQ(ierr);
9596       for (q = 0; q < dof; q++) {
9597         i[off + q + 1] = i[off + q] + annz;
9598       }
9599     }
9600   }
9601   nnz = i[m];
9602   ierr = PetscMalloc1(nnz,&j);CHKERRQ(ierr);
9603   offset = 0;
9604   for (p = pStart; p < pEnd; p++) {
9605     if (numFields) {
9606       for (f = 0; f < numFields; f++) {
9607         ierr = PetscSectionGetFieldDof(cSec,p,f,&dof);CHKERRQ(ierr);
9608         for (q = 0; q < dof; q++) {
9609           PetscInt rDof, rOff, r;
9610           ierr = PetscSectionGetDof(aSec,p,&rDof);CHKERRQ(ierr);
9611           ierr = PetscSectionGetOffset(aSec,p,&rOff);CHKERRQ(ierr);
9612           for (r = 0; r < rDof; r++) {
9613             PetscInt s;
9614 
9615             a = anchors[rOff + r];
9616             if (a < sStart || a >= sEnd) continue;
9617             ierr = PetscSectionGetFieldDof(section,a,f,&aDof);CHKERRQ(ierr);
9618             ierr = PetscSectionGetFieldOffset(section,a,f,&aOff);CHKERRQ(ierr);
9619             for (s = 0; s < aDof; s++) {
9620               j[offset++] = aOff + s;
9621             }
9622           }
9623         }
9624       }
9625     } else {
9626       ierr = PetscSectionGetDof(cSec,p,&dof);CHKERRQ(ierr);
9627       for (q = 0; q < dof; q++) {
9628         PetscInt rDof, rOff, r;
9629         ierr = PetscSectionGetDof(aSec,p,&rDof);CHKERRQ(ierr);
9630         ierr = PetscSectionGetOffset(aSec,p,&rOff);CHKERRQ(ierr);
9631         for (r = 0; r < rDof; r++) {
9632           PetscInt s;
9633 
9634           a = anchors[rOff + r];
9635           if (a < sStart || a >= sEnd) continue;
9636           ierr = PetscSectionGetDof(section,a,&aDof);CHKERRQ(ierr);
9637           ierr = PetscSectionGetOffset(section,a,&aOff);CHKERRQ(ierr);
9638           for (s = 0; s < aDof; s++) {
9639             j[offset++] = aOff + s;
9640           }
9641         }
9642       }
9643     }
9644   }
9645   ierr = MatSeqAIJSetPreallocationCSR(*cMat,i,j,NULL);CHKERRQ(ierr);
9646   ierr = PetscFree(i);CHKERRQ(ierr);
9647   ierr = PetscFree(j);CHKERRQ(ierr);
9648   ierr = ISRestoreIndices(aIS,&anchors);CHKERRQ(ierr);
9649   PetscFunctionReturn(0);
9650 }
9651 
9652 PetscErrorCode DMCreateDefaultConstraints_Plex(DM dm)
9653 {
9654   DM_Plex        *plex = (DM_Plex *)dm->data;
9655   PetscSection   anchorSection, section, cSec;
9656   Mat            cMat;
9657   PetscErrorCode ierr;
9658 
9659   PetscFunctionBegin;
9660   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9661   ierr = DMPlexGetAnchors(dm,&anchorSection,NULL);CHKERRQ(ierr);
9662   if (anchorSection) {
9663     PetscInt Nf;
9664 
9665     ierr = DMGetLocalSection(dm,&section);CHKERRQ(ierr);
9666     ierr = DMPlexCreateConstraintSection_Anchors(dm,section,&cSec);CHKERRQ(ierr);
9667     ierr = DMPlexCreateConstraintMatrix_Anchors(dm,section,cSec,&cMat);CHKERRQ(ierr);
9668     ierr = DMGetNumFields(dm,&Nf);CHKERRQ(ierr);
9669     if (Nf && plex->computeanchormatrix) {ierr = (*plex->computeanchormatrix)(dm,section,cSec,cMat);CHKERRQ(ierr);}
9670     ierr = DMSetDefaultConstraints(dm,cSec,cMat,NULL);CHKERRQ(ierr);
9671     ierr = PetscSectionDestroy(&cSec);CHKERRQ(ierr);
9672     ierr = MatDestroy(&cMat);CHKERRQ(ierr);
9673   }
9674   PetscFunctionReturn(0);
9675 }
9676 
9677 PetscErrorCode DMCreateSubDomainDM_Plex(DM dm, DMLabel label, PetscInt value, IS *is, DM *subdm)
9678 {
9679   IS             subis;
9680   PetscSection   section, subsection;
9681   PetscErrorCode ierr;
9682 
9683   PetscFunctionBegin;
9684   ierr = DMGetLocalSection(dm, &section);CHKERRQ(ierr);
9685   PetscCheckFalse(!section,PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "Must set default section for DM before splitting subdomain");
9686   PetscCheckFalse(!subdm,PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "Must set output subDM for splitting subdomain");
9687   /* Create subdomain */
9688   ierr = DMPlexFilter(dm, label, value, subdm);CHKERRQ(ierr);
9689   /* Create submodel */
9690   ierr = DMPlexGetSubpointIS(*subdm, &subis);CHKERRQ(ierr);
9691   ierr = PetscSectionCreateSubmeshSection(section, subis, &subsection);CHKERRQ(ierr);
9692   ierr = DMSetLocalSection(*subdm, subsection);CHKERRQ(ierr);
9693   ierr = PetscSectionDestroy(&subsection);CHKERRQ(ierr);
9694   ierr = DMCopyDisc(dm, *subdm);CHKERRQ(ierr);
9695   /* Create map from submodel to global model */
9696   if (is) {
9697     PetscSection    sectionGlobal, subsectionGlobal;
9698     IS              spIS;
9699     const PetscInt *spmap;
9700     PetscInt       *subIndices;
9701     PetscInt        subSize = 0, subOff = 0, pStart, pEnd, p;
9702     PetscInt        Nf, f, bs = -1, bsLocal[2], bsMinMax[2];
9703 
9704     ierr = DMPlexGetSubpointIS(*subdm, &spIS);CHKERRQ(ierr);
9705     ierr = ISGetIndices(spIS, &spmap);CHKERRQ(ierr);
9706     ierr = PetscSectionGetNumFields(section, &Nf);CHKERRQ(ierr);
9707     ierr = DMGetGlobalSection(dm, &sectionGlobal);CHKERRQ(ierr);
9708     ierr = DMGetGlobalSection(*subdm, &subsectionGlobal);CHKERRQ(ierr);
9709     ierr = PetscSectionGetChart(subsection, &pStart, &pEnd);CHKERRQ(ierr);
9710     for (p = pStart; p < pEnd; ++p) {
9711       PetscInt gdof, pSubSize  = 0;
9712 
9713       ierr = PetscSectionGetDof(sectionGlobal, p, &gdof);CHKERRQ(ierr);
9714       if (gdof > 0) {
9715         for (f = 0; f < Nf; ++f) {
9716           PetscInt fdof, fcdof;
9717 
9718           ierr     = PetscSectionGetFieldDof(subsection, p, f, &fdof);CHKERRQ(ierr);
9719           ierr     = PetscSectionGetFieldConstraintDof(subsection, p, f, &fcdof);CHKERRQ(ierr);
9720           pSubSize += fdof-fcdof;
9721         }
9722         subSize += pSubSize;
9723         if (pSubSize) {
9724           if (bs < 0) {
9725             bs = pSubSize;
9726           } else if (bs != pSubSize) {
9727             /* Layout does not admit a pointwise block size */
9728             bs = 1;
9729           }
9730         }
9731       }
9732     }
9733     /* Must have same blocksize on all procs (some might have no points) */
9734     bsLocal[0] = bs < 0 ? PETSC_MAX_INT : bs; bsLocal[1] = bs;
9735     ierr = PetscGlobalMinMaxInt(PetscObjectComm((PetscObject) dm), bsLocal, bsMinMax);CHKERRQ(ierr);
9736     if (bsMinMax[0] != bsMinMax[1]) {bs = 1;}
9737     else                            {bs = bsMinMax[0];}
9738     ierr = PetscMalloc1(subSize, &subIndices);CHKERRQ(ierr);
9739     for (p = pStart; p < pEnd; ++p) {
9740       PetscInt gdof, goff;
9741 
9742       ierr = PetscSectionGetDof(subsectionGlobal, p, &gdof);CHKERRQ(ierr);
9743       if (gdof > 0) {
9744         const PetscInt point = spmap[p];
9745 
9746         ierr = PetscSectionGetOffset(sectionGlobal, point, &goff);CHKERRQ(ierr);
9747         for (f = 0; f < Nf; ++f) {
9748           PetscInt fdof, fcdof, fc, f2, poff = 0;
9749 
9750           /* Can get rid of this loop by storing field information in the global section */
9751           for (f2 = 0; f2 < f; ++f2) {
9752             ierr  = PetscSectionGetFieldDof(section, p, f2, &fdof);CHKERRQ(ierr);
9753             ierr  = PetscSectionGetFieldConstraintDof(section, p, f2, &fcdof);CHKERRQ(ierr);
9754             poff += fdof-fcdof;
9755           }
9756           ierr = PetscSectionGetFieldDof(section, p, f, &fdof);CHKERRQ(ierr);
9757           ierr = PetscSectionGetFieldConstraintDof(section, p, f, &fcdof);CHKERRQ(ierr);
9758           for (fc = 0; fc < fdof-fcdof; ++fc, ++subOff) {
9759             subIndices[subOff] = goff+poff+fc;
9760           }
9761         }
9762       }
9763     }
9764     ierr = ISRestoreIndices(spIS, &spmap);CHKERRQ(ierr);
9765     ierr = ISCreateGeneral(PetscObjectComm((PetscObject)dm), subSize, subIndices, PETSC_OWN_POINTER, is);CHKERRQ(ierr);
9766     if (bs > 1) {
9767       /* We need to check that the block size does not come from non-contiguous fields */
9768       PetscInt i, j, set = 1;
9769       for (i = 0; i < subSize; i += bs) {
9770         for (j = 0; j < bs; ++j) {
9771           if (subIndices[i+j] != subIndices[i]+j) {set = 0; break;}
9772         }
9773       }
9774       if (set) {ierr = ISSetBlockSize(*is, bs);CHKERRQ(ierr);}
9775     }
9776     /* Attach nullspace */
9777     for (f = 0; f < Nf; ++f) {
9778       (*subdm)->nullspaceConstructors[f] = dm->nullspaceConstructors[f];
9779       if ((*subdm)->nullspaceConstructors[f]) break;
9780     }
9781     if (f < Nf) {
9782       MatNullSpace nullSpace;
9783       ierr = (*(*subdm)->nullspaceConstructors[f])(*subdm, f, f, &nullSpace);CHKERRQ(ierr);
9784 
9785       ierr = PetscObjectCompose((PetscObject) *is, "nullspace", (PetscObject) nullSpace);CHKERRQ(ierr);
9786       ierr = MatNullSpaceDestroy(&nullSpace);CHKERRQ(ierr);
9787     }
9788   }
9789   PetscFunctionReturn(0);
9790 }
9791 
9792 /*@
9793   DMPlexMonitorThroughput - Report the cell throughput of FE integration
9794 
9795   Input Parameter:
9796 - dm - The DM
9797 
9798   Level: developer
9799 
9800   Options Database Keys:
9801 . -dm_plex_monitor_throughput - Activate the monitor
9802 
9803 .seealso: DMSetFromOptions(), DMPlexCreate()
9804 @*/
9805 PetscErrorCode DMPlexMonitorThroughput(DM dm, void *dummy)
9806 {
9807 #if defined(PETSC_USE_LOG)
9808   PetscStageLog      stageLog;
9809   PetscLogEvent      event;
9810   PetscLogStage      stage;
9811   PetscEventPerfInfo eventInfo;
9812   PetscReal          cellRate, flopRate;
9813   PetscInt           cStart, cEnd, Nf, N;
9814   const char        *name;
9815   PetscErrorCode     ierr;
9816 #endif
9817 
9818   PetscFunctionBegin;
9819   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9820 #if defined(PETSC_USE_LOG)
9821   ierr = PetscObjectGetName((PetscObject) dm, &name);CHKERRQ(ierr);
9822   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
9823   ierr = DMGetNumFields(dm, &Nf);CHKERRQ(ierr);
9824   ierr = PetscLogGetStageLog(&stageLog);CHKERRQ(ierr);
9825   ierr = PetscStageLogGetCurrent(stageLog, &stage);CHKERRQ(ierr);
9826   ierr = PetscLogEventGetId("DMPlexResidualFE", &event);CHKERRQ(ierr);
9827   ierr = PetscLogEventGetPerfInfo(stage, event, &eventInfo);CHKERRQ(ierr);
9828   N        = (cEnd - cStart)*Nf*eventInfo.count;
9829   flopRate = eventInfo.flops/eventInfo.time;
9830   cellRate = N/eventInfo.time;
9831   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);
9832 #else
9833   SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Plex Throughput Monitor is not supported if logging is turned off. Reconfigure using --with-log.");
9834 #endif
9835   PetscFunctionReturn(0);
9836 }
9837